Tasks 12-13: Fix release date input to type=date, add sort direction toggle to games page
This commit is contained in:
@@ -31,6 +31,7 @@ interface DeviceOption {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type SortOption = "recent" | "name" | "benchmarks"
|
type SortOption = "recent" | "name" | "benchmarks"
|
||||||
|
type SortDirection = "asc" | "desc"
|
||||||
|
|
||||||
const DECK_STATUS_CONFIG: Record<string, { label: string; className: string }> = {
|
const DECK_STATUS_CONFIG: Record<string, { label: string; className: string }> = {
|
||||||
native: { label: "Native", className: "bg-green-500/10 border-green-500/20 text-green-400" },
|
native: { label: "Native", className: "bg-green-500/10 border-green-500/20 text-green-400" },
|
||||||
@@ -62,6 +63,7 @@ export function GamesPageClient({
|
|||||||
const [selectedGenres, setSelectedGenres] = useState<string[]>([])
|
const [selectedGenres, setSelectedGenres] = useState<string[]>([])
|
||||||
const [selectedDevice, setSelectedDevice] = useState("")
|
const [selectedDevice, setSelectedDevice] = useState("")
|
||||||
const [sort, setSort] = useState<SortOption>("recent")
|
const [sort, setSort] = useState<SortOption>("recent")
|
||||||
|
const [sortDirection, setSortDirection] = useState<SortDirection>("desc")
|
||||||
const [loading, setLoading] = useState(false)
|
const [loading, setLoading] = useState(false)
|
||||||
const [error, setError] = useState<string | null>(null)
|
const [error, setError] = useState<string | null>(null)
|
||||||
const [showFilters, setShowFilters] = useState(false)
|
const [showFilters, setShowFilters] = useState(false)
|
||||||
@@ -76,12 +78,13 @@ export function GamesPageClient({
|
|||||||
params.set("offset", String(offset))
|
params.set("offset", String(offset))
|
||||||
params.set("limit", "24")
|
params.set("limit", "24")
|
||||||
params.set("sort", sort)
|
params.set("sort", sort)
|
||||||
|
params.set("order", sortDirection)
|
||||||
if (search) params.set("search", search)
|
if (search) params.set("search", search)
|
||||||
if (selectedDevice) params.set("device", selectedDevice)
|
if (selectedDevice) params.set("device", selectedDevice)
|
||||||
if (selectedGenres.length === 1) params.set("genre", selectedGenres[0])
|
if (selectedGenres.length === 1) params.set("genre", selectedGenres[0])
|
||||||
return `/api/games/listing?${params.toString()}`
|
return `/api/games/listing?${params.toString()}`
|
||||||
},
|
},
|
||||||
[sort, search, selectedDevice, selectedGenres],
|
[sort, sortDirection, search, selectedDevice, selectedGenres],
|
||||||
)
|
)
|
||||||
|
|
||||||
// Load more function for infinite scroll
|
// Load more function for infinite scroll
|
||||||
@@ -217,6 +220,13 @@ export function GamesPageClient({
|
|||||||
</option>
|
</option>
|
||||||
))}
|
))}
|
||||||
</select>
|
</select>
|
||||||
|
<button
|
||||||
|
onClick={() => setSortDirection(prev => prev === "asc" ? "desc" : "asc")}
|
||||||
|
className="px-2 py-2 rounded-md text-sm bg-text/5 border border-border hover:bg-text/10 transition-colors cursor-pointer"
|
||||||
|
title={sortDirection === "asc" ? "Sort ascending" : "Sort descending"}
|
||||||
|
>
|
||||||
|
{sortDirection === "asc" ? "↑" : "↓"}
|
||||||
|
</button>
|
||||||
<button
|
<button
|
||||||
onClick={() => setShowFilters(!showFilters)}
|
onClick={() => setShowFilters(!showFilters)}
|
||||||
className={`px-3 py-2 rounded-md text-sm transition-colors cursor-pointer border ${
|
className={`px-3 py-2 rounded-md text-sm transition-colors cursor-pointer border ${
|
||||||
|
|||||||
@@ -179,7 +179,7 @@ export function NonSteamEditForm({ game, platformSupport, hardwareList, isOwner,
|
|||||||
<div className="space-y-1.5">
|
<div className="space-y-1.5">
|
||||||
<label className="text-xs font-medium text-text/60">Release Date</label>
|
<label className="text-xs font-medium text-text/60">Release Date</label>
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="date"
|
||||||
value={releaseDate}
|
value={releaseDate}
|
||||||
onChange={e => setReleaseDate(e.target.value)}
|
onChange={e => setReleaseDate(e.target.value)}
|
||||||
className="w-full px-4 py-3 rounded-lg border border-border bg-text/5 text-text text-sm placeholder:text-text/40 outline-none focus:border-primary"
|
className="w-full px-4 py-3 rounded-lg border border-border bg-text/5 text-text text-sm placeholder:text-text/40 outline-none focus:border-primary"
|
||||||
|
|||||||
@@ -230,10 +230,9 @@ export function NonSteamBasicInfoStep({ value, onChange }: NonSteamBasicInfoStep
|
|||||||
<div className="space-y-1.5">
|
<div className="space-y-1.5">
|
||||||
<label className="text-xs font-medium text-text/60">Release Date</label>
|
<label className="text-xs font-medium text-text/60">Release Date</label>
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="date"
|
||||||
value={value.releaseDate}
|
value={value.releaseDate}
|
||||||
onChange={(e) => update("releaseDate", e.target.value)}
|
onChange={(e) => update("releaseDate", e.target.value)}
|
||||||
placeholder="e.g. 2017-02-24"
|
|
||||||
className="w-full px-4 py-3 rounded-lg border border-border bg-text/5 text-text text-sm placeholder:text-text/40 outline-none focus:border-primary focus:ring-2 focus:ring-primary/50 transition-colors"
|
className="w-full px-4 py-3 rounded-lg border border-border bg-text/5 text-text text-sm placeholder:text-text/40 outline-none focus:border-primary focus:ring-2 focus:ring-primary/50 transition-colors"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ export const gamesListingRoutes = new Elysia({ prefix: "/games/listing" }).get(
|
|||||||
const genre = query.genre || ""
|
const genre = query.genre || ""
|
||||||
const device = query.device || ""
|
const device = query.device || ""
|
||||||
const sort = query.sort || "recent"
|
const sort = query.sort || "recent"
|
||||||
|
const order = query.order === "asc" ? asc : desc
|
||||||
|
|
||||||
// Build where conditions
|
// Build where conditions
|
||||||
const conditions = []
|
const conditions = []
|
||||||
@@ -106,12 +107,12 @@ export const gamesListingRoutes = new Elysia({ prefix: "/games/listing" }).get(
|
|||||||
let orderBy
|
let orderBy
|
||||||
switch (sort) {
|
switch (sort) {
|
||||||
case "name":
|
case "name":
|
||||||
orderBy = asc(games.title)
|
orderBy = order(games.title)
|
||||||
break
|
break
|
||||||
case "benchmarks":
|
case "benchmarks":
|
||||||
case "recent":
|
case "recent":
|
||||||
default:
|
default:
|
||||||
orderBy = desc(games.createdAt)
|
orderBy = order(games.createdAt)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -195,7 +196,10 @@ export const gamesListingRoutes = new Elysia({ prefix: "/games/listing" }).get(
|
|||||||
|
|
||||||
// If sorting by benchmarks, re-sort the enriched data
|
// If sorting by benchmarks, re-sort the enriched data
|
||||||
if (sort === "benchmarks") {
|
if (sort === "benchmarks") {
|
||||||
enrichedData.sort((a, b) => b.benchmarkCount - a.benchmarkCount)
|
const sortFn = query.order === "asc"
|
||||||
|
? (a: any, b: any) => a.benchmarkCount - b.benchmarkCount
|
||||||
|
: (a: any, b: any) => b.benchmarkCount - a.benchmarkCount
|
||||||
|
enrichedData.sort(sortFn)
|
||||||
}
|
}
|
||||||
|
|
||||||
const [{ count: total }] = await countQuery
|
const [{ count: total }] = await countQuery
|
||||||
@@ -217,6 +221,7 @@ export const gamesListingRoutes = new Elysia({ prefix: "/games/listing" }).get(
|
|||||||
genre: t.Optional(t.String()),
|
genre: t.Optional(t.String()),
|
||||||
device: t.Optional(t.String()),
|
device: t.Optional(t.String()),
|
||||||
sort: t.Optional(t.String()),
|
sort: t.Optional(t.String()),
|
||||||
|
order: t.Optional(t.String()),
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
Reference in New Issue
Block a user