diff --git a/apps/cs/app/(with-base-layout)/users/[userUnqId]/modify/page.tsx b/apps/cs/app/(with-base-layout)/users/[userUnqId]/modify/page.tsx new file mode 100644 index 000000000..a01387c44 --- /dev/null +++ b/apps/cs/app/(with-base-layout)/users/[userUnqId]/modify/page.tsx @@ -0,0 +1,10 @@ +import { ModifyPage } from "@/pages/users/ui/modify-page"; + +export default async function UserModifyPage({ + params, +}: { + params: Promise<{ userUnqId: string }>; +}) { + const { userUnqId } = await params; + return ; +} diff --git a/apps/cs/app/(with-base-layout)/users/[userUnqId]/page.tsx b/apps/cs/app/(with-base-layout)/users/[userUnqId]/page.tsx index d4e0445ec..da4e79b00 100644 --- a/apps/cs/app/(with-base-layout)/users/[userUnqId]/page.tsx +++ b/apps/cs/app/(with-base-layout)/users/[userUnqId]/page.tsx @@ -1,6 +1,6 @@ import { UserDetail as VUserDetail } from "@/pages/users"; -export default async function UserDetail({ +export default async function UserDetailPage({ params, }: { params: Promise<{ userUnqId: string }>; diff --git a/apps/cs/src/entities/user/index.ts b/apps/cs/src/entities/user/index.ts index bd3627f71..7240c1424 100644 --- a/apps/cs/src/entities/user/index.ts +++ b/apps/cs/src/entities/user/index.ts @@ -3,9 +3,11 @@ export { USER_STATE_CODE, userSaveSchema, userPasswordUpdateSchema, + userUpdateSchema, type UserSearchParams, type UserListResponse, type UserSaveData, type UserDetailResponse, type UserPasswordUpdateData, + type UserUpdateData, } from "./model/user-interface"; diff --git a/apps/cs/src/pages/users/ui/create-page.tsx b/apps/cs/src/pages/users/ui/create-page.tsx index c91fe115d..84cc23b06 100644 --- a/apps/cs/src/pages/users/ui/create-page.tsx +++ b/apps/cs/src/pages/users/ui/create-page.tsx @@ -42,21 +42,12 @@ function CreatePage() { }, }); - // 저장 처리 함수 - const handleSave = async (data: UserSaveData) => { - try { - await saveUser(data); - } catch (error) { - console.error("회원 등록 실패:", error); - } - }; - return (

회원 등록

- +
); } diff --git a/apps/cs/src/pages/users/ui/modify-page.tsx b/apps/cs/src/pages/users/ui/modify-page.tsx new file mode 100644 index 000000000..fc93e4b05 --- /dev/null +++ b/apps/cs/src/pages/users/ui/modify-page.tsx @@ -0,0 +1,75 @@ +"use client"; + +import React from "react"; +import { useRouter } from "next/navigation"; +import { useForm } from "react-hook-form"; +import { zodResolver } from "@hookform/resolvers/zod"; +import { useQuery } from "@tanstack/react-query"; +import { + UserApi, + userUpdateSchema, + type UserUpdateData, +} from "@/entities/user"; +import { ENDPOINT } from "@/shared/config"; +import { useMutationWrapper, useAlertStore } from "@/shared/lib"; +import { UsersForm } from "./users-form"; + +interface ModifyPageProps { + userUnqId: string; +} + +export function ModifyPage({ userUnqId }: ModifyPageProps) { + const router = useRouter(); + const alert = useAlertStore((state) => state.setMessage); + + const { data: userData } = useQuery({ + queryKey: [ENDPOINT.USER_SERVICE.USERS, userUnqId], + queryFn: () => UserApi.findByUserUnqId(userUnqId), + enabled: !!userUnqId, + }); + + const form = useForm({ + resolver: zodResolver(userUpdateSchema), + defaultValues: { + userId: userData?.userId ?? "", + userName: userData?.userName ?? "", + email: userData?.email ?? "", + userStateCode: userData?.userStateCode ?? "", + pswdHnt: userData?.pswdHnt ?? "", + pswdAns: userData?.pswdAns ?? "", + mphn: userData?.mphn ?? "", + telno: userData?.telno ?? "", + zip: userData?.zip ?? "", + addr: userData?.addr ?? "", + daddr: userData?.daddr ?? "", + laeSeCd: userData?.laeSeCd ?? "", + ogdpSeCd: userData?.ogdpSeCd ?? "", + aprvYn: userData?.aprvYn ?? "", + expryYmd: userData?.expryYmd ?? "", + instSeCd: userData?.instSeCd ?? "", + dtlInstCd: userData?.dtlInstCd ?? "", + aprvYmd: userData?.aprvYmd ?? "", + enoCd: userData?.enoCd ?? "", + }, + }); + + const { mutateAsync: updateUser } = useMutationWrapper({ + mutationFn: (data: UserUpdateData) => UserApi.updateUser(userUnqId, data), + onSuccess: () => { + alert("회원 정보가 수정되었습니다.", router.back); + }, + }); + + return ( +
+
+

회원 정보 수정

+
+ +
+ ); +} diff --git a/apps/cs/src/pages/users/ui/user-detail.tsx b/apps/cs/src/pages/users/ui/user-detail.tsx index 4513555c2..9673f5c02 100644 --- a/apps/cs/src/pages/users/ui/user-detail.tsx +++ b/apps/cs/src/pages/users/ui/user-detail.tsx @@ -1,7 +1,7 @@ "use client"; import dayjs from "dayjs"; -import { useRouter } from "next/navigation"; +import { usePathname, useRouter } from "next/navigation"; import { useQuery, useQueryClient } from "@tanstack/react-query"; import { Button, @@ -18,6 +18,7 @@ import { PasswordResetDialog } from "./password-reset-dialog"; function UserDetail({ userUnqId }: { userUnqId: string }) { const router = useRouter(); + const pathname = usePathname(); const queryClient = useQueryClient(); const alert = useAlertStore((state) => state.setMessage); @@ -157,7 +158,9 @@ function UserDetail({ userUnqId }: { userUnqId: string }) { - + diff --git a/apps/cs/src/pages/users/ui/users-form.tsx b/apps/cs/src/pages/users/ui/users-form.tsx index ae575f317..d69e918b0 100644 --- a/apps/cs/src/pages/users/ui/users-form.tsx +++ b/apps/cs/src/pages/users/ui/users-form.tsx @@ -1,5 +1,10 @@ import { useState, useMemo, useCallback } from "react"; -import { useWatch, type UseFormReturn } from "react-hook-form"; +import { + useWatch, + type Path, + type PathValue, + type UseFormReturn, +} from "react-hook-form"; import { useQuery } from "@tanstack/react-query"; import { Button, @@ -17,7 +22,11 @@ import { } from "@common/components"; import { FormWrapper } from "@/widgets/form-wrapper"; import { CodeApi, CodeSelect } from "@/entities/code"; -import { UserApi, type UserSaveData } from "@/entities/user"; +import { + UserApi, + type UserSaveData, + type UserUpdateData, +} from "@/entities/user"; import { FormField, FormItem, @@ -29,19 +38,23 @@ import { useAlertStore, useMutationWrapper } from "@/shared/lib"; import { ZipSearchDialog } from "./zip-search-dialog"; import { AgencySearchDialog } from "./agency-search-dialog"; -type UsersFormProps = { +type UsersFormProps = { userId?: string; - form: UseFormReturn; - handleSave: (data: UserSaveData) => Promise; + form: UseFormReturn; + handleSave: (data: T) => Promise; handleDelete?: () => Promise; }; -function UsersForm({ userId, form, ...props }: UsersFormProps) { +function UsersForm({ + userId, + form, + ...props +}: UsersFormProps) { const isModifyMode = !!userId; const [watchOgdpSeCd, watchDtlInstCd] = useWatch({ control: form.control, - name: ["ogdpSeCd", "dtlInstCd"], + name: ["ogdpSeCd" as Path, "dtlInstCd" as Path], }); const alert = useAlertStore((state) => state.setMessage); @@ -132,21 +145,24 @@ function UsersForm({ userId, form, ...props }: UsersFormProps) { ); const handlePasswordConfirmChange = useCallback((value: string) => { - const password = form.getValues("password"); + const password = form.getValues("password" as Path); setPasswordMatch(!password || value === password); }, []); const handleAddressSelect = useCallback( (data: { zip: string; addr: string }) => { - form.setValue("zip", data.zip); - form.setValue("addr", data.addr); + form.setValue("zip" as Path, data.zip as PathValue>); + form.setValue("addr" as Path, data.addr as PathValue>); }, [form], ); const handleAgencySelect = useCallback( (data: { lwpoCd: string; lwpoCdNm: string }) => { - form.setValue("instSeCd", data.lwpoCd); + form.setValue( + "instSeCd" as Path, + data.lwpoCd as PathValue>, + ); setInstSeCdNm(data.lwpoCdNm); }, [form], @@ -167,7 +183,7 @@ function UsersForm({ userId, form, ...props }: UsersFormProps) { } render={({ field }) => (
@@ -191,7 +207,7 @@ function UsersForm({ userId, form, ...props }: UsersFormProps) { className="px-6" onClick={(e) => { e.preventDefault(); - checkDuplicateUserId(field.value); + checkDuplicateUserId(field.value as string); }} disabled={!field.value || isValidUserId} > @@ -211,7 +227,7 @@ function UsersForm({ userId, form, ...props }: UsersFormProps) { } render={({ field }) => ( @@ -258,7 +274,7 @@ function UsersForm({ userId, form, ...props }: UsersFormProps) { } render={({ field }) => ( @@ -281,7 +297,7 @@ function UsersForm({ userId, form, ...props }: UsersFormProps) { } render={({ field }) => ( @@ -304,7 +320,7 @@ function UsersForm({ userId, form, ...props }: UsersFormProps) { } render={({ field }) => ( @@ -327,7 +343,7 @@ function UsersForm({ userId, form, ...props }: UsersFormProps) { } render={({ field }) => ( @@ -347,7 +363,7 @@ function UsersForm({ userId, form, ...props }: UsersFormProps) { } render={({ field }) => ( @@ -370,7 +386,7 @@ function UsersForm({ userId, form, ...props }: UsersFormProps) { } render={({ field }) => (
@@ -393,7 +409,7 @@ function UsersForm({ userId, form, ...props }: UsersFormProps) { onClick={(e) => { e.preventDefault(); if (field.value) { - checkDuplicateEmail(field.value); + checkDuplicateEmail(field.value as string); } }} disabled={!field.value || isValidEmail} @@ -415,7 +431,7 @@ function UsersForm({ userId, form, ...props }: UsersFormProps) {
} render={({ field }) => ( @@ -433,7 +449,7 @@ function UsersForm({ userId, form, ...props }: UsersFormProps) {
} render={({ field }) => ( @@ -454,7 +470,7 @@ function UsersForm({ userId, form, ...props }: UsersFormProps) { } render={({ field }) => ( @@ -477,7 +493,7 @@ function UsersForm({ userId, form, ...props }: UsersFormProps) { } render={({ field }) => ( @@ -487,9 +503,18 @@ function UsersForm({ userId, form, ...props }: UsersFormProps) { value={field.value ?? ""} onValueChange={(value) => { field.onChange(value); - form.setValue("dtlInstCd", ""); - form.setValue("laeSeCd", ""); - form.setValue("enoCd", ""); + form.setValue( + "dtlInstCd" as Path, + "" as PathValue>, + ); + form.setValue( + "laeSeCd" as Path, + "" as PathValue>, + ); + form.setValue( + "enoCd" as Path, + "" as PathValue>, + ); }} className="w-[16rem]" placeholder="기관 선택" @@ -508,7 +533,7 @@ function UsersForm({ userId, form, ...props }: UsersFormProps) { } render={({ field }) => ( @@ -516,8 +541,14 @@ function UsersForm({ userId, form, ...props }: UsersFormProps) { value={field.value ?? ""} onValueChange={(value) => { field.onChange(value); - form.setValue("laeSeCd", ""); - form.setValue("enoCd", ""); + form.setValue( + "laeSeCd" as Path, + "" as PathValue>, + ); + form.setValue( + "enoCd" as Path, + "" as PathValue>, + ); }} > @@ -544,7 +575,7 @@ function UsersForm({ userId, form, ...props }: UsersFormProps) { } render={({ field }) => ( @@ -552,7 +583,10 @@ function UsersForm({ userId, form, ...props }: UsersFormProps) { value={field.value ?? ""} onValueChange={(value) => { field.onChange(value); - form.setValue("enoCd", ""); + form.setValue( + "enoCd" as Path, + "" as PathValue>, + ); }} > @@ -579,7 +613,7 @@ function UsersForm({ userId, form, ...props }: UsersFormProps) { } render={({ field }) => ( diff --git a/apps/cs/src/widgets/post/ui/post-form.tsx b/apps/cs/src/widgets/post/ui/post-form.tsx index dc38f327d..55cd85657 100644 --- a/apps/cs/src/widgets/post/ui/post-form.tsx +++ b/apps/cs/src/widgets/post/ui/post-form.tsx @@ -1,7 +1,7 @@ import { useRouter } from "next/navigation"; import { useEffect, useState } from "react"; import { useQuery } from "@tanstack/react-query"; -import type { UseFormReturn, FieldPath } from "react-hook-form"; +import type { UseFormReturn, Path } from "react-hook-form"; import { useConfirm } from "@frontend-opensource/use-react-hooks"; import { Input, @@ -35,7 +35,7 @@ function PostForm({ form, handleSave, }: PostFormProps) { - const atflCd = form.getValues("atflCd" as FieldPath); + const atflCd = form.getValues("atflCd" as Path); const router = useRouter(); const { confirm } = useConfirm(); @@ -81,7 +81,7 @@ function PostForm({ } + name={"pstTtl" as Path} render={({ field }) => ( @@ -102,7 +102,7 @@ function PostForm({ } + name={"wrtrNm" as Path} render={({ field }) => ( @@ -124,7 +124,7 @@ function PostForm({ } + name={"pstPswd" as Path} render={({ field }) => ( @@ -147,7 +147,7 @@ function PostForm({ } + name={"pstCn" as Path} render={({ field }) => ( @@ -170,7 +170,7 @@ function PostForm({ } + name={"rfrncUrl" as Path} render={({ field }) => ( @@ -194,7 +194,7 @@ function PostForm({
} + name={"popupYn" as Path} render={({ field }) => ( @@ -218,7 +218,7 @@ function PostForm({ /> } + name={"popupYnEtc" as Path} render={({ field }) => { const fieldValues = form.getValues().popupYnEtc?.[0]; return ( @@ -227,9 +227,7 @@ function PostForm({ , - ) === "N" + form.getValues("popupYn" as Path) === "N" } handlePeriodValueChange={( periodCode, @@ -267,7 +265,7 @@ function PostForm({
} + name={"upndFixYn" as Path} render={({ field }) => ( @@ -291,7 +289,7 @@ function PostForm({ /> } + name={"upndFixYnEtc" as Path} render={({ field }) => { const fieldValues = form.getValues().upndFixYnEtc?.[0]; @@ -301,9 +299,8 @@ function PostForm({ , - ) === "N" + form.getValues("upndFixYn" as Path) === + "N" } handlePeriodValueChange={( periodCode, @@ -341,7 +338,7 @@ function PostForm({
} + name={"prdPstgYn" as Path} render={({ field }) => ( @@ -365,7 +362,7 @@ function PostForm({ /> } + name={"prdPstgYnEtc" as Path} render={({ field }) => { const fieldValues = form.getValues().prdPstgYnEtc?.[0]; @@ -375,9 +372,8 @@ function PostForm({ , - ) === "N" + form.getValues("prdPstgYn" as Path) === + "N" } handlePeriodValueChange={( periodCode,