diff --git a/src/app/portfolio/[slug]/(portfolio)/your-projects/live/PropertyDocumentsContent.tsx b/src/app/portfolio/[slug]/(portfolio)/your-projects/live/PropertyDocumentsContent.tsx index 102c2fb5..f8ff6d59 100644 --- a/src/app/portfolio/[slug]/(portfolio)/your-projects/live/PropertyDocumentsContent.tsx +++ b/src/app/portfolio/[slug]/(portfolio)/your-projects/live/PropertyDocumentsContent.tsx @@ -16,7 +16,7 @@ import { } from "lucide-react"; import type { PropertyDocument, DocStatus } from "./types"; import { EXPECTED_RETROFIT_ASSESSMENT_DOC_TYPES } from "./types"; -import { splitDocumentsByType, getMissingRetrofitTypes, getUnassignedInstallDocs } from "./propertyDocuments"; +import { splitDocumentsByType, getMissingSurveyDocTypes, getUnassignedInstallDocs } from "./propertyDocuments"; import ContractorUploadModal from "./ContractorUploadModal"; import type { ClassifiedDeal, PortfolioCapabilityType } from "./types"; @@ -59,6 +59,9 @@ export const DOC_TYPE_LABELS: Record = { installer_qualifications: "Installer Qualifications", installer_feedback: "Installer Feedback", contractor_other: "Other", + improvement_option_evaluation: "Improvement Option Evaluation", + medium_term_improvement_plan: "Medium Term Improvement Plan", + retrofit_design_doc: "Retrofit Design Document" }; function formatDocDate(iso: string): string { @@ -172,8 +175,8 @@ export default function PropertyDocumentsContent({ return next; }); - const { retrofitDocs, installDocs } = splitDocumentsByType(documents); - const missingRetrofitTypes = getMissingRetrofitTypes(retrofitDocs); + const { docs: surveyDocs, coordinationDocs, designDocs, installDocs } = splitDocumentsByType(documents); + const missingSurveyDocTypes = getMissingSurveyDocTypes(surveyDocs); const hasDocuments = documents.length > 0; const isContractor = userCapability?.includes("contractor") ?? false; @@ -232,9 +235,9 @@ export default function PropertyDocumentsContent({

- Missing Documents ({missingRetrofitTypes.length}) + Missing Documents ({missingSurveyDocTypes.length})

- {missingRetrofitTypes.map((t) => ( + {missingSurveyDocTypes.map((t) => (
{/* Retrofit Assessment */} - +

Retrofit Assessment Documents

- {retrofitDocs.length > 0 ? ( + {surveyDocs.length > 0 ? (
- {retrofitDocs.map((doc) => ( + {surveyDocs.map((doc) => ( ))}
) : (

None uploaded yet.

)} - {missingRetrofitTypes.length > 0 && ( + {missingSurveyDocTypes.length > 0 && (

- Missing ({missingRetrofitTypes.length}) + Missing ({missingSurveyDocTypes.length})

- {missingRetrofitTypes.map((t) => ( + {missingSurveyDocTypes.map((t) => (
+ {/* Coordination Documents */} + +

+ Coordination Documents +

+ {coordinationDocs.length > 0 ? ( +
+ {coordinationDocs.map((doc) => ( + + ))} +
+ ) : ( +

None uploaded yet.

+ )} +
+ + {/* Design Documents */} + +

+ Design Documents +

+ {designDocs.length > 0 ? ( +
+ {designDocs.map((doc) => ( + + ))} +
+ ) : ( +

None uploaded yet.

+ )} +
+ + + {/* Install Documents */}

diff --git a/src/app/portfolio/[slug]/(portfolio)/your-projects/live/docStatus.ts b/src/app/portfolio/[slug]/(portfolio)/your-projects/live/docStatus.ts index 1bb7960d..9472b88b 100644 --- a/src/app/portfolio/[slug]/(portfolio)/your-projects/live/docStatus.ts +++ b/src/app/portfolio/[slug]/(portfolio)/your-projects/live/docStatus.ts @@ -93,7 +93,7 @@ export function computeDocStatusMap( approved.length > 0 ? approved : (deal.proposedMeasures ?? "") - .split(",") + .split(/[,;]/) .map((m) => m.trim()) .filter(Boolean); measuresByDealId.set(deal.dealId, measures); diff --git a/src/app/portfolio/[slug]/(portfolio)/your-projects/live/propertyDocuments.test.ts b/src/app/portfolio/[slug]/(portfolio)/your-projects/live/propertyDocuments.test.ts index c81eb93b..76ba0136 100644 --- a/src/app/portfolio/[slug]/(portfolio)/your-projects/live/propertyDocuments.test.ts +++ b/src/app/portfolio/[slug]/(portfolio)/your-projects/live/propertyDocuments.test.ts @@ -1,7 +1,7 @@ import { describe, it, expect } from "vitest"; import { splitDocumentsByType, - getMissingRetrofitTypes, + getMissingSurveyDocTypes, getUnassignedInstallDocs, } from "./propertyDocuments"; import type { PropertyDocument, MeasureDocProgress } from "./types"; @@ -35,21 +35,21 @@ function makeMeasureProgress(overrides: Partial = {}): Measu describe("splitDocumentsByType", () => { it("puts survey doc types in retrofitDocs", () => { const doc = makeDoc({ docType: "photo_pack" }); - const { retrofitDocs, installDocs } = splitDocumentsByType([doc]); + const { docs: retrofitDocs, installDocs } = splitDocumentsByType([doc]); expect(retrofitDocs).toHaveLength(1); expect(installDocs).toHaveLength(0); }); it("puts install doc types in installDocs", () => { const doc = makeDoc({ docType: "pre_photo" }); - const { retrofitDocs, installDocs } = splitDocumentsByType([doc]); + const { docs: retrofitDocs, installDocs } = splitDocumentsByType([doc]); expect(retrofitDocs).toHaveLength(0); expect(installDocs).toHaveLength(1); }); it("includes optional ecmk types in retrofitDocs", () => { const doc = makeDoc({ docType: "ecmk_site_note" }); - const { retrofitDocs } = splitDocumentsByType([doc]); + const { docs: retrofitDocs } = splitDocumentsByType([doc]); expect(retrofitDocs).toHaveLength(1); }); @@ -60,13 +60,13 @@ describe("splitDocumentsByType", () => { makeDoc({ id: "3", docType: "site_note" }), makeDoc({ id: "4", docType: "post_photo" }), ]; - const { retrofitDocs, installDocs } = splitDocumentsByType(docs); + const { docs: retrofitDocs, installDocs } = splitDocumentsByType(docs); expect(retrofitDocs).toHaveLength(2); expect(installDocs).toHaveLength(2); }); it("returns empty arrays for empty input", () => { - const { retrofitDocs, installDocs } = splitDocumentsByType([]); + const { docs: retrofitDocs, installDocs } = splitDocumentsByType([]); expect(retrofitDocs).toHaveLength(0); expect(installDocs).toHaveLength(0); }); @@ -74,15 +74,15 @@ describe("splitDocumentsByType", () => { describe("getMissingRetrofitTypes", () => { it("returns all mandatory types when no docs uploaded", () => { - const missing = getMissingRetrofitTypes([]); - expect(missing).toHaveLength(9); + const missing = getMissingSurveyDocTypes([]); + expect(missing).toHaveLength(8); }); it("excludes types that have been uploaded", () => { const uploaded = [makeDoc({ docType: "photo_pack" })]; - const missing = getMissingRetrofitTypes(uploaded); + const missing = getMissingSurveyDocTypes(uploaded); expect(missing).not.toContain("photo_pack"); - expect(missing).toHaveLength(8); + expect(missing).toHaveLength(7); }); it("returns empty array when all mandatory types uploaded", () => { @@ -91,14 +91,14 @@ describe("getMissingRetrofitTypes", () => { "pas_2023_condition", "pas_significance", "par_photo_pack", "pas_2023_property", "pas_2023_occupancy", ].map((docType, i) => makeDoc({ id: String(i), docType })); - expect(getMissingRetrofitTypes(uploaded)).toHaveLength(0); + expect(getMissingSurveyDocTypes(uploaded)).toHaveLength(0); }); it("does not count ecmk types as mandatory", () => { const uploaded = [makeDoc({ docType: "ecmk_site_note" })]; - const missing = getMissingRetrofitTypes(uploaded); + const missing = getMissingSurveyDocTypes(uploaded); expect(missing).not.toContain("ecmk_site_note"); - expect(missing).toHaveLength(9); + expect(missing).toHaveLength(8); }); }); diff --git a/src/app/portfolio/[slug]/(portfolio)/your-projects/live/propertyDocuments.ts b/src/app/portfolio/[slug]/(portfolio)/your-projects/live/propertyDocuments.ts index 65a5e9e5..e9ebf415 100644 --- a/src/app/portfolio/[slug]/(portfolio)/your-projects/live/propertyDocuments.ts +++ b/src/app/portfolio/[slug]/(portfolio)/your-projects/live/propertyDocuments.ts @@ -1,21 +1,32 @@ import { SURVEY_ALL_DOC_TYPES, EXPECTED_RETROFIT_ASSESSMENT_DOC_TYPES, + COORDINATION_DOC_TYPES, + DESIGN_DOC_TYPES, } from "./types"; import type { PropertyDocument, MeasureDocProgress } from "./types"; export function splitDocumentsByType(docs: PropertyDocument[]): { - retrofitDocs: PropertyDocument[]; + docs: PropertyDocument[]; + coordinationDocs: PropertyDocument[]; + designDocs: PropertyDocument[]; installDocs: PropertyDocument[]; } { return { - retrofitDocs: docs.filter((d) => SURVEY_ALL_DOC_TYPES.has(d.docType)), - installDocs: docs.filter((d) => !SURVEY_ALL_DOC_TYPES.has(d.docType)), + docs: docs.filter((d) => SURVEY_ALL_DOC_TYPES.has(d.docType)), + coordinationDocs: docs.filter((d) => COORDINATION_DOC_TYPES.has(d.docType)), + designDocs: docs.filter((d) => DESIGN_DOC_TYPES.has(d.docType)), + installDocs: docs.filter( + (d) => + !SURVEY_ALL_DOC_TYPES.has(d.docType) && + !COORDINATION_DOC_TYPES.has(d.docType) && + !DESIGN_DOC_TYPES.has(d.docType), + ), }; } -export function getMissingRetrofitTypes(retrofitDocs: PropertyDocument[]): string[] { - const present = new Set(retrofitDocs.map((d) => d.docType)); +export function getMissingSurveyDocTypes(surveyDocs: PropertyDocument[]): string[] { + const present = new Set(surveyDocs.map((d) => d.docType)); return EXPECTED_RETROFIT_ASSESSMENT_DOC_TYPES.filter((t) => !present.has(t)); } diff --git a/src/app/portfolio/[slug]/(portfolio)/your-projects/live/types.ts b/src/app/portfolio/[slug]/(portfolio)/your-projects/live/types.ts index e1be10c1..7f19cd2e 100644 --- a/src/app/portfolio/[slug]/(portfolio)/your-projects/live/types.ts +++ b/src/app/portfolio/[slug]/(portfolio)/your-projects/live/types.ts @@ -239,7 +239,6 @@ export const EXPECTED_RETROFIT_ASSESSMENT_DOC_TYPES = [ "rd_sap_site_note", "pas_2023_ventilation", "pas_2023_condition", - "pas_significance", "par_photo_pack", "pas_2023_property", "pas_2023_occupancy", @@ -251,6 +250,18 @@ export const SURVEY_ALL_DOC_TYPES = new Set([ "ecmk_site_note", "ecmk_rd_sap_site_note", "ecmk_survey_xml", + "pas_significance", +]); + +// Coordination doc types +export const COORDINATION_DOC_TYPES = new Set([ + "improvement_option_evaluation", + "medium_term_improvement_plan" +]); + +// Design doc types +export const DESIGN_DOC_TYPES = new Set([ + "retrofit_design_doc" ]); // Per-measure document upload progress @@ -267,7 +278,7 @@ export type DocStatus = { // Retrofit assessment docs presentSurveyTypes: string[]; hasSurveyDocs: boolean; - isSurveyComplete: boolean; // all 9 EXPECTED_RETROFIT_ASSESSMENT_DOC_TYPES present (ecmk not counted) + isSurveyComplete: boolean; // all 8 EXPECTED_RETROFIT_ASSESSMENT_DOC_TYPES present (ecmk not counted) // Install docs hasInstallDocs: boolean; installStatus: "none" | "partial" | "hasDocs" | "all";