import React, {useMemo} from 'react' import {observer} from 'mobx-react-lite' import {StyleSheet, Text, TouchableOpacity, View} from 'react-native' import LinearGradient from 'react-native-linear-gradient' import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' import {AtUri} from '../../../third-party/uri' import {ProfileViewModel} from '../../../state/models/profile-view' import {useStores} from '../../../state' import { ConfirmModel, EditProfileModel, InviteToSceneModel, } from '../../../state/models/shell-ui' import {pluralize} from '../../../lib/strings' import {s, colors} from '../../lib/styles' import {getGradient} from '../../lib/asset-gen' import {DropdownBtn, DropdownItem} from '../util/DropdownBtn' import * as Toast from '../util/Toast' import {LoadingPlaceholder} from '../util/LoadingPlaceholder' import {RichText} from '../util/RichText' import {UserAvatar} from '../util/UserAvatar' import {UserBanner} from '../util/UserBanner' import {UserInfoText} from '../util/UserInfoText' export const ProfileHeader = observer(function ProfileHeader({ view, onRefreshAll, }: { view: ProfileViewModel onRefreshAll: () => void }) { const store = useStores() const isMember = useMemo( () => view.isScene && view.myState.member, [view.myState.member], ) const onPressBack = () => { store.nav.tab.goBack() } const onPressSearch = () => { store.nav.navigate(`/search`) } const onPressToggleFollow = () => { view?.toggleFollowing().then( () => { Toast.show( `${view.myState.follow ? 'Following' : 'No longer following'} ${ view.displayName || view.handle }`, ) }, err => console.error('Failed to toggle follow', err), ) } const onPressEditProfile = () => { store.shell.openModal(new EditProfileModel(view, onRefreshAll)) } const onPressFollowers = () => { store.nav.navigate(`/profile/${view.handle}/followers`) } const onPressFollows = () => { store.nav.navigate(`/profile/${view.handle}/follows`) } const onPressMembers = () => { store.nav.navigate(`/profile/${view.handle}/members`) } const onPressInviteMembers = () => { store.shell.openModal(new InviteToSceneModel(view)) } const onPressLeaveScene = () => { store.shell.openModal( new ConfirmModel( 'Leave this scene?', `You'll be able to come back unless your invite is revoked.`, onPressConfirmLeaveScene, ), ) } const onPressConfirmLeaveScene = async () => { if (view.myState.member) { await store.api.app.bsky.graph.confirmation.delete({ did: store.me.did || '', rkey: new AtUri(view.myState.member).rkey, }) Toast.show(`Scene left`) } onRefreshAll() } // loading // = if (!view || !view.hasLoaded) { return ( {view.displayName || view.handle} ) } // error // = if (view.hasError) { return ( {view.error} ) } // loaded // = const gradient = getGradient(view.handle) const isMe = store.me.did === view.did const isCreator = view.isScene && view.creator === store.me.did let dropdownItems: DropdownItem[] | undefined if (isCreator || isMember) { dropdownItems = [] if (isCreator) { dropdownItems.push({ label: 'Edit Profile', onPress: onPressEditProfile, }) } if (isMember) { dropdownItems.push({ label: 'Leave Scene...', onPress: onPressLeaveScene, }) } } return ( {isMe ? ( Edit Profile ) : ( <> {view.myState.follow ? ( Following ) : ( Follow )} )} {view.isScene && (view.myState.member || view.creator === store.me.did) ? ( ) : undefined} {view.displayName || view.handle} {view.isScene ? ( Scene ) : undefined} @{view.handle} {view.followersCount} {pluralize(view.followersCount, 'follower')} {view.isUser ? ( {view.followsCount} following ) : undefined} {view.isScene ? ( {view.membersCount} {pluralize(view.membersCount, 'member')} ) : undefined} {view.postsCount} {pluralize(view.postsCount, 'post')} {view.description ? ( ) : undefined} {view.isScene && view.creator ? ( Created by ) : undefined} {view.isScene && view.myState.member ? ( You are a member ) : undefined} {view.isScene && view.creator === store.me.did ? ( Invite Members ) : undefined} ) }) const styles = StyleSheet.create({ outer: { backgroundColor: colors.white, }, banner: { width: '100%', height: 120, }, avi: { position: 'absolute', top: 80, left: 10, width: 84, height: 84, borderRadius: 42, borderWidth: 2, borderColor: colors.white, backgroundColor: colors.white, }, content: { paddingTop: 8, paddingHorizontal: 14, paddingBottom: 4, }, buttonsLine: { flexDirection: 'row', marginLeft: 'auto', marginBottom: 12, }, gradientBtn: { paddingHorizontal: 24, paddingVertical: 6, }, mainBtn: { paddingHorizontal: 24, }, secondaryBtn: { paddingHorizontal: 14, }, btn: { flexDirection: 'row', alignItems: 'center', justifyContent: 'center', paddingVertical: 7, borderRadius: 50, backgroundColor: colors.gray1, marginLeft: 6, }, displayNameLine: { // paddingLeft: 86, // marginBottom: 14, }, displayName: { fontSize: 28, fontWeight: 'bold', }, handleLine: { flexDirection: 'row', marginBottom: 8, }, handle: { fontSize: 15, fontWeight: 'bold', color: colors.gray5, }, typeLabelWrapper: { backgroundColor: colors.gray1, paddingHorizontal: 4, borderRadius: 4, marginRight: 5, }, typeLabel: { fontSize: 15, fontWeight: 'bold', color: colors.gray5, }, metricsLine: { flexDirection: 'row', marginBottom: 8, }, metricsText: { fontSize: 15, }, description: { marginBottom: 8, fontSize: 16, lineHeight: 20.8, // 1.3 of 16px }, relationshipsLine: { flexDirection: 'row', alignItems: 'center', marginBottom: 5, }, sceneAdminContainer: { borderColor: colors.gray1, borderTopWidth: 1, borderBottomWidth: 1, paddingVertical: 12, paddingHorizontal: 12, }, sceneAdminBtn: { paddingVertical: 8, }, })