mirror of
https://github.com/Hestia-Homes/assessment-model.git
synced 2026-06-08 11:37:25 +00:00
Added portfolio page formatting
This commit is contained in:
parent
4ed3572592
commit
bcab685acb
2 changed files with 72 additions and 34 deletions
|
|
@ -3,6 +3,7 @@ import { getPortfolio, getProperties } from "../utils";
|
|||
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 } from "@/app/utils";
|
||||
|
||||
// We enfore caching of data for 60 seconds
|
||||
export const revalidate = 60;
|
||||
|
|
@ -31,6 +32,7 @@ interface SummaryBoxProps {
|
|||
rentalYieldIncrease: number | null;
|
||||
energySavings: number | null;
|
||||
energyCostSavings: number | null;
|
||||
estimatedDuration: number | null;
|
||||
}
|
||||
|
||||
function SummaryBox({
|
||||
|
|
@ -43,12 +45,13 @@ function SummaryBox({
|
|||
rentalYieldIncrease,
|
||||
energySavings,
|
||||
energyCostSavings,
|
||||
estimatedDuration,
|
||||
}: SummaryBoxProps) {
|
||||
function formatMoney(amount: number | null) {
|
||||
if (amount === null) {
|
||||
return "£0";
|
||||
} else {
|
||||
return "£" + amount.toFixed(2).replace(/\d(?=(\d{3})+\.)/g, "$&,");
|
||||
return "£" + formatNumber(amount);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -70,28 +73,55 @@ function SummaryBox({
|
|||
|
||||
function formatCo2(co2: number | null) {
|
||||
if (co2 === null) {
|
||||
return "0 tonnes";
|
||||
return "-";
|
||||
} else {
|
||||
return co2 + " tonnes";
|
||||
return co2.toFixed(1) + " tonnes";
|
||||
}
|
||||
}
|
||||
|
||||
function formatKwh(energy: number | null) {
|
||||
if (energy === null) {
|
||||
return "0 Kwh";
|
||||
return "-";
|
||||
} else {
|
||||
return energy + " Kwh";
|
||||
return formatNumber(energy) + " Kwh";
|
||||
}
|
||||
}
|
||||
|
||||
function convertDaysToWorkingWeeks(days: number | null) {
|
||||
if (days === null) {
|
||||
return "-";
|
||||
}
|
||||
|
||||
const workingDaysPerWeek = 5;
|
||||
|
||||
// Convert days to working weeks
|
||||
const workingWeeks = days / workingDaysPerWeek;
|
||||
|
||||
// Determine the range
|
||||
let lowerBound = Math.floor(workingWeeks);
|
||||
let upperBound = Math.ceil(workingWeeks);
|
||||
|
||||
// Adjust if the fraction is very small, you might not count it as a full extra week
|
||||
if (workingWeeks - lowerBound < 0.2) {
|
||||
upperBound = lowerBound;
|
||||
}
|
||||
|
||||
// Format the output
|
||||
return lowerBound === upperBound
|
||||
? `${lowerBound} weeks`
|
||||
: `${lowerBound}-${upperBound} weeks`;
|
||||
}
|
||||
|
||||
const budgetFormatted = formatBudget(budget);
|
||||
const totalCostFormatted = formatMoney(totalCost);
|
||||
const totalValueIncreaseFormatted = formatMoney(propertyValuationIncrease);
|
||||
const totalWorkHoursFormatted = formatHours(totalWorkHours);
|
||||
const rentalYieldIncreaseFormatted = formatMoney(rentalYieldIncrease);
|
||||
// const rentalYieldIncreaseFormatted = formatMoney(rentalYieldIncrease);
|
||||
const energyCostSavingsFormatted = formatMoney(energyCostSavings);
|
||||
const co2EquivalentSavingsFormatted = formatCo2(co2EquivalentSavings);
|
||||
const energySavingsFormatted = formatKwh(energySavings);
|
||||
const estimatedDurationFormatted =
|
||||
convertDaysToWorkingWeeks(estimatedDuration);
|
||||
|
||||
return (
|
||||
<div className="p-6 bg-white rounded-lg leading-relaxed">
|
||||
|
|
@ -101,7 +131,7 @@ function SummaryBox({
|
|||
<div className="grid grid-cols-1 md:grid-cols-1 gap-6">
|
||||
<div className="p-4 bg-gray-50 rounded-lg">
|
||||
<h3 className="text-lg font-semibold text-gray-700 mb-2">
|
||||
Financials
|
||||
Work Package
|
||||
</h3>
|
||||
<table className="w-full">
|
||||
<tbody>
|
||||
|
|
@ -113,45 +143,28 @@ function SummaryBox({
|
|||
<td className="text-gray-700 ">Total Cost</td>
|
||||
<td className="text-gray-600 text-end">{totalCostFormatted}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td className="text-gray-700 ">Total Value Increase</td>
|
||||
<td className="text-gray-600 text-end">{"-"}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
|
||||
{/* <tr>
|
||||
<td className="text-gray-700 ">Annual rental yield Increase</td>
|
||||
<td className="text-gray-600 text-end">{"-"}</td>
|
||||
</tr>
|
||||
</tr> */}
|
||||
|
||||
<tr>
|
||||
<td className="text-gray-700 ">
|
||||
Annual Energy Bill Savings (per property)
|
||||
</td>
|
||||
<td className="text-gray-700">Estimated Duration</td>
|
||||
<td className="text-gray-600 text-end">
|
||||
{energyCostSavingsFormatted}
|
||||
{estimatedDurationFormatted}
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div className="p-4 bg-gray-50 rounded-lg">
|
||||
<h3 className="text-lg font-semibold text-gray-700 mb-2">
|
||||
Property Data
|
||||
</h3>
|
||||
<table className="w-full">
|
||||
<tbody>
|
||||
|
||||
<tr>
|
||||
<td className="text-gray-700">Total properties</td>
|
||||
<td className="text-gray-600 text-end">{numProperties}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td className="text-gray-700">Total Labour Hours</td>
|
||||
<td className="text-gray-600 text-end">
|
||||
{totalWorkHoursFormatted}
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div className="p-4 bg-gray-50 rounded-lg">
|
||||
{/* Environmental Impact */}
|
||||
<h3 className="text-lg font-semibold text-gray-700 mb-2">
|
||||
Environmental Impact
|
||||
</h3>
|
||||
|
|
@ -178,6 +191,29 @@ function SummaryBox({
|
|||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div className="p-4 bg-gray-50 rounded-lg">
|
||||
{/* Financial Impact table */}
|
||||
<h3 className="text-lg font-semibold text-gray-700 mb-2">
|
||||
Financial Impact
|
||||
</h3>
|
||||
<table className="w-full">
|
||||
<tbody>
|
||||
<tr>
|
||||
<td className="text-gray-700 ">Annual Energy Bill Reduction</td>
|
||||
<td className="text-gray-600 text-end">
|
||||
{energyCostSavingsFormatted}
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td className="text-gray-700 ">Total Value Increase</td>
|
||||
<td className="text-gray-600 text-end">
|
||||
{totalValueIncreaseFormatted}
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
|
@ -202,6 +238,7 @@ export default async function Page({
|
|||
rentalYieldIncrease,
|
||||
energySavings,
|
||||
energyCostSavings,
|
||||
labourDays,
|
||||
} = await getPortfolio(portfolioId);
|
||||
|
||||
// Default limit to 1000 and offset to 0 for now - will handle pagination later
|
||||
|
|
@ -226,6 +263,7 @@ export default async function Page({
|
|||
rentalYieldIncrease={rentalYieldIncrease}
|
||||
energySavings={energySavings}
|
||||
energyCostSavings={energyCostSavings}
|
||||
estimatedDuration={labourDays}
|
||||
/>
|
||||
</div>
|
||||
<div className="col-span-8 bg-white">
|
||||
|
|
|
|||
|
|
@ -78,12 +78,12 @@ export function formatNumber(number: number): string {
|
|||
// Check if the number is smaller and round to 2 decimal places
|
||||
const roundedNumber: number =
|
||||
Math.abs(number) < 1000
|
||||
? Number(number.toFixed(2))
|
||||
? Number(number.toFixed(1))
|
||||
: Number(number.toPrecision(4));
|
||||
|
||||
const formattedNumber: string = (
|
||||
roundedNumber / Math.pow(1000, suffixIndex)
|
||||
).toFixed(2);
|
||||
).toFixed(1);
|
||||
|
||||
return formattedNumber + suffixes[suffixIndex];
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue