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,11 @@
function emptyFunction() {}
export const BackHandler = {
exitApp: emptyFunction,
addEventListener() {
return {
remove: emptyFunction
};
},
removeEventListener: emptyFunction
};
//# sourceMappingURL=BackHandler.js.map

View File

@@ -0,0 +1 @@
{"version":3,"names":["emptyFunction","BackHandler","exitApp","addEventListener","remove","removeEventListener"],"sourceRoot":"../../../../src","sources":["utils/BackHandler/BackHandler.tsx"],"mappings":"AAAA,SAASA,aAAaA,CAAA,EAAG,CAAC;AAE1B,OAAO,MAAMC,WAAW,GAAG;EACzBC,OAAO,EAAEF,aAAa;EACtBG,gBAAgBA,CAAA,EAA2B;IACzC,OAAO;MACLC,MAAM,EAAEJ;IACV,CAAC;EACH,CAAC;EACDK,mBAAmB,EAAEL;AACvB,CAAC","ignoreList":[]}

View File

@@ -0,0 +1,3 @@
import { BackHandler } from 'react-native';
export { BackHandler };
//# sourceMappingURL=BackHandler.native.js.map

View File

@@ -0,0 +1 @@
{"version":3,"names":["BackHandler"],"sourceRoot":"../../../../src","sources":["utils/BackHandler/BackHandler.native.tsx"],"mappings":"AAAA,SAASA,WAAW,QAAQ,cAAc;AAE1C,SAASA,WAAW","ignoreList":[]}

View File

@@ -0,0 +1,31 @@
export function addEventListener(Module, ...rest) {
const [eventName, handler] = rest;
let removed = false;
const subscription = Module.addEventListener(eventName, handler) ?? {
remove: () => {
var _Module$removeEventLi, _Module$remove;
if (removed) {
return;
}
(_Module$removeEventLi = Module.removeEventListener) === null || _Module$removeEventLi === void 0 || _Module$removeEventLi.call(Module, eventName, handler);
(_Module$remove = Module.remove) === null || _Module$remove === void 0 || _Module$remove.call(Module, eventName, handler);
removed = true;
}
};
return subscription;
}
export function addListener(Module, ...rest) {
const [eventName, handler] = rest;
let removed = false;
const subscription = Module.addListener(eventName, handler) ?? {
remove: () => {
if (removed) {
return;
}
Module.removeEventListener(eventName, handler);
removed = true;
}
};
return subscription;
}
//# sourceMappingURL=addEventListener.js.map

View File

@@ -0,0 +1 @@
{"version":3,"names":["addEventListener","Module","rest","eventName","handler","removed","subscription","remove","_Module$removeEventLi","_Module$remove","removeEventListener","call","addListener"],"sourceRoot":"../../../src","sources":["utils/addEventListener.tsx"],"mappings":"AAKA,OAAO,SAASA,gBAAgBA,CAQ9BC,MAAS,EAAE,GAAGC,IAAgD,EAAE;EAChE,MAAM,CAACC,SAAS,EAAEC,OAAO,CAAC,GAAGF,IAAI;EAEjC,IAAIG,OAAO,GAAG,KAAK;EAEnB,MAAMC,YAAY,GAAGL,MAAM,CAACD,gBAAgB,CAACG,SAAS,EAAEC,OAAO,CAAC,IAAI;IAClEG,MAAM,EAAEA,CAAA,KAAM;MAAA,IAAAC,qBAAA,EAAAC,cAAA;MACZ,IAAIJ,OAAO,EAAE;QACX;MACF;MAEA,CAAAG,qBAAA,GAAAP,MAAM,CAACS,mBAAmB,cAAAF,qBAAA,eAA1BA,qBAAA,CAAAG,IAAA,CAAAV,MAAM,EAAuBE,SAAS,EAAEC,OAAO,CAAC;MAChD,CAAAK,cAAA,GAAAR,MAAM,CAACM,MAAM,cAAAE,cAAA,eAAbA,cAAA,CAAAE,IAAA,CAAAV,MAAM,EAAUE,SAAS,EAAEC,OAAO,CAAC;MACnCC,OAAO,GAAG,IAAI;IAChB;EACF,CAAC;EAED,OAAOC,YAAY;AACrB;AAEA,OAAO,SAASM,WAAWA,CAKzBX,MAAS,EAAE,GAAGC,IAA2C,EAAE;EAC3D,MAAM,CAACC,SAAS,EAAEC,OAAO,CAAC,GAAGF,IAAI;EAEjC,IAAIG,OAAO,GAAG,KAAK;EAEnB,MAAMC,YAAY,GAAGL,MAAM,CAACW,WAAW,CAACT,SAAS,EAAEC,OAAO,CAAC,IAAI;IAC7DG,MAAM,EAAEA,CAAA,KAAM;MACZ,IAAIF,OAAO,EAAE;QACX;MACF;MAEAJ,MAAM,CAACS,mBAAmB,CAACP,SAAS,EAAEC,OAAO,CAAC;MAC9CC,OAAO,GAAG,IAAI;IAChB;EACF,CAAC;EAED,OAAOC,YAAY;AACrB","ignoreList":[]}

