| @@ -3,13 +3,14 @@ import { | |||
| Button, | |||
| Grid, Typography, Stack, Box | |||
| } from '@mui/material'; | |||
| import { useEffect, useState, lazy } from "react"; | |||
| import { useEffect, useState, useRef, lazy } from "react"; | |||
| import axios from "axios"; | |||
| import { useParams } from "react-router-dom"; | |||
| import { | |||
| GeneralConfirmWindow, | |||
| getDeletedRecordWithRefList, | |||
| getIdList, | |||
| notifyActionError, | |||
| notifyDeleteSuccess, | |||
| notifySaveSuccess | |||
| } from "../../utils/CommonFunction"; | |||
| @@ -47,7 +48,7 @@ const UserMaintainPage = () => { | |||
| const [editedGroupData, setEditedGroupData] = useState({}); | |||
| const [userGroupData, setUserGroupData] = useState([]); | |||
| const [userAuthData, setUserAuthData] = useState([]); | |||
| const [userConfirm, setUserConfirm] = useState(false); | |||
| const saveInProgressRef = useRef(false); | |||
| const [groupMember, setGroupMember] = useState([]); | |||
| const [isNewRecord, setIsNewRecord] = useState(false); | |||
| const [deletedUserList, setDeletedUserList] = useState([]); | |||
| @@ -92,10 +93,89 @@ const UserMaintainPage = () => { | |||
| setDeletedAuthList(userAuthData.deletedList); | |||
| } | |||
| const submitData = () => { | |||
| setUserConfirm(true); | |||
| const submitData = async () => { | |||
| if (!onReady || saveInProgressRef.current) { | |||
| return; | |||
| } | |||
| saveInProgressRef.current = true; | |||
| 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(() => { | |||
| if (params.id > 0) { | |||
| @@ -134,36 +214,6 @@ const UserMaintainPage = () => { | |||
| } | |||
| }, [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 ( | |||
| !onReady ? | |||
| <Grid container sx={{ minHeight: '87vh', mb: 3 }} direction="column" justifyContent="center" alignItems="center"> | |||