diff options
Diffstat (limited to 'app')
| -rw-r--r-- | app/[lng]/evcp/(evcp)/(procurement)/basic-contract/compliance-comments/[id]/page.tsx | 197 |
1 files changed, 197 insertions, 0 deletions
diff --git a/app/[lng]/evcp/(evcp)/(procurement)/basic-contract/compliance-comments/[id]/page.tsx b/app/[lng]/evcp/(evcp)/(procurement)/basic-contract/compliance-comments/[id]/page.tsx new file mode 100644 index 00000000..359efbed --- /dev/null +++ b/app/[lng]/evcp/(evcp)/(procurement)/basic-contract/compliance-comments/[id]/page.tsx @@ -0,0 +1,197 @@ +import * as React from "react"; +import { notFound } from "next/navigation"; +import Link from "next/link"; +import { eq } from "drizzle-orm"; + +import db from "@/db/db"; +import { basicContractView } from "@/db/schema"; +import { Shell } from "@/components/shell"; +import { + Breadcrumb, + BreadcrumbList, + BreadcrumbItem, + BreadcrumbLink, + BreadcrumbSeparator, + BreadcrumbPage, +} from "@/components/ui/breadcrumb"; +import { Card, CardHeader, CardTitle, CardDescription, CardContent } from "@/components/ui/card"; +import { Badge } from "@/components/ui/badge"; +import { Button } from "@/components/ui/button"; +import { AgreementCommentList } from "@/lib/basic-contract/agreement-comments/agreement-comment-list"; +import { formatDateTime } from "@/lib/utils"; +import { checkNegotiationStatus } from "@/lib/basic-contract/agreement-comments/actions"; +import { MessageCircle, Building2, FileText, Calendar, ArrowLeft } from "lucide-react"; + +interface ComplianceCommentsPageProps { + params: Promise<{ id: string }>; +} + +export const revalidate = 0; + +export default async function ComplianceCommentsPage(props: ComplianceCommentsPageProps) { + const params = await props.params; + const contractId = Number(params.id); + + if (Number.isNaN(contractId)) { + notFound(); + } + + const contract = await db + .select() + .from(basicContractView) + .where(eq(basicContractView.id, contractId)) + .limit(1) + .then((rows) => rows[0]); + + if (!contract) { + notFound(); + } + + const negotiationSummary = await checkNegotiationStatus(contractId); + + const negotiationStatusLabel = contract.negotiationCompletedAt + ? "협의 완료" + : negotiationSummary.hasComments + ? `협의 진행중 (${negotiationSummary.commentCount}건)` + : "협의 없음"; + + const negotiationBadgeClass = contract.negotiationCompletedAt + ? "bg-green-50 text-green-700 border-green-200" + : negotiationSummary.hasComments + ? "bg-orange-50 text-orange-700 border-orange-200" + : "bg-gray-50 text-gray-600 border-gray-200"; + + const templateLink = contract.templateId + ? `/evcp/basic-contract/${contract.templateId}` + : "/evcp/basic-contract"; + + return ( + <Shell className="gap-4"> + <div className="flex flex-wrap items-center justify-between gap-3"> + <Breadcrumb> + <BreadcrumbList> + <BreadcrumbItem> + <BreadcrumbLink href="/evcp">EVCP</BreadcrumbLink> + </BreadcrumbItem> + <BreadcrumbSeparator /> + <BreadcrumbItem> + <BreadcrumbLink href="/evcp/basic-contract">기본계약서/서약서 관리</BreadcrumbLink> + </BreadcrumbItem> + <BreadcrumbSeparator /> + <BreadcrumbItem> + <BreadcrumbPage> + {contract.vendorName ? `${contract.vendorName} 협의 코멘트` : "협의 코멘트"} + </BreadcrumbPage> + </BreadcrumbItem> + </BreadcrumbList> + </Breadcrumb> + + <Button asChild variant="outline" size="sm"> + <Link href={templateLink}> + <ArrowLeft className="h-4 w-4 mr-2" /> + 계약 상세로 돌아가기 + </Link> + </Button> + </div> + + <Card> + <CardHeader className="pb-3"> + <div className="flex flex-wrap items-center justify-between gap-3"> + <div className="space-y-1"> + <CardTitle className="flex items-center gap-2 text-lg"> + <FileText className="h-4 w-4 text-blue-500" /> + {contract.templateName || "기본계약서"} + </CardTitle> + <CardDescription> + 계약서 ID {contract.id} · 템플릿 ID {contract.templateId ?? "-"} + </CardDescription> + </div> + <Badge variant="outline" className={`flex items-center gap-1 ${negotiationBadgeClass}`}> + <MessageCircle className="h-3 w-3" /> + {negotiationStatusLabel} + </Badge> + </div> + </CardHeader> + <CardContent className="grid gap-4 md:grid-cols-2"> + <div className="space-y-3"> + <h4 className="text-sm font-semibold text-gray-700 flex items-center gap-2"> + <Building2 className="h-4 w-4 text-gray-500" /> + 협력업체 정보 + </h4> + <div className="rounded border bg-gray-50 p-3 text-sm space-y-1"> + <div className="flex justify-between"> + <span className="text-gray-500">업체명</span> + <span className="font-medium text-gray-900"> + {contract.vendorName || "미지정"} + </span> + </div> + <div className="flex justify-between"> + <span className="text-gray-500">업체코드</span> + <span className="font-mono text-gray-900"> + {contract.vendorCode || "-"} + </span> + </div> + <div className="flex justify-between"> + <span className="text-gray-500">이메일</span> + <span className="text-gray-900">{contract.vendorEmail || "-"}</span> + </div> + </div> + </div> + + <div className="space-y-3"> + <h4 className="text-sm font-semibold text-gray-700 flex items-center gap-2"> + <Calendar className="h-4 w-4 text-gray-500" /> + 진행 정보 + </h4> + <div className="rounded border bg-gray-50 p-3 text-sm space-y-1"> + <div className="flex justify-between"> + <span className="text-gray-500">요청일</span> + <span className="text-gray-900"> + {formatDateTime(contract.createdAt, "KR")} + </span> + </div> + <div className="flex justify-between"> + <span className="text-gray-500">서명 상태</span> + <span className="text-gray-900"> + {contract.vendorSignedAt ? "협력업체 서명완료" : "협력업체 서명대기"} + </span> + </div> + <div className="flex justify-between"> + <span className="text-gray-500">협의 완료일</span> + <span className="text-gray-900"> + {contract.negotiationCompletedAt + ? formatDateTime(contract.negotiationCompletedAt, "KR") + : "-"} + </span> + </div> + </div> + </div> + </CardContent> + </Card> + + <Card> + <CardHeader className="pb-3"> + <div className="flex flex-wrap items-center justify-between gap-3"> + <div> + <CardTitle className="text-lg">협의 코멘트</CardTitle> + <CardDescription> + {contract.vendorName + ? `${contract.vendorName}과(와)의 협의 내용을 기록하고 공유합니다.` + : "협의 코멘트를 작성하고 상대방과 공유합니다."} + </CardDescription> + </div> + </div> + </CardHeader> + <CardContent className="h-[620px] pt-0"> + <AgreementCommentList + basicContractId={contractId} + currentUserType="SHI" + readOnly={false} + isNegotiationCompleted={!!contract.negotiationCompletedAt} + /> + </CardContent> + </Card> + </Shell> + ); +} + |
