diff options
Diffstat (limited to 'lib/b-rfq/initial/update-initial-rfq-sheet.tsx')
| -rw-r--r-- | lib/b-rfq/initial/update-initial-rfq-sheet.tsx | 496 |
1 files changed, 0 insertions, 496 deletions
diff --git a/lib/b-rfq/initial/update-initial-rfq-sheet.tsx b/lib/b-rfq/initial/update-initial-rfq-sheet.tsx deleted file mode 100644 index a19b5172..00000000 --- a/lib/b-rfq/initial/update-initial-rfq-sheet.tsx +++ /dev/null @@ -1,496 +0,0 @@ -"use client" - -import * as React from "react" -import { zodResolver } from "@hookform/resolvers/zod" -import { CalendarIcon, Loader, ChevronsUpDown, Check } from "lucide-react" -import { useForm } from "react-hook-form" -import { toast } from "sonner" -import { format } from "date-fns" -import { ko } from "date-fns/locale" - -import { cn } from "@/lib/utils" -import { Button } from "@/components/ui/button" -import { Calendar } from "@/components/ui/calendar" -import { Checkbox } from "@/components/ui/checkbox" -import { - Form, - FormControl, - FormField, - FormItem, - FormLabel, - FormMessage, -} from "@/components/ui/form" -import { - Command, - CommandEmpty, - CommandGroup, - CommandInput, - CommandItem, - CommandList, - } from "@/components/ui/command" -import { Input } from "@/components/ui/input" -import { - Popover, - PopoverContent, - PopoverTrigger, -} from "@/components/ui/popover" -import { - Select, - SelectContent, - SelectItem, - SelectTrigger, - SelectValue, -} from "@/components/ui/select" -import { - Sheet, - SheetClose, - SheetContent, - SheetDescription, - SheetFooter, - SheetHeader, - SheetTitle, -} from "@/components/ui/sheet" -import { UpdateInitialRfqSchema, updateInitialRfqSchema } from "../validations" -import { getIncotermsForSelection, modifyInitialRfq } from "../service" -import { InitialRfqDetailView } from "@/db/schema" - -interface UpdateInitialRfqSheetProps - extends React.ComponentPropsWithRef<typeof Sheet> { - initialRfq: InitialRfqDetailView | null -} - -interface Incoterm { - id: number - code: string - description: string -} - -export function UpdateInitialRfqSheet({ initialRfq, ...props }: UpdateInitialRfqSheetProps) { - const [isUpdatePending, startUpdateTransition] = React.useTransition() - const [incoterms, setIncoterms] = React.useState<Incoterm[]>([]) - const [incotermsLoading, setIncotermsLoading] = React.useState(false) - const [incotermsSearchOpen, setIncotermsSearchOpen] = React.useState(false) - - const loadIncoterms = React.useCallback(async () => { - setIncotermsLoading(true) - try { - const incotermsList = await getIncotermsForSelection() - setIncoterms(incotermsList) - } catch (error) { - console.error("Failed to load incoterms:", error) - toast.error("Incoterms 목록을 불러오는데 실패했습니다.") - } finally { - setIncotermsLoading(false) - } - }, []) - - React.useEffect(() => { - if (incoterms.length === 0) { - loadIncoterms() - } - }, [incoterms.length, loadIncoterms]) - - const form = useForm<UpdateInitialRfqSchema>({ - resolver: zodResolver(updateInitialRfqSchema), - defaultValues: { - initialRfqStatus: initialRfq?.initialRfqStatus ?? "DRAFT", - dueDate: initialRfq?.dueDate ?? new Date(), - validDate: initialRfq?.validDate ?? undefined, - incotermsCode: initialRfq?.incotermsCode ?? "", - classification: initialRfq?.classification ?? "", - sparepart: initialRfq?.sparepart ?? "", - rfqRevision: initialRfq?.rfqRevision ?? 0, - shortList: initialRfq?.shortList ?? false, - returnYn: initialRfq?.returnYn ?? false, - cpRequestYn: initialRfq?.cpRequestYn ?? false, - prjectGtcYn: initialRfq?.prjectGtcYn ?? false, - }, - }) - - // initialRfq가 변경될 때 폼 값을 업데이트 - React.useEffect(() => { - if (initialRfq) { - form.reset({ - initialRfqStatus: initialRfq.initialRfqStatus ?? "DRAFT", - dueDate: initialRfq.dueDate, - validDate: initialRfq.validDate, - incotermsCode: initialRfq.incotermsCode ?? "", - classification: initialRfq.classification ?? "", - sparepart: initialRfq.sparepart ?? "", - shortList: initialRfq.shortList ?? false, - returnYn: initialRfq.returnYn ?? false, - rfqRevision: initialRfq.rfqRevision ?? 0, - cpRequestYn: initialRfq.cpRequestYn ?? false, - prjectGtcYn: initialRfq.prjectGtcYn ?? false, - }) - } - }, [initialRfq, form]) - - function onSubmit(input: UpdateInitialRfqSchema) { - startUpdateTransition(async () => { - if (!initialRfq || !initialRfq.initialRfqId) { - toast.error("유효하지 않은 RFQ입니다.") - return - } - - const { error } = await modifyInitialRfq({ - id: initialRfq.initialRfqId, - ...input, - }) - - if (error) { - toast.error(error) - return - } - - form.reset() - props.onOpenChange?.(false) - toast.success("초기 RFQ가 수정되었습니다") - }) - } - - const selectedIncoterm = incoterms.find(incoterm => incoterm.code === form.watch("incotermsCode")) - - return ( - <Sheet {...props}> - <SheetContent className="flex flex-col h-full sm:max-w-md"> - {/* 고정 헤더 */} - <SheetHeader className="flex-shrink-0 text-left pb-6"> - <SheetTitle>초기 RFQ 수정</SheetTitle> - <SheetDescription> - 초기 RFQ 정보를 수정하고 변경사항을 저장하세요 - </SheetDescription> - </SheetHeader> - - {/* 스크롤 가능한 폼 영역 */} - <div className="flex-1 overflow-y-auto"> - <Form {...form}> - <form - onSubmit={form.handleSubmit(onSubmit)} - className="flex flex-col gap-4 pr-2" - > - {/* RFQ 리비전 */} - <FormField - control={form.control} - name="rfqRevision" - render={({ field }) => ( - <FormItem> - <FormLabel>RFQ 리비전</FormLabel> - <FormControl> - <Input - type="number" - min="0" - placeholder="0" - {...field} - onChange={(e) => field.onChange(parseInt(e.target.value) || 0)} - /> - </FormControl> - <FormMessage /> - </FormItem> - )} - /> - - {/* 마감일 */} - <FormField - control={form.control} - name="dueDate" - render={({ field }) => ( - <FormItem className="flex flex-col"> - <FormLabel>마감일 *</FormLabel> - <Popover> - <PopoverTrigger asChild> - <FormControl> - <Button - variant={"outline"} - className={cn( - "w-full pl-3 text-left font-normal", - !field.value && "text-muted-foreground" - )} - > - {field.value ? ( - format(field.value, "PPP", { locale: ko }) - ) : ( - <span>날짜를 선택하세요</span> - )} - <CalendarIcon className="ml-auto h-4 w-4 opacity-50" /> - </Button> - </FormControl> - </PopoverTrigger> - <PopoverContent className="w-auto p-0" align="start"> - <Calendar - mode="single" - selected={field.value} - onSelect={field.onChange} - disabled={(date) => - date < new Date("1900-01-01") - } - initialFocus - /> - </PopoverContent> - </Popover> - <FormMessage /> - </FormItem> - )} - /> - - {/* 유효일 */} - <FormField - control={form.control} - name="validDate" - render={({ field }) => ( - <FormItem className="flex flex-col"> - <FormLabel>유효일</FormLabel> - <Popover> - <PopoverTrigger asChild> - <FormControl> - <Button - variant={"outline"} - className={cn( - "w-full pl-3 text-left font-normal", - !field.value && "text-muted-foreground" - )} - > - {field.value ? ( - format(field.value, "PPP", { locale: ko }) - ) : ( - <span>날짜를 선택하세요</span> - )} - <CalendarIcon className="ml-auto h-4 w-4 opacity-50" /> - </Button> - </FormControl> - </PopoverTrigger> - <PopoverContent className="w-auto p-0" align="start"> - <Calendar - mode="single" - selected={field.value} - onSelect={field.onChange} - disabled={(date) => - date < new Date("1900-01-01") - } - initialFocus - /> - </PopoverContent> - </Popover> - <FormMessage /> - </FormItem> - )} - /> - - {/* Incoterms 코드 */} - <FormField - control={form.control} - name="incotermsCode" - render={({ field }) => ( - <FormItem className="flex flex-col"> - <FormLabel>Incoterms</FormLabel> - <Popover open={incotermsSearchOpen} onOpenChange={setIncotermsSearchOpen}> - <PopoverTrigger asChild> - <FormControl> - <Button - variant="outline" - role="combobox" - aria-expanded={incotermsSearchOpen} - className="justify-between" - disabled={incotermsLoading} - > - {selectedIncoterm ? ( - <div className="flex items-center gap-2"> - <span className="truncate"> - {selectedIncoterm.code} - {selectedIncoterm.description} - </span> - </div> - ) : ( - <span className="text-muted-foreground"> - {incotermsLoading ? "로딩 중..." : "인코텀즈를 선택하세요"} - </span> - )} - <ChevronsUpDown className="ml-2 h-4 w-4 shrink-0 opacity-50" /> - </Button> - </FormControl> - </PopoverTrigger> - <PopoverContent className="w-full p-0" align="start"> - <Command> - <CommandInput - placeholder="코드 또는 내용으로 검색..." - className="h-9" - /> - <CommandList> - <CommandEmpty>검색 결과가 없습니다.</CommandEmpty> - <CommandGroup> - {incoterms.map((incoterm) => ( - <CommandItem - key={incoterm.id} - value={`${incoterm.code} ${incoterm.description}`} - onSelect={() => { - field.onChange(incoterm.code) - setIncotermsSearchOpen(false) - }} - > - <div className="flex items-center gap-2 w-full"> - <div className="flex-1 min-w-0"> - <div className="font-medium truncate"> - {incoterm.code} - {incoterm.description} - </div> - </div> - <Check - className={cn( - "ml-auto h-4 w-4", - incoterm.code === field.value ? "opacity-100" : "opacity-0" - )} - /> - </div> - </CommandItem> - ))} - </CommandGroup> - </CommandList> - </Command> - </PopoverContent> - </Popover> - <FormMessage /> - </FormItem> - )} - /> - {/* 체크박스 옵션들 */} - <div className="space-y-3"> - <FormField - control={form.control} - name="shortList" - render={({ field }) => ( - <FormItem className="flex flex-row items-start space-x-3 space-y-0"> - <FormControl> - <Checkbox - checked={field.value} - onCheckedChange={field.onChange} - /> - </FormControl> - <div className="space-y-1 leading-none ml-2"> - <FormLabel>Short List</FormLabel> - </div> - </FormItem> - )} - /> - - <FormField - control={form.control} - name="returnYn" - render={({ field }) => ( - <FormItem className="flex flex-row items-start space-x-3 space-y-0"> - <FormControl> - <Checkbox - checked={field.value} - onCheckedChange={field.onChange} - /> - </FormControl> - <div className="space-y-1 leading-none ml-2"> - <FormLabel>회신 여부</FormLabel> - </div> - </FormItem> - )} - /> - - {/* 선급 */} - <FormField - control={form.control} - name="classification" - render={({ field }) => ( - <FormItem> - <FormLabel>선급</FormLabel> - <FormControl> - <Input - placeholder="선급" - {...field} - /> - </FormControl> - <FormMessage /> - </FormItem> - )} - /> - - {/* 예비부품 */} - <FormField - control={form.control} - name="sparepart" - render={({ field }) => ( - <FormItem> - <FormLabel>예비부품</FormLabel> - <FormControl> - <Input - placeholder="O1, O2" - {...field} - /> - </FormControl> - <FormMessage /> - </FormItem> - )} - /> - - - - - <FormField - control={form.control} - name="cpRequestYn" - render={({ field }) => ( - <FormItem className="flex flex-row items-start space-x-3 space-y-0"> - <FormControl> - <Checkbox - checked={field.value} - onCheckedChange={field.onChange} - /> - </FormControl> - <div className="space-y-1 leading-none ml-2"> - <FormLabel>CP 요청</FormLabel> - </div> - </FormItem> - )} - /> - - <FormField - control={form.control} - name="prjectGtcYn" - render={({ field }) => ( - <FormItem className="flex flex-row items-start space-x-3 space-y-0"> - <FormControl> - <Checkbox - checked={field.value} - onCheckedChange={field.onChange} - /> - </FormControl> - <div className="space-y-1 leading-none ml-2"> - <FormLabel>프로젝트 GTC</FormLabel> - </div> - </FormItem> - )} - /> - </div> - - {/* 하단 여백 */} - <div className="h-4" /> - </form> - </Form> - </div> - - {/* 고정 푸터 */} - <SheetFooter className="flex-shrink-0 gap-2 pt-6 sm:space-x-0"> - <SheetClose asChild> - <Button type="button" variant="outline"> - 취소 - </Button> - </SheetClose> - <Button - onClick={form.handleSubmit(onSubmit)} - disabled={isUpdatePending} - > - {isUpdatePending && ( - <Loader - className="mr-2 size-4 animate-spin" - aria-hidden="true" - /> - )} - 저장 - </Button> - </SheetFooter> - </SheetContent> - </Sheet> - ) -}
\ No newline at end of file |
