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,282 @@
import * as $$Array from "bs-platform/lib/es6/array.js";
import * as Curry from "bs-platform/lib/es6/curry.js";
import * as Belt_Array from "bs-platform/lib/es6/belt_Array.js";
import * as Caml_option from "bs-platform/lib/es6/caml_option.js";
function makeEmpty(param) {
return [];
}
function makeUninitialized(prim) {
return new Array(prim);
}
function size(prim) {
return prim.length;
}
function getUnsafe(prim, prim$1) {
return prim[prim$1];
}
function setUnsafe(prim, prim$1, prim$2) {
prim[prim$1] = prim$2;
}
function fill(arr, x) {
return Belt_Array.fill(arr, 0, arr.length, x);
}
function copy(prim) {
return prim.slice(0);
}
function slice(arr, start, end_) {
var len = end_ - start | 0;
return Belt_Array.slice(arr, start, len);
}
function append(arr, x) {
return Belt_Array.concat(arr, [x]);
}
function somei(arr, f) {
var len = arr.length;
var _i = 0;
while(true) {
var i = _i;
if (i >= len) {
return false;
}
if (Curry._2(f, arr[i], i)) {
return true;
}
_i = i + 1 | 0;
continue ;
};
}
function everyi(arr, f) {
var len = arr.length;
var _i = 0;
while(true) {
var i = _i;
if (i >= len) {
return true;
}
if (!Curry._2(f, arr[i], i)) {
return false;
}
_i = i + 1 | 0;
continue ;
};
}
function findi(arr, f) {
var len = arr.length;
var _i = 0;
while(true) {
var i = _i;
if (i >= len) {
return ;
}
var x = arr[i];
if (Curry._2(f, x, i)) {
return Caml_option.some(x);
}
_i = i + 1 | 0;
continue ;
};
}
function findIndex(arr, f) {
var len = arr.length;
var _i = 0;
while(true) {
var i = _i;
if (i >= len) {
return -1;
}
if (Curry._1(f, arr[i])) {
return i;
}
_i = i + 1 | 0;
continue ;
};
}
function lastIndexOf(arr, x) {
var len = arr.length;
var _i = len - 1 | 0;
while(true) {
var i = _i;
if (i < 0) {
return -1;
}
if (x === arr[i]) {
return i;
}
_i = i - 1 | 0;
continue ;
};
}
function filteri(arr, f) {
var len = arr.length;
var res = arr.slice(0);
var j = {
contents: -1
};
var _i = 0;
while(true) {
var i = _i;
if (i >= len) {
return $$Array.sub(res, 0, j.contents + 1 | 0);
}
var x = arr[i];
if (Curry._2(f, x, i)) {
j.contents = j.contents + 1 | 0;
arr[j.contents] = x;
}
_i = i + 1 | 0;
continue ;
};
}
function removeCount(arr, pos, count) {
var len = arr.length;
var pos2 = (pos + count | 0) - 1 | 0;
var res = $$Array.sub(arr, 0, len - count | 0);
var _i = 0;
while(true) {
var i = _i;
if (i >= len) {
return res;
}
if (i >= pos && i <= pos2) {
_i = i + 1 | 0;
continue ;
}
var j = i > pos2 ? i - count | 0 : i;
arr[j] = arr[i];
_i = i + 1 | 0;
continue ;
};
}
function find(arr, f) {
return findi(arr, (function (x, _i) {
return Curry._1(f, x);
}));
}
function indexOf(arr, x) {
return findIndex(arr, (function (item) {
return item === x;
}));
}
function includes(arr, x) {
return findIndex(arr, (function (item) {
return item === x;
})) > -1;
}
function filter(arr, f) {
return filteri(arr, (function (x, _i) {
return Curry._1(f, x);
}));
}
function remove(arr, index) {
return removeCount(arr, index, 1);
}
function mapi(arr, f) {
return Belt_Array.mapWithIndexU(arr, (function (i, x) {
return Curry._2(f, x, i);
}));
}
function forEachi(arr, f) {
return Belt_Array.forEachWithIndexU(arr, (function (i, x) {
return Curry._2(f, x, i);
}));
}
function reduce(arr, reducer, acc) {
return Belt_Array.reduce(arr, acc, reducer);
}
function reduceRight(arr, reducer, acc) {
return Belt_Array.reduceReverse(arr, acc, reducer);
}
var make = Belt_Array.make;
var get = Belt_Array.get;
var set = Belt_Array.set;
var reverseInPlace = Belt_Array.reverseInPlace;
var reverse = Belt_Array.reverse;
var shuffle = Belt_Array.shuffle;
var shuffleInPlace = Belt_Array.shuffleInPlace;
var concat = Belt_Array.concat;
var some = Belt_Array.some;
var every = Belt_Array.every;
var map = Belt_Array.map;
var forEach = Belt_Array.forEach;
export {
makeEmpty ,
makeUninitialized ,
make ,
size ,
get ,
getUnsafe ,
set ,
setUnsafe ,
fill ,
reverseInPlace ,
reverse ,
shuffle ,
shuffleInPlace ,
copy ,
slice ,
concat ,
append ,
somei ,
everyi ,
findi ,
findIndex ,
lastIndexOf ,
filteri ,
removeCount ,
find ,
indexOf ,
includes ,
filter ,
remove ,
some ,
every ,
map ,
mapi ,
forEach ,
forEachi ,
reduce ,
reduceRight ,
}
/* No side effect */

