| |
| |
| |
| |
| |
|
|
| import { useEffect, useRef, useState } from 'react' |
| import { useNavigate } from 'react-router-dom' |
| import useAppStore from '../store/appStore' |
| import { logout as apiLogout } from '../api/auth' |
|
|
| export default function UserMenu() { |
| const navigate = useNavigate() |
| const currentUser = useAppStore((s) => s.currentUser) |
| const setCurrentUser = useAppStore((s) => s.setCurrentUser) |
|
|
| const [open, setOpen] = useState(false) |
| const panelRef = useRef(null) |
| const buttonRef = useRef(null) |
|
|
| useEffect(() => { |
| if (!open) return |
| function onDown(e) { |
| if (panelRef.current?.contains(e.target)) return |
| if (buttonRef.current?.contains(e.target)) return |
| setOpen(false) |
| } |
| document.addEventListener('mousedown', onDown) |
| return () => document.removeEventListener('mousedown', onDown) |
| }, [open]) |
|
|
| if (!currentUser) return null |
|
|
| |
| |
| |
| const avatar = (currentUser.first_name?.[0] ?? currentUser.email[0] ?? '?').toUpperCase() |
| const displayName = currentUser.first_name |
| ? `${currentUser.first_name} ${currentUser.last_name ?? ''}`.trim() |
| : currentUser.email |
|
|
| async function onLogout() { |
| setOpen(false) |
| await apiLogout() |
| |
| |
| |
| const { resetProject, setSessions, setActiveSessionId, setMessages } = useAppStore.getState() |
| resetProject() |
| setSessions([]) |
| setActiveSessionId(null) |
| setMessages([]) |
| setCurrentUser(null) |
| navigate('/', { replace: true }) |
| } |
|
|
| return ( |
| <div className="relative"> |
| <button |
| ref={buttonRef} |
| onClick={() => setOpen((v) => !v)} |
| className="w-7 h-7 rounded-full grid place-items-center text-[11px] font-semibold transition-transform" |
| style={{ |
| background: 'linear-gradient(135deg, var(--accent), var(--accent-lo))', |
| color: '#fff', |
| border: open ? '2px solid var(--accent-hi)' : '2px solid transparent', |
| boxSizing: 'border-box', |
| }} |
| title={currentUser.email} |
| aria-label="Account menu" |
| > |
| {avatar} |
| </button> |
| |
| {open && ( |
| <div |
| ref={panelRef} |
| className="absolute right-0 mt-2 w-[220px] rounded-lg border shadow-2xl z-50 fade-in" |
| style={{ |
| background: 'var(--surface)', |
| borderColor: 'var(--border-2)', |
| boxShadow: '0 12px 36px rgba(0,0,0,0.5)', |
| }} |
| > |
| <div className="px-3 py-2.5 border-b" style={{ borderColor: 'var(--border)' }}> |
| <div className="text-[10px] uppercase tracking-wider" style={{ color: 'var(--text-faint)' }}> |
| Signed in as |
| </div> |
| <div className="text-[13px] truncate mt-0.5" style={{ color: 'var(--text)', fontWeight: 500 }}> |
| {displayName} |
| </div> |
| {currentUser.username && ( |
| <div className="text-[11px] mono truncate" style={{ color: 'var(--text-faint)', marginTop: 2 }}> |
| @{currentUser.username} · {currentUser.email} |
| </div> |
| )} |
| </div> |
| <button |
| onClick={onLogout} |
| className="w-full text-left px-3 py-2 text-[12.5px] hover:bg-[var(--surface-2)] transition-colors" |
| style={{ color: 'var(--text)' }} |
| > |
| Sign out |
| </button> |
| </div> |
| )} |
| </div> |
| ) |
| } |
|
|