@fto-consult/expo-ui 2.22.0 → 2.23.1

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/appConfig.txt CHANGED
@@ -8,4 +8,7 @@
8
8
 
9
9
  /*** le nombre maximal de courbes qu'on peut afficher sur le même graphe***/
10
10
  maxSupportedChartSeries {number}
11
+
12
+ /***les fonctions d'aggregations du datagrid**/
13
+ datagridAggregatorFunctions : {objectOf({code:{string},label:{string},eval:{function}})|| arrayOf({code:{string},label:{string},eval:{function}})}
11
14
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fto-consult/expo-ui",
3
- "version": "2.22.0",
3
+ "version": "2.23.1",
4
4
  "description": "Bibliothèque de composants UI Expo,react-native",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -344,7 +344,7 @@ const DatagridFactory = (Factory)=>{
344
344
  } = this.props
345
345
  chartContainerProps = defaultObj(chartContainerProps);
346
346
  const canRenderChart = this.canRenderChart();
347
- const hasData = this.state.data.length ? true : false;
347
+ const hasData = this.getStateDataSize(false) ? true : false;
348
348
  testID = defaultStr(testID,"RN_DatagridAccordion");
349
349
  backToTopProps = defaultObj(backToTopProps);
350
350
  accordionProps = defaultObj(accordionProps);
@@ -445,7 +445,7 @@ const DatagridFactory = (Factory)=>{
445
445
  <View testID={testID+"_HeaderContentCntainer"} style={[styles.table,styles.pullRight]}>
446
446
  {dbSelector}
447
447
  <View testID={testID+"_HeaderQueryLimit"} style={[styles.paginationItem]}>
448
- {this.renderQueryLimit(this.state.data.length.formatNumber())}
448
+ {this.renderQueryLimit(this.getStateDataSize().formatNumber())}
449
449
  </View>
450
450
  {this.renderCustomPagination()}
451
451
  {sortedColumnsLength ? <View testID={testID+"_HeaderSortedColumns"} style={[styles.sortableItems,styles.paginationItem,{paddingRight:10}]}>
@@ -519,6 +519,7 @@ const DatagridFactory = (Factory)=>{
519
519
  ,icon : showFooters?'view-column':'view-module'
520
520
  ,text : (showFooters?'Masquer les totaux':'Afficher les totaux')
521
521
  }:null,
522
+ ...this.getAggregatorFunctionsMenuItems(),
522
523
  ...this.renderCustomMenu(),
523
524
  ...restItems,
524
525
  !canRenderChart && this.canScrollTo() && {
@@ -584,6 +585,8 @@ const DatagridFactory = (Factory)=>{
584
585
  key = {field}
585
586
  testID={testID+"_FooterItem_"+field}
586
587
  {...footer}
588
+ aggregatorFunction = {this.getActiveAggregatorFunction().code}
589
+ aggregatorFunctions = {this.aggregatorFunctions}
587
590
  anchorProps = {{style:[theme.styles.ph1,theme.styles.mh05]}}
588
591
  />
589
592
  })}
@@ -24,7 +24,7 @@ import { StyleSheet,Dimensions,useWindowDimensions} from "react-native";
24
24
  import Preloader from "$ecomponents/Preloader";
25
25
  import Checkbox from "../Checkbox";
26
26
  import { TouchableRipple } from "react-native-paper";
27
- import { evalSingleValue,Footer,getFooterColumnValue } from "../Footer";
27
+ import { evalSingleValue,Footer,getFooterColumnValue,isValidAggregator,extendAggreagatorFunctions} from "../Footer";
28
28
  import i18n from "$i18n";
29
29
  import { makePhoneCall,canMakePhoneCall as canMakeCall} from "$makePhoneCall";
30
30
  import copyToClipboard from "$capp/clipboard";
@@ -39,7 +39,6 @@ import {Menu} from "$ecomponents/BottomSheet";
39
39
  import {styles as tableStyles} from "$ecomponents/Table";
40
40
  import {DialogProvider} from "$ecomponents/Form/FormData";
41
41
  import Chart,{getMaxSupportedSeriesSize} from "$ecomponents/Chart";
42
- import { aggregatorFunctions} from "../Footer/Footer";
43
42
 
44
43
  const chart = "chart";
45
44
  export const donutChart = {
@@ -198,10 +197,15 @@ export default class CommonDatagridComponent extends AppComponent {
198
197
  sectionListDataSize : {value : {current : 0}},
199
198
  enablePointerEventsRef : {value : {current:false}},
200
199
  configureSectionListSelectedValues : {value : {}},
200
+ ///la liste des fonctions d'aggregations supportées
201
+ aggregatorFunctions : {value : extendAggreagatorFunctions(this.props.aggregatorFunctions)},
201
202
  ///les types d'affichage
202
203
  displayTypes : {value : hasFoundDisplayTypes ? disTypes : Object.clone(displayTypes)},
203
204
  sectionListColumnsSize : {value : {current:0}}, //la taille du nombre d'éléments de section dans les colonnes
204
205
  })
206
+ const sessionAggregator = defaultStr(this.getSessionData("aggregatorFunction")).trim();
207
+ const aggregatorProps = defaultStr(this.props.aggregatorFunction).trim();
208
+ this.state.aggregatorFunction= aggregatorProps && isValidAggregator(this.aggregatorFunctions[aggregatorProps]) ? aggregatorProps ? isNonNullString(sessionAggregator) && isValidAggregator(this.aggregatorFunctions[sessionAggregator]) : sessionAggregator : Object.keys(this.aggregatorFunctions)[0];
205
209
  this.isLoading = this.isLoading.bind(this);
206
210
  this.getProgressBar = this.getProgressBar.bind(this);
207
211
  this.sortRef.current.dir = defaultStr(this.sortRef.current.dir,this.sortRef.current.column == "date"?"desc":'asc')
@@ -1218,6 +1222,65 @@ export default class CommonDatagridComponent extends AppComponent {
1218
1222
  cb({...this.state.chartConfig});
1219
1223
  }
1220
1224
  }