View File

@@ -0,0 +1,11 @@
import * as React from 'react';
/**
* TypeScript generated a large union of props from `ViewProps` in
* `d.ts` files when using `React.forwardRef`. To prevent this
* `ForwardRefComponent` was created and exported. Use this
* `forwardRef` instead of `React.forwardRef` so you don't have to
* import `ForwardRefComponent`.
* More info: https://github.com/callstack/react-native-paper/pull/3603
*/
export const forwardRef = React.forwardRef;
//# sourceMappingURL=forwardRef.js.map

View File

@@ -0,0 +1 @@
{"version":3,"names":["React","forwardRef"],"sourceRoot":"../../../src","sources":["utils/forwardRef.tsx"],"mappings":"AAAA,OAAO,KAAKA,KAAK,MAAM,OAAO;AAY9B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,MAAMC,UAEiB,GAAGD,KAAK,CAACC,UAAU","ignoreList":[]}

View File

@@ -0,0 +1,8 @@
import color from 'color';
export default function getContrastingColor(input, light, dark) {
if (typeof input === 'string') {
return color(input).isLight() ? dark : light;
}
return light;
}
//# sourceMappingURL=getContrastingColor.js.map

View File

@@ -0,0 +1 @@
{"version":3,"names":["color","getContrastingColor","input","light","dark","isLight"],"sourceRoot":"../../../src","sources":["utils/getContrastingColor.tsx"],"mappings":"AAEA,OAAOA,KAAK,MAAM,OAAO;AAEzB,eAAe,SAASC,mBAAmBA,CACzCC,KAAiB,EACjBC,KAAa,EACbC,IAAY,EACJ;EACR,IAAI,OAAOF,KAAK,KAAK,QAAQ,EAAE;IAC7B,OAAOF,KAAK,CAACE,KAAK,CAAC,CAACG,OAAO,CAAC,CAAC,GAAGD,IAAI,GAAGD,KAAK;EAC9C;EAEA,OAAOA,KAAK;AACd","ignoreList":[]}

View File

@@ -0,0 +1,7 @@
const touchableEvents = ['onPress', 'onLongPress', 'onPressIn', 'onPressOut'];
export default function hasTouchHandler(touchableEventObject) {
return touchableEvents.some(event => {
return Boolean(touchableEventObject[event]);
});
}
//# sourceMappingURL=hasTouchHandler.js.map

View File

@@ -0,0 +1 @@
{"version":3,"names":["touchableEvents","hasTouchHandler","touchableEventObject","some","event","Boolean"],"sourceRoot":"../../../src","sources":["utils/hasTouchHandler.tsx"],"mappings":"AAEA,MAAMA,eAAe,GAAG,CACtB,SAAS,EACT,aAAa,EACb,WAAW,EACX,YAAY,CACJ;AASV,eAAe,SAASC,eAAeA,CACrCC,oBAA0C,EAC1C;EACA,OAAOF,eAAe,CAACG,IAAI,CAAEC,KAAK,IAAK;IACrC,OAAOC,OAAO,CAACH,oBAAoB,CAACE,KAAK,CAAC,CAAC;EAC7C,CAAC,CAAC;AACJ","ignoreList":[]}

View File

@@ -0,0 +1,2 @@
export const roundLayoutSize = size => Math.round(size * 1000) / 1000;
//# sourceMappingURL=roundLayoutSize.js.map

