| @@ -4,6 +4,7 @@ import { | |||||
| Typography, | Typography, | ||||
| Stack, | Stack, | ||||
| Button, | Button, | ||||
| CircularProgress, | |||||
| Dialog, DialogTitle, DialogContent, DialogActions, | Dialog, DialogTitle, DialogContent, DialogActions, | ||||
| } from '@mui/material'; | } from '@mui/material'; | ||||
| import MainCard from "components/MainCard"; | import MainCard from "components/MainCard"; | ||||
| @@ -55,6 +56,8 @@ const Index = () => { | |||||
| const [isPreviewLoading, setIsPreviewLoading] = React.useState(false); | const [isPreviewLoading, setIsPreviewLoading] = React.useState(false); | ||||
| const [isPopUp, setIsPopUp] = React.useState(false); | const [isPopUp, setIsPopUp] = React.useState(false); | ||||
| const [isXmlDialogSubmitting, setIsXmlDialogSubmitting] = React.useState(false); | |||||
| const xmlDownloadInFlightRef = React.useRef(false); | |||||
| const [downloadInput, setDownloadInput] = React.useState(); | const [downloadInput, setDownloadInput] = React.useState(); | ||||
| const [selectedIds, setSelectedIds] = React.useState([]); | const [selectedIds, setSelectedIds] = React.useState([]); | ||||
| @@ -66,6 +69,13 @@ const Index = () => { | |||||
| setInputDateValue(inputDate); | setInputDateValue(inputDate); | ||||
| }, [inputDate]); | }, [inputDate]); | ||||
| React.useEffect(() => { | |||||
| if (!isPopUp) { | |||||
| xmlDownloadInFlightRef.current = false; | |||||
| setIsXmlDialogSubmitting(false); | |||||
| } | |||||
| }, [isPopUp]); | |||||
| React.useEffect(() => { | React.useEffect(() => { | ||||
| setOnReady(true); | setOnReady(true); | ||||
| }, [searchCriteria]); | }, [searchCriteria]); | ||||
| @@ -94,66 +104,61 @@ const Index = () => { | |||||
| function downloadXML() { | function downloadXML() { | ||||
| console.log(selectedIds.join(',')) | |||||
| setIsPopUp(false) | |||||
| if (xmlDownloadInFlightRef.current) return; | |||||
| xmlDownloadInFlightRef.current = true; | |||||
| console.log(selectedIds.join(',')); | |||||
| setIsXmlDialogSubmitting(true); | |||||
| let sentDateFrom = ""; | let sentDateFrom = ""; | ||||
| if (inputDateValue != "dd / mm / yyyy") { | if (inputDateValue != "dd / mm / yyyy") { | ||||
| sentDateFrom = DateUtils.dateValue(inputDateValue) | |||||
| sentDateFrom = DateUtils.dateValue(inputDateValue); | |||||
| } | } | ||||
| HttpUtils.get({ | HttpUtils.get({ | ||||
| url: GEN_GFMIS_XML + "/today", | url: GEN_GFMIS_XML + "/today", | ||||
| params:{ | |||||
| params: { | |||||
| dateTo: downloadInput.dateTo, | dateTo: downloadInput.dateTo, | ||||
| dateFrom: downloadInput.dateFrom, | dateFrom: downloadInput.dateFrom, | ||||
| inputDate: sentDateFrom, | inputDate: sentDateFrom, | ||||
| paymentId: selectedIds.join(',') | paymentId: selectedIds.join(',') | ||||
| }, | }, | ||||
| onSuccess: (responseData) => { | onSuccess: (responseData) => { | ||||
| // console.log(responseData) | |||||
| const parser = new DOMParser(); | const parser = new DOMParser(); | ||||
| const xmlDoc = parser.parseFromString(responseData, 'application/xml'); | const xmlDoc = parser.parseFromString(responseData, 'application/xml'); | ||||
| // Get the DCBHeader element | |||||
| const dcbHeader = xmlDoc.querySelector("DCBHeader"); | const dcbHeader = xmlDoc.querySelector("DCBHeader"); | ||||
| // Get the Receipt and Allocation elements | |||||
| const receiptElement = dcbHeader.querySelector("Receipt"); | const receiptElement = dcbHeader.querySelector("Receipt"); | ||||
| const allocationElement = dcbHeader.querySelector("Allocation"); | const allocationElement = dcbHeader.querySelector("Allocation"); | ||||
| const paymentMethodElements = Array.from(dcbHeader.querySelectorAll("PaymentMethod")); | const paymentMethodElements = Array.from(dcbHeader.querySelectorAll("PaymentMethod")); | ||||
| // Remove existing elements from DCBHeader | |||||
| dcbHeader.innerHTML = ""; | dcbHeader.innerHTML = ""; | ||||
| dcbHeader.appendChild(receiptElement); | dcbHeader.appendChild(receiptElement); | ||||
| dcbHeader.appendChild(allocationElement); | dcbHeader.appendChild(allocationElement); | ||||
| if (paymentMethodElements) { | if (paymentMethodElements) { | ||||
| paymentMethodElements.forEach((paymentMethodElement) => { | paymentMethodElements.forEach((paymentMethodElement) => { | ||||
| dcbHeader.appendChild(paymentMethodElement); | |||||
| }); | |||||
| dcbHeader.appendChild(paymentMethodElement); | |||||
| }); | |||||
| } | } | ||||
| const updatedXmlString = new XMLSerializer().serializeToString(xmlDoc); | const updatedXmlString = new XMLSerializer().serializeToString(xmlDoc); | ||||
| const filename = xmlDoc.querySelector('FileHeader').getAttribute('H_Filename'); | const filename = xmlDoc.querySelector('FileHeader').getAttribute('H_Filename'); | ||||
| // console.log(updatedXmlString) | |||||
| const blob = new Blob([updatedXmlString], { type: 'application/xml' }); | const blob = new Blob([updatedXmlString], { type: 'application/xml' }); | ||||
| // Create a download link | |||||
| const link = document.createElement('a'); | const link = document.createElement('a'); | ||||
| link.href = URL.createObjectURL(blob); | link.href = URL.createObjectURL(blob); | ||||
| link.download = filename+'.xml'; | |||||
| // Append the link to the document body | |||||
| link.download = filename + '.xml'; | |||||
| document.body.appendChild(link); | document.body.appendChild(link); | ||||
| // Programmatically click the link to trigger the download | |||||
| link.click(); | link.click(); | ||||
| // Clean up the link | |||||
| document.body.removeChild(link); | document.body.removeChild(link); | ||||
| setIsPopUp(false); | |||||
| }, | |||||
| onFinally: () => { | |||||
| xmlDownloadInFlightRef.current = false; | |||||
| setIsXmlDialogSubmitting(false); | |||||
| } | } | ||||
| }); | |||||
| // open(UrlUtils.GEN_GFMIS_XML + "/today?online=true") | |||||
| } | |||||
| }); | |||||
| } | |||||
| function applySearch(input) { | function applySearch(input) { | ||||
| @@ -263,7 +268,11 @@ const Index = () => { | |||||
| </Grid> | </Grid> | ||||
| <Dialog | <Dialog | ||||
| open={isPopUp} | open={isPopUp} | ||||
| onClose={() => setIsPopUp(false)} | |||||
| onClose={() => { | |||||
| if (isXmlDialogSubmitting) return; | |||||
| setIsPopUp(false); | |||||
| }} | |||||
| disableEscapeKeyDown={isXmlDialogSubmitting} | |||||
| PaperProps={{ | PaperProps={{ | ||||
| sx: { | sx: { | ||||
| minWidth: '40vw', | minWidth: '40vw', | ||||
| @@ -300,8 +309,22 @@ const Index = () => { | |||||
| </LocalizationProvider> | </LocalizationProvider> | ||||
| </DialogContent> | </DialogContent> | ||||
| <DialogActions> | <DialogActions> | ||||
| <Button onClick={() => setIsPopUp(false)}><Typography variant="h5">Cancel</Typography></Button> | |||||
| <Button onClick={() => downloadXML()}><Typography variant="h5">Confirm</Typography></Button> | |||||
| <Button | |||||
| onClick={() => { | |||||
| if (isXmlDialogSubmitting) return; | |||||
| setIsPopUp(false); | |||||
| }} | |||||
| disabled={isXmlDialogSubmitting} | |||||
| > | |||||
| <Typography variant="h5">Cancel</Typography> | |||||
| </Button> | |||||
| <Button | |||||
| onClick={() => downloadXML()} | |||||
| disabled={isXmlDialogSubmitting} | |||||
| startIcon={isXmlDialogSubmitting ? <CircularProgress color="inherit" size={20} /> : null} | |||||
| > | |||||
| <Typography variant="h5">Confirm</Typography> | |||||
| </Button> | |||||
| </DialogActions> | </DialogActions> | ||||
| </Dialog> | </Dialog> | ||||
| </Grid> | </Grid> | ||||
| @@ -8,12 +8,13 @@ import { | |||||
| Button, | Button, | ||||
| Stack, | Stack, | ||||
| Dialog, DialogTitle, DialogContent, DialogActions, | Dialog, DialogTitle, DialogContent, DialogActions, | ||||
| CircularProgress, | |||||
| } from '@mui/material'; | } from '@mui/material'; | ||||
| import { useFormik } from 'formik'; | import { useFormik } from 'formik'; | ||||
| import { useIntl } from 'react-intl'; | import { useIntl } from 'react-intl'; | ||||
| import {isGranted} from "auth/utils"; | import {isGranted} from "auth/utils"; | ||||
| import {useState,useEffect,lazy} from "react"; | |||||
| import {useState, useEffect, useRef, lazy} from "react"; | |||||
| import * as HttpUtils from "utils/HttpUtils" | import * as HttpUtils from "utils/HttpUtils" | ||||
| import * as UrlUtils from "utils/ApiPathConst" | import * as UrlUtils from "utils/ApiPathConst" | ||||
| import * as DateUtils from "utils/DateUtils" | import * as DateUtils from "utils/DateUtils" | ||||
| @@ -36,6 +37,8 @@ const ApplicationDetailCard = ({ | |||||
| const [data, setData] = useState({}); | const [data, setData] = useState({}); | ||||
| const [cancelPopUp, setCancelPopUp] = useState(false); | const [cancelPopUp, setCancelPopUp] = useState(false); | ||||
| const [cancelLoading, setCancelLoading] = useState(false); | |||||
| const cancellingRef = useRef(false); | |||||
| const [onDownload, setOnDownload] = useState(false); | const [onDownload, setOnDownload] = useState(false); | ||||
| const [alertMsg, setAlertMsg] = useState(''); | const [alertMsg, setAlertMsg] = useState(''); | ||||
| const [showAlert, setShowAlert] = useState(false); | const [showAlert, setShowAlert] = useState(false); | ||||
| @@ -98,17 +101,30 @@ const ApplicationDetailCard = ({ | |||||
| } | } | ||||
| const confirmCancel = () => { | const confirmCancel = () => { | ||||
| setCancelPopUp(false); | |||||
| if (cancellingRef.current) return; | |||||
| cancellingRef.current = true; | |||||
| setCancelLoading(true); | |||||
| HttpUtils.get({ | HttpUtils.get({ | ||||
| url: UrlUtils.CANCEL_PROOF + "/" + params.id, | url: UrlUtils.CANCEL_PROOF + "/" + params.id, | ||||
| onSuccess: function (responseData) { | onSuccess: function (responseData) { | ||||
| cancellingRef.current = false; | |||||
| setCancelLoading(false); | |||||
| if (responseData && responseData.success === false) { | if (responseData && responseData.success === false) { | ||||
| setCancelPopUp(false); | |||||
| const msg = responseData.msg ? intl.formatMessage({ id: responseData.msg }) : intl.formatMessage({ id: 'proofAlreadyCancelled' }); | const msg = responseData.msg ? intl.formatMessage({ id: responseData.msg }) : intl.formatMessage({ id: 'proofAlreadyCancelled' }); | ||||
| setAlertMsg(msg); | setAlertMsg(msg); | ||||
| setShowAlert(true); | setShowAlert(true); | ||||
| } else { | } else { | ||||
| window.location.reload(false); | window.location.reload(false); | ||||
| } | } | ||||
| }, | |||||
| onFail: () => { | |||||
| cancellingRef.current = false; | |||||
| setCancelLoading(false); | |||||
| }, | |||||
| onError: () => { | |||||
| cancellingRef.current = false; | |||||
| setCancelLoading(false); | |||||
| } | } | ||||
| }); | }); | ||||
| } | } | ||||
| @@ -348,15 +364,24 @@ const ApplicationDetailCard = ({ | |||||
| <div> | <div> | ||||
| <Dialog | <Dialog | ||||
| open={cancelPopUp} | open={cancelPopUp} | ||||
| onClose={() => setCancelPopUp(false)} | |||||
| onClose={() => { | |||||
| if (cancelLoading) return; | |||||
| setCancelPopUp(false); | |||||
| }} | |||||
| > | > | ||||
| <DialogTitle><Typography variant="h3">Confirm</Typography></DialogTitle> | <DialogTitle><Typography variant="h3">Confirm</Typography></DialogTitle> | ||||
| <DialogContent style={{ display: 'flex', }}> | <DialogContent style={{ display: 'flex', }}> | ||||
| <Typography variant="h4" style={{ padding: '16px' }}>Are you sure you want to cancel this proof?</Typography> | <Typography variant="h4" style={{ padding: '16px' }}>Are you sure you want to cancel this proof?</Typography> | ||||
| </DialogContent> | </DialogContent> | ||||
| <DialogActions> | <DialogActions> | ||||
| <Button onClick={() => setCancelPopUp(false)}><Typography variant="h5">Cancel</Typography></Button> | |||||
| <Button onClick={() => confirmCancel()}><Typography variant="h5">Confirm</Typography></Button> | |||||
| <Button onClick={() => setCancelPopUp(false)} disabled={cancelLoading}><Typography variant="h5">Cancel</Typography></Button> | |||||
| <Button | |||||
| onClick={() => confirmCancel()} | |||||
| disabled={cancelLoading} | |||||
| startIcon={cancelLoading ? <CircularProgress color="inherit" size={20} /> : null} | |||||
| > | |||||
| <Typography variant="h5">Confirm</Typography> | |||||
| </Button> | |||||
| </DialogActions> | </DialogActions> | ||||
| </Dialog> | </Dialog> | ||||
| <Dialog open={showAlert} onClose={() => setShowAlert(false)}> | <Dialog open={showAlert} onClose={() => setShowAlert(false)}> | ||||
| @@ -9,6 +9,7 @@ import { | |||||
| Stack, | Stack, | ||||
| Dialog, DialogTitle, DialogContent, DialogActions, InputAdornment, Autocomplete | Dialog, DialogTitle, DialogContent, DialogActions, InputAdornment, Autocomplete | ||||
| } from '@mui/material'; | } from '@mui/material'; | ||||
| import LoadingButton from '@mui/lab/LoadingButton'; | |||||
| import { isGranted, delBugMode, getPaymentMethodGLD} from "auth/utils"; | import { isGranted, delBugMode, getPaymentMethodGLD} from "auth/utils"; | ||||
| const MainCard = Loadable(lazy(() => import('components/MainCard'))); | const MainCard = Loadable(lazy(() => import('components/MainCard'))); | ||||
| import { useForm } from "react-hook-form"; | import { useForm } from "react-hook-form"; | ||||
| @@ -37,14 +38,42 @@ import { notifyActionError } from 'utils/CommonFunction'; | |||||
| import { isGrantedAny } from "auth/utils"; | import { isGrantedAny } from "auth/utils"; | ||||
| import { useIntl } from "react-intl"; | import { useIntl } from "react-intl"; | ||||
| /** Contained buttons with custom bg must restyle disabled/loading or they stay green/orange. */ | |||||
| const publishWithdrawLoadingSx = (mainBg, hoverBg) => (theme) => ({ | |||||
| textTransform: 'capitalize', | |||||
| alignItems: 'end', | |||||
| backgroundColor: mainBg, | |||||
| color: '#fff', | |||||
| '&:hover:not(.Mui-disabled):not(.MuiLoadingButton-loading)': { | |||||
| backgroundColor: hoverBg, | |||||
| }, | |||||
| '&.Mui-disabled, &.MuiLoadingButton-loading': { | |||||
| backgroundColor: theme.palette.action.disabledBackground, | |||||
| color: theme.palette.action.disabled, | |||||
| }, | |||||
| '&.Mui-disabled .MuiSvgIcon-root, &.MuiLoadingButton-loading .MuiSvgIcon-root': { | |||||
| color: theme.palette.action.disabled, | |||||
| }, | |||||
| '&.Mui-disabled .MuiTypography-root, &.MuiLoadingButton-loading .MuiTypography-root': { | |||||
| color: `${theme.palette.action.disabled} !important`, | |||||
| }, | |||||
| }); | |||||
| // ==============================|| DASHBOARD - DEFAULT ||============================== // | // ==============================|| DASHBOARD - DEFAULT ||============================== // | ||||
| const ApplicationDetailCard = ( | const ApplicationDetailCard = ( | ||||
| { applicationDetailData, | { applicationDetailData, | ||||
| setStatus, | setStatus, | ||||
| setUploadStatus | |||||
| setUploadStatus, | |||||
| statusDialogOpen = false, | |||||
| statusDialogKind = "", | |||||
| statusActionLoading = false, | |||||
| } | } | ||||
| ) => { | ) => { | ||||
| const publishWithdrawBusy = | |||||
| statusActionLoading || | |||||
| (statusDialogOpen && (statusDialogKind === 'publish' || statusDialogKind === 'withdraw')); | |||||
| const [currentApplicationDetailData, setCurrentApplicationDetailData] = useState({}); | const [currentApplicationDetailData, setCurrentApplicationDetailData] = useState({}); | ||||
| const [companyName, setCompanyName] = useState({}); | const [companyName, setCompanyName] = useState({}); | ||||
| const [orgDetail, setOrgDetail] = useState({}); | const [orgDetail, setOrgDetail] = useState({}); | ||||
| @@ -168,10 +197,12 @@ const ApplicationDetailCard = ( | |||||
| }; | }; | ||||
| const withdrawnClick = () => () => { | const withdrawnClick = () => () => { | ||||
| if (publishWithdrawBusy) return; | |||||
| setStatus("withdraw") | setStatus("withdraw") | ||||
| }; | }; | ||||
| const doPublish = () => () => { | const doPublish = () => () => { | ||||
| if (publishWithdrawBusy) return; | |||||
| setStatus("publish") | setStatus("publish") | ||||
| } | } | ||||
| @@ -334,31 +365,26 @@ const ApplicationDetailCard = ( | |||||
| </> : | </> : | ||||
| (currentApplicationDetailData.status == "confirmed" && currentApplicationDetailData.creditor == 1) ? | (currentApplicationDetailData.status == "confirmed" && currentApplicationDetailData.creditor == 1) ? | ||||
| <> | <> | ||||
| <Button | |||||
| <LoadingButton | |||||
| // size="large" | // size="large" | ||||
| variant="contained" | variant="contained" | ||||
| onClick={doPublish()} | onClick={doPublish()} | ||||
| disabled={setCompleteDisable()} | |||||
| sx={{ | |||||
| textTransform: 'capitalize', | |||||
| alignItems: 'end', | |||||
| backgroundColor: '#52b202' | |||||
| }}> | |||||
| disabled={setCompleteDisable() || publishWithdrawBusy} | |||||
| loading={statusActionLoading && statusDialogKind === 'publish'} | |||||
| sx={publishWithdrawLoadingSx('#52b202', '#489f04')}> | |||||
| <DoneIcon /> | <DoneIcon /> | ||||
| <Typography ml={1} variant="h5">Publish</Typography> | <Typography ml={1} variant="h5">Publish</Typography> | ||||
| </Button> | |||||
| <Button | |||||
| </LoadingButton> | |||||
| <LoadingButton | |||||
| // size="large" | // size="large" | ||||
| variant="contained" | variant="contained" | ||||
| onClick={withdrawnClick()} | onClick={withdrawnClick()} | ||||
| sx={{ | |||||
| textTransform: 'capitalize', | |||||
| alignItems: 'end', | |||||
| backgroundColor: '#ffa733' | |||||
| }}> | |||||
| disabled={publishWithdrawBusy} | |||||
| loading={statusActionLoading && statusDialogKind === 'withdraw'} | |||||
| sx={publishWithdrawLoadingSx('#ffa733', '#e8982e')}> | |||||
| <CloseIcon /> | <CloseIcon /> | ||||
| <Typography ml={1} variant="h5">Withdraw</Typography> | <Typography ml={1} variant="h5">Withdraw</Typography> | ||||
| </Button> | |||||
| </LoadingButton> | |||||
| </> | </> | ||||
| : | : | ||||
| ( | ( | ||||
| @@ -392,18 +418,16 @@ const ApplicationDetailCard = ( | |||||
| <DoneIcon /> | <DoneIcon /> | ||||
| <Typography ml={1} variant="h5">Publish</Typography> | <Typography ml={1} variant="h5">Publish</Typography> | ||||
| </Button> | </Button> | ||||
| <Button | |||||
| <LoadingButton | |||||
| // size="large" | // size="large" | ||||
| variant="contained" | variant="contained" | ||||
| onClick={withdrawnClick()} | onClick={withdrawnClick()} | ||||
| sx={{ | |||||
| textTransform: 'capitalize', | |||||
| alignItems: 'end', | |||||
| backgroundColor: '#ffa733' | |||||
| }}> | |||||
| disabled={publishWithdrawBusy} | |||||
| loading={statusActionLoading && statusDialogKind === 'withdraw'} | |||||
| sx={publishWithdrawLoadingSx('#ffa733', '#e8982e')}> | |||||
| <CloseIcon /> | <CloseIcon /> | ||||
| <Typography ml={1} variant="h5">Withdraw</Typography> | <Typography ml={1} variant="h5">Withdraw</Typography> | ||||
| </Button> | |||||
| </LoadingButton> | |||||
| </> : null | </> : null | ||||
| ) | ) | ||||
| } | } | ||||
| @@ -1,6 +1,7 @@ | |||||
| import { | import { | ||||
| useEffect, | useEffect, | ||||
| useState | |||||
| useState, | |||||
| useRef | |||||
| } from "react"; | } from "react"; | ||||
| // material-ui | // material-ui | ||||
| @@ -16,8 +17,9 @@ import { | |||||
| FormLabel, | FormLabel, | ||||
| Autocomplete, | Autocomplete, | ||||
| TextField, | TextField, | ||||
| Grid | |||||
| Grid, | |||||
| } from '@mui/material'; | } from '@mui/material'; | ||||
| import LoadingButton from '@mui/lab/LoadingButton'; | |||||
| import * as ComboData from "utils/ComboData"; | import * as ComboData from "utils/ComboData"; | ||||
| import { useFormik, FormikProvider } from 'formik'; | import { useFormik, FormikProvider } from 'formik'; | ||||
| @@ -30,8 +32,15 @@ const StatusChangeDialog = (props) => { | |||||
| const [remarks, setRemarks] = useState(""); | const [remarks, setRemarks] = useState(""); | ||||
| const [helperText, setHelperText] = useState(""); | const [helperText, setHelperText] = useState(""); | ||||
| const [comboInputValue, setComboInputValue] = useState({}); | const [comboInputValue, setComboInputValue] = useState({}); | ||||
| const [positiveSubmitting, setPositiveSubmitting] = useState(false); | |||||
| const positiveOnceRef = useRef(false); | |||||
| const groupTitleComboList = ComboData.groupTitle; | const groupTitleComboList = ComboData.groupTitle; | ||||
| const confirmLoading = Boolean(props.confirmLoading) || positiveSubmitting; | |||||
| const gazetteGroupMissing = | |||||
| props.getStatus === "genGazetteCode" && | |||||
| Object.keys(props.selectedGazetteGroup ?? {}).length === 0; | |||||
| useEffect(() => { | useEffect(() => { | ||||
| setComboInputValue({}); | setComboInputValue({}); | ||||
| if (props.getStatus == "genGazetteCode") { | if (props.getStatus == "genGazetteCode") { | ||||
| @@ -58,22 +67,40 @@ const StatusChangeDialog = (props) => { | |||||
| } | } | ||||
| }, [props.getStatus]); | }, [props.getStatus]); | ||||
| useEffect(() => { | |||||
| if (!props.open) { | |||||
| positiveOnceRef.current = false; | |||||
| setPositiveSubmitting(false); | |||||
| } | |||||
| }, [props.open]); | |||||
| const wasConfirmLoadingRef = useRef(false); | |||||
| useEffect(() => { | |||||
| if (wasConfirmLoadingRef.current && !props.confirmLoading) { | |||||
| positiveOnceRef.current = false; | |||||
| setPositiveSubmitting(false); | |||||
| } | |||||
| wasConfirmLoadingRef.current = Boolean(props.confirmLoading); | |||||
| }, [props.confirmLoading]); | |||||
| const acceptedHandle = () => () => { | const acceptedHandle = () => () => { | ||||
| const getStatus = props.getStatus.status; | |||||
| if (getStatus == "notAccepted") { | |||||
| if (!remarks || remarks == "") | |||||
| if (confirmLoading) return; | |||||
| if (positiveOnceRef.current) return; | |||||
| const statusKey = props.getStatus; | |||||
| if (statusKey === "notAccepted" || statusKey === "resubmit") { | |||||
| if (!remarks || remarks === "") { | |||||
| setHelperText("Please enter reason"); | setHelperText("Please enter reason"); | ||||
| } | |||||
| if (!helperText) { | |||||
| props.setReason({ "reason": remarks }); | |||||
| if (remarks != null && remarks != "") { | |||||
| // console.log(remarks) | |||||
| // props.setStatusWindowAccepted(true); | |||||
| return; | |||||
| } | } | ||||
| setHelperText(""); | |||||
| props.setReason({ "reason": remarks }); | |||||
| } | } | ||||
| if (getStatus != "notAccepted") { | |||||
| props.setStatusWindowAccepted(true); | |||||
| } | |||||
| positiveOnceRef.current = true; | |||||
| setPositiveSubmitting(true); | |||||
| props.setStatusWindowAccepted(true); | |||||
| }; | }; | ||||
| @@ -181,7 +208,10 @@ const StatusChangeDialog = (props) => { | |||||
| return ( | return ( | ||||
| <Dialog | <Dialog | ||||
| open={props.open} | open={props.open} | ||||
| onClose={props.handleClose} | |||||
| onClose={() => { | |||||
| if (confirmLoading) return; | |||||
| props.handleClose(); | |||||
| }} | |||||
| fullWidth={true} | fullWidth={true} | ||||
| maxWidth={'md'} | maxWidth={'md'} | ||||
| > | > | ||||
| @@ -207,18 +237,24 @@ const StatusChangeDialog = (props) => { | |||||
| </FormikProvider> | </FormikProvider> | ||||
| <Stack direction="row" justifyContent="space-around"> | <Stack direction="row" justifyContent="space-around"> | ||||
| <DialogActions> | <DialogActions> | ||||
| <Button variant="contained" onClick={props.handleClose} autoFocus > | |||||
| <Button variant="contained" onClick={props.handleClose} autoFocus disabled={confirmLoading}> | |||||
| <Typography variant="h5"> | <Typography variant="h5"> | ||||
| Cancel | Cancel | ||||
| </Typography> | </Typography> | ||||
| </Button> | </Button> | ||||
| </DialogActions> | </DialogActions> | ||||
| <DialogActions> | <DialogActions> | ||||
| <Button variant="contained" color="success" onClick={acceptedHandle()} autoFocus disabled={Object.keys(props.selectedGazetteGroup).length === 0 && props.getStatus === "genGazetteCode"}> | |||||
| <Typography variant="h5"> | |||||
| <LoadingButton | |||||
| variant="contained" | |||||
| color="success" | |||||
| onClick={acceptedHandle()} | |||||
| loading={confirmLoading} | |||||
| disabled={gazetteGroupMissing} | |||||
| > | |||||
| <Typography variant="h5" component="span"> | |||||
| {prositiveBtnText} | {prositiveBtnText} | ||||
| </Typography> | </Typography> | ||||
| </Button> | |||||
| </LoadingButton> | |||||
| </DialogActions> | </DialogActions> | ||||
| </Stack> | </Stack> | ||||
| </Dialog> | </Dialog> | ||||
| @@ -70,6 +70,7 @@ const PublicNoticeDetail_GLD = () => { | |||||
| const [open, setOpen] = useState(false); | const [open, setOpen] = useState(false); | ||||
| const [getStatus, setStatus] = useState(""); | const [getStatus, setStatus] = useState(""); | ||||
| const [statusWindowAccepted, setStatusWindowAccepted] = useState(false); | const [statusWindowAccepted, setStatusWindowAccepted] = useState(false); | ||||
| const [statusConfirmLoading, setStatusConfirmLoading] = useState(false); | |||||
| const [selectedGazetteGroup, setSelectedGazetteGroup] = useState({}); | const [selectedGazetteGroup, setSelectedGazetteGroup] = useState({}); | ||||
| const [selectedGazetteGroupInputType, setSelectedGazetteGroupInputType] = useState(""); | const [selectedGazetteGroupInputType, setSelectedGazetteGroupInputType] = useState(""); | ||||
| const [getReason, setReason] = useState({}); | const [getReason, setReason] = useState({}); | ||||
| @@ -182,24 +183,30 @@ const PublicNoticeDetail_GLD = () => { | |||||
| }; | }; | ||||
| useEffect(() => { | useEffect(() => { | ||||
| if (statusWindowAccepted) { | |||||
| if (getStatus == "genGazetteCode") { | |||||
| onAcceptedClick() | |||||
| } else if (getStatus == "complete") { | |||||
| onComplatedClick() | |||||
| } else if (getStatus == "withdraw") { | |||||
| onWithdrawnClick() | |||||
| } else if (getStatus == "notAccepted") { | |||||
| onNotAcceptClick(getReason); | |||||
| } else if (getStatus == "resubmit") { | |||||
| onReSubmitClick(getReason); | |||||
| } else if (getStatus == "publish") { | |||||
| onPublishClick(); | |||||
| } else if (getStatus == "revoke") { | |||||
| onRevokeClick(); | |||||
| } else if(getStatus == "paid"){ | |||||
| onPaidClick(); | |||||
| } | |||||
| if (!statusWindowAccepted) { | |||||
| setStatusConfirmLoading(false); | |||||
| return; | |||||
| } | |||||
| setStatusConfirmLoading(true); | |||||
| if (getStatus == "genGazetteCode") { | |||||
| onAcceptedClick() | |||||
| } else if (getStatus == "complete") { | |||||
| onComplatedClick() | |||||
| } else if (getStatus == "withdraw") { | |||||
| onWithdrawnClick() | |||||
| } else if (getStatus == "notAccepted") { | |||||
| onNotAcceptClick(getReason); | |||||
| } else if (getStatus == "resubmit") { | |||||
| onReSubmitClick(getReason); | |||||
| } else if (getStatus == "publish") { | |||||
| onPublishClick(); | |||||
| } else if (getStatus == "revoke") { | |||||
| onRevokeClick(); | |||||
| } else if(getStatus == "paid"){ | |||||
| onPaidClick(); | |||||
| } else { | |||||
| setStatusConfirmLoading(false); | |||||
| setStatusWindowAccepted(false); | |||||
| } | } | ||||
| }, [statusWindowAccepted]); | }, [statusWindowAccepted]); | ||||
| @@ -223,12 +230,23 @@ const PublicNoticeDetail_GLD = () => { | |||||
| .catch(error => { | .catch(error => { | ||||
| console.log(error); | console.log(error); | ||||
| return false; | return false; | ||||
| }) | |||||
| .finally(() => { | |||||
| setStatusConfirmLoading(false); | |||||
| setStatusWindowAccepted(false); | |||||
| }); | }); | ||||
| } else { | |||||
| setStatusConfirmLoading(false); | |||||
| setStatusWindowAccepted(false); | |||||
| } | } | ||||
| }; | }; | ||||
| const onNotAcceptClick = (reason) => { | const onNotAcceptClick = (reason) => { | ||||
| if (params.id <= 0) return; | |||||
| if (params.id <= 0) { | |||||
| setStatusConfirmLoading(false); | |||||
| setStatusWindowAccepted(false); | |||||
| return; | |||||
| } | |||||
| HttpUtils.post({ | HttpUtils.post({ | ||||
| url: `${SET_PUBLIC_NOTICE_STATUS_NOT_ACCEPT}/${params.id}`, | url: `${SET_PUBLIC_NOTICE_STATUS_NOT_ACCEPT}/${params.id}`, | ||||
| params: reason, | params: reason, | ||||
| @@ -238,12 +256,24 @@ const PublicNoticeDetail_GLD = () => { | |||||
| // location.reload(); | // location.reload(); | ||||
| loadApplicationDetail() | loadApplicationDetail() | ||||
| notifySaveSuccess() | notifySaveSuccess() | ||||
| }, | |||||
| onFail: () => { | |||||
| setStatusConfirmLoading(false); | |||||
| setStatusWindowAccepted(false); | |||||
| }, | |||||
| onError: () => { | |||||
| setStatusConfirmLoading(false); | |||||
| setStatusWindowAccepted(false); | |||||
| } | } | ||||
| }); | }); | ||||
| } | } | ||||
| const onPublishClick = () => { | const onPublishClick = () => { | ||||
| if (params.id <= 0) return; | |||||
| if (params.id <= 0) { | |||||
| setStatusConfirmLoading(false); | |||||
| setStatusWindowAccepted(false); | |||||
| return; | |||||
| } | |||||
| HttpUtils.get({ | HttpUtils.get({ | ||||
| url: `${SET_PUBLIC_NOTICE_STATUS_PUBLISH}/${params.id}`, | url: `${SET_PUBLIC_NOTICE_STATUS_PUBLISH}/${params.id}`, | ||||
| onSuccess: function () { | onSuccess: function () { | ||||
| @@ -251,6 +281,18 @@ const PublicNoticeDetail_GLD = () => { | |||||
| handleClose(); | handleClose(); | ||||
| loadApplicationDetail() | loadApplicationDetail() | ||||
| notifySaveSuccess() | notifySaveSuccess() | ||||
| }, | |||||
| onFail: () => { | |||||
| setStatusConfirmLoading(false); | |||||
| setStatusWindowAccepted(false); | |||||
| }, | |||||
| onError: () => { | |||||
| setStatusConfirmLoading(false); | |||||
| setStatusWindowAccepted(false); | |||||
| }, | |||||
| onFinally: () => { | |||||
| setStatusConfirmLoading(false); | |||||
| setStatusWindowAccepted(false); | |||||
| } | } | ||||
| }); | }); | ||||
| } | } | ||||
| @@ -270,7 +312,14 @@ const PublicNoticeDetail_GLD = () => { | |||||
| .catch(error => { | .catch(error => { | ||||
| console.log(error); | console.log(error); | ||||
| return false; | return false; | ||||
| }) | |||||
| .finally(() => { | |||||
| setStatusConfirmLoading(false); | |||||
| setStatusWindowAccepted(false); | |||||
| }); | }); | ||||
| } else { | |||||
| setStatusConfirmLoading(false); | |||||
| setStatusWindowAccepted(false); | |||||
| } | } | ||||
| }; | }; | ||||
| @@ -289,7 +338,14 @@ const PublicNoticeDetail_GLD = () => { | |||||
| .catch(error => { | .catch(error => { | ||||
| console.log(error); | console.log(error); | ||||
| return false; | return false; | ||||
| }) | |||||
| .finally(() => { | |||||
| setStatusConfirmLoading(false); | |||||
| setStatusWindowAccepted(false); | |||||
| }); | }); | ||||
| } else { | |||||
| setStatusConfirmLoading(false); | |||||
| setStatusWindowAccepted(false); | |||||
| } | } | ||||
| }; | }; | ||||
| @@ -307,7 +363,14 @@ const PublicNoticeDetail_GLD = () => { | |||||
| .catch(error => { | .catch(error => { | ||||
| console.log(error); | console.log(error); | ||||
| return false; | return false; | ||||
| }) | |||||
| .finally(() => { | |||||
| setStatusConfirmLoading(false); | |||||
| setStatusWindowAccepted(false); | |||||
| }); | }); | ||||
| } else { | |||||
| setStatusConfirmLoading(false); | |||||
| setStatusWindowAccepted(false); | |||||
| } | } | ||||
| }; | }; | ||||
| @@ -322,6 +385,14 @@ const PublicNoticeDetail_GLD = () => { | |||||
| // location.reload(); | // location.reload(); | ||||
| loadApplicationDetail() | loadApplicationDetail() | ||||
| notifySaveSuccess() | notifySaveSuccess() | ||||
| }, | |||||
| onFail: () => { | |||||
| setStatusConfirmLoading(false); | |||||
| setStatusWindowAccepted(false); | |||||
| }, | |||||
| onError: () => { | |||||
| setStatusConfirmLoading(false); | |||||
| setStatusWindowAccepted(false); | |||||
| } | } | ||||
| }); | }); | ||||
| // axios.post(`${SET_PUBLIC_NOTICE_STATUS_RESUBMIT}/${params.id}`) | // axios.post(`${SET_PUBLIC_NOTICE_STATUS_RESUBMIT}/${params.id}`) | ||||
| @@ -338,11 +409,18 @@ const PublicNoticeDetail_GLD = () => { | |||||
| // console.log(error); | // console.log(error); | ||||
| // return false; | // return false; | ||||
| // }); | // }); | ||||
| } else { | |||||
| setStatusConfirmLoading(false); | |||||
| setStatusWindowAccepted(false); | |||||
| } | } | ||||
| }; | }; | ||||
| const onRevokeClick = () => { | const onRevokeClick = () => { | ||||
| if (params.id <= 0) return; | |||||
| if (params.id <= 0) { | |||||
| setStatusConfirmLoading(false); | |||||
| setStatusWindowAccepted(false); | |||||
| return; | |||||
| } | |||||
| HttpUtils.get({ | HttpUtils.get({ | ||||
| url: `${SET_PUBLIC_NOTICE_STATUS_REVOKE}/${params.id}`, | url: `${SET_PUBLIC_NOTICE_STATUS_REVOKE}/${params.id}`, | ||||
| onSuccess: function () { | onSuccess: function () { | ||||
| @@ -350,6 +428,18 @@ const PublicNoticeDetail_GLD = () => { | |||||
| handleClose(); | handleClose(); | ||||
| loadApplicationDetail() | loadApplicationDetail() | ||||
| notifySaveSuccess() | notifySaveSuccess() | ||||
| }, | |||||
| onFail: () => { | |||||
| setStatusConfirmLoading(false); | |||||
| setStatusWindowAccepted(false); | |||||
| }, | |||||
| onError: () => { | |||||
| setStatusConfirmLoading(false); | |||||
| setStatusWindowAccepted(false); | |||||
| }, | |||||
| onFinally: () => { | |||||
| setStatusConfirmLoading(false); | |||||
| setStatusWindowAccepted(false); | |||||
| } | } | ||||
| }); | }); | ||||
| } | } | ||||
| @@ -383,6 +473,7 @@ const PublicNoticeDetail_GLD = () => { | |||||
| issueDate={issueDate} | issueDate={issueDate} | ||||
| issueNum={issueNum} | issueNum={issueNum} | ||||
| gazetteIssue={gazetteIssue} | gazetteIssue={gazetteIssue} | ||||
| confirmLoading={statusConfirmLoading} | |||||
| //combo value | //combo value | ||||
| selectedGazetteGroup={selectedGazetteGroup} | selectedGazetteGroup={selectedGazetteGroup} | ||||
| setSelectedGazetteGroup={setSelectedGazetteGroup} | setSelectedGazetteGroup={setSelectedGazetteGroup} | ||||
| @@ -425,6 +516,9 @@ const PublicNoticeDetail_GLD = () => { | |||||
| setUpdateApplicationObject={setUpdateApplicationObject} | setUpdateApplicationObject={setUpdateApplicationObject} | ||||
| isEditMode={isEditMode} | isEditMode={isEditMode} | ||||
| setiIsSave={setiIsSave} | setiIsSave={setiIsSave} | ||||
| statusDialogOpen={open} | |||||
| statusDialogKind={getStatus} | |||||
| statusActionLoading={statusConfirmLoading} | |||||
| // isNewRecord={isNewRecord} | // isNewRecord={isNewRecord} | ||||
| /> | /> | ||||
| } | } | ||||
| @@ -1,6 +1,7 @@ | |||||
| import { | import { | ||||
| useEffect, | useEffect, | ||||
| useState | |||||
| useState, | |||||
| useRef | |||||
| } from "react"; | } from "react"; | ||||
| // material-ui | // material-ui | ||||
| @@ -15,6 +16,7 @@ import { | |||||
| DialogContent, | DialogContent, | ||||
| DialogContentText, | DialogContentText, | ||||
| DialogTitle, | DialogTitle, | ||||
| CircularProgress, | |||||
| } from '@mui/material'; | } from '@mui/material'; | ||||
| import { useFormik,FormikProvider } from 'formik'; | import { useFormik,FormikProvider } from 'formik'; | ||||
| import * as yup from 'yup'; | import * as yup from 'yup'; | ||||
| @@ -26,6 +28,7 @@ import {useIntl} from "react-intl"; | |||||
| const StatusChangeDialog = (props) => { | const StatusChangeDialog = (props) => { | ||||
| const [status, setStatus] = useState(""); | const [status, setStatus] = useState(""); | ||||
| const intl = useIntl(); | const intl = useIntl(); | ||||
| const confirmOnceRef = useRef(false); | |||||
| useEffect(() => { | useEffect(() => { | ||||
| // console.log(Object.keys(!props.selectedGazetteGroup).length) | // console.log(Object.keys(!props.selectedGazetteGroup).length) | ||||
| @@ -33,9 +36,25 @@ const StatusChangeDialog = (props) => { | |||||
| setStatus(intl.formatMessage({id: 'cancel'})) | setStatus(intl.formatMessage({id: 'cancel'})) | ||||
| } | } | ||||
| }, [props.getStatus]); | }, [props.getStatus]); | ||||
| useEffect(() => { | |||||
| if (!props.open) { | |||||
| confirmOnceRef.current = false; | |||||
| } | |||||
| }, [props.open]); | |||||
| const wasConfirmLoadingRef = useRef(false); | |||||
| useEffect(() => { | |||||
| if (wasConfirmLoadingRef.current && !props.confirmLoading) { | |||||
| confirmOnceRef.current = false; | |||||
| } | |||||
| wasConfirmLoadingRef.current = props.confirmLoading; | |||||
| }, [props.confirmLoading]); | |||||
| const acceptedHandle = () => () =>{ | const acceptedHandle = () => () =>{ | ||||
| // console.log(selectedGazetteGroup) | |||||
| if (props.confirmLoading) return; | |||||
| if (confirmOnceRef.current) return; | |||||
| confirmOnceRef.current = true; | |||||
| props.setStatusWindowAccepted(true) | props.setStatusWindowAccepted(true) | ||||
| }; | }; | ||||
| @@ -86,6 +105,7 @@ const StatusChangeDialog = (props) => { | |||||
| onClick={props.handleClose} | onClick={props.handleClose} | ||||
| autoFocus | autoFocus | ||||
| color="cancel" | color="cancel" | ||||
| disabled={props.confirmLoading} | |||||
| > | > | ||||
| <FormattedMessage id="cancel"/> | <FormattedMessage id="cancel"/> | ||||
| </Button> | </Button> | ||||
| @@ -96,6 +116,8 @@ const StatusChangeDialog = (props) => { | |||||
| color="save" | color="save" | ||||
| onClick={acceptedHandle()} | onClick={acceptedHandle()} | ||||
| autoFocus | autoFocus | ||||
| disabled={props.confirmLoading} | |||||
| startIcon={props.confirmLoading ? <CircularProgress color="inherit" size={20} /> : null} | |||||
| > | > | ||||
| <FormattedMessage id="confirm"/> | <FormattedMessage id="confirm"/> | ||||
| </Button> | </Button> | ||||
| @@ -1,6 +1,7 @@ | |||||
| import React, { | import React, { | ||||
| useEffect, | useEffect, | ||||
| useState, | useState, | ||||
| useRef, | |||||
| lazy | lazy | ||||
| } from "react"; | } from "react"; | ||||
| @@ -49,6 +50,8 @@ const DashboardDefault = () => { | |||||
| const [open, setOpen] = useState(false); | const [open, setOpen] = useState(false); | ||||
| const [getStatus, setStatus] = useState(""); | const [getStatus, setStatus] = useState(""); | ||||
| const [statusWindowAccepted, setStatusWindowAccepted] = useState(false); | const [statusWindowAccepted, setStatusWindowAccepted] = useState(false); | ||||
| const [cancelLoading, setCancelLoading] = useState(false); | |||||
| const cancellingRef = useRef(false); | |||||
| const [proofCount, setProofCount] = useState(0); | const [proofCount, setProofCount] = useState(0); | ||||
| const [paymentCount, setPaymentCount] = useState(0); | const [paymentCount, setPaymentCount] = useState(0); | ||||
| @@ -137,7 +140,10 @@ const DashboardDefault = () => { | |||||
| }, [getStatus]); | }, [getStatus]); | ||||
| const onCancelledClick = () => { | const onCancelledClick = () => { | ||||
| if (cancellingRef.current) return; | |||||
| if (params.id > 0) { | if (params.id > 0) { | ||||
| cancellingRef.current = true; | |||||
| setCancelLoading(true); | |||||
| axios.get(`${SET_PUBLIC_NOTICE_STATUS_CANCELLED}/${params.id}`) | axios.get(`${SET_PUBLIC_NOTICE_STATUS_CANCELLED}/${params.id}`) | ||||
| .then((response) => { | .then((response) => { | ||||
| if (response.status === 204) { | if (response.status === 204) { | ||||
| @@ -151,13 +157,23 @@ const DashboardDefault = () => { | |||||
| .catch(error => { | .catch(error => { | ||||
| console.log(error); | console.log(error); | ||||
| return false; | return false; | ||||
| }) | |||||
| .finally(() => { | |||||
| cancellingRef.current = false; | |||||
| setCancelLoading(false); | |||||
| }); | }); | ||||
| } | } | ||||
| }; | }; | ||||
| return ( | return ( | ||||
| <Grid container sx={{ backgroundColor: '#ffffff' }} direction="column"> | <Grid container sx={{ backgroundColor: '#ffffff' }} direction="column"> | ||||
| <StatusChangeDialog open={open} handleClose={handleClose} setStatusWindowAccepted={setStatusWindowAccepted} getStatus={getStatus} /> | |||||
| <StatusChangeDialog | |||||
| open={open} | |||||
| handleClose={handleClose} | |||||
| setStatusWindowAccepted={setStatusWindowAccepted} | |||||
| getStatus={getStatus} | |||||
| confirmLoading={cancelLoading} | |||||
| /> | |||||
| <Grid item xs={12}> | <Grid item xs={12}> | ||||
| <div style={BackgroundHead}> | <div style={BackgroundHead}> | ||||
| <Stack direction="row" height='70px' justifyContent="flex-start" alignItems="center"> | <Stack direction="row" height='70px' justifyContent="flex-start" alignItems="center"> | ||||
| @@ -2,7 +2,7 @@ import axios from "axios"; | |||||
| import { FILE_UP_POST, FILE_DOWN_GET } from "../utils/ApiPathConst"; | import { FILE_UP_POST, FILE_DOWN_GET } from "../utils/ApiPathConst"; | ||||
| import qs from 'qs'; | import qs from 'qs'; | ||||
| export const get = ({ url, params, onSuccess, onFail, onError }) => { | |||||
| export const get = ({ url, params, onSuccess, onFail, onError, onFinally }) => { | |||||
| axios.get(url, { | axios.get(url, { | ||||
| params, | params, | ||||
| paramsSerializer: (p) => qs.stringify(p, { arrayFormat: 'repeat' }) // <-- FIX | paramsSerializer: (p) => qs.stringify(p, { arrayFormat: 'repeat' }) // <-- FIX | ||||
| @@ -10,6 +10,10 @@ export const get = ({ url, params, onSuccess, onFail, onError }) => { | |||||
| (response) => { onResponse(response, onSuccess, onFail); } | (response) => { onResponse(response, onSuccess, onFail); } | ||||
| ).catch((error) => { | ).catch((error) => { | ||||
| return handleError(error, onError); | return handleError(error, onError); | ||||
| }).finally(() => { | |||||
| if (typeof onFinally === 'function') { | |||||
| onFinally(); | |||||
| } | |||||
| }); | }); | ||||
| }; | }; | ||||