@@ -26,7 +26,7 @@ | |||
text-decoration: none; | |||
font-size: 1.2rem; | |||
font-weight: 600; | |||
font-family: 微軟正黑體; | |||
/* font-family: 微軟正黑體; */ | |||
color: black; | |||
transition: 0.3s ease-in-out; | |||
} | |||
@@ -76,7 +76,7 @@ | |||
font-weight: 600; | |||
color: #0C489E; | |||
transition: 0.3s ease-in-out; | |||
font-family: 微軟正黑體; | |||
/* font-family: 微軟正黑體; */ | |||
text-align: center; | |||
} | |||
#mobileTitle{ | |||
@@ -85,13 +85,13 @@ | |||
font-weight: 600; | |||
color: #0C489E; | |||
transition: 0.3s ease-in-out; | |||
font-family: 微軟正黑體; | |||
/* font-family: 微軟正黑體; */ | |||
text-align: center; | |||
} | |||
#sidebar{ | |||
font-size: 1.3rem; | |||
font-weight: 600; | |||
font-family: 微軟正黑體; | |||
/* font-family: 微軟正黑體; */ | |||
} | |||
#sidebartop{ | |||
align-items: center; | |||
@@ -115,7 +115,7 @@ | |||
text-decoration: none; | |||
font-size: 1.3rem; | |||
font-weight: 600; | |||
font-family: 微軟正黑體; | |||
/* font-family: 微軟正黑體; */ | |||
color: black; | |||
transition: 0.3s ease-in-out; | |||
} | |||
@@ -1,7 +1,20 @@ | |||
body{ | |||
@import url('https://fonts.googleapis.com/css2?family=Noto+Sans+HK|Noto+Sans+SC&display=swap'); | |||
@import url('https://fonts.googleapis.com/css2?family=Noto+Sans+SC&display=swap'); | |||
html, | |||
body, | |||
#root, | |||
.app, | |||
.content { | |||
height: 100%; | |||
width: 100%; | |||
font-family: "Noto Sans HK", "Noto Sans SC"; | |||
} | |||
/* body{ | |||
padding-top: 53px; | |||
font-family: 微軟正黑體; | |||
} | |||
} */ | |||
/* main{ | |||
padding-top: 43px; | |||
} */ |
@@ -13,9 +13,38 @@ export const hostPath = `http://${hostname}:${hostPort}`; | |||
export const apiPath = `${hostPath}/api`; | |||
// export const apiPath = `/api`; | |||
export const paymentPath = `http://pnspsdev.gld.gov.hk/payment`; | |||
export const iAmSmartPath = `https://apigw-isit.staging-eid.gov.hk`; | |||
export const clientId = "cf61fa7c121e4869966f69c8694b1cd2"; | |||
export const getBowerType=()=>{ | |||
console.log(navigator.userAgent) | |||
// const regex = /Mobi|Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Mi|huawei|Opera Mini|SAMSUNG|Samsung|SGH-[I|N|T]|GT-[I|N]|SM-[A|N|P|T|Z]|SHV-E|SCH-[I|J|R|S]|SPH-L/i; | |||
// if(!regex.test(navigator.userAgent)) | |||
// clientId : cf61fa7c121e4869966f69c8694b1cd2 | |||
if (navigator.userAgent.indexOf("Edg") != -1) { | |||
if(navigator.userAgent.match(/Android/i)) return "Android_Edge" | |||
if(navigator.userAgent.match(/iPhone|iPad|iPod/i)) return "iOS_Edge" | |||
return "PC_Browser" | |||
}else if(navigator.userAgent.indexOf("Chrome") != -1){ | |||
if(navigator.userAgent.match(/Android/i)) return "Android_Chrome" | |||
if(navigator.userAgent.match(/iPhone|iPad|iPod/i)) return "iOS_Chrome" | |||
return "PC_Browser" | |||
}else if(navigator.userAgent.indexOf("Safari") != -1){ | |||
if(navigator.userAgent.match(/iPhone|iPad|iPod/i)) return "iOS_Safari" | |||
return "PC_Browser" | |||
}else if(navigator.userAgent.indexOf("Firefox") != -1){ | |||
if(navigator.userAgent.match(/Android/i)) return "Android_Firefox" | |||
if(navigator.userAgent.match(/iPhone|iPad|iPod/i)) return "iOS_Firefox" | |||
return "PC_Browser" | |||
}else if(navigator.userAgent.match(/SAMSUNG|Samsung|SGH-[I|N|T]|GT-[I|N]|SM-[A|N|P|T|Z]|SHV-E|SCH-[I|J|R|S]|SPH-L/i)){ | |||
return "Android_Samsung" | |||
}else if(navigator.userAgent.match(/huawei/i)){ | |||
return "Android_Huawei" | |||
}else if(navigator.userAgent.match(/Mi/i)){ | |||
return "Android_Xiaomi" | |||
} | |||
return "PC_Browser"; | |||
} | |||
@@ -1,6 +1,7 @@ | |||
import { StrictMode } from 'react'; | |||
import { createRoot } from 'react-dom/client'; | |||
import { BrowserRouter } from 'react-router-dom'; | |||
import "./assets/style/styles.css" | |||
// scroll bar | |||
import 'simplebar/src/simplebar.css'; | |||
@@ -109,7 +109,7 @@ const Profile = () => { | |||
> | |||
<Stack direction="row" alignItems="center" sx={{ p: 0.5 }}> | |||
<AccountCircleIcon style={{ color: 'black' }} alt="profile user" src={avatar1} sx={{ width: 32, height: 32 }} /> | |||
<Typography style={{ color: 'black',fontFamily: "微軟正黑體", fontSize: "1.2rem" }} variant="subtitle1">{userData == null ? "" : (userData.fullenName?userData.fullenName: userData.fullchName)}</Typography> | |||
<Typography style={{ color: 'black', fontSize: "1.2rem" }} variant="subtitle1">{userData == null ? "" : (userData.fullenName?userData.fullenName: userData.fullchName)}</Typography> | |||
</Stack> | |||
</ButtonBase> | |||
<Popper | |||
@@ -152,7 +152,7 @@ const Profile = () => { | |||
<Stack direction="row" spacing={1.25} alignItems="center"> | |||
<AccountCircleIcon style={{ color: 'black' }} alt="profile user" src={avatar1} sx={{ width: 32, height: 32 }} /> | |||
<Stack> | |||
<Typography style={{ color: 'black',fontFamily: "微軟正黑體", fontSize: "1.2rem" }} variant="subtitle1">{userData == null ? "" : (userData.fullenName?userData.fullenName: userData.fullchName)}</Typography> | |||
<Typography style={{ color: 'black', fontSize: "1.2rem" }} variant="subtitle1">{userData == null ? "" : (userData.fullenName?userData.fullenName: userData.fullchName)}</Typography> | |||
{/* <Typography variant="body2" color="textSecondary"> | |||
{userData == null ? "" : userData.fullenName} | |||
</Typography> */} | |||
@@ -10,6 +10,7 @@ import { | |||
FormLabel, | |||
Button | |||
} from '@mui/material'; | |||
import * as UrlUtils from "utils/ApiPathConst"; | |||
import * as HttpUtils from "utils/HttpUtils"; | |||
import MainCard from "components/MainCard"; | |||
@@ -20,8 +21,6 @@ import { useNavigate } from "react-router-dom"; | |||
import Loadable from 'components/Loadable'; | |||
import { notifySaveSuccess } from 'utils/CommonFunction'; | |||
const UploadFileTable = Loadable(React.lazy(() => import('./UploadFileTable'))); | |||
// ==============================|| DASHBOARD - DEFAULT ||============================== // | |||
const FormPanel = ({ formData }) => { | |||
@@ -239,12 +238,13 @@ const FormPanel = ({ formData }) => { | |||
size="small" | |||
type="text" | |||
onChange={(event) => { | |||
const value = event.target.value; | |||
formik.setFieldValue("length", value); | |||
formik.setFieldValue("fee", 6552 * value); | |||
const re = /^[0-9\b]+$/; | |||
if (event.target.value === '' || re.test(event.target.value)) { | |||
const value = event.target.value; | |||
formik.setFieldValue("length", value); | |||
formik.setFieldValue("fee", 6552 * value); | |||
} | |||
}} | |||
name="noOfPages" | |||
value={formik.values["noOfPages"]} | |||
variant="outlined" | |||
sx={ | |||
{ | |||
@@ -275,9 +275,13 @@ const FormPanel = ({ formData }) => { | |||
size="small" | |||
type="text" | |||
onChange={(event) => { | |||
const value = event.target.value; | |||
formik.setFieldValue("length", value); | |||
formik.setFieldValue("fee", columnPrice.value * value); | |||
const re = /^[0-9\b]+$/; | |||
if (event.target.value === '' || re.test(event.target.value)) { | |||
const value = event.target.value; | |||
formik.setFieldValue("length", value); | |||
formik.setFieldValue("fee", columnPrice.value * value); | |||
} | |||
}} | |||
name="length" | |||
value={formik.values["length"]} | |||
@@ -204,19 +204,20 @@ const ApplicationDetailCard = ({ formData, }) => { | |||
<Grid container alignItems={"center"}> | |||
<Grid item xs={12} md={12} lg={12} | |||
sx={{ display: 'flex', alignItems: 'center' }}> | |||
<Typography variant="h5">繳費及返稿最後限期:</Typography> | |||
<Typography variant="h5" display="inline"><Typography variant="h5" style={{color:'red'}} display="inline">繳費及</Typography>返稿最後限期:</Typography> | |||
</Grid> | |||
<Grid item xs={12} md={12} lg={12} sx={{ mb: 4, display: 'flex', alignItems: 'center' }}> | |||
<Typography variant="h5">{DateUtils.dateStr_Cht(data.returnBeforeDate)} 下午 2:00前</Typography> | |||
<Typography variant="h5"> {DateUtils.dateStr_Cht(data.returnBeforeDate)} 下午 2:00前</Typography> | |||
</Grid> | |||
<Grid item xs={12} md={3} lg={3} | |||
sx={{ mb: 1, display: 'flex', alignItems: 'center' }}> | |||
<Typography variant="h5">應繳費用:</Typography> | |||
</Grid> | |||
<Grid item xs={12} md={9} lg={9} sx={{ mb: 1, display: 'flex', alignItems: 'center' }}> | |||
<Typography variant="h5" style={{ color: "blue", fontWeight: "bold", }}>{FormatUtils.currencyFormat(data.fee)}</Typography> | |||
<Typography variant="h2" style={{ color: "#0049B8", fontWeight: "bold", }}>{FormatUtils.currencyFormat(data.fee)}</Typography> | |||
</Grid> | |||
<Grid item xs={12} md={12} lg={12} sx={{ mb: 4, display: 'flex', alignItems: 'center' }}> | |||
<Grid item xs={0} md={3} lg={3} sx={{ mb: 4, display: 'flex', alignItems: 'center' }}></Grid> | |||
<Grid item xs={12} md={9} lg={9} sx={{ mb: 4, display: 'flex', alignItems: 'center' }}> | |||
{ | |||
formik.values.groupType == "A" | |||
? | |||
@@ -91,7 +91,7 @@ const SearchPublicNoticeForm = ({ applySearch, orgComboData, searchCriteria, iss | |||
> | |||
<form onSubmit={handleSubmit(onSubmit)}> | |||
<Grid container sx={{ backgroundColor: '#ffffff', ml: 2, mt: 3, mb: 3 }} width="98%"> | |||
<Grid container sx={{ backgroundColor: '#ffffff', ml: 2 }} width="98%"> | |||
{/*row 1*/} | |||
<CardContent sx={{ px: 2.5, pt: 3 }}> | |||
@@ -282,7 +282,7 @@ const SearchPublicNoticeForm = ({ applySearch, orgComboData, searchCriteria, iss | |||
{/*last row*/} | |||
<Grid container maxWidth justifyContent="flex-end"> | |||
<Grid item sx={{ ml: 3, mr: 3, mb: 3, mt: 3 }}> | |||
<Grid item sx={{ ml: 3, mb: 3, mt: 3 }}> | |||
<Button | |||
size="large" | |||
variant="contained" | |||
@@ -295,7 +295,7 @@ const SearchPublicNoticeForm = ({ applySearch, orgComboData, searchCriteria, iss | |||
</Button> | |||
</Grid> | |||
<Grid item sx={{ ml: 3, mr: 3, mb: 3, mt: 3 }}> | |||
<Grid item sx={{ ml: 3, mb: 3, mt: 3 }}> | |||
<Button | |||
size="large" | |||
variant="contained" | |||
@@ -37,7 +37,8 @@ export default function SearchPublicNoticeTable({ recordList }) { | |||
navigate('/proof/reply/' + params.row.id); | |||
}; | |||
const getGroupTitle = (title) => { | |||
/*eslint no-irregular-whitespace: ["error", { "skipComments": true }]*/ | |||
/*const getGroupTitle = (title) => { | |||
switch (title) { | |||
case 'Private Bill': | |||
return "私人帳單"; | |||
@@ -52,9 +53,8 @@ export default function SearchPublicNoticeTable({ recordList }) { | |||
default: | |||
return title; | |||
} | |||
} | |||
}*/ | |||
const columns = [ | |||
{ | |||
field: 'actions', | |||
@@ -68,17 +68,17 @@ export default function SearchPublicNoticeTable({ recordList }) { | |||
{ | |||
id: 'appId', | |||
field: 'appId', | |||
headerName: '申請編號 / 憲報編號 / 憲報期數', | |||
headerName: '申請編號 / 憲報期數', | |||
flex: 1, | |||
renderCell: (params) => { | |||
let appNo = params.row.appNo; | |||
let code = params.row.groupNo; | |||
// let code = params.row.groupNo; | |||
let isssue = params.row.issueYear | |||
+ " Vol. " + FormatUtils.zeroPad(params.row.issueVolume, 3) | |||
+ ", No. " + FormatUtils.zeroPad(params.row.issueNo, 2) | |||
+ ", " + DateUtils.dateFormat(params.row.issueDate, "D MMM YYYY (ddd)"); | |||
return <div style={{ margin: 4 }}>{appNo}<br />{code}<br />{isssue}</div> | |||
return <div style={{ margin: 4 }}>{appNo}<br />{isssue}</div> | |||
}, | |||
}, | |||
{ | |||
@@ -110,15 +110,15 @@ export default function SearchPublicNoticeTable({ recordList }) { | |||
return params?.value ? DateUtils.datetimeStr(params?.value) : ""; | |||
} | |||
}, | |||
{ | |||
id: 'groupTitle', | |||
field: 'groupTitle', | |||
headerName: '憲報類型', | |||
flex: 1, | |||
valueGetter: (params) => { | |||
return getGroupTitle(params?.value); | |||
} | |||
}, | |||
// { | |||
// id: 'groupTitle', | |||
// field: 'groupTitle', | |||
// headerName: '憲報類型', | |||
// flex: 1, | |||
// valueGetter: (params) => { | |||
// return getGroupTitle(params?.value); | |||
// } | |||
// }, | |||
{ | |||
id: 'fee', | |||
field: 'fee', | |||
@@ -147,9 +147,9 @@ export default function SearchPublicNoticeTable({ recordList }) { | |||
paginationModel: { page: 0, pageSize: 10 }, | |||
}, | |||
}} | |||
getRowHeight={()=>"auto"} | |||
getRowHeight={() => "auto"} | |||
onRowDoubleClick={handleRowDoubleClick} | |||
/> | |||
</div> | |||
); | |||
} | |||
} |
@@ -154,7 +154,7 @@ const SearchPublicNoticeForm = ({ applySearch, searchCriteria, issueComboData | |||
/> | |||
</Grid> | |||
<Grid item xs={9} s={6} md={5} lg={3} sx={{ ml: 3, mr: 3, mb: 3 }}> | |||
{/* <Grid item xs={9} s={6} md={5} lg={3} sx={{ ml: 3, mr: 3, mb: 3 }}> | |||
<Autocomplete | |||
{...register("gazettGroup")} | |||
disablePortal | |||
@@ -175,7 +175,7 @@ const SearchPublicNoticeForm = ({ applySearch, searchCriteria, issueComboData | |||
/> | |||
)} | |||
/> | |||
</Grid> | |||
</Grid> */} | |||
<Grid item xs={9} s={6} md={5} lg={3} sx={{ ml: 3, mr: 3, mb: 3 }}> | |||
<TextField | |||
@@ -90,7 +90,7 @@ const PublicNoticeApplyForm = ({ loadedData, selections }) => { | |||
}, | |||
files: [attachment], | |||
onSuccess: function () { | |||
notifyActionSuccess('申請成功!') | |||
notifyActionSuccess('申請提交成功!') | |||
navigate("/publicNotice"); | |||
// location.reload(); | |||
} | |||
@@ -137,12 +137,13 @@ const ApplicationDetailCard = ( | |||
variant="contained" | |||
onClick={cancelledClick()} | |||
disabled={currentApplicationDetailData.status !== "submitted"} | |||
title={"取消"} | |||
sx={{ | |||
textTransform: 'capitalize', | |||
alignItems: 'end', | |||
backgroundColor: '#ffa733' | |||
}}> | |||
<CloseIcon /> | |||
<CloseIcon sx={{mb:0.5}}/> | |||
<Typography ml={1} variant="h5"> 取消</Typography> | |||
</Button> | |||
</Stack> | |||
@@ -480,7 +481,7 @@ const ApplicationDetailCard = ( | |||
</Grid> | |||
<Grid item xs={12} md={9} lg={9} sx={{ display: 'flex', alignItems: 'center' }}> | |||
<Grid container direction="row" justifyContent="flex-start"> | |||
<Grid item xs={12} md={5} lg={5} sx={{ display: 'flex', alignItems: 'center' }}> | |||
<Grid item xs={12} md={8} lg={8} sx={{ display: 'flex', alignItems: 'center' }}> | |||
<FormControl variant="outlined" fullWidth > | |||
<Typography | |||
fullWidth | |||
@@ -491,16 +492,18 @@ const ApplicationDetailCard = ( | |||
</Typography> | |||
</FormControl> | |||
</Grid> | |||
<Grid item md={2} lg={2}> | |||
<Grid item md={4} lg={4}> | |||
<Button | |||
size="small" | |||
variant="contained" | |||
onClick={onDownloadClick()} | |||
title="下載" | |||
style={{display:"flex-right"}} | |||
sx={{ | |||
textTransform: 'capitalize', | |||
alignItems: 'end', | |||
}}> | |||
<DownloadIcon /> | |||
<DownloadIcon sx={{mb: 0.5}}/> | |||
<Typography sx={{ml: 1}} variant="h5">下載</Typography> | |||
</Button> | |||
</Grid> | |||
</Grid> | |||
@@ -41,7 +41,7 @@ const UserSearchForm = ({ applySearch }) => { | |||
const temp = { | |||
username: data.userName, | |||
fullenName: data.fullenName, | |||
enName: data.fullenName, | |||
post: data.post, | |||
email: data.email, | |||
phone: data.phone, | |||
@@ -29,7 +29,7 @@ const UserSearchForm_Individual = ({ applySearch }) => { | |||
const temp = { | |||
username: data.userName, | |||
fullenName: data.fullenName, | |||
fullName: data.fullenName, | |||
email: data.email, | |||
phone: data.phone, | |||
accountFilter: accountFilter, | |||
@@ -44,8 +44,8 @@ const AuthWrapper = ({ children }) => ( | |||
alignItems="center" | |||
spacing={2}> | |||
<Grid item xs={12} md={8} lg={8} xl={9} sx={{ ml: 4, mt: 3 ,display: { xs: 'none', sm: 'block' }}}> | |||
<Typography style={{textAlign: "center",fontFamily: "微軟正黑體",fontSize: "1.8rem"}}>香港特別行政區政府</Typography> | |||
<Typography style={{textAlign: "center",fontFamily: "微軟正黑體",fontSize: "1.8rem",fontWeight:"bold"}}>憲報</Typography> | |||
<Typography style={{textAlign: "center",fontSize: "1.8rem"}}>香港特別行政區政府</Typography> | |||
<Typography style={{textAlign: "center",fontSize: "1.8rem",fontWeight:"bold"}}>憲報</Typography> | |||
</Grid> | |||
<Grid | |||
item | |||
@@ -2,13 +2,14 @@ | |||
// material-ui | |||
import { | |||
Dialog, DialogTitle, DialogContent, DialogActions, | |||
Dialog, DialogTitle, DialogContent, | |||
Link, Button, Card, Box, Grid | |||
} from '@mui/material'; | |||
import Typography from '@mui/material/Typography'; | |||
import iAmSmartICon from 'assets/images/icons/icon_iAmSmart.png'; | |||
import banner from 'assets/images/bg_ml.jpg'; | |||
import { Stack } from '../../../node_modules/@mui/material/index'; | |||
import { iAmSmartPath, clientId, getBowerType } from 'auth/utils' | |||
import * as React from 'react'; | |||
@@ -23,6 +24,19 @@ const RegisterCustom = () => { | |||
setIsPopUp(true); | |||
} | |||
const getQRWithIAmSmart = () => { | |||
let url = iAmSmartPath + "/api/v1/auth/getQR" | |||
+ "?clientID=" + clientId | |||
+ "&responseType=code" | |||
+"&source=" + getBowerType() | |||
+"&redirectURI=" | |||
+"&scope=eidapi_formFilling" | |||
+"&lang=zh-HK"//en-US, zh-HK, or zh-CN | |||
//+"&state=" | |||
+"&brokerPage=false" | |||
window.location.assign(url); | |||
} | |||
return ( | |||
<Stack justifyContent="center" sx={{ minHeight: '100vh', bgcolor: 'backgroundColor.default' }}> | |||
@@ -58,7 +72,7 @@ const RegisterCustom = () => { | |||
你可點擊「智方便」按鈕,系統會自動輸入個人資料,或自行輸入個人資料,以即時啟動憲報刊登公告帳戶。 | |||
<br />如欲使用「智方便」提供個人資料,請先下載「智方便」流動應用程式並登記成為「智方便」用戶。 | |||
</Typography> | |||
<Link href="#">了解更多</Link> | |||
<Link href="https://www.iamsmart.gov.hk/tc/">了解更多</Link> | |||
</Box> | |||
<Typography m={5}>或</Typography> | |||
@@ -105,29 +119,25 @@ const RegisterCustom = () => { | |||
<Typography style={{ padding: '4px' }}> | |||
- 身份證號碼 | |||
</Typography> | |||
<Typography style={{ padding: '4px' }}> | |||
- 性別 | |||
</Typography> | |||
</Grid> | |||
<Grid item xs={6} > | |||
<Typography style={{ padding: '4px' }}> | |||
- 中文姓名 | |||
</Typography> | |||
<Typography style={{ padding: '4px' }}> | |||
- 英文姓名 | |||
- 電郵地址 | |||
</Typography> | |||
<Typography style={{ padding: '4px' }}> | |||
- 身份證號碼 | |||
- 手機號碼 | |||
</Typography> | |||
<Typography style={{ padding: '4px' }}> | |||
- 性別 | |||
- 住宅地址 | |||
</Typography> | |||
</Grid> | |||
</Grid> | |||
</DialogContent> | |||
<DialogActions> | |||
<Button onClick={() => setIsPopUp(false)}>OK</Button> | |||
</DialogActions> | |||
<DialogContent align="right"> | |||
<Button variant="outlined" onClick={getQRWithIAmSmart} startIcon={<img src={iAmSmartICon} alt="iAM Smart" width="30" />}><Typography variant="h5">使用「智方便」自動填表</Typography></Button> | |||
<br /> | |||
<Link href="https://www.iamsmart.gov.hk/tc/">了解更多</Link> | |||
</DialogContent> | |||
</Dialog> | |||
</Stack> | |||
); | |||
@@ -0,0 +1,74 @@ | |||
// material-ui | |||
import { Button, Grid } from '@mui/material'; | |||
import { Link } from 'react-router-dom'; | |||
import Typography from '@mui/material/Typography'; | |||
// import iAmSmartICon from 'assets/images/icons/icon_iAmSmart.png'; | |||
// import banner from 'assets/images/bg_ml.jpg'; | |||
import { Stack } from '../../../node_modules/@mui/material/index'; | |||
import { useEffect, useState } from 'react'; | |||
import { useParams } from 'react-router-dom'; | |||
import axios from 'axios'; | |||
import { GET_VERIFY_USER_ACCOUNT } from 'utils/ApiPathConst'; | |||
import Loadable from 'components/Loadable'; | |||
import { lazy } from 'react'; | |||
const LoadingComponent = Loadable(lazy(() => import('../extra-pages/LoadingComponent'))); | |||
const AuthWrapper = Loadable(lazy(() => import('./AuthWrapperCustom'))); | |||
import CheckCircleOutlineIcon from '@mui/icons-material/CheckCircleOutline'; | |||
import CancelOutlinedIcon from '@mui/icons-material/CancelOutlined'; | |||
export default function Verify() { | |||
const [isLoading, setIsLoading] = useState(true) | |||
const [verifyState, setVerifyState] = useState(null) | |||
const params = useParams() | |||
const handleVerify = async () => { | |||
const response = await axios.get(GET_VERIFY_USER_ACCOUNT, { | |||
params: { | |||
email: decodeURIComponent(params.email), | |||
emailVerifyHash: decodeURIComponent(params.verifyCode) | |||
} | |||
}) | |||
if (response.status === 200 && response.data) { | |||
setVerifyState(true) | |||
} else { | |||
setVerifyState(false) | |||
} | |||
setIsLoading(false) | |||
} | |||
let enterUseEffect = false | |||
useEffect(() => { | |||
if (enterUseEffect) handleVerify() | |||
enterUseEffect = true | |||
}, []) | |||
return ( | |||
<Stack sx={{ width: '100%', fontSize: '2rem', paddingTop: '65px' }} alignItems="center"> | |||
<AuthWrapper> | |||
{isLoading || verifyState == null ? | |||
<LoadingComponent /> : | |||
<Grid item xs={12}> | |||
{verifyState ? | |||
// SUCCESS page | |||
<Stack mt={1} direction="column" justifyContent="flex-start" alignItems="center" spacing={2}> | |||
<CheckCircleOutlineIcon color="success" sx={{ width: "200px", height: "200px" }} /> | |||
<Typography display="inline" variant="h4">帳戶已成功驗證。</Typography> | |||
<Button variant="outlined" component={Link} to="/login" sx={{ fontSize: 20, height: '60px' }}><Typography variant="h5">返回登入頁面</Typography></Button> | |||
</Stack> | |||
: | |||
// ERROR page | |||
<Stack mt={1} direction="column" justifyContent="flex-start" alignItems="center" spacing={2}> | |||
{/* <Button disabled={true} hidden={true} variant="contained" type="submit" sx={{ fontSize: 12,height:'25px'}}>Submit</Button> */} | |||
<CancelOutlinedIcon color="error" sx={{ width: "200px", height: "200px" }} /> | |||
<Typography display="inline" variant="h4">驗證失敗,請聯絡相關的系統管理員協助。</Typography> | |||
<Button color="error" variant="outlined" component={Link} to="/login" sx={{ fontSize: 20, height: '60px' }}><Typography variant="h5">返回登入頁面</Typography></Button> | |||
</Stack> | |||
} | |||
</Grid> | |||
} | |||
</AuthWrapper> | |||
</Stack> | |||
) | |||
} |
@@ -19,41 +19,45 @@ import CancelOutlinedIcon from '@mui/icons-material/CancelOutlined'; | |||
const PasswordAlertDialog = (props) => { | |||
return ( | |||
<Dialog | |||
<Dialog | |||
open={props.open} | |||
onClose={props.handleClose} | |||
aria-labelledby="alert-dialog-title" | |||
aria-describedby="alert-dialog-description" | |||
> | |||
<DialogTitle id="alert-dialog-title"> | |||
<Stack mt={1} mr={4} direction="row" justifyContent="flex-start" alignItems="center" spacing={2}> | |||
<CancelOutlinedIcon color="error" sx={{width:"35px",height:"40px"}}/> | |||
{props.errorMassage==='ACCOUNT_LOCKED_ERROR'? | |||
<Stack direction="column"> | |||
<Typography display="inline"> | |||
帳戶將被封鎖 | |||
</Typography> | |||
<Typography display="inline"> | |||
帳戶連續五次登入錯誤,請與系統管理員聯絡 | |||
</Typography> | |||
</Stack>: | |||
<Typography display="inline"> | |||
用戶名或密碼錯誤 | |||
</Typography> | |||
} | |||
</Stack> | |||
</DialogTitle> | |||
<DialogContent> | |||
<DialogContentText id="alert-dialog-description"> | |||
{""} | |||
</DialogContentText> | |||
</DialogContent> | |||
<DialogActions> | |||
<Button variant="contained" color="error" onClick={props.handleClose} autoFocus> | |||
關閉 | |||
</Button> | |||
</DialogActions> | |||
</Dialog> | |||
> | |||
<DialogTitle id="alert-dialog-title"> | |||
<Stack mt={1} mr={4} direction="row" justifyContent="flex-start" alignItems="center" spacing={2}> | |||
<CancelOutlinedIcon color="error" sx={{ width: "35px", height: "40px" }} /> | |||
{props.errorMassage === 'ACCOUNT_LOCKED_ERROR' ? | |||
<Stack direction="column"> | |||
<Typography display="inline"> | |||
帳戶將被封鎖 | |||
</Typography> | |||
<Typography display="inline"> | |||
帳戶連續五次登入錯誤,請與系統管理員聯絡 | |||
</Typography> | |||
</Stack> : | |||
props.errorMassage === 'ACCOUNT_VERIFIED_ERROR' ? | |||
<Typography display="inline"> | |||
帳戶尚未驗證 | |||
</Typography> : | |||
<Typography display="inline"> | |||
用戶名或密碼錯誤 | |||
</Typography> | |||
} | |||
</Stack> | |||
</DialogTitle> | |||
<DialogContent> | |||
<DialogContentText id="alert-dialog-description"> | |||
{""} | |||
</DialogContentText> | |||
</DialogContent> | |||
<DialogActions> | |||
<Button variant="contained" color="error" onClick={props.handleClose} autoFocus> | |||
關閉 | |||
</Button> | |||
</DialogActions> | |||
</Dialog> | |||
); | |||
}; | |||
@@ -16,6 +16,7 @@ const IAmSmart_SuccessCallback = Loadable(lazy(() => import('pages/iAmSmart/Succ | |||
//TODO: this page for testing only, please remove at prod | |||
const TestMailPage = Loadable(lazy(() => import('pages/pnspsNotifyTest'))); | |||
const VerifyPage = Loadable(lazy(() => import('pages/authentication/Verify'))); | |||
// ==============================|| AUTH ROUTING ||============================== // | |||
@@ -54,6 +55,14 @@ const LoginRoutes = { | |||
{ | |||
path: 'iamsmart/logincallback', | |||
element: <IAmSmart_SuccessCallback/> | |||
}, | |||
{ | |||
path: 'testMailPage', | |||
element: <TestMailPage/> | |||
}, | |||
{ | |||
path: 'verify/:verifyCode/:email', | |||
element: <VerifyPage/> | |||
} | |||
] | |||
}; | |||
@@ -17,7 +17,7 @@ export default function ThemeCustomization({ children }) { | |||
const theme = Palette('light', 'default'); | |||
// eslint-disable-next-line react-hooks/exhaustive-deps | |||
const themeTypography = Typography(`微軟正黑體`); | |||
const themeTypography = Typography(``); | |||
const themeCustomShadows = useMemo(() => CustomShadows(theme), [theme]); | |||
const themeOptions = useMemo( | |||
@@ -45,6 +45,7 @@ export const POST_CAPTCHA = apiPath+'/captcha'; | |||
export const POST_PUBLIC_USER_REGISTER = apiPath+'/user/register'; | |||
export const GET_USERNAME = apiPath+'/user/username'; | |||
export const GET_USER_EMAIL = apiPath+'/user/email'; | |||
export const GET_VERIFY_USER_ACCOUNT = apiPath+'/user/verifyEmail'; | |||
//Public | |||
export const GET_PUBLIC_ORG_USER_LIST = apiPath+'/user/listOrg'; | |||