View File

@@ -0,0 +1 @@
{"version":3,"names":["roundLayoutSize","size","Math","round"],"sourceRoot":"../../../src","sources":["utils/roundLayoutSize.ts"],"mappings":"AAAA,OAAO,MAAMA,eAAe,GAAIC,IAAY,IAC1CC,IAAI,CAACC,KAAK,CAACF,IAAI,GAAG,IAAI,CAAC,GAAG,IAAI","ignoreList":[]}

View File

@@ -0,0 +1,44 @@
/**
* Utility function to extract styles in separate objects
*
* @param styles The style object you want to filter
* @param filters The filters by which you want to split the styles
* @returns An array of filtered style objects:
* - The first style object contains the properties that didn't match any filter
* - After that there will be a style object for each filter you passed in the same order as the matching filters
* - A style property will exist in a single style object, the first filter it matched
*/
export function splitStyles(styles, ...filters) {
if (process.env.NODE_ENV !== 'production' && filters.length === 0) {
console.error('No filters were passed when calling splitStyles');
}
// `Object.entries` will be used to iterate over the styles and `Object.fromEntries` will be called before returning
// Entries which match the given filters will be temporarily stored in `newStyles`
const newStyles = filters.map(() => []);
// Entries which match no filter
const rest = [];
// Iterate every style property
outer: for (const item of Object.entries(styles)) {
// Check each filter
for (let i = 0; i < filters.length; i++) {
// Check if filter matches
if (filters[i](item[0])) {
newStyles[i].push(item); // Push to temporary filtered entries array
continue outer; // Skip to checking next style property
}
}
// Adds to rest styles if not filtered
rest.push(item);
}
// Put unmatched styles in the beginning
newStyles.unshift(rest);
// Convert arrays of entries into objects
return newStyles.map(styles => Object.fromEntries(styles));
}
//# sourceMappingURL=splitStyles.js.map

View File

@@ -0,0 +1 @@
{"version":3,"names":["splitStyles","styles","filters","process","env","NODE_ENV","length","console","error","newStyles","map","rest","outer","item","Object","entries","i","push","unshift","fromEntries"],"sourceRoot":"../../../src","sources":["utils/splitStyles.ts"],"mappings":"AAWA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,SAASA,WAAWA,CACzBC,MAAiB,EACjB,GAAGC,OAAc,EACjB;EACA,IAAIC,OAAO,CAACC,GAAG,CAACC,QAAQ,KAAK,YAAY,IAAIH,OAAO,CAACI,MAAM,KAAK,CAAC,EAAE;IACjEC,OAAO,CAACC,KAAK,CAAC,iDAAiD,CAAC;EAClE;;EAEA;EACA;EACA,MAAMC,SAAS,GAAGP,OAAO,CAACQ,GAAG,CAAC,MAAM,EAAa,CAAC;;EAElD;EACA,MAAMC,IAAa,GAAG,EAAE;;EAExB;EACAC,KAAK,EAAE,KAAK,MAAMC,IAAI,IAAIC,MAAM,CAACC,OAAO,CAACd,MAAM,CAAC,EAAa;IAC3D;IACA,KAAK,IAAIe,CAAC,GAAG,CAAC,EAAEA,CAAC,GAAGd,OAAO,CAACI,MAAM,EAAEU,CAAC,EAAE,EAAE;MACvC;MACA,IAAId,OAAO,CAACc,CAAC,CAAC,CAACH,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE;QACvBJ,SAAS,CAACO,CAAC,CAAC,CAACC,IAAI,CAACJ,IAAI,CAAC,CAAC,CAAC;QACzB,SAASD,KAAK,CAAC,CAAC;MAClB;IACF;;IAEA;IACAD,IAAI,CAACM,IAAI,CAACJ,IAAI,CAAC;EACjB;;EAEA;EACAJ,SAAS,CAACS,OAAO,CAACP,IAAI,CAAC;;EAEvB;EACA,OAAOF,SAAS,CAACC,GAAG,CAAET,MAAM,IAAKa,MAAM,CAACK,WAAW,CAAClB,MAAM,CAAC,CAAC;AAI9D","ignoreList":[]}

View File

