diff --git a/src/app/components/portfolio/AddNew.tsx b/src/app/components/portfolio/AddNew.tsx index 5a347e0..39b6fff 100644 --- a/src/app/components/portfolio/AddNew.tsx +++ b/src/app/components/portfolio/AddNew.tsx @@ -39,13 +39,13 @@ ListItem.displayName = "ListItem"; export default function AddNewDropDown({ isUploadCsvOpen, setIsUploadCsvOpen, - isRemoteAssesmentOpen, - setIsRemoteAssesmentOpen, + isRemoteAssessmentOpen, + setIsRemoteAssessmentOpen, }: { isUploadCsvOpen: boolean; setIsUploadCsvOpen: React.Dispatch>; - isRemoteAssesmentOpen: boolean; - setIsRemoteAssesmentOpen: React.Dispatch>; + isRemoteAssessmentOpen: boolean; + setIsRemoteAssessmentOpen: React.Dispatch>; }) { function handleCickAddUnit() { console.log("Add unit"); @@ -55,8 +55,8 @@ export default function AddNewDropDown({ setIsUploadCsvOpen(!isUploadCsvOpen); } - function handleClickRemoteAssesment() { - setIsRemoteAssesmentOpen(!isRemoteAssesmentOpen); + function handleClickRemoteAssessment() { + setIsRemoteAssessmentOpen(!isRemoteAssessmentOpen); } return ( @@ -71,11 +71,11 @@ export default function AddNewDropDown({ Add Unit - +
- Remote Assesment + Remote Assessment
- Schedule a remote assesment + Schedule a remote assessment
diff --git a/src/app/components/portfolio/Toolbar.tsx b/src/app/components/portfolio/Toolbar.tsx index b375443..c12bbbf 100644 --- a/src/app/components/portfolio/Toolbar.tsx +++ b/src/app/components/portfolio/Toolbar.tsx @@ -13,7 +13,7 @@ import { import AddNewDropDown from "./AddNew"; import { cva } from "class-variance-authority"; import UploadCsvModal from "@/app/portfolio/[slug]/components/UploadCsvModal"; -import RemoteAssesmentModal from "@/app/portfolio/[slug]/components/RemoteAssesmentModal"; +import RemoteAssessmentModal from "@/app/portfolio/[slug]/components/RemoteAssessmentModal"; import { useState } from "react"; import { useRouter } from "next/navigation"; @@ -41,7 +41,7 @@ export function Toolbar({ portfolioId }: ToolbarProps) { } const [modalIsOpen, setModalIsOpen] = useState(false); - const [isRemoteAssesmentOpen, setIsRemoteAssesmentOpen] = useState(false); + const [isRemoteAssessmentOpen, setIsRemoteAssessmentOpen] = useState(false); return ( @@ -73,13 +73,13 @@ export function Toolbar({ portfolioId }: ToolbarProps) { - void; -}; - -const selecthousingTypeOptions = [ - { - label: "Social", - value: "Social", - disabled: false, - }, - { - label: "Private", - value: "Private", - disabled: false, - }, -]; - -const selectGoalOptions = [ - { - label: "Increase EPC", - value: "Increase EPC", - disabled: false, - }, - { - label: "Reduce energy consumption", - value: "Reduce energy consumption", - disabled: false, // TODO: Disable - }, -]; - -const goalValueOptions = [ - { - label: "C", - value: "C", - disabled: false, - }, - { - label: "B", - value: "B", - disabled: false, - }, - { - label: "A", - value: "A", - disabled: false, - }, -]; - -export function SelectDropdown({ - options, - selectedOption, - onSelectOption, -}: DropdownProps) { - return ( - - - - {selectedOption || "Select an option"} - - - - {options.map((option) => ( - - {({ active }) => ( - - )} - - ))} - - - - - ); -} - -async function uploadCsvToS3({ - presignedUrl, - file, -}: { - presignedUrl: string; - file: Blob; -}) { - try { - const response = await fetch(presignedUrl, { - method: "PUT", - body: file, - headers: { "Content-Type": "text/csv" }, - }); - - if (!response.ok) { - console.error(response); - throw new Error("Network response was not ok"); - } - } catch (error) { - console.error(error); - throw new Error("Upload failed."); - } - - return { success: true }; -} - -async function generatePresignedUrl({ - userId, - portfolioId, - fileKey, -}: { - userId: string; - portfolioId: string; - fileKey: string; -}) { - // fileKey is a location in S3 where we want to upload the file - const response = await fetch("/api/upload/csv", { - method: "POST", - body: JSON.stringify({ - userId, - portfolioId, - fileKey, - }), - }); - - if (!response.ok) { - throw new Error("Failed to generate presigned url"); - } - - return response.json(); -} - -function generateS3Keys(userId: string, portfolioId: string) { - const timestamp = new Date().toISOString().replace(/[:.-]/g, ""); - const assetListFileKey = `${userId}/${portfolioId}/${timestamp}/asset_list.csv`; - const valuationDataFileKey = `${userId}/${portfolioId}/${timestamp}/valuation_data.csv`; - return { assetListFileKey, valuationDataFileKey }; -} - -type GenericObject = Record; - -const convertToCSV = (data: T[]): string => { - // Get headers (keys from the first object) - const headers = Object.keys(data[0]) as (keyof T)[]; - - // Create CSV rows - const rows = data.map((row) => - headers.map((header) => row[header]).join(",") - ); - - // Combine headers and rows into CSV string - return [headers.join(","), ...rows].join("\n"); -}; - -function useCreateRemoteAssessment({ - portfolioId, - uprn, - addressLineOne, - postcode, -}: { - portfolioId: string; - uprn: number | null; - addressLineOne: string; - postcode: string; -}) { - // 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. - // 3) Trigger the engine!!!! This is an api at /api/plan/trigger with our body that we looked at in Miro - - // Set up the mutation with react-query, to generate a presigned URL - - const session = useSession(); - const userId = String(session.data?.user.dbId); - - const { assetListFileKey, valuationDataFileKey } = useMemo( - () => generateS3Keys(userId, portfolioId), - [userId, portfolioId] - ); - - const { - mutate: mutateUploadAssetList, - isLoading: uploadAssetListIsLoading, - isError: uploadAssetListIsError, - } = useMutation(uploadCsvToS3, { - onSuccess: (data) => { - console.log("WAS IT A SUCCESS?", data.success); - console.log("TRIGGERING THE ENGINE"); - // This is where we trigger the engine!!! - const body = { - trigger_file_path: assetListFileKey, - }; - // engine API call goes here - }, - onError: (error) => { - console.error(error); - }, - }); - - const { - mutate: mutatePresignedUrl, - isLoading: presignedUrlIsLoading, - isError: presignedUrlIsError, - } = useMutation(generatePresignedUrl, { - onSuccess: (data) => { - console.log(data.url); - // On success, upload to that URL!!!! - const assetList = [ - { - uprn: uprn, - address: addressLineOne, - postcode: postcode, - }, - ]; - const assetListCsvString = convertToCSV(assetList); - const assetListCsv = new Blob([assetListCsvString], { - type: "text/csv", - }); - - mutateUploadAssetList({ presignedUrl: data.url, file: assetListCsv }); - }, - onError: (error) => { - console.error(error); - }, - }); - - function handleSubmit() { - mutatePresignedUrl({ userId, portfolioId, fileKey: assetListFileKey }); - console.log("SUCCESS"); // This is where we would want to trigger some kind of use feedback - } - - return { - handleSubmit, - presignedUrlIsLoading, - presignedUrlIsError, - }; -} - -export default function RemoteAssesmentModal({ - portfolioId, - isOpen, - setIsOpen, -}: { - isOpen: boolean; - setIsOpen: (isOpen: boolean) => void; - portfolioId: string; -}) { - const [scenario, setScenario] = useState(undefined); - const [housingType, sethousingType] = useState(""); - const [selectedGoal, setSelectedGoal] = useState(""); - const [goalValue, setGoalValue] = useState(""); - const [addressLineOne, setAddressLineOne] = useState(""); - const [postcode, setPostcode] = useState(""); - const [uprn, setUprn] = useState(null); - const [valuation, setValuation] = useState(""); - const [buttonDisabled, setButtonDisabled] = useState(true); - - function handleScenarioChange(event: React.ChangeEvent) { - setScenario(event.target.value); - } - - function handleAddressLineOneChange( - event: React.ChangeEvent - ) { - setAddressLineOne(event.target.value); - } - - function handlePostcodeChange(event: React.ChangeEvent) { - setPostcode(event.target.value); - } - - function handleUprnChange(event: React.ChangeEvent) { - setUprn(Number(event.target.value)); - } - - function handleValuationChange(event: React.ChangeEvent) { - setValuation(event.target.value); - } - - const { handleSubmit, presignedUrlIsLoading, presignedUrlIsError } = - useCreateRemoteAssessment({ - portfolioId, - uprn, - addressLineOne, - postcode, - }); - - useEffect(() => { - function handleButtonDisabled(): boolean { - return !( - scenario && - selectedGoal && - housingType && - addressLineOne && - postcode && - uprn && - valuation - ); - } - - setButtonDisabled(handleButtonDisabled()); - }, [ - scenario, - selectedGoal, - housingType, - addressLineOne, - postcode, - uprn, - valuation, - ]); - - return ( - <> - - setIsOpen(false)} - > - -
- - -
-
- - - - {scenario} - -
- Scenario Name - -
-
- - sethousingType(option.value)} - /> -
-
- - setSelectedGoal(option.value)} - /> - {selectedGoal === "Increase EPC" && ( -
- - { - setGoalValue(option.value); - }} - /> -
- )} -
-
- Address Line 1 - -
-
- Postcode - -
-
- UPRN - -
-
- Valuation - -
-
- -
- -
-
-
-
-
-
- - ); -}