Files
J621/frontend/src/lib/preferences.ts
T
JakeBreath 1adb761c8d Fix following past 48 entries and make the e621 page size configurable
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).
2026-09-18 19:06:18 -05:00

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);
}