From 72ac1ccf38f22202724e56affe5cef3d03902fb8 Mon Sep 17 00:00:00 2001 From: Josh Payette Date: Thu, 2 Jul 2026 11:54:03 -0400 Subject: [PATCH] Added initial build types --- .../pages/created-builds/CreatedBuilds.tsx | 5 ++- src/features/game/data/build-fields.ts | 41 ------------------- src/features/game/data/types.ts | 22 ++++++---- src/features/game/data/utils.ts | 23 +++++++++++ src/features/theme/ThemeModal.tsx | 3 +- src/games/remnant2/data/created-builds.ts | 6 +-- .../data/server/created-builds.server.ts | 9 +--- .../data/server/created-builds.sync.server.ts | 9 +--- .../remnant2/data/server/created-builds.ts | 7 +--- 9 files changed, 47 insertions(+), 78 deletions(-) delete mode 100644 src/features/game/data/build-fields.ts create mode 100644 src/features/game/data/utils.ts diff --git a/src/components/pages/created-builds/CreatedBuilds.tsx b/src/components/pages/created-builds/CreatedBuilds.tsx index 517d001..23b52d3 100644 --- a/src/components/pages/created-builds/CreatedBuilds.tsx +++ b/src/components/pages/created-builds/CreatedBuilds.tsx @@ -16,6 +16,7 @@ import type { } from "#/features/game/data/types.ts"; import type { ProfileTabViewMode } from "#/features/game/types.ts"; import { useGameId } from "#/features/game/use-game-id.ts"; +import type { BuildVisibility, GameId } from "@/prisma"; import { useCreatedBuilds } from "./use-created-builds.ts"; type CreatedBuildsPageProps = { @@ -23,7 +24,7 @@ type CreatedBuildsPageProps = { viewMode: ProfileTabViewMode; }; -const VISIBILITY_COLORS: Record = { +const VISIBILITY_COLORS: Record = { PUBLIC: "green", UNLISTED: "yellow", PRIVATE: "gray", @@ -34,7 +35,7 @@ const BuildCard = ({ gameId, }: { build: CreatedBuildSummary; - gameId: string; + gameId: GameId; }) => { const imageSrc = build.thumbnailUrl ?? build.imageUrl ?? undefined; return ( diff --git a/src/features/game/data/build-fields.ts b/src/features/game/data/build-fields.ts deleted file mode 100644 index 7e69925..0000000 --- a/src/features/game/data/build-fields.ts +++ /dev/null @@ -1,41 +0,0 @@ -// Prisma-free definition of a build's user-editable fields. Shared by the client -// DAL (local IDB write), the server functions, and the sync handler so all three -// write exactly the same set of fields. Must NOT import `@/prisma` — it is pulled -// into the client bundle via the DAL. - -/** The mutable fields a user can edit on a build (visibility kept as a string here). */ -type BuildWriteFields = { - name?: string; - description?: string | null; - visibility?: string; - videoUrl?: string | null; - imageUrl?: string | null; - thumbnailUrl?: string | null; - referenceUrl?: string | null; - gameVersion?: string | null; -}; - -const BUILD_WRITE_KEYS = [ - "name", - "description", - "visibility", - "videoUrl", - "imageUrl", - "thumbnailUrl", - "referenceUrl", - "gameVersion", -] as const; - -/** Picks only the defined build-write fields from an input object (drops `buildId`, undefined). */ -const extractBuildWriteFields = ( - input: Record, -): BuildWriteFields => { - const out: Record = {}; - for (const key of BUILD_WRITE_KEYS) { - if (input[key] !== undefined) out[key] = input[key]; - } - return out as BuildWriteFields; -}; - -export type { BuildWriteFields }; -export { BUILD_WRITE_KEYS, extractBuildWriteFields }; diff --git a/src/features/game/data/types.ts b/src/features/game/data/types.ts index 3ad56cf..b2d1789 100644 --- a/src/features/game/data/types.ts +++ b/src/features/game/data/types.ts @@ -1,9 +1,5 @@ -// Plain data types shared by the per-entity data modules and the generic UI -// components. No coupling to any data-access abstraction — these are just the -// record/input shapes plus the "hooks bundle" contracts a game exposes to the -// generic ItemList / CreatedBuilds pages. - import type { UseMutationResult, UseQueryResult } from "@tanstack/react-query"; +import type { BuildVisibility } from "@/prisma"; export type CollectItemInput = { itemId: string; itemName: string }; @@ -13,12 +9,24 @@ export type CollectedItemRecord = { updatedAt?: Date | string | null; }; +/** The mutable fields a user can edit on a build. */ +export type BuildWriteFields = { + name?: string; + description?: string | null; + visibility?: BuildVisibility; + videoUrl?: string | null; + imageUrl?: string | null; + thumbnailUrl?: string | null; + referenceUrl?: string | null; + gameVersion?: string | null; +}; + /** Lightweight row for build lists (profile tabs, cards). */ export type CreatedBuildSummary = { id: string; name: string; createdById: string | null; - visibility: string; + visibility: BuildVisibility; imageUrl?: string | null; thumbnailUrl?: string | null; createdAt?: Date | string | null; @@ -42,7 +50,7 @@ export type UpdateBuildInput = { buildId: string; name?: string; description?: string | null; - visibility?: string; + visibility?: BuildVisibility; videoUrl?: string | null; imageUrl?: string | null; thumbnailUrl?: string | null; diff --git a/src/features/game/data/utils.ts b/src/features/game/data/utils.ts new file mode 100644 index 0000000..27e1ae1 --- /dev/null +++ b/src/features/game/data/utils.ts @@ -0,0 +1,23 @@ +import type { BuildWriteFields } from "#/features/game/data/types.ts"; + +const BUILD_WRITE_KEYS = [ + "name", + "description", + "visibility", + "videoUrl", + "imageUrl", + "thumbnailUrl", + "referenceUrl", + "gameVersion", +] as const; + +/** Picks only the defined build-write fields from an input object (drops `buildId`, undefined). */ +export const extractBuildWriteFields = ( + input: Record, +): BuildWriteFields => { + const out: Record = {}; + for (const key of BUILD_WRITE_KEYS) { + if (input[key] !== undefined) out[key] = input[key]; + } + return out as BuildWriteFields; +}; diff --git a/src/features/theme/ThemeModal.tsx b/src/features/theme/ThemeModal.tsx index f697b58..58da572 100644 --- a/src/features/theme/ThemeModal.tsx +++ b/src/features/theme/ThemeModal.tsx @@ -18,6 +18,7 @@ import { parseColorScheme, } from "#/features/theme/utils.ts"; import { getGameTheme } from "#/registry/game-public-registry.tsx"; +import type { GameId } from "@/prisma"; // This feature was game-aware, need to rework it const allThemeDefinitions: Array<{ label: string; className: string }> = @@ -27,7 +28,7 @@ const allThemeDefinitions: Array<{ label: string; className: string }> = const allThemeClassNames: string[] = getAllRegisteredThemeClassNames(); type ThemeModalProps = { - gameId: string | undefined; + gameId: GameId | undefined; }; const ThemeModal = ({ gameId }: ThemeModalProps) => { diff --git a/src/games/remnant2/data/created-builds.ts b/src/games/remnant2/data/created-builds.ts index c81a223..0c0f43c 100644 --- a/src/games/remnant2/data/created-builds.ts +++ b/src/games/remnant2/data/created-builds.ts @@ -1,10 +1,5 @@ -// Remnant 2 created builds: client data hooks. Each hook inlines the backend -// choice (remote when authed + online, else local IndexedDB) and, on the local -// path, mirrors the write to IDB and enqueues a pending op for later sync. - import { useNetwork } from "@mantine/hooks"; import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; -import { extractBuildWriteFields } from "#/features/game/data/build-fields.ts"; import type { CreatedBuildRecord, CreatedBuildSummary, @@ -12,6 +7,7 @@ import type { GameCreatedBuildsData, UpdateBuildInput, } from "#/features/game/data/types.ts"; +import { extractBuildWriteFields } from "#/features/game/data/utils.ts"; import { getOrCreateAnonUserId } from "#/features/sync/local-data/identity/anon-id.ts"; import { enqueueOp } from "#/features/sync/local-data/queue/pending-ops.ts"; import { diff --git a/src/games/remnant2/data/server/created-builds.server.ts b/src/games/remnant2/data/server/created-builds.server.ts index 45a3a8d..a3041a3 100644 --- a/src/games/remnant2/data/server/created-builds.server.ts +++ b/src/games/remnant2/data/server/created-builds.server.ts @@ -1,12 +1,5 @@ -// Remnant 2 created builds: server-only data access (Postgres via Prisma). Build -// CRUD is written out here rather than hidden behind a factory; the ownership- -// scoped `updateOwnedBuild` write is shared with the offline-sync handler, which -// lives alongside in created-builds.sync.server.ts. The `.server.ts` suffix opts -// this into Start's import protection, keeping prisma out of the client bundle. -// Consumed by the created-builds server-fn wrappers (inside their handlers). - -import type { BuildWriteFields } from "#/features/game/data/build-fields.ts"; import type { + BuildWriteFields, CreatedBuildRecord, CreatedBuildSummary, } from "#/features/game/data/types.ts"; diff --git a/src/games/remnant2/data/server/created-builds.sync.server.ts b/src/games/remnant2/data/server/created-builds.sync.server.ts index 923d0d2..0e54cf5 100644 --- a/src/games/remnant2/data/server/created-builds.sync.server.ts +++ b/src/games/remnant2/data/server/created-builds.sync.server.ts @@ -1,11 +1,4 @@ -// Offline-sync handler for the remnant2Build entity (mutable content record). -// Split out from created-builds.server.ts so the sync-replay path lives apart -// from the direct CRUD data access, while still reusing its ownership-scoped -// `updateOwnedBuild` write. The `.server.ts` suffix opts this into Start's import -// protection, keeping prisma out of the client bundle. Consumed only by the sync -// handler registry. - -import { extractBuildWriteFields } from "#/features/game/data/build-fields.ts"; +import { extractBuildWriteFields } from "#/features/game/data/utils.ts"; import { createRecordSyncHandler } from "#/features/sync/local-data/record-sync-handler.ts"; import type { HasUpdatedAt, diff --git a/src/games/remnant2/data/server/created-builds.ts b/src/games/remnant2/data/server/created-builds.ts index 7d5af99..90341cd 100644 --- a/src/games/remnant2/data/server/created-builds.ts +++ b/src/games/remnant2/data/server/created-builds.ts @@ -1,15 +1,10 @@ -// Remnant 2 created builds: input validation and the TanStack server-fn wrappers. -// Each wrapper delegates to ./created-builds.server.ts; those imports are -// referenced only inside handler bodies, so the compiler strips them (and prisma) -// from the client bundle. - import { createServerFn } from "@tanstack/react-start"; import { z } from "zod"; -import { extractBuildWriteFields } from "#/features/game/data/build-fields.ts"; import type { CreatedBuildRecord, CreatedBuildSummary, } from "#/features/game/data/types.ts"; +import { extractBuildWriteFields } from "#/features/game/data/utils.ts"; import { deleteBuild, getBuildById, -- 2.51.2