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,9 @@
// @component ./AvatarIcon.tsx
export { default as Icon } from './AvatarIcon';
// @component ./AvatarImage.tsx
export { default as Image } from './AvatarImage';
// @component ./AvatarText.tsx
export { default as Text } from './AvatarText';
//# sourceMappingURL=Avatar.js.map

View File

@@ -0,0 +1 @@
{"version":3,"names":["default","Icon","Image","Text"],"sourceRoot":"../../../../src","sources":["components/Avatar/Avatar.tsx"],"mappings":"AAAA;AACA,SAASA,OAAO,IAAIC,IAAI,QAAQ,cAAc;;AAE9C;AACA,SAASD,OAAO,IAAIE,KAAK,QAAQ,eAAe;;AAEhD;AACA,SAASF,OAAO,IAAIG,IAAI,QAAQ,cAAc","ignoreList":[]}

View File

@@ -0,0 +1,57 @@
function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }
import * as React from 'react';
import { StyleSheet, View } from 'react-native';
import { useInternalTheme } from '../../core/theming';
import { white } from '../../styles/themes/v2/colors';
import getContrastingColor from '../../utils/getContrastingColor';
import Icon from '../Icon';
const defaultSize = 64;
/**
* Avatars can be used to represent people in a graphical way.
*
* ## Usage
* ```js
* import * as React from 'react';
* import { Avatar } from 'react-native-paper';
*
* const MyComponent = () => (
* <Avatar.Icon size={24} icon="folder" />
* );
* ```
*/
const Avatar = ({
icon,
size = defaultSize,
style,
theme: themeOverrides,
...rest
}) => {
var _theme$colors;
const theme = useInternalTheme(themeOverrides);
const {
backgroundColor = (_theme$colors = theme.colors) === null || _theme$colors === void 0 ? void 0 : _theme$colors.primary,
...restStyle
} = StyleSheet.flatten(style) || {};
const textColor = rest.color ?? getContrastingColor(backgroundColor, white, 'rgba(0, 0, 0, .54)');
return /*#__PURE__*/React.createElement(View, _extends({
style: [{
width: size,
height: size,
borderRadius: size / 2,
backgroundColor
}, styles.container, restStyle]
}, rest), /*#__PURE__*/React.createElement(Icon, {
source: icon,
color: textColor,
size: size * 0.6
}));
};
Avatar.displayName = 'Avatar.Icon';
const styles = StyleSheet.create({
container: {
justifyContent: 'center',
alignItems: 'center'
}
});
export default Avatar;
//# sourceMappingURL=AvatarIcon.js.map

View File

@@ -0,0 +1 @@
{"version":3,"names":["React","StyleSheet","View","useInternalTheme","white","getContrastingColor","Icon","defaultSize","Avatar","icon","size","style","theme","themeOverrides","rest","_theme$colors","backgroundColor","colors","primary","restStyle","flatten","textColor","color","createElement","_extends","width","height","borderRadius","styles","container","source","displayName","create","justifyContent","alignItems"],"sourceRoot":"../../../../src","sources":["components/Avatar/AvatarIcon.tsx"],"mappings":";AAAA,OAAO,KAAKA,KAAK,MAAM,OAAO;AAC9B,SAAoBC,UAAU,EAAEC,IAAI,QAAmB,cAAc;AAErE,SAASC,gBAAgB,QAAQ,oBAAoB;AACrD,SAASC,KAAK,QAAQ,+BAA+B;AAErD,OAAOC,mBAAmB,MAAM,iCAAiC;AACjE,OAAOC,IAAI,MAAsB,SAAS;AAE1C,MAAMC,WAAW,GAAG,EAAE;AAsBtB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAMC,MAAM,GAAGA,CAAC;EACdC,IAAI;EACJC,IAAI,GAAGH,WAAW;EAClBI,KAAK;EACLC,KAAK,EAAEC,cAAc;EACrB,GAAGC;AACE,CAAC,KAAK;EAAA,IAAAC,aAAA;EACX,MAAMH,KAAK,GAAGT,gBAAgB,CAACU,cAAc,CAAC;EAC9C,MAAM;IAAEG,eAAe,IAAAD,aAAA,GAAGH,KAAK,CAACK,MAAM,cAAAF,aAAA,uBAAZA,aAAA,CAAcG,OAAO;IAAE,GAAGC;EAAU,CAAC,GAC7DlB,UAAU,CAACmB,OAAO,CAACT,KAAK,CAAC,IAAI,CAAC,CAAC;EACjC,MAAMU,SAAS,GACbP,IAAI,CAACQ,KAAK,IACVjB,mBAAmB,CAACW,eAAe,EAAEZ,KAAK,EAAE,oBAAoB,CAAC;EAEnE,oBACEJ,KAAA,CAAAuB,aAAA,CAACrB,IAAI,EAAAsB,QAAA;IACHb,KAAK,EAAE,CACL;MACEc,KAAK,EAAEf,IAAI;MACXgB,MAAM,EAAEhB,IAAI;MACZiB,YAAY,EAAEjB,IAAI,GAAG,CAAC;MACtBM;IACF,CAAC,EACDY,MAAM,CAACC,SAAS,EAChBV,SAAS;EACT,GACEL,IAAI,gBAERd,KAAA,CAAAuB,aAAA,CAACjB,IAAI;IAACwB,MAAM,EAAErB,IAAK;IAACa,KAAK,EAAED,SAAU;IAACX,IAAI,EAAEA,IAAI,GAAG;EAAI,CAAE,CACrD,CAAC;AAEX,CAAC;AAEDF,MAAM,CAACuB,WAAW,GAAG,aAAa;AAElC,MAAMH,MAAM,GAAG3B,UAAU,CAAC+B,MAAM,CAAC;EAC/BH,SAAS,EAAE;IACTI,cAAc,EAAE,QAAQ;IACxBC,UAAU,EAAE;EACd;AACF,CAAC,CAAC;AAEF,eAAe1B,MAAM","ignoreList":[]}

