Follow lists were paginated at the API default of 48, but the SPA treats them as complete sets: the tag/pool toggles read their state from page one (so the 49th follow looked unfollowed and its spinner waited for a page that could never contain it) and the Followed page rendered only 48 cards while showing that as the count. Both follow endpoints are now unpaginated — they are per-user sets and still restricted to the caller's rows — and the three consumers take plain arrays. Post visibility: the old J621-Django online view fetched limit=320 (e621's maximum) while ours hard-coded 48, and fetchPostsByIds capped id batches at 100. The Online browser now has a 'Posts per page' setting (48/100/200/320) in its sidebar, mirrored in Account -> Browsing preferences, stored per user as e621_per_page and also used for pool loading; the id-batch cap is raised to 320. Tests: follow list shape/isolation (4) and preference validation/merge (3) added; the full backend suite is 46 green. Live-checked the array response shape and the preference bounds (200 accepted, 500 rejected).
60 lines
1.9 KiB
TypeScript
60 lines
1.9 KiB
TypeScript
import { api, getToken } from "@/lib/api";
|
|
import type { UserPreferences } from "@/lib/types";
|
|
import { useUi } from "@/store/ui";
|
|
|
|
/** Seed the local browse settings from the signed-in user's saved preferences. */
|
|
export function applyPreferences(
|
|
preferences: UserPreferences | null | undefined,
|
|
): void {
|
|
if (!preferences) return;
|
|
const ui = useUi.getState();
|
|
if (Array.isArray(preferences.ratings)) ui.setRatings(preferences.ratings);
|
|
if (typeof preferences.ordering === "string") ui.setOrdering(preferences.ordering);
|
|
if (typeof preferences.per_page === "number") ui.setPerPage(preferences.per_page);
|
|
if (typeof preferences.zoom === "number") ui.setZoom(preferences.zoom);
|
|
if (typeof preferences.e621_per_page === "number") {
|
|
ui.setE621PerPage(preferences.e621_per_page);
|
|
}
|
|
}
|
|
|
|
/** The browse settings currently in effect, as a preferences payload. */
|
|
export function preferencesPayload(extra?: UserPreferences): UserPreferences {
|
|
const ui = useUi.getState();
|
|
return {
|
|
ratings: ui.ratings,
|
|
ordering: ui.ordering,
|
|
per_page: ui.perPage,
|
|
zoom: ui.zoom,
|
|
e621_per_page: ui.e621PerPage,
|
|
...extra,
|
|
};
|
|
}
|
|
|
|
export function savePreferences(
|
|
patch: UserPreferences,
|
|
): Promise<UserPreferences> {
|
|
return api<UserPreferences>("/api/auth/preferences/", {
|
|
method: "POST",
|
|
json: patch,
|
|
});
|
|
}
|
|
|
|
let pending: number | null = null;
|
|
let pendingPatch: UserPreferences = {};
|
|
|
|
/**
|
|
* Persist browse settings for the signed-in user, debounced so slider drags
|
|
* do not spam the API. Guests keep using localStorage only.
|
|
*/
|
|
export function schedulePreferenceSave(patch: UserPreferences): void {
|
|
if (!getToken()) return;
|
|
pendingPatch = { ...pendingPatch, ...patch };
|
|
if (pending !== null) window.clearTimeout(pending);
|
|
pending = window.setTimeout(() => {
|
|
pending = null;
|
|
const body = preferencesPayload(pendingPatch);
|
|
pendingPatch = {};
|
|
void savePreferences(body).catch(() => undefined);
|
|
}, 700);
|
|
}
|