mirror of https://git.lenooby09.tech/LeNooby09/social-app.git
1import React, {memo} from 'react' 2import {StyleSheet, TouchableWithoutFeedback, View} from 'react-native' 3import {AppBskyActorDefs, ModerationDecision} from '@atproto/api' 4import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' 5import {msg} from '@lingui/macro' 6import {useLingui} from '@lingui/react' 7import {useNavigation} from '@react-navigation/native' 8 9import {Shadow} from '#/state/cache/types' 10import {ProfileImageLightbox, useLightboxControls} from '#/state/lightbox' 11import {useSession} from '#/state/session' 12import {BACK_HITSLOP} from 'lib/constants' 13import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries' 14import {NavigationProp} from 'lib/routes/types' 15import {isIOS} from 'platform/detection' 16import {LoadingPlaceholder} from 'view/com/util/LoadingPlaceholder' 17import {UserAvatar} from 'view/com/util/UserAvatar' 18import {UserBanner} from 'view/com/util/UserBanner' 19import {atoms as a, useTheme} from '#/alf' 20import {LabelsOnMe} from '#/components/moderation/LabelsOnMe' 21import {ProfileHeaderAlerts} from '#/components/moderation/ProfileHeaderAlerts' 22 23interface Props { 24 profile: Shadow<AppBskyActorDefs.ProfileViewDetailed> 25 moderation: ModerationDecision 26 hideBackButton?: boolean 27 isPlaceholderProfile?: boolean 28} 29 30let ProfileHeaderShell = ({ 31 children, 32 profile, 33 moderation, 34 hideBackButton = false, 35 isPlaceholderProfile, 36}: React.PropsWithChildren<Props>): React.ReactNode => { 37 const t = useTheme() 38 const {currentAccount} = useSession() 39 const {_} = useLingui() 40 const {openLightbox} = useLightboxControls() 41 const navigation = useNavigation<NavigationProp>() 42 const {isDesktop} = useWebMediaQueries() 43 44 const onPressBack = React.useCallback(() => { 45 if (navigation.canGoBack()) { 46 navigation.goBack() 47 } else { 48 navigation.navigate('Home') 49 } 50 }, [navigation]) 51 52 const onPressAvi = React.useCallback(() => { 53 const modui = moderation.ui('avatar') 54 if (profile.avatar && !(modui.blur && modui.noOverride)) { 55 openLightbox(new ProfileImageLightbox(profile)) 56 } 57 }, [openLightbox, profile, moderation]) 58 59 const isMe = React.useMemo( 60 () => currentAccount?.did === profile.did, 61 [currentAccount, profile], 62 ) 63 64 return ( 65 <View style={t.atoms.bg} pointerEvents={isIOS ? 'auto' : 'box-none'}> 66 <View pointerEvents={isIOS ? 'auto' : 'none'}> 67 {isPlaceholderProfile ? ( 68 <LoadingPlaceholder 69 width="100%" 70 height={150} 71 style={{borderRadius: 0}} 72 /> 73 ) : ( 74 <UserBanner 75 type={profile.associated?.labeler ? 'labeler' : 'default'} 76 banner={profile.banner} 77 moderation={moderation.ui('banner')} 78 /> 79 )} 80 </View> 81 82 {children} 83 84 <View 85 style={[a.px_lg, a.pb_sm]} 86 pointerEvents={isIOS ? 'auto' : 'box-none'}> 87 {isMe ? ( 88 <LabelsOnMe details={{did: profile.did}} labels={profile.labels} /> 89 ) : ( 90 <ProfileHeaderAlerts moderation={moderation} /> 91 )} 92 </View> 93 94 {!isDesktop && !hideBackButton && ( 95 <TouchableWithoutFeedback 96 testID="profileHeaderBackBtn" 97 onPress={onPressBack} 98 hitSlop={BACK_HITSLOP} 99 accessibilityRole="button" 100 accessibilityLabel={_(msg`Back`)} 101 accessibilityHint=""> 102 <View style={styles.backBtnWrapper}> 103 <FontAwesomeIcon size={18} icon="angle-left" color="white" /> 104 </View> 105 </TouchableWithoutFeedback> 106 )} 107 <TouchableWithoutFeedback 108 testID="profileHeaderAviButton" 109 onPress={onPressAvi} 110 accessibilityRole="image" 111 accessibilityLabel={_(msg`View ${profile.handle}'s avatar`)} 112 accessibilityHint=""> 113 <View 114 style={[ 115 t.atoms.bg, 116 {borderColor: t.atoms.bg.backgroundColor}, 117 styles.avi, 118 profile.associated?.labeler && styles.aviLabeler, 119 ]}> 120 <UserAvatar 121 type={profile.associated?.labeler ? 'labeler' : 'user'} 122 size={90} 123 avatar={profile.avatar} 124 moderation={moderation.ui('avatar')} 125 /> 126 </View> 127 </TouchableWithoutFeedback> 128 </View> 129 ) 130} 131ProfileHeaderShell = memo(ProfileHeaderShell) 132export {ProfileHeaderShell} 133 134const styles = StyleSheet.create({ 135 backBtnWrapper: { 136 position: 'absolute', 137 top: 10, 138 left: 10, 139 width: 30, 140 height: 30, 141 overflow: 'hidden', 142 borderRadius: 15, 143 // @ts-ignore web only 144 cursor: 'pointer', 145 }, 146 backBtn: { 147 width: 30, 148 height: 30, 149 borderRadius: 15, 150 alignItems: 'center', 151 justifyContent: 'center', 152 }, 153 avi: { 154 position: 'absolute', 155 top: 110, 156 left: 10, 157 width: 94, 158 height: 94, 159 borderRadius: 47, 160 borderWidth: 2, 161 }, 162 aviLabeler: { 163 borderRadius: 10, 164 }, 165})