Use a modern React context for identity in the app (#30098)
This commit is contained in:
parent
6282b6da77
commit
a178ba7cd5
26 changed files with 212 additions and 223 deletions
|
@ -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 SettingsIcon from '@/material-icons/400-24px/settings.svg?react';
|
||||||
import { Icon } from 'mastodon/components/icon';
|
import { Icon } from 'mastodon/components/icon';
|
||||||
import { ButtonInTabsBar } from 'mastodon/features/ui/util/columns_context';
|
import { ButtonInTabsBar } from 'mastodon/features/ui/util/columns_context';
|
||||||
|
import { identityContextPropShape, withIdentity } from 'mastodon/identity_context';
|
||||||
import { WithRouterPropTypes } from 'mastodon/utils/react_router';
|
import { WithRouterPropTypes } from 'mastodon/utils/react_router';
|
||||||
|
|
||||||
|
|
||||||
import { useAppHistory } from './router';
|
import { useAppHistory } from './router';
|
||||||
|
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
|
@ -51,12 +53,8 @@ BackButton.propTypes = {
|
||||||
};
|
};
|
||||||
|
|
||||||
class ColumnHeader extends PureComponent {
|
class ColumnHeader extends PureComponent {
|
||||||
|
|
||||||
static contextTypes = {
|
|
||||||
identity: PropTypes.object,
|
|
||||||
};
|
|
||||||
|
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
|
identity: identityContextPropShape,
|
||||||
intl: PropTypes.object.isRequired,
|
intl: PropTypes.object.isRequired,
|
||||||
title: PropTypes.node,
|
title: PropTypes.node,
|
||||||
icon: PropTypes.string,
|
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 = (
|
collapseButton = (
|
||||||
<button
|
<button
|
||||||
className={collapsibleButtonClassName}
|
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 { Icon } from 'mastodon/components/icon';
|
||||||
import emojify from 'mastodon/features/emoji/emoji';
|
import emojify from 'mastodon/features/emoji/emoji';
|
||||||
import Motion from 'mastodon/features/ui/util/optional_motion';
|
import Motion from 'mastodon/features/ui/util/optional_motion';
|
||||||
|
import { identityContextPropShape, withIdentity } from 'mastodon/identity_context';
|
||||||
|
|
||||||
import { RelativeTimestamp } from './relative_timestamp';
|
import { RelativeTimestamp } from './relative_timestamp';
|
||||||
|
|
||||||
|
@ -38,12 +39,8 @@ const makeEmojiMap = record => record.get('emojis').reduce((obj, emoji) => {
|
||||||
}, {});
|
}, {});
|
||||||
|
|
||||||
class Poll extends ImmutablePureComponent {
|
class Poll extends ImmutablePureComponent {
|
||||||
|
|
||||||
static contextTypes = {
|
|
||||||
identity: PropTypes.object,
|
|
||||||
};
|
|
||||||
|
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
|
identity: identityContextPropShape,
|
||||||
poll: ImmutablePropTypes.map,
|
poll: ImmutablePropTypes.map,
|
||||||
lang: PropTypes.string,
|
lang: PropTypes.string,
|
||||||
intl: PropTypes.object.isRequired,
|
intl: PropTypes.object.isRequired,
|
||||||
|
@ -235,7 +232,7 @@ class Poll extends ImmutablePureComponent {
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<div className='poll__footer'>
|
<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 && <><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> · </>}
|
{showResults && !this.props.disabled && <><button className='poll__link' onClick={this.handleRefresh}><FormattedMessage id='poll.refresh' defaultMessage='Refresh' /></button> · </>}
|
||||||
{votesCount}
|
{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 RepeatDisabledIcon from '@/svg-icons/repeat_disabled.svg?react';
|
||||||
import RepeatPrivateIcon from '@/svg-icons/repeat_private.svg?react';
|
import RepeatPrivateIcon from '@/svg-icons/repeat_private.svg?react';
|
||||||
import RepeatPrivateActiveIcon from '@/svg-icons/repeat_private_active.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 { PERMISSION_MANAGE_USERS, PERMISSION_MANAGE_FEDERATION } from 'mastodon/permissions';
|
||||||
import { WithRouterPropTypes } from 'mastodon/utils/react_router';
|
import { WithRouterPropTypes } from 'mastodon/utils/react_router';
|
||||||
|
|
||||||
|
@ -74,12 +75,8 @@ const mapStateToProps = (state, { status }) => ({
|
||||||
});
|
});
|
||||||
|
|
||||||
class StatusActionBar extends ImmutablePureComponent {
|
class StatusActionBar extends ImmutablePureComponent {
|
||||||
|
|
||||||
static contextTypes = {
|
|
||||||
identity: PropTypes.object,
|
|
||||||
};
|
|
||||||
|
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
|
identity: identityContextPropShape,
|
||||||
status: ImmutablePropTypes.map.isRequired,
|
status: ImmutablePropTypes.map.isRequired,
|
||||||
relationship: ImmutablePropTypes.record,
|
relationship: ImmutablePropTypes.record,
|
||||||
onReply: PropTypes.func,
|
onReply: PropTypes.func,
|
||||||
|
@ -118,7 +115,7 @@ class StatusActionBar extends ImmutablePureComponent {
|
||||||
];
|
];
|
||||||
|
|
||||||
handleReplyClick = () => {
|
handleReplyClick = () => {
|
||||||
const { signedIn } = this.context.identity;
|
const { signedIn } = this.props.identity;
|
||||||
|
|
||||||
if (signedIn) {
|
if (signedIn) {
|
||||||
this.props.onReply(this.props.status, this.props.history);
|
this.props.onReply(this.props.status, this.props.history);
|
||||||
|
@ -136,7 +133,7 @@ class StatusActionBar extends ImmutablePureComponent {
|
||||||
};
|
};
|
||||||
|
|
||||||
handleFavouriteClick = () => {
|
handleFavouriteClick = () => {
|
||||||
const { signedIn } = this.context.identity;
|
const { signedIn } = this.props.identity;
|
||||||
|
|
||||||
if (signedIn) {
|
if (signedIn) {
|
||||||
this.props.onFavourite(this.props.status);
|
this.props.onFavourite(this.props.status);
|
||||||
|
@ -146,7 +143,7 @@ class StatusActionBar extends ImmutablePureComponent {
|
||||||
};
|
};
|
||||||
|
|
||||||
handleReblogClick = e => {
|
handleReblogClick = e => {
|
||||||
const { signedIn } = this.context.identity;
|
const { signedIn } = this.props.identity;
|
||||||
|
|
||||||
if (signedIn) {
|
if (signedIn) {
|
||||||
this.props.onReblog(this.props.status, e);
|
this.props.onReblog(this.props.status, e);
|
||||||
|
@ -250,7 +247,7 @@ class StatusActionBar extends ImmutablePureComponent {
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
const { status, relationship, intl, withDismiss, withCounters, scrollKey } = this.props;
|
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 publicStatus = ['public', 'unlisted'].includes(status.get('visibility'));
|
||||||
const pinnableStatus = ['public', 'unlisted', 'private'].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 ChevronRightIcon from '@/material-icons/400-24px/chevron_right.svg?react';
|
||||||
import { Icon } from 'mastodon/components/icon';
|
import { Icon } from 'mastodon/components/icon';
|
||||||
import PollContainer from 'mastodon/containers/poll_container';
|
import PollContainer from 'mastodon/containers/poll_container';
|
||||||
|
import { identityContextPropShape, withIdentity } from 'mastodon/identity_context';
|
||||||
import { autoPlayGif, languages as preloadedLanguages } from 'mastodon/initial_state';
|
import { autoPlayGif, languages as preloadedLanguages } from 'mastodon/initial_state';
|
||||||
|
|
||||||
|
|
||||||
const MAX_HEIGHT = 706; // 22px * 32 (+ 2px padding at the top)
|
const MAX_HEIGHT = 706; // 22px * 32 (+ 2px padding at the top)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -67,12 +69,8 @@ const mapStateToProps = state => ({
|
||||||
});
|
});
|
||||||
|
|
||||||
class StatusContent extends PureComponent {
|
class StatusContent extends PureComponent {
|
||||||
|
|
||||||
static contextTypes = {
|
|
||||||
identity: PropTypes.object,
|
|
||||||
};
|
|
||||||
|
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
|
identity: identityContextPropShape,
|
||||||
status: ImmutablePropTypes.map.isRequired,
|
status: ImmutablePropTypes.map.isRequired,
|
||||||
statusContent: PropTypes.string,
|
statusContent: PropTypes.string,
|
||||||
expanded: PropTypes.bool,
|
expanded: PropTypes.bool,
|
||||||
|
@ -245,7 +243,7 @@ class StatusContent extends PureComponent {
|
||||||
const renderReadMore = this.props.onClick && status.get('collapsed');
|
const renderReadMore = this.props.onClick && status.get('collapsed');
|
||||||
const contentLocale = intl.locale.replace(/[_-].*/, '');
|
const contentLocale = intl.locale.replace(/[_-].*/, '');
|
||||||
const targetLanguages = this.props.languages?.get(status.get('language') || 'und');
|
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 content = { __html: statusContent ?? getStatusContent(status) };
|
||||||
const spoilerContent = { __html: status.getIn(['translation', 'spoilerHtml']) || status.get('spoilerHtml') };
|
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 { PureComponent } from 'react';
|
||||||
|
|
||||||
import { Helmet } from 'react-helmet';
|
import { Helmet } from 'react-helmet';
|
||||||
|
@ -14,6 +13,7 @@ import { connectUserStream } from 'mastodon/actions/streaming';
|
||||||
import ErrorBoundary from 'mastodon/components/error_boundary';
|
import ErrorBoundary from 'mastodon/components/error_boundary';
|
||||||
import { Router } from 'mastodon/components/router';
|
import { Router } from 'mastodon/components/router';
|
||||||
import UI from 'mastodon/features/ui';
|
import UI from 'mastodon/features/ui';
|
||||||
|
import { IdentityContext, createIdentityContext } from 'mastodon/identity_context';
|
||||||
import initialState, { title as siteTitle } from 'mastodon/initial_state';
|
import initialState, { title as siteTitle } from 'mastodon/initial_state';
|
||||||
import { IntlProvider } from 'mastodon/locales';
|
import { IntlProvider } from 'mastodon/locales';
|
||||||
import { store } from 'mastodon/store';
|
import { store } from 'mastodon/store';
|
||||||
|
@ -28,33 +28,9 @@ if (initialState.meta.me) {
|
||||||
store.dispatch(fetchCustomEmojis());
|
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 {
|
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);
|
identity = createIdentityContext(initialState);
|
||||||
|
|
||||||
getChildContext() {
|
|
||||||
return {
|
|
||||||
identity: this.identity,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
if (this.identity.signedIn) {
|
if (this.identity.signedIn) {
|
||||||
this.disconnect = store.dispatch(connectUserStream());
|
this.disconnect = store.dispatch(connectUserStream());
|
||||||
|
@ -74,19 +50,21 @@ export default class Mastodon extends PureComponent {
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
return (
|
return (
|
||||||
<IntlProvider>
|
<IdentityContext.Provider value={this.identity}>
|
||||||
<ReduxProvider store={store}>
|
<IntlProvider>
|
||||||
<ErrorBoundary>
|
<ReduxProvider store={store}>
|
||||||
<Router>
|
<ErrorBoundary>
|
||||||
<ScrollContext shouldUpdateScroll={this.shouldUpdateScroll}>
|
<Router>
|
||||||
<Route path='/' component={UI} />
|
<ScrollContext shouldUpdateScroll={this.shouldUpdateScroll}>
|
||||||
</ScrollContext>
|
<Route path='/' component={UI} />
|
||||||
</Router>
|
</ScrollContext>
|
||||||
|
</Router>
|
||||||
|
|
||||||
<Helmet defaultTitle={title} titleTemplate={`%s - ${title}`} />
|
<Helmet defaultTitle={title} titleTemplate={`%s - ${title}`} />
|
||||||
</ErrorBoundary>
|
</ErrorBoundary>
|
||||||
</ReduxProvider>
|
</ReduxProvider>
|
||||||
</IntlProvider>
|
</IntlProvider>
|
||||||
|
</IdentityContext.Provider>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,7 @@ import { IconButton } from 'mastodon/components/icon_button';
|
||||||
import { LoadingIndicator } from 'mastodon/components/loading_indicator';
|
import { LoadingIndicator } from 'mastodon/components/loading_indicator';
|
||||||
import { ShortNumber } from 'mastodon/components/short_number';
|
import { ShortNumber } from 'mastodon/components/short_number';
|
||||||
import DropdownMenuContainer from 'mastodon/containers/dropdown_menu_container';
|
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 { autoPlayGif, me, domain as localDomain } from 'mastodon/initial_state';
|
||||||
import { PERMISSION_MANAGE_USERS, PERMISSION_MANAGE_FEDERATION } from 'mastodon/permissions';
|
import { PERMISSION_MANAGE_USERS, PERMISSION_MANAGE_FEDERATION } from 'mastodon/permissions';
|
||||||
import { WithRouterPropTypes } from 'mastodon/utils/react_router';
|
import { WithRouterPropTypes } from 'mastodon/utils/react_router';
|
||||||
|
@ -111,6 +112,7 @@ const dateFormatOptions = {
|
||||||
class Header extends ImmutablePureComponent {
|
class Header extends ImmutablePureComponent {
|
||||||
|
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
|
identity: identityContextPropShape,
|
||||||
account: ImmutablePropTypes.record,
|
account: ImmutablePropTypes.record,
|
||||||
identity_props: ImmutablePropTypes.list,
|
identity_props: ImmutablePropTypes.list,
|
||||||
onFollow: PropTypes.func.isRequired,
|
onFollow: PropTypes.func.isRequired,
|
||||||
|
@ -136,10 +138,6 @@ class Header extends ImmutablePureComponent {
|
||||||
...WithRouterPropTypes,
|
...WithRouterPropTypes,
|
||||||
};
|
};
|
||||||
|
|
||||||
static contextTypes = {
|
|
||||||
identity: PropTypes.object,
|
|
||||||
};
|
|
||||||
|
|
||||||
setRef = c => {
|
setRef = c => {
|
||||||
this.node = c;
|
this.node = c;
|
||||||
};
|
};
|
||||||
|
@ -255,7 +253,7 @@ class Header extends ImmutablePureComponent {
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
const { account, hidden, intl } = this.props;
|
const { account, hidden, intl } = this.props;
|
||||||
const { signedIn, permissions } = this.context.identity;
|
const { signedIn, permissions } = this.props.identity;
|
||||||
|
|
||||||
if (!account) {
|
if (!account) {
|
||||||
return null;
|
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 PeopleIcon from '@/material-icons/400-24px/group.svg?react';
|
||||||
import { DismissableBanner } from 'mastodon/components/dismissable_banner';
|
import { DismissableBanner } from 'mastodon/components/dismissable_banner';
|
||||||
|
import { identityContextPropShape, withIdentity } from 'mastodon/identity_context';
|
||||||
import { domain } from 'mastodon/initial_state';
|
import { domain } from 'mastodon/initial_state';
|
||||||
|
|
||||||
import { addColumn, removeColumn, moveColumn } from '../../actions/columns';
|
import { addColumn, removeColumn, moveColumn } from '../../actions/columns';
|
||||||
|
@ -38,16 +39,12 @@ const mapStateToProps = (state, { columnId }) => {
|
||||||
};
|
};
|
||||||
|
|
||||||
class CommunityTimeline extends PureComponent {
|
class CommunityTimeline extends PureComponent {
|
||||||
|
|
||||||
static contextTypes = {
|
|
||||||
identity: PropTypes.object,
|
|
||||||
};
|
|
||||||
|
|
||||||
static defaultProps = {
|
static defaultProps = {
|
||||||
onlyMedia: false,
|
onlyMedia: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
|
identity: identityContextPropShape,
|
||||||
dispatch: PropTypes.func.isRequired,
|
dispatch: PropTypes.func.isRequired,
|
||||||
columnId: PropTypes.string,
|
columnId: PropTypes.string,
|
||||||
intl: PropTypes.object.isRequired,
|
intl: PropTypes.object.isRequired,
|
||||||
|
@ -77,7 +74,7 @@ class CommunityTimeline extends PureComponent {
|
||||||
|
|
||||||
componentDidMount () {
|
componentDidMount () {
|
||||||
const { dispatch, onlyMedia } = this.props;
|
const { dispatch, onlyMedia } = this.props;
|
||||||
const { signedIn } = this.context.identity;
|
const { signedIn } = this.props.identity;
|
||||||
|
|
||||||
dispatch(expandCommunityTimeline({ onlyMedia }));
|
dispatch(expandCommunityTimeline({ onlyMedia }));
|
||||||
|
|
||||||
|
@ -87,7 +84,7 @@ class CommunityTimeline extends PureComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidUpdate (prevProps) {
|
componentDidUpdate (prevProps) {
|
||||||
const { signedIn } = this.context.identity;
|
const { signedIn } = this.props.identity;
|
||||||
|
|
||||||
if (prevProps.onlyMedia !== this.props.onlyMedia) {
|
if (prevProps.onlyMedia !== this.props.onlyMedia) {
|
||||||
const { dispatch, onlyMedia } = this.props;
|
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 CloseIcon from '@/material-icons/400-24px/close.svg?react';
|
||||||
import SearchIcon from '@/material-icons/400-24px/search.svg?react';
|
import SearchIcon from '@/material-icons/400-24px/search.svg?react';
|
||||||
import { Icon } from 'mastodon/components/icon';
|
import { Icon } from 'mastodon/components/icon';
|
||||||
|
import { identityContextPropShape, withIdentity } from 'mastodon/identity_context';
|
||||||
import { domain, searchEnabled } from 'mastodon/initial_state';
|
import { domain, searchEnabled } from 'mastodon/initial_state';
|
||||||
import { HASHTAG_REGEX } from 'mastodon/utils/hashtags';
|
import { HASHTAG_REGEX } from 'mastodon/utils/hashtags';
|
||||||
import { WithRouterPropTypes } from 'mastodon/utils/react_router';
|
import { WithRouterPropTypes } from 'mastodon/utils/react_router';
|
||||||
|
@ -33,12 +34,8 @@ const labelForRecentSearch = search => {
|
||||||
};
|
};
|
||||||
|
|
||||||
class Search extends PureComponent {
|
class Search extends PureComponent {
|
||||||
|
|
||||||
static contextTypes = {
|
|
||||||
identity: PropTypes.object.isRequired,
|
|
||||||
};
|
|
||||||
|
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
|
identity: identityContextPropShape,
|
||||||
value: PropTypes.string.isRequired,
|
value: PropTypes.string.isRequired,
|
||||||
recent: ImmutablePropTypes.orderedSet,
|
recent: ImmutablePropTypes.orderedSet,
|
||||||
submitted: PropTypes.bool,
|
submitted: PropTypes.bool,
|
||||||
|
@ -276,7 +273,7 @@ class Search extends PureComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
_calculateOptions (value) {
|
_calculateOptions (value) {
|
||||||
const { signedIn } = this.context.identity;
|
const { signedIn } = this.props.identity;
|
||||||
const trimmedValue = value.trim();
|
const trimmedValue = value.trim();
|
||||||
const options = [];
|
const options = [];
|
||||||
|
|
||||||
|
@ -318,7 +315,7 @@ class Search extends PureComponent {
|
||||||
render () {
|
render () {
|
||||||
const { intl, value, submitted, recent } = this.props;
|
const { intl, value, submitted, recent } = this.props;
|
||||||
const { expanded, options, selectedOption } = this.state;
|
const { expanded, options, selectedOption } = this.state;
|
||||||
const { signedIn } = this.context.identity;
|
const { signedIn } = this.props.identity;
|
||||||
|
|
||||||
const hasValue = value.length > 0 || submitted;
|
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 Column from 'mastodon/components/column';
|
||||||
import ColumnHeader from 'mastodon/components/column_header';
|
import ColumnHeader from 'mastodon/components/column_header';
|
||||||
import Search from 'mastodon/features/compose/containers/search_container';
|
import Search from 'mastodon/features/compose/containers/search_container';
|
||||||
|
import { identityContextPropShape, withIdentity } from 'mastodon/identity_context';
|
||||||
import { trendsEnabled } from 'mastodon/initial_state';
|
import { trendsEnabled } from 'mastodon/initial_state';
|
||||||
|
|
||||||
import Links from './links';
|
import Links from './links';
|
||||||
|
@ -32,12 +33,8 @@ const mapStateToProps = state => ({
|
||||||
});
|
});
|
||||||
|
|
||||||
class Explore extends PureComponent {
|
class Explore extends PureComponent {
|
||||||
|
|
||||||
static contextTypes = {
|
|
||||||
identity: PropTypes.object,
|
|
||||||
};
|
|
||||||
|
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
|
identity: identityContextPropShape,
|
||||||
intl: PropTypes.object.isRequired,
|
intl: PropTypes.object.isRequired,
|
||||||
multiColumn: PropTypes.bool,
|
multiColumn: PropTypes.bool,
|
||||||
isSearching: PropTypes.bool,
|
isSearching: PropTypes.bool,
|
||||||
|
@ -53,7 +50,7 @@ class Explore extends PureComponent {
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { intl, multiColumn, isSearching } = this.props;
|
const { intl, multiColumn, isSearching } = this.props;
|
||||||
const { signedIn } = this.context.identity;
|
const { signedIn } = this.props.identity;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Column bindToDocument={!multiColumn} ref={this.setRef} label={intl.formatMessage(messages.title)}>
|
<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 { Helmet } from 'react-helmet';
|
||||||
import { NavLink } from 'react-router-dom';
|
import { NavLink } from 'react-router-dom';
|
||||||
|
|
||||||
|
import { useIdentity } from '@/mastodon/identity_context';
|
||||||
import PublicIcon from '@/material-icons/400-24px/public.svg?react';
|
import PublicIcon from '@/material-icons/400-24px/public.svg?react';
|
||||||
import { addColumn } from 'mastodon/actions/columns';
|
import { addColumn } from 'mastodon/actions/columns';
|
||||||
import { changeSetting } from 'mastodon/actions/settings';
|
import { changeSetting } from 'mastodon/actions/settings';
|
||||||
import { connectPublicStream, connectCommunityStream } from 'mastodon/actions/streaming';
|
import { connectPublicStream, connectCommunityStream } from 'mastodon/actions/streaming';
|
||||||
import { expandPublicTimeline, expandCommunityTimeline } from 'mastodon/actions/timelines';
|
import { expandPublicTimeline, expandCommunityTimeline } from 'mastodon/actions/timelines';
|
||||||
import { DismissableBanner } from 'mastodon/components/dismissable_banner';
|
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 { useAppDispatch, useAppSelector } from 'mastodon/store';
|
||||||
|
|
||||||
import Column from '../../components/column';
|
import Column from '../../components/column';
|
||||||
|
@ -24,15 +25,6 @@ const messages = defineMessages({
|
||||||
title: { id: 'column.firehose', defaultMessage: 'Live feeds' },
|
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 ColumnSettings = () => {
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
const settings = useAppSelector((state) => state.getIn(['settings', 'firehose']));
|
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 Column from 'mastodon/components/column';
|
||||||
import ColumnHeader from 'mastodon/components/column_header';
|
import ColumnHeader from 'mastodon/components/column_header';
|
||||||
import LinkFooter from 'mastodon/features/ui/components/link_footer';
|
import LinkFooter from 'mastodon/features/ui/components/link_footer';
|
||||||
|
import { identityContextPropShape, withIdentity } from 'mastodon/identity_context';
|
||||||
|
|
||||||
import { me, showTrends } from '../../initial_state';
|
import { me, showTrends } from '../../initial_state';
|
||||||
import { NavigationBar } from '../compose/components/navigation_bar';
|
import { NavigationBar } from '../compose/components/navigation_bar';
|
||||||
|
@ -75,12 +76,8 @@ const badgeDisplay = (number, limit) => {
|
||||||
};
|
};
|
||||||
|
|
||||||
class GettingStarted extends ImmutablePureComponent {
|
class GettingStarted extends ImmutablePureComponent {
|
||||||
|
|
||||||
static contextTypes = {
|
|
||||||
identity: PropTypes.object,
|
|
||||||
};
|
|
||||||
|
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
|
identity: identityContextPropShape,
|
||||||
intl: PropTypes.object.isRequired,
|
intl: PropTypes.object.isRequired,
|
||||||
myAccount: ImmutablePropTypes.record,
|
myAccount: ImmutablePropTypes.record,
|
||||||
multiColumn: PropTypes.bool,
|
multiColumn: PropTypes.bool,
|
||||||
|
@ -91,7 +88,7 @@ class GettingStarted extends ImmutablePureComponent {
|
||||||
|
|
||||||
componentDidMount () {
|
componentDidMount () {
|
||||||
const { fetchFollowRequests } = this.props;
|
const { fetchFollowRequests } = this.props;
|
||||||
const { signedIn } = this.context.identity;
|
const { signedIn } = this.props.identity;
|
||||||
|
|
||||||
if (!signedIn) {
|
if (!signedIn) {
|
||||||
return;
|
return;
|
||||||
|
@ -102,7 +99,7 @@ class GettingStarted extends ImmutablePureComponent {
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
const { intl, myAccount, multiColumn, unreadFollowRequests } = this.props;
|
const { intl, myAccount, multiColumn, unreadFollowRequests } = this.props;
|
||||||
const { signedIn } = this.context.identity;
|
const { signedIn } = this.props.identity;
|
||||||
|
|
||||||
const navItems = [];
|
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 { expandHashtagTimeline, clearTimeline } from 'mastodon/actions/timelines';
|
||||||
import Column from 'mastodon/components/column';
|
import Column from 'mastodon/components/column';
|
||||||
import ColumnHeader from 'mastodon/components/column_header';
|
import ColumnHeader from 'mastodon/components/column_header';
|
||||||
|
import { identityContextPropShape, withIdentity } from 'mastodon/identity_context';
|
||||||
|
|
||||||
import StatusListContainer from '../ui/containers/status_list_container';
|
import StatusListContainer from '../ui/containers/status_list_container';
|
||||||
|
|
||||||
|
@ -29,14 +30,10 @@ const mapStateToProps = (state, props) => ({
|
||||||
});
|
});
|
||||||
|
|
||||||
class HashtagTimeline extends PureComponent {
|
class HashtagTimeline extends PureComponent {
|
||||||
|
|
||||||
disconnects = [];
|
disconnects = [];
|
||||||
|
|
||||||
static contextTypes = {
|
|
||||||
identity: PropTypes.object,
|
|
||||||
};
|
|
||||||
|
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
|
identity: identityContextPropShape,
|
||||||
params: PropTypes.object.isRequired,
|
params: PropTypes.object.isRequired,
|
||||||
columnId: PropTypes.string,
|
columnId: PropTypes.string,
|
||||||
dispatch: PropTypes.func.isRequired,
|
dispatch: PropTypes.func.isRequired,
|
||||||
|
@ -94,7 +91,7 @@ class HashtagTimeline extends PureComponent {
|
||||||
};
|
};
|
||||||
|
|
||||||
_subscribe (dispatch, id, tags = {}, local) {
|
_subscribe (dispatch, id, tags = {}, local) {
|
||||||
const { signedIn } = this.context.identity;
|
const { signedIn } = this.props.identity;
|
||||||
|
|
||||||
if (!signedIn) {
|
if (!signedIn) {
|
||||||
return;
|
return;
|
||||||
|
@ -168,7 +165,7 @@ class HashtagTimeline extends PureComponent {
|
||||||
handleFollow = () => {
|
handleFollow = () => {
|
||||||
const { dispatch, params, tag } = this.props;
|
const { dispatch, params, tag } = this.props;
|
||||||
const { id } = params;
|
const { id } = params;
|
||||||
const { signedIn } = this.context.identity;
|
const { signedIn } = this.props.identity;
|
||||||
|
|
||||||
if (!signedIn) {
|
if (!signedIn) {
|
||||||
return;
|
return;
|
||||||
|
@ -185,7 +182,7 @@ class HashtagTimeline extends PureComponent {
|
||||||
const { hasUnread, columnId, multiColumn, tag } = this.props;
|
const { hasUnread, columnId, multiColumn, tag } = this.props;
|
||||||
const { id, local } = this.props.params;
|
const { id, local } = this.props.params;
|
||||||
const pinned = !!columnId;
|
const pinned = !!columnId;
|
||||||
const { signedIn } = this.context.identity;
|
const { signedIn } = this.props.identity;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Column bindToDocument={!multiColumn} ref={this.setRef} label={`#${id}`}>
|
<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 { IconWithBadge } from 'mastodon/components/icon_with_badge';
|
||||||
import { NotSignedInIndicator } from 'mastodon/components/not_signed_in_indicator';
|
import { NotSignedInIndicator } from 'mastodon/components/not_signed_in_indicator';
|
||||||
import AnnouncementsContainer from 'mastodon/features/getting_started/containers/announcements_container';
|
import AnnouncementsContainer from 'mastodon/features/getting_started/containers/announcements_container';
|
||||||
|
import { identityContextPropShape, withIdentity } from 'mastodon/identity_context';
|
||||||
import { criticalUpdatesPending } from 'mastodon/initial_state';
|
import { criticalUpdatesPending } from 'mastodon/initial_state';
|
||||||
|
|
||||||
import { addColumn, removeColumn, moveColumn } from '../../actions/columns';
|
import { addColumn, removeColumn, moveColumn } from '../../actions/columns';
|
||||||
|
@ -40,12 +41,8 @@ const mapStateToProps = state => ({
|
||||||
});
|
});
|
||||||
|
|
||||||
class HomeTimeline extends PureComponent {
|
class HomeTimeline extends PureComponent {
|
||||||
|
|
||||||
static contextTypes = {
|
|
||||||
identity: PropTypes.object,
|
|
||||||
};
|
|
||||||
|
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
|
identity: identityContextPropShape,
|
||||||
dispatch: PropTypes.func.isRequired,
|
dispatch: PropTypes.func.isRequired,
|
||||||
intl: PropTypes.object.isRequired,
|
intl: PropTypes.object.isRequired,
|
||||||
hasUnread: PropTypes.bool,
|
hasUnread: PropTypes.bool,
|
||||||
|
@ -126,7 +123,7 @@ class HomeTimeline extends PureComponent {
|
||||||
render () {
|
render () {
|
||||||
const { intl, hasUnread, columnId, multiColumn, hasAnnouncements, unreadAnnouncements, showAnnouncements } = this.props;
|
const { intl, hasUnread, columnId, multiColumn, hasAnnouncements, unreadAnnouncements, showAnnouncements } = this.props;
|
||||||
const pinned = !!columnId;
|
const pinned = !!columnId;
|
||||||
const { signedIn } = this.context.identity;
|
const { signedIn } = this.props.identity;
|
||||||
const banners = [];
|
const banners = [];
|
||||||
|
|
||||||
let announcementsButton;
|
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 ImmutablePropTypes from 'react-immutable-proptypes';
|
||||||
|
|
||||||
|
import { identityContextPropShape, withIdentity } from 'mastodon/identity_context';
|
||||||
import { PERMISSION_MANAGE_USERS, PERMISSION_MANAGE_REPORTS } from 'mastodon/permissions';
|
import { PERMISSION_MANAGE_USERS, PERMISSION_MANAGE_REPORTS } from 'mastodon/permissions';
|
||||||
|
|
||||||
import { CheckboxWithLabel } from './checkbox_with_label';
|
import { CheckboxWithLabel } from './checkbox_with_label';
|
||||||
|
@ -12,13 +13,9 @@ import ClearColumnButton from './clear_column_button';
|
||||||
import GrantPermissionButton from './grant_permission_button';
|
import GrantPermissionButton from './grant_permission_button';
|
||||||
import SettingToggle from './setting_toggle';
|
import SettingToggle from './setting_toggle';
|
||||||
|
|
||||||
export default class ColumnSettings extends PureComponent {
|
class ColumnSettings extends PureComponent {
|
||||||
|
|
||||||
static contextTypes = {
|
|
||||||
identity: PropTypes.object,
|
|
||||||
};
|
|
||||||
|
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
|
identity: identityContextPropShape,
|
||||||
settings: ImmutablePropTypes.map.isRequired,
|
settings: ImmutablePropTypes.map.isRequired,
|
||||||
pushSettings: ImmutablePropTypes.map.isRequired,
|
pushSettings: ImmutablePropTypes.map.isRequired,
|
||||||
onChange: PropTypes.func.isRequired,
|
onChange: PropTypes.func.isRequired,
|
||||||
|
@ -215,7 +212,7 @@ export default class ColumnSettings extends PureComponent {
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</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'>
|
<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>
|
<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>
|
</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'>
|
<section role='group' aria-labelledby='notifications-admin-report'>
|
||||||
<h3 id='notifications-status'><FormattedMessage id='notifications.column_settings.admin.report' defaultMessage='New reports:' /></h3>
|
<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 { compareId } from 'mastodon/compare_id';
|
||||||
import { Icon } from 'mastodon/components/icon';
|
import { Icon } from 'mastodon/components/icon';
|
||||||
import { NotSignedInIndicator } from 'mastodon/components/not_signed_in_indicator';
|
import { NotSignedInIndicator } from 'mastodon/components/not_signed_in_indicator';
|
||||||
|
import { identityContextPropShape, withIdentity } from 'mastodon/identity_context';
|
||||||
|
|
||||||
import { addColumn, removeColumn, moveColumn } from '../../actions/columns';
|
import { addColumn, removeColumn, moveColumn } from '../../actions/columns';
|
||||||
import { submitMarkers } from '../../actions/markers';
|
import { submitMarkers } from '../../actions/markers';
|
||||||
|
@ -77,12 +78,8 @@ const mapStateToProps = state => ({
|
||||||
});
|
});
|
||||||
|
|
||||||
class Notifications extends PureComponent {
|
class Notifications extends PureComponent {
|
||||||
|
|
||||||
static contextTypes = {
|
|
||||||
identity: PropTypes.object,
|
|
||||||
};
|
|
||||||
|
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
|
identity: identityContextPropShape,
|
||||||
columnId: PropTypes.string,
|
columnId: PropTypes.string,
|
||||||
notifications: ImmutablePropTypes.list.isRequired,
|
notifications: ImmutablePropTypes.list.isRequired,
|
||||||
dispatch: PropTypes.func.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 { intl, notifications, isLoading, isUnread, columnId, multiColumn, hasMore, numPending, lastReadId, canMarkAsRead, needsNotificationPermission } = this.props;
|
||||||
const pinned = !!columnId;
|
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 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;
|
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 { reblog, favourite, unreblog, unfavourite } from 'mastodon/actions/interactions';
|
||||||
import { openModal } from 'mastodon/actions/modal';
|
import { openModal } from 'mastodon/actions/modal';
|
||||||
import { IconButton } from 'mastodon/components/icon_button';
|
import { IconButton } from 'mastodon/components/icon_button';
|
||||||
|
import { identityContextPropShape, withIdentity } from 'mastodon/identity_context';
|
||||||
import { me, boostModal } from 'mastodon/initial_state';
|
import { me, boostModal } from 'mastodon/initial_state';
|
||||||
import { makeGetStatus } from 'mastodon/selectors';
|
import { makeGetStatus } from 'mastodon/selectors';
|
||||||
import { WithRouterPropTypes } from 'mastodon/utils/react_router';
|
import { WithRouterPropTypes } from 'mastodon/utils/react_router';
|
||||||
|
@ -47,12 +48,8 @@ const makeMapStateToProps = () => {
|
||||||
};
|
};
|
||||||
|
|
||||||
class Footer extends ImmutablePureComponent {
|
class Footer extends ImmutablePureComponent {
|
||||||
|
|
||||||
static contextTypes = {
|
|
||||||
identity: PropTypes.object,
|
|
||||||
};
|
|
||||||
|
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
|
identity: identityContextPropShape,
|
||||||
statusId: PropTypes.string.isRequired,
|
statusId: PropTypes.string.isRequired,
|
||||||
status: ImmutablePropTypes.map.isRequired,
|
status: ImmutablePropTypes.map.isRequired,
|
||||||
intl: PropTypes.object.isRequired,
|
intl: PropTypes.object.isRequired,
|
||||||
|
@ -75,7 +72,7 @@ class Footer extends ImmutablePureComponent {
|
||||||
|
|
||||||
handleReplyClick = () => {
|
handleReplyClick = () => {
|
||||||
const { dispatch, askReplyConfirmation, status, intl } = this.props;
|
const { dispatch, askReplyConfirmation, status, intl } = this.props;
|
||||||
const { signedIn } = this.context.identity;
|
const { signedIn } = this.props.identity;
|
||||||
|
|
||||||
if (signedIn) {
|
if (signedIn) {
|
||||||
if (askReplyConfirmation) {
|
if (askReplyConfirmation) {
|
||||||
|
@ -104,7 +101,7 @@ class Footer extends ImmutablePureComponent {
|
||||||
|
|
||||||
handleFavouriteClick = () => {
|
handleFavouriteClick = () => {
|
||||||
const { dispatch, status } = this.props;
|
const { dispatch, status } = this.props;
|
||||||
const { signedIn } = this.context.identity;
|
const { signedIn } = this.props.identity;
|
||||||
|
|
||||||
if (signedIn) {
|
if (signedIn) {
|
||||||
if (status.get('favourited')) {
|
if (status.get('favourited')) {
|
||||||
|
@ -131,7 +128,7 @@ class Footer extends ImmutablePureComponent {
|
||||||
|
|
||||||
handleReblogClick = e => {
|
handleReblogClick = e => {
|
||||||
const { dispatch, status } = this.props;
|
const { dispatch, status } = this.props;
|
||||||
const { signedIn } = this.context.identity;
|
const { signedIn } = this.props.identity;
|
||||||
|
|
||||||
if (signedIn) {
|
if (signedIn) {
|
||||||
if (status.get('reblogged')) {
|
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 PublicIcon from '@/material-icons/400-24px/public.svg?react';
|
||||||
import { DismissableBanner } from 'mastodon/components/dismissable_banner';
|
import { DismissableBanner } from 'mastodon/components/dismissable_banner';
|
||||||
|
import { identityContextPropShape, withIdentity } from 'mastodon/identity_context';
|
||||||
import { domain } from 'mastodon/initial_state';
|
import { domain } from 'mastodon/initial_state';
|
||||||
|
|
||||||
import { addColumn, removeColumn, moveColumn } from '../../actions/columns';
|
import { addColumn, removeColumn, moveColumn } from '../../actions/columns';
|
||||||
|
@ -40,16 +41,12 @@ const mapStateToProps = (state, { columnId }) => {
|
||||||
};
|
};
|
||||||
|
|
||||||
class PublicTimeline extends PureComponent {
|
class PublicTimeline extends PureComponent {
|
||||||
|
|
||||||
static contextTypes = {
|
|
||||||
identity: PropTypes.object,
|
|
||||||
};
|
|
||||||
|
|
||||||
static defaultProps = {
|
static defaultProps = {
|
||||||
onlyMedia: false,
|
onlyMedia: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
|
identity: identityContextPropShape,
|
||||||
dispatch: PropTypes.func.isRequired,
|
dispatch: PropTypes.func.isRequired,
|
||||||
intl: PropTypes.object.isRequired,
|
intl: PropTypes.object.isRequired,
|
||||||
columnId: PropTypes.string,
|
columnId: PropTypes.string,
|
||||||
|
@ -80,7 +77,7 @@ class PublicTimeline extends PureComponent {
|
||||||
|
|
||||||
componentDidMount () {
|
componentDidMount () {
|
||||||
const { dispatch, onlyMedia, onlyRemote } = this.props;
|
const { dispatch, onlyMedia, onlyRemote } = this.props;
|
||||||
const { signedIn } = this.context.identity;
|
const { signedIn } = this.props.identity;
|
||||||
|
|
||||||
dispatch(expandPublicTimeline({ onlyMedia, onlyRemote }));
|
dispatch(expandPublicTimeline({ onlyMedia, onlyRemote }));
|
||||||
|
|
||||||
|
@ -90,7 +87,7 @@ class PublicTimeline extends PureComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidUpdate (prevProps) {
|
componentDidUpdate (prevProps) {
|
||||||
const { signedIn } = this.context.identity;
|
const { signedIn } = this.props.identity;
|
||||||
|
|
||||||
if (prevProps.onlyMedia !== this.props.onlyMedia || prevProps.onlyRemote !== this.props.onlyRemote) {
|
if (prevProps.onlyMedia !== this.props.onlyMedia || prevProps.onlyRemote !== this.props.onlyRemote) {
|
||||||
const { dispatch, onlyMedia, onlyRemote } = this.props;
|
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 RepeatDisabledIcon from '@/svg-icons/repeat_disabled.svg?react';
|
||||||
import RepeatPrivateIcon from '@/svg-icons/repeat_private.svg?react';
|
import RepeatPrivateIcon from '@/svg-icons/repeat_private.svg?react';
|
||||||
import RepeatPrivateActiveIcon from '@/svg-icons/repeat_private_active.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 { PERMISSION_MANAGE_USERS, PERMISSION_MANAGE_FEDERATION } from 'mastodon/permissions';
|
||||||
import { WithRouterPropTypes } from 'mastodon/utils/react_router';
|
import { WithRouterPropTypes } from 'mastodon/utils/react_router';
|
||||||
|
|
||||||
|
@ -67,12 +68,8 @@ const mapStateToProps = (state, { status }) => ({
|
||||||
});
|
});
|
||||||
|
|
||||||
class ActionBar extends PureComponent {
|
class ActionBar extends PureComponent {
|
||||||
|
|
||||||
static contextTypes = {
|
|
||||||
identity: PropTypes.object,
|
|
||||||
};
|
|
||||||
|
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
|
identity: identityContextPropShape,
|
||||||
status: ImmutablePropTypes.map.isRequired,
|
status: ImmutablePropTypes.map.isRequired,
|
||||||
relationship: ImmutablePropTypes.record,
|
relationship: ImmutablePropTypes.record,
|
||||||
onReply: PropTypes.func.isRequired,
|
onReply: PropTypes.func.isRequired,
|
||||||
|
@ -198,7 +195,7 @@ class ActionBar extends PureComponent {
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
const { status, relationship, intl } = this.props;
|
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 publicStatus = ['public', 'unlisted'].includes(status.get('visibility'));
|
||||||
const pinnableStatus = ['public', 'unlisted', 'private'].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 { LoadingIndicator } from 'mastodon/components/loading_indicator';
|
||||||
import ScrollContainer from 'mastodon/containers/scroll_container';
|
import ScrollContainer from 'mastodon/containers/scroll_container';
|
||||||
import BundleColumnError from 'mastodon/features/ui/components/bundle_column_error';
|
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 { WithRouterPropTypes } from 'mastodon/utils/react_router';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
@ -189,12 +190,8 @@ const titleFromStatus = (intl, status) => {
|
||||||
};
|
};
|
||||||
|
|
||||||
class Status extends ImmutablePureComponent {
|
class Status extends ImmutablePureComponent {
|
||||||
|
|
||||||
static contextTypes = {
|
|
||||||
identity: PropTypes.object,
|
|
||||||
};
|
|
||||||
|
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
|
identity: identityContextPropShape,
|
||||||
params: PropTypes.object.isRequired,
|
params: PropTypes.object.isRequired,
|
||||||
dispatch: PropTypes.func.isRequired,
|
dispatch: PropTypes.func.isRequired,
|
||||||
status: ImmutablePropTypes.map,
|
status: ImmutablePropTypes.map,
|
||||||
|
@ -244,7 +241,7 @@ class Status extends ImmutablePureComponent {
|
||||||
|
|
||||||
handleFavouriteClick = (status) => {
|
handleFavouriteClick = (status) => {
|
||||||
const { dispatch } = this.props;
|
const { dispatch } = this.props;
|
||||||
const { signedIn } = this.context.identity;
|
const { signedIn } = this.props.identity;
|
||||||
|
|
||||||
if (signedIn) {
|
if (signedIn) {
|
||||||
if (status.get('favourited')) {
|
if (status.get('favourited')) {
|
||||||
|
@ -274,7 +271,7 @@ class Status extends ImmutablePureComponent {
|
||||||
|
|
||||||
handleReplyClick = (status) => {
|
handleReplyClick = (status) => {
|
||||||
const { askReplyConfirmation, dispatch, intl } = this.props;
|
const { askReplyConfirmation, dispatch, intl } = this.props;
|
||||||
const { signedIn } = this.context.identity;
|
const { signedIn } = this.props.identity;
|
||||||
|
|
||||||
if (signedIn) {
|
if (signedIn) {
|
||||||
if (askReplyConfirmation) {
|
if (askReplyConfirmation) {
|
||||||
|
@ -307,7 +304,7 @@ class Status extends ImmutablePureComponent {
|
||||||
|
|
||||||
handleReblogClick = (status, e) => {
|
handleReblogClick = (status, e) => {
|
||||||
const { dispatch } = this.props;
|
const { dispatch } = this.props;
|
||||||
const { signedIn } = this.context.identity;
|
const { signedIn } = this.props.identity;
|
||||||
|
|
||||||
if (signedIn) {
|
if (signedIn) {
|
||||||
if (status.get('reblogged')) {
|
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 ServerBanner from 'mastodon/components/server_banner';
|
||||||
import ComposeFormContainer from 'mastodon/features/compose/containers/compose_form_container';
|
import ComposeFormContainer from 'mastodon/features/compose/containers/compose_form_container';
|
||||||
import SearchContainer from 'mastodon/features/compose/containers/search_container';
|
import SearchContainer from 'mastodon/features/compose/containers/search_container';
|
||||||
|
import { identityContextPropShape, withIdentity } from 'mastodon/identity_context';
|
||||||
|
|
||||||
import LinkFooter from './link_footer';
|
import LinkFooter from './link_footer';
|
||||||
|
|
||||||
class ComposePanel extends PureComponent {
|
class ComposePanel extends PureComponent {
|
||||||
|
|
||||||
static contextTypes = {
|
|
||||||
identity: PropTypes.object.isRequired,
|
|
||||||
};
|
|
||||||
|
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
|
identity: identityContextPropShape,
|
||||||
dispatch: PropTypes.func.isRequired,
|
dispatch: PropTypes.func.isRequired,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -41,7 +38,7 @@ class ComposePanel extends PureComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { signedIn } = this.context.identity;
|
const { signedIn } = this.props.identity;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='compose-panel' onFocus={this.onFocus}>
|
<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 { Avatar } from 'mastodon/components/avatar';
|
||||||
import { Icon } from 'mastodon/components/icon';
|
import { Icon } from 'mastodon/components/icon';
|
||||||
import { WordmarkLogo, SymbolLogo } from 'mastodon/components/logo';
|
import { WordmarkLogo, SymbolLogo } from 'mastodon/components/logo';
|
||||||
|
import { identityContextPropShape, withIdentity } from 'mastodon/identity_context';
|
||||||
import { registrationsOpen, me, sso_redirect } from 'mastodon/initial_state';
|
import { registrationsOpen, me, sso_redirect } from 'mastodon/initial_state';
|
||||||
|
|
||||||
const Account = connect(state => ({
|
const Account = connect(state => ({
|
||||||
|
@ -41,12 +42,8 @@ const mapDispatchToProps = (dispatch) => ({
|
||||||
});
|
});
|
||||||
|
|
||||||
class Header extends PureComponent {
|
class Header extends PureComponent {
|
||||||
|
|
||||||
static contextTypes = {
|
|
||||||
identity: PropTypes.object,
|
|
||||||
};
|
|
||||||
|
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
|
identity: identityContextPropShape,
|
||||||
openClosedRegistrationsModal: PropTypes.func,
|
openClosedRegistrationsModal: PropTypes.func,
|
||||||
location: PropTypes.object,
|
location: PropTypes.object,
|
||||||
signupUrl: PropTypes.string.isRequired,
|
signupUrl: PropTypes.string.isRequired,
|
||||||
|
@ -60,7 +57,7 @@ class Header extends PureComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
const { signedIn } = this.context.identity;
|
const { signedIn } = this.props.identity;
|
||||||
const { location, openClosedRegistrationsModal, signupUrl, intl } = this.props;
|
const { location, openClosedRegistrationsModal, signupUrl, intl } = this.props;
|
||||||
|
|
||||||
let content;
|
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 { connect } from 'react-redux';
|
||||||
|
|
||||||
import { openModal } from 'mastodon/actions/modal';
|
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 { domain, version, source_url, statusPageUrl, profile_directory as profileDirectory } from 'mastodon/initial_state';
|
||||||
import { PERMISSION_INVITE_USERS } from 'mastodon/permissions';
|
import { PERMISSION_INVITE_USERS } from 'mastodon/permissions';
|
||||||
import { logOut } from 'mastodon/utils/log_out';
|
import { logOut } from 'mastodon/utils/log_out';
|
||||||
|
@ -32,12 +33,8 @@ const mapDispatchToProps = (dispatch, { intl }) => ({
|
||||||
});
|
});
|
||||||
|
|
||||||
class LinkFooter extends PureComponent {
|
class LinkFooter extends PureComponent {
|
||||||
|
|
||||||
static contextTypes = {
|
|
||||||
identity: PropTypes.object,
|
|
||||||
};
|
|
||||||
|
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
|
identity: identityContextPropShape,
|
||||||
multiColumn: PropTypes.bool,
|
multiColumn: PropTypes.bool,
|
||||||
onLogout: PropTypes.func.isRequired,
|
onLogout: PropTypes.func.isRequired,
|
||||||
intl: PropTypes.object.isRequired,
|
intl: PropTypes.object.isRequired,
|
||||||
|
@ -53,7 +50,7 @@ class LinkFooter extends PureComponent {
|
||||||
};
|
};
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
const { signedIn, permissions } = this.context.identity;
|
const { signedIn, permissions } = this.props.identity;
|
||||||
const { multiColumn } = this.props;
|
const { multiColumn } = this.props;
|
||||||
|
|
||||||
const canInvite = signedIn && ((permissions & PERMISSION_INVITE_USERS) === PERMISSION_INVITE_USERS);
|
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 { IconWithBadge } from 'mastodon/components/icon_with_badge';
|
||||||
import { WordmarkLogo } from 'mastodon/components/logo';
|
import { WordmarkLogo } from 'mastodon/components/logo';
|
||||||
import { NavigationPortal } from 'mastodon/components/navigation_portal';
|
import { NavigationPortal } from 'mastodon/components/navigation_portal';
|
||||||
|
import { identityContextPropShape, withIdentity } from 'mastodon/identity_context';
|
||||||
import { timelinePreview, trendsEnabled } from 'mastodon/initial_state';
|
import { timelinePreview, trendsEnabled } from 'mastodon/initial_state';
|
||||||
import { transientSingleColumn } from 'mastodon/is_mobile';
|
import { transientSingleColumn } from 'mastodon/is_mobile';
|
||||||
|
|
||||||
|
@ -97,12 +98,8 @@ const FollowRequestsLink = () => {
|
||||||
};
|
};
|
||||||
|
|
||||||
class NavigationPanel extends Component {
|
class NavigationPanel extends Component {
|
||||||
|
|
||||||
static contextTypes = {
|
|
||||||
identity: PropTypes.object.isRequired,
|
|
||||||
};
|
|
||||||
|
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
|
identity: identityContextPropShape,
|
||||||
intl: PropTypes.object.isRequired,
|
intl: PropTypes.object.isRequired,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -112,7 +109,7 @@ class NavigationPanel extends Component {
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
const { intl } = this.props;
|
const { intl } = this.props;
|
||||||
const { signedIn, disabledAccountId } = this.context.identity;
|
const { signedIn, disabledAccountId } = this.props.identity;
|
||||||
|
|
||||||
let banner = undefined;
|
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 { synchronouslySubmitMarkers, submitMarkers, fetchMarkers } from 'mastodon/actions/markers';
|
||||||
import { INTRODUCTION_VERSION } from 'mastodon/actions/onboarding';
|
import { INTRODUCTION_VERSION } from 'mastodon/actions/onboarding';
|
||||||
import { PictureInPicture } from 'mastodon/features/picture_in_picture';
|
import { PictureInPicture } from 'mastodon/features/picture_in_picture';
|
||||||
|
import { identityContextPropShape, withIdentity } from 'mastodon/identity_context';
|
||||||
import { layoutFromWindow } from 'mastodon/is_mobile';
|
import { layoutFromWindow } from 'mastodon/is_mobile';
|
||||||
import { WithRouterPropTypes } from 'mastodon/utils/react_router';
|
import { WithRouterPropTypes } from 'mastodon/utils/react_router';
|
||||||
|
|
||||||
|
@ -120,12 +121,8 @@ const keyMap = {
|
||||||
};
|
};
|
||||||
|
|
||||||
class SwitchingColumnsArea extends PureComponent {
|
class SwitchingColumnsArea extends PureComponent {
|
||||||
|
|
||||||
static contextTypes = {
|
|
||||||
identity: PropTypes.object,
|
|
||||||
};
|
|
||||||
|
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
|
identity: identityContextPropShape,
|
||||||
children: PropTypes.node,
|
children: PropTypes.node,
|
||||||
location: PropTypes.object,
|
location: PropTypes.object,
|
||||||
singleColumn: PropTypes.bool,
|
singleColumn: PropTypes.bool,
|
||||||
|
@ -160,7 +157,7 @@ class SwitchingColumnsArea extends PureComponent {
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
const { children, singleColumn } = this.props;
|
const { children, singleColumn } = this.props;
|
||||||
const { signedIn } = this.context.identity;
|
const { signedIn } = this.props.identity;
|
||||||
const pathName = this.props.location.pathname;
|
const pathName = this.props.location.pathname;
|
||||||
|
|
||||||
let redirect;
|
let redirect;
|
||||||
|
@ -252,12 +249,8 @@ class SwitchingColumnsArea extends PureComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
class UI extends PureComponent {
|
class UI extends PureComponent {
|
||||||
|
|
||||||
static contextTypes = {
|
|
||||||
identity: PropTypes.object.isRequired,
|
|
||||||
};
|
|
||||||
|
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
|
identity: identityContextPropShape,
|
||||||
dispatch: PropTypes.func.isRequired,
|
dispatch: PropTypes.func.isRequired,
|
||||||
children: PropTypes.node,
|
children: PropTypes.node,
|
||||||
isComposing: PropTypes.bool,
|
isComposing: PropTypes.bool,
|
||||||
|
@ -309,7 +302,7 @@ class UI extends PureComponent {
|
||||||
this.dragTargets.push(e.target);
|
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 });
|
this.setState({ draggingOver: true });
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -337,7 +330,7 @@ class UI extends PureComponent {
|
||||||
this.setState({ draggingOver: false });
|
this.setState({ draggingOver: false });
|
||||||
this.dragTargets = [];
|
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));
|
this.props.dispatch(uploadCompose(e.dataTransfer.files));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -389,7 +382,7 @@ class UI extends PureComponent {
|
||||||
};
|
};
|
||||||
|
|
||||||
componentDidMount () {
|
componentDidMount () {
|
||||||
const { signedIn } = this.context.identity;
|
const { signedIn } = this.props.identity;
|
||||||
|
|
||||||
window.addEventListener('focus', this.handleWindowFocus, false);
|
window.addEventListener('focus', this.handleWindowFocus, false);
|
||||||
window.addEventListener('blur', this.handleWindowBlur, 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}>
|
<div className={classNames('ui', { 'is-composing': isComposing })} ref={this.setRef}>
|
||||||
<Header />
|
<Header />
|
||||||
|
|
||||||
<SwitchingColumnsArea location={location} singleColumn={layout === 'mobile' || layout === 'single-column'}>
|
<SwitchingColumnsArea identity={this.props.identity} location={location} singleColumn={layout === 'mobile' || layout === 'single-column'}>
|
||||||
{children}
|
{children}
|
||||||
</SwitchingColumnsArea>
|
</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
|
* @property {string} sso_redirect
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef Role
|
||||||
|
* @property {string} id
|
||||||
|
* @property {string} name
|
||||||
|
* @property {string} permissions
|
||||||
|
* @property {string} color
|
||||||
|
* @property {boolean} highlighted
|
||||||
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @typedef InitialState
|
* @typedef InitialState
|
||||||
* @property {Record<string, import("./api_types/accounts").ApiAccountJSON>} accounts
|
* @property {Record<string, import("./api_types/accounts").ApiAccountJSON>} accounts
|
||||||
* @property {InitialStateLanguage[]} languages
|
* @property {InitialStateLanguage[]} languages
|
||||||
* @property {boolean=} critical_updates_pending
|
* @property {boolean=} critical_updates_pending
|
||||||
* @property {InitialStateMeta} meta
|
* @property {InitialStateMeta} meta
|
||||||
|
* @property {Role?} role
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const element = document.getElementById('initial-state');
|
const element = document.getElementById('initial-state');
|
||||||
|
|
Loading…
Reference in a new issue