From eaa9d82384329842465d0ff22516cf2e5bd2d186 Mon Sep 17 00:00:00 2001 From: Khalim Conn-Kowlessar Date: Wed, 20 Nov 2024 16:34:31 +0000 Subject: [PATCH] implemented upload of asset list as csv to s3 --- .../components/RemoteAssesmentModal.tsx | 94 ++++++++++++++++++- 1 file changed, 91 insertions(+), 3 deletions(-) diff --git a/src/app/portfolio/[slug]/components/RemoteAssesmentModal.tsx b/src/app/portfolio/[slug]/components/RemoteAssesmentModal.tsx index 7887f55..600b234 100644 --- a/src/app/portfolio/[slug]/components/RemoteAssesmentModal.tsx +++ b/src/app/portfolio/[slug]/components/RemoteAssesmentModal.tsx @@ -8,6 +8,8 @@ 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 { add } from "cypress/types/lodash"; +import { post } from "cypress/types/jquery"; type Option = { label: string; @@ -113,6 +115,32 @@ export function SelectDropdown({ ); } +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, @@ -146,7 +174,32 @@ function generateS3Keys(userId: string, portfolioId: string) { return { assetListFileKey, valuationDataFileKey }; } -function useCreateRemoteAssessment({ portfolioId }: { portfolioId: string }) { +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 @@ -161,6 +214,25 @@ function useCreateRemoteAssessment({ portfolioId }: { portfolioId: string }) { [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, @@ -169,6 +241,19 @@ function useCreateRemoteAssessment({ portfolioId }: { portfolioId: string }) { 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); @@ -202,7 +287,7 @@ export default function RemoteAssesmentModal({ const [goalValue, setGoalValue] = useState(""); const [addressLineOne, setAddressLineOne] = useState(""); const [postcode, setPostcode] = useState(""); - const [uprn, setUprn] = useState(""); + const [uprn, setUprn] = useState(null); const [valuation, setValuation] = useState(""); const [buttonDisabled, setButtonDisabled] = useState(true); @@ -221,7 +306,7 @@ export default function RemoteAssesmentModal({ } function handleUprnChange(event: React.ChangeEvent) { - setUprn(event.target.value); + setUprn(Number(event.target.value)); } function handleValuationChange(event: React.ChangeEvent) { @@ -231,6 +316,9 @@ export default function RemoteAssesmentModal({ const { handleSubmit, presignedUrlIsLoading, presignedUrlIsError } = useCreateRemoteAssessment({ portfolioId, + uprn, + addressLineOne, + postcode, }); useEffect(() => {