From 9cda8482660a87fd98c9ee43f507d75ff75b4e23 Mon Sep 17 00:00:00 2001
From: dujinkim <dujin.kim@dtsolution.co.kr>
Date: Fri, 28 Nov 2025 03:12:57 +0000
Subject: (최겸) 구매 입찰 피드백 반영(90%)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../bidding/create/bidding-create-dialog.tsx       | 451 ++++++++++++++-------
 1 file changed, 303 insertions(+), 148 deletions(-)

(limited to 'components/bidding/create/bidding-create-dialog.tsx')

diff --git a/components/bidding/create/bidding-create-dialog.tsx b/components/bidding/create/bidding-create-dialog.tsx
index f298721b..bb7880f5 100644
--- a/components/bidding/create/bidding-create-dialog.tsx
+++ b/components/bidding/create/bidding-create-dialog.tsx
@@ -2,7 +2,7 @@
 
 import * as React from 'react'
 import { UseFormReturn } from 'react-hook-form'
-import { ChevronRight, Upload, FileText, Eye, User, Building, Calendar, DollarSign, Plus } from 'lucide-react'
+import { ChevronRight, Upload, FileText, Eye, User, Building, Calendar, DollarSign, Plus, Check, ChevronsUpDown } from 'lucide-react'
 import { toast } from 'sonner'
 
 import { Button } from '@/components/ui/button'
@@ -26,6 +26,20 @@ import { Textarea } from '@/components/ui/textarea'
 import { Switch } from '@/components/ui/switch'
 import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'
 import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, DialogTrigger } from '@/components/ui/dialog'
+import {
+  Command,
+  CommandEmpty,
+  CommandGroup,
+  CommandInput,
+  CommandItem,
+  CommandList,
+} from '@/components/ui/command'
+import {
+  Popover,
+  PopoverContent,
+  PopoverTrigger,
+} from '@/components/ui/popover'
+import { cn } from '@/lib/utils'
 
 import type { CreateBiddingSchema } from '@/lib/bidding/validation'
 import { contractTypeLabels, biddingTypeLabels, awardCountLabels, biddingNoticeTypeLabels } from '@/db/schema'
