mirror of
https://github.com/Hestia-Homes/assessment-model.git
synced 2026-06-08 11:37:25 +00:00
remote assessment feature working
This commit is contained in:
parent
adef91345b
commit
24e8dee32e
1 changed files with 173 additions and 1 deletions
|
|
@ -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"
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue