From b9c59ed39901750910295c3a8aa293a57777370d Mon Sep 17 00:00:00 2001 From: Jan Date: Mon, 27 May 2024 13:47:14 +0200 Subject: [PATCH] CM-810: add GroupImportTasks --- src/components/tasks/GroupImportTasks.js | 453 +++++++++++++++++++++++ 1 file changed, 453 insertions(+) create mode 100644 src/components/tasks/GroupImportTasks.js diff --git a/src/components/tasks/GroupImportTasks.js b/src/components/tasks/GroupImportTasks.js new file mode 100644 index 0000000..531f484 --- /dev/null +++ b/src/components/tasks/GroupImportTasks.js @@ -0,0 +1,453 @@ +/* eslint-disable no-use-before-define */ + +import React, { useState, useEffect } from 'react'; +import { + Paper, Fab, makeStyles, Checkbox, Divider, +} from '@material-ui/core'; +import { useDispatch, useSelector } from 'react-redux'; +import { + Table, + SelectDialog, + decodeId, + formatMessage, + formatMessageWithValues, +} from '@openimis/fe-core'; +import ClearIcon from '@material-ui/icons/Clear'; +import CheckIcon from '@material-ui/icons/Check'; + +import { useIntl } from 'react-intl'; +import { TASK_STATUS, APPROVED, FAILED } from '../../constants'; +import { fetchPendingGroupUploads, resolveTask } from '../../actions'; + +const useStyles = makeStyles((theme) => ({ + paper: theme.paper.paper, + title: theme.paper.title, + button: theme.paper.button, + fabContainer: { + display: 'flex', + justifyContent: 'center', + }, + fabHeaderContainer: { + justifyContent: 'center', + textAlign: 'center', + fontSize: '16px', + fontWeight: 'bold', + }, + fab: { + margin: theme.spacing(1), + }, + +})); + +function GroupUploadTaskDisplay({ + businessData, setAdditionalData, jsonExt, +}) { + const { + errorPendingGroups, + pendingGroups, + fetchedPendingGroups, + fetchingPendingGroups, + pendingGroupsPageInfo, + } = useSelector((state) => state.individual); + const intl = useIntl(); + const [pending, setPending] = useState([]); + const [keys, setKeys] = useState([]); + const [state, setState] = useState({ + page: 0, + pageSize: 10, + afterCursor: null, + beforeCursor: null, + }); + + const { task } = useSelector((state) => state.tasksManagement); + const currentUser = useSelector((state) => state.core.user); + + const isTaskResolved = () => ![TASK_STATUS.RECEIVED, TASK_STATUS.ACCEPTED].includes(task?.status); + const dispatch = useDispatch(); + const queryPrms = () => ({ + upload_Id: jsonExt?.data_upload_id, + isDeleted: isTaskResolved() ? undefined : false, + }); + + const [selectedRecords, setSelectedRecords] = useState([]); + const query = () => { + const prms = queryPrms(); + if (!state.pageSize || !prms) return; + prms.pageSize = state.pageSize; + if (state.afterCursor) { + prms.after = state.afterCursor; + } + if (state.beforeCursor) { + prms.before = state.beforeCursor; + } + + dispatch(fetchPendingGroupUploads(prms)); + }; + + const currentPage = () => state.page; + const currentPageSize = () => state.pageSize; + + useEffect(() => { + query(); + }, []); + + useEffect(() => { + query(); + }, [state]); + + const organizeData = (data) => { + const uniqueKeys = ['code']; + + data.forEach((i) => Object.keys(i).forEach((k) => { + if (!uniqueKeys.includes(k)) { + uniqueKeys.push(k); + } + })); + + // Remove internal identifiers + // Unnamed 0 is ordinal often found in the uploaded CSVs, it shoun't appear in new + // version but is added for backward compatibility s + return uniqueKeys.filter((k) => !['uuid', 'ID', 'Unnamed: 0'].includes(k)); + }; + + const [storedGroups, setStoredGroups] = useState({}); + + useEffect(() => { + setPending( + pendingGroups.map((x) => (x.jsonExt ? { ...JSON.parse(x.jsonExt), uuid: x.uuid } + : { uuid: x.uuid })), + ); + const withGroups = {}; + pendingGroups.forEach((x) => { + withGroups[x.id] = x.group?.id; + }); + setStoredGroups(withGroups); + }, [pendingGroups]); + + useEffect(() => setKeys(organizeData(pending)), [pending]); + + const classes = useStyles(); + + const headers = () => [ + task?.status === TASK_STATUS.ACCEPTED + ? formatMessage(intl, 'socialProtection', 'selectForEvaluation') + : formatMessage(intl, 'socialProtection', 'evaluated'), + ...keys] || []; + + const changeCheckboxState = (pending) => { + setSelectedRecords(selectedRecords.includes(pending.uuid) + ? selectedRecords.filter((x) => x !== pending.uuid) : [...selectedRecords, pending.uuid]); + }; + + const itemFormatters = () => { + const items = [ + (pending) => ( + // eslint-disable-next-line react/jsx-no-useless-fragment + <> + {!isTaskResolved() ? ( + changeCheckboxState(pending)} + disabled={isRowDisabled()} + /> + ) : ( + {}} + disabled + /> + )} + + + ), + ]; + + keys.forEach((key) => { + items.push((pending) => { + if (Object.prototype.hasOwnProperty.call(pending, key)) { + const value = pending[key]; + // Check if the value is an array and join it into a comma-separated string + return Array.isArray(value) ? value.join(', ') : value; + } + return '-'; + }); + }); + return items; + }; + + const onChangeRowsPerPage = (rows) => { + setState({ + ...state, + pageSize: rows, + }); + }; + + const onChangeSelection = (rows) => { + setSelectedRecords(rows.map((row) => row.uuid)); + }; + + const onChangePage = (page, nbr) => { + const next = nbr > state.page; + + setState( + { + page: next ? state.page + 1 : state.page - 1, + pageSize: state.pageSize, + afterCursor: next ? pendingGroupsPageInfo.endCursor : null, + beforeCursor: !next ? pendingGroupsPageInfo.startCursor : null, + }, + ); + }; + + const isCurrentUserInTaskGroup = () => { + const taskExecutors = task?.taskGroup?.taskexecutorSet?.edges.map((edge) => decodeId(edge.node.user.id)) ?? []; + return taskExecutors && taskExecutors.includes(currentUser?.id); + }; + + const isRowDisabled = () => !isCurrentUserInTaskGroup() || task?.status !== TASK_STATUS.ACCEPTED; + + const [approveOrFail, setApproveOrFail] = useState(''); + const [confirmed, setConfirmed] = useState(null); + const [openModal, setOpenModal] = useState(null); + const [disabled, setDisable] = useState(false); + + const clear = () => { + setOpenModal(null); + setApproveOrFail(''); + setConfirmed(''); + }; + + useEffect(() => { + if (task?.id && currentUser?.id) { + if (confirmed) { + setDisable(true); + dispatch(resolveTask( + task, + formatMessage(intl, 'tasksManagement', 'task.resolve.mutationLabel'), + currentUser, + approveOrFail, + selectedRecords, + )); + } + } + return () => confirmed && clear(false); + }, [confirmed]); + + const onConfirm = () => { + setOpenModal(false); + setConfirmed(true); + }; + + const onClose = () => { + setOpenModal(false); + setConfirmed(false); + }; + + const handleButtonClick = (choiceString) => { + if (task?.id && currentUser?.id) { + setApproveOrFail(choiceString); + setOpenModal(true); + } + }; + + return ( + <> + + + + {isCurrentUserInTaskGroup() + && ( + <> + {' '} + +
+ {formatMessage(intl, 'socialProtection', 'resolveSelectedTasks')} + +
+
+
+ handleButtonClick('ACCEPT')} + > + + + {formatMessage(intl, 'socialProtection', 'acceptSelected')} +
+
+ handleButtonClick('REJECT')} + > + + + {formatMessage(intl, 'socialProtection', 'rejectSelected')} +
+
+
+ + )} + + ); +} + +const GroupUploadResolutionTaskTableHeaders = () => []; + +const GroupUploadResolutionItemFormatters = () => [ + (businessData, jsonExt, formatterIndex, setAdditionalData) => ( + + ), +]; + +function GroupUploadConfirmationPanel({ defaultAction, defaultDisabled }) { + const intl = useIntl(); + const classes = useStyles(); + const { task } = useSelector((state) => state.tasksManagement); + const currentUser = useSelector((state) => state.core.user); + const [disabled, setDisable] = useState(defaultDisabled); + + const [openModal, setOpenModal] = useState(null); + const [approveOrFail, setApproveOrFail] = useState(''); + const [confirmed, setConfirmed] = useState(''); + + const onConfirm = () => { + setOpenModal(false); + setConfirmed(true); + }; + + const onClose = () => { + setOpenModal(false); + setConfirmed(false); + }; + + const isCurrentUserInTaskGroup = () => { + const taskExecutors = task?.taskGroup?.taskexecutorSet?.edges.map((edge) => decodeId(edge.node.user.id)) ?? []; + return taskExecutors && taskExecutors.includes(currentUser?.id); + }; + + const isRowDisabled = () => !isCurrentUserInTaskGroup() || task?.status !== TASK_STATUS.ACCEPTED; + + const clear = () => { + setOpenModal(null); + setApproveOrFail(''); + setConfirmed(''); + }; + + const handleButtonClick = (choiceString) => { + // () => defaultAction(APPROVED) + if (task?.id && currentUser?.id) { + setApproveOrFail(choiceString); + setOpenModal(true); + } + }; + + const dispatch = useDispatch(); + + useEffect(() => { + if (task?.id && currentUser?.id) { + if (confirmed) { + setDisable(true); + dispatch(resolveTask( + task, + formatMessage(intl, 'tasksManagement', 'task.resolve.mutationLabel'), + currentUser, + approveOrFail, + + )); + } + } + return () => confirmed && clear(); + }, [confirmed]); + + return ( + <> + + +
+ {formatMessage(intl, 'socialProtection', 'resolveAllRemainingTasks')} + +
+
+
+ handleButtonClick(APPROVED)} + > + + + {formatMessage(intl, 'socialProtection', 'approveAll')} + +
+
+ handleButtonClick(FAILED)} + > + + + {formatMessage(intl, 'socialProtection', 'rejectAll')} +
+
+
+ + ); +} + +export { GroupUploadResolutionTaskTableHeaders, GroupUploadResolutionItemFormatters, GroupUploadConfirmationPanel };