import React from 'react'
import {observer} from 'mobx-react-lite'
import {
Share,
StyleSheet,
TouchableOpacity,
TouchableWithoutFeedback,
View,
} from 'react-native'
import {
FontAwesomeIcon,
FontAwesomeIconStyle,
} from '@fortawesome/react-native-fontawesome'
import {useNavigation} from '@react-navigation/native'
import {BlurView} from '../util/BlurView'
import {ProfileViewModel} from 'state/models/profile-view'
import {useStores} from 'state/index'
import {ProfileImageLightbox} from 'state/models/ui/shell'
import {pluralize} from 'lib/strings/helpers'
import {toShareUrl} from 'lib/strings/url-helpers'
import {s, colors} from 'lib/styles'
import {DropdownButton, DropdownItem} from '../util/forms/DropdownButton'
import * as Toast from '../util/Toast'
import {LoadingPlaceholder} from '../util/LoadingPlaceholder'
import {Text} from '../util/text/Text'
import {RichText} from '../util/text/RichText'
import {UserAvatar} from '../util/UserAvatar'
import {UserBanner} from '../util/UserBanner'
import {usePalette} from 'lib/hooks/usePalette'
import {useAnalytics} from 'lib/analytics'
import {NavigationProp} from 'lib/routes/types'
import {isDesktopWeb} from 'platform/detection'
const BACK_HITSLOP = {left: 30, top: 30, right: 30, bottom: 30}
export const ProfileHeader = observer(
({
view,
onRefreshAll,
}: {
view: ProfileViewModel
onRefreshAll: () => void
}) => {
const pal = usePalette('default')
// loading
// =
if (!view || !view.hasLoaded) {
return (
{view.displayName || view.handle}
)
}
// error
// =
if (view.hasError) {
return (
{view.error}
)
}
// loaded
// =
return
},
)
const ProfileHeaderLoaded = observer(function ProfileHeaderLoaded({
view,
onRefreshAll,
}: {
view: ProfileViewModel
onRefreshAll: () => void
}) {
const pal = usePalette('default')
const store = useStores()
const navigation = useNavigation()
const {track} = useAnalytics()
const onPressBack = React.useCallback(() => {
navigation.goBack()
}, [navigation])
const onPressAvi = React.useCallback(() => {
if (view.avatar) {
store.shell.openLightbox(new ProfileImageLightbox(view))
}
}, [store, view])
const onPressToggleFollow = React.useCallback(() => {
view?.toggleFollowing().then(
() => {
Toast.show(
`${view.viewer.following ? 'Following' : 'No longer following'} ${
view.displayName || view.handle
}`,
)
},
err => store.log.error('Failed to toggle follow', err),
)
}, [view, store])
const onPressEditProfile = React.useCallback(() => {
track('ProfileHeader:EditProfileButtonClicked')
store.shell.openModal({
name: 'edit-profile',
profileView: view,
onUpdate: onRefreshAll,
})
}, [track, store, view, onRefreshAll])
const onPressFollowers = React.useCallback(() => {
track('ProfileHeader:FollowersButtonClicked')
navigation.push('ProfileFollowers', {name: view.handle})
}, [track, navigation, view])
const onPressFollows = React.useCallback(() => {
track('ProfileHeader:FollowsButtonClicked')
navigation.push('ProfileFollows', {name: view.handle})
}, [track, navigation, view])
const onPressShare = React.useCallback(() => {
track('ProfileHeader:ShareButtonClicked')
Share.share({url: toShareUrl(`/profile/${view.handle}`)})
}, [track, view])
const onPressMuteAccount = React.useCallback(async () => {
track('ProfileHeader:MuteAccountButtonClicked')
try {
await view.muteAccount()
Toast.show('Account muted')
} catch (e: any) {
store.log.error('Failed to mute account', e)
Toast.show(`There was an issue! ${e.toString()}`)
}
}, [track, view, store])
const onPressUnmuteAccount = React.useCallback(async () => {
track('ProfileHeader:UnmuteAccountButtonClicked')
try {
await view.unmuteAccount()
Toast.show('Account unmuted')
} catch (e: any) {
store.log.error('Failed to unmute account', e)
Toast.show(`There was an issue! ${e.toString()}`)
}
}, [track, view, store])
const onPressReportAccount = React.useCallback(() => {
track('ProfileHeader:ReportAccountButtonClicked')
store.shell.openModal({
name: 'report-account',
did: view.did,
})
}, [track, store, view])
const isMe = React.useMemo(
() => store.me.did === view.did,
[store.me.did, view.did],
)
const dropdownItems: DropdownItem[] = React.useMemo(() => {
let items: DropdownItem[] = [
{
testID: 'profileHeaderDropdownSahreBtn',
label: 'Share',
onPress: onPressShare,
},
]
if (!isMe) {
items.push({
testID: 'profileHeaderDropdownMuteBtn',
label: view.viewer.muted ? 'Unmute Account' : 'Mute Account',
onPress: view.viewer.muted ? onPressUnmuteAccount : onPressMuteAccount,
})
items.push({
testID: 'profileHeaderDropdownReportBtn',
label: 'Report Account',
onPress: onPressReportAccount,
})
}
return items
}, [
isMe,
view.viewer.muted,
onPressShare,
onPressUnmuteAccount,
onPressMuteAccount,
onPressReportAccount,
])
return (
{isMe ? (
Edit Profile
) : (
<>
{store.me.follows.isFollowing(view.did) ? (
Following
) : (
Follow
)}
>
)}
{dropdownItems?.length ? (
) : undefined}
{view.displayName || view.handle}
{view.viewer.followedBy ? (
Follows you
) : undefined}
@{view.handle}
{view.followersCount}
{pluralize(view.followersCount, 'follower')}
{view.followsCount}
following
{view.postsCount}
{pluralize(view.postsCount, 'post')}
{view.descriptionRichText ? (
) : undefined}
{view.viewer.muted ? (
Account muted
) : undefined}
{!isDesktopWeb && (
)}
)
})
const styles = StyleSheet.create({
banner: {
width: '100%',
height: 120,
},
backBtnWrapper: {
position: 'absolute',
top: 10,
left: 10,
width: 30,
height: 30,
},
backBtn: {
width: 30,
height: 30,
borderRadius: 15,
alignItems: 'center',
justifyContent: 'center',
},
avi: {
position: 'absolute',
top: 110,
left: 10,
width: 84,
height: 84,
borderRadius: 42,
borderWidth: 2,
},
content: {
paddingTop: 8,
paddingHorizontal: 14,
paddingBottom: 4,
},
buttonsLine: {
flexDirection: 'row',
marginLeft: 'auto',
marginBottom: 12,
},
primaryBtn: {
backgroundColor: colors.blue3,
paddingHorizontal: 24,
paddingVertical: 6,
},
mainBtn: {
paddingHorizontal: 24,
},
secondaryBtn: {
paddingHorizontal: 14,
},
btn: {
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'center',
paddingVertical: 7,
borderRadius: 50,
marginLeft: 6,
},
displayNameLine: {
// paddingLeft: 86,
// marginBottom: 14,
},
title: {lineHeight: 38},
handleLine: {
flexDirection: 'row',
marginBottom: 8,
},
metricsLine: {
flexDirection: 'row',
marginBottom: 8,
},
description: {
marginBottom: 8,
},
detailLine: {
flexDirection: 'row',
alignItems: 'center',
marginBottom: 5,
},
pill: {
borderRadius: 4,
paddingHorizontal: 6,
paddingVertical: 2,
},
br40: {borderRadius: 40},
br50: {borderRadius: 50},
})