320 lines
9.7 KiB
TypeScript

import React, { useState, useEffect } from 'react';
import {
Text,
View,
TouchableOpacity,
ScrollView,
Switch,
Image,
Alert,
} from 'react-native';
import AsyncStorage from '@react-native-async-storage/async-storage';
import { useNavigation } from '@react-navigation/native';
import Icon from 'react-native-vector-icons/Ionicons';
import { getStyles } from './profile.styles';
import { useTheme } from '../../theme';
import { ProfileInfoRow } from '@components';
import { useAppDispatch, useAppSelector, logout, RootState } from '@store';
import { NotificationService } from '@services';
export const ProfileScreen = () => {
const navigation = useNavigation<any>();
const { theme: colors, isDark, toggleTheme } = useTheme();
const styles = getStyles(colors);
const dispatch = useAppDispatch();
const [pushEnabled, setPushEnabled] = useState(true);
const userData = useAppSelector((state: RootState) => state.auth.user_data);
const handleLogout = async () => {
try {
const fcmToken = await NotificationService.getFCMToken();
console.log('fcmToken', fcmToken)
await dispatch(
logout({
id: userData?.staffid ?? '',
fcm_token: fcmToken ?? '',
}),
).unwrap();
navigation.reset({
index: 0,
routes: [{ name: 'AuthStack' }],
});
} catch (e: any) {
const message =
typeof e === 'string'
? e
: e?.message || 'Logout failed. Please try again.';
Alert.alert('Logout Failed', message);
}
};
// Derive user info
const fullName =
userData?.full_name ||
`${userData?.firstname || ''} ${userData?.lastname || ''}`.trim() ||
'User Profile';
const email = userData?.email || 'N/A';
const phone = userData?.phonenumber || 'N/A';
const staffId = userData?.staffid ? `#${userData.staffid}` : 'N/A';
const isAdmin = userData?.admin === '1';
const roleText = isAdmin ? 'Administrator' : 'Staff Member';
const isActive = userData?.active === '1';
const [profileImageUrl, setProfileImageUrl] = useState('');
useEffect(() => {
const resolveImageUrl = async () => {
if (!userData?.profile_image) {
setProfileImageUrl('');
return;
}
const rawImage = userData.profile_image.replace(/"/g, '').trim();
if (!rawImage) {
setProfileImageUrl('');
return;
}
if (
rawImage.startsWith('http') ||
rawImage.startsWith('file://') ||
rawImage.startsWith('content://')
) {
setProfileImageUrl(rawImage);
return;
}
const storedBaseUrl = await AsyncStorage.getItem('base_url');
const baseUrl = storedBaseUrl || 'https://demo-convexcrm.convexsol.co';
const cleanBase = baseUrl.replace(/\/+$/, '');
const cleanPath = rawImage.replace(/^\/+/, '');
setProfileImageUrl(`${cleanBase}/${cleanPath}`);
};
resolveImageUrl();
}, [userData?.profile_image]);
const hasProfileImage = !!profileImageUrl;
// Derive initials
const initials = fullName
.split(' ')
.filter(Boolean)
.map(n => n[0])
.join('')
.substring(0, 2)
.toUpperCase() || 'U';
const hasSocials =
Boolean(userData?.linkedin) ||
Boolean(userData?.facebook) ||
Boolean(userData?.skype);
return (
<ScrollView style={styles.container} contentContainerStyle={styles.content}>
{/* ── Header Card ── */}
<View style={styles.headerCard}>
<View style={styles.avatarWrapper}>
{hasProfileImage ? (
<Image
source={{ uri: profileImageUrl }}
style={styles.avatarImage}
/>
) : (
<View style={styles.avatarCircle}>
<Text style={styles.avatarInitial}>{initials}</Text>
</View>
)}
{isActive && <View style={styles.onlineDot} />}
</View>
<Text style={styles.profileName}>{fullName}</Text>
<Text style={styles.profileEmail}>{email}</Text>
<View style={styles.roleBadge}>
<Text style={styles.roleBadgeText}>{roleText}</Text>
</View>
</View>
{/* ── Stats Summary Row ── */}
<View style={styles.statsRow}>
<View style={styles.statBox}>
<Text style={styles.statValue}>{userData?.staffid || '—'}</Text>
<Text style={styles.statLabel}>Staff ID</Text>
</View>
<View style={styles.statBox}>
<Text style={styles.statValue}>
{userData?.total_unfinished_todos ?? '0'}
</Text>
<Text style={styles.statLabel}>Pending Todos</Text>
</View>
<View style={styles.statBox}>
<Text style={styles.statValue}>
{userData?.total_unread_notifications ?? '0'}
</Text>
<Text style={styles.statLabel}>Unread Alerts</Text>
</View>
</View>
{/* ── Personal Details ── */}
<View style={styles.sectionCard}>
<Text style={styles.sectionHeader}>Personal Details</Text>
<ProfileInfoRow
icon="person-outline"
label="Name"
value={fullName}
/>
<ProfileInfoRow
icon="card-outline"
label="Staff ID"
value={staffId}
/>
<ProfileInfoRow
icon="mail-outline"
label="Email"
value={email}
/>
<ProfileInfoRow
icon="call-outline"
label="Phone"
value={phone}
/>
<ProfileInfoRow
icon="shield-checkmark-outline"
label="Role"
value={roleText}
isLast
/>
</View>
{/* ── System & Account ── */}
<View style={styles.sectionCard}>
<Text style={styles.sectionHeader}>System &amp; Account</Text>
<ProfileInfoRow
icon="checkmark-circle-outline"
label="Account Status"
value={isActive ? 'Active' : 'Inactive'}
valueColor={isActive ? '#10B981' : '#EF4444'}
isBadge
badgeBgColor={isActive ? '#10B98120' : '#EF444420'}
/>
<ProfileInfoRow
icon="key-outline"
label="Two-Factor Auth"
value={
userData?.two_factor_auth_enabled === '1'
? 'Enabled'
: 'Disabled'
}
/>
{userData?.default_language ? (
<ProfileInfoRow
icon="language-outline"
label="Default Language"
value={userData.default_language.toUpperCase()}
/>
) : null}
<ProfileInfoRow
icon="time-outline"
label="Last Login"
value={userData?.last_login || 'N/A'}
isLast
/>
</View>
{/* ── Social Profiles ── */}
{hasSocials && (
<View style={styles.sectionCard}>
<Text style={styles.sectionHeader}>Social Profiles</Text>
{userData?.linkedin ? (
<ProfileInfoRow
icon="logo-linkedin"
label="LinkedIn"
value={userData.linkedin}
/>
) : null}
{userData?.facebook ? (
<ProfileInfoRow
icon="logo-facebook"
label="Facebook"
value={userData.facebook}
/>
) : null}
{userData?.skype ? (
<ProfileInfoRow
icon="logo-skype"
label="Skype"
value={userData.skype}
isLast
/>
) : null}
</View>
)}
{/* ── Preferences ── */}
<View style={styles.sectionCard}>
<Text style={styles.sectionHeader}>Preferences</Text>
<View style={styles.preferenceRow}>
<View style={styles.preferenceLabelGroup}>
<View style={styles.iconWrapper}>
<Icon
name={isDark ? 'moon' : 'moon-outline'}
size={18}
color={colors.icon}
/>
</View>
<Text style={styles.preferenceText}>Dark Mode</Text>
</View>
<Switch
value={isDark}
onValueChange={toggleTheme}
trackColor={{ false: '#767577', true: colors.icon }}
thumbColor={isDark ? '#ffffff' : '#f4f3f4'}
/>
</View>
{/* <TouchableOpacity style={styles.preferenceRow} activeOpacity={0.7}>
<View style={styles.preferenceLabelGroup}>
<View style={styles.iconWrapper}>
<Icon
name="notifications-outline"
size={18}
color={colors.icon}
/>
</View>
<Text style={styles.preferenceText}>Push Notifications</Text>
</View>
<Icon name="chevron-forward" size={18} color={colors.textMuted} />
</TouchableOpacity> */}
<View style={[styles.preferenceRow, styles.noBorder]}>
<View style={styles.preferenceLabelGroup}>
<View style={styles.iconWrapper}>
<Icon name="notifications-outline" size={18} color={colors.icon} />
</View>
<Text style={styles.preferenceText}>Push Notifications</Text>
</View>
<Switch
value={pushEnabled}
onValueChange={setPushEnabled}
trackColor={{ false: '#767577', true: colors.icon }}
thumbColor={pushEnabled ? '#ffffff' : '#f4f3f4'}
/>
</View>
</View>
{/* ── Sign Out ── */}
<TouchableOpacity
style={styles.signOutButton}
activeOpacity={0.8}
onPress={handleLogout}>
<Icon
name="log-out-outline"
size={20}
color="#FFFFFF"
style={styles.buttonIcon}
/>
<Text style={styles.signOutButtonText}>Sign Out</Text>
</TouchableOpacity>
</ScrollView>
);
};