erp-core/mobile/app/(tabs)/index.tsx
rckrdmrd 0086695b4c
Some checks failed
ERP Core CI / Backend Lint (push) Has been cancelled
ERP Core CI / Backend Unit Tests (push) Has been cancelled
ERP Core CI / Backend Integration Tests (push) Has been cancelled
ERP Core CI / Frontend Lint (push) Has been cancelled
ERP Core CI / Frontend Unit Tests (push) Has been cancelled
ERP Core CI / Frontend E2E Tests (push) Has been cancelled
ERP Core CI / Database DDL Validation (push) Has been cancelled
ERP Core CI / Backend Build (push) Has been cancelled
ERP Core CI / Frontend Build (push) Has been cancelled
ERP Core CI / CI Success (push) Has been cancelled
Performance Tests / Lighthouse CI (push) Has been cancelled
Performance Tests / Bundle Size Analysis (push) Has been cancelled
Performance Tests / k6 Load Tests (push) Has been cancelled
Performance Tests / Performance Summary (push) Has been cancelled
[SIMCO-V38] feat: Actualizar a SIMCO v3.8.0 + cambios backend
- HERENCIA-SIMCO.md actualizado con directivas v3.7 y v3.8
- Actualizaciones en modulos CRM y OpenAPI

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-10 08:53:05 -06:00

277 lines
7.1 KiB
TypeScript

