@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 +2 -2
- package/src/auth/ThemeSelector/index.js +3 -1
- package/src/auth/ThemeSelector/utils.js +7 -0
- package/src/components/AppBar/index.js +5 -2
- package/src/components/AppBar/utils.js +1 -1
- package/src/components/Dialog/Provider.js +8 -4
- package/src/components/Drawer/index.js +1 -1
- package/src/components/Dropdown/utils.js +5 -2
- package/src/components/Form/FormData/DialogProvider.js +3 -1
- package/src/components/Logo/Logo.js +25 -18
- package/src/layouts/ProfilAvatar/index.js +200 -0
- package/src/{navigation/Drawer → layouts}/ProfilAvatar/style.css +0 -0
- package/src/layouts/Screen/Screen.js +4 -0
- package/src/layouts/Screen/ScreenWithOrWithoutAuthContainer.js +18 -1
- package/src/layouts/Screen/TableData.js +4 -1
- package/src/navigation/Drawer/index.js +9 -2
- package/src/navigation/Drawer/items/index.js +2 -1
- package/src/screens/Auth/Profile.js +1 -1
- package/src/screens/Auth/utils.js +3 -1
- package/src/navigation/Drawer/ProfilAvatar/index.js +0 -157
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fto-consult/expo-ui",
|
|
3
|
-
"version": "2.16.
|
|
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.
|
|
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 =
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
13
|
-
|
|
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
|
-
|
|
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 =
|
|
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.
|
|
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,
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
small : flattenStyle([styles.
|
|
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";
|
|
File without changes
|
|
@@ -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
|
|
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 "
|
|
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
|
-
|
|
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
|
-
|
|
11
|
+
import {screenName} from "./utils";
|
|
12
12
|
|
|
13
13
|
export default function UserProfileScreen(prs){
|
|
14
14
|
const props = getScreenProps(prs);
|
|
@@ -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";
|