Implemented functionality on plan page

This commit is contained in:
Khalim Conn-Kowlessar 2023-05-31 18:12:52 +01:00
parent 8de210dd00
commit f03883738a
4 changed files with 169 additions and 60 deletions

View file

@ -1,16 +1,11 @@
import { Fragment } from "react";
import { Menu, Transition } from "@headlessui/react";
import { ChevronDownIcon } from "@heroicons/react/20/solid";
type Option = {
label: string;
value: string;
cost: number;
};
import { PartOption } from "@/types/parts";
type DropdownProps = {
options: Option[];
onSelectOption: (option: Option) => void;
options: PartOption[];
onSelectOption: (option: PartOption) => void;
selectedOption: string;
};
@ -39,7 +34,7 @@ export default function PartDropdown({
>
<Menu.Items className="origin-bottom left-0 w-full rounded-md shadow-lg bg-white ring-1 ring-black ring-opacity-5 focus:outline-none">
{options.map((option) => (
<Menu.Item key={option.value}>
<Menu.Item key={option.part}>
{({ active }) => (
<button
className={`${

View file

@ -2,16 +2,21 @@ import { Dialog, Transition } from "@headlessui/react";
import { Dispatch, Fragment, SetStateAction, useState } from "react";
import { TanButton } from "../Buttons";
import PartDropdown from "./PartDropdown";
import { formatNumber } from "@/app/utils";
import type { Part, PartOption } from "@/types/parts";
type ParModalProps = {
type PartModalProps = {
title: string;
isOpen: boolean;
setIsOpen: Dispatch<SetStateAction<boolean>>;
options: { label: string; value: string; cost: number }[];
options: PartOption[];
selectedOption: string;
setSelectedOption: Dispatch<SetStateAction<string>>;
cost: number;
setCost: Dispatch<SetStateAction<number>>;
parts: Part[];
setParts: Dispatch<SetStateAction<Part[]>>;
partIndex: number;
setTotalCost: Dispatch<SetStateAction<string>>;
setWorkHours: Dispatch<SetStateAction<number>>;
};
export default function PartModal({
@ -21,18 +26,31 @@ export default function PartModal({
options,
selectedOption,
setSelectedOption,
cost,
setCost,
}: ParModalProps) {
parts,
setParts,
partIndex,
setTotalCost,
setWorkHours,
}: PartModalProps) {
function handleModalSubmit() {
// Right now the dropdown is setting the state on the selected option so we might not need
setSelectedOption(optionInput);
setCost(costInput);
// recalculate total cost
parts[partIndex].cost = costInput;
setTotalCost(formatNumber(parts.reduce((sum, part) => sum + part.cost, 0)));
// recalculata total hours
parts[partIndex].workHours = hoursInput;
setWorkHours(parts.reduce((sum, part) => sum + part.workHours, 0));
setParts(parts);
setIsOpen(false);
}
const [costInput, setCostInput] = useState<number>(cost);
const [costInput, setCostInput] = useState<number>(parts[partIndex].cost);
const [optionInput, setOptionInput] = useState<string>(selectedOption);
const [hoursInput, setHoursInput] = useState<number>(
parts[partIndex].workHours
);
return (
<>
@ -80,10 +98,11 @@ export default function PartModal({
<PartDropdown
options={options}
onSelectOption={(option) => {
setOptionInput(option.value);
setOptionInput(option.part);
setCostInput(option.cost);
setHoursInput(option.workHours);
}}
selectedOption={selectedOption}
selectedOption={optionInput}
/>
</div>

View file

@ -1,53 +1,74 @@
import { useState } from "react";
import { Dispatch, SetStateAction, useState } from "react";
import PartModal from "./PartModal";
import { formatNumber } from "@/app/utils";
import type { Part, PartOption } from "@/types/parts";
type PlanPartProps = {
partIndex: number;
title: string;
cost: number;
co2Emissions: number;
co2Reduction: number;
workHours: number;
parts: Part[];
setParts: Dispatch<SetStateAction<Part[]>>;
setTotalCost: Dispatch<SetStateAction<string>>;
setWorkHours: Dispatch<SetStateAction<number>>;
};
export default function PlanPart({
partIndex,
title,
cost,
co2Emissions,
co2Reduction,
workHours,
parts,
setParts,
setTotalCost,
setWorkHours,
}: PlanPartProps) {
const [isOpen, setIsOpen] = useState(false);
const [partCost, setPartCost] = useState(cost);
const [partCost, setPartCost] = useState(parts[partIndex].cost);
// These are temporary options for the demo
const options = [
const options: PartOption[] = [
{
label: "option 1: £" + formatNumber(cost + 0.05 * cost),
value: "option 1",
part: "option 1",
cost: cost + 0.05 * cost,
co2Reduction: co2Reduction - 0.05 * co2Reduction,
workHours: workHours + 0.05 * workHours,
},
{
label: "option 2: £" + formatNumber(cost + 0.1 * cost),
value: "option 2",
part: "option 2",
cost: cost + 0.1 * cost,
co2Reduction: co2Reduction - 0.1 * co2Reduction,
workHours: workHours + 0.1 * workHours,
},
{
label: "option 3: £" + formatNumber(cost + 0.15 * cost),
value: "option 3",
part: "option 3",
cost: cost + 0.15 * cost,
co2Reduction: co2Reduction - 0.15 * co2Reduction,
workHours: workHours + 0.15 * workHours,
},
{
label: "option 4: £" + formatNumber(cost + 0.2 * cost),
value: "option 4",
part: "option 4",
cost: cost + 0.2 * cost,
co2Reduction: co2Reduction - 0.2 * co2Reduction,
workHours: workHours + 0.2 * workHours,
},
{
label: "option 5: £" + formatNumber(cost + 0.25 * cost),
value: "option 5",
part: "option 5",
cost: cost + 0.25 * cost,
co2Reduction: co2Reduction - 0.25 * co2Reduction,
workHours: workHours + 0.25 * workHours,
},
];
const [selectedOption, setSelectedOption] = useState(options[0].value);
const [selectedOption, setSelectedOption] = useState(options[0].part);
return (
<div
@ -59,13 +80,13 @@ export default function PlanPart({
<h2 className="flex-1 text-lg font-bold mb-2 text-left">{title}</h2>
<div>{selectedOption}</div>
<div className="flex-1 text-center">
<p>Cost: £{partCost}</p>
<p>Cost: £{parts[partIndex].cost}</p>
</div>
<div className="flex-1 text-center">
<p>CO2 Reduction: {co2Emissions}</p>
<p>CO2 Reduction: {parts[partIndex].co2Reduction}</p>
</div>
<div className="flex-1 text-center">
<p>Work Hours: {workHours}</p>
<p>Work Hours: {parts[partIndex].workHours}</p>
</div>
<PartModal
title={title}
@ -74,8 +95,11 @@ export default function PlanPart({
options={options}
selectedOption={selectedOption}
setSelectedOption={setSelectedOption}
cost={partCost}
setCost={setPartCost}
parts={parts}
setParts={setParts}
partIndex={partIndex}
setTotalCost={setTotalCost}
setWorkHours={setWorkHours}
/>
</div>
);

View file

@ -11,6 +11,7 @@ import EditEpctargetModal from "@/app/components/property/EditEpcTargetModal";
import Link from "next/link";
import BudgetModal from "@/app/components/plan/BudgetModal";
import { formatNumber } from "@/app/utils";
import { Part } from "@/types/parts";
export default function Plan({
params,
@ -27,46 +28,110 @@ export default function Plan({
// Temp config for the demo
const partsConfig = [
{ part: "Roof", cost: 1200, co2Emissions: 50, workHours: 20 },
{ part: "Walls", cost: 900, co2Emissions: 50, workHours: 20 },
{ part: "Floors", cost: 4300, co2Emissions: 50, workHours: 20 },
{ part: "Window Glazing", cost: 6000, co2Emissions: 50, workHours: 20 },
{
part: "Roof",
option: "option 1",
cost: 1200,
co2Reduction: 50,
workHours: 20,
},
{
part: "Walls",
option: "option 1",
cost: 900,
co2Reduction: 50,
workHours: 20,
},
{
part: "Floors",
option: "option 1",
cost: 4300,
co2Reduction: 50,
workHours: 20,
},
{
part: "Window Glazing",
option: "option 1",
cost: 6000,
co2Reduction: 50,
workHours: 20,
},
{
part: "Window Draughproofing",
option: "option 1",
cost: 10,
co2Emissions: 50,
co2Reduction: 50,
workHours: 20,
},
{
part: "Door Insulation",
option: "option 1",
cost: 250,
co2Reduction: 50,
workHours: 20,
},
{ part: "Door Insulation", cost: 250, co2Emissions: 50, workHours: 20 },
{
part: "Door Draughproofing",
option: "option 1",
cost: 70,
co2Emissions: 50,
co2Reduction: 50,
workHours: 20,
},
{
part: "Heating",
option: "option 1",
cost: 2300,
co2Reduction: 50,
workHours: 20,
},
{
part: "Hot Water",
option: "option 1",
cost: 5290,
co2Reduction: 50,
workHours: 20,
},
{
part: "Solar Panels",
option: "option 1",
cost: 1300,
co2Reduction: 50,
workHours: 20,
},
{
part: "Solar Hot Water",
option: "option 1",
cost: 1000,
co2Reduction: 50,
workHours: 20,
},
{
part: "Lighting",
option: "option 1",
cost: 20,
co2Reduction: 50,
workHours: 20,
},
{ part: "Heating", cost: 2300, co2Emissions: 50, workHours: 20 },
{ part: "Hot Water", cost: 5290, co2Emissions: 50, workHours: 20 },
{ part: "Solar Panels", cost: 1300, co2Emissions: 50, workHours: 20 },
{ part: "Solar Hot Water", cost: 1000, co2Emissions: 50, workHours: 20 },
{ part: "Lighting", cost: 20, co2Emissions: 50, workHours: 20 },
{
part: "Chimneys/ Open Fire Places",
option: "option 1",
cost: 350,
co2Emissions: 50,
co2Reduction: 50,
workHours: 20,
},
];
const totalWorkHours = partsConfig.reduce(
(sum, part) => sum + part.workHours,
0
);
const partsTotalCost = partsConfig.reduce((sum, part) => sum + part.cost, 0);
// Manage state of the selected parts - start with partsConfig
const [parts, setParts] = useState<Part[]>(partsConfig);
const [budget, setBudget] = useState<number | "Not set">("Not set");
const [totalCost, setTotalCost] = useState(partsTotalCost);
const [installTime, setInstallTime] = useState(totalWorkHours);
const [totalCost, setTotalCost] = useState<string>(
formatNumber(parts.reduce((sum, part) => sum + part.cost, 0))
);
const [workHours, setWorkHours] = useState(
parts.reduce((sum, part) => sum + part.workHours, 0)
);
const [isEditModalOpen, setIsEditModalOpen] = useState(false);
const [isBudgetModalOpen, setIsBudgetModalOpen] = useState(false);
const [targetEpcRating, setTargetEpcRating] = useState<EpcRating | "">(
@ -92,6 +157,7 @@ export default function Plan({
}
const propertyData = data.rows.filter((row) => row["lmk-key"] === lmkKey)[0];
return (
<section>
<div className="max-w-6xl mx-auto p-6 flex flex-col items-center">
@ -101,14 +167,19 @@ export default function Plan({
</div>
<div className="flex w-full">
<div className="w-3/4 pr-4">
{partsConfig.map((part, index) => {
{parts.map((part, index) => {
return (
<PlanPart
key={index}
partIndex={index}
title={part.part}
cost={part.cost}
co2Emissions={part.co2Emissions}
co2Reduction={part.co2Reduction}
workHours={part.workHours}
parts={parts}
setParts={setParts}
setTotalCost={setTotalCost}
setWorkHours={setWorkHours}
/>
);
})}
@ -143,7 +214,7 @@ export default function Plan({
</Link>
<li className="px-2 mb-2">Total cost: £{totalCost}</li>
<li className="px-2 mb-2">
Installation Time: {installTime} hours
Installation Time: {workHours} hours
</li>
</ul>
</div>