- 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
313 lines
12 KiB
HTML
313 lines
12 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="fr">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>Smart App City — 08 Signalements Citoyens</title>
|
|
<link rel="stylesheet" href="shared.css">
|
|
<style>
|
|
.report-header {
|
|
padding: 16px;
|
|
background: white;
|
|
border-bottom: 1px solid var(--neutral-200);
|
|
}
|
|
.report-title {
|
|
font-size: var(--text-lg);
|
|
font-weight: var(--weight-bold);
|
|
margin-bottom: 4px;
|
|
}
|
|
.report-sub {
|
|
font-size: var(--text-sm);
|
|
color: var(--neutral-500);
|
|
}
|
|
|
|
.report-types {
|
|
display: grid; grid-template-columns: 1fr 1fr;
|
|
gap: 10px; padding: 16px;
|
|
}
|
|
.report-type-card {
|
|
background: white;
|
|
border-radius: var(--radius-lg);
|
|
padding: 16px;
|
|
text-align: center;
|
|
box-shadow: var(--shadow-sm);
|
|
border: 1px solid var(--neutral-100);
|
|
cursor: pointer;
|
|
transition: all 0.2s;
|
|
}
|
|
.report-type-card:hover {
|
|
transform: translateY(-2px);
|
|
box-shadow: var(--shadow-md);
|
|
border-color: var(--primary-200);
|
|
}
|
|
.report-type-icon {
|
|
width: 48px; height: 48px;
|
|
border-radius: var(--radius-full);
|
|
display: flex; align-items: center; justify-content: center;
|
|
font-size: 24px;
|
|
margin: 0 auto 10px;
|
|
}
|
|
.report-type-name {
|
|
font-size: var(--text-sm);
|
|
font-weight: var(--weight-semibold);
|
|
margin-bottom: 2px;
|
|
}
|
|
.report-type-count {
|
|
font-size: var(--text-xs);
|
|
color: var(--neutral-400);
|
|
}
|
|
|
|
.section-header-row {
|
|
display: flex; justify-content: space-between;
|
|
align-items: center; padding: 0 16px 10px;
|
|
}
|
|
.section-header-title {
|
|
font-size: var(--text-md);
|
|
font-weight: var(--weight-bold);
|
|
}
|
|
|
|
.report-item {
|
|
display: flex; gap: 12px;
|
|
padding: 14px 16px;
|
|
background: white;
|
|
border-bottom: 1px solid var(--neutral-100);
|
|
}
|
|
.report-status-icon {
|
|
width: 36px; height: 36px;
|
|
border-radius: var(--radius-full);
|
|
display: flex; align-items: center; justify-content: center;
|
|
font-size: 16px;
|
|
flex-shrink: 0;
|
|
}
|
|
.report-content { flex: 1; }
|
|
.report-item-title {
|
|
font-size: var(--text-sm);
|
|
font-weight: var(--weight-semibold);
|
|
margin-bottom: 2px;
|
|
}
|
|
.report-item-desc {
|
|
font-size: var(--text-xs);
|
|
color: var(--neutral-500);
|
|
margin-bottom: 6px;
|
|
}
|
|
.report-item-meta {
|
|
display: flex; gap: 12px; align-items: center;
|
|
}
|
|
.status-badge {
|
|
display: inline-flex; align-items: center; gap: 4px;
|
|
padding: 3px 10px;
|
|
border-radius: var(--radius-full);
|
|
font-size: 10px;
|
|
font-weight: var(--weight-semibold);
|
|
}
|
|
.status-pending { background: rgba(245,124,0,0.1); color: var(--alert-warning); }
|
|
.status-progress { background: rgba(2,136,209,0.1); color: var(--alert-info); }
|
|
.status-done { background: rgba(46,125,50,0.1); color: var(--alert-success); }
|
|
.report-date { font-size: 10px; color: var(--neutral-400); }
|
|
|
|
.fab-btn {
|
|
position: absolute;
|
|
bottom: 100px; right: 16px;
|
|
width: 56px; height: 56px;
|
|
border-radius: var(--radius-full);
|
|
background: linear-gradient(135deg, var(--primary-500), var(--primary-600));
|
|
box-shadow: 0 4px 16px rgba(46,125,50,0.4);
|
|
display: flex; align-items: center; justify-content: center;
|
|
font-size: 28px;
|
|
color: white;
|
|
cursor: pointer;
|
|
z-index: 30;
|
|
}
|
|
|
|
.empty-state {
|
|
text-align: center;
|
|
padding: 40px 20px;
|
|
color: var(--neutral-400);
|
|
}
|
|
.empty-state-icon { font-size: 48px; margin-bottom: 12px; }
|
|
.empty-state-text { font-size: var(--text-sm); }
|
|
/* Fixed viewport for PDF/iframe embedding */
|
|
html, body { width: 390px !important; height: 844px !important; overflow: hidden !important; margin: 0 !important; padding: 0 !important; }
|
|
</style>
|
|
<style>
|
|
/* Fixed viewport for PDF/iframe embedding */
|
|
html, body { width: 390px !important; height: 844px !important; overflow: hidden !important; margin: 0 !important; padding: 0 !important; }
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div class="mobile-frame">
|
|
<!-- Status Bar -->
|
|
<div class="status-bar">
|
|
<span>9:41</span>
|
|
<div style="display:flex;gap:4px;align-items:center;">
|
|
<svg width="16" height="12" viewBox="0 0 16 12"><rect x="0" y="4" width="3" height="8" rx="1" fill="#333"/><rect x="4.5" y="2.5" width="3" height="9.5" rx="1" fill="#333"/><rect x="9" y="0" width="3" height="12" rx="1" fill="#333"/><rect x="13.5" y="0" width="2.5" height="12" rx="1" fill="#ccc"/></svg>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Header -->
|
|
<div class="report-header">
|
|
<div style="display:flex;justify-content:space-between;align-items:center;">
|
|
<div>
|
|
<div class="report-title">Signalements 📸</div>
|
|
<div class="report-sub">ODK Central · 12 signalements actifs</div>
|
|
</div>
|
|
<div style="font-size:var(--text-sm);color:var(--primary-500);font-weight:600;">+ Nouveau</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Content -->
|
|
<div class="content-area" style="top:80px;background:var(--neutral-50);">
|
|
|
|
<!-- Report types -->
|
|
<div style="padding:16px 16px 8px;font-size:var(--text-md);font-weight:700;">Catégories</div>
|
|
<div class="report-types">
|
|
<div class="report-type-card">
|
|
<div class="report-type-icon" style="background:rgba(211,47,47,0.1);">🕳️</div>
|
|
<div class="report-type-name">Voirie</div>
|
|
<div class="report-type-count">3 signalements</div>
|
|
</div>
|
|
<div class="report-type-card">
|
|
<div class="report-type-icon" style="background:rgba(245,124,0,0.1);">💡</div>
|
|
<div class="report-type-name">Éclairage</div>
|
|
<div class="report-type-count">2 signalements</div>
|
|
</div>
|
|
<div class="report-type-card">
|
|
<div class="report-type-icon" style="background:rgba(2,136,209,0.1);">🌊</div>
|
|
<div class="report-type-name">Inondation</div>
|
|
<div class="report-type-count">1 signalement</div>
|
|
</div>
|
|
<div class="report-type-card">
|
|
<div class="report-type-icon" style="background:rgba(46,125,50,0.1);">🌳</div>
|
|
<div class="report-type-name">Espaces verts</div>
|
|
<div class="report-type-count">4 signalements</div>
|
|
</div>
|
|
<div class="report-type-card">
|
|
<div class="report-type-icon" style="background:rgba(124,77,255,0.1);">🗑️</div>
|
|
<div class="report-type-name">Propreté</div>
|
|
<div class="report-type-count">2 signalements</div>
|
|
</div>
|
|
<div class="report-type-card">
|
|
<div class="report-type-icon" style="background:rgba(0,172,193,0.1);">⚠️</div>
|
|
<div class="report-type-name">Autre</div>
|
|
<div class="report-type-count">+ Ajouter</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- My reports -->
|
|
<div class="section-header-row">
|
|
<div class="section-header-title">Mes signalements récents</div>
|
|
<div style="font-size:var(--text-sm);color:var(--primary-500);font-weight:500;">Voir tout →</div>
|
|
</div>
|
|
|
|
<div class="report-item">
|
|
<div class="report-status-icon" style="background:rgba(245,124,0,0.1);">🕳️</div>
|
|
<div class="report-content">
|
|
<div class="report-item-title">Nid de poule — RN5</div>
|
|
<div class="report-item-desc">Gros nid de poule dangereux pour les 2 roues</div>
|
|
<div class="report-item-meta">
|
|
<div class="status-badge status-progress">🔄 En cours</div>
|
|
<div class="report-date">28 mai</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="report-item">
|
|
<div class="report-status-icon" style="background:rgba(2,136,209,0.1);">💡</div>
|
|
<div class="report-content">
|
|
<div class="report-item-title">Lampadaire en panne — Av. des Caraïbes</div>
|
|
<div class="report-item-desc">3 lampadaires éteints depuis 3 jours</div>
|
|
<div class="report-item-meta">
|
|
<div class="status-badge status-pending">⏳ En attente</div>
|
|
<div class="report-date">27 mai</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="report-item">
|
|
<div class="report-status-icon" style="background:rgba(46,125,50,0.1);">🌳</div>
|
|
<div class="report-content">
|
|
<div class="report-item-title">Arbre dangereux — Parc Floral</div>
|
|
<div class="report-item-desc">Branche morte au-dessus du chemin piéton</div>
|
|
<div class="report-item-meta">
|
|
<div class="status-badge status-done">✅ Résolu</div>
|
|
<div class="report-date">22 mai</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="report-item">
|
|
<div class="report-status-icon" style="background:rgba(124,77,255,0.1);">🗑️</div>
|
|
<div class="report-content">
|
|
<div class="report-item-title">Dépôt sauvage — Quartier Corotte</div>
|
|
<div class="report-item-desc">Gravats et encombrants abandonnés</div>
|
|
<div class="report-item-meta">
|
|
<div class="status-badge status-progress">🔄 En cours</div>
|
|
<div class="report-date">20 mai</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="report-item">
|
|
<div class="report-status-icon" style="background:rgba(211,47,47,0.1);">🌊</div>
|
|
<div class="report-content">
|
|
<div class="report-item-title">Inondation — Ruelle Périgny</div>
|
|
<div class="report-item-desc">Eau stagnante après pluie, risque sanitaire</div>
|
|
<div class="report-item-meta">
|
|
<div class="status-badge status-done">✅ Résolu</div>
|
|
<div class="report-date">15 mai</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- ODK Form preview -->
|
|
<div style="padding:16px;">
|
|
<div style="background:white;border-radius:var(--radius-lg);padding:16px;border:1px solid var(--neutral-100);">
|
|
<div style="display:flex;align-items:center;gap:10px;margin-bottom:12px;">
|
|
<div style="width:36px;height:36px;background:linear-gradient(135deg,#2E7D32,#66BB6A);border-radius:8px;display:flex;align-items:center;justify-content:center;color:white;font-size:18px;">📋</div>
|
|
<div>
|
|
<div style="font-weight:700;font-size:var(--text-sm);">Formulaire rapide</div>
|
|
<div style="font-size:var(--text-xs);color:var(--neutral-500);">ODK Form · 30 secondes</div>
|
|
</div>
|
|
</div>
|
|
<div style="display:flex;gap:8px;">
|
|
<button class="btn btn-primary" style="flex:1;font-size:13px;min-height:40px;">📸 Photo + GPS</button>
|
|
<button class="btn btn-secondary" style="flex:1;font-size:13px;min-height:40px;">📝 Texte seul</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div style="height:80px;"></div>
|
|
</div>
|
|
|
|
<!-- FAB -->
|
|
<div class="fab-btn">+</div>
|
|
|
|
<!-- Bottom Nav -->
|
|
<div class="bottom-nav">
|
|
<div class="bottom-nav-item">
|
|
<svg viewBox="0 0 24 24" fill="currentColor"><path d="M3 9l9-7 9 7v11a2 2 0 01-2 2H5a2 2 0 01-2-2z"/><polyline points="9 22 9 12 15 12 15 22" fill="none" stroke="currentColor" stroke-width="2"/></svg>
|
|
<span>Accueil</span>
|
|
</div>
|
|
<div class="bottom-nav-item">
|
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polygon points="1 6 1 22 8 18 16 22 23 18 23 2 16 6 8 2 1 6"/><line x1="8" y1="2" x2="8" y2="18"/><line x1="16" y1="6" x2="16" y2="22"/></svg>
|
|
<span>Carte</span>
|
|
</div>
|
|
<div class="bottom-nav-item">
|
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"/><path d="M8 14s1.5 2 4 2 4-2 4-2"/><line x1="9" y1="9" x2="9.01" y2="9"/><line x1="15" y1="9" x2="15.01" y2="9"/></svg>
|
|
<span>AI Chat</span>
|
|
</div>
|
|
<div class="bottom-nav-item">
|
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="2" y="3" width="20" height="14" rx="2"/><line x1="8" y1="21" x2="16" y2="21"/><line x1="12" y1="17" x2="12" y2="21"/></svg>
|
|
<span>Marché</span>
|
|
</div>
|
|
<div class="bottom-nav-item active">
|
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M20 21v-2a4 4 0 00-4-4H8a4 4 0 00-4 4v2"/><circle cx="12" cy="7" r="4"/></svg>
|
|
<span>Profil</span>
|
|
</div>
|
|
</div>
|
|
|
|
<div style="position:absolute;bottom:88px;left:0;right:0;text-align:center;font-size:10px;color:var(--neutral-400);">08 — Signalements Citoyens (ODK)</div>
|
|
</div>
|
|
</body>
|
|
</html>
|