- /*
-
- `<AccountHeader>`
- =================
-
- > For more information on the contents of this file, please contact:
- >
- > - kibigo! [@kibi@glitch.social]
-
- Original file by @gargron@mastodon.social et al as part of
- tootsuite/mastodon. We've expanded it in order to handle user bio
- frontmatter.
-
- The `<AccountHeader>` component provides the header for account
- timelines. It is a fairly simple component which mostly just consists
- of a `render()` method.
-
- __Props:__
-
- - __`account` (`ImmutablePropTypes.map`) :__
- The account to render a header for.
-
- - __`me` (`PropTypes.number.isRequired`) :__
- The id of the currently-signed-in account.
-
- - __`onFollow` (`PropTypes.func.isRequired`) :__
- The function to call when the user clicks the "follow" button.
-
- - __`intl` (`PropTypes.object.isRequired`) :__
- Our internationalization object, inserted by `@injectIntl`.
-
- */
-
- // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
-
- /*
-
- Imports:
- --------
-
- */
-
- // Package imports //
- import React from 'react';
- import ImmutablePropTypes from 'react-immutable-proptypes';
- import PropTypes from 'prop-types';
- import escapeTextContentForBrowser from 'escape-html';
- import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
- import ImmutablePureComponent from 'react-immutable-pure-component';
-
- // Mastodon imports //
- import emojify from '../../../mastodon/emoji';
- import IconButton from '../../../mastodon/components/icon_button';
- import Avatar from '../../../mastodon/components/avatar';
-
- // Our imports //
- import { processBio } from '../../util/bio_metadata';
-
- // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
-
- /*
-
- Inital setup:
- -------------
-
- The `messages` constant is used to define any messages that we need
- from inside props. In our case, these are the `unfollow`, `follow`, and
- `requested` messages used in the `title` of our buttons.
-
- */
-
- const messages = defineMessages({
- unfollow: { id: 'account.unfollow', defaultMessage: 'Unfollow' },
- follow: { id: 'account.follow', defaultMessage: 'Follow' },
- requested: { id: 'account.requested', defaultMessage: 'Awaiting approval' },
- });
-
- // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
-
- /*
-
- Implementation:
- ---------------
-
- */
-
- @injectIntl
- export default class AccountHeader extends ImmutablePureComponent {
-
- static propTypes = {
- account : ImmutablePropTypes.map,
- me : PropTypes.number.isRequired,
- onFollow : PropTypes.func.isRequired,
- intl : PropTypes.object.isRequired,
- };
-
- /*
-
- ### `render()`
-
- The `render()` function is used to render our component.
-
- */
-
- render () {
- const { account, me, intl } = this.props;
-
- /*
-
- If no `account` is provided, then we can't render a header. Otherwise,
- we get the `displayName` for the account, if available. If it's blank,
- then we set the `displayName` to just be the `username` of the account.
-
- */
-
- if (!account) {
- return null;
- }
-
- let displayName = account.get('display_name');
- let info = '';
- let actionBtn = '';
- let following = false;
-
- if (displayName.length === 0) {
- displayName = account.get('username');
- }
-
- /*
-
- Next, we handle the account relationships. If the account follows the
- user, then we add an `info` message. If the user has requested a
- follow, then we disable the `actionBtn` and display an hourglass.
- Otherwise, if the account isn't blocked, we set the `actionBtn` to the
- appropriate icon.
-
- */
-
- if (me !== account.get('id')) {
- if (account.getIn(['relationship', 'followed_by'])) {
- info = (
- <span className='account--follows-info'>
- <FormattedMessage id='account.follows_you' defaultMessage='Follows you' />
- </span>
- );
- }
- if (account.getIn(['relationship', 'requested'])) {
- actionBtn = (
- <div className='account--action-button'>
- <IconButton size={26} disabled icon='hourglass' title={intl.formatMessage(messages.requested)} />
- </div>
- );
- } else if (!account.getIn(['relationship', 'blocking'])) {
- following = account.getIn(['relationship', 'following']);
- actionBtn = (
- <div className='account--action-button'>
- <IconButton
- size={26}
- icon={following ? 'user-times' : 'user-plus'}
- active={following}
- title={intl.formatMessage(following ? messages.unfollow : messages.follow)}
- onClick={this.props.onFollow}
- />
- </div>
- );
- }
- }
-
- /*
-
- `displayNameHTML` processes the `displayName` and prepares it for
- insertion into the document. Meanwhile, we extract the `text` and
- `metadata` from our account's `note` using `processBio()`.
-
- */
-
- const displayNameHTML = {
- __html : emojify(escapeTextContentForBrowser(displayName)),
- };
- const { text, metadata } = processBio(account.get('note'));
-
- /*
-
- Here, we render our component using all the things we've defined above.
-
- */
-
- return (
- <div className='account__header__wrapper'>
- <div
- className='account__header'
- style={{ backgroundImage: `url(${account.get('header')})` }}
- >
- <div>
- <a href={account.get('url')} target='_blank' rel='noopener'>
- <span className='account__header__avatar'>
- <Avatar
- src={account.get('avatar')}
- staticSrc={account.get('avatar_static')}
- size={90}
- />
- </span>
- <span
- className='account__header__display-name'
- dangerouslySetInnerHTML={displayNameHTML}
- />
- </a>
- <span className='account__header__username'>
- @{account.get('acct')}
- {account.get('locked') ? <i className='fa fa-lock' /> : null}
- </span>
- <div className='account__header__content' dangerouslySetInnerHTML={{ __html: emojify(text) }} />
-
- {info}
- {actionBtn}
- </div>
- </div>
-
- {metadata.length && (
- <table className='account__metadata'>
- <tbody>
- {(() => {
- let data = [];
- for (let i = 0; i < metadata.length; i++) {
- data.push(
- <tr key={i}>
- <th scope='row'><div dangerouslySetInnerHTML={{ __html: emojify(metadata[i][0]) }} /></th>
- <td><div dangerouslySetInnerHTML={{ __html: emojify(metadata[i][1]) }} /></td>
- </tr>
- );
- }
- return data;
- })()}
- </tbody>
- </table>
- ) || null}
- </div>
- );
- }
-
- }
|