@fto-consult/expo-ui 2.0.14 → 2.2.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.0.14",
3
+ "version": "2.2.0",
4
4
  "description": "Bibliothèque de composants UI Expo,react-native",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -62,7 +62,7 @@
62
62
  "@expo/html-elements": "^0.2.0",
63
63
  "@expo/metro-config": "^0.4.0",
64
64
  "@expo/webpack-config": "^0.17.2",
65
- "@fto-consult/common": "^1.10.2",
65
+ "@fto-consult/common": "^1.11.1",
66
66
  "@gorhom/portal": "^1.0.14",
67
67
  "@react-native-async-storage/async-storage": "~1.17.3",
68
68
  "@react-native-community/datetimepicker": "6.5.2",
package/src/App.js CHANGED
@@ -26,6 +26,12 @@ import {isMobileNative} from "$cplatform";
26
26
  import {setDeviceIdRef} from "$capp";
27
27
  import appConfig from "$capp/config";
28
28
  import {showPrompt} from "$components/Dialog/confirm";
29
+ import * as Utils from "$utils";
30
+ Object.map(Utils,(v,i)=>{
31
+ if(typeof v =='function' && typeof window !='undefined' && window && !window[i]){
32
+ window[i] = v;
33
+ }
34
+ })
29
35
 
30
36
  export default function getIndex(options){
31
37
  const {App,onMount,onUnmount,preferences:appPreferences} = defaultObj(options);
@@ -17,7 +17,6 @@ let windowWidth = Dimensions.get("window").width;
17
17
  const FiltersAccordionComponent = React.forwardRef((props,ref)=>{
18
18
  const {filters,isLoading,filteredColumns,children,filterTitle:customFilterTitle,visible:customVisible,orOperator,andOperator,onToggleFilters,context:customContext,...restProps} = props;
19
19
  const context = defaultObj(customContext);
20
- const filtersValuesRef = React.useRef({});
21
20
  const [state,setState] = React.useState({
22
21
  visible : defaultBool(customVisible,false),
23
22
  visibleColumns : defaultObj(filteredColumns),
@@ -55,8 +54,7 @@ const FiltersAccordionComponent = React.forwardRef((props,ref)=>{
55
54
  }}
56
55
  />)
57
56
  if(!visible) return;
58
- const fOp = defaultObj(filtersValuesRef.current[key]);
59
- let defVal = isObj(filtersValuesRef.current[key]) ? filtersValuesRef.current[key].defaultValue : "";
57
+ let defVal = filter.defaultValue;
60
58
  if(typeof defVal !== 'string' && typeof defVal !=='boolean'){
61
59
  if(Array.isArray(defVal)){
62
60
  defVal = "["+defVal.join(",")+"]";
@@ -69,13 +67,11 @@ const FiltersAccordionComponent = React.forwardRef((props,ref)=>{
69
67
  mainFilterTitle +=(content.length?",":"")+"\n"+defaultStr(filter.label,filter.text,filter.field)+" : "+defVal+""
70
68
  content.push(<Filter
71
69
  {...filter}
72
- {...fOp}
73
70
  dynamicRendered
74
71
  isLoading = {isLoading && filteredRef.current[key] ? true : false}
75
72
  orOperator = {defaultBool(orOperator,filter.orOperator,true)}
76
73
  andOperator = {defaultBool(andOperator,filter.andOperator,true)}
77
74
  onChange = {(arg)=>{
78
- filtersValuesRef.current[key] = getFilterStateValues(arg);
79
75
  const canHandle = canHandleFilter(arg);
80
76
  if(filteredRef.current[key] !== canHandle){
81
77
  if(canHandle){
@@ -90,7 +86,6 @@ const FiltersAccordionComponent = React.forwardRef((props,ref)=>{
90
86
  }
91
87
  }}
92
88
  withBottomSheet
93
- //style = {[styles.filter,filter.style]}
94
89
  containerProps = {{...containerProps}}
95
90
  inputProps = {{containerProps}}
96
91
  />)
@@ -245,7 +245,7 @@ const DatagridFactory = (Factory)=>{
245
245
  getMaxSelectedRows(){
246
246
  return isMobileMedia()? 30 : 50;
247
247
  }
248
- renderFilter(props,headerFilters){
248
+ prepareFilter(props,headerFilters){
249
249
  return headerFilters.push(props);
250
250
  }
251
251
  showFilters(){
@@ -31,6 +31,7 @@ import copyToClipboard from "$capp/clipboard";
31
31
  import { Pressable } from "react-native";
32
32
  import TableLink from "$TableLink";
33
33
  import appConfig from "$capp/config";
34
+ import stableHash from "stable-hash"
34
35
 
35
36
  export const arrayValueSeparator = ", ";
36
37
 
@@ -115,10 +116,10 @@ export default class CommonDatagridComponent extends AppComponent {
115
116
  if(isPlainObject(f)){
116
117
  this.filters[v] = f;
117
118
  this.filters[v].field = defaultStr(f.field,v);
118
- this.filters[v].originalValue = defaultVal(this.filters[v].originalValue,f.defaultValue,f.value)
119
+ this.filters[v].originValue = defaultVal(this.filters[v].originValue,f.defaultValue,f.value)
119
120
  } else {
120
121
  this.filters[v] = {
121
- originalValue : f,
122
+ originValue : f,
122
123
  field : v
123
124
  }
124
125
  }
@@ -845,7 +846,9 @@ export default class CommonDatagridComponent extends AppComponent {
845
846
  if(removeFocus) document.body.click();
846
847
  });
847
848
  }
849
+ prepareFilter(props,filteredColumns){
848
850
 
851
+ }
849
852
  renderFilter(props){
850
853
  return <Filter {...props}/>
851
854
  }
@@ -884,7 +887,7 @@ export default class CommonDatagridComponent extends AppComponent {
884
887
  width,
885
888
  ...restCol
886
889
  } = header;
887
- restCol = defaultObj(restCol);
890
+ restCol = Object.clone(defaultObj(restCol));
888
891
  let colFilter = defaultVal(restCol.filter,true);
889
892
  field = header.field = defaultStr(header.field,field,headerIndex);
890
893
  delete restCol.filter;
@@ -899,7 +902,7 @@ export default class CommonDatagridComponent extends AppComponent {
899
902
  }
900
903
  totalWidths +=width;
901
904
  widths[header.field] = width;
902
- let colProps = {id,key}
905
+ const colProps = {id,key}
903
906
  colProps.key = isNonNullString(key)?key : (header.field||("datagrid-column-header-"+headerIndex))
904
907
  colProps.style = Object.assign({},StyleSheet.flatten(restCol.style));
905
908
  if(!visible){
@@ -937,7 +940,7 @@ export default class CommonDatagridComponent extends AppComponent {
937
940
  const sortedProps = isColumnSorted ? {...sortedColumn} : {};
938
941
  let filterProps = {};
939
942
  if(colFilter){
940
- let fCol = {...defaultObj(this.filters[header.field])}
943
+ const fCol = defaultObj(this.filters[header.field]);
941
944
  this.filters[header.field] = fCol;
942
945
  delete restCol.sortable;
943
946
  filterProps = {
@@ -948,14 +951,14 @@ export default class CommonDatagridComponent extends AppComponent {
948
951
  andOperator : filterAndOperator,
949
952
  searchIconTooltip : 'Filtre',
950
953
  searchIcon : 'filter_list',
951
- defaultValue : fCol.originalValue,
954
+ defaultValue : fCol.originValue,
952
955
  name : header.field,
953
956
  onClearFilter : this.onClearFilter.bind(this),
954
957
  onChange : this.onFilterChange.bind(this),
955
958
  operator : fCol.operator,
956
959
  action : defaultStr(fCol.originAction,fCol.action),
957
960
  };
958
- this.renderFilter(filterProps,headerFilters);
961
+ this.prepareFilter(filterProps,headerFilters);
959
962
  }
960
963
  this.prepareColumn({
961
964
  visible,
@@ -1129,7 +1132,7 @@ export default class CommonDatagridComponent extends AppComponent {
1129
1132
  if(!isObj(f)) return;
1130
1133
  defValue = undefined;
1131
1134
  if(f.type =="select") defValue = [];
1132
- filters[i] = {...f,value:defValue,defaultValue:defValue,originalValue:defValue}
1135
+ filters[i] = {...f,value:defValue,defaultValue:defValue,originValue:defValue}
1133
1136
  })
1134
1137
  this.filters = filters;
1135
1138
  this.refresh(true);
@@ -1155,7 +1158,7 @@ export default class CommonDatagridComponent extends AppComponent {
1155
1158
  field = defaultStr(field,name);
1156
1159
  if(field){
1157
1160
  let v = defaultStr(type).toLowerCase() == "select"? []:undefined
1158
- this.filters[field] = {value:v,defaultValue:v,originalValue:v,originValue:v}
1161
+ this.filters[field] = {value:v,defaultValue:v,originValue:v,originValue:v}
1159
1162
  this.doFilter({value:v,field,force:true})
1160
1163
  }
1161
1164
  }
@@ -1165,11 +1168,20 @@ export default class CommonDatagridComponent extends AppComponent {
1165
1168
  }
1166
1169
  onFilterChange(arg){
1167
1170
  this.filteredValues = defaultObj(this.filteredValues);
1168
- let {field,operator,action,value} = defaultObj(arg);
1171
+ let {field,operator,originAction,action,value} = defaultObj(arg);
1172
+ const filters = this.preparedColumns.filters;
1169
1173
  if(isNonNullString(field) && isNonNullString(operator) && isNonNullString(action)){
1170
1174
  this.filteredValues[field] = {
1171
1175
  operator,action,value,field
1172
1176
  }
1177
+ Object.map(filters,(filter)=>{
1178
+ if(isObj(filter) && filter.field == field){
1179
+ filter.originValue = filter.defaultValue = arg.defaultValue;
1180
+ filter.operator = operator;
1181
+ filter.action = defaultStr(originAction,action);
1182
+ }
1183
+ });
1184
+
1173
1185
  }
1174
1186
  return this.doFilter(arg);
1175
1187
  }
@@ -1369,8 +1381,11 @@ export default class CommonDatagridComponent extends AppComponent {
1369
1381
  }
1370
1382
  },isObj(p) && typeof p.force ==='boolean'?p.force : !this.state.isReady)
1371
1383
  }
1384
+ isTableData(){
1385
+ return false;
1386
+ }
1372
1387
  UNSAFE_componentWillReceiveProps(nextProps){
1373
- if('data' in nextProps && isObjOrArray(nextProps.data)){
1388
+ if(!this.isTableData() && 'data' in nextProps && isObjOrArray(nextProps.data) && nextProps.data != this.state.data && (stableHash(nextProps.data) != stableHash(this.state.data))){
1374
1389
  this.prepareData({data:nextProps.data,force:true},(state)=>{
1375
1390
  this.setState(state)
1376
1391
  });
@@ -2,6 +2,7 @@ import CommonDatagrid from "./Common";
2
2
  import {defaultObj,extendObj,defaultStr,isNonNullString,isFunction,isPromise} from "$utils";
3
3
  import actions from "$actions";
4
4
  import PropTypes from "prop-types";
5
+ import stableHash from "stable-hash";
5
6
 
6
7
  export default class CommonTableDatagrid extends CommonDatagrid{
7
8
  constructor(props){
@@ -13,12 +14,12 @@ export default class CommonTableDatagrid extends CommonDatagrid{
13
14
  } = props;
14
15
  dataSource = CommonDatagrid.getDataSource({...props,dataSource,context:this});
15
16
  tableName = defaultStr(tableName,table).toUpperCase();
17
+ this.prepareFetchData();
16
18
  if(tableName){
17
19
  Object.defineProperties(this,{
18
20
  tableName : {value:tableName,override:false,writable:false}
19
21
  })
20
22
  }
21
- this.INITIAL_STATE.fetchData = defaultVal(this.props.fetchData);
22
23
  let isPv = this.isPivotDatagrid();
23
24
  if(isPv){
24
25
  isPv = this.props.dbSelector !== false;
@@ -34,7 +35,9 @@ export default class CommonTableDatagrid extends CommonDatagrid{
34
35
  }
35
36
  this.state.isLoading = true;
36
37
  }
37
-
38
+ prepareFetchData(fetchData){
39
+ this.INITIAL_STATE.fetchData = defaultVal(fetchData,this.props.fetchData);
40
+ }
38
41
  /*** lorsque la données est modifiée */
39
42
  onUpsertData =(arg) =>{
40
43
  if(!this._isMounted()) return;
@@ -57,7 +60,9 @@ export default class CommonTableDatagrid extends CommonDatagrid{
57
60
  this.clearEvents();
58
61
  this.setSelectedRows();
59
62
  }
60
-
63
+ isTableData(){
64
+ return true;
65
+ }
61
66
  onChangeDataSources(args){
62
67
  let {dataSources,server} = args;
63
68
  this.currentDataSources = dataSources;
@@ -11,6 +11,7 @@ import TextField from "$ecomponents/TextField";
11
11
  import Icon from "$ecomponents/Icon";
12
12
  import {StyleSheet,View} from "react-native";
13
13
  import DatePickerModal from '../DatePickerModal'
14
+ import "../i18n";
14
15
 
15
16
  const validMinDate = (date,minDate)=>{
16
17
  if(!minDate || !date) return true;
@@ -55,6 +56,7 @@ const DatePickerInput = React.forwardRef(({
55
56
  visible : false
56
57
  })
57
58
  const inputFormat = useInputFormat(locale)
59
+ const inputFormatLabel = i18n.lang(inputFormat);
58
60
  const prevInputDate = React.usePrevious(state.inputDate,compareTwoDates)
59
61
  const formattedValue = !state.inputDate ? undefined : DateLib.format(state.inputDate,inputFormat.toLowerCase());
60
62
  const onDismiss = () => {
@@ -148,10 +150,10 @@ const DatePickerInput = React.forwardRef(({
148
150
  if(compareTwoDates(state.inputDate,prevInputDate) || state.errorText) return;
149
151
  if(onChange){
150
152
  const date = state.inputDate ? DateLib.toSQLDate(state.inputDate): undefined;
151
- onChange({dateObject:state.inputDate,date,sqlDate:date,value:date})
153
+ onChange({dateObject:state.inputDate,date:state.inputDate,sqlDate:date,value:date})
152
154
  }
153
155
  },[state])
154
- const labelText = render_filter ? label : withLabel!==false ? getLabel({ label, inputFormat, withDateFormatInLabel }):"";
156
+ const labelText = render_filter ? label : withLabel!==false ? getLabel({ label, inputFormat:inputFormatLabel, withDateFormatInLabel }):"";
155
157
  return (
156
158
  <>
157
159
  <TextField
@@ -166,8 +168,8 @@ const DatePickerInput = React.forwardRef(({
166
168
  ref={ref}
167
169
  label={labelText}
168
170
  defaultValue={formattedValue}
171
+ placeholder={inputFormatLabel}
169
172
  keyboardType={'number-pad'}
170
- placeholder={inputFormat}
171
173
  mask={inputFormat}
172
174
  keyboardAppearance={theme.dark ? 'dark' : 'default'}
173
175
  error={hasError}
@@ -176,6 +178,7 @@ const DatePickerInput = React.forwardRef(({
176
178
  return <TextInputWithMask
177
179
  {...inputProps}
178
180
  locale = {locale}
181
+ placeholder={inputFormatLabel}
179
182
  value = {formattedValue}
180
183
  style = {[inputProps.style,styles.input,style]}
181
184
  onChangeText={(date) => {
@@ -6,22 +6,90 @@ import Date from "./DatePickerInput";
6
6
  import Time from "./Time";
7
7
  import React from "$react";
8
8
  import PropTypes from "prop-types";
9
- import {defaultObj} from "$utils";
9
+ import {defaultObj,isNumber,defaultNumber,defaultStr,defaultBool,isNonNullString} from "$utils";
10
+ import theme,{flattenStyle} from "$theme";
11
+ import DateLib from "$date";
12
+ import { toDateObj } from "./utils";
10
13
 
11
- export default function DateTimePickerComponent({left,right,dateProps,timeProps,defaultValue,...porps}){
14
+ export default function DateTimePickerComponent({left,withSeconds,right,format,dateFormat,timeFormat,defaultValue,onChange,testID,dateProps,disabled,readOnly,timeProps,...rest}){
12
15
  dateProps = defaultObj(dateProps);
13
16
  timeProps = defaultObj(timeProps);
17
+ testID = defaultStr(testID,"RN_DateTimeComponent")
18
+ const anchorTimeProps = defaultObj(timeProps.anchorProps);
19
+ const timePropsContainerProps = defaultObj(timeProps.containerProps);
20
+ const defaultValueRef = React.useRef(toDateObj(defaultValue,format));
21
+ const dateObj = defaultValueRef.current;
22
+ if(isNonNullString(format)){
23
+ format = format.trim().split(" ");
24
+ if(!isNonNullString(dateFormat)){
25
+ dateFormat = format[0].trim();
26
+ }
27
+ if(!isNonNullString(timeFormat) && format[1]){
28
+ timeFormat = format[1].trim();
29
+ }
30
+ }
31
+ const changeDateArgsRef = React.useRef({});
32
+ const changedTimeArgsRef = React.useRef({});
33
+ withSeconds = defaultBool(timeProps.withSeconds,withSeconds,true);
34
+ const maxWidth = 120;//withSeconds ? 120 : 120;
35
+ const callOnChange = ()=>{
36
+ if(onChange){
37
+ const dObj = changeDateArgsRef.current;
38
+ const tObj = changedTimeArgsRef.current;
39
+ if(!DateLib.isValid(dObj.date) || !isNumber(tObj.hours) || !isNumber(tObj.minutes)) return;
40
+ const date = dObj.date;
41
+ date.setHours(tObj.hours);
42
+ date.setMinutes(tObj.minutes);
43
+ date.setSeconds(defaultNumber(tObj.seconds))
44
+ const sqlTime = date.toSQLTimeFormat();
45
+ const time = sqlTime.substring(0,withSeconds ?sqlTime.length :5);
46
+ const value = date.toFormat(defaultStr(dateFormat,DateLib.SQLDateFormat))+" "+time;
47
+ const args = {...dObj,...tObj,dateObject:date,date,sqlDateTime:date.toSQLDateTimeFormat(),value,sqlTime,time};
48
+ onChange(args);
49
+ }
50
+ }
14
51
  return <Date
15
- defaultValue = {defaultValue}
52
+ defaultValue = {dateObj}
53
+ disabled = {disabled}
54
+ readOnly = {readOnly}
55
+ testID = {testID}
56
+ {...rest}
57
+ format = {dateFormat}
16
58
  {...dateProps}
59
+ style = {[rest.style,dateProps.style]}
17
60
  calendarIconBefore = {true}
61
+ onChange = {(args)=>{
62
+ changeDateArgsRef.current = args;
63
+ callOnChange();
64
+ }}
18
65
  left = {left}
19
66
  right = {(p)=>{
20
67
  const r = typeof right =='function'? right(p): React.isValidElement(right)? right : null;
21
68
  return <>
22
69
  <Time
23
- defaultValue = {defaultValue}
70
+ defaultValue = {dateObj}
71
+ disabled = {disabled}
72
+ readOnly = {readOnly}
73
+ testID={testID+"_Time"}
74
+ format = {timeFormat}
24
75
  {...timeProps}
76
+ onChange = {(args)=>{
77
+ changedTimeArgsRef.current = args;
78
+ callOnChange();
79
+ }}
80
+ withLabel = {false}
81
+ mode = {"flat"}
82
+ containerProps = {{...timePropsContainerProps,style:[{maxWidth},timePropsContainerProps.style]}}
83
+ divider = {false}
84
+ anchorProps = {{
85
+ ...anchorTimeProps,
86
+ testID:testID+"_TimeAnchor",
87
+ style : [theme.styles.noPadding,{borderRadius:0},theme.styles.noMargin,anchorTimeProps.style]
88
+ }}
89
+ inputProps = {{
90
+ ...defaultObj(timeProps.inputProps),
91
+ mode : "flat",
92
+ }}
25
93
  />
26
94
  {r}
27
95
  </>
@@ -30,6 +98,13 @@ export default function DateTimePickerComponent({left,right,dateProps,timeProps,
30
98
  }
31
99
 
32
100
  DateTimePickerComponent.propTypes = {
101
+ ...Date.propTypes,
33
102
  dateProps : PropTypes.object,
34
103
  timeProps : PropTypes.object,
104
+ dateFormat : PropTypes.string, //Le format de date
105
+ timeFormat : PropTypes.string, //le format de time
106
+ defaultValue : PropTypes.oneOfType([
107
+ PropTypes.string,
108
+ PropTypes.object,
109
+ ])
35
110
  }
@@ -15,21 +15,21 @@ const compareTimeState = (a,b,ignoreVisible)=>{
15
15
  if(ignoreVisible !== true && a.visible !== b.visible) return false;
16
16
  return a.hours === b.hours && a.minutes === b.minutes;
17
17
  }
18
- const parseTime = (value,useSeconds)=>{
18
+ const parseTime = (value,withSeconds)=>{
19
19
  if(!isNonNullString(value)) return undefined;
20
20
  let split = value.trim().split(":");
21
21
  let ret = {
22
22
  hours:parseInt(split[0]) || 0,
23
23
  minutes : parseInt(split[1]) || 0,
24
24
  };
25
- if(useSeconds !== false){
25
+ if(withSeconds !== false){
26
26
  ret.seconds = parseInt(split[2]) || 0;
27
27
  }
28
28
  ret.date = getDate(ret.hours,ret.minutes,ret.seconds);
29
- ret.value = timeToString(ret,useSeconds);
29
+ ret.value = timeToString(ret,withSeconds);
30
30
  return ret;
31
31
  }
32
- const timeToString = (value,useSeconds)=>{
32
+ const timeToString = (value,withSeconds)=>{
33
33
  if(!isObj(value)) return undefined;
34
34
  let {hours,minutes,seconds} = value;
35
35
  if(hours ===undefined && minutes === undefined) return undefined;
@@ -38,31 +38,33 @@ const compareTimeState = (a,b,ignoreVisible)=>{
38
38
  seconds = defaultDecimal(seconds);
39
39
  const d = new Date(0, 0, 0, hours, minutes,seconds);
40
40
  value = d.toSQLTime();
41
- if(useSeconds !== false){
41
+ if(withSeconds !== false){
42
42
  return value;
43
43
  }
44
44
  return value.substring(0,5);
45
45
  }
46
46
  export default function TimePickerComponent (props){
47
- let {right:customRight,upper,anchorProps,dialogProps,withLabel,containerProps,mode,onChange,useSeconds,cancelLabel,confirmLabel,label,text,upperCase,defaultValue,disabled,editable,withModal,readOnly,...rest} = props;
47
+ let {right:customRight,upper,anchorProps,dialogProps,withLabel,containerProps,mode,onChange,withSeconds,cancelLabel,confirmLabel,label,text,upperCase,defaultValue,disabled,editable,withModal,readOnly,...rest} = props;
48
48
  rest = defaultObj(rest);
49
49
  const isEditable = disabled !== true && readOnly !== true && editable !== false?true : false;
50
50
  withModal = defaultBool(withModal,true);
51
51
  if(!isEditable){
52
52
  withModal = false;
53
53
  }
54
- useSeconds = defaultBool(useSeconds,false);
54
+ withSeconds = defaultBool(withSeconds,true);
55
55
  const prevDefaultValue = React.usePrevious(defaultValue);
56
56
  const [state,setState] = React.useStateIfMounted({
57
57
  visible : false,
58
- ...parseTime(defaultValue,useSeconds),
58
+ ...parseTime(defaultValue,withSeconds),
59
59
  })
60
60
  const prevState = React.usePrevious(state,compareTimeState)
61
- label = withLabel !== false ? defaultStr(label,text)+" (HH:MM"+(useSeconds !== false?":SS":"")+")":"";
61
+ const formatLabel = "HH:MM"+(withSeconds !== false?":SS":"");
62
+ label = withLabel !== false ? defaultStr(label,text)+"("+formatLabel+")":"";
62
63
  dialogProps = defaultObj(dialogProps);
63
64
  const onConfirm = ({ hours, minutes }) => {
64
- const value = hours !== undefined && minutes !== undefined ? timeToString({seconds:state.seconds,hours,minutes},useSeconds):undefined;
65
- setState({visible:false,seconds:value ? state.seconds:undefined,hours,minutes,value,date:value ? getDate(hours,minutes,useSeconds !== false ? seconds : 0):undefined})
65
+ const seconds = withSeconds ? state.seconds : 0;
66
+ const value = hours !== undefined && minutes !== undefined ? timeToString({seconds,hours,minutes},withSeconds):undefined;
67
+ setState({visible:false,seconds:value ? seconds:undefined,hours,minutes,value,date:value ? getDate(hours,minutes,seconds):undefined})
66
68
  };
67
69
  anchorProps = defaultObj(anchorProps);
68
70
  customRight = React.isValidElement(customRight) || typeof customRight =='function'? customRight : null;
@@ -76,6 +78,7 @@ const compareTimeState = (a,b,ignoreVisible)=>{
76
78
  setState({...state,visible:true});
77
79
  }}
78
80
  {...props}
81
+ style = {[props.style,anchorProps.style]}
79
82
  />
80
83
  {typeof customRight =='function'? customRight(props): customRight}
81
84
  </>
@@ -83,7 +86,7 @@ const compareTimeState = (a,b,ignoreVisible)=>{
83
86
  } else right = customRight;
84
87
  React.useEffect(()=>{
85
88
  if(prevDefaultValue !== defaultValue){
86
- const s = {...state,...parseTime(defaultValue,useSeconds)};
89
+ const s = {...state,...parseTime(defaultValue,withSeconds)};
87
90
  if(!defaultValue){
88
91
  s.hours = s.value = s.minutes = s.seconds = s.date = undefined;
89
92
  }
@@ -92,7 +95,7 @@ const compareTimeState = (a,b,ignoreVisible)=>{
92
95
  },[defaultValue]);
93
96
  React.useEffect(()=>{
94
97
  if(compareTimeState(state,prevState,true)) return;
95
- const value = isNumber(state.hours) && isNumber(state.minutes)? timeToString(state,useSeconds) : undefined;
98
+ const value = isNumber(state.hours) && isNumber(state.minutes)? timeToString(state,withSeconds) : undefined;
96
99
  if(onChange){
97
100
  onChange({...state,visible:undefined,value});
98
101
  }
@@ -104,7 +107,9 @@ const compareTimeState = (a,b,ignoreVisible)=>{
104
107
  setState({...state,visible:false})
105
108
  }
106
109
  containerProps = defaultObj(containerProps);
107
- mode = theme.textFieldMode;
110
+ if(!disabled){
111
+ containerProps.style = [containerProps.style,{opacity:1}]
112
+ }
108
113
  return <>
109
114
  <TouchableRipple {...containerProps}
110
115
  disabled = {!isEditable}
@@ -113,14 +118,17 @@ const compareTimeState = (a,b,ignoreVisible)=>{
113
118
  rippleColor={containerProps.rippleColor}
114
119
  >
115
120
  <TextField
121
+ mode = {mode||theme.textFieldMode}
116
122
  {...rest}
117
- mode = {mode}
118
123
  label = {label}
119
124
  right = {right}
120
125
  disabled = {disabled}
121
126
  editable = {false}
127
+ handleOpacity = {false}
128
+ style = {[rest.style,!disabled && {opacity:1,color:theme.colors.text}]}
122
129
  contentContainerProps = {{...defaultObj(rest.contentContainerProps),pointerEvents:'auto'}}
123
130
  defaultValue = {state.value}
131
+ placeholder = {formatLabel}
124
132
  />
125
133
  </TouchableRipple>
126
134
  {withModal && <TimePickerModal
@@ -150,5 +158,5 @@ const compareTimeState = (a,b,ignoreVisible)=>{
150
158
  dialogProps : PropTypes.shape({
151
159
  ...defaultObj(TimePickerModal.propTypes)
152
160
  }),
153
- useSeconds : PropTypes.bool, //si les sécondes devrons être utilisées
161
+ withSeconds : PropTypes.bool, //si les sécondes devrons être utilisées
154
162
  }
@@ -0,0 +1,11 @@
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
+ import i18n from "$i18n";
6
+
7
+ i18n.dictionary({
8
+ fr : {
9
+ "DD/MM/YYYY" : "JJ/MM/AAAA"
10
+ }
11
+ })
@@ -40,6 +40,7 @@ const _operators = {
40
40
  '$or' : 'Ou', //Array Matches if any of the selectors in the array match. All selectors must use the same index.
41
41
  }
42
42
 
43
+ /***** Coposant Filter, pour les filtres de données */
43
44
  export default class Filter extends AppComponent {
44
45
  constructor(props) {
45
46
  super(props);
@@ -81,7 +82,7 @@ export default class Filter extends AppComponent {
81
82
  })
82
83
  extendObj(this.state,{
83
84
  ...this.initFiltersOp(),
84
- manualRun : false,
85
+ manualRun : this.getSessionManualRunValue(),
85
86
  });
86
87
  this.autobind();
87
88
  }
@@ -95,13 +96,15 @@ export default class Filter extends AppComponent {
95
96
  };
96
97
  })
97
98
  }
99
+ getSessionManualRunValue(){
100
+ return getSessionData(manualRunKey) ? true : false
101
+ }
98
102
  willRunManually (){
99
103
  return this.state.manualRun;
100
- return getSessionData(manualRunKey) ? true : false
101
104
  }
102
105
  toggleManualRun(){
103
- //setSessionData(manualRunKey,this.willRunManually()?0:1);
104
106
  this.setState({manualRun:!this.state.manualRun},()=>{
107
+ setSessionData(manualRunKey,this.state.manualRun?0:1);
105
108
  if(!this.willRunManually()){
106
109
  this.fireValueChanged(true);
107
110
  }
@@ -150,7 +153,7 @@ export default class Filter extends AppComponent {
150
153
  } else if(type == 'select'){
151
154
  actions = _inActions;
152
155
  defaultAct = "$in";
153
- } else if(type == 'date') {
156
+ } else if(type == 'date' || type =='datetime') {
154
157
  actions = {$today:"Aujourd'hui",$prevWeek:"Semaine passée",$week:'Cette semaine',$month:'Ce mois',$period:"Période", ...actions}
155
158
  } else if(type !== 'date2time' && type !== 'time' && type !== 'number' && type !== 'decimal'){
156
159
  actions = regexActions;
@@ -170,7 +173,7 @@ export default class Filter extends AppComponent {
170
173
  if(!isObjOrArray(value) && (isNullOrEmpty(value,true) || value ==='undefined') ){
171
174
  value = undefined;
172
175
  }
173
- let originalValue = value;
176
+ let originValue = value;
174
177
  const type = defaultStr(this.props.type).toLowerCase().trim();
175
178
  value = parseDecimal(value,type);
176
179
  if(action =="$today"){
@@ -215,7 +218,7 @@ export default class Filter extends AppComponent {
215
218
  }
216
219
  }
217
220
  }
218
- this.props.onChange({...this.getStateValues(),value,originValue:originalValue,originalValue,field:this.props.field,action,operator,selector,originAction,context:this});
221
+ this.props.onChange({...this.getStateValues(),value,originValue:originValue,originValue,field:this.props.field,action,operator,selector,originAction,context:this});
219
222
  }
220
223
  }
221
224
  componentDidUpdate (){
@@ -358,6 +361,7 @@ export default class Filter extends AppComponent {
358
361
  ref,
359
362
  data,
360
363
  testID,
364
+ filterContainerProps,
361
365
  ...rest
362
366
  } = {...this.props,...this.filterProps};
363
367
  const type = this.type;
@@ -439,7 +443,7 @@ export default class Filter extends AppComponent {
439
443
  <Menu
440
444
  testID = {testID+"_Menu"}
441
445
  sheet = {withBottomSheet}
442
- anchor = {(props)=><Icon {...props} {...anchorProps} primary={hasFilterVal} icon={hasFilterVal?'filter-menu':'filter-plus'}/>}
446
+ anchor = {(props)=><Icon {...props} {...anchorProps} style={[theme.styles.noPadding,theme.styles.mt0,theme.styles.mb0,theme.styles.ml0,props.style,anchorProps.style]} primary={hasFilterVal} icon={hasFilterVal?'filter-menu':'filter-plus'}/>}
443
447
  items = {[
444
448
  {
445
449
  text : !isMob ? 'Options' : ("Options de filtre ["+label+"]"),
@@ -502,15 +506,21 @@ export default class Filter extends AppComponent {
502
506
  ]}
503
507
  />
504
508
  </>
505
- rest.containerProps = defaultObj(this.props.containerProps,rest.containerProps);
509
+ const containerProps = defaultObj(this.props.containerProps,rest.containerProps);
510
+ delete rest.containerProps;
506
511
  rest.onValidate = this.onFilterValidate.bind(this);
507
512
  const Component = this.Component;
508
- return <Component
509
- {...rest}
510
- name = {this.name}
511
- testID = {testID}
512
- ref = {React.mergeRefs(this.searchFilter,ref)}
513
- />
513
+ const responsiveProps = Object.assign({},responsiveProps);
514
+ responsiveProps.style = [theme.styles.w100,responsiveProps.style]
515
+ return <View testID={testID+"_FilterContainer"} {...containerProps} style={[theme.styles.w100,containerProps.style]}>
516
+ <Component
517
+ {...rest}
518
+ responsiveProps = {responsiveProps}
519
+ name = {this.name}
520
+ testID = {testID}
521
+ ref = {React.mergeRefs(this.searchFilter,ref)}
522
+ />
523
+ </View>
514
524
  }
515
525
  }
516
526
 
@@ -164,6 +164,10 @@ export const matchPouchDBOperator = (operator,value)=>{
164
164
  return {operator:"$lt",value}
165
165
  case "LTE":
166
166
  return {operator:"$lte",value}
167
+ case "IN":
168
+ return {operator:"$in",value}
169
+ case "NOT IN":
170
+ return {operator:"$in",value}
167
171
  }
168
172
  }
169
173
 
@@ -486,6 +490,7 @@ const operatorsMap = {
486
490
  $gte: '>=',
487
491
  $ne: '!=',
488
492
  $in: 'IN',
493
+ $nin : 'NOT IN',
489
494
  $eq: '=',
490
495
  $regex : "LIKE"
491
496
  }
@@ -0,0 +1,24 @@
1
+ import DateTime from "$ecomponents/Date/DateTime";
2
+ import {defaultObj} from "$utils";
3
+ import Field from"./Field";
4
+ import React from "react";
5
+ import DateLib from "$lib/date";
6
+
7
+ export default class FormDateTimeField extends Field{
8
+ getValidValue(){
9
+ const v = super.getValidValue();
10
+ return DateLib.isDateObj(v)? v.toSQLDateTime() : isNonNullString(v)? v : undefined;
11
+ }
12
+ _render(props){
13
+ props.onChange = (args)=>{
14
+ this.validate(args);
15
+ }
16
+ return <DateTime
17
+ {...props}
18
+ />
19
+ }
20
+ }
21
+
22
+ FormDateTimeField.propTypes = {
23
+ ...defaultObj(DateTime.propTypes),
24
+ }
@@ -8,6 +8,7 @@ import Checkbox from "./Checkbox";
8
8
  import Slider from "./Slider";
9
9
  import ColorPicker from "./Color";
10
10
  import Date from "./Date";
11
+ import DateTime from "./DateTime";
11
12
  import Time from "./Time";
12
13
  import Image from "./Image";
13
14
  import Tel from "./Tel";
@@ -26,6 +27,7 @@ export default {
26
27
  ,Slider
27
28
  ,ColorPicker
28
29
  ,Date
30
+ ,DateTime
29
31
  ,Time
30
32
  ,Image
31
33
  ,Tel
@@ -15,6 +15,8 @@ const componentTypes = {
15
15
  selectcountry : Fields.SelectCountry,
16
16
  date : Fields.Date,
17
17
  time : Fields.Time,
18
+ datetime : Fields.DateTime,
19
+ date2time : Fields.DateTime,
18
20
  checkbox : Fields.Checkbox,
19
21
  slider : Fields.Slider,
20
22
  color : Fields.ColorPicker,
@@ -92,8 +94,8 @@ export const getFilterComponentProps = (_props)=>{
92
94
  props = pR;
93
95
  props.items = [{code:checkedValue,label:checkedLabel},{code:uncheckedValue,label:uncheckedLabel}];
94
96
  component = Fields.SelectField;
95
- } else if(type == "date" || type =="time"){
96
- component = type === 'date'? Fields.Date : Fields.Time;
97
+ } else if(type == "date" || type =="time" || type =='datetime'){
98
+ component = type == 'datetime' ? Fields.DateTime : type === 'date'? Fields.Date : Fields.Time;
97
99
  } else if(type == 'color' || type =='colorpicker') {
98
100
  component = Fields.ColorPicker;
99
101
  } else {
@@ -3,6 +3,7 @@ import PropTypes from 'prop-types';
3
3
  import { findMatchedKey} from './keyEvents';
4
4
  import View from "$ecomponents/View";
5
5
  import {isWeb} from "$cplatform";
6
+ import {StyleSheet} from "react-native";
6
7
 
7
8
  let exclusiveHandlers = [];
8
9
 
@@ -90,7 +91,7 @@ export default class KeyboardEventHandler extends React.Component {
90
91
  children = children(events);
91
92
  }
92
93
  if(!React.isValidElement(children)) return null;
93
- return <View {...rest} ref={React.mergeRefs(this.childRef,innerRef)}>
94
+ return <View {...rest} style={[styles.content,rest.style]} ref={React.mergeRefs(this.childRef,innerRef)}>
94
95
  {children}
95
96
  </View>
96
97
  }
@@ -112,4 +113,11 @@ KeyboardEventHandler.defaultProps = {
112
113
  //handleEventType: 'keypress',
113
114
  handleEventType: undefined,
114
115
  onKeyEvent: () => null,
115
- };
116
+ };
117
+
118
+ const styles = StyleSheet.create({
119
+ content : {
120
+ maxWidth : '100%',
121
+ position : 'relative'
122
+ }
123
+ })
@@ -20,11 +20,14 @@ const IconComponentRef = React.forwardRef((props,ref)=>{
20
20
  }
21
21
  if(!rest.icon) return null;
22
22
  const flattenedStyle = flattenStyle(style);
23
+ if(button === false){
24
+ flattenedStyle.borderRadius = 0;
25
+ }
23
26
  return <Tooltip
24
27
  animated
25
28
  {...rest}
26
29
  color={Colors.isValid(color) ? color : Colors.isValid(flattenedStyle.color)? flattenedStyle.color : theme.colors.text}
27
- style = {[flattenedStyle,button === false ? {borderRadius:0}:null]}
30
+ style = {flattenedStyle}
28
31
  Component={React.isComponent(Component)?Component:IconButton}
29
32
  ref = {ref}
30
33
  />
@@ -13,9 +13,9 @@ import {styles as _styles} from "$theme";
13
13
  import Tooltip from "$ecomponents/Tooltip";
14
14
 
15
15
  const TableLinKComponent = React.forwardRef((props,ref)=>{
16
- let {disabled,labelProps,server,containerProps,id,columnDef,tableName,data,testID,Component,routeName,routeParams,component,primary,triggerProps,onPress,children, ...rest} = props;
16
+ let {disabled,labelProps,server,containerProps,id,columnDef,tableName,table:customTable,data,testID,Component,routeName,routeParams,component,primary,triggerProps,onPress,children, ...rest} = props;
17
17
  testID = defaultStr(testID,"RN_TableDataLinkContainer")
18
- tableName = defaultStr(tableName).trim();
18
+ tableName = defaultStr(tableName,customTable).trim();
19
19
  rest = defaultObj(rest);
20
20
  containerProps = defaultObj(containerProps)
21
21
  labelProps = defaultObj(labelProps);
@@ -55,6 +55,7 @@ const TextFieldComponent = React.forwardRef((componentProps,inputRef)=>{
55
55
  lower,
56
56
  dynamicBackgroundColor,
57
57
  lowerCase,
58
+ handleOpacity,
58
59
  ...props} = componentProps;
59
60
  upper = defaultBool(upper,upperCase,false);
60
61
  lower = defaultBool(lower,lowerCase,false);
@@ -218,7 +219,7 @@ const TextFieldComponent = React.forwardRef((componentProps,inputRef)=>{
218
219
  const pointerEvents = isEditable?"auto":'none';
219
220
  const upperStyle = text && (upper || lower) && !isAndroid ? {textTransform:upper?'uppercase':'lowercase'} : null;
220
221
  const opacity = disabled ? DISABLED_OPACITY : (useReadOnlyOpacity !== false && !error && (readOnly || editable === false)) ? READONLY_OPACITY : undefined;
221
- const disabledStyle = opacity ? {opacity} : undefined;
222
+ const disabledStyle = handleOpacity != false && opacity ? {opacity} : undefined;
222
223
  if((editable === false || disabled === true) ){
223
224
  selection = defaultObj(selection);
224
225
  if(!isNumber(selection.start)){
@@ -746,5 +747,6 @@ TextFieldComponent.propTypes = {
746
747
  ]),
747
748
  ///le style à afficher sur l'affix
748
749
  affixStyle : PropTypes.object,
750
+ handleOpacity : PropTypes.bool,///si l'opacité sera géré automatiquement en fonction du status disabled de la textField
749
751
  };
750
752
 
@@ -54,10 +54,9 @@ const UserProfileAvatarComponent = React.forwardRef(({drawerRef,...props},ref)=>
54
54
  }
55
55
  }
56
56
  ];
57
- let pseudo = defaultStr(u.code,u.pseudo,u.email)
58
- const label = defaultStr(u.label,u.name,u.fullName,u.userName,u.email)
59
- //let pT = pseudo;
60
- //pseudo = <Tooltip uppserCase={false} title={defaultStr(u.label)+" ["+pseudo+"]"}>{pT}</Tooltip>;
57
+ const userPseudo = Auth.getUserPseudo();
58
+ const pseudo = defaultStr(userPseudo,Auth.getUserEmail(),Auth.getUserCode());
59
+ const label = defaultStr(Auth.getUserFullName(),userPseudo)
61
60
  return <View ref ={ref}>
62
61
  <Menu
63
62
  anchor = { (aProps)=>{