@fto-consult/expo-ui 6.26.3 → 6.26.4
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 +2 -2
- package/src/components/Datagrid/Accordion/Filters.js +36 -38
- package/src/components/Datagrid/Common/Common.js +5 -2
- package/src/components/Datagrid/SWRDatagrid.js +22 -53
- package/src/components/Filter/index.js +1 -0
- package/src/components/Form/Fields/Field.js +3 -2
- package/src/components/Form/Fields/IdField.js +38 -28
- package/src/components/Form/FormData/componentsTypes.js +11 -4
- package/src/components/Table/index.js +2 -2
- package/src/components/TextField/index.js +1 -0
- package/src/context/hooks.js +1 -2
- package/src/context/query.js +92 -0
- package/src/screens/Help/openLibraries.js +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fto-consult/expo-ui",
|
|
3
|
-
"version": "6.26.
|
|
3
|
+
"version": "6.26.4",
|
|
4
4
|
"description": "Bibliothèque de composants UI Expo,react-native",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -68,7 +68,7 @@
|
|
|
68
68
|
"@expo/html-elements": "^0.5.1",
|
|
69
69
|
"@expo/vector-icons": "^13.0.0",
|
|
70
70
|
"@faker-js/faker": "^8.0.2",
|
|
71
|
-
"@fto-consult/common": "^3.
|
|
71
|
+
"@fto-consult/common": "^3.29.1",
|
|
72
72
|
"@gorhom/portal": "^1.0.14",
|
|
73
73
|
"@pchmn/expo-material3-theme": "^1.3.1",
|
|
74
74
|
"@react-native-async-storage/async-storage": "1.18.2",
|
|
@@ -2,7 +2,7 @@ import {Content} from "$ecomponents/BottomSheet";
|
|
|
2
2
|
import Icon from "$ecomponents/Icon";
|
|
3
3
|
import React from "$react";
|
|
4
4
|
import {defaultStr,defaultBool,defaultObj} from "$cutils";
|
|
5
|
-
import Filter, {canHandleFilter
|
|
5
|
+
import Filter, {canHandleFilter} from "$ecomponents/Filter";
|
|
6
6
|
import PropTypes from "prop-types";
|
|
7
7
|
import { StyleSheet,View } from "react-native";
|
|
8
8
|
import Menu from "$ecomponents/Menu";
|
|
@@ -18,16 +18,14 @@ const MIN_WIDTH = 250;
|
|
|
18
18
|
let windowWidth = Dimensions.get("window").width;
|
|
19
19
|
|
|
20
20
|
const FiltersAccordionComponent = React.forwardRef((props,ref)=>{
|
|
21
|
-
const {filters,isLoading,filteredColumns,children,label,filterTitle:customFilterTitle,visible:customVisible,orOperator,andOperator,onToggleFilters,context:customContext,...restProps} = props;
|
|
21
|
+
const {filters,isLoading,filteredColumns,children,label,testID:cTestID,filterTitle:customFilterTitle,visible:customVisible,orOperator,andOperator,onToggleFilters,context:customContext,...restProps} = props;
|
|
22
22
|
const context = defaultObj(customContext);
|
|
23
|
-
const
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
});
|
|
23
|
+
const testID = defaultStr(testID,"RN_AccordionFilters");
|
|
24
|
+
const [visibleColumns,setVisibleColumns] = React.useState(filteredColumns);
|
|
25
|
+
const [visible,setVisible] = React.useState(defaultBool(customVisible,false));
|
|
27
26
|
const valuesRefs = React.useRef({});
|
|
28
27
|
windowWidth = Dimensions.get("window").width;
|
|
29
28
|
const innerRef = React.useRef(null);
|
|
30
|
-
const {visible,visibleColumns} = state;
|
|
31
29
|
const rest = defaultObj(restProps);
|
|
32
30
|
const filterTitle = defaultStr(customFilterTitle,'Filtres');
|
|
33
31
|
const canHandlerFilterRef = React.useRef(0);
|
|
@@ -50,8 +48,8 @@ const FiltersAccordionComponent = React.forwardRef((props,ref)=>{
|
|
|
50
48
|
if(React.isValidElement(filter)){
|
|
51
49
|
content.push(<Grid.Cell {...cellProps} key={index}>{filter}</Grid.Cell>)
|
|
52
50
|
} else if(isObj(filter)){
|
|
53
|
-
const {onChange} = filter;
|
|
54
|
-
const key = defaultStr(filter.key,filter.field,filter.index,index+"");
|
|
51
|
+
const {onChange,visible:cVisible,...rest} = filter;
|
|
52
|
+
const key = defaultStr(filter.key,filter.field,filter.columnField,filter.index,index+"");
|
|
55
53
|
const visible = !!visibleColumns[key];
|
|
56
54
|
colMenus.push(<Menu.Item
|
|
57
55
|
key = {key}
|
|
@@ -61,7 +59,7 @@ const FiltersAccordionComponent = React.forwardRef((props,ref)=>{
|
|
|
61
59
|
if(context.toggleFilterColumnVisibility){
|
|
62
60
|
context.toggleFilterColumnVisibility(key,!visible);
|
|
63
61
|
}
|
|
64
|
-
|
|
62
|
+
setVisibleColumns({...visibleColumns,[key]:!visible});
|
|
65
63
|
}}
|
|
66
64
|
/>)
|
|
67
65
|
if(!visible) {
|
|
@@ -72,32 +70,32 @@ const FiltersAccordionComponent = React.forwardRef((props,ref)=>{
|
|
|
72
70
|
if(renderMenusOnly) return null;
|
|
73
71
|
content.push(
|
|
74
72
|
<Grid.Cell {...cellProps} key={key}>
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
73
|
+
<Filter
|
|
74
|
+
{...rest}
|
|
75
|
+
{...(isObj(valuesRefs.current[key]) ? valuesRefs.current[key] : {})}
|
|
76
|
+
dynamicRendered
|
|
77
|
+
//isLoading = {isLoading && filteredRef.current[key] ? true : false}
|
|
78
|
+
orOperator = {defaultBool(orOperator,filter.orOperator,true)}
|
|
79
|
+
andOperator = {defaultBool(andOperator,filter.andOperator,true)}
|
|
80
|
+
onChange = {(arg)=>{
|
|
81
|
+
if(!arg.action && !arg.operator || !arg.field) return;
|
|
82
|
+
const canHandle = canHandleFilter(arg);
|
|
83
|
+
valuesRefs.current[key] = arg;
|
|
84
|
+
if(filteredRef.current[key] !== canHandle){
|
|
85
|
+
if(canHandle){
|
|
86
|
+
canHandlerFilterRef.current++;
|
|
87
|
+
} else {
|
|
88
|
+
canHandlerFilterRef.current = Math.max(0,canHandlerFilterRef.current-1);
|
|
89
|
+
}
|
|
91
90
|
}
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
inputProps = {{containerProps}}
|
|
91
|
+
filteredRef.current[key] = canHandle;
|
|
92
|
+
if(onChange){
|
|
93
|
+
onChange(arg);
|
|
94
|
+
}
|
|
95
|
+
}}
|
|
96
|
+
withBottomSheet
|
|
97
|
+
containerProps = {{...containerProps}}
|
|
98
|
+
inputProps = {{containerProps}}
|
|
101
99
|
/></Grid.Cell>)
|
|
102
100
|
}
|
|
103
101
|
})
|
|
@@ -115,7 +113,7 @@ const FiltersAccordionComponent = React.forwardRef((props,ref)=>{
|
|
|
115
113
|
title = {null}
|
|
116
114
|
visible = {visible}
|
|
117
115
|
onDissmiss = {()=>{
|
|
118
|
-
|
|
116
|
+
setVisible(false);
|
|
119
117
|
}}
|
|
120
118
|
anchor = {(props)=><Tooltip title = {mainFilterTitle}Component={Pressable} {...props} style={[theme.styles.row]}>
|
|
121
119
|
<Icon
|
|
@@ -132,8 +130,8 @@ const FiltersAccordionComponent = React.forwardRef((props,ref)=>{
|
|
|
132
130
|
>
|
|
133
131
|
{({open,close})=>{
|
|
134
132
|
const {content,colMenus} = prepareContent(filters);
|
|
135
|
-
return <View style={[styles.wrapper]}>
|
|
136
|
-
<View style = {[styles.menuWrapper]}>
|
|
133
|
+
return <View style={[styles.wrapper]} testID={testID+"_AccordionFiltersWrapper"}>
|
|
134
|
+
<View style = {[styles.menuWrapper]} testID={testID+"_AccordionFilterWraperContent"}>
|
|
137
135
|
<Expandable
|
|
138
136
|
left = {(props)=><Icon {...props} icon={content.length?'filter-plus':'filter-menu'}/>}
|
|
139
137
|
style = {styles.expandable}
|
|
@@ -2560,7 +2560,6 @@ export default class CommonDatagridComponent extends AppComponent {
|
|
|
2560
2560
|
sortedProps,
|
|
2561
2561
|
width,
|
|
2562
2562
|
columnField : field,
|
|
2563
|
-
//columnDef : header,
|
|
2564
2563
|
index : headerIndex,
|
|
2565
2564
|
visible,
|
|
2566
2565
|
key : header.field,
|
|
@@ -3617,9 +3616,13 @@ export default class CommonDatagridComponent extends AppComponent {
|
|
|
3617
3616
|
return false;
|
|
3618
3617
|
}
|
|
3619
3618
|
UNSAFE_componentWillReceiveProps(nextProps){
|
|
3620
|
-
if(
|
|
3619
|
+
if(nextProps.data === this.props.data || React.areEquals(nextProps.data,this.props.data)) {
|
|
3621
3620
|
return false;
|
|
3622
3621
|
}
|
|
3622
|
+
const newStableHash = stableHash(nextProps.data);
|
|
3623
|
+
this.prevStableDataHash = this.prevStableDataHash !== undefined ? this.prevStableDataHash : stableHash(this.props.data);
|
|
3624
|
+
if(newStableHash == this.prevStableDataHash) return false;
|
|
3625
|
+
this.prevStableDataHash = newStableHash;
|
|
3623
3626
|
this.setIsLoading(true,true);
|
|
3624
3627
|
this.prepareData({...nextProps,force:true},(state)=>{
|
|
3625
3628
|
this.setState(state)
|
|
@@ -151,7 +151,6 @@ const SWRDatagridComponent = React.forwardRef((props,ref)=>{
|
|
|
151
151
|
title
|
|
152
152
|
},rest.exportTableProps.pdf);
|
|
153
153
|
const fetchOptionsRef = React.useRef(defaultObj(customFetchOptions));
|
|
154
|
-
const refreshCBRef = React.useRef(null);
|
|
155
154
|
const fPathRef = React.useRef(defaultStr(fetchPathKey,uniqid("fetchPath")));
|
|
156
155
|
fetchPath = defaultStr(fetchPath,table.queryPath,tableName.toLowerCase()).trim();
|
|
157
156
|
if(fetchPath){
|
|
@@ -160,23 +159,16 @@ const SWRDatagridComponent = React.forwardRef((props,ref)=>{
|
|
|
160
159
|
const sortRef = React.useRef({});
|
|
161
160
|
const innerRef = React.useRef(null);
|
|
162
161
|
const showProgressRef = React.useRef(true);
|
|
163
|
-
const dataRef = React.useRef([]);
|
|
164
|
-
const hasResultRef = React.useRef(false);
|
|
165
|
-
const totalRef = React.useRef(0);
|
|
166
|
-
const isFetchingRef = React.useRef(false);
|
|
167
162
|
const pageRef = React.useRef(1);
|
|
168
163
|
const canHandlePagination = handlePagination !== false ? true : false;
|
|
169
164
|
const canHandleLimit = handleQueryLimit !== false && canHandlePagination ? true : false;
|
|
170
165
|
const limitRef = React.useRef(!canHandleLimit ?0 : defaultNumber(getSessionData("limit"),500));
|
|
171
166
|
const isInitializedRef = React.useRef(false);
|
|
172
167
|
testID = defaultStr(testID,"RNSWRDatagridComponent");
|
|
173
|
-
const
|
|
174
|
-
const {error, isValidating,isLoading:customIsLoading,refresh} = useSWR(fetchPath,{
|
|
168
|
+
const {error, isValidating,isLoading,data:result,refresh} = useSWR(fetchPath,{
|
|
175
169
|
fetcher : (url,opts)=>{
|
|
176
170
|
if(!isInitializedRef.current) {
|
|
177
|
-
|
|
178
|
-
isLoadingRef.current = false;
|
|
179
|
-
return;
|
|
171
|
+
return Promise.resolve({data:[],total:0});
|
|
180
172
|
}
|
|
181
173
|
opts = defaultObj(opts);
|
|
182
174
|
opts.fetchOptions = isObj(opts.fetchOptions)? Object.clone(opts.fetchOptions) : {};
|
|
@@ -195,35 +187,14 @@ const SWRDatagridComponent = React.forwardRef((props,ref)=>{
|
|
|
195
187
|
delete opts.page;
|
|
196
188
|
delete opts.offset;
|
|
197
189
|
}
|
|
198
|
-
const fetchCB = (fArgs)=>{
|
|
199
|
-
let {data,total} = (Array.isArray(fArgs) ? {data:fArgs,total:fArgs.length} : isObj(fArgs)? fArgs : {data:[],total:0});
|
|
200
|
-
totalRef.current = total;
|
|
201
|
-
dataRef.current = data;
|
|
202
|
-
const dd = Object.size(data);
|
|
203
|
-
if(dd>total){
|
|
204
|
-
total = dd;
|
|
205
|
-
}
|
|
206
|
-
hasResultRef.current = true;
|
|
207
|
-
if(onFetchData && typeof onFetchData =='function'){
|
|
208
|
-
onFetchData({allData:data,total,data,context:innerRef.current})
|
|
209
|
-
}
|
|
210
|
-
return data;
|
|
211
|
-
};
|
|
212
|
-
hasResultRef.current = false;
|
|
213
|
-
isFetchingRef.current = true;
|
|
214
190
|
if(typeof fetcher =='function'){
|
|
215
|
-
return fetcher(url,opts)
|
|
216
|
-
isFetchingRef.current = false;
|
|
217
|
-
isLoadingRef.current = false;
|
|
218
|
-
});
|
|
191
|
+
return fetcher(url,opts);
|
|
219
192
|
}
|
|
220
193
|
const {url:fUrl,fetcher:cFetcher,...rest} = getFetcherOptions(url,opts);
|
|
221
194
|
if(showProgressRef.current ===false){
|
|
222
195
|
rest.showError = false;
|
|
223
196
|
}
|
|
224
|
-
return cFetcher(fUrl,rest).
|
|
225
|
-
isFetchingRef.current = false;
|
|
226
|
-
}).catch((e)=>{
|
|
197
|
+
return cFetcher(fUrl,rest).catch((e)=>{
|
|
227
198
|
console.log(e," is swr fetching data");
|
|
228
199
|
throw e;
|
|
229
200
|
});
|
|
@@ -231,39 +202,38 @@ const SWRDatagridComponent = React.forwardRef((props,ref)=>{
|
|
|
231
202
|
showError : false,
|
|
232
203
|
swrOptions : getSWROptions(swrConfig.refreshTimeout)
|
|
233
204
|
});
|
|
234
|
-
const
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
cb();
|
|
205
|
+
const {data,total} = React.useMemo(()=>{
|
|
206
|
+
const {data,total} = (Array.isArray(result) ? {data:result,total:result.length} : isObj(result)? result : {data:[],total:0});
|
|
207
|
+
const dd = Object.size(data);
|
|
208
|
+
if(dd>total){
|
|
209
|
+
total = dd;
|
|
210
|
+
}
|
|
211
|
+
if(onFetchData && typeof onFetchData =='function'){
|
|
212
|
+
onFetchData({allData:data,total,data,context:innerRef.current})
|
|
243
213
|
}
|
|
244
|
-
|
|
214
|
+
return {data,total};
|
|
215
|
+
},[result])
|
|
216
|
+
const loading = (isLoading || isValidating);
|
|
245
217
|
React.useEffect(()=>{
|
|
246
218
|
setTimeout(x=>{
|
|
247
219
|
if(error && innerRef.current && innerRef.current.isLoading && innerRef.current.isLoading()){
|
|
248
220
|
innerRef.current.setIsLoading(false,false);
|
|
249
221
|
}
|
|
250
|
-
},500)
|
|
251
|
-
},[error])
|
|
222
|
+
},500);
|
|
223
|
+
},[error]);
|
|
252
224
|
const doRefresh = (showProgress)=>{
|
|
253
225
|
showProgressRef.current = showProgress ? typeof showProgress ==='boolean' : false;
|
|
254
|
-
if(isFetchingRef.current) return;
|
|
255
|
-
isLoadingRef.current = true;
|
|
256
226
|
refresh();
|
|
257
227
|
}
|
|
258
228
|
const canPaginate = ()=>{
|
|
259
229
|
if(!canHandlePagination) return false;
|
|
260
|
-
if(canHandleLimit && typeof
|
|
230
|
+
if(canHandleLimit && typeof total !=='number' || typeof pageRef.current !='number' || typeof limitRef.current !='number') return false;
|
|
261
231
|
if(limitRef.current <= 0) return false;
|
|
262
232
|
return true;
|
|
263
233
|
}
|
|
264
234
|
const getTotalPages = ()=>{
|
|
265
235
|
if(!canPaginate()) return false;
|
|
266
|
-
return Math.ceil(
|
|
236
|
+
return Math.ceil(total / limitRef.current);;
|
|
267
237
|
};
|
|
268
238
|
const getNextPage = ()=>{
|
|
269
239
|
if(!canPaginate()) return false;
|
|
@@ -289,9 +259,8 @@ const SWRDatagridComponent = React.forwardRef((props,ref)=>{
|
|
|
289
259
|
}, canSortRemotely = ()=>{
|
|
290
260
|
if(!canPaginate() || autoSort === true) return false;
|
|
291
261
|
///si le nombre total d'élements est inférieur au nombre limite alors le trie peut être fait localement
|
|
292
|
-
return
|
|
262
|
+
return total > limitRef.current && true || false;
|
|
293
263
|
}
|
|
294
|
-
const loading = (isLoadingRef.current && (isLoading|| isValidating));
|
|
295
264
|
const pointerEvents = loading ?"node" : "auto";
|
|
296
265
|
const itLimits = [{
|
|
297
266
|
text : "Limite nbre elts par page",
|
|
@@ -378,7 +347,7 @@ const SWRDatagridComponent = React.forwardRef((props,ref)=>{
|
|
|
378
347
|
/>
|
|
379
348
|
<View testID={testID+"_PaginationLabel"}>
|
|
380
349
|
<Label style={{fontSize:15}}>
|
|
381
|
-
{(
|
|
350
|
+
{(total?page:0).formatNumber()}-{totalPages.formatNumber()}{" / "}{total.formatNumber()}
|
|
382
351
|
</Label>
|
|
383
352
|
</View>
|
|
384
353
|
<Icon
|
|
@@ -433,7 +402,7 @@ const SWRDatagridComponent = React.forwardRef((props,ref)=>{
|
|
|
433
402
|
isSWRDatagrid
|
|
434
403
|
isTableData
|
|
435
404
|
fetchData = {undefined}
|
|
436
|
-
data = {
|
|
405
|
+
data = {data}
|
|
437
406
|
canMakePhoneCall={canMakePhoneCall}
|
|
438
407
|
key={tableName}
|
|
439
408
|
sessionName={defaultStr(sessionName,'list-data')}
|
|
@@ -245,6 +245,7 @@ export default class Field extends AppComponent {
|
|
|
245
245
|
return false;
|
|
246
246
|
}
|
|
247
247
|
callOnChange(args){
|
|
248
|
+
args.isFilter = this.isFilter();
|
|
248
249
|
if(typeof this.props.onChange === "function" && this.hasValueChanged(args.value)){
|
|
249
250
|
this.props.onChange(args);
|
|
250
251
|
}
|
|
@@ -278,7 +279,7 @@ export default class Field extends AppComponent {
|
|
|
278
279
|
actions[k][action]();
|
|
279
280
|
}
|
|
280
281
|
let form = Forms.getForm(this.formName);
|
|
281
|
-
this.INITIAL_STATE.onValidate.call(this,{...defaultObj(rest),props:this.props,formName:this.formName,form,name:this.name,field:this.name,value,event,context:this});
|
|
282
|
+
this.INITIAL_STATE.onValidate.call(this,{...defaultObj(rest),isFilter:this.isFilter(),props:this.props,formName:this.formName,form,name:this.name,field:this.name,value,event,context:this});
|
|
282
283
|
this.callOnChange({value,event,isValid:true,...rest});
|
|
283
284
|
if(form && form.props){
|
|
284
285
|
if(canEnable){
|
|
@@ -351,7 +352,7 @@ export default class Field extends AppComponent {
|
|
|
351
352
|
for(var k in actions){
|
|
352
353
|
actions[k].disable();
|
|
353
354
|
}
|
|
354
|
-
this.INITIAL_STATE.onNoValidate.call(this,{...defaultObj(rest),props:this.props,msg,value,formName:this.formName,field:this.name,name:this.name,context:this,event,validRule,validType:validRule,validParams,context:this});
|
|
355
|
+
this.INITIAL_STATE.onNoValidate.call(this,{...defaultObj(rest),isFilter:this.isFilter(),props:this.props,msg,value,formName:this.formName,field:this.name,name:this.name,context:this,event,validRule,validType:validRule,validParams,context:this});
|
|
355
356
|
let form = Forms.getForm(this.formName);
|
|
356
357
|
this.callOnChange({value,validRule,validParams,event,isValid:false,...rest});
|
|
357
358
|
if(form){
|
|
@@ -29,6 +29,9 @@ export default class FormIDField extends TextField {
|
|
|
29
29
|
|
|
30
30
|
/*** met à jour la données du numéro de piece */
|
|
31
31
|
fetchNewId(focus){
|
|
32
|
+
if(this.isFilter()){
|
|
33
|
+
return Promise.resolve("");
|
|
34
|
+
}
|
|
32
35
|
const data = defaultObj(this.props.data);
|
|
33
36
|
if(!isNonNullString(this.name)) return undefined;
|
|
34
37
|
const cb = (value)=>{
|
|
@@ -66,41 +69,48 @@ export default class FormIDField extends TextField {
|
|
|
66
69
|
return false;
|
|
67
70
|
}
|
|
68
71
|
componentDidUpdate(){
|
|
69
|
-
if(!isNonNullString(this.newFieldIdValue)){
|
|
72
|
+
if(!this.isFilter() && !isNonNullString(this.newFieldIdValue)){
|
|
70
73
|
this.fetchNewId();
|
|
71
74
|
}
|
|
72
75
|
}
|
|
73
76
|
_render(props,setRef){
|
|
74
77
|
delete props.validType;
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
props.
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
if(typeof props.minLength !=='number'){
|
|
84
|
-
props.minLength = 2;
|
|
85
|
-
}
|
|
86
|
-
const defValue = props.defaultValue = isNonNullString(props.defaultValue)? props.defaultValue : isNonNullString(this.newFieldIdValue)? this.newFieldIdValue : undefined;
|
|
87
|
-
props.validRule = props.validType;
|
|
88
|
-
props.contentContainerProps = Object.assign({},props.contentContainerProps)
|
|
89
|
-
props.contentContainerProps.pointerEvents = defaultStr(props.contentContainerProps.pointerEvents,"auto");
|
|
90
|
-
props.enableCopy = typeof props.enableCopy ==='boolean'? props.enableCopy : (props.defaultValue || this.newFieldIdValue ? true : false);
|
|
91
|
-
const {right} = props;
|
|
92
|
-
props.readOnly = typeof props.disabled ==='boolean' ? !!!props.disabled : typeof props.readOnly =="boolean"? !!!props.disabled : false;
|
|
93
|
-
props.right = (props)=>{
|
|
94
|
-
const r = typeof right =='function'? right (props) : React.isValidElement(right)? right : null;
|
|
95
|
-
if(!defValue){
|
|
96
|
-
return <>{r}<ActivityIndicator
|
|
97
|
-
{...props}
|
|
98
|
-
style = {[props.style,{marginRight:10}]}
|
|
99
|
-
/></>
|
|
78
|
+
if(!this.isFilter()){
|
|
79
|
+
const upper = props.upper !== false ? UPPER_CASE : "";
|
|
80
|
+
if(isNonNullString(this.name) && isObj(props.data) && isNonNullString(props.data[this.name])){
|
|
81
|
+
props.disabled = true;
|
|
82
|
+
props.validType = upper;
|
|
83
|
+
props.defaultValue = props.data[this.name];
|
|
84
|
+
} else {
|
|
85
|
+
props.validType = 'required|'+upper;
|
|
100
86
|
}
|
|
101
|
-
|
|
87
|
+
if(typeof props.minLength !=='number'){
|
|
88
|
+
props.minLength = 2;
|
|
89
|
+
}
|
|
90
|
+
const defValue = props.defaultValue = isNonNullString(props.defaultValue)? props.defaultValue : isNonNullString(this.newFieldIdValue)? this.newFieldIdValue : undefined;
|
|
91
|
+
props.validRule = props.validType;
|
|
92
|
+
props.contentContainerProps = Object.assign({},props.contentContainerProps)
|
|
93
|
+
props.contentContainerProps.pointerEvents = defaultStr(props.contentContainerProps.pointerEvents,"auto");
|
|
94
|
+
props.enableCopy = typeof props.enableCopy ==='boolean'? props.enableCopy : (props.defaultValue || this.newFieldIdValue ? true : false);
|
|
95
|
+
props.readOnly = typeof props.disabled ==='boolean' ? !!!props.disabled : typeof props.readOnly =="boolean"? !!!props.disabled : false;
|
|
96
|
+
|
|
97
|
+
const {right} = props;
|
|
98
|
+
props.right = (props)=>{
|
|
99
|
+
const r = typeof right =='function'? right (props) : React.isValidElement(right)? right : null;
|
|
100
|
+
if(!defValue){
|
|
101
|
+
return <>{r}<ActivityIndicator
|
|
102
|
+
{...props}
|
|
103
|
+
style = {[props.style,{marginRight:10}]}
|
|
104
|
+
/></>
|
|
105
|
+
}
|
|
106
|
+
return r;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
this.setValidRule(props.validType);
|
|
110
|
+
} else {
|
|
111
|
+
props.enableCopy = false;
|
|
112
|
+
props.disabled = props.readOnly = false;
|
|
102
113
|
}
|
|
103
|
-
this.setValidRule(props.validType);
|
|
104
114
|
return super._render(props,setRef);
|
|
105
115
|
}
|
|
106
116
|
}
|
|
@@ -70,13 +70,19 @@ export const getFilterComponentProps = (_props)=>{
|
|
|
70
70
|
errorText,
|
|
71
71
|
label,text,
|
|
72
72
|
primary,
|
|
73
|
-
onValidate,
|
|
74
73
|
checkPiece,
|
|
75
74
|
check,
|
|
76
75
|
width,
|
|
77
76
|
type,
|
|
77
|
+
visible,
|
|
78
78
|
jsType,
|
|
79
79
|
filterType,
|
|
80
|
+
getValidValue,
|
|
81
|
+
validate,
|
|
82
|
+
onValidate,
|
|
83
|
+
onValidatorValid,///il s'agit de la fonction de rappel appelée immédiatement après que le validateur ait réuissie la validation
|
|
84
|
+
onValidateField,
|
|
85
|
+
onNoValidate,
|
|
80
86
|
...props
|
|
81
87
|
} = _props;
|
|
82
88
|
props = defaultObj(props);
|
|
@@ -86,13 +92,13 @@ export const getFilterComponentProps = (_props)=>{
|
|
|
86
92
|
const sanitizedType = type.replaceAll("_","").toLowerCase().trim();
|
|
87
93
|
props = defaultObj(props);
|
|
88
94
|
props.label = defaultStr(label,text);
|
|
89
|
-
if(
|
|
95
|
+
if(sanitizedType.startsWith("select")){
|
|
90
96
|
props.inputProps = Object.assign({},props.inputProps);
|
|
91
97
|
props.inputProps.placeholder = defaultStr(props.inputProps.placeholder,i18n.lang("search.."))
|
|
92
98
|
component = componentTypes.SelectField;
|
|
93
|
-
if(
|
|
99
|
+
if(sanitizedType ==='selectcountry'){
|
|
94
100
|
component = componentTypes.SelectCountry;
|
|
95
|
-
} else if(
|
|
101
|
+
} else if(sanitizedType ==='selecttabledata'){
|
|
96
102
|
component = componentTypes.SelectTableData;
|
|
97
103
|
} else if(React.isComponent(componentTypes[type])){
|
|
98
104
|
component = componentTypes[type];
|
|
@@ -133,6 +139,7 @@ export const getFilterComponentProps = (_props)=>{
|
|
|
133
139
|
props.multiple = true;
|
|
134
140
|
}
|
|
135
141
|
props.renderFilter = true;
|
|
142
|
+
props.isFilter = true;
|
|
136
143
|
if(type.contains("date") || type.contains("time")){
|
|
137
144
|
delete props.right;
|
|
138
145
|
}
|
|
@@ -125,9 +125,9 @@ const TableComponent = React.forwardRef(({containerProps,listContainerStyle,onRe
|
|
|
125
125
|
}
|
|
126
126
|
}
|
|
127
127
|
}
|
|
128
|
-
const onComponentRender = (
|
|
128
|
+
const onComponentRender = (...args)=>{
|
|
129
129
|
if(onRender){
|
|
130
|
-
onRender(
|
|
130
|
+
onRender(...args);
|
|
131
131
|
}
|
|
132
132
|
//au paravant il était possible de faire scroller le composant Table lorsque les données sont raffraichies, ce qui n'avait pas un bon impact sur le rendu de la table de données
|
|
133
133
|
if(false && itemsChanged){
|
|
@@ -424,6 +424,7 @@ const TextFieldComponent = React.forwardRef((componentProps,inputRef)=>{
|
|
|
424
424
|
{valueToCopy?<Icon
|
|
425
425
|
{...iconProps}
|
|
426
426
|
title = {"Copier la valeur ["+valueToCopy+"] dans le presse papier"}
|
|
427
|
+
style = {[iconProps.style,{pointerEvents:"auto"}]}
|
|
427
428
|
icon = {COPY_ICON}
|
|
428
429
|
onPress = {(e)=>{
|
|
429
430
|
/*if(selectFieldToCopy){
|
package/src/context/hooks.js
CHANGED
|
@@ -5,7 +5,6 @@ import useStableMemo from "$react/useStableMemo";
|
|
|
5
5
|
import { useWindowDimensions } from "$cdimensions";
|
|
6
6
|
import {isObj,isNonNullString} from "$cutils";
|
|
7
7
|
import { StyleSheet } from "react-native";
|
|
8
|
-
|
|
9
8
|
import { createContext,useContext as useReactContext } from "react";
|
|
10
9
|
|
|
11
10
|
export const ExpoUIContext = createContext(null);
|
|
@@ -63,4 +62,4 @@ export function useMediaQueryUpdateStyle({useCurrentMedia,target,mediaQueryUpdat
|
|
|
63
62
|
if(isObj(nStyle) || Array.isArray(nStyle)) return StyleSheet.flatten([props.style,nStyle]);
|
|
64
63
|
return StyleSheet.flatten(props.style)||{};
|
|
65
64
|
},[handleProps,useCurrentMedia,dimensions,props.style]);
|
|
66
|
-
}
|
|
65
|
+
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import {isNonNullString,isObj,extendObj,defaultObj,defaultStr} from "$utils";
|
|
2
|
+
import { useQuery as useRQuery, useMutation as RQUseMutation, useQueryClient } from "@tanstack/react-query";
|
|
3
|
+
import { getFetcherOptions as apiGetFetcherOptions } from '$capi';
|
|
4
|
+
|
|
5
|
+
export const RETRY_OPTIONS = { cacheTime: 2000,refetchInterval:5000};
|
|
6
|
+
|
|
7
|
+
export const RETRY_LIST_OPTIONS = {cacheTime:5000,refetchInterval:20000};
|
|
8
|
+
|
|
9
|
+
const isValidNetworkMode = (nMode)=>isNonNullString(nMode) && ['online','always','offlineFirst'].includes(nMode.toLowerCase().trim());
|
|
10
|
+
const isValidRetryDelay = (retryDelay) => typeof retryDelay =='number' || typeof retryDelay ==='function'? true : false;
|
|
11
|
+
|
|
12
|
+
const queries403Cached = {};
|
|
13
|
+
|
|
14
|
+
/***** override of useQuery
|
|
15
|
+
@see : https://tanstack.com/query/v4/docs/react/guides/migrating-to-react-query-4
|
|
16
|
+
@see : https://tanstack.com/query/v4/docs/react/reference/useQuery for useQuery options
|
|
17
|
+
@param {boolean} handle403, pour la prise en compte du 403
|
|
18
|
+
@param {Array} key, array of key string, The query key to use for this query.The query key will be hashed into a stable hash. See Query Keys for more information. The query will automatically update when this key changes (as long as enabled is not set to false).
|
|
19
|
+
@param {function} queryFn, query function (context: QueryFunctionContext) => Promise<TData>
|
|
20
|
+
@param {boolean} enabled Set this to false to disable this query from automatically running.
|
|
21
|
+
@param {string} networkMode 'online' | 'always' | 'offlineFirst
|
|
22
|
+
@param {boolean| number | (failureCount: number, error: TError) => boolean} retry If false, failed queries will not retry by default.If true, failed queries will retry infinitely. If set to a number, e.g. 3, failed queries will retry until the failed query count meets that number.
|
|
23
|
+
@param {boolean} retryOnMount If set to false, the query will not be retried on mount if it contains an error. Defaults to true.
|
|
24
|
+
@param {number | (retryAttempt: number, error: TError) => number} retryDelay This function receives a retryAttempt integer and the actual Error and returns the delay to apply before he next attempt in milliseconds. A function like attempt => Math.min(attempt > 1 ? 2 ** attempt * 1000 : 1000, 30 * 1000) applies exponential backoff., A function like attempt => attempt * 1000 applies linear backoff.
|
|
25
|
+
*/
|
|
26
|
+
export const useQuery = (key,queryFn,enabled,networkMode,retry,retryOnMount,retryDelay,...args)=>{
|
|
27
|
+
const options = isObj(key)? Object.assign({},key) : isNonNullString(key)? {queryKey:key.split(",")} : Array.isArray(key)? {queryKey:key} : {};
|
|
28
|
+
key = isNonNullString(key)? key.split(",") : Array.isArray(key)? key : [];
|
|
29
|
+
options.queryKey = Array.isArray(options.queryKey) && options.queryKey.length && options.queryKey || key;
|
|
30
|
+
options.queryFn = typeof queryFn =='function' ? queryFn : typeof options.queryFn =='function'? options.queryFn : undefined;
|
|
31
|
+
options.enabled = typeof enabled === "boolean" ? enabled : typeof options.enabled =='boolean' ? options.enabled : true;
|
|
32
|
+
options.networkMode = isValidNetworkMode(networkMode) ? networkMode.toLowerCase().trim() : isValidNetworkMode(options.networkMode) ? options.networkMode.toLowerCase().trim() : "online";
|
|
33
|
+
options.retry = typeof retry =='boolean' || typeof retry ==='number' ? retry : typeof options.retry ==='boolean' || typeof options.retry =='number' ? options.retry : undefined;
|
|
34
|
+
options.retryOnMount = typeof retryOnMount ==='boolean'? retryOnMount : typeof options.retryOnMount =='boolean' ? options.retryOnMount : undefined;
|
|
35
|
+
options.retryDelay = isValidRetryDelay(retryDelay)? retryDelay : isValidRetryDelay(options.retryDelay) ? options.retryDelay : undefined;
|
|
36
|
+
[queryFn,enabled,networkMode,retry,retryOnMount,retryDelay].map((a)=>{
|
|
37
|
+
isObj(a) && extendObj(true,options,a);
|
|
38
|
+
});
|
|
39
|
+
args.map((a)=>{
|
|
40
|
+
isObj(a) && extendObj(true,options,a);
|
|
41
|
+
});
|
|
42
|
+
options.enabled = !options.queryKey?.length ? false : options.enabled;
|
|
43
|
+
//if not enabled, we have to disabled retry option
|
|
44
|
+
options.retry = !options.enabled ? false : options.retry;
|
|
45
|
+
const {onError} = options;
|
|
46
|
+
const keyString = key.join(",");
|
|
47
|
+
if(keyString && queries403Cached[keyString]){
|
|
48
|
+
options.retry = false;
|
|
49
|
+
}
|
|
50
|
+
const {handle403} = options;
|
|
51
|
+
delete options.handle403;
|
|
52
|
+
options.onError = (e,...args)=>{
|
|
53
|
+
if(handle403){
|
|
54
|
+
const {response} = isObj(e)? e : {};
|
|
55
|
+
if(isObj(response) && response.status === 403){
|
|
56
|
+
keyString ? queries403Cached[keyString] = true : null;
|
|
57
|
+
setTimeout(()=>{
|
|
58
|
+
keyString && delete queries403Cached[keyString];
|
|
59
|
+
},100);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
if(typeof onError ==='function' && (onError(e,options) === false)) return;
|
|
63
|
+
}
|
|
64
|
+
//const r = !options.enabled ? console.error("unable to get query for options",options) : null;
|
|
65
|
+
return useRQuery(options);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/****
|
|
69
|
+
@see : https://tanstack.com/query/v4/docs/react/reference/useMutation
|
|
70
|
+
*/
|
|
71
|
+
export const useMutation = (mutationFn,cacheTime,mutationKey,...args)=>{
|
|
72
|
+
const options = isObj(mutationFn)? Object.assign({},mutationFn) : typeof(mutationFn) =='function'? {mutationFn} : {};
|
|
73
|
+
mutationFn = typeof mutationFn ==='function' ? mutationFn : undefined;
|
|
74
|
+
mutationFn = mutationFn || typeof options.mutationFn == 'function' ? options.mutationFn : undefined;
|
|
75
|
+
options.cacheTime = typeof cacheTime =='number' ? cacheTime : typeof options.cacheTime =='number'? options.cacheTime : undefined;
|
|
76
|
+
options.mutationKey = isNonNullString(mutationKey) && mutationKey || isNonNullString(options.mutationKey) ? options.mutationKey : undefined;
|
|
77
|
+
[cacheTime,mutationKey].map((a)=>{
|
|
78
|
+
isObj(a) && extendObj(true,options,a);
|
|
79
|
+
});
|
|
80
|
+
args.map((a)=>{
|
|
81
|
+
isObj(a) && extendObj(true,options,a);
|
|
82
|
+
});
|
|
83
|
+
options.mutationFn = async (params,...rest) => {
|
|
84
|
+
return await mutationFn(params,...rest);
|
|
85
|
+
}
|
|
86
|
+
return RQUseMutation(options);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
export const getFetcherOptions = (path,opts)=>{
|
|
91
|
+
return apiGetFetcherOptions(path,opts);
|
|
92
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
module.exports = {"@fto-consult/expo-ui":{"name":"@fto-consult/expo-ui","version":"6.26.
|
|
1
|
+
module.exports = {"@fto-consult/expo-ui":{"name":"@fto-consult/expo-ui","version":"6.26.3","repository":{"type":"git","url":"git+https://github.com/borispipo/expo-ui.git"},"homepage":"https://github.com/borispipo/expo-ui#readme"},"@emotion/native":{"version":"11.11.0","url":"https://emotion.sh","license":"MIT"},"@emotion/react":{"version":"11.11.1","url":"https://github.com/emotion-js/emotion/tree/main/packages/react","license":"MIT"},"@expo/html-elements":{"version":"0.5.1","url":"https://github.com/expo/expo/tree/main/packages/html-elements","license":"MIT"},"@expo/metro-config":{"version":"0.10.7","url":"https://github.com/expo/expo.git","license":"MIT"},"@expo/vector-icons":{"version":"13.0.0","url":"https://expo.github.io/vector-icons","license":"MIT"},"@expo/webpack-config":{"version":"18.1.2","url":"https://github.com/expo/expo-cli.git","license":"MIT"},"@faker-js/faker":{"version":"8.0.2","url":"https://github.com/faker-js/faker.git","license":"MIT"},"@fto-consult/common":{"version":"3.29.0","url":"https://github.com/borispipo/common#readme","license":"ISC"},"@gorhom/portal":{"version":"1.0.14","url":"https://github.com/gorhom/react-native-portal#readme","license":"MIT"},"@pchmn/expo-material3-theme":{"version":"1.3.1","url":"https://github.com/pchmn/expo-material3-theme#readme","license":"MIT"},"@react-native-async-storage/async-storage":{"version":"1.18.2","url":"https://github.com/react-native-async-storage/async-storage#readme","license":"MIT"},"@react-native-community/datetimepicker":{"version":"7.2.0","url":"https://github.com/react-native-community/datetimepicker#readme","license":"MIT"},"@react-native-community/netinfo":{"version":"9.3.10","url":"https://github.com/react-native-netinfo/react-native-netinfo#readme","license":"MIT"},"@react-native/assets-registry":{"version":"0.72.0","url":"git@github.com:facebook/react-native.git","license":"MIT"},"@react-navigation/native":{"version":"6.1.7","url":"https://reactnavigation.org","license":"MIT"},"@react-navigation/native-stack":{"version":"6.9.13","url":"https://github.com/software-mansion/react-native-screens#readme","license":"MIT"},"@shopify/flash-list":{"version":"1.4.3","url":"https://shopify.github.io/flash-list/","license":"MIT"},"apexcharts":{"version":"3.41.1","url":"https://apexcharts.com","license":"MIT"},"babel-plugin-inline-dotenv":{"version":"1.7.0","url":"https://github.com/brysgo/babel-plugin-inline-dotenv#readme","license":"ISC"},"babel-plugin-module-resolver":{"version":"5.0.0","url":"https://github.com/tleunen/babel-plugin-module-resolver.git","license":"MIT"},"expo":{"version":"49.0.7","url":"https://github.com/expo/expo/tree/main/packages/expo","license":"MIT"},"expo-camera":{"version":"13.4.2","url":"https://docs.expo.dev/versions/latest/sdk/camera/","license":"MIT"},"expo-clipboard":{"version":"4.3.1","url":"https://docs.expo.dev/versions/latest/sdk/clipboard","license":"MIT"},"expo-font":{"version":"11.4.0","url":"https://docs.expo.dev/versions/latest/sdk/font/","license":"MIT"},"expo-image-picker":{"version":"14.3.2","url":"https://docs.expo.dev/versions/latest/sdk/imagepicker/","license":"MIT"},"expo-linking":{"version":"5.0.2","url":"https://docs.expo.dev/versions/latest/sdk/linking","license":"MIT"},"expo-sqlite":{"version":"11.3.2","url":"https://docs.expo.dev/versions/latest/sdk/sqlite/","license":"MIT"},"expo-status-bar":{"version":"1.6.0","url":"https://docs.expo.dev/versions/latest/sdk/status-bar/","license":"MIT"},"expo-system-ui":{"version":"2.4.0","url":"https://docs.expo.dev/versions/latest/sdk/system-ui","license":"MIT"},"expo-web-browser":{"version":"12.3.2","url":"https://docs.expo.dev/versions/latest/sdk/webbrowser/","license":"MIT"},"file-saver":{"version":"2.0.5","url":"https://github.com/eligrey/FileSaver.js#readme","license":"MIT"},"fs-extra":{"version":"11.1.1","url":"https://github.com/jprichardson/node-fs-extra","license":"MIT"},"google-libphonenumber":{"version":"3.2.33","url":"https://ruimarinho.github.io/google-libphonenumber/","license":"(MIT AND Apache-2.0)"},"htmlparser2-without-node-native":{"version":"3.9.2","url":"git://github.com/fb55/htmlparser2.git","license":"MIT"},"pdfmake":{"version":"0.2.7","url":"http://pdfmake.org","license":"MIT"},"process":{"version":"0.11.10","url":"git://github.com/shtylman/node-process.git","license":"MIT"},"prop-types":{"version":"15.8.1","url":"https://facebook.github.io/react/","license":"MIT"},"react":{"version":"18.2.0","url":"https://reactjs.org/","license":"MIT"},"react-content-loader":{"version":"6.2.1","url":"https://github.com/danilowoz/react-content-loader","license":"MIT"},"react-dom":{"version":"18.2.0","url":"https://reactjs.org/","license":"MIT"},"react-native":{"version":"0.72.3","license":"MIT"},"react-native-big-list":{"version":"1.6.1","url":"https://marcocesarato.github.io/react-native-big-list-docs/","license":"GPL-3.0-or-later"},"react-native-blob-util":{"version":"0.18.6","url":"https://github.com/RonRadtke/react-native-blob-util","license":"MIT"},"react-native-gesture-handler":{"version":"2.12.1","url":"https://github.com/software-mansion/react-native-gesture-handler#readme","license":"MIT"},"react-native-iphone-x-helper":{"version":"1.3.1","url":"https://github.com/ptelad/react-native-iphone-x-helper#readme","license":"MIT"},"react-native-mime-types":{"version":"2.4.0","license":"MIT"},"react-native-paper":{"version":"5.10.1","url":"https://callstack.github.io/react-native-paper","license":"MIT"},"react-native-paper-dates":{"version":"0.18.14","url":"https://github.com/web-ridge/react-native-paper-dates#readme","license":"MIT"},"react-native-reanimated":{"version":"3.3.0","url":"https://github.com/software-mansion/react-native-reanimated#readme","license":"MIT"},"react-native-safe-area-context":{"version":"4.6.3","url":"https://github.com/th3rdwave/react-native-safe-area-context#readme","license":"MIT"},"react-native-screens":{"version":"3.22.1","url":"https://github.com/software-mansion/react-native-screens#readme","license":"MIT"},"react-native-svg":{"version":"13.9.0","url":"https://github.com/react-native-community/react-native-svg","license":"MIT"},"react-native-web":{"version":"0.19.7","url":"git://github.com/necolas/react-native-web.git","license":"MIT"},"react-native-webview":{"version":"13.2.2","url":"https://github.com/react-native-webview/react-native-webview#readme","license":"MIT"},"react-virtuoso":{"version":"4.5.0","url":"https://virtuoso.dev/","license":"MIT"},"sharp-cli":{"version":"4.1.1","url":"https://github.com/vseventer/sharp-cli","license":"MIT"},"tippy.js":{"version":"6.3.7","url":"https://atomiks.github.io/tippyjs/","license":"MIT"},"uninstall":{"version":"0.0.0","license":"MIT"},"websql":{"version":"2.0.3","url":"git://github.com/nolanlawson/node-websql.git","license":"Apache-2.0"},"xlsx":{"version":"0.18.5","url":"https://sheetjs.com/","license":"Apache-2.0"}};
|