From e5f131c0eea729a3d346419015d337c54bd13609 Mon Sep 17 00:00:00 2001 From: xiften <108333567+not-ani@users.noreply.github.com> Date: Mon, 28 Oct 2024 14:22:28 -0600 Subject: [PATCH] fix(nextjs): create projects now works --- .../permissions/_components/add-user-form.tsx | 2 +- .../app/(home)/_components/all-projects.tsx | 7 ++ .../_components/create-project-dialog.tsx | 17 +-- .../app/(home)/_components/project-card.tsx | 36 ++++++ .../app/(home)/_components/project-grid.tsx | 23 ++++ .../app/(home)/_components/user-projects.tsx | 26 ++++ apps/nextjs/src/app/(home)/_queries/index.ts | 10 +- apps/nextjs/src/app/(home)/layout.tsx | 18 +-- apps/nextjs/src/app/(home)/page.tsx | 119 +++++------------- .../src/app/_components/flow-provider.tsx | 8 +- apps/nextjs/src/components/layout-tabs.tsx | 25 ++-- .../src/components/navbar/switcher/index.tsx | 8 +- apps/nextjs/src/lib/cache.ts | 5 +- packages/api/src/router/projects.ts | 2 + 14 files changed, 167 insertions(+), 139 deletions(-) create mode 100644 apps/nextjs/src/app/(home)/_components/all-projects.tsx create mode 100644 apps/nextjs/src/app/(home)/_components/project-card.tsx create mode 100644 apps/nextjs/src/app/(home)/_components/project-grid.tsx create mode 100644 apps/nextjs/src/app/(home)/_components/user-projects.tsx diff --git a/apps/nextjs/src/app/(dashboard)/project/[id]/(root)/permissions/_components/add-user-form.tsx b/apps/nextjs/src/app/(dashboard)/project/[id]/(root)/permissions/_components/add-user-form.tsx index 424981c..777bd93 100644 --- a/apps/nextjs/src/app/(dashboard)/project/[id]/(root)/permissions/_components/add-user-form.tsx +++ b/apps/nextjs/src/app/(dashboard)/project/[id]/(root)/permissions/_components/add-user-form.tsx @@ -2,7 +2,7 @@ import React, { useState } from "react"; import { revalidateTag } from "next/cache"; -import { useParams, useRouter } from "next/navigation"; +import { useParams } from "next/navigation"; import { zodResolver } from "@hookform/resolvers/zod"; import { CheckIcon } from "lucide-react"; import { useForm } from "react-hook-form"; diff --git a/apps/nextjs/src/app/(home)/_components/all-projects.tsx b/apps/nextjs/src/app/(home)/_components/all-projects.tsx new file mode 100644 index 0000000..fb5435b --- /dev/null +++ b/apps/nextjs/src/app/(home)/_components/all-projects.tsx @@ -0,0 +1,7 @@ +import { findAllProjects } from "../_queries"; +import ProjectGrid from "./project-grid"; + +export default async function AllProjects() { + const allProjects = await findAllProjects(); + return ; +} diff --git a/apps/nextjs/src/app/(home)/_components/create-project-dialog.tsx b/apps/nextjs/src/app/(home)/_components/create-project-dialog.tsx index fe65926..99f74b6 100644 --- a/apps/nextjs/src/app/(home)/_components/create-project-dialog.tsx +++ b/apps/nextjs/src/app/(home)/_components/create-project-dialog.tsx @@ -2,6 +2,7 @@ import type { z } from "zod"; import React, { useState } from "react"; +import { useRouter } from "next/navigation"; import { zodResolver } from "@hookform/resolvers/zod"; import { useForm } from "react-hook-form"; import { toast } from "sonner"; @@ -33,6 +34,7 @@ import { api } from "~/trpc/react"; export function CreateProject() { const [isOpen, setIsOpen] = useState(false); + const router = useRouter(); const form = useForm>({ resolver: zodResolver(formSchema), @@ -43,22 +45,21 @@ export function CreateProject() { }, }); - const utils = api.useUtils(); const createProject = api.projects.create.useMutation({ onSuccess: () => { toast.success("Project created"); form.reset(); - void utils.projects.invalidate(); setIsOpen(false); + router.refresh(); + }, + onError: (error) => { + console.error(error); + toast.error("something went wrong"); }, }); - const onSubmit = async (values: CreateProjectSchema) => { - try { - await createProject.mutateAsync(values); - } catch (error) { - toast.error("Error creating project"); - } + const onSubmit = (values: CreateProjectSchema) => { + createProject.mutate(values); }; return ( diff --git a/apps/nextjs/src/app/(home)/_components/project-card.tsx b/apps/nextjs/src/app/(home)/_components/project-card.tsx new file mode 100644 index 0000000..7d890c6 --- /dev/null +++ b/apps/nextjs/src/app/(home)/_components/project-card.tsx @@ -0,0 +1,36 @@ +import { memo } from "react"; +import Image from "next/image"; +import Link from "next/link"; + +import { Card, CardContent, CardFooter } from "@amaxa/ui/card"; + +interface ProjectCardProps { + project: { + id: string; + name: string; + image: string | null; + }; +} + +const ProjectCard = memo(function ProjectCard({ project }: ProjectCardProps) { + return ( + + + + {project.name} + + +

{project.name}

+
+
+ + ); +}); + +export default ProjectCard; diff --git a/apps/nextjs/src/app/(home)/_components/project-grid.tsx b/apps/nextjs/src/app/(home)/_components/project-grid.tsx new file mode 100644 index 0000000..35f5a41 --- /dev/null +++ b/apps/nextjs/src/app/(home)/_components/project-grid.tsx @@ -0,0 +1,23 @@ +import { memo } from "react"; + +import ProjectCard from "./project-card"; + +const ProjectGrid = memo(function ProjectGrid({ + projects, +}: { + projects: { + id: string; + name: string; + image: string | null; + }[]; +}) { + return ( +
+ {projects.map((project) => ( + + ))} +
+ ); +}); + +export default ProjectGrid; diff --git a/apps/nextjs/src/app/(home)/_components/user-projects.tsx b/apps/nextjs/src/app/(home)/_components/user-projects.tsx new file mode 100644 index 0000000..5d074fa --- /dev/null +++ b/apps/nextjs/src/app/(home)/_components/user-projects.tsx @@ -0,0 +1,26 @@ +import { getUserProjects } from "~/components/navbar/switcher"; +import ProjectGrid from "./project-grid"; + +export default async function UserProjects({ + userId, + userStatus, +}: { + userId: string; + userStatus: string; +}) { + const usersProjects = await getUserProjects(userId); + + if (userStatus === "Pending" || userStatus === "Unverified") { + return ( +
+

+ {userStatus === "Pending" + ? "Your account is pending approval, please wait for the admin to approve your account" + : "Your account is unverified, please wait till we verify your account to access the platform"} +

+
+ ); + } + + return ; +} diff --git a/apps/nextjs/src/app/(home)/_queries/index.ts b/apps/nextjs/src/app/(home)/_queries/index.ts index 9d62964..61b1a0e 100644 --- a/apps/nextjs/src/app/(home)/_queries/index.ts +++ b/apps/nextjs/src/app/(home)/_queries/index.ts @@ -1,11 +1,3 @@ import { db } from "@amaxa/db/client"; -import { next_cache } from "~/lib/cache"; - -export const findAllProjects = next_cache( - async () => await db.query.Projects.findMany({}), - ["findAllProjects"], - { - revalidate: 60 * 60 * 10, - }, -); +export const findAllProjects = () => db.query.Projects.findMany({}); diff --git a/apps/nextjs/src/app/(home)/layout.tsx b/apps/nextjs/src/app/(home)/layout.tsx index 734890f..d9dd796 100644 --- a/apps/nextjs/src/app/(home)/layout.tsx +++ b/apps/nextjs/src/app/(home)/layout.tsx @@ -4,35 +4,21 @@ import { isAdmin } from "@amaxa/api"; import { AppHeader } from "~/components/app-header"; import { AppNav } from "~/components/layout-tabs"; -import { checkAuth } from "~/lib/auth"; -export default async function Layout({ +export default function Layout({ children, modal, }: { children: React.ReactNode; modal: React.ReactNode; }) { - const auth = await checkAuth(); - const links = [ - { href: "/", label: "Projects" }, - { href: "/events", label: "Events" }, - { href: "/guides/action-guides", label: "Guides" }, - isAdmin(auth) - ? { href: "/admin", label: "Admin" } - : { - href: "", - label: "", - }, - ]; - return (
loading..
}> - +
{children}
diff --git a/apps/nextjs/src/app/(home)/page.tsx b/apps/nextjs/src/app/(home)/page.tsx index dab8b13..deb9d09 100644 --- a/apps/nextjs/src/app/(home)/page.tsx +++ b/apps/nextjs/src/app/(home)/page.tsx @@ -1,102 +1,45 @@ -import React from "react"; -import Image from "next/image"; -import Link from "next/link"; +import { Suspense } from "react"; +import dynamic from "next/dynamic"; -import { Card, CardContent, CardFooter, CardHeader } from "@amaxa/ui/card"; - -import { getUserProjects } from "~/components/navbar/switcher"; import { checkAuth } from "~/lib/auth"; -import { CreateProject } from "./_components/create-project-dialog"; -import { findAllProjects } from "./_queries"; +import AllProjects from "./_components/all-projects"; +import UserProjects from "./_components/user-projects"; + +const CreateProject = dynamic( + () => + import("./_components/create-project-dialog").then( + (mod) => mod.CreateProject, + ), + { + loading: () =>

Loading...

, + }, +); export default async function Page() { const session = await checkAuth(); - const [usersProjects, allProjects] = await Promise.all([ - getUserProjects(session.user.id), - findAllProjects(), - ]); return (
-
-
-
-
-

Your Project

- {session.user.role === "Admin" ? : null} -
-
- {session.user.status == "Pending" ? ( - - - Your account is pending approval, please wait for the admin - to approve your account - - - ) : session.user.status == "Unverified" ? ( - - - Your account is unverified, please wait till we verify your - account to access the platform - - - ) : ( -
- {usersProjects.map((project) => { - return ( - - - - {String(project.id)} - - - {project.name} - - - - ); - })} -
- )} -
-
-
-

Explore Projects

-
- {allProjects.map((project) => { - return ( - - - - {String(project.id)} - - - {project.name} - - - - ); - })} -
+
+
+
+

Your Projects

+ {session.user.role === "Admin" && }
+ Loading your projects...
}> + + +
+
+

Explore Projects

+ Loading all projects...
}> + +
); } - -export const dynamic = "force-dynamic"; diff --git a/apps/nextjs/src/app/_components/flow-provider.tsx b/apps/nextjs/src/app/_components/flow-provider.tsx index f52cb69..064c343 100644 --- a/apps/nextjs/src/app/_components/flow-provider.tsx +++ b/apps/nextjs/src/app/_components/flow-provider.tsx @@ -1,4 +1,5 @@ "use client"; +import { SessionProvider } from 'next-auth/react' import React from "react"; import { ReactFlowProvider } from "@xyflow/react"; @@ -11,7 +12,12 @@ import "reactflow/dist/style.css"; function FlowProvider({ children }: { children: React.ReactNode }) { return ( - {children} + + + {children} + + + ); } diff --git a/apps/nextjs/src/components/layout-tabs.tsx b/apps/nextjs/src/components/layout-tabs.tsx index 954f0bb..6982284 100644 --- a/apps/nextjs/src/components/layout-tabs.tsx +++ b/apps/nextjs/src/components/layout-tabs.tsx @@ -5,21 +5,32 @@ import Link from "next/link"; import { usePathname } from "next/navigation"; import * as TabsPrimitive from "@radix-ui/react-tabs"; import { motion } from "framer-motion"; +import { useSession } from "next-auth/react"; import { cn } from "@amaxa/ui"; -interface TabLink { - href: string; - label: string; -} - interface VercelTabsProps { - links?: TabLink[]; className?: string; } -export function AppNav({ links, className }: VercelTabsProps) { +export function AppNav({ className }: VercelTabsProps) { const pathname = usePathname(); + const session = useSession(); + + const links = [ + { href: "/", label: "Projects" }, + { href: "/events", label: "Events" }, + { href: "/guides/action-guides", label: "Guides" }, + session?.data?.user.role === "Admin" + ? { + href: "/admin", + label: "Admin", + } + : { + href: "/", + label: "", + }, + ]; if (!links || links.length === 0) { return null; diff --git a/apps/nextjs/src/components/navbar/switcher/index.tsx b/apps/nextjs/src/components/navbar/switcher/index.tsx index 99f3c2a..872c49f 100644 --- a/apps/nextjs/src/components/navbar/switcher/index.tsx +++ b/apps/nextjs/src/components/navbar/switcher/index.tsx @@ -9,8 +9,8 @@ import { next_cache } from "~/lib/cache"; import { TeamSwitcherClient } from "./team-switcher-client"; export const getUserProjects = next_cache( - async (userId: string) => - await db + (userId: string) => + db .select({ id: Projects.id, name: Projects.name, @@ -20,14 +20,10 @@ export const getUserProjects = next_cache( .where(eq(project_tracker.userId, userId)) .innerJoin(Projects, eq(Projects.id, project_tracker.projectId)), ["getUserProjects"], - { - revalidate: 60 * 60 * 10, // 10 hours, - }, ); export const TeamSwitcher = async () => { const session = await checkAuth(); - const projects = await getUserProjects(session.user.id); return ; diff --git a/apps/nextjs/src/lib/cache.ts b/apps/nextjs/src/lib/cache.ts index 58ca126..6f35881 100644 --- a/apps/nextjs/src/lib/cache.ts +++ b/apps/nextjs/src/lib/cache.ts @@ -1,9 +1,8 @@ -import { cache } from "react"; import { unstable_cache as next_unstable_cache } from "next/cache"; // next_unstable_cache doesn't handle deduplication, so we wrap it in React's cache export const next_cache = ( callback: (...args: Inputs) => Promise, key: string[], - options: { revalidate: number }, -) => cache(next_unstable_cache(callback, key, options)); + options?: { revalidate: number | false }, +) => next_unstable_cache(callback, key, options); diff --git a/packages/api/src/router/projects.ts b/packages/api/src/router/projects.ts index 52bc024..c8e8d5b 100644 --- a/packages/api/src/router/projects.ts +++ b/packages/api/src/router/projects.ts @@ -1,5 +1,6 @@ // import { and, ilike } from "@amaxa/db"; // import { Projects } from "@amaxa/db/schema"; +import { revalidatePath } from "next/cache"; import { TRPCError } from "@trpc/server"; import { z } from "zod"; @@ -27,6 +28,7 @@ export const projectsRouter = createTRPCRouter({ code: "UNAUTHORIZED", message: "You do not have permissions to create a project", }); + revalidatePath("/"); await ctx.db.insert(Projects).values(input); }), forDashboard: protectedProcedure