From 74ac3783b9b4e28bb0d5dbfc6d8461efb246e056 Mon Sep 17 00:00:00 2001 From: Khalim Conn-Kowlessar Date: Thu, 24 Oct 2024 17:00:03 +0100 Subject: [PATCH] adding the basline for the setting api --- src/app/api/portfolio/[portfolioId]/route.ts | 31 +++++ .../settings/PortfolioSettings.tsx | 128 ++++++++++++++++-- .../[slug]/(portfolio)/settings/page.tsx | 16 --- 3 files changed, 146 insertions(+), 29 deletions(-) create mode 100644 src/app/api/portfolio/[portfolioId]/route.ts diff --git a/src/app/api/portfolio/[portfolioId]/route.ts b/src/app/api/portfolio/[portfolioId]/route.ts new file mode 100644 index 0000000..cfec932 --- /dev/null +++ b/src/app/api/portfolio/[portfolioId]/route.ts @@ -0,0 +1,31 @@ +import { db } from "@/app/db/db"; +import { NextRequest, NextResponse } from "next/server"; +import { portfolio } from "@/app/db/schema/portfolio"; +import { and, eq, inArray } from "drizzle-orm"; + +export async function PUT(request: NextRequest) { + const body = await request.json(); + console.log("HI WE MADE IT!!"); + console.log(body); + + const portfolioId = body.portfolioId; + const userId = body.userId; + + delete body.userId; + delete body.portfolioId; + + console.log(body); + + // Update the database + await db.update(portfolio).set(body).where(eq(portfolio.id, portfolioId)); + + // Returning a successful response + return new NextResponse(JSON.stringify({}), { + status: 200, + }); +} + +export async function DELETE(request: NextRequest) { + const body = await request.json(); + console.log("WE BE DELETIN'"); +} diff --git a/src/app/portfolio/[slug]/(portfolio)/settings/PortfolioSettings.tsx b/src/app/portfolio/[slug]/(portfolio)/settings/PortfolioSettings.tsx index d726382..8f17fc2 100644 --- a/src/app/portfolio/[slug]/(portfolio)/settings/PortfolioSettings.tsx +++ b/src/app/portfolio/[slug]/(portfolio)/settings/PortfolioSettings.tsx @@ -1,6 +1,7 @@ "use client"; import { useState } from "react"; +import { useMutation } from "@tanstack/react-query"; import { PortfolioSettingsType } from "../../utils"; import { Button } from "@/app/shadcn_components/ui/button"; import { Input } from "@/app/shadcn_components/ui/input"; @@ -23,6 +24,7 @@ import { } from "@/app/shadcn_components/ui/dialog"; import { PortfolioStatus as PortfolioStatusOptions } from "@/app/db/schema/portfolio"; import { PortfolioGoal as PortfolioGoalOptions } from "@/app/db/schema/portfolio"; +import { useSession } from "next-auth/react"; // dropdown selection component for both goal and status @@ -57,6 +59,74 @@ export function SettingsDropdown({ ); } +type updateSettingsArgs = { + userId: bigint; + portfolioId: string; + name: string | null; + budget: number | string | undefined | null; + goal: (typeof PortfolioGoalOptions)[number] | null; + status: (typeof PortfolioStatusOptions)[number] | null; +}; + +type bodyType = { + userId: string; + portfolioId: string; + name?: string; + budget?: number | string; + goal?: string; + status?: string; +}; + +const updateSettings = async ({ + userId, + portfolioId, + name, + budget, + goal, + status, +}: updateSettingsArgs) => { + // We convert the the bigint to a string since big ints are not serialisable and we don't want to loose precision + + // We will create a js object with the starting values + // We will then update the values that are not null + const body: bodyType = { + userId: userId.toString(), + portfolioId: portfolioId, + }; + + if (name) { + body.name = name; + } + + if (budget) { + body.budget = budget; + } + + if (goal) { + body.goal = goal; + } + + if (status) { + body.status = status; + } + + const requestBody = JSON.stringify(body); + + const response = await fetch(`/api/portfolio/${portfolioId}`, { + method: "PUT", + headers: { + "Content-Type": "application/json", + }, + body: requestBody, + }); + + if (!response.ok) { + throw new Error("Network response was not ok"); + } + + return response.json(); +}; + export default function PortfolioSettings({ portfolioId, portfolioSettingsData, @@ -64,12 +134,21 @@ export default function PortfolioSettings({ portfolioId: string; portfolioSettingsData: PortfolioSettingsType; }) { - // Running in the client + // This is a client component so we can access the session directly + const session = useSession(); + const router = useRouter(); - // Set up state for portfolioName, portfolioBudget, portfolioGoal and portfolioStatus + const { mutate, isLoading } = useMutation(updateSettings, { + onSuccess: () => { + router.refresh(); + }, + onError: (error) => { + // handle error + console.log(error); + }, + }); - // Syntax const [variable, function whos only job is to update the value of variable] = useState(initial value) const [portfolioName, setPortfolioName] = useState( portfolioSettingsData.name ); @@ -92,6 +171,14 @@ export default function PortfolioSettings({ const [deleteConfirmationByName, setDeleteConfirmationByName] = useState(""); + if (!session.data) { + // The user is not logged in, redirect them to sign in + router.push("/"); + return null; + } + + const userId = session.data.user.dbId; + function handleOpenDeleteModal() { setDeleteConfirmationByName(""); setIsDeleteModalOpen(true); @@ -120,10 +207,15 @@ export default function PortfolioSettings({ // The onClick function called to update the NAME in the DB - function handleRenameDb() { - // apiRanameFunction(portfolioSettingsData.name) - // Update portfolioName - router.refresh(); + function handleRename() { + mutate({ + userId, + portfolioId, + name: portfolioName, + budget: null, + goal: null, + status: null, + }); } // BUDGET CHANGING FUNCTIONS @@ -136,10 +228,15 @@ export default function PortfolioSettings({ // The onClick function called to update the BUDGET in the DB - function handleBudgetUpdateDb() { - // apiBudgetChangeFunction(portfolioSettingsData.budget) - // Update portfolioBudget - router.refresh(); + function handleBudgetUpdate() { + mutate({ + userId, + portfolioId, + name: null, + budget: portfolioBudget, + goal: null, + status: null, + }); } // CHANGING GOAL AND STATUS FUNCTIONALITY @@ -162,6 +259,11 @@ export default function PortfolioSettings({ // HTML to render the page + // TODO: 1) Set up the useMutate hook + // 2) Set up the api functions + // 3) add the call to mutate() so that when we submit the form, the data is updated in the DB + // 4) Create the API + return ( <>
@@ -174,7 +276,7 @@ export default function PortfolioSettings({
-
@@ -192,7 +294,7 @@ export default function PortfolioSettings({ />
-
diff --git a/src/app/portfolio/[slug]/(portfolio)/settings/page.tsx b/src/app/portfolio/[slug]/(portfolio)/settings/page.tsx index 533713c..ae3fbe0 100644 --- a/src/app/portfolio/[slug]/(portfolio)/settings/page.tsx +++ b/src/app/portfolio/[slug]/(portfolio)/settings/page.tsx @@ -7,24 +7,8 @@ export default async function PortfolioSettingsPage({ params: { slug: string }; }) { const portfolioId = params.slug; - // fetch data securely on the server - // Stef's page!!!! - // 1) Rename - // 2) Update budget, status, goal - // 3) Delete - much harder - - // fetch data in the server - name, budget, goal, - // pass it to a client component to render and take user input - const portfolioSettingsData = await getPortfolioSettings(portfolioId); - // Get goal options and status options by importing something like this: - // import { - // PortfolioStatus, - // PortfolioGoal, - // } from "./../../db/schema/portfolio"; - // and then pass them to the portfoliosettings component - return ( <>