After a reload the chips (filter panel and the row above the feed) read as raw UC… ids until the subscription list landed. The names seen last time are now kept per account (useChannelNames) and name the chips at once; the list then replaces the copy, so a renamed or dropped channel heals. A channel never named on this browser draws a placeholder bone while the list loads; a failed list still falls back to the id.
45 lines
1.7 KiB
TypeScript
45 lines
1.7 KiB
TypeScript
import { useEffect, useState } from "react";
|
|
import { useQuery } from "@tanstack/react-query";
|
|
import { qk } from "./queryKeys";
|
|
import { api, type ManagedChannel } from "./api";
|
|
import { LS, readAccount, writeAccount } from "./storage";
|
|
|
|
type Names = Record<string, string>;
|
|
|
|
const namesOf = (channels: ManagedChannel[]): Names =>
|
|
Object.fromEntries(channels.map((c) => [c.id, c.title ?? c.id]));
|
|
|
|
const readNames = (): Names => {
|
|
const raw = readAccount<unknown>(LS.channelNames, {});
|
|
return raw && typeof raw === "object" && !Array.isArray(raw) ? (raw as Names) : {};
|
|
};
|
|
|
|
/**
|
|
* Channel id → name, for the chips that name a channel filter (the filter panel's picker and the chip
|
|
* row above the feed). The names come from the subscription list, which a reload has not fetched yet:
|
|
* for a moment the chips read as raw UC… ids (the owner, 2026-10-03). The names seen last time are
|
|
* kept per account and name the chips until the list lands; the list then wins and replaces the copy,
|
|
* so a renamed or dropped channel heals on the next load.
|
|
*
|
|
* `pending` is true while the list loads: a channel this browser has never named then has no name to
|
|
* show, and the chip draws a placeholder rather than its id. A failed list leaves the id (the chips
|
|
* stay told apart, and each ✕ drops a different one).
|
|
*/
|
|
export function useChannelNames(enabled = true) {
|
|
const query = useQuery({
|
|
queryKey: qk.channels(),
|
|
queryFn: api.channels,
|
|
enabled,
|
|
staleTime: 5 * 60_000,
|
|
});
|
|
const [remembered] = useState(readNames);
|
|
useEffect(() => {
|
|
if (query.data) writeAccount(LS.channelNames, namesOf(query.data));
|
|
}, [query.data]);
|
|
return {
|
|
query,
|
|
names: query.data ? namesOf(query.data) : remembered,
|
|
pending: enabled && query.isPending,
|
|
};
|
|
}
|