mirror of
https://github.com/mastodon/mastodon.git
synced 2024-11-20 03:25:17 +01:00
Use a modern React context for identity in the app (#30098)
This commit is contained in:
parent
6282b6da77
commit
a178ba7cd5
@ -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({
|
||||
@ -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,
|
||||
@ -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}
|
||||
@ -232,4 +230,4 @@ class ColumnHeader extends PureComponent {
|
||||
|
||||
}
|
||||
|
||||
export default injectIntl(withRouter(ColumnHeader));
|
||||
export default injectIntl(withIdentity(withRouter(ColumnHeader)));
|
||||
|
@ -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';
|
||||
|
||||
@ -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,
|
||||
@ -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}
|
||||
@ -247,4 +244,4 @@ class Poll extends ImmutablePureComponent {
|
||||
|
||||
}
|
||||
|
||||
export default injectIntl(Poll);
|
||||
export default injectIntl(withIdentity(Poll));
|
||||
|
@ -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';
|
||||
|
||||
@ -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,
|
||||
@ -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);
|
||||
@ -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);
|
||||
@ -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);
|
||||
@ -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'));
|
||||
@ -410,4 +407,4 @@ class StatusActionBar extends ImmutablePureComponent {
|
||||
|
||||
}
|
||||
|
||||
export default withRouter(connect(mapStateToProps)(injectIntl(StatusActionBar)));
|
||||
export default withRouter(withIdentity(connect(mapStateToProps)(injectIntl(StatusActionBar))));
|
||||
|
@ -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)
|
||||
|
||||
/**
|
||||
@ -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,
|
||||
@ -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') };
|
||||
@ -328,4 +326,4 @@ class StatusContent extends PureComponent {
|
||||
|
||||
}
|
||||
|
||||
export default withRouter(connect(mapStateToProps)(injectIntl(StatusContent)));
|
||||
export default withRouter(withIdentity(connect(mapStateToProps)(injectIntl(StatusContent))));
|
||||
|
@ -1,4 +1,3 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import { PureComponent } from 'react';
|
||||
|
||||
import { Helmet } from 'react-helmet';
|
||||
@ -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';
|
||||
@ -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());
|
||||
@ -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>
|
||||
<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>
|
||||
<Helmet defaultTitle={title} titleTemplate={`%s - ${title}`} />
|
||||
</ErrorBoundary>
|
||||
</ReduxProvider>
|
||||
</IntlProvider>
|
||||
</IdentityContext.Provider>
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -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';
|
||||
@ -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,
|
||||
@ -136,10 +138,6 @@ class Header extends ImmutablePureComponent {
|
||||
...WithRouterPropTypes,
|
||||
};
|
||||
|
||||
static contextTypes = {
|
||||
identity: PropTypes.object,
|
||||
};
|
||||
|
||||
setRef = c => {
|
||||
this.node = c;
|
||||
};
|
||||
@ -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;
|
||||
@ -516,4 +514,4 @@ class Header extends ImmutablePureComponent {
|
||||
|
||||
}
|
||||
|
||||
export default withRouter(injectIntl(Header));
|
||||
export default withRouter(withIdentity(injectIntl(Header)));
|
||||
|
@ -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';
|
||||
@ -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,
|
||||
@ -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 }));
|
||||
|
||||
@ -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;
|
||||
@ -161,4 +158,4 @@ class CommunityTimeline extends PureComponent {
|
||||
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps)(injectIntl(CommunityTimeline));
|
||||
export default withIdentity(connect(mapStateToProps)(injectIntl(CommunityTimeline)));
|
||||
|
@ -12,6 +12,7 @@ import CancelIcon from '@/material-icons/400-24px/cancel-fill.svg?react';
|
||||
import CloseIcon from '@/material-icons/400-24px/close.svg?react';
|
||||
import SearchIcon from '@/material-icons/400-24px/search.svg?react';
|
||||
import { Icon } from 'mastodon/components/icon';
|
||||
import { identityContextPropShape, withIdentity } from 'mastodon/identity_context';
|
||||
import { domain, searchEnabled } from 'mastodon/initial_state';
|
||||
import { HASHTAG_REGEX } from 'mastodon/utils/hashtags';
|
||||
import { WithRouterPropTypes } from 'mastodon/utils/react_router';
|
||||
@ -33,12 +34,8 @@ const labelForRecentSearch = search => {
|
||||
};
|
||||
|
||||
class Search extends PureComponent {
|
||||
|
||||
static contextTypes = {
|
||||
identity: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
static propTypes = {
|
||||
identity: identityContextPropShape,
|
||||
value: PropTypes.string.isRequired,
|
||||
recent: ImmutablePropTypes.orderedSet,
|
||||
submitted: PropTypes.bool,
|
||||
@ -276,7 +273,7 @@ class Search extends PureComponent {
|
||||
}
|
||||
|
||||
_calculateOptions (value) {
|
||||
const { signedIn } = this.context.identity;
|
||||
const { signedIn } = this.props.identity;
|
||||
const trimmedValue = value.trim();
|
||||
const options = [];
|
||||
|
||||
@ -318,7 +315,7 @@ class Search extends PureComponent {
|
||||
render () {
|
||||
const { intl, value, submitted, recent } = this.props;
|
||||
const { expanded, options, selectedOption } = this.state;
|
||||
const { signedIn } = this.context.identity;
|
||||
const { signedIn } = this.props.identity;
|
||||
|
||||
const hasValue = value.length > 0 || submitted;
|
||||
|
||||
@ -402,4 +399,4 @@ class Search extends PureComponent {
|
||||
|
||||
}
|
||||
|
||||
export default withRouter(injectIntl(Search));
|
||||
export default withRouter(withIdentity(injectIntl(Search)));
|
||||
|
@ -13,6 +13,7 @@ import SearchIcon from '@/material-icons/400-24px/search.svg?react';
|
||||
import Column from 'mastodon/components/column';
|
||||
import ColumnHeader from 'mastodon/components/column_header';
|
||||
import Search from 'mastodon/features/compose/containers/search_container';
|
||||
import { identityContextPropShape, withIdentity } from 'mastodon/identity_context';
|
||||
import { trendsEnabled } from 'mastodon/initial_state';
|
||||
|
||||
import Links from './links';
|
||||
@ -32,12 +33,8 @@ const mapStateToProps = state => ({
|
||||
});
|
||||
|
||||
class Explore extends PureComponent {
|
||||
|
||||
static contextTypes = {
|
||||
identity: PropTypes.object,
|
||||
};
|
||||
|
||||
static propTypes = {
|
||||
identity: identityContextPropShape,
|
||||
intl: PropTypes.object.isRequired,
|
||||
multiColumn: PropTypes.bool,
|
||||
isSearching: PropTypes.bool,
|
||||
@ -53,7 +50,7 @@ class Explore extends PureComponent {
|
||||
|
||||
render() {
|
||||
const { intl, multiColumn, isSearching } = this.props;
|
||||
const { signedIn } = this.context.identity;
|
||||
const { signedIn } = this.props.identity;
|
||||
|
||||
return (
|
||||
<Column bindToDocument={!multiColumn} ref={this.setRef} label={intl.formatMessage(messages.title)}>
|
||||
@ -114,4 +111,4 @@ class Explore extends PureComponent {
|
||||
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps)(injectIntl(Explore));
|
||||
export default withIdentity(connect(mapStateToProps)(injectIntl(Explore)));
|
||||
|
@ -6,13 +6,14 @@ import { useIntl, defineMessages, FormattedMessage } from 'react-intl';
|
||||
import { Helmet } from 'react-helmet';
|
||||
import { NavLink } from 'react-router-dom';
|
||||
|
||||
import { useIdentity } from '@/mastodon/identity_context';
|
||||
import PublicIcon from '@/material-icons/400-24px/public.svg?react';
|
||||
import { addColumn } from 'mastodon/actions/columns';
|
||||
import { changeSetting } from 'mastodon/actions/settings';
|
||||
import { connectPublicStream, connectCommunityStream } from 'mastodon/actions/streaming';
|
||||
import { expandPublicTimeline, expandCommunityTimeline } from 'mastodon/actions/timelines';
|
||||
import { DismissableBanner } from 'mastodon/components/dismissable_banner';
|
||||
import initialState, { domain } from 'mastodon/initial_state';
|
||||
import { domain } from 'mastodon/initial_state';
|
||||
import { useAppDispatch, useAppSelector } from 'mastodon/store';
|
||||
|
||||
import Column from '../../components/column';
|
||||
@ -24,15 +25,6 @@ const messages = defineMessages({
|
||||
title: { id: 'column.firehose', defaultMessage: 'Live feeds' },
|
||||
});
|
||||
|
||||
// TODO: use a proper React context later on
|
||||
const useIdentity = () => ({
|
||||
signedIn: !!initialState.meta.me,
|
||||
accountId: initialState.meta.me,
|
||||
disabledAccountId: initialState.meta.disabled_account_id,
|
||||
accessToken: initialState.meta.access_token,
|
||||
permissions: initialState.role ? initialState.role.permissions : 0,
|
||||
});
|
||||
|
||||
const ColumnSettings = () => {
|
||||
const dispatch = useAppDispatch();
|
||||
const settings = useAppSelector((state) => state.getIn(['settings', 'firehose']));
|
||||
|
@ -24,6 +24,7 @@ import { fetchFollowRequests } from 'mastodon/actions/accounts';
|
||||
import Column from 'mastodon/components/column';
|
||||
import ColumnHeader from 'mastodon/components/column_header';
|
||||
import LinkFooter from 'mastodon/features/ui/components/link_footer';
|
||||
import { identityContextPropShape, withIdentity } from 'mastodon/identity_context';
|
||||
|
||||
import { me, showTrends } from '../../initial_state';
|
||||
import { NavigationBar } from '../compose/components/navigation_bar';
|
||||
@ -75,12 +76,8 @@ const badgeDisplay = (number, limit) => {
|
||||
};
|
||||
|
||||
class GettingStarted extends ImmutablePureComponent {
|
||||
|
||||
static contextTypes = {
|
||||
identity: PropTypes.object,
|
||||
};
|
||||
|
||||
static propTypes = {
|
||||
identity: identityContextPropShape,
|
||||
intl: PropTypes.object.isRequired,
|
||||
myAccount: ImmutablePropTypes.record,
|
||||
multiColumn: PropTypes.bool,
|
||||
@ -91,7 +88,7 @@ class GettingStarted extends ImmutablePureComponent {
|
||||
|
||||
componentDidMount () {
|
||||
const { fetchFollowRequests } = this.props;
|
||||
const { signedIn } = this.context.identity;
|
||||
const { signedIn } = this.props.identity;
|
||||
|
||||
if (!signedIn) {
|
||||
return;
|
||||
@ -102,7 +99,7 @@ class GettingStarted extends ImmutablePureComponent {
|
||||
|
||||
render () {
|
||||
const { intl, myAccount, multiColumn, unreadFollowRequests } = this.props;
|
||||
const { signedIn } = this.context.identity;
|
||||
const { signedIn } = this.props.identity;
|
||||
|
||||
const navItems = [];
|
||||
|
||||
@ -167,4 +164,4 @@ class GettingStarted extends ImmutablePureComponent {
|
||||
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(injectIntl(GettingStarted));
|
||||
export default withIdentity(connect(mapStateToProps, mapDispatchToProps)(injectIntl(GettingStarted)));
|
||||
|
@ -17,6 +17,7 @@ import { fetchHashtag, followHashtag, unfollowHashtag } from 'mastodon/actions/t
|
||||
import { expandHashtagTimeline, clearTimeline } from 'mastodon/actions/timelines';
|
||||
import Column from 'mastodon/components/column';
|
||||
import ColumnHeader from 'mastodon/components/column_header';
|
||||
import { identityContextPropShape, withIdentity } from 'mastodon/identity_context';
|
||||
|
||||
import StatusListContainer from '../ui/containers/status_list_container';
|
||||
|
||||
@ -29,14 +30,10 @@ const mapStateToProps = (state, props) => ({
|
||||
});
|
||||
|
||||
class HashtagTimeline extends PureComponent {
|
||||
|
||||
disconnects = [];
|
||||
|
||||
static contextTypes = {
|
||||
identity: PropTypes.object,
|
||||
};
|
||||
|
||||
static propTypes = {
|
||||
identity: identityContextPropShape,
|
||||
params: PropTypes.object.isRequired,
|
||||
columnId: PropTypes.string,
|
||||
dispatch: PropTypes.func.isRequired,
|
||||
@ -94,7 +91,7 @@ class HashtagTimeline extends PureComponent {
|
||||
};
|
||||
|
||||
_subscribe (dispatch, id, tags = {}, local) {
|
||||
const { signedIn } = this.context.identity;
|
||||
const { signedIn } = this.props.identity;
|
||||
|
||||
if (!signedIn) {
|
||||
return;
|
||||
@ -168,7 +165,7 @@ class HashtagTimeline extends PureComponent {
|
||||
handleFollow = () => {
|
||||
const { dispatch, params, tag } = this.props;
|
||||
const { id } = params;
|
||||
const { signedIn } = this.context.identity;
|
||||
const { signedIn } = this.props.identity;
|
||||
|
||||
if (!signedIn) {
|
||||
return;
|
||||
@ -185,7 +182,7 @@ class HashtagTimeline extends PureComponent {
|
||||
const { hasUnread, columnId, multiColumn, tag } = this.props;
|
||||
const { id, local } = this.props.params;
|
||||
const pinned = !!columnId;
|
||||
const { signedIn } = this.context.identity;
|
||||
const { signedIn } = this.props.identity;
|
||||
|
||||
return (
|
||||
<Column bindToDocument={!multiColumn} ref={this.setRef} label={`#${id}`}>
|
||||
@ -225,4 +222,4 @@ class HashtagTimeline extends PureComponent {
|
||||
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps)(HashtagTimeline);
|
||||
export default connect(mapStateToProps)(withIdentity(HashtagTimeline));
|
||||
|
@ -14,6 +14,7 @@ import { fetchAnnouncements, toggleShowAnnouncements } from 'mastodon/actions/an
|
||||
import { IconWithBadge } from 'mastodon/components/icon_with_badge';
|
||||
import { NotSignedInIndicator } from 'mastodon/components/not_signed_in_indicator';
|
||||
import AnnouncementsContainer from 'mastodon/features/getting_started/containers/announcements_container';
|
||||
import { identityContextPropShape, withIdentity } from 'mastodon/identity_context';
|
||||
import { criticalUpdatesPending } from 'mastodon/initial_state';
|
||||
|
||||
import { addColumn, removeColumn, moveColumn } from '../../actions/columns';
|
||||
@ -40,12 +41,8 @@ const mapStateToProps = state => ({
|
||||
});
|
||||
|
||||
class HomeTimeline extends PureComponent {
|
||||
|
||||
static contextTypes = {
|
||||
identity: PropTypes.object,
|
||||
};
|
||||
|
||||
static propTypes = {
|
||||
identity: identityContextPropShape,
|
||||
dispatch: PropTypes.func.isRequired,
|
||||
intl: PropTypes.object.isRequired,
|
||||
hasUnread: PropTypes.bool,
|
||||
@ -126,7 +123,7 @@ class HomeTimeline extends PureComponent {
|
||||
render () {
|
||||
const { intl, hasUnread, columnId, multiColumn, hasAnnouncements, unreadAnnouncements, showAnnouncements } = this.props;
|
||||
const pinned = !!columnId;
|
||||
const { signedIn } = this.context.identity;
|
||||
const { signedIn } = this.props.identity;
|
||||
const banners = [];
|
||||
|
||||
let announcementsButton;
|
||||
@ -190,4 +187,4 @@ class HomeTimeline extends PureComponent {
|
||||
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps)(injectIntl(HomeTimeline));
|
||||
export default connect(mapStateToProps)(withIdentity(injectIntl(HomeTimeline)));
|
||||
|
@ -5,6 +5,7 @@ import { FormattedMessage } from 'react-intl';
|
||||
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
|
||||
import { identityContextPropShape, withIdentity } from 'mastodon/identity_context';
|
||||
import { PERMISSION_MANAGE_USERS, PERMISSION_MANAGE_REPORTS } from 'mastodon/permissions';
|
||||
|
||||
import { CheckboxWithLabel } from './checkbox_with_label';
|
||||
@ -12,13 +13,9 @@ import ClearColumnButton from './clear_column_button';
|
||||
import GrantPermissionButton from './grant_permission_button';
|
||||
import SettingToggle from './setting_toggle';
|
||||
|
||||
export default class ColumnSettings extends PureComponent {
|
||||
|
||||
static contextTypes = {
|
||||
identity: PropTypes.object,
|
||||
};
|
||||
|
||||
class ColumnSettings extends PureComponent {
|
||||
static propTypes = {
|
||||
identity: identityContextPropShape,
|
||||
settings: ImmutablePropTypes.map.isRequired,
|
||||
pushSettings: ImmutablePropTypes.map.isRequired,
|
||||
onChange: PropTypes.func.isRequired,
|
||||
@ -215,7 +212,7 @@ export default class ColumnSettings extends PureComponent {
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{((this.context.identity.permissions & PERMISSION_MANAGE_USERS) === PERMISSION_MANAGE_USERS) && (
|
||||
{((this.props.identity.permissions & PERMISSION_MANAGE_USERS) === PERMISSION_MANAGE_USERS) && (
|
||||
<section role='group' aria-labelledby='notifications-admin-sign-up'>
|
||||
<h3 id='notifications-status'><FormattedMessage id='notifications.column_settings.admin.sign_up' defaultMessage='New sign-ups:' /></h3>
|
||||
|
||||
@ -228,7 +225,7 @@ export default class ColumnSettings extends PureComponent {
|
||||
</section>
|
||||
)}
|
||||
|
||||
{((this.context.identity.permissions & PERMISSION_MANAGE_REPORTS) === PERMISSION_MANAGE_REPORTS) && (
|
||||
{((this.props.identity.permissions & PERMISSION_MANAGE_REPORTS) === PERMISSION_MANAGE_REPORTS) && (
|
||||
<section role='group' aria-labelledby='notifications-admin-report'>
|
||||
<h3 id='notifications-status'><FormattedMessage id='notifications.column_settings.admin.report' defaultMessage='New reports:' /></h3>
|
||||
|
||||
@ -245,3 +242,5 @@ export default class ColumnSettings extends PureComponent {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default withIdentity(ColumnSettings);
|
||||
|
@ -17,6 +17,7 @@ import NotificationsIcon from '@/material-icons/400-24px/notifications-fill.svg?
|
||||
import { compareId } from 'mastodon/compare_id';
|
||||
import { Icon } from 'mastodon/components/icon';
|
||||
import { NotSignedInIndicator } from 'mastodon/components/not_signed_in_indicator';
|
||||
import { identityContextPropShape, withIdentity } from 'mastodon/identity_context';
|
||||
|
||||
import { addColumn, removeColumn, moveColumn } from '../../actions/columns';
|
||||
import { submitMarkers } from '../../actions/markers';
|
||||
@ -77,12 +78,8 @@ const mapStateToProps = state => ({
|
||||
});
|
||||
|
||||
class Notifications extends PureComponent {
|
||||
|
||||
static contextTypes = {
|
||||
identity: PropTypes.object,
|
||||
};
|
||||
|
||||
static propTypes = {
|
||||
identity: identityContextPropShape,
|
||||
columnId: PropTypes.string,
|
||||
notifications: ImmutablePropTypes.list.isRequired,
|
||||
dispatch: PropTypes.func.isRequired,
|
||||
@ -190,7 +187,7 @@ class Notifications extends PureComponent {
|
||||
const { intl, notifications, isLoading, isUnread, columnId, multiColumn, hasMore, numPending, lastReadId, canMarkAsRead, needsNotificationPermission } = this.props;
|
||||
const pinned = !!columnId;
|
||||
const emptyMessage = <FormattedMessage id='empty_column.notifications' defaultMessage="You don't have any notifications yet. When other people interact with you, you will see it here." />;
|
||||
const { signedIn } = this.context.identity;
|
||||
const { signedIn } = this.props.identity;
|
||||
|
||||
let scrollableContent = null;
|
||||
|
||||
@ -299,4 +296,4 @@ class Notifications extends PureComponent {
|
||||
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps)(injectIntl(Notifications));
|
||||
export default connect(mapStateToProps)(withIdentity(injectIntl(Notifications)));
|
||||
|
@ -18,6 +18,7 @@ import { replyCompose } from 'mastodon/actions/compose';
|
||||
import { reblog, favourite, unreblog, unfavourite } from 'mastodon/actions/interactions';
|
||||
import { openModal } from 'mastodon/actions/modal';
|
||||
import { IconButton } from 'mastodon/components/icon_button';
|
||||
import { identityContextPropShape, withIdentity } from 'mastodon/identity_context';
|
||||
import { me, boostModal } from 'mastodon/initial_state';
|
||||
import { makeGetStatus } from 'mastodon/selectors';
|
||||
import { WithRouterPropTypes } from 'mastodon/utils/react_router';
|
||||
@ -47,12 +48,8 @@ const makeMapStateToProps = () => {
|
||||
};
|
||||
|
||||
class Footer extends ImmutablePureComponent {
|
||||
|
||||
static contextTypes = {
|
||||
identity: PropTypes.object,
|
||||
};
|
||||
|
||||
static propTypes = {
|
||||
identity: identityContextPropShape,
|
||||
statusId: PropTypes.string.isRequired,
|
||||
status: ImmutablePropTypes.map.isRequired,
|
||||
intl: PropTypes.object.isRequired,
|
||||
@ -75,7 +72,7 @@ class Footer extends ImmutablePureComponent {
|
||||
|
||||
handleReplyClick = () => {
|
||||
const { dispatch, askReplyConfirmation, status, intl } = this.props;
|
||||
const { signedIn } = this.context.identity;
|
||||
const { signedIn } = this.props.identity;
|
||||
|
||||
if (signedIn) {
|
||||
if (askReplyConfirmation) {
|
||||
@ -104,7 +101,7 @@ class Footer extends ImmutablePureComponent {
|
||||
|
||||
handleFavouriteClick = () => {
|
||||
const { dispatch, status } = this.props;
|
||||
const { signedIn } = this.context.identity;
|
||||
const { signedIn } = this.props.identity;
|
||||
|
||||
if (signedIn) {
|
||||
if (status.get('favourited')) {
|
||||
@ -131,7 +128,7 @@ class Footer extends ImmutablePureComponent {
|
||||
|
||||
handleReblogClick = e => {
|
||||
const { dispatch, status } = this.props;
|
||||
const { signedIn } = this.context.identity;
|
||||
const { signedIn } = this.props.identity;
|
||||
|
||||
if (signedIn) {
|
||||
if (status.get('reblogged')) {
|
||||
@ -209,4 +206,4 @@ class Footer extends ImmutablePureComponent {
|
||||
|
||||
}
|
||||
|
||||
export default connect(makeMapStateToProps)(withRouter(injectIntl(Footer)));
|
||||
export default connect(makeMapStateToProps)(withIdentity(withRouter(injectIntl(Footer))));
|
||||
|
@ -9,6 +9,7 @@ import { connect } from 'react-redux';
|
||||
|
||||
import PublicIcon from '@/material-icons/400-24px/public.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';
|
||||
@ -40,16 +41,12 @@ const mapStateToProps = (state, { columnId }) => {
|
||||
};
|
||||
|
||||
class PublicTimeline extends PureComponent {
|
||||
|
||||
static contextTypes = {
|
||||
identity: PropTypes.object,
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
onlyMedia: false,
|
||||
};
|
||||
|
||||
static propTypes = {
|
||||
identity: identityContextPropShape,
|
||||
dispatch: PropTypes.func.isRequired,
|
||||
intl: PropTypes.object.isRequired,
|
||||
columnId: PropTypes.string,
|
||||
@ -80,7 +77,7 @@ class PublicTimeline extends PureComponent {
|
||||
|
||||
componentDidMount () {
|
||||
const { dispatch, onlyMedia, onlyRemote } = this.props;
|
||||
const { signedIn } = this.context.identity;
|
||||
const { signedIn } = this.props.identity;
|
||||
|
||||
dispatch(expandPublicTimeline({ onlyMedia, onlyRemote }));
|
||||
|
||||
@ -90,7 +87,7 @@ class PublicTimeline extends PureComponent {
|
||||
}
|
||||
|
||||
componentDidUpdate (prevProps) {
|
||||
const { signedIn } = this.context.identity;
|
||||
const { signedIn } = this.props.identity;
|
||||
|
||||
if (prevProps.onlyMedia !== this.props.onlyMedia || prevProps.onlyRemote !== this.props.onlyRemote) {
|
||||
const { dispatch, onlyMedia, onlyRemote } = this.props;
|
||||
@ -164,4 +161,4 @@ class PublicTimeline extends PureComponent {
|
||||
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps)(injectIntl(PublicTimeline));
|
||||
export default connect(mapStateToProps)(withIdentity(injectIntl(PublicTimeline)));
|
||||
|
@ -21,6 +21,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';
|
||||
|
||||
@ -67,12 +68,8 @@ const mapStateToProps = (state, { status }) => ({
|
||||
});
|
||||
|
||||
class ActionBar extends PureComponent {
|
||||
|
||||
static contextTypes = {
|
||||
identity: PropTypes.object,
|
||||
};
|
||||
|
||||
static propTypes = {
|
||||
identity: identityContextPropShape,
|
||||
status: ImmutablePropTypes.map.isRequired,
|
||||
relationship: ImmutablePropTypes.record,
|
||||
onReply: PropTypes.func.isRequired,
|
||||
@ -198,7 +195,7 @@ class ActionBar extends PureComponent {
|
||||
|
||||
render () {
|
||||
const { status, relationship, intl } = 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'));
|
||||
@ -326,4 +323,4 @@ class ActionBar extends PureComponent {
|
||||
|
||||
}
|
||||
|
||||
export default withRouter(connect(mapStateToProps)(injectIntl(ActionBar)));
|
||||
export default withRouter(connect(mapStateToProps)(withIdentity(injectIntl(ActionBar))));
|
||||
|
@ -20,6 +20,7 @@ import { Icon } from 'mastodon/components/icon';
|
||||
import { LoadingIndicator } from 'mastodon/components/loading_indicator';
|
||||
import ScrollContainer from 'mastodon/containers/scroll_container';
|
||||
import BundleColumnError from 'mastodon/features/ui/components/bundle_column_error';
|
||||
import { identityContextPropShape, withIdentity } from 'mastodon/identity_context';
|
||||
import { WithRouterPropTypes } from 'mastodon/utils/react_router';
|
||||
|
||||
import {
|
||||
@ -189,12 +190,8 @@ const titleFromStatus = (intl, status) => {
|
||||
};
|
||||
|
||||
class Status extends ImmutablePureComponent {
|
||||
|
||||
static contextTypes = {
|
||||
identity: PropTypes.object,
|
||||
};
|
||||
|
||||
static propTypes = {
|
||||
identity: identityContextPropShape,
|
||||
params: PropTypes.object.isRequired,
|
||||
dispatch: PropTypes.func.isRequired,
|
||||
status: ImmutablePropTypes.map,
|
||||
@ -244,7 +241,7 @@ class Status extends ImmutablePureComponent {
|
||||
|
||||
handleFavouriteClick = (status) => {
|
||||
const { dispatch } = this.props;
|
||||
const { signedIn } = this.context.identity;
|
||||
const { signedIn } = this.props.identity;
|
||||
|
||||
if (signedIn) {
|
||||
if (status.get('favourited')) {
|
||||
@ -274,7 +271,7 @@ class Status extends ImmutablePureComponent {
|
||||
|
||||
handleReplyClick = (status) => {
|
||||
const { askReplyConfirmation, dispatch, intl } = this.props;
|
||||
const { signedIn } = this.context.identity;
|
||||
const { signedIn } = this.props.identity;
|
||||
|
||||
if (signedIn) {
|
||||
if (askReplyConfirmation) {
|
||||
@ -307,7 +304,7 @@ class Status extends ImmutablePureComponent {
|
||||
|
||||
handleReblogClick = (status, e) => {
|
||||
const { dispatch } = this.props;
|
||||
const { signedIn } = this.context.identity;
|
||||
const { signedIn } = this.props.identity;
|
||||
|
||||
if (signedIn) {
|
||||
if (status.get('reblogged')) {
|
||||
@ -745,4 +742,4 @@ class Status extends ImmutablePureComponent {
|
||||
|
||||
}
|
||||
|
||||
export default withRouter(injectIntl(connect(makeMapStateToProps)(Status)));
|
||||
export default withRouter(injectIntl(connect(makeMapStateToProps)(withIdentity(Status))));
|
||||
|
@ -7,16 +7,13 @@ import { changeComposing, mountCompose, unmountCompose } from 'mastodon/actions/
|
||||
import ServerBanner from 'mastodon/components/server_banner';
|
||||
import ComposeFormContainer from 'mastodon/features/compose/containers/compose_form_container';
|
||||
import SearchContainer from 'mastodon/features/compose/containers/search_container';
|
||||
import { identityContextPropShape, withIdentity } from 'mastodon/identity_context';
|
||||
|
||||
import LinkFooter from './link_footer';
|
||||
|
||||
class ComposePanel extends PureComponent {
|
||||
|
||||
static contextTypes = {
|
||||
identity: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
static propTypes = {
|
||||
identity: identityContextPropShape,
|
||||
dispatch: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
@ -41,7 +38,7 @@ class ComposePanel extends PureComponent {
|
||||
}
|
||||
|
||||
render() {
|
||||
const { signedIn } = this.context.identity;
|
||||
const { signedIn } = this.props.identity;
|
||||
|
||||
return (
|
||||
<div className='compose-panel' onFocus={this.onFocus}>
|
||||
@ -65,4 +62,4 @@ class ComposePanel extends PureComponent {
|
||||
|
||||
}
|
||||
|
||||
export default connect()(ComposePanel);
|
||||
export default connect()(withIdentity(ComposePanel));
|
||||
|
@ -13,6 +13,7 @@ import { fetchServer } from 'mastodon/actions/server';
|
||||
import { Avatar } from 'mastodon/components/avatar';
|
||||
import { Icon } from 'mastodon/components/icon';
|
||||
import { WordmarkLogo, SymbolLogo } from 'mastodon/components/logo';
|
||||
import { identityContextPropShape, withIdentity } from 'mastodon/identity_context';
|
||||
import { registrationsOpen, me, sso_redirect } from 'mastodon/initial_state';
|
||||
|
||||
const Account = connect(state => ({
|
||||
@ -41,12 +42,8 @@ const mapDispatchToProps = (dispatch) => ({
|
||||
});
|
||||
|
||||
class Header extends PureComponent {
|
||||
|
||||
static contextTypes = {
|
||||
identity: PropTypes.object,
|
||||
};
|
||||
|
||||
static propTypes = {
|
||||
identity: identityContextPropShape,
|
||||
openClosedRegistrationsModal: PropTypes.func,
|
||||
location: PropTypes.object,
|
||||
signupUrl: PropTypes.string.isRequired,
|
||||
@ -60,7 +57,7 @@ class Header extends PureComponent {
|
||||
}
|
||||
|
||||
render () {
|
||||
const { signedIn } = this.context.identity;
|
||||
const { signedIn } = this.props.identity;
|
||||
const { location, openClosedRegistrationsModal, signupUrl, intl } = this.props;
|
||||
|
||||
let content;
|
||||
@ -121,4 +118,4 @@ class Header extends PureComponent {
|
||||
|
||||
}
|
||||
|
||||
export default injectIntl(withRouter(connect(mapStateToProps, mapDispatchToProps)(Header)));
|
||||
export default injectIntl(withRouter(withIdentity(connect(mapStateToProps, mapDispatchToProps)(Header))));
|
||||
|
@ -8,6 +8,7 @@ import { Link } from 'react-router-dom';
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import { openModal } from 'mastodon/actions/modal';
|
||||
import { identityContextPropShape, withIdentity } from 'mastodon/identity_context';
|
||||
import { domain, version, source_url, statusPageUrl, profile_directory as profileDirectory } from 'mastodon/initial_state';
|
||||
import { PERMISSION_INVITE_USERS } from 'mastodon/permissions';
|
||||
import { logOut } from 'mastodon/utils/log_out';
|
||||
@ -32,12 +33,8 @@ const mapDispatchToProps = (dispatch, { intl }) => ({
|
||||
});
|
||||
|
||||
class LinkFooter extends PureComponent {
|
||||
|
||||
static contextTypes = {
|
||||
identity: PropTypes.object,
|
||||
};
|
||||
|
||||
static propTypes = {
|
||||
identity: identityContextPropShape,
|
||||
multiColumn: PropTypes.bool,
|
||||
onLogout: PropTypes.func.isRequired,
|
||||
intl: PropTypes.object.isRequired,
|
||||
@ -53,7 +50,7 @@ class LinkFooter extends PureComponent {
|
||||
};
|
||||
|
||||
render () {
|
||||
const { signedIn, permissions } = this.context.identity;
|
||||
const { signedIn, permissions } = this.props.identity;
|
||||
const { multiColumn } = this.props;
|
||||
|
||||
const canInvite = signedIn && ((permissions & PERMISSION_INVITE_USERS) === PERMISSION_INVITE_USERS);
|
||||
@ -108,4 +105,4 @@ class LinkFooter extends PureComponent {
|
||||
|
||||
}
|
||||
|
||||
export default injectIntl(connect(null, mapDispatchToProps)(LinkFooter));
|
||||
export default injectIntl(withIdentity(connect(null, mapDispatchToProps)(LinkFooter)));
|
||||
|
@ -31,6 +31,7 @@ import { fetchFollowRequests } from 'mastodon/actions/accounts';
|
||||
import { IconWithBadge } from 'mastodon/components/icon_with_badge';
|
||||
import { WordmarkLogo } from 'mastodon/components/logo';
|
||||
import { NavigationPortal } from 'mastodon/components/navigation_portal';
|
||||
import { identityContextPropShape, withIdentity } from 'mastodon/identity_context';
|
||||
import { timelinePreview, trendsEnabled } from 'mastodon/initial_state';
|
||||
import { transientSingleColumn } from 'mastodon/is_mobile';
|
||||
|
||||
@ -97,12 +98,8 @@ const FollowRequestsLink = () => {
|
||||
};
|
||||
|
||||
class NavigationPanel extends Component {
|
||||
|
||||
static contextTypes = {
|
||||
identity: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
static propTypes = {
|
||||
identity: identityContextPropShape,
|
||||
intl: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
@ -112,7 +109,7 @@ class NavigationPanel extends Component {
|
||||
|
||||
render () {
|
||||
const { intl } = this.props;
|
||||
const { signedIn, disabledAccountId } = this.context.identity;
|
||||
const { signedIn, disabledAccountId } = this.props.identity;
|
||||
|
||||
let banner = undefined;
|
||||
|
||||
@ -189,4 +186,4 @@ class NavigationPanel extends Component {
|
||||
|
||||
}
|
||||
|
||||
export default injectIntl(NavigationPanel);
|
||||
export default injectIntl(withIdentity(NavigationPanel));
|
||||
|
@ -15,6 +15,7 @@ import { focusApp, unfocusApp, changeLayout } from 'mastodon/actions/app';
|
||||
import { synchronouslySubmitMarkers, submitMarkers, fetchMarkers } from 'mastodon/actions/markers';
|
||||
import { INTRODUCTION_VERSION } from 'mastodon/actions/onboarding';
|
||||
import { PictureInPicture } from 'mastodon/features/picture_in_picture';
|
||||
import { identityContextPropShape, withIdentity } from 'mastodon/identity_context';
|
||||
import { layoutFromWindow } from 'mastodon/is_mobile';
|
||||
import { WithRouterPropTypes } from 'mastodon/utils/react_router';
|
||||
|
||||
@ -120,12 +121,8 @@ const keyMap = {
|
||||
};
|
||||
|
||||
class SwitchingColumnsArea extends PureComponent {
|
||||
|
||||
static contextTypes = {
|
||||
identity: PropTypes.object,
|
||||
};
|
||||
|
||||
static propTypes = {
|
||||
identity: identityContextPropShape,
|
||||
children: PropTypes.node,
|
||||
location: PropTypes.object,
|
||||
singleColumn: PropTypes.bool,
|
||||
@ -160,7 +157,7 @@ class SwitchingColumnsArea extends PureComponent {
|
||||
|
||||
render () {
|
||||
const { children, singleColumn } = this.props;
|
||||
const { signedIn } = this.context.identity;
|
||||
const { signedIn } = this.props.identity;
|
||||
const pathName = this.props.location.pathname;
|
||||
|
||||
let redirect;
|
||||
@ -252,12 +249,8 @@ class SwitchingColumnsArea extends PureComponent {
|
||||
}
|
||||
|
||||
class UI extends PureComponent {
|
||||
|
||||
static contextTypes = {
|
||||
identity: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
static propTypes = {
|
||||
identity: identityContextPropShape,
|
||||
dispatch: PropTypes.func.isRequired,
|
||||
children: PropTypes.node,
|
||||
isComposing: PropTypes.bool,
|
||||
@ -309,7 +302,7 @@ class UI extends PureComponent {
|
||||
this.dragTargets.push(e.target);
|
||||
}
|
||||
|
||||
if (e.dataTransfer && Array.from(e.dataTransfer.types).includes('Files') && this.props.canUploadMore && this.context.identity.signedIn) {
|
||||
if (e.dataTransfer && Array.from(e.dataTransfer.types).includes('Files') && this.props.canUploadMore && this.props.identity.signedIn) {
|
||||
this.setState({ draggingOver: true });
|
||||
}
|
||||
};
|
||||
@ -337,7 +330,7 @@ class UI extends PureComponent {
|
||||
this.setState({ draggingOver: false });
|
||||
this.dragTargets = [];
|
||||
|
||||
if (e.dataTransfer && e.dataTransfer.files.length >= 1 && this.props.canUploadMore && this.context.identity.signedIn) {
|
||||
if (e.dataTransfer && e.dataTransfer.files.length >= 1 && this.props.canUploadMore && this.props.identity.signedIn) {
|
||||
this.props.dispatch(uploadCompose(e.dataTransfer.files));
|
||||
}
|
||||
};
|
||||
@ -389,7 +382,7 @@ class UI extends PureComponent {
|
||||
};
|
||||
|
||||
componentDidMount () {
|
||||
const { signedIn } = this.context.identity;
|
||||
const { signedIn } = this.props.identity;
|
||||
|
||||
window.addEventListener('focus', this.handleWindowFocus, false);
|
||||
window.addEventListener('blur', this.handleWindowBlur, false);
|
||||
@ -586,7 +579,7 @@ class UI extends PureComponent {
|
||||
<div className={classNames('ui', { 'is-composing': isComposing })} ref={this.setRef}>
|
||||
<Header />
|
||||
|
||||
<SwitchingColumnsArea location={location} singleColumn={layout === 'mobile' || layout === 'single-column'}>
|
||||
<SwitchingColumnsArea identity={this.props.identity} location={location} singleColumn={layout === 'mobile' || layout === 'single-column'}>
|
||||
{children}
|
||||
</SwitchingColumnsArea>
|
||||
|
||||
@ -602,4 +595,4 @@ class UI extends PureComponent {
|
||||
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps)(injectIntl(withRouter(UI)));
|
||||
export default connect(mapStateToProps)(injectIntl(withRouter(withIdentity(UI))));
|
||||
|
74
app/javascript/mastodon/identity_context.tsx
Normal file
74
app/javascript/mastodon/identity_context.tsx
Normal file
@ -0,0 +1,74 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import { createContext, useContext } from 'react';
|
||||
|
||||
import hoistStatics from 'hoist-non-react-statics';
|
||||
|
||||
import type { InitialState } from 'mastodon/initial_state';
|
||||
|
||||
export interface IdentityContextType {
|
||||
signedIn: boolean;
|
||||
accountId: string | undefined;
|
||||
disabledAccountId: string | undefined;
|
||||
accessToken: string | undefined;
|
||||
permissions: number;
|
||||
}
|
||||
|
||||
export const identityContextPropShape = PropTypes.shape({
|
||||
signedIn: PropTypes.bool.isRequired,
|
||||
accountId: PropTypes.string,
|
||||
disabledAccountId: PropTypes.string,
|
||||
accessToken: PropTypes.string,
|
||||
}).isRequired;
|
||||
|
||||
export const createIdentityContext = (state: InitialState) => ({
|
||||
signedIn: !!state.meta.me,
|
||||
accountId: state.meta.me,
|
||||
disabledAccountId: state.meta.disabled_account_id,
|
||||
accessToken: state.meta.access_token,
|
||||
permissions: state.role?.permissions ?? 0,
|
||||
});
|
||||
|
||||
export const IdentityContext = createContext<IdentityContextType>({
|
||||
signedIn: false,
|
||||
permissions: 0,
|
||||
accountId: undefined,
|
||||
disabledAccountId: undefined,
|
||||
accessToken: undefined,
|
||||
});
|
||||
|
||||
export const useIdentity = () => useContext(IdentityContext);
|
||||
|
||||
export interface IdentityProps {
|
||||
ref?: unknown;
|
||||
wrappedComponentRef?: unknown;
|
||||
}
|
||||
|
||||
/* Injects an `identity` props into the wrapped component to be able to use the new context in class components */
|
||||
export function withIdentity<
|
||||
ComponentType extends React.ComponentType<IdentityProps>,
|
||||
>(Component: ComponentType) {
|
||||
const displayName = `withIdentity(${Component.displayName ?? Component.name})`;
|
||||
const C = (props: React.ComponentProps<ComponentType>) => {
|
||||
const { wrappedComponentRef, ...remainingProps } = props;
|
||||
|
||||
return (
|
||||
<IdentityContext.Consumer>
|
||||
{(context) => {
|
||||
return (
|
||||
// @ts-expect-error - Dynamic covariant generic components are tough to type.
|
||||
<Component
|
||||
{...remainingProps}
|
||||
identity={context}
|
||||
ref={wrappedComponentRef}
|
||||
/>
|
||||
);
|
||||
}}
|
||||
</IdentityContext.Consumer>
|
||||
);
|
||||
};
|
||||
|
||||
C.displayName = displayName;
|
||||
C.WrappedComponent = Component;
|
||||
|
||||
return hoistStatics(C, Component);
|
||||
}
|
@ -44,12 +44,22 @@
|
||||
* @property {string} sso_redirect
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef Role
|
||||
* @property {string} id
|
||||
* @property {string} name
|
||||
* @property {string} permissions
|
||||
* @property {string} color
|
||||
* @property {boolean} highlighted
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef InitialState
|
||||
* @property {Record<string, import("./api_types/accounts").ApiAccountJSON>} accounts
|
||||
* @property {InitialStateLanguage[]} languages
|
||||
* @property {boolean=} critical_updates_pending
|
||||
* @property {InitialStateMeta} meta
|
||||
* @property {Role?} role
|
||||
*/
|
||||
|
||||
const element = document.getElementById('initial-state');
|
||||
|
Loading…
Reference in New Issue
Block a user