/**
* Home Screen
*
* Dashboard with quick stats and shortcuts
*/
import { View, Text, StyleSheet, ScrollView, TouchableOpacity, RefreshControl } from 'react-native';
import { useState, useCallback } from 'react';
import { router } from 'expo-router';
import { Ionicons } from '@expo/vector-icons';
import { useAuthStore } from '@/stores';
interface StatCardProps {
title: string;
value: string;
icon: keyof typeof Ionicons.glyphMap;
color: string;
onPress?: () => void;
}
function StatCard({ title, value, icon, color, onPress }: StatCardProps) {
return (
<TouchableOpacity style={styles.statCard} onPress={onPress} activeOpacity={0.7}>
<View style={[styles.statIconContainer, { backgroundColor: color + '20' }]}>
<Ionicons name={icon} size={24} color={color} />
</View>
<Text style={styles.statValue}>{value}</Text>
<Text style={styles.statTitle}>{title}</Text>
</TouchableOpacity>
);
}
interface QuickActionProps {
title: string;
icon: keyof typeof Ionicons.glyphMap;
onPress: () => void;
}
function QuickAction({ title, icon, onPress }: QuickActionProps) {
return (
<TouchableOpacity style={styles.quickAction} onPress={onPress}>
<Ionicons name={icon} size={20} color="#1e40af" />
<Text style={styles.quickActionText}>{title}</Text>
<Ionicons name="chevron-forward" size={16} color="#9ca3af" />
</TouchableOpacity>
);
}
export default function HomeScreen() {
const [refreshing, setRefreshing] = useState(false);
const user = useAuthStore((state) => state.user);
const onRefresh = useCallback(async () => {
setRefreshing(true);
// TODO: Fetch dashboard data
await new Promise((resolve) => setTimeout(resolve, 1000));
setRefreshing(false);
}, []);
return (
<ScrollView
style={styles.container}
contentContainerStyle={styles.content}
refreshControl={
<RefreshControl refreshing={refreshing} onRefresh={onRefresh} tintColor="#1e40af" />
}
>
{/* Welcome */}
<View style={styles.welcome}>
<Text style={styles.welcomeText}>¡Hola, {user?.fullName?.split(' ')[0] || 'Usuario'}!</Text>
<Text style={styles.welcomeSubtext}>Aquí está el resumen de tu negocio</Text>
</View>
{/* Stats Grid */}
<View style={styles.statsGrid}>
<StatCard
title="Clientes"
value="128"
icon="people"
color="#1e40af"
onPress={() => router.push('/(tabs)/partners')}
/>
<StatCard
title="Productos"
value="456"
icon="cube"
color="#059669"
onPress={() => router.push('/(tabs)/products')}
/>
<StatCard
title="Facturas"
value="32"
icon="document-text"
color="#d97706"
onPress={() => router.push('/(tabs)/invoices')}
/>
<StatCard
title="Pendientes"
value="$45,230"
icon="cash"
color="#dc2626"
/>
</View>
{/* Quick Actions */}
<View style={styles.section}>
<Text style={styles.sectionTitle}>Acciones Rápidas</Text>
<View style={styles.quickActions}>
<QuickAction
title="Nuevo Cliente"
icon="person-add-outline"
onPress={() => router.push('/(tabs)/partners')}
/>
<QuickAction
title="Nueva Factura"
icon="add-circle-outline"
onPress={() => router.push('/(tabs)/invoices')}
/>
<QuickAction
title="Ver Inventario"
icon="layers-outline"
onPress={() => router.push('/(tabs)/products')}
/>
<QuickAction
title="Reportes"
icon="bar-chart-outline"
onPress={() => {}}
/>
</View>
</View>
{/* Recent Activity */}
<View style={styles.section}>
<Text style={styles.sectionTitle}>Actividad Reciente</Text>
<View style={styles.activityList}>
<View style={styles.activityItem}>
<View style={[styles.activityDot, { backgroundColor: '#059669' }]} />
<View style={styles.activityContent}>
<Text style={styles.activityText}>Factura #INV-2024-001 pagada</Text>
<Text style={styles.activityTime}>Hace 2 horas</Text>
</View>
</View>
<View style={styles.activityItem}>
<View style={[styles.activityDot, { backgroundColor: '#1e40af' }]} />
<View style={styles.activityContent}>
<Text style={styles.activityText}>Nuevo cliente: Empresa ABC</Text>
<Text style={styles.activityTime}>Hace 5 horas</Text>
</View>
</View>
<View style={styles.activityItem}>
<View style={[styles.activityDot, { backgroundColor: '#d97706' }]} />
<View style={styles.activityContent}>
<Text style={styles.activityText}>Factura #INV-2024-002 creada</Text>
<Text style={styles.activityTime}>Ayer</Text>
</View>
</View>
</View>
</View>
</ScrollView>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#f8fafc',
},
content: {
padding: 16,
paddingBottom: 32,
},
welcome: {
marginBottom: 24,
},
welcomeText: {
fontSize: 24,
fontWeight: '700',
color: '#1f2937',
},
welcomeSubtext: {
fontSize: 16,
color: '#64748b',
marginTop: 4,
},
statsGrid: {
flexDirection: 'row',
flexWrap: 'wrap',
gap: 12,
marginBottom: 24,
},
statCard: {
backgroundColor: '#ffffff',
borderRadius: 12,
padding: 16,
width: '48%',
shadowColor: '#000',
shadowOffset: { width: 0, height: 1 },
shadowOpacity: 0.05,
shadowRadius: 2,
elevation: 1,
},
statIconContainer: {
width: 44,
height: 44,
borderRadius: 10,
justifyContent: 'center',
alignItems: 'center',
marginBottom: 12,
},
statValue: {
fontSize: 24,
fontWeight: '700',
color: '#1f2937',
},
statTitle: {
fontSize: 14,
color: '#64748b',
marginTop: 4,
},
section: {
marginBottom: 24,
},
sectionTitle: {
fontSize: 18,
fontWeight: '600',
color: '#1f2937',
marginBottom: 12,
},
quickActions: {
backgroundColor: '#ffffff',
borderRadius: 12,
overflow: 'hidden',
},
quickAction: {
flexDirection: 'row',
alignItems: 'center',
padding: 16,
borderBottomWidth: 1,
borderBottomColor: '#f1f5f9',
},
quickActionText: {
flex: 1,
fontSize: 16,
color: '#1f2937',
marginLeft: 12,
},
activityList: {
backgroundColor: '#ffffff',
borderRadius: 12,
padding: 16,
},
activityItem: {
flexDirection: 'row',
alignItems: 'flex-start',
marginBottom: 16,
},
activityDot: {
width: 8,
height: 8,
borderRadius: 4,
marginTop: 6,
marginRight: 12,
},
activityContent: {
flex: 1,
},
activityText: {
fontSize: 14,
color: '#1f2937',
},
activityTime: {
fontSize: 12,
color: '#9ca3af',
marginTop: 2,
},
});