|
|
|
@@ -1,8 +1,14 @@
|
|
|
|
|
import dayjs from "dayjs";
|
|
|
|
|
import React, { useEffect, useState, useCallback, memo } from "react";
|
|
|
|
|
import { useFieldArray, useForm, type UseFormReturn } from "react-hook-form";
|
|
|
|
|
import { useConfirm } from "@frontend-opensource/use-react-hooks";
|
|
|
|
|
import { zodResolver } from "@hookform/resolvers/zod";
|
|
|
|
|
import { useQuery, keepPreviousData } from "@tanstack/react-query";
|
|
|
|
|
import {
|
|
|
|
|
useQuery,
|
|
|
|
|
useMutation,
|
|
|
|
|
useQueryClient,
|
|
|
|
|
keepPreviousData,
|
|
|
|
|
} from "@tanstack/react-query";
|
|
|
|
|
import {
|
|
|
|
|
Button,
|
|
|
|
|
Checkbox,
|
|
|
|
@@ -24,11 +30,13 @@ import {
|
|
|
|
|
UserOrganizationApi,
|
|
|
|
|
userOrganizationFormSchema,
|
|
|
|
|
type UserOrganizationFormData,
|
|
|
|
|
type UserOrganizationPayloadData,
|
|
|
|
|
type User,
|
|
|
|
|
type SearchUser,
|
|
|
|
|
} from "@/entities/user-organization";
|
|
|
|
|
import { CodeApi, type ICode } from "@/entities/code";
|
|
|
|
|
import { ENDPOINT } from "@/shared/config";
|
|
|
|
|
import { useAlertStore } from "@/shared/lib/use-alert-store";
|
|
|
|
|
import { AdditionalUserDialog } from "./additional-user-dialog";
|
|
|
|
|
|
|
|
|
|
type UserOrganizationSectionProps = {
|
|
|
|
@@ -36,6 +44,10 @@ type UserOrganizationSectionProps = {
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
function UserOrganizationSection({ ognzSn }: UserOrganizationSectionProps) {
|
|
|
|
|
const queryClient = useQueryClient();
|
|
|
|
|
const { confirm } = useConfirm();
|
|
|
|
|
const { setMessage: alert } = useAlertStore((state) => state);
|
|
|
|
|
|
|
|
|
|
const [userList, setUserList] = useState<User[]>([]);
|
|
|
|
|
const [selectedUsers, setSelectedUsers] = useState<User[]>([]);
|
|
|
|
|
|
|
|
|
@@ -59,17 +71,29 @@ function UserOrganizationSection({ ognzSn }: UserOrganizationSectionProps) {
|
|
|
|
|
queryFn: () => CodeApi.getCode("JDGDCLCD"),
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const { mutate: saveUserOrganization } = useMutation({
|
|
|
|
|
mutationFn: (data: UserOrganizationPayloadData[]) =>
|
|
|
|
|
UserOrganizationApi.saveUserOrganization(data),
|
|
|
|
|
onSuccess: () => {
|
|
|
|
|
alert("저장되었습니다.");
|
|
|
|
|
queryClient.invalidateQueries({
|
|
|
|
|
queryKey: [ENDPOINT.CMS_SERVICE.USER_ORGANIZATION, ognzSn],
|
|
|
|
|
});
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const form = useForm<UserOrganizationFormData>({
|
|
|
|
|
resolver: zodResolver(userOrganizationFormSchema),
|
|
|
|
|
values: {
|
|
|
|
|
userOrganization: userList.map((user) => ({
|
|
|
|
|
mode: user.mode,
|
|
|
|
|
ognzSn: user.ognzSn,
|
|
|
|
|
userUnqId: user.userUnqId,
|
|
|
|
|
jbpsSeCd: user.jbpsSeCd,
|
|
|
|
|
jbgdSeCd: user.jbgdSeCd,
|
|
|
|
|
sortSeq: user.sortSeq,
|
|
|
|
|
})),
|
|
|
|
|
userOrganization:
|
|
|
|
|
userOrganizationList?.content.map((user) => ({
|
|
|
|
|
mode: user.mode,
|
|
|
|
|
ognzSn: user.ognzSn,
|
|
|
|
|
userUnqId: user.userUnqId,
|
|
|
|
|
jbpsSeCd: user.jbpsSeCd,
|
|
|
|
|
jbgdSeCd: user.jbgdSeCd,
|
|
|
|
|
sortSeq: user.sortSeq,
|
|
|
|
|
})) ?? [],
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
@@ -79,30 +103,25 @@ function UserOrganizationSection({ ognzSn }: UserOrganizationSectionProps) {
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const handleAddUsers = (users: SearchUser[]) => {
|
|
|
|
|
const newForm = users.map((user) => ({
|
|
|
|
|
const generateUserData = (user: SearchUser) => ({
|
|
|
|
|
mode: "C",
|
|
|
|
|
ognzSn,
|
|
|
|
|
userUnqId: user.userUnqId,
|
|
|
|
|
jbpsSeCd: "",
|
|
|
|
|
jbgdSeCd: "",
|
|
|
|
|
sortSeq: 0,
|
|
|
|
|
}));
|
|
|
|
|
append(newForm);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const newFormData = users.map(generateUserData);
|
|
|
|
|
append(newFormData);
|
|
|
|
|
|
|
|
|
|
const newUserList = users.map((user) => ({
|
|
|
|
|
mode: "C",
|
|
|
|
|
ognzSn,
|
|
|
|
|
userUnqId: user.userUnqId,
|
|
|
|
|
...generateUserData(user),
|
|
|
|
|
userUnqNm: user.userNm,
|
|
|
|
|
jbpsSeCd: "",
|
|
|
|
|
jbgdSeCd: "",
|
|
|
|
|
sortSeq: 0,
|
|
|
|
|
}));
|
|
|
|
|
const existingUserIds = new Set(newUserList.map((user) => user.userUnqId));
|
|
|
|
|
const filteredUserList = userList.filter(
|
|
|
|
|
(existingUser) =>
|
|
|
|
|
!newUserList.some(
|
|
|
|
|
(newUser) => newUser.userUnqId === existingUser.userUnqId,
|
|
|
|
|
),
|
|
|
|
|
(user) => !existingUserIds.has(user.userUnqId),
|
|
|
|
|
);
|
|
|
|
|
setUserList([...newUserList, ...filteredUserList]);
|
|
|
|
|
};
|
|
|
|
@@ -130,16 +149,29 @@ function UserOrganizationSection({ ognzSn }: UserOrganizationSectionProps) {
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const handleDeleteUsers = () => {
|
|
|
|
|
if (selectedUsers.length === 0) return;
|
|
|
|
|
|
|
|
|
|
const selectedUserIds = selectedUsers.map((user) => user.userUnqId);
|
|
|
|
|
|
|
|
|
|
const updatedFormData = form.getValues("userOrganization").map((item) => {
|
|
|
|
|
if (selectedUserIds.includes(item.userUnqId)) {
|
|
|
|
|
return { ...item, mode: "D" };
|
|
|
|
|
}
|
|
|
|
|
return item;
|
|
|
|
|
});
|
|
|
|
|
form.setValue("userOrganization", updatedFormData);
|
|
|
|
|
setUserList((prevUsers) =>
|
|
|
|
|
prevUsers.filter((user) => !selectedUserIds.includes(user.userUnqId)),
|
|
|
|
|
);
|
|
|
|
|
setSelectedUsers([]);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const handleSaveUsers = async () => {
|
|
|
|
|
if (await confirm("저장하시겠습니까?")) {
|
|
|
|
|
const filteredData = form
|
|
|
|
|
.watch("userOrganization")
|
|
|
|
|
.filter((item) => item.mode !== "R");
|
|
|
|
|
saveUserOrganization(filteredData);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const isUserSelected = useCallback(
|
|
|
|
|
(userUnqId: string) =>
|
|
|
|
|
selectedUsers.some((item) => item.userUnqId === userUnqId),
|
|
|
|
@@ -166,7 +198,9 @@ function UserOrganizationSection({ ognzSn }: UserOrganizationSectionProps) {
|
|
|
|
|
>
|
|
|
|
|
선택삭제
|
|
|
|
|
</Button>
|
|
|
|
|
<Button size="sm">저장</Button>
|
|
|
|
|
<Button size="sm" onClick={handleSaveUsers}>
|
|
|
|
|
저장
|
|
|
|
|
</Button>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<div className="card">
|
|
|
|
@@ -196,12 +230,12 @@ function UserOrganizationSection({ ognzSn }: UserOrganizationSectionProps) {
|
|
|
|
|
onCheckedChange={() => handleToggleSelectUser(user)}
|
|
|
|
|
/>
|
|
|
|
|
</TableCell>
|
|
|
|
|
<UserTableRow
|
|
|
|
|
<UserCells
|
|
|
|
|
form={form}
|
|
|
|
|
user={user}
|
|
|
|
|
index={index}
|
|
|
|
|
jobPositionCodes={jobPositionCodes}
|
|
|
|
|
jobGradeCodes={jobGradeCodes}
|
|
|
|
|
jobPositionCodeData={jobPositionCodes}
|
|
|
|
|
jobGradeCodeData={jobGradeCodes}
|
|
|
|
|
/>
|
|
|
|
|
</TableRow>
|
|
|
|
|
))}
|
|
|
|
@@ -212,28 +246,28 @@ function UserOrganizationSection({ ognzSn }: UserOrganizationSectionProps) {
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type UserTableRowProps = {
|
|
|
|
|
type UserCellsProps = {
|
|
|
|
|
form: UseFormReturn<UserOrganizationFormData>;
|
|
|
|
|
user: User;
|
|
|
|
|
index: number;
|
|
|
|
|
jobPositionCodes?: ICode[];
|
|
|
|
|
jobGradeCodes?: ICode[];
|
|
|
|
|
jobPositionCodeData?: ICode[];
|
|
|
|
|
jobGradeCodeData?: ICode[];
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const UserTableRow = memo(
|
|
|
|
|
const UserCells = memo(
|
|
|
|
|
({
|
|
|
|
|
form,
|
|
|
|
|
user,
|
|
|
|
|
index,
|
|
|
|
|
jobPositionCodes,
|
|
|
|
|
jobGradeCodes,
|
|
|
|
|
}: UserTableRowProps) => (
|
|
|
|
|
jobPositionCodeData,
|
|
|
|
|
jobGradeCodeData,
|
|
|
|
|
}: UserCellsProps) => (
|
|
|
|
|
<>
|
|
|
|
|
<TableCell align="center">{index + 1}</TableCell>
|
|
|
|
|
<TableCell align="center">{user.userUnqNm}</TableCell>
|
|
|
|
|
<TableCell align="center">
|
|
|
|
|
<CodeSelect
|
|
|
|
|
codeData={jobPositionCodes}
|
|
|
|
|
codeData={jobPositionCodeData}
|
|
|
|
|
defaultValue={user.jbpsSeCd}
|
|
|
|
|
onValueChange={(value) => {
|
|
|
|
|
const mode = form.watch(`userOrganization.${index}.mode`);
|
|
|
|
@@ -247,7 +281,7 @@ const UserTableRow = memo(
|
|
|
|
|
</TableCell>
|
|
|
|
|
<TableCell align="center">
|
|
|
|
|
<CodeSelect
|
|
|
|
|
codeData={jobGradeCodes}
|
|
|
|
|
codeData={jobGradeCodeData}
|
|
|
|
|
defaultValue={user.jbgdSeCd}
|
|
|
|
|
onValueChange={(value) => {
|
|
|
|
|
const mode = form.watch(`userOrganization.${index}.mode`);
|
|
|
|
@@ -267,7 +301,7 @@ const UserTableRow = memo(
|
|
|
|
|
),
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
UserTableRow.displayName = "UserTableRow";
|
|
|
|
|
UserCells.displayName = "UserCells";
|
|
|
|
|
|
|
|
|
|
type CodeSelectProps = React.ComponentPropsWithoutRef<typeof Select> & {
|
|
|
|
|
codeData?: ICode[];
|
|
|
|
@@ -276,14 +310,14 @@ type CodeSelectProps = React.ComponentPropsWithoutRef<typeof Select> & {
|
|
|
|
|
const CodeSelect = memo(({ codeData, ...props }: CodeSelectProps) => {
|
|
|
|
|
if (!codeData) return null;
|
|
|
|
|
|
|
|
|
|
const defaultValueText =
|
|
|
|
|
const placeholderText =
|
|
|
|
|
codeData.find((item) => item.lwpoCd === props.defaultValue)?.lwpoCdNm ??
|
|
|
|
|
"선택";
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<Select {...props}>
|
|
|
|
|
<SelectTrigger className="w-[12rem]">
|
|
|
|
|
<SelectValue placeholder={defaultValueText} />
|
|
|
|
|
<SelectTrigger className="w-[10rem]">
|
|
|
|
|
<SelectValue placeholder={placeholderText} />
|
|
|
|
|
</SelectTrigger>
|
|
|
|
|
<SelectContent>
|
|
|
|
|
{codeData.map((item) => (
|
|
|
|
|