@@ -0,0 +1,9 @@
import { Animated } from 'react-native';
import useLazyRef from './useLazyRef';
export default function useAnimatedValue(initialValue) {
const {
current
} = useLazyRef(() => new Animated.Value(initialValue));
return current;
}
//# sourceMappingURL=useAnimatedValue.js.map

View File

@@ -0,0 +1 @@
{"version":3,"names":["Animated","useLazyRef","useAnimatedValue","initialValue","current","Value"],"sourceRoot":"../../../src","sources":["utils/useAnimatedValue.tsx"],"mappings":"AAAA,SAASA,QAAQ,QAAQ,cAAc;AAEvC,OAAOC,UAAU,MAAM,cAAc;AAErC,eAAe,SAASC,gBAAgBA,CAACC,YAAoB,EAAE;EAC7D,MAAM;IAAEC;EAAQ,CAAC,GAAGH,UAAU,CAAC,MAAM,IAAID,QAAQ,CAACK,KAAK,CAACF,YAAY,CAAC,CAAC;EAEtE,OAAOC,OAAO;AAChB","ignoreList":[]}

View File

@@ -0,0 +1,11 @@
import * as React from 'react';
import { Animated } from 'react-native';
export default function useAnimatedValueArray(initialValues) {
const refs = React.useRef([]);
refs.current.length = initialValues.length;
initialValues.forEach((initialValue, i) => {
refs.current[i] = refs.current[i] ?? new Animated.Value(initialValue);
});
return refs.current;
}
//# sourceMappingURL=useAnimatedValueArray.js.map

View File

@@ -0,0 +1 @@
{"version":3,"names":["React","Animated","useAnimatedValueArray","initialValues","refs","useRef","current","length","forEach","initialValue","i","Value"],"sourceRoot":"../../../src","sources":["utils/useAnimatedValueArray.tsx"],"mappings":"AAAA,OAAO,KAAKA,KAAK,MAAM,OAAO;AAC9B,SAASC,QAAQ,QAAQ,cAAc;AAEvC,eAAe,SAASC,qBAAqBA,CAACC,aAAuB,EAAE;EACrE,MAAMC,IAAI,GAAGJ,KAAK,CAACK,MAAM,CAAmB,EAAE,CAAC;EAE/CD,IAAI,CAACE,OAAO,CAACC,MAAM,GAAGJ,aAAa,CAACI,MAAM;EAC1CJ,aAAa,CAACK,OAAO,CAAC,CAACC,YAAY,EAAEC,CAAC,KAAK;IACzCN,IAAI,CAACE,OAAO,CAACI,CAAC,CAAC,GAAGN,IAAI,CAACE,OAAO,CAACI,CAAC,CAAC,IAAI,IAAIT,QAAQ,CAACU,KAAK,CAACF,YAAY,CAAC;EACvE,CAAC,CAAC;EAEF,OAAOL,IAAI,CAACE,OAAO;AACrB","ignoreList":[]}

View File

@@ -0,0 +1,52 @@
import * as React from 'react';
import { Keyboard, Platform } from 'react-native';
export default function useIsKeyboardShown({
onShow,
onHide
}) {
React.useEffect(() => {
let willShowSubscription;
let willHideSubscription;
let didShowSubscription;
let didHideSubscription;
if (Platform.OS === 'ios') {
willShowSubscription = Keyboard.addListener('keyboardWillShow', onShow);
willHideSubscription = Keyboard.addListener('keyboardWillHide', onHide);
} else {
didShowSubscription = Keyboard.addListener('keyboardDidShow', onShow);
didHideSubscription = Keyboard.addListener('keyboardDidHide', onHide);
}
return () => {
if (Platform.OS === 'ios') {
var _willShowSubscription, _willHideSubscription;
if ((_willShowSubscription = willShowSubscription) !== null && _willShowSubscription !== void 0 && _willShowSubscription.remove) {
willShowSubscription.remove();
} else {
// @ts-expect-error: We keep deprecated listener remove method for backwards compat with old RN versions
Keyboard.removeListener('keyboardWillShow', onShow);
}
if ((_willHideSubscription = willHideSubscription) !== null && _willHideSubscription !== void 0 && _willHideSubscription.remove) {
willHideSubscription.remove();
} else {
// @ts-expect-error: We keep deprecated listener remove method for backwards compat with old RN versions
Keyboard.removeListener('keyboardWillHide', onHide);
}
} else {
var _didShowSubscription, _didHideSubscription;
if ((_didShowSubscription = didShowSubscription) !== null && _didShowSubscription !== void 0 && _didShowSubscription.remove) {
didShowSubscription.remove();
} else {
// @ts-expect-error: We keep deprecated listener remove method for backwards compat with old RN versions
Keyboard.removeListener('keyboardDidShow', onShow);
}
if ((_didHideSubscription = didHideSubscription) !== null && _didHideSubscription !== void 0 && _didHideSubscription.remove) {
didHideSubscription.remove();
} else {
// @ts-expect-error: We keep deprecated listener remove method for backwards compat with old RN versions
Keyboard.removeListener('keyboardDidHide', onHide);
}
}
};
}, [onHide, onShow]);
}
//# sourceMappingURL=useIsKeyboardShown.js.map

