Просмотр исходного кода

Merge branch 'cr022024' into uat

uat
Jason Chuang 1 день назад
Родитель
Сommit
91a381eefc
14 измененных файлов: 426 добавлений и 111 удалений
  1. +14
    -0
      src/layout/MainLayout/Header/index.js
  2. +66
    -6
      src/pages/Payment/Details_GLD/PaymentDetails.js
  3. +42
    -7
      src/pages/Payment/Details_GLD/index.js
  4. +8
    -2
      src/pages/Payment/Search_GLD/DataGrid.js
  5. +14
    -0
      src/pages/Payment/Search_Public/DataGrid.js
  6. +101
    -0
      src/pages/Setting/HkidKeyMigration/index.js
  7. +133
    -0
      src/pages/Setting/UserPiiEncryption/index.js
  8. +21
    -5
      src/pages/User/DetailsPage_Individual/UserInformationCard_Individual.js
  9. +3
    -85
      src/pages/User/DetailsPage_Individual/UserInformationCard_Individual_Pub.js
  10. +14
    -0
      src/routes/GLDUserRoutes.js
  11. +2
    -2
      src/translations/en.json
  12. +2
    -2
      src/translations/zh-CN.json
  13. +2
    -2
      src/translations/zh-HK.json
  14. +4
    -0
      src/utils/ApiPathConst.js

+ 14
- 0
src/layout/MainLayout/Header/index.js Просмотреть файл

