diff options
| author | dujinkim <dujin.kim@dtsolution.co.kr> | 2025-04-02 09:54:08 +0000 |
|---|---|---|
| committer | dujinkim <dujin.kim@dtsolution.co.kr> | 2025-04-02 09:54:08 +0000 |
| commit | dfdfae3018f8499240f48d28ce634f4a5c56e006 (patch) | |
| tree | 4493b172c061fa5bf4e94c083788110eb1507f6d /components/pq/pq-input-tabs.tsx | |
| parent | 21a72eeddc74cf775e2a76e2c569de970bd62a7f (diff) | |
벤더 코멘트 처리
Diffstat (limited to 'components/pq/pq-input-tabs.tsx')
| -rw-r--r-- | components/pq/pq-input-tabs.tsx | 136 |
1 files changed, 119 insertions, 17 deletions
diff --git a/components/pq/pq-input-tabs.tsx b/components/pq/pq-input-tabs.tsx index 743e1729..b84d9167 100644 --- a/components/pq/pq-input-tabs.tsx +++ b/components/pq/pq-input-tabs.tsx @@ -54,7 +54,7 @@ import { FileListName, } from "@/components/ui/file-list" -// Dialog components from shadcn/ui +// Dialog components import { Dialog, DialogContent, @@ -65,13 +65,15 @@ import { } from "@/components/ui/dialog" // Additional UI -import { Separator } from "../ui/separator" +import { Separator } from "@/components/ui/separator" +import { Badge } from "@/components/ui/badge" -// Server actions (adjust to your actual code) +// Server actions import { uploadFileAction, savePQAnswersAction, submitPQAction, + ProjectPQ, } from "@/lib/pq/service" import { PQGroupData } from "@/lib/pq/service" @@ -132,9 +134,13 @@ type PQFormValues = z.infer<typeof pqFormSchema> export function PQInputTabs({ data, vendorId, + projectId, + projectData, }: { data: PQGroupData[] vendorId: number + projectId?: number + projectData?: ProjectPQ | null }) { const [isSaving, setIsSaving] = React.useState(false) const [isSubmitting, setIsSubmitting] = React.useState(false) @@ -152,7 +158,7 @@ export function PQInputTabs({ data.forEach((group) => { group.items.forEach((item) => { - // Check if the server item is already “complete” + // Check if the server item is already "complete" const hasExistingAnswer = item.answer && item.answer.trim().length > 0 const hasExistingAttachments = item.attachments && item.attachments.length > 0 @@ -190,7 +196,7 @@ export function PQInputTabs({ // ---------------------------------------------------------------------- React.useEffect(() => { const values = form.getValues() - // We consider items “saved” if `saved===true` AND they have an answer or attachments + // We consider items "saved" if `saved===true` AND they have an answer or attachments const allItemsSaved = values.answers.every( (answer) => answer.saved && (answer.answer || answer.uploadedFiles.length > 0) ) @@ -299,6 +305,7 @@ export function PQInputTabs({ const updatedAnswer = form.getValues(`answers.${answerIndex}`) const saveResult = await savePQAnswersAction({ vendorId, + projectId, // 프로젝트 ID 전달 answers: [ { criteriaId: updatedAnswer.criteriaId, @@ -396,13 +403,18 @@ export function PQInputTabs({ setIsSubmitting(true) setShowConfirmDialog(false) - const result = await submitPQAction(vendorId) + const result = await submitPQAction({ + vendorId, + projectId, // 프로젝트 ID 전달 + }) + if (result.ok) { toast({ title: "PQ Submitted", description: "Your PQ information has been submitted successfully", }) - // Optionally redirect + // 제출 후 페이지 새로고침 또는 리디렉션 처리 + window.location.reload() } else { toast({ title: "Submit Error", @@ -421,6 +433,72 @@ export function PQInputTabs({ setIsSubmitting(false) } } + + // 프로젝트 정보 표시 섹션 + const renderProjectInfo = () => { + if (!projectData) return null; + + return ( + <div className="mb-6 bg-muted p-4 rounded-md"> + <div className="flex items-center justify-between mb-2"> + <h3 className="text-lg font-semibold">프로젝트 정보</h3> + <Badge variant={getStatusVariant(projectData.status)}> + {getStatusLabel(projectData.status)} + </Badge> + </div> + + <div className="grid grid-cols-1 md:grid-cols-2 gap-4"> + <div> + <p className="text-sm font-medium text-muted-foreground">프로젝트 코드</p> + <p>{projectData.projectCode}</p> + </div> + <div> + <p className="text-sm font-medium text-muted-foreground">프로젝트명</p> + <p>{projectData.projectName}</p> + </div> + {projectData.submittedAt && ( + <div className="col-span-1 md:col-span-2"> + <p className="text-sm font-medium text-muted-foreground">제출일</p> + <p>{formatDate(projectData.submittedAt)}</p> + </div> + )} + </div> + </div> + ); + }; + + // 상태 표시용 함수 + const getStatusLabel = (status: string) => { + switch (status) { + case "REQUESTED": return "요청됨"; + case "IN_PROGRESS": return "진행중"; + case "SUBMITTED": return "제출됨"; + case "APPROVED": return "승인됨"; + case "REJECTED": return "반려됨"; + default: return status; + } + }; + + const getStatusVariant = (status: string) => { + switch (status) { + case "REQUESTED": return "secondary"; + case "IN_PROGRESS": return "default"; + case "SUBMITTED": return "outline"; + case "APPROVED": return "outline"; + case "REJECTED": return "destructive"; + default: return "secondary"; + } + }; + + // 날짜 형식화 함수 + const formatDate = (date: Date) => { + if (!date) return "-"; + return new Date(date).toLocaleDateString("ko-KR", { + year: "numeric", + month: "long", + day: "numeric", + }); + }; // ---------------------------------------------------------------------- // H) Render @@ -428,6 +506,9 @@ export function PQInputTabs({ return ( <Form {...form}> <form> + {/* 프로젝트 정보 섹션 */} + {renderProjectInfo()} + <Tabs defaultValue={data[0]?.groupName || ""} className="w-full"> {/* Top Controls */} <div className="flex justify-between items-center mb-4"> @@ -485,7 +566,7 @@ export function PQInputTabs({ {/* 2-column grid */} <div className="grid grid-cols-1 md:grid-cols-2 gap-4 pb-4"> {group.items.map((item) => { - const { criteriaId, code, checkPoint, description } = item + const { criteriaId, code, checkPoint, description, contractInfo, additionalRequirement } = item const answerIndex = getAnswerIndex(criteriaId) if (answerIndex === -1) return null @@ -498,7 +579,7 @@ export function PQInputTabs({ const hasNewUploads = newUploads.length > 0 const canSave = isItemDirty || hasNewUploads - // For “Not Saved” vs. “Saved” status label + // For "Not Saved" vs. "Saved" status label const hasUploads = form.watch(`answers.${answerIndex}.uploadedFiles`).length > 0 || newUploads.length > 0 @@ -556,13 +637,32 @@ export function PQInputTabs({ </CardHeader> <CollapsibleContent> - {/* Answer Field */} - <CardHeader className="pt-0 pb-3"> + <CardContent className="pt-3 space-y-3"> + {/* 프로젝트별 추가 필드 (contractInfo, additionalRequirement) */} + {projectId && contractInfo && ( + <div className="space-y-1"> + <FormLabel className="text-sm font-medium">계약 정보</FormLabel> + <div className="rounded-md bg-muted/30 p-3 text-sm whitespace-pre-wrap"> + {contractInfo} + </div> + </div> + )} + + {projectId && additionalRequirement && ( + <div className="space-y-1"> + <FormLabel className="text-sm font-medium">추가 요구사항</FormLabel> + <div className="rounded-md bg-muted/30 p-3 text-sm whitespace-pre-wrap"> + {additionalRequirement} + </div> + </div> + )} + + {/* Answer Field */} <FormField control={form.control} name={`answers.${answerIndex}.answer`} render={({ field }) => ( - <FormItem className="mt-3"> + <FormItem className="mt-2"> <FormLabel>Answer</FormLabel> <FormControl> <Textarea @@ -583,11 +683,10 @@ export function PQInputTabs({ </FormItem> )} /> - </CardHeader> + - {/* Attachments / Dropzone */} - <CardContent> - <div className="grid gap-2"> + {/* Attachments / Dropzone */} + <div className="grid gap-2 mt-3"> <FormLabel>Attachments</FormLabel> <Dropzone maxSize={6e8} // 600MB @@ -708,7 +807,10 @@ export function PQInputTabs({ <DialogHeader> <DialogTitle>Confirm Submission</DialogTitle> <DialogDescription> - Review your answers before final submission. + {projectId + ? `${projectData?.projectCode} 프로젝트의 PQ 응답을 제출하시겠습니까?` + : "일반 PQ 응답을 제출하시겠습니까?" + } 제출 후에는 수정이 불가능합니다. </DialogDescription> </DialogHeader> |
