summaryrefslogtreecommitdiff
path: root/lib/bidding/failure
diff options
context:
space:
mode:
authordujinkim <dujin.kim@dtsolution.co.kr>2025-11-25 11:51:27 +0000
committerdujinkim <dujin.kim@dtsolution.co.kr>2025-11-25 11:51:27 +0000
commit835df8ddc115ffa74414db2a4fab7efc0d0056a9 (patch)
treebfe814c7b51ee1541d84b6e2dee01f28594763ac /lib/bidding/failure
parent6160e8bd61360ada9e8e0574671c38292eaba9e7 (diff)
(최겸) 구매 입찰 수정v2
Diffstat (limited to 'lib/bidding/failure')
-rw-r--r--lib/bidding/failure/biddings-closure-dialog.tsx53
-rw-r--r--lib/bidding/failure/biddings-failure-table.tsx131
2 files changed, 100 insertions, 84 deletions
diff --git a/lib/bidding/failure/biddings-closure-dialog.tsx b/lib/bidding/failure/biddings-closure-dialog.tsx
index f331167b..cea1f42a 100644
--- a/lib/bidding/failure/biddings-closure-dialog.tsx
+++ b/lib/bidding/failure/biddings-closure-dialog.tsx
@@ -4,7 +4,6 @@
import { useState } from "react"
import { useSession } from "next-auth/react"
import { toast } from "sonner"
-import { requestBiddingClosureWithApproval } from "@/lib/bidding/approval-actions"
import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle } from "@/components/ui/dialog"
import { Label } from "@/components/ui/label"
import { Textarea } from "@/components/ui/textarea"
@@ -21,58 +20,41 @@ interface BiddingsClosureDialogProps {
biddingNumber: string;
} | null;
onSuccess?: () => void;
+ onApprovalPreview: (data: { description: string; files: File[]; biddingId: number }) => Promise<void>;
}
export function BiddingsClosureDialog({
open,
onOpenChange,
bidding,
- onSuccess
+ onSuccess,
+ onApprovalPreview
}: BiddingsClosureDialogProps) {
const { data: session } = useSession()
const [description, setDescription] = useState('')
const [files, setFiles] = useState<File[]>([])
- const [isSubmitting, setIsSubmitting] = useState(false)
- const handleSubmit = async (e: React.FormEvent) => {
+ const handleNextStep = async (e: React.FormEvent) => {
e.preventDefault()
-
+
if (!bidding || !description.trim()) {
toast.error('폐찰 사유를 입력해주세요.')
return
}
-
- setIsSubmitting(true)
try {
- const result = await requestBiddingClosureWithApproval({
- biddingId: bidding.id,
+ // 결재자 선택 단계로 데이터 전달
+ await onApprovalPreview({
description: description.trim(),
- files,
- currentUser: {
- id: session?.user?.id ? Number(session.user.id) : 0,
- epId: session?.user?.epId || null,
- email: session?.user?.email || undefined,
- },
+ files: files,
+ biddingId: bidding.id,
})
- if (result.status === 'pending_approval') {
- toast.success('폐찰 결재가 상신되었습니다.')
- onOpenChange(false)
- // 폼 초기화
- setDescription('')
- setFiles([])
- if (onSuccess) {
- onSuccess()
- }
- } else {
- toast.error('결재 상신에 실패했습니다.')
- }
+ // 다이얼로그 닫기
+ onOpenChange(false)
} catch (error) {
- console.error('폐찰 결재 상신 실패:', error)
- toast.error(error instanceof Error ? error.message : '결재 상신 중 오류가 발생했습니다.')
- } finally {
- setIsSubmitting(false)
+ console.error('결재 미리보기 준비 실패:', error)
+ toast.error('결재 미리보기 준비 중 오류가 발생했습니다.')
}
}
@@ -98,7 +80,7 @@ interface BiddingsClosureDialogProps {
</DialogDescription>
</DialogHeader>
- <form onSubmit={handleSubmit} className="space-y-4">
+ <form onSubmit={handleNextStep} className="space-y-4">
<div className="space-y-2">
<Label htmlFor="description">폐찰 사유 <span className="text-destructive">*</span></Label>
<Textarea
@@ -133,16 +115,15 @@ interface BiddingsClosureDialogProps {
type="button"
variant="outline"
onClick={() => onOpenChange(false)}
- disabled={isSubmitting}
>
취소
</Button>
<Button
type="submit"
- variant="destructive"
- disabled={isSubmitting || !description.trim()}
+ variant="default"
+ disabled={!description.trim()}
>
- {isSubmitting ? '상신 중...' : '결재 상신'}
+ 다음 단계
</Button>
</div>
</form>
diff --git a/lib/bidding/failure/biddings-failure-table.tsx b/lib/bidding/failure/biddings-failure-table.tsx
index a0f98466..c4e3be06 100644
--- a/lib/bidding/failure/biddings-failure-table.tsx
+++ b/lib/bidding/failure/biddings-failure-table.tsx
@@ -25,7 +25,7 @@ import { FileX, RefreshCw, Undo2 } from "lucide-react"
import { bidClosureAction, cancelDisposalAction } from "@/lib/bidding/actions"
import { increaseRoundOrRebid } from "@/lib/bidding/service"
import { ApprovalPreviewDialog } from "@/lib/approval/approval-preview-dialog"
-import { requestBiddingClosureWithApproval } from "@/lib/bidding/approval-actions"
+import { requestBiddingClosureWithApproval, prepareBiddingClosureApprovalData } from "@/lib/bidding/approval-actions"
import { useToast } from "@/hooks/use-toast"
type BiddingFailureItem = {
@@ -258,6 +258,86 @@ export function BiddingsFailureTable({ promises }: BiddingsFailureTableProps) {
}
}, [session?.user?.id, toast, router])
+ // 폐찰 결재 준비 및 결재 다이얼로그 열기 핸들러
+ const handleClosureApprovalSend = async (data: { description: string; files: File[]; biddingId: number }) => {
+ try {
+ if (!session?.user?.id) {
+ toast({
+ title: '오류',
+ description: '사용자 정보가 없습니다.',
+ variant: 'destructive',
+ })
+ return
+ }
+
+ // 결재 데이터 준비 (템플릿 변수 등)
+ const approvalData = await prepareBiddingClosureApprovalData({
+ biddingId: data.biddingId,
+ description: data.description,
+ })
+
+ // 결재 준비 완료 - approvalPreviewData와 결재 데이터 저장 및 결재 다이얼로그 열기
+ setApprovalPreviewData({
+ templateName: '폐찰 품의 요청서',
+ variables: approvalData.variables,
+ title: `폐찰 - ${selectedBidding?.title || ''}`,
+ description: data.description,
+ files: data.files,
+ })
+ setIsApprovalPreviewDialogOpen(true)
+ } catch (error) {
+ console.error('결재 준비 중 오류 발생:', error)
+ toast({
+ title: '오류',
+ description: '결재 준비 중 오류가 발생했습니다.',
+ variant: 'destructive',
+ })
+ }
+ }
+
+ // 폐찰 결재 상신 핸들러 - 결재 완료 시 실제 폐찰 실행
+ const handleClosureApprovalSubmit = async (data: { approvers: string[]; title: string; attachments?: File[] }) => {
+ if (!session?.user?.id || !approvalPreviewData || !selectedBidding) return
+
+ try {
+ const result = await requestBiddingClosureWithApproval({
+ biddingId: selectedBidding.id,
+ description: approvalPreviewData.description,
+ files: approvalPreviewData.files,
+ currentUser: {
+ id: Number(session.user.id),
+ epId: session.user.epId || null,
+ email: session.user.email || undefined
+ },
+ approvers: data.approvers,
+ })
+
+ if (1) {
+ toast({
+ title: '성공',
+ description: `폐찰 결재가 상신되었습니다. (ID: ${result.approvalId})`,
+ })
+ setIsApprovalPreviewDialogOpen(false)
+ setApprovalPreviewData(null)
+ handleBiddingClosureDialogClose()
+ router.refresh()
+ } else {
+ toast({
+ title: '오류',
+ description: '폐찰 결재 상신 중 오류가 발생했습니다.',
+ variant: 'destructive',
+ })
+ }
+ } catch (error) {
+ console.error('폐찰 결재 상신 실패:', error)
+ toast({
+ title: '오류',
+ description: '폐찰 결재 상신 중 오류가 발생했습니다.',
+ variant: 'destructive',
+ })
+ }
+ }
+
const handleCancelDisposal = React.useCallback(async (bidding: BiddingFailureItem) => {
if (!session?.user?.id) {
toast({
@@ -438,10 +518,7 @@ export function BiddingsFailureTable({ promises }: BiddingsFailureTableProps) {
router.refresh()
handleBiddingClosureDialogClose()
}}
- onApprovalPreview={(data) => {
- setApprovalPreviewData(data)
- setIsApprovalPreviewDialogOpen(true)
- }}
+ onApprovalPreview={handleClosureApprovalSend}
/>
)}
@@ -498,52 +575,10 @@ export function BiddingsFailureTable({ promises }: BiddingsFailureTableProps) {
name: session.user.name || undefined,
email: session.user.email || undefined
}}
- onConfirm={handleClosureApprovalConfirm}
+ onConfirm={handleClosureApprovalSubmit}
/>
)}
</>
)
- // 폐찰 결재 상신 핸들러
- const handleClosureApprovalConfirm = async (data: { approvers: string[]; title: string; attachments?: File[] }) => {
- if (!session?.user?.id || !approvalPreviewData || !selectedBidding) return
-
- try {
- const result = await requestBiddingClosureWithApproval({
- biddingId: selectedBidding.id,
- description: approvalPreviewData.description,
- files: approvalPreviewData.files,
- currentUser: {
- id: Number(session.user.id),
- epId: session.user.epId || null,
- email: session.user.email || undefined
- },
- approvers: data.approvers,
- })
-
- if (result.status === 'pending_approval') {
- toast({
- title: '성공',
- description: `폐찰 결재가 상신되었습니다. (ID: ${result.approvalId})`,
- })
- setIsApprovalPreviewDialogOpen(false)
- setApprovalPreviewData(null)
- handleBiddingClosureDialogClose()
- router.refresh()
- } else {
- toast({
- title: '오류',
- description: '폐찰 결재 상신 중 오류가 발생했습니다.',
- variant: 'destructive',
- })
- }
- } catch (error) {
- console.error('폐찰 결재 상신 실패:', error)
- toast({
- title: '오류',
- description: '폐찰 결재 상신 중 오류가 발생했습니다.',
- variant: 'destructive',
- })
- }
- }
}