From 1b22a14e1595dfbb48b9508905529c8c77f457d5 Mon Sep 17 00:00:00 2001 From: ndom91 Date: Thu, 21 Dec 2023 19:41:15 +0100 Subject: [PATCH] feat: begin converting to next server actions for forms --- src/app/api/categories/route.js | 28 ++----- src/app/categories/actions.jsx | 80 +++++++++++++++++-- src/app/categories/categoryTable.jsx | 40 ++++++++-- src/components/categoryTableRow.jsx | 113 ++++++++++----------------- 4 files changed, 156 insertions(+), 105 deletions(-) diff --git a/src/app/api/categories/route.js b/src/app/api/categories/route.js index 952399f..29c4695 100644 --- a/src/app/api/categories/route.js +++ b/src/app/api/categories/route.js @@ -1,17 +1,7 @@ import prisma from "@/lib/prisma" import { auth } from "../../../../auth" -const verifyAuth = async () => { - const session = await auth() - console.log("AUTH.SESSION", session) - if (!session?.user?.userId) { - return Response(401) - } -} - export async function GET() { - await verifyAuth() - return Response("Hello World!", { status: 200, }) @@ -19,8 +9,6 @@ export async function GET() { // export async function POST(request) { export const POST = auth(async (request) => { - console.log("CATEGORIES.REQ.AUTH", request.auth) - const { userId, data: { name, description }, @@ -46,12 +34,12 @@ export const POST = auth(async (request) => { return Response.json({ data: createResult }) }) -export async function PUT(request) { - await verifyAuth() +export const PUT = auth(async (request) => { const { userId, name, id, description } = await request.json() + console.log("PUT DATA", { userId, name, id, description }) if (!name || !id || !userId) { - return Response( + return new Response( { message: "Missing required field(s)" }, { status: 400, @@ -70,10 +58,10 @@ export async function PUT(request) { }) return Response.json({ data: updateResult }) -} -export async function DELETE(request) { - await verifyAuth() - const { id, userId } = await request.json() +}) + +export const DELETE = auth(async (request) => { + const { userId, id } = await request.json() if (!id || !userId) { return Response( @@ -92,4 +80,4 @@ export async function DELETE(request) { return Response({ message: error }, { status: 500 }) } return Response.json({ message: "Deleted" }) -} +}) diff --git a/src/app/categories/actions.jsx b/src/app/categories/actions.jsx index 351386f..d14084e 100644 --- a/src/app/categories/actions.jsx +++ b/src/app/categories/actions.jsx @@ -37,7 +37,7 @@ const createCategory = async (userId, formData) => { } try { - const addRes = await fetch(`${protocol}${host}/api/categories`, { + const addResponse = await fetch(`${protocol}${host}/api/categories`, { method: "POST", headers: { "Content-Type": "application/json", @@ -47,9 +47,9 @@ const createCategory = async (userId, formData) => { userId, }), }) - if (addRes.ok) { - revalidatePath("/posts") - return addRes.json() + if (addResponse.ok) { + revalidatePath("/categories") + return addResponse.json() } } catch (error) { console.error(error) @@ -59,4 +59,74 @@ const createCategory = async (userId, formData) => { } } -export { createCategory } +const deleteCategory = async (userId, id) => { + const headersList = headers() + const referer = headersList.get("referer") + + const host = new URL(referer).host + const protocol = new URL(referer).protocol + + try { + const deleteResponse = await fetch(`${protocol}${host}/api/categories`, { + method: "DELETE", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ + id, + userId, + }), + }) + if (deleteResponse.ok) { + revalidatePath("/categories") + } + } catch (error) { + console.error(error) + } +} + +const saveCategoryEdit = async ({ name, description, id, userId }) => { + const headersList = headers() + const referer = headersList.get("referer") + + const host = new URL(referer).host + const protocol = new URL(referer).protocol + + try { + if (name.length > 190 || description.length > 190) { + // toast(toastTypes.WARNING, "Category or name too long") + return + } + const editRes = await fetch(`${protocol}${host}/api/categories`, { + method: "PUT", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ + id, + userId, + name, + description, + }), + }) + console.log("EDIT RES", editRes.ok) + console.log("EDIT STATUS", editRes.status) + if (editRes.ok) { + return editRes.json() + // updateCategory(id, { + // name: categoryName, + // description: categoryDesc, + // }) + // toggleEditMode() + // toast(toastTypes.SUCCESS, `Successfully edited "${name}"`) + } else { + return { errors: ["Could not save updated category!"] } + } + } catch (error) { + console.error(error) + return { message: error } + // toast(toastTypes.ERROR, `Error editing "${name}"`) + } +} + +export { createCategory, deleteCategory, saveCategoryEdit } diff --git a/src/app/categories/categoryTable.jsx b/src/app/categories/categoryTable.jsx index 3092e6e..62af9e0 100644 --- a/src/app/categories/categoryTable.jsx +++ b/src/app/categories/categoryTable.jsx @@ -1,6 +1,6 @@ "use client" -import { useState } from "react" +import { useEffect, useState } from "react" import { SubmitButton } from "./submitButton" import CategoryTableRow from "@/components/categoryTableRow" @@ -20,9 +20,30 @@ const breadcrumbs = [ ] export default function CategoryTable({ categories, userId }) { + // const toast = useToast(5000) const createCategoryWithUser = createCategory.bind(null, userId) const [searchString, setSearchString] = useState("") - const toast = useToast(5000) + const [filteredCategories, setFilteredCategories] = useState(categories) + + // Filter search results + useEffect(() => { + if (searchString) { + setFilteredCategories( + categories + .map((cat) => { + if ( + cat.name.includes(searchString) || + cat.description?.toLowerCase().includes(searchString.toLowerCase()) + ) { + return cat + } + }) + .filter(Boolean), + ) + } else { + setFilteredCategories(categories) + } + }, [searchString, categories]) return ( <> @@ -52,6 +73,7 @@ export default function CategoryTable({ categories, userId }) { setSearchString(e.target.value)} className="w-2/3 rounded-md border-2 border-slate-200 px-2 py-1 pl-8 pr-8 text-base text-slate-600 outline-none placeholder:text-slate-200 focus:border-slate-200 focus:ring-2 focus:ring-slate-200 focus:ring-offset-transparent" placeholder="Search for items" @@ -85,8 +107,8 @@ export default function CategoryTable({ categories, userId }) { - {categories?.map((category) => ( - + {filteredCategories?.map((category) => ( + ))} @@ -97,22 +119,24 @@ export default function CategoryTable({ categories, userId }) { - + - diff --git a/src/components/categoryTableRow.jsx b/src/components/categoryTableRow.jsx index a74dbad..0673742 100644 --- a/src/components/categoryTableRow.jsx +++ b/src/components/categoryTableRow.jsx @@ -1,106 +1,73 @@ +"use client" + import { useState } from "react" -import { useSession } from "next-auth/react" import { useToggle } from "react-use" -import { useToast, toastTypes } from "@/lib/hooks" +// import { useToast, toastTypes } from "@/lib/hooks" import { useStore } from "@/lib/store" +import { deleteCategory, saveCategoryEdit } from "../app/categories/actions" +import { useFormStatus } from "react-dom" -export default function CategoryTableRow({ item }) { - const { data: session } = useSession() +export default function CategoryTableRow({ item, userId }) { + const deleteCategoryWithUser = deleteCategory.bind(null, userId) const { id, name, description, createdAt, _count } = item const count = _count?.bookmarks ?? 0 + const { pending } = useFormStatus() + const [editMode, toggleEditMode] = useToggle(false) const [categoryName, setCategoryName] = useState(name) const [categoryDesc, setCategoryDesc] = useState(description) - const [loading, setLoading] = useState(false) - const removeCategory = useStore((state) => state.removeCategory) - const updateCategory = useStore((state) => state.updateCategory) + // const [loading, setLoading] = useState(false) + // const removeCategory = useStore((state) => state.removeCategory) + // const updateCategory = useStore((state) => state.updateCategory) + // const toast = useToast(5000) const settings = useStore((state) => state.settings) - const toast = useToast(5000) - const deleteCategory = async () => { + const handleCategoryEditSave = async (e) => { try { - setLoading(true) - const delRes = await fetch("/api/categories", { - method: "DELETE", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ - id, - userId: session?.user?.userId, - }), + e.preventDefault() + await saveCategoryEdit({ + id: item.id, + name: categoryName, + description: categoryDesc, + userId, }) - if (delRes.status === 200) { - removeCategory(id) - toast(toastTypes.SUCCESS, `Successfully deleted "${name}"`) - } - setLoading(false) - } catch (error) { - console.error(error) - toast(toastTypes.ERROR, `Error deleting "${name}"`) - setLoading(false) - } - } - - const saveEdit = async () => { - try { - if (categoryName.length > 190 || categoryDesc.length > 190) { - toast(toastTypes.WARNING, "Category or name too long") - return - } - const editRes = await fetch("/api/categories", { - method: "PUT", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ - id, - userId: session?.user?.userId, - name: categoryName, - description: categoryDesc, - }), - }) - if (editRes.status === 200) { - updateCategory(id, { - name: categoryName, - description: categoryDesc, - }) - toggleEditMode() - toast(toastTypes.SUCCESS, `Successfully edited "${name}"`) - } - } catch (error) { - console.error(error) - toast(toastTypes.ERROR, `Error editing "${name}"`) + } catch (e) { + console.error(e) + return } + toggleEditMode() } return ( {id} + {count ?? 0} {!editMode ? ( - {categoryName} + {categoryName} ) : ( setCategoryName(e.target.value)} - className="block w-full rounded-lg border-2 border-slate-200 bg-slate-50 p-2 py-1 text-sm text-slate-900 placeholder-slate-300 focus:border-slate-500 focus:ring-slate-500 " + className="block w-full max-w-xl rounded-lg border-2 border-slate-200 bg-slate-50 p-2 py-1 text-sm text-slate-900 placeholder-slate-300 focus:border-slate-500 focus:ring-slate-500" /> )} - + {!editMode ? ( - {categoryDesc} + + {categoryDesc} + ) : ( setCategoryDesc(e.target.value)} @@ -108,8 +75,8 @@ export default function CategoryTableRow({ item }) { /> )} - - + + {createdAt ? new Date(createdAt).toLocaleString(settings.locale) : ""} @@ -121,7 +88,8 @@ export default function CategoryTableRow({ item }) { {!editMode ? ( <>