diff --git a/actions/GameSystems/create.ts b/actions/GameSystems/create.ts new file mode 100644 index 0000000..bb5bf9e --- /dev/null +++ b/actions/GameSystems/create.ts @@ -0,0 +1,15 @@ +"use server"; + +import { prisma } from "@/prisma/prismaClient"; + +export const createGameSystem = async (name: string) => { + const { id } = await prisma.gameSystem.create({ + data: { + name, + }, + select: { + id: true, + }, + }); + return id; +}; diff --git a/actions/GameSystems/deleteAll.ts b/actions/GameSystems/deleteAll.ts new file mode 100644 index 0000000..c486aa6 --- /dev/null +++ b/actions/GameSystems/deleteAll.ts @@ -0,0 +1,7 @@ +"use server"; +import { prisma } from "@/prisma/prismaClient"; + +// DEV TOOL ONLY +export async function deleteAllGameSystems() { + await prisma.gameSystem.deleteMany(); +} diff --git a/app/game-systems/[id]/page.tsx b/app/game-systems/[id]/page.tsx new file mode 100644 index 0000000..dbb24d8 --- /dev/null +++ b/app/game-systems/[id]/page.tsx @@ -0,0 +1,49 @@ +import { Sticky } from "@/lib/sticky"; +import { prisma } from "@/prisma/prismaClient"; + +export default async function GameSystem( + { params: { id } }: { params: { id: string } }, +) { + if (!id) throw "HOW DID YOU GET HERE?"; + + const gameSystem = await prisma.gameSystem.findFirst({ + where: { + id, + }, + select: { + id: true, + name: true, + schemas: { + select: { + name: true, + id: true, + publications: { + select: { + name: true, + id: true, + }, + }, + }, + }, + }, + }); + + return ( + <> +
+

Game System

+

{gameSystem?.name}

+
+
+ +
+ +

HELLO!

+
+ + ); +} diff --git a/app/game-systems/client.tsx b/app/game-systems/client.tsx new file mode 100644 index 0000000..81b625a --- /dev/null +++ b/app/game-systems/client.tsx @@ -0,0 +1,26 @@ +"use client"; + +import { deleteAllGameSystems } from "@/actions/GameSystems/deleteAll"; +import { DevTool } from "@/components/devtools/DevTool"; +import { useRouter } from "next/navigation"; +import { FC, PropsWithChildren } from "react"; + +export const GameSystemsClient: FC = ({ children }) => { + const router = useRouter(); + // DEV TOOL ONLY + async function deleteAll() { + await deleteAllGameSystems(); + router.refresh(); + } + + return ( + <> + + + + {children} + + ); +}; diff --git a/app/game-systems/create.tsx b/app/game-systems/create.tsx new file mode 100644 index 0000000..f55a2a1 --- /dev/null +++ b/app/game-systems/create.tsx @@ -0,0 +1,35 @@ +import { prisma } from "@/prisma/prismaClient"; +import { redirect } from "next/navigation"; + +export default function CreateGameSystem() { + async function create(form: FormData) { + "use server"; + + const name = form.get("name")?.toString(); + if (!name) return; + const { id } = await prisma.gameSystem.create({ + data: { + name, + }, + select: { + id: true, + }, + }); + redirect(`/game-systems/${id}`); + } + + return ( +
+ + +
+ ); +} diff --git a/app/game-systems/page.tsx b/app/game-systems/page.tsx new file mode 100644 index 0000000..1d90f58 --- /dev/null +++ b/app/game-systems/page.tsx @@ -0,0 +1,33 @@ +import { prisma } from "@/prisma/prismaClient"; +import CreateGameSystem from "./create"; +import { GameSystemsClient } from "./client"; +import Link from "next/link"; + +export default async function GameSystems() { + const existingGameSystems = await prisma.gameSystem.findMany({ + orderBy: { + created: "asc", + }, + }); + + return ( + +
+

Tabletop Commander

+

Game Systems

+
+
+ +
+
+
    + {existingGameSystems.map((g) => ( +
  • + {g.name} +
  • + ))} +
+
+
+ ); +} diff --git a/components/devtools/DevTool.tsx b/components/devtools/DevTool.tsx new file mode 100644 index 0000000..f1c0539 --- /dev/null +++ b/components/devtools/DevTool.tsx @@ -0,0 +1,16 @@ +"use client"; + +import { FC, PropsWithChildren, use, useEffect } from "react"; +import { DevToolboxContext } from "./context"; + +export const DevTool: FC> = ( + { children, id }, +) => { + const { addTool, removeTool } = use(DevToolboxContext); + useEffect(() => { + addTool(id, children); + (() => removeTool(id)); + }, [addTool, children, id, removeTool]); + + return <>; +}; diff --git a/components/devtools/Toolbox.tsx b/components/devtools/Toolbox.tsx index a45f130..5764377 100644 --- a/components/devtools/Toolbox.tsx +++ b/components/devtools/Toolbox.tsx @@ -1,5 +1,5 @@ import { Portal } from "@/lib/portal/components"; -import { FC, PropsWithChildren, use, useEffect, useState } from "react"; +import { FC, use, useState } from "react"; import { DevToolboxContext } from "./context"; import { WrenchScrewdriverIcon } from "@heroicons/react/24/solid"; import { XMarkIcon } from "@heroicons/react/16/solid"; @@ -38,15 +38,3 @@ export const DevToolbox: FC = () => { ) : <>; }; - -export const DevTool: FC> = ( - { children, id }, -) => { - const { addTool, removeTool } = use(DevToolboxContext); - useEffect(() => { - addTool(id, children); - (() => removeTool(id)); - }, [addTool, children, id, removeTool]); - - return <>; -}; diff --git a/lib/portal/components/index.ts b/lib/portal/components/index.ts index 5d5690a..e0590c2 100644 --- a/lib/portal/components/index.ts +++ b/lib/portal/components/index.ts @@ -9,20 +9,17 @@ interface IProps { export const Portal: FC> = ( { children, className = "root-portal", el = "div" }, ) => { - const [container] = useState(() => { - // This will be executed only on the initial render - // https://reactjs.org/docs/hooks-reference.html#lazy-initial-state - return document.createElement(el); - }); + const [container, setContainer] = useState(); - // todo: this smells. appending the same element? useEffect(() => { + const container = document.createElement(el); container.classList.add(className); document.body.appendChild(container); + setContainer(container); return () => { document.body.removeChild(container); }; - }, [className, container]); + }, [className, el]); - return createPortal(children, container); + return container && createPortal(children, container); }; diff --git a/prisma/prismaClient.ts b/prisma/prismaClient.ts new file mode 100644 index 0000000..ba52e49 --- /dev/null +++ b/prisma/prismaClient.ts @@ -0,0 +1,13 @@ +import { PrismaClient } from "@prisma/client"; + +const prismaClientSingleton = () => { + return new PrismaClient(); +}; + +declare global { + var prismaGlobal: undefined | ReturnType; +} + +export const prisma = globalThis.prismaGlobal ?? prismaClientSingleton(); + +if (process.env.NODE_ENV !== "production") globalThis.prismaGlobal = prisma;