View File

@@ -0,0 +1 @@
{"version":3,"names":["React","Keyboard","Platform","useIsKeyboardShown","onShow","onHide","useEffect","willShowSubscription","willHideSubscription","didShowSubscription","didHideSubscription","OS","addListener","_willShowSubscription","_willHideSubscription","remove","removeListener","_didShowSubscription","_didHideSubscription"],"sourceRoot":"../../../src","sources":["utils/useIsKeyboardShown.tsx"],"mappings":"AAAA,OAAO,KAAKA,KAAK,MAAM,OAAO;AAC9B,SAASC,QAAQ,EAA2BC,QAAQ,QAAQ,cAAc;AAM1E,eAAe,SAASC,kBAAkBA,CAAC;EAAEC,MAAM;EAAEC;AAAc,CAAC,EAAE;EACpEL,KAAK,CAACM,SAAS,CAAC,MAAM;IACpB,IAAIC,oBAAyD;IAC7D,IAAIC,oBAAyD;IAC7D,IAAIC,mBAAwD;IAC5D,IAAIC,mBAAwD;IAE5D,IAAIR,QAAQ,CAACS,EAAE,KAAK,KAAK,EAAE;MACzBJ,oBAAoB,GAAGN,QAAQ,CAACW,WAAW,CAAC,kBAAkB,EAAER,MAAM,CAAC;MACvEI,oBAAoB,GAAGP,QAAQ,CAACW,WAAW,CAAC,kBAAkB,EAAEP,MAAM,CAAC;IACzE,CAAC,MAAM;MACLI,mBAAmB,GAAGR,QAAQ,CAACW,WAAW,CAAC,iBAAiB,EAAER,MAAM,CAAC;MACrEM,mBAAmB,GAAGT,QAAQ,CAACW,WAAW,CAAC,iBAAiB,EAAEP,MAAM,CAAC;IACvE;IAEA,OAAO,MAAM;MACX,IAAIH,QAAQ,CAACS,EAAE,KAAK,KAAK,EAAE;QAAA,IAAAE,qBAAA,EAAAC,qBAAA;QACzB,KAAAD,qBAAA,GAAIN,oBAAoB,cAAAM,qBAAA,eAApBA,qBAAA,CAAsBE,MAAM,EAAE;UAChCR,oBAAoB,CAACQ,MAAM,CAAC,CAAC;QAC/B,CAAC,MAAM;UACL;UACAd,QAAQ,CAACe,cAAc,CAAC,kBAAkB,EAAEZ,MAAM,CAAC;QACrD;QAEA,KAAAU,qBAAA,GAAIN,oBAAoB,cAAAM,qBAAA,eAApBA,qBAAA,CAAsBC,MAAM,EAAE;UAChCP,oBAAoB,CAACO,MAAM,CAAC,CAAC;QAC/B,CAAC,MAAM;UACL;UACAd,QAAQ,CAACe,cAAc,CAAC,kBAAkB,EAAEX,MAAM,CAAC;QACrD;MACF,CAAC,MAAM;QAAA,IAAAY,oBAAA,EAAAC,oBAAA;QACL,KAAAD,oBAAA,GAAIR,mBAAmB,cAAAQ,oBAAA,eAAnBA,oBAAA,CAAqBF,MAAM,EAAE;UAC/BN,mBAAmB,CAACM,MAAM,CAAC,CAAC;QAC9B,CAAC,MAAM;UACL;UACAd,QAAQ,CAACe,cAAc,CAAC,iBAAiB,EAAEZ,MAAM,CAAC;QACpD;QAEA,KAAAc,oBAAA,GAAIR,mBAAmB,cAAAQ,oBAAA,eAAnBA,oBAAA,CAAqBH,MAAM,EAAE;UAC/BL,mBAAmB,CAACK,MAAM,CAAC,CAAC;QAC9B,CAAC,MAAM;UACL;UACAd,QAAQ,CAACe,cAAc,CAAC,iBAAiB,EAAEX,MAAM,CAAC;QACpD;MACF;IACF,CAAC;EACH,CAAC,EAAE,CAACA,MAAM,EAAED,MAAM,CAAC,CAAC;AACtB","ignoreList":[]}

