diff options
| author | joonhoekim <26rote@gmail.com> | 2025-06-24 01:51:59 +0000 |
|---|---|---|
| committer | joonhoekim <26rote@gmail.com> | 2025-06-24 01:51:59 +0000 |
| commit | 6824e097d768f724cf439b410ccfb1ab9685ac98 (patch) | |
| tree | 1f297313637878e7a4ad6c89b84d5a2c3e9eb650 /lib/techsales-rfq/table/tech-sales-rfq-attachments-sheet.tsx | |
| parent | f4825dd3853188de4688fb4a56c0f4e847da314b (diff) | |
| parent | 4e63d8427d26d0d1b366ddc53650e15f3481fc75 (diff) | |
(merge) 대표님/최겸 작업사항 머지
Diffstat (limited to 'lib/techsales-rfq/table/tech-sales-rfq-attachments-sheet.tsx')
| -rw-r--r-- | lib/techsales-rfq/table/tech-sales-rfq-attachments-sheet.tsx | 183 |
1 files changed, 93 insertions, 90 deletions
diff --git a/lib/techsales-rfq/table/tech-sales-rfq-attachments-sheet.tsx b/lib/techsales-rfq/table/tech-sales-rfq-attachments-sheet.tsx index ecdf6d81..a7b487e1 100644 --- a/lib/techsales-rfq/table/tech-sales-rfq-attachments-sheet.tsx +++ b/lib/techsales-rfq/table/tech-sales-rfq-attachments-sheet.tsx @@ -27,7 +27,6 @@ import { import { Loader, Download, X, Eye, AlertCircle } from "lucide-react" import { toast } from "sonner" import { Badge } from "@/components/ui/badge" -import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select" import { Dropzone, @@ -63,7 +62,7 @@ export interface ExistingTechSalesAttachment { filePath: string fileSize?: number fileType?: string - attachmentType: "RFQ_COMMON" | "VENDOR_SPECIFIC" + attachmentType: "RFQ_COMMON" | "TBE_RESULT" | "CBE_RESULT" description?: string createdBy: number createdAt: Date @@ -72,7 +71,7 @@ export interface ExistingTechSalesAttachment { /** 새로 업로드할 파일 */ const newUploadSchema = z.object({ fileObj: z.any().optional(), // 실제 File - attachmentType: z.enum(["RFQ_COMMON", "VENDOR_SPECIFIC"]).default("RFQ_COMMON"), + attachmentType: z.enum(["RFQ_COMMON", "TBE_RESULT", "CBE_RESULT"]).default("RFQ_COMMON"), description: z.string().optional(), }) @@ -85,7 +84,7 @@ const existingAttachSchema = z.object({ filePath: z.string(), fileSize: z.number().optional(), fileType: z.string().optional(), - attachmentType: z.enum(["RFQ_COMMON", "VENDOR_SPECIFIC"]), + attachmentType: z.enum(["RFQ_COMMON", "TBE_RESULT", "CBE_RESULT"]), description: z.string().optional(), createdBy: z.number(), createdAt: z.custom<Date>(), @@ -112,27 +111,54 @@ interface TechSalesRfqAttachmentsSheetProps extends React.ComponentPropsWithRef<typeof Sheet> { defaultAttachments?: ExistingTechSalesAttachment[] rfq: TechSalesRfq | null + /** 첨부파일 타입 */ + attachmentType?: "RFQ_COMMON" | "TBE_RESULT" | "CBE_RESULT" /** 업로드/삭제 후 상위 테이블에 attachmentCount 등을 업데이트하기 위한 콜백 */ - onAttachmentsUpdated?: (rfqId: number, newAttachmentCount: number) => void - /** 강제 읽기 전용 모드 (파트너/벤더용) */ - readOnly?: boolean + // onAttachmentsUpdated?: (rfqId: number, newAttachmentCount: number) => void + } export function TechSalesRfqAttachmentsSheet({ defaultAttachments = [], - onAttachmentsUpdated, + // onAttachmentsUpdated, rfq, - readOnly = false, + attachmentType = "RFQ_COMMON", ...props }: TechSalesRfqAttachmentsSheetProps) { const [isPending, setIsPending] = React.useState(false) - // RFQ 상태에 따른 편집 가능 여부 결정 (readOnly prop이 true면 항상 false) - const isEditable = React.useMemo(() => { - if (!rfq || readOnly) return false - // RFQ Created, RFQ Vendor Assignned 상태에서만 편집 가능 - return ["RFQ Created", "RFQ Vendor Assignned"].includes(rfq.status) - }, [rfq, readOnly]) + // 첨부파일 타입별 제목과 설명 설정 + const attachmentConfig = React.useMemo(() => { + switch (attachmentType) { + case "TBE_RESULT": + return { + title: "TBE 결과 첨부파일", + description: "기술 평가(TBE) 결과 파일을 관리합니다.", + fileTypeLabel: "TBE 결과", + canEdit: true + } + case "CBE_RESULT": + return { + title: "CBE 결과 첨부파일", + description: "상업성 평가(CBE) 결과 파일을 관리합니다.", + fileTypeLabel: "CBE 결과", + canEdit: true + } + default: // RFQ_COMMON + return { + title: "RFQ 첨부파일", + description: "RFQ 공통 첨부파일을 관리합니다.", + fileTypeLabel: "공통", + canEdit: true + } + } + }, [attachmentType, rfq?.status]) + + // // RFQ 상태에 따른 편집 가능 여부 결정 (readOnly prop이 true면 항상 false) + // const isEditable = React.useMemo(() => { + // if (!rfq) return false + // return attachmentConfig.canEdit + // }, [rfq, attachmentConfig.canEdit]) const form = useForm<AttachmentsFormValues>({ resolver: zodResolver(attachmentsFormSchema), @@ -236,7 +262,7 @@ export function TechSalesRfqAttachmentsSheet({ .filter(upload => upload.fileObj) .map(upload => ({ file: upload.fileObj as File, - attachmentType: upload.attachmentType, + attachmentType: attachmentType, description: upload.description, })) @@ -268,50 +294,50 @@ export function TechSalesRfqAttachmentsSheet({ toast.success(successMessage) - // 즉시 첨부파일 목록 새로고침 - const refreshResult = await getTechSalesRfqAttachments(rfq.id) - if (refreshResult.error) { - console.error("첨부파일 목록 새로고침 실패:", refreshResult.error) - toast.warning("첨부파일 목록 새로고침에 실패했습니다. 시트를 다시 열어주세요.") - } else { - // 새로운 첨부파일 목록으로 폼 업데이트 - const refreshedAttachments = refreshResult.data.map(att => ({ - id: att.id, - techSalesRfqId: att.techSalesRfqId || rfq.id, - fileName: att.fileName, - originalFileName: att.originalFileName, - filePath: att.filePath, - fileSize: att.fileSize, - fileType: att.fileType, - attachmentType: att.attachmentType as "RFQ_COMMON" | "VENDOR_SPECIFIC", - description: att.description, - createdBy: att.createdBy, - createdAt: att.createdAt, - })) - - // 폼을 새로운 데이터로 리셋 (새 업로드 목록은 비움) - form.reset({ - techSalesRfqId: rfq.id, - existing: refreshedAttachments.map(att => ({ - ...att, - fileSize: att.fileSize || undefined, - fileType: att.fileType || undefined, - description: att.description || undefined, - })), - newUploads: [], - }) + // // 즉시 첨부파일 목록 새로고침 + // const refreshResult = await getTechSalesRfqAttachments(rfq.id) + // if (refreshResult.error) { + // console.error("첨부파일 목록 새로고침 실패:", refreshResult.error) + // toast.warning("첨부파일 목록 새로고침에 실패했습니다. 시트를 다시 열어주세요.") + // } else { + // // 새로운 첨부파일 목록으로 폼 업데이트 + // const refreshedAttachments = refreshResult.data.map(att => ({ + // id: att.id, + // techSalesRfqId: att.techSalesRfqId || rfq.id, + // fileName: att.fileName, + // originalFileName: att.originalFileName, + // filePath: att.filePath, + // fileSize: att.fileSize, + // fileType: att.fileType, + // attachmentType: att.attachmentType as "RFQ_COMMON" | "TBE_RESULT" | "CBE_RESULT", + // description: att.description, + // createdBy: att.createdBy, + // createdAt: att.createdAt, + // })) + + // // 폼을 새로운 데이터로 리셋 (새 업로드 목록은 비움) + // form.reset({ + // techSalesRfqId: rfq.id, + // existing: refreshedAttachments.map(att => ({ + // ...att, + // fileSize: att.fileSize || undefined, + // fileType: att.fileType || undefined, + // description: att.description || undefined, + // })), + // newUploads: [], + // }) - // 즉시 UI 업데이트를 위한 추가 피드백 - if (uploadedCount > 0) { - toast.success("첨부파일 목록이 업데이트되었습니다.", { duration: 2000 }) - } - } + // // 즉시 UI 업데이트를 위한 추가 피드백 + // if (uploadedCount > 0) { + // toast.success("첨부파일 목록이 업데이트되었습니다.", { duration: 2000 }) + // } + // } - // 콜백으로 상위 컴포넌트에 변경사항 알림 - const newAttachmentCount = refreshResult.error ? - (data.existing.length + newFiles.length - deleteAttachmentIds.length) : - refreshResult.data.length - onAttachmentsUpdated?.(rfq.id, newAttachmentCount) + // // 콜백으로 상위 컴포넌트에 변경사항 알림 + // const newAttachmentCount = refreshResult.error ? + // (data.existing.length + newFiles.length - deleteAttachmentIds.length) : + // refreshResult.data.length + // onAttachmentsUpdated?.(rfq.id, newAttachmentCount) } catch (error) { console.error("첨부파일 저장 오류:", error) @@ -325,10 +351,11 @@ export function TechSalesRfqAttachmentsSheet({ <Sheet {...props}> <SheetContent className="flex flex-col gap-6 sm:max-w-md"> <SheetHeader className="text-left"> - <SheetTitle>첨부파일 관리</SheetTitle> + <SheetTitle>{attachmentConfig.title}</SheetTitle> <SheetDescription> - RFQ: {rfq?.rfqCode || "N/A"} - {!isEditable && ( + <div>RFQ: {rfq?.rfqCode || "N/A"}</div> + <div className="mt-1">{attachmentConfig.description}</div> + {!attachmentConfig.canEdit && ( <div className="mt-2 flex items-center gap-2 text-amber-600"> <AlertCircle className="h-4 w-4" /> <span className="text-sm">현재 상태에서는 편집할 수 없습니다</span> @@ -345,7 +372,7 @@ export function TechSalesRfqAttachmentsSheet({ 기존 첨부파일 ({existingFields.length}개) </h6> {existingFields.map((field, index) => { - const typeLabel = field.attachmentType === "RFQ_COMMON" ? "공통" : "벤더별" + const typeLabel = attachmentConfig.fileTypeLabel const sizeText = field.fileSize ? prettyBytes(field.fileSize) : "알 수 없음" const dateText = field.createdAt ? formatDate(field.createdAt) : "" @@ -384,7 +411,7 @@ export function TechSalesRfqAttachmentsSheet({ </a> )} {/* Remove button - 편집 가능할 때만 표시 */} - {isEditable && ( + {attachmentConfig.canEdit && ( <Button type="button" variant="ghost" @@ -402,7 +429,7 @@ export function TechSalesRfqAttachmentsSheet({ </div> {/* 2) Dropzone for new uploads - 편집 가능할 때만 표시 */} - {isEditable ? ( + {attachmentConfig.canEdit ? ( <> <Dropzone maxSize={MAX_FILE_SIZE} @@ -467,30 +494,6 @@ export function TechSalesRfqAttachmentsSheet({ </FileListAction> </FileListHeader> - {/* 파일별 설정 */} - <div className="px-4 pb-3 space-y-3"> - <FormField - control={form.control} - name={`newUploads.${idx}.attachmentType`} - render={({ field: formField }) => ( - <FormItem> - <FormLabel className="text-xs">파일 타입</FormLabel> - <Select onValueChange={formField.onChange} defaultValue={formField.value}> - <FormControl> - <SelectTrigger className="h-8"> - <SelectValue placeholder="파일 타입 선택" /> - </SelectTrigger> - </FormControl> - <SelectContent> - <SelectItem value="RFQ_COMMON">공통 파일</SelectItem> - {/* <SelectItem value="VENDOR_SPECIFIC">벤더별 파일</SelectItem> */} - </SelectContent> - </Select> - <FormMessage /> - </FormItem> - )} - /> - </div> </FileListItem> ) })} @@ -510,10 +513,10 @@ export function TechSalesRfqAttachmentsSheet({ <SheetFooter className="gap-2 pt-2 sm:space-x-0"> <SheetClose asChild> <Button type="button" variant="outline"> - {isEditable ? "취소" : "닫기"} + {attachmentConfig.canEdit ? "취소" : "닫기"} </Button> </SheetClose> - {isEditable && ( + {attachmentConfig.canEdit && ( <Button type="submit" disabled={ |
