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})