mirror of
https://github.com/Hestia-Homes/assessment-model.git
synced 2026-06-30 12:55:02 +00:00
Added epc target modal
This commit is contained in:
parent
3c160ea6a5
commit
984d2053a1
5 changed files with 184 additions and 26 deletions
19
src/app/components/button.tsx
Normal file
19
src/app/components/button.tsx
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
import { Dispatch, SetStateAction } from "react";
|
||||
|
||||
export function TanButton({
|
||||
label,
|
||||
onClick,
|
||||
}: {
|
||||
label: string;
|
||||
onClick: Dispatch<SetStateAction<any>>;
|
||||
}) {
|
||||
return (
|
||||
<button
|
||||
type="button"
|
||||
className="inline-flex justify-center rounded-md border border-transparent bg-brandtan px-4 py-2 text-sm font-medium text-white hover:bg-hovertan focus:outline-none focus-visible:ring-2 focus-visible:ring-blue-500 focus-visible:ring-offset-2"
|
||||
onClick={onClick}
|
||||
>
|
||||
{label}
|
||||
</button>
|
||||
);
|
||||
}
|
||||
96
src/app/components/property/EditEpcTargetModal.tsx
Normal file
96
src/app/components/property/EditEpcTargetModal.tsx
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
import { Dialog, Transition } from "@headlessui/react";
|
||||
import { Dispatch, Fragment, SetStateAction, useState } from "react";
|
||||
import { TanButton } from "../button";
|
||||
import EpcDropdownMenu from "../../components/property/EpcDropDownMenu";
|
||||
import { EpcRating } from "@/types/epc";
|
||||
|
||||
export default function EditEpctargetModal({
|
||||
isEditModalOpen,
|
||||
setIsEditModalOpen,
|
||||
setTargetEpcRating,
|
||||
targetEpcRating,
|
||||
}: {
|
||||
isEditModalOpen: boolean;
|
||||
setIsEditModalOpen: Dispatch<SetStateAction<boolean>>;
|
||||
setTargetEpcRating: Dispatch<SetStateAction<EpcRating>>;
|
||||
targetEpcRating: EpcRating;
|
||||
}) {
|
||||
function handleEditModalClose() {
|
||||
setIsEditModalOpen(false);
|
||||
}
|
||||
|
||||
const [modalEpcTarget, setModalEpcTarget] =
|
||||
useState<EpcRating>(targetEpcRating);
|
||||
|
||||
function handleModalSubmit() {
|
||||
setTargetEpcRating(modalEpcTarget);
|
||||
setIsEditModalOpen(false);
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<Transition appear show={isEditModalOpen} as={Fragment}>
|
||||
<Dialog
|
||||
as="div"
|
||||
className="relative z-10"
|
||||
onClose={() => setIsEditModalOpen(false)}
|
||||
>
|
||||
<Transition.Child
|
||||
as={Fragment}
|
||||
enter="ease-out duration-300"
|
||||
enterFrom="opacity-0"
|
||||
enterTo="opacity-100"
|
||||
leave="ease-in duration-200"
|
||||
leaveFrom="opacity-100"
|
||||
leaveTo="opacity-0"
|
||||
>
|
||||
<div className="fixed inset-0 bg-black bg-opacity-25" />
|
||||
</Transition.Child>
|
||||
|
||||
<div className="fixed inset-0 overflow-y-auto">
|
||||
<div className="flex min-h-full items-center justify-center p-4 text-center">
|
||||
<Transition.Child
|
||||
as={Fragment}
|
||||
enter="ease-out duration-300"
|
||||
enterFrom="opacity-0 scale-95"
|
||||
enterTo="opacity-100 scale-100"
|
||||
leave="ease-in duration-200"
|
||||
leaveFrom="opacity-100 scale-100"
|
||||
leaveTo="opacity-0 scale-95"
|
||||
>
|
||||
<Dialog.Panel className="w-full max-w-screen-md transform overflow-hidden rounded-2xl bg-white p-6 text-left align-middle shadow-xl transition-all">
|
||||
<Dialog.Title
|
||||
as="h3"
|
||||
className="text-lg font-medium leading-6 text-brandblue mb-3"
|
||||
>
|
||||
Set a target EPC rating
|
||||
</Dialog.Title>
|
||||
<EpcDropdownMenu
|
||||
options={[
|
||||
{ label: "A", value: "A" },
|
||||
{ label: "C", value: "C" },
|
||||
]}
|
||||
selectedOption={{ label: "C", value: "C" }}
|
||||
onSelectOption={(option) => setModalEpcTarget(option.value)}
|
||||
modalEpcTarget={modalEpcTarget}
|
||||
/>
|
||||
|
||||
<div className="mt-4 flex justify-end gap-2">
|
||||
<button
|
||||
type="button"
|
||||
className="inline-flex justify-center rounded-md border border-transparent bg-blue-100 px-4 py-2 text-sm font-medium text-blue-900 hover:bg-blue-200 focus:outline-none focus-visible:ring-2 focus-visible:ring-blue-500 focus-visible:ring-offset-2"
|
||||
onClick={() => setIsEditModalOpen(false)}
|
||||
>
|
||||
Cancel
|
||||
</button>
|
||||
<TanButton label={"Save"} onClick={handleModalSubmit} />
|
||||
</div>
|
||||
</Dialog.Panel>
|
||||
</Transition.Child>
|
||||
</div>
|
||||
</div>
|
||||
</Dialog>
|
||||
</Transition>
|
||||
</>
|
||||
);
|
||||
}
|
||||
48
src/app/components/property/EpcDropDownMenu.tsx
Normal file
48
src/app/components/property/EpcDropDownMenu.tsx
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
import { Fragment } from "react";
|
||||
import { Menu, Transition } from "@headlessui/react";
|
||||
import { SearchData, SearchResult } from "@/types/epc";
|
||||
|
||||
type Option = {
|
||||
label: SearchResult["current-energy-rating"];
|
||||
value: SearchResult["current-energy-rating"];
|
||||
};
|
||||
|
||||
type DropdownProps = {
|
||||
options: Option[];
|
||||
selectedOption: Option | null;
|
||||
onSelectOption: (option: Option) => void;
|
||||
modalEpcTarget: SearchResult["current-energy-rating"];
|
||||
};
|
||||
|
||||
export default function EpcDropdownMenu({
|
||||
options,
|
||||
selectedOption,
|
||||
onSelectOption,
|
||||
modalEpcTarget,
|
||||
}: DropdownProps) {
|
||||
return (
|
||||
<Menu>
|
||||
<Menu.Button className="inline-flex w-full justify-center rounded-md bg-black bg-opacity-20 px-4 py-2 text-sm font-medium text-white hover:bg-opacity-30 focus:outline-none focus-visible:ring-2 focus-visible:ring-white focus-visible:ring-opacity-75">
|
||||
{"Selected option: " + modalEpcTarget ?? ""}
|
||||
</Menu.Button>
|
||||
<Transition as={Fragment}>
|
||||
<Menu.Items>
|
||||
{options.map((option) => (
|
||||
<Menu.Item key={option.value}>
|
||||
{({ active }) => (
|
||||
<button
|
||||
className={`${
|
||||
active ? "bg-blue-500 text-white" : "text-gray-900"
|
||||
} group flex items-center w-full px-2 py-2 text-sm`}
|
||||
onClick={() => onSelectOption(option)}
|
||||
>
|
||||
{option.label}
|
||||
</button>
|
||||
)}
|
||||
</Menu.Item>
|
||||
))}
|
||||
</Menu.Items>
|
||||
</Transition>
|
||||
</Menu>
|
||||
);
|
||||
}
|
||||
|
|
@ -4,11 +4,12 @@ import { useState } from "react";
|
|||
import { Dialog } from "@headlessui/react";
|
||||
import Link from "next/link";
|
||||
import { ArrowLeftIcon } from "@heroicons/react/24/outline";
|
||||
import { SearchData } from "@/types/epc";
|
||||
import { SearchData, EpcRating } from "@/types/epc";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import EditEpcTargetModal from "../../../../components/property/EditEpctargetModal";
|
||||
|
||||
const EpcDefaults = {
|
||||
const EpcDefaults: { [key in EpcRating]: EpcRating } = {
|
||||
G: "C",
|
||||
F: "C",
|
||||
E: "C",
|
||||
|
|
@ -50,6 +51,7 @@ export default function PropertyPage({
|
|||
|
||||
const [isEditModalOpen, setIsEditModalOpen] = useState(false);
|
||||
const [isDetailModalOpen, setIsDetailModalOpen] = useState(false);
|
||||
const [targetEpcRating, setTargetEpcRating] = useState<EpcRating>("C");
|
||||
|
||||
const { data, error, isLoading } = useQuery<SearchData, Error>({
|
||||
queryKey: ["search", postcode],
|
||||
|
|
@ -68,6 +70,10 @@ export default function PropertyPage({
|
|||
const propertyData = data.rows.filter((row) => row["lmk-key"] === lmkKey)[0];
|
||||
const currentEpcRating = propertyData["current-energy-rating"];
|
||||
|
||||
if (!targetEpcRating) {
|
||||
setTargetEpcRating(EpcDefaults[currentEpcRating]);
|
||||
}
|
||||
|
||||
const handleEditClick = () => {
|
||||
setIsEditModalOpen(true);
|
||||
};
|
||||
|
|
@ -83,7 +89,7 @@ export default function PropertyPage({
|
|||
<section>
|
||||
<div className="h-2"></div>
|
||||
<Link href={`/portfolio/${portfolioId}`}>
|
||||
<div className="ml-2 px-4 py-1 inline-flex items-center bg-brandtan hover:bg-hovertan text-white rounded transition-colors duration-200 cursor-pointer">
|
||||
<div className="ml-2 px-4 py-1 inline-flex items-center bg-brandtan hover:bg-hovertan text-white rounded-md transition-colors duration-200 cursor-pointer">
|
||||
<ArrowLeftIcon className="w-5 h-5 mr-1" />
|
||||
Back to portfolio
|
||||
</div>
|
||||
|
|
@ -94,17 +100,17 @@ export default function PropertyPage({
|
|||
<p className="text-center mb-4">{propertyData.address}</p>
|
||||
|
||||
<div className="flex space-x-4">
|
||||
<div className="flex-1 border p-4">
|
||||
<div className="flex-1 border p-4 rounded-lg bg-brandblue text-white">
|
||||
<h2 className="text-lg font-bold mb-2">Current EPC rating</h2>
|
||||
<p>Rating: {currentEpcRating}</p>
|
||||
</div>
|
||||
|
||||
<div
|
||||
className="flex-1 border p-4 cursor-pointer"
|
||||
className="flex-1 border p-4 rounded-lg bg-brandblue text-white hover:bg-hoverblue transition-colors duration-200 cursor-pointer"
|
||||
onClick={handleEditClick}
|
||||
>
|
||||
<h2 className="text-lg font-bold mb-2">Target EPC rating</h2>
|
||||
<p>Rating: {EpcDefaults[currentEpcRating]}</p>
|
||||
<p>Rating: {targetEpcRating}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
@ -124,25 +130,12 @@ export default function PropertyPage({
|
|||
|
||||
{/* Add more rectangular cards here */}
|
||||
|
||||
{/* Edit Modal */}
|
||||
<Dialog
|
||||
open={isEditModalOpen}
|
||||
onClose={() => setIsEditModalOpen(false)}
|
||||
className="fixed inset-0 z-10"
|
||||
>
|
||||
<div className="flex items-center justify-center min-h-screen">
|
||||
<Dialog.Overlay className="fixed inset-0 bg-black opacity-50" />
|
||||
|
||||
<div className="bg-white rounded p-6">
|
||||
<Dialog.Title>Edit Target EPC Rating</Dialog.Title>
|
||||
<Dialog.Description>
|
||||
This is the modal content for editing the target EPC rating.
|
||||
</Dialog.Description>
|
||||
|
||||
{/* Add your form inputs and actions here */}
|
||||
</div>
|
||||
</div>
|
||||
</Dialog>
|
||||
<EditEpcTargetModal
|
||||
isEditModalOpen={isEditModalOpen}
|
||||
setIsEditModalOpen={setIsEditModalOpen}
|
||||
setTargetEpcRating={setTargetEpcRating}
|
||||
targetEpcRating={targetEpcRating}
|
||||
/>
|
||||
|
||||
{/* Detail Modal */}
|
||||
<Dialog
|
||||
|
|
|
|||
|
|
@ -102,4 +102,6 @@ interface EpcDataProps {
|
|||
data: SearchData;
|
||||
}
|
||||
|
||||
export type { SearchData, SearchResult, EpcDataProps };
|
||||
type EpcRating = SearchResult["current-energy-rating"];
|
||||
|
||||
export type { SearchData, SearchResult, EpcDataProps, EpcRating };
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue