change how we render layouts

This commit is contained in:
Dawid Wysokiński 2021-01-02 00:43:20 +12:00
parent ea71ef5e0b
commit 3e87c42e0b
29 changed files with 592 additions and 634 deletions

View File

@ -4,25 +4,44 @@ import { heights } from '@theme/toolbar';
import { makeStyles } from '@material-ui/core/styles';
export interface Props extends React.HTMLProps<HTMLElement> {
export interface Props extends React.HTMLAttributes<HTMLOrSVGElement> {
footer?: boolean;
component?: keyof JSX.IntrinsicElements;
minHeight?: boolean;
}
interface MakeStylesProps {
footer?: boolean;
}
function Content({ className, footer = false, ...props }: Props) {
function Content({
className,
footer = false,
component: Wrapper = 'main',
minHeight = true,
...props
}: Props) {
const classes = useStyles({ footer });
return <main className={clsx(classes.main, className)} {...props} />;
return (
<Wrapper
className={clsx(
{ [classes.minHeight]: minHeight },
classes.padding,
className
)}
{...props}
/>
);
}
const useStyles = makeStyles(theme => {
return {
main: ({ footer }: MakeStylesProps) => {
padding: {
padding: theme.spacing(3, 0),
},
minHeight: ({ footer }: MakeStylesProps) => {
const multiplier = footer ? 2 : 1;
return {
padding: theme.spacing(3, 0),
minHeight: `calc(100vh - ${heights.tabletDesktop * multiplier}px)`,
[`${theme.breakpoints.down('xs')} and (orientation: landscape)`]: {
minHeight: `calc(100vh - ${heights.mobileLandscape * multiplier}px)`,

View File

@ -1,5 +1,7 @@
import React from 'react';
import { StringParam, useQueryParam, withDefault } from 'use-query-params';
import { useTranslation } from 'react-i18next';
import { useLocation } from 'react-router-dom';
import { TWHELP, NAME } from '@config/app';
import * as ROUTES from '@config/routes';
import * as NAMESPACES from '@config/namespaces';
@ -21,20 +23,14 @@ import VersionSelector from '@common/VersionSelector/VersionSelector';
import SearchInput from './SearchInput';
export interface Props {
showLinkToHomePage?: boolean;
hideVersionSelectorOnMobile?: boolean;
defaultQ?: string;
appBarProps?: AppBarProps;
}
export default function Header({
showLinkToHomePage = true,
hideVersionSelectorOnMobile = false,
defaultQ = '',
appBarProps = {},
}: Props) {
export default function Header({ appBarProps = {} }: Props) {
const { t } = useTranslation(NAMESPACES.COMMON);
const location = useLocation();
const classes = useStyles();
const [q] = useQueryParam('q', withDefault(StringParam, ''));
const versionSelector = (
<div>
@ -46,9 +42,11 @@ export default function Header({
<Container>
<Toolbar disableGutters className={classes.toolbar}>
<form className={classes.form}>
<SearchInput defaultQ={defaultQ} />
<SearchInput
defaultQ={location.pathname === ROUTES.SEARCH_PAGE ? q : ''}
/>
</form>
{showLinkToHomePage && (
{location.pathname !== ROUTES.INDEX_PAGE && (
<Link to={ROUTES.INDEX_PAGE}>
<Hidden xsDown implementation="css">
<Button startIcon={<InputIcon />}>
@ -62,7 +60,7 @@ export default function Header({
</Hidden>
</Link>
)}
{hideVersionSelectorOnMobile ? (
{location.pathname !== ROUTES.INDEX_PAGE ? (
<Hidden xsDown implementation="css">
{versionSelector}
</Hidden>

View File

@ -7,6 +7,7 @@ import ScrollToTop from '@common/ScrollToTop/ScrollToTop';
import VersionProvider from '../libs/VersionContext/Provider';
import DateUtilsProvider from '../libs/date/DateUtilsProvider';
import MainLayout from '../common/MainLayout/MainLayout';
import IndexPage from './IndexPage/IndexPage';
import NotFoundPage from './NotFoundPage/NotFoundPage';
import SearchPage from './SearchPage/SearchPage';
@ -17,6 +18,9 @@ function App() {
<Fragment>
<VersionProvider>
<DateUtilsProvider>
<Switch>
<Route path={[ROUTES.INDEX_PAGE, ROUTES.SEARCH_PAGE]} exact>
<MainLayout>
<Switch>
<Route path={ROUTES.INDEX_PAGE} exact>
<IndexPage />
@ -24,6 +28,9 @@ function App() {
<Route path={ROUTES.SEARCH_PAGE} exact>
<SearchPage />
</Route>
</Switch>
</MainLayout>
</Route>
<Route path={ROUTES.SERVER_PAGE.INDEX_PAGE}>
<ServerPage />
</Route>

View File

@ -4,7 +4,6 @@ import useTitle from '@libs/useTitle';
import { INDEX_PAGE } from '@config/namespaces';
import { Container, Box } from '@material-ui/core';
import MainLayout from '@common/MainLayout/MainLayout';
import DevNote from '@common/DevNote/DevNote';
import ServerSelection from './components/ServerSelection/ServerSelection';
@ -12,18 +11,11 @@ export default function IndexPage() {
const { t } = useTranslation(INDEX_PAGE);
useTitle(t('title'));
return (
<MainLayout
headerProps={{
showLinkToHomePage: false,
hideVersionSelectorOnMobile: false,
}}
>
<Container>
<Box mb={3}>
<DevNote />
</Box>
<ServerSelection />
</Container>
</MainLayout>
);
}

View File

@ -1,4 +1,4 @@
import React, { useRef } from 'react';
import React, { useRef, useState } from 'react';
import formatNumber from '@utils/formatNumber';
import * as ROUTES from '@config/routes';
import * as NAMESPACES from '@config/namespaces';
@ -31,7 +31,7 @@ export interface Props {
function GridItem({ t, server, hideTooltip = true }: Props) {
const classes = useStyles();
const [expanded, setExpanded] = React.useState<boolean>(false);
const [expanded, setExpanded] = useState<boolean>(false);
const accordion = useRef<HTMLDivElement | null>(null);
const handleClick = (e: React.ChangeEvent<{}>, expanded: boolean) => {

View File

@ -14,7 +14,6 @@ import { SEARCH_PAGE } from '@config/namespaces';
import { MODES, LIMIT } from './constants';
import { Container, Paper } from '@material-ui/core';
import MainLayout from '@common/MainLayout/MainLayout';
import ModeSelector from '@common/ModeSelector/ModeSelector';
import PlayerTable from './components/PlayerTable/PlayerTable';
import TribeTable from './components/TribeTable/TribeTable';
@ -55,9 +54,6 @@ function SearchPage() {
};
return (
<MainLayout
headerProps={{ hideVersionSelectorOnMobile: true, defaultQ: query.q }}
>
<Container>
<Paper>
<ModeSelector
@ -87,7 +83,6 @@ function SearchPage() {
)}
</Paper>
</Container>
</MainLayout>
);
}

View File

@ -3,6 +3,7 @@ import { SERVER_PAGE } from '@config/routes';
import { Switch, Route } from 'react-router-dom';
import ServerProvider from './libs/ServerContext/Provider';
import PageLayout from './common/PageLayout/PageLayout';
import IndexPage from './features/IndexPage/IndexPage';
import PlayerPage from './features/PlayerPage/PlayerPage';
import TribePage from './features/TribePage/TribePage';
@ -16,6 +17,7 @@ import NotFoundPage from './features/NotFoundPage/NotFoundPage';
function ServerPage() {
return (
<ServerProvider>
<PageLayout>
<Switch>
<Route exact path={SERVER_PAGE.INDEX_PAGE}>
<IndexPage />
@ -45,6 +47,7 @@ function ServerPage() {
<NotFoundPage />
</Route>
</Switch>
</PageLayout>
</ServerProvider>
);
}

View File

@ -7,23 +7,15 @@ import { DRAWER_WIDTH } from './components/Sidebar/contants';
import { makeStyles, useTheme } from '@material-ui/core/styles';
import { useMediaQuery, Toolbar } from '@material-ui/core';
import Content, { Props as ContentProps } from '@common/Content/Content';
import Content from '@common/Content/Content';
import Sidebar from './components/Sidebar/Sidebar';
import TopBar from './components/TopBar/TopBar';
export interface Props {
children?: React.ReactNode;
noPadding?: boolean;
contentClassName?: string;
contentStyle?: ContentProps['style'];
}
function PageLayout({
children,
noPadding,
contentClassName,
contentStyle,
}: Props) {
function PageLayout({ children }: Props) {
const [open, setOpen] = useState(false);
const classes = useStyles();
const theme = useTheme();
@ -56,14 +48,7 @@ function PageLayout({
t={t}
onOpen={openSidebar}
/>
<Content
className={clsx(classes.content, contentClassName, {
'no-padding': noPadding,
})}
style={contentStyle}
>
{children}
</Content>
<Content className={classes.content}>{children}</Content>
</div>
);
}
@ -81,10 +66,7 @@ const useStyles = makeStyles(theme => ({
},
content: {
height: '100%',
padding: theme.spacing(3, 0),
'&.no-padding': {
padding: '0 0',
},
padding: 0,
},
}));

View File

@ -53,6 +53,7 @@ const Sidebar = ({ t, className, open, variant, onClose, onOpen }: Props) => {
name: t('pageLayout.sidebar.routes.rankings.name'),
Icon: <GradeIcon color="inherit" />,
to: ROUTES.SERVER_PAGE.RANKING_PAGE.BASE,
isExpandable: true,
nested: [
{
name: t('pageLayout.sidebar.routes.rankings.player.index'),

View File

@ -1,4 +1,4 @@
import React, { Fragment, useState } from 'react';
import React, { Fragment, useState, memo } from 'react';
import { useLocation, matchPath } from 'react-router-dom';
import { Route } from './types';
@ -26,7 +26,7 @@ function ListItem({ route, nestedLevel }: Props) {
const isActive =
!!route.to && !!matchPath(pathname, { path: route.to, exact: route.exact });
const [open, setOpen] = useState(
(hasNested && isActive) || !route.isExpandable
(hasNested && !route.isExpandable) || isActive
);
const getItem = () => {
@ -97,4 +97,4 @@ const useStyles = makeStyles(theme => ({
},
}));
export default ListItem;
export default memo(ListItem);

View File

@ -1,7 +1,6 @@
import React from 'react';
import { Route } from './types';
import { makeStyles } from '@material-ui/core/styles';
import { List } from '@material-ui/core';
import ListItem from './ListItem';
@ -9,15 +8,9 @@ export interface Props {
routes: Route[];
}
const useStyles = makeStyles(theme => ({
root: {},
}));
const Nav = ({ routes }: Props) => {
const classes = useStyles();
return (
<List className={classes.root}>
<List>
{routes.map(route => (
<ListItem nestedLevel={1} route={route} key={route.name} />
))}

View File

@ -6,7 +6,7 @@ import useServer from '@features/ServerPage/libs/ServerContext/useServer';
import { SERVER_PAGE } from '@config/namespaces';
import { Container, Paper } from '@material-ui/core';
import ServerPageLayout from '@features/ServerPage/common/PageLayout/PageLayout';
import Content from '@common/Content/Content';
import ModeSelector from '@common/ModeSelector/ModeSelector';
import LiveEnnoblements from './components/LiveEnnoblements/LiveEnnoblements';
import LatestSavedEnnoblements from './components/LatestSavedEnnoblements/LatestSavedEnnoblements';
@ -22,7 +22,7 @@ function EnnoblementsPage() {
);
return (
<ServerPageLayout>
<Content component="div" minHeight={false}>
<Container>
<Paper>
<ModeSelector
@ -53,7 +53,7 @@ function EnnoblementsPage() {
)}
</Paper>
</Container>
</ServerPageLayout>
</Content>
);
}

View File

@ -5,7 +5,7 @@ import useServer from '../../libs/ServerContext/useServer';
import { SERVER_PAGE } from '@config/namespaces';
import { Container, Grid, Hidden } from '@material-ui/core';
import PageLayout from '@features/ServerPage/common/PageLayout/PageLayout';
import Content from '@common/Content/Content';
import PlayerStatistics from './components/PlayerStatistics/PlayerStatistics';
import TribeStatistics from './components/TribeStatistics/TribeStatistics';
import Top5Players from './components/Top5Players/Top5Players';
@ -23,7 +23,7 @@ function IndexPage() {
useTitle(t('title', { key }));
return (
<PageLayout>
<Content component="div" minHeight={false}>
<Container>
<Grid container spacing={2}>
<Grid
@ -72,7 +72,7 @@ function IndexPage() {
</Grid>
</Grid>
</Container>
</PageLayout>
</Content>
);
}

View File

@ -25,7 +25,7 @@ import {
Checkbox,
FormControlLabel,
} from '@material-ui/core';
import ServerPageLayout from '@features/ServerPage/common/PageLayout/PageLayout';
import Content from '@common/Content/Content';
import ColorInput from '@common/Form/ColorInput';
import Spinner from '@common/Spinner/Spinner';
import Map from './components/Map/Map';
@ -188,9 +188,8 @@ function MapPage() {
return blacklist.some(id2 => id === id2);
};
if (loading) {
return (
<ServerPageLayout>
{loading && (
<Spinner
containerProps={{
display: 'flex',
@ -203,8 +202,11 @@ function MapPage() {
}}
description={t('loading')}
/>
)}
{!loading && (
);
}
return (
<Content component="div" minHeight={false}>
<Container>
<form onSubmit={handleSubmit}>
<Grid container spacing={2}>
@ -269,9 +271,7 @@ function MapPage() {
{
name: 'playerVillageColor',
color: query.playerVillageColor,
onChange: createSettingsChangeHandler(
'playerVillageColor'
),
onChange: createSettingsChangeHandler('playerVillageColor'),
},
{
name: 'barbarianVillageColor',
@ -406,9 +406,7 @@ function MapPage() {
<MarkerField
key={marker.id}
onDelete={createDeletePlayerMarkerHandler(marker.id)}
onChange={createUpdatePlayerMarkerItemHandler(
marker.id
)}
onChange={createUpdatePlayerMarkerItemHandler(marker.id)}
onChangeColor={createUpdatePlayerMarkerColorHandler(
marker.id
)}
@ -455,8 +453,7 @@ function MapPage() {
</Grid>
</form>
</Container>
)}
</ServerPageLayout>
</Content>
);
}

View File

@ -5,11 +5,10 @@ import { NOT_FOUND_PAGE } from '@config/namespaces';
import { makeStyles } from '@material-ui/core/styles';
import { Typography } from '@material-ui/core';
import PageLayout from '@features/ServerPage/common/PageLayout/PageLayout';
import Content from '@common/Content/Content';
const useStyles = makeStyles(theme => ({
container: {
padding: theme.spacing(3, 0),
width: '100%',
minHeight: 'inherit',
display: 'flex',
@ -24,40 +23,20 @@ const useStyles = makeStyles(theme => ({
export interface Props {
title?: string;
description?: string;
wrapIntoServerPageLayout?: boolean;
}
function NotFoundPage({
title,
description,
wrapIntoServerPageLayout = true,
}: Props) {
function NotFoundPage({ title, description }: Props) {
const classes = useStyles();
const { t } = useTranslation(NOT_FOUND_PAGE);
useTitle(t('title'));
const jsx = (
<div className={classes.container}>
<div>
<Typography variant="h1">{title ? title : t('title')}</Typography>
{description && <Typography variant="h4">{description}</Typography>}
</div>
</div>
);
if (!wrapIntoServerPageLayout) {
return jsx;
}
return (
<PageLayout noPadding>
<div className={classes.container}>
<Content component="div" className={classes.container}>
<div>
<Typography variant="h1">{title ? title : t('title')}</Typography>
{description && <Typography variant="h4">{description}</Typography>}
</div>
</div>
</PageLayout>
</Content>
);
}

View File

@ -28,7 +28,7 @@ function PlayerPage() {
<EnnoblementsPage />
</Route>
<Route path="*">
<NotFoundPage wrapIntoServerPageLayout={false} />
<NotFoundPage />
</Route>
</Switch>
</PageLayout>

View File

@ -11,9 +11,9 @@ import * as ROUTES from '@config/routes';
import { makeStyles } from '@material-ui/core/styles';
import { Chip, Toolbar, Typography, Tabs, ChipProps } from '@material-ui/core';
import Content from '@common/Content/Content';
import Link from '@common/Link/Link';
import TabLink from '@common/Link/TabLink';
import ServerPageLayout from '@features/ServerPage/common/PageLayout/PageLayout';
import background1 from './backgrounds/bg-1-dark.png';
import background2 from './backgrounds/bg-2-dark.jpg';
@ -37,7 +37,7 @@ function PageLayout({ children }: Props) {
size: 'small',
};
return (
<ServerPageLayout noPadding>
<div>
<header className={clsx(classes.header, 'bg-' + bg)}>
<Toolbar className={classes.toolbar}>
<div style={{ width: '100%' }}>
@ -124,8 +124,10 @@ function PageLayout({ children }: Props) {
})}
</Tabs>
</header>
<div className={classes.content}>{children}</div>
</ServerPageLayout>
<Content component="div" minHeight={false}>
{children}
</Content>
</div>
);
}
@ -181,13 +183,6 @@ const useStyles = makeStyles(theme => ({
margin: theme.spacing(0.5),
},
},
content: {
height: '100%',
padding: theme.spacing(3, 0),
'&.no-padding': {
padding: '0 0',
},
},
}));
export default PageLayout;

View File

@ -10,7 +10,6 @@ import { PlayerQueryVariables } from '@libs/graphql/types';
import { Params, PlayerQueryResult } from './types';
import NotFoundPage from '@features/ServerPage/features/NotFoundPage/NotFoundPage';
import PageLayout from '@features/ServerPage/common/PageLayout/PageLayout';
import Spinner from '@common/Spinner/Spinner';
export interface Props {
@ -41,17 +40,15 @@ function Provider({ children }: Props) {
alignItems: 'center',
};
return (
<PageLayout noPadding contentStyle={centerFlex as React.CSSProperties}>
<Spinner
containerProps={{
...centerFlex,
textAlign: 'center',
height: '100%',
minHeight: 'inherit',
paddingY: 5,
}}
description={t('playerPageContextProvider.loadingPlayer')}
/>
</PageLayout>
);
}

View File

@ -18,7 +18,7 @@ function RankingPage() {
<TribePage />
</Route>
<Route path="*">
<NotFoundPage wrapIntoServerPageLayout={false} />
<NotFoundPage />
</Route>
</Switch>
</PageLayout>

View File

@ -8,7 +8,7 @@ import { makeStyles } from '@material-ui/core/styles';
import { Tabs } from '@material-ui/core';
import TabLink from '@common/Link/TabLink';
import ServerPageLayout from '@features/ServerPage/common/PageLayout/PageLayout';
import Content from '@common/Content/Content';
import background from './backgrounds/bg-1-dark.png';
@ -22,7 +22,7 @@ function PageLayout({ children }: Props) {
const { t } = useTranslation(NAMESPACES.SERVER_PAGE.RANKING_PAGE.COMMON);
const { currentTab, tabs } = useTabs(t);
return (
<ServerPageLayout noPadding>
<div>
<header className={classes.header}>
<Tabs variant="scrollable" value={currentTab}>
{tabs.map(({ to, label }) => {
@ -40,8 +40,10 @@ function PageLayout({ children }: Props) {
})}
</Tabs>
</header>
<div className={classes.content}>{children}</div>
</ServerPageLayout>
<Content minHeight={false} component="div">
{children}
</Content>
</div>
);
}
@ -61,15 +63,6 @@ const useStyles = makeStyles(theme => ({
minHeight: theme.spacing(10),
},
},
content: {
padding: theme.spacing(3, 0),
'&.no-padding': {
padding: '0 0',
},
},
tabs: {
overflowX: 'auto',
},
}));
export default PageLayout;

View File

@ -24,7 +24,7 @@ function PlayerPage() {
<ArchivePage />
</Route>
<Route path="*">
<NotFoundPage wrapIntoServerPageLayout={false} />
<NotFoundPage />
</Route>
</Switch>
);

View File

@ -24,7 +24,7 @@ function TribePage() {
<ArchivePage />
</Route>
<Route path="*">
<NotFoundPage wrapIntoServerPageLayout={false} />
<NotFoundPage />
</Route>
</Switch>
);

View File

@ -32,7 +32,7 @@ function TribePage() {
<EnnoblementsPage />
</Route>
<Route path="*">
<NotFoundPage wrapIntoServerPageLayout={false} />
<NotFoundPage />
</Route>
</Switch>
</PageLayout>

View File

@ -10,8 +10,8 @@ import * as NAMESPACES from '@config/namespaces';
import { makeStyles } from '@material-ui/core/styles';
import { Chip, Toolbar, Typography, Tabs, ChipProps } from '@material-ui/core';
import Content from '@common/Content/Content';
import TabLink from '@common/Link/TabLink';
import ServerPageLayout from '@features/ServerPage/common/PageLayout/PageLayout';
import background1 from './backgrounds/bg-1-dark.jpg';
import background2 from './backgrounds/bg-2-dark.jpg';
@ -35,7 +35,7 @@ function PageLayout({ children }: Props) {
size: 'small',
};
return (
<ServerPageLayout noPadding>
<div>
<header className={clsx(classes.header, 'bg-' + bg)}>
<Toolbar className={classes.toolbar}>
<div style={{ width: '100%' }}>
@ -105,8 +105,10 @@ function PageLayout({ children }: Props) {
})}
</Tabs>
</header>
<div className={classes.content}>{children}</div>
</ServerPageLayout>
<Content minHeight={false} component="div">
{children}
</Content>
</div>
);
}
@ -161,13 +163,6 @@ const useStyles = makeStyles(theme => ({
margin: theme.spacing(0.5),
},
},
content: {
height: '100%',
padding: theme.spacing(3, 0),
'&.no-padding': {
padding: '0 0',
},
},
}));
export default PageLayout;

View File

@ -10,7 +10,6 @@ import { TribeQueryVariables } from '@libs/graphql/types';
import { Params, TribeQueryResult } from './types';
import NotFoundPage from '@features/ServerPage/features/NotFoundPage/NotFoundPage';
import PageLayout from '@features/ServerPage/common/PageLayout/PageLayout';
import Spinner from '@common/Spinner/Spinner';
export interface Props {
@ -41,17 +40,16 @@ function Provider({ children }: Props) {
alignItems: 'center',
};
return (
<PageLayout noPadding contentStyle={centerFlex as React.CSSProperties}>
<Spinner
containerProps={{
...centerFlex,
textAlign: 'center',
minHeight: 'inherit',
height: '100%',
paddingY: 5,
}}
description={t('tribePageContextProvider.loadingTribe')}
/>
</PageLayout>
);
}

View File

@ -7,7 +7,6 @@ import { SERVER_PAGE } from '@config/namespaces';
import { Container } from '@material-ui/core';
import NotFoundPage from '@features/ServerPage/features/NotFoundPage/NotFoundPage';
import ServerPageLayout from '@features/ServerPage/common/PageLayout/PageLayout';
import Spinner from '@common/Spinner/Spinner';
import PageLayout from './components/PageLayout/PageLayout';
import Ennoblements from './components/Ennoblements/Ennoblements';
@ -28,20 +27,15 @@ function VillagePage() {
alignItems: 'center',
};
return (
<ServerPageLayout
noPadding
contentStyle={centerFlex as React.CSSProperties}
>
<Spinner
containerProps={{
...centerFlex,
textAlign: 'center',
height: '100%',
minHeight: 'inherit',
paddingY: 5,
}}
description={t('loadingVillage')}
/>
</ServerPageLayout>
);
}

View File

@ -6,7 +6,7 @@ import { Village } from '../../types';
import { makeStyles } from '@material-ui/core/styles';
import { Toolbar, Typography } from '@material-ui/core';
import ServerPageLayout from '@features/ServerPage/common/PageLayout/PageLayout';
import Content from '@common/Content/Content';
import PlayerProfileLink from '@features/ServerPage/common/PlayerProfileLink/PlayerProfileLink';
import background from './backgrounds/bg-1-dark.jpg';
@ -21,7 +21,7 @@ export interface Props {
function PageLayout({ children, village, server, t }: Props) {
const classes = useStyles();
return (
<ServerPageLayout noPadding>
<div>
<header className={classes.header}>
<Toolbar className={classes.toolbar}>
<div>
@ -40,8 +40,10 @@ function PageLayout({ children, village, server, t }: Props) {
</div>
</Toolbar>
</header>
<div className={classes.content}>{children}</div>
</ServerPageLayout>
<Content minHeight={false} component="div">
{children}
</Content>
</div>
);
}
@ -68,13 +70,6 @@ const useStyles = makeStyles(theme => ({
marginBottom: theme.spacing(1),
},
},
content: {
height: '100%',
padding: theme.spacing(3, 0),
'&.no-padding': {
padding: '0 0',
},
},
}));
export default PageLayout;

View File

@ -18,7 +18,7 @@ import {
Button,
} from '@material-ui/core';
import DateTimePicker from '@common/Picker/DateTimePicker';
import ServerPageLayout from '@features/ServerPage/common/PageLayout/PageLayout';
import Content from '@common/Content/Content';
import Spinner from '@common/Spinner/Spinner';
import Card from './components/Card/Card';
import OneSide from './components/OneSide/OneSide';
@ -205,9 +205,8 @@ function WarStatsPage() {
setIsSubmitting(false);
};
if (loading) {
return (
<ServerPageLayout>
{loading && (
<Spinner
containerProps={{
minHeight: 'inherit',
@ -220,8 +219,11 @@ function WarStatsPage() {
}}
description={t('loading')}
/>
)}
{!loading && (
);
}
return (
<Content component="div" minHeight={false}>
<Container>
<form onSubmit={handleSubmit}>
<Grid container spacing={2}>
@ -308,8 +310,7 @@ function WarStatsPage() {
isSubmitting ||
(sideOnePlayers.length === 0 &&
sideOneTribes.length === 0) ||
(sideTwoPlayers.length === 0 &&
sideTwoTribes.length === 0)
(sideTwoPlayers.length === 0 && sideTwoTribes.length === 0)
}
>
{t('buttons.generateStats')}
@ -324,8 +325,7 @@ function WarStatsPage() {
</Grid>
</form>
</Container>
)}
</ServerPageLayout>
</Content>
);
}

View File

@ -0,0 +1,25 @@
export function getEncodedValue(
input: string | (string | null)[] | null | undefined,
allowEmptyString?: boolean
): string | null | undefined {
if (!input) {
return undefined;
}
// '' or []
if (
input.length === 0 &&
(!allowEmptyString || (allowEmptyString && input !== ''))
) {
return null;
}
const str = input instanceof Array ? input[0] : input;
if (str == null) {
return str;
}
if (!allowEmptyString && str === '') {
return null;
}
return str;
}