UNPKG

@fto-consult/expo-ui

Version:

Bibliothèque de composants UI Expo,react-native

256 lines (251 loc) 11.3 kB
import {defaultObj} from "$cutils"; import i18n from "$i18n" import Auth from "$cauth"; import Menu from "$ecomponents/Menu"; import React from "$react"; import { screenName } from "$escreens/Auth/utils"; import Image from "$ecomponents/Image"; import { StyleSheet,View,Pressable} from "react-native"; import avatarProps from "$eauth/avatarProps"; import Label from "$ecomponents/Label"; import Icon from "$ecomponents/Icon"; import {navigate} from "$cnavigation"; import theme from "$theme"; import {isMobileNative} from "$cplatform"; import appConfig from "$capp/config"; import Preloader from "$preloader"; import {defaultNumber} from "$cutils"; import Tooltip from "$ecomponents/Tooltip"; import PropTypes from "prop-types"; import { useContext } from "$econtext/hooks"; const UserProfileAvatarComponent = React.forwardRef(({drawerRef,renderedOnAppBar,chevronIconProps:customChevronIconProps,size,withLabel,menuItems,...props},ref)=>{ let u = defaultObj(Auth.getLoggedUser()); const deviceNameRef = React.useRef(null); const deviceName = appConfig.deviceName; customChevronIconProps = defaultObj(customChevronIconProps); props = defaultObj(props); const navigateToPreferences = (a)=>{ closeDrawer(()=>{ return navigate({ routeName : screenName, params : { user : u, } }) }); }; const signOut = (a)=>{ closeDrawer(()=>{ Preloader.open("Déconnexion en cours..."); Auth.signOut().finally(Preloader.close) }); }; const closeDrawer = cb => { if(drawerRef && drawerRef.current && drawerRef.current.close){ return drawerRef && drawerRef.current && drawerRef.current.close(cb); } return typeof cb =='function'? cb() : null; } if(withLabel === undefined){ withLabel = theme.showProfilAvatarOnDrawer; } withLabel = withLabel !== false ? true : false; props.src = u.avatar; size = defaultNumber(size,!withLabel?40:40); const userPseudo = Auth.getUserPseudo(); const defaultPseudo = "Default User"; const canSignOut = Auth.canSignOut(); const {components:{profilAvatarProps}} = useContext(); const customProps = Object.assign({},typeof profilAvatarProps =='function'? profilAvatarProps({...props,signOut,navigateToPreferences,canSignOut,closeDrawer,user:u,size,close:closeDrawer,setDeviceId:onLongPress,renderedOnAppBar,}) : profilAvatarProps); if(typeof customProps.size =="number"){ size = customProps.size; } const pseudo = defaultStr(customProps.pseudo,userPseudo,Auth.getUserCode(),Auth.getUserEmail(),appConfig.authDefaultUsername,defaultPseudo); const label = defaultStr(customProps.label,Auth.getUserFullName(),userPseudo); delete customProps.label; const onLongPress = ()=>{ appConfig.setDeviceId().then((r)=>{ if(deviceNameRef.current && deviceNameRef.current.update){ deviceNameRef.current.update(r?("["+r+"]"):""); } }); }; const pseudoTooltip = (pseudo == defaultPseudo ? `Pour modifier la valeur du pseudo actuel, définissez dans le fichier package.json, la propriété : authDefaultUsername de type chaine de caractère`:""); const tooltip = "Pressez longtemps pour définir un identifiant unique pour l'appareil"; const testID = defaultStr(customProps.testID,props.testID,"RN_ProfilAvatar") const pseudoContent = <Label testID={testID+"_PseudoContent"} splitText numberOfLines={1} style={{color:theme.colors.primaryOnSurface,fontSize:15}}>{pseudo}</Label>; const children = <View testID={testID+"_AnchorContainer"} style={[styles.labelContainer,!withLabel && theme.styles.justifyContentCenter]}> {pseudoTooltip?<Tooltip title={pseudoTooltip}> {pseudoContent} </Tooltip>:pseudoContent} {label != pseudo ? <Label testID={testID+"_ProfilAvatarLabel"} splitText numberOfLines={1} style={[{fontSize:12,color:theme.colors.secondaryOnSurface,marginTop:6},!withLabel && styles.withNotLabel]}> {label} </Label>:null} {deviceName && <Label.withRef testID={testID+"_ProfilAvatarDeviceName"} textBold splitText title={"Identifiant unique de l'application, installé sur cet appareil"} ref={deviceNameRef} secondary style={{fontSize:10}}> [{deviceName}] </Label.withRef> || null} </View> const menItems = [ !withLabel && { text : <Tooltip tooltip={tooltip} Component={Pressable} onLongPress={onLongPress} testID={"RNProfilAvatar_ContainerMenu"}> {children} </Tooltip>, closeOnPress : false, divider : true, }, ...(Array.isArray(menuItems)? menuItems : isObj(menuItems)? Object.keys(menuItems).map(k=>{ return menuItems[k]; }) : []), ...(Array.isArray(customProps.menuItems)? customProps.menuItems : isObj(customProps.menuItems)? Object.keys(customProps.menuItems).map(k=>{ return customProps.menuItems[k]; }) : []), customProps.preferencesMenuItem != false && { label : i18n.lang("preferences",'Préférences'), icon : "account-cog", onPress : navigateToPreferences, }, canSignOut && customProps.signOutMenuItem !== false && { label : i18n.lang("logout",'Déconnexion'), icon : "logout", onPress : signOut, }, ]; const onChangeAvatar = ({dataURL})=>{ if(u.avatar === dataURL) { return; } if(!dataURL){ u.avatar = null; } else { u.avatar = dataURL; } Auth.upsertUser({...u,avatar:u.avatar},false); } return <View ref ={ref} testID={testID+"_ProfilAvatarWrapper"}> <Menu anchor = { (aProps)=>{ const chevronIconProps = { size : 20, icon : "chevron-down", secondary : true, ...customChevronIconProps, ...aProps, style : [styles.icon,withLabel=== false && {color:theme.colors.onPrimary},customChevronIconProps.style], } if(!withLabel){ return <Pressable testID={testID+"_AvatarContainer"} style={[theme.styles.row,theme.styles.alignItemsCenter,theme.styles.pr1]}> <Image pickImageProps = {{quality:0.4}} {...props} {...aProps} {...customProps} size={size} style = {styles.itemLeft} testID = {testID+"_Avatar"} readOnly = {false} defaultSource ={avatarProps.defaultSrc} onChange = {onChangeAvatar} /> <Icon.Font testID={testID+"_ChevronIcon"} {...chevronIconProps} {...aProps} style = {[chevronIconProps.style,{marginLeft:-5}]} /> </Pressable> } return <Pressable testID={testID+"_ProfilAvatarContainer"} normal upperCase = {false} disableRipple title = {tooltip} {...aProps} style = {[styles.container]} //surfaceProps = {{style:[theme.styles.noMargin,theme.styles.noPadding]}} onLongPress = {onLongPress} > <Image {...props} {...customProps} size={size} style = {styles.itemLeft} testID = {testID+"_Avatar"} readOnly = {false} defaultSource ={avatarProps.defaultSrc} onChange = {onChangeAvatar} /> {children} <Icon testID={testID+"_ChevronIcon"} {...chevronIconProps} /> </Pressable> } } items={menItems} /> </View> }); const styles = StyleSheet.create({ itemLeft : { marginHorizontal : 5, marginTop : isMobileNative()? 10 : 0, }, container : { marginLeft : 0, marginVertical : 10, flex : 1, flexDirection : "row", justifyContent : "start", alignItems : "center", }, labelContainer : { flexDirection : 'column', paddingRight : 5, maxWidth : 140, minWidth : 100, }, withNotLabel : { textAlign : "center", }, pseudo : { flexDirection : "row", justifyContent : "center", alignItems : "center" }, appName : { marginLeft : 5, fontWeight : "bold", }, icon : { marginHorizontal:0, paddingHorizontal : 0, }, notLabelHeader : { textAlign : "left", alignSelf :"flex-start" }, }); export default UserProfileAvatarComponent; UserProfileAvatarComponent.displayName = "UserProfileAvatarComponent"; UserProfileAvatarComponent.propTypes = { renderedOnAppBar : PropTypes.bool,//spécifie si le profil avatar est rendu si true sur l'appBar, si false sur le drawer ...Object.assign({},Image.propTypes), //par défaut les props de l'image qui est utilisée pour le rendu de l'avatar withLabel : PropTypes.bool, //si le label sera affiché, ie, le nom où pseudo de l'utilisateur menuItems : PropTypes.oneOfType([ PropTypes.array, PropTypes.object, ]), /**** La props customProps issue de la propriété {component:profilAvatarProps} de useContext, prend les propriétés suivatnes : il peut s'agir d'une fonction où d'un objet. s'il s'agit d'une fonction alors la dite fonction est de la forme : ({canSignOut<boolean>,renderedOnAppBar<boolean>,user<object>,....rest})=> <CustomAvatarProps> <CustomAvatarProps> : { ...Image.propTypes, size <number>, pseudo <string>, le pseudo à afficher label <string>, la chaine de caractère à afficher pour le rendu du label/FullName, menuItems : <Array<object> | object<object>>, les menu items personnalisés à utiliser pour l'affichage } */ }