refactor: form wrapper 선언 및 적용
This commit is contained in:
@@ -0,0 +1 @@
|
||||
export { CodeSelect } from "../ui/code-select";
|
||||
@@ -25,8 +25,8 @@ import {
|
||||
DialogFooter,
|
||||
} from "@common/components/ui";
|
||||
import { cn } from "@common/components/lib";
|
||||
import { CodeSelect } from "@/entities/code";
|
||||
import { SiteApi, type Site } from "@/entities/site";
|
||||
import { CodeSelect } from "@/entities/code/@x/posting";
|
||||
import { SiteApi, type Site } from "@/entities/site/@x/posting";
|
||||
import type { PageableList } from "@/shared/model";
|
||||
import { ENDPOINT } from "@/shared/config";
|
||||
import { PostingApi } from "../api/posting-service";
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
export { SiteApi } from "../api/site-service";
|
||||
export type { Site } from "../model/site-interface";
|
||||
@@ -35,17 +35,17 @@ export interface SiteDetail extends SiteFormData {
|
||||
export const siteFormSchema = z.object({
|
||||
siteId: z.string().max(2).nonempty(),
|
||||
siteNm: z.string().max(100).nonempty(),
|
||||
siteExpln: z.string().max(1000).nullable(),
|
||||
siteExpln: z.string().max(1000).nullish(),
|
||||
siteKndCd: z.string().max(10).nonempty(),
|
||||
siteAddr: z.string().max(2000).nullable(),
|
||||
faxNo: z.string().max(100).nullable(),
|
||||
telNo: z.string().max(1000).nullable(),
|
||||
lwndCn: z.string().max(2000).nullable(),
|
||||
siteAddr: z.string().max(2000).nullish(),
|
||||
faxNo: z.string().max(100).nullish(),
|
||||
telNo: z.string().max(1000).nullish(),
|
||||
lwndCn: z.string().max(2000).nullish(),
|
||||
bscSiteYn: z.string(),
|
||||
bkmkIcon: z.string().max(100).nullable(),
|
||||
bkmkIcon: z.string().max(100).nullish(),
|
||||
useYn: z.string(),
|
||||
siteSkn: z.string().max(10).nullable(),
|
||||
dmnAddr: z.string().nullable(),
|
||||
siteSkn: z.string().max(10).nullish(),
|
||||
dmnAddr: z.string().nullish(),
|
||||
});
|
||||
|
||||
export type SiteFormData = z.infer<typeof siteFormSchema>;
|
||||
|
||||
@@ -2,13 +2,10 @@
|
||||
|
||||
import Image from "next/image";
|
||||
import { useEffect, useState } from "react";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import type { UseFormReturn } from "react-hook-form";
|
||||
import type { HttpResponse, Upload } from "tus-js-client";
|
||||
import { useConfirm } from "@frontend-opensource/use-react-hooks";
|
||||
import {
|
||||
Button,
|
||||
FileUploader,
|
||||
Input,
|
||||
Label,
|
||||
@@ -25,9 +22,10 @@ import {
|
||||
import { CodeSelect } from "@/entities/code";
|
||||
import { AttachmentApi } from "@/entities/attachment";
|
||||
import { ENDPOINT } from "@/shared/config";
|
||||
import { Form, FormControl, FormField, FormItem } from "@/shared/ui/form";
|
||||
import { FormControl, FormField, FormItem } from "@/shared/ui/form";
|
||||
import type { BannerFormData } from "../model/banner-interface";
|
||||
import { handleUpload } from "../lib/utils";
|
||||
import { FormWrapper } from "@/widgets/form-wrapper";
|
||||
|
||||
type BannerFormProps = {
|
||||
form: UseFormReturn<BannerFormData>;
|
||||
@@ -36,17 +34,9 @@ type BannerFormProps = {
|
||||
handleDelete?: () => Promise<void>;
|
||||
};
|
||||
|
||||
function BannerForm({
|
||||
form,
|
||||
bnrSn,
|
||||
handleSave,
|
||||
handleDelete,
|
||||
}: BannerFormProps) {
|
||||
const isModifyMode = !!bnrSn;
|
||||
function BannerForm({ form, bnrSn, ...props }: BannerFormProps) {
|
||||
const atflCd = form.watch("atflCd");
|
||||
|
||||
const router = useRouter();
|
||||
const { confirm } = useConfirm();
|
||||
const [imageUrl, setImageUrl] = useState("");
|
||||
const [upload, setUpload] = useState<Upload | null>(null);
|
||||
const [progress, setProgress] = useState(0);
|
||||
@@ -58,22 +48,6 @@ function BannerForm({
|
||||
enabled: !!atflCd,
|
||||
});
|
||||
|
||||
const onSubmit = async (data: BannerFormData) => {
|
||||
const confirmMessage = isModifyMode
|
||||
? "수정하시겠습니까?"
|
||||
: "저장하시겠습니까?";
|
||||
|
||||
if (await confirm(confirmMessage)) {
|
||||
await handleSave(data);
|
||||
}
|
||||
};
|
||||
|
||||
const onDelete = async () => {
|
||||
if (await confirm("삭제하시겠습니까?")) {
|
||||
await handleDelete?.();
|
||||
}
|
||||
};
|
||||
|
||||
const handleProgress = (percentage: string) => {
|
||||
setProgress(Number(percentage));
|
||||
};
|
||||
@@ -96,245 +70,223 @@ function BannerForm({
|
||||
}, [atflId]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Form {...form}>
|
||||
<form onSubmit={form.handleSubmit(onSubmit)}>
|
||||
<div className="card">
|
||||
<Table variant="secondary">
|
||||
<colgroup>
|
||||
<col width="20%" />
|
||||
<col width="80%" />
|
||||
</colgroup>
|
||||
<TableBody>
|
||||
<TableRow>
|
||||
<TableHead>배너명</TableHead>
|
||||
<TableCell className="border">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="bnrTtl"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<Input
|
||||
{...field}
|
||||
value={field.value ?? ""}
|
||||
className="!text-[1.3rem]"
|
||||
placeholder="배너명을 입력해주세요"
|
||||
/>
|
||||
</FormControl>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableHead>배너구분</TableHead>
|
||||
<TableCell className="border">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="bnrTypeCd"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<CodeSelect
|
||||
{...field}
|
||||
value={field.value ?? ""}
|
||||
upCd="BNRTYPE"
|
||||
onValueChange={field.onChange}
|
||||
/>
|
||||
</FormControl>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableHead>배너 이미지</TableHead>
|
||||
<TableCell className="border">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="atflCd"
|
||||
render={() => (
|
||||
<FormItem className="flex flex-col">
|
||||
<FormControl>
|
||||
<FileUploader
|
||||
id="atflCd"
|
||||
className="!h-auto !max-w-none flex-col !items-start"
|
||||
accept=".jpeg,.jpg,.png"
|
||||
onUpload={(e) => {
|
||||
const files = e.target.files;
|
||||
if (!files) return;
|
||||
handleUpload(files, {
|
||||
handleUploadStart: setUpload,
|
||||
handleProgress,
|
||||
handleSuccess: setUpload,
|
||||
handleResponse: handleUploadResponse,
|
||||
});
|
||||
}}
|
||||
customPreview={
|
||||
<>
|
||||
<Label htmlFor="atflCd">
|
||||
<div className="relative h-[27rem] w-[48rem] overflow-hidden rounded-sm border border-border bg-accent">
|
||||
<p className="absolute bottom-3 left-0 p-2 text-base leading-none">
|
||||
{(upload?.file as File)?.name}
|
||||
</p>
|
||||
<div className="relative h-full w-full">
|
||||
{imageUrl && (
|
||||
<Image
|
||||
src={imageUrl}
|
||||
alt="업로드된 이미지"
|
||||
fill
|
||||
objectFit="contain"
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
<Progress
|
||||
value={progress}
|
||||
className="absolute bottom-0 left-0"
|
||||
<FormWrapper form={form} isModifyMode={!!bnrSn} {...props}>
|
||||
<div className="card">
|
||||
<Table variant="secondary">
|
||||
<colgroup>
|
||||
<col width="20%" />
|
||||
<col width="80%" />
|
||||
</colgroup>
|
||||
<TableBody>
|
||||
<TableRow>
|
||||
<TableHead>배너명</TableHead>
|
||||
<TableCell className="border">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="bnrTtl"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<Input
|
||||
{...field}
|
||||
value={field.value ?? ""}
|
||||
className="!text-[1.3rem]"
|
||||
placeholder="배너명을 입력해주세요"
|
||||
/>
|
||||
</FormControl>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableHead>배너구분</TableHead>
|
||||
<TableCell className="border">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="bnrTypeCd"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<CodeSelect
|
||||
{...field}
|
||||
value={field.value ?? ""}
|
||||
upCd="BNRTYPE"
|
||||
onValueChange={field.onChange}
|
||||
/>
|
||||
</FormControl>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableHead>배너 이미지</TableHead>
|
||||
<TableCell className="border">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="atflCd"
|
||||
render={() => (
|
||||
<FormItem className="flex flex-col">
|
||||
<FormControl>
|
||||
<FileUploader
|
||||
id="atflCd"
|
||||
className="!h-auto !max-w-none flex-col !items-start"
|
||||
accept=".jpeg,.jpg,.png"
|
||||
onUpload={(e) => {
|
||||
const files = e.target.files;
|
||||
if (!files) return;
|
||||
handleUpload(files, {
|
||||
handleUploadStart: setUpload,
|
||||
handleProgress,
|
||||
handleSuccess: setUpload,
|
||||
handleResponse: handleUploadResponse,
|
||||
});
|
||||
}}
|
||||
customPreview={
|
||||
<>
|
||||
<Label htmlFor="atflCd">
|
||||
<div className="relative h-[27rem] w-[48rem] overflow-hidden rounded-sm border border-border bg-accent">
|
||||
<p className="absolute bottom-3 left-0 p-2 text-base leading-none">
|
||||
{(upload?.file as File)?.name}
|
||||
</p>
|
||||
<div className="relative h-full w-full">
|
||||
{imageUrl && (
|
||||
<Image
|
||||
src={imageUrl}
|
||||
alt="업로드된 이미지"
|
||||
fill
|
||||
objectFit="contain"
|
||||
/>
|
||||
</div>
|
||||
</Label>
|
||||
<div className="mb-2 text-lg font-medium text-label">
|
||||
<ul className="ml-10 list-disc">
|
||||
<li>
|
||||
이미지 파일(jpg, jpeg, png, gif)만
|
||||
업로드 가능합니다.
|
||||
</li>
|
||||
</ul>
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
}
|
||||
/>
|
||||
</FormControl>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableHead>링크 URL</TableHead>
|
||||
<TableCell className="border">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="lnkgUrlAddr"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<Input
|
||||
{...field}
|
||||
value={field.value ?? ""}
|
||||
className="!text-[1.3rem]"
|
||||
placeholder="배너에 연결할 링크를 입력해주세요"
|
||||
/>
|
||||
</FormControl>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableHead>링크 열기</TableHead>
|
||||
<TableCell className="border">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="newWndwYn"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<RadioGroup
|
||||
{...field}
|
||||
name="newWndwYn"
|
||||
onValueChange={field.onChange}
|
||||
>
|
||||
<div className="flex items-center space-x-2">
|
||||
<RadioGroupItem value="N" id="newWndwN" />
|
||||
<Label htmlFor="newWndwN">현재창</Label>
|
||||
<Progress
|
||||
value={progress}
|
||||
className="absolute bottom-0 left-0"
|
||||
/>
|
||||
</div>
|
||||
</Label>
|
||||
<div className="mb-2 text-lg font-medium text-label">
|
||||
<ul className="ml-10 list-disc">
|
||||
<li>
|
||||
이미지 파일(jpg, jpeg, png, gif)만 업로드
|
||||
가능합니다.
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div className="flex items-center space-x-2">
|
||||
<RadioGroupItem value="Y" id="newWndwY" />
|
||||
<Label htmlFor="newWndwY">새창</Label>
|
||||
</div>
|
||||
</RadioGroup>
|
||||
</FormControl>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableHead>배너 설명</TableHead>
|
||||
<TableCell className="border">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="bnrExpln"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<Textarea
|
||||
{...field}
|
||||
value={field.value ?? ""}
|
||||
className="!text-[1.3rem] !leading-6"
|
||||
placeholder="배너에 대한 설명을 입력해주세요"
|
||||
/>
|
||||
</FormControl>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableHead>사용여부</TableHead>
|
||||
<TableCell className="border">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="useYn"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<RadioGroup
|
||||
{...field}
|
||||
name="useYn"
|
||||
onValueChange={field.onChange}
|
||||
>
|
||||
<div className="flex items-center space-x-2">
|
||||
<RadioGroupItem value="Y" id="useY" />
|
||||
<Label htmlFor="useY">사용</Label>
|
||||
</div>
|
||||
<div className="flex items-center space-x-2">
|
||||
<RadioGroupItem value="N" id="useN" />
|
||||
<Label htmlFor="useN">미사용</Label>
|
||||
</div>
|
||||
</RadioGroup>
|
||||
</FormControl>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
</TableBody>
|
||||
</Table>
|
||||
</div>
|
||||
<div className="flex justify-center gap-4 pb-12 pt-10">
|
||||
<Button
|
||||
size="lg"
|
||||
color="white"
|
||||
type="button"
|
||||
onClick={() => router.back()}
|
||||
>
|
||||
목록
|
||||
</Button>
|
||||
<Button size="lg" type="submit">
|
||||
저장
|
||||
</Button>
|
||||
{isModifyMode && (
|
||||
<Button size="lg" color="red" type="button" onClick={onDelete}>
|
||||
삭제
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
</form>
|
||||
</Form>
|
||||
</>
|
||||
</>
|
||||
}
|
||||
/>
|
||||
</FormControl>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableHead>링크 URL</TableHead>
|
||||
<TableCell className="border">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="lnkgUrlAddr"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<Input
|
||||
{...field}
|
||||
value={field.value ?? ""}
|
||||
className="!text-[1.3rem]"
|
||||
placeholder="배너에 연결할 링크를 입력해주세요"
|
||||
/>
|
||||
</FormControl>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableHead>링크 열기</TableHead>
|
||||
<TableCell className="border">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="newWndwYn"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<RadioGroup
|
||||
{...field}
|
||||
name="newWndwYn"
|
||||
onValueChange={field.onChange}
|
||||
>
|
||||
<div className="flex items-center space-x-2">
|
||||
<RadioGroupItem value="N" id="newWndwN" />
|
||||
<Label htmlFor="newWndwN">현재창</Label>
|
||||
</div>
|
||||
<div className="flex items-center space-x-2">
|
||||
<RadioGroupItem value="Y" id="newWndwY" />
|
||||
<Label htmlFor="newWndwY">새창</Label>
|
||||
</div>
|
||||
</RadioGroup>
|
||||
</FormControl>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableHead>배너 설명</TableHead>
|
||||
<TableCell className="border">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="bnrExpln"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<Textarea
|
||||
{...field}
|
||||
value={field.value ?? ""}
|
||||
className="!text-[1.3rem] !leading-6"
|
||||
placeholder="배너에 대한 설명을 입력해주세요"
|
||||
/>
|
||||
</FormControl>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableHead>사용여부</TableHead>
|
||||
<TableCell className="border">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="useYn"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<RadioGroup
|
||||
{...field}
|
||||
name="useYn"
|
||||
onValueChange={field.onChange}
|
||||
>
|
||||
<div className="flex items-center space-x-2">
|
||||
<RadioGroupItem value="Y" id="useY" />
|
||||
<Label htmlFor="useY">사용</Label>
|
||||
</div>
|
||||
<div className="flex items-center space-x-2">
|
||||
<RadioGroupItem value="N" id="useN" />
|
||||
<Label htmlFor="useN">미사용</Label>
|
||||
</div>
|
||||
</RadioGroup>
|
||||
</FormControl>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
</TableBody>
|
||||
</Table>
|
||||
</div>
|
||||
</FormWrapper>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -2,13 +2,10 @@
|
||||
|
||||
import Image from "next/image";
|
||||
import { useEffect, useState } from "react";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import type { UseFormReturn } from "react-hook-form";
|
||||
import type { HttpResponse, Upload } from "tus-js-client";
|
||||
import { useConfirm } from "@frontend-opensource/use-react-hooks";
|
||||
import {
|
||||
Button,
|
||||
FileUploader,
|
||||
Input,
|
||||
Label,
|
||||
@@ -21,10 +18,11 @@ import {
|
||||
TableHead,
|
||||
TableRow,
|
||||
} from "@common/components";
|
||||
import { FormWrapper } from "@/widgets/form-wrapper";
|
||||
import { CodeSelect } from "@/entities/code";
|
||||
import { AttachmentApi } from "@/entities/attachment";
|
||||
import { ENDPOINT } from "@/shared/config";
|
||||
import { Form, FormControl, FormField, FormItem } from "@/shared/ui/form";
|
||||
import { FormControl, FormField, FormItem } from "@/shared/ui/form";
|
||||
import type { ImageFormData } from "../model/image-interface";
|
||||
import { handleUpload } from "../lib/utils";
|
||||
|
||||
@@ -35,13 +33,10 @@ type ImageFormProps = {
|
||||
handleDelete?: () => Promise<void>;
|
||||
};
|
||||
|
||||
function ImageForm({ form, imgSn, handleSave, handleDelete }: ImageFormProps) {
|
||||
const isModifyMode = !!imgSn;
|
||||
function ImageForm({ form, imgSn, ...props }: ImageFormProps) {
|
||||
const atflYn = form.watch("atflYn");
|
||||
const atflCd = form.watch("atflCd");
|
||||
|
||||
const router = useRouter();
|
||||
const { confirm } = useConfirm();
|
||||
const [imageUrl, setImageUrl] = useState("");
|
||||
const [upload, setUpload] = useState<Upload | null>(null);
|
||||
const [progress, setProgress] = useState(0);
|
||||
@@ -53,22 +48,6 @@ function ImageForm({ form, imgSn, handleSave, handleDelete }: ImageFormProps) {
|
||||
enabled: !!atflCd,
|
||||
});
|
||||
|
||||
const onSubmit = async (data: ImageFormData) => {
|
||||
const confirmMessage = isModifyMode
|
||||
? "수정하시겠습니까?"
|
||||
: "저장하시겠습니까?";
|
||||
|
||||
if (await confirm(confirmMessage)) {
|
||||
await handleSave(data);
|
||||
}
|
||||
};
|
||||
|
||||
const onDelete = async () => {
|
||||
if (await confirm("삭제하시겠습니까?")) {
|
||||
await handleDelete?.();
|
||||
}
|
||||
};
|
||||
|
||||
const handleProgress = (percentage: string) => {
|
||||
setProgress(Number(percentage));
|
||||
};
|
||||
@@ -91,255 +70,233 @@ function ImageForm({ form, imgSn, handleSave, handleDelete }: ImageFormProps) {
|
||||
}, [atflId]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Form {...form}>
|
||||
<form onSubmit={form.handleSubmit(onSubmit)}>
|
||||
<div className="card">
|
||||
<Table variant="secondary">
|
||||
<colgroup>
|
||||
<col width="20%" />
|
||||
<col width="80%" />
|
||||
</colgroup>
|
||||
<TableBody>
|
||||
<TableRow>
|
||||
<TableHead>이미지명</TableHead>
|
||||
<TableCell className="border">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="imgTtl"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<Input
|
||||
{...field}
|
||||
value={field.value ?? ""}
|
||||
className="!text-[1.3rem]"
|
||||
placeholder="이미지명을 입력해주세요"
|
||||
/>
|
||||
</FormControl>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableHead>정렬순서</TableHead>
|
||||
<TableCell className="border">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="sortSeq"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<Input
|
||||
{...field}
|
||||
type="number"
|
||||
min={0}
|
||||
value={field.value ?? ""}
|
||||
onChange={(e) => {
|
||||
const value = e.target.value;
|
||||
if (isNaN(Number(value))) return;
|
||||
field.onChange(Number(value));
|
||||
}}
|
||||
className="w-[12rem] !text-[1.3rem]"
|
||||
placeholder="정렬순서를 입력해주세요"
|
||||
/>
|
||||
</FormControl>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableHead>이미지유형</TableHead>
|
||||
<TableCell className="border">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="imgTypeCd"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<CodeSelect
|
||||
{...field}
|
||||
value={field.value ?? ""}
|
||||
upCd="IMGTYPE"
|
||||
onValueChange={field.onChange}
|
||||
/>
|
||||
</FormControl>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableHead>첨부파일</TableHead>
|
||||
<TableCell className="border">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="atflYn"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<RadioGroup
|
||||
{...field}
|
||||
name="atflYn"
|
||||
onValueChange={field.onChange}
|
||||
>
|
||||
<div className="flex items-center space-x-2">
|
||||
<RadioGroupItem value="Y" id="atflY" />
|
||||
<Label htmlFor="atflY">이미지파일</Label>
|
||||
</div>
|
||||
<div className="flex items-center space-x-2">
|
||||
<RadioGroupItem value="N" id="atflN" />
|
||||
<Label htmlFor="atflN">외부링크</Label>
|
||||
</div>
|
||||
</RadioGroup>
|
||||
</FormControl>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
{atflYn === "Y" && (
|
||||
<TableRow>
|
||||
<TableHead>이미지파일</TableHead>
|
||||
<TableCell className="border">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="atflCd"
|
||||
render={() => (
|
||||
<FormItem className="flex flex-col">
|
||||
<FormControl>
|
||||
<FileUploader
|
||||
id="atflCd"
|
||||
className="!h-auto !max-w-none flex-col !items-start"
|
||||
accept=".jpeg,.jpg,.png"
|
||||
onUpload={(e) => {
|
||||
const files = e.target.files;
|
||||
if (!files) return;
|
||||
handleUpload(files, {
|
||||
handleUploadStart: setUpload,
|
||||
handleProgress,
|
||||
handleSuccess: setUpload,
|
||||
handleResponse: handleUploadResponse,
|
||||
});
|
||||
}}
|
||||
customPreview={
|
||||
<>
|
||||
<Label htmlFor="atflCd">
|
||||
<div className="relative h-[27rem] w-[48rem] overflow-hidden rounded-sm border border-border bg-accent">
|
||||
<p className="absolute bottom-3 left-0 p-2 text-base leading-none">
|
||||
{(upload?.file as File)?.name}
|
||||
</p>
|
||||
<div className="relative h-full w-full">
|
||||
{imageUrl && (
|
||||
<Image
|
||||
src={imageUrl}
|
||||
alt="업로드된 이미지"
|
||||
fill
|
||||
objectFit="contain"
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
<Progress
|
||||
value={progress}
|
||||
className="absolute bottom-0 left-0"
|
||||
<FormWrapper form={form} isModifyMode={!!imgSn} {...props}>
|
||||
<div className="card">
|
||||
<Table variant="secondary">
|
||||
<colgroup>
|
||||
<col width="20%" />
|
||||
<col width="80%" />
|
||||
</colgroup>
|
||||
<TableBody>
|
||||
<TableRow>
|
||||
<TableHead>이미지명</TableHead>
|
||||
<TableCell className="border">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="imgTtl"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<Input
|
||||
{...field}
|
||||
value={field.value ?? ""}
|
||||
className="!text-[1.3rem]"
|
||||
placeholder="이미지명을 입력해주세요"
|
||||
/>
|
||||
</FormControl>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableHead>정렬순서</TableHead>
|
||||
<TableCell className="border">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="sortSeq"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<Input
|
||||
{...field}
|
||||
type="number"
|
||||
min={0}
|
||||
value={field.value ?? ""}
|
||||
onChange={(e) => {
|
||||
const value = e.target.value;
|
||||
if (isNaN(Number(value))) return;
|
||||
field.onChange(Number(value));
|
||||
}}
|
||||
className="w-[12rem] !text-[1.3rem]"
|
||||
placeholder="정렬순서를 입력해주세요"
|
||||
/>
|
||||
</FormControl>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableHead>이미지유형</TableHead>
|
||||
<TableCell className="border">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="imgTypeCd"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<CodeSelect
|
||||
{...field}
|
||||
value={field.value ?? ""}
|
||||
upCd="IMGTYPE"
|
||||
onValueChange={field.onChange}
|
||||
/>
|
||||
</FormControl>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableHead>첨부파일</TableHead>
|
||||
<TableCell className="border">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="atflYn"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<RadioGroup
|
||||
{...field}
|
||||
name="atflYn"
|
||||
onValueChange={field.onChange}
|
||||
>
|
||||
<div className="flex items-center space-x-2">
|
||||
<RadioGroupItem value="Y" id="atflY" />
|
||||
<Label htmlFor="atflY">이미지파일</Label>
|
||||
</div>
|
||||
<div className="flex items-center space-x-2">
|
||||
<RadioGroupItem value="N" id="atflN" />
|
||||
<Label htmlFor="atflN">외부링크</Label>
|
||||
</div>
|
||||
</RadioGroup>
|
||||
</FormControl>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
{atflYn === "Y" && (
|
||||
<TableRow>
|
||||
<TableHead>이미지파일</TableHead>
|
||||
<TableCell className="border">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="atflCd"
|
||||
render={() => (
|
||||
<FormItem className="flex flex-col">
|
||||
<FormControl>
|
||||
<FileUploader
|
||||
id="atflCd"
|
||||
className="!h-auto !max-w-none flex-col !items-start"
|
||||
accept=".jpeg,.jpg,.png"
|
||||
onUpload={(e) => {
|
||||
const files = e.target.files;
|
||||
if (!files) return;
|
||||
handleUpload(files, {
|
||||
handleUploadStart: setUpload,
|
||||
handleProgress,
|
||||
handleSuccess: setUpload,
|
||||
handleResponse: handleUploadResponse,
|
||||
});
|
||||
}}
|
||||
customPreview={
|
||||
<>
|
||||
<Label htmlFor="atflCd">
|
||||
<div className="relative h-[27rem] w-[48rem] overflow-hidden rounded-sm border border-border bg-accent">
|
||||
<p className="absolute bottom-3 left-0 p-2 text-base leading-none">
|
||||
{(upload?.file as File)?.name}
|
||||
</p>
|
||||
<div className="relative h-full w-full">
|
||||
{imageUrl && (
|
||||
<Image
|
||||
src={imageUrl}
|
||||
alt="업로드된 이미지"
|
||||
fill
|
||||
objectFit="contain"
|
||||
/>
|
||||
</div>
|
||||
</Label>
|
||||
<div className="mb-2 text-lg font-medium text-label">
|
||||
<ul className="ml-10 list-disc">
|
||||
<li>권장 사이즈: 1920x500</li>
|
||||
<li>파일 최대 크기: 2MB</li>
|
||||
<li>확장자: jpg, jpeg, png 가능</li>
|
||||
</ul>
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
}
|
||||
/>
|
||||
</FormControl>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
)}
|
||||
{atflYn === "N" && (
|
||||
<TableRow>
|
||||
<TableHead>외부링크</TableHead>
|
||||
<TableCell className="border">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="lnkgUrlAddr"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<Input
|
||||
{...field}
|
||||
value={field.value ?? ""}
|
||||
className="!text-[1.3rem]"
|
||||
placeholder="외부링크를 입력해주세요"
|
||||
/>
|
||||
</FormControl>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
)}
|
||||
<TableRow>
|
||||
<TableHead>사용여부</TableHead>
|
||||
<TableCell className="border">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="useYn"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<RadioGroup
|
||||
{...field}
|
||||
name="useYn"
|
||||
onValueChange={field.onChange}
|
||||
>
|
||||
<div className="flex items-center space-x-2">
|
||||
<RadioGroupItem value="Y" id="useY" />
|
||||
<Label htmlFor="useY">사용</Label>
|
||||
</div>
|
||||
<div className="flex items-center space-x-2">
|
||||
<RadioGroupItem value="N" id="useN" />
|
||||
<Label htmlFor="useN">미사용</Label>
|
||||
</div>
|
||||
</RadioGroup>
|
||||
</FormControl>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
</TableBody>
|
||||
</Table>
|
||||
</div>
|
||||
<div className="flex justify-center gap-4 pb-12 pt-10">
|
||||
<Button
|
||||
size="lg"
|
||||
color="white"
|
||||
type="button"
|
||||
onClick={() => router.back()}
|
||||
>
|
||||
목록
|
||||
</Button>
|
||||
<Button size="lg" type="submit">
|
||||
저장
|
||||
</Button>
|
||||
{isModifyMode && (
|
||||
<Button size="lg" color="red" type="button" onClick={onDelete}>
|
||||
삭제
|
||||
</Button>
|
||||
<Progress
|
||||
value={progress}
|
||||
className="absolute bottom-0 left-0"
|
||||
/>
|
||||
</div>
|
||||
</Label>
|
||||
<div className="mb-2 text-lg font-medium text-label">
|
||||
<ul className="ml-10 list-disc">
|
||||
<li>권장 사이즈: 1920x500</li>
|
||||
<li>파일 최대 크기: 2MB</li>
|
||||
<li>확장자: jpg, jpeg, png 가능</li>
|
||||
</ul>
|
||||
</div>
|
||||
</>
|
||||
}
|
||||
/>
|
||||
</FormControl>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
)}
|
||||
</div>
|
||||
</form>
|
||||
</Form>
|
||||
</>
|
||||
{atflYn === "N" && (
|
||||
<TableRow>
|
||||
<TableHead>외부링크</TableHead>
|
||||
<TableCell className="border">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="lnkgUrlAddr"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<Input
|
||||
{...field}
|
||||
value={field.value ?? ""}
|
||||
className="!text-[1.3rem]"
|
||||
placeholder="외부링크를 입력해주세요"
|
||||
/>
|
||||
</FormControl>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
)}
|
||||
<TableRow>
|
||||
<TableHead>사용여부</TableHead>
|
||||
<TableCell className="border">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="useYn"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<RadioGroup
|
||||
{...field}
|
||||
name="useYn"
|
||||
onValueChange={field.onChange}
|
||||
>
|
||||
<div className="flex items-center space-x-2">
|
||||
<RadioGroupItem value="Y" id="useY" />
|
||||
<Label htmlFor="useY">사용</Label>
|
||||
</div>
|
||||
<div className="flex items-center space-x-2">
|
||||
<RadioGroupItem value="N" id="useN" />
|
||||
<Label htmlFor="useN">미사용</Label>
|
||||
</div>
|
||||
</RadioGroup>
|
||||
</FormControl>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
</TableBody>
|
||||
</Table>
|
||||
</div>
|
||||
</FormWrapper>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
import { useState } from "react";
|
||||
import type { UseFormReturn } from "react-hook-form";
|
||||
import { useConfirm } from "@frontend-opensource/use-react-hooks";
|
||||
import { Button } from "@common/components";
|
||||
import { Form } from "@/shared/ui/form";
|
||||
import { ConfirmDialog } from "@/shared/ui/confirm-dialog";
|
||||
import type { MenuFormData } from "../model/menu-interface";
|
||||
import { BaseMenuForm } from "./base-menu-form";
|
||||
import { TypeMenuForm } from "./type-menu-form";
|
||||
@@ -33,13 +31,6 @@ function MenuForm({
|
||||
const isModifyMode = !!menuCd;
|
||||
|
||||
const { confirm } = useConfirm();
|
||||
const [onConfirm, setOnConfirm] = useState(false);
|
||||
|
||||
const handleConfirm = async (callback: () => Promise<void>) => {
|
||||
setOnConfirm(true);
|
||||
await callback();
|
||||
setOnConfirm(false);
|
||||
};
|
||||
|
||||
const onSubmit = async (data: MenuFormData) => {
|
||||
if (isModifyMode) {
|
||||
@@ -50,65 +41,53 @@ function MenuForm({
|
||||
};
|
||||
|
||||
const onCreate = async (data: MenuFormData) => {
|
||||
await handleConfirm(async () => {
|
||||
if (await confirm("저장하시겠습니까?")) {
|
||||
setOnConfirm(false);
|
||||
handleCreate(data);
|
||||
}
|
||||
});
|
||||
if (await confirm("저장하시겠습니까?")) {
|
||||
handleCreate(data);
|
||||
}
|
||||
};
|
||||
|
||||
const onUpdate = async (data: MenuFormData) => {
|
||||
await handleConfirm(async () => {
|
||||
if (await confirm("수정하시겠습니까?")) {
|
||||
setOnConfirm(false);
|
||||
handleUpdate({ menuCd: menuCd!, data });
|
||||
}
|
||||
});
|
||||
if (await confirm("수정하시겠습니까?")) {
|
||||
handleUpdate({ menuCd: menuCd!, data });
|
||||
}
|
||||
};
|
||||
|
||||
const onDelete = () => {
|
||||
handleConfirm(async () => {
|
||||
if (await confirm("삭제하시겠습니까?")) {
|
||||
setOnConfirm(false);
|
||||
handleDelete?.(menuCd!);
|
||||
}
|
||||
});
|
||||
const onDelete = async () => {
|
||||
if (await confirm("삭제하시겠습니까?")) {
|
||||
handleDelete?.(menuCd!);
|
||||
}
|
||||
};
|
||||
|
||||
const menuType = form.watch("menuLnkgTypeCd");
|
||||
const isSubmitDisabled = !form.watch("siteId");
|
||||
|
||||
return (
|
||||
<>
|
||||
<Form {...form}>
|
||||
<form onSubmit={form.handleSubmit(onSubmit)}>
|
||||
<div className="card card-border">
|
||||
<div className="card-header">
|
||||
<h3 className="text-2xl font-medium text-label">
|
||||
{isModifyMode ? "메뉴 수정" : "메뉴 등록"}
|
||||
</h3>
|
||||
<PermissionsManagementDialog menuCd={menuCd} />
|
||||
</div>
|
||||
<div className="card">
|
||||
<BaseMenuForm form={form} menuCd={menuCd} />
|
||||
<TypeMenuForm form={form} menuType={menuType} />
|
||||
</div>
|
||||
<Form {...form}>
|
||||
<form onSubmit={form.handleSubmit(onSubmit)}>
|
||||
<div className="card card-border">
|
||||
<div className="card-header">
|
||||
<h3 className="text-2xl font-medium text-label">
|
||||
{isModifyMode ? "메뉴 수정" : "메뉴 등록"}
|
||||
</h3>
|
||||
<PermissionsManagementDialog menuCd={menuCd} />
|
||||
</div>
|
||||
<div className="flex justify-center gap-4 pb-12 pt-10">
|
||||
<Button size="lg" type="submit" disabled={isSubmitDisabled}>
|
||||
저장
|
||||
<div className="card">
|
||||
<BaseMenuForm form={form} menuCd={menuCd} />
|
||||
<TypeMenuForm form={form} menuType={menuType} />
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex justify-center gap-4 pb-12 pt-10">
|
||||
<Button size="lg" type="submit" disabled={isSubmitDisabled}>
|
||||
저장
|
||||
</Button>
|
||||
{isModifyMode && (
|
||||
<Button size="lg" color="red" type="button" onClick={onDelete}>
|
||||
삭제
|
||||
</Button>
|
||||
{isModifyMode && (
|
||||
<Button size="lg" color="red" type="button" onClick={onDelete}>
|
||||
삭제
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
</form>
|
||||
</Form>
|
||||
<ConfirmDialog open={onConfirm} />
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</form>
|
||||
</Form>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -29,9 +29,9 @@ function CreatePage() {
|
||||
faxNo: "",
|
||||
telNo: "",
|
||||
lwndCn: "",
|
||||
bscSiteYn: "",
|
||||
bscSiteYn: "Y",
|
||||
bkmkIcon: "",
|
||||
useYn: "",
|
||||
useYn: "Y",
|
||||
siteSkn: "",
|
||||
},
|
||||
});
|
||||
|
||||
@@ -32,7 +32,6 @@ import {
|
||||
type Domain,
|
||||
type DomainFormData,
|
||||
} from "../model/domain-interface";
|
||||
import { ConfirmDialog } from "@/shared/ui/confirm-dialog";
|
||||
import { useAlertStore } from "@/shared/lib/use-alert-store";
|
||||
|
||||
type DomainManagementDialogProps = {
|
||||
@@ -79,7 +78,6 @@ function DomainManagementDialog({
|
||||
name: "domains",
|
||||
});
|
||||
|
||||
const [onConfirm, setOnConfirm] = useState(false);
|
||||
const [selectedRows, setSelectedRows] = useState<number[]>([]);
|
||||
|
||||
const initialForm = () => {
|
||||
@@ -88,14 +86,11 @@ function DomainManagementDialog({
|
||||
};
|
||||
|
||||
const onSubmit = async (data: DomainFormData) => {
|
||||
setOnConfirm(true);
|
||||
if (await confirm("저장하시겠습니까?")) {
|
||||
setOnConfirm(false);
|
||||
await mutateAsync(data.domains);
|
||||
handleSaveDomain?.(data.domains);
|
||||
alert("저장되었습니다.");
|
||||
}
|
||||
setOnConfirm(false);
|
||||
};
|
||||
|
||||
const handleAddDomain = () => {
|
||||
@@ -153,160 +148,157 @@ function DomainManagementDialog({
|
||||
fields.length > 0 && selectedRows.length === fields.length;
|
||||
|
||||
return (
|
||||
<>
|
||||
<Dialog {...props}>
|
||||
<DialogTrigger asChild>
|
||||
<Button>도메인 관리</Button>
|
||||
</DialogTrigger>
|
||||
<DialogContent className="max-w-[60rem]" aria-describedby={undefined}>
|
||||
<DialogHeader>
|
||||
<DialogTitle>도메인 관리</DialogTitle>
|
||||
</DialogHeader>
|
||||
<Form {...form}>
|
||||
<form
|
||||
onSubmit={(e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
form.handleSubmit(onSubmit)(e);
|
||||
}}
|
||||
>
|
||||
<div className="mb-4 flex justify-end gap-2">
|
||||
<Button type="button" size="sm" onClick={handleAddDomain}>
|
||||
항목 추가
|
||||
<Dialog {...props}>
|
||||
<DialogTrigger asChild>
|
||||
<Button>도메인 관리</Button>
|
||||
</DialogTrigger>
|
||||
<DialogContent className="max-w-[60rem]" aria-describedby={undefined}>
|
||||
<DialogHeader>
|
||||
<DialogTitle>도메인 관리</DialogTitle>
|
||||
</DialogHeader>
|
||||
<Form {...form}>
|
||||
<form
|
||||
onSubmit={(e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
form.handleSubmit(onSubmit)(e);
|
||||
}}
|
||||
>
|
||||
<div className="mb-4 flex justify-end gap-2">
|
||||
<Button type="button" size="sm" onClick={handleAddDomain}>
|
||||
항목 추가
|
||||
</Button>
|
||||
<Button
|
||||
type="button"
|
||||
size="sm"
|
||||
color="red"
|
||||
onClick={handleDeleteDomain}
|
||||
disabled={selectedRows.length === 0}
|
||||
>
|
||||
항목 삭제
|
||||
</Button>
|
||||
</div>
|
||||
<div className="card card-border max-h-[28.5rem] overflow-auto">
|
||||
<Table variant="secondary">
|
||||
<colgroup>
|
||||
<col width="10%" />
|
||||
<col width="auto" />
|
||||
<col width="15%" />
|
||||
<col width="25%" />
|
||||
</colgroup>
|
||||
<TableHeader className="sticky -top-[0.6rem]">
|
||||
<TableRow>
|
||||
<TableHead className="!px-0">
|
||||
<Checkbox
|
||||
checked={isAllSelected}
|
||||
onCheckedChange={handleSelectAll}
|
||||
/>
|
||||
</TableHead>
|
||||
<TableHead>도메인 주소</TableHead>
|
||||
<TableHead>대표 URL</TableHead>
|
||||
<TableHead>사용여부</TableHead>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
{fields.map((field, i) => {
|
||||
if (field.mode === "D") return null;
|
||||
return (
|
||||
<TableRow key={field.id}>
|
||||
<TableCell align="center" className="!px-0">
|
||||
<Checkbox
|
||||
checked={selectedRows.includes(i)}
|
||||
onCheckedChange={() => handleSelectRow(i)}
|
||||
/>
|
||||
</TableCell>
|
||||
<TableCell align="center">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name={`domains.${i}.dmnAddr`}
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<Input
|
||||
{...field}
|
||||
className="!text-[1.3rem]"
|
||||
/>
|
||||
</FormControl>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</TableCell>
|
||||
<TableCell align="center">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name={`domains.${i}.rprsDmnYn`}
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<Checkbox
|
||||
checked={field.value === "Y"}
|
||||
onCheckedChange={(checked) => {
|
||||
field.onChange(checked ? "Y" : "N");
|
||||
handleChangeRprsDmnYn(i);
|
||||
}}
|
||||
/>
|
||||
</FormControl>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</TableCell>
|
||||
<TableCell align="center">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name={`domains.${i}.useYn`}
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<RadioGroup
|
||||
value={field.value}
|
||||
onValueChange={field.onChange}
|
||||
className="flex justify-center"
|
||||
>
|
||||
<div className="flex items-center space-x-2">
|
||||
<RadioGroupItem
|
||||
value="Y"
|
||||
id={`useY-${i}`}
|
||||
/>
|
||||
<Label htmlFor={`useY-${i}`}>예</Label>
|
||||
</div>
|
||||
<div className="flex items-center space-x-2">
|
||||
<RadioGroupItem
|
||||
value="N"
|
||||
id={`useN-${i}`}
|
||||
/>
|
||||
<Label htmlFor={`useN-${i}`}>
|
||||
아니오
|
||||
</Label>
|
||||
</div>
|
||||
</RadioGroup>
|
||||
</FormControl>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
);
|
||||
})}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</div>
|
||||
<DialogFooter className="!justify-center">
|
||||
<Button type="submit" size="lg">
|
||||
저장
|
||||
</Button>
|
||||
<DialogClose asChild>
|
||||
<Button type="button" size="lg" color="white">
|
||||
취소
|
||||
</Button>
|
||||
<Button
|
||||
type="button"
|
||||
size="sm"
|
||||
color="red"
|
||||
onClick={handleDeleteDomain}
|
||||
disabled={selectedRows.length === 0}
|
||||
>
|
||||
항목 삭제
|
||||
</Button>
|
||||
</div>
|
||||
<div className="card card-border max-h-[28.5rem] overflow-auto">
|
||||
<Table variant="secondary">
|
||||
<colgroup>
|
||||
<col width="10%" />
|
||||
<col width="auto" />
|
||||
<col width="15%" />
|
||||
<col width="25%" />
|
||||
</colgroup>
|
||||
<TableHeader className="sticky -top-[0.6rem]">
|
||||
<TableRow>
|
||||
<TableHead className="!px-0">
|
||||
<Checkbox
|
||||
checked={isAllSelected}
|
||||
onCheckedChange={handleSelectAll}
|
||||
/>
|
||||
</TableHead>
|
||||
<TableHead>도메인 주소</TableHead>
|
||||
<TableHead>대표 URL</TableHead>
|
||||
<TableHead>사용여부</TableHead>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
{fields.map((field, i) => {
|
||||
if (field.mode === "D") return null;
|
||||
return (
|
||||
<TableRow key={field.id}>
|
||||
<TableCell align="center" className="!px-0">
|
||||
<Checkbox
|
||||
checked={selectedRows.includes(i)}
|
||||
onCheckedChange={() => handleSelectRow(i)}
|
||||
/>
|
||||
</TableCell>
|
||||
<TableCell align="center">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name={`domains.${i}.dmnAddr`}
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<Input
|
||||
{...field}
|
||||
className="!text-[1.3rem]"
|
||||
/>
|
||||
</FormControl>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</TableCell>
|
||||
<TableCell align="center">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name={`domains.${i}.rprsDmnYn`}
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<Checkbox
|
||||
checked={field.value === "Y"}
|
||||
onCheckedChange={(checked) => {
|
||||
field.onChange(checked ? "Y" : "N");
|
||||
handleChangeRprsDmnYn(i);
|
||||
}}
|
||||
/>
|
||||
</FormControl>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</TableCell>
|
||||
<TableCell align="center">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name={`domains.${i}.useYn`}
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<RadioGroup
|
||||
value={field.value}
|
||||
onValueChange={field.onChange}
|
||||
className="flex justify-center"
|
||||
>
|
||||
<div className="flex items-center space-x-2">
|
||||
<RadioGroupItem
|
||||
value="Y"
|
||||
id={`useY-${i}`}
|
||||
/>
|
||||
<Label htmlFor={`useY-${i}`}>예</Label>
|
||||
</div>
|
||||
<div className="flex items-center space-x-2">
|
||||
<RadioGroupItem
|
||||
value="N"
|
||||
id={`useN-${i}`}
|
||||
/>
|
||||
<Label htmlFor={`useN-${i}`}>
|
||||
아니오
|
||||
</Label>
|
||||
</div>
|
||||
</RadioGroup>
|
||||
</FormControl>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
);
|
||||
})}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</div>
|
||||
<DialogFooter className="!justify-center">
|
||||
<Button type="submit" size="lg">
|
||||
저장
|
||||
</Button>
|
||||
<DialogClose asChild>
|
||||
<Button type="button" size="lg" color="white">
|
||||
취소
|
||||
</Button>
|
||||
</DialogClose>
|
||||
</DialogFooter>
|
||||
</form>
|
||||
</Form>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
<ConfirmDialog open={onConfirm} />
|
||||
</>
|
||||
</DialogClose>
|
||||
</DialogFooter>
|
||||
</form>
|
||||
</Form>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -28,7 +28,6 @@ import { Form, FormControl, FormField, FormItem } from "@/shared/ui/form";
|
||||
import { ENDPOINT } from "@/shared/config";
|
||||
import { IpApi } from "../api/ip-service";
|
||||
import { ipFormSchema, type IP, type IPFormData } from "../model/ip-interface";
|
||||
import { ConfirmDialog } from "@/shared/ui/confirm-dialog";
|
||||
import { useAlertStore } from "@/shared/lib/use-alert-store";
|
||||
|
||||
type IPManagementDialogProps = {
|
||||
@@ -75,7 +74,6 @@ function IPManagementDialog({
|
||||
name: "ips",
|
||||
});
|
||||
|
||||
const [onConfirm, setOnConfirm] = useState(false);
|
||||
const [selectedRows, setSelectedRows] = useState<number[]>([]);
|
||||
|
||||
const initialForm = () => {
|
||||
@@ -84,13 +82,10 @@ function IPManagementDialog({
|
||||
};
|
||||
|
||||
const onSubmit = async (data: IPFormData) => {
|
||||
setOnConfirm(true);
|
||||
if (await confirm("저장하시겠습니까?")) {
|
||||
setOnConfirm(false);
|
||||
await mutateAsync(data.ips);
|
||||
alert("저장되었습니다.");
|
||||
}
|
||||
setOnConfirm(false);
|
||||
};
|
||||
|
||||
const handleAddIP = () => {
|
||||
@@ -140,139 +135,136 @@ function IPManagementDialog({
|
||||
fields.length > 0 && selectedRows.length === fields.length;
|
||||
|
||||
return (
|
||||
<>
|
||||
<Dialog {...props}>
|
||||
<DialogTrigger asChild>
|
||||
<Button disabled={triggerDisabled}>IP 관리</Button>
|
||||
</DialogTrigger>
|
||||
<DialogContent className="max-w-[60rem]" aria-describedby={undefined}>
|
||||
<DialogHeader>
|
||||
<DialogTitle>IP 관리</DialogTitle>
|
||||
</DialogHeader>
|
||||
<Form {...form}>
|
||||
<form
|
||||
onSubmit={(e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
form.handleSubmit(onSubmit)(e);
|
||||
}}
|
||||
>
|
||||
<div className="mb-4 flex justify-end gap-2">
|
||||
<Button type="button" size="sm" onClick={handleAddIP}>
|
||||
항목 추가
|
||||
<Dialog {...props}>
|
||||
<DialogTrigger asChild>
|
||||
<Button disabled={triggerDisabled}>IP 관리</Button>
|
||||
</DialogTrigger>
|
||||
<DialogContent className="max-w-[60rem]" aria-describedby={undefined}>
|
||||
<DialogHeader>
|
||||
<DialogTitle>IP 관리</DialogTitle>
|
||||
</DialogHeader>
|
||||
<Form {...form}>
|
||||
<form
|
||||
onSubmit={(e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
form.handleSubmit(onSubmit)(e);
|
||||
}}
|
||||
>
|
||||
<div className="mb-4 flex justify-end gap-2">
|
||||
<Button type="button" size="sm" onClick={handleAddIP}>
|
||||
항목 추가
|
||||
</Button>
|
||||
<Button
|
||||
type="button"
|
||||
size="sm"
|
||||
color="red"
|
||||
onClick={handleDeleteIP}
|
||||
disabled={selectedRows.length === 0}
|
||||
>
|
||||
항목 삭제
|
||||
</Button>
|
||||
</div>
|
||||
<div className="card card-border max-h-[28.5rem] overflow-auto">
|
||||
<Table variant="secondary">
|
||||
<colgroup>
|
||||
<col width="10%" />
|
||||
<col width="65%" />
|
||||
<col width="25%" />
|
||||
</colgroup>
|
||||
<TableHeader className="sticky -top-[0.6rem]">
|
||||
<TableRow>
|
||||
<TableHead className="!px-0">
|
||||
<Checkbox
|
||||
checked={isAllSelected}
|
||||
onCheckedChange={handleSelectAll}
|
||||
/>
|
||||
</TableHead>
|
||||
<TableHead>IP 주소</TableHead>
|
||||
<TableHead>허용여부</TableHead>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
{fields.map((field, i) => {
|
||||
if (field.mode === "D") return null;
|
||||
return (
|
||||
<TableRow key={field.id}>
|
||||
<TableCell align="center" className="!px-0">
|
||||
<Checkbox
|
||||
checked={selectedRows.includes(i)}
|
||||
onCheckedChange={() => handleSelectRow(i)}
|
||||
/>
|
||||
</TableCell>
|
||||
<TableCell align="center">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name={`ips.${i}.ipAddr`}
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<Input
|
||||
{...field}
|
||||
className="!text-[1.3rem]"
|
||||
/>
|
||||
</FormControl>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</TableCell>
|
||||
<TableCell align="center">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name={`ips.${i}.prmYn`}
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<RadioGroup
|
||||
value={field.value}
|
||||
onValueChange={field.onChange}
|
||||
className="flex justify-center"
|
||||
>
|
||||
<div className="flex items-center space-x-2">
|
||||
<RadioGroupItem
|
||||
value="Y"
|
||||
id={`prmY-${i}`}
|
||||
/>
|
||||
<Label htmlFor={`prmY-${i}`}>예</Label>
|
||||
</div>
|
||||
<div className="flex items-center space-x-2">
|
||||
<RadioGroupItem
|
||||
value="N"
|
||||
id={`prmN-${i}`}
|
||||
/>
|
||||
<Label htmlFor={`prmN-${i}`}>
|
||||
아니오
|
||||
</Label>
|
||||
</div>
|
||||
</RadioGroup>
|
||||
</FormControl>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
);
|
||||
})}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</div>
|
||||
<DialogFooter className="!justify-center">
|
||||
<Button type="submit" size="lg">
|
||||
저장
|
||||
</Button>
|
||||
<DialogClose asChild>
|
||||
<Button type="button" size="lg" color="white">
|
||||
취소
|
||||
</Button>
|
||||
<Button
|
||||
type="button"
|
||||
size="sm"
|
||||
color="red"
|
||||
onClick={handleDeleteIP}
|
||||
disabled={selectedRows.length === 0}
|
||||
>
|
||||
항목 삭제
|
||||
</Button>
|
||||
</div>
|
||||
<div className="card card-border max-h-[28.5rem] overflow-auto">
|
||||
<Table variant="secondary">
|
||||
<colgroup>
|
||||
<col width="10%" />
|
||||
<col width="65%" />
|
||||
<col width="25%" />
|
||||
</colgroup>
|
||||
<TableHeader className="sticky -top-[0.6rem]">
|
||||
<TableRow>
|
||||
<TableHead className="!px-0">
|
||||
<Checkbox
|
||||
checked={isAllSelected}
|
||||
onCheckedChange={handleSelectAll}
|
||||
/>
|
||||
</TableHead>
|
||||
<TableHead>IP 주소</TableHead>
|
||||
<TableHead>허용여부</TableHead>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
{fields.map((field, i) => {
|
||||
if (field.mode === "D") return null;
|
||||
return (
|
||||
<TableRow key={field.id}>
|
||||
<TableCell align="center" className="!px-0">
|
||||
<Checkbox
|
||||
checked={selectedRows.includes(i)}
|
||||
onCheckedChange={() => handleSelectRow(i)}
|
||||
/>
|
||||
</TableCell>
|
||||
<TableCell align="center">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name={`ips.${i}.ipAddr`}
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<Input
|
||||
{...field}
|
||||
className="!text-[1.3rem]"
|
||||
/>
|
||||
</FormControl>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</TableCell>
|
||||
<TableCell align="center">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name={`ips.${i}.prmYn`}
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<RadioGroup
|
||||
value={field.value}
|
||||
onValueChange={field.onChange}
|
||||
className="flex justify-center"
|
||||
>
|
||||
<div className="flex items-center space-x-2">
|
||||
<RadioGroupItem
|
||||
value="Y"
|
||||
id={`prmY-${i}`}
|
||||
/>
|
||||
<Label htmlFor={`prmY-${i}`}>예</Label>
|
||||
</div>
|
||||
<div className="flex items-center space-x-2">
|
||||
<RadioGroupItem
|
||||
value="N"
|
||||
id={`prmN-${i}`}
|
||||
/>
|
||||
<Label htmlFor={`prmN-${i}`}>
|
||||
아니오
|
||||
</Label>
|
||||
</div>
|
||||
</RadioGroup>
|
||||
</FormControl>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
);
|
||||
})}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</div>
|
||||
<DialogFooter className="!justify-center">
|
||||
<Button type="submit" size="lg">
|
||||
저장
|
||||
</Button>
|
||||
<DialogClose asChild>
|
||||
<Button type="button" size="lg" color="white">
|
||||
취소
|
||||
</Button>
|
||||
</DialogClose>
|
||||
</DialogFooter>
|
||||
</form>
|
||||
</Form>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
<ConfirmDialog open={onConfirm} />
|
||||
</>
|
||||
</DialogClose>
|
||||
</DialogFooter>
|
||||
</form>
|
||||
</Form>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
import { useState } from "react";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { useConfirm } from "@frontend-opensource/use-react-hooks";
|
||||
import { type UseFormReturn } from "react-hook-form";
|
||||
import {
|
||||
Button,
|
||||
Input,
|
||||
Label,
|
||||
RadioGroup,
|
||||
@@ -14,10 +11,10 @@ import {
|
||||
TableHead,
|
||||
TableRow,
|
||||
} from "@common/components";
|
||||
import { FormWrapper } from "@/widgets/form-wrapper";
|
||||
import { CodeSelect } from "@/entities/code";
|
||||
import type { SiteFormData } from "@/entities/site";
|
||||
import { FormItem, FormControl, FormField, Form } from "@/shared/ui/form";
|
||||
import { ConfirmDialog } from "@/shared/ui/confirm-dialog";
|
||||
import { FormItem, FormControl, FormField } from "@/shared/ui/form";
|
||||
import type { Domain } from "../model/domain-interface";
|
||||
import { IPManagementDialog } from "./ip-management-dialog";
|
||||
import { DomainManagementDialog } from "./domain-management-dialog";
|
||||
@@ -29,21 +26,12 @@ type SiteFormProps = {
|
||||
handleDelete?: () => Promise<void>;
|
||||
};
|
||||
|
||||
function SiteForm({ form, siteId, handleSave, handleDelete }: SiteFormProps) {
|
||||
function SiteForm({ form, siteId, ...props }: SiteFormProps) {
|
||||
const isModifyMode = !!siteId;
|
||||
|
||||
const router = useRouter();
|
||||
const { confirm } = useConfirm();
|
||||
const [onConfirm, setOnConfirm] = useState(false);
|
||||
const [isIpManagementOpen, setIsIpManagementOpen] = useState(false);
|
||||
const [isDomainManagementOpen, setIsDomainManagementOpen] = useState(false);
|
||||
|
||||
const handleConfirm = async (callback: () => Promise<void>) => {
|
||||
setOnConfirm(true);
|
||||
await callback();
|
||||
setOnConfirm(false);
|
||||
};
|
||||
|
||||
const handleSaveDomain = (rows: Domain[]) => {
|
||||
form.setValue(
|
||||
"dmnAddr",
|
||||
@@ -51,359 +39,314 @@ function SiteForm({ form, siteId, handleSave, handleDelete }: SiteFormProps) {
|
||||
);
|
||||
};
|
||||
|
||||
const onSubmit = async (data: SiteFormData) => {
|
||||
const confirmMessage = isModifyMode
|
||||
? "수정하시겠습니까?"
|
||||
: "저장하시겠습니까?";
|
||||
|
||||
await handleConfirm(async () => {
|
||||
if (await confirm(confirmMessage)) {
|
||||
setOnConfirm(false);
|
||||
handleSave(data);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const onDelete = async () => {
|
||||
await handleConfirm(async () => {
|
||||
if (await confirm("삭제하시겠습니까?")) {
|
||||
setOnConfirm(false);
|
||||
handleDelete?.();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<Form {...form}>
|
||||
<form onSubmit={form.handleSubmit(onSubmit)}>
|
||||
<div className="card">
|
||||
<Table variant="secondary">
|
||||
<colgroup>
|
||||
<col width="20%" />
|
||||
<col width="80%" />
|
||||
</colgroup>
|
||||
<TableBody>
|
||||
<TableRow>
|
||||
<TableHead>사이트 코드</TableHead>
|
||||
<TableCell className="border">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="siteId"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<Input
|
||||
{...field}
|
||||
value={field.value ?? ""}
|
||||
className="w-[12rem] !text-[1.3rem]"
|
||||
disabled={isModifyMode}
|
||||
/>
|
||||
</FormControl>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableHead>사이트 구분</TableHead>
|
||||
<TableCell className="border">
|
||||
<div className="flex gap-2">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="siteKndCd"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<CodeSelect
|
||||
{...field}
|
||||
upCd="SITEKNDCD"
|
||||
onValueChange={field.onChange}
|
||||
/>
|
||||
</FormControl>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
{isModifyMode && (
|
||||
<IPManagementDialog
|
||||
siteId={siteId}
|
||||
triggerDisabled={form.watch("siteKndCd") === "O"}
|
||||
open={isIpManagementOpen}
|
||||
onOpenChange={setIsIpManagementOpen}
|
||||
<FormWrapper form={form} isModifyMode={isModifyMode} {...props}>
|
||||
<div className="card">
|
||||
<Table variant="secondary">
|
||||
<colgroup>
|
||||
<col width="20%" />
|
||||
<col width="80%" />
|
||||
</colgroup>
|
||||
<TableBody>
|
||||
<TableRow>
|
||||
<TableHead>사이트 코드</TableHead>
|
||||
<TableCell className="border">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="siteId"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<Input
|
||||
{...field}
|
||||
value={field.value ?? ""}
|
||||
className="w-[12rem] !text-[1.3rem]"
|
||||
disabled={isModifyMode}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableHead>사이트 디자인</TableHead>
|
||||
<TableCell className="border">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="siteSkn"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<CodeSelect
|
||||
{...field}
|
||||
value={field.value ?? ""}
|
||||
upCd="SITESKINCD"
|
||||
onValueChange={field.onChange}
|
||||
/>
|
||||
</FormControl>
|
||||
</FormItem>
|
||||
)}
|
||||
</FormControl>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableHead>사이트 구분</TableHead>
|
||||
<TableCell className="border">
|
||||
<div className="flex gap-2">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="siteKndCd"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<CodeSelect
|
||||
{...field}
|
||||
upCd="SITEKNDCD"
|
||||
onValueChange={field.onChange}
|
||||
/>
|
||||
</FormControl>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
{isModifyMode && (
|
||||
<IPManagementDialog
|
||||
siteId={siteId}
|
||||
triggerDisabled={form.watch("siteKndCd") === "O"}
|
||||
open={isIpManagementOpen}
|
||||
onOpenChange={setIsIpManagementOpen}
|
||||
/>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableHead>사이트명</TableHead>
|
||||
<TableCell className="border">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="siteNm"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<Input
|
||||
{...field}
|
||||
value={field.value ?? ""}
|
||||
className="!text-[1.3rem]"
|
||||
placeholder="사이트명을 입력하십시오."
|
||||
/>
|
||||
</FormControl>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableHead>사이트 설명</TableHead>
|
||||
<TableCell className="border">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="siteExpln"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<Input
|
||||
{...field}
|
||||
value={field.value ?? ""}
|
||||
className="!text-[1.3rem]"
|
||||
placeholder="사이트 설명을 입력하십시오."
|
||||
/>
|
||||
</FormControl>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
{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">
|
||||
{form.watch("dmnAddr")}
|
||||
</div>
|
||||
<DomainManagementDialog
|
||||
siteId={siteId}
|
||||
open={isDomainManagementOpen}
|
||||
onOpenChange={setIsDomainManagementOpen}
|
||||
handleSaveDomain={handleSaveDomain}
|
||||
)}
|
||||
</div>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableHead>사이트 디자인</TableHead>
|
||||
<TableCell className="border">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="siteSkn"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<CodeSelect
|
||||
{...field}
|
||||
value={field.value ?? ""}
|
||||
upCd="SITESKINCD"
|
||||
onValueChange={field.onChange}
|
||||
/>
|
||||
</div>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
)}
|
||||
<TableRow>
|
||||
<TableHead>사이트 하단 표기 주소</TableHead>
|
||||
<TableCell className="border">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="siteAddr"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<Input
|
||||
{...field}
|
||||
value={field.value ?? ""}
|
||||
className="!text-[1.3rem]"
|
||||
placeholder="사이트 하단 주소를 입력하십시오."
|
||||
/>
|
||||
</FormControl>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableHead>사이트 하단 표기 전화번호</TableHead>
|
||||
<TableCell className="border">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="telNo"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<Input
|
||||
{...field}
|
||||
value={field.value ?? ""}
|
||||
className="!text-[1.3rem]"
|
||||
placeholder="사이트 하단 전화번호를 입력하십시오."
|
||||
/>
|
||||
</FormControl>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableHead>사이트 하단 표기 팩스번호</TableHead>
|
||||
<TableCell className="border">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="faxNo"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<Input
|
||||
{...field}
|
||||
value={field.value ?? ""}
|
||||
className="!text-[1.3rem]"
|
||||
placeholder="사이트 하단 팩스번호를 입력하십시오."
|
||||
/>
|
||||
</FormControl>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableHead>사이트 하단 표기 내용</TableHead>
|
||||
<TableCell className="border">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="lwndCn"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<Input
|
||||
{...field}
|
||||
value={field.value ?? ""}
|
||||
className="!text-[1.3rem]"
|
||||
placeholder="사이트 표기 내용을 입력하십시오. (ex. COPYRIGHT c 2013 KECO. ALL RIGHTS RESERVED.)"
|
||||
/>
|
||||
</FormControl>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableHead>북마크 아이콘</TableHead>
|
||||
<TableCell className="border">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="bkmkIcon"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<Input
|
||||
{...field}
|
||||
value={field.value ?? ""}
|
||||
className="!text-[1.3rem]"
|
||||
placeholder="아이콘 파일 경로 및 파일명을 입력하여 주십시오."
|
||||
/>
|
||||
</FormControl>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableHead>기본 사이트 여부</TableHead>
|
||||
<TableCell className="border">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="bscSiteYn"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<RadioGroup
|
||||
{...field}
|
||||
name="bscSiteYn"
|
||||
onValueChange={field.onChange}
|
||||
>
|
||||
<div className="flex items-center space-x-2">
|
||||
<RadioGroupItem value="Y" id="bscSiteY" />
|
||||
<Label htmlFor="bscSiteY">예</Label>
|
||||
</div>
|
||||
<div className="flex items-center space-x-2">
|
||||
<RadioGroupItem value="N" id="bscSiteN" />
|
||||
<Label htmlFor="bscSiteN">아니오</Label>
|
||||
</div>
|
||||
</RadioGroup>
|
||||
</FormControl>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableHead>사용 여부</TableHead>
|
||||
<TableCell className="border">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="useYn"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<RadioGroup
|
||||
{...field}
|
||||
name="useYn"
|
||||
onValueChange={field.onChange}
|
||||
>
|
||||
<div className="flex items-center space-x-2">
|
||||
<RadioGroupItem value="Y" id="useY" />
|
||||
<Label htmlFor="useY">사용</Label>
|
||||
</div>
|
||||
<div className="flex items-center space-x-2">
|
||||
<RadioGroupItem value="N" id="useN" />
|
||||
<Label htmlFor="useN">사용안함</Label>
|
||||
</div>
|
||||
</RadioGroup>
|
||||
</FormControl>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
</TableBody>
|
||||
</Table>
|
||||
</div>
|
||||
<div className="flex justify-center gap-4 pb-12 pt-10">
|
||||
<Button
|
||||
size="lg"
|
||||
color="white"
|
||||
type="button"
|
||||
onClick={() => router.back()}
|
||||
>
|
||||
목록
|
||||
</Button>
|
||||
<Button size="lg" type="submit">
|
||||
저장
|
||||
</Button>
|
||||
</FormControl>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableHead>사이트명</TableHead>
|
||||
<TableCell className="border">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="siteNm"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<Input
|
||||
{...field}
|
||||
value={field.value ?? ""}
|
||||
className="!text-[1.3rem]"
|
||||
placeholder="사이트명을 입력하십시오."
|
||||
/>
|
||||
</FormControl>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableHead>사이트 설명</TableHead>
|
||||
<TableCell className="border">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="siteExpln"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<Input
|
||||
{...field}
|
||||
value={field.value ?? ""}
|
||||
className="!text-[1.3rem]"
|
||||
placeholder="사이트 설명을 입력하십시오."
|
||||
/>
|
||||
</FormControl>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
{isModifyMode && (
|
||||
<Button size="lg" color="red" type="button" onClick={onDelete}>
|
||||
삭제
|
||||
</Button>
|
||||
<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">
|
||||
{form.watch("dmnAddr")}
|
||||
</div>
|
||||
<DomainManagementDialog
|
||||
siteId={siteId}
|
||||
open={isDomainManagementOpen}
|
||||
onOpenChange={setIsDomainManagementOpen}
|
||||
handleSaveDomain={handleSaveDomain}
|
||||
/>
|
||||
</div>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
)}
|
||||
</div>
|
||||
</form>
|
||||
</Form>
|
||||
<ConfirmDialog open={onConfirm} />
|
||||
</>
|
||||
<TableRow>
|
||||
<TableHead>사이트 하단 표기 주소</TableHead>
|
||||
<TableCell className="border">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="siteAddr"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<Input
|
||||
{...field}
|
||||
value={field.value ?? ""}
|
||||
className="!text-[1.3rem]"
|
||||
placeholder="사이트 하단 주소를 입력하십시오."
|
||||
/>
|
||||
</FormControl>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableHead>사이트 하단 표기 전화번호</TableHead>
|
||||
<TableCell className="border">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="telNo"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<Input
|
||||
{...field}
|
||||
value={field.value ?? ""}
|
||||
className="!text-[1.3rem]"
|
||||
placeholder="사이트 하단 전화번호를 입력하십시오."
|
||||
/>
|
||||
</FormControl>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableHead>사이트 하단 표기 팩스번호</TableHead>
|
||||
<TableCell className="border">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="faxNo"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<Input
|
||||
{...field}
|
||||
value={field.value ?? ""}
|
||||
className="!text-[1.3rem]"
|
||||
placeholder="사이트 하단 팩스번호를 입력하십시오."
|
||||
/>
|
||||
</FormControl>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableHead>사이트 하단 표기 내용</TableHead>
|
||||
<TableCell className="border">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="lwndCn"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<Input
|
||||
{...field}
|
||||
value={field.value ?? ""}
|
||||
className="!text-[1.3rem]"
|
||||
placeholder="사이트 표기 내용을 입력하십시오. (ex. COPYRIGHT c 2013 KECO. ALL RIGHTS RESERVED.)"
|
||||
/>
|
||||
</FormControl>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableHead>북마크 아이콘</TableHead>
|
||||
<TableCell className="border">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="bkmkIcon"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<Input
|
||||
{...field}
|
||||
value={field.value ?? ""}
|
||||
className="!text-[1.3rem]"
|
||||
placeholder="아이콘 파일 경로 및 파일명을 입력하여 주십시오."
|
||||
/>
|
||||
</FormControl>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableHead>기본 사이트 여부</TableHead>
|
||||
<TableCell className="border">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="bscSiteYn"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<RadioGroup
|
||||
{...field}
|
||||
name="bscSiteYn"
|
||||
onValueChange={field.onChange}
|
||||
>
|
||||
<div className="flex items-center space-x-2">
|
||||
<RadioGroupItem value="Y" id="bscSiteY" />
|
||||
<Label htmlFor="bscSiteY">예</Label>
|
||||
</div>
|
||||
<div className="flex items-center space-x-2">
|
||||
<RadioGroupItem value="N" id="bscSiteN" />
|
||||
<Label htmlFor="bscSiteN">아니오</Label>
|
||||
</div>
|
||||
</RadioGroup>
|
||||
</FormControl>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
<TableRow>
|
||||
<TableHead>사용 여부</TableHead>
|
||||
<TableCell className="border">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="useYn"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<RadioGroup
|
||||
{...field}
|
||||
name="useYn"
|
||||
onValueChange={field.onChange}
|
||||
>
|
||||
<div className="flex items-center space-x-2">
|
||||
<RadioGroupItem value="Y" id="useY" />
|
||||
<Label htmlFor="useY">사용</Label>
|
||||
</div>
|
||||
<div className="flex items-center space-x-2">
|
||||
<RadioGroupItem value="N" id="useN" />
|
||||
<Label htmlFor="useN">사용안함</Label>
|
||||
</div>
|
||||
</RadioGroup>
|
||||
</FormControl>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
</TableBody>
|
||||
</Table>
|
||||
</div>
|
||||
</FormWrapper>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
export { FormWrapper } from "./ui/form-wrapper";
|
||||
@@ -0,0 +1,68 @@
|
||||
import { useRouter } from "next/navigation";
|
||||
import { useConfirm } from "@frontend-opensource/use-react-hooks";
|
||||
import { type FieldValues, type UseFormReturn } from "react-hook-form";
|
||||
import { Button } from "@common/components/ui";
|
||||
import { Form } from "@/shared/ui/form";
|
||||
|
||||
type FormWrapperProps<T extends FieldValues> = {
|
||||
form: UseFormReturn<T>;
|
||||
children: React.ReactNode;
|
||||
isModifyMode?: boolean;
|
||||
handleSave: (data: T) => Promise<void>;
|
||||
handleDelete?: () => Promise<void>;
|
||||
};
|
||||
|
||||
function FormWrapper<T extends FieldValues>({
|
||||
form,
|
||||
children,
|
||||
isModifyMode,
|
||||
handleSave,
|
||||
handleDelete,
|
||||
}: FormWrapperProps<T>) {
|
||||
const router = useRouter();
|
||||
const { confirm } = useConfirm();
|
||||
|
||||
const onSubmit = async (data: T) => {
|
||||
const confirmMessage = isModifyMode
|
||||
? "수정하시겠습니까?"
|
||||
: "저장하시겠습니까?";
|
||||
|
||||
if (await confirm(confirmMessage)) {
|
||||
await handleSave(data);
|
||||
}
|
||||
};
|
||||
|
||||
const onDelete = async () => {
|
||||
if (await confirm("삭제하시겠습니까?")) {
|
||||
await handleDelete?.();
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Form {...form}>
|
||||
<form onSubmit={form.handleSubmit(onSubmit)}>
|
||||
{children}
|
||||
<div className="flex justify-center gap-4 pb-12 pt-10">
|
||||
<Button
|
||||
size="lg"
|
||||
color="white"
|
||||
type="button"
|
||||
onClick={() => router.back()}
|
||||
>
|
||||
목록
|
||||
</Button>
|
||||
<Button size="lg" type="submit">
|
||||
저장
|
||||
</Button>
|
||||
{isModifyMode && (
|
||||
<Button size="lg" color="red" type="button" onClick={onDelete}>
|
||||
삭제
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
</form>
|
||||
</Form>
|
||||
);
|
||||
}
|
||||
|
||||
export { FormWrapper };
|
||||
Reference in New Issue
Block a user