| @@ -2,6 +2,9 @@ | |||
| import { useMediaQuery, Container, Link, Typography, Stack } from '@mui/material'; | |||
| import bhkLogo from 'assets/images/BHK_logo_rgb_zh-hk.png'; | |||
| import {FormattedMessage} from "react-intl"; | |||
| import { | |||
| isGLDLoggedIn, | |||
| } from "utils/Utils"; | |||
| // ==============================|| FOOTER - AUTHENTICATION ||============================== // | |||
| const AuthFooter = () => { | |||
| @@ -42,14 +45,16 @@ const AuthFooter = () => { | |||
| </Typography> | |||
| </Stack> | |||
| <Stack direction={matchDownSM ? 'column' : 'row'} spacing={matchDownSM ? 1 : 3} textAlign={matchDownSM ? 'center' : 'inherit'} justifyContent={matchDownSM?"center":"flex-end"}> | |||
| <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> | |||
| {!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" | |||
| @@ -221,7 +221,7 @@ const MultiPaymentWindow = (props) => { | |||
| const readyToPayment = appIdList.every(appId => combinedAppIdsArray.includes(appId)); | |||
| if (readyToPayment){ | |||
| // props.setConfirmPayment(true); | |||
| props.setConfirmPayment(true); | |||
| return; | |||
| }else{ | |||
| const appIdsInData = appIdList.filter(appId => !combinedAppIdsArray.some(item => item === appId)); | |||
| @@ -0,0 +1,81 @@ | |||
| // material-ui | |||
| import * as React from 'react'; | |||
| import {FiDataGrid} from "components/FiDataGrid"; | |||
| import { | |||
| // Button, | |||
| // Typography, | |||
| useMediaQuery | |||
| } from '@mui/material'; | |||
| import * as DateUtils from "utils/DateUtils" | |||
| // import {useNavigate} from "react-router-dom"; | |||
| // import { | |||
| // isORGLoggedIn, | |||
| // } from "utils/Utils"; | |||
| import {useTheme} from "@emotion/react"; | |||
| // import {getStatusIntl} from "utils/statusUtils/PublicNoteStatusUtils"; | |||
| // import { | |||
| // FormattedMessage, | |||
| // useIntl} from "react-intl"; | |||
| // ==============================|| EVENT TABLE ||============================== // | |||
| export default function LoginGrid({rows}) { | |||
| // const navigate = useNavigate() | |||
| const theme = useTheme(); | |||
| const isMdOrLg = useMediaQuery(theme.breakpoints.up('md')); | |||
| // const intl = useIntl(); | |||
| // const handleDetailClick = (params) => () => { | |||
| // navigate('/publicNotice/'+ params.id); | |||
| // }; | |||
| // const remarkHeadername = rows.orgId===null?"我的備註":"Care Of / 我的備註" | |||
| const columns = [ | |||
| { | |||
| id: 'loginTime', | |||
| field: 'loginTime', | |||
| headerName: "Date Time", | |||
| width: isMdOrLg ? 'auto' : 160, | |||
| flex: isMdOrLg ? 1 : undefined, | |||
| valueGetter:(params)=>{ | |||
| return DateUtils.datetimeStr(params?.value); | |||
| } | |||
| }, | |||
| { | |||
| id: 'result', | |||
| field: 'result', | |||
| headerName: 'Result', | |||
| width: isMdOrLg ? 'auto' : 300, | |||
| flex: isMdOrLg ? 2 : undefined, | |||
| valueGetter:(params)=>{ | |||
| let resultMessage = ""; | |||
| if (params.row.success>0){ | |||
| resultMessage="Success" | |||
| } | |||
| if (params.row.success==0){ | |||
| resultMessage="Fail" | |||
| } | |||
| if (params.row.success<0){ | |||
| resultMessage= params.row.actionType + " by " + (params.row.modifiedBy == null?"multiple times failed login attempt.":params.row.modifiedBy) | |||
| } | |||
| return resultMessage; | |||
| } | |||
| }, | |||
| ]; | |||
| // function handleRowDoubleClick(params) { | |||
| // navigate('/publicNotice/'+ params.id); | |||
| // } | |||
| return ( | |||
| <div style={{minHeight: 200, height:"100%", width: '100%', padding: 4}}> | |||
| <FiDataGrid | |||
| rows={rows} | |||
| columns={columns} | |||
| customPageSize={10} | |||
| // onRowDoubleClick={handleRowDoubleClick} | |||
| getRowHeight={() => 'auto'} | |||
| /> | |||
| </div> | |||
| ); | |||
| } | |||
| @@ -15,7 +15,7 @@ const LoadingComponent = Loadable(lazy(() => import('../../extra-pages/LoadingCo | |||
| // ==============================|| EVENT TABLE ||============================== // | |||
| export default function UserAuthTable({setSelectedRow, userAuth,isNewRecord}) { | |||
| export default function UserAuthTable({setSelectedRow, userAuth,isNewRecord,editMode}) { | |||
| const [authData, setAuthData] = useState([]); | |||
| const [onReady, setOnReady] = useState(false); | |||
| const [currentSelectedRow, setCurrentSelectedRow] = useState(userAuth); | |||
| @@ -37,7 +37,8 @@ export default function UserAuthTable({setSelectedRow, userAuth,isNewRecord}) { | |||
| axios.get(`${apiPath}${GET_AUTH_LIST}`) | |||
| .then((response) => { | |||
| if (response.status === 200) { | |||
| setAuthData(response.data.records); | |||
| const data = response.data.records | |||
| setAuthData(data); | |||
| } | |||
| }) | |||
| .catch(error => { | |||
| @@ -79,7 +80,7 @@ export default function UserAuthTable({setSelectedRow, userAuth,isNewRecord}) { | |||
| editMode="row" | |||
| initialState={{ | |||
| pagination: { | |||
| paginationModel: {page: 0, pageSize: 20}, | |||
| paginationModel: {page: 0, pageSize: 10}, | |||
| }, | |||
| }} | |||
| pageSizeOptions={[10, 20, 30]} | |||
| @@ -87,8 +88,10 @@ export default function UserAuthTable({setSelectedRow, userAuth,isNewRecord}) { | |||
| rowSelectionModel={currentSelectedRow} | |||
| onRowSelectionModelChange={(ids) => { | |||
| // console.log(ids); | |||
| setSelectedRow(ids); | |||
| setCurrentSelectedRow(ids); | |||
| if (editMode){ | |||
| setSelectedRow(ids); | |||
| setCurrentSelectedRow(ids); | |||
| } | |||
| }} | |||
| autoHeight | |||
| sx={_sx} | |||
| @@ -16,7 +16,7 @@ const LoadingComponent = Loadable(lazy(() => import('../../extra-pages/LoadingCo | |||
| // ==============================|| DASHBOARD - DEFAULT ||============================== // | |||
| const UserAuthorityCard = ({ isCollectData, updateUserAuthList, userData, isNewRecord }) => { | |||
| const UserAuthorityCard = ({ isCollectData, updateUserAuthList, userData, isNewRecord, editMode}) => { | |||
| const [currentAuthData, setCurrentAuthData] = React.useState({}); | |||
| const [onReady, setOnReady] = useState(false); | |||
| const [selectedRow, setSelectedRow] = useState([]); | |||
| @@ -59,6 +59,7 @@ const UserAuthorityCard = ({ isCollectData, updateUserAuthList, userData, isNewR | |||
| userAuth={userData.authIds} | |||
| setSelectedRow={setSelectedRow} | |||
| isNewRecord={isNewRecord} | |||
| editMode={editMode} | |||
| /> | |||
| <br/> | |||
| </MainCard> | |||
| @@ -15,7 +15,7 @@ const LoadingComponent = Loadable(lazy(() => import('../../extra-pages/LoadingCo | |||
| // ==============================|| DASHBOARD - DEFAULT ||============================== // | |||
| const UserGroupCard = ({isCollectData, updateUserGroupList,userData,isNewRecord}) => { | |||
| const UserGroupCard = ({isCollectData, updateUserGroupList,userData,isNewRecord,editMode}) => { | |||
| const [currentUserData, setCurrentUserData] = React.useState({}); | |||
| const [onReady, setOnReady] = useState(false); | |||
| const [selectedRow, setSelectedRow] = useState([]); | |||
| @@ -58,6 +58,7 @@ const UserGroupCard = ({isCollectData, updateUserGroupList,userData,isNewRecord} | |||
| userGroup={userData.groupIds} | |||
| setSelectedRow={setSelectedRow} | |||
| isNewRecord={isNewRecord} | |||
| editMode={editMode} | |||
| /> | |||
| <br/> | |||
| </MainCard> | |||
| @@ -13,7 +13,7 @@ const LoadingComponent = Loadable(lazy(() => import('../../extra-pages/LoadingCo | |||
| // ==============================|| EVENT TABLE ||============================== // | |||
| export default function UserGroupTable({setSelectedRow, userGroup,isNewRecord}) { | |||
| export default function UserGroupTable({setSelectedRow, userGroup,isNewRecord,editMode}) { | |||
| const [groupData, setGroupData] = useState([]); | |||
| const [onReady, setOnReady] = useState(false); | |||
| const [currentSelectedRow, setCurrentSelectedRow] = useState(userGroup); | |||
| @@ -85,8 +85,10 @@ export default function UserGroupTable({setSelectedRow, userGroup,isNewRecord}) | |||
| rowSelectionModel={currentSelectedRow} | |||
| onRowSelectionModelChange={(ids) => { | |||
| // console.log(ids); | |||
| setSelectedRow(ids); | |||
| setCurrentSelectedRow(ids); | |||
| if (editMode){ | |||
| setSelectedRow(ids); | |||
| setCurrentSelectedRow(ids); | |||
| } | |||
| }} | |||
| autoHeight | |||
| sx={_sx} | |||
| @@ -22,7 +22,7 @@ import VisibilityOff from '@mui/icons-material/VisibilityOff'; | |||
| import { useIntl } from "react-intl"; | |||
| // ==============================|| DASHBOARD - DEFAULT ||============================== // | |||
| const UserInformationCard = ({ isCollectData, updateUserObject, userData, isNewRecord }) => { | |||
| const UserInformationCard = ({ isCollectData, updateUserObject, userData, isNewRecord, editMode}) => { | |||
| //const params = useParams(); | |||
| const [currentUserData, setCurrentUserData] = React.useState({}); | |||
| const [locked, setLocked] = useState(false); | |||
| @@ -56,12 +56,12 @@ const UserInformationCard = ({ isCollectData, updateUserObject, userData, isNewR | |||
| }, [currentUserData]); | |||
| useEffect(() => { | |||
| console.log("num"); | |||
| console.log(pw.match(/^(?=.*[0-9])/)); | |||
| console.log("small char"); | |||
| console.log(pw.match(/^(?=.*[a-z])/)); | |||
| console.log("SpecialChar"); | |||
| console.log(pw.match(/^(?=.*[!@#%&]?)/)); | |||
| // console.log("num"); | |||
| // console.log(pw.match(/^(?=.*[0-9])/)); | |||
| // console.log("small char"); | |||
| // console.log(pw.match(/^(?=.*[a-z])/)); | |||
| // console.log("SpecialChar"); | |||
| // console.log(pw.match(/^(?=.*[!@#%&]?)/)); | |||
| setPwErr(''); | |||
| if (pw.length == 0) { | |||
| @@ -205,6 +205,7 @@ const UserInformationCard = ({ isCollectData, updateUserObject, userData, isNewR | |||
| value: currentUserData.enName, | |||
| })} | |||
| id='enName' | |||
| disabled={!editMode} | |||
| /> | |||
| </FormControl> | |||
| </Grid> | |||
| @@ -228,6 +229,7 @@ const UserInformationCard = ({ isCollectData, updateUserObject, userData, isNewR | |||
| value: currentUserData.post, | |||
| })} | |||
| id='post' | |||
| disabled={!editMode} | |||
| /> | |||
| </FormControl> | |||
| </Grid> | |||
| @@ -251,6 +253,7 @@ const UserInformationCard = ({ isCollectData, updateUserObject, userData, isNewR | |||
| value: currentUserData.emailAddress, | |||
| })} | |||
| id='emailAddress' | |||
| disabled={!editMode} | |||
| /> | |||
| </FormControl> | |||
| </Grid> | |||
| @@ -294,6 +297,7 @@ const UserInformationCard = ({ isCollectData, updateUserObject, userData, isNewR | |||
| name="checked" | |||
| color="primary" | |||
| size="small" | |||
| disabled={!editMode} | |||
| /> | |||
| </Grid> | |||
| </Grid> | |||
| @@ -10,7 +10,8 @@ import { useEffect, useState } from "react"; | |||
| import * as React from "react"; | |||
| import axios from "axios"; | |||
| import { useNavigate, useParams } from "react-router-dom"; | |||
| import { GLD_USER_PATH, DELETE_USER, POST_ADMIN_USER_REGISTER } from "utils/ApiPathConst"; | |||
| import { GLD_USER_PATH, DELETE_USER, POST_ADMIN_USER_REGISTER,GET_LOGIN_LOG_LIST } from "utils/ApiPathConst"; | |||
| import * as HttpUtils from "utils/HttpUtils"; | |||
| import Loadable from 'components/Loadable'; | |||
| import { lazy } from 'react'; | |||
| @@ -18,6 +19,10 @@ const UserInformationCard = Loadable(lazy(() => import('./UserInformationCard')) | |||
| const LoadingComponent = Loadable(lazy(() => import('../../extra-pages/LoadingComponent'))); | |||
| const UserGroupCard = Loadable(lazy(() => import('./UserGroupCard'))); | |||
| const UserAuthorityCard = Loadable(lazy(() => import('./UserAuthorityCard'))); | |||
| const LoginGrid = Loadable(React.lazy(() => import('./LoginGrid'))); | |||
| import {ThemeProvider} from "@emotion/react"; | |||
| import {PNSPS_BUTTON_THEME} from "themes/buttonConst"; | |||
| import { | |||
| GeneralConfirmWindow, | |||
| getDeletedRecordWithRefList, | |||
| @@ -51,7 +56,8 @@ const UserMaintainPage = () => { | |||
| const [userConfirm, setUserConfirm] = useState(false); | |||
| const [isNewRecord, setIsNewRecord] = useState(false); | |||
| const [refUserData, setRefUserData] = React.useState({}); | |||
| const [loginLogData, setLoginLogData] = React.useState([]) | |||
| const [editMode, setEditMode] = React.useState(false); | |||
| function updateUserObject(userData) { | |||
| setEditedCustomerData(userData); | |||
| @@ -99,17 +105,7 @@ const UserMaintainPage = () => { | |||
| useEffect(() => { | |||
| if (params.id > 0) { | |||
| axios.get(`${GLD_USER_PATH}/${params.id}`) | |||
| .then((response) => { | |||
| if (response.status === 200) { | |||
| setRefUserData(response.data); | |||
| setUserData(response.data); | |||
| } | |||
| }) | |||
| .catch(error => { | |||
| console.log(error); | |||
| return false; | |||
| }); | |||
| loadData() | |||
| } | |||
| else { | |||
| setUserData( | |||
| @@ -131,7 +127,25 @@ const UserMaintainPage = () => { | |||
| }, []); | |||
| const loadData = () => { | |||
| setOnReady(false); | |||
| setEditMode(false); | |||
| axios.get(`${GLD_USER_PATH}/${params.id}`) | |||
| .then((response) => { | |||
| if (response.status === 200) { | |||
| setRefUserData(response.data); | |||
| setUserData(response.data); | |||
| getLoginLogList() | |||
| } | |||
| }) | |||
| .catch(error => { | |||
| console.log(error); | |||
| return false; | |||
| }); | |||
| } | |||
| useEffect(() => { | |||
| // if (Object.keys(userData).length > 0 && userData !== undefined) { | |||
| if (Object.keys(userData).length > 0 && userData !== undefined) { | |||
| setOnReady(true); | |||
| } | |||
| @@ -201,6 +215,23 @@ const UserMaintainPage = () => { | |||
| setUserConfirm(false); | |||
| }, [editedCustomerData, userGroupData, userAuthData]); | |||
| const getLoginLogList = () => { | |||
| HttpUtils.get({ | |||
| url: `${GET_LOGIN_LOG_LIST}`, | |||
| params:{ | |||
| userId:params.id | |||
| }, | |||
| onSuccess: function (response) { | |||
| // console.log(response) | |||
| setLoginLogData(response); | |||
| } | |||
| }); | |||
| } | |||
| const onEditClick = () => { | |||
| setEditMode(true); | |||
| }; | |||
| return ( | |||
| !onReady ? | |||
| <Grid container sx={{ minHeight: '87vh', mb: 3 }} direction="column" justifyContent="center" alignItems="center"> | |||
| @@ -223,6 +254,70 @@ const UserMaintainPage = () => { | |||
| </Button> | |||
| </Grid> | |||
| {/*col 1*/} | |||
| {/*bottom button*/} | |||
| <Grid item s={12} md={12} lg={12} sx={{ mt:2, mb:2 }} alignItems={"start"} justifyContent="center"> | |||
| <Grid container maxWidth justifyContent="flex-start"> | |||
| {editMode ? | |||
| <ThemeProvider theme={PNSPS_BUTTON_THEME}> | |||
| <Grid item sx={{ ml: 3, mr: 3 }}> | |||
| <Button | |||
| variant="contained" | |||
| onClick={loadData} | |||
| color="cancel" | |||
| > | |||
| Reset & Back | |||
| </Button> | |||
| </Grid> | |||
| <Grid item sx={{ ml: 3, mr: 3 }}> | |||
| <Button | |||
| size="large" | |||
| variant="contained" | |||
| type="submit" | |||
| sx={{ | |||
| textTransform: 'capitalize', | |||
| alignItems: 'end' | |||
| }} | |||
| onClick={submitData} | |||
| > | |||
| Save | |||
| </Button> | |||
| </Grid> | |||
| </ThemeProvider>: | |||
| <ThemeProvider theme={PNSPS_BUTTON_THEME}> | |||
| <Grid item sx={{ml: 3,mr: 3 }}> | |||
| <Button | |||
| variant="contained" | |||
| onClick={onEditClick} | |||
| > | |||
| Edit | |||
| </Button> | |||
| </Grid> | |||
| <Grid item sx={{ ml: 3, mr: 3 }}> | |||
| <Button | |||
| size="large" | |||
| variant="contained" | |||
| sx={{ | |||
| textTransform: 'capitalize', | |||
| alignItems: 'end' | |||
| }} | |||
| disabled={isNewRecord} | |||
| onClick={handleDeleteClick} | |||
| > | |||
| Delete User | |||
| </Button> | |||
| <GeneralConfirmWindow | |||
| isWindowOpen={isWindowOpen} | |||
| title={"Attention"} | |||
| content={`Confirm to delete User "${userData.data.username}" ?`} | |||
| onNormalClose={handleClose} | |||
| onConfirmClose={deleteData} | |||
| /> | |||
| </Grid> | |||
| </ThemeProvider> | |||
| } | |||
| </Grid> | |||
| </Grid> | |||
| <Grid item xs={12} md={5} lg={5}> | |||
| <Grid container> | |||
| <Grid item xs={12} md={12} lg={12}> | |||
| @@ -232,6 +327,7 @@ const UserMaintainPage = () => { | |||
| userData={userData} | |||
| isCollectData={isCollectData} | |||
| isNewRecord={isNewRecord} | |||
| editMode={editMode} | |||
| /> | |||
| </Box> | |||
| </Grid> | |||
| @@ -243,6 +339,7 @@ const UserMaintainPage = () => { | |||
| userData={userData} | |||
| isCollectData={isCollectData} | |||
| isNewRecord={isNewRecord} | |||
| editMode={editMode} | |||
| /> | |||
| </Box> | |||
| </Grid> | |||
| @@ -256,50 +353,16 @@ const UserMaintainPage = () => { | |||
| userData={userData} | |||
| isCollectData={isCollectData} | |||
| isNewRecord={isNewRecord} | |||
| editMode={editMode} | |||
| /> | |||
| </Box> | |||
| </Grid> | |||
| {/*bottom button*/} | |||
| <Grid item s={12} md={12} lg={12} sx={{ mt:1, mb:2 }} alignItems={"end"} justifyContent="center"> | |||
| <Grid container maxWidth justifyContent="flex-end"> | |||
| <Grid item sx={{ ml: 3, mr: 3 }}> | |||
| <Button | |||
| size="large" | |||
| variant="contained" | |||
| sx={{ | |||
| textTransform: 'capitalize', | |||
| alignItems: 'end' | |||
| }} | |||
| disabled={isNewRecord} | |||
| onClick={handleDeleteClick} | |||
| > | |||
| <Typography variant="h5">Delete User</Typography> | |||
| </Button> | |||
| <GeneralConfirmWindow | |||
| isWindowOpen={isWindowOpen} | |||
| title={"Attention"} | |||
| content={`Confirm to delete User "${userData.data.username}" ?`} | |||
| onNormalClose={handleClose} | |||
| onConfirmClose={deleteData} | |||
| /> | |||
| </Grid> | |||
| <Grid item sx={{ ml: 3, mr: 3 }}> | |||
| <Button | |||
| size="large" | |||
| variant="contained" | |||
| type="submit" | |||
| sx={{ | |||
| textTransform: 'capitalize', | |||
| alignItems: 'end' | |||
| }} | |||
| onClick={submitData} | |||
| > | |||
| <Typography variant="h5">Save</Typography> | |||
| </Button> | |||
| </Grid> | |||
| </Grid> | |||
| <Grid item xs={12} md={12} lg={12}> | |||
| <Box xs={12} ml={2} mt={2} mr={3} sx={{ borderRadius: '10px', backgroundColor: '#fff' }}> | |||
| <LoginGrid | |||
| rows = {loginLogData} | |||
| /> | |||
| </Box> | |||
| </Grid> | |||
| </Grid> | |||
| ); | |||