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,15 @@
import '../Expo.fx';
import * as React from 'react';
type InitialProps = {
exp?: {
notification?: any;
manifestString?: string;
[key: string]: any;
};
shell?: boolean;
shellManifestUrl?: string;
[key: string]: any;
};
export default function registerRootComponent<P extends InitialProps>(component: React.ComponentType<P>): void;
export {};
//# sourceMappingURL=registerRootComponent.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"registerRootComponent.d.ts","sourceRoot":"","sources":["../../src/launch/registerRootComponent.tsx"],"names":[],"mappings":"AAAA,OAAO,YAAY,CAAC;AAEpB,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAG/B,KAAK,YAAY,GAAG;IAClB,GAAG,CAAC,EAAE;QACJ,YAAY,CAAC,EAAE,GAAG,CAAC;QACnB,cAAc,CAAC,EAAE,MAAM,CAAC;QACxB,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;KACpB,CAAC;IACF,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;CACpB,CAAC;AAEF,MAAM,CAAC,OAAO,UAAU,qBAAqB,CAAC,CAAC,SAAS,YAAY,EAClE,SAAS,EAAE,KAAK,CAAC,aAAa,CAAC,CAAC,CAAC,GAChC,IAAI,CAsBN"}

View File

@@ -0,0 +1,24 @@
import '../Expo.fx';
import { AppRegistry, Platform } from 'react-native';
export default function registerRootComponent(component) {
let qualifiedComponent = component;
if (process.env.NODE_ENV !== 'production') {
const { withDevTools } = require('./withDevTools');
qualifiedComponent = withDevTools(component);
}
AppRegistry.registerComponent('main', () => qualifiedComponent);
// Skip querying the DOM if we're in a Node.js environment.
if (Platform.OS === 'web' && typeof window !== 'undefined') {
const rootTag = document.getElementById('root');
if (process.env.NODE_ENV !== 'production') {
if (!rootTag) {
throw new Error('Required HTML element with id "root" was not found in the document HTML.');
}
}
AppRegistry.runApplication('main', {
rootTag,
hydrate: process.env.EXPO_PUBLIC_USE_STATIC === '1',
});
}
}
//# sourceMappingURL=registerRootComponent.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"registerRootComponent.js","sourceRoot":"","sources":["../../src/launch/registerRootComponent.tsx"],"names":[],"mappings":"AAAA,OAAO,YAAY,CAAC;AAGpB,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAarD,MAAM,CAAC,OAAO,UAAU,qBAAqB,CAC3C,SAAiC;IAEjC,IAAI,kBAAkB,GAAG,SAAS,CAAC;IAEnC,IAAI,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,YAAY,EAAE;QACzC,MAAM,EAAE,YAAY,EAAE,GAAG,OAAO,CAAC,gBAAgB,CAAoC,CAAC;QACtF,kBAAkB,GAAG,YAAY,CAAC,SAAS,CAAC,CAAC;KAC9C;IAED,WAAW,CAAC,iBAAiB,CAAC,MAAM,EAAE,GAAG,EAAE,CAAC,kBAAkB,CAAC,CAAC;IAChE,2DAA2D;IAC3D,IAAI,QAAQ,CAAC,EAAE,KAAK,KAAK,IAAI,OAAO,MAAM,KAAK,WAAW,EAAE;QAC1D,MAAM,OAAO,GAAG,QAAQ,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC;QAChD,IAAI,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,YAAY,EAAE;YACzC,IAAI,CAAC,OAAO,EAAE;gBACZ,MAAM,IAAI,KAAK,CAAC,0EAA0E,CAAC,CAAC;aAC7F;SACF;QACD,WAAW,CAAC,cAAc,CAAC,MAAM,EAAE;YACjC,OAAO;YACP,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,sBAAsB,KAAK,GAAG;SACpD,CAAC,CAAC;KACJ;AACH,CAAC","sourcesContent":["import '../Expo.fx';\n\nimport * as React from 'react';\nimport { AppRegistry, Platform } from 'react-native';\n\ntype InitialProps = {\n exp?: {\n notification?: any;\n manifestString?: string;\n [key: string]: any;\n };\n shell?: boolean;\n shellManifestUrl?: string;\n [key: string]: any;\n};\n\nexport default function registerRootComponent<P extends InitialProps>(\n component: React.ComponentType<P>\n): void {\n let qualifiedComponent = component;\n\n if (process.env.NODE_ENV !== 'production') {\n const { withDevTools } = require('./withDevTools') as typeof import('./withDevTools');\n qualifiedComponent = withDevTools(component);\n }\n\n AppRegistry.registerComponent('main', () => qualifiedComponent);\n // Skip querying the DOM if we're in a Node.js environment.\n if (Platform.OS === 'web' && typeof window !== 'undefined') {\n const rootTag = document.getElementById('root');\n if (process.env.NODE_ENV !== 'production') {\n if (!rootTag) {\n throw new Error('Required HTML element with id \"root\" was not found in the document HTML.');\n }\n }\n AppRegistry.runApplication('main', {\n rootTag,\n hydrate: process.env.EXPO_PUBLIC_USE_STATIC === '1',\n });\n }\n}\n"]}

