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,22 @@
# React & React Native Versions
This page describes how React and React Native versions interact each other.
The version alignment between the two frameworks relies on two synchronization points:
1. The versions in the `package.json` of the new app template. For example [for React Native 0.68.1](https://github.com/facebook/react-native/blob/0.68-stable/template/package.json#L12-L15) the versions are aligned as follows:
```
"dependencies": {
"react": "17.0.2",
"react-native": "0.68.1"
},
```
1. The React renderers **shipped** with React Native inside this folder, the [./Libraries/Renderer](https://github.com/facebook/react-native/tree/main/Libraries/Renderer) folder, of React Native.
This practically means that you **can't bump** the version of React in your `package.json` to a later version,
as you will still be using the older renderer from the folder mentioned above. Bumping the react version in your `package.json` will lead to unexpected behaviors.
For the sake of React 18, the first version of React Native compatible with React 18 is **0.69.0**. Users on React Native 0.68.0 and previous versions won't be able to use React 18.
If you use the `react-native upgrade` command or the React Native Upgrade Helper, you'll bump to the correct React version once you upgrade React Native.

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,33 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @noformat
* @flow
* @nolint
* @generated SignedSource<<c1cc197c110e3a49a5e8f6bd5d32b23f>>
*/
'use strict';
import {BatchedBridge} from 'react-native/Libraries/ReactPrivate/ReactNativePrivateInterface';
import type {ReactFabricType} from './ReactNativeTypes';
let ReactFabric;
if (__DEV__) {
ReactFabric = require('../implementations/ReactFabric-dev');
} else {
ReactFabric = require('../implementations/ReactFabric-prod');
}
global.RN$stopSurface = ReactFabric.stopSurface;
if (global.RN$Bridgeless !== true) {
BatchedBridge.registerCallableModule('ReactFabric', ReactFabric);
}
module.exports = (ReactFabric: ReactFabricType);

View File

@@ -0,0 +1,19 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @noformat
* @flow strict-local
* @nolint
* @generated SignedSource<<2881c8e89ef0f73f4cf6612cb518b197>>
*/
'use strict';
const ReactFeatureFlags = {
debugRenderPhaseSideEffects: false,
};
module.exports = ReactFeatureFlags;

View File

@@ -0,0 +1,25 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @noformat
* @flow
* @nolint
* @generated SignedSource<<0debd6e5a17dc037cb4661315a886de6>>
*/
'use strict';
import type {ReactNativeType} from './ReactNativeTypes';
let ReactNative;
if (__DEV__) {
ReactNative = require('../implementations/ReactNativeRenderer-dev');
} else {
ReactNative = require('../implementations/ReactNativeRenderer-prod');
}
module.exports = (ReactNative: ReactNativeType);

View File

@@ -0,0 +1,305 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @noformat
* @flow strict
* @nolint
* @generated SignedSource<<fbf33f04ca9428c149262f17c8a4b6ab>>
*/
import type {ElementRef, ElementType, Element, AbstractComponent} from 'react';
export type MeasureOnSuccessCallback = (
x: number,
y: number,
width: number,
height: number,
pageX: number,
pageY: number,
) => void;
export type MeasureInWindowOnSuccessCallback = (
x: number,
y: number,
width: number,
height: number,
) => void;
export type MeasureLayoutOnSuccessCallback = (
left: number,
top: number,
width: number,
height: number,
) => void;
export type AttributeType<T, V> =
| true
| $ReadOnly<{
diff?: (arg1: T, arg2: T) => boolean,
process?: (arg1: V) => T,
}>;
// We either force that `diff` and `process` always use mixed,
// or we allow them to define specific types and use this hack
export type AnyAttributeType = AttributeType<$FlowFixMe, $FlowFixMe>;
export type AttributeConfiguration = $ReadOnly<{
[propName: string]: AnyAttributeType,
style: $ReadOnly<{
[propName: string]: AnyAttributeType,
...
}>,
...
}>;
export type PartialAttributeConfiguration = $ReadOnly<{
[propName: string]: AnyAttributeType,
style?: $ReadOnly<{
[propName: string]: AnyAttributeType,
...
}>,
...
}>;
export type ViewConfig = $ReadOnly<{
Commands?: $ReadOnly<{[commandName: string]: number, ...}>,
Constants?: $ReadOnly<{[name: string]: mixed, ...}>,
Manager?: string,
NativeProps?: $ReadOnly<{[propName: string]: string, ...}>,
baseModuleName?: ?string,
bubblingEventTypes?: $ReadOnly<{
[eventName: string]: $ReadOnly<{
phasedRegistrationNames: $ReadOnly<{
captured: string,
bubbled: string,
skipBubbling?: ?boolean,
}>,
}>,
...
}>,
directEventTypes?: $ReadOnly<{
[eventName: string]: $ReadOnly<{
registrationName: string,
}>,
...
}>,
uiViewClassName: string,
validAttributes: AttributeConfiguration,
}>;
export type PartialViewConfig = $ReadOnly<{
bubblingEventTypes?: $PropertyType<ViewConfig, 'bubblingEventTypes'>,
directEventTypes?: $PropertyType<ViewConfig, 'directEventTypes'>,
uiViewClassName: string,
validAttributes?: PartialAttributeConfiguration,
}>;
/**
* Current usages should migrate to this definition
*/
export interface INativeMethods {
blur(): void;
focus(): void;
measure(callback: MeasureOnSuccessCallback): void;
measureInWindow(callback: MeasureInWindowOnSuccessCallback): void;
measureLayout(
relativeToNativeNode: number | ElementRef<HostComponent<mixed>>,
onSuccess: MeasureLayoutOnSuccessCallback,
onFail?: () => void,
): void;
setNativeProps(nativeProps: {...}): void;
}
export type NativeMethods = $ReadOnly<{|
blur(): void,
focus(): void,
measure(callback: MeasureOnSuccessCallback): void,
measureInWindow(callback: MeasureInWindowOnSuccessCallback): void,
measureLayout(
relativeToNativeNode: number | ElementRef<HostComponent<mixed>>,
onSuccess: MeasureLayoutOnSuccessCallback,
onFail?: () => void,
): void,
setNativeProps(nativeProps: {...}): void,
|}>;
// This validates that INativeMethods and NativeMethods stay in sync using Flow!
declare var ensureNativeMethodsAreSynced: NativeMethods;
(ensureNativeMethodsAreSynced: INativeMethods);
export type HostComponent<T> = AbstractComponent<T, $ReadOnly<NativeMethods>>;
type SecretInternalsType = {
computeComponentStackForErrorReporting(tag: number): string,
// TODO (bvaughn) Decide which additional types to expose here?
// And how much information to fill in for the above types.
...
};
type InspectorDataProps = $ReadOnly<{
[propName: string]: string,
...
}>;
type InspectorDataGetter = (
<TElementType: ElementType>(
componentOrHandle: ElementRef<TElementType> | number,
) => ?number,
) => $ReadOnly<{
measure: (callback: MeasureOnSuccessCallback) => void,
props: InspectorDataProps,
}>;
export type InspectorData = $ReadOnly<{
closestInstance?: mixed,
hierarchy: Array<{
name: ?string,
getInspectorData: InspectorDataGetter,
}>,
selectedIndex: ?number,
props: InspectorDataProps,
componentStack: string,
}>;
export type TouchedViewDataAtPoint = $ReadOnly<{
pointerY: number,
touchedViewTag?: number,
frame: $ReadOnly<{
top: number,
left: number,
width: number,
height: number,
}>,
...InspectorData,
}>;
/**
* Flat ReactNative renderer bundles are too big for Flow to parse efficiently.
* Provide minimal Flow typing for the high-level RN API and call it a day.
*/
export type ReactNativeType = {
findHostInstance_DEPRECATED<TElementType: ElementType>(
componentOrHandle: ?(ElementRef<TElementType> | number),
): ?ElementRef<HostComponent<mixed>>,
findNodeHandle<TElementType: ElementType>(
componentOrHandle: ?(ElementRef<TElementType> | number),
): ?number,
isChildPublicInstance(
parent: PublicInstance | HostComponent<mixed>,
child: PublicInstance | HostComponent<mixed>,
): boolean,
dispatchCommand(
handle: ElementRef<HostComponent<mixed>>,
command: string,
args: Array<mixed>,
): void,
sendAccessibilityEvent(
handle: ElementRef<HostComponent<mixed>>,
eventType: string,
): void,
render(
element: Element<ElementType>,
containerTag: number,
callback: ?() => void,
): ?ElementRef<ElementType>,
unmountComponentAtNode(containerTag: number): void,
unmountComponentAtNodeAndRemoveContainer(containerTag: number): void,
unstable_batchedUpdates: <T>(fn: (T) => void, bookkeeping: T) => void,
__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED: SecretInternalsType,
...
};
export opaque type Node = mixed;
export opaque type InternalInstanceHandle = mixed;
type PublicInstance = mixed;
type PublicTextInstance = mixed;
export type ReactFabricType = {
findHostInstance_DEPRECATED<TElementType: ElementType>(
componentOrHandle: ?(ElementRef<TElementType> | number),
): ?ElementRef<HostComponent<mixed>>,
findNodeHandle<TElementType: ElementType>(
componentOrHandle: ?(ElementRef<TElementType> | number),
): ?number,
dispatchCommand(
handle: ElementRef<HostComponent<mixed>>,
command: string,
args: Array<mixed>,
): void,
isChildPublicInstance(parent: PublicInstance, child: PublicInstance): boolean,
sendAccessibilityEvent(
handle: ElementRef<HostComponent<mixed>>,
eventType: string,
): void,
render(
element: Element<ElementType>,
containerTag: number,
callback: ?() => void,
concurrentRoot: ?boolean,
): ?ElementRef<ElementType>,
unmountComponentAtNode(containerTag: number): void,
getNodeFromInternalInstanceHandle(
internalInstanceHandle: InternalInstanceHandle,
): ?Node,
getPublicInstanceFromInternalInstanceHandle(
internalInstanceHandle: InternalInstanceHandle,
): PublicInstance | PublicTextInstance | null,
...
};
export type ReactFabricEventTouch = {
identifier: number,
locationX: number,
locationY: number,
pageX: number,
pageY: number,
screenX: number,
screenY: number,
target: number,
timestamp: number,
force: number,
...
};
export type ReactFabricEvent = {
touches: Array<ReactFabricEventTouch>,
changedTouches: Array<ReactFabricEventTouch>,
targetTouches: Array<ReactFabricEventTouch>,
target: number,
...
};
// Imperative LayoutAnimation API types
//
export type LayoutAnimationType =
| 'spring'
| 'linear'
| 'easeInEaseOut'
| 'easeIn'
| 'easeOut'
| 'keyboard';
export type LayoutAnimationProperty =
| 'opacity'
| 'scaleX'
| 'scaleY'
| 'scaleXY';
export type LayoutAnimationAnimationConfig = $ReadOnly<{
duration?: number,
delay?: number,
springDamping?: number,
initialVelocity?: number,
type?: LayoutAnimationType,
property?: LayoutAnimationProperty,
}>;
export type LayoutAnimationConfig = $ReadOnly<{
duration: number,
create?: LayoutAnimationAnimationConfig,
update?: LayoutAnimationAnimationConfig,
delete?: LayoutAnimationAnimationConfig,
}>;

View File

@@ -0,0 +1,124 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @noformat
* @flow strict-local
* @nolint
* @generated SignedSource<<73af5b3fe29d226634ed64bc861634df>>
*/
'use strict';
import {type ViewConfig} from './ReactNativeTypes';
import invariant from 'invariant';
// Event configs
export const customBubblingEventTypes: {
[eventName: string]: $ReadOnly<{
phasedRegistrationNames: $ReadOnly<{
captured: string,
bubbled: string,
skipBubbling?: ?boolean,
}>,
}>,
} = {};
export const customDirectEventTypes: {
[eventName: string]: $ReadOnly<{
registrationName: string,
}>,
} = {};
const viewConfigCallbacks = new Map<string, ?() => ViewConfig>();
const viewConfigs = new Map<string, ViewConfig>();
function processEventTypes(viewConfig: ViewConfig): void {
const {bubblingEventTypes, directEventTypes} = viewConfig;
if (__DEV__) {
if (bubblingEventTypes != null && directEventTypes != null) {
for (const topLevelType in directEventTypes) {
invariant(
bubblingEventTypes[topLevelType] == null,
'Event cannot be both direct and bubbling: %s',
topLevelType,
);
}
}
}
if (bubblingEventTypes != null) {
for (const topLevelType in bubblingEventTypes) {
if (customBubblingEventTypes[topLevelType] == null) {
customBubblingEventTypes[topLevelType] =
bubblingEventTypes[topLevelType];
}
}
}
if (directEventTypes != null) {
for (const topLevelType in directEventTypes) {
if (customDirectEventTypes[topLevelType] == null) {
customDirectEventTypes[topLevelType] = directEventTypes[topLevelType];
}
}
}
}
/**
* Registers a native view/component by name.
* A callback is provided to load the view config from UIManager.
* The callback is deferred until the view is actually rendered.
*/
export function register(name: string, callback: () => ViewConfig): string {
invariant(
!viewConfigCallbacks.has(name),
'Tried to register two views with the same name %s',
name,
);
invariant(
typeof callback === 'function',
'View config getter callback for component `%s` must be a function (received `%s`)',
name,
callback === null ? 'null' : typeof callback,
);
viewConfigCallbacks.set(name, callback);
return name;
}
/**
* Retrieves a config for the specified view.
* If this is the first time the view has been used,
* This configuration will be lazy-loaded from UIManager.
*/
export function get(name: string): ViewConfig {
let viewConfig;
if (!viewConfigs.has(name)) {
const callback = viewConfigCallbacks.get(name);
if (typeof callback !== 'function') {
invariant(
false,
'View config getter callback for component `%s` must be a function (received `%s`).%s',
name,
callback === null ? 'null' : typeof callback,
// $FlowFixMe[recursive-definition]
typeof name[0] === 'string' && /[a-z]/.test(name[0])
? ' Make sure to start component names with a capital letter.'
: '',
);
}
viewConfig = callback();
processEventTypes(viewConfig);
viewConfigs.set(name, viewConfig);
// Clear the callback after the config is set so that
// we don't mask any errors during registration.
viewConfigCallbacks.set(name, null);
} else {
viewConfig = viewConfigs.get(name);
}
invariant(viewConfig, 'View config not found for name %s', name);
return viewConfig;
}

View File

@@ -0,0 +1,35 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @noformat
* @flow strict-local
* @nolint
* @generated SignedSource<<ede54ac2fa1b9a09e234cdf098048989>>
*/
'use strict';
import {ReactNativeViewConfigRegistry} from 'react-native/Libraries/ReactPrivate/ReactNativePrivateInterface';
import {type ViewConfig} from './ReactNativeTypes';
const {register} = ReactNativeViewConfigRegistry;
/**
* Creates a renderable ReactNative host component.
* Use this method for view configs that are loaded from UIManager.
* Use createReactNativeComponentClass() for view configs defined within JavaScript.
*
* @param {string} config iOS View configuration.
* @private
*/
const createReactNativeComponentClass = function (
name: string,
callback: () => ViewConfig,
): string {
return register(name, callback);
};
module.exports = createReactNativeComponentClass;