@fto-consult/expo-ui 2.16.2 → 2.16.5

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.16.2",
3
+ "version": "2.16.5",
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.21.3",
64
+ "@fto-consult/common": "^1.22.8",
65
65
  "@gorhom/portal": "^1.0.14",
66
66
  "@react-native-async-storage/async-storage": "~1.17.3",
67
67
  "@react-native-community/datetimepicker": "6.5.2",
@@ -51,6 +51,7 @@ export const getThemeFieldProps = (props,ref)=>{
51
51
  const title = data && data.name ? ("Modifier ["+data.name+"]") : ('Nouv theme['+user.code+"]");
52
52
  const isEditing = isDocEditing(data);
53
53
  fields.textFieldMode.defaultValue = theme.textFieldMode;
54
+ fields.profilAvatarPosition.defaultValue = theme.profilAvatarPosition;
54
55
  Provider.open({
55
56
  cancelButton : true,
56
57
  dialogProps : {
@@ -81,7 +82,8 @@ export const getThemeFieldProps = (props,ref)=>{
81
82
  }
82
83
  data.custom = true;
83
84
  customThemes[data.name] = data;
84
- itemsRef.current = user.customThemes = customThemes;
85
+ itemsRef.current = {...customThemes,...getColors()};
86
+ user.customThemes = customThemes;
85
87
  open((isEditing?"Modification ":"Enregistrement ")+"du thème...");
86
88
  Auth.upsertUser(user,false).then(()=>{
87
89
  if(Auth.getLoggedUserCode() == user.code){
@@ -33,6 +33,13 @@ export const fields = {
33
33
  }
34
34
  }
35
35
  },
36
+ profilAvatarPosition : {
37
+ type : 'switch',
38
+ checkedValue : "drawer",
39
+ uncheckedValue : "appBar",
40
+ label : "Profil affiché sur le drawer",
41
+ checkedTooltip : "Votre profil avatar sera affiché sur la barre de navigation latéralle de l'application"
42
+ },
36
43
  textFieldMode : {
37
44
  type : 'select',
38
45
  items : {...modesObject,none:{code:'',label:'Dynamique'}},
@@ -7,7 +7,7 @@ import theme,{Colors,flattenStyle} from "$theme";
7
7
  import {StyleSheet} from "react-native";
8
8
  import {goBack as navGoBack,useNavigation,useRoute,useScreenOptions } from "$cnavigation";
9
9
  import PropTypes from "prop-types";
10
- import { Dimensions,TouchableWithoutFeedback} from "react-native";
10
+ import { Dimensions,View,TouchableWithoutFeedback} from "react-native";
11
11
  import Content from "./Content";
12
12
  import Icon from "$ecomponents/Icon";
13
13
  import {Elevations} from "$ecomponents/Surface";
@@ -35,6 +35,7 @@ const AppBarComponent = React.forwardRef((props,ref)=> {
35
35
  onUnmount,drawerType,options,allowDrawer,back,menuProps,appBarType,
36
36
  drawerRef,beforeGoBack,title,subtitle,titleProps,backAction,backActionProps,
37
37
  subtitleProps,testID,
38
+ right,
38
39
  onBackActionPress : customOnBackActionPress,actions,backActionRef,route,
39
40
  ...appBarProps} = props;
40
41
  const customOptions = options;
@@ -99,6 +100,7 @@ const AppBarComponent = React.forwardRef((props,ref)=> {
99
100
  context.forceUpdate = ()=>{
100
101
  return setLayout({...Dimensions.get("window")});
101
102
  }
103
+ const rightContent = typeof right =='function' ? right ({drawerRef,context,isMobile:Dimensions.isMobileMedia(),isDesktop:Dimensions.isDesktopMedia(),isTablet:Dimensions.isTabletMedia(),isPhone:Dimensions.isPhoneMedia(),dimensions,...dimensions}): right;
102
104
  const splitedActions = isSplitedActions(actions)? actions: splitActions({...appBarProps,windowWidth:layout.width,canGoBack:back || options.back?true:false,isAppBarAction:true,onBackActionPress,goBack,route,navigation,actions});
103
105
  const onPageResize = bindResizeEvent !== false ? (e)=>{
104
106
  if(!e || !e.nativeEvent || !e.nativeEvent.layout) return null;
@@ -128,6 +130,7 @@ const AppBarComponent = React.forwardRef((props,ref)=> {
128
130
  color : anchorStyle.color,
129
131
  }
130
132
  })}
133
+ {React.isValidElement(rightContent) && rightContent || right}
131
134
  </Appbar.Header>
132
135
  );
133
136
  });
@@ -144,7 +147,7 @@ const styles = StyleSheet.create({
144
147
  header : {
145
148
  paddingHorizontal : 5,
146
149
  paddingRight : 10,
147
- }
150
+ },
148
151
  })
149
152
 
150
153
  AppBarComponent.GO_BACK_EVENT = GO_BACK_EVENT;
@@ -14,7 +14,7 @@ export const ACTION_ICON_SIZE = 30;
14
14
  export const TITLE_FONT_SIZE = 16;
15
15
 
16
16
  export const getMaxActions = (windowWidth) => {
17
- let iWidth = typeof windowWidth =='number' && windowWidth > 200 ? windowWidth : getWindowSizes().width;
17
+ let iWidth = typeof windowWidth =='number' && windowWidth > 200 ? windowWidth : getWindowSizes().width - 100;
18
18
  return iWidth >= 3000 ? 8 : iWidth >= 2500? 7 : iWidth >= 2000 ? 6 : iWidth >= 1600 ? 5 : iWidth >= 1300 ? 4 : iWidth >= 800 ? 2 : iWidth >= 600 ? 1 : 0
19
19
  }
20
20
 
@@ -46,19 +46,23 @@ const Provider = React.forwardRef((props,innerRef)=>{
46
46
  const [state,setState] = React.useState({
47
47
  visible : defaultBool(props.visible,false),
48
48
  });
49
- const [context] = React.useState({
49
+ const context = {
50
50
  open : (props)=>{
51
+ if(state.visible) return;
51
52
  let bfOpen = typeof state.beforeOpen == 'function'? state.beforeOpen : typeof beforeOpen =='function'? beforeOpen : x=>true;
52
53
  if(bfOpen(state) === false) return;
53
54
  return setState({onDismiss:undefined,...defaultObj(props),visible:true})
54
55
  },
55
56
  close : (props)=>{
56
- return setState({...state,...props,visible:false});
57
+ if(!state.visible) return;
58
+ return setState({...state,...props,visible:false});
57
59
  },
58
- });
60
+ };
59
61
  React.setRef(ref,context);
60
62
  return <Dialog {...props} {...state} controlled onDismiss = {(e)=>{
61
- setState({...state,visible:false});
63
+ if(state.visible){
64
+ setState({...state,visible:false});
65
+ }
62
66
  if(typeof state.onDismiss =='function'){
63
67
  state.onDismiss({context,state});
64
68
  } else if(onDismiss){
@@ -220,7 +220,7 @@ const DrawerComponent = React.forwardRef((props,ref)=>{
220
220
 
221
221
  const getDrawerRef = x=> drawerRef;
222
222
  ///lorsque le drawer est en mode permanent, l'icone par défaut est l'icon devant le dépingler du mode permanent
223
- const backIcon = isLeftPosition ? "arrow-left" : "arrow-right";
223
+ const backIcon = "window-close";//isLeftPosition ? "arrow-left" : "arrow-right";
224
224
  const chevronIcon = isLeftPosition ? "chevron-left":"chevron-right";
225
225
  temporaryToggleIcon = React.isValidElement(temporaryToggleIcon)? temporaryToggleIcon : backIcon;
226
226
  permanentToggleIcon = React.isValidElement(permanentToggleIcon)? permanentToggleIcon : chevronIcon;
@@ -1,5 +1,5 @@
1
1
  import {isMobileOrTabletMedia} from "$cplatform/dimensions";
2
- import {isNativeMobile} from "$cplatform";
2
+ import {isNativeMobile,isTouchDevice} from "$cplatform";
3
3
 
4
4
  export const matchOperators = /[|\\{}()[\]^$+*?.]/g;
5
5
 
@@ -15,5 +15,8 @@ export const getSearchTimeout = (itemCount)=>{
15
15
  /**** voir si le champ de recherche du composant peut être autofocus enf onction du nombre d'items et du type d'environnement */
16
16
  export const canAutoFocusSearchField = ({visible,items})=>{
17
17
  const count = typeof items =='number'? items : typeof (items) === 'object' ? Object.size(items) : 0;
18
- return visible && (!isNativeMobile() || count > MAX_AUTO_FOCUS_ITEMS) ? true : false;
18
+ if(!visible) return false;
19
+ const ret = count > MAX_AUTO_FOCUS_ITEMS && true || false;
20
+ if(!isNativeMobile() && !isTouchDevice()) return ret;
21
+ return isNativeMobile()? ret : false;
19
22
  }
@@ -79,7 +79,9 @@ const FormDataDialogProvider = React.forwardRef((props,innerRef)=>{
79
79
  dialogProps = {dialogProps}
80
80
  controlled={false}
81
81
  onDismiss = {(e)=>{
82
- setState({...state,visible:false});
82
+ if(state.visible){
83
+ setState({...state,visible:false});
84
+ }
83
85
  if(typeof state.onDismiss =='function'){
84
86
  state.onDismiss({context,state});
85
87
  } else if(onDismiss){
@@ -4,16 +4,18 @@ import View from "$ecomponents/View";
4
4
  import React from "$react";
5
5
  import theme,{remToPixel,Colors,flattenStyle} from '$theme';
6
6
  import {StyleSheet} from "react-native";
7
- import {defaultStr} from "$utils";
7
+ import {defaultStr,defaultObj,defaultNumber} from "$utils";
8
8
  import LogoComponent from "$logoComponent";
9
9
 
10
10
  export const height = 150;
11
11
  export const width = undefined;//300;
12
- export default class Logo extends Component {
13
- render(props){
14
- let {icon,color,style,testID,logo,text} = this.props;
12
+ export default function Logo (props) {
13
+ let {icon,color,style,testID,containerProps,smallStyle,largeStyle,mediumStyle,height:customHeight,withImage,withText} = props;
15
14
  testID = defaultStr(testID,"RN_LogoComponent");
16
- const styles = getStyle(style,color);
15
+ containerProps = defaultObj(containerProps);
16
+ customHeight =defaultNumber(customHeight,height);
17
+ const hasHeight = customHeight && customHeight != height? true : false;
18
+ const styles = getStyle({style,color,height:hasHeight?customHeight:undefined,smallStyle,largeStyle,mediumStyle});
17
19
  let logoImage = null,img,txt=null,hasTwice = false;
18
20
  if(LogoComponent){
19
21
  hasTwice = React.isComponent(LogoComponent.Image) && React.isComponent(LogoComponent.Text);
@@ -23,26 +25,30 @@ export default class Logo extends Component {
23
25
  img = icon !== false ? <View testID={testID+"_ContentContainer"} style={styles.logoImage}>
24
26
  <LogoComponent.Image styles={styles}/>
25
27
  </View> : null;
26
- txt = text !== false ? <LogoComponent.Text style={styles.logoContent} styles={styles}/> : null;
28
+ txt = withText !== false && React.isComponent(LogoComponent.Text) ? <LogoComponent.Text style={styles.logoContent} styles={styles}/> : null;
27
29
  }
28
30
  }
29
- return <View testID={testID} style={styles.container}>
30
- {hasTwice ? img : null}
31
+ return <View testID={testID} style={[styles.container,hasHeight && {height:customHeight}]}>
32
+ {hasTwice && withImage !== false ? img : null}
31
33
  {hasTwice? txt : null}
32
34
  {!hasTwice ? logoImage : null}
33
35
  </View>
34
- }
35
-
36
- }
36
+ }
37
37
 
38
- const getStyle = (style,color)=>{
39
- const cColor = flattenStyle([{color:Colors.isValid(color)? color : theme.colors.primary}]);
38
+ const getStyle = ({style,color,height:customHeight,smallStyle,mediumStyle,largeStyle})=>{
39
+ const cColor = flattenStyle([{color:Colors.isValid(color)? color : theme.colors.primaryOnSurface}]);
40
+ let size = 5;
41
+ if(typeof customHeight =='number' && customHeight <= customHeight){
42
+ const divider = Math.min(size,Math.max(Math.ceil(height/customHeight),2));
43
+ size = divider <= 2 ? 2 : divider;
44
+ }
45
+ let smallSize = size/2, medium = (3/4)*size;
40
46
  return {
41
47
  ...styles,
42
- container : flattenStyle([styles.container,cColor,style]),
43
- firstText : flattenStyle([styles.medium,cColor]),
44
- large : flattenStyle([styles.medium,styles.large,cColor]),
45
- small : flattenStyle([styles.medium,cColor,styles.small]),
48
+ container : flattenStyle([styles.container,style]),
49
+ large : flattenStyle([styles.large,styles.large,{color:theme.colors.secondaryOnSurface,fontSize:remToPixel(size)},largeStyle]),
50
+ medium : flattenStyle([styles.medium,cColor,{fontSize:remToPixel(medium)},mediumStyle]),
51
+ small : flattenStyle([styles.small,cColor,styles.small,{fontSize:remToPixel(smallSize)},smallStyle]),
46
52
  };
47
53
  }
48
54
 
@@ -88,4 +94,5 @@ const styles = StyleSheet.create({
88
94
  })
89
95
 
90
96
  Logo.height = height;
91
- Logo.width = width;
97
+ Logo.width = width;
98
+ Logo.displayName = "ExpoLogoComponent";
@@ -0,0 +1,200 @@
1
+ import {defaultObj} from "$utils";
2
+ import i18n from "$i18n"
3
+ import Auth from "$cauth";
4
+ import Menu from "$ecomponents/Menu";
5
+ import React from "$react";
6
+ import { screenName } from "$escreens/Auth/utils";
7
+ import Image from "$ecomponents/Image";
8
+ import { StyleSheet,View,Pressable} from "react-native";
9
+ import avatarProps from "$eauth/avatarProps";
10
+ import Button from "$ecomponents/Button";
11
+ import Label from "$ecomponents/Label";
12
+ import Icon from "$ecomponents/Icon";
13
+ import {navigate} from "$cnavigation";
14
+ import theme from "$theme";
15
+ import {isMobileNative} from "$cplatform";
16
+ import appConfig from "$capp/config";
17
+ import Preloader from "$preloader";
18
+ import {defaultNumber} from "$utils";
19
+ import Tooltip from "$ecomponents/Tooltip";
20
+ const UserProfileAvatarComponent = React.forwardRef(({drawerRef,chevronIconProps:customChevronIconProps,size,withLabel,...props},ref)=>{
21
+ let u = defaultObj(Auth.getLoggedUser());
22
+ const deviceNameRef = React.useRef(null);
23
+ const deviceName = appConfig.deviceName;
24
+ customChevronIconProps = defaultObj(customChevronIconProps);
25
+ props = defaultObj(props);
26
+ const closeDrawer = cb => {
27
+ if(drawerRef && drawerRef.current && drawerRef.current.close){
28
+ return drawerRef && drawerRef.current && drawerRef.current.close(cb);
29
+ }
30
+ return typeof cb =='function'? cb() : null;
31
+ }
32
+ if(withLabel === undefined){
33
+ withLabel = theme.showAvatarProfileOnDrawer;
34
+ }
35
+ withLabel = withLabel !== false ? true : false;
36
+ props.src = u.avatar;
37
+ size = defaultNumber(size,!withLabel?40:40);
38
+ const userPseudo = Auth.getUserPseudo();
39
+ const pseudo = defaultStr(userPseudo,Auth.getUserEmail(),Auth.getUserCode());
40
+ const label = defaultStr(Auth.getUserFullName(),userPseudo);
41
+ const onLongPress = ()=>{
42
+ appConfig.setDeviceId().then((r)=>{
43
+ if(deviceNameRef.current && deviceNameRef.current.update){
44
+ deviceNameRef.current.update(r?("["+r+"]"):"");
45
+ }
46
+ });
47
+ };
48
+ const tooltip = "Pressez longtemps pour définir un identifiant unique pour l'appareil";
49
+ const children = <View style={styles.labelContainer}>
50
+ <Label splitText numberOfLines={1} style={{color:theme.colors.primaryOnSurface,fontSize:15}}>{pseudo}</Label>
51
+ <Label splitText numberOfLines={1} style={{fontSize:12,color:theme.colors.secondaryOnSurface,marginTop:6}}>
52
+ {label}
53
+ </Label>
54
+ {deviceName && <Label.withRef textBold splitText title={"Identifiant unique de l'application, installé sur cet appareil"} ref={deviceNameRef} secondary style={{fontSize:10}}>
55
+ [{deviceName}]
56
+ </Label.withRef> || null}
57
+ </View>
58
+ const menItems = [
59
+ !withLabel && {
60
+ text : <Tooltip tooltip={tooltip} Component={Pressable} onLongPress={onLongPress} testID={"RNProfilAvatar_ContainerMenu"}>
61
+ {children}
62
+ </Tooltip>,
63
+ closeOnPress : false,
64
+ divider : true,
65
+ },
66
+ {
67
+ label : i18n.lang("preferences",'Préférences'),
68
+ icon : "account-cog",
69
+ onPress : (a)=>{
70
+ closeDrawer(()=>{
71
+ return navigate({
72
+ routeName : screenName,
73
+ params : {
74
+ user : u,
75
+ }
76
+ })
77
+ });
78
+ }
79
+ },
80
+ {
81
+ label : i18n.lang("logout",'Déconnexion'),
82
+ icon : "logout",
83
+ onPress : (a)=>{
84
+ closeDrawer(()=>{
85
+ Preloader.open("Déconnexion en cours...");
86
+ Auth.signOut().finally(Preloader.close)
87
+ });
88
+ }
89
+ }
90
+ ];
91
+
92
+ const onChangeAvatar = ({dataURL})=>{
93
+ if(u.avatar === dataURL) {
94
+ return;
95
+ }
96
+ if(!dataURL){
97
+ u.avatar = null;
98
+ } else {
99
+ u.avatar = dataURL;
100
+ }
101
+ Auth.upsertUser({...u,avatar:u.avatar},false);
102
+ }
103
+
104
+ return <View ref ={ref}>
105
+ <Menu
106
+ anchor = { (aProps)=>{
107
+ const chevronIconProps = {
108
+ size : 20,
109
+ icon : "chevron-down",
110
+ secondary : true,
111
+ ...customChevronIconProps,
112
+ ...aProps,
113
+ style : [styles.icon,withLabel=== false && {color:theme.colors.primaryText},customChevronIconProps.style],
114
+ }
115
+ if(!withLabel){
116
+ return <View testID={"RNProfilAvatar_AvatarContainer"} style={[theme.styles.row,theme.styles.alignItemsCenter]}>
117
+ <Image
118
+ {...props}
119
+ {...aProps}
120
+ size={size}
121
+ style = {styles.itemLeft}
122
+ testID = {"RN_ProfilAvatar_Avatar"}
123
+ editable
124
+ defaultSource ={avatarProps.defaultSrc}
125
+ onChange = {onChangeAvatar}
126
+ />
127
+ <Icon
128
+ {...chevronIconProps}
129
+ {...aProps}
130
+ style = {[chevronIconProps.style,{marginLeft:-5}]}
131
+ />
132
+ </View>
133
+ }
134
+ return <Button
135
+ normal
136
+ upperCase = {false}
137
+ disableRipple
138
+ title = {tooltip}
139
+ {...aProps}
140
+ style = {[styles.container]}
141
+ surfaceProps = {{style:[theme.styles.noMargin,theme.styles.noPadding]}}
142
+ onLongPress = {onLongPress}
143
+ left={props1 => <Image
144
+ {...props}
145
+ {...props1}
146
+ size={size}
147
+ style = {styles.itemLeft}
148
+ testID = {"RN_ProfilAvatar_AvatarImage"}
149
+ editable
150
+ defaultSource ={avatarProps.defaultSrc}
151
+ onChange = {onChangeAvatar}
152
+ />}
153
+ right = {(p)=>{
154
+ return <Icon
155
+ {...p}
156
+ {...chevronIconProps}
157
+ />
158
+ }}
159
+ >
160
+ {children}
161
+ </Button>
162
+ } }
163
+ items={menItems}
164
+ />
165
+ </View>
166
+ });
167
+
168
+ const styles = StyleSheet.create({
169
+ itemLeft : {
170
+ marginHorizontal : 5,
171
+ marginTop : isMobileNative()? 10 : 0,
172
+ },
173
+ container : {
174
+ marginLeft : 0,
175
+ marginVertical : 10,
176
+ },
177
+ labelContainer : {
178
+ flexDirection : 'column',
179
+ paddingRight : 5,
180
+ maxWidth : 150,
181
+ minWidth : 100,
182
+ },
183
+ pseudo : {
184
+ flexDirection : "row",
185
+ justifyContent : "center",
186
+ alignItems : "center"
187
+ },
188
+ appName : {
189
+ marginLeft : 5,
190
+ fontWeight : "bold",
191
+ },
192
+ icon : {
193
+ marginHorizontal:0,
194
+ paddingHorizontal : 0,
195
+ }
196
+ })
197
+
198
+ export default UserProfileAvatarComponent;
199
+
200
+ UserProfileAvatarComponent.displayName = "UserProfileAvatarComponent";
@@ -4,10 +4,14 @@
4
4
 
5
5
  import Container from "$cauth/Container";
6
6
  import ScreenWithOrWithoutAuthContainer from "./ScreenWithOrWithoutAuthContainer";
7
+ import ProfilAvatar from "$elayouts/ProfilAvatar";
7
8
 
8
9
  export default function MainScreenComponent(props){
9
10
  return <ScreenWithOrWithoutAuthContainer
10
11
  {...props}
12
+ renderProfilAvatar = {(props)=>{
13
+ return <ProfilAvatar withLabel = {false} {...props} />
14
+ }}
11
15
  renderChildren = {({containerProps,children})=>{
12
16
  return <Container {...containerProps}>
13
17
  {children}
@@ -51,12 +51,17 @@ export default function MainScreenScreenWithOrWithoutAuthContainer(props) {
51
51
  screenName,
52
52
  containerProps,
53
53
  testID,
54
+ profilAvatarProps,
55
+ profilAvatarContainerProps,
54
56
  renderChildren,
57
+ renderProfilAvatar,
55
58
  ...rest
56
59
  } = getScreenProps(props);
57
60
  const insets = useSafeAreaInsets();
58
61
  testID = defaultStr(testID,"RN_MainScreenScreenWithOrWithoutAuthContainer")
59
62
  containerProps = defaultObj(containerProps);
63
+ profilAvatarContainerProps = defaultObj(profilAvatarContainerProps);
64
+ profilAvatarProps = defaultObj(profilAvatarProps);
60
65
  const backgroundColor = theme.colors.background;
61
66
  const containerStyle = [
62
67
  styles.container,
@@ -83,6 +88,7 @@ export default function MainScreenScreenWithOrWithoutAuthContainer(props) {
83
88
  if(authRequired === false){
84
89
  withFab = false;
85
90
  }
91
+ const withProfilAvatarOnAppBar = withDrawer && !theme.showAvatarProfileOnDrawer ? true : false;
86
92
  React.useEffect(() => {
87
93
  if((title||subtitle) && navigation && navigation.setOptions){
88
94
  const appName = APP.getName().toUpperCase();
@@ -107,11 +113,22 @@ export default function MainScreenScreenWithOrWithoutAuthContainer(props) {
107
113
  {...fabProps}
108
114
  screenName={screenName}
109
115
  /> : null;
116
+ const profilAvatar = typeof renderProfilAvatar =='function'? renderProfilAvatar(profilAvatarProps) : null;
110
117
  const child = <>
111
118
  {withStatusBar !== false ? <StatusBar/> : null}
112
119
  <ErrorBoundary testID={testID+"_ScreenLayoutErrorBoundary"}>
113
120
  <View testID={testID} {...containerProps} style={[styles.container,{backgroundColor},modal && styles.modal]}>
114
- {appBar === false ? null : React.isValidElement(appBar)? state.AppBar : <AppBar testID={testID+'_AppBar'} {...appBarProps} backAction = {defaultVal(appBarProps.backAction,backAction)} elevation={defaultNumber(appBarProps.elevation,elevation)} withDrawer={withDrawer} options={options} ref={appBarRef} title={title} subtitle={subtitle}/>}
121
+ {appBar === false ? null : React.isValidElement(appBar)? state.AppBar : <AppBar
122
+ testID={testID+'_AppBar'} {...appBarProps}
123
+ backAction = {defaultVal(appBarProps.backAction,backAction)}
124
+ elevation={defaultNumber(appBarProps.elevation,elevation)}
125
+ withDrawer={withDrawer} options={options}
126
+ ref={appBarRef} title={title}
127
+ subtitle={subtitle}
128
+ right = {withProfilAvatarOnAppBar && <View testID={testID+"_ProfilAvatar_Container"} {...profilAvatarContainerProps} style={[profilAvatarContainerProps.style,styles.profilAvatarContainer]} >
129
+ {React.isValidElement(profilAvatar) && profilAvatar || null}
130
+ </View> || null}
131
+ />}
115
132
  {withScrollView !== false ? (
116
133
  <ScrollView
117
134
  testID = {testID+'_ScreenContentScrollView'}
@@ -113,7 +113,10 @@ export default class TableDataScreenComponent extends FormDataScreen{
113
113
  context.onNoValidate({...args,msg:message,message,context,validRule:context.getValidRule()});
114
114
  }
115
115
  }).catch((e)=>{
116
-
116
+ const message = defaultStr(e?.message,e?.msg);
117
+ if(message){
118
+ context.onNoValidate({...args,msg:message,message,error:e,context,validRule:context.getValidRule()});
119
+ }
117
120
  })
118
121
  }
119
122
  }
@@ -1,17 +1,24 @@
1
1
  import Drawer,{DrawerItems} from "$ecomponents/Drawer";
2
- import ProfilAvatar from "./ProfilAvatar";
2
+ import ProfilAvatar from "$elayouts/ProfilAvatar";
3
3
  import React from "$react";
4
4
  import items,{isItemActive,refresh as refreshItems} from "./items";
5
5
  import APP from "$capp/instance";
6
6
  import Auth from "$cauth";
7
7
  import Login from "$eauth/Login";
8
8
  import {navigate} from "$cnavigation";
9
+ import theme from "$theme";
10
+ import Label from "$ecomponents/Label";
11
+ import Logo from "$ecomponents/Logo";
9
12
 
10
13
  const DrawerNavigator = React.forwardRef(({content,children,state,...props},ref)=>{
11
14
  const drawerRef = React.useRef(null);
12
15
  const mergedRefs = React.useMergeRefs(drawerRef,ref);
13
16
  const headerCB = ({isMinimized})=>{
14
- return isMinimized ? null : <ProfilAvatar ref={uProfileRef} drawerRef={drawerRef}/>;
17
+ if(isMinimized) return null;
18
+ if(!theme.showAvatarProfileOnDrawer){
19
+ return <Logo height = {70} withImage = {false} style={[theme.styles.justifyContentFlexStart,{maxWidth:220,overflow:'hidden'}]}/>
20
+ }
21
+ return <ProfilAvatar ref={uProfileRef} drawerRef={drawerRef}/>;
15
22
  };
16
23
  const isAuthLoggedIn = Auth.isLoggedIn();
17
24
  const [isLoggedIn,setIsLoggedIn] = React.useState(isAuthLoggedIn);
@@ -9,9 +9,10 @@ import APP from "$capp";
9
9
  ///les items du drawer
10
10
  import items from "$drawerItems";
11
11
  import { screenName as aboutScreenName} from "$escreens/Help/About";
12
+ import theme from "$theme";
12
13
 
13
14
  export const getItems = (force)=>{
14
- const name = APP.getName();
15
+ const name = !theme.showAvatarProfileOnDrawer ? 'Dashboard' : APP.getName();
15
16
  const itx = typeof items === "function" ? items() : items;
16
17
  const handleHelp = appConfig.get("handleHelpScreen") !== false ? true : false;
17
18
  const r = [
@@ -8,7 +8,7 @@ import {SignIn2SignOut} from "$cauth";
8
8
  import React from "$react";
9
9
  import avatarProps from "$eauth/avatarProps";
10
10
 
11
- export const screenName = "UserProfile";
11
+ import {screenName} from "./utils";
12
12
 
13
13
  export default function UserProfileScreen(prs){
14
14
  const props = getScreenProps(prs);
@@ -2,4 +2,6 @@ import APP from "$capp/instance";
2
2
  import i18n from "$i18n";
3
3
 
4
4
  export const getTitle = x => APP.name+" "+APP.version+"/"+i18n.lang("login");
5
- export const title = getTitle();
5
+ export const title = getTitle();
6
+
7
+ export const screenName = "UserProfile";
@@ -1,157 +0,0 @@
1
- import {defaultObj} from "$utils";
2
- import i18n from "$i18n"
3
- import Auth from "$cauth";
4
- import Menu from "$ecomponents/Menu";
5
- import React from "$react";
6
- import { screenName } from "$escreens/Auth/Profile";
7
- import Image from "$ecomponents/Image";
8
- import { StyleSheet,View} from "react-native";
9
- import avatarProps from "$eauth/avatarProps";
10
- import Button from "$ecomponents/Button";
11
- import Label from "$ecomponents/Label";
12
- import Icon from "$ecomponents/Icon";
13
- import {navigate} from "$cnavigation";
14
- import theme from "$theme";
15
- import {isMobileNative} from "$cplatform";
16
- import appConfig from "$capp/config";
17
- import Preloader from "$preloader";
18
- const UserProfileAvatarComponent = React.forwardRef(({drawerRef,...props},ref)=>{
19
- let u = defaultObj(Auth.getLoggedUser());
20
- const deviceNameRef = React.useRef(null);
21
- const deviceName = appConfig.deviceName;
22
- props = defaultObj(props);
23
- const closeDrawer = cb => {
24
- if(drawerRef && drawerRef.current && drawerRef.current.close){
25
- return drawerRef && drawerRef.current && drawerRef.current.close(cb);
26
- }
27
- return typeof cb =='function'? cb() : null;
28
- }
29
- props.src = u.avatar;
30
- props.size = 60;
31
- const menItems = [
32
- {
33
- label : i18n.lang("preferences",'Préférences'),
34
- icon : "account-cog",
35
- onPress : (a)=>{
36
- closeDrawer(()=>{
37
- return navigate({
38
- routeName : screenName,
39
- params : {
40
- user : u,
41
- }
42
- })
43
- });
44
- }
45
- },
46
- {
47
- label : i18n.lang("logout",'Déconnexion'),
48
- icon : "logout",
49
- onPress : (a)=>{
50
- closeDrawer(()=>{
51
- Preloader.open("Déconnexion en cours...");
52
- Auth.signOut().finally(Preloader.close)
53
- });
54
- }
55
- }
56
- ];
57
- const userPseudo = Auth.getUserPseudo();
58
- const pseudo = defaultStr(userPseudo,Auth.getUserEmail(),Auth.getUserCode());
59
- const label = defaultStr(Auth.getUserFullName(),userPseudo)
60
- return <View ref ={ref}>
61
- <Menu
62
- anchor = { (aProps)=>{
63
- return <Button
64
- normal
65
- upperCase = {false}
66
- disableRipple
67
- title = {"Pressez longtemps pour définir un identifiant unique pour l'appareil"}
68
- {...aProps}
69
- style = {[styles.container]}
70
- onLongPress = {()=>{
71
- appConfig.setDeviceId().then((r)=>{
72
- if(deviceNameRef.current && deviceNameRef.current.update){
73
- deviceNameRef.current.update(r?("["+r+"]"):"");
74
- }
75
- });
76
- }}
77
- left={props1 => <Image
78
- {...props}
79
- {...props1}
80
- size={60}
81
- style = {styles.itemLeft}
82
- testID = {"RN_ProfilAvatar_Avatar"}
83
- editable
84
- defaultSource ={avatarProps.defaultSrc}
85
- onChange = {({dataURL})=>{
86
- if(u.avatar === dataURL) {
87
- return;
88
- }
89
- if(!dataURL){
90
- u.avatar = null;
91
- } else {
92
- u.avatar = dataURL;
93
- }
94
- Auth.upsertUser({...u,avatar:u.avatar},false);
95
- }
96
- }
97
- />}
98
- right = {(p)=>{
99
- return <Icon
100
- {...p}
101
- {...aProps}
102
- secondary
103
- size={20}
104
- icon={"chevron-down"}
105
- style = {styles.icon}
106
- />
107
- }}
108
- >
109
- <View style={styles.labelContainer}>
110
- <Label splitText numberOfLines={1} style={{color:theme.colors.primaryOnSurface,fontSize:14}}>{pseudo}</Label>
111
- <Label splitText numberOfLines={1} style={{fontSize:12,color:theme.colors.secondaryOnSurface,marginTop:6}}>
112
- {label}
113
- </Label>
114
- {deviceName && <Label.withRef textBold splitText title={"Identifiant unique de l'application, installé sur cet appareil"} ref={deviceNameRef} secondary style={{fontSize:10}}>
115
- [{deviceName}]
116
- </Label.withRef> || null}
117
- </View>
118
- </Button>
119
- } }
120
- items={menItems}
121
- />
122
- </View>
123
- });
124
-
125
- const styles = StyleSheet.create({
126
- itemLeft : {
127
- marginHorizontal : 5,
128
- marginTop : isMobileNative()? 10 : 0,
129
- },
130
- container : {
131
- marginLeft : 0,
132
- marginVertical : 10,
133
- },
134
- labelContainer : {
135
- flexDirection : 'column',
136
- paddingRight : 5,
137
- maxWidth : 150,
138
- minWidth : 100,
139
- },
140
- pseudo : {
141
- flexDirection : "row",
142
- justifyContent : "center",
143
- alignItems : "center"
144
- },
145
- appName : {
146
- marginLeft : 5,
147
- fontWeight : "bold",
148
- },
149
- icon : {
150
- marginHorizontal:0,
151
- paddingHorizontal : 0,
152
- }
153
- })
154
-
155
- export default UserProfileAvatarComponent;
156
-
157
- UserProfileAvatarComponent.displayName = "UserProfileAvatarComponent";