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
- 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>
277 lines
7.1 KiB
TypeScript
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,
|
|
},
|
|
});
|