summaryrefslogtreecommitdiff
path: root/lib/vendors/table
diff options
context:
space:
mode:
Diffstat (limited to 'lib/vendors/table')
-rw-r--r--lib/vendors/table/approve-vendor-dialog.tsx31
-rw-r--r--lib/vendors/table/request-pq-dialog.tsx115
-rw-r--r--lib/vendors/table/vendors-table-toolbar-actions.tsx2
3 files changed, 123 insertions, 25 deletions
diff --git a/lib/vendors/table/approve-vendor-dialog.tsx b/lib/vendors/table/approve-vendor-dialog.tsx
index 9c175dc5..940710f5 100644
--- a/lib/vendors/table/approve-vendor-dialog.tsx
+++ b/lib/vendors/table/approve-vendor-dialog.tsx
@@ -55,20 +55,29 @@ export function ApproveVendorsDialog({
}
startApproveTransition(async () => {
- const { error } = await approveVendors({
- ids: vendors.map((vendor) => vendor.id),
- userId: Number(session.user.id)
+ try {
+ console.log("πŸ” [DEBUG] 승인 μš”μ²­ μ‹œμž‘ - vendors:", vendors.map(v => ({ id: v.id, vendorName: v.vendorName, email: v.email })));
+ console.log("πŸ” [DEBUG] μ„Έμ…˜ 정보:", { userId: session.user.id, userType: typeof session.user.id });
+
+ const { error } = await approveVendors({
+ ids: vendors.map((vendor) => vendor.id),
+ userId: Number(session.user.id)
+ })
- })
+ if (error) {
+ console.error("🚨 [DEBUG] 승인 처리 μ—λŸ¬:", error);
+ toast.error(error)
+ return
+ }
- if (error) {
- toast.error(error)
- return
+ console.log("βœ… [DEBUG] 승인 처리 성곡");
+ props.onOpenChange?.(false)
+ toast.success("Vendors successfully approved for review")
+ onSuccess?.()
+ } catch (error) {
+ console.error("🚨 [DEBUG] μ˜ˆμƒμΉ˜ λͺ»ν•œ μ—λŸ¬:", error);
+ toast.error("μ˜ˆμƒμΉ˜ λͺ»ν•œ 였λ₯˜κ°€ λ°œμƒν–ˆμŠ΅λ‹ˆλ‹€.")
}
-
- props.onOpenChange?.(false)
- toast.success("Vendors successfully approved for review")
- onSuccess?.()
})
}
diff --git a/lib/vendors/table/request-pq-dialog.tsx b/lib/vendors/table/request-pq-dialog.tsx
index 20388f71..14a1cd01 100644
--- a/lib/vendors/table/request-pq-dialog.tsx
+++ b/lib/vendors/table/request-pq-dialog.tsx
@@ -37,6 +37,7 @@ import { Checkbox } from "@/components/ui/checkbox"
import { Label } from "@/components/ui/label"
import { Input } from "@/components/ui/input"
import { Badge } from "@/components/ui/badge"
+import { Progress } from "@/components/ui/progress"
import { Vendor } from "@/db/schema/vendors"
import { requestBasicContractInfo, requestPQVendors } from "../service"
import { getProjectsWithPQList } from "@/lib/pq/service"
@@ -98,6 +99,11 @@ export function RequestPQDialog({ vendors, showTrigger = true, onSuccess, ...pro
// λΉ„λ°€μœ μ§€ κ³„μ•½μ„œ μ²¨λΆ€νŒŒμΌ κ΄€λ ¨ μƒνƒœ
const [ndaAttachments, setNdaAttachments] = React.useState<File[]>([])
const [isUploadingNdaFiles, setIsUploadingNdaFiles] = React.useState(false)
+
+ // ν”„λ‘œκ·Έλ ˆμŠ€ κ΄€λ ¨ μƒνƒœ
+ const [progressValue, setProgressValue] = React.useState(0)
+ const [currentStep, setCurrentStep] = React.useState("")
+ const [showProgress, setShowProgress] = React.useState(false)
// μ•„μ΄ν…œ 검색 필터링
React.useEffect(() => {
@@ -180,6 +186,9 @@ export function RequestPQDialog({ vendors, showTrigger = true, onSuccess, ...pro
setShowItemDropdown(false)
setNdaAttachments([])
setIsUploadingNdaFiles(false)
+ setProgressValue(0)
+ setCurrentStep("")
+ setShowProgress(false)
}
}, [props.open])
@@ -235,9 +244,22 @@ export function RequestPQDialog({ vendors, showTrigger = true, onSuccess, ...pro
if (!dueDate) return toast.error("λ§ˆκ°μΌμ„ μ„ νƒν•˜μ„Έμš”.")
if (!session?.user?.id) return toast.error("인증 μ‹€νŒ¨")
+ // ν”„λ‘œκ·Έλ ˆμŠ€ λ°”λ₯Ό μ¦‰μ‹œ ν‘œμ‹œ
+ setShowProgress(true)
+ setProgressValue(0)
+ setCurrentStep("μ‹œμž‘ 쀑...")
+
startApproveTransition(async () => {
try {
+
+ // 전체 단계 수 계산
+ const totalSteps = 1 +
+ (selectedTemplateIds.length > 0 ? 1 : 0) +
+ (isNdaTemplateSelected() && ndaAttachments.length > 0 ? 1 : 0)
+ let completedSteps = 0
+
// 1단계: PQ 생성
+ setCurrentStep("PQ 생성 쀑...")
console.log("πŸš€ PQ 생성 μ‹œμž‘")
const { error: pqError } = await requestPQVendors({
ids: vendors.map((v) => v.id),
@@ -252,9 +274,13 @@ export function RequestPQDialog({ vendors, showTrigger = true, onSuccess, ...pro
})
if (pqError) {
+ setShowProgress(false)
toast.error(`PQ 생성 μ‹€νŒ¨: ${pqError}`)
return
}
+
+ completedSteps++
+ setProgressValue((completedSteps / totalSteps) * 100)
console.log("βœ… PQ 생성 μ™„λ£Œ")
toast.success("PQκ°€ μ„±κ³΅μ μœΌλ‘œ μš”μ²­λ˜μ—ˆμŠ΅λ‹ˆλ‹€")
@@ -264,12 +290,17 @@ export function RequestPQDialog({ vendors, showTrigger = true, onSuccess, ...pro
selectedTemplateIds.includes(t.id)
)
+ setCurrentStep(`κΈ°λ³Έκ³„μ•½μ„œ 생성 쀑... (${templates.length}개 ν…œν”Œλ¦Ώ)`)
console.log("πŸ“‹ κΈ°λ³Έκ³„μ•½μ„œ λ°±κ·ΈλΌμš΄λ“œ 처리 μ‹œμž‘", templates.length, "개 ν…œν”Œλ¦Ώ")
await processBasicContractsInBackground(templates, vendors)
+
+ completedSteps++
+ setProgressValue((completedSteps / totalSteps) * 100)
}
// 3단계: λΉ„λ°€μœ μ§€ κ³„μ•½μ„œ μ²¨λΆ€νŒŒμΌμ΄ μžˆλŠ” 경우 μ €μž₯
if (isNdaTemplateSelected() && ndaAttachments.length > 0) {
+ setCurrentStep(`λΉ„λ°€μœ μ§€ κ³„μ•½μ„œ μ²¨λΆ€νŒŒμΌ μ €μž₯ 쀑... (${ndaAttachments.length}개 파일)`)
console.log("πŸ“Ž λΉ„λ°€μœ μ§€ κ³„μ•½μ„œ μ²¨λΆ€νŒŒμΌ 처리 μ‹œμž‘", ndaAttachments.length, "개 파일")
const ndaResult = await saveNdaAttachments({
@@ -283,14 +314,24 @@ export function RequestPQDialog({ vendors, showTrigger = true, onSuccess, ...pro
} else {
toast.error(`μ²¨λΆ€νŒŒμΌ 처리 쀑 일뢀 였λ₯˜κ°€ λ°œμƒν–ˆμŠ΅λ‹ˆλ‹€: ${ndaResult.error}`)
}
+
+ completedSteps++
+ setProgressValue((completedSteps / totalSteps) * 100)
}
- // μ™„λ£Œ ν›„ λ‹€μ΄μ–Όλ‘œκ·Έ λ‹«κΈ°
- props.onOpenChange?.(false)
- onSuccess?.()
+ setCurrentStep("μ™„λ£Œ!")
+ setProgressValue(100)
+
+ // μž μ‹œ μ™„λ£Œ μƒνƒœλ₯Ό 보여쀀 ν›„ λ‹€μ΄μ–Όλ‘œκ·Έ λ‹«κΈ°
+ setTimeout(() => {
+ setShowProgress(false)
+ props.onOpenChange?.(false)
+ onSuccess?.()
+ }, 1000)
} catch (error) {
console.error('PQ 생성 였λ₯˜:', error)
+ setShowProgress(false)
toast.error(`처리 쀑 였λ₯˜κ°€ λ°œμƒν–ˆμŠ΅λ‹ˆλ‹€: ${error instanceof Error ? error.message : 'μ•Œ 수 μ—†λŠ” 였λ₯˜'}`)
}
})
@@ -328,6 +369,13 @@ export function RequestPQDialog({ vendors, showTrigger = true, onSuccess, ...pro
const template = templates[templateIndex]
processedCount++
+ // μ§„ν–‰λ₯  μ—…λ°μ΄νŠΈ (2단계 λ²”μœ„ λ‚΄μ—μ„œ)
+ const baseProgress = 33.33 // 1단계 μ™„λ£Œ ν›„
+ const contractProgress = (processedCount / totalContracts) * 33.33 // 2λ‹¨κ³„λŠ” 33.33% μ°¨μ§€
+ const newProgress = baseProgress + contractProgress
+ setProgressValue(newProgress)
+ setCurrentStep(`κΈ°λ³Έκ³„μ•½μ„œ 생성 쀑... (${processedCount}/${totalContracts})`)
+
console.log(`πŸ“„ 처리 쀑: ${vendor.vendorName} - ${template.templateName} (${processedCount}/${totalContracts})`)
// κ°œλ³„ 벀더에 λŒ€ν•œ 기본계약 생성
@@ -720,11 +768,31 @@ export function RequestPQDialog({ vendors, showTrigger = true, onSuccess, ...pro
<div className="flex-1 overflow-y-auto">
{dialogContent}
</div>
- <DialogFooter>
- <DialogClose asChild><Button variant="outline">μ·¨μ†Œ</Button></DialogClose>
- <Button onClick={onApprove} disabled={isApprovePending || !type || (type === "PROJECT" && !selectedProjectId)}>
- {isApprovePending && <Loader className="mr-2 size-4 animate-spin" />}μš”μ²­ν•˜κΈ°
- </Button>
+ <DialogFooter className="flex-col gap-4">
+ {/* ν”„λ‘œκ·Έλ ˆμŠ€ λ°” */}
+ {(showProgress || isApprovePending) && (
+ <div className="w-full space-y-2">
+ <div className="flex items-center justify-between text-sm">
+ <span className="text-muted-foreground">{currentStep || "처리 쀑..."}</span>
+ <span className="font-medium">{Math.round(progressValue)}%</span>
+ </div>
+ <Progress value={progressValue} className="w-full" />
+ </div>
+ )}
+
+ {/* λ²„νŠΌλ“€ */}
+ <div className="flex justify-end gap-2">
+ <DialogClose asChild>
+ <Button variant="outline" disabled={isApprovePending}>μ·¨μ†Œ</Button>
+ </DialogClose>
+ <Button
+ onClick={onApprove}
+ disabled={isApprovePending || !type || (type === "PROJECT" && !selectedProjectId)}
+ >
+ {isApprovePending && <Loader className="mr-2 size-4 animate-spin" />}
+ μš”μ²­ν•˜κΈ°
+ </Button>
+ </div>
</DialogFooter>
</DialogContent>
@@ -753,11 +821,32 @@ export function RequestPQDialog({ vendors, showTrigger = true, onSuccess, ...pro
<div className="flex-1 overflow-y-auto px-4">
{dialogContent}
</div>
- <DrawerFooter>
- <DrawerClose asChild><Button variant="outline">μ·¨μ†Œ</Button></DrawerClose>
- <Button onClick={onApprove} disabled={isApprovePending || !type || (type === "PROJECT" && !selectedProjectId)}>
- {isApprovePending && <Loader className="mr-2 size-4 animate-spin" />}μš”μ²­ν•˜κΈ°
- </Button>
+ <DrawerFooter className="gap-4">
+ {/* ν”„λ‘œκ·Έλ ˆμŠ€ λ°” */}
+ {(showProgress || isApprovePending) && (
+ <div className="w-full space-y-2">
+ <div className="flex items-center justify-between text-sm">
+ <span className="text-muted-foreground">{currentStep || "처리 쀑..."}</span>
+ <span className="font-medium">{Math.round(progressValue)}%</span>
+ </div>
+ <Progress value={progressValue} className="w-full" />
+ </div>
+ )}
+
+ {/* λ²„νŠΌλ“€ */}
+ <div className="flex gap-2">
+ <DrawerClose asChild>
+ <Button variant="outline" disabled={isApprovePending} className="flex-1">μ·¨μ†Œ</Button>
+ </DrawerClose>
+ <Button
+ onClick={onApprove}
+ disabled={isApprovePending || !type || (type === "PROJECT" && !selectedProjectId)}
+ className="flex-1"
+ >
+ {isApprovePending && <Loader className="mr-2 size-4 animate-spin" />}
+ μš”μ²­ν•˜κΈ°
+ </Button>
+ </div>
</DrawerFooter>
</DrawerContent>
diff --git a/lib/vendors/table/vendors-table-toolbar-actions.tsx b/lib/vendors/table/vendors-table-toolbar-actions.tsx
index 6d5f7425..3d77486d 100644
--- a/lib/vendors/table/vendors-table-toolbar-actions.tsx
+++ b/lib/vendors/table/vendors-table-toolbar-actions.tsx
@@ -83,7 +83,7 @@ export function VendorsTableToolbarActions({ table }: VendorsTableToolbarActions
.rows
.map(row => row.original)
.filter(vendor =>
- ["PENDING_REVIEW", "IN_REVIEW", "IN_PQ", "PQ_APPROVED", "APPROVED", "READY_TO_SEND", "ACTIVE"].includes(vendor.status)
+ ["IN_REVIEW", "IN_PQ", "PQ_APPROVED", "APPROVED", "READY_TO_SEND", "ACTIVE"].includes(vendor.status)
);
}, [table.getFilteredSelectedRowModel().rows]);