@fto-consult/expo-ui 2.23.11 → 2.24.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fto-consult/expo-ui",
3
- "version": "2.23.11",
3
+ "version": "2.24.0",
4
4
  "description": "Bibliothèque de composants UI Expo,react-native",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -61,7 +61,7 @@
61
61
  "@emotion/native": "^11.10.0",
62
62
  "@expo/html-elements": "^0.2.0",
63
63
  "@expo/vector-icons": "^13.0.0",
64
- "@fto-consult/common": "^1.23.10",
64
+ "@fto-consult/common": "^1.24.6",
65
65
  "@fto-consult/expo-ui": "^2.21.0",
66
66
  "@gorhom/portal": "^1.0.14",
67
67
  "@react-native-async-storage/async-storage": "~1.17.3",
@@ -1261,8 +1261,8 @@ export default class CommonDatagridComponent extends AppComponent {
1261
1261
  if(!isValidAggregator(ag) || ag.code == this.state.aggregatorFunction) return null;
1262
1262
  setTimeout(()=>{
1263
1263
  this.setIsLoading(true,()=>{
1264
- this.prepareData({data:this.INITIAL_STATE.data},(state)=>{
1265
- this.setState({...state,aggregatorFunction:ag.code},()=>{
1264
+ this.prepareData({data:this.INITIAL_STATE.data,aggregatorFunction:ag.code},(state)=>{
1265
+ this.setState(state,()=>{
1266
1266
  this.setSessionData("aggregatorFunction",ag.code);
1267
1267
  this.setIsLoading(false,false);
1268
1268
  })
@@ -2018,8 +2018,9 @@ export default class CommonDatagridComponent extends AppComponent {
2018
2018
  return defaultNumber(this.sectionListDataSize.current)
2019
2019
  }
2020
2020
  prepareData(args,cb){
2021
- let {pagination,displayOnlySectionListHeaders:cdisplayOnlySectionListHeaders,data,force,sectionListColumns,updateFooters} = defaultObj(args);
2021
+ let {pagination,aggregatorFunction:customAggregatorFunction,displayOnlySectionListHeaders:cdisplayOnlySectionListHeaders,data,force,sectionListColumns,updateFooters} = defaultObj(args);
2022
2022
  cb = typeof cb ==='function'? cb : typeof args.cb == 'function'? args.cb : undefined;
2023
+ const aggregatorFunction = isNonNullString(customAggregatorFunction) && customAggregatorFunction in this.aggregatorFunctions ? this.aggregatorFunctions[customAggregatorFunction] : this.getActiveAggregatorFunction();
2023
2024
  sectionListColumns = isObj(sectionListColumns) ? sectionListColumns : this.state.sectionListColumns;
2024
2025
  const displayOnlySectionListHeaders = typeof cdisplayOnlySectionListHeaders == 'boolean'?cdisplayOnlySectionListHeaders : this.state.displayOnlySectionListHeaders;
2025
2026
  let isArr = Array.isArray(data);
@@ -2096,7 +2097,7 @@ export default class CommonDatagridComponent extends AppComponent {
2096
2097
  result.push(currentSectionListFooter);
2097
2098
  }
2098
2099
  Object.map(footersColumns,(columnDef,field)=>{
2099
- evalSingleValue({data:d,aggregatorFunction:this.getActiveAggregatorFunction(),aggregatorFunctions:this.aggregatorFunctions,columnDef,field,result,displayLabel:false})
2100
+ evalSingleValue({data:d,aggregatorFunction,aggregatorFunctions:this.aggregatorFunctions,columnDef,field,result,displayLabel:false})
2100
2101
  });
2101
2102
  }
2102
2103
  newData.push(d);
@@ -2127,7 +2128,7 @@ export default class CommonDatagridComponent extends AppComponent {
2127
2128
  } else if(force){
2128
2129
  this.setSelectedRows();
2129
2130
  }
2130
- const state = {data,displayOnlySectionListHeaders};
2131
+ const state = {data,displayOnlySectionListHeaders,aggregatorFunction:aggregatorFunction.code};
2131
2132
  if((cb)){
2132
2133
  cb(state);
2133
2134
  }
@@ -2263,9 +2264,10 @@ export default class CommonDatagridComponent extends AppComponent {
2263
2264
  if(typeof props !=='object' || !props){
2264
2265
  props = {};
2265
2266
  }
2266
- const children = React.isValidElement(this.props.progressBar) ? this.props.progressBar :
2267
+ const ProgressBar = this.props.progressBar;
2268
+ const children = React.isValidElement(ProgressBar) ? ProgressBar :
2267
2269
  this.props.useLinesProgressBar === true || this.props.useLineProgressBar === true ? CommonDatagridComponent.LineProgressBar(props)
2268
- : this.getDefaultPreloader(props);
2270
+ : React.isComponent(ProgressBar) ?<ProgressBar/> : this.getDefaultPreloader(props);
2269
2271
  return <DatagridProgressBar
2270
2272
  {...props}
2271
2273
  onChange = {(context)=>{
@@ -3172,6 +3174,7 @@ CommonDatagridComponent.propTypes = {
3172
3174
  aggregatorFunction : PropTypes.string,
3173
3175
  /*** permet de faire une mutation sur les options de la recherche, immédiatement avant le lancement de la recherche */
3174
3176
  fetchOptionsMutator : PropTypes.func,
3177
+ useLinesProgressBar : PropTypes.bool,//si le progress bar lignes horizontale seront utilisés
3175
3178
  }
3176
3179
 
3177
3180
  const styles = StyleSheet.create({
@@ -6,13 +6,12 @@ import React from "$react";
6
6
  import {defaultObj,isNonNullString} from "$utils";
7
7
  import SimpleSelect from "$ecomponents/SimpleSelect";
8
8
  import Provider from "$ecomponents/Dialog/Provider";
9
- import TextField from "$components/TextField";
10
- import Label from "$components/Label";
9
+ import TextField from "$ecomponents/TextField";
10
+ import Label from "$ecomponents/Label";
11
11
  import theme from "$theme";
12
12
  import notify from "$notify";
13
13
  import { View } from "react-native";
14
- import Icon from "$components/Icon";
15
- import PropTypes from "prop-types";
14
+ import Icon from "$ecomponents/Icon";
16
15
 
17
16
  const DateFormatSelector = React.forwardRef((props,ref)=>{
18
17
  return <SimpleSelect ref={ref} {...selectDateFormatFieldProps(props)}/>
@@ -797,7 +797,7 @@ export default class Field extends AppComponent {
797
797
  jsType,
798
798
  fieldToPopulateOnBlur,
799
799
  ...rest
800
- } = this.props;
800
+ } = this.getComponentProps(this.props);
801
801
  if(this.state.caughtAnError){
802
802
  return <ErrorMessage
803
803
  error={this.state.caughtError}
@@ -0,0 +1,39 @@
1
+ import SelectField from "./SelectField";
2
+ import {selectCurrencyFieldProps} from "$ecomponents/SelectCurrency";
3
+ import appConfig from "$app/config";
4
+ import {defaultStr} from "$utils";
5
+
6
+ export default class FormFieldSelectCurrency extends SelectField{
7
+ constructor(props){
8
+ super(props);
9
+ Object.defineProperties(this,{
10
+ currencyFormatRef : {value : {current:defaultStr(appConfig.currencyFormat)}}
11
+ });
12
+ }
13
+ onValidate(args){
14
+ const {context} = args;
15
+ if(context && context.getField){
16
+ const field = context.getField("currencyFormat");
17
+ if(field && field.setValue){
18
+ field.setValue(defaultStr(this.currencyFormatRef.current));
19
+ }
20
+ }
21
+ super.onValidate(args);
22
+ }
23
+ getComponentProps(props){
24
+ this.currencyFormatRef.current = defaultStr(props.currencyFormat,this.currencyFormatRef.current,appConfig.currencyFormat)
25
+ return {...selectCurrencyFieldProps({...props,onChange:(args)=>{
26
+ this.currencyFormatRef.current = defaultStr(args.currencyFormat);
27
+ if(this.props.onChange){
28
+ this.props.onChange(args);
29
+ }
30
+ }})}
31
+ }
32
+ getValidValue(data){
33
+ data.currencyFormat = this.currencyFormatRef.current;
34
+ return super.getValidValue(data);
35
+ }
36
+ }
37
+ FormFieldSelectCurrency.propTypes = {
38
+ ...SelectField.propTypes,
39
+ }
@@ -130,7 +130,9 @@ export default class FormSelectField extends Field{
130
130
  }}
131
131
  onChange = {(args)=>{
132
132
  this.validateWithCallOnChange(args);
133
- if(typeof this.props.onChange =='function'){
133
+ if(typeof props.onChange =='function'){
134
+ props.onChange(args);
135
+ } else if(this.props.onChange =='function'){
134
136
  this.props.onChange(args);
135
137
  }
136
138
  }}
@@ -4,6 +4,7 @@ import SelectField from "./SelectField";
4
4
  import Switch from "./Switch";
5
5
  import Checkbox from "./Checkbox";
6
6
  import SelectTableData from "./SelectTableData";
7
+ import SelectCurrency from "./SelectCurrency";
7
8
  //import IdField from "./IdField";
8
9
  //import PieceField from "./PieceField";
9
10
  import Slider from "./Slider";
@@ -27,7 +28,8 @@ const defFormFields = {
27
28
  TextField,
28
29
  SelectField,
29
30
  SelectTableData,
30
- SelectCountry
31
+ SelectCountry,
32
+ SelectCurrency
31
33
  ,Switch
32
34
  ,Checkbox
33
35
  //,IdField
@@ -58,6 +60,7 @@ export {
58
60
  SelectField,
59
61
  SelectTableData,
60
62
  SelectCountry
63
+ ,SelectCurrency
61
64
  ,Switch
62
65
  ,Checkbox
63
66
  //,IdField
@@ -8,7 +8,6 @@ const componentTypes = {
8
8
  ...Fields,
9
9
  id : Fields.IdField,
10
10
  selecttabledata : Fields.SelectTableData,
11
- select_tabledata : Fields.SelectTableData,
12
11
  idfield : Fields.IdField,
13
12
  piecefield : Fields.PieceField,
14
13
  piece : Fields.PieceField,
@@ -16,6 +15,7 @@ const componentTypes = {
16
15
  switch : Fields.Switch,
17
16
  selectcountry : Fields.SelectCountry,
18
17
  selectdateformat : Fields.SelectDateFormat,
18
+ selectcurrency : Fields.SelectCurrency,
19
19
  dateformat : Fields.SelectDateFormat,
20
20
  date : Fields.Date,
21
21
  time : Fields.Time,
@@ -100,9 +100,11 @@ export const getFilterComponentProps = (_props)=>{
100
100
  component = Fields.ColorPicker;
101
101
  } else if(type == 'dateformat' || type =='select_dateformat' || type =='select_date_format') {
102
102
  component = Fields.SelectDateFormat;
103
- } else if(React.isComponent()) {
103
+ } else if(React.isComponent(componentTypes[type])) {
104
104
  component = componentTypes[type];
105
- }else {
105
+ } else if(React.isComponent(componentTypes[type.replaceAll("_","")])){
106
+ component = componentTypes[type.replaceAll("_","")];
107
+ } else {
106
108
  const tt = type.replaceAll("_","").toLowerCase();
107
109
  if(React.isComponent(componentTypes[tt])){
108
110
  component = componentTypes[tt];
@@ -14,6 +14,7 @@ const OptimizedHeavyScreen = React.forwardRef(({
14
14
  ),
15
15
  style,
16
16
  children,
17
+ isLoading,
17
18
  timeout,
18
19
  testID,
19
20
  transitionTimeout,
@@ -30,7 +31,7 @@ const OptimizedHeavyScreen = React.forwardRef(({
30
31
  style={[{flex:1},style]}
31
32
  ref={React.useMergeRefs(transitionRef,ref)}
32
33
  >
33
- {areInteractionsComplete ? (children) : placeholder}
34
+ {areInteractionsComplete && isLoading !==true ? (children) : placeholder}
34
35
  </Transitioning.View>
35
36
  )
36
37
  });
@@ -46,7 +47,8 @@ OptimizedHeavyScreen.propTypes = {
46
47
  placeholder : PropTypes.oneOfType([
47
48
  PropTypes.node,
48
49
  PropTypes.element,
49
- ])
50
+ ]),
51
+ isLoading : PropTypes.bool,//si l'écan où les données sont en train d'être chargé
50
52
  }
51
53
 
52
54
  OptimizedHeavyScreen.displayName = "OptimizedHeavyScreenComponent";
@@ -0,0 +1,100 @@
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
+ import React from "$react";
5
+ import {defaultObj,defaultStr,isNonNullString} from "$utils";
6
+ import SimpleSelect from "$ecomponents/SimpleSelect";
7
+ import TextField from "$ecomponents/TextField";
8
+ import Icon from "$ecomponents/Icon";
9
+ import {currencies} from "$ccurrency";
10
+ import { Pressable } from "react-native";
11
+ import {styles} from "$theme";
12
+ import appConfig from "$app/config";
13
+
14
+ const CurrencySelector = React.forwardRef((props,ref)=>{
15
+ return <SimpleSelect ref={ref} {...selectCurrencyFieldProps(props)}/>
16
+ });
17
+
18
+ CurrencySelector.displayName = "CurrencySelector";
19
+
20
+ export default CurrencySelector;
21
+
22
+ export const currencyFormatRef = React.createRef(null);
23
+
24
+ /*** onAdd est appelé lorsqu'on ajoute un format personalisé */
25
+ export const selectCurrencyFieldProps = ({right,disabled,readOnly,isFilter,onChange,onBlur,editable,...props})=>{
26
+ const isEditable = disabled !== true && readOnly !== true && editable !== false;
27
+ const currency = appConfig.currency;
28
+ currencyFormatRef.current = defaultStr(currencyFormatRef.current,appConfig.currencyFormat,"%v%s");
29
+ const iconSize = 25;
30
+ return {
31
+ items : currencies,
32
+ getItemValue : ({item})=>item.code,
33
+ renderItem : ({item}) => "["+item.code+"] " +item.name,
34
+ showAdd : false,
35
+ defaultValue : defaultStr(currency.code),
36
+ enableCopy : false,
37
+ ...props,
38
+ isFilter,
39
+ onChange : (args)=>{
40
+ args.currencyFormat = args.format = defaultStr(currencyFormatRef.current)
41
+ if(onChange){
42
+ onChange(args);
43
+ }
44
+ },
45
+ onBlur : (args)=>{
46
+ args.currencyFormat = args.format = defaultStr(currencyFormatRef.current);
47
+ if(onBlur){
48
+ onBlur(args);
49
+ }
50
+ },
51
+ disabled : !isEditable,
52
+ editable : isEditable,
53
+ right : !isEditable || isFilter ? right : (rP)=>{
54
+ const r = typeof right =='function'? right(rP) : right;
55
+ return <>
56
+ <Pressable style={{width:80}}
57
+ onPress = {(e)=>{
58
+ React.stopEventPropagation(e);
59
+ }}
60
+ >
61
+ <TextField
62
+ {...rP}
63
+ affix = {false}
64
+ editable = {isEditable}
65
+ disabled = {disabled}
66
+ readOnly = {readOnly}
67
+ enableCopy = {false}
68
+ contentContainerProps = {{
69
+ style:{height:37,paddingVertical:0,paddingHorizontal:0},
70
+ }}
71
+ mode = {'flat'}
72
+ left = {(p)=>{
73
+ return <Icon
74
+ {...rP}
75
+ {...p}
76
+ size = {iconSize}
77
+ style = {[styles.ml0,styles.mr0,{width:iconSize,height:iconSize}]}
78
+ icon = "alpha-f-box"
79
+ title="Format d'affichage des valeurs numériques : de la forme %v%s ou %v représente la valeur du montant et %s représente la devise : exemple %s%v => $10 et %s %v => 10 $"
80
+ />
81
+ }}
82
+ defaultValue = {currencyFormatRef.current}
83
+ containerProps = {{
84
+ width:70,
85
+ }}
86
+ onChange = {({value})=>{
87
+ currencyFormatRef.current = value;
88
+ }}
89
+ />
90
+ </Pressable>
91
+ {React.isValidElement(r) && r || null}
92
+ </>
93
+ },
94
+ type : 'select',
95
+ }
96
+ }
97
+
98
+ CurrencySelector.propTypes = {
99
+ ...SimpleSelect.propTypes,
100
+ }
@@ -19,7 +19,7 @@ export default function DatabaseStatisticScreen ({withScreen,title:customTitle,c
19
19
  }
20
20
  let content = [];
21
21
  Object.map(tables,(table,index,suffix)=>{
22
- if(isObj(table) && table.databaseStatistic !== false){
22
+ if(isObj(table) && table.databaseStatistic !== false && table.databaseStatistics !== false){
23
23
  content.push(
24
24
  <Cell elevation = {5} withSurface mobileSize={12} desktopSize={3} tabletSize={4} {...contentProps} key = {index} >
25
25
  <DatabaseStatistic
@@ -68,13 +68,14 @@ export default class FormDataLayout extends FormDataActions {
68
68
  preloader,
69
69
  preloaderProps,
70
70
  testID,
71
+ isLoading,
71
72
  } = this.props;
72
73
  wProps = defaultObj(wProps);
73
- const useHeavyScreen = withHeavyScreen !== false ? true : false;
74
+ const useHeavyScreen = withHeavyScreen !== false || isLoading == true? true : false;
74
75
  const Wrapper = useHeavyScreen ? HeavyScreen : React.Fragment;
75
76
  testID = defaultStr(wProps.testID,testID,"RN_FormDataScren");
76
77
  const placeholder = React.isValidElement(preloader)? preloader : <FormLoader {...defaultObj(preloaderProps)}/>;
77
- const wrapperProps = useHeavyScreen ? {...wProps,placeholder,testID:testID+"_HeavyScreen"} : {}
78
+ const wrapperProps = useHeavyScreen ? {...wProps,isLoading,placeholder,testID:testID+"_HeavyScreen"} : {}
78
79
  return <Wrapper {...wrapperProps}>
79
80
  {content}
80
81
  </Wrapper>
@@ -94,6 +95,7 @@ FormDataLayout.propTypes = {
94
95
  withHeavyScreen : PropTypes.bool,
95
96
  withAppBar : PropTypes.bool, ///si l'appBar sera affiché
96
97
  preloader : PropTypes.node,
98
+ isLoading : PropTypes.bool,//Si l'écran est en mode chargement des données
97
99
  preloaderProps : PropTypes.object,
98
100
  header : PropTypes.oneOfType([
99
101
  PropTypes.element,
@@ -1,4 +1,5 @@
1
1
  import {defaultStr,isNumber,isPromise,defaultVal,extendObj,defaultObj,uniqid,isObj,isObjOrArray} from "$utils";
2
+ import stableHash from "stable-hash";
2
3
  import {FormData} from "$ecomponents/Form";
3
4
  import FormDataScreen from "./FormData";
4
5
  import ScreenContainer from "./Screen";
@@ -71,18 +72,8 @@ export const isDocEditing = (data,fields,checkPrimaryKey)=>{
71
72
  export default class TableDataScreenComponent extends FormDataScreen{
72
73
  constructor(props){
73
74
  super(props);
74
- let cDatas = [];
75
75
  const mainProps = getScreenProps(props);
76
- const hasManyData = isObjOrArray(mainProps.datas) && Object.size(mainProps.datas,true) > 0 ? true : false;
77
- if(hasManyData){
78
- cDatas = Object.toArray(mainProps.datas);
79
- }
80
- extendObj(this.state,{
81
- hasManyData,
82
- datas : cDatas,
83
- currentIndex : 0,
84
- data : hasManyData ? defaultObj(cDatas[0]) : isObj(mainProps.data)? mainProps.data : {}
85
- });
76
+ extendObj(this.state,this.prepareStateData(mainProps));
86
77
  const table = defaultObj(mainProps.table);
87
78
  const fields = {},primaryKeyFields = {};
88
79
  Object.map(table.fields,(field,i)=>{
@@ -157,6 +148,20 @@ export default class TableDataScreenComponent extends FormDataScreen{
157
148
  this.hidePreloader = this.hidePreloader.bind(this);
158
149
  this.showPreloader = this.showPreloader.bind(this);
159
150
  };
151
+ prepareStateData(props){
152
+ const mainProps = defaultObj(props,this.props);
153
+ const hasManyData = isObjOrArray(mainProps.datas) && Object.size(mainProps.datas,true) > 0 ? true : false;
154
+ let cDatas = [];
155
+ if(hasManyData){
156
+ cDatas = Object.toArray(mainProps.datas);
157
+ }
158
+ return {
159
+ hasManyData,
160
+ datas : cDatas,
161
+ currentIndex : 0,
162
+ data : hasManyData ? defaultObj(cDatas[0]) : isObj(mainProps.data)? mainProps.data : {}
163
+ };
164
+ }
160
165
  isCurrentDocEditingUpdate(){
161
166
  return this.isDocEditingRef.current === true ? true : false;
162
167
  }
@@ -561,6 +566,14 @@ export default class TableDataScreenComponent extends FormDataScreen{
561
566
  },typeof timeoutCallback =='number'? timeoutCallback : HIDE_PRELOADER_TIMEOUT);
562
567
  return this.hidePreloaderTimeout;
563
568
  }
569
+ UNSAFE_componentWillReceiveProps(nextProps){
570
+ const props = getScreenProps(nextProps);
571
+ const {data,datas}= props;
572
+ if(stableHash({data,datas}) != stableHash({data:this.state.data,datas:this.state.datas})){
573
+ this.setState(this.prepareStateData(props));
574
+ }
575
+ return;
576
+ }
564
577
  reset (args,cb){
565
578
  if(!this._isMounted()) return;
566
579
  clearTimeout(this.timeoutCallback);