Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

OM-119: add a voucher export functionality #24

Merged
merged 2 commits into from
Feb 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions src/actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -245,3 +245,19 @@ export function deleteVoucherPrice(voucherPriceUuid, clientMutationLabel) {
},
);
}

export function downloadWorkerVoucher(params) {
const payload = `
{
workerVoucherExport${!!params && params.length ? `(${params.join(',')})` : ''}
}`;
return graphql(payload, ACTION_TYPE.EXPORT_WORKER_VOUCHER);
}

export function clearWorkerVoucherExport() {
return (dispatch) => {
dispatch({
type: CLEAR(ACTION_TYPE.EXPORT_WORKER_VOUCHER),
});
};
}
127 changes: 96 additions & 31 deletions src/components/VoucherSearcher.js
Original file line number Diff line number Diff line change
@@ -1,21 +1,27 @@
import React from 'react';
import { useDispatch, useSelector } from 'react-redux';
import React, { useState, useEffect } from 'react';
import { useSelector, connect } from 'react-redux';
import { bindActionCreators } from 'redux';

import { IconButton, Tooltip } from '@material-ui/core';
import {
IconButton, Button, Tooltip, Dialog, DialogActions, DialogTitle, DialogContent,
} from '@material-ui/core';
import VisibilityIcon from '@material-ui/icons/Visibility';

import {
Searcher, useHistory, useModulesManager, useTranslations,
Searcher, useHistory, useModulesManager, useTranslations, downloadExport,
} from '@openimis/fe-core';
import { fetchWorkerVouchers } from '../actions';
import { fetchWorkerVouchers, downloadWorkerVoucher, clearWorkerVoucherExport } from '../actions';
import {
DEFAULT_PAGE_SIZE, MODULE_NAME, REF_ROUTE_WORKER_VOUCHER, ROWS_PER_PAGE_OPTIONS, VOUCHER_RIGHT_SEARCH,
DEFAULT_PAGE_SIZE,
MODULE_NAME,
REF_ROUTE_WORKER_VOUCHER,
ROWS_PER_PAGE_OPTIONS,
VOUCHER_RIGHT_SEARCH,
} from '../constants';
import VoucherFilter from './VoucherFilter';

function VoucherSearcher() {
function VoucherSearcher({ downloadWorkerVoucher, fetchWorkerVouchers, clearWorkerVoucherExport }) {
const history = useHistory();
const dispatch = useDispatch();
const modulesManager = useModulesManager();
const rights = useSelector((state) => state.core?.user?.i_user?.rights ?? []);
const { formatMessage, formatMessageWithValues } = useTranslations(MODULE_NAME, modulesManager);
Expand All @@ -26,11 +32,23 @@ function VoucherSearcher() {
workerVouchers,
workerVouchersPageInfo,
workerVouchersTotalCount,
workerVoucherExport,
errorWorkerVoucherExport,
} = useSelector((state) => state.workerVoucher);
const [failedExport, setFailedExport] = useState(false);
const exportConfiguration = {
exportFields: ['code', 'policyholder', 'insuree', 'status'],
exportFieldsColumns: {
code: formatMessage('code'),
policyholder: formatMessage('employer'),
insuree: formatMessage('worker'),
status: formatMessage('status'),
},
};

const fetchVouchers = (params) => {
try {
dispatch(fetchWorkerVouchers(modulesManager, params));
fetchWorkerVouchers(modulesManager, params);
} catch (error) {
throw new Error(`[VOUCHER_SEARCHER]: Fetching vouchers failed. ${error}`);
}
Expand All @@ -57,9 +75,8 @@ function VoucherSearcher() {

const rowIdentifier = (workerVoucher) => workerVoucher.uuid;

const openWorkerVoucher = (workerVoucher) => rights.includes(VOUCHER_RIGHT_SEARCH) && history.push(
`/${modulesManager.getRef(REF_ROUTE_WORKER_VOUCHER)}/${workerVoucher?.uuid}`,
);
const openWorkerVoucher = (workerVoucher) => rights.includes(VOUCHER_RIGHT_SEARCH)
&& history.push(`/${modulesManager.getRef(REF_ROUTE_WORKER_VOUCHER)}/${workerVoucher?.uuid}`);

const onDoubleClick = (workerVoucher) => openWorkerVoucher(workerVoucher);

Expand All @@ -81,30 +98,78 @@ function VoucherSearcher() {
),
];

useEffect(() => {
if (errorWorkerVoucherExport) {
setFailedExport(true);
}
}, [errorWorkerVoucherExport]);

useEffect(() => {
if (workerVoucherExport) {
downloadExport(workerVoucherExport, `${formatMessage('export.filename')}.csv`)();
clearWorkerVoucherExport();
}
}, [workerVoucherExport]);

const handleExportErrorDialogClose = () => {
setFailedExport(false);
};

const voucherFilter = ({ filters, onChangeFilters }) => (
<VoucherFilter filters={filters} onChangeFilters={onChangeFilters} formatMessage={formatMessage} />
);

return (
<Searcher
module="workerVoucher"
FilterPane={voucherFilter}
fetch={fetchVouchers}
items={workerVouchers}
itemsPageInfo={workerVouchersPageInfo}
fetchedItems={fetchedWorkerVouchers}
fetchingItems={fetchingWorkerVouchers}
errorItems={errorWorkerVouchers}
tableTitle={formatMessageWithValues('workerVoucher.searcherResultsTitle', { workerVouchersTotalCount })}
headers={headers}
itemFormatters={itemFormatters}
sorts={sorts}
rowsPerPageOptions={ROWS_PER_PAGE_OPTIONS}
defaultPageSize={DEFAULT_PAGE_SIZE}
rowIdentifier={rowIdentifier}
onDoubleClick={onDoubleClick}
/>
<>
<Searcher
module="workerVoucher"
FilterPane={voucherFilter}
fetch={fetchVouchers}
items={workerVouchers}
itemsPageInfo={workerVouchersPageInfo}
fetchedItems={fetchedWorkerVouchers}
fetchingItems={fetchingWorkerVouchers}
errorItems={errorWorkerVouchers}
tableTitle={formatMessageWithValues('workerVoucher.searcherResultsTitle', { workerVouchersTotalCount })}
headers={headers}
itemFormatters={itemFormatters}
sorts={sorts}
rowsPerPageOptions={ROWS_PER_PAGE_OPTIONS}
defaultPageSize={DEFAULT_PAGE_SIZE}
rowIdentifier={rowIdentifier}
onDoubleClick={onDoubleClick}
exportable
exportFetch={downloadWorkerVoucher}
exportFields={exportConfiguration.exportFields}
exportFieldsColumns={exportConfiguration.exportFieldsColumns}
exportFieldLabel={formatMessage('export.vouchers')}
chooseExportableColumns
/>
{failedExport && (
<Dialog open={failedExport} fullWidth maxWidth="sm">
<DialogTitle>{errorWorkerVouchers?.message}</DialogTitle>
<DialogContent>
<strong>{`${errorWorkerVouchers?.code}:`}</strong>
{errorWorkerVouchers?.detail}
</DialogContent>
<DialogActions>
<Button onClick={handleExportErrorDialogClose} color="primary" variant="contained">
{formatMessage('close')}
</Button>
</DialogActions>
</Dialog>
)}
</>
);
}

export default VoucherSearcher;
const mapDispatchToProps = (dispatch) => bindActionCreators(
{
downloadWorkerVoucher,
fetchWorkerVouchers,
clearWorkerVoucherExport,
},
dispatch,
);

export default connect(null, mapDispatchToProps)(VoucherSearcher);
47 changes: 41 additions & 6 deletions src/reducer.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,7 @@ import {
parseData,
} from '@openimis/fe-core';
import {
CLEAR,
ERROR, REQUEST, SUCCESS,
CLEAR, ERROR, REQUEST, SUCCESS,
} from './utils/action-type';

export const ACTION_TYPE = {
Expand All @@ -25,6 +24,7 @@ export const ACTION_TYPE = {
SEARCH_VOUCHER_PRICES: 'WORKER_VOUCHER_VOUCHER_PRICES',
MANAGE_VOUCHER_PRICE: 'WORKER_VOUCHER_MANAGE_VOUCHER_PRICE',
DELETE_VOUCHER_PRICE: 'WORKER_VOUCHER_DELETE_VOUCHER_PRICE',
EXPORT_WORKER_VOUCHER: 'WORKER_VOUCHER_VOUCHER_EXPORT',
};

const STORE_STATE = {
Expand All @@ -46,12 +46,14 @@ const STORE_STATE = {
voucherPrices: [],
voucherPricesPageInfo: {},
voucherPricesTotalCount: 0,
fetchingWorkerVoucherExport: false,
fetchedWorkerVoucherExport: false,
workerVoucherExport: null,
workerVoucherExportPageInfo: {},
errorWorkerVoucherExport: null,
};

function reducer(
state = STORE_STATE,
action,
) {
function reducer(state = STORE_STATE, action) {
switch (action.type) {
case REQUEST(ACTION_TYPE.SEARCH_WORKER_VOUCHERS):
return {
Expand Down Expand Up @@ -151,6 +153,39 @@ function reducer(
voucherPricesPageInfo: {},
voucherPricesTotalCount: 0,
};
case REQUEST(ACTION_TYPE.EXPORT_WORKER_VOUCHER):
return {
...state,
fetchingWorkerVoucherExport: true,
fetchedWorkerVoucherExport: false,
workerVoucherExport: null,
workerVoucherExportPageInfo: {},
errorWorkerVoucherExport: null,
};
case SUCCESS(ACTION_TYPE.EXPORT_WORKER_VOUCHER):
return {
...state,
fetchingWorkerVoucherExport: false,
fetchedWorkerVoucherExport: true,
workerVoucherExport: action.payload.data.workerVoucherExport,
workerVoucherExportPageInfo: pageInfo(action.payload.data.workerVoucherExportPageInfo),
errorWorkerVoucherExport: formatGraphQLError(action.payload),
};
case ERROR(ACTION_TYPE.EXPORT_WORKER_VOUCHER):
return {
...state,
fetchingWorkerVoucherExport: false,
errorWorkerVoucherExport: formatServerError(action.payload),
};
case CLEAR(ACTION_TYPE.EXPORT_WORKER_VOUCHER):
return {
...state,
fetchingWorkerVoucherExport: false,
fetchedWorkerVoucherExport: false,
workerVoucherExport: null,
workerVoucherExportPageInfo: {},
errorWorkerVoucherExport: null,
};
case REQUEST(ACTION_TYPE.MUTATION):
return dispatchMutationReq(state, action);
case ERROR(ACTION_TYPE.MUTATION):
Expand Down
2 changes: 2 additions & 0 deletions src/translations/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
"workerVoucher.searcherResultsTitle": "{workerVouchersTotalCount} Vouchers Found",
"workerVoucher.code": "Code",
"workerVoucher.employer": "Employer",
"workerVoucher.export.filename": "worker_voucher_export",
"workerVoucher.export.vouchers": "DOWNLOAD VOUCHERS",
"workerVoucher.employer.tradename": "Employer Trade Name",
"workerVoucher.employer.code": "Employer Code",
"workerVoucher.worker": "Worker",
Expand Down
Loading