about summary refs log tree commit diff
path: root/app/javascript/flavours/glitch/features/directory/components/account_card.js
diff options
context:
space:
mode:
Diffstat (limited to 'app/javascript/flavours/glitch/features/directory/components/account_card.js')
-rw-r--r--app/javascript/flavours/glitch/features/directory/components/account_card.js286
1 files changed, 286 insertions, 0 deletions
diff --git a/app/javascript/flavours/glitch/features/directory/components/account_card.js b/app/javascript/flavours/glitch/features/directory/components/account_card.js
new file mode 100644
index 000000000..2ef9d5ba4
--- /dev/null
+++ b/app/javascript/flavours/glitch/features/directory/components/account_card.js
@@ -0,0 +1,286 @@
+import React from 'react';
+import ImmutablePureComponent from 'react-immutable-pure-component';
+import ImmutablePropTypes from 'react-immutable-proptypes';
+import PropTypes from 'prop-types';
+import { connect } from 'react-redux';
+import { makeGetAccount } from 'flavours/glitch/selectors';
+import Avatar from 'flavours/glitch/components/avatar';
+import DisplayName from 'flavours/glitch/components/display_name';
+import Permalink from 'flavours/glitch/components/permalink';
+import RelativeTimestamp from 'flavours/glitch/components/relative_timestamp';
+import IconButton from 'flavours/glitch/components/icon_button';
+import { FormattedMessage, injectIntl, defineMessages } from 'react-intl';
+import { autoPlayGif, me, unfollowModal } from 'flavours/glitch/util/initial_state';
+import ShortNumber from 'flavours/glitch/components/short_number';
+import {
+  followAccount,
+  unfollowAccount,
+  blockAccount,
+  unblockAccount,
+  unmuteAccount,
+} from 'flavours/glitch/actions/accounts';
+import { openModal } from 'flavours/glitch/actions/modal';
+import { initMuteModal } from 'flavours/glitch/actions/mutes';
+
+const messages = defineMessages({
+  follow: { id: 'account.follow', defaultMessage: 'Follow' },
+  unfollow: { id: 'account.unfollow', defaultMessage: 'Unfollow' },
+  requested: { id: 'account.requested', defaultMessage: 'Awaiting approval' },
+  unblock: { id: 'account.unblock', defaultMessage: 'Unblock @{name}' },
+  unmute: { id: 'account.unmute', defaultMessage: 'Unmute @{name}' },
+  unfollowConfirm: {
+    id: 'confirmations.unfollow.confirm',
+    defaultMessage: 'Unfollow',
+  },
+});
+
+const makeMapStateToProps = () => {
+  const getAccount = makeGetAccount();
+
+  const mapStateToProps = (state, { id }) => ({
+    account: getAccount(state, id),
+  });
+
+  return mapStateToProps;
+};
+
+const mapDispatchToProps = (dispatch, { intl }) => ({
+  onFollow(account) {
+    if (
+      account.getIn(['relationship', 'following']) ||
+      account.getIn(['relationship', 'requested'])
+    ) {
+      if (unfollowModal) {
+        dispatch(
+          openModal('CONFIRM', {
+            message: (
+              <FormattedMessage
+                id='confirmations.unfollow.message'
+                defaultMessage='Are you sure you want to unfollow {name}?'
+                values={{ name: <strong>@{account.get('acct')}</strong> }}
+              />
+            ),
+            confirm: intl.formatMessage(messages.unfollowConfirm),
+            onConfirm: () => dispatch(unfollowAccount(account.get('id'))),
+          }),
+        );
+      } else {
+        dispatch(unfollowAccount(account.get('id')));
+      }
+    } else {
+      dispatch(followAccount(account.get('id')));
+    }
+  },
+
+  onBlock(account) {
+    if (account.getIn(['relationship', 'blocking'])) {
+      dispatch(unblockAccount(account.get('id')));
+    } else {
+      dispatch(blockAccount(account.get('id')));
+    }
+  },
+
+  onMute(account) {
+    if (account.getIn(['relationship', 'muting'])) {
+      dispatch(unmuteAccount(account.get('id')));
+    } else {
+      dispatch(initMuteModal(account));
+    }
+  },
+});
+
+export default
+@injectIntl
+@connect(makeMapStateToProps, mapDispatchToProps)
+class AccountCard extends ImmutablePureComponent {
+
+  static propTypes = {
+    account: ImmutablePropTypes.map.isRequired,
+    intl: PropTypes.object.isRequired,
+    onFollow: PropTypes.func.isRequired,
+    onBlock: PropTypes.func.isRequired,
+    onMute: PropTypes.func.isRequired,
+  };
+
+  _updateEmojis() {
+    const node = this.node;
+
+    if (!node || autoPlayGif) {
+      return;
+    }
+
+    const emojis = node.querySelectorAll('.custom-emoji');
+
+    for (var i = 0; i < emojis.length; i++) {
+      let emoji = emojis[i];
+      if (emoji.classList.contains('status-emoji')) {
+        continue;
+      }
+      emoji.classList.add('status-emoji');
+
+      emoji.addEventListener('mouseenter', this.handleEmojiMouseEnter, false);
+      emoji.addEventListener('mouseleave', this.handleEmojiMouseLeave, false);
+    }
+  }
+
+  componentDidMount() {
+    this._updateEmojis();
+  }
+
+  componentDidUpdate() {
+    this._updateEmojis();
+  }
+
+  handleEmojiMouseEnter = ({ target }) => {
+    target.src = target.getAttribute('data-original');
+  };
+
+  handleEmojiMouseLeave = ({ target }) => {
+    target.src = target.getAttribute('data-static');
+  };
+
+  handleFollow = () => {
+    this.props.onFollow(this.props.account);
+  };
+
+  handleBlock = () => {
+    this.props.onBlock(this.props.account);
+  };
+
+  handleMute = () => {
+    this.props.onMute(this.props.account);
+  };
+
+  setRef = (c) => {
+    this.node = c;
+  };
+
+  render() {
+    const { account, intl } = this.props;
+
+    let buttons;
+
+    if (
+      account.get('id') !== me &&
+      account.get('relationship', null) !== null
+    ) {
+      const following = account.getIn(['relationship', 'following']);
+      const requested = account.getIn(['relationship', 'requested']);
+      const blocking = account.getIn(['relationship', 'blocking']);
+      const muting = account.getIn(['relationship', 'muting']);
+
+      if (requested) {
+        buttons = (
+          <IconButton
+            disabled
+            icon='hourglass'
+            title={intl.formatMessage(messages.requested)}
+          />
+        );
+      } else if (blocking) {
+        buttons = (
+          <IconButton
+            active
+            icon='unlock'
+            title={intl.formatMessage(messages.unblock, {
+              name: account.get('username'),
+            })}
+            onClick={this.handleBlock}
+          />
+        );
+      } else if (muting) {
+        buttons = (
+          <IconButton
+            active
+            icon='volume-up'
+            title={intl.formatMessage(messages.unmute, {
+              name: account.get('username'),
+            })}
+            onClick={this.handleMute}
+          />
+        );
+      } else if (!account.get('moved') || following) {
+        buttons = (
+          <IconButton
+            icon={following ? 'user-times' : 'user-plus'}
+            title={intl.formatMessage(
+              following ? messages.unfollow : messages.follow,
+            )}
+            onClick={this.handleFollow}
+            active={following}
+          />
+        );
+      }
+    }
+
+    return (
+      <div className='directory__card'>
+        <div className='directory__card__img'>
+          <img
+            src={
+              autoPlayGif ? account.get('header') : account.get('header_static')
+            }
+            alt=''
+          />
+        </div>
+
+        <div className='directory__card__bar'>
+          <Permalink
+            className='directory__card__bar__name'
+            href={account.get('url')}
+            to={`/accounts/${account.get('id')}`}
+          >
+            <Avatar account={account} size={48} />
+            <DisplayName account={account} />
+          </Permalink>
+
+          <div className='directory__card__bar__relationship account__relationship'>
+            {buttons}
+          </div>
+        </div>
+
+        <div className='directory__card__extra' ref={this.setRef}>
+          <div
+            className='account__header__content'
+            dangerouslySetInnerHTML={{ __html: account.get('note_emojified') }}
+          />
+        </div>
+
+        <div className='directory__card__extra'>
+          <div className='accounts-table__count'>
+            <ShortNumber value={account.get('statuses_count')} />
+            <small>
+              <FormattedMessage id='account.posts' defaultMessage='Toots' />
+            </small>
+          </div>
+          <div className='accounts-table__count'>
+            {account.get('followers_count') < 0 ? '-' : <ShortNumber value={account.get('followers_count')} />}{' '}
+            <small>
+              <FormattedMessage
+                id='account.followers'
+                defaultMessage='Followers'
+              />
+            </small>
+          </div>
+          <div className='accounts-table__count'>
+            {account.get('last_status_at') === null ? (
+              <FormattedMessage
+                id='account.never_active'
+                defaultMessage='Never'
+              />
+            ) : (
+              <RelativeTimestamp timestamp={account.get('last_status_at')} />
+            )}{' '}
+            <small>
+              <FormattedMessage
+                id='account.last_status'
+                defaultMessage='Last active'
+              />
+            </small>
+          </div>
+        </div>
+      </div>
+    );
+  }
+
+}