Files
frontend/apps/cs/src/pages/image/ui/image-form.tsx
T

308 lines
11 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,
setFile,
} = useTus();
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}
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="relative h-[27rem] w-[48rem] overflow-hidden rounded-sm border border-border bg-accent">
<div className="relative h-full w-full">
{imageUrl && (
<Image
src={imageUrl}
className="object-contain"
fill
alt="업로드된 이미지"
/>
)}
</div>
<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>
</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 };