diff options
Diffstat (limited to 'lib/bidding/list')
| -rw-r--r-- | lib/bidding/list/biddings-delete-dialog.tsx | 102 | ||||
| -rw-r--r-- | lib/bidding/list/biddings-table-toolbar-actions.tsx | 38 |
2 files changed, 135 insertions, 5 deletions
diff --git a/lib/bidding/list/biddings-delete-dialog.tsx b/lib/bidding/list/biddings-delete-dialog.tsx new file mode 100644 index 00000000..9291742f --- /dev/null +++ b/lib/bidding/list/biddings-delete-dialog.tsx @@ -0,0 +1,102 @@ +"use client" + +import * as React from "react" +import { + AlertDialog, + AlertDialogAction, + AlertDialogCancel, + AlertDialogContent, + AlertDialogDescription, + AlertDialogFooter, + AlertDialogHeader, + AlertDialogTitle, +} from "@/components/ui/alert-dialog" +import { Input } from "@/components/ui/input" +import { Label } from "@/components/ui/label" +import { BiddingListItem } from "@/db/schema" +import { deleteBidding } from "@/lib/bidding/delete-action" +import { toast } from "sonner" +import { Loader2 } from "lucide-react" + +interface BiddingDeleteDialogProps { + open: boolean + onOpenChange: (open: boolean) => void + bidding: BiddingListItem + onSuccess?: () => void +} + +export function BiddingDeleteDialog({ + open, + onOpenChange, + bidding, + onSuccess +}: BiddingDeleteDialogProps) { + const [isDeleting, setIsDeleting] = React.useState(false) + const [deleteReason, setDeleteReason] = React.useState("") + + const handleDelete = async () => { + if (!bidding) return + + setIsDeleting(true) + try { + const result = await deleteBidding([bidding.id], deleteReason) + + if (result.success) { + toast.success(result.message) + onOpenChange(false) + onSuccess?.() + } else { + toast.error(result.message) + } + } catch (error) { + toast.error("삭제 중 오류가 발생했습니다.") + console.error(error) + } finally { + setIsDeleting(false) + } + } + + return ( + <AlertDialog open={open} onOpenChange={onOpenChange}> + <AlertDialogContent> + <AlertDialogHeader> + <AlertDialogTitle>입찰 삭제</AlertDialogTitle> + <AlertDialogDescription> + 선택한 입찰({bidding?.biddingNumber})을 삭제하시겠습니까?<br/> + 삭제된 입찰은 복구할 수 없습니다. + <div className="mt-4"> + <Label htmlFor="deleteReason" className="mb-2 block">삭제 사유</Label> + <Input + id="deleteReason" + value={deleteReason} + onChange={(e) => setDeleteReason(e.target.value)} + placeholder="삭제 사유를 입력하세요" + /> + </div> + </AlertDialogDescription> + </AlertDialogHeader> + <AlertDialogFooter> + <AlertDialogCancel disabled={isDeleting}>취소</AlertDialogCancel> + <AlertDialogAction + onClick={(e) => { + e.preventDefault() + handleDelete() + }} + disabled={isDeleting} + className="bg-destructive text-destructive-foreground hover:bg-destructive/90" + > + {isDeleting ? ( + <> + <Loader2 className="mr-2 size-4 animate-spin" /> + 삭제 중... + </> + ) : ( + "삭제" + )} + </AlertDialogAction> + </AlertDialogFooter> + </AlertDialogContent> + </AlertDialog> + ) +} + diff --git a/lib/bidding/list/biddings-table-toolbar-actions.tsx b/lib/bidding/list/biddings-table-toolbar-actions.tsx index a3851630..33368218 100644 --- a/lib/bidding/list/biddings-table-toolbar-actions.tsx +++ b/lib/bidding/list/biddings-table-toolbar-actions.tsx @@ -3,7 +3,7 @@ import * as React from "react" import { type Table } from "@tanstack/react-table" import { - Send, Download, FileSpreadsheet + Send, Download, FileSpreadsheet, Trash } from "lucide-react" import { toast } from "sonner" import { useSession } from "next-auth/react" @@ -21,6 +21,8 @@ import { BiddingCreateDialog } from "@/components/bidding/create/bidding-create- import { useForm } from "react-hook-form" import { zodResolver } from "@hookform/resolvers/zod" import { createBiddingSchema } from "@/lib/bidding/validation" +import { deleteBidding } from "@/lib/bidding/delete-action" +import { BiddingDeleteDialog } from "./biddings-delete-dialog" interface BiddingsTableToolbarActionsProps { table: Table<BiddingListItem> @@ -30,7 +32,8 @@ export function BiddingsTableToolbarActions({ table }: BiddingsTableToolbarActio const { data: session } = useSession() const [isExporting, setIsExporting] = React.useState(false) const [isTransmissionDialogOpen, setIsTransmissionDialogOpen] = React.useState(false) - + const [isDeleteDialogOpen, setIsDeleteDialogOpen] = React.useState(false) + const userId = session?.user?.id ? Number(session.user.id) : 1 // 입찰 생성 폼 @@ -83,8 +86,11 @@ export function BiddingsTableToolbarActions({ table }: BiddingsTableToolbarActio // 업체선정이 완료된 입찰만 전송 가능 const canTransmit = true - console.log(canTransmit, 'canTransmit') - console.log(selectedBiddings, 'selectedBiddings') + + // 삭제 가능 여부: 선택된 항목이 정확히 1개이고, '입찰생성' 상태여야 함 + const canDelete = React.useMemo(() => { + return selectedBiddings.length === 1 && selectedBiddings[0].status === 'bidding_generated' + }, [selectedBiddings]) return ( <> @@ -94,7 +100,6 @@ export function BiddingsTableToolbarActions({ table }: BiddingsTableToolbarActio // 성공 시 테이블 새로고침 등 추가 작업 // window.location.reload() }} /> - {/* 전송하기 (업체선정 완료된 입찰만) */} <Button variant="default" @@ -106,6 +111,21 @@ export function BiddingsTableToolbarActions({ table }: BiddingsTableToolbarActio <Send className="size-4" aria-hidden="true" /> <span className="hidden sm:inline">전송하기</span> </Button> + {/* 삭제 버튼 */} + + <Button + variant="destructive" + size="sm" + onClick={() => setIsDeleteDialogOpen(true)} + disabled={!canDelete} + className="gap-2" + > + <Trash className="size-4" aria-hidden="true" /> + <span className="hidden sm:inline">삭제</span> + </Button> + + + </div> {/* 전송 다이얼로그 */} @@ -115,6 +135,14 @@ export function BiddingsTableToolbarActions({ table }: BiddingsTableToolbarActio bidding={selectedBiddings[0]} userId={userId} /> + + {/* 삭제 다이얼로그 */} + <BiddingDeleteDialog + open={isDeleteDialogOpen} + onOpenChange={setIsDeleteDialogOpen} + bidding={selectedBiddings[0]} + onSuccess={() => table.resetRowSelection()} + /> </> ) }
\ No newline at end of file |