View File

@@ -0,0 +1,166 @@
type t('a) = array('a);
let makeEmpty = (): t('a) => [||];
let makeUninitialized = Belt.Array.makeUninitializedUnsafe;
let make = Belt.Array.make;
let size = Belt.Array.size;
let get = Belt.Array.get;
let getUnsafe = Belt.Array.getUnsafe;
let set = Belt.Array.set;
let setUnsafe = Belt.Array.setUnsafe;
let fill = (arr: t('a), x: 'a) =>
Belt.Array.fill(arr, ~offset=0, ~len=size(arr), x);
let reverseInPlace = Belt.Array.reverseInPlace;
let reverse = Belt.Array.reverse;
let shuffle = Belt.Array.shuffle;
let shuffleInPlace = Belt.Array.shuffleInPlace;
let copy = Belt.Array.copy;
let slice = (arr: t('a), ~start: int, ~end_: int): t('a) => {
let len = end_ - start;
Belt.Array.slice(arr, ~offset=start, ~len);
};
let concat = Belt.Array.concat;
let append = (arr: t('a), x: 'a) => Belt.Array.concat(arr, [|x|]);
let somei = (arr: t('a), f: ('a, int) => bool): bool => {
let len = size(arr);
let rec search = (i: int) =>
if (i >= len) {
false;
} else if (f(getUnsafe(arr, i), i)) {
true;
} else {
search(i + 1);
};
search(0);
};
let everyi = (arr: t('a), f: ('a, int) => bool): bool => {
let len = size(arr);
let rec search = (i: int) =>
if (i >= len) {
true;
} else if (!f(getUnsafe(arr, i), i)) {
false;
} else {
search(i + 1);
};
search(0);
};
let findi = (arr: t('a), f: ('a, int) => bool): option('a) => {
let len = size(arr);
let rec search = (i: int) =>
if (i >= len) {
None;
} else {
let x = getUnsafe(arr, i);
if (f(x, i)) {
Some(x);
} else {
search(i + 1);
};
};
search(0);
};
let findIndex = (arr: t('a), f: 'a => bool): int => {
let len = size(arr);
let rec search = (i: int) =>
if (i >= len) {
(-1);
} else if (f(getUnsafe(arr, i))) {
i;
} else {
search(i + 1);
};
search(0);
};
let lastIndexOf = (arr: t('a), x: 'a): int => {
let len = size(arr);
let rec search = (i: int) =>
if (i < 0) {
(-1);
} else if (x === getUnsafe(arr, i)) {
i;
} else {
search(i - 1);
};
search(len - 1);
};
let filteri = (arr: t('a), f: ('a, int) => bool): t('a) => {
let len = size(arr);
let res: t('a) = copy(arr);
let j = ref(-1);
let rec filter = (i: int) =>
if (i >= len) {
Array.sub(res, 0, j^ + 1);
} else {
let x = getUnsafe(arr, i);
if (f(x, i)) {
j := j^ + 1;
Belt.Array.setUnsafe(arr, j^, x);
};
filter(i + 1);
};
filter(0);
};
let removeCount = (arr: t('a), ~pos: int, ~count: int): t('a) => {
let len = size(arr);
let pos2 = pos + count - 1;
let res = Array.sub(arr, 0, len - count);
let rec copy = (i: int) =>
if (i >= len) {
res;
} else if (i >= pos && i <= pos2) {
copy(i + 1);
} else {
let j = i > pos2 ? i - count : i;
Belt.Array.setUnsafe(arr, j, Belt.Array.getUnsafe(arr, i));
copy(i + 1);
};
copy(0);
};
let find = (arr: t('a), f: 'a => bool): option('a) =>
findi(arr, (x, _i) => f(x));
let indexOf = (arr: t('a), x: 'a): int => findIndex(arr, item => item === x);
let includes = (arr: t('a), x: 'a): bool =>
findIndex(arr, item => item === x) > (-1);
let filter = (arr: t('a), f: 'a => bool): t('a) =>
filteri(arr, (x, _i) => f(x));
let remove = (arr: t('a), index: int): t('a) =>
removeCount(arr, ~pos=index, ~count=1);
let some = Belt.Array.some;
let every = Belt.Array.every;
let map = Belt.Array.map;
let mapi = (arr: t('a), f: ('a, int) => 'b): t('b) =>
Belt.Array.mapWithIndexU(arr, (. i, x) => f(x, i));
let forEach = Belt.Array.forEach;
let forEachi = (arr: t('a), f: ('a, int) => unit): unit =>
Belt.Array.forEachWithIndexU(arr, (. i, x) => f(x, i));
let reduce = (arr: t('a), reducer: ('b, 'a) => 'b, acc: 'b): 'b =>
Belt.Array.reduce(arr, acc, reducer);
let reduceRight = (arr: t('a), reducer: ('b, 'a) => 'b, acc: 'b): 'b =>
Belt.Array.reduceReverse(arr, acc, reducer);

View File

@@ -0,0 +1,64 @@
import * as Belt_MutableQueue from "bs-platform/lib/es6/belt_MutableQueue.js";
function addMany(q1, q2) {
return Belt_MutableQueue.transfer(Belt_MutableQueue.copy(q1), q2);
}
var fromArray = Belt_MutableQueue.fromArray;
var toArray = Belt_MutableQueue.toArray;
var make = Belt_MutableQueue.make;
var clear = Belt_MutableQueue.clear;
var add = Belt_MutableQueue.add;
var peek = Belt_MutableQueue.peek;
var pop = Belt_MutableQueue.pop;
var copy = Belt_MutableQueue.copy;
var size = Belt_MutableQueue.size;
var mapU = Belt_MutableQueue.mapU;
var map = Belt_MutableQueue.map;
var forEachU = Belt_MutableQueue.forEachU;
var forEach = Belt_MutableQueue.forEach;
var isEmpty = Belt_MutableQueue.isEmpty;
var reduceU = Belt_MutableQueue.reduceU;
var reduce = Belt_MutableQueue.reduce;
var transfer = Belt_MutableQueue.transfer;
export {
fromArray ,
toArray ,
make ,
clear ,
add ,
peek ,
pop ,
copy ,
size ,
mapU ,
map ,
forEachU ,
forEach ,
isEmpty ,
reduceU ,
reduce ,
addMany ,
transfer ,
}
/* No side effect */

View File

@@ -0,0 +1,24 @@
type t('a) = Belt.MutableQueue.t('a);
let fromArray = Belt.MutableQueue.fromArray;
let toArray = Belt.MutableQueue.toArray;
let make = Belt.MutableQueue.make;
let clear = Belt.MutableQueue.clear;
let add = Belt.MutableQueue.add;
let peek = Belt.MutableQueue.peek;
let pop = Belt.MutableQueue.pop;
let copy = Belt.MutableQueue.copy;
let size = Belt.MutableQueue.size;
let mapU = Belt.MutableQueue.mapU;
let map = Belt.MutableQueue.map;
let forEachU = Belt.MutableQueue.forEachU;
let forEach = Belt.MutableQueue.forEach;
let isEmpty = Belt.MutableQueue.isEmpty;
let reduceU = Belt.MutableQueue.reduceU;
let reduce = Belt.MutableQueue.reduce;
let addMany = (q1: t('a), q2: t('a)) =>
Belt.MutableQueue.transfer(copy(q1), q2);
let transfer = Belt.MutableQueue.transfer;

View File

@@ -0,0 +1,38 @@
import * as Belt_MutableStack from "bs-platform/lib/es6/belt_MutableStack.js";
var make = Belt_MutableStack.make;
var clear = Belt_MutableStack.clear;
var push = Belt_MutableStack.push;
var pop = Belt_MutableStack.pop;
var copy = Belt_MutableStack.copy;
var size = Belt_MutableStack.size;
var forEachU = Belt_MutableStack.forEachU;
var forEach = Belt_MutableStack.forEach;
var isEmpty = Belt_MutableStack.isEmpty;
var top = Belt_MutableStack.top;
export {
make ,
clear ,
push ,
pop ,
copy ,
size ,
forEachU ,
forEach ,
isEmpty ,
top ,
}
/* No side effect */

View File

@@ -0,0 +1,13 @@
type t('a) = Belt.MutableStack.t('a);
let make = Belt.MutableStack.make;
let clear = Belt.MutableStack.clear;
let push = Belt.MutableStack.push;
let pop = Belt.MutableStack.pop;
let copy = Belt.MutableStack.copy;
let size = Belt.MutableStack.size;
let forEachU = Belt.MutableStack.forEachU;
let forEach = Belt.MutableStack.forEach;
let isEmpty = Belt.MutableStack.isEmpty;
let top = Belt.MutableStack.top;

View File

@@ -0,0 +1,16 @@
var $$Array;
var MutableStack;
var MutableQueue;
export {
$$Array ,
MutableStack ,
MutableQueue ,
}
/* No side effect */

View File

@@ -0,0 +1,3 @@
module Array = Array_native;
module MutableStack = MutableStack_native;
module MutableQueue = MutableQueue_native;