]> cat aescling's git repositories - mastodon.git/blob - app/javascript/mastodon/features/account/components/header.js
Change IDs to strings rather than numbers in API JSON output (#5019)
[mastodon.git] / app / javascript / mastodon / features / account / components / header.js
1 import React from 'react';
2 import ImmutablePropTypes from 'react-immutable-proptypes';
3 import PropTypes from 'prop-types';
4 import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
5 import IconButton from '../../../components/icon_button';
6 import Motion from 'react-motion/lib/Motion';
7 import spring from 'react-motion/lib/spring';
8 import { connect } from 'react-redux';
9 import ImmutablePureComponent from 'react-immutable-pure-component';
10
11 const messages = defineMessages({
12 unfollow: { id: 'account.unfollow', defaultMessage: 'Unfollow' },
13 follow: { id: 'account.follow', defaultMessage: 'Follow' },
14 requested: { id: 'account.requested', defaultMessage: 'Awaiting approval. Click to cancel follow request' },
15 });
16
17 const makeMapStateToProps = () => {
18 const mapStateToProps = state => ({
19 autoPlayGif: state.getIn(['meta', 'auto_play_gif']),
20 });
21
22 return mapStateToProps;
23 };
24
25 class Avatar extends ImmutablePureComponent {
26
27 static propTypes = {
28 account: ImmutablePropTypes.map.isRequired,
29 autoPlayGif: PropTypes.bool.isRequired,
30 };
31
32 state = {
33 isHovered: false,
34 };
35
36 handleMouseOver = () => {
37 if (this.state.isHovered) return;
38 this.setState({ isHovered: true });
39 }
40
41 handleMouseOut = () => {
42 if (!this.state.isHovered) return;
43 this.setState({ isHovered: false });
44 }
45
46 render () {
47 const { account, autoPlayGif } = this.props;
48 const { isHovered } = this.state;
49
50 return (
51 <Motion defaultStyle={{ radius: 90 }} style={{ radius: spring(isHovered ? 30 : 90, { stiffness: 180, damping: 12 }) }}>
52 {({ radius }) =>
53 <a
54 href={account.get('url')}
55 className='account__header__avatar'
56 role='presentation'
57 target='_blank'
58 rel='noopener'
59 style={{ borderRadius: `${radius}px`, backgroundImage: `url(${autoPlayGif || isHovered ? account.get('avatar') : account.get('avatar_static')})` }}
60 onMouseOver={this.handleMouseOver}
61 onMouseOut={this.handleMouseOut}
62 onFocus={this.handleMouseOver}
63 onBlur={this.handleMouseOut}
64 >
65 <span style={{ display: 'none' }}>{account.get('acct')}</span>
66 </a>
67 }
68 </Motion>
69 );
70 }
71
72 }
73
74 @connect(makeMapStateToProps)
75 @injectIntl
76 export default class Header extends ImmutablePureComponent {
77
78 static propTypes = {
79 account: ImmutablePropTypes.map,
80 me: PropTypes.string.isRequired,
81 onFollow: PropTypes.func.isRequired,
82 intl: PropTypes.object.isRequired,
83 autoPlayGif: PropTypes.bool.isRequired,
84 };
85
86 render () {
87 const { account, me, intl } = this.props;
88
89 if (!account) {
90 return null;
91 }
92
93 let info = '';
94 let actionBtn = '';
95 let lockedIcon = '';
96
97 if (me !== account.get('id') && account.getIn(['relationship', 'followed_by'])) {
98 info = <span className='account--follows-info'><FormattedMessage id='account.follows_you' defaultMessage='Follows you' /></span>;
99 }
100
101 if (me !== account.get('id')) {
102 if (account.getIn(['relationship', 'requested'])) {
103 actionBtn = (
104 <div className='account--action-button'>
105 <IconButton size={26} active icon='hourglass' title={intl.formatMessage(messages.requested)} onClick={this.props.onFollow} />
106 </div>
107 );
108 } else if (!account.getIn(['relationship', 'blocking'])) {
109 actionBtn = (
110 <div className='account--action-button'>
111 <IconButton size={26} icon={account.getIn(['relationship', 'following']) ? 'user-times' : 'user-plus'} active={account.getIn(['relationship', 'following'])} title={intl.formatMessage(account.getIn(['relationship', 'following']) ? messages.unfollow : messages.follow)} onClick={this.props.onFollow} />
112 </div>
113 );
114 }
115 }
116
117 if (account.get('locked')) {
118 lockedIcon = <i className='fa fa-lock' />;
119 }
120
121 const content = { __html: account.get('note_emojified') };
122 const displayNameHtml = { __html: account.get('display_name_html') };
123
124 return (
125 <div className='account__header' style={{ backgroundImage: `url(${account.get('header')})` }}>
126 <div>
127 <Avatar account={account} autoPlayGif={this.props.autoPlayGif} />
128
129 <span className='account__header__display-name' dangerouslySetInnerHTML={displayNameHtml} />
130 <span className='account__header__username'>@{account.get('acct')} {lockedIcon}</span>
131 <div className='account__header__content' dangerouslySetInnerHTML={content} />
132
133 {info}
134 {actionBtn}
135 </div>
136 </div>
137 );
138 }
139
140 }
This page took 0.135556 seconds and 4 git commands to generate.