'use strict'; import React from 'react'; import { defineMessages, useIntl, FormattedMessage } from 'react-intl'; import Badge from 'soapbox/components/badge'; import { Icon, HStack, Stack, Text } from 'soapbox/components/ui'; import VerificationBadge from 'soapbox/components/verification_badge'; import { useSoapboxConfig } from 'soapbox/hooks'; import { isLocal } from 'soapbox/utils/accounts'; import ProfileFamiliarFollowers from './profile_familiar_followers'; import ProfileStats from './profile_stats'; import type { Account } from 'soapbox/types/entities'; /** Basically ensure the URL isn't `javascript:alert('hi')` or something like that */ const isSafeUrl = (text: string): boolean => { try { const url = new URL(text); return ['http:', 'https:'].includes(url.protocol); } catch (e) { return false; } }; const messages = defineMessages({ 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.' }, deactivated: { id: 'account.deactivated', defaultMessage: 'Deactivated' }, bot: { id: 'account.badges.bot', defaultMessage: 'Bot' }, }); interface IProfileInfoPanel { account: Account, /** Username from URL params, in case the account isn't found. */ username: string, } /** User profile metadata, such as location, birthday, etc. */ const ProfileInfoPanel: React.FC = ({ account, username }) => { const intl = useIntl(); const { displayFqn } = useSoapboxConfig(); const getStaffBadge = (): React.ReactNode => { if (account?.admin) { return ; } else if (account?.moderator) { return ; } else { return null; } }; const getBadges = (): React.ReactNode[] => { const staffBadge = getStaffBadge(); const isPatron = account.getIn(['patron', 'is_patron']) === true; const badges = []; if (staffBadge) { badges.push(staffBadge); } if (isPatron) { badges.push(); } if (account.donor) { badges.push(); } return badges; }; const renderBirthday = (): React.ReactNode => { const birthday = account.birthday; if (!birthday) return null; const formattedBirthday = intl.formatDate(birthday, { timeZone: 'UTC', day: 'numeric', month: 'long', year: 'numeric' }); const date = new Date(birthday); const today = new Date(); const hasBirthday = date.getDate() === today.getDate() && date.getMonth() === today.getMonth(); return ( {hasBirthday ? ( ) : ( )} ); }; if (!account) { return (
@{username}
); } const content = { __html: account.note_emojified }; const deactivated = !account.pleroma.get('is_active', true) === true; const displayNameHtml = deactivated ? { __html: intl.formatMessage(messages.deactivated) } : { __html: account.display_name_html }; const memberSinceDate = intl.formatDate(account.created_at, { month: 'long', year: 'numeric' }); const verified = account.verified; const badges = getBadges(); return (
{/* Not sure if this is actual used. */} {/*
*/} {verified && } {account.bot && } {badges.length > 0 && ( {badges} )} @{displayFqn ? account.fqn : account.acct} {account.locked && ( )} {account.note.length > 0 && account.note !== '

' && ( )}
{isLocal(account as any) ? ( ) : null} {account.location ? ( {account.location} ) : null} {account.website ? (
{isSafeUrl(account.website) ? ( {account.website} ) : ( account.website )}
) : null} {renderBirthday()}
); }; export default ProfileInfoPanel;