diff --git a/App.tsx b/App.tsx index 6d02f72..1be16e7 100644 --- a/App.tsx +++ b/App.tsx @@ -1,70 +1,1761 @@ -import AsyncStorage from '@react-native-async-storage/async-storage'; -import { LinearGradient } from 'expo-linear-gradient'; -import { StatusBar } from 'expo-status-bar'; -import React, { useEffect, useMemo, useState } from 'react'; -import { Alert, Pressable, SafeAreaView, ScrollView, Share, StyleSheet, Switch, Text, TextInput, View, useWindowDimensions } from 'react-native'; -import { Activity, Apple, Bell, Camera, Check, ChevronRight, CircleUserRound, Download, Droplets, Footprints, HeartPulse, Home, Lightbulb, Minus, Moon, Plus, Scale, ShieldCheck, Sparkles, Sprout, TrendingUp, Utensils } from 'lucide-react-native'; +import AsyncStorage from "@react-native-async-storage/async-storage"; +import { LinearGradient } from "expo-linear-gradient"; +import { StatusBar } from "expo-status-bar"; +import React, { useEffect, useMemo, useState } from "react"; +import { + ActivityIndicator, + Alert, + Pressable, + SafeAreaView, + ScrollView, + Share, + StyleSheet, + Switch, + Text, + TextInput, + View, + useWindowDimensions, +} from "react-native"; +import { + Activity, + Apple, + Bell, + Bot, + Camera, + Check, + ChevronRight, + CircleUserRound, + Download, + Droplets, + Footprints, + HeartPulse, + Home, + Lightbulb, + Minus, + Moon, + Plus, + Scale, + Send, + ShieldCheck, + Sparkles, + Sprout, + TrendingUp, + UserRound, + Utensils, +} from "lucide-react-native"; type LucideIcon = any; -type Tab = 'today' | 'journal' | 'progress' | 'coach' | 'profile'; -type Entry = { date: string; iso?: string; weight: number; water: number; steps: number; glucose?: number; sleep?: number; meals?: number; mood?: string }; -type ProfileData = { name:string; goal:string; journey:string; glucoseUnit:'mg/dL'|'mmol/L'; reminders:boolean; complete:boolean }; -const C = { ink:'#15211c', muted:'#637169', cream:'#f6f7f2', white:'#fff', green:'#1d6b50', mint:'#dcefe5', coral:'#ef835f', yellow:'#f4d58d', line:'#e5e9e3' }; +type Tab = "today" | "journal" | "progress" | "coach" | "profile"; +type Entry = { + date: string; + iso?: string; + weight: number; + water: number; + steps: number; + glucose?: number; + sleep?: number; + meals?: number; + mood?: string; +}; +type ProfileData = { + name: string; + goal: string; + journey: string; + glucoseUnit: "mg/dL" | "mmol/L"; + reminders: boolean; + complete: boolean; +}; +type ChatMessage = { id: string; role: "user" | "assistant"; content: string }; +const C = { + ink: "#15211c", + muted: "#637169", + cream: "#f6f7f2", + white: "#fff", + green: "#1d6b50", + mint: "#dcefe5", + coral: "#ef835f", + yellow: "#f4d58d", + line: "#e5e9e3", +}; const seed: Entry[] = [ - {date:'Lun',weight:91.4,water:1500,steps:6100,glucose:112},{date:'Mar',weight:91.2,water:1800,steps:7400,glucose:108}, - {date:'Mer',weight:91.1,water:1600,steps:6900,glucose:110},{date:'Jeu',weight:90.9,water:2000,steps:8200,glucose:105}, - {date:'Ven',weight:90.8,water:2100,steps:8600,glucose:104},{date:'Sam',weight:90.7,water:1750,steps:7200,glucose:107},{date:'Auj.',weight:90.6,water:1250,steps:6240,glucose:103}, + { date: "Lun", weight: 91.4, water: 1500, steps: 6100, glucose: 112 }, + { date: "Mar", weight: 91.2, water: 1800, steps: 7400, glucose: 108 }, + { date: "Mer", weight: 91.1, water: 1600, steps: 6900, glucose: 110 }, + { date: "Jeu", weight: 90.9, water: 2000, steps: 8200, glucose: 105 }, + { date: "Ven", weight: 90.8, water: 2100, steps: 8600, glucose: 104 }, + { date: "Sam", weight: 90.7, water: 1750, steps: 7200, glucose: 107 }, + { date: "Auj.", weight: 90.6, water: 1250, steps: 6240, glucose: 103 }, ]; -function Card({children, style}: any){return {children}} -function Pill({children, tone='green'}:any){return {children}} -function IconTile({icon:Icon,color=C.green,bg=C.mint,size=22}:any){return } -function Metric({icon,label,value,sub,onPress}:any){const content=<>{label}{value}{sub};return onPress?[s.metric,pressed&&s.pressed]}>{content}:{content}} -function ProgressBar({value,color=C.green}:any){return } -function Nav({tab,setTab}:any){const items:any[]=[['today',Home,'Aujourd’hui'],['journal',Plus,'Journal'],['progress',TrendingUp,'Progrès'],['coach',Sparkles,'Coach'],['profile',CircleUserRound,'Profil']];return {items.map(([id,Icon,label])=>{const active=tab===id;return setTab(id)} style={({pressed})=>[s.navItem,active&&s.navItemActive,pressed&&s.pressed]}>{label}})}} - -export default function App(){ - const [tab,setTab]=useState('today'); const [entries,setEntries]=useState(seed); const [water,setWater]=useState(1250); const [steps,setSteps]=useState(6240); - const [weight,setWeight]=useState('90.6'); const [glucose,setGlucose]=useState('103'); const [sleep,setSleep]=useState('7.2'); const [meals,setMeals]=useState(2); const [mood,setMood]=useState('🙂'); const [saved,setSaved]=useState(false); const [loaded,setLoaded]=useState(false); const [profile,setProfile]=useState({name:'',goal:'Retrouver mon équilibre',journey:'Prévention',glucoseUnit:'mg/dL',reminders:false,complete:false}); const {width}=useWindowDimensions(); - useEffect(()=>{AsyncStorage.getItem('metabloom-v2').then(v=>{if(v){const d=JSON.parse(v);setEntries(Array.isArray(d.entries)&&d.entries.length?d.entries:seed);setWater(typeof d.water==='number'?d.water:1250);setSteps(typeof d.steps==='number'?d.steps:6240);setProfile(d.profile||profile)}}).catch(()=>{}).finally(()=>setLoaded(true))},[]); - useEffect(()=>{if(loaded)AsyncStorage.setItem('metabloom-v2',JSON.stringify({entries,water,steps,profile})).catch(()=>{})},[entries,water,steps,profile,loaded]); - const score=Math.round((Math.min(water/2000,1)+Math.min(steps/8000,1)+.82+.75)*25); - const save=()=>{const w=parseFloat(weight.replace(',','.')); const g=parseFloat(glucose.replace(',','.')); const sl=parseFloat(sleep.replace(',','.')); if(!Number.isFinite(w)||w<30||w>300){Alert.alert('Valeur à vérifier','Saisis un poids compris entre 30 et 300 kg.');return} const glucoseBounds=profile.glucoseUnit==='mmol/L'?[1.1,33.3]:[20,600]; if(glucose.trim()&&(!Number.isFinite(g)||gglucoseBounds[1])){Alert.alert('Valeur à vérifier','La glycémie saisie semble hors de la plage de saisie autorisée. Vérifie l’unité et la valeur.');return} if(!Number.isFinite(sl)||sl<0||sl>24){Alert.alert('Valeur à vérifier','Le sommeil doit être compris entre 0 et 24 heures.');return} const now=new Date();setEntries(x=>[...x.slice(-29),{date:'Auj.',iso:now.toISOString(),weight:w,water,steps,glucose:Number.isFinite(g)?g:undefined,sleep:sl,meals,mood}]);setSaved(true);setTimeout(()=>setSaved(false),2200)}; - const reset=()=>{setEntries(seed);setWater(1250);setSteps(6240);setProfile({...profile,complete:false});AsyncStorage.removeItem('metabloom-v2')}; - const content=useMemo(()=>tab==='today'?:tab==='journal'?:tab==='progress'?:tab==='coach'?:,[tab,score,water,steps,weight,glucose,sleep,meals,mood,saved,entries,profile]); - if(!loaded)return ; - if(!profile.complete)return ; - return 900?1120:680}]}>{content}