diff --git a/src/app/components/portfolio/SummaryBox.tsx b/src/app/components/portfolio/SummaryBox.tsx new file mode 100644 index 00000000..80006664 --- /dev/null +++ b/src/app/components/portfolio/SummaryBox.tsx @@ -0,0 +1,203 @@ +"use client"; +import { useState } from "react"; +import { convertDaysToWorkingWeeks, formatNumber } from "@/app/utils"; + +interface SummaryBoxProps { + scenarios: Array<{ + id: bigint; + name: string; + budget: number | null; + totalCost: number | null; + co2EquivalentSavings: number | null; + totalWorkHours: number | null; + propertyValuationIncrease: number | null; + energySavings: number | null; + energyCostSavings: number | null; + labourDays: number | null; + isDefault: boolean; + }>; + numProperties: number; +} + +function SummaryBox({ scenarios, numProperties }: SummaryBoxProps) { + // Get the default scenario + const defaultScenario = + scenarios.find((scenario) => scenario.isDefault) || scenarios[0]; + + const [selectedScenarioId, setSelectedScenarioId] = useState( + Number(defaultScenario.id) + ); + + const [budgetFormatted, setBudgetFormatted] = useState( + formatBudget(defaultScenario.budget) + ); + const [totalCostFormatted, setTotalCostFormatted] = useState( + formatMoney(defaultScenario.totalCost) + ); + const [totalValueIncreaseFormatted, setTotalValueIncreaseFormatted] = + useState(formatMoney(defaultScenario.propertyValuationIncrease)); + const [energyCostSavingsFormatted, setEnergyCostSavingsFormatted] = useState( + formatMoney(defaultScenario.energyCostSavings) + ); + const [co2EquivalentSavingsFormatted, setCo2EquivalentSavingsFormatted] = + useState(formatCo2(defaultScenario.co2EquivalentSavings)); + const [energySavingsFormatted, setEnergySavingsFormatted] = useState( + formatKwh(defaultScenario.energySavings) + ); + const [estimatedDurationFormatted, setEstimatedDurationFormatted] = useState( + convertDaysToWorkingWeeks(defaultScenario.labourDays) + ); + + const handleScenarioChange = (scenarioId: string) => { + setSelectedScenarioId(Number(scenarioId)); + const selectedScenario = scenarios.find( + (scenario) => Number(scenario.id) === Number(scenarioId) + ); + + if (!selectedScenario) { + return; + } + + setBudgetFormatted(formatBudget(selectedScenario.budget)); + setTotalCostFormatted(formatMoney(selectedScenario.totalCost)); + setTotalValueIncreaseFormatted( + formatMoney(selectedScenario.propertyValuationIncrease) + ); + setEnergyCostSavingsFormatted( + formatMoney(selectedScenario.energyCostSavings) + ); + setCo2EquivalentSavingsFormatted( + formatCo2(selectedScenario.co2EquivalentSavings) + ); + setEnergySavingsFormatted(formatKwh(selectedScenario.energySavings)); + setEstimatedDurationFormatted( + convertDaysToWorkingWeeks(selectedScenario.labourDays) + ); + }; + + function formatMoney(amount: number | null) { + return amount === null ? "£0" : "£" + formatNumber(amount); + } + + function formatBudget(budget: number | null) { + return budget === null ? "Not set" : formatMoney(budget); + } + + function formatHours(hours: number | null) { + return hours === null ? "0 hours" : Math.round(hours) + " hours"; + } + + function formatCo2(co2: number | null) { + return co2 === null ? "-" : co2.toFixed(1) + " tonnes"; + } + + function formatKwh(energy: number | null) { + return energy === null ? "-" : formatNumber(energy) + " kWh"; + } + + return ( +
+

+ Portfolio Summary +

+
+ + +
+
+
+

+ Work Package +

+ + + + + + + + + + + + + + + + + + + +
Total Budget{budgetFormatted}
Total Cost + {totalCostFormatted} +
Estimated Duration + {estimatedDurationFormatted} +
Total properties{numProperties}
+
+
+

+ Environmental Impact +

+ + + + + + + + + + + +
+ Annual{" "} + + CO2 + {" "} + Savings + + {co2EquivalentSavingsFormatted} +
Annual Energy Savings + {energySavingsFormatted} +
+
+
+

+ Financial Impact +

+ + + + + + + + + + + +
Annual Energy Bill Reduction + {energyCostSavingsFormatted} +
Total Value Increase + {totalValueIncreaseFormatted} +
+
+
+
+ ); +} + +export default SummaryBox; diff --git a/src/app/portfolio/[slug]/(portfolio)/page.tsx b/src/app/portfolio/[slug]/(portfolio)/page.tsx index a754ede6..409ecdfc 100644 --- a/src/app/portfolio/[slug]/(portfolio)/page.tsx +++ b/src/app/portfolio/[slug]/(portfolio)/page.tsx @@ -4,6 +4,8 @@ import DataTable from "@/app/portfolio/[slug]/components/propertyTable"; import { columns } from "@/app/portfolio/[slug]/components/propertyTableColumns"; import { PropertyWithRelations } from "@/app/db/schema/property"; import { formatNumber, convertDaysToWorkingWeeks } from "@/app/utils"; +import SummaryBox from "@/app/components/portfolio/SummaryBox"; +import { is } from "cypress/types/bluebird"; // We enfore caching of data for 60 seconds export const revalidate = 60; @@ -22,175 +24,6 @@ function EmptyPropertyState() { ); } -interface SummaryBoxProps { - budget: number | null; - totalCost: number | null; - numProperties: number; - co2EquivalentSavings: number | null; - totalWorkHours: number | null; - propertyValuationIncrease: number | null; - energySavings: number | null; - energyCostSavings: number | null; - estimatedDuration: number | null; -} - -function SummaryBox({ - budget, - totalCost, - numProperties, - co2EquivalentSavings, - totalWorkHours, - propertyValuationIncrease, - energySavings, - energyCostSavings, - estimatedDuration, -}: SummaryBoxProps) { - function formatMoney(amount: number | null) { - if (amount === null) { - return "£0"; - } else { - return "£" + formatNumber(amount); - } - } - - function formatBudget(budget: number | null) { - if (budget === null) { - return "Not set"; - } else { - return formatMoney(budget); - } - } - - function formatHours(hours: number | null) { - if (hours === null) { - return "0 hours"; - } else { - return Math.round(hours) + " hours"; - } - } - - function formatCo2(co2: number | null) { - if (co2 === null) { - return "-"; - } else { - return co2.toFixed(1) + " tonnes"; - } - } - - function formatKwh(energy: number | null) { - if (energy === null) { - return "-"; - } else { - return formatNumber(energy) + " kWh"; - } - } - - const budgetFormatted = formatBudget(budget); - const totalCostFormatted = formatMoney(totalCost); - const totalValueIncreaseFormatted = formatMoney(propertyValuationIncrease); - // const totalWorkHoursFormatted = formatHours(totalWorkHours); - // const rentalYieldIncreaseFormatted = formatMoney(rentalYieldIncrease); - const energyCostSavingsFormatted = formatMoney(energyCostSavings); - const co2EquivalentSavingsFormatted = formatCo2(co2EquivalentSavings); - const energySavingsFormatted = formatKwh(energySavings); - const estimatedDurationFormatted = - convertDaysToWorkingWeeks(estimatedDuration); - - return ( -
-

