import { useState } from 'react'; import { View, Text, Pressable, Modal, Image } from 'react-native'; import { useSafeAreaInsets } from 'react-native-safe-area-context'; import { Ionicons } from '@expo/vector-icons'; import { useRouter, type RelativePathString } from 'expo-router'; import { useTranslation } from 'react-i18next'; import { useAuthStore } from '../stores/auth'; import { useNotificationStore } from '../stores/notifications'; import { supabase } from '../lib/supabase'; import { resolveAvatar } from '../lib/resolveAvatar'; import { useMe } from '../hooks/useMe'; import { NotificationsDropdown } from './NotificationsDropdown'; type Props = { notifCount?: number; }; type MenuItem = { icon: React.ComponentProps['name']; label: string; color?: string; action: () => void; }; export function AppHeader({ notifCount }: Props = {}) { const insets = useSafeAreaInsets(); const router = useRouter(); const { t } = useTranslation(); const { user } = useAuthStore(); const { me } = useMe(); const storeUnread = useNotificationStore((s) => s.unread); const badge = notifCount ?? storeUnread; const [dropdownOpen, setDropdownOpen] = useState(false); const [notifOpen, setNotifOpen] = useState(false); const firstName = (user?.user_metadata?.first_name as string | undefined) ?? ''; const lastName = (user?.user_metadata?.last_name as string | undefined) ?? ''; const email = user?.email ?? ''; // Initials-Fallback: erst nickname (DB), dann firstName/email const initials = (() => { if (me?.nickname) return me.nickname.slice(0, 2).toUpperCase(); return ((firstName.charAt(0) + (lastName.charAt(0) || email.charAt(0))).toUpperCase() || '?'); })(); // Avatar: aus DB (`/api/auth/me` → profiles.avatar). Kann Hero-Avatar-ID // ("spider"/"hulk"/...) ODER Custom-Photo-URL (https://... von Foto-Upload) // sein. resolveAvatar handlet beide Fälle. // user_metadata.avatar_id ist veraltet — wird bei Profile-Edit nicht // aktualisiert. DB ist Single Source of Truth. const avatarUrl = me ? resolveAvatar(me.avatar, me.nickname ?? '') : ''; const [avatarLoadFailed, setAvatarLoadFailed] = useState(false); const showAvatarImage = !!avatarUrl && !avatarLoadFailed && !!me?.avatar; function closeAndNavigate(path: RelativePathString) { setDropdownOpen(false); router.push(path); } async function handleSignOut() { setDropdownOpen(false); await supabase.auth.signOut(); router.replace('/' as RelativePathString); } const menuItems: MenuItem[] = [ { icon: 'person-outline', label: t('appHeader.editProfile'), action: () => closeAndNavigate('/settings' as RelativePathString), }, { icon: 'settings-outline', label: t('appHeader.settings'), action: () => closeAndNavigate('/settings' as RelativePathString), }, ]; const headerHeight = insets.top + 56; return ( {t('appHeader.appName')} {/* Notifications dropdown trigger */} setNotifOpen(true)} className="w-9 h-9 rounded-full bg-white items-center justify-center" style={({ pressed }) => ({ opacity: pressed ? 0.7 : 1 })} > {badge > 0 && ( {badge > 9 ? '9+' : String(badge)} )} {/* Profil-Avatar — tap → dropdown */} setDropdownOpen(true)} className={`w-9 h-9 rounded-full items-center justify-center overflow-hidden ${showAvatarImage ? 'bg-neutral-100' : 'bg-rebreak-500'}`} style={({ pressed }) => ({ opacity: pressed ? 0.7 : 1 })} > {showAvatarImage ? ( setAvatarLoadFailed(true)} style={{ width: 36, height: 36, borderRadius: 18 }} /> ) : ( {initials} )} {/* Dropdown modal */} setDropdownOpen(false)} > setDropdownOpen(false)} style={{ flex: 1, backgroundColor: 'rgba(0,0,0,0.18)' }} > true} style={{ position: 'absolute', top: headerHeight + 6, right: 12, backgroundColor: '#ffffff', borderRadius: 18, shadowColor: '#000', shadowOffset: { width: 0, height: 8 }, shadowOpacity: 0.18, shadowRadius: 20, elevation: 12, minWidth: 260, overflow: 'hidden', }} > {/* SOS prominent oben — Pressable mit innerem Row-View */} closeAndNavigate('/urge' as RelativePathString)}> {t('appHeader.sosLabel')} {t('appHeader.sosSubtitle')} {menuItems.map((item) => ( {item.label} ))} {t('appHeader.signOut')} setNotifOpen(false)} topOffset={headerHeight} /> ); }