full e2e behavior, nice
This commit is contained in:
@@ -35,6 +35,10 @@ const App = () => (
|
|||||||
path="/:game"
|
path="/:game"
|
||||||
component={lazy(() => import("./routes/[game]/index"))}
|
component={lazy(() => import("./routes/[game]/index"))}
|
||||||
/>
|
/>
|
||||||
|
<Route
|
||||||
|
path="/:game/:instance"
|
||||||
|
component={lazy(() => import("./routes/[game]/[instance]"))}
|
||||||
|
/>
|
||||||
</Router>
|
</Router>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import {
|
import {
|
||||||
Accessor,
|
Accessor,
|
||||||
createContext,
|
createContext,
|
||||||
|
createEffect,
|
||||||
createResource,
|
createResource,
|
||||||
JSX,
|
JSX,
|
||||||
Show,
|
Show,
|
||||||
@@ -11,7 +12,7 @@ import Hand from "./Hand";
|
|||||||
import Pile from "./Pile";
|
import Pile from "./Pile";
|
||||||
import { GameState, newDeck, shuffle, Hand as THand } from "../types/cards";
|
import { GameState, newDeck, shuffle, Hand as THand } from "../types/cards";
|
||||||
import { createStore, produce, SetStoreFunction, Store } from "solid-js/store";
|
import { createStore, produce, SetStoreFunction, Store } from "solid-js/store";
|
||||||
import { getGameState, updateGameState } from "../db/Instances";
|
import api from "../api";
|
||||||
|
|
||||||
export const GameContext = createContext<{
|
export const GameContext = createContext<{
|
||||||
gameState: Accessor<GameState | undefined>;
|
gameState: Accessor<GameState | undefined>;
|
||||||
@@ -19,17 +20,24 @@ export const GameContext = createContext<{
|
|||||||
}>();
|
}>();
|
||||||
|
|
||||||
export default (props: { instanceId: number }) => {
|
export default (props: { instanceId: number }) => {
|
||||||
const [gameState, { refetch }] = createResource(() =>
|
const [gameState, { refetch }] = createResource<GameState>(() =>
|
||||||
getGameState(props.instanceId)
|
api.gameState[":gameId"]
|
||||||
|
.$get({ param: { gameId: props.instanceId.toString() } })
|
||||||
|
.then((res) => res.json())
|
||||||
);
|
);
|
||||||
|
|
||||||
const setGameState = (state: GameState) =>
|
const setGameState = (state: GameState) =>
|
||||||
updateGameState(props.instanceId, state).then(refetch);
|
api.gameState[":gameId"]
|
||||||
|
.$put({
|
||||||
|
param: { gameId: props.instanceId.toString() },
|
||||||
|
json: state,
|
||||||
|
})
|
||||||
|
.then(refetch);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<GameContext.Provider value={{ gameState, setGameState }}>
|
<GameContext.Provider value={{ gameState, setGameState }}>
|
||||||
<Show when={gameState() != undefined}>
|
<Show when={gameState() != undefined}>
|
||||||
<div
|
<div
|
||||||
onClick={() => {}}
|
|
||||||
class="full column center"
|
class="full column center"
|
||||||
style={{ "row-gap": "20px", "font-size": "32px" }}
|
style={{ "row-gap": "20px", "font-size": "32px" }}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ import { A, useParams } from "@solidjs/router";
|
|||||||
|
|
||||||
import { createEffect, createResource, Show, Suspense } from "solid-js";
|
import { createEffect, createResource, Show, Suspense } from "solid-js";
|
||||||
import Game from "../../components/Game";
|
import Game from "../../components/Game";
|
||||||
import { getGameState } from "../../db/Instances";
|
|
||||||
|
|
||||||
export default () => {
|
export default () => {
|
||||||
const params = useParams<{ game: string; instance: string }>();
|
const params = useParams<{ game: string; instance: string }>();
|
||||||
|
|||||||
@@ -1,32 +1,27 @@
|
|||||||
import { A, useParams } from "@solidjs/router";
|
import { A, useParams } from "@solidjs/router";
|
||||||
|
|
||||||
import { createEffect, createResource, For, Suspense } from "solid-js";
|
import { createEffect, createResource, For, Suspense } from "solid-js";
|
||||||
import * as Instance from "../../db/Instances";
|
import api from "../../api";
|
||||||
|
|
||||||
export default () => {
|
export default () => {
|
||||||
const params = useParams<{ game: string }>();
|
const param = useParams<{ game: string }>();
|
||||||
|
|
||||||
const [instances, { refetch }] = createResource(
|
const [instances, { refetch }] = createResource(
|
||||||
() => params.game,
|
() => param.game,
|
||||||
() => Instance.queryInstances(params.game)
|
async () =>
|
||||||
|
api.instances.$get({ query: param }).then((res) => res.json())
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Suspense>
|
<Suspense>
|
||||||
<div style={{ padding: "20px" }}>
|
<div style={{ padding: "20px" }}>
|
||||||
<h1 style={{ margin: 0 }}>{params.game}</h1>
|
<h1 style={{ margin: 0 }}>{param.game}</h1>
|
||||||
<button
|
<button onClick={() => null}>New Game</button>
|
||||||
onClick={() =>
|
|
||||||
Instance.createInstance(params.game).then(refetch)
|
|
||||||
}
|
|
||||||
>
|
|
||||||
New Game
|
|
||||||
</button>
|
|
||||||
<ul>
|
<ul>
|
||||||
<For each={instances() ?? []}>
|
<For each={instances() ?? []}>
|
||||||
{(instance) => (
|
{(instance) => (
|
||||||
<li>
|
<li>
|
||||||
<A href={`/${params.game}/${instance.id}`}>
|
<A href={`/${param.game}/${instance.id}`}>
|
||||||
{instance.id}
|
{instance.id}
|
||||||
</A>
|
</A>
|
||||||
</li>
|
</li>
|
||||||
|
|||||||
@@ -1,19 +1,17 @@
|
|||||||
import { A } from "@solidjs/router";
|
import { A } from "@solidjs/router";
|
||||||
import { createEffect, createResource, For } from "solid-js";
|
import { createEffect, createResource, For } from "solid-js";
|
||||||
import * as Games from "../db/Games";
|
|
||||||
import api from "../api";
|
import api from "../api";
|
||||||
|
|
||||||
export default () => {
|
export default () => {
|
||||||
const [ping] = createResource(async () =>
|
const [games] = createResource(async () =>
|
||||||
api.ping.$get().then(async (res) => await res.text())
|
api.games.$get().then((res) => res.json())
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div style={{ padding: "20px" }}>
|
<div style={{ padding: "20px" }}>
|
||||||
{ping()}
|
<For each={games()}>
|
||||||
{/* <For each={games()}>
|
|
||||||
{(game) => <A href={`/${game.name}`}>{game.name}</A>}
|
{(game) => <A href={`/${game.name}`}>{game.name}</A>}
|
||||||
</For> */}
|
</For>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -9,8 +9,10 @@
|
|||||||
"start": "NODE_ENV=production bun run --port 5001 src/index.ts"
|
"start": "NODE_ENV=production bun run --port 5001 src/index.ts"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@hono/zod-validator": "^0.7.2",
|
||||||
"@prisma/client": "6.13.0",
|
"@prisma/client": "6.13.0",
|
||||||
"hono": "^4.8.12"
|
"hono": "^4.8.12",
|
||||||
|
"zod": "^4.0.15"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/bun": "latest",
|
"@types/bun": "latest",
|
||||||
|
|||||||
@@ -1,6 +1,68 @@
|
|||||||
import { Hono } from "hono";
|
import { Hono } from "hono";
|
||||||
|
import { prisma } from "./db/db";
|
||||||
|
import { zValidator } from "@hono/zod-validator";
|
||||||
|
import { z } from "zod";
|
||||||
|
|
||||||
const api = new Hono().get("/ping", (c) => c.text("pong"));
|
const api = new Hono()
|
||||||
|
.get("/ping", (c) => c.text("pong"))
|
||||||
|
|
||||||
|
.get("/games", async (c) => {
|
||||||
|
const games = await prisma.game.findMany();
|
||||||
|
return c.json(games);
|
||||||
|
})
|
||||||
|
|
||||||
|
.get(
|
||||||
|
"/instances",
|
||||||
|
zValidator("query", z.object({ game: z.string() })),
|
||||||
|
async (c) => {
|
||||||
|
const { game } = c.req.valid("query");
|
||||||
|
const instances = await prisma.instance.findMany({
|
||||||
|
where: {
|
||||||
|
game: {
|
||||||
|
name: game,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
select: {
|
||||||
|
id: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
return c.json(instances);
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
.get(
|
||||||
|
"/gameState/:gameId",
|
||||||
|
zValidator("param", z.object({ gameId: z.string() })),
|
||||||
|
async (c) => {
|
||||||
|
const { gameId } = c.req.valid("param");
|
||||||
|
const instance = await prisma.instance.findUnique({
|
||||||
|
where: {
|
||||||
|
id: Number(gameId),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
return c.json(instance?.gameState);
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
.put(
|
||||||
|
"/gameState/:gameId",
|
||||||
|
zValidator("param", z.object({ gameId: z.string() }), (result) => {
|
||||||
|
console.log(JSON.stringify(result, null, 2));
|
||||||
|
}),
|
||||||
|
zValidator("json", z.any()),
|
||||||
|
async (c) => {
|
||||||
|
const { gameId } = c.req.valid("param");
|
||||||
|
const gameState = c.req.valid("json");
|
||||||
|
|
||||||
|
await prisma.instance.update({
|
||||||
|
data: { gameState },
|
||||||
|
where: {
|
||||||
|
id: Number(gameId),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return c.text("", 200);
|
||||||
|
}
|
||||||
|
);
|
||||||
export default api;
|
export default api;
|
||||||
export type ApiType = typeof api;
|
export type ApiType = typeof api;
|
||||||
|
|||||||
22
pnpm-lock.yaml
generated
22
pnpm-lock.yaml
generated
@@ -29,12 +29,18 @@ importers:
|
|||||||
|
|
||||||
packages/server:
|
packages/server:
|
||||||
dependencies:
|
dependencies:
|
||||||
|
'@hono/zod-validator':
|
||||||
|
specifier: ^0.7.2
|
||||||
|
version: 0.7.2(hono@4.8.12)(zod@4.0.15)
|
||||||
'@prisma/client':
|
'@prisma/client':
|
||||||
specifier: 6.13.0
|
specifier: 6.13.0
|
||||||
version: 6.13.0(prisma@6.13.0)
|
version: 6.13.0(prisma@6.13.0)
|
||||||
hono:
|
hono:
|
||||||
specifier: ^4.8.12
|
specifier: ^4.8.12
|
||||||
version: 4.8.12
|
version: 4.8.12
|
||||||
|
zod:
|
||||||
|
specifier: ^4.0.15
|
||||||
|
version: 4.0.15
|
||||||
devDependencies:
|
devDependencies:
|
||||||
'@types/bun':
|
'@types/bun':
|
||||||
specifier: latest
|
specifier: latest
|
||||||
@@ -289,6 +295,12 @@ packages:
|
|||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [win32]
|
os: [win32]
|
||||||
|
|
||||||
|
'@hono/zod-validator@0.7.2':
|
||||||
|
resolution: {integrity: sha512-ub5eL/NeZ4eLZawu78JpW/J+dugDAYhwqUIdp9KYScI6PZECij4Hx4UsrthlEUutqDDhPwRI0MscUfNkvn/mqQ==}
|
||||||
|
peerDependencies:
|
||||||
|
hono: '>=3.9.0'
|
||||||
|
zod: ^3.25.0 || ^4.0.0
|
||||||
|
|
||||||
'@jridgewell/gen-mapping@0.3.12':
|
'@jridgewell/gen-mapping@0.3.12':
|
||||||
resolution: {integrity: sha512-OuLGC46TjB5BbN1dH8JULVVZY4WTdkF7tV9Ys6wLL1rubZnCMstOhNHueU5bLCrnRuDhKPDM4g6sw4Bel5Gzqg==}
|
resolution: {integrity: sha512-OuLGC46TjB5BbN1dH8JULVVZY4WTdkF7tV9Ys6wLL1rubZnCMstOhNHueU5bLCrnRuDhKPDM4g6sw4Bel5Gzqg==}
|
||||||
|
|
||||||
@@ -958,6 +970,9 @@ packages:
|
|||||||
resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==}
|
resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==}
|
||||||
engines: {node: '>=12'}
|
engines: {node: '>=12'}
|
||||||
|
|
||||||
|
zod@4.0.15:
|
||||||
|
resolution: {integrity: sha512-2IVHb9h4Mt6+UXkyMs0XbfICUh1eUrlJJAOupBHUhLRnKkruawyDddYRCs0Eizt900ntIMk9/4RksYl+FgSpcQ==}
|
||||||
|
|
||||||
snapshots:
|
snapshots:
|
||||||
|
|
||||||
'@ampproject/remapping@2.3.0':
|
'@ampproject/remapping@2.3.0':
|
||||||
@@ -1154,6 +1169,11 @@ snapshots:
|
|||||||
'@esbuild/win32-x64@0.25.8':
|
'@esbuild/win32-x64@0.25.8':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
|
'@hono/zod-validator@0.7.2(hono@4.8.12)(zod@4.0.15)':
|
||||||
|
dependencies:
|
||||||
|
hono: 4.8.12
|
||||||
|
zod: 4.0.15
|
||||||
|
|
||||||
'@jridgewell/gen-mapping@0.3.12':
|
'@jridgewell/gen-mapping@0.3.12':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@jridgewell/sourcemap-codec': 1.5.4
|
'@jridgewell/sourcemap-codec': 1.5.4
|
||||||
@@ -1778,3 +1798,5 @@ snapshots:
|
|||||||
string-width: 4.2.3
|
string-width: 4.2.3
|
||||||
y18n: 5.0.8
|
y18n: 5.0.8
|
||||||
yargs-parser: 21.1.1
|
yargs-parser: 21.1.1
|
||||||
|
|
||||||
|
zod@4.0.15: {}
|
||||||
|
|||||||
Reference in New Issue
Block a user