game systems: game system pages, game system create
components: moved DevTool to client component
This commit is contained in:
parent
50e5ff0663
commit
56f0442d33
15
actions/GameSystems/create.ts
Normal file
15
actions/GameSystems/create.ts
Normal file
@ -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;
|
||||||
|
};
|
7
actions/GameSystems/deleteAll.ts
Normal file
7
actions/GameSystems/deleteAll.ts
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
"use server";
|
||||||
|
import { prisma } from "@/prisma/prismaClient";
|
||||||
|
|
||||||
|
// DEV TOOL ONLY
|
||||||
|
export async function deleteAllGameSystems() {
|
||||||
|
await prisma.gameSystem.deleteMany();
|
||||||
|
}
|
49
app/game-systems/[id]/page.tsx
Normal file
49
app/game-systems/[id]/page.tsx
Normal file
@ -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 (
|
||||||
|
<>
|
||||||
|
<section className="heading">
|
||||||
|
<h2 className="strapline">Game System</h2>
|
||||||
|
<h1>{gameSystem?.name}</h1>
|
||||||
|
</section>
|
||||||
|
<section>
|
||||||
|
<ul>
|
||||||
|
{gameSystem?.schemas.map((schema) => (
|
||||||
|
<li key={schema.id}>{schema.name}</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
</section>
|
||||||
|
<Sticky sidedness={-1}>
|
||||||
|
<h1>HELLO!</h1>
|
||||||
|
</Sticky>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
26
app/game-systems/client.tsx
Normal file
26
app/game-systems/client.tsx
Normal file
@ -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<PropsWithChildren> = ({ children }) => {
|
||||||
|
const router = useRouter();
|
||||||
|
// DEV TOOL ONLY
|
||||||
|
async function deleteAll() {
|
||||||
|
await deleteAllGameSystems();
|
||||||
|
router.refresh();
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<DevTool id="game-system-home">
|
||||||
|
<button onClick={deleteAll} className="btn-primary bg-lime-600">
|
||||||
|
Delete All Game Systems
|
||||||
|
</button>
|
||||||
|
</DevTool>
|
||||||
|
{children}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
35
app/game-systems/create.tsx
Normal file
35
app/game-systems/create.tsx
Normal file
@ -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 (
|
||||||
|
<form action={create}>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
// {...bind}
|
||||||
|
name="name"
|
||||||
|
placeholder="Create a new game system..."
|
||||||
|
className="w-min"
|
||||||
|
/>
|
||||||
|
<button className="btn-primary p-2 px-2 ml-2" type="submit">
|
||||||
|
Create
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
);
|
||||||
|
}
|
33
app/game-systems/page.tsx
Normal file
33
app/game-systems/page.tsx
Normal file
@ -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 (
|
||||||
|
<GameSystemsClient>
|
||||||
|
<section className="heading">
|
||||||
|
<h2 className="strapline">Tabletop Commander</h2>
|
||||||
|
<h1>Game Systems</h1>
|
||||||
|
</section>
|
||||||
|
<section className="mb-6">
|
||||||
|
<CreateGameSystem />
|
||||||
|
</section>
|
||||||
|
<section className="">
|
||||||
|
<ul>
|
||||||
|
{existingGameSystems.map((g) => (
|
||||||
|
<li key={g.id} className="odd:bg-black/20 p-2 text-lg">
|
||||||
|
<Link href={`/game-systems/${g.id}`}>{g.name}</Link>
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
</section>
|
||||||
|
</GameSystemsClient>
|
||||||
|
);
|
||||||
|
}
|
16
components/devtools/DevTool.tsx
Normal file
16
components/devtools/DevTool.tsx
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { FC, PropsWithChildren, use, useEffect } from "react";
|
||||||
|
import { DevToolboxContext } from "./context";
|
||||||
|
|
||||||
|
export const DevTool: FC<PropsWithChildren<{ id: string }>> = (
|
||||||
|
{ children, id },
|
||||||
|
) => {
|
||||||
|
const { addTool, removeTool } = use(DevToolboxContext);
|
||||||
|
useEffect(() => {
|
||||||
|
addTool(id, children);
|
||||||
|
(() => removeTool(id));
|
||||||
|
}, [addTool, children, id, removeTool]);
|
||||||
|
|
||||||
|
return <></>;
|
||||||
|
};
|
@ -1,5 +1,5 @@
|
|||||||
import { Portal } from "@/lib/portal/components";
|
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 { DevToolboxContext } from "./context";
|
||||||
import { WrenchScrewdriverIcon } from "@heroicons/react/24/solid";
|
import { WrenchScrewdriverIcon } from "@heroicons/react/24/solid";
|
||||||
import { XMarkIcon } from "@heroicons/react/16/solid";
|
import { XMarkIcon } from "@heroicons/react/16/solid";
|
||||||
@ -38,15 +38,3 @@ export const DevToolbox: FC = () => {
|
|||||||
)
|
)
|
||||||
: <></>;
|
: <></>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const DevTool: FC<PropsWithChildren<{ id: string }>> = (
|
|
||||||
{ children, id },
|
|
||||||
) => {
|
|
||||||
const { addTool, removeTool } = use(DevToolboxContext);
|
|
||||||
useEffect(() => {
|
|
||||||
addTool(id, children);
|
|
||||||
(() => removeTool(id));
|
|
||||||
}, [addTool, children, id, removeTool]);
|
|
||||||
|
|
||||||
return <></>;
|
|
||||||
};
|
|
||||||
|
@ -9,20 +9,17 @@ interface IProps {
|
|||||||
export const Portal: FC<PropsWithChildren<IProps>> = (
|
export const Portal: FC<PropsWithChildren<IProps>> = (
|
||||||
{ children, className = "root-portal", el = "div" },
|
{ children, className = "root-portal", el = "div" },
|
||||||
) => {
|
) => {
|
||||||
const [container] = useState(() => {
|
const [container, setContainer] = useState<HTMLElement>();
|
||||||
// This will be executed only on the initial render
|
|
||||||
// https://reactjs.org/docs/hooks-reference.html#lazy-initial-state
|
|
||||||
return document.createElement(el);
|
|
||||||
});
|
|
||||||
|
|
||||||
// todo: this smells. appending the same element?
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
const container = document.createElement(el);
|
||||||
container.classList.add(className);
|
container.classList.add(className);
|
||||||
document.body.appendChild(container);
|
document.body.appendChild(container);
|
||||||
|
setContainer(container);
|
||||||
return () => {
|
return () => {
|
||||||
document.body.removeChild(container);
|
document.body.removeChild(container);
|
||||||
};
|
};
|
||||||
}, [className, container]);
|
}, [className, el]);
|
||||||
|
|
||||||
return createPortal(children, container);
|
return container && createPortal(children, container);
|
||||||
};
|
};
|
||||||
|
13
prisma/prismaClient.ts
Normal file
13
prisma/prismaClient.ts
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
import { PrismaClient } from "@prisma/client";
|
||||||
|
|
||||||
|
const prismaClientSingleton = () => {
|
||||||
|
return new PrismaClient();
|
||||||
|
};
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
var prismaGlobal: undefined | ReturnType<typeof prismaClientSingleton>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const prisma = globalThis.prismaGlobal ?? prismaClientSingleton();
|
||||||
|
|
||||||
|
if (process.env.NODE_ENV !== "production") globalThis.prismaGlobal = prisma;
|
Loading…
x
Reference in New Issue
Block a user