View File

@@ -0,0 +1,68 @@
function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }
import * as React from 'react';
import { Image, StyleSheet, View } from 'react-native';
import { useInternalTheme } from '../../core/theming';
const defaultSize = 64;
/**
* Avatars can be used to represent people in a graphical way.
*
* ## Usage
* ```js
* import * as React from 'react';
* import { Avatar } from 'react-native-paper';
*
* const MyComponent = () => (
* <Avatar.Image size={24} source={require('../assets/avatar.png')} />
* );
* export default MyComponent
* ```
*/
const AvatarImage = ({
size = defaultSize,
source,
style,
onError,
onLayout,
onLoad,
onLoadEnd,
onLoadStart,
onProgress,
theme: themeOverrides,
testID,
...rest
}) => {
const {
colors
} = useInternalTheme(themeOverrides);
const {
backgroundColor = colors === null || colors === void 0 ? void 0 : colors.primary
} = StyleSheet.flatten(style) || {};
return /*#__PURE__*/React.createElement(View, _extends({
style: [{
width: size,
height: size,
borderRadius: size / 2,
backgroundColor
}, style]
}, rest), typeof source === 'function' && source({
size
}), typeof source !== 'function' && /*#__PURE__*/React.createElement(Image, {
testID: testID,
source: source,
style: {
width: size,
height: size,
borderRadius: size / 2
},
onError: onError,
onLayout: onLayout,
onLoad: onLoad,
onLoadEnd: onLoadEnd,
onLoadStart: onLoadStart,
onProgress: onProgress,
accessibilityIgnoresInvertColors: true
}));
};
AvatarImage.displayName = 'Avatar.Image';
export default AvatarImage;
//# sourceMappingURL=AvatarImage.js.map

View File

