2022-08-11 09:57:09 -07:00
'use strict' ;
2022-11-03 09:13:54 -07:00
import { useMutation } from '@tanstack/react-query' ;
import { AxiosError } from 'axios' ;
2022-10-13 11:05:08 -07:00
import { List as ImmutableList } from 'immutable' ;
2022-08-11 09:57:09 -07:00
import React from 'react' ;
import { defineMessages , FormattedMessage , useIntl } from 'react-intl' ;
2023-02-10 11:43:41 -08:00
import { useHistory } from 'react-router-dom' ;
2022-08-11 09:57:09 -07:00
2022-08-11 10:00:15 -07:00
import { blockAccount , followAccount , pinAccount , removeFromFollowers , unblockAccount , unmuteAccount , unpinAccount } from 'soapbox/actions/accounts' ;
2022-08-11 09:57:09 -07:00
import { mentionCompose , directCompose } from 'soapbox/actions/compose' ;
2022-11-16 05:32:32 -08:00
import { blockDomain , unblockDomain } from 'soapbox/actions/domain-blocks' ;
2022-08-11 09:57:09 -07:00
import { openModal } from 'soapbox/actions/modals' ;
import { initMuteModal } from 'soapbox/actions/mutes' ;
2023-03-22 10:56:32 -07:00
import { initReport , ReportableEntities } from 'soapbox/actions/reports' ;
2022-08-11 09:57:09 -07:00
import { setSearchAccount } from 'soapbox/actions/search' ;
import { getSettings } from 'soapbox/actions/settings' ;
import Badge from 'soapbox/components/badge' ;
2023-02-10 11:43:41 -08:00
import DropdownMenu , { Menu } from 'soapbox/components/dropdown-menu' ;
2022-11-15 08:00:49 -08:00
import StillImage from 'soapbox/components/still-image' ;
2023-02-10 11:43:41 -08:00
import { Avatar , HStack , IconButton } from 'soapbox/components/ui' ;
2023-02-14 12:28:16 -08:00
import VerificationBadge from 'soapbox/components/verification-badge' ;
2022-11-15 09:23:36 -08:00
import MovedNote from 'soapbox/features/account-timeline/components/moved-note' ;
2022-08-11 09:57:09 -07:00
import ActionButton from 'soapbox/features/ui/components/action-button' ;
import SubscriptionButton from 'soapbox/features/ui/components/subscription-button' ;
2022-11-21 12:03:35 -08:00
import { useAppDispatch , useAppSelector , useFeatures , useOwnAccount } from 'soapbox/hooks' ;
2022-10-13 11:05:08 -07:00
import { normalizeAttachment } from 'soapbox/normalizers' ;
2022-11-03 09:13:54 -07:00
import { ChatKeys , useChats } from 'soapbox/queries/chats' ;
import { queryClient } from 'soapbox/queries/client' ;
2022-12-20 07:47:46 -08:00
import toast from 'soapbox/toast' ;
2022-08-11 09:57:09 -07:00
import { Account } from 'soapbox/types/entities' ;
2023-01-30 14:16:25 -08:00
import { isDefaultHeader , isLocal , isRemote } from 'soapbox/utils/accounts' ;
2023-05-14 13:35:53 -07:00
import copy from 'soapbox/utils/copy' ;
2022-11-21 12:03:35 -08:00
import { MASTODON , parseVersion } from 'soapbox/utils/features' ;
2022-08-11 09:57:09 -07:00
const messages = defineMessages ( {
edit_profile : { id : 'account.edit_profile' , defaultMessage : 'Edit profile' } ,
linkVerifiedOn : { id : 'account.link_verified_on' , defaultMessage : 'Ownership of this link was checked on {date}' } ,
account_locked : { id : 'account.locked_info' , defaultMessage : 'This account privacy status is set to locked. The owner manually reviews who can follow them.' } ,
mention : { id : 'account.mention' , defaultMessage : 'Mention' } ,
chat : { id : 'account.chat' , defaultMessage : 'Chat with @{name}' } ,
direct : { id : 'account.direct' , defaultMessage : 'Direct message @{name}' } ,
unmute : { id : 'account.unmute' , defaultMessage : 'Unmute @{name}' } ,
block : { id : 'account.block' , defaultMessage : 'Block @{name}' } ,
unblock : { id : 'account.unblock' , defaultMessage : 'Unblock @{name}' } ,
mute : { id : 'account.mute' , defaultMessage : 'Mute @{name}' } ,
report : { id : 'account.report' , defaultMessage : 'Report @{name}' } ,
2023-05-21 14:32:46 -07:00
copy : { id : 'account.copy' , defaultMessage : 'Copy link to profile' } ,
2022-08-11 09:57:09 -07:00
share : { id : 'account.share' , defaultMessage : 'Share @{name}\'s profile' } ,
media : { id : 'account.media' , defaultMessage : 'Media' } ,
blockDomain : { id : 'account.block_domain' , defaultMessage : 'Hide everything from {domain}' } ,
unblockDomain : { id : 'account.unblock_domain' , defaultMessage : 'Unhide {domain}' } ,
hideReblogs : { id : 'account.hide_reblogs' , defaultMessage : 'Hide reposts from @{name}' } ,
showReblogs : { id : 'account.show_reblogs' , defaultMessage : 'Show reposts from @{name}' } ,
preferences : { id : 'navigation_bar.preferences' , defaultMessage : 'Preferences' } ,
follow_requests : { id : 'navigation_bar.follow_requests' , defaultMessage : 'Follow requests' } ,
blocks : { id : 'navigation_bar.blocks' , defaultMessage : 'Blocked users' } ,
domain_blocks : { id : 'navigation_bar.domain_blocks' , defaultMessage : 'Hidden domains' } ,
mutes : { id : 'navigation_bar.mutes' , defaultMessage : 'Muted users' } ,
endorse : { id : 'account.endorse' , defaultMessage : 'Feature on profile' } ,
unendorse : { id : 'account.unendorse' , defaultMessage : 'Don\'t feature on profile' } ,
removeFromFollowers : { id : 'account.remove_from_followers' , defaultMessage : 'Remove this follower' } ,
2022-09-11 09:25:48 -07:00
adminAccount : { id : 'status.admin_account' , defaultMessage : 'Moderate @{name}' } ,
2022-08-11 09:57:09 -07:00
add_or_remove_from_list : { id : 'account.add_or_remove_from_list' , defaultMessage : 'Add or Remove from lists' } ,
search : { id : 'account.search' , defaultMessage : 'Search from @{name}' } ,
2022-09-09 14:06:18 -07:00
searchSelf : { id : 'account.search_self' , defaultMessage : 'Search your posts' } ,
2022-08-11 09:57:09 -07:00
unfollowConfirm : { id : 'confirmations.unfollow.confirm' , defaultMessage : 'Unfollow' } ,
blockConfirm : { id : 'confirmations.block.confirm' , defaultMessage : 'Block' } ,
blockDomainConfirm : { id : 'confirmations.domain_block.confirm' , defaultMessage : 'Hide entire domain' } ,
blockAndReport : { id : 'confirmations.block.block_and_report' , defaultMessage : 'Block & Report' } ,
removeFromFollowersConfirm : { id : 'confirmations.remove_from_followers.confirm' , defaultMessage : 'Remove' } ,
userEndorsed : { id : 'account.endorse.success' , defaultMessage : 'You are now featuring @{acct} on your profile' } ,
userUnendorsed : { id : 'account.unendorse.success' , defaultMessage : 'You are no longer featuring @{acct}' } ,
2022-11-15 19:53:35 -08:00
profileExternal : { id : 'account.profile_external' , defaultMessage : 'View profile on {domain}' } ,
2022-11-26 07:00:54 -08:00
header : { id : 'account.header.alt' , defaultMessage : 'Profile header' } ,
2022-11-21 12:03:35 -08:00
subscribeFeed : { id : 'account.rss_feed' , defaultMessage : 'Subscribe to RSS feed' } ,
2022-08-11 09:57:09 -07:00
} ) ;
interface IHeader {
2023-02-15 13:26:27 -08:00
account? : Account
2022-08-11 09:57:09 -07:00
}
const Header : React.FC < IHeader > = ( { account } ) = > {
const intl = useIntl ( ) ;
const history = useHistory ( ) ;
const dispatch = useAppDispatch ( ) ;
const features = useFeatures ( ) ;
const ownAccount = useOwnAccount ( ) ;
2022-11-21 12:03:35 -08:00
const { software } = useAppSelector ( ( state ) = > parseVersion ( state . instance . version ) ) ;
2022-11-03 09:13:54 -07:00
const { getOrCreateChatByAccountId } = useChats ( ) ;
const createAndNavigateToChat = useMutation ( ( accountId : string ) = > {
return getOrCreateChatByAccountId ( accountId ) ;
} , {
onError : ( error : AxiosError ) = > {
const data = error . response ? . data as any ;
2022-12-20 08:34:53 -08:00
toast . error ( data ? . error ) ;
2022-11-03 09:13:54 -07:00
} ,
onSuccess : ( response ) = > {
history . push ( ` /chats/ ${ response . data . id } ` ) ;
queryClient . invalidateQueries ( ChatKeys . chatSearch ( ) ) ;
} ,
} ) ;
2022-08-11 12:02:01 -07:00
if ( ! account ) {
return (
2023-04-11 05:55:17 -07:00
< div className = '-mx-4 -mt-4 sm:-mx-6 sm:-mt-6' >
2022-08-11 12:02:01 -07:00
< div >
2023-02-01 14:13:42 -08:00
< div className = 'relative h-32 w-full bg-gray-200 dark:bg-gray-900/50 md:rounded-t-xl lg:h-48' / >
2022-08-11 12:02:01 -07:00
< / div >
< div className = 'px-4 sm:px-6' >
2022-11-25 09:04:11 -08:00
< HStack alignItems = 'bottom' space = { 5 } className = '-mt-12' >
2023-02-01 14:13:42 -08:00
< div className = 'relative flex' >
2022-08-11 12:02:01 -07:00
< div
2023-02-01 14:13:42 -08:00
className = 'h-24 w-24 rounded-full bg-gray-400 ring-4 ring-white dark:ring-gray-800'
2022-08-11 12:02:01 -07:00
/ >
< / div >
2022-11-25 09:04:11 -08:00
< / HStack >
2022-08-11 12:02:01 -07:00
< / div >
< / div >
) ;
}
2022-08-11 09:57:09 -07:00
const onBlock = ( ) = > {
if ( account . relationship ? . blocking ) {
dispatch ( unblockAccount ( account . id ) ) ;
} else {
dispatch ( openModal ( 'CONFIRM' , {
icon : require ( '@tabler/icons/ban.svg' ) ,
heading : < FormattedMessage id = 'confirmations.block.heading' defaultMessage = 'Block @{name}' values = { { name : account.acct } } / > ,
2023-05-02 11:28:42 -07:00
message : < FormattedMessage id = 'confirmations.block.message' defaultMessage = 'Are you sure you want to block {name}?' values = { { name : < strong className = 'break-words' > @ { account . acct } < / strong > } } / > ,
2022-08-11 09:57:09 -07:00
confirm : intl.formatMessage ( messages . blockConfirm ) ,
onConfirm : ( ) = > dispatch ( blockAccount ( account . id ) ) ,
secondary : intl.formatMessage ( messages . blockAndReport ) ,
onSecondary : ( ) = > {
dispatch ( blockAccount ( account . id ) ) ;
2023-03-22 10:56:32 -07:00
dispatch ( initReport ( ReportableEntities . ACCOUNT , account ) ) ;
2022-08-11 09:57:09 -07:00
} ,
} ) ) ;
}
} ;
const onMention = ( ) = > {
dispatch ( mentionCompose ( account ) ) ;
} ;
const onDirect = ( ) = > {
dispatch ( directCompose ( account ) ) ;
} ;
const onReblogToggle = ( ) = > {
if ( account . relationship ? . showing_reblogs ) {
dispatch ( followAccount ( account . id , { reblogs : false } ) ) ;
} else {
dispatch ( followAccount ( account . id , { reblogs : true } ) ) ;
}
} ;
const onEndorseToggle = ( ) = > {
if ( account . relationship ? . endorsed ) {
dispatch ( unpinAccount ( account . id ) )
2022-12-20 07:47:46 -08:00
. then ( ( ) = > toast . success ( intl . formatMessage ( messages . userUnendorsed , { acct : account.acct } ) ) )
2022-09-13 11:11:22 -07:00
. catch ( ( ) = > { } ) ;
2022-08-11 09:57:09 -07:00
} else {
dispatch ( pinAccount ( account . id ) )
2022-12-20 07:47:46 -08:00
. then ( ( ) = > toast . success ( intl . formatMessage ( messages . userEndorsed , { acct : account.acct } ) ) )
2022-09-13 11:11:22 -07:00
. catch ( ( ) = > { } ) ;
2022-08-11 09:57:09 -07:00
}
} ;
const onReport = ( ) = > {
2023-03-22 10:56:32 -07:00
dispatch ( initReport ( ReportableEntities . ACCOUNT , account ) ) ;
2022-08-11 09:57:09 -07:00
} ;
const onMute = ( ) = > {
if ( account . relationship ? . muting ) {
dispatch ( unmuteAccount ( account . id ) ) ;
} else {
dispatch ( initMuteModal ( account ) ) ;
}
} ;
const onBlockDomain = ( domain : string ) = > {
dispatch ( openModal ( 'CONFIRM' , {
icon : require ( '@tabler/icons/ban.svg' ) ,
heading : < FormattedMessage id = 'confirmations.domain_block.heading' defaultMessage = 'Block {domain}' values = { { domain } } / > ,
message : < FormattedMessage id = 'confirmations.domain_block.message' defaultMessage = 'Are you really, really sure you want to block the entire {domain}? In most cases a few targeted blocks or mutes are sufficient and preferable. You will not see content from that domain in any public timelines or your notifications.' values = { { domain : < strong > { domain } < / strong > } } / > ,
confirm : intl.formatMessage ( messages . blockDomainConfirm ) ,
onConfirm : ( ) = > dispatch ( blockDomain ( domain ) ) ,
} ) ) ;
} ;
const onUnblockDomain = ( domain : string ) = > {
dispatch ( unblockDomain ( domain ) ) ;
} ;
2022-11-15 19:53:35 -08:00
const onProfileExternal = ( url : string ) = > {
window . open ( url , '_blank' ) ;
} ;
2022-08-11 09:57:09 -07:00
const onAddToList = ( ) = > {
dispatch ( openModal ( 'LIST_ADDER' , {
accountId : account.id ,
} ) ) ;
} ;
2022-09-11 09:25:48 -07:00
const onModerate = ( ) = > {
dispatch ( openModal ( 'ACCOUNT_MODERATION' , { accountId : account.id } ) ) ;
} ;
2022-08-11 09:57:09 -07:00
const onRemoveFromFollowers = ( ) = > {
dispatch ( ( _ , getState ) = > {
const unfollowModal = getSettings ( getState ( ) ) . get ( 'unfollowModal' ) ;
if ( unfollowModal ) {
dispatch ( openModal ( 'CONFIRM' , {
2023-05-02 11:28:42 -07:00
message : < FormattedMessage id = 'confirmations.remove_from_followers.message' defaultMessage = 'Are you sure you want to remove {name} from your followers?' values = { { name : < strong className = 'break-words' > @ { account . acct } < / strong > } } / > ,
2022-08-11 09:57:09 -07:00
confirm : intl.formatMessage ( messages . removeFromFollowersConfirm ) ,
onConfirm : ( ) = > dispatch ( removeFromFollowers ( account . id ) ) ,
} ) ) ;
} else {
dispatch ( removeFromFollowers ( account . id ) ) ;
}
} ) ;
} ;
const onSearch = ( ) = > {
dispatch ( setSearchAccount ( account . id ) ) ;
history . push ( '/search' ) ;
} ;
const onAvatarClick = ( ) = > {
2022-10-13 11:05:08 -07:00
const avatar = normalizeAttachment ( {
2022-08-11 09:57:09 -07:00
type : 'image' ,
2022-10-13 11:05:08 -07:00
url : account.avatar ,
2022-08-11 09:57:09 -07:00
} ) ;
dispatch ( openModal ( 'MEDIA' , { media : ImmutableList.of ( avatar ) , index : 0 } ) ) ;
} ;
const handleAvatarClick : React.MouseEventHandler = ( e ) = > {
if ( e . button === 0 && ! ( e . ctrlKey || e . metaKey ) ) {
e . preventDefault ( ) ;
onAvatarClick ( ) ;
}
} ;
const onHeaderClick = ( ) = > {
2022-10-13 11:05:08 -07:00
const header = normalizeAttachment ( {
2022-08-11 09:57:09 -07:00
type : 'image' ,
2022-10-13 11:05:08 -07:00
url : account.header ,
2022-08-11 09:57:09 -07:00
} ) ;
dispatch ( openModal ( 'MEDIA' , { media : ImmutableList.of ( header ) , index : 0 } ) ) ;
} ;
const handleHeaderClick : React.MouseEventHandler = ( e ) = > {
if ( e . button === 0 && ! ( e . ctrlKey || e . metaKey ) ) {
e . preventDefault ( ) ;
onHeaderClick ( ) ;
}
} ;
2022-11-21 12:03:35 -08:00
const handleRssFeedClick = ( ) = > {
window . open ( software === MASTODON ? ` ${ account . url } .rss ` : ` ${ account . url } /feed.rss ` , '_blank' ) ;
} ;
2022-08-11 09:57:09 -07:00
const handleShare = ( ) = > {
navigator . share ( {
text : ` @ ${ account . acct } ` ,
url : account.url ,
} ) . catch ( ( e ) = > {
if ( e . name !== 'AbortError' ) console . error ( e ) ;
} ) ;
} ;
2023-05-14 13:35:53 -07:00
const handleCopy : React.EventHandler < React.MouseEvent > = ( e ) = > {
copy ( account . url ) ;
} ;
2022-08-11 09:57:09 -07:00
const makeMenu = ( ) = > {
2023-02-10 11:43:41 -08:00
const menu : Menu = [ ] ;
2022-08-11 09:57:09 -07:00
2022-11-21 12:03:35 -08:00
if ( ! account ) {
2022-08-11 09:57:09 -07:00
return [ ] ;
}
2022-11-21 12:03:35 -08:00
if ( features . rssFeeds && isLocal ( account ) ) {
menu . push ( {
text : intl.formatMessage ( messages . subscribeFeed ) ,
action : handleRssFeedClick ,
icon : require ( '@tabler/icons/rss.svg' ) ,
} ) ;
}
2022-08-11 09:57:09 -07:00
if ( 'share' in navigator ) {
menu . push ( {
text : intl.formatMessage ( messages . share , { name : account.username } ) ,
action : handleShare ,
icon : require ( '@tabler/icons/upload.svg' ) ,
} ) ;
2022-11-21 12:03:35 -08:00
}
if ( features . federating && isRemote ( account ) ) {
const domain = account . fqn . split ( '@' ) [ 1 ] ;
menu . push ( {
text : intl.formatMessage ( messages . profileExternal , { domain } ) ,
action : ( ) = > onProfileExternal ( account . url ) ,
icon : require ( '@tabler/icons/external-link.svg' ) ,
} ) ;
}
2023-05-14 13:35:53 -07:00
menu . push ( {
text : intl.formatMessage ( messages . copy ) ,
action : handleCopy ,
icon : require ( '@tabler/icons/clipboard-copy.svg' ) ,
} ) ;
2022-11-21 12:03:35 -08:00
if ( ! ownAccount ) return menu ;
2023-05-14 13:35:53 -07:00
if ( features . searchFromAccount ) {
menu . push ( {
text : intl.formatMessage ( account . id === ownAccount . id ? messages.searchSelf : messages.search , { name : account.username } ) ,
action : onSearch ,
icon : require ( '@tabler/icons/search.svg' ) ,
} ) ;
}
2022-11-21 12:03:35 -08:00
if ( menu . length ) {
2022-08-11 09:57:09 -07:00
menu . push ( null ) ;
}
2022-11-21 12:03:35 -08:00
if ( account . id === ownAccount . id ) {
2022-08-11 09:57:09 -07:00
menu . push ( {
text : intl.formatMessage ( messages . edit_profile ) ,
to : '/settings/profile' ,
icon : require ( '@tabler/icons/user.svg' ) ,
} ) ;
menu . push ( {
text : intl.formatMessage ( messages . preferences ) ,
to : '/settings' ,
icon : require ( '@tabler/icons/settings.svg' ) ,
} ) ;
menu . push ( null ) ;
menu . push ( {
text : intl.formatMessage ( messages . mutes ) ,
to : '/mutes' ,
icon : require ( '@tabler/icons/circle-x.svg' ) ,
} ) ;
menu . push ( {
text : intl.formatMessage ( messages . blocks ) ,
to : '/blocks' ,
icon : require ( '@tabler/icons/ban.svg' ) ,
} ) ;
} else {
menu . push ( {
text : intl.formatMessage ( messages . mention , { name : account.username } ) ,
action : onMention ,
icon : require ( '@tabler/icons/at.svg' ) ,
} ) ;
2022-11-07 08:43:17 -08:00
if ( features . privacyScopes ) {
2022-08-11 09:57:09 -07:00
menu . push ( {
text : intl.formatMessage ( messages . direct , { name : account.username } ) ,
action : onDirect ,
icon : require ( '@tabler/icons/mail.svg' ) ,
} ) ;
}
if ( account . relationship ? . following ) {
if ( account . relationship ? . showing_reblogs ) {
menu . push ( {
text : intl.formatMessage ( messages . hideReblogs , { name : account.username } ) ,
action : onReblogToggle ,
icon : require ( '@tabler/icons/repeat.svg' ) ,
} ) ;
} else {
menu . push ( {
text : intl.formatMessage ( messages . showReblogs , { name : account.username } ) ,
action : onReblogToggle ,
icon : require ( '@tabler/icons/repeat.svg' ) ,
} ) ;
}
if ( features . lists ) {
menu . push ( {
text : intl.formatMessage ( messages . add_or_remove_from_list ) ,
action : onAddToList ,
icon : require ( '@tabler/icons/list.svg' ) ,
} ) ;
}
if ( features . accountEndorsements ) {
menu . push ( {
text : intl.formatMessage ( account . relationship ? . endorsed ? messages.unendorse : messages.endorse ) ,
action : onEndorseToggle ,
icon : require ( '@tabler/icons/user-check.svg' ) ,
} ) ;
}
} else if ( features . lists && features . unrestrictedLists ) {
menu . push ( {
text : intl.formatMessage ( messages . add_or_remove_from_list ) ,
action : onAddToList ,
icon : require ( '@tabler/icons/list.svg' ) ,
} ) ;
}
2023-05-14 13:35:53 -07:00
menu . push ( null ) ;
2022-08-11 09:57:09 -07:00
if ( features . removeFromFollowers && account . relationship ? . followed_by ) {
menu . push ( {
text : intl.formatMessage ( messages . removeFromFollowers ) ,
action : onRemoveFromFollowers ,
icon : require ( '@tabler/icons/user-x.svg' ) ,
} ) ;
}
if ( account . relationship ? . muting ) {
menu . push ( {
text : intl.formatMessage ( messages . unmute , { name : account.username } ) ,
action : onMute ,
icon : require ( '@tabler/icons/circle-x.svg' ) ,
} ) ;
} else {
menu . push ( {
text : intl.formatMessage ( messages . mute , { name : account.username } ) ,
action : onMute ,
icon : require ( '@tabler/icons/circle-x.svg' ) ,
} ) ;
}
if ( account . relationship ? . blocking ) {
menu . push ( {
text : intl.formatMessage ( messages . unblock , { name : account.username } ) ,
action : onBlock ,
icon : require ( '@tabler/icons/ban.svg' ) ,
} ) ;
} else {
menu . push ( {
text : intl.formatMessage ( messages . block , { name : account.username } ) ,
action : onBlock ,
icon : require ( '@tabler/icons/ban.svg' ) ,
} ) ;
}
menu . push ( {
text : intl.formatMessage ( messages . report , { name : account.username } ) ,
action : onReport ,
icon : require ( '@tabler/icons/flag.svg' ) ,
} ) ;
}
if ( isRemote ( account ) ) {
const domain = account . fqn . split ( '@' ) [ 1 ] ;
menu . push ( null ) ;
if ( account . relationship ? . domain_blocking ) {
menu . push ( {
text : intl.formatMessage ( messages . unblockDomain , { domain } ) ,
action : ( ) = > onUnblockDomain ( domain ) ,
icon : require ( '@tabler/icons/ban.svg' ) ,
} ) ;
} else {
menu . push ( {
text : intl.formatMessage ( messages . blockDomain , { domain } ) ,
action : ( ) = > onBlockDomain ( domain ) ,
icon : require ( '@tabler/icons/ban.svg' ) ,
} ) ;
}
}
2022-11-21 12:03:35 -08:00
if ( ownAccount . staff ) {
2022-08-11 09:57:09 -07:00
menu . push ( null ) ;
2022-09-11 12:46:01 -07:00
menu . push ( {
text : intl.formatMessage ( messages . adminAccount , { name : account.username } ) ,
action : onModerate ,
icon : require ( '@tabler/icons/gavel.svg' ) ,
} ) ;
2022-08-11 09:57:09 -07:00
}
return menu ;
} ;
const makeInfo = ( ) = > {
const info : React.ReactNode [ ] = [ ] ;
if ( ! account || ! ownAccount ) return info ;
2022-11-21 12:03:35 -08:00
if ( ownAccount . id !== account . id && account . relationship ? . followed_by ) {
2022-08-11 09:57:09 -07:00
info . push (
< Badge
key = 'followed_by'
slug = 'opaque'
title = { < FormattedMessage id = 'account.follows_you' defaultMessage = 'Follows you' / > }
/ > ,
) ;
2022-11-21 12:03:35 -08:00
} else if ( ownAccount . id !== account . id && account . relationship ? . blocking ) {
2022-08-11 09:57:09 -07:00
info . push (
< Badge
key = 'blocked'
slug = 'opaque'
title = { < FormattedMessage id = 'account.blocked' defaultMessage = 'Blocked' / > }
/ > ,
) ;
}
2022-11-21 12:03:35 -08:00
if ( ownAccount . id !== account . id && account . relationship ? . muting ) {
2022-08-11 09:57:09 -07:00
info . push (
< Badge
key = 'muted'
slug = 'opaque'
title = { < FormattedMessage id = 'account.muted' defaultMessage = 'Muted' / > }
/ > ,
) ;
2022-11-21 12:03:35 -08:00
} else if ( ownAccount . id !== account . id && account . relationship ? . domain_blocking ) {
2022-08-11 09:57:09 -07:00
info . push (
< Badge
key = 'domain_blocked'
slug = 'opaque'
title = { < FormattedMessage id = 'account.domain_blocked' defaultMessage = 'Domain hidden' / > }
/ > ,
) ;
}
return info ;
} ;
2022-12-12 14:58:11 -08:00
const renderHeader = ( ) = > {
let header : React.ReactNode ;
if ( account . header ) {
header = (
< StillImage
src = { account . header }
alt = { intl . formatMessage ( messages . header ) }
/ >
) ;
if ( ! isDefaultHeader ( account . header ) ) {
header = (
< a href = { account . header } onClick = { handleHeaderClick } target = '_blank' >
{ header }
< / a >
) ;
}
}
return header ;
} ;
2022-11-03 09:13:54 -07:00
const renderMessageButton = ( ) = > {
2022-12-18 10:58:19 -08:00
if ( ! ownAccount || ! account || account . id === ownAccount ? . id ) {
return null ;
}
2022-11-03 09:13:54 -07:00
2022-12-18 10:58:19 -08:00
if ( features . chatsWithFollowers ) { // Truth Social
2022-11-07 08:43:17 -08:00
const canChat = account . relationship ? . followed_by ;
if ( ! canChat ) {
return null ;
}
return (
< IconButton
2022-12-07 06:23:35 -08:00
src = { require ( '@tabler/icons/messages.svg' ) }
2022-11-07 08:43:17 -08:00
onClick = { ( ) = > createAndNavigateToChat . mutate ( account . id ) }
title = { intl . formatMessage ( messages . chat , { name : account.username } ) }
theme = 'outlined'
className = 'px-2'
2023-02-15 13:26:27 -08:00
iconClassName = 'h-4 w-4'
2022-11-07 08:43:17 -08:00
disabled = { createAndNavigateToChat . isLoading }
/ >
) ;
2022-12-07 06:23:35 -08:00
} else if ( account . getIn ( [ 'pleroma' , 'accepts_chat_messages' ] ) === true ) {
return (
< IconButton
src = { require ( '@tabler/icons/messages.svg' ) }
onClick = { ( ) = > createAndNavigateToChat . mutate ( account . id ) }
title = { intl . formatMessage ( messages . chat , { name : account.username } ) }
theme = 'outlined'
className = 'px-2'
2023-02-15 13:26:27 -08:00
iconClassName = 'h-4 w-4'
2022-12-07 06:23:35 -08:00
/ >
) ;
} else {
return null ;
2022-11-03 09:13:54 -07:00
}
} ;
2022-08-11 09:57:09 -07:00
const renderShareButton = ( ) = > {
const canShare = 'share' in navigator ;
if ( ! ( account && ownAccount ? . id && account . id === ownAccount ? . id && canShare ) ) {
return null ;
}
return (
< IconButton
src = { require ( '@tabler/icons/upload.svg' ) }
onClick = { handleShare }
title = { intl . formatMessage ( messages . share , { name : account.username } ) }
2022-08-12 08:42:26 -07:00
theme = 'outlined'
className = 'px-2'
2023-02-15 13:26:27 -08:00
iconClassName = 'h-4 w-4'
2022-08-11 09:57:09 -07:00
/ >
) ;
} ;
const info = makeInfo ( ) ;
const menu = makeMenu ( ) ;
return (
2023-04-11 05:55:17 -07:00
< div className = '-mx-4 -mt-4 sm:-mx-6 sm:-mt-6' >
2022-08-11 11:24:46 -07:00
{ ( account . moved && typeof account . moved === 'object' ) && (
2023-06-20 12:24:39 -07:00
< MovedNote from = { account } to = { account . moved as Account } / >
2022-08-11 11:24:46 -07:00
) }
2022-08-11 09:57:09 -07:00
< div >
2023-02-01 14:13:42 -08:00
< div className = 'relative isolate flex h-32 w-full flex-col justify-center overflow-hidden bg-gray-200 dark:bg-gray-900/50 md:rounded-t-xl lg:h-48' >
2022-12-12 14:58:11 -08:00
{ renderHeader ( ) }
2022-08-11 09:57:09 -07:00
2023-04-01 11:37:34 -07:00
< div className = 'absolute left-2 top-2' >
2022-08-11 09:57:09 -07:00
< HStack alignItems = 'center' space = { 1 } >
{ info }
< / HStack >
< / div >
< / div >
< / div >
< div className = 'px-4 sm:px-6' >
2022-11-25 09:04:11 -08:00
< HStack className = '-mt-12' alignItems = 'bottom' space = { 5 } >
2023-02-14 12:28:16 -08:00
< div className = 'relative flex' >
2022-08-11 09:57:09 -07:00
< a href = { account . avatar } onClick = { handleAvatarClick } target = '_blank' >
< Avatar
2022-08-24 11:46:40 -07:00
src = { account . avatar }
size = { 96 }
2023-02-01 14:13:42 -08:00
className = 'relative h-24 w-24 rounded-full bg-white ring-4 ring-white dark:bg-primary-900 dark:ring-primary-900'
2022-08-11 09:57:09 -07:00
/ >
< / a >
2023-02-14 12:28:16 -08:00
{ account . verified && (
< div className = 'absolute bottom-0 right-0' >
< VerificationBadge className = 'h-6 w-6 rounded-full bg-white ring-2 ring-white dark:bg-primary-900 dark:ring-primary-900' / >
< / div >
) }
2022-08-11 09:57:09 -07:00
< / div >
2023-02-01 14:13:42 -08:00
< div className = 'mt-6 flex w-full justify-end sm:pb-1' >
2022-11-25 09:04:11 -08:00
< HStack space = { 2 } className = 'mt-10' >
2022-08-11 09:57:09 -07:00
< SubscriptionButton account = { account } / >
2022-12-07 06:23:35 -08:00
{ renderMessageButton ( ) }
{ renderShareButton ( ) }
2022-08-11 09:57:09 -07:00
2022-11-21 12:03:35 -08:00
{ menu . length > 0 && (
2023-02-10 11:43:41 -08:00
< DropdownMenu items = { menu } placement = 'bottom-end' >
< IconButton
2022-08-11 09:57:09 -07:00
src = { require ( '@tabler/icons/dots.svg' ) }
2022-08-12 08:42:26 -07:00
theme = 'outlined'
className = 'px-2'
2023-02-15 13:26:27 -08:00
iconClassName = 'h-4 w-4'
2022-08-11 09:57:09 -07:00
children = { null }
/ >
2023-02-10 11:43:41 -08:00
< / DropdownMenu >
2022-08-11 09:57:09 -07:00
) }
< ActionButton account = { account } / >
2022-11-25 09:04:11 -08:00
< / HStack >
2022-08-11 09:57:09 -07:00
< / div >
2022-11-25 09:04:11 -08:00
< / HStack >
2022-08-11 09:57:09 -07:00
< / div >
< / div >
) ;
} ;
export default Header ;