"use client"
import { useEffect, useState } from "react"
import { motion } from "motion/react"
import { Send, Loader2, AlertCircle, Monitor, Gauge, SlidersHorizontal, Terminal, FileText, ImagePlus, X } from "lucide-react"
import { TiptapEditor } from "@/components/tiptap-editor"
import type { SettingCategory } from "@/components/wizard/settings-editor"
import type { PerformanceData } from "./performance-step"
import type { EnvironmentData } from "./environment-step"
import { UPSCALER_TYPE_OPTIONS, FRAME_GEN_OPTIONS } from "./environment-step"
export interface ReviewData {
hardwareSlug: string
hardwareName: string
gameVersionLabel: string
antiCheat: {
antiCheatRelevant: boolean
antiCheatName: string
antiCheatStatus: "none" | "supported" | "unsupported" | "unknown"
}
performance: PerformanceData
settings: SettingCategory[]
environment: EnvironmentData
}
interface ReviewStepProps {
data: ReviewData
userNotes: string
onUserNotesChange: (notes: string) => void
onSubmit: () => void
isSubmitting: boolean
error: string | null
screenshotFiles: File[]
onScreenshotFilesChange: (files: File[]) => void
screenshotUploading: boolean
screenshotError: string | null
}
function SectionHeader({ icon: Icon, label }: { icon: React.ElementType; label: string }) {
return (
{label}
)
}
function SummaryRow({ label, value }: { label: string; value: React.ReactNode }) {
return (
{label}
{value}
)
}
function formatNumber(val: number | undefined): string {
if (val === undefined || val === null) return "Not set"
return String(val)
}
export function ReviewStep({
data,
userNotes,
onUserNotesChange,
onSubmit,
isSubmitting,
error,
screenshotFiles,
onScreenshotFilesChange,
screenshotUploading,
screenshotError,
}: ReviewStepProps) {
const { hardwareName, gameVersionLabel, antiCheat, performance, environment, settings } = data
const [previews, setPreviews] = useState<{ file: File; url: string }[]>([])
useEffect(() => {
if (!screenshotFiles?.length) {
setPreviews([])
return
}
const next = screenshotFiles.map((file) => ({ file, url: URL.createObjectURL(file) }))
setPreviews(next)
return () => {
next.forEach((p) => URL.revokeObjectURL(p.url))
}
}, [screenshotFiles])
const upscalerLabel = (() => {
if (!data.environment.upscalerType || data.environment.upscalerType === "none") return "None"
const opt = UPSCALER_TYPE_OPTIONS.find(o => o.value === data.environment.upscalerType)
const base = opt?.label ?? data.environment.upscalerType
return data.environment.upscalerVersion ? `${base} ${data.environment.upscalerVersion}` : base
})()
const frameGenLabel = (() => {
if (!environment.frameGenMethod || environment.frameGenMethod === "none") return "None"
const opt = FRAME_GEN_OPTIONS.find(o => o.value === environment.frameGenMethod)
return opt?.label ?? environment.frameGenMethod
})()
return (
Review & Submit
Review your submission details below. Add any additional notes and click Submit when ready.
{/* Summary Cards */}
{/* Setup: Hardware + Version + Anti-Cheat */}
{antiCheat.antiCheatRelevant && (
<>
>
)}
{!antiCheat.antiCheatRelevant && (
)}
{/* Performance */}
{/* Environment */}
{environment.launchOptions && (
{environment.launchOptions}
}
/>
)}
{/* Settings */}
{settings.length === 0 ? (
No settings configured
) : (
{settings.map((cat) => (
{cat.category}
{cat.settings.map((s) => (
{s.title}: {String(s.value)}
))}
))}
)}
{/* Screenshots */}
{data.settings.length === 0 ? (
Add game settings to enable screenshot upload
) : (
{screenshotUploading && (
Uploading...
)}
{previews.length > 0 && (
{previews.map((preview) => (
))}
)}
{(!screenshotFiles || screenshotFiles.length < 2) && !screenshotUploading && (
)}
{screenshotFiles && screenshotFiles.length >= 2 && (
Maximum 2 screenshots reached
)}
{screenshotError && (
{screenshotError}
)}
)}
{/* User Notes */}
onUserNotesChange(JSON.stringify(json))}
placeholder="Add any extra details about your experience..."
/>
{/* Error */}
{error && (
{error}
)}
{/* Submit Button */}
)
}