From e6b0b702700139ac162f84857db0f8eeb7bb6e93 Mon Sep 17 00:00:00 2001 From: Khalim Conn-Kowlessar Date: Tue, 23 Sep 2025 17:21:28 +0000 Subject: [PATCH] added decent homes tab button --- .../components/building-passport/Toolbar.tsx | 36 +++++---- src/app/db/surveyDB/schema/documents.ts | 76 ++++++++++++------- src/app/db/surveyDB/schema/surveyDB.ts | 26 ++++--- .../portfolio/[slug]/(portfolio)/layout.tsx | 12 ++- .../[propertyId]/assessment/page.tsx | 23 ------ .../[propertyId]/documents/DocumentsTable.tsx | 22 ++++-- .../[propertyId]/documents/page.tsx | 20 ++--- .../building-passport/[propertyId]/layout.tsx | 25 +++--- 8 files changed, 129 insertions(+), 111 deletions(-) diff --git a/src/app/components/building-passport/Toolbar.tsx b/src/app/components/building-passport/Toolbar.tsx index 3ff861cf..b0759e4e 100644 --- a/src/app/components/building-passport/Toolbar.tsx +++ b/src/app/components/building-passport/Toolbar.tsx @@ -7,7 +7,7 @@ import { WrenchScrewdriverIcon, SunIcon, CircleStackIcon, - BoltIcon, + HeartIcon, } from "@heroicons/react/24/outline"; import { NavigationMenu, @@ -21,7 +21,7 @@ import { getUploadedFile } from "@/app/db/surveyDB/schema/surveyDB"; interface ToolbarProps { propertyId: string; portfolioId: string; - conditionReport: getUploadedFile; + decentHomes: getUploadedFile; } const navigationMenuTriggerStyle = cva( @@ -55,7 +55,11 @@ const navigationMenuTriggerStyle = cva( ].join(" ") ); -export function Toolbar({ propertyId, portfolioId, conditionReport }: ToolbarProps) { +export function Toolbar({ + propertyId, + portfolioId, + decentHomes, +}: ToolbarProps) { function handleClickSettings() { console.log("Settings were clicked, implement me"); } @@ -70,16 +74,6 @@ export function Toolbar({ propertyId, portfolioId, conditionReport }: ToolbarPro ); - // const energyAssessmentsReportButton = ( - // - // - // Energy Assessment - // - // ); - const documentsButton = ( ); + const decentHomesButton = ( + + + Decent Homes + + ); + return ( {preAssessmentReportButton} + {/* We only show decent homes button if decent homes is not an empty object */} + {Object.keys(decentHomes).length > 0 && + decentHomes.uprn && + decentHomesButton} {solarAnalysisButton} {recommendationsButton} {documentsButton} - {/* {energyAssessmentsReportButton} */} + = { -// quidos_presite_note: "RdSAP Summary Report", -// charted_surveyor_report: "Chartered Surveyor Report", -// u_value_calculator_report: "U-Value Calculator Report", -// overwriting_u_value_declaration_form: "Overwriting U-Value Declaration Form", + // quidos_presite_note: "RdSAP Summary Report", + // charted_surveyor_report: "Chartered Surveyor Report", + // u_value_calculator_report: "U-Value Calculator Report", + // overwriting_u_value_declaration_form: "Overwriting U-Value Declaration Form", osmosis_condition_pas_2035_report: "Osmosis Condition Report (PAS 2035)", -// warm_homes_condition_pas_2035_report: "Warm Homes PAS 2035 Report", -// energy_performance_report_with_data: "EPC Report With Data", + // warm_homes_condition_pas_2035_report: "Warm Homes PAS 2035 Report", + // energy_performance_report_with_data: "EPC Report With Data", energy_performance_report_summary_information: "EPC Summary Report", lodgement_xml_needed_for_lodgement_to_like_trademark: "LIG XML", reduce_xml_needed_to_generate_full_sap_xml: "RdSAP XML", full_xml_needed_for_co_ordination: "Full SAP XML", -// floor_plan: "Floor Plan", -// occupancy_assessment: "Occupancy Assessment", + decent_homes_summary: "Decent Homes Summary", + decent_homes_property_meta: "Decent Homes Property Meta", + // decent_homes_energy_performance_report: "Decent Homes Energy Performance Report", + // decent_homes_energy_performance_report_summary_information: + // "Decent Homes Energy Performance Report Summary Information", + // floor_plan: "Floor Plan", + // occupancy_assessment: "Occupancy Assessment", }; // Map reportType → accepted file extensions -export const documentTypeFileTypes: Record = { -// quidos_presite_note: ".pdf", -// charted_surveyor_report: ".pdf", -// u_value_calculator_report: ".pdf", -// overwriting_u_value_declaration_form: ".pdf", +export const documentTypeFileTypes: Record< + ReportType, + ".pdf" | ".xml" | ".xml,.pdf" | ".json" +> = { + // quidos_presite_note: ".pdf", + // charted_surveyor_report: ".pdf", + // u_value_calculator_report: ".pdf", + // overwriting_u_value_declaration_form: ".pdf", osmosis_condition_pas_2035_report: ".pdf", -// warm_homes_condition_pas_2035_report: ".pdf", -// energy_performance_report_with_data: ".pdf", + // warm_homes_condition_pas_2035_report: ".pdf", + // energy_performance_report_with_data: ".pdf", energy_performance_report_summary_information: ".pdf", lodgement_xml_needed_for_lodgement_to_like_trademark: ".xml", reduce_xml_needed_to_generate_full_sap_xml: ".xml", full_xml_needed_for_co_ordination: ".xml", -// floor_plan: ".pdf", -// occupancy_assessment: ".pdf", + decent_homes_property_meta: ".json", + decent_homes_summary: ".json", + // floor_plan: ".pdf", + // occupancy_assessment: ".pdf", }; export const ReportTypeSchema = z.enum(REPORT_TYPES); // Map UI value -> DB enum NAME export const reportTypeToDbLabel: Record = { osmosis_condition_pas_2035_report: "ECO_CONDITION_REPORT", - energy_performance_report_summary_information: "ENERGY_PERFORMANCE_REPORT_SUMMARY_INFORMATION", + energy_performance_report_summary_information: + "ENERGY_PERFORMANCE_REPORT_SUMMARY_INFORMATION", lodgement_xml_needed_for_lodgement_to_like_trademark: "LIG_XML", reduce_xml_needed_to_generate_full_sap_xml: "RDSAP_XML", full_xml_needed_for_co_ordination: "FULLSAP_XML", + decent_homes_summary: "DECENT_HOMES_SUMMARY", + decent_homes_property_meta: "DECENT_HOMES_PROPERTY_META", }; // Optional reverse map (for reading from API): export const dbLabelToReportType: Record = { ECO_CONDITION_REPORT: "osmosis_condition_pas_2035_report", - ENERGY_PERFORMANCE_REPORT_SUMMARY_INFORMATION: "energy_performance_report_summary_information", + ENERGY_PERFORMANCE_REPORT_SUMMARY_INFORMATION: + "energy_performance_report_summary_information", LIG_XML: "lodgement_xml_needed_for_lodgement_to_like_trademark", RDSAP_XML: "reduce_xml_needed_to_generate_full_sap_xml", FULLSAP_XML: "full_xml_needed_for_co_ordination", -}; \ No newline at end of file + DECENT_HOMES_SUMMARY: "decent_homes_summary", + DECENT_HOMES_PROPERTY_META: "decent_homes_property_meta", +}; diff --git a/src/app/db/surveyDB/schema/surveyDB.ts b/src/app/db/surveyDB/schema/surveyDB.ts index 2f7c92de..65ea00bd 100644 --- a/src/app/db/surveyDB/schema/surveyDB.ts +++ b/src/app/db/surveyDB/schema/surveyDB.ts @@ -1,13 +1,15 @@ 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", - "ENERGY_PERFORMANCE_REPORT_SUMMARY_INFORMATION", - "LIG_XML", - "RDSAP_XML", - "FULLSAP_XML", + "ECO_CONDITION_REPORT", + "ENERGY_PERFORMANCE_REPORT_SUMMARY_INFORMATION", + "LIG_XML", + "RDSAP_XML", + "FULLSAP_XML", + "DECENT_HOMES_RAW_DATA", + "DECENT_HOMES_PROPERTY_META", + "DECENT_HOMES_SUMMARY", ] as const; export const docTypeEnum = pgEnum("reporttype", DB_REPORT_TYPES); @@ -18,14 +20,18 @@ export const uploadedFiles = pgTable("uploaded_files", { s3JsonUri: text("s3_json_uri"), s3FileUri: text("s3_file_uri").notNull(), - docType: docTypeEnum("doc_type").notNull(), // enum used here ✅ + docType: docTypeEnum("doc_type").notNull(), // enum used here ✅ - s3FileUploadTimestamp: timestamp("s3_file_upload_timestamp", { withTimezone: true }).notNull(), - s3JsonUploadTimestamp: timestamp("s3_json_upload_timestamp", { withTimezone: true }), + s3FileUploadTimestamp: timestamp("s3_file_upload_timestamp", { + withTimezone: true, + }).notNull(), + s3JsonUploadTimestamp: timestamp("s3_json_upload_timestamp", { + withTimezone: true, + }), uprn: text("uprn").notNull(), }); -export type getUploadedFile = typeof uploadedFiles.$inferSelect +export type getUploadedFile = typeof uploadedFiles.$inferSelect; export type getUploadedFiles = getUploadedFile[]; diff --git a/src/app/portfolio/[slug]/(portfolio)/layout.tsx b/src/app/portfolio/[slug]/(portfolio)/layout.tsx index 136fdb01..862f5e27 100644 --- a/src/app/portfolio/[slug]/(portfolio)/layout.tsx +++ b/src/app/portfolio/[slug]/(portfolio)/layout.tsx @@ -1,17 +1,15 @@ import { Toolbar } from "@/app/components/portfolio/Toolbar"; import { getPortfolio, getPortfolioScenarios } from "../utils"; -export default async function PortfolioLayout( - props: { - children: React.ReactNode; - params: Promise<{ slug: string; propertyId: string }>; - } -) { +export default async function PortfolioLayout(props: { + children: React.ReactNode; + params: Promise<{ slug: string; propertyId: string }>; +}) { const params = await props.params; const { // will be a page or nested layout - children + children, } = props; const portfolioId = params.slug; diff --git a/src/app/portfolio/[slug]/building-passport/[propertyId]/assessment/page.tsx b/src/app/portfolio/[slug]/building-passport/[propertyId]/assessment/page.tsx index 6fe81848..084954b6 100644 --- a/src/app/portfolio/[slug]/building-passport/[propertyId]/assessment/page.tsx +++ b/src/app/portfolio/[slug]/building-passport/[propertyId]/assessment/page.tsx @@ -1,7 +1,6 @@ import EpcCard from "@/app/components/building-passport/EpcCard"; import FeatureTable from "@/app/components/building-passport/FeatureTable"; import { - ConditionReportData, PropertyDetailsEpc, PropertyDetailsSpatial, PropertyMeta, @@ -23,7 +22,6 @@ import { getDocument, getEnergyAssessmentFromS3, } from "../utils"; -import ConditionReport from "@/app/portfolio/[slug]/building-passport/[propertyId]/assessment/ConditionReport"; interface PropertyDetailsCardProps { conditionReportData: PropertyDetailsEpc; @@ -133,18 +131,6 @@ export default async function PreAssessmentReport(props: { conditionReportData, propertyMeta.propertyType ); - const conditionReportMeta = await getDocument({ - uprn: String(propertyMeta.uprn), - documentType: "ECO_CONDITION_REPORT", - }); - let conditionReport = { rooms: {} }; - if (conditionReportMeta && conditionReportMeta.s3JsonUri) { - conditionReport = await getEnergyAssessmentFromS3( - conditionReportMeta.s3JsonUri - ); - } - - console.log("conditionReport", conditionReport); const nonIntrusiveSurvey = await getNonIntrusiveSurvey(propertyMeta.uprn); @@ -179,15 +165,6 @@ export default async function PreAssessmentReport(props: { - {Object.keys(conditionReportMeta).length > 0 && ( - - )} - {nonIntrusiveSurvey && (
Non-Intrusive Survey
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 53c9cd94..a6956fc9 100644 --- a/src/app/portfolio/[slug]/building-passport/[propertyId]/documents/DocumentsTable.tsx +++ b/src/app/portfolio/[slug]/building-passport/[propertyId]/documents/DocumentsTable.tsx @@ -1,11 +1,16 @@ "use client"; import React from "react"; -import { Table, TableBody, TableRow, TableCell } from "@/app/shadcn_components/ui/table"; +import { + Table, + TableBody, + TableRow, + TableCell, +} from "@/app/shadcn_components/ui/table"; import { DocumentSection } from "./DocumentSection"; import { type ReportType, REPORT_TYPES, - dbLabelToReportType, // <-- import the map + dbLabelToReportType, // <-- import the map } from "@/app/db/surveyDB/schema/documents"; import type { getUploadedFile } from "@/app/db/surveyDB/schema/surveyDB"; @@ -14,7 +19,10 @@ type Props = { uploadedFilesData: getUploadedFile[]; }; -export const DocumentsTable: React.FC = ({ uprn, uploadedFilesData }) => { +export const DocumentsTable: React.FC = ({ + uprn, + uploadedFilesData, +}) => { const filesByType = React.useMemo(() => { const map: Partial> = {}; @@ -26,7 +34,7 @@ export const DocumentsTable: React.FC = ({ uprn, uploadedFilesData }) => } // newest first within each group - Object.values(map).forEach(arr => + Object.values(map).forEach((arr) => arr!.sort( (a, b) => new Date(b.s3FileUploadTimestamp as any).getTime() - @@ -37,18 +45,20 @@ export const DocumentsTable: React.FC = ({ uprn, uploadedFilesData }) => return map; }, [uploadedFilesData]); + console.log("filesByType", filesByType); + return ( {REPORT_TYPES.map((reportType) => { const filesForType = filesByType[reportType] ?? []; - console.log("reportType", reportType) + console.log("reportType", reportType); return ( 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 1ded30a0..799142af 100644 --- a/src/app/portfolio/[slug]/building-passport/[propertyId]/documents/page.tsx +++ b/src/app/portfolio/[slug]/building-passport/[propertyId]/documents/page.tsx @@ -5,22 +5,17 @@ import { surveyDB } from "@/app/db/surveyDB/connection"; import { uploadedFiles } from "@/app/db/surveyDB/schema/surveyDB"; import { type getUploadedFiles } from "@/app/db/surveyDB/schema/surveyDB"; - -async function getDocuments( - uprn: number -): Promise< getUploadedFiles> { +async function getDocuments(uprn: number): Promise { const result = surveyDB.query.uploadedFiles.findMany({ where: eq(uploadedFiles.uprn, String(uprn)), }); - + return result; } -export default async function DocumentsPage( - props: { - params: Promise<{ slug: string; propertyId: string }>; - } -) { +export default async function DocumentsPage(props: { + params: Promise<{ slug: string; propertyId: string }>; +}) { const params = await props.params; // Get the property UPRN const propertyId = params.propertyId; @@ -31,6 +26,8 @@ export default async function DocumentsPage( const propertyMeta = await getPropertyMeta(propertyId); const uploadedFiles = await getDocuments(propertyMeta.uprn); + console.log("Uploaded files:", uploadedFiles); + return ( <>
@@ -38,7 +35,7 @@ export default async function DocumentsPage( Core Survey Documents
- @@ -51,4 +48,3 @@ export default async function DocumentsPage( ); } - diff --git a/src/app/portfolio/[slug]/building-passport/[propertyId]/layout.tsx b/src/app/portfolio/[slug]/building-passport/[propertyId]/layout.tsx index 4a313f1d..5da4b86b 100644 --- a/src/app/portfolio/[slug]/building-passport/[propertyId]/layout.tsx +++ b/src/app/portfolio/[slug]/building-passport/[propertyId]/layout.tsx @@ -12,17 +12,15 @@ function EstimatedDataNotification() { ); } -export default async function DashboardLayout( - props: { - children: React.ReactNode; - params: Promise<{ slug: string; propertyId: string }>; - } -) { +export default async function DashboardLayout(props: { + children: React.ReactNode; + params: Promise<{ slug: string; propertyId: string }>; +}) { const params = await props.params; const { // will be a page or nested layout - children + children, } = props; const propertyId = params.propertyId ?? ""; @@ -32,9 +30,10 @@ export default async function DashboardLayout( const propertyMeta = await getPropertyMeta(params.propertyId); // We check if we have an uploaded condition report and if so, we show the condition tab. Otherwise, we // don't show it - const conditionReport = await getDocument( - { uprn: String(propertyMeta.uprn), documentType: "ECO_CONDITION_REPORT" } - ); + const decentHomes = await getDocument({ + uprn: String(propertyMeta.uprn), + documentType: "DECENT_HOMES_SUMMARY", + }); if (!propertyId && propertyId !== "0") { throw Error("Invalid propertyId"); @@ -58,7 +57,11 @@ export default async function DashboardLayout(

{propertyMeta.postcode}

- +
{propertyMeta.detailsEpc.estimated && } {children}