import { useEffect, useRef, useState } from 'react'; import type { UserStatus } from '@backspace/shared'; import { useAuthStore } from '../../stores/authStore'; import { useT, type TranslationKey } from '../../i18n'; interface AccountMenuProps { onClose: () => void; onEditProfile: () => void; } const STATUSES: { value: UserStatus; key: TranslationKey; dot: string }[] = [ { value: 'online', key: 'accountMenu.status.online', dot: 'bg-status-online' }, { value: 'idle', key: 'accountMenu.status.idle', dot: 'bg-status-idle' }, { value: 'dnd', key: 'accountMenu.status.dnd', dot: 'bg-status-dnd' }, // 'offline' chosen deliberately is what other clients call invisible. { value: 'offline', key: 'accountMenu.status.offline', dot: 'bg-txt-tertiary' }, ]; export function AccountMenu({ onClose, onEditProfile }: AccountMenuProps) { const t = useT(); const user = useAuthStore((s) => s.user); const updateProfile = useAuthStore((s) => s.updateProfile); const [copied, setCopied] = useState(false); const menuRef = useRef(null); useEffect(() => { const handlePointer = (e: MouseEvent | TouchEvent) => { if (!menuRef.current?.contains(e.target as Node)) onClose(); }; const handleKey = (e: KeyboardEvent) => { if (e.key === 'Escape') { e.stopPropagation(); onClose(); } }; // touchstart alongside mousedown: iOS Safari does not reliably synthesise // mousedown from a tap, matching what the other popovers here do. document.addEventListener('mousedown', handlePointer); document.addEventListener('touchstart', handlePointer); document.addEventListener('keydown', handleKey); return () => { document.removeEventListener('mousedown', handlePointer); document.removeEventListener('touchstart', handlePointer); document.removeEventListener('keydown', handleKey); }; }, [onClose]); if (!user) return null; const handleStatus = async (status: UserStatus) => { if (status === (user.status ?? 'online')) return onClose(); try { await updateProfile({ status }); } finally { onClose(); } }; const handleCopyId = async () => { try { await navigator.clipboard.writeText(user.id); setCopied(true); // Left open on purpose: the confirmation is the only feedback, and // closing immediately would hide it. setTimeout(() => setCopied(false), 1500); } catch { // Clipboard is unavailable over plain http or without permission. } }; return (
{t('accountMenu.status')}
{STATUSES.map((option) => ( ))}
); }