import { useEffect, useId, useRef, useState } from 'react'; import { useUserAvatar } from '../hooks/useUserAvatar'; import { AVATAR_PICKER_OPEN_EVENT, getAvatarPickerInput, openAvatarPicker, registerAvatarPickerInput, } from '../utils/userAvatar'; import { UserAvatar } from './UserAvatar'; type AvatarPickerProps = { variant?: 'sidebar' | 'compact'; }; export function AvatarPicker({ variant = 'sidebar' }: AvatarPickerProps) { const inputId = useId(); const inputRef = useRef(null); const ownsInput = true; const { avatarUrl, updateAvatar, resetAvatar } = useUserAvatar(); const [error, setError] = useState(null); const [busy, setBusy] = useState(false); useEffect(() => { if (!ownsInput) return; registerAvatarPickerInput(inputRef.current); const handleOpen = () => { if (!busy) inputRef.current?.click(); }; window.addEventListener(AVATAR_PICKER_OPEN_EVENT, handleOpen); return () => { if (getAvatarPickerInput() === inputRef.current) { registerAvatarPickerInput(null); } window.removeEventListener(AVATAR_PICKER_OPEN_EVENT, handleOpen); }; }, [busy, ownsInput]); const triggerPicker = () => { if (busy) return; if (ownsInput) { inputRef.current?.click(); } else { openAvatarPicker(); } }; const handleChange = async (e: React.ChangeEvent) => { const file = e.target.files?.[0]; e.target.value = ''; if (!file) return; setBusy(true); setError(null); try { await updateAvatar(file); } catch (err) { setError(err instanceof Error ? err.message : '头像更新失败'); } finally { setBusy(false); } }; const fileInput = ownsInput ? ( void handleChange(e)} /> ) : null; if (variant === 'compact') { return ( <> {fileInput} ); } return (
{avatarUrl && ( )} {error &&

{error}

} {fileInput}
); }