import React from 'react'; import { defineMessages, useIntl, FormattedMessage } from 'react-intl'; import { Link, useHistory } from 'react-router-dom'; import HoverRefWrapper from 'soapbox/components/hover-ref-wrapper'; import VerificationBadge from 'soapbox/components/verification-badge'; import ActionButton from 'soapbox/features/ui/components/action-button'; import { useAppSelector, useOnScreen } from 'soapbox/hooks'; import { getAcct } from 'soapbox/utils/accounts'; import { displayFqn } from 'soapbox/utils/state'; import Badge from './badge'; import RelativeTimestamp from './relative-timestamp'; import { Avatar, Emoji, HStack, Icon, IconButton, Stack, Text } from './ui'; import type { StatusApprovalStatus } from 'soapbox/normalizers/status'; import type { Account as AccountEntity } from 'soapbox/types/entities'; interface IInstanceFavicon { account: AccountEntity, disabled?: boolean, } const messages = defineMessages({ bot: { id: 'account.badges.bot', defaultMessage: 'Bot' }, }); const InstanceFavicon: React.FC = ({ account, disabled }) => { const history = useHistory(); const handleClick: React.MouseEventHandler = (e) => { e.stopPropagation(); if (disabled) return; const timelineUrl = `/timeline/${account.domain}`; if (!(e.ctrlKey || e.metaKey)) { history.push(timelineUrl); } else { window.open(timelineUrl, '_blank'); } }; return ( ); }; interface IProfilePopper { condition: boolean, wrapper: (children: React.ReactNode) => React.ReactNode children: React.ReactNode } const ProfilePopper: React.FC = ({ condition, wrapper, children }) => { return ( <> {condition ? wrapper(children) : children} ); }; export interface IAccount { account: AccountEntity, action?: React.ReactElement, actionAlignment?: 'center' | 'top', actionIcon?: string, actionTitle?: string, /** Override other actions for specificity like mute/unmute. */ actionType?: 'muting' | 'blocking' | 'follow_request', avatarSize?: number, hidden?: boolean, hideActions?: boolean, id?: string, onActionClick?: (account: any) => void, showProfileHoverCard?: boolean, timestamp?: string, timestampUrl?: string, futureTimestamp?: boolean, withAccountNote?: boolean, withDate?: boolean, withLinkToProfile?: boolean, withRelationship?: boolean, showEdit?: boolean, approvalStatus?: StatusApprovalStatus, emoji?: string, note?: string, } const Account = ({ account, actionType, action, actionIcon, actionTitle, actionAlignment = 'center', avatarSize = 42, hidden = false, hideActions = false, onActionClick, showProfileHoverCard = true, timestamp, timestampUrl, futureTimestamp = false, withAccountNote = false, withDate = false, withLinkToProfile = true, withRelationship = true, showEdit = false, approvalStatus, emoji, note, }: IAccount) => { const overflowRef = React.useRef(null); const actionRef = React.useRef(null); // @ts-ignore const isOnScreen = useOnScreen(overflowRef); const [style, setStyle] = React.useState({ visibility: 'hidden' }); const me = useAppSelector((state) => state.me); const username = useAppSelector((state) => account ? getAcct(account, displayFqn(state)) : null); const handleAction = () => { // @ts-ignore onActionClick(account); }; const renderAction = () => { if (action) { return action; } if (hideActions) { return null; } if (onActionClick && actionIcon) { return ( ); } if (account.id !== me) { return ; } return null; }; const intl = useIntl(); React.useEffect(() => { const style: React.CSSProperties = {}; const actionWidth = actionRef.current?.clientWidth || 0; if (overflowRef.current) { style.maxWidth = overflowRef.current.clientWidth - 30 - avatarSize - actionWidth; } else { style.visibility = 'hidden'; } setStyle(style); }, [isOnScreen, overflowRef, actionRef]); if (!account) { return null; } if (hidden) { return ( <> {account.display_name} {account.username} ); } if (withDate) timestamp = account.created_at; const LinkEl: any = withLinkToProfile ? Link : 'div'; return (
{children}} > event.stopPropagation()} > {emoji && ( )}
{children}} > event.stopPropagation()} > {account.verified && } {account.bot && } @{username} {account.favicon && ( )} {(timestamp) ? ( <> · {timestampUrl ? ( event.stopPropagation()}> ) : ( )} ) : null} {approvalStatus && ['pending', 'rejected'].includes(approvalStatus) && ( <> · {approvalStatus === 'pending' ? : } )} {showEdit ? ( <> · ) : null} {actionType === 'muting' && account.mute_expires_at ? ( <> · ) : null} {note ? ( {note} ) : withAccountNote && ( )}
{withRelationship ? renderAction() : null}
); }; export default Account;