| @@ -3,13 +3,14 @@ import { | |||||
| Button, | Button, | ||||
| Grid, Typography, Stack, Box | Grid, Typography, Stack, Box | ||||
| } from '@mui/material'; | } from '@mui/material'; | ||||
| import { useEffect, useState, lazy } from "react"; | |||||
| import { useEffect, useState, useRef, lazy } from "react"; | |||||
| import axios from "axios"; | import axios from "axios"; | ||||
| import { useParams } from "react-router-dom"; | import { useParams } from "react-router-dom"; | ||||
| import { | import { | ||||
| GeneralConfirmWindow, | GeneralConfirmWindow, | ||||
| getDeletedRecordWithRefList, | getDeletedRecordWithRefList, | ||||
| getIdList, | getIdList, | ||||
| notifyActionError, | |||||
| notifyDeleteSuccess, | notifyDeleteSuccess, | ||||
| notifySaveSuccess | notifySaveSuccess | ||||
| } from "../../utils/CommonFunction"; | } from "../../utils/CommonFunction"; | ||||
| @@ -47,7 +48,7 @@ const UserMaintainPage = () => { | |||||
| const [editedGroupData, setEditedGroupData] = useState({}); | const [editedGroupData, setEditedGroupData] = useState({}); | ||||
| const [userGroupData, setUserGroupData] = useState([]); | const [userGroupData, setUserGroupData] = useState([]); | ||||
| const [userAuthData, setUserAuthData] = useState([]); | const [userAuthData, setUserAuthData] = useState([]); | ||||
| const [userConfirm, setUserConfirm] = useState(false); | |||||
| const saveInProgressRef = useRef(false); | |||||
| const [groupMember, setGroupMember] = useState([]); | const [groupMember, setGroupMember] = useState([]); | ||||
| const [isNewRecord, setIsNewRecord] = useState(false); | const [isNewRecord, setIsNewRecord] = useState(false); | ||||
| const [deletedUserList, setDeletedUserList] = useState([]); | const [deletedUserList, setDeletedUserList] = useState([]); | ||||
| @@ -92,10 +93,89 @@ const UserMaintainPage = () => { | |||||
| setDeletedAuthList(userAuthData.deletedList); | setDeletedAuthList(userAuthData.deletedList); | ||||
| } | } | ||||
| const submitData = () => { | |||||
| setUserConfirm(true); | |||||
| const submitData = async () => { | |||||
| if (!onReady || saveInProgressRef.current) { | |||||
| return; | |||||
| } | |||||
| saveInProgressRef.current = true; | |||||
| setIsCollectData(!isCollectData); | setIsCollectData(!isCollectData); | ||||
| } | |||||
| try { | |||||
| const isNameValid = await validateGroupName(); | |||||
| if (!isNameValid) { | |||||
| return; | |||||
| } | |||||
| const latestGroupFormData = getLatestGroupFormData(); | |||||
| const finalDeletedUserList = getDeletedRecordWithRefList(deletedUserList, getIdList(groupMember)); | |||||
| const response = await axios.post(POST_AND_UPDATE_USER_GROUP, { | |||||
| id: parseInt(params.id) !== -1 ? parseInt(params.id) : null, | |||||
| name: latestGroupFormData.userGroupName, | |||||
| description: latestGroupFormData.description, | |||||
| addUserIds: getIdList(groupMember), | |||||
| removeUserIds: finalDeletedUserList, | |||||
| addAuthIds: userAuthData, | |||||
| removeAuthIds: deletedAuthList, | |||||
| }); | |||||
| if (response.status === 200) { | |||||
| navigate('/usergroupSearchview'); | |||||
| notifySaveSuccess(); | |||||
| } | |||||
| } catch (error) { | |||||
| console.log(error); | |||||
| notifyActionError(error?.response?.data?.message || "Save failed."); | |||||
| } finally { | |||||
| saveInProgressRef.current = false; | |||||
| } | |||||
| }; | |||||
| const normalizeName = (name) => (name || "").trim().toLowerCase(); | |||||
| const getLatestGroupFormData = () => { | |||||
| const nameEl = document.getElementById("groupName"); | |||||
| const descEl = document.getElementById("description"); | |||||
| // Prefer what the user actually typed. Parent `editedGroupData` can still be stale on the | |||||
| // first Save click (sync runs after `isCollectData` toggles in a child effect). | |||||
| return { | |||||
| userGroupName: nameEl != null ? nameEl.value : (editedGroupData?.userGroupName ?? ""), | |||||
| description: descEl != null ? descEl.value : (editedGroupData?.description ?? "") | |||||
| }; | |||||
| }; | |||||
| const validateGroupName = async () => { | |||||
| const latestGroupFormData = getLatestGroupFormData(); | |||||
| const groupName = (latestGroupFormData.userGroupName || "").trim(); | |||||
| if (groupName.length === 0) { | |||||
| notifyActionError("User Group Name is required."); | |||||
| return false; | |||||
| } | |||||
| try { | |||||
| const response = await axios.get(GET_GROUP_LIST_PATH, { | |||||
| params: { | |||||
| name: groupName, | |||||
| start: 0, | |||||
| limit: 1000 | |||||
| } | |||||
| }); | |||||
| const records = response?.data?.records || []; | |||||
| const currentId = parseInt(params.id); | |||||
| const isDuplicateName = records.some((record) => | |||||
| normalizeName(record?.name) === normalizeName(groupName) && | |||||
| parseInt(record?.id) !== currentId | |||||
| ); | |||||
| if (isDuplicateName) { | |||||
| notifyActionError(`User Group Name "${groupName}" already exists.`); | |||||
| return false; | |||||
| } | |||||
| } catch (error) { | |||||
| console.log(error); | |||||
| notifyActionError("Unable to validate User Group Name. Please try again."); | |||||
| return false; | |||||
| } | |||||
| return true; | |||||
| }; | |||||
| useEffect(() => { | useEffect(() => { | ||||
| if (params.id > 0) { | if (params.id > 0) { | ||||
| @@ -134,36 +214,6 @@ const UserMaintainPage = () => { | |||||
| } | } | ||||
| }, [userGroupData]); | }, [userGroupData]); | ||||
| useEffect(() => { | |||||
| if (userConfirm && onReady) { | |||||
| //avoid delete and add user at the same time | |||||
| let finalDeletedUserList = getDeletedRecordWithRefList(deletedUserList, getIdList(groupMember)); | |||||
| // console.log(finalDeletedUserList) | |||||
| axios.post(POST_AND_UPDATE_USER_GROUP, | |||||
| { | |||||
| "id": parseInt(params.id) !== -1 ? parseInt(params.id) : null, | |||||
| "name": editedGroupData.userGroupName, | |||||
| "description": editedGroupData.description, | |||||
| "addUserIds": getIdList(groupMember), | |||||
| "removeUserIds": finalDeletedUserList, | |||||
| "addAuthIds": userAuthData, | |||||
| "removeAuthIds": deletedAuthList, | |||||
| }, | |||||
| ) | |||||
| .then((response) => { | |||||
| if (response.status === 200) { | |||||
| navigate('/usergroupSearchview'); | |||||
| notifySaveSuccess() | |||||
| } | |||||
| }) | |||||
| .catch(error => { | |||||
| console.log(error); | |||||
| return false; | |||||
| }); | |||||
| } | |||||
| setUserConfirm(false); | |||||
| }, [editedGroupData, userGroupData, userAuthData]); | |||||
| return ( | return ( | ||||
| !onReady ? | !onReady ? | ||||
| <Grid container sx={{ minHeight: '87vh', mb: 3 }} direction="column" justifyContent="center" alignItems="center"> | <Grid container sx={{ minHeight: '87vh', mb: 3 }} direction="column" justifyContent="center" alignItems="center"> | ||||