summaryrefslogtreecommitdiff
path: root/lib/bidding/list
diff options
context:
space:
mode:
Diffstat (limited to 'lib/bidding/list')
-rw-r--r--lib/bidding/list/biddings-table-toolbar-actions.tsx9
-rw-r--r--lib/bidding/list/biddings-table.tsx25
-rw-r--r--lib/bidding/list/create-bidding-dialog.tsx78
3 files changed, 89 insertions, 23 deletions
diff --git a/lib/bidding/list/biddings-table-toolbar-actions.tsx b/lib/bidding/list/biddings-table-toolbar-actions.tsx
index 70b48a36..2b7a9d7d 100644
--- a/lib/bidding/list/biddings-table-toolbar-actions.tsx
+++ b/lib/bidding/list/biddings-table-toolbar-actions.tsx
@@ -22,9 +22,11 @@ import { CreateBiddingDialog } from "./create-bidding-dialog"
interface BiddingsTableToolbarActionsProps {
table: Table<BiddingListItem>
+ paymentTermsOptions: Array<{code: string, description: string}>
+ incotermsOptions: Array<{code: string, description: string}>
}
-export function BiddingsTableToolbarActions({ table }: BiddingsTableToolbarActionsProps) {
+export function BiddingsTableToolbarActions({ table, paymentTermsOptions, incotermsOptions }: BiddingsTableToolbarActionsProps) {
const router = useRouter()
const [isExporting, setIsExporting] = React.useState(false)
@@ -54,7 +56,10 @@ export function BiddingsTableToolbarActions({ table }: BiddingsTableToolbarActio
return (
<div className="flex items-center gap-2">
{/* 신규 생성 */}
- <CreateBiddingDialog/>
+ <CreateBiddingDialog
+ paymentTermsOptions={paymentTermsOptions}
+ incotermsOptions={incotermsOptions}
+ />
{/* 개찰 (입찰 오픈) */}
{/* {openEligibleBiddings.length > 0 && (
diff --git a/lib/bidding/list/biddings-table.tsx b/lib/bidding/list/biddings-table.tsx
index 3b60c69b..2a8f98c3 100644
--- a/lib/bidding/list/biddings-table.tsx
+++ b/lib/bidding/list/biddings-table.tsx
@@ -12,7 +12,7 @@ import { useDataTable } from "@/hooks/use-data-table"
import { DataTable } from "@/components/data-table/data-table"
import { DataTableAdvancedToolbar } from "@/components/data-table/data-table-advanced-toolbar"
import { getBiddingsColumns } from "./biddings-table-columns"
-import { getBiddings, getBiddingStatusCounts } from "@/lib/bidding/service"
+import { getBiddings, getBiddingStatusCounts, getActivePaymentTerms, getActiveIncoterms, getBiddingTypeCounts, getBiddingManagerCounts, getBiddingMonthlyStats } from "@/lib/bidding/service"
import { BiddingListItem } from "@/db/schema"
import { BiddingsTableToolbarActions } from "./biddings-table-toolbar-actions"
import {
@@ -28,13 +28,26 @@ interface BiddingsTableProps {
promises: Promise<
[
Awaited<ReturnType<typeof getBiddings>>,
- Awaited<ReturnType<typeof getBiddingStatusCounts>>
+ Awaited<ReturnType<typeof getBiddingStatusCounts>>,
+ Awaited<ReturnType<typeof getBiddingTypeCounts>>, // 추가
+ Awaited<ReturnType<typeof getBiddingManagerCounts>>, // 추가
+ Awaited<ReturnType<typeof getBiddingMonthlyStats>>, // 추가
+ Awaited<ReturnType<typeof getActivePaymentTerms>>,
+ Awaited<ReturnType<typeof getActiveIncoterms>>
]
>
}
export function BiddingsTable({ promises }: BiddingsTableProps) {
- const [{ data, pageCount }, statusCounts] = React.use(promises)
+ const [biddingsResult, statusCounts, typeCounts, managerCounts, monthlyStats, paymentTermsResult, incotermsResult] = React.use(promises)
+
+ // biddingsResult에서 data와 pageCount 추출
+ const { data, pageCount } = biddingsResult
+
+ const paymentTermsOptions = paymentTermsResult.success && 'data' in paymentTermsResult ? paymentTermsResult.data || [] : []
+ const incotermsOptions = incotermsResult.success && 'data' in incotermsResult ? incotermsResult.data || [] : []
+ console.log(paymentTermsOptions,"paymentTermsOptions")
+ console.log(incotermsOptions,"incotermsOptions")
const [isCompact, setIsCompact] = React.useState<boolean>(false)
const [specMeetingDialogOpen, setSpecMeetingDialogOpen] = React.useState(false)
const [prDocumentsDialogOpen, setPrDocumentsDialogOpen] = React.useState(false)
@@ -164,7 +177,11 @@ export function BiddingsTable({ promises }: BiddingsTableProps) {
compactStorageKey="biddingsTableCompact"
onCompactChange={handleCompactChange}
>
- <BiddingsTableToolbarActions table={table} />
+ <BiddingsTableToolbarActions
+ table={table}
+ paymentTermsOptions={paymentTermsOptions}
+ incotermsOptions={incotermsOptions}
+ />
</DataTableAdvancedToolbar>
</DataTable>
diff --git a/lib/bidding/list/create-bidding-dialog.tsx b/lib/bidding/list/create-bidding-dialog.tsx
index 57cc1002..4fc4fd7b 100644
--- a/lib/bidding/list/create-bidding-dialog.tsx
+++ b/lib/bidding/list/create-bidding-dialog.tsx
@@ -67,7 +67,7 @@ import {
} from "@/components/ui/file-list"
import { Checkbox } from "@/components/ui/checkbox"
-import { createBidding, type CreateBiddingInput } from "@/lib/bidding/service"
+import { createBidding, type CreateBiddingInput, getActivePaymentTerms, getActiveIncoterms } from "@/lib/bidding/service"
import {
createBiddingSchema,
type CreateBiddingSchema
@@ -116,6 +116,8 @@ interface PRItemInfo {
quantityUnit: string
totalWeight: string
weightUnit: string
+ materialDescription: string
+ hasSpecDocument: boolean
requestedDeliveryDate: string
specFiles: File[]
isRepresentative: boolean // 대표 아이템 여부
@@ -125,7 +127,12 @@ interface PRItemInfo {
const TAB_ORDER = ["basic", "contract", "schedule", "conditions", "details", "manager"] as const
type TabType = typeof TAB_ORDER[number]
-export function CreateBiddingDialog() {
+interface CreateBiddingDialogProps {
+ paymentTermsOptions?: Array<{code: string, description: string}>
+ incotermsOptions?: Array<{code: string, description: string}>
+}
+
+export function CreateBiddingDialog({ paymentTermsOptions = [], incotermsOptions = [] }: CreateBiddingDialogProps) {
const router = useRouter()
const [isSubmitting, setIsSubmitting] = React.useState(false)
const { data: session } = useSession()
@@ -168,6 +175,7 @@ export function CreateBiddingDialog() {
sparePartOptions: "",
})
+
// 사양설명회 파일 추가
const addMeetingFiles = (files: File[]) => {
setSpecMeetingInfo(prev => ({
@@ -311,6 +319,8 @@ export function CreateBiddingDialog() {
form.setValue("prNumber", representativePrNumber)
}, [hasPrDocuments, representativePrNumber, form])
+
+
// 세션 정보로 담당자 정보 자동 채우기
React.useEffect(() => {
if (session?.user) {
@@ -331,8 +341,8 @@ export function CreateBiddingDialog() {
}
// 담당자 전화번호는 세션에 있다면 설정 (보통 세션에 전화번호는 없지만, 있다면)
- if (session.user.phone) {
- form.setValue("managerPhone", session.user.phone)
+ if ('phone' in session.user && session.user.phone) {
+ form.setValue("managerPhone", session.user.phone as string)
}
}
}, [session, form])
@@ -340,7 +350,7 @@ export function CreateBiddingDialog() {
// PR 아이템 추가
const addPRItem = () => {
const newItem: PRItemInfo = {
- id: `pr-${Date.now()}`,
+ id: `pr-${Math.random().toString(36).substr(2, 9)}`,
prNumber: "",
itemCode: "",
itemInfo: "",
@@ -348,6 +358,8 @@ export function CreateBiddingDialog() {
quantityUnit: "EA",
totalWeight: "",
weightUnit: "KG",
+ materialDescription: "",
+ hasSpecDocument: false,
requestedDeliveryDate: "",
specFiles: [],
isRepresentative: prItems.length === 0, // 첫 번째 아이템은 자동으로 대표 아이템
@@ -477,7 +489,7 @@ export function CreateBiddingDialog() {
const result = await createBidding(extendedData, userId)
if (result.success) {
- toast.success(result.message || "입찰이 성공적으로 생성되었습니다.")
+ toast.success((result as { success: true; message: string }).message || "입찰이 성공적으로 생성되었습니다.")
setOpen(false)
router.refresh()
@@ -624,7 +636,7 @@ export function CreateBiddingDialog() {
>
{/* 탭 영역 */}
<div className="flex-1 overflow-hidden">
- <Tabs value={activeTab} onValueChange={setActiveTab} className="h-full flex flex-col">
+ <Tabs value={activeTab} onValueChange={(value) => setActiveTab(value as TabType)} className="h-full flex flex-col">
<div className="px-6">
<div className="flex space-x-1 bg-muted p-1 rounded-lg overflow-x-auto">
<button
@@ -1305,14 +1317,30 @@ export function CreateBiddingDialog() {
<label className="text-sm font-medium">
지급조건 <span className="text-red-500">*</span>
</label>
- <Input
- placeholder="예: 월말결제, 60일"
+ <Select
value={biddingConditions.paymentTerms}
- onChange={(e) => setBiddingConditions(prev => ({
+ onValueChange={(value) => setBiddingConditions(prev => ({
...prev,
- paymentTerms: e.target.value
+ paymentTerms: value
}))}
- />
+ >
+ <SelectTrigger>
+ <SelectValue placeholder="지급조건 선택" />
+ </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">
@@ -1333,14 +1361,30 @@ export function CreateBiddingDialog() {
<label className="text-sm font-medium">
운송조건(인코텀즈) <span className="text-red-500">*</span>
</label>
- <Input
- placeholder="예: FOB, CIF 등"
+ <Select
value={biddingConditions.incoterms}
- onChange={(e) => setBiddingConditions(prev => ({
+ onValueChange={(value) => setBiddingConditions(prev => ({
...prev,
- incoterms: e.target.value
+ incoterms: value
}))}
- />
+ >
+ <SelectTrigger>
+ <SelectValue placeholder="인코텀즈 선택" />
+ </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">