Merge remote-tracking branch 'origin/feature/exchange_rates'

This commit is contained in:
Ahmed Bouhuolia
2020-05-12 01:10:11 +02:00
62 changed files with 2587 additions and 1155 deletions

View File

@@ -0,0 +1,132 @@
import React, { useEffect, useState, useCallback } from 'react';
import { useQuery } from 'react-query';
import { useParams } from 'react-router-dom';
import { Alert, Intent } from '@blueprintjs/core';
import AppToaster from 'components/AppToaster';
import DashboardPageContent from 'components/Dashboard/DashboardPageContent';
import DashboardInsider from 'components/Dashboard/DashboardInsider';
import ExchangeRateTable from './ExchangeRateTable';
import ExchangeRateActionsBar from './ExchangeRateActionsBar';
import withDashboardActions from 'containers/Dashboard/withDashboard';
import withResourceActions from 'containers/Resources/withResourcesActions';
import withExchangeRatesActions from 'containers/ExchangeRates/withExchangeRatesActions';
import { compose } from 'utils';
import { FormattedMessage as T, useIntl } from 'react-intl';
function ExchangeRate({
// #withDashboard
changePageTitle,
//#withResourceActions
requestFetchResourceFields,
// #withExchangeRatesActions
requestFetchExchangeRates,
requestDeleteExchangeRate,
addExchangeRatesTableQueries,
}) {
const { id } = useParams();
const [deleteExchangeRate, setDeleteExchangeRate] = useState(false);
const [selectedRows, setSelectedRows] = useState([]);
const { formatMessage } = useIntl();
// const fetchExchangeRates = useQuery('exchange-rates-table', () => {
// return Promise.all([requestFetchExchangeRates()]);
// });
const fetchExchangeRates = useQuery('exchange-rates-table',
() => requestFetchExchangeRates(),
{ refetchInterval: 3000 });
useEffect(() => {
id
? changePageTitle(formatMessage({id:'exchange_rate_details'}))
: changePageTitle(formatMessage({id:'exchange_rate_list'}));
}, [id, changePageTitle]);
const handelDeleteExchangeRate = useCallback(
(exchange_rate) => {
setDeleteExchangeRate(exchange_rate);
},
[setDeleteExchangeRate]
);
const handelEditExchangeRate = (exchange_rate) => {};
const handelCancelExchangeRateDelete = useCallback(() => {
setDeleteExchangeRate(false);
}, [setDeleteExchangeRate]);
const handelConfirmExchangeRateDelete = useCallback(() => {
requestDeleteExchangeRate(deleteExchangeRate.id).then(() => {
setDeleteExchangeRate(false);
AppToaster.show({
message: 'the_exchange_rate_has_been_delete',
});
});
}, [deleteExchangeRate, requestDeleteExchangeRate]);
// Handle fetch data of Exchange_rates datatable.
const handleFetchData = useCallback(
({ pageIndex, pageSize, sortBy }) => {
addExchangeRatesTableQueries({
...(sortBy.length > 0
? {
column_sort_by: sortBy[0].id,
sort_order: sortBy[0].desc ? 'desc' : 'asc',
}
: {}),
});
},
[addExchangeRatesTableQueries]
);
const handleSelectedRowsChange = useCallback(
(exchange_rates) => {
setSelectedRows(exchange_rates);
},
[setSelectedRows]
);
return (
<DashboardInsider>
<ExchangeRateActionsBar
onDeleteExchangeRate={handelDeleteExchangeRate}
selectedRows={selectedRows}
/>
<DashboardPageContent>
<ExchangeRateTable
onDeleteExchangeRate={handelDeleteExchangeRate}
onEditExchangeRate={handelEditExchangeRate}
onFetchData={handleFetchData}
onSelectedRowsChange={handleSelectedRowsChange}
/>
<Alert
cancelButtonText={<T id={'cancel'} />}
confirmButtonText={<T id={'move_to_trash'} />}
icon='trash'
intent={Intent.DANGER}
isOpen={deleteExchangeRate}
onCancel={handelCancelExchangeRateDelete}
onConfirm={handelConfirmExchangeRateDelete}
>
<p>
Are you sure you want to move <b>filename</b> to Trash? You will be
able to restore it later, but it will become private to you.
</p>
</Alert>
</DashboardPageContent>
</DashboardInsider>
);
}
export default compose(
withExchangeRatesActions,
withResourceActions,
withDashboardActions
)(ExchangeRate);

