diff options
Diffstat (limited to 'lib/bidding/list')
| -rw-r--r-- | lib/bidding/list/biddings-table-toolbar-actions.tsx | 9 | ||||
| -rw-r--r-- | lib/bidding/list/biddings-table.tsx | 25 | ||||
| -rw-r--r-- | lib/bidding/list/create-bidding-dialog.tsx | 78 |
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"> |
