feat(smart-app): implement complete mobile app MVP

- App.tsx: full navigation (Auth stack + Main tabs with 5 screens)
- Auth: LoginScreen, RegisterScreen, ForgotPasswordScreen
- HomeScreen: dashboard with IoT metrics, weather widget, alerts, quick actions, sensors
- MapScreen: interactive map with layer toggles (6 layers)
- MarketplaceScreen: categories (6), products (5), search
- ChatScreen: AI chat with quick prompts (4), bot responses
- ProfileScreen: user info, stats, menu (9 items), logout
- AlertsScreen: alert list with severity, acknowledge
- SensorsScreen: sensor list with type filters (6 types), search
- ZonesScreen: zone cards with stats
- SettingsScreen: language picker (FR/EN/ES/DE), privacy, about
- Stores: iotStore (sensors, zones, alerts), notificationStore, uiStore + i18n
- Hooks: useSensors, useAlerts, useNotifications, useLocation
- Components: Card, Button, LoadingSpinner, ErrorBoundary, Header
- Services: iotService, notificationService (with axios API client)
- Utils: formatters (temp, AQI, noise, dates), validators (email, password, IBAN)
- Theme: colors.ts with full design system (Blue Ocean palette)
- Ditto: fixed MongoDB connection, new JWT secrets, official gateway image
This commit is contained in:
Eric FELIXINE
2026-06-01 18:00:35 -04:00
parent 08ca495bde
commit e30ae8ed09
35578 changed files with 3703534 additions and 43 deletions

View File

@@ -0,0 +1,84 @@
// Smart App City — Zones Screen
import React from 'react';
import { View, Text, ScrollView, TouchableOpacity, StyleSheet } from 'react-native';
import { NativeStackNavigationProp } from '@react-navigation/native-stack';
import { Colors, Typography, Spacing, BorderRadius, Shadows } from '../../../../src/theme/colors';
import { useIoTStore } from '../../../stores/iotStore';
type Props = { navigation: NativeStackNavigationProp<any> };
export default function ZonesScreen({ navigation }: Props) {
const zones = useIoTStore((s) => s.zones);
const sensors = useIoTStore((s) => s.sensors);
return (
<View style={styles.container}>
<View style={styles.header}>
<TouchableOpacity onPress={() => navigation.goBack()}>
<Text style={styles.backText}> Retour</Text>
</TouchableOpacity>
<Text style={styles.title}>Zones</Text>
<Text style={styles.count}>{zones.length}</Text>
</View>
<ScrollView style={styles.list} showsVerticalScrollIndicator={false}>
{zones.map((zone) => {
const zoneSensors = sensors.filter((s) => s.zoneId === zone.id);
return (
<TouchableOpacity key={zone.id} style={styles.zoneCard}>
<View style={[styles.zoneColorBar, { backgroundColor: zone.color }]} />
<View style={styles.zoneContent}>
<Text style={styles.zoneName}>{zone.name}</Text>
<Text style={styles.zoneDesc}>{zone.description}</Text>
<View style={styles.zoneStats}>
<View style={styles.zoneStat}>
<Text style={styles.zoneStatValue}>{zoneSensors.length}</Text>
<Text style={styles.zoneStatLabel}>Capteurs</Text>
</View>
<View style={styles.zoneStat}>
<Text style={[styles.zoneStatValue, { color: zone.alertCount > 0 ? Colors.danger : Colors.success }]}>
{zone.alertCount}
</Text>
<Text style={styles.zoneStatLabel}>Alertes</Text>
</View>
<View style={styles.zoneStat}>
<Text style={styles.zoneStatValue}>{(zone.radius / 1000).toFixed(1)}km</Text>
<Text style={styles.zoneStatLabel}>Rayon</Text>
</View>
</View>
</View>
</TouchableOpacity>
);
})}
<View style={{ height: 40 }} />
</ScrollView>
</View>
);
}
const styles = StyleSheet.create({
container: { flex: 1, backgroundColor: Colors.neutral50 },
header: {
flexDirection: 'row', alignItems: 'center',
backgroundColor: Colors.primary[500],
paddingTop: 50, paddingBottom: Spacing.base,
paddingHorizontal: Spacing.base, gap: Spacing.base,
},
backText: { color: Colors.white, fontSize: Typography.sizes.base },
title: { flex: 1, fontSize: Typography.sizes.lg, fontWeight: Typography.weights.bold, color: Colors.white },
count: { color: 'rgba(255,255,255,0.8)', fontSize: Typography.sizes.base },
list: { flex: 1, padding: Spacing.base },
zoneCard: {
flexDirection: 'row', backgroundColor: Colors.white,
borderRadius: BorderRadius.lg, marginBottom: Spacing.sm,
...Shadows.sm, overflow: 'hidden',
},
zoneColorBar: { width: 4 },
zoneContent: { flex: 1, padding: Spacing.base },
zoneName: { fontSize: Typography.sizes.md, fontWeight: Typography.weights.bold, color: Colors.neutral900 },
zoneDesc: { fontSize: Typography.sizes.sm, color: Colors.neutral500, marginTop: 2, marginBottom: Spacing.sm },
zoneStats: { flexDirection: 'row', gap: Spacing.base },
zoneStat: { alignItems: 'center' },
zoneStatValue: { fontSize: Typography.sizes.lg, fontWeight: Typography.weights.bold, color: Colors.primary[500] },
zoneStatLabel: { fontSize: Typography.sizes.xs, color: Colors.neutral400, marginTop: 2 },
});