Sergei abcc380984 Sync all changes - profile restructure and scheme updates
- Restructured profile screens location
- Updated beneficiary detail page
- Updated API service
- Updated all scheme files (MainScheme, ENV API, Discussion, AppStore, SysAnal)
- Added PageHeader component

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-12 16:48:07 -08:00

508 lines
15 KiB
TypeScript

import React, { useState } from 'react';
import {
View,
Text,
StyleSheet,
ScrollView,
TouchableOpacity,
Alert,
Switch,
} from 'react-native';
import { router } from 'expo-router';
import { Ionicons } from '@expo/vector-icons';
import { SafeAreaView } from 'react-native-safe-area-context';
import { useAuth } from '@/contexts/AuthContext';
import { AppColors, BorderRadius, FontSizes, Spacing } from '@/constants/theme';
interface MenuItemProps {
icon: keyof typeof Ionicons.glyphMap;
iconColor?: string;
iconBgColor?: string;
title: string;
subtitle?: string;
onPress?: () => void;
showChevron?: boolean;
rightElement?: React.ReactNode;
}
function MenuItem({
icon,
iconColor = AppColors.primary,
iconBgColor = '#DBEAFE',
title,
subtitle,
onPress,
showChevron = true,
rightElement,
}: MenuItemProps) {
return (
<TouchableOpacity style={styles.menuItem} onPress={onPress} disabled={!onPress}>
<View style={[styles.menuIconContainer, { backgroundColor: iconBgColor }]}>
<Ionicons name={icon} size={20} color={iconColor} />
</View>
<View style={styles.menuTextContainer}>
<Text style={styles.menuTitle}>{title}</Text>
{subtitle && <Text style={styles.menuSubtitle}>{subtitle}</Text>}
</View>
{rightElement ? rightElement : showChevron && onPress && (
<Ionicons name="chevron-forward" size={20} color={AppColors.textMuted} />
)}
</TouchableOpacity>
);
}
export default function ProfileScreen() {
const { user, logout } = useAuth();
// Settings states
const [pushNotifications, setPushNotifications] = useState(true);
const [emailNotifications, setEmailNotifications] = useState(false);
const [biometricLogin, setBiometricLogin] = useState(false);
const handleLogout = () => {
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');
},
},
],
{ cancelable: true }
);
};
// Navigation handlers - now using actual page navigation
const handleEditProfile = () => router.push('/(tabs)/profile/edit');
const handleNotifications = () => router.push('/(tabs)/profile/notifications');
const handlePrivacy = () => router.push('/(tabs)/profile/privacy');
const handleUpgrade = () => router.push('/(tabs)/profile/subscription');
const handlePayment = () => router.push('/(tabs)/profile/subscription');
const handleHelp = () => router.push('/(tabs)/profile/help');
const handleSupport = () => router.push('/(tabs)/profile/support');
const handleTerms = () => router.push('/(tabs)/profile/terms');
const handlePrivacyPolicy = () => router.push('/(tabs)/profile/privacy-policy');
const handleLanguage = () => router.push('/(tabs)/profile/language');
const handleAbout = () => router.push('/(tabs)/profile/about');
const handleDevInfo = () => {
Alert.alert(
'Developer Info',
`User ID: ${user?.user_id || 'N/A'}\n` +
`Username: ${user?.user_name || 'N/A'}\n` +
`Role: ${user?.max_role || 'N/A'}\n` +
`Privileges: ${user?.privileges || 'N/A'}\n\n` +
'Tap "Copy" to copy debug info.',
[
{ text: 'Close' },
{ text: 'Copy', onPress: () => Alert.alert('Copied', 'Debug info copied to clipboard') },
]
);
};
return (
<SafeAreaView style={styles.container} edges={['top']}>
<ScrollView showsVerticalScrollIndicator={false}>
{/* Header */}
<View style={styles.header}>
<Text style={styles.headerTitle}>Profile</Text>
</View>
{/* User Info */}
<View style={styles.userCard}>
<View style={styles.avatarContainer}>
<Text style={styles.avatarText}>
{user?.user_name?.charAt(0).toUpperCase() || 'U'}
</Text>
</View>
<View style={styles.userInfo}>
<Text style={styles.userName}>{user?.user_name || 'User'}</Text>
<Text style={styles.userRole}>
{user?.max_role === 2 ? 'Administrator' : 'Caregiver'}
</Text>
<Text style={styles.userId}>ID: {user?.user_id || 'N/A'}</Text>
</View>
<TouchableOpacity style={styles.editButton} onPress={handleEditProfile}>
<Ionicons name="pencil" size={18} color={AppColors.primary} />
</TouchableOpacity>
</View>
{/* Quick Stats */}
<View style={styles.statsContainer}>
<View style={styles.statItem}>
<Text style={styles.statValue}>{user?.privileges?.split(',').length || 0}</Text>
<Text style={styles.statLabel}>Beneficiaries</Text>
</View>
<View style={styles.statDivider} />
<View style={styles.statItem}>
<Text style={styles.statValue}>24/7</Text>
<Text style={styles.statLabel}>Monitoring</Text>
</View>
<View style={styles.statDivider} />
<View style={styles.statItem}>
<Text style={styles.statValue}>Free</Text>
<Text style={styles.statLabel}>Plan</Text>
</View>
</View>
{/* Account Section */}
<View style={styles.section}>
<Text style={styles.sectionTitle}>Account</Text>
<View style={styles.menuCard}>
<MenuItem
icon="person-outline"
title="Edit Profile"
subtitle="Update your personal information"
onPress={handleEditProfile}
/>
<View style={styles.menuDivider} />
<MenuItem
icon="notifications-outline"
iconBgColor="#FEF3C7"
iconColor={AppColors.warning}
title="Notifications"
subtitle="Manage notification preferences"
onPress={handleNotifications}
/>
<View style={styles.menuDivider} />
<MenuItem
icon="shield-checkmark-outline"
iconBgColor="#D1FAE5"
iconColor={AppColors.success}
title="Privacy & Security"
subtitle="Password, 2FA, data"
onPress={handlePrivacy}
/>
</View>
</View>
{/* App Settings */}
<View style={styles.section}>
<Text style={styles.sectionTitle}>App Settings</Text>
<View style={styles.menuCard}>
<MenuItem
icon="notifications"
iconBgColor="#DBEAFE"
iconColor={AppColors.primary}
title="Push Notifications"
subtitle="Receive alerts on your device"
showChevron={false}
rightElement={
<Switch
value={pushNotifications}
onValueChange={setPushNotifications}
trackColor={{ false: '#E5E7EB', true: AppColors.primaryLight }}
thumbColor={pushNotifications ? AppColors.primary : '#9CA3AF'}
/>
}
/>
<View style={styles.menuDivider} />
<MenuItem
icon="mail-outline"
iconBgColor="#FEE2E2"
iconColor="#EF4444"
title="Email Notifications"
subtitle="Daily summary reports"
showChevron={false}
rightElement={
<Switch
value={emailNotifications}
onValueChange={setEmailNotifications}
trackColor={{ false: '#E5E7EB', true: AppColors.primaryLight }}
thumbColor={emailNotifications ? AppColors.primary : '#9CA3AF'}
/>
}
/>
<View style={styles.menuDivider} />
<MenuItem
icon="finger-print"
iconBgColor="#D1FAE5"
iconColor={AppColors.success}
title="Biometric Login"
subtitle="Face ID / Touch ID"
showChevron={false}
rightElement={
<Switch
value={biometricLogin}
onValueChange={(value) => {
setBiometricLogin(value);
if (value) {
Alert.alert('Biometric Login', 'Biometric authentication enabled!');
}
}}
trackColor={{ false: '#E5E7EB', true: AppColors.primaryLight }}
thumbColor={biometricLogin ? AppColors.primary : '#9CA3AF'}
/>
}
/>
<View style={styles.menuDivider} />
<MenuItem
icon="language-outline"
iconBgColor="#FEF3C7"
iconColor="#F59E0B"
title="Language"
subtitle="English"
onPress={handleLanguage}
/>
</View>
</View>
{/* Subscription */}
<View style={styles.section}>
<Text style={styles.sectionTitle}>Subscription</Text>
<View style={styles.menuCard}>
<MenuItem
icon="diamond-outline"
iconBgColor="#F3E8FF"
iconColor="#9333EA"
title="WellNuo Pro"
subtitle="Upgrade for premium features"
onPress={handleUpgrade}
/>
<View style={styles.menuDivider} />
<MenuItem
icon="card-outline"
title="Payment Methods"
subtitle="Manage your payment options"
onPress={handlePayment}
/>
</View>
</View>
{/* Support */}
<View style={styles.section}>
<Text style={styles.sectionTitle}>Support</Text>
<View style={styles.menuCard}>
<MenuItem
icon="help-circle-outline"
title="Help Center"
subtitle="FAQs and guides"
onPress={handleHelp}
/>
<View style={styles.menuDivider} />
<MenuItem
icon="chatbubble-outline"
title="Contact Support"
subtitle="Get help from our team"
onPress={handleSupport}
/>
<View style={styles.menuDivider} />
<MenuItem
icon="document-text-outline"
title="Terms of Service"
onPress={handleTerms}
/>
<View style={styles.menuDivider} />
<MenuItem
icon="shield-outline"
title="Privacy Policy"
onPress={handlePrivacyPolicy}
/>
</View>
</View>
{/* About */}
<View style={styles.section}>
<Text style={styles.sectionTitle}>About</Text>
<View style={styles.menuCard}>
<MenuItem
icon="information-circle-outline"
iconBgColor="#DBEAFE"
iconColor={AppColors.primary}
title="About WellNuo"
subtitle="Version, licenses, credits"
onPress={handleAbout}
/>
<View style={styles.menuDivider} />
<MenuItem
icon="bug-outline"
iconBgColor="#FEE2E2"
iconColor="#EF4444"
title="Developer Info"
subtitle="Debug information"
onPress={handleDevInfo}
/>
</View>
</View>
{/* Logout Button */}
<View style={styles.section}>
<TouchableOpacity style={styles.logoutButton} onPress={handleLogout}>
<Ionicons name="log-out-outline" size={20} color={AppColors.error} />
<Text style={styles.logoutText}>Logout</Text>
</TouchableOpacity>
</View>
{/* Version */}
<Text style={styles.version}>WellNuo v1.0.0 (Expo SDK 54)</Text>
</ScrollView>
</SafeAreaView>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: AppColors.surface,
},
header: {
paddingHorizontal: Spacing.lg,
paddingVertical: Spacing.md,
backgroundColor: AppColors.background,
borderBottomWidth: 1,
borderBottomColor: AppColors.border,
},
headerTitle: {
fontSize: FontSizes.xl,
fontWeight: '700',
color: AppColors.textPrimary,
},
userCard: {
flexDirection: 'row',
alignItems: 'center',
backgroundColor: AppColors.background,
padding: Spacing.lg,
},
avatarContainer: {
width: 64,
height: 64,
borderRadius: BorderRadius.full,
backgroundColor: AppColors.primary,
justifyContent: 'center',
alignItems: 'center',
},
avatarText: {
fontSize: FontSizes['2xl'],
fontWeight: '600',
color: AppColors.white,
},
userInfo: {
flex: 1,
marginLeft: Spacing.md,
},
userName: {
fontSize: FontSizes.lg,
fontWeight: '600',
color: AppColors.textPrimary,
},
userRole: {
fontSize: FontSizes.sm,
color: AppColors.textSecondary,
marginTop: 2,
},
userId: {
fontSize: FontSizes.xs,
color: AppColors.textMuted,
marginTop: 2,
},
editButton: {
width: 40,
height: 40,
borderRadius: BorderRadius.full,
backgroundColor: AppColors.surface,
justifyContent: 'center',
alignItems: 'center',
},
statsContainer: {
flexDirection: 'row',
backgroundColor: AppColors.background,
paddingVertical: Spacing.md,
paddingHorizontal: Spacing.lg,
borderTopWidth: 1,
borderTopColor: AppColors.border,
marginBottom: Spacing.md,
},
statItem: {
flex: 1,
alignItems: 'center',
},
statValue: {
fontSize: FontSizes.xl,
fontWeight: '700',
color: AppColors.primary,
},
statLabel: {
fontSize: FontSizes.xs,
color: AppColors.textMuted,
marginTop: 2,
},
statDivider: {
width: 1,
backgroundColor: AppColors.border,
marginVertical: Spacing.xs,
},
section: {
marginBottom: Spacing.md,
},
sectionTitle: {
fontSize: FontSizes.sm,
fontWeight: '600',
color: AppColors.textSecondary,
paddingHorizontal: Spacing.lg,
paddingVertical: Spacing.sm,
textTransform: 'uppercase',
},
menuCard: {
backgroundColor: AppColors.background,
},
menuItem: {
flexDirection: 'row',
alignItems: 'center',
paddingVertical: Spacing.md,
paddingHorizontal: Spacing.lg,
},
menuIconContainer: {
width: 36,
height: 36,
borderRadius: BorderRadius.md,
justifyContent: 'center',
alignItems: 'center',
},
menuTextContainer: {
flex: 1,
marginLeft: Spacing.md,
},
menuTitle: {
fontSize: FontSizes.base,
fontWeight: '500',
color: AppColors.textPrimary,
},
menuSubtitle: {
fontSize: FontSizes.xs,
color: AppColors.textMuted,
marginTop: 2,
},
menuDivider: {
height: 1,
backgroundColor: AppColors.border,
marginLeft: Spacing.lg + 36 + Spacing.md,
},
logoutButton: {
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'center',
backgroundColor: AppColors.background,
paddingVertical: Spacing.md,
marginHorizontal: Spacing.lg,
borderRadius: BorderRadius.lg,
},
logoutText: {
fontSize: FontSizes.base,
fontWeight: '600',
color: AppColors.error,
marginLeft: Spacing.sm,
},
version: {
textAlign: 'center',
fontSize: FontSizes.xs,
color: AppColors.textMuted,
paddingVertical: Spacing.xl,
},
});