summaryrefslogtreecommitdiff
path: root/lib/bidding/failure/biddings-closure-dialog.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'lib/bidding/failure/biddings-closure-dialog.tsx')
-rw-r--r--lib/bidding/failure/biddings-closure-dialog.tsx142
1 files changed, 142 insertions, 0 deletions
diff --git a/lib/bidding/failure/biddings-closure-dialog.tsx b/lib/bidding/failure/biddings-closure-dialog.tsx
new file mode 100644
index 00000000..64aba42f
--- /dev/null
+++ b/lib/bidding/failure/biddings-closure-dialog.tsx
@@ -0,0 +1,142 @@
+// 폐찰하기 다이얼로그
+"use client"
+
+import { useState } from "react"
+import { toast } from "sonner"
+import { bidClosureAction } from "@/lib/bidding/actions"
+import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle } from "@/components/ui/dialog"
+import { Label } from "@/components/ui/label"
+import { Textarea } from "@/components/ui/textarea"
+import { Input } from "@/components/ui/input"
+import { Button } from "@/components/ui/button"
+import { FileXIcon } from "lucide-react"
+
+interface BiddingsClosureDialogProps {
+ open: boolean;
+ onOpenChange: (open: boolean) => void;
+ bidding: {
+ id: number;
+ title: string;
+ biddingNumber: string;
+ } | null;
+ userId: string;
+ onSuccess?: () => void;
+ }
+
+ export function BiddingsClosureDialog({
+ open,
+ onOpenChange,
+ bidding,
+ userId,
+ onSuccess
+ }: BiddingsClosureDialogProps) {
+ const [description, setDescription] = useState('')
+ const [files, setFiles] = useState<File[]>([])
+ const [isSubmitting, setIsSubmitting] = useState(false)
+
+ const handleSubmit = async (e: React.FormEvent) => {
+ e.preventDefault()
+
+ if (!bidding || !description.trim()) {
+ toast.error('폐찰 사유를 입력해주세요.')
+ return
+ }
+
+ setIsSubmitting(true)
+
+ try {
+ const result = await bidClosureAction(bidding.id, {
+ description: description.trim(),
+ files
+ }, userId)
+
+ if (result.success) {
+ toast.success(result.message)
+ onOpenChange(false)
+ onSuccess?.()
+ // 페이지 새로고침 또는 상태 업데이트
+ window.location.reload()
+ } else {
+ toast.error(result.error || '폐찰 처리 중 오류가 발생했습니다.')
+ }
+ } catch (error) {
+ toast.error('폐찰 처리 중 오류가 발생했습니다.')
+ } finally {
+ setIsSubmitting(false)
+ }
+ }
+
+ const handleFileChange = (e: React.ChangeEvent<HTMLInputElement>) => {
+ if (e.target.files) {
+ setFiles(Array.from(e.target.files))
+ }
+ }
+
+ if (!bidding) return null
+
+ return (
+ <Dialog open={open} onOpenChange={onOpenChange}>
+ <DialogContent className="max-w-2xl">
+ <DialogHeader>
+ <DialogTitle className="flex items-center gap-2">
+ <FileXIcon className="h-5 w-5 text-destructive" />
+ 폐찰하기
+ </DialogTitle>
+ <DialogDescription>
+ {bidding.title} ({bidding.biddingNumber})를 폐찰합니다.
+ </DialogDescription>
+ </DialogHeader>
+
+ <form onSubmit={handleSubmit} className="space-y-4">
+ <div className="space-y-2">
+ <Label htmlFor="description">폐찰 사유 <span className="text-destructive">*</span></Label>
+ <Textarea
+ id="description"
+ placeholder="폐찰 사유를 입력해주세요..."
+ value={description}
+ onChange={(e) => setDescription(e.target.value)}
+ className="min-h-[100px]"
+ required
+ />
+ </div>
+
+ <div className="space-y-2">
+ <Label htmlFor="files">첨부파일</Label>
+ <Input
+ id="files"
+ type="file"
+ multiple
+ onChange={handleFileChange}
+ className="cursor-pointer"
+ accept=".pdf,.doc,.docx,.xls,.xlsx,.txt,.jpg,.jpeg,.png"
+ />
+ {files.length > 0 && (
+ <div className="text-sm text-muted-foreground">
+ 선택된 파일: {files.map(f => f.name).join(', ')}
+ </div>
+ )}
+ </div>
+
+ <div className="flex justify-end gap-2 pt-4">
+ <Button
+ type="button"
+ variant="outline"
+ onClick={() => onOpenChange(false)}
+ disabled={isSubmitting}
+ >
+ 취소
+ </Button>
+ <Button
+ type="submit"
+ variant="destructive"
+ disabled={isSubmitting || !description.trim()}
+ >
+ {isSubmitting ? '처리 중...' : '폐찰하기'}
+ </Button>
+ </div>
+ </form>
+ </DialogContent>
+ </Dialog>
+ )
+ }
+ \ No newline at end of file