import React, { useState, useEffect, useCallback, useMemo } from 'react'; import { View, Text, StyleSheet, TouchableOpacity, Alert, Image, ScrollView, } from 'react-native'; import { Ionicons } from '@expo/vector-icons'; import { SafeAreaView } from 'react-native-safe-area-context'; import * as SecureStore from 'expo-secure-store'; import * as ImagePicker from 'expo-image-picker'; import * as Clipboard from 'expo-clipboard'; import { router } from 'expo-router'; import { useAuth } from '@/contexts/AuthContext'; import { ProfileDrawer } from '@/components/ProfileDrawer'; import { useToast } from '@/components/ui/Toast'; import { AppColors, BorderRadius, FontSizes, Spacing, FontWeights, Shadows, AvatarSizes, } from '@/constants/theme'; // Generate stable 5-digit invite code from user identifier const generateInviteCode = (identifier: string): string => { // Simple hash to get a stable code let hash = 0; for (let i = 0; i < identifier.length; i++) { const char = identifier.charCodeAt(i); hash = ((hash << 5) - hash) + char; hash = hash & hash; // Convert to 32bit integer } // Convert to 5-digit code (10000-99999 range) const code = 10000 + (Math.abs(hash) % 90000); return code.toString(); }; export default function ProfileScreen() { const { user, logout } = useAuth(); const toast = useToast(); // Drawer state const [drawerVisible, setDrawerVisible] = useState(false); // Settings states const [settings, setSettings] = useState({ pushNotifications: true, emailNotifications: false, biometricLogin: false, }); // Avatar const [avatarUri, setAvatarUri] = useState(null); useEffect(() => { loadAvatar(); }, [user?.user_id]); const loadAvatar = async () => { try { const uri = await SecureStore.getItemAsync('userAvatar'); if (uri) { setAvatarUri(uri); } } catch (err) { console.error('Failed to load avatar:', err); } }; const handleAvatarPress = async () => { const { status } = await ImagePicker.requestMediaLibraryPermissionsAsync(); if (status !== 'granted') { Alert.alert('Permission needed', 'Please allow access to your photo library to change avatar.'); return; } const result = await ImagePicker.launchImageLibraryAsync({ mediaTypes: ['images'], allowsEditing: true, aspect: [1, 1], quality: 0.5, }); if (!result.canceled && result.assets[0]) { const uri = result.assets[0].uri; setAvatarUri(uri); await SecureStore.setItemAsync('userAvatar', uri); } }; const handleSettingChange = (key: string, value: boolean) => { setSettings(prev => ({ ...prev, [key]: value })); if (key === 'biometricLogin' && value) { Alert.alert('Biometric Login', 'Biometric authentication enabled!'); } }; const handleLogout = () => { setDrawerVisible(false); Alert.alert( 'Logout', 'Are you sure you want to logout?', [ { text: 'Cancel', style: 'cancel' }, { text: 'Logout', style: 'destructive', onPress: async () => { await logout(); router.replace('/(auth)/login'); }, }, ] ); }; const userName = user?.user_name || 'User'; const userInitial = userName.charAt(0).toUpperCase(); // Generate invite code based on user email or id const inviteCode = useMemo(() => { const identifier = user?.email || user?.user_id?.toString() || 'default'; return generateInviteCode(identifier); }, [user?.email, user?.user_id]); const handleCopyInviteCode = async () => { await Clipboard.setStringAsync(inviteCode); toast.success(`Invite code "${inviteCode}" copied to clipboard`); }; return ( {/* Header */} setDrawerVisible(true)} > Profile {/* Profile Card */} {avatarUri ? ( ) : ( {userInitial} )} {userName} {user?.email || ''} {/* Invite Code */} Your Invite Code {inviteCode} Tap to copy ยท Share with friends for rewards {/* Menu Items */} router.push('/(tabs)/profile/edit')} > Edit Profile router.push('/(tabs)')} > My Loved Ones setDrawerVisible(true)} > Settings Log Out {/* Settings Drawer */} setDrawerVisible(false)} onLogout={handleLogout} settings={settings} onSettingChange={handleSettingChange} /> ); } const styles = StyleSheet.create({ container: { flex: 1, backgroundColor: AppColors.background, }, header: { flexDirection: 'row', alignItems: 'center', justifyContent: 'space-between', paddingHorizontal: Spacing.lg, paddingVertical: Spacing.md, borderBottomWidth: 1, borderBottomColor: AppColors.border, }, menuButton: { width: 40, height: 40, borderRadius: BorderRadius.md, backgroundColor: AppColors.surfaceSecondary, justifyContent: 'center', alignItems: 'center', }, headerTitle: { fontSize: FontSizes.lg, fontWeight: FontWeights.semibold, color: AppColors.textPrimary, }, placeholder: { width: 40, }, scrollView: { flex: 1, }, scrollContent: { padding: Spacing.lg, paddingBottom: Spacing.xxl, }, // Profile Card profileCard: { backgroundColor: AppColors.surface, borderRadius: BorderRadius.xl, padding: Spacing.xl, alignItems: 'center', marginBottom: Spacing.lg, ...Shadows.sm, }, avatarSection: { marginBottom: Spacing.md, }, avatarContainer: { width: AvatarSizes.xl, height: AvatarSizes.xl, borderRadius: AvatarSizes.xl / 2, backgroundColor: AppColors.primary, justifyContent: 'center', alignItems: 'center', position: 'relative', }, avatarImage: { width: AvatarSizes.xl, height: AvatarSizes.xl, borderRadius: AvatarSizes.xl / 2, }, avatarText: { fontSize: FontSizes['3xl'], fontWeight: FontWeights.bold, color: AppColors.white, }, avatarEditBadge: { position: 'absolute', bottom: 0, right: 0, width: 32, height: 32, borderRadius: 16, backgroundColor: AppColors.primary, justifyContent: 'center', alignItems: 'center', borderWidth: 3, borderColor: AppColors.surface, }, userName: { fontSize: FontSizes['2xl'], fontWeight: FontWeights.bold, color: AppColors.textPrimary, marginBottom: Spacing.xs, }, userEmail: { fontSize: FontSizes.sm, color: AppColors.textSecondary, }, // Invite Code inviteCodeSection: { marginTop: Spacing.lg, alignItems: 'center', paddingTop: Spacing.md, borderTopWidth: 1, borderTopColor: AppColors.border, width: '100%', }, inviteCodeBadge: { flexDirection: 'row', alignItems: 'center', gap: Spacing.xs, marginBottom: Spacing.sm, }, inviteCodeLabel: { fontSize: FontSizes.xs, color: AppColors.primary, fontWeight: FontWeights.medium, }, inviteCodeBox: { flexDirection: 'row', alignItems: 'center', backgroundColor: AppColors.primaryLighter, paddingVertical: Spacing.sm, paddingHorizontal: Spacing.lg, borderRadius: BorderRadius.lg, gap: Spacing.sm, }, inviteCodeText: { fontSize: FontSizes.xl, fontWeight: FontWeights.bold, color: AppColors.primary, letterSpacing: 3, }, inviteCodeHint: { fontSize: FontSizes.xs, color: AppColors.textMuted, marginTop: Spacing.xs, }, // Menu Section menuSection: { backgroundColor: AppColors.surface, borderRadius: BorderRadius.xl, overflow: 'hidden', ...Shadows.sm, }, menuItem: { flexDirection: 'row', alignItems: 'center', paddingVertical: Spacing.md, paddingHorizontal: Spacing.lg, borderBottomWidth: 1, borderBottomColor: AppColors.border, }, menuItemLast: { borderBottomWidth: 0, }, menuIcon: { width: 40, height: 40, borderRadius: BorderRadius.md, backgroundColor: AppColors.surfaceSecondary, justifyContent: 'center', alignItems: 'center', marginRight: Spacing.md, }, menuIconDanger: { backgroundColor: AppColors.errorLight, }, menuLabel: { flex: 1, fontSize: FontSizes.base, color: AppColors.textPrimary, fontWeight: FontWeights.medium, }, // Legacy styles (keeping for potential use) subscriptionCard: { backgroundColor: AppColors.surface, borderRadius: BorderRadius.xl, padding: Spacing.lg, marginBottom: Spacing.lg, ...Shadows.sm, }, subscriptionCardHeader: { flexDirection: 'row', alignItems: 'center', gap: Spacing.md, }, subscriptionIconContainer: { width: 44, height: 44, borderRadius: BorderRadius.lg, justifyContent: 'center', alignItems: 'center', }, subscriptionIconActive: { backgroundColor: AppColors.successLight, }, subscriptionIconInactive: { backgroundColor: `${AppColors.warning}20`, }, subscriptionHeaderText: { flex: 1, }, subscriptionCardTitle: { fontSize: FontSizes.lg, fontWeight: FontWeights.bold, color: AppColors.textPrimary, }, subscriptionCardSubtitle: { fontSize: FontSizes.sm, color: AppColors.textSecondary, marginTop: 2, }, });