remote assessment feature working

This commit is contained in:
Khalim Conn-Kowlessar 2025-04-15 22:40:27 +01:00
parent adef91345b
commit 24e8dee32e

View file

@ -5,7 +5,7 @@ import { Fragment, useMemo } from "react";
import { Input } from "@/app/shadcn_components/ui/input";
import { Button } from "@/app/shadcn_components/ui/button";
import { Float } from "@headlessui-float/react";
import { ChevronDownIcon } from "@heroicons/react/20/solid";
import { ChevronDownIcon, ChevronRightIcon } from "@heroicons/react/20/solid";
import { useMutation } from "@tanstack/react-query";
import { useSession } from "next-auth/react";
import { useForm, FormProvider } from "react-hook-form";
@ -31,6 +31,12 @@ type DropdownProps = {
options: Option[];
selectedOption: string;
onSelectOption: (option: Option) => void;
width?: string;
};
// Extend the existing props
type OptionalDropdownProps = Omit<DropdownProps, "selectedOption"> & {
selectedOption: string | null | undefined;
};
const selecthousingTypeOptions = [
@ -46,6 +52,57 @@ const selecthousingTypeOptions = [
},
];
const propertyTypeOptions = [
{
label: "House",
value: "House",
disabled: false,
},
{
label: "Flat",
value: "Flat",
disabled: false,
},
{
label: "Bungalow",
value: "bungalow",
disabled: false,
},
{
label: "Maisonette",
value: "Maisonette",
disabled: false,
},
{
label: "Other",
value: "Other",
disabled: false,
},
];
const builtFormOptions = [
{
label: "Detached",
value: "Detached",
disabled: false,
},
{
label: "Semi-Detached",
value: "Semi-Detached",
disabled: false,
},
{
label: "Mid-Terrace",
value: "Mid-Terrace",
disabled: false,
},
{
label: "End-Terrace",
value: "End-Terrace",
disabled: false,
},
];
const selectGoalOptions = [
{
label: "Increasing EPC",
@ -102,6 +159,9 @@ const formSchema = z.object({
postcode: z.string().min(1, "Postcode is required"),
uprn: z.number().min(1, "UPRN is required"),
valuation: z.number().min(1, "Valuation is required"),
// Both property type and build form are optional
propertyType: z.string().optional().nullable(),
builtForm: z.string().optional().nullable(),
});
type FormValues = z.infer<typeof formSchema>;
@ -154,6 +214,58 @@ export function SelectDropdown({
);
}
export function SelectUpDropdown({
options,
selectedOption,
onSelectOption,
width = "w-1/2",
}: OptionalDropdownProps) {
const menuButtonStyle = (width = "w-full") =>
`inline-flex justify-center ${width} px-4 py-2 text-sm font-medium text-white bg-brandblue rounded-md focus:outline-none focus-visible:ring-2 focus-visible:ring-white focus-visible:ring-opacity-75`;
return (
<Menu as="div" className="relative inline-block text-left w-full">
<Float placement="right-end" offset={4} shift>
<Menu.Button className={menuButtonStyle(width)}>
{selectedOption || "Select an option"}
<ChevronRightIcon
className="ml-2 -mr-1 h-5 w-5 text-violet-200 hover:text-violet-100"
aria-hidden="true"
/>
</Menu.Button>
<Transition
as={Fragment}
enter="transition ease-out duration-200"
enterFrom="opacity-0 scale-95"
enterTo="opacity-100 scale-100"
leave="transition ease-in duration-150"
leaveFrom="opacity-100 scale-100"
leaveTo="opacity-0 scale-95"
>
<Menu.Items className=" origin-bottom left-0 w-56 rounded-md shadow-lg bg-white ring-1 ring-black ring-opacity-5 focus:outline-none">
{options.map((option) => (
<Menu.Item key={option.value} disabled={option.disabled}>
{({ active }) => (
<button
className={`${
active
? "bg-brandmidblue text-white w-full"
: "text-gray-900 w-full"
} group flex items-center px-4 py-2 text-sm `}
onClick={() => onSelectOption(option)}
>
{option.label}
</button>
)}
</Menu.Item>
))}
</Menu.Items>
</Transition>
</Float>
</Menu>
);
}
async function uploadCsvToS3({
presignedUrl,
file,
@ -239,12 +351,16 @@ function useCreateRemoteAssessment({
addressLineOne,
postcode,
valuation,
propertyType,
builtForm,
}: {
portfolioId: string;
uprn: number | null;
addressLineOne: string;
postcode: string;
valuation: string | number | null;
propertyType?: string | null;
builtForm?: string | null;
}) {
// 1) We want to upload the asset data. To do this, we format the asset data, generate a presigned URL, and upload the data to S3.
// 2) We then want to upload valuation data. To do this, we format the valuation data, generate a presigned URL, and upload the data to S3.
@ -293,6 +409,8 @@ function useCreateRemoteAssessment({
uprn: uprn,
address: addressLineOne,
postcode: postcode,
property_type: propertyType,
built_form: builtForm,
},
];
@ -436,6 +554,8 @@ export default function RemoteAssessmentModal({
addressLineOne: form.watch("addressLineOne"),
postcode: form.watch("postcode"),
valuation: form.watch("valuation"),
propertyType: form.watch("propertyType"),
builtForm: form.watch("builtForm"),
});
return (
@ -640,6 +760,58 @@ export default function RemoteAssessmentModal({
)}
/>
<div className="flex flex-col gap-2">
<p className="text-sm text-gray-600">
<strong>Optional:</strong> Property Type and Built
Form are only required if no EPC is available.
</p>
<div className="flex flex-row gap-4">
<div className="w-full">
<FormField
control={form.control}
name="propertyType"
render={({ field }) => (
<FormItem>
<FormLabel>Property Type</FormLabel>
<FormControl>
<SelectUpDropdown
options={propertyTypeOptions}
selectedOption={field.value}
onSelectOption={(option) =>
field.onChange(option.value)
}
/>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
</div>
<div className="w-full">
<FormField
control={form.control}
name="builtForm"
render={({ field }) => (
<FormItem>
<FormLabel>Built Form</FormLabel>
<FormControl>
<SelectUpDropdown
options={builtFormOptions}
selectedOption={field.value}
onSelectOption={(option) =>
field.onChange(option.value)
}
/>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
</div>
</div>
</div>
<div className="flex justify-end gap-4 mt-6">
<Button
type="button"