@@ -589,37 +603,62 @@ export function BiddingCreateDialog({ form, onSuccess }: BiddingCreateDialogProp
                       control={form.control}
                       name="biddingConditions.paymentTerms"
                       render={({ field }) => (
-                        <FormItem>
+                        <FormItem className="flex flex-col">
                           <FormLabel>SHI 지급조건 <span className="text-red-500">*</span></FormLabel>
-                          <FormControl>
-                            <Select
-                              value={biddingConditions.paymentTerms}
-                              onValueChange={(value) => {
-                                setBiddingConditions(prev => ({
-                                  ...prev,
-                                  paymentTerms: value
-                                }))
-                                field.onChange(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>
-                          </FormControl>
+                          <Popover>
+                            <PopoverTrigger asChild>
+                              <FormControl>
+                                <Button
+                                  variant="outline"
+                                  role="combobox"
+                                  className={cn(
+                                    "justify-between",
+                                    !biddingConditions.paymentTerms && "text-muted-foreground"
+                                  )}
+                                >
+                                  {biddingConditions.paymentTerms
+                                    ? paymentTermsOptions.find((option) => option.code === biddingConditions.paymentTerms)
+                                      ? `${paymentTermsOptions.find((option) => option.code === biddingConditions.paymentTerms)?.code} ${paymentTermsOptions.find((option) => option.code === biddingConditions.paymentTerms)?.description ? `(${paymentTermsOptions.find((option) => option.code === biddingConditions.paymentTerms)?.description})` : ''}`
+                                      : "지급조건 선택"
+                                    : "지급조건 선택"}
+                                  <ChevronsUpDown className="ml-2 h-4 w-4 shrink-0 opacity-50" />
+                                </Button>
+                              </FormControl>
+                            </PopoverTrigger>
+                            <PopoverContent className="w-[400px] p-0">
+                              <Command>
+                                <CommandInput placeholder="지급조건 검색..." />
+                                <CommandList>
+                                  <CommandEmpty>검색 결과가 없습니다.</CommandEmpty>
+                                  <CommandGroup>
+                                    {paymentTermsOptions.map((option) => (
+                                      <CommandItem
+                                        key={option.code}
+                                        value={`${option.code} ${option.description || ''}`}
+                                        onSelect={() => {
+                                          setBiddingConditions(prev => ({
+                                            ...prev,
+                                            paymentTerms: option.code
+                                          }))
+                                          field.onChange(option.code)
+                                        }}
+                                      >
+                                        <Check
+                                          className={cn(
+                                            "mr-2 h-4 w-4",
+                                            option.code === biddingConditions.paymentTerms
+                                              ? "opacity-100"
+                                              : "opacity-0"
+                                          )}
+                                        />
+                                        {option.code} {option.description && `(${option.description})`}
+                                      </CommandItem>
+                                    ))}
+                                  </CommandGroup>
+                                </CommandList>
+                              </Command>
+                            </PopoverContent>
+                          </Popover>
                           <FormMessage />
                         </FormItem>
                       )}
@@ -632,37 +671,62 @@ export function BiddingCreateDialog({ form, onSuccess }: BiddingCreateDialogProp
                       control={form.control}
                       name="biddingConditions.incoterms"
                       render={({ field }) => (
-                        <FormItem>
+                        <FormItem className="flex flex-col">
                           <FormLabel>SHI 인도조건 <span className="text-red-500">*</span></FormLabel>
-                          <Select
-                            value={biddingConditions.incoterms}
-                            onValueChange={(value) => {
-                              setBiddingConditions(prev => ({
-                                ...prev,
-                                incoterms: value
-                              }))
-                              field.onChange(value)
-                            }}
-                          >
-                            <FormControl>
-                              <SelectTrigger>
-                                <SelectValue placeholder="인코텀즈 선택" />
-                              </SelectTrigger>
-                            </FormControl>
-                            <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>
+                          <Popover>
+                            <PopoverTrigger asChild>
+                              <FormControl>
+                                <Button
+                                  variant="outline"
+                                  role="combobox"
+                                  className={cn(
+                                    "justify-between",
+                                    !biddingConditions.incoterms && "text-muted-foreground"
+                                  )}
+                                >
+                                  {biddingConditions.incoterms
+                                    ? incotermsOptions.find((option) => option.code === biddingConditions.incoterms)
+                                      ? `${incotermsOptions.find((option) => option.code === biddingConditions.incoterms)?.code} ${incotermsOptions.find((option) => option.code === biddingConditions.incoterms)?.description ? `(${incotermsOptions.find((option) => option.code === biddingConditions.incoterms)?.description})` : ''}`
+                                      : "인코텀즈 선택"
+                                    : "인코텀즈 선택"}
+                                  <ChevronsUpDown className="ml-2 h-4 w-4 shrink-0 opacity-50" />
+                                </Button>
+                              </FormControl>
+                            </PopoverTrigger>
+                            <PopoverContent className="w-[400px] p-0">
+                              <Command>
+                                <CommandInput placeholder="인코텀즈 검색..." />
+                                <CommandList>
+                                  <CommandEmpty>검색 결과가 없습니다.</CommandEmpty>
+                                  <CommandGroup>
+                                    {incotermsOptions.map((option) => (
+                                      <CommandItem
+                                        key={option.code}
+                                        value={`${option.code} ${option.description || ''}`}
+                                        onSelect={() => {
+                                          setBiddingConditions(prev => ({
+                                            ...prev,
+                                            incoterms: option.code
+                                          }))
+                                          field.onChange(option.code)
+                                        }}
+                                      >
+                                        <Check
+                                          className={cn(
+                                            "mr-2 h-4 w-4",
+                                            option.code === biddingConditions.incoterms
+                                              ? "opacity-100"
+                                              : "opacity-0"
+                                          )}
+                                        />
+                                        {option.code} {option.description && `(${option.description})`}
+                                      </CommandItem>
+                                    ))}
+                                  </CommandGroup>
+                                </CommandList>
+                              </Command>
+                            </PopoverContent>
+                          </Popover>
                           <FormMessage />
                         </FormItem>
                       )}
@@ -699,31 +763,60 @@ export function BiddingCreateDialog({ form, onSuccess }: BiddingCreateDialogProp
                       control={form.control}
                       name="biddingConditions.taxConditions"
                       render={({ field }) => (
-                        <FormItem>
+                        <FormItem className="flex flex-col">
                           <FormLabel>SHI 매입부가가치세 <span className="text-red-500">*</span></FormLabel>
-                          <FormControl>
-                            <Select
-                              value={biddingConditions.taxConditions}
-                              onValueChange={(value) => {
-                                setBiddingConditions(prev => ({
-                                  ...prev,
-                                  taxConditions: value
-                                }))
-                                field.onChange(value)
-                              }}
-                            >
-                              <SelectTrigger>
-                                <SelectValue placeholder="세금조건 선택" />
-                              </SelectTrigger>
-                              <SelectContent>
-                                {TAX_CONDITIONS.map((condition) => (
-                                  <SelectItem key={condition.code} value={condition.code}>
-                                    {condition.name}
-                                  </SelectItem>
-                                ))}
-                              </SelectContent>
-                            </Select>
-                          </FormControl>
+                          <Popover>
+                            <PopoverTrigger asChild>
+                              <FormControl>
+                                <Button
+                                  variant="outline"
+                                  role="combobox"
+                                  className={cn(
+                                    "justify-between",
+                                    !biddingConditions.taxConditions && "text-muted-foreground"
+                                  )}
+                                >
+                                  {biddingConditions.taxConditions
+                                    ? TAX_CONDITIONS.find((condition) => condition.code === biddingConditions.taxConditions)?.name
+                                    : "세금조건 선택"}
+                                  <ChevronsUpDown className="ml-2 h-4 w-4 shrink-0 opacity-50" />
+                                </Button>
+                              </FormControl>
+                            </PopoverTrigger>
+                            <PopoverContent className="w-[400px] p-0">
+                              <Command>
+                                <CommandInput placeholder="세금조건 검색..." />
+                                <CommandList>
+                                  <CommandEmpty>검색 결과가 없습니다.</CommandEmpty>
+                                  <CommandGroup>
+                                    {TAX_CONDITIONS.map((condition) => (
+                                      <CommandItem
+                                        key={condition.code}
+                                        value={`${condition.code} ${condition.name}`}
+                                        onSelect={() => {
+                                          setBiddingConditions(prev => ({
+                                            ...prev,
+                                            taxConditions: condition.code
+                                          }))
+                                          field.onChange(condition.code)
+                                        }}
+                                      >
+                                        <Check
+                                          className={cn(
+                                            "mr-2 h-4 w-4",
+                                            condition.code === biddingConditions.taxConditions
+                                              ? "opacity-100"
+                                              : "opacity-0"
+                                          )}
+                                        />
+                                        {condition.name}
+                                      </CommandItem>
+                                    ))}
+                                  </CommandGroup>
+                                </CommandList>
+                              </Command>
+                            </PopoverContent>
+                          </Popover>
                           <FormMessage />
                         </FormItem>
                       )}
@@ -733,37 +826,62 @@ export function BiddingCreateDialog({ form, onSuccess }: BiddingCreateDialogProp
                       control={form.control}
                       name="biddingConditions.shippingPort"
                       render={({ field }) => (
-                        <FormItem>
+                        <FormItem className="flex flex-col">
                           <FormLabel>SHI 선적지</FormLabel>
-                          <Select
-                            value={biddingConditions.shippingPort}
-                            onValueChange={(value) => {
-                              setBiddingConditions(prev => ({
-                                ...prev,
-                                shippingPort: value
-                              }))
-                              field.onChange(value)
-                            }}
-                          >
-                            <FormControl>
-                              <SelectTrigger>
-                                <SelectValue placeholder="선적지 선택" />
-                              </SelectTrigger>
-                            </FormControl>
-                            <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>
+                          <Popover>
+                            <PopoverTrigger asChild>
+                              <FormControl>
+                                <Button
+                                  variant="outline"
+                                  role="combobox"
+                                  className={cn(
+                                    "justify-between",
+                                    !biddingConditions.shippingPort && "text-muted-foreground"
+                                  )}
+                                >
+                                  {biddingConditions.shippingPort
+                                    ? shippingPlaces.find((place) => place.code === biddingConditions.shippingPort)
+                                      ? `${shippingPlaces.find((place) => place.code === biddingConditions.shippingPort)?.code} ${shippingPlaces.find((place) => place.code === biddingConditions.shippingPort)?.description ? `(${shippingPlaces.find((place) => place.code === biddingConditions.shippingPort)?.description})` : ''}`
+                                      : "선적지 선택"
+                                    : "선적지 선택"}
+                                  <ChevronsUpDown className="ml-2 h-4 w-4 shrink-0 opacity-50" />
+                                </Button>
+                              </FormControl>
+                            </PopoverTrigger>
+                            <PopoverContent className="w-[400px] p-0">
+                              <Command>
+                                <CommandInput placeholder="선적지 검색..." />
+                                <CommandList>
+                                  <CommandEmpty>검색 결과가 없습니다.</CommandEmpty>
+                                  <CommandGroup>
+                                    {shippingPlaces.map((place) => (
+                                      <CommandItem
+                                        key={place.code}
+                                        value={`${place.code} ${place.description || ''}`}
+                                        onSelect={() => {
+                                          setBiddingConditions(prev => ({
+                                            ...prev,
+                                            shippingPort: place.code
+                                          }))
+                                          field.onChange(place.code)
+                                        }}
+                                      >
+                                        <Check
+                                          className={cn(
+                                            "mr-2 h-4 w-4",
+                                            place.code === biddingConditions.shippingPort
+                                              ? "opacity-100"
+                                              : "opacity-0"
+                                          )}
+                                        />
+                                        {place.code} {place.description && `(${place.description})`}
+                                      </CommandItem>
+                                    ))}
+                                  </CommandGroup>
+                                </CommandList>
+                              </Command>
+                            </PopoverContent>
+                          </Popover>
                           <FormMessage />
                         </FormItem>
                       )}
@@ -776,43 +894,68 @@ export function BiddingCreateDialog({ form, onSuccess }: BiddingCreateDialogProp
                       control={form.control}
                       name="biddingConditions.destinationPort"
                       render={({ field }) => (
-                        <FormItem>
+                        <FormItem className="flex flex-col">
                           <FormLabel>SHI 하역지</FormLabel>
-                          <Select
-                            value={biddingConditions.destinationPort}
-                            onValueChange={(value) => {
-                              setBiddingConditions(prev => ({
-                                ...prev,
-                                destinationPort: value
-                              }))
-                              field.onChange(value)
-                            }}
-                          >
-                            <FormControl>
-                              <SelectTrigger>
-                                <SelectValue placeholder="하역지 선택" />
-                              </SelectTrigger>
-                            </FormControl>
-                            <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>
+                          <Popover>
+                            <PopoverTrigger asChild>
+                              <FormControl>
+                                <Button
+                                  variant="outline"
+                                  role="combobox"
+                                  className={cn(
+                                    "justify-between",
+                                    !biddingConditions.destinationPort && "text-muted-foreground"
+                                  )}
+                                >
+                                  {biddingConditions.destinationPort
+                                    ? destinationPlaces.find((place) => place.code === biddingConditions.destinationPort)
+                                      ? `${destinationPlaces.find((place) => place.code === biddingConditions.destinationPort)?.code} ${destinationPlaces.find((place) => place.code === biddingConditions.destinationPort)?.description ? `(${destinationPlaces.find((place) => place.code === biddingConditions.destinationPort)?.description})` : ''}`
+                                      : "하역지 선택"
+                                    : "하역지 선택"}
+                                  <ChevronsUpDown className="ml-2 h-4 w-4 shrink-0 opacity-50" />
+                                </Button>
+                              </FormControl>
+                            </PopoverTrigger>
+                            <PopoverContent className="w-[400px] p-0">
+                              <Command>
+                                <CommandInput placeholder="하역지 검색..." />
+                                <CommandList>
+                                  <CommandEmpty>검색 결과가 없습니다.</CommandEmpty>
+                                  <CommandGroup>
+                                    {destinationPlaces.map((place) => (
+                                      <CommandItem
+                                        key={place.code}
+                                        value={`${place.code} ${place.description || ''}`}
+                                        onSelect={() => {
+                                          setBiddingConditions(prev => ({
+                                            ...prev,
+                                            destinationPort: place.code
+                                          }))
+                                          field.onChange(place.code)
+                                        }}
+                                      >
+                                        <Check
+                                          className={cn(
+                                            "mr-2 h-4 w-4",
+                                            place.code === biddingConditions.destinationPort
+                                              ? "opacity-100"
+                                              : "opacity-0"
+                                          )}
+                                        />
+                                        {place.code} {place.description && `(${place.description})`}
+                                      </CommandItem>
+                                    ))}
+                                  </CommandGroup>
+                                </CommandList>
+                              </Command>
+                            </PopoverContent>
+                          </Popover>
                           <FormMessage />
                         </FormItem>
                       )}
                     />
 
-                    {/* <FormField
+                    {/*                     <FormField
                       control={form.control}
                       name="biddingConditions.contractDeliveryDate"
                       render={({ field }) => (
@@ -829,6 +972,8 @@ export function BiddingCreateDialog({ form, onSuccess }: BiddingCreateDialogProp
                                 }))
                                 field.onChange(e.target.value)
                               }}
+                              min="1900-01-01"
+                              max="2100-12-31"
                             />
                           </FormControl>
                           <FormMessage />
@@ -849,7 +994,12 @@ export function BiddingCreateDialog({ form, onSuccess }: BiddingCreateDialogProp
                             계약기간 시작
                           </FormLabel>
                           <FormControl>
-                            <Input type="date" {...field} />
+                            <Input 
+                              type="date" 
+                              {...field} 
+                              min="1900-01-01" 
+                              max="2100-12-31"
+                            />
                           </FormControl>
                           <FormMessage />
                         </FormItem>
@@ -866,7 +1016,12 @@ export function BiddingCreateDialog({ form, onSuccess }: BiddingCreateDialogProp
                             계약기간 종료
                           </FormLabel>
                           <FormControl>
-                            <Input type="date" {...field} />
+                            <Input 
+                              type="date" 
+                              {...field} 
+                              min="1900-01-01" 
+                              max="2100-12-31"
+                            />
                           </FormControl>
                           <FormMessage />
                         </FormItem>
-- 
cgit v1.2.3

