diff options
Diffstat (limited to 'lib/docu-list-rule/code-groups/table/code-groups-edit-sheet.tsx')
| -rw-r--r-- | lib/docu-list-rule/code-groups/table/code-groups-edit-sheet.tsx | 259 |
1 files changed, 259 insertions, 0 deletions
diff --git a/lib/docu-list-rule/code-groups/table/code-groups-edit-sheet.tsx b/lib/docu-list-rule/code-groups/table/code-groups-edit-sheet.tsx new file mode 100644 index 00000000..28aebd54 --- /dev/null +++ b/lib/docu-list-rule/code-groups/table/code-groups-edit-sheet.tsx @@ -0,0 +1,259 @@ +"use client" + +import * as React from "react" +import { useForm } from "react-hook-form" +import { zodResolver } from "@hookform/resolvers/zod" +import { toast } from "sonner" +import { Loader } from "lucide-react" + +import { Button } from "@/components/ui/button" +import { + Sheet, + SheetClose, + SheetContent, + SheetDescription, + SheetFooter, + SheetHeader, + SheetTitle, +} from "@/components/ui/sheet" +import { + Form, + FormControl, + FormField, + FormItem, + FormLabel, + FormMessage, +} from "@/components/ui/form" +import { Input } from "@/components/ui/input" +import { Switch } from "@/components/ui/switch" +import { + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, +} from "@/components/ui/select" +import { updateCodeGroup } from "../service" +import { codeGroups } from "@/db/schema/codeGroups" +import { z } from "zod" + +const updateCodeGroupSchema = z.object({ + description: z.string().min(1, "Description은 필수입니다."), + codeFormat: z.string().optional().refine((val) => { + if (!val) return true; // 빈 값은 허용 + return /^[AN]*$/.test(val); + }, "Code Format은 A(영어 대문자) 또는 N(숫자)만 입력 가능합니다."), + controlType: z.string().min(1, "Control Type은 필수입니다."), + isActive: z.boolean().default(true), +}) + +type UpdateCodeGroupFormValues = z.infer<typeof updateCodeGroupSchema> + +interface CodeGroupsEditSheetProps { + open: boolean + onOpenChange: (open: boolean) => void + data: typeof codeGroups.$inferSelect | null + onSuccess: () => void +} + +export function CodeGroupsEditSheet({ + open, + onOpenChange, + data, + onSuccess, +}: CodeGroupsEditSheetProps) { + const [isUpdatePending, startUpdateTransition] = React.useTransition() + + const form = useForm<UpdateCodeGroupFormValues>({ + resolver: zodResolver(updateCodeGroupSchema), + defaultValues: { + description: data?.description ?? "", + codeFormat: data?.codeFormat ?? "", + controlType: data?.controlType ?? "", + isActive: data?.isActive ?? true, + }, + mode: "onChange" + }) + + // Code Format을 기반으로 정규식 자동 생성 함수 + const generateExpression = (codeFormat: string): string => { + if (!codeFormat) return '' + + let expression = '^' + let currentChar = codeFormat[0] + let count = 1 + + for (let i = 1; i < codeFormat.length; i++) { + if (codeFormat[i] === currentChar) { + count++ + } else { + // 이전 문자에 대한 정규식 추가 + if (currentChar === 'A') { + expression += `[A-Z]{${count}}` + } else if (currentChar === 'N') { + expression += `[0-9]{${count}}` + } + currentChar = codeFormat[i] + count = 1 + } + } + + // 마지막 문자 처리 + if (currentChar === 'A') { + expression += `[A-Z]{${count}}` + } else if (currentChar === 'N') { + expression += `[0-9]{${count}}` + } + + expression += '$' + return expression + } + + React.useEffect(() => { + if (data) { + form.reset({ + description: data.description, + codeFormat: data.codeFormat || "", + controlType: data.controlType, + isActive: data.isActive ?? true, + }) + } + }, [data, form]) + + async function onSubmit(input: UpdateCodeGroupFormValues) { + if (!data) return + + startUpdateTransition(async () => { + try { + // Code Format이 변경되면 Expression 자동 업데이트 + const expressions = generateExpression(input.codeFormat || "") + + const result = await updateCodeGroup({ + id: data.id, + description: input.description, + codeFormat: input.codeFormat, + expressions: expressions, + controlType: input.controlType, + isActive: input.isActive, + }) + + if (result.success) { + toast.success("Code Group이 성공적으로 수정되었습니다.") + onSuccess() + onOpenChange(false) + } else { + toast.error(result.error || "Code Group 수정에 실패했습니다.") + } + } catch (error) { + console.error("Update error:", error) + toast.error("Code Group 수정 중 오류가 발생했습니다.") + } + }) + } + + return ( + <Sheet open={open} onOpenChange={onOpenChange}> + <SheetContent className="flex flex-col gap-6 sm:max-w-md"> + <SheetHeader className="text-left"> + <SheetTitle>Code Group 수정</SheetTitle> + <SheetDescription> + Code Group 정보를 수정하고 변경사항을 저장하세요 + </SheetDescription> + </SheetHeader> + <Form {...form}> + <form onSubmit={form.handleSubmit(onSubmit)} className="flex flex-col gap-4"> + <FormField + control={form.control} + name="description" + render={({ field }) => ( + <FormItem> + <FormLabel>Description</FormLabel> + <FormControl> + <Input placeholder="예: PROJECT NO" {...field} /> + </FormControl> + <FormMessage /> + </FormItem> + )} + /> + <FormField + control={form.control} + name="codeFormat" + render={({ field }) => ( + <FormItem> + <FormLabel>Code Format</FormLabel> + <FormControl> + <Input + placeholder="예: AANNN (A:영어대문자, N:숫자)" + {...field} + onBlur={() => form.trigger('codeFormat')} + /> + </FormControl> + <FormMessage /> + </FormItem> + )} + /> + + <FormField + control={form.control} + name="controlType" + render={({ field }) => ( + <FormItem> + <FormLabel>Control Type</FormLabel> + <Select onValueChange={field.onChange} defaultValue={field.value}> + <FormControl> + <SelectTrigger> + <SelectValue placeholder="Control Type을 선택하세요" /> + </SelectTrigger> + </FormControl> + <SelectContent> + <SelectItem value="textbox">Textbox</SelectItem> + <SelectItem value="combobox">Combobox</SelectItem> + </SelectContent> + </Select> + <FormMessage /> + </FormItem> + )} + /> + <FormField + control={form.control} + name="isActive" + render={({ field }) => ( + <FormItem className="flex flex-row items-center justify-between rounded-lg border p-4"> + <div className="space-y-0.5"> + <FormLabel className="text-base">활성 상태</FormLabel> + </div> + <FormControl> + <Switch + checked={field.value} + onCheckedChange={field.onChange} + /> + </FormControl> + </FormItem> + )} + /> + + <SheetFooter className="gap-2 pt-2 sm:space-x-0"> + <SheetClose asChild> + <Button type="button" variant="outline"> + 취소 + </Button> + </SheetClose> + <Button + type="submit" + disabled={isUpdatePending || !form.formState.isValid} + > + {isUpdatePending && ( + <Loader + className="mr-2 size-4 animate-spin" + aria-hidden="true" + /> + )} + 저장 + </Button> + </SheetFooter> + </form> + </Form> + </SheetContent> + </Sheet> + ) +}
\ No newline at end of file |
