From c4f5472b961afb237dc819f9dd3f42a7b8f71075 Mon Sep 17 00:00:00 2001
From: dujinkim <dujin.kim@dtsolution.co.kr>
Date: Tue, 18 Nov 2025 10:30:31 +0000
Subject: (최겸) 구매 입찰 수정, 입찰초대 결재 등록, 재입찰, 차수증가, 폐찰,
 유찰취소 로직 수정, readonly 추가 등
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../bidding/manage/bidding-basic-info-editor.tsx   | 136 ++++++++++++---------
 1 file changed, 77 insertions(+), 59 deletions(-)

(limited to 'components/bidding/manage/bidding-basic-info-editor.tsx')

diff --git a/components/bidding/manage/bidding-basic-info-editor.tsx b/components/bidding/manage/bidding-basic-info-editor.tsx
index e92c39a5..f0d56689 100644
--- a/components/bidding/manage/bidding-basic-info-editor.tsx
+++ b/components/bidding/manage/bidding-basic-info-editor.tsx
@@ -45,6 +45,16 @@ import type { ProcurementManagerWithUser } from '@/components/common/selectors/p
 import { getBiddingDocuments, uploadBiddingDocument, deleteBiddingDocument } from '@/lib/bidding/detail/service'
 import { downloadFile } from '@/lib/file-download'
 
