import { addGroupMember, type ConversationSummary, leaveGroup } from '@chat-app/shared/chat'; import { extractErrorCode } from '@chat-app/shared/i18n'; import { useMemo, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { useNavigate } from 'react-router-dom'; import { useAuth } from '../context/AuthContext'; import { useFriendshipsContext } from '../context/FriendshipsContext'; import { supabase } from '../lib/supabase'; import { AlertIcon, PlusIcon, SignOutIcon, SpinnerIcon, UsersIcon, XIcon } from './icons'; interface Props { open: boolean; onClose: () => void; conversation: ConversationSummary; } export function GroupInfoPanel({ open, onClose, conversation }: Props) { const { t } = useTranslation(['app', 'errors']); const { session } = useAuth(); const { friendships } = useFriendshipsContext(); const navigate = useNavigate(); const [busyLeave, setBusyLeave] = useState(false); const [busyAddId, setBusyAddId] = useState(null); const [error, setError] = useState(null); const myId = session?.user.id; const myRole = conversation.members.find((m) => m.userId === myId)?.role ?? conversation.myRole; const canAdd = myRole === 'admin' || myRole === 'mod'; const addableFriends = useMemo(() => { const memberIds = new Set(conversation.members.map((m) => m.userId)); return friendships .filter((f) => f.status === 'accepted') .map((f) => f.peer) .filter((p) => !memberIds.has(p.userId)); }, [friendships, conversation.members]); async function handleAdd(userId: string) { if (busyAddId) return; setBusyAddId(userId); setError(null); try { await addGroupMember(supabase, conversation.id, userId); } catch (err: unknown) { const code = extractErrorCode(err); setError( code ? t('errors:' + code, { defaultValue: t('errors:generic') }) : err instanceof Error ? err.message : t('errors:generic'), ); } finally { setBusyAddId(null); } } async function handleLeave() { if (busyLeave) return; if (!window.confirm(t('app:group.info_leave_confirm'))) return; setBusyLeave(true); setError(null); try { await leaveGroup(supabase, conversation.id); onClose(); navigate('/chats'); } catch (err: unknown) { const code = extractErrorCode(err); setError( code ? t('errors:' + code, { defaultValue: t('errors:generic') }) : err instanceof Error ? err.message : t('errors:generic'), ); } finally { setBusyLeave(false); } } if (!open) return null; const roleLabel = (role: string) => role === 'admin' ? t('app:group.info_role_admin') : role === 'mod' ? t('app:group.info_role_mod') : t('app:group.info_role_member'); return ( ); }