diff --git a/app/(main)/page.tsx b/app/(main)/page.tsx index 788ad2d..beec46c 100644 --- a/app/(main)/page.tsx +++ b/app/(main)/page.tsx @@ -1,15 +1,54 @@ +"use client" + import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar" import { Badge } from "@/components/ui/badge" import { Button } from "@/components/ui/button" import { Card, CardContent, CardFooter, CardHeader, CardTitle } from "@/components/ui/card" import { IconInput } from "@/components/ui/icon-input" import { listGames, listPlayers, listShops } from "@/lib/api" +import { toApiError } from "@/lib/errors" import { GameIcon } from "@/lib/game-icons" import { ArrowRight, Search, ShoppingBag, Star } from "lucide-react" import Link from "next/link" +import { useEffect, useState } from "react" -export default async function HomePage() { - const [games, players, shops] = await Promise.all([listGames(), listPlayers(), listShops()]) +export default function HomePage() { + const [games, setGames] = useState>>([]) + const [players, setPlayers] = useState>>([]) + const [shops, setShops] = useState>>([]) + const [loading, setLoading] = useState(true) + const [loadingError, setLoadingError] = useState(null) + + useEffect(() => { + let cancelled = false + + const load = async () => { + try { + const [nextGames, nextPlayers, nextShops] = await Promise.all([ + listGames(), + listPlayers(), + listShops(), + ]) + + if (cancelled) return + + setGames(nextGames) + setPlayers(nextPlayers) + setShops(nextShops) + setLoading(false) + } catch (err: unknown) { + if (cancelled) return + setLoading(false) + setLoadingError(toApiError(err).msg) + } + } + + void load() + + return () => { + cancelled = true + } + }, []) return (
@@ -42,6 +81,11 @@ export default async function HomePage() {
+ {loading &&

加载中...

} + {!loading && loadingError && ( +

{loadingError}

+ )} +

游戏分类

@@ -57,14 +101,16 @@ export default async function HomePage() {
- {games.map((game) => ( - - ))} + {!loading && !loadingError + ? games.map((game) => ( + + )) + : null}
@@ -92,68 +138,74 @@ export default async function HomePage() {
{/* Players */} - {players.map((player) => ( - - - - - {player.user.nickname[0]} - -
- {player.user.nickname} -
-
- - {player.rating} + {!loading && !loadingError + ? players.map((player) => ( + + + + + {player.user.nickname[0]} + +
+ {player.user.nickname} +
+
+ + {player.rating} +
+ + {player.totalOrders} 单 + + + {player.status === "available" + ? "可接单" + : player.status === "busy" + ? "忙碌" + : "离线"} + +
- {player.totalOrders} 单 - - {player.status === "available" - ? "可接单" - : player.status === "busy" - ? "忙碌" - : "离线"} - -
-
- - -
- {player.tags.map((tag) => ( - - {tag} - - ))} -
- {player.shopName && ( -

所属店铺: {player.shopName}

- )} -
- -
- - {player.services?.[0]?.price ?? 35} - - - 元/{player.services?.[0]?.unit ?? "时"} - -
- -
- - ))} + + +
+ {player.tags.map((tag) => ( + + {tag} + + ))} +
+ {player.shopName && ( +

+ 所属店铺: {player.shopName} +

+ )} +
+ +
+ + {player.services?.[0]?.price ?? 35} + + + 元/{player.services?.[0]?.unit ?? "时"} + +
+ +
+ + )) + : null} {/* Community Teaser */} @@ -174,35 +226,37 @@ export default async function HomePage() { {/* Shops */} - {shops.map((shop) => ( - - - {shop.name} -

{shop.description}

-
- -
-
- - {shop.rating} -
-
- - {shop.totalOrders} 单 -
- {shop.playerCount} 名打手 -
-
- - - -
- ))} + {!loading && !loadingError + ? shops.map((shop) => ( + + + {shop.name} +

{shop.description}

+
+ +
+
+ + {shop.rating} +
+
+ + {shop.totalOrders} 单 +
+ {shop.playerCount} 名打手 +
+
+ + + +
+ )) + : null}