mirror of
https://github.com/Hestia-Homes/assessment-model.git
synced 2026-06-08 11:37:25 +00:00
improving ui of remote assessment modal
This commit is contained in:
parent
b99069a7d4
commit
4b23c950d5
4 changed files with 308 additions and 288 deletions
|
|
@ -0,0 +1,172 @@
|
|||
import { Menu, Transition } from "@headlessui/react";
|
||||
import { Fragment } from "react";
|
||||
import { Button } from "@/app/shadcn_components/ui/button";
|
||||
import { PlusIcon, ChevronDownIcon } from "@heroicons/react/20/solid";
|
||||
import { Float } from "@headlessui-float/react";
|
||||
|
||||
export type Option = { label: string; value: string; disabled?: boolean };
|
||||
|
||||
// Extend ScenarioOption to include extra metadata
|
||||
export type ScenarioOption = {
|
||||
label: string; // scenario name
|
||||
value: string; // scenario value
|
||||
housingType?: string; // existing scenario housing type
|
||||
goal?: string; // existing scenario goal
|
||||
goalValue?: string; // existing scenario goal value
|
||||
};
|
||||
|
||||
interface ScenarioSelectProps {
|
||||
selectedValue: string | null;
|
||||
onSelect: (option: ScenarioOption) => void;
|
||||
scenarios: ScenarioOption[];
|
||||
}
|
||||
|
||||
interface SelectDropdownProps {
|
||||
options: Option[];
|
||||
selectedOption: string;
|
||||
onSelectOption: (opt: Option) => void;
|
||||
}
|
||||
|
||||
export function SelectScenarioDropdown({
|
||||
selectedValue,
|
||||
onSelect,
|
||||
scenarios,
|
||||
}: ScenarioSelectProps) {
|
||||
const newOption: ScenarioOption = {
|
||||
label: "New scenario",
|
||||
value: "__new__",
|
||||
};
|
||||
const options = [newOption, ...scenarios];
|
||||
|
||||
const selectedLabel =
|
||||
options.find((o) => o.value === selectedValue)?.label || "Choose scenario";
|
||||
|
||||
return (
|
||||
<Menu as="div" className="relative w-full text-left">
|
||||
<Menu.Button
|
||||
as={Button}
|
||||
variant="default"
|
||||
className="w-full justify-start bg-brandmidblue text-white rounded-lg shadow-sm hover:bg-brandblue focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-brandmidblue"
|
||||
>
|
||||
{selectedValue === newOption.value && (
|
||||
<PlusIcon className="mr-2 h-5 w-5 text-white" aria-hidden="true" />
|
||||
)}
|
||||
<span className="flex-1 text-left">{selectedLabel}</span>
|
||||
<ChevronDownIcon
|
||||
className="ml-2 h-5 w-5 text-white"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
</Menu.Button>
|
||||
|
||||
<Transition
|
||||
as={Fragment}
|
||||
enter="transition ease-out duration-150"
|
||||
enterFrom="opacity-0 scale-95"
|
||||
enterTo="opacity-100 scale-100"
|
||||
leave="transition ease-in duration-100"
|
||||
leaveFrom="opacity-100 scale-100"
|
||||
leaveTo="opacity-0 scale-95"
|
||||
>
|
||||
<Menu.Items className="absolute mt-2 w-full bg-white border border-gray-200 rounded-lg shadow-lg z-10 py-1">
|
||||
{options.map((opt) => (
|
||||
<Menu.Item key={opt.value}>
|
||||
{({ active }) => (
|
||||
<button
|
||||
onClick={() => onSelect(opt)}
|
||||
className={
|
||||
`group w-full text-left px-4 py-3 text-sm transition-colors flex flex-col space-y-1 ` +
|
||||
(active ? "bg-brandmidblue text-white" : "text-gray-800")
|
||||
}
|
||||
>
|
||||
{/* If new scenario, show plus icon and label only */}
|
||||
{opt.value === newOption.value ? (
|
||||
<div className="flex items-center">
|
||||
<PlusIcon
|
||||
className={`mr-2 h-5 w-5 ${
|
||||
active ? "text-white" : "text-brandmidblue"
|
||||
}`}
|
||||
aria-hidden="true"
|
||||
/>
|
||||
<span>{opt.label}</span>
|
||||
</div>
|
||||
) : (
|
||||
/* Existing scenario: show two rows side-by-side pairs */
|
||||
<>
|
||||
<div className="flex justify-between w-full">
|
||||
<span className="font-medium">{opt.label}</span>
|
||||
<span className="italic">{opt.housingType}</span>
|
||||
</div>
|
||||
<div className="flex justify-between w-full text-sm">
|
||||
<span>{opt.goal}</span>
|
||||
<span>{opt.goalValue}</span>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</button>
|
||||
)}
|
||||
</Menu.Item>
|
||||
))}
|
||||
</Menu.Items>
|
||||
</Transition>
|
||||
</Menu>
|
||||
);
|
||||
}
|
||||
|
||||
export function SelectDropdown({
|
||||
options,
|
||||
selectedOption,
|
||||
onSelectOption,
|
||||
}: {
|
||||
options: Option[];
|
||||
selectedOption: string;
|
||||
onSelectOption: (opt: Option) => void;
|
||||
}) {
|
||||
const label =
|
||||
options.find((o) => o.value === selectedOption)?.label || "Select…";
|
||||
|
||||
return (
|
||||
<Menu as="div" className="relative w-full text-left">
|
||||
<Menu.Button
|
||||
as={Button}
|
||||
variant="outline"
|
||||
className="w-full flex items-center justify-between gap-2 rounded-lg border border-brandbrown bg-white px-4 py-2 text-sm text-gray-700 shadow-sm hover:border-brandbrown focus:outline-none focus:ring-2 focus:ring-brandbrown"
|
||||
>
|
||||
<span className="truncate flex-1 text-left">{label}</span>
|
||||
<ChevronDownIcon className="h-5 w-5 text-gray-500" />
|
||||
</Menu.Button>
|
||||
|
||||
<Transition
|
||||
as={Fragment}
|
||||
enter="transition ease-out duration-150"
|
||||
enterFrom="opacity-0 scale-95"
|
||||
enterTo="opacity-100 scale-100"
|
||||
leave="transition ease-in duration-100"
|
||||
leaveFrom="opacity-100 scale-100"
|
||||
leaveTo="opacity-0 scale-95"
|
||||
>
|
||||
<Menu.Items className="absolute z-10 mt-2 w-full rounded-lg border border-brandbrown bg-white shadow-xl focus:outline-none">
|
||||
{options.map((opt) => (
|
||||
<Menu.Item key={opt.value} disabled={opt.disabled}>
|
||||
{({ active, disabled }) => (
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => onSelectOption(opt)}
|
||||
disabled={disabled}
|
||||
className={`w-full px-4 py-2 text-sm text-left transition-colors ${
|
||||
disabled
|
||||
? "cursor-not-allowed text-gray-400"
|
||||
: active
|
||||
? "bg-brandbrown text-white"
|
||||
: "text-gray-700 hover:bg-gray-50"
|
||||
}`}
|
||||
>
|
||||
{opt.label}
|
||||
</button>
|
||||
)}
|
||||
</Menu.Item>
|
||||
))}
|
||||
</Menu.Items>
|
||||
</Transition>
|
||||
</Menu>
|
||||
);
|
||||
}
|
||||
|
|
@ -4,8 +4,6 @@ import { Dialog, Transition, Menu } from "@headlessui/react";
|
|||
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, 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";
|
||||
|
|
@ -22,7 +20,10 @@ import {
|
|||
import { useToast } from "@/app/hooks/use-toast";
|
||||
import { ScenarioSelect } from "@/app/db/schema/recommendations";
|
||||
import { useState } from "react";
|
||||
import { SelectScenarioDropdown } from "./SelectScenarioDropdown";
|
||||
import {
|
||||
SelectScenarioDropdown,
|
||||
SelectDropdown,
|
||||
} from "./RemoteAssessmentDropdowns";
|
||||
|
||||
type Option = {
|
||||
label: string;
|
||||
|
|
@ -169,106 +170,6 @@ const formSchema = z.object({
|
|||
|
||||
type FormValues = z.infer<typeof formSchema>;
|
||||
|
||||
export function SelectDropdown({
|
||||
options,
|
||||
selectedOption,
|
||||
onSelectOption,
|
||||
}: DropdownProps) {
|
||||
return (
|
||||
<Menu as="div" className="relative inline-block text-left w-full">
|
||||
<Float>
|
||||
<Menu.Button className="inline-flex justify-center w-1/2 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">
|
||||
{selectedOption || "Select option"}
|
||||
<ChevronDownIcon
|
||||
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>
|
||||
);
|
||||
}
|
||||
|
||||
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 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,
|
||||
|
|
@ -645,7 +546,7 @@ export default function RemoteAssessmentModal({
|
|||
leaveFrom="opacity-100 scale-100"
|
||||
leaveTo="opacity-0 scale-95"
|
||||
>
|
||||
<div className="inline-block w-full max-w-2xl p-6 my-8 overflow-hidden text-left align-middle transition-all transform bg-white shadow-xl rounded-2xl">
|
||||
<div className="inline-block w-full max-w-2xl p-6 my-8 overflow-visible text-left align-middle transition-all transform bg-white shadow-xl rounded-2xl">
|
||||
<Dialog.Title className="text-lg font-medium">
|
||||
Remote Assessment Details
|
||||
</Dialog.Title>
|
||||
|
|
@ -669,99 +570,112 @@ export default function RemoteAssessmentModal({
|
|||
|
||||
{selectedScenario !== null && (
|
||||
<>
|
||||
{/* 2) Scenario Name */}
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="scenario"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Scenario Name</FormLabel>
|
||||
<FormControl>
|
||||
<Input
|
||||
placeholder="Enter scenario name"
|
||||
disabled={selectedScenario !== NEW_SENTINEL}
|
||||
{...field}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
{/* 3) Housing Type */}
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="housingType"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Housing Type</FormLabel>
|
||||
<FormControl>
|
||||
{selectedScenario === NEW_SENTINEL ? (
|
||||
<SelectDropdown
|
||||
options={selecthousingTypeOptions}
|
||||
selectedOption={field.value}
|
||||
onSelectOption={(o) =>
|
||||
field.onChange(o.value)
|
||||
}
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
{/* Scenario Name */}
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="scenario"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel className="text-gray-800">
|
||||
Scenario Name
|
||||
</FormLabel>
|
||||
<FormControl>
|
||||
<Input
|
||||
{...field}
|
||||
disabled={selectedScenario !== NEW_SENTINEL}
|
||||
placeholder="Scenario name"
|
||||
className="border-brandbrown focus-visible:ring-brandbrown focus-visible:border-brandbrown"
|
||||
/>
|
||||
) : (
|
||||
<Input value={field.value} disabled />
|
||||
)}
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage className="text-brandbrown" />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
{/* 4) Goal */}
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="goal"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Goal</FormLabel>
|
||||
<FormControl>
|
||||
{selectedScenario === NEW_SENTINEL ? (
|
||||
<SelectDropdown
|
||||
options={selectGoalOptions}
|
||||
selectedOption={field.value}
|
||||
onSelectOption={(o) =>
|
||||
field.onChange(o.value)
|
||||
}
|
||||
/>
|
||||
) : (
|
||||
<Input value={field.value} disabled />
|
||||
)}
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
{/* Housing Type */}
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="housingType"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel className="text-gray-800">
|
||||
Housing Type
|
||||
</FormLabel>
|
||||
<FormControl>
|
||||
{selectedScenario === NEW_SENTINEL ? (
|
||||
<SelectDropdown
|
||||
options={selecthousingTypeOptions}
|
||||
selectedOption={field.value}
|
||||
onSelectOption={(o) =>
|
||||
field.onChange(o.value)
|
||||
}
|
||||
/>
|
||||
) : (
|
||||
<Input value={field.value} disabled />
|
||||
)}
|
||||
</FormControl>
|
||||
<FormMessage className="text-brandbrown" />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* 5) Goal Value */}
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="goalValue"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Goal Value</FormLabel>
|
||||
<FormControl>
|
||||
{selectedScenario === NEW_SENTINEL ? (
|
||||
<SelectDropdown
|
||||
options={goalValueOptions}
|
||||
selectedOption={field.value}
|
||||
onSelectOption={(o) =>
|
||||
field.onChange(o.value)
|
||||
}
|
||||
/>
|
||||
) : (
|
||||
<Input value={field.value} disabled />
|
||||
)}
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
{/* Goal */}
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="goal"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel className="text-gray-800">
|
||||
Goal
|
||||
</FormLabel>
|
||||
<FormControl>
|
||||
{selectedScenario === NEW_SENTINEL ? (
|
||||
<SelectDropdown
|
||||
options={selectGoalOptions}
|
||||
selectedOption={field.value}
|
||||
onSelectOption={(o) =>
|
||||
field.onChange(o.value)
|
||||
}
|
||||
/>
|
||||
) : (
|
||||
<Input value={field.value} disabled />
|
||||
)}
|
||||
</FormControl>
|
||||
<FormMessage className="text-brandbrown" />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
{/* Goal Value */}
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="goalValue"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel className="text-gray-800">
|
||||
Goal Value
|
||||
</FormLabel>
|
||||
<FormControl>
|
||||
{selectedScenario === NEW_SENTINEL ? (
|
||||
<SelectDropdown
|
||||
options={selecthousingTypeOptions}
|
||||
selectedOption={field.value}
|
||||
onSelectOption={(opt) =>
|
||||
field.onChange(opt.value)
|
||||
}
|
||||
/>
|
||||
) : (
|
||||
<Input value={field.value} disabled />
|
||||
)}
|
||||
</FormControl>
|
||||
<FormMessage className="text-brandbrown" />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
|
||||
|
|
@ -770,11 +684,15 @@ export default function RemoteAssessmentModal({
|
|||
name="addressLineOne"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Address</FormLabel>
|
||||
<FormLabel className="text-gray-800">Address</FormLabel>
|
||||
<FormControl>
|
||||
<Input placeholder="Enter address" {...field} />
|
||||
<Input
|
||||
placeholder="Enter address"
|
||||
{...field}
|
||||
className="border-brandbrown focus-visible:ring-brandbrown focus-visible:border-brandbrown"
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
<FormMessage className="text-brandbrown" />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
|
@ -784,11 +702,17 @@ export default function RemoteAssessmentModal({
|
|||
name="postcode"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Postcode</FormLabel>
|
||||
<FormLabel className="text-gray-800">
|
||||
Postcode
|
||||
</FormLabel>
|
||||
<FormControl>
|
||||
<Input placeholder="Enter postcode" {...field} />
|
||||
<Input
|
||||
placeholder="Enter postcode"
|
||||
{...field}
|
||||
className="border-brandbrown focus-visible:ring-brandbrown focus-visible:border-brandbrown"
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
<FormMessage className="text-brandbrown" />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
|
@ -798,7 +722,7 @@ export default function RemoteAssessmentModal({
|
|||
name="uprn"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>UPRN</FormLabel>
|
||||
<FormLabel className="text-gray-800">UPRN</FormLabel>
|
||||
<FormControl>
|
||||
<Input
|
||||
type="number"
|
||||
|
|
@ -807,9 +731,10 @@ export default function RemoteAssessmentModal({
|
|||
onChange={(e) =>
|
||||
field.onChange(Number(e.target.value))
|
||||
}
|
||||
className="border-brandbrown focus-visible:ring-brandbrown focus-visible:border-brandbrown"
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
<FormMessage className="text-brandbrown" />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
|
@ -819,7 +744,9 @@ export default function RemoteAssessmentModal({
|
|||
name="valuation"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Valuation</FormLabel>
|
||||
<FormLabel className="text-gray-800">
|
||||
Valuation
|
||||
</FormLabel>
|
||||
<FormDescription>
|
||||
The valuation can be found at{" "}
|
||||
<a
|
||||
|
|
@ -840,9 +767,10 @@ export default function RemoteAssessmentModal({
|
|||
onChange={(e) =>
|
||||
field.onChange(Number(e.target.value))
|
||||
}
|
||||
className="border-brandbrown focus-visible:ring-brandbrown focus-visible:border-brandbrown"
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
<FormMessage className="text-brandbrown" />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
|
@ -860,7 +788,7 @@ export default function RemoteAssessmentModal({
|
|||
<FormItem className="w-full">
|
||||
<FormLabel>Property Type</FormLabel>
|
||||
<FormControl>
|
||||
<SelectUpDropdown
|
||||
<SelectDropdown
|
||||
options={propertyTypeOptions}
|
||||
selectedOption={field.value}
|
||||
onSelectOption={(o) => field.onChange(o.value)}
|
||||
|
|
@ -877,7 +805,7 @@ export default function RemoteAssessmentModal({
|
|||
<FormItem className="w-full">
|
||||
<FormLabel>Built Form</FormLabel>
|
||||
<FormControl>
|
||||
<SelectUpDropdown
|
||||
<SelectDropdown
|
||||
options={builtFormOptions}
|
||||
selectedOption={field.value}
|
||||
onSelectOption={(o) => field.onChange(o.value)}
|
||||
|
|
|
|||
|
|
@ -1,80 +0,0 @@
|
|||
import { Menu, Transition } from "@headlessui/react";
|
||||
import { Fragment } from "react";
|
||||
import { Button } from "@/app/shadcn_components/ui/button";
|
||||
import { PlusIcon, ChevronDownIcon } from "@heroicons/react/20/solid";
|
||||
|
||||
export type ScenarioOption = {
|
||||
label: string;
|
||||
value: string;
|
||||
};
|
||||
|
||||
interface ScenarioSelectProps {
|
||||
selectedValue: string | null;
|
||||
onSelect: (option: ScenarioOption) => void;
|
||||
scenarios: ScenarioOption[];
|
||||
}
|
||||
|
||||
export function SelectScenarioDropdown({
|
||||
selectedValue,
|
||||
onSelect,
|
||||
scenarios,
|
||||
}: ScenarioSelectProps) {
|
||||
const createOption: ScenarioOption = {
|
||||
label: "Create new scenario…",
|
||||
value: "__new__",
|
||||
};
|
||||
const options = [createOption, ...scenarios];
|
||||
|
||||
const selectedLabel =
|
||||
options.find((o) => o.value === selectedValue)?.label ||
|
||||
"Select or create...";
|
||||
|
||||
return (
|
||||
<Menu as="div" className="relative w-full text-left">
|
||||
<Menu.Button
|
||||
as={Button}
|
||||
variant="default"
|
||||
className="w-full justify-between bg-brandmidblue text-white"
|
||||
>
|
||||
<span>{selectedLabel}</span>
|
||||
<ChevronDownIcon className="ml-2 h-5 w-5" aria-hidden="true" />
|
||||
</Menu.Button>
|
||||
|
||||
<Transition
|
||||
as={Fragment}
|
||||
enter="transition ease-out duration-150"
|
||||
enterFrom="opacity-0 scale-95"
|
||||
enterTo="opacity-100 scale-100"
|
||||
leave="transition ease-in duration-100"
|
||||
leaveFrom="opacity-100 scale-100"
|
||||
leaveTo="opacity-0 scale-95"
|
||||
>
|
||||
<Menu.Items className="absolute mt-2 w-full bg-white border border-gray-200 rounded-lg shadow-lg z-10">
|
||||
{options.map((opt) => (
|
||||
<Menu.Item key={opt.value}>
|
||||
{({ active }) => (
|
||||
<Button
|
||||
variant="ghost"
|
||||
className={`w-full flex items-center text-left px-4 py-2 ${
|
||||
active ? "bg-brandmidblue text-white" : "text-gray-700"
|
||||
}`}
|
||||
onClick={() => onSelect(opt)}
|
||||
>
|
||||
{opt.value === createOption.value && (
|
||||
<PlusIcon
|
||||
className={`mr-2 h-5 w-5 ${
|
||||
active ? "text-white" : "text-brandmidblue"
|
||||
}`}
|
||||
aria-hidden="true"
|
||||
/>
|
||||
)}
|
||||
{opt.label}
|
||||
</Button>
|
||||
)}
|
||||
</Menu.Item>
|
||||
))}
|
||||
</Menu.Items>
|
||||
</Transition>
|
||||
</Menu>
|
||||
);
|
||||
}
|
||||
|
|
@ -102,7 +102,7 @@ module.exports = {
|
|||
hovertan: "#947750",
|
||||
brandgold: "#f1bb06",
|
||||
hovergold: "#c79d12",
|
||||
brandbrown: "#3d1e05",
|
||||
brandbrown: "#c4a47c",
|
||||
brandmidblue: "#3943b7",
|
||||
brandlightblue: "#00a9f4",
|
||||
border: "hsl(var(--border))",
|
||||
|
|
@ -144,7 +144,7 @@ module.exports = {
|
|||
hoverblue: "#3e4073",
|
||||
brandtan: "#d3b488",
|
||||
hovertan: "#947750",
|
||||
brandbrown: "#3d1e05",
|
||||
brandbrown: "#c4a47c",
|
||||
brandmidblue: "#3943b7",
|
||||
brandlightblue: "#00a9f4",
|
||||
},
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue