@fto-consult/expo-ui 2.1.0 → 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 +2 -2
- package/src/App.js +6 -0
- package/src/components/Date/DatePickerInput/index.js +6 -3
- package/src/components/Date/DateTime.js +79 -4
- package/src/components/Date/Time.js +24 -16
- package/src/components/Date/i18n.js +11 -0
- package/src/components/Filter/index.js +22 -12
- package/src/components/Form/Fields/DateTime.js +24 -0
- package/src/components/Form/Fields/index.js +2 -0
- package/src/components/Form/FormData/componentsTypes.js +4 -2
- package/src/components/Form/KeyboardEventHandler/index.js +10 -2
- package/src/components/Icon/Icon.js +4 -1
- package/src/components/TextField/index.js +3 -1
- package/src/navigation/Drawer/ProfilAvatar/index.js +3 -4
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fto-consult/expo-ui",
|
|
3
|
-
"version": "2.
|
|
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.
|
|
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);
|
|
@@ -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
|
|
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 = {
|
|
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 = {
|
|
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,
|
|
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(
|
|
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,
|
|
29
|
+
ret.value = timeToString(ret,withSeconds);
|
|
30
30
|
return ret;
|
|
31
31
|
}
|
|
32
|
-
const timeToString = (value,
|
|
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(
|
|
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,
|
|
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
|
-
|
|
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,
|
|
58
|
+
...parseTime(defaultValue,withSeconds),
|
|
59
59
|
})
|
|
60
60
|
const prevState = React.usePrevious(state,compareTimeState)
|
|
61
|
-
|
|
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
|
|
65
|
-
|
|
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,
|
|
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,
|
|
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
|
-
|
|
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
|
-
|
|
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 :
|
|
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;
|
|
@@ -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
|
-
|
|
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
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
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
|
|
|
@@ -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 = {
|
|
30
|
+
style = {flattenedStyle}
|
|
28
31
|
Component={React.isComponent(Component)?Component:IconButton}
|
|
29
32
|
ref = {ref}
|
|
30
33
|
/>
|
|
@@ -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
|
-
|
|
58
|
-
const
|
|
59
|
-
|
|
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)=>{
|