Merge branch 'fe/refactor/project-create-modal' into 'fe/develop'

Refactor: 파일로 카테고리 추가하는 기능 구현(cvat 모방)

See merge request s11-s-project/S11P21S002!270
This commit is contained in:
홍창기 2024-10-02 21:09:57 +09:00
commit 29bc04bced

View File

@ -7,6 +7,8 @@ import { Button } from '../ui/button';
import { RadioGroup, RadioGroupItem } from '../ui/radio-group';
import { useRef, useState } from 'react';
import { X } from 'lucide-react';
import { Tabs, TabsList, TabsTrigger, TabsContent } from '../ui/tabs';
import { cn } from '@/lib/utils';
const formSchema = z.object({
projectName: z.string().max(50).min(1, {
@ -27,11 +29,14 @@ const defaultValues: Partial<ProjectCreateFormValues> = {
export default function ProjectCreateForm({ onSubmit }: { onSubmit: (data: ProjectCreateFormValues) => void }) {
const [categories, setCategories] = useState<string[]>([]);
const [isDragging, setIsDragging] = useState<boolean>(false);
const form = useForm<ProjectCreateFormValues>({
resolver: zodResolver(formSchema),
defaultValues: { ...defaultValues, categories },
});
const categoryRef = useRef<HTMLInputElement>(null);
const fileInputRef = useRef<HTMLInputElement>(null);
const handleAddCategory = (event: React.MouseEvent<HTMLButtonElement>, onChange: (value: string[]) => void) => {
event.preventDefault();
@ -47,6 +52,63 @@ export default function ProjectCreateForm({ onSubmit }: { onSubmit: (data: Proje
categoryRef.current!.value = '';
};
const handleFileUpload = async (event: React.ChangeEvent<HTMLInputElement>, onChange: (value: string[]) => void) => {
event.preventDefault();
const file = event.target.files?.[0];
if (!file) return;
try {
const text = await file.text();
const newCategories = text
.split('\n')
.map((line) => line.trim())
.filter((line) => line.length > 0);
if (newCategories.length > 0) {
const uniqueCategories = Array.from(new Set([...categories, ...newCategories]));
onChange(uniqueCategories);
setCategories(uniqueCategories);
}
} catch (error) {
console.error('파일을 읽는 중 오류가 발생했습니다:', error);
}
};
const handleDragOver = (event: React.DragEvent<HTMLDivElement>) => {
event.preventDefault();
setIsDragging(true);
};
const handleDragLeave = (event: React.DragEvent<HTMLDivElement>) => {
event.preventDefault();
setIsDragging(false);
};
const handleDrop = async (event: React.DragEvent<HTMLDivElement>, onChange: (value: string[]) => void) => {
event.preventDefault();
setIsDragging(false);
const file = event.dataTransfer.files?.[0];
if (!file) return;
try {
const text = await file.text();
const newCategories = text
.split('\n')
.map((line) => line.trim())
.filter((line) => line.length > 0);
if (newCategories.length > 0) {
const uniqueCategories = Array.from(new Set([...categories, ...newCategories]));
onChange(uniqueCategories);
setCategories(uniqueCategories);
}
} catch (error) {
console.error('파일을 읽는 중 오류가 발생했습니다:', error);
}
};
return (
<Form {...form}>
<form
@ -106,20 +168,51 @@ export default function ProjectCreateForm({ onSubmit }: { onSubmit: (data: Proje
render={({ field }) => (
<div className="mb-1 flex w-full flex-col gap-2">
<div className="body-strong"></div>
<div className="flex gap-2">
<FormControl>
<Input
ref={categoryRef}
placeholder="카테고리를 추가해주세요."
/>
</FormControl>
<Button
variant="blue"
onClick={(event) => handleAddCategory(event, field.onChange)}
>
</Button>
</div>
<Tabs defaultValue="manual">
<TabsList className="mb-4">
<TabsTrigger value="manual"> </TabsTrigger>
<TabsTrigger value="file"> </TabsTrigger>
</TabsList>
<TabsContent value="manual">
<div className="mt-2 flex gap-2">
<FormControl>
<Input
ref={categoryRef}
placeholder="카테고리를 추가해주세요."
/>
</FormControl>
<Button
variant="blue"
onClick={(event) => handleAddCategory(event, field.onChange)}
>
</Button>
</div>
</TabsContent>
<TabsContent value="file">
<div
className={cn(
'mt-2 flex w-full items-center justify-center rounded-lg border-2 border-dashed p-5 text-center transition-colors',
isDragging ? 'border-blue-500 bg-blue-100' : 'border-gray-300 bg-gray-100'
)}
onDragOver={handleDragOver}
onDragLeave={handleDragLeave}
onDrop={(event) => handleDrop(event, field.onChange)}
onClick={() => fileInputRef.current?.click()}
>
<p className="text-gray-500">
.
</p>
<input
type="file"
ref={fileInputRef}
accept=".txt"
onChange={(event) => handleFileUpload(event, field.onChange)}
className="hidden"
/>
</div>
</TabsContent>
</Tabs>
{categories.length > 0 && (
<div className="flex w-full flex-col overflow-x-auto">
<div className="flex gap-2 py-1">