@fto-consult/expo-ui 2.12.5 → 2.12.7
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 +10 -8
- package/readMe.md +8 -0
- package/src/components/Datagrid/Common/Common.js +4 -1
- package/src/components/Datagrid/Common/TableData.js +3 -3
- package/src/components/Datagrid/SWRDatagrid.js +215 -0
- package/src/components/Datagrid/index.js +3 -1
- 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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fto-consult/expo-ui",
|
|
3
|
-
"version": "2.12.
|
|
3
|
+
"version": "2.12.7",
|
|
4
4
|
"description": "Bibliothèque de composants UI Expo,react-native",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -58,13 +58,9 @@
|
|
|
58
58
|
},
|
|
59
59
|
"homepage": "https://github.com/borispipo/expo-ui#readme",
|
|
60
60
|
"dependencies": {
|
|
61
|
-
"@babel/plugin-proposal-export-namespace-from": "^7.18.9",
|
|
62
|
-
"@babel/preset-react": "^7.18.6",
|
|
63
61
|
"@emotion/native": "^11.10.0",
|
|
64
62
|
"@expo/html-elements": "^0.2.0",
|
|
65
|
-
"@expo/metro-config": "^0.4.0",
|
|
66
63
|
"@expo/vector-icons": "^13.0.0",
|
|
67
|
-
"@expo/webpack-config": "^0.17.2",
|
|
68
64
|
"@fto-consult/common": "^1.20.2",
|
|
69
65
|
"@gorhom/portal": "^1.0.14",
|
|
70
66
|
"@react-native-async-storage/async-storage": "~1.17.3",
|
|
@@ -73,9 +69,6 @@
|
|
|
73
69
|
"@react-navigation/native": "^6.0.13",
|
|
74
70
|
"@react-navigation/native-stack": "^6.9.1",
|
|
75
71
|
"@shopify/flash-list": "1.3.1",
|
|
76
|
-
"babel-plugin-inline-dotenv": "^1.7.0",
|
|
77
|
-
"babel-plugin-module-resolver": "^4.1.0",
|
|
78
|
-
"babel-plugin-transform-inline-environment-variables": "^0.4.4",
|
|
79
72
|
"expo": "^47.0.8",
|
|
80
73
|
"expo-camera": "~13.1.0",
|
|
81
74
|
"expo-clipboard": "~4.0.1",
|
|
@@ -110,5 +103,14 @@
|
|
|
110
103
|
"react-native-webview": "11.23.1",
|
|
111
104
|
"sharp-cli": "^2.1.0",
|
|
112
105
|
"tippy.js": "^6.3.7"
|
|
106
|
+
},
|
|
107
|
+
"devDependencies": {
|
|
108
|
+
"@babel/plugin-proposal-export-namespace-from": "^7.18.9",
|
|
109
|
+
"@babel/preset-react": "^7.18.6",
|
|
110
|
+
"@expo/metro-config": "^0.5.1",
|
|
111
|
+
"@expo/webpack-config": "^0.17.3",
|
|
112
|
+
"babel-plugin-inline-dotenv": "^1.7.0",
|
|
113
|
+
"babel-plugin-module-resolver": "^4.1.0",
|
|
114
|
+
"babel-plugin-transform-inline-environment-variables": "^0.4.4"
|
|
113
115
|
}
|
|
114
116
|
}
|
package/readMe.md
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
Copyright 2022 @fto-consult/Boris Fouomene. All rights reserved.
|
|
3
|
+
Use of this source code is governed by a BSD-style
|
|
4
|
+
license that can be found in the LICENSE file.
|
|
5
|
+
-->
|
|
6
|
+
|
|
7
|
+
## Installation des dépendences, packages de dévéloppement
|
|
8
|
+
npm i --D @babel/plugin-proposal-export-namespace-from @babel/preset-react babel-plugin-inline-dotenv babel-plugin-module-resolver babel-plugin-transform-inline-environment-variables @expo/metro-config @expo/webpack-config
|
|
@@ -839,6 +839,9 @@ export default class CommonDatagridComponent extends AppComponent {
|
|
|
839
839
|
this.setSessionData({showFooters:true})
|
|
840
840
|
})
|
|
841
841
|
}
|
|
842
|
+
setState(a,b){
|
|
843
|
+
super.setState(a,b);
|
|
844
|
+
}
|
|
842
845
|
hideFooter (){
|
|
843
846
|
if(!this._isMounted()) {
|
|
844
847
|
this.isUpdating = false;
|
|
@@ -1513,7 +1516,7 @@ export default class CommonDatagridComponent extends AppComponent {
|
|
|
1513
1516
|
if( typeof this.props.isLoading=='boolean' && nextProps.isLoading !== this.props.isLoading && typeof nextProps.isLoading =='boolean'){
|
|
1514
1517
|
this.setIsLoading(nextProps.isLoading)
|
|
1515
1518
|
}
|
|
1516
|
-
return;
|
|
1519
|
+
return false;
|
|
1517
1520
|
}
|
|
1518
1521
|
this.prepareData({...nextProps,force:true},(state)=>{
|
|
1519
1522
|
this.setState(state)
|
|
@@ -76,9 +76,6 @@ export default class CommonTableDatagrid extends CommonDatagrid{
|
|
|
76
76
|
force = cb;
|
|
77
77
|
cb = undefined;
|
|
78
78
|
}
|
|
79
|
-
if(force !== true && isArray(this.INITIAL_STATE.data)) {
|
|
80
|
-
return this.resolveFetchedDataPromise({cb,data:this.INITIAL_STATE.data}).then(resolve).catch(reject)
|
|
81
|
-
}
|
|
82
79
|
const fetchFilters = this.getFilters();
|
|
83
80
|
fetchOptions = isObj(fetchOptions)?Object.clone(fetchOptions):{};
|
|
84
81
|
fetchOptions.selector = defaultObj(fetchOptions.selector);
|
|
@@ -99,6 +96,9 @@ export default class CommonTableDatagrid extends CommonDatagrid{
|
|
|
99
96
|
this.isFetchingData = false;
|
|
100
97
|
return resolve(this.state.data);
|
|
101
98
|
}
|
|
99
|
+
if(force !== true && isArray(this.INITIAL_STATE.data)) {
|
|
100
|
+
return this.resolveFetchedDataPromise({cb,data:this.INITIAL_STATE.data}).then(resolve).catch(reject)
|
|
101
|
+
}
|
|
102
102
|
let fetchData = this.INITIAL_STATE.fetchData;
|
|
103
103
|
if(isFunction(this.props.fetchData)){
|
|
104
104
|
/**** l'on peut définir la props fetchData, qui est la fonction appelée pour la recherche des données */
|
|
@@ -0,0 +1,215 @@
|
|
|
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
|
+
* @see : https://swr.vercel.app/examples/infinite-loading
|
|
6
|
+
* @see :
|
|
7
|
+
*/
|
|
8
|
+
import Datagrid from "./IndexComponent";
|
|
9
|
+
import {defaultStr,defaultObj,defaultVal,isObjOrArray,isObj,extendObj} from "$utils";
|
|
10
|
+
import React from "$react";
|
|
11
|
+
import Auth from "$cauth";
|
|
12
|
+
import DateLib from "$lib/date";
|
|
13
|
+
import {getFetchOptions} from "$cutils/filters";
|
|
14
|
+
import {setQueryParams} from "$cutils/uri";
|
|
15
|
+
import Icon from "$ecomponents/Icon";
|
|
16
|
+
import Label from "$ecomponents/Label";
|
|
17
|
+
import { StyleSheet,View } from "react-native";
|
|
18
|
+
import theme from "$theme";
|
|
19
|
+
import useSWR,{useInfinite} from "$swr";
|
|
20
|
+
import appConfig from "$capp/config";
|
|
21
|
+
import APP from "$capp/instance";
|
|
22
|
+
import cAction from "$cactions";
|
|
23
|
+
import PropTypes from "prop-types";
|
|
24
|
+
|
|
25
|
+
const timeout = 5000*60*60;
|
|
26
|
+
export const swrOptions = {
|
|
27
|
+
refreshInterval : timeout, //5 minutes
|
|
28
|
+
shouldRetryOnError : false, //retry when fetcher has an error
|
|
29
|
+
dedupingInterval : timeout,
|
|
30
|
+
errorRetryInterval : timeout*2,
|
|
31
|
+
errorRetryCount : 5,
|
|
32
|
+
}
|
|
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
|
+
*/
|
|
38
|
+
const SWRDatagridComponent = React.forwardRef((props,ref)=>{
|
|
39
|
+
let {
|
|
40
|
+
table,
|
|
41
|
+
data:customData,
|
|
42
|
+
saveButton,
|
|
43
|
+
title,
|
|
44
|
+
fab,
|
|
45
|
+
rowKey,
|
|
46
|
+
actions,
|
|
47
|
+
sessionName,
|
|
48
|
+
server,
|
|
49
|
+
columns,
|
|
50
|
+
canMakePhoneCall,
|
|
51
|
+
makePhoneCallProps,
|
|
52
|
+
fetchData,
|
|
53
|
+
fetchPath,
|
|
54
|
+
fetcher,
|
|
55
|
+
...rest
|
|
56
|
+
} = props;
|
|
57
|
+
rest = defaultObj(rest);
|
|
58
|
+
rest.exportTableProps = defaultObj(rest.exportTableProps)
|
|
59
|
+
const tableName = defaultStr(table.tableName,table.table).trim().toUpperCase();
|
|
60
|
+
canMakePhoneCall = defaultBool(canMakePhoneCall,table.canMakePhoneCall);
|
|
61
|
+
makePhoneCallProps = defaultObj(makePhoneCallProps,rest.makePhoneCallProps,table.makePhoneCallProps);
|
|
62
|
+
const isExportable = !!Auth.isTableDataAllowed({table:tableName,action:'export'});
|
|
63
|
+
rest.exportable = isExportable;
|
|
64
|
+
rowKey = defaultStr(rowKey,table.rowKey,table.primaryKeyColumnName);
|
|
65
|
+
title = defaultStr(title,table.label,table.text)
|
|
66
|
+
columns = table.fields;
|
|
67
|
+
const fetchFields = [];
|
|
68
|
+
Object.map(columns,(column,i)=>{
|
|
69
|
+
if(isObj(column)){
|
|
70
|
+
fetchFields.push(defaultStr(column.field,i));
|
|
71
|
+
}
|
|
72
|
+
})
|
|
73
|
+
actions = defaultVal(table.actions,actions);
|
|
74
|
+
for(let i in Datagrid.propTypes){
|
|
75
|
+
if(i in table){
|
|
76
|
+
rest[i] = isObj(rest[i])? extendObj(true,{},rest[i],table[i]) : table[i];
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
rest.actions = actions;
|
|
80
|
+
rest.columns = columns || [];
|
|
81
|
+
const icon = defaultStr(table.icon);
|
|
82
|
+
rest.tableName = tableName;
|
|
83
|
+
rest.canMakePhoneCall = canMakePhoneCall;
|
|
84
|
+
rest.makePhoneCallProps = makePhoneCallProps;
|
|
85
|
+
rest.exportTableProps.fileName = defaultStr(rest.exportTableProps.fileName,title+"-"+DateLib.format(DateLib.toObj(),'dd-mm-yyyy HH-MM'))
|
|
86
|
+
rest.exportTableProps.pdf = defaultObj(rest.exportTableProps.pdf);
|
|
87
|
+
rest.exportTableProps.pdf = extendObj(true,{},{
|
|
88
|
+
fileName : rest.exportTableProps.fileName,
|
|
89
|
+
title
|
|
90
|
+
},rest.exportTableProps.pdf);
|
|
91
|
+
const fetchOptionsRef = React.useRef({});
|
|
92
|
+
const refreshCBRef = React.useRef(null);
|
|
93
|
+
fetchPath = defaultStr(fetchPath,table.queryPath,tableName.toLowerCase()).trim();
|
|
94
|
+
const innerRef = React.useRef(null);
|
|
95
|
+
const showProgressRef = React.useRef(true);
|
|
96
|
+
const {data:fetchedData, error, isValidating,size, setSize,isLoading,refresh} = useSWR(fetchPath,{
|
|
97
|
+
fetchOptionsMutator : (opts)=>{
|
|
98
|
+
const {url} = opts;
|
|
99
|
+
const fo = fetchOptionsRef.current;
|
|
100
|
+
if(Object.size(fo.queryParams,true)){
|
|
101
|
+
return {url : setQueryParams(url,fo.queryParams)};
|
|
102
|
+
}
|
|
103
|
+
},
|
|
104
|
+
fetcher,
|
|
105
|
+
showError : false,
|
|
106
|
+
swrOptions : {
|
|
107
|
+
...swrOptions,
|
|
108
|
+
...defaultObj(appConfig.swr),
|
|
109
|
+
},
|
|
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;
|
|
118
|
+
React.useEffect(()=>{
|
|
119
|
+
innerRef.current && innerRef.current.setIsLoading && innerRef.current.setIsLoading(isLoading);
|
|
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
|
+
}
|
|
135
|
+
React.useEffect(()=>{
|
|
136
|
+
const upsert = cAction.upsert(tableName);
|
|
137
|
+
const remove = cAction.remove(tableName);
|
|
138
|
+
const onUpsert = ()=>{
|
|
139
|
+
doRefresh(false);
|
|
140
|
+
}
|
|
141
|
+
APP.on(remove,onUpsert);
|
|
142
|
+
APP.on(upsert,onUpsert);
|
|
143
|
+
return ()=>{
|
|
144
|
+
APP.off(upsert,onUpsert);
|
|
145
|
+
APP.off(remove,onUpsert);
|
|
146
|
+
}
|
|
147
|
+
},[]);
|
|
148
|
+
return (
|
|
149
|
+
<Datagrid
|
|
150
|
+
{...rest}
|
|
151
|
+
{...defaultObj(table.datagrid)}
|
|
152
|
+
isLoading = {isLoading|| isValidating && !error && showProgressRef.current && true || false}
|
|
153
|
+
beforeFetchData = {({fetchOptions:opts})=>{
|
|
154
|
+
opts.fields = fetchFields;
|
|
155
|
+
opts = getFetchOptions({fetcher,showError:showProgressRef.current,...opts});
|
|
156
|
+
opts.queryParams.withTotal = true;
|
|
157
|
+
fetchOptionsRef.current = opts;
|
|
158
|
+
doRefresh(true);
|
|
159
|
+
return false;
|
|
160
|
+
}}
|
|
161
|
+
isTableData
|
|
162
|
+
fetchData = {undefined}
|
|
163
|
+
data = {data}
|
|
164
|
+
canMakePhoneCall={canMakePhoneCall}
|
|
165
|
+
key={tableName}
|
|
166
|
+
sessionName={defaultStr(sessionName,'list-data')}
|
|
167
|
+
ref={React.useMergeRefs(ref,innerRef)}
|
|
168
|
+
rowKey={rowKey}
|
|
169
|
+
renderEmpty = {(p)=>{
|
|
170
|
+
return <View style={styles.emptyAccordion}>
|
|
171
|
+
{icon ? <Icon name={icon} color={theme.colors.primaryOnSurface} size={80}/> : null}
|
|
172
|
+
{<Label secondary style={styles.labelTitle}>{title}</Label>}
|
|
173
|
+
<Label style={[styles.emptyText]}>
|
|
174
|
+
{"Aucune données enrégistrée!!"}
|
|
175
|
+
</Label>
|
|
176
|
+
</View>
|
|
177
|
+
}}
|
|
178
|
+
/>
|
|
179
|
+
)
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
export default SWRDatagridComponent;
|
|
183
|
+
|
|
184
|
+
SWRDatagridComponent.displayName = "SWRDatagridComponent";
|
|
185
|
+
|
|
186
|
+
SWRDatagridComponent.propTypes = {
|
|
187
|
+
...Datagrid.propTypes,
|
|
188
|
+
fetchPath : PropTypes.string,
|
|
189
|
+
fetchData : PropTypes.func,
|
|
190
|
+
table : PropTypes.shape({
|
|
191
|
+
tableName : PropTypes.string,
|
|
192
|
+
table : PropTypes.string,
|
|
193
|
+
fields : PropTypes.oneOfType([
|
|
194
|
+
PropTypes.objectOf(PropTypes.object),
|
|
195
|
+
PropTypes.arrayOf(PropTypes.object),
|
|
196
|
+
])
|
|
197
|
+
}).isRequired,
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
const styles = StyleSheet.create({
|
|
201
|
+
emptyAccordion : {
|
|
202
|
+
alignSelf : 'center',
|
|
203
|
+
alignItems:'center'
|
|
204
|
+
},
|
|
205
|
+
labelTitle: {
|
|
206
|
+
fontSize : 18,
|
|
207
|
+
},
|
|
208
|
+
emptyText : {
|
|
209
|
+
fontSize : 16,
|
|
210
|
+
fontWeight : 'bold',
|
|
211
|
+
flexWrap : 'wrap',
|
|
212
|
+
marginVertical : 10,
|
|
213
|
+
textAlign : 'center'
|
|
214
|
+
}
|
|
215
|
+
})
|
|
@@ -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";
|