import { useState } from 'react'; import { useMutation, useQueryClient } from '@tanstack/react-query'; import { useTranslation } from 'react-i18next'; import { deleteInstanceGuild, instanceGuildsQueryKey, instanceUsersQueryKey, updateInstanceGuild, } from '@/api/instance'; import { ErrorNotice } from '@/components/ui/ErrorNotice'; import { Field } from '@/components/ui/Field'; import { Button } from '@/components/ui/primitives'; import { useUnsavedChanges } from '@/lib/unsavedChanges'; import type { InstanceGuild } from '@/api/types'; interface InstanceGuildsPanelProps { guilds: InstanceGuild[]; isPending: boolean; error: unknown; onRetry: () => void; /** Открыть настройки сервера: админ правит комнаты, роли и ники там. */ onOpenSettings: (guildId: string) => void; } /** * Серверы инстанса (AGENT.md 7.19): администратор переименовывает и удаляет * любой сервер и открывает его настройки — комнаты, роли и ники правятся * обычными разделами, права администратора инстанса действуют везде. */ export function InstanceGuildsPanel({ guilds, isPending, error, onRetry, onOpenSettings, }: InstanceGuildsPanelProps) { const { t } = useTranslation(); const queryClient = useQueryClient(); const [renaming, setRenaming] = useState(null); const [name, setName] = useState(''); const [actionError, setActionError] = useState(null); const invalidate = (): void => { void queryClient.invalidateQueries({ queryKey: instanceGuildsQueryKey }); void queryClient.invalidateQueries({ queryKey: instanceUsersQueryKey }); }; const rename = useMutation({ mutationFn: (input: { id: string; name: string }) => updateInstanceGuild(input.id, { name: input.name }), onSuccess: () => { setActionError(null); setRenaming(null); invalidate(); }, onError: (cause: unknown) => setActionError(cause), }); const remove = useMutation({ mutationFn: (guildId: string) => deleteInstanceGuild(guildId), onSuccess: () => { setActionError(null); invalidate(); }, onError: (cause: unknown) => setActionError(cause), }); // Незаконченное переименование сервера: черновик живёт в поле, пока форма открыта. useUnsavedChanges({ dirty: renaming !== null && name.trim() !== '' && name.trim() !== renaming.name, save: async () => { if (renaming === null || name.trim() === '') { return; } await rename.mutateAsync({ id: renaming.id, name: name.trim() }); }, }); const pending = rename.isPending || remove.isPending; if (isPending) { return

{t('common.loading')}

; } if (error !== null && error !== undefined) { return ; } if (guilds.length === 0) { return

{t('settings.instance.guildsEmpty')}

; } return (
{actionError === null ? null : }
    {guilds.map((guild) => (
  • {guild.name} {guild.is_main ? `${t('settings.instance.mainBadge')} · ` : ''} {t('settings.instance.memberCount', { count: guild.member_count })}
  • ))}
{renaming === null ? null : (
{ event.preventDefault(); if (renaming !== null && name.trim() !== '') { rename.mutate({ id: renaming.id, name: name.trim() }); } }} > setName(event.target.value)} /> )}
); }