// app/(tabs)/profile/overview.tsx
import React, { useState, useCallback } from 'react';
import { View, FlatList, RefreshControl, Pressable, TouchableOpacity, ImageBackground, Clipboard } 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 { useProfileStats } from '@/lib/hooks/useProfileStats';
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';
import { nip19 } from 'nostr-tools';
// 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;
// Profile follower stats component
const ProfileFollowerStats = React.memo(({ pubkey }: { pubkey?: string }) => {
const { followersCount, followingCount, isLoading, error } = useProfileStats({
pubkey,
refreshInterval: 60000 * 15 // refresh every 15 minutes
});
return (
{isLoading ? '...' : followingCount.toLocaleString()}
following
{isLoading ? '...' : followersCount.toLocaleString()}
followers
);
});
// Generate npub format for display
const npubFormat = React.useMemo(() => {
if (!pubkey) return '';
try {
const npub = nip19.npubEncode(pubkey);
return npub;
} catch (error) {
console.error('Error encoding npub:', error);
return '';
}
}, [pubkey]);
// Get shortened npub display version
const shortenedNpub = React.useMemo(() => {
if (!npubFormat) return '';
return `${npubFormat.substring(0, 8)}...${npubFormat.substring(npubFormat.length - 5)}`;
}, [npubFormat]);
// 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 npub to clipboard
const copyPubkey = useCallback(() => {
if (pubkey) {
try {
const npub = nip19.npubEncode(pubkey);
Clipboard.setString(npub);
Alert.alert('Copied', 'Public key copied to clipboard in npub format');
console.log('npub copied to clipboard:', npub);
} catch (error) {
console.error('Error copying npub:', error);
Alert.alert('Error', 'Failed to copy public key');
}
}
}, [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 */}
{/* Edit Profile button - positioned to the right */}
router.push('/profile/settings')}
>
Edit Profile
{/* Profile info */}
{displayName}
{username}
{/* Display npub below username with sharing options */}
{npubFormat && (
{shortenedNpub}
)}
{/* Follower stats */}
{/* About text */}
{aboutText && (
{aboutText}
)}
{/* Divider */}
), [displayName, username, profileImageUrl, aboutText, pubkey, npubFormat, shortenedNpub, 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
}}
/>
);
}