@fto-consult/expo-ui 2.12.6 → 2.12.8
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.
- package/package.json +13 -10
- package/readMe.md +11 -0
- package/src/components/Countries/resources/countries-normalized.json +1987 -1987
- package/src/components/Countries/resources/countries-with-not-extra.json +1211 -1211
- package/src/components/Countries/resources/countries.sql +243 -243
- package/src/components/Datagrid/Common/Common.js +4 -1
- package/src/components/Datagrid/Common/TableData.js +3 -3
- package/src/components/Datagrid/SWRDatagrid.js +49 -13
- package/src/components/Grid/Cell.js +31 -11
- package/src/layouts/Screen/TableData.js +1 -1
- package/src/layouts/Screen/index.js +1 -1
- package/src/media/file-system/exports.js +16 -0
- package/src/media/file-system/index.js +6 -17
- package/src/media/file-system/utils/index.js +3 -1
- package/src/media/file-system/utils/write.js +30 -4
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
// Copyright 2022 @fto-consult/Boris Fouomene. All rights reserved.
|
|
2
2
|
// Use of this source code is governed by a BSD-style
|
|
3
3
|
// license that can be found in the LICENSE file.
|
|
4
|
-
|
|
4
|
+
/****
|
|
5
|
+
* @see : https://swr.vercel.app/examples/infinite-loading
|
|
6
|
+
* @see :
|
|
7
|
+
*/
|
|
5
8
|
import Datagrid from "./IndexComponent";
|
|
6
|
-
import {defaultStr,defaultObj,defaultVal,extendObj} from "$utils";
|
|
9
|
+
import {defaultStr,defaultObj,defaultVal,isObjOrArray,isObj,extendObj} from "$utils";
|
|
7
10
|
import React from "$react";
|
|
8
11
|
import Auth from "$cauth";
|
|
9
12
|
import DateLib from "$lib/date";
|
|
@@ -28,10 +31,14 @@ export const swrOptions = {
|
|
|
28
31
|
errorRetryCount : 5,
|
|
29
32
|
}
|
|
30
33
|
|
|
34
|
+
/****la fonction fetcher doit toujours retourner :
|
|
35
|
+
* 1. la liste des éléments fetchés dans la props data
|
|
36
|
+
* 2. le nombre total d'éléments de la liste obtenue en escluant les clause limit et offset correspondant à la même requête
|
|
37
|
+
*/
|
|
31
38
|
const SWRDatagridComponent = React.forwardRef((props,ref)=>{
|
|
32
39
|
let {
|
|
33
40
|
table,
|
|
34
|
-
data,
|
|
41
|
+
data:customData,
|
|
35
42
|
saveButton,
|
|
36
43
|
title,
|
|
37
44
|
fab,
|
|
@@ -82,9 +89,11 @@ const SWRDatagridComponent = React.forwardRef((props,ref)=>{
|
|
|
82
89
|
title
|
|
83
90
|
},rest.exportTableProps.pdf);
|
|
84
91
|
const fetchOptionsRef = React.useRef({});
|
|
92
|
+
const refreshCBRef = React.useRef(null);
|
|
85
93
|
fetchPath = defaultStr(fetchPath,table.queryPath,tableName.toLowerCase()).trim();
|
|
86
94
|
const innerRef = React.useRef(null);
|
|
87
|
-
|
|
95
|
+
const showProgressRef = React.useRef(true);
|
|
96
|
+
const {data:fetchedData, error, isValidating,size, setSize,isLoading,refresh} = useSWR(fetchPath,{
|
|
88
97
|
fetchOptionsMutator : (opts)=>{
|
|
89
98
|
const {url} = opts;
|
|
90
99
|
const fo = fetchOptionsRef.current;
|
|
@@ -99,32 +108,59 @@ const SWRDatagridComponent = React.forwardRef((props,ref)=>{
|
|
|
99
108
|
...defaultObj(appConfig.swr),
|
|
100
109
|
},
|
|
101
110
|
});
|
|
111
|
+
const fetchedRef = React.useRef(fetchedData);
|
|
112
|
+
const hasResult = !isLoading && !isValidating && isObj(fetchedData) && 'data' in fetchedData;
|
|
113
|
+
if(hasResult){
|
|
114
|
+
fetchedRef.current = fetchedData;
|
|
115
|
+
}
|
|
116
|
+
const data = fetchedRef.current?.data;
|
|
117
|
+
const total = fetchedRef.current?.total;
|
|
102
118
|
React.useEffect(()=>{
|
|
103
119
|
innerRef.current && innerRef.current.setIsLoading && innerRef.current.setIsLoading(isLoading);
|
|
104
120
|
},[isLoading])
|
|
121
|
+
React.useEffect(()=>{
|
|
122
|
+
const cb = refreshCBRef.current;
|
|
123
|
+
refreshCBRef.current = null;
|
|
124
|
+
if(!isValidating && !isLoading && typeof cb =='function'){
|
|
125
|
+
cb();
|
|
126
|
+
}
|
|
127
|
+
},[isValidating,isLoading])
|
|
128
|
+
const doRefresh = (showProgress)=>{
|
|
129
|
+
showProgressRef.current = showProgress ? typeof showProgress ==='boolean' : false;
|
|
130
|
+
refreshCBRef.current = ()=>{
|
|
131
|
+
showProgressRef.current = true;
|
|
132
|
+
};
|
|
133
|
+
refresh();
|
|
134
|
+
}
|
|
105
135
|
React.useEffect(()=>{
|
|
106
136
|
const upsert = cAction.upsert(tableName);
|
|
107
137
|
const remove = cAction.remove(tableName);
|
|
108
|
-
|
|
109
|
-
|
|
138
|
+
const onUpsert = ()=>{
|
|
139
|
+
doRefresh(false);
|
|
140
|
+
}
|
|
141
|
+
APP.on(remove,onUpsert);
|
|
142
|
+
APP.on(upsert,onUpsert);
|
|
110
143
|
return ()=>{
|
|
111
|
-
APP.off(upsert,
|
|
112
|
-
APP.off(remove,
|
|
144
|
+
APP.off(upsert,onUpsert);
|
|
145
|
+
APP.off(remove,onUpsert);
|
|
113
146
|
}
|
|
114
|
-
},[])
|
|
147
|
+
},[]);
|
|
115
148
|
return (
|
|
116
149
|
<Datagrid
|
|
117
150
|
{...rest}
|
|
118
151
|
{...defaultObj(table.datagrid)}
|
|
119
|
-
isLoading = {isLoading|| isValidating}
|
|
152
|
+
isLoading = {isLoading|| isValidating && !error && showProgressRef.current && true || false}
|
|
120
153
|
beforeFetchData = {({fetchOptions:opts})=>{
|
|
121
154
|
opts.fields = fetchFields;
|
|
122
|
-
opts = getFetchOptions({fetcher,...opts});
|
|
155
|
+
opts = getFetchOptions({fetcher,showError:showProgressRef.current,...opts});
|
|
156
|
+
opts.queryParams.withTotal = true;
|
|
123
157
|
fetchOptionsRef.current = opts;
|
|
124
|
-
|
|
158
|
+
doRefresh(true);
|
|
159
|
+
return false;
|
|
125
160
|
}}
|
|
161
|
+
isTableData
|
|
126
162
|
fetchData = {undefined}
|
|
127
|
-
data = {
|
|
163
|
+
data = {data}
|
|
128
164
|
canMakePhoneCall={canMakePhoneCall}
|
|
129
165
|
key={tableName}
|
|
130
166
|
sessionName={defaultStr(sessionName,'list-data')}
|
|
@@ -20,22 +20,42 @@ export const defaultDesktopSize = 4;
|
|
|
20
20
|
|
|
21
21
|
const isV = x=> typeof x =='number' && x && x <= totalSize ? true : false;
|
|
22
22
|
export const getSizeStyle = (props)=>{
|
|
23
|
-
let {size,smallPhoneSize,paddingMultiplicator,phoneSize,marginMultiplicator,mobileSize,tabletSize,gutter,desktopSize
|
|
23
|
+
let {size,smallPhoneSize,paddingMultiplicator,phoneSize,marginMultiplicator,mobileSize,tabletSize,gutter,desktopSize
|
|
24
|
+
,smallPhoneGutter,phoneGutter,mobileGutter,tabletGutter,desktopGutter,
|
|
25
|
+
} = defaultObj(props);
|
|
24
26
|
gutter = gutter === false ? 0 : typeof gutter =='number'? gutter : undefined;
|
|
25
|
-
|
|
26
|
-
|
|
27
|
+
let hasFound = false;
|
|
28
|
+
const isValidSmallSize = isV(smallPhoneSize),
|
|
29
|
+
isValidPhoneSize = isV(phoneSize),
|
|
30
|
+
isValidMobileSize = isV(mobileSize),
|
|
31
|
+
isValidTabletSize = isV(tabletSize),
|
|
32
|
+
isValidDesktopSize = isV(desktopSize);
|
|
33
|
+
if(Dimensions.isSmallPhoneMedia() && isValidSmallSize){
|
|
34
|
+
size = smallPhoneSize;
|
|
35
|
+
if(smallPhoneGutter !== undefined){gutter = smallPhoneGutter;}
|
|
27
36
|
gutter = gutter !== undefined ? gutter : medias.sp;
|
|
28
|
-
|
|
29
|
-
|
|
37
|
+
hasFound = true;
|
|
38
|
+
}
|
|
39
|
+
if(!hasFound && Dimensions.isPhoneMedia() && isValidPhoneSize){
|
|
40
|
+
size = phoneSize;
|
|
41
|
+
if(phoneGutter !== undefined){gutter = phoneGutter;}
|
|
30
42
|
gutter = gutter !== undefined ? gutter : medias.mp;
|
|
31
|
-
|
|
32
|
-
|
|
43
|
+
hasFound = true;
|
|
44
|
+
}
|
|
45
|
+
if(!hasFound && Dimensions.isMobileMedia()){
|
|
46
|
+
size = isValidMobileSize? mobileSize : size || defaultMobileSize;
|
|
47
|
+
if(mobileGutter !== undefined) gutter = mobileGutter;
|
|
33
48
|
gutter = gutter !== undefined ? gutter : medias.xs;
|
|
34
|
-
|
|
35
|
-
|
|
49
|
+
hasFound = true;
|
|
50
|
+
}
|
|
51
|
+
if(!hasFound && Dimensions.isTabletMedia()){
|
|
52
|
+
size = isValidTabletSize ? tabletSize : size || defaultTabletSize;
|
|
53
|
+
if(tabletGutter !== undefined) gutter = tabletGutter;
|
|
36
54
|
gutter = gutter !== undefined ? gutter : medias.sm;
|
|
37
|
-
|
|
38
|
-
|
|
55
|
+
hasFound = true;
|
|
56
|
+
} else if(!hasFound){
|
|
57
|
+
size = isValidDesktopSize ? desktopSize : size || defaultDesktopSize;
|
|
58
|
+
if(desktopGutter !== undefined) gutter = desktopGutter;
|
|
39
59
|
gutter = gutter !== undefined ? gutter : medias.md;
|
|
40
60
|
}
|
|
41
61
|
if(!isV(size)){
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {defaultStr,isNumber,isPromise,defaultVal,extendObj,defaultObj,uniqid,isObj,isObjOrArray} from "$utils";
|
|
2
2
|
import {FormData} from "$ecomponents/Form";
|
|
3
3
|
import FormDataScreen from "./FormData";
|
|
4
|
-
import ScreenContainer from "
|
|
4
|
+
import ScreenContainer from "./Screen";
|
|
5
5
|
import React from "$react";
|
|
6
6
|
import { StyleSheet} from "react-native";
|
|
7
7
|
import ScrollView from "$ecomponents/ScrollView";
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { readAsStringAsync } from "./utils";
|
|
2
|
+
import { loadAsset } from "../Assets/utils";
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
export * from "./utils";
|
|
6
|
+
|
|
7
|
+
export const readFileAsText = async (asset)=>{
|
|
8
|
+
return await new Promise((resolve,reject)=>{
|
|
9
|
+
loadAsset(asset).then((a)=>{
|
|
10
|
+
readAsStringAsync(a.localUri).then((data) => {
|
|
11
|
+
resolve(data);
|
|
12
|
+
}).catch(reject);
|
|
13
|
+
}).catch(reject);
|
|
14
|
+
})
|
|
15
|
+
}
|
|
16
|
+
export const readFile = readFileAsText;
|
|
@@ -1,20 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
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.
|
|
3
4
|
|
|
4
|
-
|
|
5
|
+
import * as FileSystem from "./exports";
|
|
5
6
|
|
|
6
|
-
export
|
|
7
|
-
return await new Promise((resolve,reject)=>{
|
|
8
|
-
loadAsset(asset).then((a)=>{
|
|
9
|
-
readAsStringAsync(a.localUri).then((data) => {
|
|
10
|
-
resolve(data);
|
|
11
|
-
}).catch(reject);
|
|
12
|
-
}).catch(reject);
|
|
13
|
-
})
|
|
14
|
-
}
|
|
15
|
-
export const readFile = readFileAsText;
|
|
7
|
+
export default FileSystem;
|
|
16
8
|
|
|
17
|
-
export
|
|
18
|
-
readFileAsText,
|
|
19
|
-
readFile,
|
|
20
|
-
}
|
|
9
|
+
export * from "./exports";
|
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
// Copyright 2022 @fto-consult/Boris Fouomene. All rights reserved.
|
|
2
2
|
// Use of this source code is governed by a BSD-style
|
|
3
3
|
// license that can be found in the LICENSE file.
|
|
4
|
-
import {defaultStr,isNonNullString,defaultNumber,defaultBool,dataURLToBase64,isBlob,isBase64,isDataURL} from "$utils";
|
|
4
|
+
import {defaultStr,isNonNullString,getFileName,getFileExtension,defaultNumber,defaultBool,dataURLToBase64,isBlob,isBase64,isDataURL} from "$utils";
|
|
5
5
|
const FileSaver = require('file-saver');
|
|
6
6
|
const mime = require('mime-types')
|
|
7
|
+
const XLSX = require("xlsx");
|
|
8
|
+
import Preloader from "$preloader";
|
|
9
|
+
|
|
7
10
|
/**** sauvegarde un fichier sur le disque
|
|
8
11
|
* @param {object} {
|
|
9
12
|
* content {mix}: le contenu du fichier à enregistrer
|
|
@@ -16,9 +19,9 @@ const mime = require('mime-types')
|
|
|
16
19
|
* isBinary : si c'est un fichier binaire
|
|
17
20
|
* }
|
|
18
21
|
*/
|
|
19
|
-
export const write = ({content,type,isBinary,timeout,delay,share,contentType,
|
|
22
|
+
export const write = ({content,type,isBinary,timeout,delay,share,contentType,path,directory,fileName})=>{
|
|
20
23
|
share = defaultBool(share,true);
|
|
21
|
-
fileName = sanitizeFileName(
|
|
24
|
+
fileName = sanitizeFileName(fileName);
|
|
22
25
|
contentType = defaultStr(contentType) || mime.contentType(fileName) || mime.contentType(".txt");
|
|
23
26
|
return new Promise((resolve,reject)=>{
|
|
24
27
|
if(!isNonNullString(fileName)){
|
|
@@ -27,7 +30,7 @@ const mime = require('mime-types')
|
|
|
27
30
|
}
|
|
28
31
|
content = isBlob(content)? content : new Blob(content,contentType);
|
|
29
32
|
try {
|
|
30
|
-
FileSaver.saveAs(
|
|
33
|
+
FileSaver.saveAs(content, fileName);
|
|
31
34
|
setTimeout(() => {
|
|
32
35
|
resolve({path:fileName,isWeb : true});
|
|
33
36
|
}, defaultNumber(timeout,delay,3000));
|
|
@@ -39,4 +42,27 @@ const mime = require('mime-types')
|
|
|
39
42
|
|
|
40
43
|
export const writeText = (args)=>{
|
|
41
44
|
return write({...args,contentType:mime.contentType(".txt")});
|
|
45
|
+
}
|
|
46
|
+
/***
|
|
47
|
+
* @see https://ourtechroom.com/tech/mime-type-for-excel/ for excel mimesTypes
|
|
48
|
+
* .xls : application/vnd.ms-excel
|
|
49
|
+
*/
|
|
50
|
+
export const writeExcel = ({workbook,content,contentType,fileName,...rest})=>{
|
|
51
|
+
if(!isNonNullString(contentType) || !contentType.contains("application/vnd.")){
|
|
52
|
+
//contentType = "application/vnd.ms-excel";
|
|
53
|
+
contentType : "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
|
|
54
|
+
}
|
|
55
|
+
let ext = defaultStr(getFileExtension(fileName,true),"xlsx");
|
|
56
|
+
fileName = sanitizeFileName(getFileName(fileName,true))+"."+ext;
|
|
57
|
+
if(!isNonNullString(fileName)){
|
|
58
|
+
return Promise.reject({status:false,message:'Nom de fichier invalide pour le contenu excel à créer'});
|
|
59
|
+
}
|
|
60
|
+
if(isBlob(content)){
|
|
61
|
+
return write({...rest,content,fileName,contentType})
|
|
62
|
+
}
|
|
63
|
+
Preloader.open("génération du fichier excel "+fileName);
|
|
64
|
+
XLSX.writeFile(workbook, fileName);
|
|
65
|
+
setTimeout(()=>{
|
|
66
|
+
Preloader.close();
|
|
67
|
+
},1000);
|
|
42
68
|
}
|