| @@ -1,7 +1,7 @@ | |||||
| // material-ui | // material-ui | ||||
| import { useMediaQuery, Container, Link, Typography, Stack } from '@mui/material'; | |||||
| import { useMediaQuery, Container, Stack } from '@mui/material'; | |||||
| import bhkLogo from 'assets/images/BHK_logo_rgb_zh-hk.png'; | import bhkLogo from 'assets/images/BHK_logo_rgb_zh-hk.png'; | ||||
| import {FormattedMessage} from "react-intl"; | |||||
| import {useIntl} from "react-intl"; | |||||
| import { | import { | ||||
| isGLDLoggedIn, | isGLDLoggedIn, | ||||
| } from "utils/Utils"; | } from "utils/Utils"; | ||||
| @@ -9,57 +9,43 @@ import { | |||||
| const AuthFooter = () => { | const AuthFooter = () => { | ||||
| const matchDownSM = useMediaQuery((theme) => theme.breakpoints.down('sm')); | const matchDownSM = useMediaQuery((theme) => theme.breakpoints.down('sm')); | ||||
| const intl = useIntl(); | |||||
| const bhkAlt = intl.formatMessage({ id: "bhkLogoAlt" }); | |||||
| const wcagAlt = intl.formatMessage({ id: "wcagAaAlt" }); | |||||
| return ( | return ( | ||||
| <Container maxWidth= "xl" sx={{minHeight: '5vh'}}> | |||||
| <Container maxWidth="xl" sx={{ minHeight: '5vh' }}> | |||||
| <Stack | <Stack | ||||
| direction={matchDownSM ? 'column' : 'row'} | direction={matchDownSM ? 'column' : 'row'} | ||||
| justifyContent={matchDownSM ? 'center' : 'flex-start'} | |||||
| spacing={2} | |||||
| spacing={matchDownSM ? 1 : 3} | |||||
| textAlign={matchDownSM ? 'center' : 'inherit'} | textAlign={matchDownSM ? 'center' : 'inherit'} | ||||
| alignItems="center" | |||||
| justifyContent={matchDownSM ? "center" : "flex-end"} | |||||
| > | > | ||||
| <Typography variant="subtitle2" color="secondary" component="span"> | |||||
| 2024 © <FormattedMessage id="HKGLD" /> | |||||
| </Typography> | |||||
| <Typography | |||||
| variant="subtitle2" | |||||
| color="secondary" | |||||
| component={Link} | |||||
| href="/importantNotice" | |||||
| target="_blank" | |||||
| underline="hover" | |||||
| > | |||||
| <FormattedMessage id="importantNotice" /> | |||||
| </Typography> | |||||
| <Typography | |||||
| variant="subtitle2" | |||||
| color="secondary" | |||||
| component={Link} | |||||
| href="/privacyPolicy" | |||||
| target="_blank" | |||||
| underline="hover" | |||||
| {!isGLDLoggedIn() ? ( | |||||
| <a | |||||
| href="https://www.w3.org/WAI/WCAG2AA-Conformance" | |||||
| title="Explanation of WCAG 2 Level AA conformance" | |||||
| > | > | ||||
| <FormattedMessage id="privacyPolicy" /> | |||||
| </Typography> | |||||
| </Stack> | |||||
| <Stack direction={matchDownSM ? 'column' : 'row'} spacing={matchDownSM ? 1 : 3} textAlign={matchDownSM ? 'center' : 'inherit'} justifyContent={matchDownSM?"center":"flex-end"}> | |||||
| {!isGLDLoggedIn()? | |||||
| <a href="https://www.w3.org/WAI/WCAG2AA-Conformance" | |||||
| title="Explanation of WCAG 2 Level AA conformance"> | |||||
| <img height="32" width="88" | |||||
| src="https://www.w3.org/WAI/wcag2AA" | |||||
| alt="Level AA conformance, | |||||
| W3C WAI Web Content Accessibility Guidelines 2.0"/> | |||||
| </a>:null | |||||
| } | |||||
| <a href="https://www.brandhk.gov.hk/zh-hk" | |||||
| title="Brand Hong Kong"> | |||||
| <img src={bhkLogo} alt="logo" height="32" width="88" | |||||
| <img | |||||
| height="32" | |||||
| width="88" | |||||
| src="https://www.w3.org/WAI/wcag2AA" | |||||
| alt={wcagAlt} | |||||
| /> | /> | ||||
| </a> | </a> | ||||
| </Stack> | |||||
| ) : null} | |||||
| <a href="https://www.brandhk.gov.hk/zh-hk" title="Brand Hong Kong"> | |||||
| <img | |||||
| src={bhkLogo} | |||||
| alt={bhkAlt} | |||||
| height="32" | |||||
| width="88" | |||||
| /> | |||||
| </a> | |||||
| </Stack> | |||||
| </Container> | </Container> | ||||
| ); | ); | ||||
| }; | }; | ||||
| @@ -25,7 +25,7 @@ import * as yup from 'yup'; | |||||
| import { strengthColorChi, strengthIndicator } from 'utils/password-strength'; | import { strengthColorChi, strengthIndicator } from 'utils/password-strength'; | ||||
| // import {apiPath} from "auth/utils"; | // import {apiPath} from "auth/utils"; | ||||
| import axios from "axios"; | import axios from "axios"; | ||||
| import { POST_USERNAME, POST_USER_EMAIL, POST_CAPTCHA, POST_PUBLIC_USER_REGISTER, POST_IDNO } from "utils/ApiPathConst"; | |||||
| import { POST_USERNAME, POST_USER_EMAIL, POST_CAPTCHA, POST_PUBLIC_USER_REGISTER, POST_IDNO, POST_CAPTCHA_AUDIO } from "utils/ApiPathConst"; | |||||
| // import * as HttpUtils from 'utils/HttpUtils'; | // import * as HttpUtils from 'utils/HttpUtils'; | ||||
| import * as ComboData from "utils/ComboData"; | import * as ComboData from "utils/ComboData"; | ||||
| @@ -137,6 +137,16 @@ const CustomFormWizard = (props) => { | |||||
| onCaptchaChange(); | onCaptchaChange(); | ||||
| } | } | ||||
| }, []); | }, []); | ||||
| const playCaptchaAudio = async () => { | |||||
| const resp = await axios.post(`${POST_CAPTCHA_AUDIO}`, | |||||
| { base64Url, lang: intl.locale }, | |||||
| { responseType: "arraybuffer" } | |||||
| ); | |||||
| const blob = new Blob([resp.data], { type: "audio/wav" }); | |||||
| const url = URL.createObjectURL(blob); | |||||
| new Audio(url).play(); | |||||
| }; | |||||
| useEffect(() => { | useEffect(() => { | ||||
| if (selectedIdDocType.type === "HKID"){ | if (selectedIdDocType.type === "HKID"){ | ||||
| @@ -1881,6 +1891,11 @@ const CustomFormWizard = (props) => { | |||||
| {formik.errors.captchaField} | {formik.errors.captchaField} | ||||
| </FormHelperText> | </FormHelperText> | ||||
| )} | )} | ||||
| <Stack spacing={1} direction="row"> | |||||
| <Button onClick={playCaptchaAudio} aria-label={intl.formatMessage({id:"captchaPlayAudioAria"})}> | |||||
| <FormattedMessage id="captchaPlayAudio" /> | |||||
| </Button> | |||||
| </Stack> | |||||
| </Stack> | </Stack> | ||||
| </Grid> | </Grid> | ||||
| </Grid> | </Grid> | ||||
| @@ -40,17 +40,49 @@ const UserMenuPub = () => { | |||||
| padding: "8px" | padding: "8px" | ||||
| }; | }; | ||||
| const getRow = ({ title, orgEn, orgZh, orgCn, indEn, indZh, indCn }) => { | |||||
| const getRow = ({ titleId, orgEn, orgZh, orgCn, indEn, indZh, indCn }) => { | |||||
| const guideTitle = intl.formatMessage({ id: titleId }); | |||||
| const orgUserType = intl.formatMessage({ id: "forOrgUser" }); | |||||
| const indUserType = intl.formatMessage({ id: "forIndUser" }); | |||||
| return <> | |||||
| const orgHref = locale === "zh-HK" ? orgZh : locale === "en" ? orgEn : orgCn; | |||||
| const indHref = locale === "zh-HK" ? indZh : locale === "en" ? indEn : indCn; | |||||
| return ( | |||||
| <tr> | <tr> | ||||
| <td style={cellStyle}>{title}</td> | |||||
| <td style={cellStyle}><a href={locale=="zh-HK"?orgZh: locale=="en"?orgEn:orgCn} target='_brank'><DownloadIcon /></a></td> | |||||
| <td style={cellStyle}><a href={locale=="zh-HK"?indZh: locale=="en"?indEn:indCn} target='_brank'><DownloadIcon /></a></td> | |||||
| <td style={cellStyle}>{guideTitle}</td> | |||||
| <td style={cellStyle}> | |||||
| <a | |||||
| href={orgHref} | |||||
| target="_blank" | |||||
| rel="noopener noreferrer" | |||||
| aria-label={intl.formatMessage( | |||||
| { id: "downloadPdfAria" }, | |||||
| { guide: guideTitle, userType: orgUserType } | |||||
| )} | |||||
| > | |||||
| <DownloadIcon aria-hidden="true" focusable="false" /> | |||||
| </a> | |||||
| </td> | |||||
| <td style={cellStyle}> | |||||
| <a | |||||
| href={indHref} | |||||
| target="_blank" | |||||
| rel="noopener noreferrer" | |||||
| aria-label={intl.formatMessage( | |||||
| { id: "downloadPdfAria" }, | |||||
| { guide: guideTitle, userType: indUserType } | |||||
| )} | |||||
| > | |||||
| <DownloadIcon aria-hidden="true" focusable="false" /> | |||||
| </a> | |||||
| </td> | |||||
| </tr> | </tr> | ||||
| </> | |||||
| ; | |||||
| } | |||||
| ); | |||||
| }; | |||||
| const pnspsurl = "https://"+window.location.hostname; | const pnspsurl = "https://"+window.location.hostname; | ||||
| @@ -8,7 +8,12 @@ | |||||
| "datetimeStrFormat": "DD MMMM YYYY HH:mm:ss", | "datetimeStrFormat": "DD MMMM YYYY HH:mm:ss", | ||||
| "paymentMethodDatetimeStrFormat": "DD MMMM YYYY h:mm a", | "paymentMethodDatetimeStrFormat": "DD MMMM YYYY h:mm a", | ||||
| "datetimeFormate": "DD MMMM YYYY h:mm a", | "datetimeFormate": "DD MMMM YYYY h:mm a", | ||||
| "bhkLogoAlt": "Brand Hong Kong logo", | |||||
| "wcagAaAlt": "Level AA conformance, W3C WAI Web Content Accessibility Guidelines 2.0", | |||||
| "downloadPdfAria": "Download PDF: {guide} ({userType})", | |||||
| "captchaPlayAudio": "Play audio CAPTCHA", | |||||
| "PNSPS": "PNSPS", | "PNSPS": "PNSPS", | ||||
| "PNSPS_fullname": "Public Notice Submission and Payment System", | "PNSPS_fullname": "Public Notice Submission and Payment System", | ||||
| "HKSARGOV": "The Government of the Hong Kong Special Administrative Region", | "HKSARGOV": "The Government of the Hong Kong Special Administrative Region", | ||||
| @@ -9,6 +9,11 @@ | |||||
| "paymentMethodDatetimeStrFormat": "YYYY年MM月DD日 ah时mm分", | "paymentMethodDatetimeStrFormat": "YYYY年MM月DD日 ah时mm分", | ||||
| "datetimeFormate": "YYYY年MM月DD日 ah时mm分", | "datetimeFormate": "YYYY年MM月DD日 ah时mm分", | ||||
| "bhkLogoAlt": "香港品牌标志", | |||||
| "wcagAaAlt": "符合 WCAG 2.0 AA 级别(W3C WAI 网页内容无障碍指引)", | |||||
| "downloadPdfAria": "下载 PDF:{guide}({userType})", | |||||
| "captchaPlayAudio": "播放语音验证码", | |||||
| "PNSPS": "宪报公共启事提交及缴费系统", | "PNSPS": "宪报公共启事提交及缴费系统", | ||||
| "PNSPS_fullname": "公共启事提交及缴费系统", | "PNSPS_fullname": "公共启事提交及缴费系统", | ||||
| "HKSARGOV": "香港特别行政区政府", | "HKSARGOV": "香港特别行政区政府", | ||||
| @@ -8,6 +8,11 @@ | |||||
| "datetimeStrFormat": "YYYY年MM月DD日 HH:mm:ss", | "datetimeStrFormat": "YYYY年MM月DD日 HH:mm:ss", | ||||
| "paymentMethodDatetimeStrFormat": "YYYY年MM月DD日 ah時mm分", | "paymentMethodDatetimeStrFormat": "YYYY年MM月DD日 ah時mm分", | ||||
| "datetimeFormate": "YYYY年MM月DD日 ah時mm分", | "datetimeFormate": "YYYY年MM月DD日 ah時mm分", | ||||
| "bhkLogoAlt": "香港品牌標誌", | |||||
| "wcagAaAlt": "符合 WCAG 2.0 AA 級別(W3C WAI 網頁內容無障礙指引)", | |||||
| "downloadPdfAria": "下載 PDF:{guide}({userType})", | |||||
| "captchaPlayAudio": "播放語音驗證碼", | |||||
| "PNSPS": "憲報公共啟事提交及繳費系統", | "PNSPS": "憲報公共啟事提交及繳費系統", | ||||
| "PNSPS_fullname": "公共啟事提交及繳費系統", | "PNSPS_fullname": "公共啟事提交及繳費系統", | ||||
| @@ -94,6 +94,9 @@ export const POST_CAPTCHA = apiPath+'/captcha'; | |||||
| export const GET_CONTENT = apiPath+'/getContent'; | export const GET_CONTENT = apiPath+'/getContent'; | ||||
| export const POST_VERIFY_CAPTCHA = apiPath+'/verifyCaptcha'; | export const POST_VERIFY_CAPTCHA = apiPath+'/verifyCaptcha'; | ||||
| export const GET_COMBO = apiPath+'/combo-data'; | export const GET_COMBO = apiPath+'/combo-data'; | ||||
| export const POST_CAPTCHA_AUDIO = apiPath+'/captcha/audio'; | |||||
| //register | //register | ||||
| export const POST_PUBLIC_USER_REGISTER = apiPath+'/user/register'; | export const POST_PUBLIC_USER_REGISTER = apiPath+'/user/register'; | ||||