"use client" import { useState, useCallback } from "react" import { useRouter } from "next/navigation" import { motion, AnimatePresence } from "motion/react" import { StepIndicator } from "./step-indicator" import { NonSteamBasicInfoStep, BasicInfoData } from "./steps/non-steam-basic-info-step" import { NonSteamImageStep } from "./steps/non-steam-image-step" import { NonSteamPlatformStep, PlatformSupportItem } from "./steps/non-steam-platform-step" import { NonSteamReviewStep } from "./steps/non-steam-review-step" const STEPS = [ { label: "Basic Info", tooltip: "Enter the game title, developer, publisher, and other details." }, { label: "Cover Art", tooltip: "Search SteamGridDB for cover art or enter an image URL." }, { label: "Platform Support", tooltip: "Select supported devices and Proton compatibility." }, { label: "Review", tooltip: "Review all details before submitting the game." }, ] interface FormData { basicInfo: BasicInfoData headerImage: string capsuleImage: string platformSupport: PlatformSupportItem[] } export function NonSteamWizard() { const router = useRouter() const [step, setStep] = useState(0) const [loading, setLoading] = useState(false) const [error, setError] = useState(null) const [success, setSuccess] = useState(false) const [formData, setFormData] = useState({ basicInfo: { title: "", developer: "", publisher: "", description: "", source: "manual", storeUrl: "", genres: [], releaseDate: "", }, headerImage: "", capsuleImage: "", platformSupport: [], }) const updateBasicInfo = useCallback( (value: BasicInfoData) => { setFormData((prev) => ({ ...prev, basicInfo: value })) }, [] ) const updateImages = useCallback( (headerImage: string, capsuleImage: string) => { setFormData((prev) => ({ ...prev, headerImage, capsuleImage })) }, [] ) const updatePlatformSupport = useCallback( (value: PlatformSupportItem[]) => { setFormData((prev) => ({ ...prev, platformSupport: value })) }, [] ) const handleSubmit = async () => { setLoading(true) setError(null) try { const payload = { title: formData.basicInfo.title, developer: formData.basicInfo.developer || undefined, publisher: formData.basicInfo.publisher || undefined, description: formData.basicInfo.description || undefined, source: formData.basicInfo.source, storeUrl: formData.basicInfo.storeUrl || undefined, genres: formData.basicInfo.genres.length > 0 ? formData.basicInfo.genres : undefined, releaseDate: formData.basicInfo.releaseDate || undefined, headerImage: formData.headerImage || undefined, capsuleImage: formData.capsuleImage || undefined, platformSupport: formData.platformSupport.map((ps) => ({ hardwareSlug: ps.hardwareSlug, isSupported: ps.isSupported, protonStatus: ps.protonStatus, })), } const res = await fetch("/api/games/manual", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(payload), }) const data = await res.json() if (!res.ok) { if (res.status === 409 && data.existingGame) { setError(`Game already exists: "${data.existingGame.title}". Redirecting...`) setTimeout(() => router.push(`/game/${data.existingGame.id}`), 2000) return } throw new Error(data.error || "Failed to create game") } setSuccess(true) setTimeout(() => router.push(`/game/${data.game.id}`), 1500) } catch (err) { setError(err instanceof Error ? err.message : "Failed to create game") } finally { setLoading(false) } } const canProceed = () => { switch (step) { case 0: return formData.basicInfo.title.trim().length > 0 default: return true } } const handleNext = () => { if (step < STEPS.length - 1 && canProceed()) { setStep(step + 1) } } const handleBack = () => { if (step > 0) { setStep(step - 1) } } const handleStepClick = (clickedStep: number) => { if (clickedStep <= step) { setStep(clickedStep) } } if (success) { return (

Game Created!

Redirecting to game page...

) } return (
* Required fields
{step === 0 && ( )} {step === 1 && ( )} {step === 2 && ( )} {step === 3 && ( )} {/* Navigation Buttons */} {step < STEPS.length - 1 && (
)}
) }