View File

@@ -0,0 +1,24 @@
import * as React from 'react';
export default function useLayout() {
const [layout, setLayout] = React.useState({
height: 0,
width: 0,
measured: false
});
const onLayout = React.useCallback(e => {
const {
height,
width
} = e.nativeEvent.layout;
if (height === layout.height && width === layout.width) {
return;
}
setLayout({
height,
width,
measured: true
});
}, [layout.height, layout.width]);
return [layout, onLayout];
}
//# sourceMappingURL=useLayout.js.map

View File

@@ -0,0 +1 @@
{"version":3,"names":["React","useLayout","layout","setLayout","useState","height","width","measured","onLayout","useCallback","e","nativeEvent"],"sourceRoot":"../../../src","sources":["utils/useLayout.tsx"],"mappings":"AAAA,OAAO,KAAKA,KAAK,MAAM,OAAO;AAG9B,eAAe,SAASC,SAASA,CAAA,EAAG;EAClC,MAAM,CAACC,MAAM,EAAEC,SAAS,CAAC,GAAGH,KAAK,CAACI,QAAQ,CAIvC;IAAEC,MAAM,EAAE,CAAC;IAAEC,KAAK,EAAE,CAAC;IAAEC,QAAQ,EAAE;EAAM,CAAC,CAAC;EAE5C,MAAMC,QAAQ,GAAGR,KAAK,CAACS,WAAW,CAC/BC,CAAoB,IAAK;IACxB,MAAM;MAAEL,MAAM;MAAEC;IAAM,CAAC,GAAGI,CAAC,CAACC,WAAW,CAACT,MAAM;IAE9C,IAAIG,MAAM,KAAKH,MAAM,CAACG,MAAM,IAAIC,KAAK,KAAKJ,MAAM,CAACI,KAAK,EAAE;MACtD;IACF;IAEAH,SAAS,CAAC;MACRE,MAAM;MACNC,KAAK;MACLC,QAAQ,EAAE;IACZ,CAAC,CAAC;EACJ,CAAC,EACD,CAACL,MAAM,CAACG,MAAM,EAAEH,MAAM,CAACI,KAAK,CAC9B,CAAC;EAED,OAAO,CAACJ,MAAM,EAAEM,QAAQ,CAAC;AAC3B","ignoreList":[]}

View File

@@ -0,0 +1,9 @@
import * as React from 'react';
export default function useLazyRef(callback) {
const lazyRef = React.useRef(undefined);
if (lazyRef.current === undefined) {
lazyRef.current = callback();
}
return lazyRef;
}
//# sourceMappingURL=useLazyRef.js.map

View File

@@ -0,0 +1 @@
{"version":3,"names":["React","useLazyRef","callback","lazyRef","useRef","undefined","current"],"sourceRoot":"../../../src","sources":["utils/useLazyRef.tsx"],"mappings":"AAAA,OAAO,KAAKA,KAAK,MAAM,OAAO;AAE9B,eAAe,SAASC,UAAUA,CAAIC,QAAiB,EAAE;EACvD,MAAMC,OAAO,GAAGH,KAAK,CAACI,MAAM,CAAgBC,SAAS,CAAC;EAEtD,IAAIF,OAAO,CAACG,OAAO,KAAKD,SAAS,EAAE;IACjCF,OAAO,CAACG,OAAO,GAAGJ,QAAQ,CAAC,CAAC;EAC9B;EAEA,OAAOC,OAAO;AAChB","ignoreList":[]}