kopia lustrzana https://gitlab.com/soapbox-pub/soapbox
WrappedRoute: refactor with TSX+FC
rodzic
5af0e40ad2
commit
3c90937bf2
|
@ -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;
|
||||
|
|
|
@ -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>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
|
@ -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);
|
|
@ -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 };
|
|
@ -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,
|
||||
};
|
Ładowanie…
Reference in New Issue