mirror of
https://github.com/Hestia-Homes/assessment-model.git
synced 2026-06-08 11:37:25 +00:00
Working on rough upload csv ui - added float menu for headless-ui
This commit is contained in:
parent
c89060650d
commit
d1ae0c8470
4 changed files with 255 additions and 19 deletions
99
package-lock.json
generated
99
package-lock.json
generated
|
|
@ -8,12 +8,14 @@
|
|||
"name": "assessment-model",
|
||||
"version": "0.1.0",
|
||||
"dependencies": {
|
||||
"@headlessui-float/react": "^0.11.2",
|
||||
"@headlessui/react": "^1.7.14",
|
||||
"@heroicons/react": "^2.0.18",
|
||||
"@radix-ui/react-dialog": "^1.0.4",
|
||||
"@radix-ui/react-hover-card": "^1.0.6",
|
||||
"@radix-ui/react-label": "^2.0.2",
|
||||
"@radix-ui/react-navigation-menu": "^1.1.3",
|
||||
"@radix-ui/react-select": "^1.2.2",
|
||||
"@radix-ui/react-slot": "^1.0.2",
|
||||
"@tanstack/react-query": "^4.29.12",
|
||||
"@types/node": "20.2.3",
|
||||
|
|
@ -1066,6 +1068,20 @@
|
|||
"@floating-ui/core": "^1.2.6"
|
||||
}
|
||||
},
|
||||
"node_modules/@floating-ui/react": {
|
||||
"version": "0.19.2",
|
||||
"resolved": "https://registry.npmjs.org/@floating-ui/react/-/react-0.19.2.tgz",
|
||||
"integrity": "sha512-JyNk4A0Ezirq8FlXECvRtQOX/iBe5Ize0W/pLkrZjfHW9GUV7Xnq6zm6fyZuQzaHHqEnVizmvlA96e1/CkZv+w==",
|
||||
"dependencies": {
|
||||
"@floating-ui/react-dom": "^1.3.0",
|
||||
"aria-hidden": "^1.1.3",
|
||||
"tabbable": "^6.0.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": ">=16.8.0",
|
||||
"react-dom": ">=16.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@floating-ui/react-dom": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.0.0.tgz",
|
||||
|
|
@ -1078,6 +1094,18 @@
|
|||
"react-dom": ">=16.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@floating-ui/react/node_modules/@floating-ui/react-dom": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-1.3.0.tgz",
|
||||
"integrity": "sha512-htwHm67Ji5E/pROEAr7f8IKFShuiCKHwUC/UY4vC3I5jiSvGFAYnSYiZO5MlGmads+QqvUkR9ANHEguGrDv72g==",
|
||||
"dependencies": {
|
||||
"@floating-ui/dom": "^1.2.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": ">=16.8.0",
|
||||
"react-dom": ">=16.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@hapi/hoek": {
|
||||
"version": "9.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.3.0.tgz",
|
||||
|
|
@ -1093,6 +1121,21 @@
|
|||
"@hapi/hoek": "^9.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@headlessui-float/react": {
|
||||
"version": "0.11.2",
|
||||
"resolved": "https://registry.npmjs.org/@headlessui-float/react/-/react-0.11.2.tgz",
|
||||
"integrity": "sha512-ghnA7wOgrSDcLl9O+TTsW7VC7RjivVopt03hHPpKRMAMzV5TLnq8UW0ok6C6xnKb78LRdhCvlaZsvJXcXqb5Yg==",
|
||||
"dependencies": {
|
||||
"@floating-ui/core": "^1.0.0",
|
||||
"@floating-ui/dom": "^1.0.0",
|
||||
"@floating-ui/react": "^0.19.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@headlessui/react": "^1.0.0",
|
||||
"react": "^16 || ^17 || ^18",
|
||||
"react-dom": "^16 || ^17 || ^18"
|
||||
}
|
||||
},
|
||||
"node_modules/@headlessui/react": {
|
||||
"version": "1.7.14",
|
||||
"resolved": "https://registry.npmjs.org/@headlessui/react/-/react-1.7.14.tgz",
|
||||
|
|
@ -1448,6 +1491,14 @@
|
|||
"url": "https://opencollective.com/unts"
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/number": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/number/-/number-1.0.1.tgz",
|
||||
"integrity": "sha512-T5gIdVO2mmPW3NNhjNgEP3cqMXjXL9UbO0BzWcXfvdBs+BohbQxvd/K5hSVKmn9/lbTdsQVKbUcP5WLCwvUbBg==",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.13.10"
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/primitive": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.0.1.tgz",
|
||||
|
|
@ -1871,6 +1922,49 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-select": {
|
||||
"version": "1.2.2",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-select/-/react-select-1.2.2.tgz",
|
||||
"integrity": "sha512-zI7McXr8fNaSrUY9mZe4x/HC0jTLY9fWNhO1oLWYMQGDXuV4UCivIGTxwioSzO0ZCYX9iSLyWmAh/1TOmX3Cnw==",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.13.10",
|
||||
"@radix-ui/number": "1.0.1",
|
||||
"@radix-ui/primitive": "1.0.1",
|
||||
"@radix-ui/react-collection": "1.0.3",
|
||||
"@radix-ui/react-compose-refs": "1.0.1",
|
||||
"@radix-ui/react-context": "1.0.1",
|
||||
"@radix-ui/react-direction": "1.0.1",
|
||||
"@radix-ui/react-dismissable-layer": "1.0.4",
|
||||
"@radix-ui/react-focus-guards": "1.0.1",
|
||||
"@radix-ui/react-focus-scope": "1.0.3",
|
||||
"@radix-ui/react-id": "1.0.1",
|
||||
"@radix-ui/react-popper": "1.1.2",
|
||||
"@radix-ui/react-portal": "1.0.3",
|
||||
"@radix-ui/react-primitive": "1.0.3",
|
||||
"@radix-ui/react-slot": "1.0.2",
|
||||
"@radix-ui/react-use-callback-ref": "1.0.1",
|
||||
"@radix-ui/react-use-controllable-state": "1.0.1",
|
||||
"@radix-ui/react-use-layout-effect": "1.0.1",
|
||||
"@radix-ui/react-use-previous": "1.0.1",
|
||||
"@radix-ui/react-visually-hidden": "1.0.3",
|
||||
"aria-hidden": "^1.1.1",
|
||||
"react-remove-scroll": "2.5.5"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "*",
|
||||
"@types/react-dom": "*",
|
||||
"react": "^16.8 || ^17.0 || ^18.0",
|
||||
"react-dom": "^16.8 || ^17.0 || ^18.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
},
|
||||
"@types/react-dom": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-slot": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.0.2.tgz",
|
||||
|
|
@ -8447,6 +8541,11 @@
|
|||
"url": "https://opencollective.com/unts"
|
||||
}
|
||||
},
|
||||
"node_modules/tabbable": {
|
||||
"version": "6.2.0",
|
||||
"resolved": "https://registry.npmjs.org/tabbable/-/tabbable-6.2.0.tgz",
|
||||
"integrity": "sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew=="
|
||||
},
|
||||
"node_modules/tailwind-merge": {
|
||||
"version": "1.13.2",
|
||||
"resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-1.13.2.tgz",
|
||||
|
|
|
|||
|
|
@ -14,12 +14,14 @@
|
|||
"create_user": "node -r esbuild-register src/app/db/create_user.ts"
|
||||
},
|
||||
"dependencies": {
|
||||
"@headlessui-float/react": "^0.11.2",
|
||||
"@headlessui/react": "^1.7.14",
|
||||
"@heroicons/react": "^2.0.18",
|
||||
"@radix-ui/react-dialog": "^1.0.4",
|
||||
"@radix-ui/react-hover-card": "^1.0.6",
|
||||
"@radix-ui/react-label": "^2.0.2",
|
||||
"@radix-ui/react-navigation-menu": "^1.1.3",
|
||||
"@radix-ui/react-select": "^1.2.2",
|
||||
"@radix-ui/react-slot": "^1.0.2",
|
||||
"@tanstack/react-query": "^4.29.12",
|
||||
"@types/node": "20.2.3",
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
"use client";
|
||||
|
||||
import { Cog6ToothIcon } from "@heroicons/react/24/outline";
|
||||
import { Cog6ToothIcon, CalculatorIcon } from "@heroicons/react/24/outline";
|
||||
import {
|
||||
NavigationMenu,
|
||||
NavigationMenuItem,
|
||||
|
|
@ -24,11 +24,23 @@ export function Toolbar({ portfolioId }: ToolbarProps) {
|
|||
console.log("Settings were clicked, implement me");
|
||||
}
|
||||
|
||||
function handleClickPortfolioPlan() {
|
||||
console.log("Opt Plan was clicked, implement me");
|
||||
}
|
||||
|
||||
const [modalIsOpen, setModalIsOpen] = useState(false);
|
||||
|
||||
return (
|
||||
<NavigationMenu>
|
||||
<NavigationMenuList>
|
||||
<NavigationMenuItem
|
||||
className={navigationMenuTriggerStyle() + " ml-3 mr-2"}
|
||||
onClick={handleClickPortfolioPlan}
|
||||
>
|
||||
<CalculatorIcon className="h-4 w-4 mr-2" />
|
||||
Portfolio Plan
|
||||
</NavigationMenuItem>
|
||||
|
||||
<NavigationMenuItem
|
||||
className={navigationMenuTriggerStyle() + " ml-3 mr-2"}
|
||||
onClick={handleClickSettings}
|
||||
|
|
@ -36,6 +48,7 @@ export function Toolbar({ portfolioId }: ToolbarProps) {
|
|||
<Cog6ToothIcon className="h-4 w-4 mr-2" />
|
||||
Settings
|
||||
</NavigationMenuItem>
|
||||
|
||||
<AddNewDropDown
|
||||
portfolioId={portfolioId}
|
||||
isUploadCsvOpen={modalIsOpen}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,21 @@
|
|||
import { Dialog, Transition } from "@headlessui/react";
|
||||
import { Menu, Dialog, Transition } from "@headlessui/react";
|
||||
import { Fragment, useState } from "react";
|
||||
import { ChevronDownIcon } from "@heroicons/react/20/solid";
|
||||
import { Float } from "@headlessui-float/react";
|
||||
|
||||
import ModalSubmit from "@/app/components/home/ModalSubmit";
|
||||
|
||||
import { Input } from "@/app/shadcn_components/ui/input";
|
||||
import { Label } from "@/app/shadcn_components/ui/label";
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectGroup,
|
||||
SelectItem,
|
||||
SelectLabel,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from "@/app/shadcn_components/ui/select";
|
||||
|
||||
export function InputFile() {
|
||||
return (
|
||||
|
|
@ -15,9 +26,64 @@ export function InputFile() {
|
|||
);
|
||||
}
|
||||
|
||||
interface SelectDropdownProps {
|
||||
options: string[];
|
||||
placeholder: string;
|
||||
onValueChange: (value: string) => void;
|
||||
}
|
||||
|
||||
export function SelectDropdown({
|
||||
options,
|
||||
placeholder,
|
||||
onValueChange,
|
||||
}: SelectDropdownProps) {
|
||||
return (
|
||||
<Menu as="div" className="relative inline-block text-left w-full">
|
||||
<Float>
|
||||
<Menu.Button className="inline-flex justify-center w-full px-4 py-2 text-sm font-medium text-gray-900 bg-gray-200 rounded-md focus:outline-none focus-visible:ring-2 focus-visible:ring-blue-500 focus-visible:ring-opacity-75">
|
||||
{placeholder}
|
||||
<ChevronDownIcon
|
||||
className="ml-2 -mr-1 h-5 w-5 text-gray-500 hover:text-gray-400"
|
||||
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-top right-0 w-full rounded-md shadow-lg bg-white ring-1 ring-black ring-opacity-5 focus:outline-none">
|
||||
{options.map((option, idx) => (
|
||||
<Menu.Item key={idx}>
|
||||
{({ active }) => (
|
||||
<button
|
||||
className={`${
|
||||
active ? "bg-blue-500 text-white" : "text-gray-900"
|
||||
} group flex items-center w-full px-4 py-2 text-sm`}
|
||||
onClick={() => onValueChange(option)}
|
||||
>
|
||||
{option}
|
||||
</button>
|
||||
)}
|
||||
</Menu.Item>
|
||||
))}
|
||||
</Menu.Items>
|
||||
</Transition>
|
||||
</Float>
|
||||
</Menu>
|
||||
);
|
||||
}
|
||||
|
||||
const hiddenInputArrows =
|
||||
"[-moz-appearance:_textfield] [&::-webkit-inner-spin-button]:m-0 [&::-webkit-inner-spin-button]:appearance-none [&::-webkit-outer-spin-button]:m-0 [&::-webkit-outer-spin-button]:appearance-none";
|
||||
|
||||
const selectFundingSchemeOptions = ["None", "SHDF", "ECO4"];
|
||||
const selectGoalOptions = ["None", "Increase EPC", "Reduce energy consumption"];
|
||||
|
||||
export default function UploadCsvModal({
|
||||
isOpen = false,
|
||||
setIsOpen,
|
||||
|
|
@ -25,23 +91,41 @@ export default function UploadCsvModal({
|
|||
isOpen?: boolean;
|
||||
setIsOpen: (isOpen: boolean) => void;
|
||||
}) {
|
||||
// There is a lingering issue with selecting a dropdown inside of a dialog
|
||||
// https://github.com/radix-ui/primitives/issues/1658
|
||||
// This issue will affect shadcn since it's built on top of radix
|
||||
// The problem comes strictly from the select component propagating clicks to the dialog being, causing the
|
||||
// dialog to close
|
||||
|
||||
const [portfolioName, setPortfolioName] = useState("");
|
||||
const [budget, setBudget] = useState<undefined | number>(undefined);
|
||||
const [selectedOutcome, setSelectedOutcome] =
|
||||
useState<string>("Nothing Specific");
|
||||
const [buttonDisabled, setButtonDisabled] = useState(true);
|
||||
const [selectedGoal, setSelectedGoal] = useState<string>("");
|
||||
const [selectedEPC, setSelectedEPC] = useState<string>("");
|
||||
|
||||
function closeModal() {
|
||||
setIsOpen(false);
|
||||
}
|
||||
|
||||
function handlePortfolioNameChange(e: React.ChangeEvent<HTMLInputElement>) {
|
||||
if (e.target.value.length > 0) {
|
||||
setButtonDisabled(false);
|
||||
} else {
|
||||
setButtonDisabled(true);
|
||||
}
|
||||
setPortfolioName(e.target.value);
|
||||
// function handlePortfolioNameChange(e: React.ChangeEvent<HTMLInputElement>) {
|
||||
// if (e.target.value.length > 0) {
|
||||
// setButtonDisabled(false);
|
||||
// } else {
|
||||
// setButtonDisabled(true);
|
||||
// }
|
||||
// setPortfolioName(e.target.value);
|
||||
// }
|
||||
|
||||
function handleGoalChange(value: string) {
|
||||
// e.stopPropagation();
|
||||
console.log(value);
|
||||
setSelectedGoal(value);
|
||||
}
|
||||
|
||||
function handleFundingSchemeChange(e: React.ChangeEvent<HTMLSelectElement>) {
|
||||
setSelectedEPC(e.target.value);
|
||||
}
|
||||
|
||||
return (
|
||||
|
|
@ -87,13 +171,17 @@ export default function UploadCsvModal({
|
|||
Budget
|
||||
<span className="text-red-500">*</span>
|
||||
</label>
|
||||
<p className="text-sm text-gray-500 mb-1">
|
||||
If you don't set a budget, we will aim to minimise cost
|
||||
anyway
|
||||
</p>
|
||||
<input
|
||||
id="csv-upload-budget"
|
||||
type="number"
|
||||
placeholder="Set a budget"
|
||||
required
|
||||
value={portfolioName}
|
||||
onChange={(e) => handlePortfolioNameChange(e)}
|
||||
// value={portfolioName}
|
||||
// onChange={(e) => handlePortfolioNameChange(e)}
|
||||
className="p-2 border border-gray-200 rounded-md focus:outline-none bg-gray-100"
|
||||
/>
|
||||
</div>
|
||||
|
|
@ -106,17 +194,51 @@ export default function UploadCsvModal({
|
|||
Funding Scheme
|
||||
<span className="text-red-500">*</span>
|
||||
</label>
|
||||
<input
|
||||
id="csv-upload-funding-scheme"
|
||||
type="text"
|
||||
placeholder="Choose Funding Scheme"
|
||||
required
|
||||
// value={portfolioName}
|
||||
// onChange={(e) => handlePortfolioNameChange(e)}
|
||||
className="p-2 border border-gray-200 rounded-md focus:outline-none bg-gray-100"
|
||||
<SelectDropdown
|
||||
options={selectFundingSchemeOptions}
|
||||
placeholder="Select a value "
|
||||
onValueChange={handleFundingSchemeChange}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col">
|
||||
<label
|
||||
htmlFor="portfolio-name"
|
||||
className="text-sm font-semibold text-gray-600 mb-1 relative"
|
||||
>
|
||||
Select your goal
|
||||
<span className="text-red-500">*</span>
|
||||
</label>
|
||||
<SelectDropdown
|
||||
options={selectGoalOptions}
|
||||
placeholder="Select a value "
|
||||
onValueChange={handleGoalChange}
|
||||
/>
|
||||
{selectedGoal && (
|
||||
<div className="mt-4">
|
||||
<label
|
||||
htmlFor="csv-upload-epc"
|
||||
className="text-sm font-semibold text-gray-600 mb-1 relative"
|
||||
>
|
||||
Choose a target EPC value
|
||||
<span className="text-red-500">*</span>
|
||||
</label>
|
||||
<Select
|
||||
// id="csv-upload-epc"
|
||||
// placeholder="Select a target EPC value"
|
||||
required
|
||||
value={selectedEPC}
|
||||
// onChange={handleEPCChange}
|
||||
// className="p-2 border border-gray-200 rounded-md focus:outline-none bg-gray-100"
|
||||
>
|
||||
<option value="C">C</option>
|
||||
<option value="B">B</option>
|
||||
<option value="A">A</option>
|
||||
</Select>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col space-y-2">
|
||||
<div className="flex space-x-2">
|
||||
<InputFile />
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue