@@ -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> | |||
); | |||