312 lines
12 KiB
TypeScript
312 lines
12 KiB
TypeScript
"use client";
|
|
|
|
import Image from "next/image";
|
|
import { useEffect, useState } from "react";
|
|
import { useQuery } from "@tanstack/react-query";
|
|
import type { UseFormReturn } from "react-hook-form";
|
|
import type { HttpResponse } from "tus-js-client";
|
|
import {
|
|
FileUploader,
|
|
Input,
|
|
Label,
|
|
Progress,
|
|
RadioGroup,
|
|
RadioGroupItem,
|
|
Table,
|
|
TableBody,
|
|
TableCell,
|
|
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 { useTus } from "@/shared/lib/use-tus";
|
|
import { FormControl, FormField, FormItem } from "@/shared/ui/form";
|
|
import { useAttachmentStore } from "@/shared/lib/use-attachment-store";
|
|
import type { ImageFormData } from "../model/image-interface";
|
|
|
|
type ImageFormProps = {
|
|
form: UseFormReturn<ImageFormData>;
|
|
imgSn?: number;
|
|
handleSave: (data: ImageFormData) => Promise<void>;
|
|
handleDelete?: () => Promise<void>;
|
|
};
|
|
|
|
function ImageForm({ form, imgSn, ...props }: ImageFormProps) {
|
|
const atflYn = form.watch("atflYn");
|
|
const atflCd = form.watch("atflCd");
|
|
|
|
const {
|
|
file: uploadFile,
|
|
response: uploadResponse,
|
|
progress,
|
|
isValid,
|
|
setFile,
|
|
} = useTus({ accept: ".jpeg,.jpg,.png" });
|
|
const setAttachmentFileCode = useAttachmentStore(
|
|
(state) => state.setAttachmentFileCode,
|
|
);
|
|
const [imageUrl, setImageUrl] = useState("");
|
|
|
|
const { data: attachmentData } = useQuery({
|
|
queryKey: [ENDPOINT.ATTACH_SERVICE.ATTACHMENTS, atflCd],
|
|
queryFn: () => AttachmentApi.getAttachmentsInfo(atflCd!),
|
|
select: (data) => data?.[data.length - 1],
|
|
enabled: !!atflCd,
|
|
});
|
|
|
|
const handleUploadResponse = async (res: HttpResponse) => {
|
|
const fileInfo = res.getHeader("X-File-Info");
|
|
if (fileInfo === undefined || fileInfo === null) return;
|
|
|
|
const { atflCd, atflId } = JSON.parse(fileInfo) ?? {};
|
|
if (atflCd) form.setValue("atflCd", atflCd);
|
|
if (atflId) setImageUrl(await AttachmentApi.getImageUrlByAtflId(atflId));
|
|
if (attachmentData)
|
|
await AttachmentApi.deleteAttachmentByAtflCd(attachmentData.atflCd);
|
|
};
|
|
|
|
useEffect(() => {
|
|
if (!uploadResponse) return;
|
|
handleUploadResponse(uploadResponse);
|
|
}, [uploadResponse]);
|
|
|
|
useEffect(() => {
|
|
(async () => {
|
|
setImageUrl(
|
|
await AttachmentApi.getImageUrlByAtflCd(attachmentData?.atflCd ?? ""),
|
|
);
|
|
})();
|
|
}, [attachmentData]);
|
|
|
|
return (
|
|
<FormWrapper form={form} isModifyMode={!!imgSn} {...props}>
|
|
<div className="card">
|
|
<Table variant="secondary">
|
|
<colgroup>
|
|
<col width="15%" />
|
|
<col width="85%" />
|
|
</colgroup>
|
|
<TableBody>
|
|
<TableRow>
|
|
<TableHead data-required>이미지명</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 data-required>정렬순서</TableHead>
|
|
<TableCell className="border">
|
|
<FormField
|
|
control={form.control}
|
|
name="sortSeq"
|
|
render={({ field }) => (
|
|
<FormItem>
|
|
<FormControl>
|
|
<Input
|
|
{...field}
|
|
type="number"
|
|
min={0}
|
|
max={9999}
|
|
value={field.value ?? ""}
|
|
onChange={(e) =>
|
|
field.onChange(parseInt(e.target.value))
|
|
}
|
|
className="w-[12rem] !text-[1.3rem]"
|
|
placeholder="정렬순서 입력"
|
|
/>
|
|
</FormControl>
|
|
</FormItem>
|
|
)}
|
|
/>
|
|
</TableCell>
|
|
</TableRow>
|
|
<TableRow>
|
|
<TableHead data-required>이미지유형</TableHead>
|
|
<TableCell className="border">
|
|
<FormField
|
|
control={form.control}
|
|
name="imgTypeCd"
|
|
render={({ field }) => (
|
|
<FormItem>
|
|
<FormControl>
|
|
<CodeSelect
|
|
{...field}
|
|
upCd="IMGTYPE"
|
|
onValueChange={field.onChange}
|
|
/>
|
|
</FormControl>
|
|
</FormItem>
|
|
)}
|
|
/>
|
|
</TableCell>
|
|
</TableRow>
|
|
<TableRow>
|
|
<TableHead data-required>첨부파일</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;
|
|
setAttachmentFileCode("");
|
|
setFile(files[0] ?? null);
|
|
}}
|
|
customPreview={
|
|
<>
|
|
<Label htmlFor="atflCd">
|
|
<div className="h-[27rem] w-[48rem] overflow-hidden rounded-sm border border-border bg-accent">
|
|
{isValid && (
|
|
<div className="relative size-full">
|
|
{imageUrl && (
|
|
<Image
|
|
src={imageUrl}
|
|
className="object-contain"
|
|
fill
|
|
alt="업로드된 이미지"
|
|
/>
|
|
)}
|
|
<p className="absolute bottom-3 left-0 z-10 p-2 text-base leading-none">
|
|
{uploadFile?.name}
|
|
</p>
|
|
<Progress
|
|
value={progress}
|
|
className="absolute bottom-0 left-0 z-10"
|
|
/>
|
|
</div>
|
|
)}
|
|
</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 data-required>사용여부</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>
|
|
);
|
|
}
|
|
|
|
export { ImageForm };
|