summaryrefslogtreecommitdiff
path: root/lib/bidding/detail/table/bidding-award-dialog.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'lib/bidding/detail/table/bidding-award-dialog.tsx')
-rw-r--r--lib/bidding/detail/table/bidding-award-dialog.tsx136
1 files changed, 96 insertions, 40 deletions
diff --git a/lib/bidding/detail/table/bidding-award-dialog.tsx b/lib/bidding/detail/table/bidding-award-dialog.tsx
index b168e884..613e2fc8 100644
--- a/lib/bidding/detail/table/bidding-award-dialog.tsx
+++ b/lib/bidding/detail/table/bidding-award-dialog.tsx
@@ -27,14 +27,27 @@ import {
import { Trophy, Building2, Calculator } from 'lucide-react'
import { useToast } from '@/hooks/use-toast'
import { getAwardedCompanies } from '@/lib/bidding/detail/service'
-import { requestBiddingAwardWithApproval } from '@/lib/bidding/approval-actions'
+import { requestBiddingAwardWithApproval, prepareBiddingAwardApprovalData } from '@/lib/bidding/approval-actions'
import { AwardSimpleFileUpload } from './components/award-simple-file-upload'
+import { ApprovalPreviewDialog } from '@/lib/approval/approval-preview-dialog'
interface BiddingAwardDialogProps {
biddingId: number
open: boolean
onOpenChange: (open: boolean) => void
onSuccess: () => void
+ onApprovalPreview?: (data: {
+ templateName: string
+ variables: Record<string, string>
+ title: string
+ selectionReason: string
+ awardedCompanies: {
+ companyId: number
+ companyName: string | null
+ finalQuoteAmount: number
+ awardRatio: number
+ }[]
+ }) => void
}
interface AwardedCompany {
@@ -48,7 +61,8 @@ export function BiddingAwardDialog({
biddingId,
open,
onOpenChange,
- onSuccess
+ onSuccess,
+ onApprovalPreview
}: BiddingAwardDialogProps) {
const { toast } = useToast()
const { data: session } = useSession()
@@ -56,7 +70,10 @@ export function BiddingAwardDialog({
const [selectionReason, setSelectionReason] = React.useState('')
const [awardedCompanies, setAwardedCompanies] = React.useState<AwardedCompany[]>([])
const [isLoading, setIsLoading] = React.useState(false)
-const userId = session?.user?.id || '2';
+ const [isApprovalDialogOpen, setIsApprovalDialogOpen] = React.useState(false)
+ const [approvalVariables, setApprovalVariables] = React.useState<Record<string, string>>({})
+ const [approvalTitle, setApprovalTitle] = React.useState('')
+ const userId = session?.user?.id || '2';
// 낙찰된 업체 정보 로드
React.useEffect(() => {
if (open) {
@@ -86,9 +103,8 @@ const userId = session?.user?.id || '2';
}, 0)
}, [awardedCompanies])
- const handleSubmit = (e: React.FormEvent) => {
- e.preventDefault()
-
+ // 다음단계 버튼 핸들러 - 결재 준비 및 부모로 데이터 전달
+ const handleNextStep = async () => {
if (!selectionReason.trim()) {
toast({
title: '유효성 오류',
@@ -107,45 +123,83 @@ const userId = session?.user?.id || '2';
return
}
- // 서버 액션을 사용하여 결재 상신
- startTransition(async () => {
- try {
- const result = await requestBiddingAwardWithApproval({
- biddingId,
+ try {
+ // 결재 데이터 준비 (템플릿 변수, 제목 등)
+ const approvalData = await prepareBiddingAwardApprovalData({
+ biddingId,
+ selectionReason: selectionReason.trim(),
+ awardedCompanies,
+ })
+
+ // 결재 준비 완료 - 부모 컴포넌트의 결재 미리보기 콜백 호출
+ if (onApprovalPreview) {
+ onApprovalPreview({
+ templateName: '입찰 결과 업체 선정 품의 요청서',
+ variables: approvalData.variables,
+ title: `낙찰 - ${approvalData.bidding.title}`,
selectionReason: selectionReason.trim(),
- currentUser: {
- id: Number(userId),
- epId: session?.user?.epId || null,
- email: session?.user?.email || undefined,
- },
+ awardedCompanies,
})
+ } else {
+ // 기존 로직 유지 (내부 결재 다이얼로그 사용)
+ setApprovalVariables(approvalData.variables)
+ setApprovalTitle(`낙찰 - ${approvalData.bidding.title}`)
+ setIsApprovalDialogOpen(true)
+ }
+ } catch (error) {
+ console.error('결재 준비 중 오류 발생:', error)
+ toast({
+ title: '오류',
+ description: '결재 준비 중 오류가 발생했습니다.',
+ variant: 'destructive',
+ })
+ }
+ }
- if (result.status === 'pending_approval') {
- toast({
- title: '성공',
- description: '낙찰 결재가 상신되었습니다.',
- })
- onOpenChange(false)
- setSelectionReason('')
- onSuccess()
- } else {
- toast({
- title: '오류',
- description: '결재 상신에 실패했습니다.',
- variant: 'destructive',
- })
- }
- } catch (error) {
- console.error('낙찰 결재 상신 실패:', error)
+ // 결재 상신 핸들러 - 결재 완료 시 실제 낙찰 등록 실행
+ const handleApprovalSubmit = async ({ approvers, title, attachments }: { approvers: string[], title: string, attachments?: File[] }) => {
+ try {
+ if (!session?.user?.id || !session.user.epId) {
toast({
title: '오류',
- description: error instanceof Error ? error.message : '결재 상신 중 오류가 발생했습니다.',
+ description: '필요한 정보가 없습니다.',
variant: 'destructive',
})
+ return
}
- })
- }
+ // 결재 상신
+ const result = await requestBiddingAwardWithApproval({
+ biddingId,
+ selectionReason: selectionReason.trim(),
+ awardedCompanies, // ✅ 결재 상신 시점의 낙찰 대상 정보 전달
+ currentUser: {
+ id: Number(session.user.id),
+ epId: session.user.epId,
+ email: session.user.email || undefined,
+ },
+ approvers,
+ })
+
+ if (result.status === 'pending_approval') {
+ toast({
+ title: '낙찰 결재 상신 완료',
+ description: `결재가 상신되었습니다. (ID: ${result.approvalId})`,
+ })
+ setIsApprovalDialogOpen(false)
+ onOpenChange(false)
+ setSelectionReason('')
+ onSuccess()
+ }
+ } catch (error) {
+ console.error('결재 상신 중 오류 발생:', error)
+ toast({
+ title: '오류',
+ description: '결재 상신 중 오류가 발생했습니다.',
+ variant: 'destructive',
+ })
+ }
+ }
return (
<Dialog open={open} onOpenChange={onOpenChange}>
@@ -160,7 +214,7 @@ const userId = session?.user?.id || '2';
</DialogDescription>
</DialogHeader>
- <form onSubmit={handleSubmit}>
+ <div>
<div className="space-y-6">
{/* 낙찰 업체 정보 */}
<Card>
@@ -266,14 +320,16 @@ const userId = session?.user?.id || '2';
취소
</Button>
<Button
- type="submit"
+ type="button"
+ onClick={handleNextStep}
disabled={isPending || awardedCompanies.length === 0}
>
- {isPending ? '상신 중...' : '결재 상신'}
+ 다음단계
</Button>
</DialogFooter>
- </form>
+ </div>
</DialogContent>
</Dialog>
+
)
}