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
2.0 KiB
TypeScript
45 lines
2.0 KiB
TypeScript
import { useTranslation } from "react-i18next";
|
|
import type { FeedFilters } from "../lib/api";
|
|
import { useChannelNames } from "../lib/useChannelNames";
|
|
import Combobox, { type ComboboxOption } from "./ui/Combobox";
|
|
|
|
// Pick channels to narrow the feed to — several OR together, so every other filter then applies
|
|
// across all of them. Until this existed the filter was settable only via a shared "?channel=" link:
|
|
// the panel had a remove button for something nothing could apply.
|
|
//
|
|
// It owns its channel query rather than letting the Sidebar hold it: the Sidebar is mounted for the
|
|
// whole feed page, but SidePanel only renders its children once the panel is open, so keeping the
|
|
// fetch here means a subscription list of a few hundred loads when the picker is actually looked at.
|
|
export default function ChannelPicker({
|
|
filters,
|
|
setFilters,
|
|
}: {
|
|
filters: FeedFilters;
|
|
setFilters: (f: FeedFilters) => void;
|
|
}) {
|
|
const { t } = useTranslation();
|
|
const { query: channelsQuery, names, pending } = useChannelNames();
|
|
|
|
const all = channelsQuery.data ?? [];
|
|
// The list order isn't alphabetical — it's the user's channel priority — and Combobox preserves the
|
|
// options order, so it stays meaningful. selectedLabels keeps a picked channel named even if a later
|
|
// narrowing ever drops it from the visible rows, and names a reloaded filter before the list lands.
|
|
const options: ComboboxOption[] = all.map((c) => ({ value: c.id, label: c.title ?? c.id }));
|
|
|
|
return (
|
|
<Combobox
|
|
label={t("sidebar.channelSearch")}
|
|
placeholder={t("sidebar.channelSearch")}
|
|
options={options}
|
|
selected={filters.channelIds}
|
|
onChange={(channelIds) => setFilters({ ...filters, channelIds })}
|
|
loading={channelsQuery.isLoading}
|
|
error={channelsQuery.isError && !channelsQuery.data ? t("common.loadError") : undefined}
|
|
onRetry={() => void channelsQuery.refetch()}
|
|
emptyText={t("sidebar.noChannelMatch")}
|
|
selectedLabels={names}
|
|
labelsPending={pending}
|
|
/>
|
|
);
|
|
}
|