View File

@@ -0,0 +1,3 @@
import * as React from 'react';
export declare function withDevTools<TComponent extends React.ComponentType<any>>(AppRootComponent: TComponent): React.ComponentType<React.ComponentProps<TComponent>>;
//# sourceMappingURL=withDevTools.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"withDevTools.d.ts","sourceRoot":"","sources":["../../src/launch/withDevTools.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAI/B,wBAAgB,YAAY,CAAC,UAAU,SAAS,KAAK,CAAC,aAAa,CAAC,GAAG,CAAC,EACtE,gBAAgB,EAAE,UAAU,GAC3B,KAAK,CAAC,aAAa,CAAC,KAAK,CAAC,cAAc,CAAC,UAAU,CAAC,CAAC,CAuBvD"}

View File

@@ -0,0 +1,7 @@
import * as React from 'react';
/**
* Append the Expo Fast Refresh view and optionally
* keep the screen awake if `expo-keep-awake` is installed.
*/
export declare function withDevTools<TComponent extends React.ComponentType<any>>(AppRootComponent: TComponent): React.ComponentType<React.ComponentProps<TComponent>>;
//# sourceMappingURL=withDevTools.ios.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"withDevTools.ios.d.ts","sourceRoot":"","sources":["../../src/launch/withDevTools.ios.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAK/B;;;GAGG;AACH,wBAAgB,YAAY,CAAC,UAAU,SAAS,KAAK,CAAC,aAAa,CAAC,GAAG,CAAC,EACtE,gBAAgB,EAAE,UAAU,GAC3B,KAAK,CAAC,aAAa,CAAC,KAAK,CAAC,cAAc,CAAC,UAAU,CAAC,CAAC,CAmCvD"}

View File

