// app/(tabs)/profile/overview.tsx import React, { useState, useCallback } from 'react'; import { View, FlatList, RefreshControl, Pressable, TouchableOpacity, ImageBackground } from 'react-native'; import { Text } from '@/components/ui/text'; import { Button } from '@/components/ui/button'; import { useNDKCurrentUser } from '@/lib/hooks/useNDK'; import { ActivityIndicator } from 'react-native'; import { useSafeAreaInsets } from 'react-native-safe-area-context'; import NostrLoginSheet from '@/components/sheets/NostrLoginSheet'; import EnhancedSocialPost from '@/components/social/EnhancedSocialPost'; import EmptyFeed from '@/components/social/EmptyFeed'; import { useSocialFeed } from '@/lib/hooks/useSocialFeed'; import { AnyFeedEntry, WorkoutFeedEntry, ExerciseFeedEntry, TemplateFeedEntry, SocialFeedEntry, ArticleFeedEntry } from '@/types/feed'; import UserAvatar from '@/components/UserAvatar'; import { useRouter } from 'expo-router'; import { QrCode, Mail, Copy } from 'lucide-react-native'; import { useTheme } from '@react-navigation/native'; import type { CustomTheme } from '@/lib/theme'; import { Alert } from 'react-native'; // Define the conversion function for feed items function convertToLegacyFeedItem(entry: AnyFeedEntry) { return { id: entry.eventId, type: entry.type, originalEvent: entry.event!, parsedContent: entry.content!, createdAt: (entry.timestamp || Date.now()) / 1000 }; } export default function OverviewScreen() { const insets = useSafeAreaInsets(); const router = useRouter(); const theme = useTheme() as CustomTheme; const { currentUser, isAuthenticated } = useNDKCurrentUser(); const [isLoginSheetOpen, setIsLoginSheetOpen] = useState(false); // Use useSocialFeed with the profile feed type const { feedItems, loading, refresh, isOffline } = useSocialFeed({ feedType: 'profile', authors: currentUser?.pubkey ? [currentUser.pubkey] : undefined, limit: 30 }); // Convert to the format expected by the component const entries = React.useMemo(() => { return feedItems.map(item => { // Create a properly typed AnyFeedEntry based on the item type const baseEntry = { id: item.id, eventId: item.id, event: item.originalEvent, timestamp: item.createdAt * 1000, }; // Add type-specific properties switch (item.type) { case 'workout': return { ...baseEntry, type: 'workout', content: item.parsedContent } as WorkoutFeedEntry; case 'exercise': return { ...baseEntry, type: 'exercise', content: item.parsedContent } as ExerciseFeedEntry; case 'template': return { ...baseEntry, type: 'template', content: item.parsedContent } as TemplateFeedEntry; case 'social': return { ...baseEntry, type: 'social', content: item.parsedContent } as SocialFeedEntry; case 'article': return { ...baseEntry, type: 'article', content: item.parsedContent } as ArticleFeedEntry; default: // Fallback to social type if unknown return { ...baseEntry, type: 'social', content: item.parsedContent } as SocialFeedEntry; } }); }, [feedItems]); const resetFeed = refresh; const hasContent = entries.length > 0; const [isRefreshing, setIsRefreshing] = useState(false); // Profile data const profileImageUrl = currentUser?.profile?.image || currentUser?.profile?.picture || (currentUser?.profile as any)?.avatar; const bannerImageUrl = currentUser?.profile?.banner || (currentUser?.profile as any)?.background; const displayName = isAuthenticated ? (currentUser?.profile?.displayName || currentUser?.profile?.name || 'Nostr User') : 'Guest User'; const username = isAuthenticated ? (currentUser?.profile?.nip05 || '@user') : '@guest'; const aboutText = currentUser?.profile?.about || (currentUser?.profile as any)?.description; const pubkey = currentUser?.pubkey; // Handle refresh const handleRefresh = useCallback(async () => { setIsRefreshing(true); try { await resetFeed(); // Add a slight delay to ensure the UI updates await new Promise(resolve => setTimeout(resolve, 300)); } catch (error) { console.error('Error refreshing feed:', error); } finally { setIsRefreshing(false); } }, [resetFeed]); // Handle post selection const handlePostPress = useCallback((entry: AnyFeedEntry) => { // Just log the entry info for now console.log(`Selected ${entry.type}:`, entry); }, []); // Copy pubkey to clipboard const copyPubkey = useCallback(() => { if (pubkey) { // Simple alert instead of clipboard functionality Alert.alert('Pubkey', pubkey, [ { text: 'OK' } ]); console.log('Pubkey shown to user'); } }, [pubkey]); // Show QR code alert const showQRCode = useCallback(() => { Alert.alert('QR Code', 'QR Code functionality will be implemented soon', [ { text: 'OK' } ]); }, []); // Memoize render item function const renderItem = useCallback(({ item }: { item: AnyFeedEntry }) => ( handlePostPress(item)} /> ), [handlePostPress]); // Show different UI when not authenticated if (!isAuthenticated) { return ( Login with your Nostr private key to view your profile and posts. {/* NostrLoginSheet */} setIsLoginSheetOpen(false)} /> ); } // Profile header component const ProfileHeader = useCallback(() => ( {/* Banner Image */} {bannerImageUrl ? ( ) : ( )} {/* Left side - Avatar */} {/* Action buttons - positioned to the right */} router.push('/profile/settings')} > Edit Profile {/* Profile info */} {displayName} {username} {/* Follower stats */} 2,003 following 4,764 followers {/* About text */} {aboutText && ( {aboutText} )} {/* Divider */} ), [displayName, username, profileImageUrl, aboutText, pubkey, theme.colors.text, router, showQRCode, copyPubkey]); if (loading && entries.length === 0) { return ( ); } return ( item.id} renderItem={renderItem} refreshControl={ } ListHeaderComponent={} ListEmptyComponent={ } contentContainerStyle={{ paddingBottom: insets.bottom + 20, flexGrow: entries.length === 0 ? 1 : undefined }} /> ); }