[Glitch] Upgrade to react-router v5

Port 1b70d7ed7c to glitch-soc

Co-authored-by: Claire <claire.github-309c@sitedethib.com>
Signed-off-by: Claire <claire.github-309c@sitedethib.com>
This commit is contained in:
Renaud ChaputandClaire authored and Claire committed 2023-10-21 22:14:24 +02:00
1 parent 245513d630
commit d6eacb79c6
51 files changed
+413 -385

No files matched your search

@@ -4,26 +4,25 @@ import { createPortal } from 'react-dom';
import { FormattedMessage } from 'react-intl';
import { Icon } from 'flavours/glitch/components/icon';
import { withRouter } from 'react-router-dom';
import { Icon } from 'flavours/glitch/components/icon';
import { WithRouterPropTypes } from 'flavours/glitch/utils/react_router';
export default class ColumnBackButton extends PureComponent {
static contextTypes = {
router: PropTypes.object,
};
class ColumnBackButton extends PureComponent {
static propTypes = {
multiColumn: PropTypes.bool,
...WithRouterPropTypes,
};
handleClick = () => {
const { router } = this.context;
const { history } = this.props;
if (router.history.location?.state?.fromMastodon) {
router.history.goBack();
if (history.location?.state?.fromMastodon) {
history.goBack();
} else {
router.history.push('/');
history.push('/');
}
};
@@ -57,3 +56,5 @@ export default class ColumnBackButton extends PureComponent {
}
}
export default withRouter(ColumnBackButton);
@@ -1,25 +1,27 @@
import PropTypes from 'prop-types';
import { PureComponent } from 'react';
import { FormattedMessage } from 'react-intl';
import { withRouter } from 'react-router-dom';
import { Icon } from 'flavours/glitch/components/icon';
import { WithRouterPropTypes } from 'flavours/glitch/utils/react_router';
export default class ColumnBackButtonSlim extends PureComponent {
class ColumnBackButtonSlim extends PureComponent {
static contextTypes = {
router: PropTypes.object,
static propTypes = {
...WithRouterPropTypes,
};
handleClick = () => {
const { router } = this.context;
const { location, history } = this.props;
// Check if there is a previous page in the app to go back to per https://stackoverflow.com/a/70532858/9703201
// When upgrading to V6, check `location.key !== 'default'` instead per https://github.com/remix-run/history/blob/main/docs/api-reference.md#location
if (router.route.location.key) {
router.history.goBack();
if (location.key) {
history.goBack();
} else {
router.history.push('/');
history.push('/');
}
};
@@ -35,3 +37,5 @@ export default class ColumnBackButtonSlim extends PureComponent {
}
}
export default withRouter(ColumnBackButtonSlim);
@@ -5,8 +5,10 @@ import { createPortal } from 'react-dom';
import { FormattedMessage, injectIntl, defineMessages } from 'react-intl';
import classNames from 'classnames';
import { withRouter } from 'react-router-dom';
import { Icon } from 'flavours/glitch/components/icon';
import { Icon } from 'flavours/glitch/components/icon';
import { WithRouterPropTypes } from 'flavours/glitch/utils/react_router';
const messages = defineMessages({
show: { id: 'column_header.show_settings', defaultMessage: 'Show settings' },
@@ -18,7 +20,6 @@ const messages = defineMessages({
class ColumnHeader extends PureComponent {
static contextTypes = {
router: PropTypes.object,
identity: PropTypes.object,
};
@@ -38,6 +39,7 @@ class ColumnHeader extends PureComponent {
onClick: PropTypes.func,
appendContent: PropTypes.node,
collapseIssues: PropTypes.bool,
...WithRouterPropTypes,
};
state = {
@@ -63,12 +65,12 @@ class ColumnHeader extends PureComponent {
};
handleBackClick = () => {
const { router } = this.context;
const { history } = this.props;
if (router.history.location?.state?.fromMastodon) {
router.history.goBack();
if (history.location?.state?.fromMastodon) {
history.goBack();
} else {
router.history.push('/');
history.push('/');
}
};
@@ -78,15 +80,14 @@ class ColumnHeader extends PureComponent {
handlePin = () => {
if (!this.props.pinned) {
this.context.router.history.replace('/');
this.props.history.replace('/');
}
this.props.onPin();
};
render () {
const { router } = this.context;
const { title, icon, active, children, pinned, multiColumn, extraButton, showBackButton, intl: { formatMessage }, placeholder, appendContent, collapseIssues } = this.props;
const { title, icon, active, children, pinned, multiColumn, extraButton, showBackButton, intl: { formatMessage }, placeholder, appendContent, collapseIssues, history } = this.props;
const { collapsed, animating } = this.state;
const wrapperClassName = classNames('column-header__wrapper', {
@@ -129,7 +130,7 @@ class ColumnHeader extends PureComponent {
pinButton = <button key='pin-button' className='text-btn column-header__setting-btn' onClick={this.handlePin}><Icon id='plus' /> <FormattedMessage id='column_header.pin' defaultMessage='Pin' /></button>;
}
if (!pinned && ((multiColumn && router.history.location?.state?.fromMastodon) || showBackButton)) {
if (!pinned && ((multiColumn && history.location?.state?.fromMastodon) || showBackButton)) {
backButton = (
<button onClick={this.handleBackClick} className='column-header__back-button'>
<Icon id='chevron-left' className='column-back-button__icon' fixedWidth />
@@ -215,4 +216,4 @@ class ColumnHeader extends PureComponent {
}
export default injectIntl(ColumnHeader);
export default injectIntl(withRouter(ColumnHeader));
@@ -2,13 +2,16 @@ import PropTypes from 'prop-types';
import { PureComponent, cloneElement, Children } from 'react';
import classNames from 'classnames';
import { withRouter } from 'react-router-dom';
import ImmutablePropTypes from 'react-immutable-proptypes';
import { supportsPassiveEvents } from 'detect-passive-events';
import Overlay from 'react-overlays/Overlay';
import { CircularProgress } from "./circular_progress";
import { CircularProgress } from 'flavours/glitch/components/circular_progress';
import { WithRouterPropTypes } from 'flavours/glitch/utils/react_router';
import { IconButton } from './icon_button';
const listenerOptions = supportsPassiveEvents ? { passive: true, capture: true } : true;
@@ -16,10 +19,6 @@ let id = 0;
class DropdownMenu extends PureComponent {
static contextTypes = {
router: PropTypes.object,
};
static propTypes = {
items: PropTypes.oneOfType([PropTypes.array, ImmutablePropTypes.list]).isRequired,
loading: PropTypes.bool,
@@ -159,11 +158,7 @@ class DropdownMenu extends PureComponent {
}
export default class Dropdown extends PureComponent {
static contextTypes = {
router: PropTypes.object,
};
class Dropdown extends PureComponent {
static propTypes = {
children: PropTypes.node,
@@ -183,6 +178,7 @@ export default class Dropdown extends PureComponent {
renderItem: PropTypes.func,
renderHeader: PropTypes.func,
onItemClick: PropTypes.func,
...WithRouterPropTypes
};
static defaultProps = {
@@ -250,7 +246,7 @@ export default class Dropdown extends PureComponent {
item.action();
} else if (item && item.to) {
e.preventDefault();
this.context.router.history.push(item.to);
this.props.history.push(item.to);
}
};
@@ -338,3 +334,5 @@ export default class Dropdown extends PureComponent {
}
}
export default withRouter(Dropdown);
@@ -2,14 +2,13 @@ import PropTypes from 'prop-types';
import { PureComponent } from 'react';
import 'wicg-inert';
import { multiply } from 'color-blend';
import { createBrowserHistory } from 'history';
export default class ModalRoot extends PureComponent {
import { WithOptionalRouterPropTypes, withOptionalRouter } from 'flavours/glitch/utils/react_router';
static contextTypes = {
router: PropTypes.object,
};
class ModalRoot extends PureComponent {
static propTypes = {
children: PropTypes.node,
@@ -21,6 +20,7 @@ export default class ModalRoot extends PureComponent {
}),
noEsc: PropTypes.bool,
ignoreFocus: PropTypes.bool,
...WithOptionalRouterPropTypes,
};
activeElement = this.props.children ? document.activeElement : null;
@@ -56,7 +56,7 @@ export default class ModalRoot extends PureComponent {
componentDidMount () {
window.addEventListener('keyup', this.handleKeyUp, false);
window.addEventListener('keydown', this.handleKeyDown, false);
this.history = this.context.router ? this.context.router.history : createBrowserHistory();
this.history = this.props.history || createBrowserHistory();
if (this.props.children) {
this._handleModalOpen();
@@ -160,3 +160,5 @@ export default class ModalRoot extends PureComponent {
}
}
export default withOptionalRouter(ModalRoot);
@@ -1,36 +0,0 @@
import { PureComponent } from 'react';
import { Switch, Route, withRouter } from 'react-router-dom';
import AccountNavigation from 'flavours/glitch/features/account/navigation';
import Trends from 'flavours/glitch/features/getting_started/containers/trends_container';
import { showTrends } from 'flavours/glitch/initial_state';
const DefaultNavigation = () => (
showTrends ? (
<>
<div className='flex-spacer' />
<Trends />
</>
) : null
);
class NavigationPortal extends PureComponent {
render () {
return (
<Switch>
<Route path='/@:acct' exact component={AccountNavigation} />
<Route path='/@:acct/tagged/:tagged?' exact component={AccountNavigation} />
<Route path='/@:acct/with_replies' exact component={AccountNavigation} />
<Route path='/@:acct/followers' exact component={AccountNavigation} />
<Route path='/@:acct/following' exact component={AccountNavigation} />
<Route path='/@:acct/media' exact component={AccountNavigation} />
<Route component={DefaultNavigation} />
</Switch>
);
}
}
export default withRouter(NavigationPortal);
@@ -0,0 +1,25 @@
import { Switch, Route } from 'react-router-dom';
import AccountNavigation from 'flavours/glitch/features/account/navigation';
import Trends from 'flavours/glitch/features/getting_started/containers/trends_container';
import { showTrends } from 'flavours/glitch/initial_state';
const DefaultNavigation: React.FC = () =>
showTrends ? (
<>
<div className='flex-spacer' />
<Trends />
</>
) : null;
export const NavigationPortal: React.FC = () => (
<Switch>
<Route path='/@:acct' exact component={AccountNavigation} />
<Route path='/@:acct/tagged/:tagged?' exact component={AccountNavigation} />
<Route path='/@:acct/with_replies' exact component={AccountNavigation} />
<Route path='/@:acct/followers' exact component={AccountNavigation} />
<Route path='/@:acct/following' exact component={AccountNavigation} />
<Route path='/@:acct/media' exact component={AccountNavigation} />
<Route component={DefaultNavigation} />
</Switch>
);
@@ -1,11 +1,9 @@
import PropTypes from 'prop-types';
import { PureComponent } from 'react';
export default class Permalink extends PureComponent {
import { withOptionalRouter, WithOptionalRouterPropTypes } from 'flavours/glitch/utils/react_router';
static contextTypes = {
router: PropTypes.object,
};
class Permalink extends PureComponent {
static propTypes = {
className: PropTypes.string,
@@ -13,6 +11,7 @@ export default class Permalink extends PureComponent {
to: PropTypes.string.isRequired,
children: PropTypes.node,
onInterceptClick: PropTypes.func,
...WithOptionalRouterPropTypes,
};
handleClick = (e) => {
@@ -22,9 +21,9 @@ export default class Permalink extends PureComponent {
return;
}
if (this.context.router) {
if (this.props.history) {
e.preventDefault();
this.context.router.history.push(this.props.to);
this.props.history.push(this.props.to);
}
}
};
@@ -47,3 +46,5 @@ export default class Permalink extends PureComponent {
}
}
export default withOptionalRouter(Permalink);
@@ -1,15 +1,18 @@
import type { PropsWithChildren } from 'react';
import React from 'react';
import { createBrowserHistory } from 'history';
import { Router as OriginalRouter } from 'react-router';
import type { LocationDescriptor, Path } from 'history';
import { createBrowserHistory } from 'history';
import { layoutFromWindow } from 'flavours/glitch/is_mobile';
interface MastodonLocationState {
fromMastodon?: boolean;
mastodonModalKey?: string;
}
type HistoryPath = Path | LocationDescriptor<MastodonLocationState>;
const browserHistory = createBrowserHistory<
MastodonLocationState | undefined
@@ -17,25 +20,36 @@ const browserHistory = createBrowserHistory<
const originalPush = browserHistory.push.bind(browserHistory);
const originalReplace = browserHistory.replace.bind(browserHistory);
browserHistory.push = (path: string, state?: MastodonLocationState) => {
function extractRealPath(path: HistoryPath) {
if (typeof path === 'string') return path;
else return path.pathname;
}
browserHistory.push = (path: HistoryPath, state?: MastodonLocationState) => {
state = state ?? {};
state.fromMastodon = true;
if (layoutFromWindow() === 'multi-column' && !path.startsWith('/deck')) {
originalPush(`/deck${path}`, state);
const realPath = extractRealPath(path);
if (!realPath) return;
if (layoutFromWindow() === 'multi-column' && !realPath.startsWith('/deck')) {
originalPush(`/deck${realPath}`, state);
} else {
originalPush(path, state);
}
};
browserHistory.replace = (path: string, state?: MastodonLocationState) => {
browserHistory.replace = (path: HistoryPath, state?: MastodonLocationState) => {
if (browserHistory.location.state?.fromMastodon) {
state = state ?? {};
state.fromMastodon = true;
}
if (layoutFromWindow() === 'multi-column' && !path.startsWith('/deck')) {
originalReplace(`/deck${path}`, state);
const realPath = extractRealPath(path);
if (!realPath) return;
if (layoutFromWindow() === 'multi-column' && !realPath.startsWith('/deck')) {
originalReplace(`/deck${realPath}`, state);
} else {
originalReplace(path, state);
}
@@ -2,6 +2,7 @@ import PropTypes from 'prop-types';
import { Children, cloneElement, PureComponent } from 'react';
import classNames from 'classnames';
import { useLocation } from 'react-router-dom';
import { List as ImmutableList } from 'immutable';
import { connect } from 'react-redux';
@@ -34,11 +35,32 @@ const mapStateToProps = (state, { scrollKey }) => {
};
};
class ScrollableList extends PureComponent {
// This component only exists to be able to call useLocation()
const IOArticleContainerWrapper = ({id, index, listLength, intersectionObserverWrapper, trackScroll, scrollKey, children}) => {
const location = useLocation();
static contextTypes = {
router: PropTypes.object,
};
return (<IntersectionObserverArticleContainer
id={id}
index={index}
listLength={listLength}
intersectionObserverWrapper={intersectionObserverWrapper}
saveHeightKey={trackScroll ? `${location.key}:${scrollKey}` : null}
>
{children}
</IntersectionObserverArticleContainer>);
};
IOArticleContainerWrapper.propTypes = {
id: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
index: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
listLength: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
scrollKey: PropTypes.string.isRequired,
intersectionObserverWrapper: PropTypes.object.isRequired,
trackScroll: PropTypes.bool.isRequired,
children: PropTypes.node,
};
class ScrollableList extends PureComponent {
static propTypes = {
scrollKey: PropTypes.string.isRequired,
@@ -331,13 +353,14 @@ class ScrollableList extends PureComponent {
{loadPending}
{Children.map(this.props.children, (child, index) => (
<IntersectionObserverArticleContainer
<IOArticleContainerWrapper
key={child.key}
id={child.key}
index={index}
listLength={childrenCount}
intersectionObserverWrapper={this.intersectionObserverWrapper}
saveHeightKey={trackScroll ? `${this.context.router.route.location.key}:${scrollKey}` : null}
trackScroll={trackScroll}
scrollKey={scrollKey}
>
{cloneElement(child, {
getScrollPosition: this.getScrollPosition,
@@ -345,7 +368,7 @@ class ScrollableList extends PureComponent {
cachedMediaWidth: this.state.cachedMediaWidth,
cacheMediaWidth: this.cacheMediaWidth,
})}
</IntersectionObserverArticleContainer>
</IOArticleContainerWrapper>
))}
{loadMore}
@@ -14,6 +14,7 @@ import PollContainer from 'flavours/glitch/containers/poll_container';
import NotificationOverlayContainer from 'flavours/glitch/features/notifications/containers/overlay_container';
import { displayMedia } from 'flavours/glitch/initial_state';
import { autoUnfoldCW } from 'flavours/glitch/utils/content_warning';
import { withOptionalRouter, WithRouterPropTypes } from 'flavours/glitch/utils/react_router';
import Card from '../features/status/components/card';
import Bundle from '../features/ui/components/bundle';
@@ -67,10 +68,6 @@ export const defaultMediaVisibility = (status, settings) => {
class Status extends ImmutablePureComponent {
static contextTypes = {
router: PropTypes.object,
};
static propTypes = {
containerId: PropTypes.string,
id: PropTypes.string,
@@ -117,6 +114,7 @@ class Status extends ImmutablePureComponent {
inUse: PropTypes.bool,
available: PropTypes.bool,
}),
...WithRouterPropTypes,
};
state = {
@@ -356,10 +354,9 @@ class Status extends ImmutablePureComponent {
// Otherwise, we open the url handed to us in `destination`, if
// applicable.
parseClick = (e, destination) => {
const { router } = this.context;
const { status } = this.props;
const { status, history } = this.props;
const { isCollapsed } = this.state;
if (!router) return;
if (!history) return;
if (e.button === 0 && !(e.ctrlKey || e.altKey || e.metaKey)) {
if (isCollapsed) this.setCollapsed(false);
@@ -377,7 +374,7 @@ class Status extends ImmutablePureComponent {
status.getIn(['reblog', 'id'], status.get('id'))
}`;
}
router.history.push(destination);
history.push(destination);
}
e.preventDefault();
}
@@ -431,7 +428,7 @@ class Status extends ImmutablePureComponent {
handleHotkeyReply = e => {
e.preventDefault();
this.props.onReply(this.props.status, this.context.router.history);
this.props.onReply(this.props.status, this.props.history);
};
handleHotkeyFavourite = (e) => {
@@ -448,16 +445,16 @@ class Status extends ImmutablePureComponent {
handleHotkeyMention = e => {
e.preventDefault();
this.props.onMention(this.props.status.get('account'), this.context.router.history);
this.props.onMention(this.props.status.get('account'), this.props.history);
};
handleHotkeyOpen = () => {
const status = this.props.status;
this.context.router.history.push(`/@${status.getIn(['account', 'acct'])}/${status.get('id')}`);
this.props.history.push(`/@${status.getIn(['account', 'acct'])}/${status.get('id')}`);
};
handleHotkeyOpenProfile = () => {
this.context.router.history.push(`/@${this.props.status.getIn(['account', 'acct'])}`);
this.props.history.push(`/@${this.props.status.getIn(['account', 'acct'])}`);
};
handleHotkeyMoveUp = e => {
@@ -514,7 +511,6 @@ class Status extends ImmutablePureComponent {
parseClick,
setCollapsed,
} = this;
const { router } = this.context;
const {
intl,
status,
@@ -533,6 +529,7 @@ class Status extends ImmutablePureComponent {
previousId,
nextInReplyToId,
rootId,
history,
...other
} = this.props;
const { isCollapsed } = this.state;
@@ -828,7 +825,7 @@ class Status extends ImmutablePureComponent {
onExpandedToggle={this.handleExpandedToggle}
onTranslate={this.handleTranslate}
parseClick={parseClick}
disabled={!router}
disabled={!history}
tagLinks={settings.get('tag_misleading_links')}
rewriteMentions={settings.get('rewrite_mentions')}
/>
@@ -854,4 +851,4 @@ class Status extends ImmutablePureComponent {
}
export default injectIntl(Status);
export default withOptionalRouter(injectIntl(Status));
@@ -3,6 +3,7 @@ import PropTypes from 'prop-types';
import { defineMessages, injectIntl } from 'react-intl';
import classNames from 'classnames';
import { withRouter } from 'react-router-dom';
import ImmutablePropTypes from 'react-immutable-proptypes';
import ImmutablePureComponent from 'react-immutable-pure-component';
@@ -11,6 +12,7 @@ import DropdownMenuContainer from 'flavours/glitch/containers/dropdown_menu_cont
import { me } from 'flavours/glitch/initial_state';
import { PERMISSION_MANAGE_USERS, PERMISSION_MANAGE_FEDERATION } from 'flavours/glitch/permissions';
import { accountAdminLink, statusAdminLink } from 'flavours/glitch/utils/backend_links';
import { WithRouterPropTypes } from 'flavours/glitch/utils/react_router';
import { IconButton } from './icon_button';
import { RelativeTimestamp } from './relative_timestamp';
@@ -53,7 +55,6 @@ const messages = defineMessages({
class StatusActionBar extends ImmutablePureComponent {
static contextTypes = {
router: PropTypes.object,
identity: PropTypes.object,
};
@@ -80,6 +81,7 @@ class StatusActionBar extends ImmutablePureComponent {
showReplyCount: PropTypes.bool,
scrollKey: PropTypes.string,
intl: PropTypes.object.isRequired,
...WithRouterPropTypes,
};
// Avoid checking props that are functions (and whose equality will always
@@ -95,7 +97,7 @@ class StatusActionBar extends ImmutablePureComponent {
const { signedIn } = this.context.identity;
if (signedIn) {
this.props.onReply(this.props.status, this.context.router.history);
this.props.onReply(this.props.status, this.props.history);
} else {
this.props.onInteractionModal('reply', this.props.status);
}
@@ -132,15 +134,15 @@ class StatusActionBar extends ImmutablePureComponent {
};
handleDeleteClick = () => {
this.props.onDelete(this.props.status, this.context.router.history);
this.props.onDelete(this.props.status, this.props.history);
};
handleRedraftClick = () => {
this.props.onDelete(this.props.status, this.context.router.history, true);
this.props.onDelete(this.props.status, this.props.history, true);
};
handleEditClick = () => {
this.props.onEdit(this.props.status, this.context.router.history);
this.props.onEdit(this.props.status, this.props.history);
};
handlePinClick = () => {
@@ -148,11 +150,11 @@ class StatusActionBar extends ImmutablePureComponent {
};
handleMentionClick = () => {
this.props.onMention(this.props.status.get('account'), this.context.router.history);
this.props.onMention(this.props.status.get('account'), this.props.history);
};
handleDirectClick = () => {
this.props.onDirect(this.props.status.get('account'), this.context.router.history);
this.props.onDirect(this.props.status.get('account'), this.props.history);
};
handleMuteClick = () => {
@@ -164,12 +166,7 @@ class StatusActionBar extends ImmutablePureComponent {
};
handleOpen = () => {
let state = { ...this.context.router.history.location.state };
if (state.mastodonModalKey) {
this.context.router.history.replace(`/@${this.props.status.getIn(['account', 'acct'])}/${this.props.status.get('id')}`);
} else {
this.context.router.history.push(`/@${this.props.status.getIn(['account', 'acct'])}/${this.props.status.get('id')}`);
}
this.props.history.push(`/@${this.props.status.getIn(['account', 'acct'])}/${this.props.status.get('id')}`);
};
handleEmbed = () => {
@@ -340,4 +337,4 @@ class StatusActionBar extends ImmutablePureComponent {
}
export default injectIntl(StatusActionBar);
export default withRouter(injectIntl(StatusActionBar));
@@ -4,6 +4,7 @@ import { PureComponent } from 'react';
import { FormattedMessage, injectIntl } from 'react-intl';
import classnames from 'classnames';
import { withRouter } from 'react-router-dom';
import ImmutablePropTypes from 'react-immutable-proptypes';
import { connect } from 'react-redux';
@@ -131,6 +132,10 @@ class StatusContent extends PureComponent {
rewriteMentions: PropTypes.string,
languages: ImmutablePropTypes.map,
intl: PropTypes.object,
// from react-router
match: PropTypes.object.isRequired,
location: PropTypes.object.isRequired,
history: PropTypes.object.isRequired
};
static defaultProps = {
@@ -472,4 +477,4 @@ class StatusContent extends PureComponent {
}
export default connect(mapStateToProps)(injectIntl(StatusContent));
export default withRouter(connect(mapStateToProps)(injectIntl(StatusContent)));