Procházet zdrojové kódy

Merge branch 'master' into auditLog

master
Alex Cheung před 1 rokem
rodič
revize
115e0e5d56
20 změnil soubory, kde provedl 433 přidání a 58 odebrání
  1. +1
    -1
      src/pages/DemandNote/Search/SearchForm.js
  2. +5
    -1
      src/pages/Payment/Details_GLD/PaymentDetails.js
  3. +20
    -1
      src/pages/Payment/Details_GLD/index.js
  4. +77
    -3
      src/pages/Payment/MultiPaymentWindow.js
  5. +15
    -13
      src/pages/Payment/index.js
  6. +7
    -0
      src/pages/Proof/Create_FromApp/ProofForm.js
  7. +69
    -1
      src/pages/Proof/Payment/Pay.js
  8. +2
    -2
      src/pages/Proof/Reply_GLD/ApplicationDetails.js
  9. +3
    -1
      src/pages/Proof/Reply_Public/ApplicationDetails.js
  10. +1
    -0
      src/pages/PublicNotice/Details_GLD/GazetteDetailCard.js
  11. +72
    -2
      src/pages/PublicNotice/Details_Public/ApplicationDetailCard.js
  12. +3
    -1
      src/pages/PublicNotice/Details_Public/tabTableDetail/PaymentTab.js
  13. +70
    -1
      src/pages/PublicNotice/ListPanel/PendingPaymentTab.js
  14. +27
    -19
      src/pages/authentication/auth-forms/CustomFormWizard.js
  15. +14
    -1
      src/pages/dashboard/GLD/index.js
  16. +17
    -1
      src/pages/dashboard/Public/index.js
  17. +11
    -4
      src/translations/en.json
  18. +9
    -3
      src/translations/zh-CN.json
  19. +8
    -2
      src/translations/zh-HK.json
  20. +2
    -1
      src/utils/ApiPathConst.js

+ 1
- 1
src/pages/DemandNote/Search/SearchForm.js Zobrazit soubor