+// Dropzone components
+import {
+  Dropzone,
+  DropzoneDescription,
+  DropzoneInput,
+  DropzoneTitle,
+  DropzoneUploadIcon,
+  DropzoneZone,
+} from "@/components/ui/dropzone"
+
 // 입찰 기본 정보 에디터 컴포넌트
 interface BiddingBasicInfo {
   title?: string
@@ -78,6 +88,7 @@ interface BiddingBasicInfo {
 
 interface BiddingBasicInfoEditorProps {
   biddingId: number
+  readonly?: boolean
 }
 
 interface UploadedDocument {
@@ -95,7 +106,7 @@ interface UploadedDocument {
   uploadedBy: string
 }
 
-export function BiddingBasicInfoEditor({ biddingId }: BiddingBasicInfoEditorProps) {
+export function BiddingBasicInfoEditor({ biddingId, readonly = false }: BiddingBasicInfoEditorProps) {
   const [isLoading, setIsLoading] = React.useState(true)
   const [isSubmitting, setIsSubmitting] = React.useState(false)
   const [isLoadingTemplate, setIsLoadingTemplate] = React.useState(false)
@@ -535,7 +546,7 @@ export function BiddingBasicInfoEditor({ biddingId }: BiddingBasicInfoEditorProp
                   <FormItem>
                     <FormLabel>입찰명 <span className="text-red-500">*</span></FormLabel>
                     <FormControl>
-                      <Input placeholder="입찰명을 입력하세요" {...field} />
+                      <Input placeholder="입찰명을 입력하세요" {...field} disabled={readonly} />  
                     </FormControl>
                     <FormMessage />
                   </FormItem>
@@ -883,7 +894,7 @@ export function BiddingBasicInfoEditor({ biddingId }: BiddingBasicInfoEditorProp
                   <FormItem>
                     <FormLabel>입찰개요</FormLabel>
                     <FormControl>
-                      <Textarea placeholder="입찰에 대한 설명을 입력하세요" rows={2} {...field} />
+                      <Textarea placeholder="입찰에 대한 설명을 입력하세요" rows={2} {...field} readOnly={readonly} />
                     </FormControl>
                     <FormMessage />
                   </FormItem>
@@ -896,7 +907,7 @@ export function BiddingBasicInfoEditor({ biddingId }: BiddingBasicInfoEditorProp
                   <FormItem>
                     <FormLabel>비고</FormLabel>
                     <FormControl>
-                      <Textarea placeholder="추가 사항이나 참고사항을 입력하세요" rows={3} {...field} />
+                      <Textarea placeholder="추가 사항이나 참고사항을 입력하세요" rows={3} {...field} readOnly={readonly} />
                     </FormControl>
                     <FormMessage />
                   </FormItem>
@@ -1123,6 +1134,7 @@ export function BiddingBasicInfoEditor({ biddingId }: BiddingBasicInfoEditorProp
                         }))
                       }}
                       rows={3}
+                      readOnly={readonly}
                     />
                   </div>
                 </div>
@@ -1138,7 +1150,7 @@ export function BiddingBasicInfoEditor({ biddingId }: BiddingBasicInfoEditorProp
                         <TiptapEditor
                           content={field.value || noticeTemplate}
                           setContent={field.onChange}
-                          disabled={isLoadingTemplate}
+                          disabled={isLoadingTemplate || readonly}
                           height="300px"
                         />
                       </div>
@@ -1156,12 +1168,14 @@ export function BiddingBasicInfoEditor({ biddingId }: BiddingBasicInfoEditorProp
               </div>
 
               {/* 액션 버튼 */}
-              <div className="flex justify-end gap-4 pt-4">
-                <Button type="submit" disabled={isSubmitting} className="flex items-center gap-2">
-                  {isSubmitting ? '저장 중...' : '저장'}
-                  <ChevronRight className="h-4 w-4" />
-                </Button>
-              </div>
+              {!readonly && (
+                <div className="flex justify-end gap-4 pt-4">
+                  <Button type="submit" disabled={isSubmitting} className="flex items-center gap-2">
+                    {isSubmitting ? '저장 중...' : '저장'}
+                    <ChevronRight className="h-4 w-4" />
+                  </Button>
+                </div>
+              )}
             </form>
           </Form>
         </CardContent>
@@ -1175,33 +1189,35 @@ export function BiddingBasicInfoEditor({ biddingId }: BiddingBasicInfoEditorProp
             SHI용 첨부파일
           </CardTitle>
           <p className="text-sm text-muted-foreground">
-            SHI에서 제공하는 문서나 파일을 업로드하세요
+            내부 보관를 위해 필요한 문서나 파일을 업로드 하세요.
           </p>
         </CardHeader>
         <CardContent className="space-y-4">
-          <div className="border-2 border-dashed border-gray-300 rounded-lg p-6">
-            <div className="text-center">
-              <Upload className="h-12 w-12 text-gray-400 mx-auto mb-4" />
-              <div className="space-y-2">
-                <p className="text-sm text-gray-600">
-                  파일을 드래그 앤 드롭하거나{' '}
-                  <label className="text-blue-600 hover:text-blue-500 cursor-pointer">
-                    <input
-                      type="file"
-                      multiple
-                      className="hidden"
-                      onChange={(e) => {
-                        const files = Array.from(e.target.files || [])
-                        setShiAttachmentFiles(prev => [...prev, ...files])
-                      }}
-                      accept=".pdf,.doc,.docx,.xls,.xlsx,.png,.jpg,.jpeg"
-                    />
-                    찾아보세요
-                  </label>
-                </p>
-              </div>
-            </div>
-          </div>
+          <Dropzone
+            maxSize={6e8} // 600MB
+            onDropAccepted={(files) => {
+              const newFiles = Array.from(files)
+              setShiAttachmentFiles(prev => [...prev, ...newFiles])
+            }}
+            onDropRejected={() => {
+              toast({
+                title: "File upload rejected",
+                description: "Please check file size and type.",
+                variant: "destructive",
+              })
+            }}
+          >
+            {() => (
+              <DropzoneZone className="flex justify-center h-32">
+                <div className="flex items-center gap-6">
+                  <DropzoneUploadIcon />
+                  <div className="grid gap-0.5">
+                    <DropzoneTitle>파일을 드래그하여 업로드</DropzoneTitle>
+                  </div>
+                </div>
+              </DropzoneZone>
+            )}
+          </Dropzone>
 
           {shiAttachmentFiles.length > 0 && (
             <div className="space-y-2">
@@ -1307,33 +1323,35 @@ export function BiddingBasicInfoEditor({ biddingId }: BiddingBasicInfoEditorProp
             협력업체용 첨부파일
           </CardTitle>
           <p className="text-sm text-muted-foreground">
-            협력업체에서 제공하는 문서나 파일을 업로드하세요
+            협력사로 제공하는 문서나 파일을 업로드 하세요.
           </p>
         </CardHeader>
         <CardContent className="space-y-4">
-          <div className="border-2 border-dashed border-gray-300 rounded-lg p-6">
-            <div className="text-center">
-              <Upload className="h-12 w-12 text-gray-400 mx-auto mb-4" />
-              <div className="space-y-2">
-                <p className="text-sm text-gray-600">
-                  파일을 드래그 앤 드롭하거나{' '}
-                  <label className="text-blue-600 hover:text-blue-500 cursor-pointer">
-                    <input
-                      type="file"
-                      multiple
-                      className="hidden"
-                      onChange={(e) => {
-                        const files = Array.from(e.target.files || [])
-                        setVendorAttachmentFiles(prev => [...prev, ...files])
-                      }}
-                      accept=".pdf,.doc,.docx,.xls,.xlsx,.png,.jpg,.jpeg"
-                    />
-                    찾아보세요
-                  </label>
-                </p>
-              </div>
-            </div>
-          </div>
+          <Dropzone
+            maxSize={6e8} // 600MB
+            onDropAccepted={(files) => {
+              const newFiles = Array.from(files)
+              setVendorAttachmentFiles(prev => [...prev, ...newFiles])
+            }}
+            onDropRejected={() => {
+              toast({
+                title: "File upload rejected",
+                description: "Please check file size and type.",
+                variant: "destructive",
+              })
+            }}
+          >
+            {() => (
+              <DropzoneZone className="flex justify-center h-32">
+                <div className="flex items-center gap-6">
+                  <DropzoneUploadIcon />
+                  <div className="grid gap-0.5">
+                    <DropzoneTitle>파일을 드래그하여 업로드</DropzoneTitle>
+                  </div>
+                </div>
+              </DropzoneZone>
+            )}
+          </Dropzone>
 
           {vendorAttachmentFiles.length > 0 && (
             <div className="space-y-2">
-- 
cgit v1.2.3

