WrappedRoute: refactor with TSX+FC

next
Alex Gleason 2022-04-26 12:01:57 -05:00
rodzic 5af0e40ad2
commit 3c90937bf2
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 7211D1F99744FBB7
6 zmienionych plików z 164 dodań i 187 usunięć

Wyświetl plik

@ -2,7 +2,13 @@ import classNames from 'classnames';
import React from 'react';
import StickyBox from 'react-sticky-box';
const Layout: React.FC = ({ children }) => (
interface LayoutType extends React.FC {
Sidebar: React.FC,
Main: React.FC<React.HTMLAttributes<HTMLDivElement>>,
Aside: React.FC,
}
const Layout: LayoutType = ({ children }) => (
<div className='sm:pt-4 relative pb-36'>
<div className='max-w-3xl mx-auto sm:px-6 md:max-w-7xl md:px-8 md:grid md:grid-cols-12 md:gap-8'>
{children}
@ -10,7 +16,6 @@ const Layout: React.FC = ({ children }) => (
</div>
);
const Sidebar: React.FC = ({ children }) => (
<div className='hidden lg:block lg:col-span-3'>
<StickyBox offsetTop={80} className='pb-4'>
@ -37,11 +42,8 @@ const Aside: React.FC = ({ children }) => (
</aside>
);
// @ts-ignore
Layout.Sidebar = Sidebar;
// @ts-ignore
Layout.Main = Main;
// @ts-ignore
Layout.Aside = Aside;
export default Layout;

Wyświetl plik

@ -1,40 +0,0 @@
import PropTypes from 'prop-types';
import React from 'react';
import ImmutablePropTypes from 'react-immutable-proptypes';
import ImmutablePureComponent from 'react-immutable-pure-component';
import { injectIntl } from 'react-intl';
import { Layout } from '../../../components/ui';
export default @(component => injectIntl(component, { withRef: true }))
class ColumnsArea extends ImmutablePureComponent {
static propTypes = {
intl: PropTypes.object.isRequired,
columns: ImmutablePropTypes.list.isRequired,
children: PropTypes.node,
layout: PropTypes.object,
};
render() {
const { children } = this.props;
const layout = this.props.layout || { LEFT: null, RIGHT: null };
return (
<Layout>
<Layout.Sidebar>
{layout.LEFT}
</Layout.Sidebar>
<Layout.Main>
{children}
</Layout.Main>
<Layout.Aside>
{layout.RIGHT}
</Layout.Aside>
</Layout>
);
}
}

Wyświetl plik

@ -0,0 +1,30 @@
import React from 'react';
import { Layout } from '../../../components/ui';
interface IColumnsArea {
layout: any,
}
const ColumnsArea: React.FC<IColumnsArea> = (props) => {
const { children } = props;
const layout = props.layout || { LEFT: null, RIGHT: null };
return (
<Layout>
<Layout.Sidebar>
{layout.LEFT}
</Layout.Sidebar>
<Layout.Main>
{children}
</Layout.Main>
<Layout.Aside>
{layout.RIGHT}
</Layout.Aside>
</Layout>
);
};
export default ColumnsArea;

Wyświetl plik

@ -1,11 +0,0 @@
import { connect } from 'react-redux';
import { getSettings } from 'soapbox/actions/settings';
import ColumnsArea from '../components/columns_area';
const mapStateToProps = state => ({
columns: getSettings(state).get('columns'),
});
export default connect(mapStateToProps, null, null, { forwardRef: true })(ColumnsArea);

Wyświetl plik

@ -1,131 +0,0 @@
import PropTypes from 'prop-types';
import React from 'react';
import ImmutablePropTypes from 'react-immutable-proptypes';
import { connect } from 'react-redux';
import { Redirect, Route } from 'react-router-dom';
import { getSettings } from 'soapbox/actions/settings';
import BundleColumnError from '../components/bundle_column_error';
import ColumnForbidden from '../components/column_forbidden';
import ColumnLoading from '../components/column_loading';
import BundleContainer from '../containers/bundle_container';
import ColumnsAreaContainer from '../containers/columns_area_container';
const mapStateToProps = state => {
const me = state.get('me');
return {
account: state.getIn(['accounts', me]),
settings: getSettings(state),
};
};
class WrappedRoute extends React.Component {
static propTypes = {
component: PropTypes.func.isRequired,
page: PropTypes.oneOfType([PropTypes.object, PropTypes.func]),
content: PropTypes.node,
componentParams: PropTypes.object,
layout: PropTypes.object,
account: ImmutablePropTypes.record,
settings: ImmutablePropTypes.map.isRequired,
publicRoute: PropTypes.bool,
staffOnly: PropTypes.bool,
adminOnly: PropTypes.bool,
developerOnly: PropTypes.bool,
};
static defaultProps = {
componentParams: {},
};
renderComponent = ({ match }) => {
const { component, content, componentParams, layout, page: Page } = this.props;
if (Page) {
return (
<BundleContainer fetchComponent={component} loading={this.renderLoading} error={this.renderError}>
{Component =>
(
<Page params={match.params} layout={layout} {...componentParams}>
<Component params={match.params} {...componentParams}>
{content}
</Component>
</Page>
)
}
</BundleContainer>
);
}
return (
<BundleContainer fetchComponent={component} loading={this.renderLoading} error={this.renderError}>
{Component =>
(
<ColumnsAreaContainer layout={layout}>
<Component params={match.params} {...componentParams}>
{content}
</Component>
</ColumnsAreaContainer>
)
}
</BundleContainer>
);
}
renderLoading = () => {
return (
<ColumnsAreaContainer layout={this.props.layout}>
<ColumnLoading />
</ColumnsAreaContainer>
);
}
renderForbidden = () => {
return (
<ColumnsAreaContainer layout={this.props.layout}>
<ColumnForbidden />
</ColumnsAreaContainer>
);
}
renderError = (props) => {
return (
<ColumnsAreaContainer layout={this.props.layout}>
<BundleColumnError {...props} />
</ColumnsAreaContainer>
);
}
loginRedirect = () => {
const actualUrl = encodeURIComponent(`${this.props.computedMatch.url}${this.props.location.search}`); // eslint-disable-line react/prop-types
return <Redirect to={`/login?redirect_uri=${actualUrl}`} />;
}
render() {
const { component: Component, content, account, settings, publicRoute, developerOnly, staffOnly, adminOnly, ...rest } = this.props;
const authorized = [
account || publicRoute,
developerOnly ? settings.get('isDeveloper') : true,
staffOnly ? account && account.staff : true,
adminOnly ? account && account.admin : true,
].every(c => c);
if (!authorized) {
if (!account) {
return this.loginRedirect();
} else {
return this.renderForbidden();
}
}
return <Route {...rest} render={this.renderComponent} />;
}
}
const wrappedRoute = connect(mapStateToProps)(WrappedRoute);
export { wrappedRoute as WrappedRoute };

Wyświetl plik

@ -0,0 +1,127 @@
import React from 'react';
import { Redirect, Route, useHistory, RouteComponentProps, match as MatchType } from 'react-router-dom';
import { useOwnAccount, useSettings } from 'soapbox/hooks';
import BundleColumnError from '../components/bundle_column_error';
import ColumnForbidden from '../components/column_forbidden';
import ColumnLoading from '../components/column_loading';
import ColumnsArea from '../components/columns_area';
import BundleContainer from '../containers/bundle_container';
type PageProps = {
params?: MatchType['params'],
layout?: any,
};
interface IWrappedRoute {
component: (...args: any[]) => any,
page: React.ComponentType<PageProps>,
content: React.ReactNode,
componentParams: Record<string, any>,
layout: any,
publicRoute?: boolean,
staffOnly?: boolean,
adminOnly?: boolean,
developerOnly?: boolean,
}
const WrappedRoute: React.FC<IWrappedRoute> = ({
component,
page: Page,
content,
componentParams = {},
layout,
publicRoute = false,
staffOnly = false,
adminOnly = false,
developerOnly = false,
...rest
}) => {
const history = useHistory();
const account = useOwnAccount();
const settings = useSettings();
const renderComponent = ({ match }: RouteComponentProps) => {
if (Page) {
return (
<BundleContainer fetchComponent={component} loading={renderLoading} error={renderError}>
{Component =>
(
<Page params={match.params} layout={layout} {...componentParams}>
<Component params={match.params} {...componentParams}>
{content}
</Component>
</Page>
)
}
</BundleContainer>
);
}
return (
<BundleContainer fetchComponent={component} loading={renderLoading} error={renderError}>
{Component =>
(
<ColumnsArea layout={layout}>
<Component params={match.params} {...componentParams}>
{content}
</Component>
</ColumnsArea>
)
}
</BundleContainer>
);
};
const renderLoading = () => {
return (
<ColumnsArea layout={layout}>
<ColumnLoading />
</ColumnsArea>
);
};
const renderForbidden = () => {
return (
<ColumnsArea layout={layout}>
<ColumnForbidden />
</ColumnsArea>
);
};
const renderError = (props: any) => {
return (
<ColumnsArea layout={layout}>
<BundleColumnError {...props} />
</ColumnsArea>
);
};
const loginRedirect = () => {
const actualUrl = encodeURIComponent(`${history.location.pathname}${history.location.search}`);
return <Redirect to={`/login?redirect_uri=${actualUrl}`} />;
};
const authorized = [
account || publicRoute,
developerOnly ? settings.get('isDeveloper') : true,
staffOnly ? account && account.staff : true,
adminOnly ? account && account.admin : true,
].every(c => c);
if (!authorized) {
if (!account) {
return loginRedirect();
} else {
return renderForbidden();
}
}
return <Route {...rest} render={renderComponent} />;
};
export {
WrappedRoute,
};