1225
+ getActiveAggregatorFunction(){
1226
+ if(isNonNullString(this.state.aggregatorFunction) && this.aggregatorFunctions[this.state.aggregatorFunction]){
1227
+ return this.aggregatorFunctions[this.state.aggregatorFunction]
1228
+ }
1229
+ return this.aggregatorFunctions[Object.keys(this.aggregatorFunctions)[0]];
1230
+ }
1231
+ /**** récupère l'item de menu permettant lié à la sélection de la fonction d'aggggrégation */
1232
+ getAggregatorFunctionsMenuItems(withDivider){
1233
+ if(!this.hasFootersFields()) return [];
1234
+ const m = [];
1235
+ const aggregatorFunction = this.getActiveAggregatorFunction().code;
1236
+ Object.map(this.aggregatorFunctions,(ag)=>{
1237
+ const active = ag.code == aggregatorFunction;
1238
+ m.push({
1239
+ ...ag,
1240
+ icon : active?"check":null,
1241
+ onPress : active ? undefined : ()=>{
1242
+ this.toggleActiveAggregatorFunction(ag);
1243
+ }
1244
+ })
1245
+ });
1246
+ if(m.length){
1247
+ m.unshift({
1248
+ text : "Fonctions d'aggrégation",
1249
+ icon : "material-functions",
1250
+ divider : true,
1251
+ });
1252
+ if(withDivider !== false){
1253
+ m.unshift({divider:true});
1254
+ }
1255
+ if(withDivider !== false){
1256
+ m[m.length-1].divider = true;
1257
+ }
1258
+ }
1259
+ return m;
1260
+ }
1261
+ toggleActiveAggregatorFunction(ag){
1262
+ if(!isValidAggregator(ag) || ag.code == this.state.aggregatorFunction) return null;
1263
+ setTimeout(()=>{
1264
+ this.setIsLoading(true,()=>{
1265
+ this.prepareData({data:this.INITIAL_STATE.data},(state)=>{
1266
+ this.setState({...state,aggregatorFunction:ag.code},()=>{
1267
+ this.setSessionData("aggregatorFunction",ag.code);
1268
+ this.setIsLoading(false,false);
1269
+ })
1270
+ })
1271
+ },true);
1272
+ },200);
1273
+ }
1274
+ renderAggregatorFunctionsMenu(){
1275
+ const m = this.getAggregatorFunctionsMenuItems(false,false);
1276
+ if(!m.length) return null;
1277
+ return <Menu
1278
+ items = {m}
1279
+ anchor = {(p)=><Icon name="material-functions" {...p}
1280
+ title = "Fonctions d'aggrégations. Veuillez sélectionner la fonction à utiliser par défaut pour la totalisation des données des colonnes de type nombre"
1281
+ />}
1282
+ />
1283
+ }
1221
1284
  configureChart(refreshChart){
1222
1285
  if(!this.isChartRendable()){
1223
1286
  return Promise.reject({message:'Impossible de configurer le graphe car le type de données ne permet pas de rendu de type graphe'});
@@ -1283,14 +1346,6 @@ export default class CommonDatagridComponent extends AppComponent {
1283
1346
  items : yItems,
1284
1347
  multiple : true,
1285
1348
  },
1286
- aggregatorFunction : {
1287
- type : 'select',
1288
- text : "Foncton d'aggrégation",
1289
- required : true,
1290
- multiple : false,
1291
- defaultValue : "sum",
1292
- items : aggregatorFunctions,
1293
- },
1294
1349
  stacked : {
1295
1350
  type : 'switch',
1296
1351
  text : "Graphe empilé?",
@@ -1438,8 +1493,8 @@ export default class CommonDatagridComponent extends AppComponent {
1438
1493
  getSectionListHeadersChartOptions({chartType,yAxisColumn,xAxisColumn,aggregatorFunction}){
1439
1494
  if(!this.isSectionList()) return null;
1440
1495
  if(!isObj(chartType) || !isObj(yAxisColumn) || !yAxisColumn.field) return null;
1441
- if(!isObj(aggregatorFunction) || !isNonNullString(aggregatorFunction.code) || !aggregatorFunctions[aggregatorFunction.code]){
1442
- aggregatorFunction = aggregatorFunctions.sum;
1496
+ if(!isValidAggregator(aggregatorFunction)){
1497
+ aggregatorFunction = this.getActiveAggregatorFunction();
1443
1498
  }
1444
1499
  const code = aggregatorFunction.code;
1445
1500
  const isDonut = chartType.isDonut || chartType.isRadial;
@@ -1544,17 +1599,12 @@ export default class CommonDatagridComponent extends AppComponent {
1544
1599
  }
1545
1600
  xAxisColumn = this.state.columns[config.x];
1546
1601
  }
1547
- let aggregatorFunction = typeof config.aggregatorFunction =='string' && aggregatorFunctions[config.aggregatorFunction]?aggregatorFunctions[config.aggregatorFunction] :aggregatorFunctions.sum;
1602
+ const aggregatorFunction = this.getActiveAggregatorFunction().eval;
1548
1603
  const emptyValue = this.getEmptyDataValue();
1549
1604
  const indexes = {};
1550
1605
  let series = [],xaxis = {},customConfig = {};
1551
1606
  let count = 0;
1552
1607
  if(!this.isSectionList()){
1553
- if(isObj(aggregatorFunction) && typeof aggregatorFunction.eval =='function'){
1554
- aggregatorFunction = aggregatorFunction.eval;
1555
- } else {
1556
- aggregatorFunction = aggregatorFunctions.sum.eval;
1557
- }
1558
1608
  this.state.data.map((data,index)=>{
1559
1609
  if(!isObj(data))return null;
1560
1610
  const txt = this.renderRowCell({
@@ -1575,8 +1625,9 @@ export default class CommonDatagridComponent extends AppComponent {
1575
1625
  const current = indexes[s];
1576
1626
  current[text] = typeof current[text] =="number"? current[text] : 0;
1577
1627
  const value = getFooterColumnValue({data,columnDef,columnField:columnDef.field});
1578
- current[text] = aggregatorFunction(value,current[text],count);
1579
- })
1628
+ const rArgs = aggregatorFunction =='average'?{sum:current[text]+value,count:count+1} : {};
1629
+ current[text] = aggregatorFunction({value,total:current[text],data,columnDef,columnField:columnDef.field,count,...rArgs});
1630
+ });
1580
1631
  });
1581
1632
  Object.map(indexes,(values,serieName)=>{
1582
1633
  const col = this.state.columns[serieName];
@@ -2041,7 +2092,7 @@ export default class CommonDatagridComponent extends AppComponent {
2041
2092
  result.push(currentSectionListFooter);
2042
2093
  }
2043
2094
  Object.map(footersColumns,(columnDef,field)=>{
2044
- evalSingleValue({data:d,columnDef,field,result,displayLabel:false})
2095
+ evalSingleValue({data:d,aggregatorFunction:this.getActiveAggregatorFunction(),aggregatorFunctions:this.aggregatorFunctions,columnDef,field,result,displayLabel:false})
2045
2096
  });
2046
2097
  }
2047
2098
  newData.push(d);
@@ -2152,6 +2203,8 @@ export default class CommonDatagridComponent extends AppComponent {
2152
2203
  key = {key}
2153
2204
  testID={testID+"_FooterItem_"+key}
2154
2205
  {...footer}
2206
+ aggregatorFunction = {this.getActiveAggregatorFunction().code}
2207
+ aggregatorFunctions = {this.aggregatorFunctions}
2155
2208
  displayLabel = {false}
2156
2209
  //anchorProps = {{style:[theme.styles.ph1,theme.styles.mh05]}}
2157
2210
  />
@@ -2483,10 +2536,18 @@ export default class CommonDatagridComponent extends AppComponent {
2483
2536
  getMaxSelectedRows(){
2484
2537
  return 0;
2485
2538
  }
2539
+ ///retourne la longueur réelle du nombre d'éléments du tableau en excluant les valerus d'entêtes de section
2540
+ getStateDataSize(includeSectionListDataSize){
2541
+ const dSize = defaultNumber(this.state.data.length);
2542
+ if(!dSize) return 0;
2543
+ if(includeSectionListDataSize === false) return dSize;
2544
+ return Math.max(dSize - this.getSectionListDataSize(),0);
2545
+ }
2486
2546
  getMaxSelectableRows(){
2487
2547
  let max = this.getMaxSelectedRows();
2488
- if(this.state.data && typeof this.state.data.length ==='number'){
2489
- max = max ? Math.min(max,this.state.data.length,max) : this.state.data.length;
2548
+ const dataSize = this.getStateDataSize();
2549
+ if(dataSize){
2550
+ max = max ? Math.min(max,dataSize,max) : dataSize;
2490
2551
  }
2491
2552
  return Math.max(max-this.getSectionListDataSize(),0);
2492
2553
  }
@@ -3095,7 +3156,9 @@ CommonDatagridComponent.propTypes = {
3095
3156
  }),
3096
3157
  displayType : chartDisplayType,
3097
3158
  /*** les types d'afichates supportés par l'application */
3098
- displayTypes : PropTypes.arrayOf(chartDisplayType)
3159
+ displayTypes : PropTypes.arrayOf(chartDisplayType),
3160
+ /***le code de la fonction d'aggregation à utilier par défaut, dans la liste des fonctions d'aggrégations du composant */
3161
+ aggregatorFunction : PropTypes.string,
3099
3162
  }
3100
3163
 
3101
3164
  const styles = StyleSheet.create({
@@ -2,66 +2,89 @@ import Menu from "$ecomponents/BottomSheet/Menu";
2
2
  import View from "$ecomponents/View";
3
3
  import {Pressable,StyleSheet} from "react-native";
4
4
  import Label from "$ecomponents/Label";
5
- import {defaultVal,defaultObj} from "$utils";
5
+ import {defaultVal,defaultObj,isNonNullString,isObj} from "$utils";
6
6
  import React from "$react";
7
7
  import theme from "$theme"
8
+ import appConfig from "$capp/config";
8
9
 
9
- let methods = {
10
- sum : "Somme",
11
- average : "Moyenne",
12
- min : "Minimum",
13
- max : 'Maximum',
14
- count : "Nombre",
15
- }
16
10
  /*** les fonction d'aggreations */
17
11
  export const aggregatorFunctions = {
18
12
  sum : {
19
13
  code : "sum",
20
14
  label : "Somme",
21
- eval : (current,prev,count)=>{
22
- current = typeof current =='number'?current : 0;
23
- prev = typeof prev =='number'? prev : 0;
24
- return current+prev;
15
+ eval : ({value,total,count})=>{
16
+ value = typeof value =='number'?value : 0;
17
+ total = typeof total =='number'? total : 0;
18
+ return value+total;
25
19
  }
26
20
  },
27
- /*average : {
28
- code : "average",
29
- label : "Moyenne",
30
- eval : ()=>{
31
-
32
- }
33
- },*/
34
21
  min : {
35
22
  code : "min",
36
23
  label : "Minimum",
37
- eval : (current,prev,count)=>{
38
- current = typeof current =='number'?current : 0;
39
- prev = typeof prev =='number'? prev : 0;
40
- return Math.min(current,prev);
24
+ eval : ({value,total,count})=>{
25
+ value = typeof value =='number'?value : 0;
26
+ total = typeof total =='number'? total : 0;
27
+ return Math.min(value,total);
41
28
  },
42
29
  },
43
30
  max : {
44
31
  code : "max",
45
32
  label: 'Maximum',
46
- eval : (current,prev,count)=>{
47
- current = typeof current =='number'?current : 0;
48
- prev = typeof prev =='number'? prev : 0;
49
- return Math.max(current,prev);
33
+ eval : ({value,total,count})=>{
34
+ value = typeof value =='number'?value : 0;
35
+ total = typeof total =='number'? total : 0;
36
+ return Math.max(value,total);
50
37
  },
51
38
  },
52
39
  count : {
53
40
  code : "count",
54
41
  label : "Nombre",
55
- eval : (current,prev,count)=>{
42
+ eval : ({value,total,count})=>{
56
43
  return (typeof count =='number'? count : 0)+1;
57
44
  }
58
45
  },
46
+ average : {
47
+ code : "average",
48
+ label : "Moyenne",
49
+ eval : ({count,sum})=>{
50
+ return typeof count =='number' && count > 0 && typeof sum =='number'? sum/count : 0;
51
+ }
52
+ },
53
+ }
54
+ /****
55
+ * Vérifie si la fonction d'aggregation est valide
56
+ */
57
+ export const isValidAggregator = (aggregatorFunctionObject)=>{
58
+ return isObj(aggregatorFunctionObject) && isNonNullString(aggregatorFunctionObject.code) && typeof aggregatorFunctionObject.eval =='function' && true || false;
59
+ }
60
+ /*** permet d'étendre les fonction d'aggregations
61
+ * @param {object|Array} liste des functions d'aggregation supplémentaires, de la forme
62
+ * {
63
+ * code {string} le code de la fonction d'aggrégation
64
+ * label {string} le libele
65
+ * eval {function} la function a utiiser pour évaluer la données via l'aggregator
66
+
67
+ * }
68
+ */
69
+ export function extendAggreagatorFunctions(aFunctions){
70
+ const r = {...aggregatorFunctions};
71
+ loopForAggregator(appConfig.get("datagridAggregatorFunctions"),r);
72
+ loopForAggregator(aFunctions,r);
73
+ return r;
74
+ }
75
+ const loopForAggregator = (aggregatorFunctions,result)=>{
76
+ result = defaultObj(result);
77
+ Object.map(aggregatorFunctions,(aggregatorObj,key)=>{
78
+ if(!isValidAggregator(aggregatorObj)) return null;
79
+ result[aggregatorObj.code] = aggregatorObj;
80
+ });
59
81
  }
60
- const formatValue = ({value,format,method})=>{
61
- return (format === 'money' && method != 'count')? value.formatMoney():value.formatNumber();
82
+ const formatValue = ({value,format,aggregatorFunction})=>{
83
+ return (format === 'money' && aggregatorFunction != 'count')? value.formatMoney():value.formatNumber();
62
84
  }
63
85
  export default function DGGridFooterValue (props){
64
- let {label,text,displayLabel,style,format,testID,anchorProps} = props;
86
+ let {label,text,displayLabel,style,aggregatorFunctions,aggregatorFunction,format,testID,anchorProps} = props;
87
+ aggregatorFunctions = defaultObj(aggregatorFunctions);
65
88
  anchorProps = defaultObj(anchorProps);
66
89
  testID = defaultStr(testID,"RN_DatagridFooterComponent");
67
90
  label = defaultVal(label,text);
@@ -69,27 +92,28 @@ export default function DGGridFooterValue (props){
69
92
  if(displayLabel !== false){
70
93
  if(!label || !React.isValidElement(label,true)) return null;
71
94
  } else label = undefined;
72
- const [active,setActive] = React.useState(isNonNullString(props.method) && props.method in methods ? props.method : "sum")
95
+ const [active,setActive] = React.useState(isNonNullString(aggregatorFunction) && aggregatorFunction in aggregatorFunctions ? aggregatorFunction : aggregatorFunctions[Object.keys(aggregatorFunctions)[0]]?.code)
73
96
  React.useEffect(()=>{
74
- if(isNonNullString(props.method) && props.method in methods){
75
- setActive(props.method)
97
+ if(aggregatorFunction !== active && isNonNullString(aggregatorFunction) && aggregatorFunction in aggregatorFunctions){
98
+ setActive(aggregatorFunction)
76
99
  }
77
- },[props.method])
100
+ },[aggregatorFunction])
78
101
  let title = "";
79
102
  let menuItems = []
80
103
  const activeStyle = {color:theme.colors.primaryOnSurface};
81
- for(let method in methods){
82
- let val = defaultDecimal(props[method]);
104
+ for(let aggregatorFunction in aggregatorFunctions){
105
+ let val = defaultDecimal(props[aggregatorFunction]);
83
106
  if(isDecimal(val)){
84
- let fText = formatValue({value:val,format,method});
85
- title +=(title? ", ":"")+methods[method]+" : "+fText
107
+ let fText = formatValue({value:val,format,aggregatorFunction});
108
+ const mText = defaultStr(aggregatorFunctions[aggregatorFunction].label,aggregatorFunctions[aggregatorFunction].code,aggregatorFunction);
109
+ title +=(title? ", ":"")+mText +" : "+fText
86
110
  menuItems.push({
87
- text : methods[method] + " : "+fText,
88
- icon : active == method ? "check" : null,
89
- style : [{paddingHorizontal:0},active ===method ?activeStyle:null],
111
+ text : mText + " : "+fText,
112
+ icon : active == aggregatorFunction ? "check" : null,
113
+ style : [{paddingHorizontal:0},active ===aggregatorFunction ?activeStyle:null],
90
114
  onPress : (e)=>{
91
115
  React.stopEventPropagation(e);
92
- setActive(method)
116
+ setActive(aggregatorFunction)
93
117
  }
94
118
  })
95
119
  }
@@ -108,7 +132,7 @@ export default function DGGridFooterValue (props){
108
132
  </>
109
133
  : null}
110
134
  <Label testID={testID+"_LabelContent"} primary style={[styles.value]}>
111
- {formatValue({value:defaultDecimal(props[active]),method:active,format})}
135
+ {formatValue({value:defaultDecimal(props[active]),aggregatorFunction:active,format})}
112
136
  </Label>
113
137
  </Pressable>
114
138
  }}
@@ -4,7 +4,7 @@ import React from "$react";
4
4
  import memoize from "$react/memoize";
5
5
  export {default as FooterItem} from "./Footer";
6
6
  import {parseDecimal,defaultObj,defaultStr,isNonNullString} from "$utils";
7
-
7
+ import { aggregatorFunctions as mAggregatorFunctions } from "./Footer";
8
8
  export * from "./Footer";
9
9
 
10
10
  /***évalue la valeur décimale selon les paramètres */
@@ -19,8 +19,9 @@ export const getFooterColumnValue = ({data,columnDef,field,result,columnField})
19
19
  return typeof val =='number'? parseDecimal(val.toFixed(12)) : 0;
20
20
  }
21
21
 
22
- export const evalSingleValue = ({data,columnDef,field,columnField,withLabel,result,displayLabel,onlyVisible})=>{
23
- if(!isNonNullString(field) || !isObj(columnDef)) return result;
22
+ export const evalSingleValue = ({data,columnDef,field,count,columnField,aggregatorFunctions,withLabel,result,displayLabel,onlyVisible})=>{
23
+ if(!isNonNullString(field) || !isObj(columnDef) || !isObj(data)) return result;
24
+ aggregatorFunctions = defaultObj(aggregatorFunctions,mAggregatorFunctions);
24
25
  onlyVisible = defaultBool(onlyVisible,true);
25
26
  if(onlyVisible === true && !(columnDef.visible !== false)) result;
26
27
  let val = getFooterColumnValue({data,columnDef,columnField,result,field});
@@ -36,21 +37,27 @@ export const evalSingleValue = ({data,columnDef,field,columnField,withLabel,resu
36
37
  }
37
38
  }
38
39
  const obj = currentResult[field];
39
- obj.max = isDecimal(obj.max) ? Math.max(obj.max,val) : val;
40
- obj.min = isDecimal(obj.min) ? Math.min(obj.min,val) : val;
41
- obj.count = isDecimal(obj.count) ? (obj.count = obj.count +1) : 1;
42
- obj.sum = isDecimal(obj.sum) ? (parseDecimal((obj.sum+val).toFixed(10))) : val;
43
- obj.average = obj.sum / obj.count;
40
+ //obj.max = isDecimal(obj.max) ? Math.max(obj.max,val) : val;
41
+ //obj.min = isDecimal(obj.min) ? Math.min(obj.min,val) : val;
42
+ //obj.count = isDecimal(obj.count) ? obj.count : 0;
43
+ //obj.sum = isDecimal(obj.sum) ? (parseDecimal((obj.sum+val).toFixed(10))) : val;
44
+ Object.map(aggregatorFunctions,(aggegatorFunction,key)=>{
45
+ const code = aggegatorFunction.code;
46
+ obj[code] = aggegatorFunction.eval({columnDef,columnField,data,value : val,count,...obj,total:defaultNumber(obj[code])});
47
+ });
48
+ if(typeof obj.count =='number' && obj.count >0 && typeof obj.sum =='number'){
49
+ obj.average = obj.sum / obj.count;
50
+ }
44
51
  return currentResult;
45
52
  })
46
53
  return result;
47
54
  }
48
- export const evalValues = memoize(({data,columns,onlyVisible,withLabel,displayLabel})=>{
55
+ export const evalValues = memoize(({data,columns,aggregatorFunctions,onlyVisible,withLabel,displayLabel})=>{
49
56
  let result = {};
50
57
  Object.map(data,(rowData,i)=>{
51
58
  if(!isObj(rowData)) return result;
52
59
  Object.map(columns,(columnDef,field)=>{
53
- result = evalSingleValue({data:rowData,columnDef,field,result,withLabel,displayLabel,onlyVisible})
60
+ result = evalSingleValue({data:rowData,aggregatorFunctions,columnDef,field,result,withLabel,displayLabel,onlyVisible})
54
61
  })
55
62
  })
56
63
  return result;
@@ -65,7 +72,7 @@ export const evalValues = memoize(({data,columns,onlyVisible,withLabel,displayLa
65
72
  * @param : children {func}, fonction permettant de générer le contenu du footer
66
73
  */
67
74
  export default function DGGridFooters (props){
68
- let {columns,children,displayLabel,Component,data,onlyVisible,...rest} = props;
75
+ let {columns,children,displayLabel,aggregatorFunctions,Component,data,onlyVisible,...rest} = props;
69
76
  rest = defaultObj(rest)
70
77
  if(Component === false){
71
78
  Component = React.Fragment;
@@ -83,7 +90,7 @@ export default function DGGridFooters (props){
83
90
  React.useEffect(()=>{
84
91
  setState({...state,data:props.data})
85
92
  },[props.data]);
86
- let footers = evalValues({data:state.data,columns:state.columns,onlyVisible,displayLabel});
93
+ let footers = evalValues({data:state.data,aggregatorFunctions,columns:state.columns,onlyVisible,displayLabel});
87
94
  return <Component {...rest}>
88
95
  {children({
89
96
  footers,
@@ -18,7 +18,7 @@ const DatagridMainComponent = React.forwardRef((props,ref)=>{
18
18
  const AccordionComponent = isTableDataRef.current ? TableDataAccordion : Accordion;
19
19
  let Component = TableComponent;
20
20
  const canRenderAccordion = (isFunction(props.accordion) || (isObj(props.accordionProps) && isFunction(props.accordionProps.accordion)) || props.accordion === true);
21
- let renderType = defaultStr(getRenderType(),isDesk? "fixed":'accordion').trim().toLowerCase()
21
+ let renderType = defaultStr(getRenderType(),isDesk? "table":'accordion').trim().toLowerCase()
22
22
  if(renderType == 'accordion' && canRenderAccordion){
23
23
  Component = AccordionComponent;
24
24
  } else if(renderType =='table'){
@@ -18,9 +18,9 @@ const DatagridRenderTypeComponent = (props)=>{
18
18
  let type = defaultStr(get(typeKey),isDesk? "fixed":'accordion').toLowerCase().trim();
19
19
  const rTypes = [
20
20
  {...getActiveProps(type,'accordion'),tooltip:"Les éléments de liste s'affichent de manière optimisé pour téléphone mobile",code:'accordion',icon:accordionIcon,label:'Mobile',labelText:'environnement optimisé pour téléphone mobile'},
21
- //{...getActiveProps(type,'table'),tooltip:"Les éléments de listes s'affichent dans un tableau rééel",code:'table',icon:tableIcon,label:'Tableau réel avec pagination'}
21
+ {...getActiveProps(type,'table'),tooltip:"Les éléments de listes s'affichent dans un tableau",code:'table',icon:tableIcon,label:'Tableau'}
22
22
  ]
23
- Object.map(rendersTypes,(t,i)=>{
23
+ /*Object.map(rendersTypes,(t,i)=>{
24
24
  if(isObj(t)){
25
25
  if((isDesk && t.desktop) || (!isDesk && t.mobile)){
26
26
  rTypes.push({
@@ -29,7 +29,7 @@ const DatagridRenderTypeComponent = (props)=>{
29
29
  })
30
30
  }
31
31
  }
32
- });
32
+ });*/
33
33
  let typeObj = {};
34
34
  Object.map(rTypes,(t)=>{
35
35
  if(isObj(t) && t.code == type){
@@ -56,10 +56,11 @@ const DatagridFactory = (Factory)=>{
56
56
  const footerFields = this.getFootersFields();
57
57
  if(isObj(footerFields[columnField])){
58
58
  return <Footer
59
- //{...footerFields[columnField]}
60
59
  {...defaultObj(footersValues[columnField])}
61
60
  displayLabel = {false}
62
61
  style = {[style]}
62
+ aggregatorFunction = {this.getActiveAggregatorFunction().code}
63
+ aggregatorFunctions = {this.aggregatorFunctions}
63
64
  />
64
65
  }
65
66
  return null;
@@ -203,7 +204,7 @@ const DatagridFactory = (Factory)=>{
203
204
  <ScrollView horizontal showsHorizontalScrollIndicator={!isLoading} style={styles.paginationContainerStyle} contentContainerStyle={styles.minW100}>
204
205
  <View style={[styles.paginationContent]}>
205
206
  <View testID={testID+"_HeaderQueryLimit"}>
206
- {this.renderQueryLimit(this.state.data.length.formatNumber())}
207
+ {this.renderQueryLimit(this.getStateDataSize().formatNumber())}
207
208
  </View>
208
209
  {this.renderCustomPagination()}
209
210
  {!isMobile && <>
@@ -283,12 +284,14 @@ const DatagridFactory = (Factory)=>{
283
284
  ,icon : showFooters?'view-column':'view-module'
284
285
  ,text : (showFooters?'Masquer/Ligne des totaux':'Afficher/Ligne des totaux')
285
286
  } : null,
287
+ ...this.getAggregatorFunctionsMenuItems(),
286
288
  ...(selectableMultiple ? restItems : [])
287
289
  ] : visibleColumns}
288
290
 
289
291
  />
290
292
  {this.renderSectionListMenu()}
291
293
  {this.renderDisplayTypes()}
294
+ {!isMobile && this.renderAggregatorFunctionsMenu() || null}
292
295
  <View testID={testID+"_HeaderPagination"} style = {styles.paginationItem}>
293
296
  <BottomSheetMenu
294
297
  testID={testID+"_HeaderMenus"}
@@ -218,7 +218,9 @@ const styles = StyleSheet.create({
218
218
  flexDirection: 'row',
219
219
  flexWrap : "wrap",
220
220
  justifyContent: 'space-between',
221
- margin: 8,
221
+ margin: 0,
222
+ marginHorizontal : 10,
223
+ paddingRight : 10,
222
224
  borderRadius: 4,
223
225
  minHeight: 48,
224
226
  },