@@ -0,0 +1,37 @@
import * as React from 'react';
import DevLoadingView from '../environment/DevLoadingView';
import { isRunningInExpoGo } from '../environment/ExpoGo';
/**
* Append the Expo Fast Refresh view and optionally
* keep the screen awake if `expo-keep-awake` is installed.
*/
export function withDevTools(AppRootComponent) {
// This hook can be optionally imported because __DEV__ never changes during runtime.
// Using __DEV__ like this enables tree shaking to remove the hook in production.
const useOptionalKeepAwake = (() => {
try {
// Optionally import expo-keep-awake
const { useKeepAwake, ExpoKeepAwakeTag } = require('expo-keep-awake');
return () => useKeepAwake(ExpoKeepAwakeTag, { suppressDeactivateWarnings: true });
}
catch { }
return () => { };
})();
const shouldUseExpoFastRefreshView = isRunningInExpoGo();
function WithDevTools(props) {
useOptionalKeepAwake();
if (shouldUseExpoFastRefreshView) {
return (<>
<AppRootComponent {...props}/>
<DevLoadingView />
</>);
}
return <AppRootComponent {...props}/>;
}
if (process.env.NODE_ENV !== 'production') {
const name = AppRootComponent.displayName || AppRootComponent.name || 'Anonymous';
WithDevTools.displayName = `withDevTools(${name})`;
}
return WithDevTools;
}
//# sourceMappingURL=withDevTools.ios.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"withDevTools.ios.js","sourceRoot":"","sources":["../../src/launch/withDevTools.ios.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B,OAAO,cAAc,MAAM,+BAA+B,CAAC;AAC3D,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAE1D;;;GAGG;AACH,MAAM,UAAU,YAAY,CAC1B,gBAA4B;IAE5B,qFAAqF;IACrF,iFAAiF;IACjF,MAAM,oBAAoB,GAA2B,CAAC,GAAG,EAAE;QACzD,IAAI;YACF,oCAAoC;YACpC,MAAM,EAAE,YAAY,EAAE,gBAAgB,EAAE,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAAC;YACtE,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,gBAAgB,EAAE,EAAE,0BAA0B,EAAE,IAAI,EAAE,CAAC,CAAC;SACnF;QAAC,MAAM,GAAE;QACV,OAAO,GAAG,EAAE,GAAE,CAAC,CAAC;IAClB,CAAC,CAAC,EAAE,CAAC;IAEL,MAAM,4BAA4B,GAAG,iBAAiB,EAAE,CAAC;IAEzD,SAAS,YAAY,CAAC,KAAuC;QAC3D,oBAAoB,EAAE,CAAC;QAEvB,IAAI,4BAA4B,EAAE;YAChC,OAAO,CACL,EACE;UAAA,CAAC,gBAAgB,CAAC,IAAI,KAAK,CAAC,EAC5B;UAAA,CAAC,cAAc,CAAC,AAAD,EACjB;QAAA,GAAG,CACJ,CAAC;SACH;QAED,OAAO,CAAC,gBAAgB,CAAC,IAAI,KAAK,CAAC,EAAG,CAAC;IACzC,CAAC;IAED,IAAI,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,YAAY,EAAE;QACzC,MAAM,IAAI,GAAG,gBAAgB,CAAC,WAAW,IAAI,gBAAgB,CAAC,IAAI,IAAI,WAAW,CAAC;QAClF,YAAY,CAAC,WAAW,GAAG,gBAAgB,IAAI,GAAG,CAAC;KACpD;IAED,OAAO,YAAY,CAAC;AACtB,CAAC","sourcesContent":["import * as React from 'react';\n\nimport DevLoadingView from '../environment/DevLoadingView';\nimport { isRunningInExpoGo } from '../environment/ExpoGo';\n\n/**\n * Append the Expo Fast Refresh view and optionally\n * keep the screen awake if `expo-keep-awake` is installed.\n */\nexport function withDevTools<TComponent extends React.ComponentType<any>>(\n AppRootComponent: TComponent\n): React.ComponentType<React.ComponentProps<TComponent>> {\n // This hook can be optionally imported because __DEV__ never changes during runtime.\n // Using __DEV__ like this enables tree shaking to remove the hook in production.\n const useOptionalKeepAwake: (tag?: string) => void = (() => {\n try {\n // Optionally import expo-keep-awake\n const { useKeepAwake, ExpoKeepAwakeTag } = require('expo-keep-awake');\n return () => useKeepAwake(ExpoKeepAwakeTag, { suppressDeactivateWarnings: true });\n } catch {}\n return () => {};\n })();\n\n const shouldUseExpoFastRefreshView = isRunningInExpoGo();\n\n function WithDevTools(props: React.ComponentProps<TComponent>) {\n useOptionalKeepAwake();\n\n if (shouldUseExpoFastRefreshView) {\n return (\n <>\n <AppRootComponent {...props} />\n <DevLoadingView />\n </>\n );\n }\n\n return <AppRootComponent {...props} />;\n }\n\n if (process.env.NODE_ENV !== 'production') {\n const name = AppRootComponent.displayName || AppRootComponent.name || 'Anonymous';\n WithDevTools.displayName = `withDevTools(${name})`;\n }\n\n return WithDevTools;\n}\n"]}

View File

@@ -0,0 +1,26 @@
import * as React from 'react';
// Keep the screen awake on Android, we don't use the Fast Refresh overlay here.
// The default behavior here is to skip the custom Fast Refresh indicator.
export function withDevTools(AppRootComponent) {
// This hook can be optionally imported because __DEV__ never changes during runtime.
// Using __DEV__ like this enables tree shaking to remove the hook in production.
const useOptionalKeepAwake = (() => {
try {
// Optionally import expo-keep-awake
const { useKeepAwake, ExpoKeepAwakeTag } = require('expo-keep-awake');
return () => useKeepAwake(ExpoKeepAwakeTag, { suppressDeactivateWarnings: true });
}
catch { }
return () => { };
})();
function WithDevTools(props) {
useOptionalKeepAwake();
return <AppRootComponent {...props}/>;
}
if (process.env.NODE_ENV !== 'production') {
const name = AppRootComponent.displayName || AppRootComponent.name || 'Anonymous';
WithDevTools.displayName = `withDevTools(${name})`;
}
return WithDevTools;
}
//# sourceMappingURL=withDevTools.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"withDevTools.js","sourceRoot":"","sources":["../../src/launch/withDevTools.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B,gFAAgF;AAChF,0EAA0E;AAC1E,MAAM,UAAU,YAAY,CAC1B,gBAA4B;IAE5B,qFAAqF;IACrF,iFAAiF;IACjF,MAAM,oBAAoB,GAA2B,CAAC,GAAG,EAAE;QACzD,IAAI;YACF,oCAAoC;YACpC,MAAM,EAAE,YAAY,EAAE,gBAAgB,EAAE,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAAC;YACtE,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,gBAAgB,EAAE,EAAE,0BAA0B,EAAE,IAAI,EAAE,CAAC,CAAC;SACnF;QAAC,MAAM,GAAE;QACV,OAAO,GAAG,EAAE,GAAE,CAAC,CAAC;IAClB,CAAC,CAAC,EAAE,CAAC;IAEL,SAAS,YAAY,CAAC,KAAuC;QAC3D,oBAAoB,EAAE,CAAC;QACvB,OAAO,CAAC,gBAAgB,CAAC,IAAI,KAAK,CAAC,EAAG,CAAC;IACzC,CAAC;IAED,IAAI,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,YAAY,EAAE;QACzC,MAAM,IAAI,GAAG,gBAAgB,CAAC,WAAW,IAAI,gBAAgB,CAAC,IAAI,IAAI,WAAW,CAAC;QAClF,YAAY,CAAC,WAAW,GAAG,gBAAgB,IAAI,GAAG,CAAC;KACpD;IAED,OAAO,YAAY,CAAC;AACtB,CAAC","sourcesContent":["import * as React from 'react';\n\n// Keep the screen awake on Android, we don't use the Fast Refresh overlay here.\n// The default behavior here is to skip the custom Fast Refresh indicator.\nexport function withDevTools<TComponent extends React.ComponentType<any>>(\n AppRootComponent: TComponent\n): React.ComponentType<React.ComponentProps<TComponent>> {\n // This hook can be optionally imported because __DEV__ never changes during runtime.\n // Using __DEV__ like this enables tree shaking to remove the hook in production.\n const useOptionalKeepAwake: (tag?: string) => void = (() => {\n try {\n // Optionally import expo-keep-awake\n const { useKeepAwake, ExpoKeepAwakeTag } = require('expo-keep-awake');\n return () => useKeepAwake(ExpoKeepAwakeTag, { suppressDeactivateWarnings: true });\n } catch {}\n return () => {};\n })();\n\n function WithDevTools(props: React.ComponentProps<TComponent>) {\n useOptionalKeepAwake();\n return <AppRootComponent {...props} />;\n }\n\n if (process.env.NODE_ENV !== 'production') {\n const name = AppRootComponent.displayName || AppRootComponent.name || 'Anonymous';\n WithDevTools.displayName = `withDevTools(${name})`;\n }\n\n return WithDevTools;\n}\n"]}