@@ -0,0 +1 @@
{"version":3,"names":["React","Image","StyleSheet","View","useInternalTheme","defaultSize","AvatarImage","size","source","style","onError","onLayout","onLoad","onLoadEnd","onLoadStart","onProgress","theme","themeOverrides","testID","rest","colors","backgroundColor","primary","flatten","createElement","_extends","width","height","borderRadius","accessibilityIgnoresInvertColors","displayName"],"sourceRoot":"../../../../src","sources":["components/Avatar/AvatarImage.tsx"],"mappings":";AAAA,OAAO,KAAKA,KAAK,MAAM,OAAO;AAC9B,SACEC,KAAK,EAILC,UAAU,EACVC,IAAI,QAEC,cAAc;AAErB,SAASC,gBAAgB,QAAQ,oBAAoB;AAGrD,MAAMC,WAAW,GAAG,EAAE;AAgDtB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAMC,WAAW,GAAGA,CAAC;EACnBC,IAAI,GAAGF,WAAW;EAClBG,MAAM;EACNC,KAAK;EACLC,OAAO;EACPC,QAAQ;EACRC,MAAM;EACNC,SAAS;EACTC,WAAW;EACXC,UAAU;EACVC,KAAK,EAAEC,cAAc;EACrBC,MAAM;EACN,GAAGC;AACE,CAAC,KAAK;EACX,MAAM;IAAEC;EAAO,CAAC,GAAGhB,gBAAgB,CAACa,cAAc,CAAC;EACnD,MAAM;IAAEI,eAAe,GAAGD,MAAM,aAANA,MAAM,uBAANA,MAAM,CAAEE;EAAQ,CAAC,GAAGpB,UAAU,CAACqB,OAAO,CAACd,KAAK,CAAC,IAAI,CAAC,CAAC;EAE7E,oBACET,KAAA,CAAAwB,aAAA,CAACrB,IAAI,EAAAsB,QAAA;IACHhB,KAAK,EAAE,CACL;MACEiB,KAAK,EAAEnB,IAAI;MACXoB,MAAM,EAAEpB,IAAI;MACZqB,YAAY,EAAErB,IAAI,GAAG,CAAC;MACtBc;IACF,CAAC,EACDZ,KAAK;EACL,GACEU,IAAI,GAEP,OAAOX,MAAM,KAAK,UAAU,IAAIA,MAAM,CAAC;IAAED;EAAK,CAAC,CAAC,EAChD,OAAOC,MAAM,KAAK,UAAU,iBAC3BR,KAAA,CAAAwB,aAAA,CAACvB,KAAK;IACJiB,MAAM,EAAEA,MAAO;IACfV,MAAM,EAAEA,MAAO;IACfC,KAAK,EAAE;MAAEiB,KAAK,EAAEnB,IAAI;MAAEoB,MAAM,EAAEpB,IAAI;MAAEqB,YAAY,EAAErB,IAAI,GAAG;IAAE,CAAE;IAC7DG,OAAO,EAAEA,OAAQ;IACjBC,QAAQ,EAAEA,QAAS;IACnBC,MAAM,EAAEA,MAAO;IACfC,SAAS,EAAEA,SAAU;IACrBC,WAAW,EAAEA,WAAY;IACzBC,UAAU,EAAEA,UAAW;IACvBc,gCAAgC;EAAA,CACjC,CAEC,CAAC;AAEX,CAAC;AAEDvB,WAAW,CAACwB,WAAW,GAAG,cAAc;AAExC,eAAexB,WAAW","ignoreList":[]}

View File

@@ -0,0 +1,71 @@
function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }
import * as React from 'react';
import { StyleSheet, useWindowDimensions, View } from 'react-native';
import { useInternalTheme } from '../../core/theming';
import { white } from '../../styles/themes/v2/colors';
import getContrastingColor from '../../utils/getContrastingColor';
import Text from '../Typography/Text';
const defaultSize = 64;
/**
* Avatars can be used to represent people in a graphical way.
*
* ## Usage
* ```js
* import * as React from 'react';
* import { Avatar } from 'react-native-paper';
*
* const MyComponent = () => (
* <Avatar.Text size={24} label="XD" />
* );
* ```
*/
const AvatarText = ({
label,
size = defaultSize,
style,
labelStyle,
color: customColor,
theme: themeOverrides,
maxFontSizeMultiplier,
...rest
}) => {
var _theme$colors;
const theme = useInternalTheme(themeOverrides);
const {
backgroundColor = (_theme$colors = theme.colors) === null || _theme$colors === void 0 ? void 0 : _theme$colors.primary,
...restStyle
} = StyleSheet.flatten(style) || {};
const textColor = customColor ?? getContrastingColor(backgroundColor, white, 'rgba(0, 0, 0, .54)');
const {
fontScale
} = useWindowDimensions();
return /*#__PURE__*/React.createElement(View, _extends({
style: [{
width: size,
height: size,
borderRadius: size / 2,
backgroundColor
}, styles.container, restStyle]
}, rest), /*#__PURE__*/React.createElement(Text, {
style: [styles.text, {
color: textColor,
fontSize: size / 2,
lineHeight: size / fontScale
}, labelStyle],
numberOfLines: 1,
maxFontSizeMultiplier: maxFontSizeMultiplier
}, label));
};
AvatarText.displayName = 'Avatar.Text';
const styles = StyleSheet.create({
container: {
justifyContent: 'center',
alignItems: 'center'
},
text: {
textAlign: 'center',
textAlignVertical: 'center'
}
});
export default AvatarText;
//# sourceMappingURL=AvatarText.js.map

