feat: 사이트 등록/수정 작업

This commit is contained in:
2025-03-14 18:42:32 +09:00
parent 5505838bc5
commit ec5acf9291
6 changed files with 114 additions and 55 deletions
+2 -2
View File
@@ -1,2 +1,2 @@
import { RegisterPage } from "@/pages/site";
export default RegisterPage;
import { CreatePage } from "@/pages/site";
export default CreatePage;
+18 -7
View File
@@ -1,11 +1,12 @@
import { client } from "@/shared/api/client";
import { ENDPOINT } from "@/shared/config/api";
import type {
ISiteInfo,
SiteService,
ISiteDetail,
ISiteParams,
SiteFormData,
import {
siteFormSchema,
type ISiteInfo,
type SiteService,
type ISiteDetail,
type ISiteParams,
type SiteFormData,
} from "../model/site-interface";
export class SiteApiService implements SiteService {
@@ -25,9 +26,19 @@ export class SiteApiService implements SiteService {
}
public async modifySite(siteId: string, data: SiteFormData): Promise<void> {
const validatedData = siteFormSchema.parse(data);
const response = await client.put<void>(
`${ENDPOINT.CMS_SERVICE.SITES}/${siteId}`,
data,
validatedData,
);
return response.data;
}
public async createSite(data: SiteFormData): Promise<void> {
const validatedData = siteFormSchema.parse(data);
const response = await client.post<void>(
`${ENDPOINT.CMS_SERVICE.SITES}`,
validatedData,
);
return response.data;
}
@@ -63,17 +63,17 @@ export interface ISiteDetail extends SiteFormData {
}
export const siteFormSchema = z.object({
siteId: z.string().max(2),
siteNm: z.string().max(100),
siteId: z.string().max(2).nonempty(),
siteNm: z.string().max(100).nonempty(),
siteExpln: z.string().max(1000).optional(),
siteKndCd: z.string().max(10),
siteKndCd: z.string().max(10).nonempty(),
siteAddr: z.string().max(2000).optional(),
faxNo: z.string().max(100).optional(),
telNo: z.string().max(1000).optional(),
lwndCn: z.string().max(2000).optional(),
bscSiteYn: z.string().optional(),
bscSiteYn: z.string(),
bkmkIcon: z.string().max(100).optional(),
useYn: z.string().optional(),
useYn: z.string(),
siteSkn: z.string().max(10).optional(),
});
@@ -83,4 +83,5 @@ export interface SiteService {
siteInfo(query: ISiteParams): Promise<ISiteInfo>;
siteDetail(siteId: string): Promise<ISiteDetail>;
modifySite(siteId: string, data: SiteFormData): Promise<void>;
createSite(data: SiteFormData): Promise<void>;
}
+40 -9
View File
@@ -1,22 +1,53 @@
"use client";
import type { z } from "zod";
import { useState } from "react";
import { useRouter } from "next/navigation";
import { useForm } from "react-hook-form";
import { useMutation } from "@tanstack/react-query";
import { zodResolver } from "@hookform/resolvers/zod";
import { siteFormSchema } from "../model/form-schema";
import { SiteApi, siteFormSchema, type SiteFormData } from "@/entities/site";
import { SitePageLayout } from "./layout";
import { SiteForm } from "./site-form";
import {
Button,
Dialog,
DialogClose,
DialogContent,
DialogFooter,
} from "@common/components/ui";
function CreatePage() {
const form = useForm<z.infer<typeof siteFormSchema>>({
defaultValues: siteFormSchema.parse({
siteId: "",
siteNm: "",
siteKndCd: "",
}),
const router = useRouter();
const { mutateAsync: createSite } = useMutation({
mutationFn: (data: SiteFormData) => SiteApi.createSite(data),
onSuccess: () => {
setIsCreateSuccess(true);
},
});
const [isCreateSuccess, setIsCreateSuccess] = useState(false);
const form = useForm<SiteFormData>({
resolver: zodResolver(siteFormSchema),
});
return <SiteForm form={form} handleSave={() => {}} />;
return (
<SitePageLayout>
<SiteForm form={form} handleSave={createSite} />
<Dialog open={isCreateSuccess} onOpenChange={() => router.back()}>
<DialogContent aria-describedby={undefined}>
<div className="py-10">
<p className="text-center text-[1.4rem]">등록되었습니다.</p>
</div>
<DialogFooter className="!justify-center">
<DialogClose asChild>
<Button>확인</Button>
</DialogClose>
</DialogFooter>
</DialogContent>
</Dialog>
</SitePageLayout>
);
}
export { CreatePage };
+28 -16
View File
@@ -1,6 +1,7 @@
"use client";
import { useEffect } from "react";
import { useEffect, useState } from "react";
import { useRouter } from "next/navigation";
import { useForm } from "react-hook-form";
import { useMutation, useQuery } from "@tanstack/react-query";
import { zodResolver } from "@hookform/resolvers/zod";
@@ -13,10 +14,18 @@ import {
import { ENDPOINT } from "@/shared/config/api";
import { SitePageLayout } from "./layout";
import { SiteForm } from "./site-form";
import {
Button,
Dialog,
DialogClose,
DialogContent,
DialogFooter,
} from "@common/components/ui";
function ModifyPage({ siteId }: { siteId: string }) {
const isModifyMode = !!siteId;
const router = useRouter();
const { data: siteDetail } = useQuery({
queryKey: [ENDPOINT.CMS_SERVICE.SITES, siteId],
queryFn: () => SiteApi.siteDetail(siteId),
@@ -30,24 +39,17 @@ function ModifyPage({ siteId }: { siteId: string }) {
const { mutateAsync: modifySite } = useMutation({
mutationFn: (data: SiteFormData) => SiteApi.modifySite(siteId, data),
onSuccess: (data) => {
console.log("success!", data);
onSuccess: () => {
setIsModifySuccess(true);
},
});
const [isModifySuccess, setIsModifySuccess] = useState(false);
const form = useForm<SiteFormData>({
defaultValues: siteFormSchema.omit({ siteId: true }).parse({
siteNm: "",
siteKndCd: "",
}),
resolver: zodResolver(siteFormSchema),
});
const handleSave = (data: SiteFormData) => {
console.log(data);
modifySite(data);
};
useEffect(() => {
if (!siteDetail) return;
@@ -55,16 +57,26 @@ function ModifyPage({ siteId }: { siteId: string }) {
for (const key of keys) {
form.setValue(
key as keyof SiteFormData,
siteDetail[key as keyof ISiteDetail],
siteDetail[key as keyof ISiteDetail] ?? "",
);
}
}, [siteDetail]);
console.log(form.watch());
return (
<SitePageLayout>
<SiteForm form={form} siteId={siteId} handleSave={handleSave} />
<SiteForm form={form} siteId={siteId} handleSave={modifySite} />
<Dialog open={isModifySuccess} onOpenChange={() => router.back()}>
<DialogContent aria-describedby={undefined}>
<div className="py-10">
<p className="text-center text-[1.4rem]">수정되었습니다.</p>
</div>
<DialogFooter className="!justify-center">
<DialogClose asChild>
<Button>확인</Button>
</DialogClose>
</DialogFooter>
</DialogContent>
</Dialog>
</SitePageLayout>
);
}
+20 -16
View File
@@ -187,17 +187,19 @@ function SiteForm({ form, siteId, handleSave }: SiteFormProps) {
/>
</TableCell>
</TableRow>
<TableRow className={`${!isModifyMode ? "hidden" : ""}`}>
<TableHead>사이트 도메인</TableHead>
<TableCell className="border">
<div className="flex gap-2">
<div className="h-[3.2rem] w-[21.5rem] cursor-not-allowed rounded-md border border-input bg-form px-3 py-2 text-[1.3rem] opacity-50">
{representativeDomain}
{isModifyMode && (
<TableRow>
<TableHead>사이트 도메인</TableHead>
<TableCell className="border">
<div className="flex gap-2">
<div className="h-[3.2rem] w-[21.5rem] cursor-not-allowed rounded-md border border-input bg-form px-3 py-2 text-[1.3rem] opacity-50">
{representativeDomain}
</div>
<DomainManagementDialog handleSave={handleDomainSave} />
</div>
<DomainManagementDialog handleSave={handleDomainSave} />
</div>
</TableCell>
</TableRow>
</TableCell>
</TableRow>
)}
<TableRow>
<TableHead>사이트 하단 표기 주소</TableHead>
<TableCell className="border">
@@ -368,15 +370,17 @@ function SiteForm({ form, siteId, handleSave }: SiteFormProps) {
</div>
</div>
<div className="flex justify-center gap-4 pb-12 pt-10">
<Button size="lg" color="white" onClick={() => router.back()}>
목록
</Button>
<Button size="lg" type="submit">
저장
</Button>
<Button size="lg" color="white" onClick={() => router.back()}>
취소
</Button>
<Button size="lg" color="red">
삭제
</Button>
{isModifyMode && (
<Button size="lg" color="red">
삭제
</Button>
)}
</div>
</form>
</Form>