From 0127d282e2ef36e2fbbd9e61c1823b683530761b Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Fri, 29 Apr 2022 20:33:26 -0500 Subject: [PATCH] ProfileInfoPanel: convert to TSX --- .../ui/components/profile_info_panel.js | 271 ------------------ .../ui/components/profile_info_panel.tsx | 230 +++++++++++++++ 2 files changed, 230 insertions(+), 271 deletions(-) delete mode 100644 app/soapbox/features/ui/components/profile_info_panel.js create mode 100644 app/soapbox/features/ui/components/profile_info_panel.tsx diff --git a/app/soapbox/features/ui/components/profile_info_panel.js b/app/soapbox/features/ui/components/profile_info_panel.js deleted file mode 100644 index 9b1f83c4e..000000000 --- a/app/soapbox/features/ui/components/profile_info_panel.js +++ /dev/null @@ -1,271 +0,0 @@ -'use strict'; - -import { List as ImmutableList } from 'immutable'; -import PropTypes from 'prop-types'; -import React from 'react'; -import ImmutablePropTypes from 'react-immutable-proptypes'; -import ImmutablePureComponent from 'react-immutable-pure-component'; -import { defineMessages, injectIntl, FormattedMessage } from 'react-intl'; -import { connect } from 'react-redux'; - -import { initAccountNoteModal } from 'soapbox/actions/account_notes'; -import Badge from 'soapbox/components/badge'; -import { Icon, HStack, Stack, Text } from 'soapbox/components/ui'; -import VerificationBadge from 'soapbox/components/verification_badge'; -import { isLocal } from 'soapbox/utils/accounts'; -import { displayFqn } from 'soapbox/utils/state'; - -import ProfileStats from './profile_stats'; - -// Basically ensure the URL isn't `javascript:alert('hi')` or something like that -const isSafeUrl = text => { - 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' }, -}); - -class ProfileInfoPanel extends ImmutablePureComponent { - - static propTypes = { - account: ImmutablePropTypes.record, - identity_proofs: ImmutablePropTypes.list, - intl: PropTypes.object.isRequired, - username: PropTypes.string, - displayFqn: PropTypes.bool, - onShowNote: PropTypes.func, - }; - - getStaffBadge = () => { - const { account } = this.props; - - if (account?.admin) { - return ; - } else if (account?.moderator) { - return ; - } else { - return null; - } - } - - getBadges = () => { - const { account } = this.props; - const staffBadge = this.getStaffBadge(); - const isPatron = account.getIn(['patron', 'is_patron']); - - const badges = []; - - if (staffBadge) { - badges.push(staffBadge); - } - - if (isPatron) { - badges.push(); - } - - if (account.donor) { - badges.push(); - } - - return badges; - } - - renderBirthday = () => { - const { account, intl } = this.props; - - const birthday = account.get('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 ? ( - - ) : ( - - )} - - - ); - } - - handleShowNote = e => { - const { account, onShowNote } = this.props; - - e.preventDefault(); - onShowNote(account); - } - - render() { - const { account, displayFqn, intl, username } = this.props; - - if (!account) { - return ( -
- - - - - @{username} - - - - -
- ); - } - - const content = { __html: account.get('note_emojified') }; - const deactivated = !account.getIn(['pleroma', 'is_active'], true); - const displayNameHtml = deactivated ? { __html: intl.formatMessage(messages.deactivated) } : { __html: account.get('display_name_html') }; - const memberSinceDate = intl.formatDate(account.get('created_at'), { month: 'long', year: 'numeric' }); - const verified = account.get('verified'); - const badges = this.getBadges(); - - return ( -
- - {/* Not sure if this is actual used. */} - {/*
- -
*/} - - - - - - {verified && } - - {account.bot && } - - {badges.length > 0 && ( - - {badges} - - )} - - - - - @{displayFqn ? account.fqn : account.acct} - - - {account.get('locked') && ( - - )} - - - - - - { - (account.get('note').length > 0 && account.get('note') !== '

') && - - } - -
- {isLocal(account) ? ( - - - - - - - - ) : null} - - {account.get('location') ? ( - - - - - {account.get('location')} - - - ) : null} - - {account.get('website') ? ( - - - -
- - {isSafeUrl(account.get('website')) ? ( - {account.get('website')} - ) : ( - account.get('website') - )} - -
-
- ) : null} - - {this.renderBirthday()} -
-
-
- ); - } - -} - -const mapStateToProps = (state, { account }) => { - const identity_proofs = account ? state.getIn(['identity_proofs', account.get('id')], ImmutableList()) : ImmutableList(); - return { - identity_proofs, - domain: state.getIn(['meta', 'domain']), - displayFqn: displayFqn(state), - }; -}; - -const mapDispatchToProps = (dispatch) => ({ - onShowNote(account) { - dispatch(initAccountNoteModal(account)); - }, -}); - -export default injectIntl( - connect(mapStateToProps, mapDispatchToProps, null, { - forwardRef: true, - }, - )(ProfileInfoPanel)); diff --git a/app/soapbox/features/ui/components/profile_info_panel.tsx b/app/soapbox/features/ui/components/profile_info_panel.tsx new file mode 100644 index 000000000..7fe628ddb --- /dev/null +++ b/app/soapbox/features/ui/components/profile_info_panel.tsx @@ -0,0 +1,230 @@ +'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 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;