diff options
| author | 0-Zz-ang <s1998319@gmail.com> | 2025-07-10 15:56:13 +0900 |
|---|---|---|
| committer | 0-Zz-ang <s1998319@gmail.com> | 2025-07-10 15:56:13 +0900 |
| commit | 356929b399ef31a4de82906267df438cf29ea59d (patch) | |
| tree | c353a55c076e987042f99f3dbf1eab54706f6829 /lib/integration/table/integration-add-dialog.tsx | |
| parent | 25d569828b704a102f681a627c76c4129afa8be3 (diff) | |
인터페이스 관련 파일 수정
Diffstat (limited to 'lib/integration/table/integration-add-dialog.tsx')
| -rw-r--r-- | lib/integration/table/integration-add-dialog.tsx | 272 |
1 files changed, 272 insertions, 0 deletions
diff --git a/lib/integration/table/integration-add-dialog.tsx b/lib/integration/table/integration-add-dialog.tsx new file mode 100644 index 00000000..aeab2a5f --- /dev/null +++ b/lib/integration/table/integration-add-dialog.tsx @@ -0,0 +1,272 @@ +"use client"; + +import * as React from "react"; +import { useForm } from "react-hook-form"; +import { zodResolver } from "@hookform/resolvers/zod"; +import { z } from "zod"; +import { Plus, Loader2 } from "lucide-react"; + +import { Button } from "@/components/ui/button"; +import { + Dialog, + DialogContent, + DialogDescription, + DialogFooter, + DialogHeader, + DialogTitle, + DialogTrigger, +} from "@/components/ui/dialog"; +import { + Form, + FormControl, + FormField, + FormItem, + FormLabel, + FormMessage, +} from "@/components/ui/form"; +import { Input } from "@/components/ui/input"; +import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; +import { Textarea } from "@/components/ui/textarea"; +import { createIntegration } from "../service"; +import { toast } from "sonner"; + +const createIntegrationSchema = z.object({ + code: z.string().min(1, "코드는 필수입니다."), + name: z.string().min(1, "이름은 필수입니다."), + type: z.enum(["rest_api", "soap", "db_to_db"], { required_error: "타입은 필수입니다." }), + description: z.string().optional(), + sourceSystem: z.string().min(1, "소스 시스템은 필수입니다."), + targetSystem: z.string().min(1, "타겟 시스템은 필수입니다."), + status: z.enum(["active", "inactive", "deprecated"]).default("active"), + metadata: z.any().optional(), +}); + +type CreateIntegrationFormValues = z.infer<typeof createIntegrationSchema>; + +interface IntegrationAddDialogProps { + onSuccess?: () => void; +} + +export function IntegrationAddDialog({ onSuccess }: IntegrationAddDialogProps) { + const [open, setOpen] = React.useState(false); + const [isLoading, setIsLoading] = React.useState(false); + + const form = useForm<CreateIntegrationFormValues>({ + resolver: zodResolver(createIntegrationSchema), + defaultValues: { + code: "", + name: "", + type: "rest_api", + description: "", + sourceSystem: "", + targetSystem: "", + status: "active", + metadata: {}, + }, + }); + + const handleOpenChange = (newOpen: boolean) => { + setOpen(newOpen); + if (!newOpen) { + form.reset(); + } + }; + + const handleCancel = () => { + form.reset(); + setOpen(false); + }; + + const onSubmit = async (data: CreateIntegrationFormValues) => { + setIsLoading(true); + try { + const result = await createIntegration(data); + if (result.data) { + toast.success("인터페이스가 성공적으로 추가되었습니다."); + form.reset(); + setOpen(false); + if (onSuccess) { + onSuccess(); + } + } else { + toast.error(result.error || "생성 중 오류가 발생했습니다."); + } + } catch (error) { + console.error("인터페이스 생성 오류:", error); + toast.error("인터페이스 생성에 실패했습니다."); + } finally { + setIsLoading(false); + } + }; + + return ( + <Dialog open={open} onOpenChange={handleOpenChange}> + <DialogTrigger asChild> + <Button variant="outline" size="sm"> + <Plus className="mr-2 h-4 w-4" /> + 인터페이스 추가 + </Button> + </DialogTrigger> + <DialogContent className="max-w-md"> + <DialogHeader> + <DialogTitle>새 인터페이스 추가</DialogTitle> + <DialogDescription> + 새로운 인터페이스를 추가합니다. 필수 정보를 입력해주세요. + <span className="text-red-500 mt-1 block text-sm">* 표시된 항목은 필수 입력사항입니다.</span> + </DialogDescription> + </DialogHeader> + + <Form {...form}> + <form onSubmit={form.handleSubmit(onSubmit)} className="space-y-4"> + <FormField + control={form.control} + name="code" + render={({ field }) => ( + <FormItem> + <FormLabel> + 코드 <span className="text-red-500">*</span> + </FormLabel> + <FormControl> + <Input placeholder="INT_OPS_001" {...field} /> + </FormControl> + <FormMessage /> + </FormItem> + )} + /> + + <FormField + control={form.control} + name="name" + render={({ field }) => ( + <FormItem> + <FormLabel> + 이름 <span className="text-red-500">*</span> + </FormLabel> + <FormControl> + <Input placeholder="인터페이스 이름" {...field} /> + </FormControl> + <FormMessage /> + </FormItem> + )} + /> + + <FormField + control={form.control} + name="type" + render={({ field }) => ( + <FormItem> + <FormLabel> + 타입 <span className="text-red-500">*</span> + </FormLabel> + <Select onValueChange={field.onChange} defaultValue={field.value}> + <FormControl> + <SelectTrigger> + <SelectValue placeholder="타입 선택" /> + </SelectTrigger> + </FormControl> + <SelectContent> + <SelectItem value="rest_api">REST API</SelectItem> + <SelectItem value="soap">SOAP</SelectItem> + <SelectItem value="db_to_db">DB to DB</SelectItem> + </SelectContent> + </Select> + <FormMessage /> + </FormItem> + )} + /> + + <FormField + control={form.control} + name="sourceSystem" + render={({ field }) => ( + <FormItem> + <FormLabel> + 소스 시스템 <span className="text-red-500">*</span> + </FormLabel> + <FormControl> + <Input placeholder="ERP, WMS 등" {...field} /> + </FormControl> + <FormMessage /> + </FormItem> + )} + /> + + <FormField + control={form.control} + name="targetSystem" + render={({ field }) => ( + <FormItem> + <FormLabel> + 타겟 시스템 <span className="text-red-500">*</span> + </FormLabel> + <FormControl> + <Input placeholder="ERP, WMS 등" {...field} /> + </FormControl> + <FormMessage /> + </FormItem> + )} + /> + + <FormField + control={form.control} + name="status" + render={({ field }) => ( + <FormItem> + <FormLabel> + 상태 <span className="text-red-500">*</span> + </FormLabel> + <Select onValueChange={field.onChange} defaultValue={field.value}> + <FormControl> + <SelectTrigger> + <SelectValue placeholder="상태 선택" /> + </SelectTrigger> + </FormControl> + <SelectContent> + <SelectItem value="active">활성</SelectItem> + <SelectItem value="inactive">비활성</SelectItem> + <SelectItem value="deprecated">사용중단</SelectItem> + </SelectContent> + </Select> + <FormMessage /> + </FormItem> + )} + /> + + <FormField + control={form.control} + name="description" + render={({ field }) => ( + <FormItem> + <FormLabel>설명</FormLabel> + <FormControl> + <Textarea placeholder="인터페이스에 대한 설명" {...field} /> + </FormControl> + <FormMessage /> + </FormItem> + )} + /> + </form> + </Form> + + <DialogFooter> + <Button + type="button" + variant="outline" + onClick={handleCancel} + disabled={isLoading} + > + 취소 + </Button> + <Button + type="submit" + onClick={form.handleSubmit(onSubmit)} + disabled={isLoading} + > + {isLoading && <Loader2 className="mr-2 h-4 w-4 animate-spin" />} + {isLoading ? "생성 중..." : "추가"} + </Button> + </DialogFooter> + </DialogContent> + </Dialog> + ); +}
\ No newline at end of file |
