diff options
Diffstat (limited to 'lib/b-rfq/vendor-response/comment-edit-dialog.tsx')
| -rw-r--r-- | lib/b-rfq/vendor-response/comment-edit-dialog.tsx | 187 |
1 files changed, 187 insertions, 0 deletions
diff --git a/lib/b-rfq/vendor-response/comment-edit-dialog.tsx b/lib/b-rfq/vendor-response/comment-edit-dialog.tsx new file mode 100644 index 00000000..0c2c0c62 --- /dev/null +++ b/lib/b-rfq/vendor-response/comment-edit-dialog.tsx @@ -0,0 +1,187 @@ +// components/rfq/comment-edit-dialog.tsx +"use client"; + +import { useState } from "react"; +import { Button } from "@/components/ui/button"; +import { + Dialog, + DialogContent, + DialogHeader, + DialogTitle, + DialogTrigger, +} from "@/components/ui/dialog"; +import { + Form, + FormControl, + FormField, + FormItem, + FormLabel, + FormMessage, +} from "@/components/ui/form"; +import { Textarea } from "@/components/ui/textarea"; +import { useForm } from "react-hook-form"; +import { zodResolver } from "@hookform/resolvers/zod"; +import * as z from "zod"; +import { MessageSquare, Loader2 } from "lucide-react"; +import { useToast } from "@/hooks/use-toast"; +import { useRouter } from "next/navigation"; + +const commentFormSchema = z.object({ + responseComment: z.string().optional(), + vendorComment: z.string().optional(), +}); + +type CommentFormData = z.infer<typeof commentFormSchema>; + +interface CommentEditDialogProps { + responseId: number; + currentResponseComment?: string; + currentVendorComment?: string; + trigger?: React.ReactNode; + onSuccess?: () => void; +} + +export function CommentEditDialog({ + responseId, + currentResponseComment, + currentVendorComment, + trigger, + onSuccess, +}: CommentEditDialogProps) { + const [open, setOpen] = useState(false); + const [isSaving, setIsSaving] = useState(false); + const { toast } = useToast(); + const router = useRouter(); + + const form = useForm<CommentFormData>({ + resolver: zodResolver(commentFormSchema), + defaultValues: { + responseComment: currentResponseComment || "", + vendorComment: currentVendorComment || "", + }, + }); + + const onSubmit = async (data: CommentFormData) => { + setIsSaving(true); + + try { + const response = await fetch("/api/vendor-responses/update-comment", { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ + responseId, + responseComment: data.responseComment, + vendorComment: data.vendorComment, + }), + }); + + if (!response.ok) { + const error = await response.json(); + throw new Error(error.message || "코멘트 업데이트 실패"); + } + + toast({ + title: "코멘트 업데이트 완료", + description: "코멘트가 성공적으로 업데이트되었습니다.", + }); + + setOpen(false); + + router.refresh(); + onSuccess?.(); + + } catch (error) { + console.error("Comment update error:", error); + toast({ + title: "업데이트 실패", + description: error instanceof Error ? error.message : "알 수 없는 오류가 발생했습니다.", + variant: "destructive", + }); + } finally { + setIsSaving(false); + } + }; + + return ( + <Dialog open={open} onOpenChange={setOpen}> + <DialogTrigger asChild> + {trigger || ( + <Button size="sm" variant="outline"> + <MessageSquare className="h-3 w-3 mr-1" /> + 코멘트 + </Button> + )} + </DialogTrigger> + <DialogContent className="max-w-lg"> + <DialogHeader> + <DialogTitle className="flex items-center gap-2"> + <MessageSquare className="h-5 w-5" /> + 코멘트 수정 + </DialogTitle> + </DialogHeader> + + <Form {...form}> + <form onSubmit={form.handleSubmit(onSubmit)} className="space-y-6"> + {/* 응답 코멘트 */} + <FormField + control={form.control} + name="responseComment" + render={({ field }) => ( + <FormItem> + <FormLabel>응답 코멘트</FormLabel> + <FormControl> + <Textarea + placeholder="응답에 대한 설명을 입력하세요..." + className="resize-none" + rows={3} + {...field} + /> + </FormControl> + <FormMessage /> + </FormItem> + )} + /> + + {/* 벤더 코멘트 */} + <FormField + control={form.control} + name="vendorComment" + render={({ field }) => ( + <FormItem> + <FormLabel>벤더 코멘트 (내부용)</FormLabel> + <FormControl> + <Textarea + placeholder="내부 참고용 코멘트를 입력하세요..." + className="resize-none" + rows={3} + {...field} + /> + </FormControl> + <FormMessage /> + </FormItem> + )} + /> + + {/* 버튼 */} + <div className="flex justify-end gap-2"> + <Button + type="button" + variant="outline" + onClick={() => setOpen(false)} + disabled={isSaving} + > + 취소 + </Button> + <Button type="submit" disabled={isSaving}> + {isSaving && <Loader2 className="h-4 w-4 mr-2 animate-spin" />} + {isSaving ? "저장 중..." : "저장"} + </Button> + </div> + </form> + </Form> + </DialogContent> + </Dialog> + ); +}
\ No newline at end of file |
