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; +};