Files
games/packages/client/src/components/Game.tsx
2025-08-20 21:56:23 -04:00

96 lines
2.1 KiB
TypeScript

import {
Accessor,
createContext,
createEffect,
createResource,
createSignal,
For,
onCleanup,
Resource,
ResourceReturn,
Show,
untrack,
} from "solid-js";
import {
GameState,
Action,
vGameState,
PlayerView,
} from "../../../server/src/games/simple";
import api from "../api";
import Hand from "./Hand";
import Pile from "./Pile";
import { ApiType } from "../fn";
import { createStore } from "solid-js/store";
export const GameContext = createContext<{
view: Accessor<PlayerView | undefined>;
submitAction: (action: Action) => Promise<any>;
}>();
const [playerProfiles, setPlayerProfiles] = createStore<
Record<string, Resource<ApiType<typeof api.profile.get>>>
>({});
export default (props: { tableKey: string }) => {
const [view, setView] = createSignal<PlayerView>();
const [players, setPlayers] = createSignal<string[]>([]);
createEffect(() => {
players().forEach((player) => {
if (!untrack(() => playerProfiles[player])) {
const [playerProfile] = createResource(() =>
api.profile
.get({ query: { otherHumanKey: player } })
.then((r) => r.data)
);
setPlayerProfiles((prev) => ({
...prev,
[player]: playerProfile,
}));
}
});
});
const ws = api(props).subscribe;
onCleanup(() => ws.close());
ws.on("message", (evt) => {
if (evt.data.players) {
setPlayers(evt.data.players);
}
if (evt.data.view) {
setView(evt.data.view);
}
});
const submitAction = (action: Action) => api.simple(props).post({ action });
const Lobby = () => {
return (
<div class="fixed tc mt-20 flex flex-col items-center">
<button class="button p-1 m-10">Start Game!</button>
<For each={players()}>
{(player) => (
<p style={{ "font-size": "2em" }}>
{playerProfiles[player]?.()?.name}
</p>
)}
</For>
</div>
);
};
return (
<GameContext.Provider value={{ view, submitAction }}>
<Show when={view() != undefined} fallback={<Lobby />}>
<Pile
count={view()!.deckCount}
class="cursor-pointer fixed center"
onClick={() => submitAction({ type: "draw" })}
/>
<Hand class="fixed bc" hand={view()!.myHand} />
</Show>
</GameContext.Provider>
);
};