import { useEffect, useMemo } from 'react'; import { useQuery } from '@tanstack/react-query'; import { useTranslation } from 'react-i18next'; import { fetchChannels, guildChannelsQueryKey } from '@/api/guilds'; import type { Channel } from '@/api/types'; import { fetchMyGuilds, myGuildsQueryKey } from '@/api/users'; import { ErrorNotice } from '@/components/ui/ErrorNotice'; import { SelectField } from '@/components/ui/Field'; import { Card } from '@/components/ui/primitives'; import { SkeletonLines } from '@/components/ui/Skeleton'; import { canManageWebhooks } from '@/lib/identity'; import { useCurrentUser } from '@/lib/hooks'; import { useSessionStore } from '@/stores/session'; import { ChannelWebhooksSection } from '@/pages/settings/ChannelWebhooksSection'; import { GuildPicker } from '@/pages/settings/GuildPicker'; /** * Пункт «Комната» окна настроек: управление одной комнатой — пока это вебхуки * (AGENT.md 7.11). Сервер выбирается тем же списком, что и в пункте «Сервер», * комната — выпадающим списком текстовых комнат. */ export function ChannelSettingsPage() { const sessionGuilds = useSessionStore((state) => state.guilds); const upsertGuild = useSessionStore((state) => state.upsertGuild); const selectSettingsGuild = useSessionStore((state) => state.selectSettingsGuild); const settingsGuildId = useSessionStore((state) => state.settingsGuildId); // Подстраховка снапшота: без неё список серверов пуст до подключения шлюза. const myGuilds = useQuery({ queryKey: myGuildsQueryKey, queryFn: ({ signal }) => fetchMyGuilds(signal), retry: 0, enabled: sessionGuilds.length === 0, }); useEffect(() => { if (sessionGuilds.length > 0 || myGuilds.data === undefined) { return; } for (const guild of myGuilds.data) { upsertGuild(guild); } }, [sessionGuilds.length, myGuilds.data, upsertGuild]); const guilds = useMemo( () => (sessionGuilds.length > 0 ? sessionGuilds : (myGuilds.data ?? [])), [sessionGuilds, myGuilds.data], ); return (
); } /** Тело пункта: выбор комнаты и её секции. */ function ChannelSettingsBody({ guildId }: { guildId: string | null }) { const { t } = useTranslation(); const currentUser = useCurrentUser(); const settingsChannelId = useSessionStore((state) => state.settingsChannelId); const selectSettingsChannel = useSessionStore((state) => state.selectSettingsChannel); const guild = useSessionStore((state) => guildId === null ? null : (state.guilds.find((item) => item.id === guildId) ?? null), ); // Комнаты сервера: в снапшоте они могут быть пустыми (сервер только открыли), // поэтому тянем их по REST. const channels = useQuery({ queryKey: guildChannelsQueryKey(guildId ?? ''), queryFn: ({ signal }) => fetchChannels(guildId ?? '', signal), enabled: guildId !== null, retry: 0, }); const textChannels = useMemo( () => (channels.data ?? []).filter((channel: Channel) => channel.type === 'text'), [channels.data], ); // Первую текстовую комнату выбираем сами: список только что загрузился. useEffect(() => { if (settingsChannelId !== null || textChannels.length === 0) { return; } const first = textChannels[0]; if (first !== undefined) { selectSettingsChannel(first.id); } }, [settingsChannelId, textChannels, selectSettingsChannel]); if (guildId === null || guild === null) { return (

{t('settings.channel.noGuild')}

); } const isInstanceAdmin = currentUser.data?.is_instance_admin === true; const canManage = canManageWebhooks( guild.my_permissions ?? [], guild.owner_id, currentUser.data?.id, isInstanceAdmin, ); const active = textChannels.find((channel) => channel.id === settingsChannelId) ?? null; return ( <> {channels.isPending ? ( ) : null} {channels.isError ? ( void channels.refetch()} /> ) : null} {channels.isSuccess && textChannels.length === 0 ? (

{t('settings.channel.noChannels')}

) : null} {textChannels.length === 0 ? null : ( selectSettingsChannel(value)} options={textChannels.map((channel) => ({ value: channel.id, label: `#${channel.name}`, }))} /> )} {active === null ? null : ( <> {canManage ? null : (

{t('settings.channel.noPermission')}

)} )} ); }