From 116a022a203bda8454563b2486865421cff4285a Mon Sep 17 00:00:00 2001 From: bicochan Date: Mon, 9 Jun 2025 13:16:44 +0900 Subject: [PATCH] =?UTF-8?q?feat:=20=EA=B6=8C=ED=95=9C=EB=93=B1=EB=A1=9D=20?= =?UTF-8?q?=EC=9E=91=EC=97=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../(with-base-layout)/role/register/page.tsx | 2 + apps/cs/src/pages/role/api/role-service.ts | 15 +- apps/cs/src/pages/role/index.ts | 1 + .../cs/src/pages/role/model/role-interface.ts | 12 ++ apps/cs/src/pages/role/ui/create-page.tsx | 41 ++++ apps/cs/src/pages/role/ui/role-form.tsx | 200 ++++++++++++++++++ apps/cs/src/pages/role/ui/role-page.tsx | 7 +- .../widgets/form-wrapper/ui/form-wrapper.tsx | 7 +- 8 files changed, 277 insertions(+), 8 deletions(-) create mode 100644 apps/cs/app/(with-base-layout)/role/register/page.tsx create mode 100644 apps/cs/src/pages/role/ui/create-page.tsx create mode 100644 apps/cs/src/pages/role/ui/role-form.tsx diff --git a/apps/cs/app/(with-base-layout)/role/register/page.tsx b/apps/cs/app/(with-base-layout)/role/register/page.tsx new file mode 100644 index 000000000..d0a8eb9e0 --- /dev/null +++ b/apps/cs/app/(with-base-layout)/role/register/page.tsx @@ -0,0 +1,2 @@ +import { CreatePage } from "@/pages/role"; +export default CreatePage; diff --git a/apps/cs/src/pages/role/api/role-service.ts b/apps/cs/src/pages/role/api/role-service.ts index 1072e324c..2d5e93462 100644 --- a/apps/cs/src/pages/role/api/role-service.ts +++ b/apps/cs/src/pages/role/api/role-service.ts @@ -1,9 +1,10 @@ import { client } from "@/shared/api"; import { ENDPOINT } from "@/shared/config"; import type { + RoleService, RoleList, RoleParams, - RoleService, + RoleFormData, } from "../model/role-interface"; export class RoleApiService implements RoleService { @@ -13,6 +14,18 @@ export class RoleApiService implements RoleService { }); return response.data; } + + public async createRole(data: RoleFormData): Promise { + await client.post(ENDPOINT.USER_SERVICE.ROLES, data); + } + + public async checkDuplicateRoleId(roleId: string): Promise { + const response = await client.get( + `${ENDPOINT.USER_SERVICE.ROLES}/check/dup`, + { params: { roleId } }, + ); + return response.data as boolean; + } } export const RoleApi = new RoleApiService(); diff --git a/apps/cs/src/pages/role/index.ts b/apps/cs/src/pages/role/index.ts index 8cd31a0b1..361a5fc10 100644 --- a/apps/cs/src/pages/role/index.ts +++ b/apps/cs/src/pages/role/index.ts @@ -1 +1,2 @@ export { RolePage } from "./ui/role-page"; +export { CreatePage } from "./ui/create-page"; diff --git a/apps/cs/src/pages/role/model/role-interface.ts b/apps/cs/src/pages/role/model/role-interface.ts index 7d739ebbd..a412912b6 100644 --- a/apps/cs/src/pages/role/model/role-interface.ts +++ b/apps/cs/src/pages/role/model/role-interface.ts @@ -1,3 +1,4 @@ +import { z } from "zod"; import type { PageableList, PageableParams } from "@/shared/model"; export interface RoleParams extends PageableParams { @@ -15,8 +16,19 @@ export interface Role { mngrYn: string; } +export const roleFormSchema = z.object({ + roleId: z.string(), + roleName: z.string(), + roleContent: z.string(), + useYn: z.string(), + mngrYn: z.string(), +}); + export type RoleList = PageableList; +export type RoleFormData = z.infer; export interface RoleService { getRoles: (params: RoleParams) => Promise; + createRole: (data: RoleFormData) => Promise; + checkDuplicateRoleId: (roleId: string) => Promise; } diff --git a/apps/cs/src/pages/role/ui/create-page.tsx b/apps/cs/src/pages/role/ui/create-page.tsx new file mode 100644 index 000000000..e37f63f6d --- /dev/null +++ b/apps/cs/src/pages/role/ui/create-page.tsx @@ -0,0 +1,41 @@ +"use client"; + +import { useRouter } from "next/navigation"; +import { useForm } from "react-hook-form"; +import { zodResolver } from "@hookform/resolvers/zod"; +import { useMutation } from "@tanstack/react-query"; +import { useAlertStore } from "@/shared/lib/use-alert-store"; +import { RoleForm } from "./role-form"; +import { RoleApi } from "../api/role-service"; +import { roleFormSchema, type RoleFormData } from "../model/role-interface"; + +function CreatePage() { + const router = useRouter(); + const alert = useAlertStore((state) => state.setMessage); + + const { mutateAsync: createRole } = useMutation({ + mutationFn: (data: RoleFormData) => RoleApi.createRole(data), + onSuccess: () => { + alert("등록되었습니다.", router.back); + }, + }); + + const form = useForm({ + resolver: zodResolver(roleFormSchema), + defaultValues: { + mngrYn: "Y", + useYn: "Y", + }, + }); + + return ( +
+
+

권한 등록

+
+ +
+ ); +} + +export { CreatePage }; diff --git a/apps/cs/src/pages/role/ui/role-form.tsx b/apps/cs/src/pages/role/ui/role-form.tsx new file mode 100644 index 000000000..5a7973f63 --- /dev/null +++ b/apps/cs/src/pages/role/ui/role-form.tsx @@ -0,0 +1,200 @@ +import type { UseFormReturn } from "react-hook-form"; +import { + Button, + Input, + Label, + RadioGroup, + RadioGroupItem, + Table, + TableBody, + TableCell, + TableHead, + TableRow, +} from "@common/components"; +import { FormWrapper } from "@/widgets/form-wrapper"; +import { FormField, FormItem, FormControl } from "@/shared/ui/form"; +import { RoleApi } from "../api/role-service"; +import type { RoleFormData } from "../model/role-interface"; +import { useMutation } from "@tanstack/react-query"; +import { useAlertStore } from "@/shared/lib"; +import { useState } from "react"; + +type RoleFormProps = { + roleId?: string; + form: UseFormReturn; + handleSave: (data: RoleFormData) => Promise; +}; + +function RoleForm({ form, roleId, ...props }: RoleFormProps) { + const alert = useAlertStore((state) => state.setMessage); + + const [isValidRoleId, setIsValidRoleId] = useState(false); + + const { mutateAsync: checkDuplicateRoleId } = useMutation({ + mutationFn: (roleId: string) => RoleApi.checkDuplicateRoleId(roleId), + onSuccess: (duplicate) => { + if (!duplicate) { + alert("사용가능한 권한ID입니다."); + setIsValidRoleId(true); + return; + } + alert("중복된 권한ID입니다."); + }, + }); + + return ( + +
+ + + + + + + + 권한ID + + ( +
+ + + { + field.onChange(e); + setIsValidRoleId(false); + }} + className="w-[20rem] !text-[1.3rem]" + placeholder="권한ID를 입력하세요" + /> + + + +
+ )} + /> +
+
+ + 권한명 + + ( + + + + + + )} + /> + + + + 권한내용 + + ( + + + + + + )} + /> + + + + 관리권한여부 + + ( + + + +
+ + +
+
+ + +
+
+
+
+ )} + /> +
+
+ + 사용여부 + + ( + + + +
+ + +
+
+ + +
+
+
+
+ )} + /> +
+
+
+
+
+
+ ); +} + +export { RoleForm }; diff --git a/apps/cs/src/pages/role/ui/role-page.tsx b/apps/cs/src/pages/role/ui/role-page.tsx index 0c64ada7a..eea0aec8f 100644 --- a/apps/cs/src/pages/role/ui/role-page.tsx +++ b/apps/cs/src/pages/role/ui/role-page.tsx @@ -1,6 +1,7 @@ "use client"; import { useState } from "react"; +import { useRouter } from "next/navigation"; import { useQuery } from "@tanstack/react-query"; import { getCoreRowModel, @@ -14,6 +15,8 @@ import { columns } from "../model/table-columns"; import type { Role, RoleParams } from "../model/role-interface"; function RolePage() { + const router = useRouter(); + const [roleQuery, setRoleQuery] = useState({ keyword: "", }); @@ -76,7 +79,9 @@ function RolePage() {

권한 목록

- +
diff --git a/apps/cs/src/widgets/form-wrapper/ui/form-wrapper.tsx b/apps/cs/src/widgets/form-wrapper/ui/form-wrapper.tsx index caba0b595..b275b6a36 100644 --- a/apps/cs/src/widgets/form-wrapper/ui/form-wrapper.tsx +++ b/apps/cs/src/widgets/form-wrapper/ui/form-wrapper.tsx @@ -43,12 +43,7 @@ function FormWrapper({
{children}
-