v3: code quality pass, various bug fixes
This commit is contained in:
@@ -2,6 +2,7 @@ import {
|
||||
useCallback,
|
||||
useEffect,
|
||||
useLayoutEffect,
|
||||
useMemo,
|
||||
useRef,
|
||||
useState,
|
||||
} from "react";
|
||||
@@ -11,11 +12,12 @@ import { Avatar } from "../components/Avatar.tsx";
|
||||
import { DumpCard } from "../components/DumpCard.tsx";
|
||||
import { AppHeader } from "../components/AppHeader.tsx";
|
||||
|
||||
import { API_URL } from "../config/api.ts";
|
||||
import { API_URL, DEFAULT_PAGE_SIZE } from "../config/api.ts";
|
||||
|
||||
import {
|
||||
deserializeDump,
|
||||
type Dump,
|
||||
hydrateDump,
|
||||
type PaginatedData,
|
||||
type RawDump,
|
||||
type User,
|
||||
@@ -29,12 +31,6 @@ import { useWS } from "../hooks/useWS.ts";
|
||||
import { useDumpListSync } from "../hooks/useDumpListSync.ts";
|
||||
import { useInfiniteScroll } from "../hooks/useInfiniteScroll.ts";
|
||||
|
||||
const PAGE_SIZE = 20;
|
||||
|
||||
// After JSON roundtrip, createdAt is a string — re-parse it
|
||||
const hydrateDump = (raw: Dump): Dump =>
|
||||
deserializeDump(raw as unknown as RawDump);
|
||||
|
||||
type DumpsState =
|
||||
| { status: "loading" }
|
||||
| { status: "error"; error: string }
|
||||
@@ -210,11 +206,13 @@ export function Index() {
|
||||
useEffect(() => {
|
||||
if (mainFetchDone.current || cached) return;
|
||||
mainFetchDone.current = true;
|
||||
const controller = new AbortController();
|
||||
(async () => {
|
||||
try {
|
||||
const res = await fetch(
|
||||
`${API_URL}/api/dumps/?page=1&limit=${PAGE_SIZE}`,
|
||||
`${API_URL}/api/dumps/?page=1&limit=${DEFAULT_PAGE_SIZE}`,
|
||||
{
|
||||
signal: controller.signal,
|
||||
headers: token ? { Authorization: `Bearer ${token}` } : {},
|
||||
},
|
||||
);
|
||||
@@ -229,12 +227,17 @@ export function Index() {
|
||||
loadingMore: false,
|
||||
});
|
||||
} catch (err) {
|
||||
if ((err as Error).name === "AbortError") return;
|
||||
setDumpsState({
|
||||
status: "error",
|
||||
error: friendlyFetchError(err),
|
||||
});
|
||||
}
|
||||
})();
|
||||
return () => {
|
||||
mainFetchDone.current = false;
|
||||
controller.abort();
|
||||
};
|
||||
}, [cached, token]);
|
||||
|
||||
// ── Followed feeds fetch (lazy, on first tab open) ──
|
||||
@@ -252,7 +255,7 @@ export function Index() {
|
||||
loadingMore: false,
|
||||
});
|
||||
} else {
|
||||
fetch(`${API_URL}/api/follows/feed/users?page=1&limit=${PAGE_SIZE}`, {
|
||||
fetch(`${API_URL}/api/follows/feed/users?page=1&limit=${DEFAULT_PAGE_SIZE}`, {
|
||||
headers: { Authorization: `Bearer ${token}` },
|
||||
})
|
||||
.then((r) => r.json())
|
||||
@@ -286,7 +289,7 @@ export function Index() {
|
||||
});
|
||||
} else {
|
||||
fetch(
|
||||
`${API_URL}/api/follows/feed/playlists?page=1&limit=${PAGE_SIZE}`,
|
||||
`${API_URL}/api/follows/feed/playlists?page=1&limit=${DEFAULT_PAGE_SIZE}`,
|
||||
{
|
||||
headers: { Authorization: `Bearer ${token}` },
|
||||
},
|
||||
@@ -312,7 +315,7 @@ export function Index() {
|
||||
}
|
||||
}, [
|
||||
tab,
|
||||
user?.id,
|
||||
user,
|
||||
token,
|
||||
cachedFollowedUsers,
|
||||
cachedFollowedPlaylists,
|
||||
@@ -331,7 +334,7 @@ export function Index() {
|
||||
setDumpsState((s) =>
|
||||
s.status === "loaded" ? { ...s, loadingMore: true } : s
|
||||
);
|
||||
fetch(`${API_URL}/api/dumps/?page=${nextPage}&limit=${PAGE_SIZE}`, {
|
||||
fetch(`${API_URL}/api/dumps/?page=${nextPage}&limit=${DEFAULT_PAGE_SIZE}`, {
|
||||
headers: token ? { Authorization: `Bearer ${token}` } : {},
|
||||
})
|
||||
.then((r) => r.json())
|
||||
@@ -368,7 +371,7 @@ export function Index() {
|
||||
s.status === "loaded" ? { ...s, loadingMore: true } : s
|
||||
);
|
||||
fetch(
|
||||
`${API_URL}/api/follows/feed/users?page=${nextPage}&limit=${PAGE_SIZE}`,
|
||||
`${API_URL}/api/follows/feed/users?page=${nextPage}&limit=${DEFAULT_PAGE_SIZE}`,
|
||||
{
|
||||
headers: { Authorization: `Bearer ${token}` },
|
||||
},
|
||||
@@ -407,7 +410,7 @@ export function Index() {
|
||||
s.status === "loaded" ? { ...s, loadingMore: true } : s
|
||||
);
|
||||
fetch(
|
||||
`${API_URL}/api/follows/feed/playlists?page=${nextPage}&limit=${PAGE_SIZE}`,
|
||||
`${API_URL}/api/follows/feed/playlists?page=${nextPage}&limit=${DEFAULT_PAGE_SIZE}`,
|
||||
{
|
||||
headers: { Authorization: `Bearer ${token}` },
|
||||
},
|
||||
@@ -529,7 +532,7 @@ export function Index() {
|
||||
const dumps = dumpsState.status === "loaded" ? dumpsState.dumps : [];
|
||||
const loadingMore = dumpsState.status === "loaded" && dumpsState.loadingMore;
|
||||
|
||||
const restIds = new Set(dumps.map((d) => d.id));
|
||||
const restIds = useMemo(() => new Set(dumps.map((d) => d.id)), [dumps]);
|
||||
const combined = [...recentDumps.filter((d) => !restIds.has(d.id)), ...dumps]
|
||||
.filter((d) => !deletedDumpIds.has(d.id) && d.id !== justDeletedId);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user