diff --git a/src/app/api/upload/csv/route.ts b/src/app/api/upload/csv/route.ts index f26e918..faf865d 100644 --- a/src/app/api/upload/csv/route.ts +++ b/src/app/api/upload/csv/route.ts @@ -13,7 +13,7 @@ function generateS3Key(userId: number, portfolioId: number, filename: string) { return key; } -export async function GET(request: NextRequest) { +export async function POST(request: NextRequest) { // For the moment, this api specifically handles uploads of csvs const body = await request.json(); diff --git a/src/app/components/portfolio/Toolbar.tsx b/src/app/components/portfolio/Toolbar.tsx index 3ff9fdf..e3f747f 100644 --- a/src/app/components/portfolio/Toolbar.tsx +++ b/src/app/components/portfolio/Toolbar.tsx @@ -55,7 +55,11 @@ export function Toolbar({ portfolioId }: ToolbarProps) { setIsUploadCsvOpen={setModalIsOpen} /> - + ); } diff --git a/src/app/components/portfolio/UploadCsvModal.tsx b/src/app/components/portfolio/UploadCsvModal.tsx index d91d8d8..2a619e4 100644 --- a/src/app/components/portfolio/UploadCsvModal.tsx +++ b/src/app/components/portfolio/UploadCsvModal.tsx @@ -9,63 +9,119 @@ import { Input } from "@/app/shadcn_components/ui/input"; import { Label } from "@/app/shadcn_components/ui/label"; import { useRouter } from "next/navigation"; import { useMutation } from "@tanstack/react-query"; -import Link from "next/link"; +import { useSession } from "next-auth/react"; + +async function generatePresignedUrl({ + userId, + portfolioId, +}: { + userId: number; + portfolioId: number; +}) { + const body = JSON.stringify({ userId: userId, portfolioId: portfolioId }); + console.log("body before: ", body); + + const presignedResponse = await fetch(`/api/upload/csv`, { + method: "POST", + body: body, + }); + if (!presignedResponse.ok) { + throw new Error("Network response was not ok"); + } + const presignedUrl = await presignedResponse.json(); + return presignedUrl; +} + +async function uploadCsvToS3({ + presignedUrl, + file, +}: { + presignedUrl: string; + file: File; +}) { + console.log("Uploading file to s3"); + const upload = await fetch(presignedUrl, { + method: "PUT", + body: file, + }); + + if (!upload.ok) { + throw new Error("Upload failed."); + } + + return upload; +} export const SubmitPlan = ({ buttonDisabled, goal, housingType, goalValue, + file, + portfolioId, }: { buttonDisabled: boolean; goal: string; housingType: string; goalValue: string; + file: File | null; + portfolioId: number; }) => { const router = useRouter(); + const session = useSession(); + // This state will hold the presignedUrl once it is available + const [presignedUrl, setPresignedUrl] = useState(null); - async function triggerPlanBuild() { - const requestBody = JSON.stringify({ - goal: goal, - goalValue: goalValue, - housingType: housingType, - }); - - const response = await fetch("/api/portfolio/plan", { - method: "POST", - headers: { - "Content-Type": "application/json", + const { mutate: mutateUploadCsv, isLoading: isUploadLoading } = useMutation( + uploadCsvToS3, + { + onSuccess: (data) => { + return data; + }, + onError: (error) => { + // handle error + console.error(error); }, - body: requestBody, - }); - - if (!response.ok) { - throw new Error("Network response was not ok"); } + ); - return response.json(); - } - - const { mutate, isLoading } = useMutation(triggerPlanBuild, { + const { mutate, isLoading } = useMutation(generatePresignedUrl, { onSuccess: (data) => { - console.log("uploading csv"); - // router.push(`/portfolio/${data.id}`); + // After the presigned URL has been generated, we can upload the file to S3 + mutateUploadCsv({ presignedUrl: data.url, file: file }); }, onError: (error) => { // handle error - console.log(error); + console.error(error); }, }); - const handleSubmit = () => { - mutate(); + if (!session.data) { + // The user is not logged in, redirect them to sign in + router.push("/"); + return null; + } + const userId = session.data.user.dbId; + + const handlePlanBuild = () => { + // The plan build is triggered by clicking submit which will: + // 1) Generate a pre-signed url to upload to + // 2) Upload the csv to the pre-signed url + // 3) Trigger the job to build the plan + // 4) Redirect the user to some loading page - this could be the portfolio page itself and we just trigger a regresh with skeleton cards for the properties + mutate({ userId: userId, portfolioId: portfolioId }); + + // mutateUploadCsv(presignedUrl); + + // console.log("Redirect user to loading page"); + // router.push("/portfolio/somewhere"); }; return (