diff --git a/CHANGELOG.md b/CHANGELOG.md index 6269de0..a471b8c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,7 +11,7 @@ All notable changes to DeckyVault will be documented in this file. - Anti-cheat badges on games list and search results - Anti-cheat filter in games list - Anti-cheat awareness step in benchmark submission wizard -- Anti-cheat status shown per device in platform support section +- Anti-cheat is game-level property (not per-device) #### Steam Reviews Integration - Steam review score and sentiment stored on game records @@ -26,6 +26,7 @@ All notable changes to DeckyVault will be documented in this file. - Manual override capability for admins/contributors - Color-coded playability badges across all game views - "Plays Great" quick-filter in games list +- Auto-recalculates on benchmark submission and Steam sync #### Games List Revamp - FPS range filter (min/max) @@ -40,7 +41,7 @@ All notable changes to DeckyVault will be documented in this file. - Saved/bookmarked filter presets #### Community Suggestions -- "Suggest Edit" button on game details page +- "Suggest Edit" button on game details page (non-Steam games only) - Community suggestion submission for editable fields - Moderation queue for pending suggestions - Approve/reject workflow with review notes @@ -60,16 +61,30 @@ All notable changes to DeckyVault will be documented in this file. - Report status tracking (open/reviewed/dismissed) - Verified badge on peer-reviewed benchmarks +#### Preset Detail Modal +- Added load times (SSD/SD) display +- Added battery life estimate display +- Added custom system indicator + ### Changed - Manage page now shows dashboard by default instead of redirecting to users - Games list now supports 12 filter dimensions and 7 sort options - Game details page now shows anti-cheat, playability, and Steam reviews +- "Suggest Edit" only appears for non-Steam games (manual, GOG, Epic sources) +- Anti-cheat step in wizard now shows game-level status, not per-device + +### Fixed +- Steam reviews component now handles missing/error data gracefully +- Anti-cheat badge no longer shows for games without anti-cheat +- Playability calculation only considers anti-cheat if game actually uses it +- API routes registered correctly (removed duplicate `/api` prefix) +- Dashboard and saved-filters routes now accessible ### Technical - Added `steamReviewScore`, `steamReviewSentiment`, `steamReviewCount` to games table - Added `playabilityStatus`, `playabilityOverride`, `playabilityCalculatedAt` to games and gamePlatformSupport tables - Created `community_suggestions` table for moderation workflow - Created `saved_filters` table for user filter presets -- Added playability auto-calculation engine +- Added playability auto-calculation engine with `recalculatePlayability()` export - Added Steam reviews caching API - Added admin dashboard stats API diff --git a/app/game/[id]/game-page-client.tsx b/app/game/[id]/game-page-client.tsx index a050fd9..e55f6a3 100644 --- a/app/game/[id]/game-page-client.tsx +++ b/app/game/[id]/game-page-client.tsx @@ -101,6 +101,7 @@ interface PlatformSupport { interface Preset { id: string + gameId?: string hardwareSlug: string hardwareName: string upvotes: number @@ -117,6 +118,10 @@ interface Preset { protonVersion: string | null osVersion: string | null launchOptions: string | null + loadTimeSsd: number | null + loadTimeSd: number | null + estimatedBatteryMin: number | null + customSystem: boolean userNotes: string | null userId: string userName: string | null @@ -638,17 +643,19 @@ export function GamePageClient({ Add Benchmark )} - + {game.source !== "steam" && ( + + )} )} diff --git a/app/game/[id]/preset-detail-modal.tsx b/app/game/[id]/preset-detail-modal.tsx index 1a78286..734a4fd 100644 --- a/app/game/[id]/preset-detail-modal.tsx +++ b/app/game/[id]/preset-detail-modal.tsx @@ -40,6 +40,10 @@ interface Preset { protonVersion: string | null osVersion: string | null launchOptions: string | null + loadTimeSsd: number | null + loadTimeSd: number | null + estimatedBatteryMin: number | null + customSystem: boolean userNotes: string | null userId: string userName: string | null @@ -346,6 +350,18 @@ export function PresetDetailModal({ } /> + {preset.loadTimeSsd !== null && ( + + )} + {preset.loadTimeSd !== null && ( + + )} + {preset.estimatedBatteryMin !== null && ( + + )} + {preset.customSystem && ( + + )}
diff --git a/components/steam-reviews.tsx b/components/steam-reviews.tsx index d601916..c9d3ffd 100644 --- a/components/steam-reviews.tsx +++ b/components/steam-reviews.tsx @@ -1,7 +1,7 @@ "use client"; import { useState, useEffect } from "react"; -import { ThumbsUp, ThumbsDown, ExternalLink } from "lucide-react"; +import { ThumbsUp, ThumbsDown, ExternalLink, MessageSquare } from "lucide-react"; import { cn } from "@/lib/utils"; interface SteamReview { @@ -51,7 +51,10 @@ export function SteamReviews({ gameId, steamAppId, className }: SteamReviewsProp `/api/steam-reviews/${gameId}?offset=${newOffset}&limit=5&language=english` ); - if (!res.ok) throw new Error("Failed to load reviews"); + if (!res.ok) { + const errData = await res.json().catch(() => null); + throw new Error(errData?.error || `HTTP ${res.status}`); + } const result = await res.json(); setData(result); @@ -67,6 +70,7 @@ export function SteamReviews({ gameId, steamAppId, className }: SteamReviewsProp fetchReviews(0); }, [gameId]); + // Loading skeleton if (loading && !data) { return (
@@ -80,15 +84,46 @@ export function SteamReviews({ gameId, steamAppId, className }: SteamReviewsProp ); } + // Error state if (error) { return (
-

Failed to load Steam reviews

+
+ +

Steam reviews unavailable

+
+

{error}

+ + View on Steam +
); } - if (!data?.query_summary) return null; + // No data or no summary + if (!data?.query_summary) { + return ( +
+
+ +

No Steam reviews available

+
+ + View on Steam + +
+ ); + } const { query_summary: summary } = data; const totalReviews = summary.total_reviews ?? 0; @@ -98,6 +133,26 @@ export function SteamReviews({ gameId, steamAppId, className }: SteamReviewsProp ? Math.round((totalPositive / totalReviews) * 100) : 0; + // No reviews case + if (totalReviews === 0) { + return ( +
+
+ +

No reviews yet

+
+ + Be the first to review on Steam + +
+ ); + } + return (
{/* Summary header */} @@ -155,22 +210,27 @@ export function SteamReviews({ gameId, steamAppId, className }: SteamReviewsProp
{/* Pagination */} -
- - -
+ {totalReviews > 5 && ( +
+ + + Showing {offset + 1}-{Math.min(offset + 5, totalReviews)} of {totalReviews} + + +
+ )}
); }