View File

@@ -0,0 +1,3 @@
import * as React from 'react';
export declare function withDevTools<TComponent extends React.ComponentType<any>>(AppRootComponent: TComponent): React.ComponentType<React.ComponentProps<TComponent>>;
//# sourceMappingURL=withDevTools.web.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"withDevTools.web.d.ts","sourceRoot":"","sources":["../../src/launch/withDevTools.web.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAI/B,wBAAgB,YAAY,CAAC,UAAU,SAAS,KAAK,CAAC,aAAa,CAAC,GAAG,CAAC,EACtE,gBAAgB,EAAE,UAAU,GAC3B,KAAK,CAAC,aAAa,CAAC,KAAK,CAAC,cAAc,CAAC,UAAU,CAAC,CAAC,CAgBvD"}

View File

@@ -0,0 +1,16 @@
import * as React from 'react';
import DevLoadingView from '../environment/DevLoadingView';
export function withDevTools(AppRootComponent) {
function WithDevTools(props) {
return (<>
<AppRootComponent {...props}/>
<DevLoadingView />
</>);
}
if (process.env.NODE_ENV !== 'production') {
const name = AppRootComponent.displayName || AppRootComponent.name || 'Anonymous';
WithDevTools.displayName = `withDevTools(${name})`;
}
return WithDevTools;
}
//# sourceMappingURL=withDevTools.web.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"withDevTools.web.js","sourceRoot":"","sources":["../../src/launch/withDevTools.web.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B,OAAO,cAAc,MAAM,+BAA+B,CAAC;AAE3D,MAAM,UAAU,YAAY,CAC1B,gBAA4B;IAE5B,SAAS,YAAY,CAAC,KAAuC;QAC3D,OAAO,CACL,EACE;QAAA,CAAC,gBAAgB,CAAC,IAAI,KAAK,CAAC,EAC5B;QAAA,CAAC,cAAc,CAAC,AAAD,EACjB;MAAA,GAAG,CACJ,CAAC;IACJ,CAAC;IAED,IAAI,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,YAAY,EAAE;QACzC,MAAM,IAAI,GAAG,gBAAgB,CAAC,WAAW,IAAI,gBAAgB,CAAC,IAAI,IAAI,WAAW,CAAC;QAClF,YAAY,CAAC,WAAW,GAAG,gBAAgB,IAAI,GAAG,CAAC;KACpD;IAED,OAAO,YAAY,CAAC;AACtB,CAAC","sourcesContent":["import * as React from 'react';\n\nimport DevLoadingView from '../environment/DevLoadingView';\n\nexport function withDevTools<TComponent extends React.ComponentType<any>>(\n AppRootComponent: TComponent\n): React.ComponentType<React.ComponentProps<TComponent>> {\n function WithDevTools(props: React.ComponentProps<TComponent>) {\n return (\n <>\n <AppRootComponent {...props} />\n <DevLoadingView />\n </>\n );\n }\n\n if (process.env.NODE_ENV !== 'production') {\n const name = AppRootComponent.displayName || AppRootComponent.name || 'Anonymous';\n WithDevTools.displayName = `withDevTools(${name})`;\n }\n\n return WithDevTools;\n}\n"]}