summaryrefslogtreecommitdiff
path: root/lib/bidding/vendor/partners-bidding-detail.tsx
diff options
context:
space:
mode:
authordujinkim <dujin.kim@dtsolution.co.kr>2025-09-02 10:30:58 +0000
committerdujinkim <dujin.kim@dtsolution.co.kr>2025-09-02 10:30:58 +0000
commit581b415e6707d9f1d0d0b667b84c4314461bfe37 (patch)
tree5476543a290ada5c3f29a0cba24ee86fc9c215b2 /lib/bidding/vendor/partners-bidding-detail.tsx
parentd5ddafa4276b0031538261400e431009b0734be9 (diff)
(최겸) 입찰 등록, 협력업체 응찰 기능 개발
Diffstat (limited to 'lib/bidding/vendor/partners-bidding-detail.tsx')
-rw-r--r--lib/bidding/vendor/partners-bidding-detail.tsx176
1 files changed, 73 insertions, 103 deletions
diff --git a/lib/bidding/vendor/partners-bidding-detail.tsx b/lib/bidding/vendor/partners-bidding-detail.tsx
index 4c4db37f..c6ba4926 100644
--- a/lib/bidding/vendor/partners-bidding-detail.tsx
+++ b/lib/bidding/vendor/partners-bidding-detail.tsx
@@ -29,7 +29,6 @@ import {
submitPartnerResponse,
updatePartnerAttendance
} from '../detail/service'
-import { PartnersBiddingAttendanceDialog } from './partners-bidding-attendance-dialog'
import {
biddingStatusLabels,
contractTypeLabels,
@@ -75,20 +74,15 @@ interface BiddingDetail {
finalQuoteSubmittedAt: string
isWinner: boolean
isAttendingMeeting: boolean | null
- offeredPaymentTerms: string
- offeredTaxConditions: string
- offeredIncoterms: string
- offeredContractDeliveryDate: string
- offeredShippingPort: string
- offeredDestinationPort: string
- isPriceAdjustmentApplicable: boolean
- responsePaymentTerms: string
- responseTaxConditions: string
- responseIncoterms: string
+ // companyConditionResponses에서 가져온 조건들 (제시된 조건과 응답 모두)
+ paymentTermsResponse: string
+ taxConditionsResponse: string
+ incotermsResponse: string
proposedContractDeliveryDate: string
proposedShippingPort: string
proposedDestinationPort: string
priceAdjustmentResponse: boolean
+ sparePartResponse: string
additionalProposals: string
responseSubmittedAt: string
}
@@ -110,13 +104,11 @@ export function PartnersBiddingDetail({ biddingId, companyId }: PartnersBiddingD
proposedShippingPort: '',
proposedDestinationPort: '',
priceAdjustmentResponse: false,
+ sparePartResponse: '',
additionalProposals: '',
isAttendingMeeting: false,
})
- // 사양설명회 참석 여부 다이얼로그 상태
- const [isAttendanceDialogOpen, setIsAttendanceDialogOpen] = React.useState(false)
-
// 데이터 로드
React.useEffect(() => {
const loadData = async () => {
@@ -129,15 +121,16 @@ export function PartnersBiddingDetail({ biddingId, companyId }: PartnersBiddingD
// 기존 응답 데이터로 폼 초기화
setResponseData({
finalQuoteAmount: result.finalQuoteAmount?.toString() || '',
- paymentTermsResponse: result.responsePaymentTerms || '',
- taxConditionsResponse: result.responseTaxConditions || '',
- incotermsResponse: result.responseIncoterms || '',
+ paymentTermsResponse: result.paymentTermsResponse || '',
+ taxConditionsResponse: result.taxConditionsResponse || '',
+ incotermsResponse: result.incotermsResponse || '',
proposedContractDeliveryDate: result.proposedContractDeliveryDate || '',
proposedShippingPort: result.proposedShippingPort || '',
proposedDestinationPort: result.proposedDestinationPort || '',
priceAdjustmentResponse: result.priceAdjustmentResponse || false,
+ sparePartResponse: result.sparePartResponse || '',
additionalProposals: result.additionalProposals || '',
- isAttendingMeeting: false, // TODO: biddingCompanies에서 가져와야 함
+ isAttendingMeeting: result.isAttendingMeeting || false,
})
}
} catch (error) {
@@ -180,6 +173,7 @@ export function PartnersBiddingDetail({ biddingId, companyId }: PartnersBiddingD
proposedShippingPort: responseData.proposedShippingPort,
proposedDestinationPort: responseData.proposedDestinationPort,
priceAdjustmentResponse: responseData.priceAdjustmentResponse,
+ sparePartResponse: responseData.sparePartResponse,
additionalProposals: responseData.additionalProposals,
},
'current-user' // TODO: 실제 사용자 ID
@@ -191,15 +185,6 @@ export function PartnersBiddingDetail({ biddingId, companyId }: PartnersBiddingD
description: result.message,
})
- // 사양설명회 참석 여부도 업데이트
- if (responseData.isAttendingMeeting !== undefined) {
- await updatePartnerAttendance(
- biddingDetail.biddingCompanyId,
- responseData.isAttendingMeeting,
- 'current-user'
- )
- }
-
// 데이터 새로고침
const updatedDetail = await getBiddingDetailsForPartners(biddingId, companyId)
if (updatedDetail) {
@@ -272,26 +257,6 @@ export function PartnersBiddingDetail({ biddingId, companyId }: PartnersBiddingD
</div>
</div>
- {/* 사양설명회 참석 여부 버튼 */}
- <div className="flex items-center gap-2">
- <Button
- variant="outline"
- onClick={() => setIsAttendanceDialogOpen(true)}
- className="flex items-center gap-2"
- >
- <Users className="w-4 h-4" />
- 사양설명회 참석
- {biddingDetail.isAttendingMeeting !== null && (
- <div className="ml-1">
- {biddingDetail.isAttendingMeeting ? (
- <CheckCircle className="w-4 h-4 text-green-600" />
- ) : (
- <XCircle className="w-4 h-4 text-red-600" />
- )}
- </div>
- )}
- </Button>
- </div>
</div>
{/* 입찰 공고 섹션 */}
@@ -368,48 +333,68 @@ export function PartnersBiddingDetail({ biddingId, companyId }: PartnersBiddingD
</CardContent>
</Card>
- {/* 제시된 조건 섹션 */}
+ {/* 현재 설정된 조건 섹션 */}
<Card>
<CardHeader>
- <CardTitle>제시된 입찰 조건</CardTitle>
+ <CardTitle>현재 설정된 입찰 조건</CardTitle>
</CardHeader>
<CardContent>
- <div className="space-y-4">
+ <div className="grid grid-cols-2 gap-4">
<div>
<Label className="text-sm font-medium">지급조건</Label>
<div className="mt-1 p-3 bg-muted rounded-md">
- {biddingDetail.offeredPaymentTerms ?
- JSON.parse(biddingDetail.offeredPaymentTerms).join(', ') :
- '정보 없음'}
+ {biddingDetail.paymentTermsResponse}
</div>
</div>
<div>
<Label className="text-sm font-medium">세금조건</Label>
<div className="mt-1 p-3 bg-muted rounded-md">
- {biddingDetail.offeredTaxConditions ?
- JSON.parse(biddingDetail.offeredTaxConditions).join(', ') :
- '정보 없음'}
+ {biddingDetail.taxConditionsResponse}
</div>
</div>
<div>
<Label className="text-sm font-medium">운송조건</Label>
<div className="mt-1 p-3 bg-muted rounded-md">
- {biddingDetail.offeredIncoterms ?
- JSON.parse(biddingDetail.offeredIncoterms).join(', ') :
- '정보 없음'}
+ {biddingDetail.incotermsResponse}
</div>
</div>
- {biddingDetail.offeredContractDeliveryDate && (
- <div>
- <Label className="text-sm font-medium">계약납기일</Label>
- <div className="mt-1 p-3 bg-muted rounded-md">
- {formatDate(biddingDetail.offeredContractDeliveryDate, 'KR')}
- </div>
+ <div>
+ <Label className="text-sm font-medium">제안 계약납기일</Label>
+ <div className="mt-1 p-3 bg-muted rounded-md">
+ {biddingDetail.proposedContractDeliveryDate ? formatDate(biddingDetail.proposedContractDeliveryDate, 'KR') : '미설정'}
+ </div>
+ </div>
+
+ <div>
+ <Label className="text-sm font-medium">제안 선적지</Label>
+ <div className="mt-1 p-3 bg-muted rounded-md">
+ {biddingDetail.proposedShippingPort}
+ </div>
+ </div>
+
+ <div>
+ <Label className="text-sm font-medium">제안 도착지</Label>
+ <div className="mt-1 p-3 bg-muted rounded-md">
+ {biddingDetail.proposedDestinationPort}
+ </div>
+ </div>
+
+ <div>
+ <Label className="text-sm font-medium">스페어파트 응답</Label>
+ <div className="mt-1 p-3 bg-muted rounded-md">
+ {biddingDetail.sparePartResponse}
+ </div>
+ </div>
+
+ <div>
+ <Label className="text-sm font-medium">연동제 적용</Label>
+ <div className="mt-1 p-3 bg-muted rounded-md">
+ {biddingDetail.priceAdjustmentResponse ? '적용' : '미적용'}
</div>
- )}
+ </div>
</div>
</CardContent>
</Card>
@@ -490,6 +475,28 @@ export function PartnersBiddingDetail({ biddingId, companyId }: PartnersBiddingD
</div>
</div>
+ <div className="grid grid-cols-1 md:grid-cols-2 gap-6">
+ <div className="space-y-2">
+ <Label htmlFor="proposedDestinationPort">제안 도착지</Label>
+ <Input
+ id="proposedDestinationPort"
+ value={responseData.proposedDestinationPort}
+ onChange={(e) => setResponseData({...responseData, proposedDestinationPort: e.target.value})}
+ placeholder="도착지를 입력하세요"
+ />
+ </div>
+
+ <div className="space-y-2">
+ <Label htmlFor="sparePartResponse">스페어파트 응답</Label>
+ <Input
+ id="sparePartResponse"
+ value={responseData.sparePartResponse}
+ onChange={(e) => setResponseData({...responseData, sparePartResponse: e.target.value})}
+ placeholder="스페어파트 관련 응답을 입력하세요"
+ />
+ </div>
+ </div>
+
<div className="space-y-2">
<Label htmlFor="additionalProposals">추가 제안사항</Label>
<Textarea
@@ -512,17 +519,6 @@ export function PartnersBiddingDetail({ biddingId, companyId }: PartnersBiddingD
<Label htmlFor="priceAdjustmentResponse">연동제 적용에 동의합니다</Label>
</div>
- <div className="flex items-center space-x-2">
- <Checkbox
- id="isAttendingMeeting"
- checked={responseData.isAttendingMeeting}
- onCheckedChange={(checked) =>
- setResponseData({...responseData, isAttendingMeeting: !!checked})
- }
- />
- <Label htmlFor="isAttendingMeeting">사양설명회에 참석합니다</Label>
- </div>
-
<div className="flex justify-end pt-4">
<Button onClick={handleSubmitResponse} disabled={isPending}>
<Send className="w-4 h-4 mr-2" />
@@ -531,32 +527,6 @@ export function PartnersBiddingDetail({ biddingId, companyId }: PartnersBiddingD
</div>
</CardContent>
</Card>
-
- {/* 사양설명회 참석 여부 다이얼로그 */}
- <PartnersBiddingAttendanceDialog
- biddingDetail={{
- id: biddingDetail.id,
- biddingNumber: biddingDetail.biddingNumber,
- title: biddingDetail.title,
- preQuoteDate: biddingDetail.preQuoteDate,
- biddingRegistrationDate: biddingDetail.biddingRegistrationDate,
- evaluationDate: biddingDetail.evaluationDate,
- }}
- biddingCompanyId={biddingDetail.biddingCompanyId}
- isAttending={biddingDetail.isAttendingMeeting}
- open={isAttendanceDialogOpen}
- onOpenChange={setIsAttendanceDialogOpen}
- onSuccess={() => {
- // 데이터 새로고침
- const refreshData = async () => {
- const updatedDetail = await getBiddingDetailsForPartners(biddingId, companyId)
- if (updatedDetail) {
- setBiddingDetail(updatedDetail)
- }
- }
- refreshData()
- }}
- />
</div>
)
}