Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use a modern React context for identity in the app #30098

Merged
merged 1 commit into from
May 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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)));