mirror of
https://github.com/Hestia-Homes/assessment-model.git
synced 2026-06-08 11:37:25 +00:00
got the react hook form with zod to work, FormProvder got rid of the getField errors somehow, all hail Overlord Claude, aesthetic clean up needed as well as linked up to trigger the engine
This commit is contained in:
parent
3520d0858d
commit
710d60b5ed
1 changed files with 208 additions and 147 deletions
|
|
@ -8,6 +8,10 @@ import { Float } from "@headlessui-float/react";
|
|||
import { ChevronDownIcon } from "@heroicons/react/20/solid";
|
||||
import { useMutation } from "@tanstack/react-query";
|
||||
import { useSession } from "next-auth/react";
|
||||
import { Form, useForm, FormProvider } from "react-hook-form";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import * as z from "zod";
|
||||
import { FormField, FormItem, FormLabel, FormControl, FormMessage } from "@/app/shadcn_components/ui/form";
|
||||
|
||||
type Option = {
|
||||
label: string;
|
||||
|
|
@ -291,6 +295,8 @@ function useCreateRemoteAssessment({
|
|||
},
|
||||
});
|
||||
|
||||
|
||||
|
||||
async function handleSubmit() {
|
||||
try {
|
||||
// Mutate presigned URL for asset list file
|
||||
|
|
@ -325,71 +331,58 @@ export default function RemoteAssessmentModal({
|
|||
setIsOpen: (isOpen: boolean) => void;
|
||||
portfolioId: string;
|
||||
}) {
|
||||
const [scenario, setScenario] = useState<undefined | string>(undefined);
|
||||
const [housingType, sethousingType] = useState<string>("");
|
||||
const [selectedGoal, setSelectedGoal] = useState<string>("");
|
||||
const [goalValue, setGoalValue] = useState<string>("");
|
||||
const [addressLineOne, setAddressLineOne] = useState<string>("");
|
||||
const [postcode, setPostcode] = useState<string>("");
|
||||
const [uprn, setUprn] = useState<number | null>(null);
|
||||
const [valuation, setValuation] = useState<number | string | null>("");
|
||||
const [buttonDisabled, setButtonDisabled] = useState(true);
|
||||
|
||||
const formSchema = z.object({
|
||||
scenario: z.string().min(1, "Scenario is required"),
|
||||
goal: z.string().min(1, "Goal is required"),
|
||||
goalValue: z.string().min(1, "Goal value is required"),
|
||||
housingType: z.string().min(1, "Housing type is required"),
|
||||
addressLineOne: z.string().min(1, "Address is required"),
|
||||
postcode: z.string().min(1, "Postcode is required"),
|
||||
uprn: z.number().min(1, "UPRN is required"),
|
||||
valuation: z.number().min(1, "Valuation is required"),
|
||||
});
|
||||
|
||||
function handleScenarioChange(event: React.ChangeEvent<HTMLInputElement>) {
|
||||
setScenario(event.target.value);
|
||||
}
|
||||
const form = useForm<FormValues>({
|
||||
resolver: zodResolver(formSchema),
|
||||
defaultValues: {
|
||||
scenario: "",
|
||||
housingType: "",
|
||||
goal: "",
|
||||
goalValue: "",
|
||||
addressLineOne: "",
|
||||
postcode: "",
|
||||
uprn: 0,
|
||||
valuation: 0,
|
||||
},
|
||||
});
|
||||
|
||||
function handleAddressLineOneChange(
|
||||
event: React.ChangeEvent<HTMLInputElement>
|
||||
) {
|
||||
setAddressLineOne(event.target.value);
|
||||
}
|
||||
type FormValues = z.infer<typeof formSchema>;
|
||||
|
||||
function handlePostcodeChange(event: React.ChangeEvent<HTMLInputElement>) {
|
||||
setPostcode(event.target.value);
|
||||
}
|
||||
|
||||
function handleUprnChange(event: React.ChangeEvent<HTMLInputElement>) {
|
||||
setUprn(Number(event.target.value));
|
||||
}
|
||||
|
||||
function handleValuationChange(event: React.ChangeEvent<HTMLInputElement>) {
|
||||
setValuation(event.target.value);
|
||||
}
|
||||
const onSubmit = async (data: FormValues) => {
|
||||
try {
|
||||
// First handle the form submission from react-hook-form
|
||||
const formData = form.getValues();
|
||||
|
||||
// Then trigger the data upload using handleSubmit from useCreateRemoteAssessment
|
||||
await handleSubmit();
|
||||
|
||||
// Close the modal on success
|
||||
setIsOpen(false);
|
||||
} catch (error) {
|
||||
console.error('Error submitting form:', error);
|
||||
}
|
||||
};
|
||||
|
||||
const { handleSubmit, presignedUrlIsLoading, presignedUrlIsError } =
|
||||
useCreateRemoteAssessment({
|
||||
portfolioId,
|
||||
uprn,
|
||||
addressLineOne,
|
||||
postcode,
|
||||
valuation,
|
||||
uprn: form.watch("uprn"),
|
||||
addressLineOne: form.watch("addressLineOne"),
|
||||
postcode: form.watch("postcode"),
|
||||
valuation: form.watch("valuation"),
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
function handleButtonDisabled(): boolean {
|
||||
return !(
|
||||
scenario &&
|
||||
selectedGoal &&
|
||||
housingType &&
|
||||
addressLineOne &&
|
||||
postcode &&
|
||||
uprn &&
|
||||
valuation
|
||||
);
|
||||
}
|
||||
|
||||
setButtonDisabled(handleButtonDisabled());
|
||||
}, [
|
||||
scenario,
|
||||
selectedGoal,
|
||||
housingType,
|
||||
addressLineOne,
|
||||
postcode,
|
||||
uprn,
|
||||
valuation,
|
||||
]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Transition appear show={isOpen} as={Fragment}>
|
||||
|
|
@ -422,101 +415,169 @@ export default function RemoteAssessmentModal({
|
|||
leaveTo="opacity-0 scale-95"
|
||||
>
|
||||
<Dialog.Panel className="w-1/2 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"
|
||||
>
|
||||
{scenario}
|
||||
</Dialog.Title>
|
||||
<div className="flex justify-center">
|
||||
Scenario Name
|
||||
<Input
|
||||
type="text"
|
||||
defaultValue={"Remote Assessment"}
|
||||
onChange={handleScenarioChange}
|
||||
<Dialog.Title as="h3" className="text-lg font-medium leading-6 text-gray-900">
|
||||
Remote Assessment Details
|
||||
</Dialog.Title>
|
||||
<FormProvider {...form}>
|
||||
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-6">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="scenario"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Scenario Name</FormLabel>
|
||||
<FormControl>
|
||||
<Input
|
||||
placeholder="Enter scenario name"
|
||||
{...field}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex flex-col mt-6">
|
||||
<label
|
||||
htmlFor="portfolio-name"
|
||||
className="text-sm font-semibold text-gray-600 mb-1 relative leading-relaxed tracking-wider"
|
||||
>
|
||||
Housing type
|
||||
<span className="text-red-500">*</span>
|
||||
</label>
|
||||
<SelectDropdown
|
||||
options={selecthousingTypeOptions}
|
||||
selectedOption={housingType}
|
||||
onSelectOption={(option) => sethousingType(option.value)}
|
||||
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="housingType"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Housing Type</FormLabel>
|
||||
<FormControl>
|
||||
<SelectDropdown
|
||||
options={selecthousingTypeOptions}
|
||||
selectedOption={field.value}
|
||||
onSelectOption={(option) => field.onChange(option.value)}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex flex-col mt-6">
|
||||
<label
|
||||
htmlFor="portfolio-name"
|
||||
className="text-sm font-semibold text-gray-600 mb-1 relative leading-relaxed tracking-wider"
|
||||
>
|
||||
Select Goal
|
||||
<span className="text-red-500">*</span>
|
||||
</label>
|
||||
<SelectDropdown
|
||||
options={selectGoalOptions}
|
||||
selectedOption={selectedGoal}
|
||||
onSelectOption={(option) => setSelectedGoal(option.value)}
|
||||
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="goal"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Goal</FormLabel>
|
||||
<FormControl>
|
||||
<SelectDropdown
|
||||
options={selectGoalOptions}
|
||||
selectedOption={field.value}
|
||||
onSelectOption={(option) => field.onChange(option.value)}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
{selectedGoal === "Increase EPC" && (
|
||||
<div className="flex flex-col mt-6">
|
||||
<label
|
||||
htmlFor="csv-upload-epc"
|
||||
className="text-sm font-semibold text-gray-600 relative leading-relaxed tracking-wider"
|
||||
>
|
||||
Choose a target EPC value
|
||||
<span className="text-red-500">*</span>
|
||||
</label>
|
||||
<SelectDropdown
|
||||
options={goalValueOptions}
|
||||
selectedOption={goalValue}
|
||||
onSelectOption={(option) => {
|
||||
setGoalValue(option.value);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="goalValue"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Goal Value</FormLabel>
|
||||
<FormControl>
|
||||
<SelectDropdown
|
||||
options={goalValueOptions}
|
||||
selectedOption={field.value}
|
||||
onSelectOption={(option) => field.onChange(option.value)}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="addressLineOne"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Address</FormLabel>
|
||||
<FormControl>
|
||||
<Input placeholder="Enter address" {...field} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="postcode"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Postcode</FormLabel>
|
||||
<FormControl>
|
||||
<Input placeholder="Enter postcode" {...field} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="uprn"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>UPRN</FormLabel>
|
||||
<FormControl>
|
||||
<Input
|
||||
type="number"
|
||||
placeholder="Enter UPRN"
|
||||
{...field}
|
||||
onChange={(e) => field.onChange(Number(e.target.value))}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="valuation"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Valuation</FormLabel>
|
||||
<FormControl>
|
||||
<Input
|
||||
type="number"
|
||||
placeholder="Enter valuation"
|
||||
{...field}
|
||||
onChange={(e) => field.onChange(Number(e.target.value))}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<div className="flex justify-end gap-4 mt-6">
|
||||
<Button
|
||||
type="button"
|
||||
variant="outline"
|
||||
onClick={() => setIsOpen(false)}
|
||||
>
|
||||
Cancel
|
||||
</Button>
|
||||
<Button
|
||||
type="submit"
|
||||
disabled={presignedUrlIsLoading}
|
||||
>
|
||||
{presignedUrlIsLoading ? "Submitting..." : "Submit"}
|
||||
</Button>
|
||||
</div>
|
||||
{presignedUrlIsError && (
|
||||
<p className="text-red-500 mt-2">Error uploading files</p>
|
||||
)}
|
||||
</div>
|
||||
<div className="flex justify-center mt-6">
|
||||
Address Line 1
|
||||
<Input type="text" onChange={handleAddressLineOneChange} />
|
||||
</div>
|
||||
<div className="flex justify-center mt-6">
|
||||
Postcode
|
||||
<Input type="text" onChange={handlePostcodeChange} />
|
||||
</div>
|
||||
<div className="flex justify-center mt-6">
|
||||
UPRN
|
||||
<Input type="text" onChange={handleUprnChange} />
|
||||
</div>
|
||||
<div className="flex justify-center mt-6">
|
||||
Valuation
|
||||
<Input type="text" onChange={handleValuationChange} />
|
||||
</div>
|
||||
<div className="flex justify-center mt-6">
|
||||
<Button
|
||||
disabled={buttonDisabled}
|
||||
onClick={() => {
|
||||
handleSubmit();
|
||||
setIsOpen(false);
|
||||
}}
|
||||
>
|
||||
Submit
|
||||
</Button>
|
||||
</div>
|
||||
<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={() => setIsOpen(false)}
|
||||
>
|
||||
Cancel
|
||||
</button>
|
||||
</Dialog.Panel>
|
||||
</form>
|
||||
</FormProvider>
|
||||
</Dialog.Panel>
|
||||
</Transition.Child>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue