diff --git a/src/actions.js b/src/actions.js
index 8b8162f..7bf2e62 100644
--- a/src/actions.js
+++ b/src/actions.js
@@ -11,7 +11,7 @@ import { ACTION_TYPE } from './reducer';
import {
CLEAR, ERROR, REQUEST, SUCCESS,
} from './utils/action-type';
-import { EMPTY_STRING } from './constants';
+import { DRAFT_FORM_TYPE, EMPTY_STRING } from './constants';
const WORKER_VOUCHER_PROJECTION = (modulesManager) => [
'id',
@@ -56,12 +56,16 @@ export const GROUP_PROJECTION = (modulesManager, withWorkers = true) => [
`policyholder ${modulesManager.getProjection('policyHolder.PolicyHolderPicker.projection')}`,
`groupWorkers {
totalCount
- ${withWorkers ? `edges {
+ ${
+ withWorkers
+ ? `edges {
node {
isDeleted,
insuree ${modulesManager.getProjection('insuree.InsureePicker.projection')},
}
- }` : ''}
+ }`
+ : ''
+}
}`,
];
@@ -336,9 +340,7 @@ export async function fetchAllPages(dispatch, query, variables, categories) {
while (hasNextPage) {
try {
// eslint-disable-next-line no-await-in-loop
- const response = await dispatch(
- graphqlWithVariables(query, { ...variables, after }),
- );
+ const response = await dispatch(graphqlWithVariables(query, { ...variables, after }));
const data = response?.payload?.data || {};
const pageInfos = categories.map((category) => processCategoryData(category, data, allData));
@@ -414,12 +416,11 @@ export async function fetchAllAvailableWorkers(dispatch, economicUnitCode, dateR
}
}
`;
- const response = await fetchAllPages(
- dispatch,
- query,
- { economicUnitCode, dateRange },
- ['allAvailableWorkers', 'previousWorkers', 'previousDayWorkers'],
- );
+ const response = await fetchAllPages(dispatch, query, { economicUnitCode, dateRange }, [
+ 'allAvailableWorkers',
+ 'previousWorkers',
+ 'previousDayWorkers',
+ ]);
return response;
}
@@ -679,3 +680,77 @@ export function fetchPublicVoucherDetails(voucherUuid) {
{ voucherUuid },
);
}
+
+export function fetchVoucherDraftForm(modulesManager, economicUnitCode) {
+ return graphqlWithVariables(
+ `
+ query getCurrentDraft($economicUnitCode: String) {
+ voucherFormDraft(policyholder_Code: $economicUnitCode) {
+ edges {
+ node {
+ policyholder ${modulesManager.getProjection('policyHolder.PolicyHolderPicker.projection')}
+ workers ${modulesManager.getProjection('insuree.InsureePicker.projection')}
+ dateRanges { startDate endDate }
+ }
+ }
+ }
+ }
+ `,
+ { economicUnitCode },
+ );
+}
+
+export function createOrUpdateVoucherDraftForm(
+ voucherAssignment,
+ clientMutationLabel,
+ typeOfForm = DRAFT_FORM_TYPE.ASSIGNMENT,
+) {
+ const { employer, workers, dateRanges } = voucherAssignment;
+ const workerIds = workers ? workers.map((worker) => decodeId(worker.id)).join(', ') : EMPTY_STRING;
+
+ const mutationInput = `
+ typeOfForm: "${typeOfForm}"
+ economicUnitCode: "${employer.code}"
+ workers: [${workerIds}]
+ ${dateRanges ? `dateRanges: ${formatGraphQLDateRanges(dateRanges)}` : 'dateRanges: []'}
+ `;
+
+ const mutation = formatMutation('createOrUpdateVoucherDraftForm', mutationInput, clientMutationLabel);
+ const requestedDateTime = new Date();
+
+ return graphql(
+ mutation.payload,
+ [
+ REQUEST(ACTION_TYPE.MUTATION),
+ SUCCESS(ACTION_TYPE.CREATE_OR_UPDATE_ASSIGNMENT_DRAFT),
+ ERROR(ACTION_TYPE.MUTATION),
+ ],
+ {
+ actionType: ACTION_TYPE.CREATE_OR_UPDATE_ASSIGNMENT_DRAFT,
+ clientMutationId: mutation.clientMutationId,
+ clientMutationLabel,
+ requestedDateTime,
+ },
+ );
+}
+
+export function deleteVoucherDraftForm(economicUnit, clientMutationLabel, typeOfForm = DRAFT_FORM_TYPE.ASSIGNMENT) {
+ const mutationInput = `
+ ${`economicUnitCode: "${economicUnit.code}"`}
+ ${`typeOfForm: "${typeOfForm}"`}
+ `;
+
+ const mutation = formatMutation('deleteVoucherDraftForm', mutationInput, clientMutationLabel);
+ const requestedDateTime = new Date();
+
+ return graphql(
+ mutation.payload,
+ [REQUEST(ACTION_TYPE.MUTATION), SUCCESS(ACTION_TYPE.DELETE_ASSIGNMENT_DRAFT), ERROR(ACTION_TYPE.MUTATION)],
+ {
+ actionType: ACTION_TYPE.DELETE_ASSIGNMENT_DRAFT,
+ clientMutationId: mutation.clientMutationId,
+ clientMutationLabel,
+ requestedDateTime,
+ },
+ );
+}
diff --git a/src/components/VoucherAcquirementGenericVoucher.js b/src/components/VoucherAcquirementGenericVoucher.js
index 3f374a0..1c3c35a 100644
--- a/src/components/VoucherAcquirementGenericVoucher.js
+++ b/src/components/VoucherAcquirementGenericVoucher.js
@@ -100,7 +100,7 @@ function VoucherAcquirementGenericVoucher() {
historyPush(modulesManager, history, REF_ROUTE_BILL, [billId]);
dispatch(
coreAlert(
- formatMessage('menu.voucherAcquirementSuccess'),
+ formatMessage('menu.voucherAcquirement'),
formatMessageWithValues('workerVoucher.VoucherAcquirementForm.genericVoucherConfirmation', {
quantity: voucherAcquirement?.quantity,
}),
diff --git a/src/components/VoucherAcquirementSpecificWorker.js b/src/components/VoucherAcquirementSpecificWorker.js
index 00ac740..1a06ac6 100644
--- a/src/components/VoucherAcquirementSpecificWorker.js
+++ b/src/components/VoucherAcquirementSpecificWorker.js
@@ -110,7 +110,7 @@ function VoucherAcquirementSpecificWorker() {
historyPush(modulesManager, history, REF_ROUTE_BILL, [billId]);
dispatch(
coreAlert(
- formatMessage('menu.voucherAcquirementSuccess'),
+ formatMessage('menu.voucherAcquirement'),
formatMessage('workerVoucher.VoucherAcquirementForm.specificVoucherConfirmation'),
),
);
diff --git a/src/components/VoucherAssignmentForm.js b/src/components/VoucherAssignmentForm.js
index e169960..7beb520 100644
--- a/src/components/VoucherAssignmentForm.js
+++ b/src/components/VoucherAssignmentForm.js
@@ -1,25 +1,29 @@
-import React, { useState, useEffect, useRef } from 'react';
+import React, { useEffect, useState, useRef } from 'react';
import { useDispatch, useSelector } from 'react-redux';
+import _ from 'lodash';
import {
- Divider, Grid, Paper, Typography, Button, Tooltip,
+ Button, Divider, Grid, Paper, Tooltip, Typography,
} from '@material-ui/core';
-import { makeStyles } from '@material-ui/styles';
import AssignmentIndIcon from '@material-ui/icons/AssignmentInd';
+import { makeStyles } from '@material-ui/styles';
import {
+ InfoButton,
coreAlert,
- useModulesManager,
- useTranslations,
- journalize,
historyPush,
useHistory,
- InfoButton,
+ useModulesManager,
+ useTranslations,
+ parseData,
} from '@openimis/fe-core';
-import { assignVouchers, voucherAssignmentValidation } from '../actions';
-import { MODULE_NAME, REF_ROUTE_WORKER_VOUCHERS, USER_ECONOMIC_UNIT_STORAGE_KEY } from '../constants';
+import {
+ assignVouchers, deleteVoucherDraftForm, fetchVoucherDraftForm, voucherAssignmentValidation,
+} from '../actions';
+import { MODULE_NAME, REF_ROUTE_WORKER_VOUCHERS } from '../constants';
import AssignmentVoucherForm from './AssignmentVoucherForm';
import VoucherAssignmentConfirmModal from './VoucherAssignmentConfirmModal';
+import VoucherAssignmentProgressTracker from './VoucherAssignmentProgressTracker';
export const useStyles = makeStyles((theme) => ({
paper: { ...theme.paper.paper, margin: '10px 0 0 0' },
@@ -46,7 +50,6 @@ export const useStyles = makeStyles((theme) => ({
}));
function VoucherAssignmentForm() {
- const prevSubmittingMutationRef = useRef();
const modulesManager = useModulesManager();
const dispatch = useDispatch();
const classes = useStyles();
@@ -57,8 +60,8 @@ function VoucherAssignmentForm() {
const [assignmentSummaryLoading, setAssignmentSummaryLoading] = useState(false);
const [isAssignmentLoading, setIsAssignmentLoading] = useState(false);
const [isConfirmationModalOpen, setIsConfirmationModalOpen] = useState(false);
- const { mutation, submittingMutation } = useSelector((state) => state.workerVoucher);
const { economicUnit } = useSelector((state) => state.policyHolder);
+ const prevEconomicUnitRef = useRef();
const assignmentBlocked = (voucherAssignment) => !voucherAssignment?.workers?.length
|| !voucherAssignment?.dateRanges?.length;
@@ -93,6 +96,7 @@ function VoucherAssignmentForm() {
'Assign Vouchers',
),
);
+ await dispatch(deleteVoucherDraftForm(economicUnit, 'Delete Voucher Draft'));
historyPush(modulesManager, history, REF_ROUTE_WORKER_VOUCHERS);
dispatch(
coreAlert(
@@ -109,26 +113,38 @@ function VoucherAssignmentForm() {
setIsConfirmationModalOpen((prevState) => !prevState);
};
- useEffect(() => {
- if (prevSubmittingMutationRef.current && !submittingMutation) {
- dispatch(journalize(mutation));
+ useEffect(async () => {
+ if (_.isEqual(economicUnit, prevEconomicUnitRef.current)) {
+ return;
}
- }, [submittingMutation]);
-
- useEffect(() => {
- prevSubmittingMutationRef.current = submittingMutation;
- });
-
- useEffect(() => {
- const storedUserEconomicUnit = localStorage.getItem(USER_ECONOMIC_UNIT_STORAGE_KEY);
- if (storedUserEconomicUnit) {
- const userEconomicUnit = JSON.parse(storedUserEconomicUnit);
- setVoucherAssignment((prevState) => ({
- ...prevState,
- employer: userEconomicUnit,
- workers: [],
- dateRanges: [],
+
+ try {
+ const response = await dispatch(fetchVoucherDraftForm(modulesManager, economicUnit.code));
+
+ if (response.error) {
+ // eslint-disable-next-line no-console
+ console.error(`[ERROR]: Error while fetching voucher draft form. ${response.error}`);
+ }
+
+ const voucherFormDraft = parseData(response.payload.data.voucherFormDraft)?.[0];
+
+ if (!voucherFormDraft) {
+ setVoucherAssignment(() => ({
+ employer: economicUnit,
+ workers: [],
+ dateRanges: [],
+ }));
+ return;
+ }
+
+ setVoucherAssignment(() => ({
+ employer: voucherFormDraft.policyholder,
+ workers: voucherFormDraft.workers,
+ dateRanges: voucherFormDraft.dateRanges,
}));
+ } catch (error) {
+ // eslint-disable-next-line no-console
+ console.error(`[ERROR]: Error during assignment init. ${error}`);
}
}, [setVoucherAssignment, economicUnit]);
@@ -168,6 +184,8 @@ function VoucherAssignmentForm() {
+
+
({
+ container: {
+ display: 'flex',
+ alignItems: 'center',
+ justifyContent: 'start',
+ gap: '4px',
+ padding: theme.spacing(1),
+ },
+}));
+
+function VoucherAssignmentProgressTracker({ voucherAssignment }) {
+ const prevVoucherAssignment = useRef();
+ const dispatch = useDispatch();
+ const classes = useStyles();
+ const { showError } = useToast();
+ const { formatMessage } = useTranslations(MODULE_NAME);
+ const [isSaving, setIsSaving] = useState(false);
+
+ const saveAssignmentDraft = useCallback(
+ _debounce(async (voucherAssignment) => {
+ try {
+ await dispatch(createOrUpdateVoucherDraftForm(voucherAssignment, 'Save Assignment Draft'));
+ } catch (error) {
+ showError('[ERROR]: Error while saving the progress.');
+ // eslint-disable-next-line no-console
+ console.error(error);
+ } finally {
+ setIsSaving(false);
+ }
+ }, DEFAULT_DEBOUNCE_TIME * 2),
+ [dispatch, showError],
+ );
+
+ useEffect(() => {
+ if (
+ !_.isEqual(voucherAssignment, prevVoucherAssignment.current)
+ && !_.isEmpty(voucherAssignment)
+ ) {
+ setIsSaving(true);
+ prevVoucherAssignment.current = voucherAssignment;
+ saveAssignmentDraft(voucherAssignment);
+ }
+ }, [voucherAssignment, saveAssignmentDraft]);
+
+ return (
+
+ {isSaving ? (
+ <>
+
+ {formatMessage('VoucherAssignmentProgressTracker.saving')}
+ >
+ ) : (
+ <>
+
+ {formatMessage('VoucherAssignmentProgressTracker.upToDate')}
+ >
+ )}
+
+ );
+}
+
+export default VoucherAssignmentProgressTracker;
diff --git a/src/constants.js b/src/constants.js
index 73b275a..ded1284 100644
--- a/src/constants.js
+++ b/src/constants.js
@@ -112,3 +112,7 @@ export const UPLOAD_STAGE = {
FILE_UPLOAD: 'FILE_UPLOAD',
WORKER_UPLOAD: 'WORKER_UPLOAD',
};
+
+export const DRAFT_FORM_TYPE = {
+ ASSIGNMENT: 'ASSIGNMENT',
+};
diff --git a/src/pickers/WorkerMultiplePicker.js b/src/pickers/WorkerMultiplePicker.js
index bc49422..2809c39 100644
--- a/src/pickers/WorkerMultiplePicker.js
+++ b/src/pickers/WorkerMultiplePicker.js
@@ -136,6 +136,7 @@ function WorkerMultiplePicker({
flexDirection: 'column',
gap: '8px',
alignItems: 'end',
+ marginTop: '8px',
}}
>