diff --git a/src/app/db/surveyDB/schema/surveyDB.ts b/src/app/db/surveyDB/schema/surveyDB.ts index 1c16a7ab..f8b89da4 100644 --- a/src/app/db/surveyDB/schema/surveyDB.ts +++ b/src/app/db/surveyDB/schema/surveyDB.ts @@ -1,5 +1,6 @@ import { pgTable, uuid, text, timestamp } from "drizzle-orm/pg-core"; import { pgEnum } from "drizzle-orm/pg-core"; + export const DB_REPORT_TYPES = [ "ECO_CONDITION_REPORT", @@ -23,4 +24,8 @@ export const uploaded_files = pgTable("uploaded_files", { s3JsonUploadTimestamp: timestamp("s3_json_upload_timestamp", { withTimezone: true }), uprn: text("uprn").notNull(), -}); \ No newline at end of file +}); + +export type getUploadedFile = typeof uploaded_files.$inferSelect + +export type getUploadedFiles = getUploadedFile[]; diff --git a/src/app/portfolio/[slug]/building-passport/[propertyId]/documents/DocumentSection.tsx b/src/app/portfolio/[slug]/building-passport/[propertyId]/documents/DocumentSection.tsx index 3cf21d85..7d8a1e45 100644 --- a/src/app/portfolio/[slug]/building-passport/[propertyId]/documents/DocumentSection.tsx +++ b/src/app/portfolio/[slug]/building-passport/[propertyId]/documents/DocumentSection.tsx @@ -1,20 +1,42 @@ "use client"; - -import React, { useState } from "react"; +import { useRouter } from "next/navigation"; +import React from "react"; import { TableCell, TableRow } from "@/app/shadcn_components/ui/table"; import { BrandButton } from "@/app/components/Buttons"; import { UploadModal } from "./UploadModal"; import { documentTypeTitles, type ReportType } from "@/app/db/surveyDB/schema/documents"; +import type { getUploadedFiles, getUploadedFile } from "@/app/db/surveyDB/schema/surveyDB"; type Props = { - reportType: ReportType; // <- the only type selector needed + reportType: ReportType; uprn: string; + files: getUploadedFiles; }; -export const DocumentSection: React.FC = ({ reportType, uprn }) => { - const [showUploadModal, setShowUploadModal] = useState(false); +export const DocumentSection: React.FC = ({ reportType, uprn, files }) => { + const [showUploadModal, setShowUploadModal] = React.useState(false); + const router = useRouter(); + + const latestFile = React.useMemo(() => { + if (!files?.length) return null; + return files.reduce((acc, cur) => { + const accTime = new Date(acc.s3FileUploadTimestamp as any).getTime(); + const curTime = new Date(cur.s3FileUploadTimestamp as any).getTime(); + return curTime > accTime ? cur : acc; + }, files[0]); + }, [files]); + + const formatWhen = (d: string | Date) => + new Intl.DateTimeFormat(undefined, { + year: "numeric", + month: "short", + day: "2-digit", + hour: "2-digit", + minute: "2-digit", + }).format(new Date(d)); const title = documentTypeTitles[reportType]; + const count = files.length; return ( <> @@ -23,7 +45,30 @@ export const DocumentSection: React.FC = ({ reportType, uprn }) => { {title} - + + {latestFile ? ( +
+
+ + View latest file + + + uploaded {formatWhen(latestFile.s3FileUploadTimestamp)} + +
+ + {count} file{count !== 1 && "s"} on record + +
+ ) : ( + No files uploaded yet + )} +
= ({ reportType, uprn }) => { onClick={() => setShowUploadModal(true)} backgroundColor="brandblue" /> - setShowUploadModal(false)} - documentType={reportType} // <- strong ReportType + onClose={() => { + setShowUploadModal(false); + router.refresh(); + }} + documentType={reportType} uprn={uprn} /> diff --git a/src/app/portfolio/[slug]/building-passport/[propertyId]/documents/DocumentsTable.tsx b/src/app/portfolio/[slug]/building-passport/[propertyId]/documents/DocumentsTable.tsx index 9661527d..d81acab3 100644 --- a/src/app/portfolio/[slug]/building-passport/[propertyId]/documents/DocumentsTable.tsx +++ b/src/app/portfolio/[slug]/building-passport/[propertyId]/documents/DocumentsTable.tsx @@ -2,26 +2,60 @@ import React from "react"; import { Table, TableBody, TableRow, TableCell } from "@/app/shadcn_components/ui/table"; import { DocumentSection } from "./DocumentSection"; -import { type ReportType, REPORT_TYPES, documentTypeFileTypes, documentTypeTitles } from "@/app/db/surveyDB/schema/documents"; +import { + type ReportType, + REPORT_TYPES, + dbLabelToReportType, // <-- import the map +} from "@/app/db/surveyDB/schema/documents"; +import type { getUploadedFile } from "@/app/db/surveyDB/schema/surveyDB"; -type Props = { uprn: string }; +type Props = { + uprn: string; + uploadedFilesData: getUploadedFile[]; +}; + +export const DocumentsTable: React.FC = ({ uprn, uploadedFilesData }) => { + const filesByType = React.useMemo(() => { + const map: Partial> = {}; + + for (const file of uploadedFilesData ?? []) { + const uiKey = dbLabelToReportType[file.docType]; // map DB → UI + if (!uiKey) continue; // unknown/legacy type? skip safely + + (map[uiKey] ??= []).push(file); + } + + // newest first within each group + Object.values(map).forEach(arr => + arr!.sort( + (a, b) => + new Date(b.s3FileUploadTimestamp as any).getTime() - + new Date(a.s3FileUploadTimestamp as any).getTime() + ) + ); + + return map; + }, [uploadedFilesData]); -export const DocumentsTable: React.FC = ({ uprn }) => { return ( - {REPORT_TYPES.map((rt) => ( - - - - - - - ))} + {REPORT_TYPES.map((reportType) => { + const filesForType = filesByType[reportType] ?? []; + return ( + + + + + + + ); + })}
); -}; \ No newline at end of file +}; diff --git a/src/app/portfolio/[slug]/building-passport/[propertyId]/documents/page.tsx b/src/app/portfolio/[slug]/building-passport/[propertyId]/documents/page.tsx index d7698701..df910e07 100644 --- a/src/app/portfolio/[slug]/building-passport/[propertyId]/documents/page.tsx +++ b/src/app/portfolio/[slug]/building-passport/[propertyId]/documents/page.tsx @@ -1,8 +1,28 @@ import { getPropertyMeta } from "@/app/portfolio/[slug]/building-passport/[propertyId]/utils"; import { eq } from "drizzle-orm"; import { DocumentsTable } from "./DocumentsTable"; +import { surveyDB } from "@/app/db/surveyDB/connection"; +import { uploaded_files } from "@/app/db/surveyDB/schema/surveyDB"; +import { type getUploadedFiles } from "@/app/db/surveyDB/schema/surveyDB"; +import { EmptyObject } from "react-hook-form"; +export async function fetchDocuments(uprn: number): Promise { + return surveyDB.query.uploaded_files.findMany({ + where: eq(uploaded_files.uprn, String(uprn)), + }); +} + +async function getDocuments( + uprn: number +): Promise< getUploadedFiles> { + const result = surveyDB.query.uploaded_files.findMany({ + where: eq(uploaded_files.uprn, String(uprn)), + }); + + return result; +} + export default async function DocumentsPage( props: { params: Promise<{ slug: string; propertyId: string }>; @@ -16,6 +36,7 @@ export default async function DocumentsPage( } const propertyMeta = await getPropertyMeta(propertyId); + const uploadedFiles = await getDocuments(propertyMeta.uprn); return ( <> @@ -26,6 +47,7 @@ export default async function DocumentsPage(