@fto-consult/expo-ui 8.19.2 → 8.20.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -77,5 +77,6 @@ module.exports = (opts)=>{
77
77
  r.$electronProjectRoot = path.resolve(r.$projectRoot,"electron");
78
78
  r.$econtext = path.resolve(expo,"context");
79
79
  r.$epdf = path.resolve(expo,"pdf");
80
+ r.$session = path.resolve(expo,"session");
80
81
  return r;
81
82
  }
@@ -24,7 +24,6 @@ module.exports = {
24
24
  "expo-web-browser": "~12.8.2",
25
25
  "react":"18.2.0",
26
26
  "react-native": "0.73.2",
27
- "@react-native-async-storage/async-storage": "1.21.0",
28
27
  "react-native-safe-area-context": "4.8.2",
29
28
  "react-native-screens": "~3.29.0",
30
29
  "react-native-svg": "14.1.0",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fto-consult/expo-ui",
3
- "version": "8.19.2",
3
+ "version": "8.20.0",
4
4
  "description": "Bibliothèque de composants UI Expo,react-native",
5
5
  "scripts": {
6
6
  "clear-npx-cache": "npx clear-npx-cache",
@@ -69,7 +69,7 @@
69
69
  "dependencies": {
70
70
  "@emotion/react": "^11.11.1",
71
71
  "@faker-js/faker": "^8.0.2",
72
- "@fto-consult/common": "^4.19.4",
72
+ "@fto-consult/common": "^4.20.0",
73
73
  "@fto-consult/node-utils": "^1.4.7",
74
74
  "apexcharts": "^3.45.2",
75
75
  "crypto-browserify": "^3.12.0",
package/src/App.js CHANGED
@@ -1,3 +1,5 @@
1
+ import session from "$session";
2
+ import {useState,useEffect} from "$react";
1
3
  import Provider from "$econtext/Provider";
2
4
  import App from "./AppEntry";
3
5
  /****
@@ -14,7 +16,18 @@ import App from "./AppEntry";
14
16
  */
15
17
 
16
18
  export default function ExpoUIAppEntryProvider({children,init,...rest}){
17
- return <Provider {...rest}>
18
- <App init={init} children={children}/>
19
- </Provider>
19
+ const [children,setChildren] = useState(null);
20
+ useEffect(()=>{
21
+ const end = ()=>{
22
+ setChildren(<Provider {...rest}>
23
+ <App init={init} children={children}/>
24
+ </Provider>);
25
+ };
26
+ if(typeof session?.init =="function"){
27
+ return Promise.resolve(init).finally(end);
28
+ } else {
29
+ end();
30
+ }
31
+ },[]);
32
+ return children;
20
33
  }
@@ -25,7 +25,6 @@ import notify from "$cnotify";
25
25
  import {showPrompt} from "$ecomponents/Dialog/confirm";
26
26
  import {SWRConfig} from "$swr";
27
27
  import {Keyboard } from 'react-native';
28
- import initSQLite from "./init-sqlite";
29
28
 
30
29
  Object.map(Utils,(v,i)=>{
31
30
  if(typeof v =='function' && typeof window !='undefined' && window && !window[i]){
@@ -305,9 +304,7 @@ const Provider = ({children,getTableData,handleHelpScreen,navigation,swrConfig,a
305
304
  });
306
305
  return [...r,...getMainScreens(handleHelpScreen)];
307
306
  },[]);
308
- const {linking} = navigation;
309
307
  React.useEffect(()=>{
310
- initSQLite();
311
308
  const onScreenFocus = ({sanitizedName})=>{
312
309
  if(activeScreenRef.current){
313
310
  screensRef.current[activeScreenRef.current] = null;
@@ -0,0 +1,2 @@
1
+ export * from "$csession";
2
+ export {default} from "$csession";
@@ -0,0 +1,163 @@
1
+ import * as SQLite from 'expo-sqlite/next';
2
+ import {isDev} from "$cplatform";
3
+ import appConfig from "$capp/config";
4
+ import {sanitizeFileName,isNonNullString,isObj,defaultObj} from "$cutils";
5
+ import {sanitizeKey as cSanitizeKey,handleGetValue,handleSetValue} from "$csession/utils";
6
+ import * as FileSystem from 'expo-file-system';
7
+
8
+ export const SESSION_TABLE = "SESSION";
9
+
10
+ const debug = (...args)=>{
11
+ if(!isDev()) return;
12
+ return console.log(...args);
13
+ }
14
+
15
+ export class SQLiteSession {
16
+ constructor () {
17
+ this.hasInit = false
18
+ this.db = null
19
+ this.data = new Map();
20
+ }
21
+ getDBName(){
22
+ let appName = appConfig.name;
23
+ const suffix = "sqlite-sessname";
24
+ if(isNonNullString(appName)){
25
+ appName = sanitizeFileName(appName.replaceAll("\\","/").replaceAll("\\","")).replace(/\s+/g, "").trim();
26
+ return `${appName}-${suffix}`;
27
+ }
28
+ return `${suffix}`;
29
+ }
30
+
31
+ sanitizeKey (key) {
32
+ if(!isNonNullString(key)) return "";
33
+ return sanitizeFileName(cSanitizeKey(key)).replace(/\s+/g, "").trim();
34
+ }
35
+ async init () {
36
+ if (!this.db || !this.hasInit) {
37
+ const dbName = this.getDBName();
38
+ debug(`Opening sqlite database ${dbName} for session storage`);
39
+ if(!this.openingPromise){
40
+ this.openingPromise = SQLite.openDatabaseAsync(dbName).then((db)=>{
41
+ return db.execAsync(`
42
+ CREATE TABLE IF NOT EXISTS ${SESSION_TABLE} (id INTEGER PRIMARY KEY NOT NULL, key TEXT, value TEXT);
43
+ `).then((d)=>{
44
+ this.db = db;
45
+ this.hasInit = true;
46
+ this.getAll();
47
+ }).catch((e)=>{
48
+ debug(e," error when initializing sqlite session");
49
+ throw e;
50
+ });
51
+ }).finally(()=>{
52
+ delete this.openingPromise;
53
+ });;
54
+ }
55
+ return this.openingPromise;
56
+ }
57
+ return Promise.resolve(true);
58
+ }
59
+ get(key){
60
+ key = this.sanitizeKey(key);
61
+ if(!key) return undefined;
62
+ return defaultObj(this.data.get(key)).value;
63
+ }
64
+ async getAsync (key,callback) {
65
+ key = this.sanitizeKey(key);
66
+ if(!key) return undefined;
67
+ await this.init()
68
+ const resp = await this.db.getFirstAsync(`SELECT value FROM ${SESSION_TABLE} WHERE key = ? `,key)
69
+ if (!resp) {
70
+ if(typeof callback =='function'){
71
+ callback(undefined);
72
+ }
73
+ return undefined;
74
+ }
75
+ const r = handleGetValue(resp?.value);
76
+ if(typeof callback =='function'){
77
+ callback(r);
78
+ }
79
+ return r;
80
+ }
81
+
82
+ async set (key,value) {
83
+ key = this.sanitizeKey(key);
84
+ if (!key) return undefined;
85
+ const toUpdate = {...defaultObj(this.data.get(key)),value};
86
+ this.data.set(key,toUpdate);
87
+ const isUpdate = "id" in toUpdate && !!String(toUpdate.id) || false;
88
+ value = handleSetValue(value,true);
89
+ try {
90
+ await this.init();
91
+ const params = {$key: key,$value:value};
92
+ if(isUpdate){
93
+ params.$id = toUpdate.id;
94
+ }
95
+ const statement = await this.db.prepareAsync(isUpdate ? `UPDATE ${SESSION_TABLE} SET value = $value WHERE id = $id` : `INSERT INTO ${SESSION_TABLE}(key,value) VALUES ($key,$value)`);
96
+ try {
97
+ const result = await statement.executeAsync(params)
98
+ if(!isUpdate && result.lastInsertRowId){
99
+ toUpdate.id = result.lastInsertRowId;
100
+ this.data.set(key,toUpdate);
101
+ }
102
+ } finally {
103
+ await statement.finalizeAsync();
104
+ }
105
+ } catch(e){
106
+ debug(e," error on inserting session data");
107
+ }
108
+ return;
109
+ }
110
+ async remove (key) {
111
+ key = this.sanitizeKey(key);
112
+ if (!key) return false;
113
+ this.data.delete(key);
114
+ await this.init();
115
+ debug(`removing session: ${key}`)
116
+ return await this.db.runAsync(SQL`DELETE FROM sessions WHERE key = ?`,key);
117
+ }
118
+ async getAll () {
119
+ if(!this.hasInit || !this.db) return {};
120
+ const data = await this.db.getAllAsync(`SELECT * FROM ${SESSION_TABLE}`);
121
+ debug("getting all sql session");
122
+ this.data.clear();
123
+ return data.map(({key,id,value})=>{
124
+ value = handleGetValue(value);
125
+ this.data.set(key,{id,value});
126
+ });
127
+ }
128
+ async length () {
129
+ await this.init()
130
+ const data = await this.db.getFirstAsync(`SELECT count(*) as total FROM ${SESSION_TABLE}`)
131
+ return data.total
132
+ }
133
+
134
+ async clearAll () {
135
+ await this.init()
136
+ debug(`Clearing all sessions`)
137
+ this.data.clear();
138
+ return await this.db.runAsync(`DELETE FROM ${SESSION_TABLE}`);
139
+ }
140
+ }
141
+
142
+ export function initSQLite (){
143
+ return new Promise((resolve,reject)=>{
144
+ const createD = ()=>{
145
+ return FileSystem.makeDirectoryAsync(FileSystem.documentDirectory + 'SQLite').then(resolve).catch(e=>{
146
+ resolve(null);
147
+ });
148
+ };
149
+ FileSystem.getInfoAsync(FileSystem.documentDirectory + 'SQLite').then((info)=>{
150
+ if(!info?.exists){
151
+ return createD();
152
+ }
153
+ resolve(info);
154
+ return info;
155
+ }).catch(createD);
156
+ })
157
+ }
158
+
159
+ const sqliteSession = new SQLiteSession();
160
+ sqliteSession.init();
161
+ initSQLite();
162
+
163
+ export default sqliteSession;
@@ -0,0 +1,14 @@
1
+ // Copyright 2022 @fto-consult/Boris Fouomene. All rights reserved.
2
+ // Use of this source code is governed by a BSD-style
3
+ // license that can be found in the LICENSE file.
4
+
5
+ export const handleError= function (func, param) {
6
+ let message;
7
+ if (!param) {
8
+ message = func;
9
+ } else {
10
+ message = `${func}() requires at least ${param} as its first parameter.`;
11
+ }
12
+ console.warn(message); // eslint-disable-line no-console
13
+ return Promise.reject(message);
14
+ }
@@ -0,0 +1,37 @@
1
+ // Copyright 2022 @fto-consult/Boris Fouomene. All rights reserved.
2
+ // Use of this source code is governed by a BSD-style
3
+ // license that can be found in the LICENSE file.
4
+
5
+ /*** for usage, @see : https://github.com/raphaelpor/sync-storage
6
+ @see : https://github.com/echowaves/expo-storage
7
+ */
8
+ import { MMKV } from 'react-native-mmkv'
9
+ import {handleError} from './helpers';
10
+ import {stringify} from "$cutils/json";
11
+ import { sanitizeKey } from '../../../../common/src/session/utils';
12
+
13
+ export const storage = new MMKV();
14
+
15
+ export const get = (key)=> {
16
+ return storage.get(sanitizeKey(key));
17
+ }
18
+
19
+ export const set = (key, value)=> {
20
+ key = sanitizeKey(key);
21
+ if (!key) return handleError('set', `a key`);
22
+ storage.set(key, value);
23
+ value = stringify(value);
24
+ return storage.set(key, value).then((v)=>{return {[key]:value}});
25
+ }
26
+
27
+ export const remove = (key)=> {
28
+ key = sanitizeKey(key);
29
+ if (!key) return handleError('remove', 'a key');
30
+ return storage.delete(key);
31
+ }
32
+ export const clearAll = storage.clearAll;
33
+ export const removeAll = storage.clearAll;
34
+
35
+ export {MMKV};
36
+
37
+ export default {...storage,set,get,remove,clearAll,removeAll};
@@ -0,0 +1,60 @@
1
+ // Copyright 2022 @fto-consult/Boris Fouomene. All rights reserved.
2
+ // Use of this source code is governed by a BSD-style
3
+ // license that can be found in the LICENSE file.
4
+
5
+ import {handleError} from './helpers';
6
+ import {stringify,isJSON,parseJSON} from "$cutils/json";
7
+ import {sanitizeFileName} from "$cutils";
8
+ import isPromise from "$cutils/isPromise";
9
+ import { sanitizeKey } from '../../../../common/src/session/utils';
10
+ import * as FileSystem from 'expo-file-system';
11
+
12
+ export class Storage {
13
+ data = new Map();
14
+ currentPromise = null;
15
+ getPath(){
16
+ const appName = require("$packageJSON").name;
17
+ return `${FileSystem.documentDirectory}${appName?`${sanitizeFileName(appName).toLowerCase().trim()}.session`:"session"}`;
18
+ }
19
+ init() {
20
+ if(isPromise(this.currentPromise)) return this.currentPromise;
21
+ this.currentPromise = FileSystem.readAsStringAsync(`${this.getPath()}`).then((its)=>{
22
+ if(isJSON(its)){
23
+ this.data = new Map(parseJSON(its));
24
+ }
25
+ return this.data;
26
+ }).catch(e=>{});
27
+ return this.currentPromise;
28
+ }
29
+ get(key) {
30
+ return this.data.get(sanitizeKey(key));
31
+ }
32
+ persist(){
33
+ return FileSystem.writeAsStringAsync(this.getPath(), stringify(Array.from(this.data.entries())));
34
+ }
35
+ set(key, value) {
36
+ key = sanitizeKey(key);
37
+ if (!key) return handleError('set', 'a key');
38
+ this.data.set(key, value);
39
+ return this.persist();
40
+ }
41
+ remove(key) {
42
+ key = sanitizeKey(key);
43
+ if (!key) return handleError('remove', 'a key');
44
+ this.data.delete(key);
45
+ return this.persist();
46
+ }
47
+ getAllKeysSync(){
48
+ return Array.from(this.data.keys());
49
+ }
50
+ getItem(key){
51
+ return FileSystem.readAsStringAsync(`${this.getPath()}${key}`);
52
+ }
53
+ }
54
+
55
+
56
+ const storage = new Storage();
57
+
58
+ storage.init();
59
+
60
+ export default storage;
@@ -0,0 +1,79 @@
1
+ // Copyright 2022 @fto-consult/Boris Fouomene. All rights reserved.
2
+ // Use of this source code is governed by a BSD-style
3
+ // license that can be found in the LICENSE file.
4
+
5
+ /*** for usage, @see : https://github.com/raphaelpor/sync-storage
6
+ @see : https://github.com/echowaves/expo-storage
7
+ */
8
+ import AsyncStorage from '@react-native-async-storage/async-storage';
9
+ import isPromise from "$cutils/isPromise";
10
+ import {handleError} from './helpers';
11
+ import {stringify} from "$cutils/json";
12
+ import { sanitizeKey } from '../utils';
13
+
14
+ let currentInitSession = undefined;
15
+
16
+ export const isInitialized = x=> isPromise(currentInitSession);
17
+
18
+ class SyncAsyncStorage {
19
+ data = new Map();
20
+ loading = true;
21
+
22
+ init() {
23
+ if(isInitialized()){
24
+ return currentInitSession;
25
+ }
26
+ currentInitSession = AsyncStorage.getAllKeys().then((keys) =>
27
+ AsyncStorage.multiGet(keys).then((data) => {
28
+ data.forEach(this.saveItem.bind(this));
29
+ this.isInitialized = true;
30
+ return [...this.data];
31
+ }),
32
+ );
33
+ return currentInitSession;
34
+ }
35
+
36
+ get(key) {
37
+ return this.data.get(sanitizeKey(key));
38
+ }
39
+
40
+ set(key, value) {
41
+ key = sanitizeKey(key);
42
+ if (!key) return handleError('set', 'a key');
43
+ this.data.set(key, value);
44
+ value = stringify(value);
45
+ return AsyncStorage.setItem(key, value).then((v)=>{return {[key]:value}});
46
+ }
47
+
48
+ remove(key) {
49
+ key = sanitizeKey(key);
50
+ if (!key) return handleError('remove', 'a key');
51
+
52
+ this.data.delete(key);
53
+ return AsyncStorage.removeItem(key);
54
+ }
55
+
56
+ saveItem(item) {
57
+ let value;
58
+
59
+ try {
60
+ value = JSON.parse(item[1]);
61
+ } catch (e) {
62
+ [, value] = item;
63
+ }
64
+
65
+ this.data.set(item[0], value);
66
+ this.loading = false;
67
+ }
68
+
69
+ getAllKeys(){
70
+ return Array.from(this.data.keys());
71
+ }
72
+ }
73
+
74
+
75
+ const syncAsyncStorage = new SyncAsyncStorage();
76
+
77
+ syncAsyncStorage.init();
78
+
79
+ export default syncAsyncStorage;
@@ -0,0 +1,14 @@
1
+ // Copyright 2022 @fto-consult/Boris Fouomene. All rights reserved.
2
+ // Use of this source code is governed by a BSD-style
3
+ // license that can be found in the LICENSE file.
4
+
5
+ import { handleGetValue,handleSetValue } from './utils'
6
+ import storage from "./native";
7
+ const get = key => handleGetValue(storage.get(key))
8
+ const set = (key,value,decycle)=>{
9
+ return Promise.resolve(storage.set(key,handleSetValue(value,decycle)));
10
+ }
11
+
12
+ export default {get,set};
13
+
14
+ export {get,set}
@@ -1,2 +0,0 @@
1
- export default function initSQLite(){
2
- }
@@ -1,9 +0,0 @@
1
- import * as FileSystem from 'expo-file-system';
2
- export default function initSQLite (){
3
- const createD = ()=>FileSystem.makeDirectoryAsync(FileSystem.documentDirectory + 'SQLite').catch(e=>{});
4
- return FileSystem.getInfoAsync(FileSystem.documentDirectory + 'SQLite').then((info)=>{
5
- if(!info?.exists){
6
- createD();
7
- }
8
- }).catch(createD);
9
- }