Skip to content

Commit

Permalink
Use a modern React context for identity in the app (mastodon#30098)
Browse files Browse the repository at this point in the history
  • Loading branch information
renchap authored May 19, 2024
1 parent 6282b6d commit a178ba7
Show file tree
Hide file tree
Showing 26 changed files with 213 additions and 224 deletions.
12 changes: 5 additions & 7 deletions app/javascript/mastodon/components/column_header.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,10 @@ import CloseIcon from '@/material-icons/400-24px/close.svg?react';
import SettingsIcon from '@/material-icons/400-24px/settings.svg?react';
import { Icon } from 'mastodon/components/icon';
import { ButtonInTabsBar } from 'mastodon/features/ui/util/columns_context';
import { identityContextPropShape, withIdentity } from 'mastodon/identity_context';
import { WithRouterPropTypes } from 'mastodon/utils/react_router';


import { useAppHistory } from './router';

const messages = defineMessages({
Expand Down Expand Up @@ -51,12 +53,8 @@ BackButton.propTypes = {
};

class ColumnHeader extends PureComponent {

static contextTypes = {
identity: PropTypes.object,
};

static propTypes = {
identity: identityContextPropShape,
intl: PropTypes.object.isRequired,
title: PropTypes.node,
icon: PropTypes.string,
Expand Down Expand Up @@ -171,7 +169,7 @@ class ColumnHeader extends PureComponent {
);
}

if (this.context.identity.signedIn && (children || (multiColumn && this.props.onPin))) {
if (this.props.identity.signedIn && (children || (multiColumn && this.props.onPin))) {
collapseButton = (
<button
className={collapsibleButtonClassName}
Expand Down Expand Up @@ -232,4 +230,4 @@ class ColumnHeader extends PureComponent {

}

export default injectIntl(withRouter(ColumnHeader));
export default injectIntl(withIdentity(withRouter(ColumnHeader)));
11 changes: 4 additions & 7 deletions app/javascript/mastodon/components/poll.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import CheckIcon from '@/material-icons/400-24px/check.svg?react';
import { Icon } from 'mastodon/components/icon';
import emojify from 'mastodon/features/emoji/emoji';
import Motion from 'mastodon/features/ui/util/optional_motion';
import { identityContextPropShape, withIdentity } from 'mastodon/identity_context';

import { RelativeTimestamp } from './relative_timestamp';

Expand All @@ -38,12 +39,8 @@ const makeEmojiMap = record => record.get('emojis').reduce((obj, emoji) => {
}, {});

class Poll extends ImmutablePureComponent {

static contextTypes = {
identity: PropTypes.object,
};

static propTypes = {
identity: identityContextPropShape,
poll: ImmutablePropTypes.map,
lang: PropTypes.string,
intl: PropTypes.object.isRequired,
Expand Down Expand Up @@ -235,7 +232,7 @@ class Poll extends ImmutablePureComponent {
</ul>

<div className='poll__footer'>
{!showResults && <button className='button button-secondary' disabled={disabled || !this.context.identity.signedIn} onClick={this.handleVote}><FormattedMessage id='poll.vote' defaultMessage='Vote' /></button>}
{!showResults && <button className='button button-secondary' disabled={disabled || !this.props.identity.signedIn} onClick={this.handleVote}><FormattedMessage id='poll.vote' defaultMessage='Vote' /></button>}
{!showResults && <><button className='poll__link' onClick={this.handleReveal}><FormattedMessage id='poll.reveal' defaultMessage='See results' /></button> · </>}
{showResults && !this.props.disabled && <><button className='poll__link' onClick={this.handleRefresh}><FormattedMessage id='poll.refresh' defaultMessage='Refresh' /></button> · </>}
{votesCount}
Expand All @@ -247,4 +244,4 @@ class Poll extends ImmutablePureComponent {

}

export default injectIntl(Poll);
export default injectIntl(withIdentity(Poll));
17 changes: 7 additions & 10 deletions app/javascript/mastodon/components/status_action_bar.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import RepeatActiveIcon from '@/svg-icons/repeat_active.svg?react';
import RepeatDisabledIcon from '@/svg-icons/repeat_disabled.svg?react';
import RepeatPrivateIcon from '@/svg-icons/repeat_private.svg?react';
import RepeatPrivateActiveIcon from '@/svg-icons/repeat_private_active.svg?react';
import { identityContextPropShape, withIdentity } from 'mastodon/identity_context';
import { PERMISSION_MANAGE_USERS, PERMISSION_MANAGE_FEDERATION } from 'mastodon/permissions';
import { WithRouterPropTypes } from 'mastodon/utils/react_router';

Expand Down Expand Up @@ -74,12 +75,8 @@ const mapStateToProps = (state, { status }) => ({
});

class StatusActionBar extends ImmutablePureComponent {

static contextTypes = {
identity: PropTypes.object,
};

static propTypes = {
identity: identityContextPropShape,
status: ImmutablePropTypes.map.isRequired,
relationship: ImmutablePropTypes.record,
onReply: PropTypes.func,
Expand Down Expand Up @@ -118,7 +115,7 @@ class StatusActionBar extends ImmutablePureComponent {
];

handleReplyClick = () => {
const { signedIn } = this.context.identity;
const { signedIn } = this.props.identity;

if (signedIn) {
this.props.onReply(this.props.status, this.props.history);
Expand All @@ -136,7 +133,7 @@ class StatusActionBar extends ImmutablePureComponent {
};

handleFavouriteClick = () => {
const { signedIn } = this.context.identity;
const { signedIn } = this.props.identity;

if (signedIn) {
this.props.onFavourite(this.props.status);
Expand All @@ -146,7 +143,7 @@ class StatusActionBar extends ImmutablePureComponent {
};

handleReblogClick = e => {
const { signedIn } = this.context.identity;
const { signedIn } = this.props.identity;

if (signedIn) {
this.props.onReblog(this.props.status, e);
Expand Down Expand Up @@ -250,7 +247,7 @@ class StatusActionBar extends ImmutablePureComponent {

render () {
const { status, relationship, intl, withDismiss, withCounters, scrollKey } = this.props;
const { signedIn, permissions } = this.context.identity;
const { signedIn, permissions } = this.props.identity;

const publicStatus = ['public', 'unlisted'].includes(status.get('visibility'));
const pinnableStatus = ['public', 'unlisted', 'private'].includes(status.get('visibility'));
Expand Down Expand Up @@ -410,4 +407,4 @@ class StatusActionBar extends ImmutablePureComponent {

}

export default withRouter(connect(mapStateToProps)(injectIntl(StatusActionBar)));
export default withRouter(withIdentity(connect(mapStateToProps)(injectIntl(StatusActionBar))));
12 changes: 5 additions & 7 deletions app/javascript/mastodon/components/status_content.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,10 @@ import { connect } from 'react-redux';
import ChevronRightIcon from '@/material-icons/400-24px/chevron_right.svg?react';
import { Icon } from 'mastodon/components/icon';
import PollContainer from 'mastodon/containers/poll_container';
import { identityContextPropShape, withIdentity } from 'mastodon/identity_context';
import { autoPlayGif, languages as preloadedLanguages } from 'mastodon/initial_state';


const MAX_HEIGHT = 706; // 22px * 32 (+ 2px padding at the top)

/**
Expand Down Expand Up @@ -67,12 +69,8 @@ const mapStateToProps = state => ({
});

class StatusContent extends PureComponent {

static contextTypes = {
identity: PropTypes.object,
};

static propTypes = {
identity: identityContextPropShape,
status: ImmutablePropTypes.map.isRequired,
statusContent: PropTypes.string,
expanded: PropTypes.bool,
Expand Down Expand Up @@ -245,7 +243,7 @@ class StatusContent extends PureComponent {
const renderReadMore = this.props.onClick && status.get('collapsed');
const contentLocale = intl.locale.replace(/[_-].*/, '');
const targetLanguages = this.props.languages?.get(status.get('language') || 'und');
const renderTranslate = this.props.onTranslate && this.context.identity.signedIn && ['public', 'unlisted'].includes(status.get('visibility')) && status.get('search_index').trim().length > 0 && targetLanguages?.includes(contentLocale);
const renderTranslate = this.props.onTranslate && this.props.identity.signedIn && ['public', 'unlisted'].includes(status.get('visibility')) && status.get('search_index').trim().length > 0 && targetLanguages?.includes(contentLocale);

const content = { __html: statusContent ?? getStatusContent(status) };
const spoilerContent = { __html: status.getIn(['translation', 'spoilerHtml']) || status.get('spoilerHtml') };
Expand Down Expand Up @@ -328,4 +326,4 @@ class StatusContent extends PureComponent {

}

export default withRouter(connect(mapStateToProps)(injectIntl(StatusContent)));
export default withRouter(withIdentity(connect(mapStateToProps)(injectIntl(StatusContent))));
54 changes: 16 additions & 38 deletions app/javascript/mastodon/containers/mastodon.jsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import PropTypes from 'prop-types';
import { PureComponent } from 'react';

import { Helmet } from 'react-helmet';
Expand All @@ -14,6 +13,7 @@ import { connectUserStream } from 'mastodon/actions/streaming';
import ErrorBoundary from 'mastodon/components/error_boundary';
import { Router } from 'mastodon/components/router';
import UI from 'mastodon/features/ui';
import { IdentityContext, createIdentityContext } from 'mastodon/identity_context';
import initialState, { title as siteTitle } from 'mastodon/initial_state';
import { IntlProvider } from 'mastodon/locales';
import { store } from 'mastodon/store';
Expand All @@ -28,33 +28,9 @@ if (initialState.meta.me) {
store.dispatch(fetchCustomEmojis());
}

const createIdentityContext = state => ({
signedIn: !!state.meta.me,
accountId: state.meta.me,
disabledAccountId: state.meta.disabled_account_id,
accessToken: state.meta.access_token,
permissions: state.role ? state.role.permissions : 0,
});

export default class Mastodon extends PureComponent {

static childContextTypes = {
identity: PropTypes.shape({
signedIn: PropTypes.bool.isRequired,
accountId: PropTypes.string,
disabledAccountId: PropTypes.string,
accessToken: PropTypes.string,
}).isRequired,
};

identity = createIdentityContext(initialState);

getChildContext() {
return {
identity: this.identity,
};
}

componentDidMount() {
if (this.identity.signedIn) {
this.disconnect = store.dispatch(connectUserStream());
Expand All @@ -74,19 +50,21 @@ export default class Mastodon extends PureComponent {

render () {
return (
<IntlProvider>
<ReduxProvider store={store}>
<ErrorBoundary>
<Router>
<ScrollContext shouldUpdateScroll={this.shouldUpdateScroll}>
<Route path='/' component={UI} />
</ScrollContext>
</Router>

<Helmet defaultTitle={title} titleTemplate={`%s - ${title}`} />
</ErrorBoundary>
</ReduxProvider>
</IntlProvider>
<IdentityContext.Provider value={this.identity}>
<IntlProvider>
<ReduxProvider store={store}>
<ErrorBoundary>
<Router>
<ScrollContext shouldUpdateScroll={this.shouldUpdateScroll}>
<Route path='/' component={UI} />
</ScrollContext>
</Router>

<Helmet defaultTitle={title} titleTemplate={`%s - ${title}`} />
</ErrorBoundary>
</ReduxProvider>
</IntlProvider>
</IdentityContext.Provider>
);
}

Expand Down
10 changes: 4 additions & 6 deletions app/javascript/mastodon/features/account/components/header.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import { IconButton } from 'mastodon/components/icon_button';
import { LoadingIndicator } from 'mastodon/components/loading_indicator';
import { ShortNumber } from 'mastodon/components/short_number';
import DropdownMenuContainer from 'mastodon/containers/dropdown_menu_container';
import { identityContextPropShape, withIdentity } from 'mastodon/identity_context';
import { autoPlayGif, me, domain as localDomain } from 'mastodon/initial_state';
import { PERMISSION_MANAGE_USERS, PERMISSION_MANAGE_FEDERATION } from 'mastodon/permissions';
import { WithRouterPropTypes } from 'mastodon/utils/react_router';
Expand Down Expand Up @@ -111,6 +112,7 @@ const dateFormatOptions = {
class Header extends ImmutablePureComponent {

static propTypes = {
identity: identityContextPropShape,
account: ImmutablePropTypes.record,
identity_props: ImmutablePropTypes.list,
onFollow: PropTypes.func.isRequired,
Expand All @@ -136,10 +138,6 @@ class Header extends ImmutablePureComponent {
...WithRouterPropTypes,
};

static contextTypes = {
identity: PropTypes.object,
};

setRef = c => {
this.node = c;
};
Expand Down Expand Up @@ -255,7 +253,7 @@ class Header extends ImmutablePureComponent {

render () {
const { account, hidden, intl } = this.props;
const { signedIn, permissions } = this.context.identity;
const { signedIn, permissions } = this.props.identity;

if (!account) {
return null;
Expand Down Expand Up @@ -516,4 +514,4 @@ class Header extends ImmutablePureComponent {

}

export default withRouter(injectIntl(Header));
export default withRouter(withIdentity(injectIntl(Header)));
13 changes: 5 additions & 8 deletions app/javascript/mastodon/features/community_timeline/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { connect } from 'react-redux';

import PeopleIcon from '@/material-icons/400-24px/group.svg?react';
import { DismissableBanner } from 'mastodon/components/dismissable_banner';
import { identityContextPropShape, withIdentity } from 'mastodon/identity_context';
import { domain } from 'mastodon/initial_state';

import { addColumn, removeColumn, moveColumn } from '../../actions/columns';
Expand Down Expand Up @@ -38,16 +39,12 @@ const mapStateToProps = (state, { columnId }) => {
};

class CommunityTimeline extends PureComponent {

static contextTypes = {
identity: PropTypes.object,
};

static defaultProps = {
onlyMedia: false,
};

static propTypes = {
identity: identityContextPropShape,
dispatch: PropTypes.func.isRequired,
columnId: PropTypes.string,
intl: PropTypes.object.isRequired,
Expand Down Expand Up @@ -77,7 +74,7 @@ class CommunityTimeline extends PureComponent {

componentDidMount () {
const { dispatch, onlyMedia } = this.props;
const { signedIn } = this.context.identity;
const { signedIn } = this.props.identity;

dispatch(expandCommunityTimeline({ onlyMedia }));

Expand All @@ -87,7 +84,7 @@ class CommunityTimeline extends PureComponent {
}

componentDidUpdate (prevProps) {
const { signedIn } = this.context.identity;
const { signedIn } = this.props.identity;

if (prevProps.onlyMedia !== this.props.onlyMedia) {
const { dispatch, onlyMedia } = this.props;
Expand Down Expand Up @@ -161,4 +158,4 @@ class CommunityTimeline extends PureComponent {

}

export default connect(mapStateToProps)(injectIntl(CommunityTimeline));
export default withIdentity(connect(mapStateToProps)(injectIntl(CommunityTimeline)));
Loading

0 comments on commit a178ba7

Please sign in to comment.