terry-wallet-login #15

Merged
terry merged 95 commits from terry-wallet-login into terry-staging 2026-06-05 16:32:43 +00:00
3 changed files with 58 additions and 2 deletions
Showing only changes of commit 6471559b3b - Show all commits

View File

@@ -0,0 +1,41 @@
---
title: "Favorites Display Loading Blank Page — Quick Fix"
type: quick-fix
date: 2026-06-04
---
# Favorites Display Loading Blank Page — Quick Fix
## Bug
When clicking the desktop header “我的收藏” button, the favorites page could briefly show the no-favorites empty state and then appear blank. The correct behavior is to show the user's favorited posts after loading.
## Root Cause
Two issues combined:
1. The favorites page initialized with `loading=false` and `items=[]`. When the wallet was already logged in, React rendered the empty state once before the `useEffect` started the favorites request.
2. The desktop header favorites link had been changed to `reloadDocument` as a previous workaround. In the local Vite/dev-browser state this could force a full document reload and land in a broken empty document state instead of keeping the React app mounted.
## Fix
- Added an explicit `loaded` state to `src/pages/Favorites/index.tsx`.
- The favorites page now shows loading skeletons while logged-in favorites have not completed their first load, so the empty state only appears after a completed request returns zero items.
- Added a loading UI for `wallet.status === "loading"` so a persisted wallet token does not briefly show the logged-out prompt.
- Removed `reloadDocument` from the desktop header favorites link and kept client-side navigation with a top scroll reset.
### Files Modified
- `src/pages/Favorites/index.tsx` — tracks loaded state and gates empty-state rendering until favorites data has loaded.
- `src/layouts/PublicLayout.tsx` — removes hard document reload from the desktop header favorites link.
## Verification
- `npx tsc --noEmit`
- `npm run format:check`
- `npm test`
- Browser native: opened `http://192.168.1.187:5173/cn/browse`, clicked the desktop header “我的收藏”, and verified the resulting page URL is `/cn/favorites`, `document.getElementById("root")` exists, and `window.scrollY === 0`.
## Notes
No deploy was performed.

View File

@@ -698,7 +698,6 @@ export function PublicLayout() {
/>
<Link
to={lp("/favorites")}
reloadDocument
onClick={() => window.scrollTo({ top: 0, left: 0 })}
className={`hidden h-10 shrink-0 items-center justify-center gap-2 rounded-full border px-3 text-sm font-bold outline-none transition focus-visible:ring-2 focus-visible:ring-ark-gold/80 focus-visible:ring-offset-2 focus-visible:ring-offset-ark-bg md:inline-flex ${
na("favorites")

View File

@@ -137,6 +137,7 @@ export default function Favorites() {
const [items, setItems] = useState<Resource[]>([]);
const [total, setTotal] = useState(0);
const [loading, setLoading] = useState(false);
const [loaded, setLoaded] = useState(false);
const [error, setError] = useState("");
const [reloadKey, setReloadKey] = useState(0);
const [showFilters, setShowFilters] = useState(false);
@@ -151,10 +152,13 @@ export default function Favorites() {
if (!wallet.token || wallet.status !== "loggedIn") {
setItems([]);
setTotal(0);
setLoading(false);
setLoaded(false);
return;
}
let cancelled = false;
setLoading(true);
setLoaded(false);
setError("");
listFavorites(wallet.token, {
sort,
@@ -170,6 +174,7 @@ export default function Favorites() {
setItems(resources);
setTotal(data.total ?? resources.length);
resources.forEach((resource) => markFavorite(resource.id, true));
setLoaded(true);
})
.catch((err) => {
if (cancelled) return;
@@ -179,6 +184,7 @@ export default function Favorites() {
return;
}
setError(err instanceof Error ? err.message : t("loadFailed"));
setLoaded(true);
})
.finally(() => {
if (!cancelled) setLoading(false);
@@ -200,6 +206,16 @@ export default function Favorites() {
[t],
);
if (wallet.status === "loading") {
return (
<Reveal className="mx-auto grid max-w-[980px] gap-3 px-0 py-2 md:py-4">
{Array.from({ length: 4 }).map((_, index) => (
<Skeleton key={index} className="h-[132px] rounded-2xl" />
))}
</Reveal>
);
}
if (wallet.status !== "loggedIn") {
return (
<Reveal className="flex min-h-[60vh] flex-col items-center justify-center gap-5 px-4 py-12 text-center">
@@ -330,7 +346,7 @@ export default function Favorites() {
) : null}
</div>
{loading ? (
{loading || !loaded ? (
<div className="grid gap-3">
{Array.from({ length: 4 }).map((_, index) => (
<Skeleton key={index} className="h-[132px] rounded-2xl" />