- Portfolio Summary -

-
-
-

- Work Package -

- - - - - - - - - - - - - - - - - - - - - -
Total Budget{budgetFormatted}
Total Cost - {totalCostFormatted} -
Estimated Duration - {estimatedDurationFormatted} -
Total properties{numProperties}
-
-
- {/* Environmental Impact */} -

- Environmental Impact -

- - - - - - - - - - - -
- Annual{" "} - - CO2 - {" "} - Savings - - {co2EquivalentSavingsFormatted} -
Annual Energy Savings - {energySavingsFormatted} -
-
-
- {/* Financial Impact table */} -

- Financial Impact -

- - - - - - - - - - - - -
- Annual Energy Bill Reduction - - {energyCostSavingsFormatted} -
Total Value Increase - {totalValueIncreaseFormatted} -
-
-
-
- ); -} - export default async function Page({ params, searchParams, @@ -201,16 +34,43 @@ export default async function Page({ // This page is served from the server so we can make calls to the database const portfolioId = params.slug; - const portfolio = await getPortfolio(portfolioId); - const portfolioPerformance = await getPortfolioPerformance(portfolioId); - const defaultPerformance = portfolioPerformance.find( - (perf) => perf.isDefault - ); + let portfolioPerformance = await getPortfolioPerformance(portfolioId); + let scenarios; - const portfolioData = defaultPerformance || portfolio; + if (portfolioPerformance.length > 0) { + scenarios = portfolioPerformance.map((performance) => ({ + id: BigInt(performance.id), + name: performance.name || "Default Scenario", + budget: performance.budget, + totalCost: performance.cost, + co2EquivalentSavings: performance.co2EquivalentSavings, + totalWorkHours: performance.totalWorkHours, + propertyValuationIncrease: performance.propertyValuationIncrease, + energySavings: performance.energySavings, + energyCostSavings: performance.energyCostSavings, + labourDays: performance.labourDays, + isDefault: performance.isDefault, + })); + } else { + const portfolio = await getPortfolio(portfolioId); + scenarios = [ + { + id: BigInt(0), + name: "Default", + budget: portfolio.budget, + totalCost: portfolio.cost, + co2EquivalentSavings: portfolio.co2EquivalentSavings, + totalWorkHours: portfolio.totalWorkHours, + propertyValuationIncrease: portfolio.propertyValuationIncrease, + energySavings: portfolio.energySavings, + energyCostSavings: portfolio.energyCostSavings, + labourDays: portfolio.labourDays, + isDefault: true, + }, + ]; + } - // Default limit to 1000 and offset to 0 for now - will handle pagination later const properties: PropertyWithRelations[] = await getProperties( portfolioId, 1000, @@ -223,17 +83,8 @@ export default async function Page({