@@ -516,6 +516,20 @@ function Header(props) {

{isGranted("MAINTAIN_SETTING") ? (
<>
<li>
<Link className="systemSetting" to="/setting/hkidKeyMigration">
<Typography style={{ opacity: 0.9 }} variant={"pnspsHeaderTitle"} sx={{ ml: 2, mt: 1, mb: 1 }}>
HKID Key Migration
</Typography>
</Link>
</li>
<li>
<Link className="systemSetting" to="/setting/userPiiEncryption">
<Typography style={{ opacity: 0.9 }} variant={"pnspsHeaderTitle"} sx={{ ml: 2, mt: 1, mb: 1 }}>
User PII Encryption
</Typography>
</Link>
</li>
<li>
<Link className="systemSetting" to="/setting/sys">
<Typography style={{ opacity: 0.9 }} variant={"pnspsHeaderTitle"} sx={{ ml: 2, mt: 1, mb: 1 }}>


+ 66
- 6
src/pages/Payment/Details_GLD/PaymentDetails.js Просмотреть файл

@@ -3,24 +3,33 @@ import {
Grid,
Typography,
FormLabel,
Button
Button,
Dialog,
DialogTitle,
DialogContent,
DialogActions,
Box
} from '@mui/material';

import * as React from "react";
import * as FormatUtils from "utils/FormatUtils";
import * as PaymentStatus from "utils/statusUtils/PaymentStatus";
import * as DateUtils from "utils/DateUtils";
import * as HttpUtils from "utils/HttpUtils";
import { PAYMENT_MARK_AS_PAID } from "utils/ApiPathConst";
import Loadable from 'components/Loadable';
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';
import {useIntl} from "react-intl";
// ==============================|| DASHBOARD - DEFAULT ||============================== //
const PaymentDetails = ({ formData,doPrint,onDownload }) => {
const PaymentDetails = ({ formData, doPrint, onDownload, onRefresh }) => {

const intl = useIntl();
const [data, setData] = React.useState({});
const [onReady, setOnReady] = React.useState(false);
const [confirmOpen, setConfirmOpen] = React.useState(false);
const [markingPaid, setMarkingPaid] = React.useState(false);
// const { locale } = intl;

React.useEffect(() => {
@@ -40,9 +49,29 @@ const PaymentDetails = ({ formData,doPrint,onDownload }) => {
if("01" == paymentmethod) return "PPS";
if("02" == paymentmethod || "03" == paymentmethod) return "Credit Card";
if("04" == paymentmethod) return "FPS";
if (data.payMethod === "04,BCFP,FPS") return "FPS";
return paymentmethod;
}

const showMarkAsPaid = data.status === "REJT" && getPaymentMethod() === "FPS";

const handleMarkAsPaid = () => {
setMarkingPaid(true);
HttpUtils.post({
url: PAYMENT_MARK_AS_PAID + "/" + data.id,
onSuccess: () => {
setConfirmOpen(false);
setMarkingPaid(false);
if (onRefresh) {
onRefresh();
}
},
onError: () => {
setMarkingPaid(false);
}
});
};

return (
!onReady ?
<LoadingComponent />
@@ -51,9 +80,21 @@ const PaymentDetails = ({ formData,doPrint,onDownload }) => {
border={false}
content={false}
>
<Typography variant="h5" sx={{ textAlign: "left", mb: 2, borderBottom: "1px solid black" }}>
Payment Details
</Typography>
<Box sx={{ display: "flex", alignItems: "center", justifyContent: "space-between", mb: 2, borderBottom: "1px solid black" }}>
<Typography variant="h5" sx={{ textAlign: "left" }}>
Payment Details
</Typography>
{showMarkAsPaid && (
<Button
className="printHidden"
variant="contained"
color="primary"
onClick={() => setConfirmOpen(true)}
>
Mark as Paid
</Button>
)}
</Box>
<form>
<Grid container>
<Grid item xs={12} md={12} >
@@ -116,7 +157,7 @@ const PaymentDetails = ({ formData,doPrint,onDownload }) => {
<Grid container >
<Grid item xs={6} md={6} sx={{ml:-5, textAlign: "right" }}>
<FormLabel sx={{ color: "#000000" }}>
EGIS Reference No.:
Payment Reference No.:
</FormLabel>
</Grid>
<Grid item xs={6} md={5} sx={{ml:5, textAlign: "left" }}>
@@ -176,6 +217,25 @@ const PaymentDetails = ({ formData,doPrint,onDownload }) => {
}
</Grid>
</form>
<Dialog
open={confirmOpen}
onClose={() => !markingPaid && setConfirmOpen(false)}
>
<DialogTitle>Confirm</DialogTitle>
<DialogContent>
<Typography variant="h5" sx={{ padding: '16px' }}>
{`Are you sure to mark as paid for Payment No. ${data.transNo || data.payload?.transactionid} ?`}
</Typography>
</DialogContent>
<DialogActions>
<Button onClick={() => setConfirmOpen(false)} disabled={markingPaid}>
<Typography variant="h5">Cancel</Typography>
</Button>
<Button onClick={handleMarkAsPaid} disabled={markingPaid}>
<Typography variant="h5">Confirm</Typography>
</Button>
</DialogActions>
</Dialog>
</MainCard>
);
};


+ 42
- 7
src/pages/Payment/Details_GLD/index.js Просмотреть файл

@@ -35,6 +35,9 @@ const Index = () => {
const params = useParams();
const navigate = useNavigate()

const [responeData, setResponeData] = React.useState({});
const [transactionData, setTransactionData] = React.useState({});

const [record, setRecord] = React.useState();
const [itemList, setItemList] = React.useState([]);
const [onReady, setOnReady] = React.useState(false);
@@ -47,8 +50,16 @@ const Index = () => {
}, []);

React.useEffect(() => {
setOnReady(true);
}, [record]);
if (Object.keys(responeData).length > 0) {
setTransactionData(responeData);
}
}, [responeData]);

React.useEffect(() => {
if (Object.keys(transactionData).length > 0) {
setOnReady(true);
}
}, [transactionData]);

// const handleResize = () => {
// setDetailsOrder(window.innerWidth > 1023 ? 2 : -1);
@@ -70,17 +81,40 @@ const Index = () => {

const loadForm = () => {
if (params.id > 0) {

HttpUtils.get({
url: UrlUtils.PAYMENT_LOAD + "/" + params.id,
onSuccess: (responseData) => {
if (!responseData.data?.id) {
navigate("/paymentPage/search");
}
responseData.data["transDateStr"] = responseData.data.transDateTime;
responseData.data["transTimeStr"] = DateUtils.dateFormat(responseData.data.transDateTime, "HH:mm:ss");
setItemList(responseData.paymentItemList)
setRecord(responseData.data);
if (responseData.data.status == null || responseData.data.status == "INPR") {
HttpUtils.post({
url: UrlUtils.PAYMENT_RETRY_STATUS_API,
params: {
"paymentId": params.id
},
onSuccess: function (responseData2) {
responseData2.data["transDateStr"] = responseData2.data.transDateTime;
responseData2.data["transTimeStr"] = DateUtils.dateFormat(responseData2.data.transDateTime, "HH:mm:ss");
setResponeData(responseData2.transactionData);
setItemList(responseData2.paymentItemList);
setRecord(responseData2.data);
},
onError: function () {
responseData.data["transDateStr"] = responseData.data.transDateTime;
responseData.data["transTimeStr"] = DateUtils.dateFormat(responseData.data.transDateTime, "HH:mm:ss");
setResponeData(responseData);
setItemList(responseData.paymentItemList);
setRecord(responseData.data);
}
});
} else {
responseData.data["transDateStr"] = responseData.data.transDateTime;
responseData.data["transTimeStr"] = DateUtils.dateFormat(responseData.data.transDateTime, "HH:mm:ss");
setResponeData(responseData);
setItemList(responseData.paymentItemList);
setRecord(responseData.data);
}
}
});
}
@@ -125,6 +159,7 @@ const Index = () => {
formData={record}
doPrint={doPrint}
onDownload={onDownload}
onRefresh={loadForm}
style={{
display: "flex",
height: "100%",


+ 8
- 2
src/pages/Payment/Search_GLD/DataGrid.js Просмотреть файл

@@ -87,7 +87,7 @@ export default function SearchPaymentTable({ searchCriteria, applyGridOnReady, a
},
{
field: 'actions',
headerName: 'Transaction No.',
headerName: 'Payment No.',
flex: 1,
minWidth: 200,
cellClassName: 'actions',
@@ -95,6 +95,12 @@ export default function SearchPaymentTable({ searchCriteria, applyGridOnReady, a
return clickableLink('/paymentPage/details/' + params.row.id, params.row.transNo);
},
},
{
field: 'egisRefNo',
headerName: 'Payment Reference No.',
flex: 1,
minWidth: 200,
},
{
field: 'payMethod',
headerName: 'Payment Method',
@@ -107,7 +113,7 @@ export default function SearchPaymentTable({ searchCriteria, applyGridOnReady, a
{
id: 'transDateTime',
field: 'transDateTime',
headerName: 'Transaction Date',
headerName: 'Payment Date',
flex: 1,
minWidth: 150,



+ 14
- 0
src/pages/Payment/Search_Public/DataGrid.js Просмотреть файл

@@ -11,6 +11,7 @@ import { FiDataGrid } from "components/FiDataGrid";
import {useTheme} from "@emotion/react";
import {useIntl} from "react-intl";
import { clickableLink } from 'utils/CommonFunction';
import { getPaymentMethodByCode } from "auth/utils";
import {PAYMENT_LIST} from "utils/ApiPathConst";
// ==============================|| EVENT TABLE ||============================== //

@@ -58,6 +59,12 @@ export default function SearchPublicNoticeTable({ searchCriteria, applyGridOnRea
return clickableLink('/paymentPage/details/' + params.row.id, params.row.transNo);
},
},
{
field: 'egisRefNo',
headerName: intl.formatMessage({id: 'paymentRefCode'}),
width: isMdOrLg ? 'auto' : 160,
flex: isMdOrLg ? 1 : undefined,
},
{
id: 'appNos',
field: 'appNos',
@@ -69,6 +76,13 @@ export default function SearchPublicNoticeTable({ searchCriteria, applyGridOnRea
return <div style={{ margin: 4 }}>{appNo}</div>
},
},
{
field: 'payMethod',
headerName: intl.formatMessage({id: 'paymentMethod'}),
width: isMdOrLg ? 'auto' : 160,
flex: isMdOrLg ? 1 : undefined,
renderCell: (params) => getPaymentMethodByCode(params?.value),
},
{
id: 'transDateTime',
field: 'transDateTime',


+ 101
- 0
src/pages/Setting/HkidKeyMigration/index.js Просмотреть файл

@@ -0,0 +1,101 @@
import * as React from "react";
import * as HttpUtils from "utils/HttpUtils";
import * as DateUtils from "utils/DateUtils";
import * as UrlUtils from "utils/ApiPathConst";

import {
Grid, Typography, Button,
Stack, Box, CircularProgress,
} from '@mui/material';
import { notifyActionError } from 'utils/CommonFunction';

import titleBackgroundImg from 'assets/images/dashboard/gazette-bar.png'

const formatLog = (responData) => {
if (responData?.msg && !responData?.log) {
return <>{DateUtils.datetimeStr(new Date())}<br/><span style={{ color: "red" }}>Error</span><br/>{responData.msg}</>;
}
const statusColor = responData?.success ? "green" : "red";
const statusText = responData?.success ? "Success" : "Completed with errors";
const logText = (responData?.log || []).join("\n");
return (
<>
{DateUtils.datetimeStr(new Date())}<br/>
<span style={{ color: statusColor }}>{responData?.dryRun ? "Dry-run " : ""}{statusText}</span><br/>
Total: {responData?.total ?? 0}, OK: {responData?.successCount ?? 0}, Skipped: {responData?.skipped ?? 0}, Failed: {responData?.failed ?? 0}<br/>
<span style={{ whiteSpace: "pre-line" }}>{logText}</span>
</>
);
};

const HkidKeyMigration = () => {
const [resultStr, setResultStr] = React.useState("");
const [wait, setWait] = React.useState(false);

const BackgroundHead = {
backgroundImage: `url(${titleBackgroundImg})`,
width: 'auto',
height: 'auto',
backgroundSize: 'contain',
backgroundRepeat: 'no-repeat',
backgroundColor: '#0C489E',
backgroundPosition: 'right'
};

const runMigration = (dryRun) => {
setWait(true);
HttpUtils.post({
url: `${UrlUtils.HKID_REKEY_MIGRATION}?dryRun=${dryRun}&batchSize=100`,
params: {},
onSuccess: function (responData) {
setWait(false);
setResultStr(formatLog(responData));
},
onError: function () {
setWait(false);
notifyActionError("HKID re-key migration failed");
}
});
};

return (
<Grid container sx={{ minHeight: '87vh', backgroundColor: "backgroundColor.default" }} direction="column">
<Grid item xs={12}>
<div style={BackgroundHead}>
<Stack direction="row" height='70px' justifyContent="space-between" alignItems="center">
<Typography ml={15} color='#FFF' variant="h4" sx={{ textShadow: "0px 0px 25px #0C489E" }}>
HKID Key Migration
</Typography>
</Stack>
</div>
</Grid>

<Grid item xs={12} sx={{ backgroundColor: '#ffffff', ml: 2, mt: 1 }} width="98%">
<Box sx={{ borderRadius: '10px', backgroundColor: '#fff', p: 4 }}>
<Typography variant="body1" sx={{ mb: 2 }}>
Re-encrypt identification and checkDigit from the legacy key to the new key.
Ensure Tomcat has both <code>security.hkid-secret</code> and <code>security.hkid-secret-legacy</code> configured before running.
</Typography>
<Stack direction="row" spacing={2}>
<Button variant="outlined" size="large" disabled={wait} onClick={() => runMigration(true)}>
Dry Run
</Button>
<Button variant="contained" size="large" disabled={wait} onClick={() => runMigration(false)}>
Run Migration
</Button>
{wait ? <CircularProgress size={32} /> : null}
</Stack>
</Box>
</Grid>

<Grid item xs={12} sx={{ backgroundColor: '#ffffff', ml: 2, mt: 1, mb: 2 }} width="98%">
<Box sx={{ borderRadius: '10px', backgroundColor: '#fff', p: 4 }}>
<Typography variant="h4">Result:</Typography>
<Box sx={{ pl: 2, pt: 2 }}>{resultStr}</Box>
</Box>
</Grid>
</Grid>
);
};

export default HkidKeyMigration;

+ 133
- 0
src/pages/Setting/UserPiiEncryption/index.js Просмотреть файл

@@ -0,0 +1,133 @@
import * as React from "react";
import * as HttpUtils from "utils/HttpUtils";
import * as DateUtils from "utils/DateUtils";
import * as UrlUtils from "utils/ApiPathConst";

import {
Grid, Typography, Button,
Stack, Box, CircularProgress,
} from '@mui/material';
import { notifyActionError } from 'utils/CommonFunction';

import titleBackgroundImg from 'assets/images/dashboard/gazette-bar.png'

const formatEncryptLog = (responData) => {
if (responData?.msg && !responData?.log) {
return <>{DateUtils.datetimeStr(new Date())}<br/><span style={{ color: "red" }}>Error</span><br/>{responData.msg}</>;
}
const statusColor = responData?.success ? "green" : "red";
const statusText = responData?.success ? "Success" : "Completed with errors";
const logText = (responData?.log || []).join("\n");
return (
<>
{DateUtils.datetimeStr(new Date())}<br/>
<span style={{ color: statusColor }}>{responData?.dryRun ? "Dry-run " : ""}{statusText}</span><br/>
Total: {responData?.total ?? 0}, OK: {responData?.successCount ?? 0}, Skipped: {responData?.skipped ?? 0}, Failed: {responData?.failed ?? 0}<br/>
<span style={{ whiteSpace: "pre-line" }}>{logText}</span>
</>
);
};

const formatVerifyLog = (responData) => {
const tests = responData?.tests || [];
const logText = tests.map(t => `${t.passed ? "PASS" : "FAIL"} - ${t.name}: ${t.message}`).join("\n");
const statusColor = responData?.success ? "green" : "red";
return (
<>
{DateUtils.datetimeStr(new Date())}<br/>
<span style={{ color: statusColor }}>{responData?.success ? "All tests passed" : "Some tests failed"}</span><br/>
Passed: {responData?.passed ?? 0}, Failed: {responData?.failed ?? 0}<br/>
<span style={{ whiteSpace: "pre-line" }}>{logText}</span>
</>
);
};

const UserPiiEncryption = () => {
const [resultStr, setResultStr] = React.useState("");
const [wait, setWait] = React.useState(false);

const BackgroundHead = {
backgroundImage: `url(${titleBackgroundImg})`,
width: 'auto',
height: 'auto',
backgroundSize: 'contain',
backgroundRepeat: 'no-repeat',
backgroundColor: '#0C489E',
backgroundPosition: 'right'
};

const runEncrypt = (dryRun) => {
setWait(true);
HttpUtils.post({
url: `${UrlUtils.USER_PII_ENCRYPT_MIGRATION}?dryRun=${dryRun}&batchSize=100`,
params: {},
onSuccess: function (responData) {
setWait(false);
setResultStr(formatEncryptLog(responData));
},
onError: function () {
setWait(false);
notifyActionError("User PII encryption failed");
}
});
};

const runVerify = () => {
setWait(true);
HttpUtils.post({
url: UrlUtils.USER_PII_VERIFY_MIGRATION,
params: {},
onSuccess: function (responData) {
setWait(false);
setResultStr(formatVerifyLog(responData));
},
onError: function () {
setWait(false);
notifyActionError("User PII verification failed");
}
});
};

return (
<Grid container sx={{ minHeight: '87vh', backgroundColor: "backgroundColor.default" }} direction="column">
<Grid item xs={12}>
<div style={BackgroundHead}>
<Stack direction="row" height='70px' justifyContent="space-between" alignItems="center">
<Typography ml={15} color='#FFF' variant="h4" sx={{ textShadow: "0px 0px 25px #0C489E" }}>
User PII Encryption
</Typography>
</Stack>
</div>
</Grid>

<Grid item xs={12} sx={{ backgroundColor: '#ffffff', ml: 2, mt: 1 }} width="98%">
<Box sx={{ borderRadius: '10px', backgroundColor: '#fff', p: 4 }}>
<Typography variant="body1" sx={{ mb: 2 }}>
Encrypt enName, chName, mobileNumber, and address for existing user records, then verify data retrieval.
</Typography>
<Stack direction="row" spacing={2} flexWrap="wrap">
<Button variant="outlined" size="large" disabled={wait} onClick={() => runEncrypt(true)}>
Dry Run Encrypt
</Button>
<Button variant="contained" size="large" disabled={wait} onClick={() => runEncrypt(false)}>
Run Encrypt
</Button>
<Button variant="contained" color="secondary" size="large" disabled={wait} onClick={runVerify}>
Verify Retrieval
</Button>
{wait ? <CircularProgress size={32} /> : null}
</Stack>
</Box>
</Grid>

<Grid item xs={12} sx={{ backgroundColor: '#ffffff', ml: 2, mt: 1, mb: 2 }} width="98%">
<Box sx={{ borderRadius: '10px', backgroundColor: '#fff', p: 4 }}>
<Typography variant="h4">Result:</Typography>
<Box sx={{ pl: 2, pt: 2 }}>{resultStr}</Box>
</Box>
</Grid>
</Grid>
);
};

export default UserPiiEncryption;

+ 21
- 5
src/pages/User/DetailsPage_Individual/UserInformationCard_Individual.js Просмотреть файл

@@ -81,7 +81,10 @@ const UserInformationCard_Individual = ({ formData, loadDataFun }) => {
addressLine3: yup.string().max(40, getMaxErrStr(40)).nullable(),
emailAddress: yup.string().email(intl.formatMessage({ id: 'validEmailFormat' })).max(255).required(intl.formatMessage({ id: 'requireEmail' })),
idDocType: yup.string().max(255, getMaxErrStr(255)).required(intl.formatMessage({ id: 'requireIdDocType' })),
identification: yup.string().required(getRequiredErrStr('number'))
identification: yup.string().when('verifiedBy', {
is: (verifiedBy) => verifiedBy != null,
then: (schema) => schema.notRequired(),
otherwise: (schema) => schema.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) {
@@ -133,8 +136,12 @@ const UserInformationCard_Individual = ({ formData, loadDataFun }) => {
break;
}
}
})
}),
checkDigit: yup.string().max(1, getMaxErrStr(1)).nullable()
checkDigit: yup.string().when('verifiedBy', {
is: (verifiedBy) => verifiedBy != null,
then: (schema) => schema.notRequired(),
otherwise: (schema) => schema.max(1, getMaxErrStr(1)).nullable()
.matches(/^[A-Z0-9\s]+$/, { message: displayErrorMsg(`${selectedIdDocInputType}${intl.formatMessage({ id: 'noSpecialCharacter' })}`) })
.test('checkIDCardFormat', displayErrorMsg(`${intl.formatMessage({ id: 'requiredNumberInQuote' })}`), function (value) {
// console.log(selectedIdDocInputType)
@@ -162,7 +169,8 @@ const UserInformationCard_Individual = ({ formData, loadDataFun }) => {
return false
}
}
}),
})
}),
tel_countryCode: yup.string().min(3, intl.formatMessage({ id: 'require3Number' })).required(intl.formatMessage({ id: 'requireDialingCode' })),
fax_countryCode: yup.string().min(3, intl.formatMessage({ id: 'require3Number' })),
phoneNumber: yup.string().min(8, intl.formatMessage({ id: 'require8Number' })).required(intl.formatMessage({ id: 'requireContactNumber' })),
@@ -186,8 +194,10 @@ const UserInformationCard_Individual = ({ formData, loadDataFun }) => {
countryCode: values.tel_countryCode,
phoneNumber: values.phoneNumber
},
identification: values.identification,
checkDigit: values.checkDigit,
...(values.verifiedBy == null ? {
identification: values.identification,
checkDigit: values.checkDigit,
} : {}),
faxNo: {
countryCode: values.fax_countryCode,
faxNumber: values.faxNumber
@@ -471,6 +481,11 @@ const UserInformationCard_Individual = ({ formData, loadDataFun }) => {
</Grid>

<Grid item xs={12} sm={12} md={9} lg={6}>
{currentUserData.verifiedBy ?
<Typography variant="h5" mt={1}>
Hidden for security purpose
</Typography>
:
<Grid container>
{formik.values.idDocType === "HKID" ?
editMode ?
@@ -549,6 +564,7 @@ const UserInformationCard_Individual = ({ formData, loadDataFun }) => {
</Stack>
}
</Grid>
}
</Grid>
</Grid>
</Grid>


+ 3
- 85
src/pages/User/DetailsPage_Individual/UserInformationCard_Individual_Pub.js Просмотреть файл

@@ -2,8 +2,6 @@
import {
Grid, Button, Typography,
FormHelperText,
Stack,
IconButton
} from '@mui/material';
import MainCard from "components/MainCard";
import * as React from "react";
@@ -23,7 +21,6 @@ import { PRIMARY_CONTAINED_BUTTON_SX } from 'themes/colorConst';
import {FormattedMessage, useIntl} from "react-intl";
import {PNSPS_BUTTON_THEME} from "../../../themes/buttonConst";
import {ThemeProvider} from "@emotion/react";
import { EyeInvisibleOutlined, EyeOutlined } from '@ant-design/icons';
// ==============================|| DASHBOARD - DEFAULT ||============================== //


@@ -34,15 +31,6 @@ const UserInformationCard_Individual_Pub = ({ formData, loadDataFun }) => {
const [editMode, setEditMode] = useState(false);
const [onReady, setOnReady] = useState(false);
const [errorMsg, setErrorMsg] = useState("");
const [showId, setshowId] = useState(false);

const handleClickShowId = () => {
setshowId(!showId);
};

const handleMouseDownId = (event) => {
event.preventDefault();
};

useEffect(() => {
if (Object.keys(formData).length > 0) {
@@ -252,79 +240,9 @@ const UserInformationCard_Individual_Pub = ({ formData, loadDataFun }) => {
</Grid>

<Grid item xs={12} sm={12} md={9} lg={6}>
<Grid container>
{formik.values.idDocType === "HKID" ?
// <>
// <Grid item xs={6} sm={6} md={6} lg={7.5} sx={{mr:1}}>
// {FieldUtils.initField({
// valueName: "identification",
// disabled: true,
// form: formik,
// placeholder: intl.formatMessage({id: 'idDocNumber'}),
// inputProps: {
// maxLength: 7,
// onKeyDown: (e) => {
// if (e.key === 'Enter') {
// e.preventDefault();
// }
// },
// }
// })}

// </Grid>
// <Grid item xs={2} sm={2} md={2} lg={2} style={{minWidth:40}}>
// {FieldUtils.initField({
// valueName: "checkDigit",
// disabled: true,
// form: formik,
// })}
// </Grid>
// </>
<Stack direction="row">
<Typography variant="h5" mt={1}>
{formik.values.identification?.slice(0, 4)}
</Typography>
<Typography variant="h5"mt={1}>
{/* {showId ?formik.values.identification.slice(4):"****"}{showId ? '(' + formik.values.checkDigit + ')' :null} */}
{showId ? formik.values.identification?.slice(4) : "****"}{showId ? formik.values.checkDigit?'(' +formik.values.checkDigit+ ')': "()" : ""}
</Typography>
<IconButton
aria-label={intl.formatMessage({ id: 'ariaToggleIdVisibility' })}
onClick={handleClickShowId}
onMouseDown={handleMouseDownId}
edge="end"
size="large"
>
{showId ? <EyeOutlined /> : <EyeInvisibleOutlined />}
</IconButton>
</Stack>
:
// <Grid item xs={10} sm={4} md={4} lg={10}>
// {FieldUtils.initField({
// valueName: "identification",
// disabled: true,
// form: formik
// })}
// </Grid>
<Stack direction="row">
<Typography variant="h5" mt={1}>
{formik.values.identification?.slice(0, 4)}
</Typography>
<Typography variant="h5"mt={1}>
{showId ?formik.values.identification?.slice(4):"****"}
</Typography>
<IconButton
aria-label={intl.formatMessage({ id: 'ariaToggleIdVisibility' })}
onClick={handleClickShowId}
onMouseDown={handleMouseDownId}
edge="end"
size="large"
>
{showId ? <EyeOutlined /> : <EyeInvisibleOutlined />}
</IconButton>
</Stack>
}
</Grid>
<Typography variant="h5" mt={1}>
{formik.values.identification?.slice(0, 4)}
</Typography>
</Grid>
</Grid>
</Grid>


+ 14
- 0
src/routes/GLDUserRoutes.js Просмотреть файл

@@ -30,6 +30,8 @@ const EmailTemplateDetailPage = Loadable(lazy(() => import('pages/EmailTemplate/
const HolidayPage = Loadable(lazy(() => import('pages/Holiday')));
const GazetteIssuePage = Loadable(lazy(() => import('pages/GazetteIssue/index')));
const DrImport = Loadable(lazy(() => import('pages/Setting/DrImport')));
const HkidKeyMigration = Loadable(lazy(() => import('pages/Setting/HkidKeyMigration')));
const UserPiiEncryption = Loadable(lazy(() => import('pages/Setting/UserPiiEncryption')));
const AuditLogPage = Loadable(lazy(() => import('pages/AuditLog/index')));
const ReconReportPage = Loadable(lazy(() => import('pages/Recon')));
const ChangePasswordPage = Loadable(lazy(() => import('pages/User/ChangePasswordPage')));
@@ -190,6 +192,18 @@ const GLDUserRoutes = {
element: <DrImport />
}:{},

isGranted("MAINTAIN_SETTING")?
{
path: '/setting/hkidKeyMigration',
element: <HkidKeyMigration />
}:{},

isGranted("MAINTAIN_SETTING")?
{
path: '/setting/userPiiEncryption',
element: <UserPiiEncryption />
}:{},

isGranted("MAINTAIN_SETTING")?
{
path: '/setting/auditLog',


+ 2
- 2
src/translations/en.json Просмотреть файл

@@ -421,7 +421,7 @@
"payTotal": "Total Payment Amount",
"payDetail": "Payment Details",
"payMethod": "Payment methods",
"epayMethod": " e-Payment Method",
"epayMethod": " Payment Method",
"selectPaymentMethod": "Please select a payment method",
"selectPaymentMethodBtn": "Select payment method",
"payReceipt": "Payment Receipt",
@@ -448,7 +448,7 @@
"paymentLimitPrice2":" is only applicable when minimum amount is HK$0.10 and maximum amount is HK$9,999,999.99",
"paymentLimitPPS":" Payment could not be made via mobile device browsers, please use desktop computers to make payment.",
"paymentMethod": "Payment Method",
"paymentProcessLimited":"Payment process must be completed within 30 minutes and return to this system.",
"paymentProcessLimited":"Please complete the payment process within 15 minutes. Note: For FPS payments, scanning, payment and all necessary approvals must be finished within 3 minutes due to security-related QR code expiry.",
"publicNoticeDetailTitle": "Public Notice Application Information",
"applyPerson": "Applicant",


+ 2
- 2
src/translations/zh-CN.json Просмотреть файл

@@ -454,7 +454,7 @@
"payTotal": "付款总额",
"payDetail": "付款详情",
"payMethod": "付款方式",
"epayMethod": "电子付款方法",
"epayMethod": "付款方法",
"selectPaymentMethod": "请选择付款方法",
"selectPaymentMethodBtn": "选择付款方法",
"payReceipt": "付款收据",
@@ -482,7 +482,7 @@
"paymentLimitPrice2":"只适用于最小金额为 0.10 港元及最高金额为 9,999,999.99港元",
"paymentLimitPPS":"付款不适用于流动装置的浏览器,请使用桌面电脑。",
"paymentMethod": "付款方式",
"paymentProcessLimited":"付款过程必须在 30 分钟内完成及返回本系统。",
"paymentProcessLimited":"请于15分钟内完成付款程序。 注意:使用转数快(FPS)时,因二维码具安全时效限制,须于3分钟内完成扫码、付款及所有相关审核程序。",

"publicNoticeDetailTitle": "公共启事申请资料",
"applyPerson": "申请人",


+ 2
- 2
src/translations/zh-HK.json Просмотреть файл

@@ -455,7 +455,7 @@
"payTotal": "付款總額",
"payDetail": "付款詳情",
"payMethod": "付款方式",
"epayMethod": "電子付款方法",
"epayMethod": "付款方法",
"selectPaymentMethod": "請選擇付款方法",
"selectPaymentMethodBtn": "選擇付款方法",
"payReceipt": "付款收據",
@@ -483,7 +483,7 @@
"paymentLimitPrice2":"只適用於最小金額為 0.10 港元及最高金額為 9,999,999.99港元",
"paymentLimitPPS":"付款不適用於流動裝置的瀏覽器,請使用桌面電腦。",
"paymentMethod": "付款方法",
"paymentProcessLimited":"付款程序必須在 30 分鐘內完成及返回本系统。",
"paymentProcessLimited":"請於15分鐘內完成付款程序。 注意:使用轉數快(FPS)時,因二維碼具安全時效限制,須於3分鐘內完成掃碼、付款及所有相關審核程序。",

"publicNoticeDetailTitle": "公共啟事申請資料",
"applyPerson": "申請人",


+ 4
- 0
src/utils/ApiPathConst.js Просмотреть файл

@@ -84,6 +84,9 @@ export const GET_FILE_DELETE = apiPath+'/file/delete';
export const DR_EXPORT = apiPath+'/settings/dr/export';
export const DR_IMPORT = apiPath+'/settings/dr/import';
export const OFFLINE_IMPORT = apiPath+'/settings/dr/importOffline';
export const HKID_REKEY_MIGRATION = apiPath+'/settings/migration/hkid-rekey';
export const USER_PII_ENCRYPT_MIGRATION = apiPath+'/settings/migration/user-pii-encrypt';
export const USER_PII_VERIFY_MIGRATION = apiPath+'/settings/migration/user-pii-verify';
export const AUDIT_LOG_EXPORT = apiPath+'/settings/auditLog-export';


@@ -180,6 +183,7 @@ 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_BIB = apiPath+'/payment/set-bib';//POST
export const PAYMENT_MARK_AS_PAID = apiPath+'/payment/mark-as-paid';//POST
export const PAYMENT_GFMIS_LIST = apiPath+'/payment/listGFMIS';//GET

export const PAYMENT_LIMIT_SETTING_LIST = apiPath+'/settings/payment';//GET


Загрузка…
Отмена
Сохранить