From 21bbae5ad91ccb8da5a3a6039330f86d30cda163 Mon Sep 17 00:00:00 2001
From: Thibault Reidy <147397675+ReidyT@users.noreply.github.com>
Date: Thu, 19 Dec 2024 11:00:02 +0100
Subject: [PATCH] feat: compute the wall cost (#112)
---
.github/workflows/deploy-github.yml | 4 +++
src/config/buildingMaterials.ts | 2 +-
src/langs/en.json | 3 +-
src/models/BuildingMaterial.ts | 3 +-
.../SimulationInformations.tsx | 18 ++++++++--
.../useSimulationInformations.tsx | 16 +++++++++
src/utils/numbers.test.ts | 36 +++++++++++++++++++
src/utils/numbers.ts | 22 ++++++++++++
8 files changed, 98 insertions(+), 6 deletions(-)
create mode 100644 src/utils/numbers.test.ts
create mode 100644 src/utils/numbers.ts
diff --git a/.github/workflows/deploy-github.yml b/.github/workflows/deploy-github.yml
index dfe9b03..d474829 100644
--- a/.github/workflows/deploy-github.yml
+++ b/.github/workflows/deploy-github.yml
@@ -4,6 +4,10 @@ name: Deploy to GitHub Pages
on:
# Triggers the workflow on repository-dispatch event
workflow_dispatch:
+ # Automatically trigger on push on main
+ push:
+ branches:
+ - main
# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages
permissions:
diff --git a/src/config/buildingMaterials.ts b/src/config/buildingMaterials.ts
index 66b5a34..94237ca 100644
--- a/src/config/buildingMaterials.ts
+++ b/src/config/buildingMaterials.ts
@@ -27,7 +27,7 @@ export const BUILDING_MATERIALS = {
}),
Brick: BuildingMaterial.create({
name: 'Brick',
- price: 0,
+ price: 55,
thermalConductivity: 0.6,
thickness: 0.2,
}),
diff --git a/src/langs/en.json b/src/langs/en.json
index 3ec6bb2..43b67d2 100644
--- a/src/langs/en.json
+++ b/src/langs/en.json
@@ -30,7 +30,8 @@
"TITLE": "Total",
"HEAT_LOSS": "Heat Loss",
"ELECTRICITY_COST": "Electricity Cost",
- "HOUSE_WALL_SIZE": "House Wall"
+ "HOUSE_WALL_SIZE": "House Wall",
+ "HOUSE_WALL_MATERIAL_COST": "Wall Cost"
}
},
"SIMULATION_SETTINGS_PANEL": {
diff --git a/src/models/BuildingMaterial.ts b/src/models/BuildingMaterial.ts
index 474bce5..f7c9e2b 100644
--- a/src/models/BuildingMaterial.ts
+++ b/src/models/BuildingMaterial.ts
@@ -16,7 +16,7 @@ export class BuildingMaterial {
public readonly name: string;
/**
- * Thermal conductivity W/m^2*K.
+ * Thermal conductivity W/m*K.
*/
public readonly thermalConductivity: number;
@@ -36,7 +36,6 @@ export class BuildingMaterial {
price,
thickness,
}: Constructor) {
- // TODO: validates the constructor!
this.name = name;
this.thermalConductivity = thermalConductivity;
this.price = price;
diff --git a/src/modules/common/SimulationInformations/SimulationInformations.tsx b/src/modules/common/SimulationInformations/SimulationInformations.tsx
index bac3b10..f222c21 100644
--- a/src/modules/common/SimulationInformations/SimulationInformations.tsx
+++ b/src/modules/common/SimulationInformations/SimulationInformations.tsx
@@ -9,6 +9,7 @@ import {
} from '@mui/material';
import {
+ BrickWall,
CalendarRange,
Heater,
House,
@@ -21,6 +22,7 @@ import { useSeason } from '@/context/SeasonContext';
import { useSimulation } from '@/context/SimulationContext';
import { LoadingComponent } from '@/modules/common/LoadingComponent';
import { SimulationStatus } from '@/types/simulation';
+import { formatNumber } from '@/utils/numbers';
import { useSimulationInformations } from './useSimulationInformations';
@@ -38,7 +40,7 @@ export const SimulationInformations = (): JSX.Element => {
electricityCost,
} = useSimulation();
- const { seasonIcon, heatLoss, formattedWallSize } =
+ const { seasonIcon, heatLoss, formattedWallSize, wallsPrice } =
useSimulationInformations();
const theme = useTheme();
@@ -136,7 +138,7 @@ export const SimulationInformations = (): JSX.Element => {
{tInformations('TOTAL.ELECTRICITY_COST')}
- {electricityCost} CHF
+ {formatNumber(electricityCost)} CHF
@@ -151,6 +153,18 @@ export const SimulationInformations = (): JSX.Element => {
{formattedWallSize}
+
+
+
+
+
+
+
+ {tInformations('TOTAL.HOUSE_WALL_MATERIAL_COST')}
+
+ {formatNumber(wallsPrice)} CHF
+
+
diff --git a/src/modules/common/SimulationInformations/useSimulationInformations.tsx b/src/modules/common/SimulationInformations/useSimulationInformations.tsx
index e52f30d..1ed9a8d 100644
--- a/src/modules/common/SimulationInformations/useSimulationInformations.tsx
+++ b/src/modules/common/SimulationInformations/useSimulationInformations.tsx
@@ -19,6 +19,7 @@ const iconsBySeason: IconBySeasonType = {
type UseSimulationInformationsReturnType = {
heatLoss: FormattedHeatLoss;
+ wallsPrice: number;
seasonIcon: JSX.Element;
formattedWallSize: React.ReactNode;
};
@@ -33,8 +34,23 @@ export const useSimulationInformations =
HouseComponent.Wall,
);
+ const wallPrices = houseComponentsConfigurator
+ .getByType(HouseComponent.Wall)
+ .reduce(
+ (totCost, houseComponent) =>
+ totCost +
+ houseComponent.actualArea *
+ houseComponent.buildingMaterials.reduce(
+ (componentCost, material) =>
+ componentCost + material.price * material.thickness,
+ 0,
+ ),
+ 0,
+ );
+
return {
heatLoss: formatHeatLossRate(heatLoss),
+ wallsPrice: Math.round(wallPrices),
seasonIcon: iconsBySeason[season],
formattedWallSize: wallComponent
? formatComponentSize({
diff --git a/src/utils/numbers.test.ts b/src/utils/numbers.test.ts
new file mode 100644
index 0000000..d880faf
--- /dev/null
+++ b/src/utils/numbers.test.ts
@@ -0,0 +1,36 @@
+import { describe, expect, it } from 'vitest';
+
+import { formatNumber } from '@/utils/numbers';
+
+describe('formatNumber', () => {
+ it('should format numbers correctly with thousands separators', () => {
+ expect(formatNumber(1)).toBe('1');
+ expect(formatNumber(12)).toBe('12');
+ expect(formatNumber(123)).toBe('123');
+ expect(formatNumber(1234)).toBe("1'234");
+ expect(formatNumber(12345)).toBe("12'345");
+ expect(formatNumber(123456)).toBe("123'456");
+ expect(formatNumber(1234567)).toBe("1'234'567");
+ expect(formatNumber(12345678)).toBe("12'345'678");
+ expect(formatNumber(123456789)).toBe("123'456'789");
+ expect(formatNumber(1234567890)).toBe("1'234'567'890");
+ });
+
+ it('should handle zero correctly', () => {
+ expect(formatNumber(0)).toBe('0');
+ });
+
+ it('should handle negative numbers correctly', () => {
+ expect(formatNumber(-1)).toBe('-1');
+ expect(formatNumber(-12)).toBe('-12');
+ expect(formatNumber(-123)).toBe('-123');
+ expect(formatNumber(-1234)).toBe("-1'234");
+ expect(formatNumber(-12345)).toBe("-12'345");
+ expect(formatNumber(-1234567)).toBe("-1'234'567");
+ });
+
+ it('should handle floating point numbers by discarding the decimal part', () => {
+ expect(formatNumber(1234.56)).toBe("1'234.56");
+ expect(formatNumber(1234567.89)).toBe("1'234'567.89");
+ });
+});
diff --git a/src/utils/numbers.ts b/src/utils/numbers.ts
new file mode 100644
index 0000000..5793998
--- /dev/null
+++ b/src/utils/numbers.ts
@@ -0,0 +1,22 @@
+export const formatNumber = (
+ number: number,
+ separator: string = "'",
+): string => {
+ const [integerPart, decimalPart] = number.toString().split('.');
+
+ const formattedNumber = integerPart
+ .split('')
+ .reverse()
+ .reduce((acc, curr, idx) => {
+ if (curr === '-' || idx % 3 !== 0) {
+ return `${acc}${curr}`;
+ }
+
+ return `${acc}${separator}${curr}`;
+ })
+ .split('')
+ .reverse()
+ .join('');
+
+ return decimalPart ? `${formattedNumber}.${decimalPart}` : formattedNumber;
+};