View File

@@ -0,0 +1,125 @@
import React, { useCallback, useState, useMemo } from 'react';
import {
NavbarGroup,
Button,
Classes,
Intent,
Popover,
Position,
PopoverInteractionKind,
} from '@blueprintjs/core';
import classNames from 'classnames';
import Icon from 'components/Icon';
import { connect } from 'react-redux';
import DashboardActionsBar from 'components/Dashboard/DashboardActionsBar';
import DialogConnect from 'connectors/Dialog.connector';
import FilterDropdown from 'components/FilterDropdown';
import withResourceDetail from 'containers/Resources/withResourceDetails';
import { compose } from 'utils';
import { FormattedMessage as T } from 'react-intl';
function ExchangeRateActionsBar({
// #withDialog.
openDialog,
// #withResourceDetail
resourceFields,
selectedRows = [],
onDeleteExchangeRate,
onFilterChanged,
}) {
const [filterCount, setFilterCount] = useState(0);
const onClickNewExchangeRate = () => {
openDialog('exchangeRate-form', {});
};
const filterDropdown = FilterDropdown({
fields: resourceFields,
onFilterChange: (filterConditions) => {
setFilterCount(filterConditions.length || 0);
onFilterChanged && onFilterChanged(filterConditions);
},
});
const handelDeleteExchangeRate = useCallback(
(exchangeRate) => {
onDeleteExchangeRate(exchangeRate);
},
[selectedRows, onDeleteExchangeRate]
);
const hasSelectedRows = useMemo(() => selectedRows.length > 0, [
selectedRows,
]);
return (
<DashboardActionsBar>
<NavbarGroup>
<Button
className={Classes.MINIMAL}
icon={<Icon icon='plus' />}
text={<T id={'new_exchange_rate'} />}
onClick={onClickNewExchangeRate}
/>
<Popover
minimal={true}
content={filterDropdown}
interactionKind={PopoverInteractionKind.CLICK}
position={Position.BOTTOM_LEFT}
>
<Button
className={classNames(Classes.MINIMAL, 'button--filter')}
text={
filterCount <= 0 ? (
<T id={'filter'} />
) : (
`${filterCount} filters applied`
)
}
icon={<Icon icon='filter' />}
/>
</Popover>
{hasSelectedRows && (
<Button
className={Classes.MINIMAL}
icon={<Icon icon='trash' iconSize={15} />}
text={<T id={'delete'} />}
intent={Intent.DANGER}
onClick={handelDeleteExchangeRate}
/>
)}
<Button
className={Classes.MINIMAL}
icon={<Icon icon='file-import' />}
text={<T id={'import'} />}
/>
<Button
className={Classes.MINIMAL}
icon={<Icon icon='file-export' />}
text={<T id={'export'} />}
/>
</NavbarGroup>
</DashboardActionsBar>
);
}
const mapStateToProps = (state, props) => ({
resourceName: 'exchange_rates',
});
const withExchangeRateActionBar = connect(mapStateToProps);
export default compose(
withExchangeRateActionBar,
DialogConnect,
withResourceDetail(({ resourceFields }) => ({
resourceFields,
}))
)(ExchangeRateActionsBar);

View File

@@ -0,0 +1,136 @@
import React, { useCallback, useMemo,useState } from 'react';
import Icon from 'components/Icon';
import DialogConnect from 'connectors/Dialog.connector';
import LoadingIndicator from 'components/LoadingIndicator';
import DataTable from 'components/DataTable';
import { Button, Popover, Menu, MenuItem, Position } from '@blueprintjs/core';
import withExchangeRatesActions from 'containers/ExchangeRates/withExchangeRatesActions';
import withExchangeRates from 'containers/ExchangeRates/withExchangeRates';
import { compose } from 'utils';
import { FormattedMessage as T, useIntl } from 'react-intl';
function ExchangeRateTable({
// #withExchangeRates
exchangeRatesList,
exchangeRatesLoading,
// #withDialog.
openDialog,
// own properties
loading,
onFetchData,
onDeleteExchangeRate,
onEditExchangeRate,
onSelectedRowsChange,
}) {
const [initialMount, setInitialMount] = useState(false);
const { formatMessage } = useIntl();
const handelEditExchangeRate = (exchange_rate) => () => {
openDialog('exchangeRate-form', { action: 'edit', id: exchange_rate.id });
onEditExchangeRate(exchange_rate.id);
};
const handleDeleteExchangeRate = (exchange_rate) => () => {
onDeleteExchangeRate(exchange_rate);
};
const actionMenuList = useCallback(
(ExchangeRate) => (
<Menu>
<MenuItem
text={<T id={'edit_exchange_rate'} />}
onClick={handelEditExchangeRate(ExchangeRate)}
/>
<MenuItem
text={<T id={'delete_exchange_rate'} />}
onClick={handleDeleteExchangeRate(ExchangeRate)}
/>
</Menu>
),
[handelEditExchangeRate, handleDeleteExchangeRate]
);
const columns = useMemo(() => [
{
id: 'date',
Header: formatMessage({ id: 'date' }),
// accessor: 'date',
width: 150,
},
{
id: 'currency_code',
Header: formatMessage({ id: 'currency_code' }),
accessor: 'currency_code',
className: 'currency_code',
width: 150,
},
{
id: 'exchange_rate',
Header: formatMessage({ id: 'exchange_rate' }),
accessor: 'exchange_rate',
className: 'exchange_rate',
width: 150,
},
{
id: 'actions',
Header: '',
Cell: ({ cell }) => (
<Popover
content={actionMenuList(cell.row.original)}
position={Position.RIGHT_BOTTOM}
>
<Button icon={<Icon icon='ellipsis-h' />} />
</Popover>
),
className: 'actions',
width: 50,
disableResizing: false,
},
], [actionMenuList]);
const selectionColumn = useMemo(() => ({
minWidth: 42,
width: 42,
maxWidth: 42,
}), []);
const handelFetchData = useCallback(
(...params) => {
onFetchData && onFetchData(...params);
},
[onFetchData]
);
const handelSelectedRowsChange = useCallback((selectRows) => {
onSelectedRowsChange && onSelectedRowsChange(selectRows.map((c) => c.original));
}, [onSelectedRowsChange]);
return (
<DataTable
columns={columns}
data={exchangeRatesList}
onFetchData={handelFetchData}
loading={exchangeRatesLoading && !initialMount}
manualSortBy={true}
selectionColumn={selectionColumn}
expandable={true}
treeGraph={true}
onSelectedRowsChange={handelSelectedRowsChange}
spinnerProps={{ size: 30 }}
/>
);
}
export default compose(
DialogConnect,
withExchangeRatesActions,
withExchangeRates(({ exchangeRatesList ,exchangeRatesLoading }) => ({
exchangeRatesList,
exchangeRatesLoading
}))
)(ExchangeRateTable);

View File

@@ -0,0 +1,14 @@
import { connect } from 'react-redux';
import { getResourceViews } from 'store/customViews/customViews.selectors';
export default (mapState) => {
const mapStateToProps = (state, props) => {
const mapped = {
exchangeRatesList: Object.values(state.exchangeRates.exchangeRates),
exchangeRatesLoading: state.exchangeRates.loading,
};
return mapState ? mapState(mapped, state, props) : mapped;
};
return connect(mapStateToProps);
};

View File

@@ -0,0 +1,21 @@
import { connect } from 'react-redux';
import {
submitExchangeRate,
fetchExchangeRates,
deleteExchangeRate,
editExchangeRate,
} from 'store/ExchangeRate/exchange.actions';
const mapActionsToProps = (dispatch) => ({
requestSubmitExchangeRate: (form) => dispatch(submitExchangeRate({ form })),
requestFetchExchangeRates: () => dispatch(fetchExchangeRates()),
requestDeleteExchangeRate: (id) => dispatch(deleteExchangeRate(id)),
requestEditExchangeRate: (id, form) => dispatch(editExchangeRate(id, form)),
addExchangeRatesTableQueries: (queries) =>
dispatch({
type: 'ExchangeRates_TABLE_QUERIES_ADD',
queries,
}),
});
export default connect(null, mapActionsToProps);