diff options
Diffstat (limited to 'lib/rfq-last/vendor-response/participation-dialog.tsx')
| -rw-r--r-- | lib/rfq-last/vendor-response/participation-dialog.tsx | 230 |
1 files changed, 230 insertions, 0 deletions
diff --git a/lib/rfq-last/vendor-response/participation-dialog.tsx b/lib/rfq-last/vendor-response/participation-dialog.tsx new file mode 100644 index 00000000..a7337ac2 --- /dev/null +++ b/lib/rfq-last/vendor-response/participation-dialog.tsx @@ -0,0 +1,230 @@ +// components/vendor/participation-dialog.tsx + +"use client" + +import * as React from "react" +import { useRouter } from "next/navigation" +import { + Dialog, + DialogContent, + DialogDescription, + DialogFooter, + DialogHeader, + DialogTitle, +} from "@/components/ui/dialog" +import { Button } from "@/components/ui/button" +import { Textarea } from "@/components/ui/textarea" +import { Label } from "@/components/ui/label" +import { + AlertDialog, + AlertDialogAction, + AlertDialogCancel, + AlertDialogContent, + AlertDialogDescription, + AlertDialogFooter, + AlertDialogHeader, + AlertDialogTitle, +} from "@/components/ui/alert-dialog" +import { useToast } from "@/hooks/use-toast" +import { updateParticipationStatus } from "@/lib/rfq-last/vendor-response/service" +import { CheckCircle, XCircle } from "lucide-react" + +interface ParticipationDialogProps { + rfqId: number + rfqCode: string + rfqLastDetailsId: number + currentStatus?: string + onClose: () => void +} + +export function ParticipationDialog({ + rfqId, + rfqCode, + rfqLastDetailsId, + currentStatus, + onClose, +}: ParticipationDialogProps) { + const router = useRouter() + const [showDeclineDialog, setShowDeclineDialog] = React.useState(false) + const [showConfirmDialog, setShowConfirmDialog] = React.useState(false) + const [declineReason, setDeclineReason] = React.useState("") + const [isLoading, setIsLoading] = React.useState(false) + const { toast } = useToast(); + + const handleParticipate = () => { + setShowConfirmDialog(true) + } + + const handleDecline = () => { + setShowDeclineDialog(true) + } + + const confirmParticipation = async () => { + setIsLoading(true) + try { + const result = await updateParticipationStatus({ + rfqId, + rfqLastDetailsId, + participationStatus: "참여", + }) + + if (result.success) { + toast({ + title: "참여 확정", + description: result.message, + }) + // router.push(`/partners/rfq-last/${rfqId}`) + router.refresh() + } else { + toast({ + title: "오류", + description: result.message, + variant: "destructive", + }) + } + } catch (error) { + toast({ + title: "오류", + description: "참여 처리 중 오류가 발생했습니다.", + variant: "destructive", + }) + } finally { + setIsLoading(false) + onClose() + } + } + + const confirmDecline = async () => { + if (!declineReason.trim()) { + toast({ + title: "불참 사유 필요", + description: "불참 사유를 입력해주세요.", + variant: "destructive", + }) + return + } + + setIsLoading(true) + try { + const result = await updateParticipationStatus({ + rfqId, + rfqLastDetailsId, + participationStatus: "불참", + nonParticipationReason: declineReason, + }) + + if (result.success) { + toast({ + title: "불참 처리 완료", + description: result.message, + }) + router.refresh() + } else { + toast({ + title: "오류", + description: result.message, + variant: "destructive", + }) + } + } catch (error) { + toast({ + title: "오류", + description: "불참 처리 중 오류가 발생했습니다.", + variant: "destructive", + }) + } finally { + setIsLoading(false) + onClose() + } + } + + return ( + <> + {/* 메인 다이얼로그 */} + <AlertDialog open={true} onOpenChange={onClose}> + <AlertDialogContent> + <AlertDialogHeader> + <AlertDialogTitle>견적 참여 여부 결정</AlertDialogTitle> + <AlertDialogDescription> + {rfqCode} 견적 요청에 참여하시겠습니까? + </AlertDialogDescription> + </AlertDialogHeader> + <AlertDialogFooter> + <AlertDialogCancel>취소</AlertDialogCancel> + <Button + variant="outline" + onClick={handleDecline} + disabled={isLoading} + > + <XCircle className="mr-2 h-4 w-4" /> + 불참 + </Button> + <Button + onClick={handleParticipate} + disabled={isLoading} + > + <CheckCircle className="mr-2 h-4 w-4" /> + 참여 + </Button> + </AlertDialogFooter> + </AlertDialogContent> + </AlertDialog> + + {/* 참여 확인 다이얼로그 */} + <AlertDialog open={showConfirmDialog} onOpenChange={setShowConfirmDialog}> + <AlertDialogContent> + <AlertDialogHeader> + <AlertDialogTitle>견적 참여 확정</AlertDialogTitle> + <AlertDialogDescription> + 견적 참여를 확정하시면 견적서 작성 페이지로 이동합니다. + </AlertDialogDescription> + </AlertDialogHeader> + <AlertDialogFooter> + <AlertDialogCancel>취소</AlertDialogCancel> + <AlertDialogAction onClick={confirmParticipation}> + 확정 + </AlertDialogAction> + </AlertDialogFooter> + </AlertDialogContent> + </AlertDialog> + + {/* 불참 사유 입력 다이얼로그 */} + <Dialog open={showDeclineDialog} onOpenChange={setShowDeclineDialog}> + <DialogContent> + <DialogHeader> + <DialogTitle>견적 불참</DialogTitle> + <DialogDescription> + 불참 사유를 입력해주세요. + </DialogDescription> + </DialogHeader> + <div className="grid gap-4 py-4"> + <div className="grid gap-2"> + <Label htmlFor="reason">불참 사유</Label> + <Textarea + id="reason" + placeholder="불참 사유를 입력하세요..." + value={declineReason} + onChange={(e) => setDeclineReason(e.target.value)} + rows={4} + /> + </div> + </div> + <DialogFooter> + <Button + variant="outline" + onClick={() => setShowDeclineDialog(false)} + > + 취소 + </Button> + <Button + onClick={confirmDecline} + disabled={isLoading || !declineReason.trim()} + > + 불참 확정 + </Button> + </DialogFooter> + </DialogContent> + </Dialog> + </> + ) +}
\ No newline at end of file |
