veza/veza-mobile/src/screens/DashboardScreen.tsx

336 lines
9.1 KiB
TypeScript
Raw Normal View History

import React, { useEffect } from 'react';
import {
View,
Text,
ScrollView,
StyleSheet,
RefreshControl,
TouchableOpacity,
} from 'react-native';
import { useSelector, useDispatch } from 'react-redux';
import { Ionicons } from '@expo/vector-icons';
import { RootState } from '../store/store';
import { fetchFeatures } from '../store/slices/featuresSlice';
import { fetchAnalytics } from '../store/slices/analyticsSlice';
const DashboardScreen: React.FC = () => {
const dispatch = useDispatch();
const { features, loading: featuresLoading } = useSelector((state: RootState) => state.features);
const { realtimeData, loading: analyticsLoading } = useSelector((state: RootState) => state.analytics);
const [refreshing, setRefreshing] = React.useState(false);
useEffect(() => {
loadData();
}, []);
const loadData = () => {
dispatch(fetchFeatures());
dispatch(fetchAnalytics());
};
const onRefresh = async () => {
setRefreshing(true);
await Promise.all([
dispatch(fetchFeatures()),
dispatch(fetchAnalytics()),
]);
setRefreshing(false);
};
const getStatusColor = (status: string) => {
switch (status) {
case 'running':
return '#10B981';
case 'error':
return '#EF4444';
case 'stopped':
return '#6B7280';
default:
return '#F59E0B';
}
};
const getStatusIcon = (status: string) => {
switch (status) {
case 'running':
return 'checkmark-circle';
case 'error':
return 'close-circle';
case 'stopped':
return 'stop-circle';
default:
return 'help-circle';
}
};
return (
<ScrollView
style={styles.container}
refreshControl={
<RefreshControl refreshing={refreshing} onRefresh={onRefresh} />
}
>
{/* Header */}
<View style={styles.header}>
<Text style={styles.title}>Tableau de bord</Text>
<Text style={styles.subtitle}>Vue d'ensemble de la plateforme Veza</Text>
</View>
{/* Quick Stats */}
<View style={styles.statsContainer}>
<View style={styles.statCard}>
<Ionicons name="apps" size={24} color="#3B82F6" />
<Text style={styles.statNumber}>{features.length}</Text>
<Text style={styles.statLabel}>Features Actives</Text>
</View>
<View style={styles.statCard}>
<Ionicons name="analytics" size={24} color="#10B981" />
<Text style={styles.statNumber}>{realtimeData.length}</Text>
<Text style={styles.statLabel}>Métriques Temps Réel</Text>
</View>
<View style={styles.statCard}>
<Ionicons name="musical-notes" size={24} color="#F59E0B" />
<Text style={styles.statNumber}>12</Text>
<Text style={styles.statLabel}>Médias</Text>
</View>
<View style={styles.statCard}>
<Ionicons name="chatbubbles" size={24} color="#8B5CF6" />
<Text style={styles.statNumber}>5</Text>
<Text style={styles.statLabel}>Chats Actifs</Text>
</View>
</View>
{/* Feature Status */}
<View style={styles.section}>
<Text style={styles.sectionTitle}>Statut des Features</Text>
{features.slice(0, 5).map((feature) => (
<TouchableOpacity key={feature.id} style={styles.featureCard}>
<View style={styles.featureHeader}>
<View style={styles.featureInfo}>
<Text style={styles.featureName}>{feature.name}</Text>
<Text style={styles.featureDomain}>{feature.domain}</Text>
</View>
<View style={styles.statusContainer}>
<Ionicons
name={getStatusIcon(feature.status) as any}
size={20}
color={getStatusColor(feature.status)}
/>
<Text style={[styles.statusText, { color: getStatusColor(feature.status) }]}>
{feature.status}
</Text>
</View>
</View>
<View style={styles.metricsRow}>
<View style={styles.metric}>
<Text style={styles.metricLabel}>CPU</Text>
<Text style={styles.metricValue}>{feature.metrics.cpu}%</Text>
</View>
<View style={styles.metric}>
<Text style={styles.metricLabel}>RAM</Text>
<Text style={styles.metricValue}>{(feature.metrics.memory / 1024 / 1024).toFixed(0)}MB</Text>
</View>
<View style={styles.metric}>
<Text style={styles.metricLabel}>DISK</Text>
<Text style={styles.metricValue}>{(feature.metrics.disk / 1024 / 1024).toFixed(0)}MB</Text>
</View>
</View>
</TouchableOpacity>
))}
</View>
{/* Recent Activity */}
<View style={styles.section}>
<Text style={styles.sectionTitle}>Activité Récente</Text>
<View style={styles.activityCard}>
<View style={styles.activityItem}>
<Ionicons name="checkmark-circle" size={16} color="#10B981" />
<Text style={styles.activityText}>Feature "Smart Recommendations" démarrée</Text>
<Text style={styles.activityTime}>Il y a 2 min</Text>
</View>
<View style={styles.activityItem}>
<Ionicons name="musical-notes" size={16} color="#3B82F6" />
<Text style={styles.activityText}>Nouveau média uploadé</Text>
<Text style={styles.activityTime}>Il y a 5 min</Text>
</View>
<View style={styles.activityItem}>
<Ionicons name="analytics" size={16} color="#F59E0B" />
<Text style={styles.activityText}>Rapport analytics généré</Text>
<Text style={styles.activityTime}>Il y a 10 min</Text>
</View>
</View>
</View>
{/* Quick Actions */}
<View style={styles.section}>
<Text style={styles.sectionTitle}>Actions Rapides</Text>
<View style={styles.actionsContainer}>
<TouchableOpacity style={styles.actionButton}>
<Ionicons name="add" size={24} color="#FFFFFF" />
<Text style={styles.actionText}>Nouveau Feature</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.actionButton}>
<Ionicons name="refresh" size={24} color="#FFFFFF" />
<Text style={styles.actionText}>Actualiser</Text>
</TouchableOpacity>
</View>
</View>
</ScrollView>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#111827',
},
header: {
padding: 20,
paddingTop: 40,
},
title: {
fontSize: 28,
fontWeight: 'bold',
color: '#FFFFFF',
marginBottom: 8,
},
subtitle: {
fontSize: 16,
color: '#9CA3AF',
},
statsContainer: {
flexDirection: 'row',
flexWrap: 'wrap',
paddingHorizontal: 20,
marginBottom: 20,
},
statCard: {
backgroundColor: '#1F2937',
borderRadius: 12,
padding: 16,
marginBottom: 12,
width: '48%',
marginRight: '2%',
alignItems: 'center',
},
statNumber: {
fontSize: 24,
fontWeight: 'bold',
color: '#FFFFFF',
marginTop: 8,
},
statLabel: {
fontSize: 12,
color: '#9CA3AF',
marginTop: 4,
textAlign: 'center',
},
section: {
paddingHorizontal: 20,
marginBottom: 20,
},
sectionTitle: {
fontSize: 18,
fontWeight: 'bold',
color: '#FFFFFF',
marginBottom: 12,
},
featureCard: {
backgroundColor: '#1F2937',
borderRadius: 12,
padding: 16,
marginBottom: 12,
},
featureHeader: {
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
marginBottom: 12,
},
featureInfo: {
flex: 1,
},
featureName: {
fontSize: 16,
fontWeight: '600',
color: '#FFFFFF',
},
featureDomain: {
fontSize: 12,
color: '#9CA3AF',
marginTop: 2,
},
statusContainer: {
flexDirection: 'row',
alignItems: 'center',
},
statusText: {
fontSize: 12,
fontWeight: '500',
marginLeft: 4,
},
metricsRow: {
flexDirection: 'row',
justifyContent: 'space-between',
},
metric: {
alignItems: 'center',
},
metricLabel: {
fontSize: 10,
color: '#9CA3AF',
},
metricValue: {
fontSize: 12,
fontWeight: '600',
color: '#FFFFFF',
marginTop: 2,
},
activityCard: {
backgroundColor: '#1F2937',
borderRadius: 12,
padding: 16,
},
activityItem: {
flexDirection: 'row',
alignItems: 'center',
marginBottom: 12,
},
activityText: {
flex: 1,
fontSize: 14,
color: '#FFFFFF',
marginLeft: 8,
},
activityTime: {
fontSize: 12,
color: '#9CA3AF',
},
actionsContainer: {
flexDirection: 'row',
justifyContent: 'space-between',
},
actionButton: {
backgroundColor: '#3B82F6',
borderRadius: 12,
padding: 16,
flexDirection: 'row',
alignItems: 'center',
flex: 1,
marginRight: 8,
},
actionText: {
color: '#FFFFFF',
fontWeight: '600',
marginLeft: 8,
},
});
export default DashboardScreen;