Skip to content

Commit

Permalink
feat: tenure cost per month (#269)
Browse files Browse the repository at this point in the history
* wip initial cards

* wip add data

* fixed freehold color

* wip second bar

* fixed data format and color

* fix text

* fix radius

* fix background color

* add white labels

* removed chartconfig as not used anywhere

* delete comments

* fix props

* fix error

* delete comment

---------

Co-authored-by: Gabriele Granello <gabriele@opensystemslab.io>
  • Loading branch information
gabrielegranello and Gabriele Granello authored Jan 17, 2025
1 parent 3c1faa8 commit cb5cc91
Show file tree
Hide file tree
Showing 6 changed files with 206 additions and 9 deletions.
26 changes: 26 additions & 0 deletions app/components/Dashboard/Cards/HowMuchPerMonth.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import GraphCard from "../../ui/GraphCard";
import TenureComparisonWrapper from "../../graphs/TenureComparisonWrapper";
import { Drawer } from "../../ui/Drawer";
import { DashboardProps } from "../../ui/Dashboard";

type ProcessedDataOnly = Pick<DashboardProps, "processedData">;

export const HowMuchPerMonth: React.FC<ProcessedDataOnly> = ({
processedData,
}) => {
return (
<GraphCard
title="How much would it cost every month?"
subtitle="Monthly cost of housing, not including energy bills."
>
<div className="flex flex-col h-full w-3/4 justify-between">
<TenureComparisonWrapper household={processedData} />
<Drawer
buttonTitle="Find out more about how we estimated these"
title="How we estimated these figures"
description="Lorem ipsum dolor sit amet consectetur adipisicing elit. Illum minus eligendi fugit nulla officia dolor inventore nemo ex quo quia, laborum qui ratione aperiam, pariatur explicabo ipsum culpa impedit ad!"
/>
</div>
</GraphCard>
);
};
103 changes: 103 additions & 0 deletions app/components/graphs/TenureComparisonBarChart.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
"use client";

import React from "react";
import { Bar, BarChart, CartesianGrid, XAxis, LabelList } from "recharts";
import { Card, CardContent, CardHeader } from "@/components/ui/card";
import {
ChartContainer,
ChartLegend,
ChartLegendContent,
ChartTooltip,
ChartTooltipContent,
} from "@/components/ui/chart";
import { formatValue } from "@/app/lib/format";

type DataInput = {
category: string;
marketPurchase: number;
marketRent: number;
socialRent: number;
fairholdLandPurchase: number;
fairholdLandRent: number;
affordabilityMonthly: number;
[key: string]: string | number;
};

interface StackedBarChartProps {
data: DataInput[];
}

const TenureComparisonBarChart: React.FC<StackedBarChartProps> = ({ data }) => {
const chartData = [
{
tenure: "Freehold",
land: data[0].marketPurchase,
house: data[1].marketPurchase,
monthly: data[0].marketPurchase + data[1].marketPurchase,
fill: "rgb(var(--freehold-land-color-rgb))",
},
{
tenure: "Private Rent",
land: data[0].marketRent,
house: data[1].marketRent,
monthly: data[0].marketRent + data[1].marketRent,
fill: "rgb(var(--private-rent-color-rgb))",
},

{
tenure: "Fairhold - Land Purchase",
land: data[0].fairholdLandPurchase,
house: data[1].fairholdLandPurchase,
monthly: data[0].fairholdLandPurchase + data[1].fairholdLandPurchase,
fill: "rgb(var(--fairhold-land-color-rgb))",
},
{
tenure: "Fairhold - Land Rent",
land: data[0].fairholdLandRent,
house: data[1].fairholdLandRent,
monthly: data[0].fairholdLandRent + data[1].fairholdLandRent,
fill: "rgb(var(--fairhold-house-color-rgb))",
},

{
tenure: "Social Rent",
land: data[0].socialRent,
house: data[1].socialRent,
monthly: data[0].socialRent + data[1].socialRent,
fill: "rgb(var(--social-rent-color-rgb))",
},
];

return (
<Card>
<CardHeader></CardHeader>
<CardContent>
<ChartContainer config={{}}>
<BarChart accessibilityLayer data={chartData}>
<CartesianGrid vertical={false} />
<XAxis
dataKey="tenure"
tickLine={false}
tickMargin={10}
axisLine={false}
tickFormatter={(value) => value}
/>
<ChartTooltip content={<ChartTooltipContent hideLabel />} />
<ChartLegend content={<ChartLegendContent />} />
<Bar dataKey="monthly" strokeWidth={2} activeIndex={2}>
<LabelList
dataKey="monthly"
position="center"
formatter={formatValue}
fill="white"
fontSize={12}
/>
</Bar>
</BarChart>
</ChartContainer>
</CardContent>
</Card>
);
};

export default TenureComparisonBarChart;
69 changes: 69 additions & 0 deletions app/components/graphs/TenureComparisonWrapper.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
"use client";
import React from "react";
import ErrorBoundary from "../ErrorBoundary";
import { Household } from "@/app/models/Household";
import TenureComparisonBarChart from "./TenureComparisonBarChart";

interface TenureComparisonWrapperProps {
household: Household;
}

const TenureComparisonWrapper: React.FC<TenureComparisonWrapperProps> = ({
household,
}) => {
console.log("TenureComparisonWrapper household:", household);

if (!household) {
return <div>No household data available</div>;
}

const formatData = (household: Household) => {
return [
{
category: "Monthly Costs Land",
marketPurchase:
household.tenure.marketPurchase?.landMortgage?.monthlyPayment || 0,
marketRent: household.tenure.marketRent?.averageRentLandMonthly || 0,
socialRent: household.tenure.socialRent?.socialRentMonthlyLand || 0,
fairholdLandPurchase:
household.tenure.fairholdLandPurchase?.discountedLandMortgage
?.monthlyPayment || 0,
fairholdLandRent:
household.tenure.fairholdLandRent?.discountedLandRentMonthly || 0,
affordabilityMonthly:
(household.incomeYearly / 12) *
household.forecastParameters
.affordabilityThresholdIncomePercentage || 0,
},
{
category: "Monthly Costs House",
marketPurchase:
household.tenure.marketPurchase?.houseMortgage?.monthlyPayment || 0,
marketRent: household.tenure.marketRent?.averageRentHouseMonthly || 0,
socialRent: household.tenure.socialRent?.socialRentMonthlyHouse || 0,
fairholdLandPurchase:
household.tenure.fairholdLandPurchase?.depreciatedHouseMortgage
?.monthlyPayment || 0,
fairholdLandRent:
household.tenure.fairholdLandPurchase?.depreciatedHouseMortgage
?.monthlyPayment || 0,
affordabilityMonthly:
(household.incomeYearly / 12) *
household.forecastParameters
.affordabilityThresholdIncomePercentage || 0,
},
];
};

const formattedData = formatData(household);

return (
<ErrorBoundary>
<div>
<TenureComparisonBarChart data={formattedData} />
</div>
</ErrorBoundary>
);
};

export default TenureComparisonWrapper;
9 changes: 4 additions & 5 deletions app/components/ui/Dashboard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@ import { WhatWouldYouChoose } from "../Dashboard/Cards/WhatWouldYouChoose";
import { WhatDifference } from "../Dashboard/Cards/WhatDifference";
import { HowMuchFHCost } from "../Dashboard/Cards/HowMuchFHCost";
import { Carousel } from "./Carousel";
import { HowMuchPerMonth } from "../Dashboard/Cards/HowMuchPerMonth";
import { ResaleValue } from "../Dashboard/Cards/ResaleValue";

interface DashboardProps {
export interface DashboardProps {
processedData: Household;
inputData: FormFrontend;
}
Expand Down Expand Up @@ -37,11 +38,9 @@ const Dashboard: React.FC<DashboardProps> = ({ inputData, processedData }) => {
onScroll={handleScroll}
>
<HowMuchFHCost data={processedData} />
<GraphCard title="How much would it cost every month?">
<span className="text-red-500">in theory less than Freehold</span>
</GraphCard>
<HowMuchPerMonth processedData={processedData} />
<GraphCard title="How would the cost change over my life?"></GraphCard>
<ResaleValue data={processedData}/>
<ResaleValue data={processedData} />
<WhatDifference />
<WhatWouldYouChoose />
</div>
Expand Down
4 changes: 2 additions & 2 deletions app/globals.css
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
--fairhold-land-color-rgb: 74 179 91;
--fairhold-house-color-rgb: 159 211 166;
--fairhold-house-alpha: 0.5;
--private-rent-color-rgb: 74 179 91 0.5;
--private-rent-color-rgb: 131 164 255;
--affordable-rent-color-rgb: 255 97 118 0.5;
--social-rent-color-rgb: 255, 97, 118;
}
Expand Down Expand Up @@ -133,4 +133,4 @@ body {

main {
background: #f2f2f0;
}
}
4 changes: 2 additions & 2 deletions app/lib/format.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ export const formatValue = (value: number) => {
if (value >= 1000000) {
return ${(value / 1000000).toFixed(1)}M`;
}
if (value >= 1000) {
if (value >= 10000) {
return ${(value / 1000).toFixed(0)}K`;
}
return ${value}`;
return ${value.toFixed(0)}`;
};

0 comments on commit cb5cc91

Please sign in to comment.