|
- 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 } from 'react';
- import { FormattedMessage, useIntl } from 'react-intl';
- import { checkSysEnv } from "utils/Utils";
- import backbroundImg from 'assets/images/bg_ml.jpg';
- import lgceImg from 'assets/images/2025_lgce.jpg'; // <-- your popup image
- import 'assets/style/loginStyles.css';
- import { SysContext } from 'components/SysSettingProvider';
-
- const AuthCard = Loadable(lazy(() => import('./AuthCardCustom')));
-
- const BackgroundHead = {
- backgroundImage: `url(${backbroundImg})`,
- width: '100%',
- height: '100%',
- backgroundSize: 'cover'
- };
-
- const parseToDate = (v) => {
- if (v == null || v === "") return null;
-
- // timestamp: 10 digits (sec) or 13 digits (ms)
- const s = String(v).trim();
- if (/^\d{10,13}$/.test(s)) {
- const n = Number(s);
- return new Date(s.length === 10 ? n * 1000 : n);
- }
-
- // date-only: YYYY-MM-DD -> treat as LOCAL midnight
- const m = /^(\d{4})-(\d{2})-(\d{2})$/.exec(s);
- if (m) {
- const y = Number(m[1]);
- const mo = Number(m[2]) - 1; // 0-based
- const d = Number(m[3]);
- return new Date(y, mo, d, 0, 0, 0, 0);
- }
-
- // otherwise: ISO datetime or other formats
- const d = new Date(s);
- return Number.isNaN(d.getTime()) ? null : d;
- };
-
- const AuthWrapper = ({ children }) => {
- const intl = useIntl();
- const { sysSetting } = useContext(SysContext);
-
- // ===== Popup #1 (image popup) =====
- const today = new Date();
- 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]);
-
- 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);
- };
-
- return (
- <Box sx={{ minHeight: '87vh' }}>
- <Dialog
- open={openImagePopup}
- onClose={handleCloseImagePopup}
- aria-labelledby="election-promo-title"
- maxWidth="md"
- PaperProps={{
- sx: {
- borderRadius: 2,
- overflow: 'hidden',
- boxShadow: 6
- }
- }}
- >
- <Box sx={{ position: 'relative' }}>
- <IconButton
- aria-label="Close"
- onClick={handleCloseImagePopup}
- sx={{
- position: 'absolute',
- top: 6,
- right: 6,
- zIndex: 1,
- bgcolor: 'rgba(255,255,255,0.8)',
- '&:hover': { bgcolor: 'rgba(255,255,255,1)' }
- }}
- >
- <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' }}
- />
- </DialogContent>
- </Box>
- </Dialog>
-
- {/* =========================
- 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
- direction="row"
- justifyContent="space-between"
- alignItems="center"
- sx={{ minHeight: '87vh' }}
- >
- <Grid item xs={12} md={8} lg={8} xl={8}>
- <Grid
- container
- direction="column"
- justifyContent="flex-start"
- alignItems="flex-start"
- sx={{ minHeight: { md: 'calc(87vh)' } }}
- >
- <Grid item xs={12} sx={{ ml: 4 }}>
- <Typography style={{ textAlign: "flex-start" }}>
- <div
- style={{ padding: 12 }}
- dangerouslySetInnerHTML={{ __html: intl.formatMessage({ id: "homePageHeaderMessage" }) }}
- />
- </Typography>
- </Grid>
- <Grid
- container
- direction="column"
- justifyContent="flex-start"
- alignItems="center"
- spacing={2}
- 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' }}>
- <FormattedMessage id="HKSARGOV" />
- </Typography>
- <Typography style={{ textAlign: 'center', fontSize: '1.8rem' }}>
- <FormattedMessage id="Gazette" />
- </Typography>
- <Typography style={{ textAlign: 'center', fontSize: '1.8rem' }}>
- <FormattedMessage id="PNSPS_fullname" />
- </Typography>
- {checkSysEnv() !== '' ? (
- <Typography style={{ color: 'red', textAlign: 'center', fontSize: '1.8rem' }}>
- User Acceptance Test Environment
- </Typography>
- ) : (
- ''
- )}
- </Grid>
- </Grid>
- </Grid>
- </Grid>
-
- <Grid item xs={12} md={4} lg={4} xl={4}>
- <Grid
- container
- justifyContent="center"
- alignItems="center"
- sx={{ minHeight: { xs: 'calc(90vh - 134px)', md: 'calc(90vh - 112px)' } }}
- >
- <Grid item xs={12} md={11} lg={11} xl={11}>
- <AuthCard>{children}</AuthCard>
- </Grid>
- </Grid>
- </Grid>
- </Grid>
- </div>
- </Box>
- );
- };
-
- AuthWrapper.propTypes = {
- children: PropTypes.node
- };
-
- export default AuthWrapper;
|