diff --git a/components/steam-reviews.tsx b/components/steam-reviews.tsx new file mode 100644 index 0000000..e82a057 --- /dev/null +++ b/components/steam-reviews.tsx @@ -0,0 +1,174 @@ +"use client"; + +import { useState, useEffect } from "react"; +import { ThumbsUp, ThumbsDown, ExternalLink } from "lucide-react"; +import { cn } from "@/lib/utils"; + +interface SteamReview { + recommendationid: string; + author: { + steamid: string; + playtime_forever: number; + }; + language: string; + review: string; + timestamp_created: number; + voted_up: boolean; + votes_up: number; + votes_funny: number; +} + +interface SteamReviewsData { + success: number; + query_summary: { + num_reviews: number; + review_score_desc: string; + total_positive: number; + total_negative: number; + total_reviews: number; + }; + reviews: SteamReview[]; +} + +interface SteamReviewsProps { + gameId: string; + steamAppId: number; + className?: string; +} + +export function SteamReviews({ gameId, steamAppId, className }: SteamReviewsProps) { + const [data, setData] = useState(null); + const [loading, setLoading] = useState(true); + const [error, setError] = useState(null); + const [offset, setOffset] = useState(0); + + const fetchReviews = async (newOffset: number) => { + setLoading(true); + setError(null); + + try { + const res = await fetch( + `/api/steam-reviews/${gameId}?offset=${newOffset}&limit=5&language=english` + ); + + if (!res.ok) throw new Error("Failed to load reviews"); + + const result = await res.json(); + setData(result); + setOffset(newOffset); + } catch (err) { + setError(err instanceof Error ? err.message : "Unknown error"); + } finally { + setLoading(false); + } + }; + + useEffect(() => { + fetchReviews(0); + }, [gameId]); + + if (loading && !data) { + return ( +
+
+
+ {[...Array(3)].map((_, i) => ( +
+ ))} +
+
+ ); + } + + if (error) { + return ( +
+

Failed to load Steam reviews

+
+ ); + } + + if (!data?.query_summary) return null; + + const { query_summary: summary } = data; + const positivePercent = + summary.total_reviews > 0 + ? Math.round((summary.total_positive / summary.total_reviews) * 100) + : 0; + + return ( +
+ {/* Summary header */} +
+
+

Steam Reviews

+

+ {summary.review_score_desc} — {positivePercent}% positive ({summary.total_reviews.toLocaleString()} reviews) +

+
+ + View on Steam + +
+ + {/* Review cards */} +
+ {data.reviews.map((review) => ( +
+
+
+ {review.voted_up ? ( + + ) : ( + + )} + + {review.voted_up ? "Recommended" : "Not Recommended"} + +
+ + {Math.floor(review.author.playtime_forever / 60)}h played + +
+

{review.review}

+
+ {review.votes_up} found helpful + {review.votes_funny > 0 && ( + {review.votes_funny} funny + )} +
+
+ ))} +
+ + {/* Pagination */} +
+ + +
+
+ ); +}