feat: major UI/UX overhaul + user management + ticket detail refactor
- 5-tab navigation (Home/Clients/Collect/Tickets/Profile) - Inline styles throughout (17px min font, SafeAreaView) - Dashboard fixed to match real API shape - Ticket detail: 2 tabs (Details + Comments), always-visible comment input - Installation confirmation: GPS coordinate capture + client location update - User management screens (Admin only): list, create, detail + role/active toggle - Tasks folder replaces tickets folder - Remittance detail: inline styles - Record payment: prefill from client, live button text - Icon component with SVG icons - Color system: primary #0891B2
This commit is contained in:
@@ -1,57 +1,81 @@
|
||||
import { View, Text, TouchableOpacity, Alert, ScrollView } from 'react-native';
|
||||
import { SafeAreaView } from 'react-native-safe-area-context';
|
||||
import { useAuthStore } from '../../stores/authStore';
|
||||
import { router } from 'expo-router';
|
||||
|
||||
export default function ProfileScreen() {
|
||||
const { user, logout, tenantSlug } = useAuthStore();
|
||||
const initials = `${user?.firstName?.[0] ?? ''}${user?.lastName?.[0] ?? ''}`.toUpperCase() || 'U';
|
||||
const fullName = `${user?.firstName ?? ''} ${user?.lastName ?? ''}`.trim();
|
||||
const role = user?.roles?.[0] ?? user?.role ?? 'Staff';
|
||||
|
||||
const handleLogout = () => {
|
||||
Alert.alert('Sign Out', 'Are you sure you want to sign out?', [
|
||||
{ text: 'Cancel', style: 'cancel' },
|
||||
{
|
||||
text: 'Sign Out', style: 'destructive',
|
||||
onPress: async () => {
|
||||
await logout();
|
||||
router.replace('/(auth)/company-code');
|
||||
}
|
||||
}
|
||||
{ text: 'Sign Out', style: 'destructive', onPress: async () => { await logout(); router.replace('/(auth)/company-code'); } },
|
||||
]);
|
||||
};
|
||||
|
||||
return (
|
||||
<ScrollView className="flex-1 bg-gray-50">
|
||||
<View className="px-4 pt-14 pb-6 bg-primary">
|
||||
<View className="w-16 h-16 rounded-full bg-white/20 items-center justify-center mb-3">
|
||||
<Text className="text-white text-2xl font-bold">
|
||||
{user?.firstName?.[0]?.toUpperCase() ?? 'U'}
|
||||
</Text>
|
||||
</View>
|
||||
<Text className="text-white text-xl font-bold">{user?.firstName} {user?.lastName}</Text>
|
||||
<Text className="text-white/70 text-sm">{user?.role} · {tenantSlug}</Text>
|
||||
</View>
|
||||
|
||||
<View className="px-4 py-6">
|
||||
<View className="bg-white rounded-2xl border border-gray-100 mb-4">
|
||||
{[
|
||||
{ label: 'Username', value: user?.username },
|
||||
{ label: 'Email', value: user?.email },
|
||||
{ label: 'Role', value: user?.role },
|
||||
{ label: 'Company', value: tenantSlug },
|
||||
].map((item, i) => (
|
||||
<View key={item.label} className={`px-4 py-3 ${i > 0 ? 'border-t border-gray-100' : ''}`}>
|
||||
<Text className="text-gray-500 text-xs mb-0.5">{item.label}</Text>
|
||||
<Text className="text-gray-900 font-medium">{item.value ?? '—'}</Text>
|
||||
</View>
|
||||
))}
|
||||
<SafeAreaView style={{ flex: 1, backgroundColor: '#0891B2' }} edges={['top']}>
|
||||
<ScrollView style={{ flex: 1, backgroundColor: '#F8FAFC' }}>
|
||||
{/* Header */}
|
||||
<View style={{ backgroundColor: '#0891B2', paddingHorizontal: 20, paddingTop: 16, paddingBottom: 32, alignItems: 'center' }}>
|
||||
<View style={{ width: 80, height: 80, borderRadius: 40, backgroundColor: 'rgba(255,255,255,0.2)', alignItems: 'center', justifyContent: 'center', marginBottom: 12 }}>
|
||||
<Text style={{ color: '#FFF', fontSize: 32, fontWeight: '800' }}>{initials}</Text>
|
||||
</View>
|
||||
<Text style={{ color: '#FFF', fontSize: 24, fontWeight: '800' }}>{fullName}</Text>
|
||||
<View style={{ backgroundColor: 'rgba(255,255,255,0.2)', borderRadius: 20, paddingHorizontal: 14, paddingVertical: 5, marginTop: 8 }}>
|
||||
<Text style={{ color: '#E0F2FE', fontSize: 14, fontWeight: '600' }}>{role}</Text>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
<TouchableOpacity
|
||||
className="bg-red-50 border border-red-200 rounded-2xl py-4 items-center"
|
||||
onPress={handleLogout}
|
||||
>
|
||||
<Text className="text-red-600 font-semibold">Sign Out</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
</ScrollView>
|
||||
<View style={{ padding: 16 }}>
|
||||
{/* Info */}
|
||||
<View style={{ backgroundColor: '#FFF', borderRadius: 20, marginBottom: 16, borderWidth: 1, borderColor: '#F1F5F9', overflow: 'hidden' }}>
|
||||
{[
|
||||
{ label: 'Email', value: user?.email },
|
||||
{ label: 'Company', value: tenantSlug },
|
||||
{ label: 'Role', value: role },
|
||||
].map((row, i, arr) => (
|
||||
<View key={row.label} style={{ paddingHorizontal: 20, paddingVertical: 16, borderBottomWidth: i < arr.length - 1 ? 1 : 0, borderBottomColor: '#F1F5F9' }}>
|
||||
<Text style={{ fontSize: 12, fontWeight: '600', color: '#94A3B8', textTransform: 'uppercase', letterSpacing: 0.5, marginBottom: 4 }}>{row.label}</Text>
|
||||
<Text style={{ fontSize: 17, fontWeight: '600', color: '#0F172A' }}>{row.value ?? '—'}</Text>
|
||||
</View>
|
||||
))}
|
||||
</View>
|
||||
|
||||
{/* User Management — admin only */}
|
||||
{(user?.roles?.includes('ADMIN') || user?.role === 'ADMIN' || role === 'ADMIN') && (
|
||||
<TouchableOpacity
|
||||
style={{ backgroundColor: '#FFF', borderRadius: 20, borderWidth: 1, borderColor: '#F1F5F9', paddingHorizontal: 20, paddingVertical: 18, marginBottom: 16, flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center' }}
|
||||
onPress={() => router.push('/(app)/users')}
|
||||
activeOpacity={0.7}
|
||||
>
|
||||
<View>
|
||||
<Text style={{ fontSize: 17, fontWeight: '700', color: '#0F172A' }}>User Management</Text>
|
||||
<Text style={{ fontSize: 14, color: '#64748B', marginTop: 2 }}>Add & manage team members</Text>
|
||||
</View>
|
||||
<Text style={{ fontSize: 20, color: '#94A3B8' }}>›</Text>
|
||||
</TouchableOpacity>
|
||||
)}
|
||||
|
||||
{/* App version */}
|
||||
<View style={{ backgroundColor: '#FFF', borderRadius: 20, marginBottom: 16, borderWidth: 1, borderColor: '#F1F5F9', paddingHorizontal: 20, paddingVertical: 16 }}>
|
||||
<Text style={{ fontSize: 12, fontWeight: '600', color: '#94A3B8', textTransform: 'uppercase', letterSpacing: 0.5, marginBottom: 4 }}>App</Text>
|
||||
<Text style={{ fontSize: 17, fontWeight: '600', color: '#0F172A' }}>FiberOps Mobile v1.0.0</Text>
|
||||
</View>
|
||||
|
||||
{/* Sign out */}
|
||||
<TouchableOpacity
|
||||
style={{ backgroundColor: '#FFF', borderRadius: 20, paddingVertical: 18, alignItems: 'center', borderWidth: 1.5, borderColor: '#FECACA' }}
|
||||
onPress={handleLogout}
|
||||
activeOpacity={0.7}
|
||||
>
|
||||
<Text style={{ color: '#DC2626', fontSize: 17, fontWeight: '700' }}>Sign Out</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
</ScrollView>
|
||||
</SafeAreaView>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user