@@ -156,7 +156,7 @@ const SearchDemandNoteForm = ({ applySearch, orgComboData, searchCriteria, issue
}}
renderInput={(params) => (
<TextField {...params}
label="Organisation"
label="BR No./Organisation"
InputLabelProps={{
shrink: true
}}


+ 5
- 1
src/pages/Payment/Details_GLD/PaymentDetails.js Zobrazit soubor

@@ -14,7 +14,7 @@ const MainCard = Loadable(React.lazy(() => import('components/MainCard')));
const LoadingComponent = Loadable(React.lazy(() => import('pages/extra-pages/LoadingComponent')));
import DownloadIcon from '@mui/icons-material/Download';
// ==============================|| DASHBOARD - DEFAULT ||============================== //
const PaymentDetails = ({ formData,doPrint }) => {
const PaymentDetails = ({ formData,doPrint,onDownload }) => {

const [data, setData] = React.useState({});
const [onReady, setOnReady] = React.useState(false);
@@ -158,10 +158,14 @@ const PaymentDetails = ({ formData,doPrint }) => {
</FormLabel>
</Grid>
<Grid xs={6} md={5} sx={{ml:5,textAlign: "left" }}>
{onDownload?
<LoadingComponent disableText={true} alignItems="flex-start"/>
:
<Button className="printHidden" variant="contained" sx={{ mt:2 }} onClick={doPrint}>
<DownloadIcon/>
<Typography sx={{fontSize: "16px"}}>Download</Typography>
</Button>
}
</Grid>
</Grid>
</Grid>


+ 20
- 1
src/pages/Payment/Details_GLD/index.js Zobrazit soubor

@@ -4,7 +4,7 @@ import {
Typography,
Stack,
Box,
// Button
Button
} from '@mui/material';
import * as UrlUtils from "utils/ApiPathConst";
import * as React from "react";
@@ -12,6 +12,7 @@ import * as HttpUtils from "utils/HttpUtils";
import * as DateUtils from "utils/DateUtils";
import { useParams } from "react-router-dom";
import { useNavigate } from "react-router-dom";
import ForwardIcon from '@mui/icons-material/Forward';

import Loadable from 'components/Loadable';
const LoadingComponent = Loadable(React.lazy(() => import('pages/extra-pages/LoadingComponent')));
@@ -37,6 +38,7 @@ const Index = () => {
const [record, setRecord] = React.useState();
const [itemList, setItemList] = React.useState([]);
const [onReady, setOnReady] = React.useState(false);
const [onDownload, setOnDownload] = React.useState(false);
// const [detailsOrder, setDetailsOrder] = React.useState(2);

React.useEffect(() => {
@@ -54,8 +56,15 @@ const Index = () => {

const doPrint = () => {
// window.print();
setOnDownload(true)
HttpUtils.fileDownload({
url: UrlUtils.GEN_PAYMENT_RECEIPT+"/"+params.id,
onResponse:()=>{
setOnDownload(false)
},
onError:()=>{
setOnDownload(false)
}
});
};

@@ -98,6 +107,15 @@ const Index = () => {
</Stack>
</div>
</Grid>
<Grid item xs={12} width={{xs:"90%", sm:"90%", md:"90%", lg:"90%"}}>
<Button
aria-label={"back"}
title={"back"}
sx={{ ml: 0, mt: 2.5 }} style={{ border: '2px solid' }} variant="outlined" onClick={() => { navigate(-1) }}
>
<ForwardIcon style={{ height: 30, width: 50, transform: "rotate(180deg)" }} />
</Button>
</Grid>
{/*row 1*/}
<Grid item xs={12} md={12} sx={{textAlign: "center" }}>
<Grid container justifyContent="center" direction="column" spacing={2} sx={{ p: 2 }} alignitems="stretch" >
@@ -106,6 +124,7 @@ const Index = () => {
<PaymentDetails
formData={record}
doPrint={doPrint}
onDownload={onDownload}
style={{
display: "flex",
height: "100%",


+ 77
- 3
src/pages/Payment/MultiPaymentWindow.js Zobrazit soubor

@@ -32,6 +32,8 @@ import UnionPayIcon from "assets/images/icons/unionpay.svg";
import PpsIcon from "assets/images/icons/ppshk.svg";
import FpsIcon from "assets/images/icons/fps.svg";
import {FormattedMessage, useIntl} from "react-intl";
import * as HttpUtils from "utils/HttpUtils"
import * as UrlUtils from "utils/ApiPathConst"

const MultiPaymentWindow = (props) => {
const intl = useIntl();
@@ -52,7 +54,10 @@ const MultiPaymentWindow = (props) => {
const [pPSClass, setPPSlass] = useState("");
const [filteredPaymentMethod, setFilteredPaymentMethod] = useState([]);
const [onReady, setOnReady] = useState(false);

const [paymentHoldedErrText, setPaymentHoldedErrText] = React.useState("");
const [paymentHoldedErr, setPaymentHoldedErr] = React.useState(false);
useEffect(() => {
// console.log(props.transactionData)
if(Object.keys(props.transactionData).length > 0){
@@ -185,7 +190,49 @@ const MultiPaymentWindow = (props) => {
};

const confirmPaymentHandle = () => () =>{
props.setConfirmPayment(true);
handlePaymentCheck()
};

const handlePaymentCheck = () => {
let appIdList = props.appIds
// console.log(props.appIds)
// console.log(appIdList)
HttpUtils.post({
url: UrlUtils.PAYMENT_CHECK,
params: {
appIds: appIdList
},
onSuccess: (responseData) => {
const latestData = {};

responseData.forEach(item => {
const { appId, timeDiff } = item;
if (latestData[appId] === undefined || timeDiff < latestData[appId].timeDiff) {
latestData[appId] = item;
}
});
const latestDataObjects = Object.values(latestData);
const filteredData = latestDataObjects.filter(item => item.timeDiff > 20 && item.status !== "APPR");
const filteredAppIds = filteredData.map(item => item.appId);
const appIdsNotInData = appIdList.filter(appId => !latestDataObjects.some(item => item.appId === appId));
const combinedAppIdsArray = [...appIdsNotInData, ...filteredAppIds];
const readyToPayment = appIdList.every(appId => combinedAppIdsArray.includes(appId));
if (readyToPayment){
// props.setConfirmPayment(true);
return;
}else{
const appIdsInData = appIdList.filter(appId => !combinedAppIdsArray.some(item => item === appId));
const HoldingApplication = latestDataObjects.filter(item => appIdsInData.includes(item.appId));
const resultString = HoldingApplication.map(item => item.appNo).join(' , ');
setPaymentHoldedErrText(resultString);
// setPaymentHoldedErrText(intl.formatMessage({ id: 'MSG.paymentHolded' }, { appNo: record.appNo }));
setPaymentHoldedErr(true);
}
}
});
};

const closeHandle = () => () =>{
@@ -387,10 +434,37 @@ const MultiPaymentWindow = (props) => {
</DialogActions>
<DialogActions>
<Button variant="contained" color="success" onClick={confirmPaymentHandle()} disabled={paymentMethod === "" || isLimit || isPPSLimit}>
<FormattedMessage id="confirm"/>
<FormattedMessage id="pay"/>
</Button>
</DialogActions>
</Stack>
<div>
<Dialog
open={paymentHoldedErr}
onClose={() => setPaymentHoldedErr(false)}
PaperProps={{
sx: {
minWidth: '40vw',
maxWidth: { xs: '90vw', s: '90vw', m: '70vw', lg: '70vw' },
maxHeight: { xs: '90vh', s: '70vh', m: '70vh', lg: '60vh' }
}
}}
>
<DialogTitle></DialogTitle>
<Typography variant="h4" style={{ paddingLeft: '24px' }}><FormattedMessage id="MSG.actionFail" /></Typography>
<DialogContent style={{ display: 'flex', }}>
<Stack direction="column" justifyContent="space-between">
<div dangerouslySetInnerHTML={{ __html: intl.formatMessage({ id: 'MSG.paymentHolded' }, { appNo: paymentHoldedErrText }) }} />
</Stack>
</DialogContent>
<DialogActions>
<Button onClick={() => setPaymentHoldedErr(false)} aria-label={intl.formatMessage({ id: 'close' })}>
<Typography variant="h5">
<FormattedMessage id="close" />
</Typography></Button>
</DialogActions>
</Dialog>
</div>
</Dialog>
);
};


+ 15
- 13
src/pages/Payment/index.js Zobrazit soubor

@@ -157,12 +157,12 @@ const Index = () => {
});
}

// //For testing
//For testing
// if (paymentMethod != "") {
// HttpUtils.post({
// url: UrlUtils.PAYMENT_CREATE,
// params: {
// transNo: "test0001",
// transNo: "test0002",
// payMethod: paymentMethod,
// payAmount: totalAmount,
// appIdList: location.state?.appIdList ?? []
@@ -209,18 +209,18 @@ const Index = () => {
}
});
// HttpUtils.get({
// url: UrlUtils.PAYMENT_LIMIT_SETTING_LIST,
// params: {},
// onSuccess: (responseData) => {
// // console.log(responseData)
// setPaymentLimit(responseData)
HttpUtils.get({
url: UrlUtils.PAYMENT_LIMIT_SETTING_LIST,
params: {},
onSuccess: (responseData) => {
// console.log(responseData)
setPaymentLimit(responseData)

// },
// onError: () =>{
// // setOnReady(true)
// }
// });
},
onError: () =>{
// setOnReady(true)
}
});

// const responseData = {
// "availablepaymentmethods": [
@@ -540,6 +540,8 @@ const Index = () => {
onReady = {onReady}
locale = {locale}
isFullScreen={isFullScreen}
appIds={appIds}
// appNo={itemList.appNo}
/>
</Grid >
);


+ 7
- 0
src/pages/Proof/Create_FromApp/ProofForm.js Zobrazit soubor

@@ -37,6 +37,9 @@ const FormPanel = ({ formData }) => {

const [saving, setSaving] = React.useState(false);

const [proofPaymentDeadlineMin, setProofPaymentDeadlineMin] = React.useState({});
const [reviseDeadlineMin, setReviseDeadlineMin] = React.useState({});

const navigate = useNavigate()

React.useEffect(() => {
@@ -46,6 +49,8 @@ const FormPanel = ({ formData }) => {
setColumnPrice(ComboData.proofPrice[1])
formData['length'] = 18;
}
setProofPaymentDeadlineMin(formData.proofPaymentDeadline);
setReviseDeadlineMin(formData.reviseDeadline);
}
}, [formData]);

@@ -206,6 +211,7 @@ const FormPanel = ({ formData }) => {
onChange={formik.handleChange}
name="reviseDeadline"
value={formik.values["reviseDeadline"]}
InputProps={{ inputProps: { min: DateUtils.datetimeStr(reviseDeadlineMin) } }}
variant="outlined"
sx={
{
@@ -232,6 +238,7 @@ const FormPanel = ({ formData }) => {
onChange={formik.handleChange}
name="proofPaymentDeadline"
value={formik.values["proofPaymentDeadline"]}
InputProps={{ inputProps: { min: DateUtils.datetimeStr(proofPaymentDeadlineMin) } }}
variant="outlined"
sx={
{


+ 69
- 1
src/pages/Proof/Payment/Pay.js Zobrazit soubor

@@ -45,6 +45,8 @@ const Index = () => {
const [record, setRecord] = React.useState({});
const [onReady, setOnReady] = React.useState(false);
const [isPopUp, setIsPopUp] = useState(false);
const [paymentHoldedErrText, setPaymentHoldedErrText] = React.useState("");
const [paymentHoldedErr, setPaymentHoldedErr] = React.useState(false);

const intl = useIntl();

@@ -77,9 +79,48 @@ const Index = () => {

function doPayment() {
setIsPopUp(false);
navigate('/paymentPage', { state: { amount: fee, appIdList: [record?.appId] } });
let appIdList = [record?.appId]
handlePaymentCheck(appIdList)
}

const handlePaymentCheck = (appIdList) => {
HttpUtils.post({
url: UrlUtils.PAYMENT_CHECK,
params: {
appIds: appIdList
},
onSuccess: (responseData) => {
const latestData = {};

responseData.forEach(item => {
const { appId, timeDiff } = item;
if (latestData[appId] === undefined || timeDiff < latestData[appId].timeDiff) {
latestData[appId] = item;
}
});
const latestDataObjects = Object.values(latestData);
const filteredData = latestDataObjects.filter(item => item.timeDiff > 20 && item.status !== "APPR");
const filteredAppIds = filteredData.map(item => item.appId);
const appIdsNotInData = appIdList.filter(appId => !latestDataObjects.some(item => item.appId === appId));
const combinedAppIdsArray = [...appIdsNotInData, ...filteredAppIds];
const readyToPayment = appIdList.every(appId => combinedAppIdsArray.includes(appId));
if (readyToPayment){
navigate('/paymentPage', { state: { amount: fee, appIdList: appIdList } });
}else{
const appIdsInData = appIdList.filter(appId => !combinedAppIdsArray.some(item => item === appId));
const HoldingApplication = latestDataObjects.filter(item => appIdsInData.includes(item.appId));
const resultString = HoldingApplication.map(item => item.appNo).join(' , ');
setPaymentHoldedErrText(resultString);
// setPaymentHoldedErrText(intl.formatMessage({ id: 'MSG.paymentHolded' }, { appNo: record.appNo }));
setPaymentHoldedErr(true);
}
}
});
};

return (
!onReady ?
<Grid container sx={{ minHeight: '87vh', mb: 3 }} direction="column" justifyContent="center" alignItems="center">
@@ -200,6 +241,33 @@ const Index = () => {
</Dialog>
</div>
{/*row 2*/}
<div>
<Dialog
open={paymentHoldedErr}
onClose={() => setPaymentHoldedErr(false)}
PaperProps={{
sx: {
minWidth: '40vw',
maxWidth: { xs: '90vw', s: '90vw', m: '70vw', lg: '70vw' },
maxHeight: { xs: '90vh', s: '70vh', m: '70vh', lg: '60vh' }
}
}}
>
<DialogTitle></DialogTitle>
<Typography variant="h4" style={{ paddingLeft: '24px' }}><FormattedMessage id="MSG.actionFail" /></Typography>
<DialogContent style={{ display: 'flex', }}>
<Stack direction="column" justifyContent="space-between">
<div dangerouslySetInnerHTML={{ __html: intl.formatMessage({ id: 'MSG.paymentHolded' }, { appNo: paymentHoldedErrText }) }} />
</Stack>
</DialogContent>
<DialogActions>
<Button onClick={() => setPaymentHoldedErr(false)} aria-label={intl.formatMessage({ id: 'close' })}>
<Typography variant="h5">
<FormattedMessage id="close" />
</Typography></Button>
</DialogActions>
</Dialog>
</div>
</Grid >




+ 2
- 2
src/pages/Proof/Reply_GLD/ApplicationDetails.js Zobrazit soubor

@@ -139,7 +139,7 @@ const ApplicationDetailCard = ({
<Grid container alignItems={"center"}>
<Grid item xs={12} md={3} lg={3}
sx={{ display: 'flex', alignItems: 'center' }}>
<FormLabel><Typography variant="h5">App No.:</Typography></FormLabel>
<FormLabel><Typography variant="h5">App. No.:</Typography></FormLabel>
</Grid>

<Grid item xs={12} md={9} lg={9}>
@@ -151,7 +151,7 @@ const ApplicationDetailCard = ({
<Grid container alignItems={"left"}>
<Grid item xs={12} md={3} lg={3}
sx={{ display: 'flex', alignItems: 'center' }}>
<FormLabel><Typography variant="h5">Status:</Typography></FormLabel>
<FormLabel><Typography variant="h5">App. Status:</Typography></FormLabel>
</Grid>

<Grid item xs={12} md={9} lg={9} sx={{ display: 'flex', alignItems: 'center' }}>


+ 3
- 1
src/pages/Proof/Reply_Public/ApplicationDetails.js Zobrazit soubor

@@ -278,7 +278,9 @@ const ApplicationDetailCard = ({ formData, }) => {
?
<Typography variant="pnspsFormParagraph">( {data.noOfPages} {intl.formatMessage({id: 'page'})} x $6,552 )</Typography>
:
<Typography variant="pnspsFormParagraph">( {data.length} cm x {data.colCount === 2 ? "$364 二格位" : "$182 一格位"} )</Typography>
<Typography variant="pnspsFormParagraph">( {data.length} cm x {data.colCount === 2 ?
"$364 "+intl.formatMessage({id: 'doubleCol'}) :
"$182 "+intl.formatMessage({id: 'singleCol'})} )</Typography>
}
</Grid>
</Grid>


+ 1
- 0
src/pages/PublicNotice/Details_GLD/GazetteDetailCard.js Zobrazit soubor

@@ -119,6 +119,7 @@ const GazetteDetailCard = (
// size="large"
variant="contained"
onClick={groupDetailClick()}
disabled={applicationDetailData.data.status!="submitted"&&applicationDetailData.data.status!="reviewed"}
sx={{
textTransform: 'capitalize',
alignItems: 'end'


+ 72
- 2
src/pages/PublicNotice/Details_Public/ApplicationDetailCard.js Zobrazit soubor

@@ -52,6 +52,8 @@ const ApplicationDetailCard = (
const [isPopUp, setIsPopUp] = useState(false);
const [errorText, setErrorText] = useState("");
const [errorPopUp, setErrorPopUp] = useState(false);
const [paymentHoldedErrText, setPaymentHoldedErrText] = React.useState("");
const [paymentHoldedErr, setPaymentHoldedErr] = React.useState(false);
// const params = useParams();
const [currentApplicationDetailData, setCurrentApplicationDetailData] = useState({});
const [fee, setFee] = useState(0);
@@ -113,7 +115,8 @@ const ApplicationDetailCard = (
},
onSuccess: (responData) => {
if (responData.success == true) {
setIsPopUp(true);
let appIdList = [currentApplicationDetailData.id]
handlePaymentCheck(appIdList)
return;
}
setErrorText("公共啟事申請已過期");
@@ -125,9 +128,49 @@ const ApplicationDetailCard = (

function doPayment() {
setIsPopUp(false);
navigate('/paymentPage', { state: { amount: fee, appIdList: [currentApplicationDetailData.id] } });
let appIdList = [currentApplicationDetailData.id]
navigate('/paymentPage', { state: { amount: fee, appIdList: appIdList } });
}

const handlePaymentCheck = (appIdList) => {
HttpUtils.post({
url: UrlUtils.PAYMENT_CHECK,
params: {
appIds: appIdList
},
onSuccess: (responseData) => {
const latestData = {};

responseData.forEach(item => {
const { appId, timeDiff } = item;
if (latestData[appId] === undefined || timeDiff < latestData[appId].timeDiff) {
latestData[appId] = item;
}
});
const latestDataObjects = Object.values(latestData);
const filteredData = latestDataObjects.filter(item => item.timeDiff > 20 && item.status !== "APPR");
const filteredAppIds = filteredData.map(item => item.appId);
const appIdsNotInData = appIdList.filter(appId => !latestDataObjects.some(item => item.appId === appId));
const combinedAppIdsArray = [...appIdsNotInData, ...filteredAppIds];
const readyToPayment = appIdList.every(appId => combinedAppIdsArray.includes(appId));
if (readyToPayment){
setIsPopUp(true);
return;
}else{
const appIdsInData = appIdList.filter(appId => !combinedAppIdsArray.some(item => item === appId));
const HoldingApplication = latestDataObjects.filter(item => appIdsInData.includes(item.appId));
const resultString = HoldingApplication.map(item => item.appNo).join(' , ');
setPaymentHoldedErrText(resultString);
// setPaymentHoldedErrText(intl.formatMessage({ id: 'MSG.paymentHolded' }, { appNo: record.appNo }));
setPaymentHoldedErr(true);
}
}
});
};

return (
!onReady ?
<LoadingComponent />
@@ -669,6 +712,33 @@ const ApplicationDetailCard = (
</DialogActions>
</Dialog>
</div>
<div>
<Dialog
open={paymentHoldedErr}
onClose={() => setPaymentHoldedErr(false)}
PaperProps={{
sx: {
minWidth: '40vw',
maxWidth: { xs: '90vw', s: '90vw', m: '70vw', lg: '70vw' },
maxHeight: { xs: '90vh', s: '70vh', m: '70vh', lg: '60vh' }
}
}}
>
<DialogTitle></DialogTitle>
<Typography variant="h4" style={{ paddingLeft: '24px' }}><FormattedMessage id="MSG.actionFail" /></Typography>
<DialogContent style={{ display: 'flex', }}>
<Stack direction="column" justifyContent="space-between">
<div dangerouslySetInnerHTML={{ __html: intl.formatMessage({ id: 'MSG.paymentHolded' }, { appNo: paymentHoldedErrText }) }} />
</Stack>
</DialogContent>
<DialogActions>
<Button onClick={() => setPaymentHoldedErr(false)} aria-label={intl.formatMessage({ id: 'close' })}>
<Typography variant="h5">
<FormattedMessage id="close" />
</Typography></Button>
</DialogActions>
</Dialog>
</div>
</form>
</MainCard >
);


+ 3
- 1
src/pages/PublicNotice/Details_Public/tabTableDetail/PaymentTab.js Zobrazit soubor

@@ -19,6 +19,8 @@ export default function SubmittedTab({ rows }) {
const theme = useTheme();
const isMdOrLg = useMediaQuery(theme.breakpoints.up('md'));
const intl = useIntl();
const { locale } = intl;

const handleEditClick = (params) => () => {
navigate('/paymentPage/details/' + params.row.id);
@@ -52,7 +54,7 @@ export default function SubmittedTab({ rows }) {
width: isMdOrLg ? 'auto' : 160,
flex: isMdOrLg ? 1 : undefined,
renderCell: (params) => {
return PaymentStatus.getStatus_Cht(params);
return locale === 'en' ? PaymentStatus.getStatus_Eng(params):PaymentStatus.getStatus_Cht(params);
}
},
{


+ 70
- 1
src/pages/PublicNotice/ListPanel/PendingPaymentTab.js Zobrazit soubor

@@ -34,6 +34,10 @@ export default function SubmittedTab({ rows }) {
const [selectedCareOf, setSelectedCareOf] = React.useState(null);
const [expiryDateErrText, setExpiryDateErrText] = React.useState("");
const [expiryDateErr, setExpiryDateErr] = React.useState(false);
const [paymentHoldedErrText, setPaymentHoldedErrText] = React.useState("");
const [paymentHoldedErr, setPaymentHoldedErr] = React.useState(false);
const theme = useTheme();
const isMdOrLg = useMediaQuery(theme.breakpoints.up('md'));
const intl = useIntl();
@@ -103,7 +107,8 @@ export default function SubmittedTab({ rows }) {
},
onSuccess: (responData) => {
if (responData.success == true) {
setIsPopUp(true);
// setIsPopUp(true);
handlePaymentCheck(appIdList)
return;
}
let str = "";
@@ -114,8 +119,45 @@ export default function SubmittedTab({ rows }) {
setExpiryDateErr(true);
}
});
};

const handlePaymentCheck = (appIdList) => {
HttpUtils.post({
url: UrlUtils.PAYMENT_CHECK,
params: {
appIds: appIdList
},
onSuccess: (responseData) => {
const latestData = {};

responseData.forEach(item => {
const { appId, timeDiff } = item;
if (latestData[appId] === undefined || timeDiff < latestData[appId].timeDiff) {
latestData[appId] = item;
}
});
const latestDataObjects = Object.values(latestData);
const filteredData = latestDataObjects.filter(item => item.timeDiff > 20 && item.status !== "APPR");
const filteredAppIds = filteredData.map(item => item.appId);
const appIdsNotInData = appIdList.filter(appId => !latestDataObjects.some(item => item.appId === appId));
const combinedAppIdsArray = [...appIdsNotInData, ...filteredAppIds];
const readyToPayment = appIdList.every(appId => combinedAppIdsArray.includes(appId));
if (readyToPayment){
setIsPopUp(true);
return;
}else{
const appIdsInData = appIdList.filter(appId => !combinedAppIdsArray.some(item => item === appId));
const HoldingApplication = latestDataObjects.filter(item => appIdsInData.includes(item.appId));
const resultString = HoldingApplication.map(item => item.appNo).join(' , ');
setPaymentHoldedErrText(resultString);
// setPaymentHoldedErrText(intl.formatMessage({ id: 'MSG.paymentHolded' }, { appNo: record.appNo }));
setPaymentHoldedErr(true);
}
}
});
};

const columns = [
@@ -405,6 +447,33 @@ export default function SubmittedTab({ rows }) {
</DialogActions>
</Dialog>
</div>
<div>
<Dialog
open={paymentHoldedErr}
onClose={() => setPaymentHoldedErr(false)}
PaperProps={{
sx: {
minWidth: '40vw',
maxWidth: { xs: '90vw', s: '90vw', m: '70vw', lg: '70vw' },
maxHeight: { xs: '90vh', s: '70vh', m: '70vh', lg: '60vh' }
}
}}
>
<DialogTitle></DialogTitle>
<Typography variant="h4" style={{ paddingLeft: '24px' }}><FormattedMessage id="MSG.actionFail" /></Typography>
<DialogContent style={{ display: 'flex', }}>
<Stack direction="column" justifyContent="space-between">
<div dangerouslySetInnerHTML={{ __html: intl.formatMessage({ id: 'MSG.paymentHolded' }, { appNo: paymentHoldedErrText }) }} />
</Stack>
</DialogContent>
<DialogActions>
<Button onClick={() => setPaymentHoldedErr(false)} aria-label={intl.formatMessage({ id: 'close' })}>
<Typography variant="h5">
<FormattedMessage id="close" />
</Typography></Button>
</DialogActions>
</Dialog>
</div>
</>
);



+ 27
- 19
src/pages/authentication/auth-forms/CustomFormWizard.js Zobrazit soubor

@@ -303,13 +303,13 @@ const CustomFormWizard = (props) => {
selectedAddress4, selectedAddress5,
termsAndConAccept, termsAndConNotAccept, fileList])

useEffect(()=>{
useEffect(() => {
setDistrictErrStr("");
if(selectedAddress5?.type === "hongKong"){
if(selectedAddress4 ==null || selectedAddress4 == ""|| selectedAddress4 == {})
if (selectedAddress5?.type === "hongKong") {
if (selectedAddress4 == null || selectedAddress4 == "" || selectedAddress4 == {})
setDistrictErrStr(getRequiredErrStr("district"))
}
},[selectedAddress4, selectedAddress5])
}, [selectedAddress4, selectedAddress5])

useEffect(() => {
props.step == 2 ? _onSubmit() : null;
@@ -541,11 +541,11 @@ const CustomFormWizard = (props) => {
return <Typography variant="errorMessage1">{errorMsg}</Typography>
}

function getMaxErrStr(num, fieldname){
return displayErrorMsg(intl.formatMessage({ id: 'noMoreThenNWords' },{num:num, fieldname:fieldname?intl.formatMessage({ id: fieldname})+": ":""}));
function getMaxErrStr(num, fieldname) {
return displayErrorMsg(intl.formatMessage({ id: 'noMoreThenNWords' }, { num: num, fieldname: fieldname ? intl.formatMessage({ id: fieldname }) + ": " : "" }));
}
function getRequiredErrStr(fieldname){
return displayErrorMsg(intl.formatMessage({ id: 'require'},{fieldname:fieldname?intl.formatMessage({ id: fieldname}):""}));
function getRequiredErrStr(fieldname) {
return displayErrorMsg(intl.formatMessage({ id: 'require' }, { fieldname: fieldname ? intl.formatMessage({ id: fieldname }) : "" }));
}

const formik = useFormik({
@@ -581,14 +581,17 @@ const CustomFormWizard = (props) => {
.matches(/^(?=.*[0-9])/, { message: displayErrorMsg(intl.formatMessage({ id: 'atLeast1Number' })) })
.matches(/^(?=.*[!@#%&])/, { message: displayErrorMsg(intl.formatMessage({ id: 'atLeast1SpecialChar' })) }),
confirmPassword: yup.string().min(8, displayErrorMsg(intl.formatMessage({ id: 'atLeast8CharPassword' }))).required(displayErrorMsg(intl.formatMessage({ id: 'pleaseConfirmPassword' }))).oneOf([yup.ref('password'), null], displayErrorMsg(intl.formatMessage({ id: 'samePassword' }))),
enName: yup.string().max(40, getMaxErrStr(40)).required(displayErrorMsg(intl.formatMessage({ id: 'userRequireEnglishName' }))),
chName: yup.string().max(6, getMaxErrStr(6)).required(displayErrorMsg(intl.formatMessage({ id: 'userRequireChineseName' }))),
enName: yup.string().max(40, getMaxErrStr(40)),
chName: yup.string().max(6, getMaxErrStr(6)).when('enName', {
is: (enName) => enName?false:true,
then: yup.string().required(displayErrorMsg(intl.formatMessage({ id: 'userRequireChineseName' })))
}),
address1: yup.string().max(40, getMaxErrStr(40, "addressLine1")).required(displayErrorMsg(intl.formatMessage({ id: 'validateAddressLine1' }))),
address2: yup.string().max(40, getMaxErrStr(40, "addressLine2")),
address3: yup.string().max(40, getMaxErrStr(40, "addressLine3")),
email: yup.string().email(displayErrorMsg(intl.formatMessage({ id: 'validEmailFormat' }))).max(128, getMaxErrStr(128)).required(displayErrorMsg(intl.formatMessage({ id: 'requireEmail' }))),
emailConfirm: yup.string().email(displayErrorMsg(intl.formatMessage({ id: 'validEmailFormat' }))).max(128, getMaxErrStr(128)).required(displayErrorMsg(intl.formatMessage({ id: 'requireEmail' }))).oneOf([yup.ref('email'), null], displayErrorMsg(intl.formatMessage({ id: 'validSameEmail' }))),
idNo: yup.string().required(displayErrorMsg(`${intl.formatMessage({ id: 'require' })}${selectedIdDocInputType}${intl.formatMessage({ id: 'number' })}`))
idNo: yup.string().required(getRequiredErrStr('number'))
.matches(/^[aA-zZ0-9\s]+$/, { message: displayErrorMsg(`${selectedIdDocInputType}${intl.formatMessage({ id: 'noSpecialCharacter' })}`) })
.matches(/^\S*$/, { message: displayErrorMsg(`${selectedIdDocInputType}${intl.formatMessage({ id: 'noSpace' })}`) })
.test('checkIDCardFormat', displayErrorMsg(`${intl.formatMessage({ id: 'requiredValid' })}${selectedIdDocInputType}${intl.formatMessage({ id: 'number' })}`), function (value) {
@@ -648,7 +651,7 @@ const CustomFormWizard = (props) => {
// faxCountryCode: yup.string().min(3,'請輸入3位數字'),
phone: yup.string().min(8, displayErrorMsg(intl.formatMessage({ id: 'requireAtLeast8Number' }))).required(displayErrorMsg(intl.formatMessage({ id: 'requireContactNumber' }))),
// fax: yup.string().min(8,'請輸入8位數字'),
captchaField: yup.string().max(5, getMaxErrStr(5)).required(displayErrorMsg(intl.formatMessage({ id: 'requireVerify' }))),//.oneOf([captcha], displayErrorMsg('請輸入有效驗證')),
captchaField: yup.string().max(5, getMaxErrStr(5)).required(displayErrorMsg(intl.formatMessage({ id: 'requireVerify' }))),//.oneOf([captcha], displayErrorMsg('請輸入有效驗證')),
}),
});

@@ -934,7 +937,7 @@ const CustomFormWizard = (props) => {
/>
{formik.touched.idDocType && (
selectedIdDocType === null || selectedIdDocType?.type == null ?
<FormHelperText error id="helper-text-idDocType-signup" sx={{fontSize:16,fontWeight: 'bold',}}>
<FormHelperText error id="helper-text-idDocType-signup" sx={{ fontSize: 16, fontWeight: 'bold', }}>
<FormattedMessage id="requireIdDocType" />
</FormHelperText> : ''
)}
@@ -1067,12 +1070,17 @@ const CustomFormWizard = (props) => {
}
</Grid>
</Grid>
<Grid item xs={12} md={12}>
<Typography variant="subtitle1">
<FormattedMessage id="registerNameLabel" />
</Typography>
</Grid>
<Grid item xs={12} md={6}>
<Stack spacing={1}>
<InputLabel htmlFor="enName-signup">
<Typography variant="pnspsFormHeader">
<FormattedMessage id="userEnglishName" />
{selectedIdDocType.type === "CNID" ? "" : <span style={{ color: '#f10000' }}>*</span>}
{selectedIdDocType.type === "CNID" ? "" : <span style={{ color: '#f10000' }}></span>}
</Typography>
</InputLabel>
<OutlinedInput
@@ -1105,7 +1113,7 @@ const CustomFormWizard = (props) => {
<InputLabel htmlFor="chName-signup">
<Typography variant="pnspsFormHeader">
<FormattedMessage id="userChineseName" />
<span style={{ color: '#f10000' }}>*</span>
<span style={{ color: '#f10000' }}></span>
</Typography>
</InputLabel>
<OutlinedInput
@@ -1199,7 +1207,7 @@ const CustomFormWizard = (props) => {
value={selectedAddress4}
options={ComboData.district}
disabled={checkCountry}
error={Boolean(districtErrStr!="")}
error={Boolean(districtErrStr != "")}
onBlur={formik.handleBlur}
getOptionLabel={(option) => option.type ? intl.formatMessage({ id: option.type }) : ""}
onChange={(event, newValue) => {
@@ -1252,7 +1260,7 @@ const CustomFormWizard = (props) => {
{formik.errors.address3}
</FormHelperText>
)}
{districtErrStr!= "" && (
{districtErrStr != "" && (
<FormHelperText error >
{districtErrStr}
</FormHelperText>
@@ -1685,8 +1693,8 @@ const CustomFormWizard = (props) => {
<FormattedMessage id="idDocType" />:
</Typography>
<Typography variant="pnspsFormHeader" name="preview-idDocType">
{intl.formatMessage({ id: selectedIdDocType?.label??" " })}
{intl.formatMessage({ id: selectedIdDocType?.label ?? " " })}
</Typography>
</Stack>
</Grid>


+ 14
- 1
src/pages/dashboard/GLD/index.js Zobrazit soubor

@@ -20,13 +20,26 @@ const DashboardDefault = () => {
backgroundColor: '#0C489E',
backgroundPosition: 'right'
}
const getWelcomeMsg=()=>{
var current = new Date()
var curHr = current.getHours()

if (curHr < 12) {
return "Good Morning"
} else if (curHr < 18) {
return "Good Afternoon"
} else {
//evening
return "Good Evening"
}
}
return (
<Grid container sx={{minHeight: '87vh', backgroundColor: "backgroundColor.default"}} direction="column">
<Grid item xs={12}>
<div style={BackgroundHead}>
<Stack direction="row" height='70px' justifyContent="flex-start" alignItems="center">
<Typography ml={15} color='#FFF' variant="h4" sx={{display: { xs: 'none', sm: 'none', md: 'block' }}}>
Morning, {userData.fullenName}
{getWelcomeMsg()}, {userData.fullenName}
</Typography>
</Stack>
</div>


+ 17
- 1
src/pages/dashboard/Public/index.js Zobrazit soubor

@@ -35,6 +35,22 @@ const DashboardDefault = () => {
backgroundColor: '#0C489E',
backgroundPosition: 'right'
}

const { locale } = intl;

const getWelcomeMsg=()=>{
var current = new Date()
var curHr = current.getHours()

if (curHr < 12) {
return <FormattedMessage id="welcomeMsg_am" />
} else if (curHr < 18) {
return <FormattedMessage id="welcomeMsg_pm" />
} else {
return <FormattedMessage id="welcomeMsg_night" />
}
}

return (
<Grid container sx={{ minHeight: '87vh' }} direction="column">
<Grid item xs={12} >
@@ -42,7 +58,7 @@ const DashboardDefault = () => {
<Stack direction="row" height='70px' justifyContent="flex-start" alignItems="center">
{/* <Typography variant="h5">我的公共啟事</Typography> */}
<Typography color='#FFF' variant="h5" sx={{ ml: 10, display: { xs: 'none', sm: 'none', md: 'block' } }}>
{isORGLoggedIn() ? userData.fullenName : userData.fullchName}, <FormattedMessage id="welcomeMsg" />
{isORGLoggedIn() ? userData.fullenName: (locale === 'en' ?userData.fullenName: userData.fullchName)}, {getWelcomeMsg()}
</Typography>
</Stack>
</div>


+ 11
- 4
src/translations/en.json Zobrazit soubor

@@ -67,6 +67,7 @@
"MSG.proofOutOfTime": "Response out of time, please apply again.",
"MSG.plzSelectApp": "Please select application",
"MSG.actionFail": "Action failed",
"MSG.paymentHolded": "Application number {appNo} is currently in the process of payment. If the payment is unsuccessful, please try again after 20 minutes. We apologise for any inconvenience caused.",

"registerTitle1": "Become",
"registerTitle2": "Gazette Notice",
@@ -96,7 +97,10 @@
"onlinePaymentHistory": "Online Payment History",
"setting": "Settings",
"companyOrUserRecord": "Company/Institutional User Records",
"welcomeMsg": "Good afternoon! Please select the required service.",
"welcomeMsg_am": "Good morning! Please select the required service.",
"welcomeMsg_pm": "Good afternoon! Please select the required service.",
"welcomeMsg_night": "Good evening! Please select the required service.",


"login": "Login",
"logout": "Logout",
@@ -147,6 +151,7 @@
"registerNewBusinessUser": "Apply as organisation/company user",
"becomeNewBusinessUser": "Become New Organisation/Company user",
"userName": "Username",
"registerNameLabel": "Please provide either an English name or a Chinese name, at a minimum.",
"userChineseName": "Chinese Name",
"userEnglishName": "English Name",
"userContactName": "Name",
@@ -256,7 +261,7 @@
"mainlandIDCard": "Mainland ID card",
"proCert": "Professional Practice Certificate",
"idDocType": "Document Category",
"requireIdDocType": "Please enter the document type",
"requireIdDocType": "Please select the document type",
"idDocNumber": "ID number",
"requireIdDocNumber": "Please enter the document ID",
"requiredNumberInQuote": "Please enter the numbers or letters in brackets",
@@ -354,7 +359,7 @@
"publicNoticeDetailTitle": "Public Notice Application Information",
"applyPerson": "Applicant",
"applyStatus": "Application Status",
"applyStatus": "App. Status",
"gazetteCount": "Gazette issues number",
"gazetteCount2" :"Gazette issues number / Remarks",
"gazetteCount2_1" :"Care Of / Remarks",
@@ -391,6 +396,8 @@
"upload": "Upload",
"actionFail": "Action failed: Please check the content and submit the reply again",
"issueInvalidMsg": "Action failed: The Gazette Issue invalid, please apply again",
"singleCol":"Single Column",
"doubleCol":"Double Column",

"transactionNo": "Transaction number",
"transactionDate": "Transaction date",
@@ -436,7 +443,7 @@
"noRecordFound": "No record found",
"rowsPerPage": "Rows Per Page",
"date" : "Date",
"keyword": "Key word",
"keyword": "Keyword",
"dateFrom": "Date(From)",
"dateTo": "Date(To)",
"of": "of",


+ 9
- 3
src/translations/zh-CN.json Zobrazit soubor

@@ -66,7 +66,8 @@
"MSG.proofOutOfTime": "回覆逾时,请重新申请。",
"MSG.plzSelectApp": "请选择公共启事。",
"MSG.actionFail": "行动失败",

"MSG.paymentHolded": "申请编号 {appNo} 已正在付款的流程中,如相关付款没有成功,请于20分钟后再尝试付款,不便之处,请见谅!",
"registerTitle1": "立即成为",
"registerTitle2": "宪报刊登公共启事",
"registerTitle3": "用户",
@@ -95,7 +96,9 @@
"onlinePaymentHistory": "网上付款记录",
"setting": "设置",
"companyOrUserRecord": "公司/机构用户记录",
"welcomeMsg": "午安! 请选择所需服务。",
"welcomeMsg_am": "早安! 请选择所需服务。",
"welcomeMsg_pm": "午安! 请选择所需服务。",
"welcomeMsg_night": "晚安! 请选择所需服务。",

"login": "登录",
"logout": "登出",
@@ -142,6 +145,7 @@
"registerNewBusinessUser": "申请机构/公司用户",
"becomeNewBusinessUser": "成为新的机构/公司用户",
"userName": "用户名称",
"registerNameLabel": "请至少输入英文姓名或中文姓名。",
"userChineseName": "中文姓名",
"userEnglishName": "英文姓名",
"userContactName": "姓名",
@@ -251,7 +255,7 @@
"mainlandIDCard": "内地身份证",
"proCert": "专业执业证书",
"idDocType": "证件类别",
"requireIdDocType": "请输入证件类别",
"requireIdDocType": "请选择证件类别",
"idDocNumber": "证件号码",
"requireIdDocNumber": "请输入证件号码",
"requiredNumberInQuote": "请输入括号内的数字或字母",
@@ -386,6 +390,8 @@
"upload": "上载",
"actionFail": "行动失败: 请检查内容并再次提交回覆",
"issueInvalidMsg": "行动失败: 无效宪报期数,请重新申请",
"singleCol":"一格位",
"doubleCol":"二格位",

"transactionNo": "交易号码",
"transactionDate": "交易日期",


+ 8
- 2
src/translations/zh-HK.json Zobrazit soubor

@@ -66,6 +66,7 @@
"MSG.proofOutOfTime": "回覆逾時,請重新申請。",
"MSG.plzSelectApp": "請選擇公共啟事。",
"MSG.actionFail": "行動失敗",
"MSG.paymentHolded": "申請編號 {appNo} 已正在付款的流程中,如相關付款沒有成功,請於20分鐘後再嘗試付款,不便之處,請見諒!",

"registerTitle1": "立即成為",
"registerTitle2": "憲報刊登公共啟事",
@@ -95,7 +96,9 @@
"onlinePaymentHistory": "網上付款記錄",
"setting": "設定",
"companyOrUserRecord": "公司/機構用戶記錄",
"welcomeMsg": "午安! 請選擇所需服務。",
"welcomeMsg_am": "早安! 請選擇所需服務。",
"welcomeMsg_pm": "午安! 請選擇所需服務。",
"welcomeMsg_night": "晚安! 請選擇所需服務。",

"login": "登入",
"logout": "登出",
@@ -145,6 +148,7 @@
"registerNewBusinessUser": "申請機構/公司用戶",
"becomeNewBusinessUser": "成為新的機構/公司用戶",
"userName": "用戶名稱",
"registerNameLabel": "請至少輸入英文姓名或中文姓名。",
"userChineseName": "中文姓名",
"userEnglishName": "英文姓名",
"userContactName": "姓名",
@@ -254,7 +258,7 @@
"mainlandIDCard": "內地身份證",
"proCert": "專業執業證書",
"idDocType": "證件類別",
"requireIdDocType": "請輸入證件類別",
"requireIdDocType": "請選擇證件類別",
"idDocNumber": "證件號碼",
"requireIdDocNumber": "請輸入證件號碼",
"requiredNumberInQuote": "請輸入括號內的數字或字母",
@@ -389,6 +393,8 @@
"upload": "上載",
"actionFail": "行動失敗: 請檢查內容並再次提交回覆",
"issueInvalidMsg": "行動失敗: 無效憲報期數,請重新申請",
"singleCol":"一格位",
"doubleCol":"二格位",

"transactionNo": "交易號碼",
"transactionDate": "交易日期",


+ 2
- 1
src/utils/ApiPathConst.js Zobrazit soubor

@@ -133,12 +133,13 @@ export const PROOF_CHECK_PRICE = apiPath+'/proof/check-price';//GET
export const GET_PROOF_PAY = apiPath+'/proof/pay-details';//GET
export const CANCEL_PROOF = apiPath+'/proof/cancel';//GET

//payment
export const PAYMENT_CREATE = apiPath+'/payment/create';//POST
export const PAYMENT_SAVE = apiPath+'/payment/save';//POST
export const PAYMENT_LIST = apiPath+'/payment/list';//GET
export const PAYMENT_LOAD = apiPath+'/payment/load';//GET
export const PAYMENT_APP_LIST = apiPath+'/payment/applist';//POST
export const PAYMENT_CHECK = apiPath+'/payment/check-payment';//GET

export const PAYMENT_LIMIT_SETTING_LIST = apiPath+'/settings/payment';//GET
export const PAYMENT_AVAILABLE_PAYMENT = paymentPath+'/api/payment/availability';//POST


Načítá se…
Zrušit
Uložit