summaryrefslogtreecommitdiff
path: root/lib/bidding/vendor/partners-bidding-pre-quote.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'lib/bidding/vendor/partners-bidding-pre-quote.tsx')
-rw-r--r--lib/bidding/vendor/partners-bidding-pre-quote.tsx178
1 files changed, 149 insertions, 29 deletions
diff --git a/lib/bidding/vendor/partners-bidding-pre-quote.tsx b/lib/bidding/vendor/partners-bidding-pre-quote.tsx
index 4ec65413..6a76ffa1 100644
--- a/lib/bidding/vendor/partners-bidding-pre-quote.tsx
+++ b/lib/bidding/vendor/partners-bidding-pre-quote.tsx
@@ -10,12 +10,18 @@ import { Label } from '@/components/ui/label'
import { Textarea } from '@/components/ui/textarea'
import { Checkbox } from '@/components/ui/checkbox'
import {
+ Select,
+ SelectContent,
+ SelectItem,
+ SelectTrigger,
+ SelectValue,
+} from '@/components/ui/select'
+import {
ArrowLeft,
Calendar,
Building2,
Package,
User,
- DollarSign,
FileText,
Users,
Send,
@@ -35,12 +41,11 @@ import {
} from '../pre-quote/service'
import { getBiddingConditions } from '../service'
import { getPriceAdjustmentFormByBiddingCompanyId } from '../detail/service'
+import { getIncotermsForSelection, getPaymentTermsForSelection, getPlaceOfShippingForSelection, getPlaceOfDestinationForSelection } from '@/lib/procurement-select/service'
import { PrItemsPricingTable } from './components/pr-items-pricing-table'
import { SimpleFileUpload } from './components/simple-file-upload'
import {
biddingStatusLabels,
- contractTypeLabels,
- biddingTypeLabels
} from '@/db/schema'
import { useToast } from '@/hooks/use-toast'
import { useTransition } from 'react'
@@ -63,7 +68,8 @@ interface BiddingDetail {
contractType: string
biddingType: string
awardCount: string
- contractPeriod: string | null
+ contractStartDate: Date | null
+ contractEndDate: Date | null
preQuoteDate: string | null
biddingRegistrationDate: string | null
submissionStartDate: string | null
@@ -105,6 +111,12 @@ export function PartnersBiddingPreQuote({ biddingId, companyId }: PartnersBiddin
const [biddingDetail, setBiddingDetail] = React.useState<BiddingDetail | null>(null)
const [isLoading, setIsLoading] = React.useState(true)
const [biddingConditions, setBiddingConditions] = React.useState<any | null>(null)
+
+ // Procurement 데이터 상태들
+ const [paymentTermsOptions, setPaymentTermsOptions] = React.useState<Array<{code: string, description: string}>>([])
+ const [incotermsOptions, setIncotermsOptions] = React.useState<Array<{code: string, description: string}>>([])
+ const [shippingPlaces, setShippingPlaces] = React.useState<Array<{code: string, description: string}>>([])
+ const [destinationPlaces, setDestinationPlaces] = React.useState<Array<{code: string, description: string}>>([])
// 품목별 견적 관련 상태
const [prItems, setPrItems] = React.useState<any[]>([])
@@ -151,6 +163,43 @@ export function PartnersBiddingPreQuote({ biddingId, companyId }: PartnersBiddin
})
const userId = session.data?.user?.id || ''
+ // Procurement 데이터 로드 함수들
+ const loadPaymentTerms = React.useCallback(async () => {
+ try {
+ const data = await getPaymentTermsForSelection();
+ setPaymentTermsOptions(data);
+ } catch (error) {
+ console.error("Failed to load payment terms:", error);
+ }
+ }, []);
+
+ const loadIncoterms = React.useCallback(async () => {
+ try {
+ const data = await getIncotermsForSelection();
+ setIncotermsOptions(data);
+ } catch (error) {
+ console.error("Failed to load incoterms:", error);
+ }
+ }, []);
+
+ const loadShippingPlaces = React.useCallback(async () => {
+ try {
+ const data = await getPlaceOfShippingForSelection();
+ setShippingPlaces(data);
+ } catch (error) {
+ console.error("Failed to load shipping places:", error);
+ }
+ }, []);
+
+ const loadDestinationPlaces = React.useCallback(async () => {
+ try {
+ const data = await getPlaceOfDestinationForSelection();
+ setDestinationPlaces(data);
+ } catch (error) {
+ console.error("Failed to load destination places:", error);
+ }
+ }, []);
+
// 데이터 로드
React.useEffect(() => {
const loadData = async () => {
@@ -229,6 +278,14 @@ export function PartnersBiddingPreQuote({ biddingId, companyId }: PartnersBiddin
if (prItemsData) {
setPrItems(prItemsData)
}
+
+ // Procurement 데이터 로드
+ await Promise.all([
+ loadPaymentTerms(),
+ loadIncoterms(),
+ loadShippingPlaces(),
+ loadDestinationPlaces()
+ ])
} catch (error) {
console.error('Failed to load bidding company:', error)
toast({
@@ -242,7 +299,7 @@ export function PartnersBiddingPreQuote({ biddingId, companyId }: PartnersBiddin
}
loadData()
- }, [biddingId, companyId, toast])
+ }, [biddingId, companyId, toast, loadPaymentTerms, loadIncoterms, loadShippingPlaces, loadDestinationPlaces])
// 임시저장 기능
const handleTempSave = () => {
@@ -428,7 +485,7 @@ export function PartnersBiddingPreQuote({ biddingId, companyId }: PartnersBiddin
{ value: responseData.taxConditionsResponse, name: '응답 세금조건' },
{ value: responseData.incotermsResponse, name: '응답 운송조건' },
{ value: responseData.proposedShippingPort, name: '제안 선적지' },
- { value: responseData.proposedDestinationPort, name: '제안 도착지' },
+ { value: responseData.proposedDestinationPort, name: '제안 하역지' },
{ value: responseData.sparePartResponse, name: '스페어파트 응답' },
]
@@ -775,7 +832,7 @@ export function PartnersBiddingPreQuote({ biddingId, companyId }: PartnersBiddin
</div>
<div>
- <Label className="text-muted-foreground">도착지</Label>
+ <Label className="text-muted-foreground">하역지</Label>
<div className="mt-1 p-3 bg-muted rounded-md">
<p className="font-medium">{biddingConditions.destinationPort || "미설정"}</p>
</div>
@@ -849,12 +906,13 @@ export function PartnersBiddingPreQuote({ biddingId, companyId }: PartnersBiddin
</span>
</div>
{participationDecision === false && (
+ <>
<div className="p-4 bg-muted rounded-lg">
<p className="text-muted-foreground">
미참여로 설정되어 견적 작성 섹션이 숨겨집니다. 참여하시려면 아래 버튼을 클릭해주세요.
</p>
</div>
- )}
+
<Button
variant="outline"
size="sm"
@@ -863,6 +921,8 @@ export function PartnersBiddingPreQuote({ biddingId, companyId }: PartnersBiddin
>
결정 변경하기
</Button>
+ </>
+ )}
</div>
)}
</CardContent>
@@ -961,12 +1021,27 @@ export function PartnersBiddingPreQuote({ biddingId, companyId }: PartnersBiddin
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
<div className="space-y-2">
<Label htmlFor="paymentTermsResponse">응답 지급조건 <span className="text-red-500">*</span></Label>
- <Input
- id="paymentTermsResponse"
+ <Select
value={responseData.paymentTermsResponse}
- onChange={(e) => setResponseData({...responseData, paymentTermsResponse: e.target.value})}
- placeholder={biddingConditions?.paymentTerms ? `참고: ${biddingConditions.paymentTerms}` : "지급조건에 대한 의견을 입력하세요"}
- />
+ onValueChange={(value) => setResponseData({...responseData, paymentTermsResponse: value})}
+ >
+ <SelectTrigger>
+ <SelectValue placeholder={biddingConditions?.paymentTerms ? `참고: ${biddingConditions.paymentTerms}` : "지급조건 선택"} />
+ </SelectTrigger>
+ <SelectContent>
+ {paymentTermsOptions.length > 0 ? (
+ paymentTermsOptions.map((option) => (
+ <SelectItem key={option.code} value={option.code}>
+ {option.code} {option.description && `(${option.description})`}
+ </SelectItem>
+ ))
+ ) : (
+ <SelectItem value="loading" disabled>
+ 데이터를 불러오는 중...
+ </SelectItem>
+ )}
+ </SelectContent>
+ </Select>
</div>
<div className="space-y-2">
@@ -983,34 +1058,79 @@ export function PartnersBiddingPreQuote({ biddingId, companyId }: PartnersBiddin
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
<div className="space-y-2">
<Label htmlFor="incotermsResponse">응답 운송조건 <span className="text-red-500">*</span></Label>
- <Input
- id="incotermsResponse"
+ <Select
value={responseData.incotermsResponse}
- onChange={(e) => setResponseData({...responseData, incotermsResponse: e.target.value})}
- placeholder={biddingConditions?.incoterms ? `참고: ${biddingConditions.incoterms}` : "운송조건에 대한 의견을 입력하세요"}
- />
+ onValueChange={(value) => setResponseData({...responseData, incotermsResponse: value})}
+ >
+ <SelectTrigger>
+ <SelectValue placeholder={biddingConditions?.incoterms ? `참고: ${biddingConditions.incoterms}` : "운송조건 선택"} />
+ </SelectTrigger>
+ <SelectContent>
+ {incotermsOptions.length > 0 ? (
+ incotermsOptions.map((option) => (
+ <SelectItem key={option.code} value={option.code}>
+ {option.code} {option.description && `(${option.description})`}
+ </SelectItem>
+ ))
+ ) : (
+ <SelectItem value="loading" disabled>
+ 데이터를 불러오는 중...
+ </SelectItem>
+ )}
+ </SelectContent>
+ </Select>
</div>
<div className="space-y-2">
<Label htmlFor="proposedShippingPort">제안 선적지 <span className="text-red-500">*</span></Label>
- <Input
- id="proposedShippingPort"
+ <Select
value={responseData.proposedShippingPort}
- onChange={(e) => setResponseData({...responseData, proposedShippingPort: e.target.value})}
- placeholder={biddingConditions?.shippingPort ? `참고: ${biddingConditions.shippingPort}` : "선적지를 입력하세요"}
- />
+ onValueChange={(value) => setResponseData({...responseData, proposedShippingPort: value})}
+ >
+ <SelectTrigger>
+ <SelectValue placeholder={biddingConditions?.shippingPort ? `참고: ${biddingConditions.shippingPort}` : "선적지 선택"} />
+ </SelectTrigger>
+ <SelectContent>
+ {shippingPlaces.length > 0 ? (
+ shippingPlaces.map((place) => (
+ <SelectItem key={place.code} value={place.code}>
+ {place.code} {place.description && `(${place.description})`}
+ </SelectItem>
+ ))
+ ) : (
+ <SelectItem value="loading" disabled>
+ 데이터를 불러오는 중...
+ </SelectItem>
+ )}
+ </SelectContent>
+ </Select>
</div>
</div>
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
<div className="space-y-2">
- <Label htmlFor="proposedDestinationPort">제안 도착지 <span className="text-red-500">*</span></Label>
- <Input
- id="proposedDestinationPort"
+ <Label htmlFor="proposedDestinationPort">제안 하역지 <span className="text-red-500">*</span></Label>
+ <Select
value={responseData.proposedDestinationPort}
- onChange={(e) => setResponseData({...responseData, proposedDestinationPort: e.target.value})}
- placeholder={biddingConditions?.destinationPort ? `참고: ${biddingConditions.destinationPort}` : "도착지를 입력하세요"}
- />
+ onValueChange={(value) => setResponseData({...responseData, proposedDestinationPort: value})}
+ >
+ <SelectTrigger>
+ <SelectValue placeholder={biddingConditions?.destinationPort ? `참고: ${biddingConditions.destinationPort}` : "하역지 선택"} />
+ </SelectTrigger>
+ <SelectContent>
+ {destinationPlaces.length > 0 ? (
+ destinationPlaces.map((place) => (
+ <SelectItem key={place.code} value={place.code}>
+ {place.code} {place.description && `(${place.description})`}
+ </SelectItem>
+ ))
+ ) : (
+ <SelectItem value="loading" disabled>
+ 데이터를 불러오는 중...
+ </SelectItem>
+ )}
+ </SelectContent>
+ </Select>
</div>
<div className="space-y-2">