diff --git a/app/game/[id]/edit/page.tsx b/app/game/[id]/edit/page.tsx
new file mode 100644
index 0000000..30772c4
--- /dev/null
+++ b/app/game/[id]/edit/page.tsx
@@ -0,0 +1,90 @@
+import { notFound, redirect } from "next/navigation"
+import { headers } from "next/headers"
+import { db } from "@/lib/db/index"
+import { games, gamePlatformSupport, hardware } from "@/lib/db/schema"
+import { eq } from "drizzle-orm"
+import { auth } from "@/lib/auth"
+import { NonSteamEditForm } from "@/components/wizard/non-steam-edit-form"
+
+export const dynamic = "force-dynamic"
+
+export const metadata = {
+ title: "Edit Game",
+}
+
+async function resolveGame(id: string) {
+ const isNumeric = /^\d+$/.test(id)
+ if (isNumeric) {
+ const rows = await db.select().from(games).where(eq(games.steamAppId, Number(id))).limit(1)
+ return rows[0]
+ }
+ const rows = await db.select().from(games).where(eq(games.id, id)).limit(1)
+ return rows[0]
+}
+
+export default async function EditGamePage({
+ params,
+}: {
+ params: Promise<{ id: string }>
+}) {
+ const { id } = await params
+ const h = await headers()
+ const session = await auth.api.getSession({ headers: h })
+ if (!session?.user) redirect("/login")
+
+ const game = await resolveGame(id)
+ if (!game) notFound()
+
+ if (game.source === "steam") {
+ notFound()
+ }
+
+ const platformSupport = await db
+ .select()
+ .from(gamePlatformSupport)
+ .where(eq(gamePlatformSupport.gameId, game.id))
+
+ const hardwareList = await db
+ .select({ slug: hardware.slug, name: hardware.name, deviceType: hardware.deviceType })
+ .from(hardware)
+ .orderBy(hardware.sortOrder)
+
+ const serializedGame = {
+ id: game.id,
+ title: game.title,
+ developer: game.developer,
+ publisher: game.publisher,
+ description: game.description,
+ source: game.source,
+ storeUrl: game.storeUrl,
+ headerImage: game.headerImage,
+ capsuleImage: game.capsuleImage,
+ genres: game.genres,
+ releaseDate: game.releaseDate,
+ createdBy: game.createdBy,
+ }
+
+ const serializedPlatformSupport = platformSupport.map(ps => ({
+ hardwareSlug: ps.hardwareSlug,
+ isSupported: ps.isSupported,
+ protonStatus: ps.protonStatus,
+ }))
+
+ return (
+
+
+
Edit Game
+
+ Update details for {game.title}
+
+
+
+
+ )
+}
diff --git a/app/game/[id]/game-page-client.tsx b/app/game/[id]/game-page-client.tsx
index 8637656..68334b4 100644
--- a/app/game/[id]/game-page-client.tsx
+++ b/app/game/[id]/game-page-client.tsx
@@ -17,6 +17,7 @@ import {
ThumbsDownIcon,
GaugeIcon,
ChevronDownIcon,
+ PencilIcon,
} from "lucide-react"
import Link from "next/link"
import { useSession } from "@/lib/auth-client"
@@ -589,6 +590,15 @@ export function GamePageClient({
{stats && (
+ {session?.user && game.source !== "steam" && (
+
+
+ Edit Game
+
+ )}
{session && (
(null)
+
+ const [title, setTitle] = useState(game.title ?? "")
+ const [developer, setDeveloper] = useState(game.developer ?? "")
+ const [publisher, setPublisher] = useState(game.publisher ?? "")
+ const [description, setDescription] = useState(game.description ?? "")
+ const [storeUrl, setStoreUrl] = useState(game.storeUrl ?? "")
+ const [headerImage, setHeaderImage] = useState(game.headerImage ?? "")
+ const [capsuleImage, setCapsuleImage] = useState(game.capsuleImage ?? "")
+ const [genresStr, setGenresStr] = useState(game.genres?.join(", ") ?? "")
+ const [releaseDate, setReleaseDate] = useState(game.releaseDate ?? "")
+ const [platforms, setPlatforms] = useState
(platformSupport)
+
+ const canEdit = isOwner || isAdmin
+
+ const handleTogglePlatform = (slug: string) => {
+ setPlatforms(prev => {
+ const existing = prev.find(p => p.hardwareSlug === slug)
+ if (existing) {
+ return prev.filter(p => p.hardwareSlug !== slug)
+ }
+ return [...prev, { hardwareSlug: slug, isSupported: true, protonStatus: "unknown" }]
+ })
+ }
+
+ const handleProtonChange = (slug: string, protonStatus: string) => {
+ setPlatforms(prev =>
+ prev.map(p => p.hardwareSlug === slug ? { ...p, protonStatus } : p)
+ )
+ }
+
+ const handleSubmit = async () => {
+ setLoading(true)
+ setError(null)
+ try {
+ const res = await fetch(`/api/games/${game.id}/manual`, {
+ method: "PUT",
+ headers: { "Content-Type": "application/json" },
+ body: JSON.stringify({
+ title: title.trim(),
+ developer: developer.trim() || null,
+ publisher: publisher.trim() || null,
+ description: description.trim() || null,
+ storeUrl: storeUrl.trim() || null,
+ headerImage: headerImage.trim() || null,
+ capsuleImage: capsuleImage.trim() || null,
+ genres: genresStr.split(",").map(g => g.trim()).filter(Boolean),
+ releaseDate: releaseDate.trim() || null,
+ }),
+ })
+ if (!res.ok) {
+ const data = await res.json()
+ throw new Error(data.error || "Failed to update game")
+ }
+ router.push(`/game/${game.id}`)
+ router.refresh()
+ } catch (err: any) {
+ setError(err.message || "Failed to update game")
+ } finally {
+ setLoading(false)
+ }
+ }
+
+ if (!canEdit) {
+ return (
+
+
+
Only the creator or an admin can edit this game.
+
+ )
+ }
+
+ return (
+
+ {/* Basic Info */}
+
+
Basic Info
+
+
+
+
+
+
+
+ {/* Images */}
+
+
+ {/* Platform Support */}
+
+
Platform Support
+
+ {hardwareList.map(device => {
+ const active = platforms.find(p => p.hardwareSlug === device.slug)
+ return (
+
+
+
+ {device.name}
+
+
+
+ {active && (
+
+ )}
+
+
+ )
+ })}
+
+
+
+ {/* Actions */}
+
+
+
+
+
+ {error &&
{error}
}
+
+ )
+}