288 lines
9.8 KiB
TypeScript
288 lines
9.8 KiB
TypeScript
"use client";
|
|
|
|
import React, { useMemo, useCallback } from "react";
|
|
import { Input } from "@/components/ui/input";
|
|
import { Label } from "@/components/ui/label";
|
|
import { Checkbox } from "@/components/ui/checkbox";
|
|
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
|
|
import { Separator } from "@/components/ui/separator";
|
|
import { FileUploadConfig } from "./types";
|
|
import { V2FileUploadDefaultConfig } from "./config";
|
|
|
|
export interface FileUploadConfigPanelProps {
|
|
config: FileUploadConfig;
|
|
onChange: (config: Partial<FileUploadConfig>) => void;
|
|
screenTableName?: string;
|
|
}
|
|
|
|
/**
|
|
* V2 FileUpload 설정 패널
|
|
* 컴포넌트의 설정값들을 편집할 수 있는 UI 제공
|
|
*/
|
|
export const FileUploadConfigPanel: React.FC<FileUploadConfigPanelProps> = ({
|
|
config: propConfig,
|
|
onChange,
|
|
screenTableName,
|
|
}) => {
|
|
// config 안전하게 초기화 (useMemo)
|
|
const config = useMemo(() => ({
|
|
...V2FileUploadDefaultConfig,
|
|
...propConfig,
|
|
}), [propConfig]);
|
|
|
|
// 핸들러
|
|
const handleChange = useCallback(<K extends keyof FileUploadConfig>(
|
|
key: K,
|
|
value: FileUploadConfig[K]
|
|
) => {
|
|
onChange({ [key]: value });
|
|
}, [onChange]);
|
|
|
|
// 파일 크기를 MB 단위로 변환
|
|
const maxSizeMB = useMemo(() => {
|
|
return (config.maxSize || 10 * 1024 * 1024) / (1024 * 1024);
|
|
}, [config.maxSize]);
|
|
|
|
const handleMaxSizeChange = useCallback((value: string) => {
|
|
const mb = parseFloat(value) || 10;
|
|
handleChange("maxSize", mb * 1024 * 1024);
|
|
}, [handleChange]);
|
|
|
|
return (
|
|
<div className="space-y-4 p-4">
|
|
<div className="text-sm font-medium text-muted-foreground">
|
|
V2 파일 업로드 설정
|
|
</div>
|
|
|
|
<Separator />
|
|
|
|
{/* 기본 설정 */}
|
|
<div className="space-y-3">
|
|
<Label className="text-xs font-semibold uppercase text-muted-foreground">
|
|
기본 설정
|
|
</Label>
|
|
|
|
<div className="space-y-2">
|
|
<Label htmlFor="placeholder" className="text-xs">플레이스홀더</Label>
|
|
<Input
|
|
id="placeholder"
|
|
value={config.placeholder || ""}
|
|
onChange={(e) => handleChange("placeholder", e.target.value)}
|
|
placeholder="파일을 선택하세요"
|
|
className="h-8 text-xs"
|
|
/>
|
|
</div>
|
|
|
|
<div className="space-y-2">
|
|
<Label htmlFor="accept" className="text-xs">허용 파일 형식</Label>
|
|
<Select
|
|
value={config.accept || "*/*"}
|
|
onValueChange={(value) => handleChange("accept", value)}
|
|
>
|
|
<SelectTrigger className="h-8 text-xs">
|
|
<SelectValue placeholder="파일 형식 선택" />
|
|
</SelectTrigger>
|
|
<SelectContent>
|
|
<SelectItem value="*/*">모든 파일</SelectItem>
|
|
<SelectItem value="image/*">이미지만</SelectItem>
|
|
<SelectItem value=".pdf,.doc,.docx,.xls,.xlsx">문서만</SelectItem>
|
|
<SelectItem value="image/*,.pdf">이미지 + PDF</SelectItem>
|
|
<SelectItem value=".zip,.rar,.7z">압축 파일만</SelectItem>
|
|
</SelectContent>
|
|
</Select>
|
|
</div>
|
|
|
|
<div className="grid grid-cols-2 gap-2">
|
|
<div className="space-y-2">
|
|
<Label htmlFor="maxSize" className="text-xs">최대 크기 (MB)</Label>
|
|
<Input
|
|
id="maxSize"
|
|
type="number"
|
|
min={1}
|
|
max={100}
|
|
value={maxSizeMB}
|
|
onChange={(e) => handleMaxSizeChange(e.target.value)}
|
|
className="h-8 text-xs"
|
|
/>
|
|
</div>
|
|
<div className="space-y-2">
|
|
<Label htmlFor="maxFiles" className="text-xs">최대 파일 수</Label>
|
|
<Input
|
|
id="maxFiles"
|
|
type="number"
|
|
min={1}
|
|
max={50}
|
|
value={config.maxFiles || 10}
|
|
onChange={(e) => handleChange("maxFiles", parseInt(e.target.value) || 10)}
|
|
className="h-8 text-xs"
|
|
/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<Separator />
|
|
|
|
{/* 동작 설정 */}
|
|
<div className="space-y-3">
|
|
<Label className="text-xs font-semibold uppercase text-muted-foreground">
|
|
동작 설정
|
|
</Label>
|
|
|
|
<div className="flex items-center space-x-2">
|
|
<Checkbox
|
|
id="multiple"
|
|
checked={config.multiple !== false}
|
|
onCheckedChange={(checked) => handleChange("multiple", checked as boolean)}
|
|
/>
|
|
<Label htmlFor="multiple" className="text-xs">다중 파일 선택 허용</Label>
|
|
</div>
|
|
|
|
<div className="flex items-center space-x-2">
|
|
<Checkbox
|
|
id="allowDelete"
|
|
checked={config.allowDelete !== false}
|
|
onCheckedChange={(checked) => handleChange("allowDelete", checked as boolean)}
|
|
/>
|
|
<Label htmlFor="allowDelete" className="text-xs">파일 삭제 허용</Label>
|
|
</div>
|
|
|
|
<div className="flex items-center space-x-2">
|
|
<Checkbox
|
|
id="allowDownload"
|
|
checked={config.allowDownload !== false}
|
|
onCheckedChange={(checked) => handleChange("allowDownload", checked as boolean)}
|
|
/>
|
|
<Label htmlFor="allowDownload" className="text-xs">파일 다운로드 허용</Label>
|
|
</div>
|
|
</div>
|
|
|
|
<Separator />
|
|
|
|
{/* 표시 설정 */}
|
|
<div className="space-y-3">
|
|
<Label className="text-xs font-semibold uppercase text-muted-foreground">
|
|
표시 설정
|
|
</Label>
|
|
|
|
<div className="flex items-center space-x-2">
|
|
<Checkbox
|
|
id="showPreview"
|
|
checked={config.showPreview !== false}
|
|
onCheckedChange={(checked) => handleChange("showPreview", checked as boolean)}
|
|
/>
|
|
<Label htmlFor="showPreview" className="text-xs">미리보기 표시</Label>
|
|
</div>
|
|
|
|
<div className="flex items-center space-x-2">
|
|
<Checkbox
|
|
id="showFileList"
|
|
checked={config.showFileList !== false}
|
|
onCheckedChange={(checked) => handleChange("showFileList", checked as boolean)}
|
|
/>
|
|
<Label htmlFor="showFileList" className="text-xs">파일 목록 표시</Label>
|
|
</div>
|
|
|
|
<div className="flex items-center space-x-2">
|
|
<Checkbox
|
|
id="showFileSize"
|
|
checked={config.showFileSize !== false}
|
|
onCheckedChange={(checked) => handleChange("showFileSize", checked as boolean)}
|
|
/>
|
|
<Label htmlFor="showFileSize" className="text-xs">파일 크기 표시</Label>
|
|
</div>
|
|
</div>
|
|
|
|
<Separator />
|
|
|
|
{/* 상태 설정 */}
|
|
<div className="space-y-3">
|
|
<Label className="text-xs font-semibold uppercase text-muted-foreground">
|
|
상태 설정
|
|
</Label>
|
|
|
|
<div className="flex items-center space-x-2">
|
|
<Checkbox
|
|
id="required"
|
|
checked={config.required || false}
|
|
onCheckedChange={(checked) => handleChange("required", checked as boolean)}
|
|
/>
|
|
<Label htmlFor="required" className="text-xs">필수 입력</Label>
|
|
</div>
|
|
|
|
<div className="flex items-center space-x-2">
|
|
<Checkbox
|
|
id="readonly"
|
|
checked={config.readonly || false}
|
|
onCheckedChange={(checked) => handleChange("readonly", checked as boolean)}
|
|
/>
|
|
<Label htmlFor="readonly" className="text-xs">읽기 전용</Label>
|
|
</div>
|
|
|
|
<div className="flex items-center space-x-2">
|
|
<Checkbox
|
|
id="disabled"
|
|
checked={config.disabled || false}
|
|
onCheckedChange={(checked) => handleChange("disabled", checked as boolean)}
|
|
/>
|
|
<Label htmlFor="disabled" className="text-xs">비활성화</Label>
|
|
</div>
|
|
</div>
|
|
|
|
<Separator />
|
|
|
|
{/* 스타일 설정 */}
|
|
<div className="space-y-3">
|
|
<Label className="text-xs font-semibold uppercase text-muted-foreground">
|
|
스타일 설정
|
|
</Label>
|
|
|
|
<div className="space-y-2">
|
|
<Label htmlFor="variant" className="text-xs">스타일 변형</Label>
|
|
<Select
|
|
value={config.variant || "default"}
|
|
onValueChange={(value) => handleChange("variant", value as "default" | "outlined" | "filled")}
|
|
>
|
|
<SelectTrigger className="h-8 text-xs">
|
|
<SelectValue placeholder="스타일 선택" />
|
|
</SelectTrigger>
|
|
<SelectContent>
|
|
<SelectItem value="default">기본</SelectItem>
|
|
<SelectItem value="outlined">테두리</SelectItem>
|
|
<SelectItem value="filled">채움</SelectItem>
|
|
</SelectContent>
|
|
</Select>
|
|
</div>
|
|
|
|
<div className="space-y-2">
|
|
<Label htmlFor="size" className="text-xs">크기</Label>
|
|
<Select
|
|
value={config.size || "md"}
|
|
onValueChange={(value) => handleChange("size", value as "sm" | "md" | "lg")}
|
|
>
|
|
<SelectTrigger className="h-8 text-xs">
|
|
<SelectValue placeholder="크기 선택" />
|
|
</SelectTrigger>
|
|
<SelectContent>
|
|
<SelectItem value="sm">작게</SelectItem>
|
|
<SelectItem value="md">보통</SelectItem>
|
|
<SelectItem value="lg">크게</SelectItem>
|
|
</SelectContent>
|
|
</Select>
|
|
</div>
|
|
</div>
|
|
|
|
{/* 도움말 */}
|
|
<div className="space-y-2">
|
|
<Label htmlFor="helperText" className="text-xs">도움말</Label>
|
|
<Input
|
|
id="helperText"
|
|
value={config.helperText || ""}
|
|
onChange={(e) => handleChange("helperText", e.target.value)}
|
|
placeholder="파일 업로드에 대한 안내 문구"
|
|
className="h-8 text-xs"
|
|
/>
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|