View File

@@ -0,0 +1 @@
{"version":3,"names":["React","StyleSheet","useWindowDimensions","View","useInternalTheme","white","getContrastingColor","Text","defaultSize","AvatarText","label","size","style","labelStyle","color","customColor","theme","themeOverrides","maxFontSizeMultiplier","rest","_theme$colors","backgroundColor","colors","primary","restStyle","flatten","textColor","fontScale","createElement","_extends","width","height","borderRadius","styles","container","text","fontSize","lineHeight","numberOfLines","displayName","create","justifyContent","alignItems","textAlign","textAlignVertical"],"sourceRoot":"../../../../src","sources":["components/Avatar/AvatarText.tsx"],"mappings":";AAAA,OAAO,KAAKA,KAAK,MAAM,OAAO;AAC9B,SAEEC,UAAU,EAEVC,mBAAmB,EACnBC,IAAI,QAEC,cAAc;AAErB,SAASC,gBAAgB,QAAQ,oBAAoB;AACrD,SAASC,KAAK,QAAQ,+BAA+B;AAErD,OAAOC,mBAAmB,MAAM,iCAAiC;AACjE,OAAOC,IAAI,MAAM,oBAAoB;AAErC,MAAMC,WAAW,GAAG,EAAE;AAiCtB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAMC,UAAU,GAAGA,CAAC;EAClBC,KAAK;EACLC,IAAI,GAAGH,WAAW;EAClBI,KAAK;EACLC,UAAU;EACVC,KAAK,EAAEC,WAAW;EAClBC,KAAK,EAAEC,cAAc;EACrBC,qBAAqB;EACrB,GAAGC;AACE,CAAC,KAAK;EAAA,IAAAC,aAAA;EACX,MAAMJ,KAAK,GAAGZ,gBAAgB,CAACa,cAAc,CAAC;EAC9C,MAAM;IAAEI,eAAe,IAAAD,aAAA,GAAGJ,KAAK,CAACM,MAAM,cAAAF,aAAA,uBAAZA,aAAA,CAAcG,OAAO;IAAE,GAAGC;EAAU,CAAC,GAC7DvB,UAAU,CAACwB,OAAO,CAACb,KAAK,CAAC,IAAI,CAAC,CAAC;EACjC,MAAMc,SAAS,GACbX,WAAW,IACXT,mBAAmB,CAACe,eAAe,EAAEhB,KAAK,EAAE,oBAAoB,CAAC;EACnE,MAAM;IAAEsB;EAAU,CAAC,GAAGzB,mBAAmB,CAAC,CAAC;EAE3C,oBACEF,KAAA,CAAA4B,aAAA,CAACzB,IAAI,EAAA0B,QAAA;IACHjB,KAAK,EAAE,CACL;MACEkB,KAAK,EAAEnB,IAAI;MACXoB,MAAM,EAAEpB,IAAI;MACZqB,YAAY,EAAErB,IAAI,GAAG,CAAC;MACtBU;IACF,CAAC,EACDY,MAAM,CAACC,SAAS,EAChBV,SAAS;EACT,GACEL,IAAI,gBAERnB,KAAA,CAAA4B,aAAA,CAACrB,IAAI;IACHK,KAAK,EAAE,CACLqB,MAAM,CAACE,IAAI,EACX;MACErB,KAAK,EAAEY,SAAS;MAChBU,QAAQ,EAAEzB,IAAI,GAAG,CAAC;MAClB0B,UAAU,EAAE1B,IAAI,GAAGgB;IACrB,CAAC,EACDd,UAAU,CACV;IACFyB,aAAa,EAAE,CAAE;IACjBpB,qBAAqB,EAAEA;EAAsB,GAE5CR,KACG,CACF,CAAC;AAEX,CAAC;AAEDD,UAAU,CAAC8B,WAAW,GAAG,aAAa;AAEtC,MAAMN,MAAM,GAAGhC,UAAU,CAACuC,MAAM,CAAC;EAC/BN,SAAS,EAAE;IACTO,cAAc,EAAE,QAAQ;IACxBC,UAAU,EAAE;EACd,CAAC;EACDP,IAAI,EAAE;IACJQ,SAAS,EAAE,QAAQ;IACnBC,iBAAiB,EAAE;EACrB;AACF,CAAC,CAAC;AAEF,eAAenC,UAAU","ignoreList":[]}