| @@ -1,15 +1,15 @@ | |||||
| import PropTypes from 'prop-types'; | import PropTypes from 'prop-types'; | ||||
| import React, { useContext, useEffect, useMemo, useState } from 'react'; | |||||
| import { Box, Grid, Typography, Dialog, DialogContent, IconButton } from '@mui/material'; | import { Box, Grid, Typography, Dialog, DialogContent, IconButton } from '@mui/material'; | ||||
| import CloseIcon from '@mui/icons-material/Close'; | import CloseIcon from '@mui/icons-material/Close'; | ||||
| import Loadable from 'components/Loadable'; | 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 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 'assets/style/loginStyles.css'; | ||||
| import { checkIsOnlyOnlinePayment } from '../../utils/Utils'; | |||||
| import { SysContext } from 'components/SysSettingProvider'; | |||||
| const AuthCard = Loadable(lazy(() => import('./AuthCardCustom'))); | const AuthCard = Loadable(lazy(() => import('./AuthCardCustom'))); | ||||
| const BackgroundHead = { | const BackgroundHead = { | ||||
| @@ -19,26 +19,60 @@ const BackgroundHead = { | |||||
| backgroundSize: 'cover' | 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 AuthWrapper = ({ children }) => { | ||||
| const intl = useIntl(); | const intl = useIntl(); | ||||
| const { sysSetting } = useContext(SysContext); | |||||
| // --- Date control --- | |||||
| // ===== Popup #1 (image popup) ===== | |||||
| const today = new Date(); | 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(); | const isOnlyOnline = checkIsOnlyOnlinePayment(); | ||||
| console.log("isOnlyOnlinePayment =", isOnlyOnline); | |||||
| return ( | return ( | ||||
| <Box sx={{ minHeight: '87vh' }}> | <Box sx={{ minHeight: '87vh' }}> | ||||
| {/* ========================= | |||||
| Popup #1: Image popup | |||||
| ========================= */} | |||||
| <Dialog | <Dialog | ||||
| open={openPopup} | |||||
| onClose={handleClosePopup} | |||||
| open={openImagePopup} | |||||
| onClose={handleCloseImagePopup} | |||||
| aria-labelledby="election-promo-title" | aria-labelledby="election-promo-title" | ||||
| maxWidth="md" | maxWidth="md" | ||||
| PaperProps={{ | PaperProps={{ | ||||
| @@ -52,7 +86,7 @@ const AuthWrapper = ({ children }) => { | |||||
| <Box sx={{ position: 'relative' }}> | <Box sx={{ position: 'relative' }}> | ||||
| <IconButton | <IconButton | ||||
| aria-label="Close" | aria-label="Close" | ||||
| onClick={handleClosePopup} | |||||
| onClick={handleCloseImagePopup} | |||||
| sx={{ | sx={{ | ||||
| position: 'absolute', | position: 'absolute', | ||||
| top: 6, | top: 6, | ||||
| @@ -64,24 +98,74 @@ const AuthWrapper = ({ children }) => { | |||||
| > | > | ||||
| <CloseIcon /> | <CloseIcon /> | ||||
| </IconButton> | </IconButton> | ||||
| <DialogContent sx={{ p: 0 }}> | <DialogContent sx={{ p: 0 }}> | ||||
| <Box | <Box | ||||
| component="img" | component="img" | ||||
| src={lgceImg} | src={lgceImg} | ||||
| alt={intl.formatMessage({ id: 'lgce_alt', defaultMessage: '2025 Legislative Council General Election' })} | alt={intl.formatMessage({ id: 'lgce_alt', defaultMessage: '2025 Legislative Council General Election' })} | ||||
| title={intl.formatMessage({ id: 'lgce_title', 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> | </DialogContent> | ||||
| </Box> | </Box> | ||||
| </Dialog> | </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}> | <div style={BackgroundHead}> | ||||
| <Grid | <Grid | ||||
| container | container | ||||
| @@ -98,27 +182,31 @@ const AuthWrapper = ({ children }) => { | |||||
| alignItems="flex-start" | alignItems="flex-start" | ||||
| sx={{ minHeight: { md: 'calc(87vh)' } }} | 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> | ||||
| <Grid | <Grid | ||||
| container | container | ||||
| direction="column" | direction="column" | ||||
| @@ -128,21 +216,21 @@ const AuthWrapper = ({ children }) => { | |||||
| sx={{ minHeight: { md: 'calc(50vh)' } }} | sx={{ minHeight: { md: 'calc(50vh)' } }} | ||||
| > | > | ||||
| <Grid item xs={12} sx={{ ml: 4, mt: 12, display: { xs: 'none', sm: 'block' } }}> | <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" /> | <FormattedMessage id="HKSARGOV" /> | ||||
| </Typography> | </Typography> | ||||
| <Typography style={{ textAlign: "center", fontSize: "1.8rem" }}> | |||||
| <Typography style={{ textAlign: 'center', fontSize: '1.8rem' }}> | |||||
| <FormattedMessage id="Gazette" /> | <FormattedMessage id="Gazette" /> | ||||
| </Typography> | </Typography> | ||||
| <Typography style={{ textAlign: "center", fontSize: "1.8rem" }}> | |||||
| <Typography style={{ textAlign: 'center', fontSize: '1.8rem' }}> | |||||
| <FormattedMessage id="PNSPS_fullname" /> | <FormattedMessage id="PNSPS_fullname" /> | ||||
| </Typography> | </Typography> | ||||
| {checkSysEnv() !== '' ? ( | {checkSysEnv() !== '' ? ( | ||||
| <Typography style={{ color: 'red', textAlign: "center", fontSize: "1.8rem" }}> | |||||
| <Typography style={{ color: 'red', textAlign: 'center', fontSize: '1.8rem' }}> | |||||
| User Acceptance Test Environment | User Acceptance Test Environment | ||||
| </Typography> | </Typography> | ||||
| ) : ( | ) : ( | ||||
| "" | |||||
| '' | |||||
| )} | )} | ||||
| </Grid> | </Grid> | ||||
| </Grid> | </Grid> | ||||