| @@ -1,15 +1,15 @@ | |||
| import PropTypes from 'prop-types'; | |||
| import React, { useContext, useEffect, useMemo, useState } from 'react'; | |||
| import { Box, Grid, Typography, Dialog, DialogContent, IconButton } from '@mui/material'; | |||
| import CloseIcon from '@mui/icons-material/Close'; | |||
| import Loadable from 'components/Loadable'; | |||
| import { lazy, useState } from 'react'; | |||
| import { FormattedMessage, useIntl } from "react-intl"; | |||
| import { checkSysEnv, checkPaymentSuspension } from "utils/Utils"; | |||
| import { lazy } from 'react'; | |||
| import { FormattedMessage, useIntl } from 'react-intl'; | |||
| import { checkSysEnv, checkPaymentSuspension, checkIsOnlyOnlinePayment } from 'utils/Utils'; | |||
| import backbroundImg from 'assets/images/bg_ml.jpg'; | |||
| import lgceImg from 'assets/images/2025_lgce.jpg'; // <-- your popup image | |||
| import lgceImg from 'assets/images/2025_lgce.jpg'; | |||
| import 'assets/style/loginStyles.css'; | |||
| import { checkIsOnlyOnlinePayment } from '../../utils/Utils'; | |||
| import { SysContext } from 'components/SysSettingProvider'; | |||
| const AuthCard = Loadable(lazy(() => import('./AuthCardCustom'))); | |||
| const BackgroundHead = { | |||
| @@ -19,26 +19,60 @@ const BackgroundHead = { | |||
| backgroundSize: 'cover' | |||
| }; | |||
| const parseToDate = (v) => { | |||
| if (!v) return null; | |||
| if (/^\d{10,13}$/.test(String(v))) return new Date(Number(v)); | |||
| const d = new Date(String(v)); | |||
| return Number.isNaN(d.getTime()) ? null : d; | |||
| }; | |||
| const AuthWrapper = ({ children }) => { | |||
| const intl = useIntl(); | |||
| const { sysSetting } = useContext(SysContext); | |||
| // --- Date control --- | |||
| // ===== Popup #1 (image popup) ===== | |||
| const today = new Date(); | |||
| const showUntil = new Date("2025-11-27T00:00:00"); // 8 Dec 2025 and onwards = hide popup | |||
| const [openPopup, setOpenPopup] = useState(today < showUntil); | |||
| const showUntil = new Date('2025-11-27T00:00:00'); | |||
| const [openImagePopup, setOpenImagePopup] = useState(today < showUntil); | |||
| const handleCloseImagePopup = () => setOpenImagePopup(false); | |||
| // ===== Popup #2 (system popup) ===== | |||
| const [openNoticePopup, setOpenNoticePopup] = useState(false); | |||
| const popupStart = useMemo(() => parseToDate(sysSetting?.loginPopupStart), [sysSetting?.loginPopupStart]); | |||
| const popupEnd = useMemo(() => parseToDate(sysSetting?.loginPopupEnd), [sysSetting?.loginPopupEnd]); | |||
| const popupHtml = useMemo(() => { | |||
| return intl.formatMessage({ id: 'loginPopupHtml', defaultMessage: '' }) || ''; | |||
| }, [intl]); | |||
| const handleClosePopup = () => { | |||
| setOpenPopup(false); | |||
| useEffect(() => { | |||
| const now = new Date(); | |||
| const inRange = | |||
| (popupStart ? now >= popupStart : true) && | |||
| (popupEnd ? now <= popupEnd : true); | |||
| const hasMessage = popupHtml && popupHtml.trim().length > 0; | |||
| setOpenNoticePopup(Boolean(hasMessage && inRange)); | |||
| }, [popupHtml, popupStart, popupEnd]); | |||
| const handleCloseNoticePopup = () => { | |||
| setOpenNoticePopup(false); | |||
| }; | |||
| const isOnlyOnline = checkIsOnlyOnlinePayment(); | |||
| console.log("isOnlyOnlinePayment =", isOnlyOnline); | |||
| return ( | |||
| <Box sx={{ minHeight: '87vh' }}> | |||
| {/* ========================= | |||
| Popup #1: Image popup | |||
| ========================= */} | |||
| <Dialog | |||
| open={openPopup} | |||
| onClose={handleClosePopup} | |||
| open={openImagePopup} | |||
| onClose={handleCloseImagePopup} | |||
| aria-labelledby="election-promo-title" | |||
| maxWidth="md" | |||
| PaperProps={{ | |||
| @@ -52,7 +86,7 @@ const AuthWrapper = ({ children }) => { | |||
| <Box sx={{ position: 'relative' }}> | |||
| <IconButton | |||
| aria-label="Close" | |||
| onClick={handleClosePopup} | |||
| onClick={handleCloseImagePopup} | |||
| sx={{ | |||
| position: 'absolute', | |||
| top: 6, | |||
| @@ -64,24 +98,74 @@ const AuthWrapper = ({ children }) => { | |||
| > | |||
| <CloseIcon /> | |||
| </IconButton> | |||
| <DialogContent sx={{ p: 0 }}> | |||
| <Box | |||
| component="img" | |||
| src={lgceImg} | |||
| alt={intl.formatMessage({ id: 'lgce_alt', defaultMessage: '2025 Legislative Council General Election' })} | |||
| title={intl.formatMessage({ id: 'lgce_title', defaultMessage: '2025 Legislative Council General Election' })} | |||
| sx={{ | |||
| display: 'block', | |||
| width: '100%', | |||
| maxWidth: '720px', | |||
| height: 'auto' | |||
| }} | |||
| sx={{ display: 'block', width: '100%', maxWidth: '720px', height: 'auto' }} | |||
| /> | |||
| </DialogContent> | |||
| </Box> | |||
| </Dialog> | |||
| {/* Page content */} | |||
| {/* ========================= | |||
| Popup #2: system popup | |||
| ========================= */} | |||
| <Dialog | |||
| open={openNoticePopup} | |||
| onClose={handleCloseNoticePopup} | |||
| maxWidth="md" | |||
| PaperProps={{ | |||
| sx: { | |||
| borderRadius: 1, | |||
| overflow: 'hidden', | |||
| width: { xs: '95vw', md: 900 }, | |||
| maxWidth: '95vw', | |||
| boxShadow: 10, | |||
| border: '1px solid #0c489e' | |||
| } | |||
| }} | |||
| > | |||
| <IconButton | |||
| aria-label="Close" | |||
| onClick={handleCloseNoticePopup} | |||
| sx={{ | |||
| position: 'absolute', | |||
| top: 8, | |||
| right: 8, | |||
| zIndex: 10, | |||
| width: 34, | |||
| height: 34, | |||
| border: '1px solid rgba(0,0,0,0.5)', | |||
| borderRadius: 0, | |||
| bgcolor: '#fff' | |||
| }} | |||
| > | |||
| <CloseIcon /> | |||
| </IconButton> | |||
| <DialogContent | |||
| sx={{ | |||
| bgcolor: '#d9ecff', | |||
| p: 3, | |||
| maxHeight: { xs: '70vh', md: '60vh' }, | |||
| overflowY: 'auto', | |||
| '& h1, & h2, & h3': { marginTop: 0, marginBottom: '12px' }, | |||
| '& p': { marginBottom: '12px', lineHeight: 1.7 } | |||
| }} | |||
| > | |||
| <Typography component="div" sx={{ fontSize: 18, lineHeight: 1.8 }}> | |||
| <div dangerouslySetInnerHTML={{ __html: popupHtml }} /> | |||
| </Typography> | |||
| </DialogContent> | |||
| </Dialog> | |||
| {/* ========================= | |||
| Page content | |||
| ========================= */} | |||
| <div style={BackgroundHead}> | |||
| <Grid | |||
| container | |||
| @@ -98,27 +182,31 @@ const AuthWrapper = ({ children }) => { | |||
| alignItems="flex-start" | |||
| sx={{ minHeight: { md: 'calc(87vh)' } }} | |||
| > | |||
| <Grid item xs={12} sx={{ ml: 4,}}> | |||
| {checkPaymentSuspension()? | |||
| <Typography style={{ color: 'red', textAlign: "flex-start" }}> | |||
| <div style={{ padding: 12 }} dangerouslySetInnerHTML={{ __html: intl.formatMessage({ id: "suspensionMessageText" }) }} /> | |||
| </Typography> | |||
| : | |||
| <Typography style={{ textAlign: "flex-start" }}> | |||
| <div | |||
| style={{ padding: 12 }} | |||
| dangerouslySetInnerHTML={{ | |||
| __html: intl.formatMessage({ | |||
| id: isOnlyOnline | |||
| ? "homePageHeaderMessageFullImpl" | |||
| : "homePageHeaderMessage" | |||
| }) | |||
| }} | |||
| /> | |||
| </Typography> | |||
| } | |||
| <Grid item xs={12} sx={{ ml: 4 }}> | |||
| {checkPaymentSuspension() ? ( | |||
| <Typography style={{ color: 'red', textAlign: 'flex-start' }}> | |||
| <div | |||
| style={{ padding: 12 }} | |||
| dangerouslySetInnerHTML={{ | |||
| __html: intl.formatMessage({ id: 'suspensionMessageText', defaultMessage: '' }) | |||
| }} | |||
| /> | |||
| </Typography> | |||
| ) : ( | |||
| <Typography style={{ textAlign: 'flex-start' }}> | |||
| <div | |||
| style={{ padding: 12 }} | |||
| dangerouslySetInnerHTML={{ | |||
| __html: intl.formatMessage({ | |||
| id: isOnlyOnline ? 'homePageHeaderMessageFullImpl' : 'homePageHeaderMessage', | |||
| defaultMessage: '' | |||
| }) | |||
| }} | |||
| /> | |||
| </Typography> | |||
| )} | |||
| </Grid> | |||
| <Grid | |||
| container | |||
| direction="column" | |||
| @@ -128,21 +216,21 @@ const AuthWrapper = ({ children }) => { | |||
| sx={{ minHeight: { md: 'calc(50vh)' } }} | |||
| > | |||
| <Grid item xs={12} sx={{ ml: 4, mt: 12, display: { xs: 'none', sm: 'block' } }}> | |||
| <Typography style={{ textAlign: "center", fontSize: "1.8rem" }}> | |||
| <Typography style={{ textAlign: 'center', fontSize: '1.8rem' }}> | |||
| <FormattedMessage id="HKSARGOV" /> | |||
| </Typography> | |||
| <Typography style={{ textAlign: "center", fontSize: "1.8rem" }}> | |||
| <Typography style={{ textAlign: 'center', fontSize: '1.8rem' }}> | |||
| <FormattedMessage id="Gazette" /> | |||
| </Typography> | |||
| <Typography style={{ textAlign: "center", fontSize: "1.8rem" }}> | |||
| <Typography style={{ textAlign: 'center', fontSize: '1.8rem' }}> | |||
| <FormattedMessage id="PNSPS_fullname" /> | |||
| </Typography> | |||
| {checkSysEnv() !== '' ? ( | |||
| <Typography style={{ color: 'red', textAlign: "center", fontSize: "1.8rem" }}> | |||
| <Typography style={{ color: 'red', textAlign: 'center', fontSize: '1.8rem' }}> | |||
| User Acceptance Test Environment | |||
| </Typography> | |||
| ) : ( | |||
| "" | |||
| '' | |||
| )} | |||
| </Grid> | |||
| </Grid> | |||