'use client'; import { useState, useEffect } from 'react'; import { Menu, Avatar, NavLink, ActionIcon, SegmentedControl, Text, Stack, ScrollArea, Code } from '@mantine/core'; import { useMantineColorScheme } from '@mantine/core'; import { notifications } from '@mantine/notifications'; import { IconSun, IconMoon, IconDeviceDesktop } from '@tabler/icons-react'; import { useRouter } from 'next/navigation'; interface UserProfile { did: string; handle: string; displayName: string | null; avatar: string | null; } interface Node { id: string; title: string; user_did: string; } export function UserMenu({ showLabel = false }: { showLabel?: boolean } = {}) { const router = useRouter(); const { colorScheme, setColorScheme } = useMantineColorScheme(); const [profile, setProfile] = useState(null); const [loading, setLoading] = useState(true); const [nodes, setNodes] = useState([]); const [nodesLoading, setNodesLoading] = useState(false); const [isDeleting, setIsDeleting] = useState(false); useEffect(() => { // Fetch user profile on mount fetch('/api/user/profile') .then((res) => res.json()) .then((data) => { if (!data.error) { setProfile(data); } }) .catch((error) => { console.error('Failed to fetch profile:', error); }) .finally(() => { setLoading(false); }); }, []); // Fetch user's nodes for debugging const fetchNodes = async () => { setNodesLoading(true); try { const response = await fetch('/api/nodes/debug', { credentials: 'include', }); const data = await response.json(); if (!data.error) { setNodes(data.nodes || []); } } catch (error) { console.error('Failed to fetch nodes:', error); } finally { setNodesLoading(false); } }; // Delete a node (debug) - Matches ThoughtGalaxy delete pattern const handleDebugDelete = async (nodeId: string) => { setIsDeleting(true); try { // Extract clean ID from SurrealDB RecordId format (removes angle brackets ⟨⟩) const cleanId = String(nodeId).replace(/[⟨⟩]/g, ''); const response = await fetch(`/api/nodes/${cleanId}`, { method: 'DELETE', credentials: 'include', }); if (!response.ok) { const errorData = await response.json(); throw new Error(errorData.error || 'Failed to delete node'); } notifications.show({ title: 'Node deleted', message: 'Node has been deleted from Bluesky and your galaxy', color: 'green', }); // Update local state to remove the deleted node setNodes((prevNodes) => prevNodes.filter((n) => n.id !== nodeId)); } catch (error) { console.error('[UserMenu Debug] Delete error:', error); notifications.show({ title: 'Delete failed', message: error instanceof Error ? error.message : 'Failed to delete node', color: 'red', }); } finally { setIsDeleting(false); } }; const handleLogout = async () => { try { await fetch('/api/auth/logout', { method: 'POST' }); router.push('/login'); } catch (error) { console.error('Logout failed:', error); } }; if (loading || !profile) { return showLabel ? ( ? } variant="filled" color="blue" styles={{ root: { borderRadius: '8px', fontWeight: 400, }, }} disabled /> ) : ( ? ); } // Get display name or handle const displayText = profile.displayName || profile.handle; // Get initials for fallback const initials = profile.displayName ? profile.displayName .split(' ') .map((n) => n[0]) .join('') .toUpperCase() .slice(0, 2) : profile.handle.slice(0, 2).toUpperCase(); return ( {showLabel ? ( {initials} } variant="filled" color="blue" styles={{ root: { borderRadius: '8px', fontWeight: 400, }, }} /> ) : ( {initials} )} {displayText}
@{profile.handle}
{/* Theme Selection */}
Theme setColorScheme(value as 'light' | 'dark' | 'auto')} data={[ { value: 'light', label: (
), }, { value: 'dark', label: (
), }, { value: 'auto', label: (
), }, ]} fullWidth size="xs" />
{/* Debug: Show all nodes */} {process.env.NODE_ENV === 'development' && ( <> Debug: SurrealDB Nodes
{nodes.length > 0 && ( {nodes.map((node) => (
{node.title}
{node.id}
))}
)} {nodes.length === 0 && !nodesLoading && ( No nodes found in SurrealDB )}
)} Log out
); }