|
- import { Grid, Typography, Stack, Box, Button, FormHelperText, CircularProgress } from '@mui/material';
- import * as React from "react";
- import { useFormik } from 'formik';
- import * as yup from 'yup';
- import * as HttpUtils from "utils/HttpUtils";
- import * as UrlUtils from "utils/ApiPathConst";
- import * as DateUtils from "utils/DateUtils";
- import * as FieldUtils from "utils/FieldUtils";
- import * as ComboData from "utils/ComboData";
- import { getObjectByType } from "utils/CommonFunction";
- import { isORGLoggedIn, isPrimaryLoggedIn } from "utils/Utils";
- import Loadable from "components/Loadable";
- import { lazy } from "react";
- import MainCard from "components/MainCard";
- import ForwardIcon from "@mui/icons-material/Forward";
- import { useNavigate } from "react-router-dom";
- import titleBackgroundImg from "assets/images/dashboard/gazette-bar.png";
- import { FormattedMessage, useIntl } from "react-intl";
- import usePageTitle from "components/usePageTitle";
- import { PNSPS_BUTTON_THEME } from "themes/buttonConst";
- import { PRIMARY_CONTAINED_BUTTON_SX } from "themes/colorConst";
- import { ThemeProvider } from "@emotion/react";
- import { DatePicker } from "@mui/x-date-pickers/DatePicker";
- import dayjs from "dayjs";
- import { DemoItem } from "@mui/x-date-pickers/internals/demo";
- import { LocalizationProvider } from "@mui/x-date-pickers/LocalizationProvider";
- import { AdapterDayjs } from "@mui/x-date-pickers/AdapterDayjs";
- import { Dialog, DialogTitle, DialogContent, DialogActions } from "@mui/material";
- import BrStatusDialog from "components/BrStatusDialog";
-
- const LoadingComponent = Loadable(lazy(() => import("pages/extra-pages/LoadingComponent")));
- const UploadFileTable = Loadable(lazy(() => import("pages/Proof/Reply_Public/UploadFileTable")));
-
- const BackgroundHead = {
- backgroundImage: `url(${titleBackgroundImg})`,
- width: "100%",
- height: "100%",
- backgroundSize: "contain",
- backgroundRepeat: "no-repeat",
- backgroundColor: "#0C489E",
- backgroundPosition: "right"
- };
-
- const SubmitBrPage = () => {
- usePageTitle("submitBrCertificate");
- const intl = useIntl();
- const navigate = useNavigate();
- const [formData, setFormData] = React.useState({});
- const [isLoading, setLoading] = React.useState(true);
- const [errorMsg, setErrorMsg] = React.useState("");
- const [attachments, setAttachments] = React.useState([]);
- const attachmentsRef = React.useRef([]);
- attachmentsRef.current = attachments;
- const [warningText, setWarningText] = React.useState("");
- const [isWarningPopUp, setIsWarningPopUp] = React.useState(false);
- const [showSubmittedDialog, setShowSubmittedDialog] = React.useState(false);
- const fileInputRef = React.useRef(null);
- const minDate = React.useMemo(() => new Date().setDate(new Date().getDate() + 1), []);
-
- React.useEffect(() => {
- if (!isORGLoggedIn()) {
- navigate("/dashboard");
- return;
- }
- HttpUtils.get({
- url: UrlUtils.GET_PUB_ORG_PATH,
- onSuccess: (response) => {
- const data = response.data || {};
- if (!data.canSubmitBr) {
- navigate(isPrimaryLoggedIn() ? "/org" : "/dashboard");
- return;
- }
- data.country = getObjectByType(ComboData.country, "type", data.addressTemp?.country);
- data.district = getObjectByType(ComboData.district, "type", data.addressTemp?.district);
- data.addressLine1 = data.addressTemp?.addressLine1;
- data.addressLine2 = data.addressTemp?.addressLine2;
- data.addressLine3 = data.addressTemp?.addressLine3;
- setFormData(data);
- setLoading(false);
- },
- onFail: () => {
- navigate("/dashboard");
- },
- onError: () => {
- navigate("/dashboard");
- }
- });
- }, [navigate]);
-
- const displayErrorMsg = (msg) => <Typography variant="errorMessage1">{msg}</Typography>;
-
- const getFileExtension = (fileName) => {
- const name = (fileName || "").toLowerCase();
- const dot = name.lastIndexOf(".");
- if (dot <= 0 || dot === name.length - 1) {
- return "";
- }
- return name.substring(dot + 1);
- };
-
- const isAcceptedFile = (fileName) => ["pdf", "jpg", "jpeg", "png"].includes(getFileExtension(fileName));
-
- const initialValues = React.useMemo(() => ({
- ...formData,
- chCompanyName: formData.chCompanyName ?? "",
- brExpiryDate: null,
- certificateFile: null,
- }), [formData]);
-
- const formik = useFormik({
- enableReinitialize: true,
- initialValues,
- validationSchema: yup.object().shape({
- enCompanyName: yup.string().trim().max(150).required(displayErrorMsg(intl.formatMessage({ id: "userRequireEnglishName" }))),
- chCompanyName: yup.string().max(150).nullable(),
- addressLine1: yup.string().trim().max(40).required(displayErrorMsg(intl.formatMessage({ id: "validateAddressLine1" }))),
- addressLine2: yup.string().max(40, displayErrorMsg(intl.formatMessage({ id: "noMoreThen40Words" }))),
- addressLine3: yup.string().max(40, displayErrorMsg(intl.formatMessage({ id: "noMoreThen40Words" }))),
- brExpiryDate: yup.mixed().required(displayErrorMsg(intl.formatMessage({ id: "pleaseFillInBusinessRegCertValidityDate" }))),
- certificateFile: yup.mixed().required(displayErrorMsg(intl.formatMessage({ id: "requireValidFileWithProofReplyFormat" }))),
- country: yup.mixed().required(displayErrorMsg(intl.formatMessage({ id: "pleaseFillInCountry" }))),
- district: yup.mixed().nullable().test(
- "hk-district",
- displayErrorMsg(intl.formatMessage({ id: "pleaseFillInDistrict" })),
- function (value) {
- const country = this.parent.country;
- if (country && country.type === "hongKong") {
- return value != null;
- }
- return true;
- }
- ),
- }),
- onSubmit: (values, { setSubmitting }) => {
- setErrorMsg("");
- const files = attachmentsRef.current;
- if (!values.brExpiryDate || !files || files.length === 0 || values.country == null
- || (values.country.type === "hongKong" && values.district == null)) {
- setSubmitting(false);
- return;
- }
- return new Promise((resolve, reject) => {
- HttpUtils.postWithFiles({
- url: UrlUtils.POST_PUB_ORG_SUBMIT_BR,
- params: {
- enCompanyName: values.enCompanyName,
- chCompanyName: values.chCompanyName?.trim() || "",
- brExpiryDate: DateUtils.dateValue(values.brExpiryDate),
- address: {
- country: values.country.type,
- district: values.district?.type,
- addressLine1: values.addressLine1,
- addressLine2: values.addressLine2,
- addressLine3: values.addressLine3,
- },
- },
- files: files,
- onSuccess: (response) => {
- if (response?.msg) {
- setErrorMsg(intl.formatMessage({ id: response.msg, defaultMessage: response.msg }));
- reject();
- return;
- }
- setShowSubmittedDialog(true);
- resolve();
- },
- onFail: () => reject(),
- onError: () => reject(),
- });
- });
- }
- });
-
- const setCertificateFiles = (files) => {
- const next = files || [];
- setAttachments(next);
- formik.setFieldValue("certificateFile", next[0] || null, true);
- };
-
- const handleSelectCertificate = (event) => {
- const file = event.target.files[0];
- if (!file) {
- return;
- }
- if (!isAcceptedFile(file.name)) {
- setWarningText(intl.formatMessage({ id: "requireValidFileWithProofReplyFormat" }));
- setIsWarningPopUp(true);
- event.target.value = "";
- return;
- }
- if (file.size >= (10 * 1024 * 1034)) {
- setWarningText(intl.formatMessage({ id: "fileSizeWarning" }));
- setIsWarningPopUp(true);
- event.target.value = "";
- return;
- }
- file.id = 0;
- setCertificateFiles([file]);
- event.target.value = "";
- };
-
- return (
- isLoading ?
- <Grid container sx={{ minHeight: "87vh", mb: 3 }} direction="column" justifyContent="center" alignItems="center">
- <Grid item><LoadingComponent /></Grid>
- </Grid>
- :
- <Grid container direction="column" sx={{ minHeight: "87vh", backgroundColor: "#ffffff" }}>
- <Grid item xs={12}>
- <div style={BackgroundHead}>
- <Stack direction="row" height="70px" justifyContent="flex-start" alignItems="center">
- <Typography component="h1" ml={15} color="#FFF" variant="h4" sx={{ display: { xs: "none", md: "block" } }}>
- <FormattedMessage id="submitBrCertificate" />
- </Typography>
- </Stack>
- </div>
- </Grid>
- <Grid item xs={12}>
- <Button aria-label={intl.formatMessage({ id: "back" })} title="Back" sx={{ ml: 3.5, mt: 2 }} style={{ border: "2px solid" }} variant="outlined" onClick={() => navigate(-1)}>
- <ForwardIcon style={{ height: 30, width: 50, transform: "rotate(180deg)" }} />
- </Button>
- </Grid>
- <Grid item xs={12}>
- <Box sx={{ p: 1, borderRadius: "10px" }}>
- <MainCard elevation={0} border={false} content={false}>
- <form onSubmit={formik.handleSubmit} noValidate style={{ padding: 24 }}>
- <Grid container spacing={1}>
- <Grid item xs={12}>
- <FormHelperText error>
- <Typography variant="errorMessage1">{errorMsg}</Typography>
- </FormHelperText>
- </Grid>
- <Grid item xs={12} lg={4}>
- {FieldUtils.getTextField({
- label: intl.formatMessage({ id: "brNo" }) + ":",
- valueName: "brNo",
- disabled: true,
- form: formik
- })}
- </Grid>
- <Grid item xs={12} lg={4}>
- <Grid container alignItems={"center"}>
- <Grid item xs={12} md={3} lg={3} sx={{ display: "flex", alignItems: "center" }}>
- <Typography variant="pnspsFormParagraphBold">{FieldUtils.notNullFieldLabel(intl.formatMessage({ id: "newBrExpiryDate" }) + ":")}</Typography>
- </Grid>
- <Grid item xs={12} md={6} lg={6}>
- <LocalizationProvider dateAdapter={AdapterDayjs} localeText={DateUtils.getPickerLocaleText(intl.locale)}>
- <DemoItem components={["DatePicker"]}>
- <DatePicker
- id="brExpiryDate"
- name="brExpiryDate"
- slotProps={{
- field: { readOnly: true },
- textField: {
- error: Boolean(formik.errors.brExpiryDate && (formik.touched.brExpiryDate || formik.submitCount > 0)),
- helperText: (formik.touched.brExpiryDate || formik.submitCount > 0) ? formik.errors.brExpiryDate : "",
- },
- }}
- format="DD/MM/YYYY"
- value={formik.values.brExpiryDate == null ? null : dayjs(formik.values.brExpiryDate)}
- minDate={minDate == null ? null : dayjs(minDate)}
- onChange={(newValue) => {
- if (DateUtils.dateValue(newValue) > DateUtils.dateValue(new Date())) {
- formik.setFieldValue("brExpiryDate", newValue, true);
- formik.setFieldTouched("brExpiryDate", true, false);
- }
- }}
- />
- </DemoItem>
- </LocalizationProvider>
- </Grid>
- </Grid>
- </Grid>
- <Grid item xs={12} lg={4}></Grid>
- <Grid item xs={12} lg={4}>
- {FieldUtils.getTextField({
- label: FieldUtils.notNullFieldLabel(intl.formatMessage({ id: "nameEng" }) + ":"),
- valueName: "enCompanyName",
- form: formik
- })}
- </Grid>
- <Grid item xs={12} lg={4}>
- {FieldUtils.getTextField({
- label: intl.formatMessage({ id: "nameChi" }) + ":",
- valueName: "chCompanyName",
- form: formik
- })}
- </Grid>
- <Grid item xs={12} lg={4}></Grid>
- <Grid item xs={12} lg={12}>
- {FieldUtils.getAddressField({
- label: FieldUtils.notNullFieldLabel(intl.formatMessage({ id: "formAddress" }) + ":"),
- valueName: ["addressLine1", "addressLine2", "addressLine3"],
- form: formik
- })}
- </Grid>
- <Grid item xs={12} lg={12}>
- {FieldUtils.getProfileComboField({
- label: "",
- valueName: "district",
- dataList: ComboData.district,
- getOptionLabel: (option) => option.type ? intl.formatMessage({ id: option.type }) : "",
- form: formik
- })}
- </Grid>
- <Grid item xs={12} lg={12}>
- {FieldUtils.getProfileComboField({
- label: "",
- valueName: "country",
- disabled: true,
- dataList: ComboData.country,
- getOptionLabel: (option) => option.type ? intl.formatMessage({ id: option.type }) : "",
- form: formik
- })}
- </Grid>
- <Grid item xs={12}>
- <Typography variant="subtitle1" sx={{ color: "primary.primary" }}>
- <FormattedMessage id="acceptProofReplyFileFormats" />
- </Typography>
- </Grid>
- <Grid item xs={12}>
- <input
- ref={fileInputRef}
- id="uploadFileBtn"
- type="file"
- accept=".pdf,.jpg,.jpeg,.png,image/png,image/jpeg,application/pdf"
- hidden
- onChange={handleSelectCertificate}
- />
- <ThemeProvider theme={PNSPS_BUTTON_THEME}>
- <Button
- variant="contained"
- type="button"
- sx={PRIMARY_CONTAINED_BUTTON_SX}
- onClick={() => fileInputRef.current && fileInputRef.current.click()}
- >
- <FormattedMessage id="selectCertificateFile" />
- </Button>
- </ThemeProvider>
- {(formik.touched.certificateFile || formik.submitCount > 0) && formik.errors.certificateFile ?
- <FormHelperText error>{formik.errors.certificateFile}</FormHelperText>
- : null}
- </Grid>
- {attachments.length > 0 ?
- <Grid item xs={12} md={8}>
- <UploadFileTable recordList={attachments} setRecordList={setCertificateFiles} />
- </Grid>
- : null}
- <Grid item xs={12} sx={{ mt: 2 }}>
- <ThemeProvider theme={PNSPS_BUTTON_THEME}>
- <Button
- variant="contained"
- type="submit"
- color="success"
- disabled={formik.isSubmitting || showSubmittedDialog}
- startIcon={formik.isSubmitting ? <CircularProgress color="inherit" size={18} /> : null}
- >
- <FormattedMessage id="submit" />
- </Button>
- </ThemeProvider>
- </Grid>
- </Grid>
- </form>
- </MainCard>
- </Box>
- </Grid>
- <Dialog open={isWarningPopUp} onClose={() => setIsWarningPopUp(false)}>
- <DialogTitle><FormattedMessage id="attention" /></DialogTitle>
- <DialogContent><Typography>{warningText}</Typography></DialogContent>
- <DialogActions>
- <Button onClick={() => setIsWarningPopUp(false)}><FormattedMessage id="close" /></Button>
- </DialogActions>
- </Dialog>
- <BrStatusDialog
- open={showSubmittedDialog}
- variant={formData.brStatus === "Invalid" || formData.applyBlockState === "expired"
- ? "submitExpired"
- : "submitNotExpired"}
- expiryDate={formData.brExpiryDate}
- onClose={() => {
- setShowSubmittedDialog(false);
- navigate(isPrimaryLoggedIn() ? "/org" : "/dashboard");
- }}
- />
- </Grid>
- );
- };
-
- export default SubmitBrPage;
|