diff --git a/package.json b/package.json index 9b3fb72..0925b8c 100644 --- a/package.json +++ b/package.json @@ -14,6 +14,7 @@ "@types/node": "^12.0.0", "@types/react": "^16.9.53", "@types/react-dom": "^16.9.8", + "clsx": "^1.1.1", "date-fns": "^2.16.1", "graphql": "^15.4.0", "i18next": "^19.8.3", diff --git a/src/common/Link/Link.tsx b/src/common/Link/Link.tsx index 7faba77..ea5a2fd 100644 --- a/src/common/Link/Link.tsx +++ b/src/common/Link/Link.tsx @@ -19,12 +19,30 @@ const CustomizedRRDLink = forwardRef( ) ); -function Link({ children, ...props }: Props) { - return ( - - {children} - - ); -} +const Link = forwardRef( + ( + { children, ...props }: Props, + ref: + | ((instance: HTMLAnchorElement | null) => void) + | RefObject + | null + | undefined + ) => { + return ( + + {children} + + ); + } +); + +// function Link({ children, ...props }: Props) { +// return ; +// } + +Link.defaultProps = { + color: 'secondary', + underline: 'none', +}; export default Link; diff --git a/src/common/Spinner/Spinner.tsx b/src/common/Spinner/Spinner.tsx new file mode 100644 index 0000000..41f0937 --- /dev/null +++ b/src/common/Spinner/Spinner.tsx @@ -0,0 +1,44 @@ +import React from 'react'; +import { + Box, + Typography, + CircularProgress, + BoxProps, + TypographyProps, +} from '@material-ui/core'; + +export interface Props { + size?: number; + containerProps?: BoxProps; + typographyProps?: TypographyProps; + description?: string; +} + +function Spinner({ + size, + containerProps, + typographyProps, + description, +}: Props) { + return ( + + + + + {description && ( + {description} + )} + + ); +} + +Spinner.defaultProps = { + size: 200, + containerProps: {} as BoxProps, + typographyProps: { + variant: 'h3', + } as TypographyProps, + description: '', +} as Props; + +export default Spinner; diff --git a/src/config/app.ts b/src/config/app.ts index 57d6233..0ba51ef 100644 --- a/src/config/app.ts +++ b/src/config/app.ts @@ -2,9 +2,11 @@ export const DEFAULT_LANGUAGE = process.env.DEFAULT_LANGUAGE ?? 'en'; export const NAME = 'TWHelp'; +export type ServerStatus = 'open' | 'closed'; + export const SERVER_STATUS = { - CLOSED: 'closed', - OPEN: 'open', + CLOSED: 'closed' as ServerStatus, + OPEN: 'open' as ServerStatus, }; export const TWHELP = process.env.TWHelp ?? 'https://tribalwarshelp.com'; diff --git a/src/config/namespaces.ts b/src/config/namespaces.ts index 5975c0f..ea22acd 100644 --- a/src/config/namespaces.ts +++ b/src/config/namespaces.ts @@ -1,3 +1,7 @@ export const COMMON = 'common'; export const INDEX_PAGE = 'index-page'; export const NOT_FOUND_PAGE = 'not-found-page'; +export const SERVER_PAGE = { + COMMON: 'server-page/common', + INDEX_PAGE: 'server-page/index-page', +}; diff --git a/src/config/routes.ts b/src/config/routes.ts index 17706a8..60a78bd 100644 --- a/src/config/routes.ts +++ b/src/config/routes.ts @@ -1 +1,7 @@ export const INDEX_PAGE = '/'; +export const SERVER_PAGE = { + BASE: '/server', + get INDEX_PAGE() { + return this.BASE + '/:key'; + }, +}; diff --git a/src/features/App.tsx b/src/features/App.tsx index ec6c940..074cd21 100644 --- a/src/features/App.tsx +++ b/src/features/App.tsx @@ -6,6 +6,7 @@ import { CssBaseline } from '@material-ui/core'; import IndexPage from './IndexPage/IndexPage'; import NotFoundPage from './NotFoundPage/NotFoundPage'; +import ServerPage from './ServerPage/ServerPage'; function App() { return ( @@ -14,6 +15,9 @@ function App() { + + + diff --git a/src/features/IndexPage/components/Footer/Footer.tsx b/src/features/IndexPage/components/Footer/Footer.tsx index 1cafc05..fe630ba 100644 --- a/src/features/IndexPage/components/Footer/Footer.tsx +++ b/src/features/IndexPage/components/Footer/Footer.tsx @@ -8,7 +8,7 @@ export default function Header() { const classes = useStyles(); return ( - + diff --git a/src/features/IndexPage/components/Header/Header.tsx b/src/features/IndexPage/components/Header/Header.tsx index fedaa9d..ce358fb 100644 --- a/src/features/IndexPage/components/Header/Header.tsx +++ b/src/features/IndexPage/components/Header/Header.tsx @@ -31,7 +31,7 @@ export default function Header() { const classes = useStyles(); return ( - +
diff --git a/src/features/IndexPage/components/ServerSelection/ServerSelection.tsx b/src/features/IndexPage/components/ServerSelection/ServerSelection.tsx index c962150..fa699ec 100644 --- a/src/features/IndexPage/components/ServerSelection/ServerSelection.tsx +++ b/src/features/IndexPage/components/ServerSelection/ServerSelection.tsx @@ -7,6 +7,8 @@ import { withDefault, } from 'use-query-params'; import { useTranslation } from 'react-i18next'; +import { generatePath } from 'react-router'; +import * as ROUTES from '@config/routes'; import * as NAMESPACES from '@config/namespaces'; import { SERVER_STATUS } from '@config/app'; import { ServerList } from './types'; @@ -26,6 +28,7 @@ import { ExpandMore as ExpandMoreIcon } from '@material-ui/icons'; import Pagination, { Props as PaginationProps, } from '@common/Pagination/Pagination'; +import Link from '@common/Link/Link'; const PER_PAGE = 48; const arr = new Array(PER_PAGE).fill(0); @@ -102,13 +105,19 @@ export default function ServerSelection() { }> - {server.key}{' '} - {SERVER_STATUS.CLOSED === server.status - ? `(${t( - NAMESPACES.COMMON + - `:serverStatus.${server.status}` - ).toLowerCase()})` - : ''} + + {server.key}{' '} + {SERVER_STATUS.CLOSED === server.status + ? `(${t( + NAMESPACES.COMMON + + `:serverStatus.${server.status}` + ).toLowerCase()})` + : ''} + diff --git a/src/features/IndexPage/components/ServerSelection/types.ts b/src/features/IndexPage/components/ServerSelection/types.ts index 135c981..86f9a0d 100644 --- a/src/features/IndexPage/components/ServerSelection/types.ts +++ b/src/features/IndexPage/components/ServerSelection/types.ts @@ -1,8 +1,9 @@ import { List } from '@libs/graphql/types'; +import { ServerStatus } from '@config/app'; export type Server = { key: string; - status: string; + status: ServerStatus; numberOfPlayers: number; numberOfTribes: number; numberOfVillages: number; diff --git a/src/features/ServerPage/ServerPage.tsx b/src/features/ServerPage/ServerPage.tsx new file mode 100644 index 0000000..a14155e --- /dev/null +++ b/src/features/ServerPage/ServerPage.tsx @@ -0,0 +1,21 @@ +import React from 'react'; +import { SERVER_PAGE } from '@config/routes'; + +import { Switch, Route } from 'react-router-dom'; +import IndexPage from './features/IndexPage/IndexPage'; +import NotFoundPage from '../NotFoundPage/NotFoundPage'; + +function ServerPage() { + return ( + + + + + + + + + ); +} + +export default ServerPage; diff --git a/src/features/ServerPage/common/PageLayout/PageLayout.tsx b/src/features/ServerPage/common/PageLayout/PageLayout.tsx new file mode 100644 index 0000000..140dbc1 --- /dev/null +++ b/src/features/ServerPage/common/PageLayout/PageLayout.tsx @@ -0,0 +1,75 @@ +import React, { useState } from 'react'; +import clsx from 'clsx'; +import { useTranslation } from 'react-i18next'; +import { SERVER_PAGE } from '@config/namespaces'; +import { DRAWER_WIDTH } from './components/Sidebar/contants'; + +import { makeStyles, useTheme } from '@material-ui/core/styles'; +import { useMediaQuery, Toolbar } from '@material-ui/core'; + +import ServerProvider from '@features/ServerPage/libs/ServerContext/Provider'; +import Sidebar from './components/Sidebar/Sidebar'; +import TopBar from './components/TopBar/TopBar'; + +export interface Props { + children: React.ReactNode; +} + +const useStyles = makeStyles(theme => ({ + root: { + paddingTop: 56, + height: '100%', + [theme.breakpoints.up('sm')]: { + paddingTop: 64, + }, + }, + shiftContent: { + paddingLeft: DRAWER_WIDTH, + }, + content: { + height: '100%', + padding: theme.spacing(2), + }, +})); + +function PageLayout({ children }: Props) { + const [open, setOpen] = useState(false); + const classes = useStyles(); + const theme = useTheme(); + const isDesktop = useMediaQuery(theme.breakpoints.up('lg'), { + defaultMatches: true, + }); + const { t } = useTranslation(SERVER_PAGE.COMMON); + const shouldOpenSidebar = isDesktop ? true : open; + + const openSidebar = () => { + setOpen(true); + }; + + const closeSidebar = () => { + setOpen(false); + }; + + return ( + +
+ + + +
{children}
+
+
+ ); +} + +export default PageLayout; diff --git a/src/features/ServerPage/common/PageLayout/components/Sidebar/Sidebar.tsx b/src/features/ServerPage/common/PageLayout/components/Sidebar/Sidebar.tsx new file mode 100644 index 0000000..d7ac5b4 --- /dev/null +++ b/src/features/ServerPage/common/PageLayout/components/Sidebar/Sidebar.tsx @@ -0,0 +1,58 @@ +import React from 'react'; +import clsx from 'clsx'; +import { generatePath } from 'react-router'; +import { TFunction } from 'i18next'; +import useServer from '@features/ServerPage/libs/ServerContext/useServer'; +import useStyles from './useStyles'; +import * as ROUTES from '@config/routes'; +import { Route } from './components/Nav/types'; + +import { Divider, SwipeableDrawer, DrawerProps } from '@material-ui/core'; +import DashboardIcon from '@material-ui/icons/Dashboard'; + +import Nav from './components/Nav/Nav'; +import ServerInfo from './components/ServerInfo/ServerInfo'; + +export interface Props { + t: TFunction; + className?: string; + open: boolean; + onClose: React.ReactEventHandler<{}>; + onOpen: React.ReactEventHandler<{}>; + variant?: DrawerProps['variant']; +} + +const Sidebar = ({ t, className, open, variant, onClose, onOpen }: Props) => { + const classes = useStyles(); + const { key } = useServer(); + + const routes: Route[] = [ + { + name: t('pageLayout.sidebar.routes.dashboard'), + to: generatePath(ROUTES.SERVER_PAGE.INDEX_PAGE, { + key: key, + }), + Icon: , + }, + ]; + + return ( + +
+ + +
+
+ ); +}; + +export default Sidebar; diff --git a/src/features/ServerPage/common/PageLayout/components/Sidebar/components/Nav/ListItem.tsx b/src/features/ServerPage/common/PageLayout/components/Sidebar/components/Nav/ListItem.tsx new file mode 100644 index 0000000..9a4637e --- /dev/null +++ b/src/features/ServerPage/common/PageLayout/components/Sidebar/components/Nav/ListItem.tsx @@ -0,0 +1,80 @@ +import React, { Fragment, useState } from 'react'; +import { Route } from './types'; + +import { makeStyles } from '@material-ui/core/styles'; +import { + ListItem as MUIListItem, + ListItemIcon, + ListItemText, + Collapse, + List, + Box, +} from '@material-ui/core'; +import { ExpandLess, ExpandMore } from '@material-ui/icons'; +import Link from '@common/Link/Link'; + +export interface Props { + route: Route; + nestedLevel: number; +} + +const useStyles = makeStyles(theme => ({ + link: { + display: 'block', + width: '100%', + }, +})); + +function ListItem({ route, nestedLevel }: Props) { + const [open, setOpen] = useState(false); + const classes = useStyles(); + const hasNested = Array.isArray(route.nested) && route.nested.length > 0; + + const getItem = () => { + return ( + setOpen(!open) : undefined} + disableGutters + button + component={Box} + pl={nestedLevel} + dense + > + {route.Icon} + + {hasNested && ( + {open ? : } + )} + + ); + }; + + return ( + + {!hasNested ? ( + + {getItem()} + + ) : ( + getItem() + )} + {hasNested && ( + + + {route.nested?.map(route => { + return ( + + ); + })} + + + )} + + ); +} + +export default ListItem; diff --git a/src/features/ServerPage/common/PageLayout/components/Sidebar/components/Nav/Nav.tsx b/src/features/ServerPage/common/PageLayout/components/Sidebar/components/Nav/Nav.tsx new file mode 100644 index 0000000..004e75b --- /dev/null +++ b/src/features/ServerPage/common/PageLayout/components/Sidebar/components/Nav/Nav.tsx @@ -0,0 +1,28 @@ +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'; + +export interface Props { + routes: Route[]; +} + +const useStyles = makeStyles(theme => ({ + root: {}, +})); + +const Nav = ({ routes }: Props) => { + const classes = useStyles(); + + return ( + + {routes.map(route => ( + + ))} + + ); +}; + +export default Nav; diff --git a/src/features/ServerPage/common/PageLayout/components/Sidebar/components/Nav/types.ts b/src/features/ServerPage/common/PageLayout/components/Sidebar/components/Nav/types.ts new file mode 100644 index 0000000..5f4986c --- /dev/null +++ b/src/features/ServerPage/common/PageLayout/components/Sidebar/components/Nav/types.ts @@ -0,0 +1,6 @@ +export interface Route { + name: string; + to: string; + Icon: React.ReactElement; + nested?: Route[]; +} diff --git a/src/features/ServerPage/common/PageLayout/components/Sidebar/components/ServerInfo/ServerInfo.tsx b/src/features/ServerPage/common/PageLayout/components/Sidebar/components/ServerInfo/ServerInfo.tsx new file mode 100644 index 0000000..082458f --- /dev/null +++ b/src/features/ServerPage/common/PageLayout/components/Sidebar/components/ServerInfo/ServerInfo.tsx @@ -0,0 +1,59 @@ +import React from 'react'; +import { TFunction } from 'i18next'; +import useServer from '@features/ServerPage/libs/ServerContext/useServer'; +import useStyles from './useStyles'; +import formatDistanceToNow from '@libs/date/formatDistanceToNow'; +import { Locale } from '@libs/date/locales'; +import extractVersionCodeFromHostname from '@utils/extractVersionCodeFromHostname'; + +import { Typography } from '@material-ui/core'; + +export interface Props { + t: TFunction; +} + +const ServerInfo = ({ t }: Props) => { + const { + numberOfPlayers, + numberOfTribes, + dataUpdatedAt, + numberOfVillages, + } = useServer(); + + const classes = useStyles(); + + return ( +
+ + {t('pageLayout.sidebar.serverInfo.numberOfPlayers', { + num: numberOfPlayers.toLocaleString(), + count: numberOfPlayers, + })} + + + {t('pageLayout.sidebar.serverInfo.numberOfTribes', { + num: numberOfTribes.toLocaleString(), + count: numberOfTribes, + })} + + + {t('pageLayout.sidebar.serverInfo.numberOfVillages', { + num: numberOfVillages.toLocaleString(), + count: numberOfVillages, + })} + + + {t('pageLayout.sidebar.serverInfo.dataUpdatedAt', { + date: formatDistanceToNow(new Date(dataUpdatedAt), { + locale: extractVersionCodeFromHostname( + window.location.hostname + ) as Locale, + addSuffix: true, + }), + })} + +
+ ); +}; + +export default ServerInfo; diff --git a/src/features/ServerPage/common/PageLayout/components/Sidebar/components/ServerInfo/useStyles.ts b/src/features/ServerPage/common/PageLayout/components/Sidebar/components/ServerInfo/useStyles.ts new file mode 100644 index 0000000..a16c46a --- /dev/null +++ b/src/features/ServerPage/common/PageLayout/components/Sidebar/components/ServerInfo/useStyles.ts @@ -0,0 +1,20 @@ +import { makeStyles } from '@material-ui/core/styles'; + +const useStyles = makeStyles(theme => ({ + root: { + display: 'flex', + flexDirection: 'column', + alignItems: 'center', + minHeight: 'fit-content', + textAlign: 'center', + padding: theme.spacing(1), + '& > *:not(:last-child)': { + marginBottom: theme.spacing(0.5), + }, + }, + status: { + marginBottom: theme.spacing(1), + }, +})); + +export default useStyles; diff --git a/src/features/ServerPage/common/PageLayout/components/Sidebar/contants.ts b/src/features/ServerPage/common/PageLayout/components/Sidebar/contants.ts new file mode 100644 index 0000000..72ad401 --- /dev/null +++ b/src/features/ServerPage/common/PageLayout/components/Sidebar/contants.ts @@ -0,0 +1 @@ +export const DRAWER_WIDTH = 250; diff --git a/src/features/ServerPage/common/PageLayout/components/Sidebar/useStyles.ts b/src/features/ServerPage/common/PageLayout/components/Sidebar/useStyles.ts new file mode 100644 index 0000000..ea7ad9a --- /dev/null +++ b/src/features/ServerPage/common/PageLayout/components/Sidebar/useStyles.ts @@ -0,0 +1,19 @@ +import { makeStyles } from '@material-ui/core/styles'; +import { DRAWER_WIDTH } from './contants'; + +const useStyles = makeStyles(theme => ({ + drawer: { + width: DRAWER_WIDTH, + [theme.breakpoints.up('lg')]: { + marginTop: 64, + height: 'calc(100% - 64px) !important', + }, + }, + root: { + backgroundColor: theme.palette.background.paper, + display: 'flex', + flexDirection: 'column', + height: '100%', + }, +})); +export default useStyles; diff --git a/src/features/ServerPage/common/PageLayout/components/TopBar/TopBar.tsx b/src/features/ServerPage/common/PageLayout/components/TopBar/TopBar.tsx new file mode 100644 index 0000000..558e054 --- /dev/null +++ b/src/features/ServerPage/common/PageLayout/components/TopBar/TopBar.tsx @@ -0,0 +1,28 @@ +import React from 'react'; +import clsx from 'clsx'; +import { TFunction } from 'i18next'; + +import { AppBar, Toolbar, Hidden, IconButton } from '@material-ui/core'; +import MenuIcon from '@material-ui/icons/Menu'; + +export interface Props { + className?: string; + t: TFunction; + openSidebar?: () => void; +} + +const TopBar = ({ className, openSidebar }: Props) => { + return ( + + + + + + + + + + ); +}; + +export default TopBar; diff --git a/src/features/ServerPage/features/IndexPage/IndexPage.tsx b/src/features/ServerPage/features/IndexPage/IndexPage.tsx new file mode 100644 index 0000000..294e486 --- /dev/null +++ b/src/features/ServerPage/features/IndexPage/IndexPage.tsx @@ -0,0 +1,580 @@ +import React from 'react'; +import PageLayout from '@features/ServerPage/common/PageLayout/PageLayout'; + +function IndexPage() { + return ( + +

+ Lorem ipsum dolor sit amet consectetur adipisicing elit. Doloremque vel, + sequi laborum fugit et libero facilis officiis, fuga dolorem iste ea in + iusto at, repellendus facere. Facilis voluptatibus error illum? Lorem + ipsum dolor sit amet consectetur, adipisicing elit. Officiis eveniet, + facilis aut neque, aliquam ullam amet consequuntur numquam asperiores + ducimus ab, explicabo iure? Aliquid numquam ab excepturi facere dolores + illum. Lorem ipsum dolor sit, amet consectetur adipisicing elit. Fugit, + quae consequuntur? Unde dicta, non inventore magni at rem, debitis et + molestiae officia obcaecati expedita suscipit est fugiat deserunt, + beatae hic? Lorem ipsum dolor sit amet consectetur adipisicing elit. + Molestiae recusandae facilis iure, ipsum excepturi voluptates amet + libero explicabo! Mollitia magni consequuntur perspiciatis consectetur + officiis cum. Illum exercitationem eveniet dolorum maiores. Lorem ipsum + dolor sit amet, consectetur adipisicing elit. Amet commodi molestiae + veritatis ad suscipit at, eos sapiente illum laborum ipsum, unde + reiciendis, praesentium temporibus officia optio nemo dolorum magni + tempora. Lorem ipsum dolor sit amet consectetur adipisicing elit. Fuga, + consectetur laborum? Impedit deserunt dolor qui eligendi aspernatur + magnam ratione at inventore, placeat est. Commodi nobis tenetur suscipit + cupiditate ipsum excepturi. Lorem ipsum dolor sit amet consectetur + adipisicing elit. Vitae illum, explicabo maxime placeat aliquam quos, + harum aliquid aspernatur officia ullam voluptatum beatae? Fugit laborum + in recusandae eius tempore ab quasi. Lorem ipsum dolor sit amet + consectetur adipisicing elit. Doloremque vel, sequi laborum fugit et + libero facilis officiis, fuga dolorem iste ea in iusto at, repellendus + facere. Facilis voluptatibus error illum? Lorem ipsum dolor sit amet + consectetur, adipisicing elit. Officiis eveniet, facilis aut neque, + aliquam ullam amet consequuntur numquam asperiores ducimus ab, explicabo + iure? Aliquid numquam ab excepturi facere dolores illum. Lorem ipsum + dolor sit, amet consectetur adipisicing elit. Fugit, quae consequuntur? + Unde dicta, non inventore magni at rem, debitis et molestiae officia + obcaecati expedita suscipit est fugiat deserunt, beatae hic? Lorem ipsum + dolor sit amet consectetur adipisicing elit. Molestiae recusandae + facilis iure, ipsum excepturi voluptates amet libero explicabo! Mollitia + magni consequuntur perspiciatis consectetur officiis cum. Illum + exercitationem eveniet dolorum maiores. Lorem ipsum dolor sit amet, + consectetur adipisicing elit. Amet commodi molestiae veritatis ad + suscipit at, eos sapiente illum laborum ipsum, unde reiciendis, + praesentium temporibus officia optio nemo dolorum magni tempora. Lorem + ipsum dolor sit amet consectetur adipisicing elit. Fuga, consectetur + laborum? Impedit deserunt dolor qui eligendi aspernatur magnam ratione + at inventore, placeat est. Commodi nobis tenetur suscipit cupiditate + ipsum excepturi. Lorem ipsum dolor sit amet consectetur adipisicing + elit. Vitae illum, explicabo maxime placeat aliquam quos, harum aliquid + aspernatur officia ullam voluptatum beatae? Fugit laborum in recusandae + eius tempore ab quasi. Lorem ipsum dolor sit amet consectetur + adipisicing elit. Doloremque vel, sequi laborum fugit et libero facilis + officiis, fuga dolorem iste ea in iusto at, repellendus facere. Facilis + voluptatibus error illum? Lorem ipsum dolor sit amet consectetur, + adipisicing elit. Officiis eveniet, facilis aut neque, aliquam ullam + amet consequuntur numquam asperiores ducimus ab, explicabo iure? Aliquid + numquam ab excepturi facere dolores illum. Lorem ipsum dolor sit, amet + consectetur adipisicing elit. Fugit, quae consequuntur? Unde dicta, non + inventore magni at rem, debitis et molestiae officia obcaecati expedita + suscipit est fugiat deserunt, beatae hic? Lorem ipsum dolor sit amet + consectetur adipisicing elit. Molestiae recusandae facilis iure, ipsum + excepturi voluptates amet libero explicabo! Mollitia magni consequuntur + perspiciatis consectetur officiis cum. Illum exercitationem eveniet + dolorum maiores. Lorem ipsum dolor sit amet, consectetur adipisicing + elit. Amet commodi molestiae veritatis ad suscipit at, eos sapiente + illum laborum ipsum, unde reiciendis, praesentium temporibus officia + optio nemo dolorum magni tempora. Lorem ipsum dolor sit amet consectetur + adipisicing elit. Fuga, consectetur laborum? Impedit deserunt dolor qui + eligendi aspernatur magnam ratione at inventore, placeat est. Commodi + nobis tenetur suscipit cupiditate ipsum excepturi. Lorem ipsum dolor sit + amet consectetur adipisicing elit. Vitae illum, explicabo maxime placeat + aliquam quos, harum aliquid aspernatur officia ullam voluptatum beatae? + Fugit laborum in recusandae eius tempore ab quasi. Lorem ipsum dolor sit + amet consectetur adipisicing elit. Doloremque vel, sequi laborum fugit + et libero facilis officiis, fuga dolorem iste ea in iusto at, + repellendus facere. Facilis voluptatibus error illum? Lorem ipsum dolor + sit amet consectetur, adipisicing elit. Officiis eveniet, facilis aut + neque, aliquam ullam amet consequuntur numquam asperiores ducimus ab, + explicabo iure? Aliquid numquam ab excepturi facere dolores illum. Lorem + ipsum dolor sit, amet consectetur adipisicing elit. Fugit, quae + consequuntur? Unde dicta, non inventore magni at rem, debitis et + molestiae officia obcaecati expedita suscipit est fugiat deserunt, + beatae hic? Lorem ipsum dolor sit amet consectetur adipisicing elit. + Molestiae recusandae facilis iure, ipsum excepturi voluptates amet + libero explicabo! Mollitia magni consequuntur perspiciatis consectetur + officiis cum. Illum exercitationem eveniet dolorum maiores. Lorem ipsum + dolor sit amet, consectetur adipisicing elit. Amet commodi molestiae + veritatis ad suscipit at, eos sapiente illum laborum ipsum, unde + reiciendis, praesentium temporibus officia optio nemo dolorum magni + tempora. Lorem ipsum dolor sit amet consectetur adipisicing elit. Fuga, + consectetur laborum? Impedit deserunt dolor qui eligendi aspernatur + magnam ratione at inventore, placeat est. Commodi nobis tenetur suscipit + cupiditate ipsum excepturi. Lorem ipsum dolor sit amet consectetur + adipisicing elit. Vitae illum, explicabo maxime placeat aliquam quos, + harum aliquid aspernatur officia ullam voluptatum beatae? Fugit laborum + in recusandae eius tempore ab quasi. Lorem ipsum dolor sit amet + consectetur adipisicing elit. Doloremque vel, sequi laborum fugit et + libero facilis officiis, fuga dolorem iste ea in iusto at, repellendus + facere. Facilis voluptatibus error illum? Lorem ipsum dolor sit amet + consectetur, adipisicing elit. Officiis eveniet, facilis aut neque, + aliquam ullam amet consequuntur numquam asperiores ducimus ab, explicabo + iure? Aliquid numquam ab excepturi facere dolores illum. Lorem ipsum + dolor sit, amet consectetur adipisicing elit. Fugit, quae consequuntur? + Unde dicta, non inventore magni at rem, debitis et molestiae officia + obcaecati expedita suscipit est fugiat deserunt, beatae hic? Lorem ipsum + dolor sit amet consectetur adipisicing elit. Molestiae recusandae + facilis iure, ipsum excepturi voluptates amet libero explicabo! Mollitia + magni consequuntur perspiciatis consectetur officiis cum. Illum + exercitationem eveniet dolorum maiores. Lorem ipsum dolor sit amet, + consectetur adipisicing elit. Amet commodi molestiae veritatis ad + suscipit at, eos sapiente illum laborum ipsum, unde reiciendis, + praesentium temporibus officia optio nemo dolorum magni tempora. Lorem + ipsum dolor sit amet consectetur adipisicing elit. Fuga, consectetur + laborum? Impedit deserunt dolor qui eligendi aspernatur magnam ratione + at inventore, placeat est. Commodi nobis tenetur suscipit cupiditate + ipsum excepturi. Lorem ipsum dolor sit amet consectetur adipisicing + elit. Vitae illum, explicabo maxime placeat aliquam quos, harum aliquid + aspernatur officia ullam voluptatum beatae? Fugit laborum in recusandae + eius tempore ab quasi. Lorem ipsum dolor sit amet consectetur + adipisicing elit. Doloremque vel, sequi laborum fugit et libero facilis + officiis, fuga dolorem iste ea in iusto at, repellendus facere. Facilis + voluptatibus error illum? Lorem ipsum dolor sit amet consectetur, + adipisicing elit. Officiis eveniet, facilis aut neque, aliquam ullam + amet consequuntur numquam asperiores ducimus ab, explicabo iure? Aliquid + numquam ab excepturi facere dolores illum. Lorem ipsum dolor sit, amet + consectetur adipisicing elit. Fugit, quae consequuntur? Unde dicta, non + inventore magni at rem, debitis et molestiae officia obcaecati expedita + suscipit est fugiat deserunt, beatae hic? Lorem ipsum dolor sit amet + consectetur adipisicing elit. Molestiae recusandae facilis iure, ipsum + excepturi voluptates amet libero explicabo! Mollitia magni consequuntur + perspiciatis consectetur officiis cum. Illum exercitationem eveniet + dolorum maiores. Lorem ipsum dolor sit amet, consectetur adipisicing + elit. Amet commodi molestiae veritatis ad suscipit at, eos sapiente + illum laborum ipsum, unde reiciendis, praesentium temporibus officia + optio nemo dolorum magni tempora. Lorem ipsum dolor sit amet consectetur + adipisicing elit. Fuga, consectetur laborum? Impedit deserunt dolor qui + eligendi aspernatur magnam ratione at inventore, placeat est. Commodi + nobis tenetur suscipit cupiditate ipsum excepturi. Lorem ipsum dolor sit + amet consectetur adipisicing elit. Vitae illum, explicabo maxime placeat + aliquam quos, harum aliquid aspernatur officia ullam voluptatum beatae? + Fugit laborum in recusandae eius tempore ab quasi. Lorem ipsum dolor sit + amet consectetur adipisicing elit. Doloremque vel, sequi laborum fugit + et libero facilis officiis, fuga dolorem iste ea in iusto at, + repellendus facere. Facilis voluptatibus error illum? Lorem ipsum dolor + sit amet consectetur, adipisicing elit. Officiis eveniet, facilis aut + neque, aliquam ullam amet consequuntur numquam asperiores ducimus ab, + explicabo iure? Aliquid numquam ab excepturi facere dolores illum. Lorem + ipsum dolor sit, amet consectetur adipisicing elit. Fugit, quae + consequuntur? Unde dicta, non inventore magni at rem, debitis et + molestiae officia obcaecati expedita suscipit est fugiat deserunt, + beatae hic? Lorem ipsum dolor sit amet consectetur adipisicing elit. + Molestiae recusandae facilis iure, ipsum excepturi voluptates amet + libero explicabo! Mollitia magni consequuntur perspiciatis consectetur + officiis cum. Illum exercitationem eveniet dolorum maiores. Lorem ipsum + dolor sit amet, consectetur adipisicing elit. Amet commodi molestiae + veritatis ad suscipit at, eos sapiente illum laborum ipsum, unde + reiciendis, praesentium temporibus officia optio nemo dolorum magni + tempora. Lorem ipsum dolor sit amet consectetur adipisicing elit. Fuga, + consectetur laborum? Impedit deserunt dolor qui eligendi aspernatur + magnam ratione at inventore, placeat est. Commodi nobis tenetur suscipit + cupiditate ipsum excepturi. Lorem ipsum dolor sit amet consectetur + adipisicing elit. Vitae illum, explicabo maxime placeat aliquam quos, + harum aliquid aspernatur officia ullam voluptatum beatae? Fugit laborum + in recusandae eius tempore ab quasi. Lorem ipsum dolor sit amet + consectetur adipisicing elit. Doloremque vel, sequi laborum fugit et + libero facilis officiis, fuga dolorem iste ea in iusto at, repellendus + facere. Facilis voluptatibus error illum? Lorem ipsum dolor sit amet + consectetur, adipisicing elit. Officiis eveniet, facilis aut neque, + aliquam ullam amet consequuntur numquam asperiores ducimus ab, explicabo + iure? Aliquid numquam ab excepturi facere dolores illum. Lorem ipsum + dolor sit, amet consectetur adipisicing elit. Fugit, quae consequuntur? + Unde dicta, non inventore magni at rem, debitis et molestiae officia + obcaecati expedita suscipit est fugiat deserunt, beatae hic? Lorem ipsum + dolor sit amet consectetur adipisicing elit. Molestiae recusandae + facilis iure, ipsum excepturi voluptates amet libero explicabo! Mollitia + magni consequuntur perspiciatis consectetur officiis cum. Illum + exercitationem eveniet dolorum maiores. Lorem ipsum dolor sit amet, + consectetur adipisicing elit. Amet commodi molestiae veritatis ad + suscipit at, eos sapiente illum laborum ipsum, unde reiciendis, + praesentium temporibus officia optio nemo dolorum magni tempora. Lorem + ipsum dolor sit amet consectetur adipisicing elit. Fuga, consectetur + laborum? Impedit deserunt dolor qui eligendi aspernatur magnam ratione + at inventore, placeat est. Commodi nobis tenetur suscipit cupiditate + ipsum excepturi. Lorem ipsum dolor sit amet consectetur adipisicing + elit. Vitae illum, explicabo maxime placeat aliquam quos, harum aliquid + aspernatur officia ullam voluptatum beatae? Fugit laborum in recusandae + eius tempore ab quasi. Lorem ipsum dolor sit amet consectetur + adipisicing elit. Doloremque vel, sequi laborum fugit et libero facilis + officiis, fuga dolorem iste ea in iusto at, repellendus facere. Facilis + voluptatibus error illum? Lorem ipsum dolor sit amet consectetur, + adipisicing elit. Officiis eveniet, facilis aut neque, aliquam ullam + amet consequuntur numquam asperiores ducimus ab, explicabo iure? Aliquid + numquam ab excepturi facere dolores illum. Lorem ipsum dolor sit, amet + consectetur adipisicing elit. Fugit, quae consequuntur? Unde dicta, non + inventore magni at rem, debitis et molestiae officia obcaecati expedita + suscipit est fugiat deserunt, beatae hic? Lorem ipsum dolor sit amet + consectetur adipisicing elit. Molestiae recusandae facilis iure, ipsum + excepturi voluptates amet libero explicabo! Mollitia magni consequuntur + perspiciatis consectetur officiis cum. Illum exercitationem eveniet + dolorum maiores. Lorem ipsum dolor sit amet, consectetur adipisicing + elit. Amet commodi molestiae veritatis ad suscipit at, eos sapiente + illum laborum ipsum, unde reiciendis, praesentium temporibus officia + optio nemo dolorum magni tempora. Lorem ipsum dolor sit amet consectetur + adipisicing elit. Fuga, consectetur laborum? Impedit deserunt dolor qui + eligendi aspernatur magnam ratione at inventore, placeat est. Commodi + nobis tenetur suscipit cupiditate ipsum excepturi. Lorem ipsum dolor sit + amet consectetur adipisicing elit. Vitae illum, explicabo maxime placeat + aliquam quos, harum aliquid aspernatur officia ullam voluptatum beatae? + Fugit laborum in recusandae eius tempore ab quasi. Lorem ipsum dolor sit + amet consectetur adipisicing elit. Doloremque vel, sequi laborum fugit + et libero facilis officiis, fuga dolorem iste ea in iusto at, + repellendus facere. Facilis voluptatibus error illum? Lorem ipsum dolor + sit amet consectetur, adipisicing elit. Officiis eveniet, facilis aut + neque, aliquam ullam amet consequuntur numquam asperiores ducimus ab, + explicabo iure? Aliquid numquam ab excepturi facere dolores illum. Lorem + ipsum dolor sit, amet consectetur adipisicing elit. Fugit, quae + consequuntur? Unde dicta, non inventore magni at rem, debitis et + molestiae officia obcaecati expedita suscipit est fugiat deserunt, + beatae hic? Lorem ipsum dolor sit amet consectetur adipisicing elit. + Molestiae recusandae facilis iure, ipsum excepturi voluptates amet + libero explicabo! Mollitia magni consequuntur perspiciatis consectetur + officiis cum. Illum exercitationem eveniet dolorum maiores. Lorem ipsum + dolor sit amet, consectetur adipisicing elit. Amet commodi molestiae + veritatis ad suscipit at, eos sapiente illum laborum ipsum, unde + reiciendis, praesentium temporibus officia optio nemo dolorum magni + tempora. Lorem ipsum dolor sit amet consectetur adipisicing elit. Fuga, + consectetur laborum? Impedit deserunt dolor qui eligendi aspernatur + magnam ratione at inventore, placeat est. Commodi nobis tenetur suscipit + cupiditate ipsum excepturi. Lorem ipsum dolor sit amet consectetur + adipisicing elit. Vitae illum, explicabo maxime placeat aliquam quos, + harum aliquid aspernatur officia ullam voluptatum beatae? Fugit laborum + in recusandae eius tempore ab quasi. Lorem ipsum dolor sit amet + consectetur adipisicing elit. Doloremque vel, sequi laborum fugit et + libero facilis officiis, fuga dolorem iste ea in iusto at, repellendus + facere. Facilis voluptatibus error illum? Lorem ipsum dolor sit amet + consectetur, adipisicing elit. Officiis eveniet, facilis aut neque, + aliquam ullam amet consequuntur numquam asperiores ducimus ab, explicabo + iure? Aliquid numquam ab excepturi facere dolores illum. Lorem ipsum + dolor sit, amet consectetur adipisicing elit. Fugit, quae consequuntur? + Unde dicta, non inventore magni at rem, debitis et molestiae officia + obcaecati expedita suscipit est fugiat deserunt, beatae hic? Lorem ipsum + dolor sit amet consectetur adipisicing elit. Molestiae recusandae + facilis iure, ipsum excepturi voluptates amet libero explicabo! Mollitia + magni consequuntur perspiciatis consectetur officiis cum. Illum + exercitationem eveniet dolorum maiores. Lorem ipsum dolor sit amet, + consectetur adipisicing elit. Amet commodi molestiae veritatis ad + suscipit at, eos sapiente illum laborum ipsum, unde reiciendis, + praesentium temporibus officia optio nemo dolorum magni tempora. Lorem + ipsum dolor sit amet consectetur adipisicing elit. Fuga, consectetur + laborum? Impedit deserunt dolor qui eligendi aspernatur magnam ratione + at inventore, placeat est. Commodi nobis tenetur suscipit cupiditate + ipsum excepturi. Lorem ipsum dolor sit amet consectetur adipisicing + elit. Vitae illum, explicabo maxime placeat aliquam quos, harum aliquid + aspernatur officia ullam voluptatum beatae? Fugit laborum in recusandae + eius tempore ab quasi. Lorem ipsum dolor sit amet consectetur + adipisicing elit. Doloremque vel, sequi laborum fugit et libero facilis + officiis, fuga dolorem iste ea in iusto at, repellendus facere. Facilis + voluptatibus error illum? Lorem ipsum dolor sit amet consectetur, + adipisicing elit. Officiis eveniet, facilis aut neque, aliquam ullam + amet consequuntur numquam asperiores ducimus ab, explicabo iure? Aliquid + numquam ab excepturi facere dolores illum. Lorem ipsum dolor sit, amet + consectetur adipisicing elit. Fugit, quae consequuntur? Unde dicta, non + inventore magni at rem, debitis et molestiae officia obcaecati expedita + suscipit est fugiat deserunt, beatae hic? Lorem ipsum dolor sit amet + consectetur adipisicing elit. Molestiae recusandae facilis iure, ipsum + excepturi voluptates amet libero explicabo! Mollitia magni consequuntur + perspiciatis consectetur officiis cum. Illum exercitationem eveniet + dolorum maiores. Lorem ipsum dolor sit amet, consectetur adipisicing + elit. Amet commodi molestiae veritatis ad suscipit at, eos sapiente + illum laborum ipsum, unde reiciendis, praesentium temporibus officia + optio nemo dolorum magni tempora. Lorem ipsum dolor sit amet consectetur + adipisicing elit. Fuga, consectetur laborum? Impedit deserunt dolor qui + eligendi aspernatur magnam ratione at inventore, placeat est. Commodi + nobis tenetur suscipit cupiditate ipsum excepturi. Lorem ipsum dolor sit + amet consectetur adipisicing elit. Vitae illum, explicabo maxime placeat + aliquam quos, harum aliquid aspernatur officia ullam voluptatum beatae? + Fugit laborum in recusandae eius tempore ab quasi. Lorem ipsum dolor sit + amet consectetur adipisicing elit. Doloremque vel, sequi laborum fugit + et libero facilis officiis, fuga dolorem iste ea in iusto at, + repellendus facere. Facilis voluptatibus error illum? Lorem ipsum dolor + sit amet consectetur, adipisicing elit. Officiis eveniet, facilis aut + neque, aliquam ullam amet consequuntur numquam asperiores ducimus ab, + explicabo iure? Aliquid numquam ab excepturi facere dolores illum. Lorem + ipsum dolor sit, amet consectetur adipisicing elit. Fugit, quae + consequuntur? Unde dicta, non inventore magni at rem, debitis et + molestiae officia obcaecati expedita suscipit est fugiat deserunt, + beatae hic? Lorem ipsum dolor sit amet consectetur adipisicing elit. + Molestiae recusandae facilis iure, ipsum excepturi voluptates amet + libero explicabo! Mollitia magni consequuntur perspiciatis consectetur + officiis cum. Illum exercitationem eveniet dolorum maiores. Lorem ipsum + dolor sit amet, consectetur adipisicing elit. Amet commodi molestiae + veritatis ad suscipit at, eos sapiente illum laborum ipsum, unde + reiciendis, praesentium temporibus officia optio nemo dolorum magni + tempora. Lorem ipsum dolor sit amet consectetur adipisicing elit. Fuga, + consectetur laborum? Impedit deserunt dolor qui eligendi aspernatur + magnam ratione at inventore, placeat est. Commodi nobis tenetur suscipit + cupiditate ipsum excepturi. Lorem ipsum dolor sit amet consectetur + adipisicing elit. Vitae illum, explicabo maxime placeat aliquam quos, + harum aliquid aspernatur officia ullam voluptatum beatae? Fugit laborum + in recusandae eius tempore ab quasi. Lorem ipsum dolor sit amet + consectetur adipisicing elit. Doloremque vel, sequi laborum fugit et + libero facilis officiis, fuga dolorem iste ea in iusto at, repellendus + facere. Facilis voluptatibus error illum? Lorem ipsum dolor sit amet + consectetur, adipisicing elit. Officiis eveniet, facilis aut neque, + aliquam ullam amet consequuntur numquam asperiores ducimus ab, explicabo + iure? Aliquid numquam ab excepturi facere dolores illum. Lorem ipsum + dolor sit, amet consectetur adipisicing elit. Fugit, quae consequuntur? + Unde dicta, non inventore magni at rem, debitis et molestiae officia + obcaecati expedita suscipit est fugiat deserunt, beatae hic? Lorem ipsum + dolor sit amet consectetur adipisicing elit. Molestiae recusandae + facilis iure, ipsum excepturi voluptates amet libero explicabo! Mollitia + magni consequuntur perspiciatis consectetur officiis cum. Illum + exercitationem eveniet dolorum maiores. Lorem ipsum dolor sit amet, + consectetur adipisicing elit. Amet commodi molestiae veritatis ad + suscipit at, eos sapiente illum laborum ipsum, unde reiciendis, + praesentium temporibus officia optio nemo dolorum magni tempora. Lorem + ipsum dolor sit amet consectetur adipisicing elit. Fuga, consectetur + laborum? Impedit deserunt dolor qui eligendi aspernatur magnam ratione + at inventore, placeat est. Commodi nobis tenetur suscipit cupiditate + ipsum excepturi. Lorem ipsum dolor sit amet consectetur adipisicing + elit. Vitae illum, explicabo maxime placeat aliquam quos, harum aliquid + aspernatur officia ullam voluptatum beatae? Fugit laborum in recusandae + eius tempore ab quasi. Lorem ipsum dolor sit amet consectetur + adipisicing elit. Doloremque vel, sequi laborum fugit et libero facilis + officiis, fuga dolorem iste ea in iusto at, repellendus facere. Facilis + voluptatibus error illum? Lorem ipsum dolor sit amet consectetur, + adipisicing elit. Officiis eveniet, facilis aut neque, aliquam ullam + amet consequuntur numquam asperiores ducimus ab, explicabo iure? Aliquid + numquam ab excepturi facere dolores illum. Lorem ipsum dolor sit, amet + consectetur adipisicing elit. Fugit, quae consequuntur? Unde dicta, non + inventore magni at rem, debitis et molestiae officia obcaecati expedita + suscipit est fugiat deserunt, beatae hic? Lorem ipsum dolor sit amet + consectetur adipisicing elit. Molestiae recusandae facilis iure, ipsum + excepturi voluptates amet libero explicabo! Mollitia magni consequuntur + perspiciatis consectetur officiis cum. Illum exercitationem eveniet + dolorum maiores. Lorem ipsum dolor sit amet, consectetur adipisicing + elit. Amet commodi molestiae veritatis ad suscipit at, eos sapiente + illum laborum ipsum, unde reiciendis, praesentium temporibus officia + optio nemo dolorum magni tempora. Lorem ipsum dolor sit amet consectetur + adipisicing elit. Fuga, consectetur laborum? Impedit deserunt dolor qui + eligendi aspernatur magnam ratione at inventore, placeat est. Commodi + nobis tenetur suscipit cupiditate ipsum excepturi. Lorem ipsum dolor sit + amet consectetur adipisicing elit. Vitae illum, explicabo maxime placeat + aliquam quos, harum aliquid aspernatur officia ullam voluptatum beatae? + Fugit laborum in recusandae eius tempore ab quasi. Lorem ipsum dolor sit + amet consectetur adipisicing elit. Doloremque vel, sequi laborum fugit + et libero facilis officiis, fuga dolorem iste ea in iusto at, + repellendus facere. Facilis voluptatibus error illum? Lorem ipsum dolor + sit amet consectetur, adipisicing elit. Officiis eveniet, facilis aut + neque, aliquam ullam amet consequuntur numquam asperiores ducimus ab, + explicabo iure? Aliquid numquam ab excepturi facere dolores illum. Lorem + ipsum dolor sit, amet consectetur adipisicing elit. Fugit, quae + consequuntur? Unde dicta, non inventore magni at rem, debitis et + molestiae officia obcaecati expedita suscipit est fugiat deserunt, + beatae hic? Lorem ipsum dolor sit amet consectetur adipisicing elit. + Molestiae recusandae facilis iure, ipsum excepturi voluptates amet + libero explicabo! Mollitia magni consequuntur perspiciatis consectetur + officiis cum. Illum exercitationem eveniet dolorum maiores. Lorem ipsum + dolor sit amet, consectetur adipisicing elit. Amet commodi molestiae + veritatis ad suscipit at, eos sapiente illum laborum ipsum, unde + reiciendis, praesentium temporibus officia optio nemo dolorum magni + tempora. Lorem ipsum dolor sit amet consectetur adipisicing elit. Fuga, + consectetur laborum? Impedit deserunt dolor qui eligendi aspernatur + magnam ratione at inventore, placeat est. Commodi nobis tenetur suscipit + cupiditate ipsum excepturi. Lorem ipsum dolor sit amet consectetur + adipisicing elit. Vitae illum, explicabo maxime placeat aliquam quos, + harum aliquid aspernatur officia ullam voluptatum beatae? Fugit laborum + in recusandae eius tempore ab quasi. Lorem ipsum dolor sit amet + consectetur adipisicing elit. Doloremque vel, sequi laborum fugit et + libero facilis officiis, fuga dolorem iste ea in iusto at, repellendus + facere. Facilis voluptatibus error illum? Lorem ipsum dolor sit amet + consectetur, adipisicing elit. Officiis eveniet, facilis aut neque, + aliquam ullam amet consequuntur numquam asperiores ducimus ab, explicabo + iure? Aliquid numquam ab excepturi facere dolores illum. Lorem ipsum + dolor sit, amet consectetur adipisicing elit. Fugit, quae consequuntur? + Unde dicta, non inventore magni at rem, debitis et molestiae officia + obcaecati expedita suscipit est fugiat deserunt, beatae hic? Lorem ipsum + dolor sit amet consectetur adipisicing elit. Molestiae recusandae + facilis iure, ipsum excepturi voluptates amet libero explicabo! Mollitia + magni consequuntur perspiciatis consectetur officiis cum. Illum + exercitationem eveniet dolorum maiores. Lorem ipsum dolor sit amet, + consectetur adipisicing elit. Amet commodi molestiae veritatis ad + suscipit at, eos sapiente illum laborum ipsum, unde reiciendis, + praesentium temporibus officia optio nemo dolorum magni tempora. Lorem + ipsum dolor sit amet consectetur adipisicing elit. Fuga, consectetur + laborum? Impedit deserunt dolor qui eligendi aspernatur magnam ratione + at inventore, placeat est. Commodi nobis tenetur suscipit cupiditate + ipsum excepturi. Lorem ipsum dolor sit amet consectetur adipisicing + elit. Vitae illum, explicabo maxime placeat aliquam quos, harum aliquid + aspernatur officia ullam voluptatum beatae? Fugit laborum in recusandae + eius tempore ab quasi. Lorem ipsum dolor sit amet consectetur + adipisicing elit. Doloremque vel, sequi laborum fugit et libero facilis + officiis, fuga dolorem iste ea in iusto at, repellendus facere. Facilis + voluptatibus error illum? Lorem ipsum dolor sit amet consectetur, + adipisicing elit. Officiis eveniet, facilis aut neque, aliquam ullam + amet consequuntur numquam asperiores ducimus ab, explicabo iure? Aliquid + numquam ab excepturi facere dolores illum. Lorem ipsum dolor sit, amet + consectetur adipisicing elit. Fugit, quae consequuntur? Unde dicta, non + inventore magni at rem, debitis et molestiae officia obcaecati expedita + suscipit est fugiat deserunt, beatae hic? Lorem ipsum dolor sit amet + consectetur adipisicing elit. Molestiae recusandae facilis iure, ipsum + excepturi voluptates amet libero explicabo! Mollitia magni consequuntur + perspiciatis consectetur officiis cum. Illum exercitationem eveniet + dolorum maiores. Lorem ipsum dolor sit amet, consectetur adipisicing + elit. Amet commodi molestiae veritatis ad suscipit at, eos sapiente + illum laborum ipsum, unde reiciendis, praesentium temporibus officia + optio nemo dolorum magni tempora. Lorem ipsum dolor sit amet consectetur + adipisicing elit. Fuga, consectetur laborum? Impedit deserunt dolor qui + eligendi aspernatur magnam ratione at inventore, placeat est. Commodi + nobis tenetur suscipit cupiditate ipsum excepturi. Lorem ipsum dolor sit + amet consectetur adipisicing elit. Vitae illum, explicabo maxime placeat + aliquam quos, harum aliquid aspernatur officia ullam voluptatum beatae? + Fugit laborum in recusandae eius tempore ab quasi. Lorem ipsum dolor sit + amet consectetur adipisicing elit. Doloremque vel, sequi laborum fugit + et libero facilis officiis, fuga dolorem iste ea in iusto at, + repellendus facere. Facilis voluptatibus error illum? Lorem ipsum dolor + sit amet consectetur, adipisicing elit. Officiis eveniet, facilis aut + neque, aliquam ullam amet consequuntur numquam asperiores ducimus ab, + explicabo iure? Aliquid numquam ab excepturi facere dolores illum. Lorem + ipsum dolor sit, amet consectetur adipisicing elit. Fugit, quae + consequuntur? Unde dicta, non inventore magni at rem, debitis et + molestiae officia obcaecati expedita suscipit est fugiat deserunt, + beatae hic? Lorem ipsum dolor sit amet consectetur adipisicing elit. + Molestiae recusandae facilis iure, ipsum excepturi voluptates amet + libero explicabo! Mollitia magni consequuntur perspiciatis consectetur + officiis cum. Illum exercitationem eveniet dolorum maiores. Lorem ipsum + dolor sit amet, consectetur adipisicing elit. Amet commodi molestiae + veritatis ad suscipit at, eos sapiente illum laborum ipsum, unde + reiciendis, praesentium temporibus officia optio nemo dolorum magni + tempora. Lorem ipsum dolor sit amet consectetur adipisicing elit. Fuga, + consectetur laborum? Impedit deserunt dolor qui eligendi aspernatur + magnam ratione at inventore, placeat est. Commodi nobis tenetur suscipit + cupiditate ipsum excepturi. Lorem ipsum dolor sit amet consectetur + adipisicing elit. Vitae illum, explicabo maxime placeat aliquam quos, + harum aliquid aspernatur officia ullam voluptatum beatae? Fugit laborum + in recusandae eius tempore ab quasi. Lorem ipsum dolor sit amet + consectetur adipisicing elit. Doloremque vel, sequi laborum fugit et + libero facilis officiis, fuga dolorem iste ea in iusto at, repellendus + facere. Facilis voluptatibus error illum? Lorem ipsum dolor sit amet + consectetur, adipisicing elit. Officiis eveniet, facilis aut neque, + aliquam ullam amet consequuntur numquam asperiores ducimus ab, explicabo + iure? Aliquid numquam ab excepturi facere dolores illum. Lorem ipsum + dolor sit, amet consectetur adipisicing elit. Fugit, quae consequuntur? + Unde dicta, non inventore magni at rem, debitis et molestiae officia + obcaecati expedita suscipit est fugiat deserunt, beatae hic? Lorem ipsum + dolor sit amet consectetur adipisicing elit. Molestiae recusandae + facilis iure, ipsum excepturi voluptates amet libero explicabo! Mollitia + magni consequuntur perspiciatis consectetur officiis cum. Illum + exercitationem eveniet dolorum maiores. Lorem ipsum dolor sit amet, + consectetur adipisicing elit. Amet commodi molestiae veritatis ad + suscipit at, eos sapiente illum laborum ipsum, unde reiciendis, + praesentium temporibus officia optio nemo dolorum magni tempora. Lorem + ipsum dolor sit amet consectetur adipisicing elit. Fuga, consectetur + laborum? Impedit deserunt dolor qui eligendi aspernatur magnam ratione + at inventore, placeat est. Commodi nobis tenetur suscipit cupiditate + ipsum excepturi. Lorem ipsum dolor sit amet consectetur adipisicing + elit. Vitae illum, explicabo maxime placeat aliquam quos, harum aliquid + aspernatur officia ullam voluptatum beatae? Fugit laborum in recusandae + eius tempore ab quasi. Lorem ipsum dolor sit amet consectetur + adipisicing elit. Doloremque vel, sequi laborum fugit et libero facilis + officiis, fuga dolorem iste ea in iusto at, repellendus facere. Facilis + voluptatibus error illum? Lorem ipsum dolor sit amet consectetur, + adipisicing elit. Officiis eveniet, facilis aut neque, aliquam ullam + amet consequuntur numquam asperiores ducimus ab, explicabo iure? Aliquid + numquam ab excepturi facere dolores illum. Lorem ipsum dolor sit, amet + consectetur adipisicing elit. Fugit, quae consequuntur? Unde dicta, non + inventore magni at rem, debitis et molestiae officia obcaecati expedita + suscipit est fugiat deserunt, beatae hic? Lorem ipsum dolor sit amet + consectetur adipisicing elit. Molestiae recusandae facilis iure, ipsum + excepturi voluptates amet libero explicabo! Mollitia magni consequuntur + perspiciatis consectetur officiis cum. Illum exercitationem eveniet + dolorum maiores. Lorem ipsum dolor sit amet, consectetur adipisicing + elit. Amet commodi molestiae veritatis ad suscipit at, eos sapiente + illum laborum ipsum, unde reiciendis, praesentium temporibus officia + optio nemo dolorum magni tempora. Lorem ipsum dolor sit amet consectetur + adipisicing elit. Fuga, consectetur laborum? Impedit deserunt dolor qui + eligendi aspernatur magnam ratione at inventore, placeat est. Commodi + nobis tenetur suscipit cupiditate ipsum excepturi. Lorem ipsum dolor sit + amet consectetur adipisicing elit. Vitae illum, explicabo maxime placeat + aliquam quos, harum aliquid aspernatur officia ullam voluptatum beatae? + Fugit laborum in recusandae eius tempore ab quasi. Lorem ipsum dolor sit + amet consectetur adipisicing elit. Doloremque vel, sequi laborum fugit + et libero facilis officiis, fuga dolorem iste ea in iusto at, + repellendus facere. Facilis voluptatibus error illum? Lorem ipsum dolor + sit amet consectetur, adipisicing elit. Officiis eveniet, facilis aut + neque, aliquam ullam amet consequuntur numquam asperiores ducimus ab, + explicabo iure? Aliquid numquam ab excepturi facere dolores illum. Lorem + ipsum dolor sit, amet consectetur adipisicing elit. Fugit, quae + consequuntur? Unde dicta, non inventore magni at rem, debitis et + molestiae officia obcaecati expedita suscipit est fugiat deserunt, + beatae hic? Lorem ipsum dolor sit amet consectetur adipisicing elit. + Molestiae recusandae facilis iure, ipsum excepturi voluptates amet + libero explicabo! Mollitia magni consequuntur perspiciatis consectetur + officiis cum. Illum exercitationem eveniet dolorum maiores. Lorem ipsum + dolor sit amet, consectetur adipisicing elit. Amet commodi molestiae + veritatis ad suscipit at, eos sapiente illum laborum ipsum, unde + reiciendis, praesentium temporibus officia optio nemo dolorum magni + tempora. Lorem ipsum dolor sit amet consectetur adipisicing elit. Fuga, + consectetur laborum? Impedit deserunt dolor qui eligendi aspernatur + magnam ratione at inventore, placeat est. Commodi nobis tenetur suscipit + cupiditate ipsum excepturi. Lorem ipsum dolor sit amet consectetur + adipisicing elit. Vitae illum, explicabo maxime placeat aliquam quos, + harum aliquid aspernatur officia ullam voluptatum beatae? Fugit laborum + in recusandae eius tempore ab quasi. Lorem ipsum dolor sit amet + consectetur adipisicing elit. Doloremque vel, sequi laborum fugit et + libero facilis officiis, fuga dolorem iste ea in iusto at, repellendus + facere. Facilis voluptatibus error illum? Lorem ipsum dolor sit amet + consectetur, adipisicing elit. Officiis eveniet, facilis aut neque, + aliquam ullam amet consequuntur numquam asperiores ducimus ab, explicabo + iure? Aliquid numquam ab excepturi facere dolores illum. Lorem ipsum + dolor sit, amet consectetur adipisicing elit. Fugit, quae consequuntur? + Unde dicta, non inventore magni at rem, debitis et molestiae officia + obcaecati expedita suscipit est fugiat deserunt, beatae hic? Lorem ipsum + dolor sit amet consectetur adipisicing elit. Molestiae recusandae + facilis iure, ipsum excepturi voluptates amet libero explicabo! Mollitia + magni consequuntur perspiciatis consectetur officiis cum. Illum + exercitationem eveniet dolorum maiores. Lorem ipsum dolor sit amet, + consectetur adipisicing elit. Amet commodi molestiae veritatis ad + suscipit at, eos sapiente illum laborum ipsum, unde reiciendis, + praesentium temporibus officia optio nemo dolorum magni tempora. Lorem + ipsum dolor sit amet consectetur adipisicing elit. Fuga, consectetur + laborum? Impedit deserunt dolor qui eligendi aspernatur magnam ratione + at inventore, placeat est. Commodi nobis tenetur suscipit cupiditate + ipsum excepturi. Lorem ipsum dolor sit amet consectetur adipisicing + elit. Vitae illum, explicabo maxime placeat aliquam quos, harum aliquid + aspernatur officia ullam voluptatum beatae? Fugit laborum in recusandae + eius tempore ab quasi. Lorem ipsum dolor sit amet consectetur + adipisicing elit. Doloremque vel, sequi laborum fugit et libero facilis + officiis, fuga dolorem iste ea in iusto at, repellendus facere. Facilis + voluptatibus error illum? Lorem ipsum dolor sit amet consectetur, + adipisicing elit. Officiis eveniet, facilis aut neque, aliquam ullam + amet consequuntur numquam asperiores ducimus ab, explicabo iure? Aliquid + numquam ab excepturi facere dolores illum. Lorem ipsum dolor sit, amet + consectetur adipisicing elit. Fugit, quae consequuntur? Unde dicta, non + inventore magni at rem, debitis et molestiae officia obcaecati expedita + suscipit est fugiat deserunt, beatae hic? Lorem ipsum dolor sit amet + consectetur adipisicing elit. Molestiae recusandae facilis iure, ipsum + excepturi voluptates amet libero explicabo! Mollitia magni consequuntur + perspiciatis consectetur officiis cum. Illum exercitationem eveniet + dolorum maiores. Lorem ipsum dolor sit amet, consectetur adipisicing + elit. Amet commodi molestiae veritatis ad suscipit at, eos sapiente + illum laborum ipsum, unde reiciendis, praesentium temporibus officia + optio nemo dolorum magni tempora. Lorem ipsum dolor sit amet consectetur + adipisicing elit. Fuga, consectetur laborum? Impedit deserunt dolor qui + eligendi aspernatur magnam ratione at inventore, placeat est. Commodi + nobis tenetur suscipit cupiditate ipsum excepturi. Lorem ipsum dolor sit + amet consectetur adipisicing elit. Vitae illum, explicabo maxime placeat + aliquam quos, harum aliquid aspernatur officia ullam voluptatum beatae? + Fugit laborum in recusandae eius tempore ab quasi. Lorem ipsum dolor sit + amet consectetur adipisicing elit. Doloremque vel, sequi laborum fugit + et libero facilis officiis, fuga dolorem iste ea in iusto at, + repellendus facere. Facilis voluptatibus error illum? Lorem ipsum dolor + sit amet consectetur, adipisicing elit. Officiis eveniet, facilis aut + neque, aliquam ullam amet consequuntur numquam asperiores ducimus ab, + explicabo iure? Aliquid numquam ab excepturi facere dolores illum. Lorem + ipsum dolor sit, amet consectetur adipisicing elit. Fugit, quae + consequuntur? Unde dicta, non inventore magni at rem, debitis et + molestiae officia obcaecati expedita suscipit est fugiat deserunt, + beatae hic? Lorem ipsum dolor sit amet consectetur adipisicing elit. + Molestiae recusandae facilis iure, ipsum excepturi voluptates amet + libero explicabo! Mollitia magni consequuntur perspiciatis consectetur + officiis cum. Illum exercitationem eveniet dolorum maiores. Lorem ipsum + dolor sit amet, consectetur adipisicing elit. Amet commodi molestiae + veritatis ad suscipit at, eos sapiente illum laborum ipsum, unde + reiciendis, praesentium temporibus officia optio nemo dolorum magni + tempora. Lorem ipsum dolor sit amet consectetur adipisicing elit. Fuga, + consectetur laborum? Impedit deserunt dolor qui eligendi aspernatur + magnam ratione at inventore, placeat est. Commodi nobis tenetur suscipit + cupiditate ipsum excepturi. Lorem ipsum dolor sit amet consectetur + adipisicing elit. Vitae illum, explicabo maxime placeat aliquam quos, + harum aliquid aspernatur officia ullam voluptatum beatae? Fugit laborum + in recusandae eius tempore ab quasi. +

+
+ ); +} + +export default IndexPage; diff --git a/src/features/ServerPage/libs/ServerContext/Provider.tsx b/src/features/ServerPage/libs/ServerContext/Provider.tsx new file mode 100644 index 0000000..3247d9f --- /dev/null +++ b/src/features/ServerPage/libs/ServerContext/Provider.tsx @@ -0,0 +1,57 @@ +import React from 'react'; +import { useParams } from 'react-router-dom'; +import { useQuery } from '@apollo/client'; +import { SERVERS } from './queries'; +import Context from './context'; +import extractVersionCodeFromHostname from '@utils/extractVersionCodeFromHostname'; +import { Params, ServerList } from './types'; + +import NotFoundPage from '@features/NotFoundPage/NotFoundPage'; +import Spinner from '@common/Spinner/Spinner'; + +export interface Props { + children: React.ReactNode; +} + +function Provider({ children }: Props) { + const { key } = useParams(); + const { loading: loadingServers, data } = useQuery(SERVERS, { + fetchPolicy: 'cache-first', + variables: { + filter: { + limit: 1, + versionCode: [extractVersionCodeFromHostname(window.location.hostname)], + key: [key], + }, + }, + }); + const server = + data?.servers?.items && data.servers.items.length > 0 + ? data.servers.items[0] + : undefined; + const loading = loadingServers && !server; + + if (loading) { + return ( + + ); + } + + if (!server) { + return ; + } + + return {children}; +} + +export default Provider; diff --git a/src/features/ServerPage/libs/ServerContext/context.ts b/src/features/ServerPage/libs/ServerContext/context.ts new file mode 100644 index 0000000..e266e69 --- /dev/null +++ b/src/features/ServerPage/libs/ServerContext/context.ts @@ -0,0 +1,16 @@ +import { createContext } from 'react'; +import { SERVER_STATUS } from '@config/app'; +import { Server } from './types'; + +const ctx = createContext({ + key: '', + numberOfPlayers: 0, + numberOfTribes: 0, + numberOfVillages: 0, + dataUpdatedAt: new Date(0), + historyUpdatedAt: new Date(0), + statsUpdatedAt: new Date(0), + status: SERVER_STATUS.OPEN, +}); + +export default ctx; diff --git a/src/features/ServerPage/libs/ServerContext/queries.ts b/src/features/ServerPage/libs/ServerContext/queries.ts new file mode 100644 index 0000000..5798cce --- /dev/null +++ b/src/features/ServerPage/libs/ServerContext/queries.ts @@ -0,0 +1,19 @@ +import { gql } from '@apollo/client'; + +export const SERVERS = gql` + query servers($filter: ServerFilter) { + servers(filter: $filter) { + total + items { + key + numberOfPlayers + numberOfTribes + numberOfVillages + status + dataUpdatedAt + historyUpdatedAt + statsUpdatedAt + } + } + } +`; diff --git a/src/features/ServerPage/libs/ServerContext/types.ts b/src/features/ServerPage/libs/ServerContext/types.ts new file mode 100644 index 0000000..41be22c --- /dev/null +++ b/src/features/ServerPage/libs/ServerContext/types.ts @@ -0,0 +1,21 @@ +import { List } from '@libs/graphql/types'; +import { ServerStatus } from '@config/app'; + +export type Server = { + key: string; + status: ServerStatus; + numberOfPlayers: number; + numberOfTribes: number; + numberOfVillages: number; + dataUpdatedAt: string | Date; + historyUpdatedAt: string | Date; + statsUpdatedAt: string | Date; +}; + +export type ServerList = { + servers?: List; +}; + +export type Params = { + key: string; +}; diff --git a/src/features/ServerPage/libs/ServerContext/useServer.ts b/src/features/ServerPage/libs/ServerContext/useServer.ts new file mode 100644 index 0000000..dff7678 --- /dev/null +++ b/src/features/ServerPage/libs/ServerContext/useServer.ts @@ -0,0 +1,9 @@ +import { useContext } from 'react'; +import ctx from './context'; +import { Server } from './types'; + +const useServer = (): Server => { + return useContext(ctx); +}; + +export default useServer; diff --git a/src/libs/date/format.ts b/src/libs/date/format.ts new file mode 100644 index 0000000..9c837f5 --- /dev/null +++ b/src/libs/date/format.ts @@ -0,0 +1,12 @@ +const format = (d: Date) => { + return d.toLocaleString(undefined, { + year: 'numeric', + month: '2-digit', + day: '2-digit', + hour: '2-digit', + minute: '2-digit', + second: '2-digit', + }); +}; + +export default format; diff --git a/src/libs/i18n/en/index.ts b/src/libs/i18n/en/index.ts index 1fab2cb..ce23654 100644 --- a/src/libs/i18n/en/index.ts +++ b/src/libs/i18n/en/index.ts @@ -2,11 +2,13 @@ import * as NAMESPACES from '@config/namespaces'; import common from './common'; import indexPage from './index-page'; import notFoundPage from './not-found-page'; +import serverPage from './server-page'; const translations = { [NAMESPACES.COMMON]: common, [NAMESPACES.INDEX_PAGE]: indexPage, [NAMESPACES.NOT_FOUND_PAGE]: notFoundPage, + ...serverPage, }; export default translations; diff --git a/src/libs/i18n/en/server-page/common.ts b/src/libs/i18n/en/server-page/common.ts new file mode 100644 index 0000000..ec4029a --- /dev/null +++ b/src/libs/i18n/en/server-page/common.ts @@ -0,0 +1,20 @@ +const translations = { + pageLayout: { + sidebar: { + routes: { + dashboard: 'Dashboard', + }, + serverInfo: { + numberOfPlayers: '{{num}} player', + numberOfPlayers_plural: '{{num}} players', + numberOfTribes: '{{num}} tribe', + numberOfTribes_plural: '{{num}} tribes', + numberOfVillages: '{{num}} village', + numberOfVillages_plural: '{{num}} villages', + dataUpdatedAt: 'The server data was updated {{date}}', + }, + }, + }, +}; + +export default translations; diff --git a/src/libs/i18n/en/server-page/index.ts b/src/libs/i18n/en/server-page/index.ts new file mode 100644 index 0000000..eacf4bb --- /dev/null +++ b/src/libs/i18n/en/server-page/index.ts @@ -0,0 +1,8 @@ +import * as NAMESPACES from '@config/namespaces'; +import common from './common'; + +const translations = { + [NAMESPACES.SERVER_PAGE.COMMON]: common, +}; + +export default translations; diff --git a/src/libs/i18n/pl/index.ts b/src/libs/i18n/pl/index.ts index 1fab2cb..ce23654 100644 --- a/src/libs/i18n/pl/index.ts +++ b/src/libs/i18n/pl/index.ts @@ -2,11 +2,13 @@ import * as NAMESPACES from '@config/namespaces'; import common from './common'; import indexPage from './index-page'; import notFoundPage from './not-found-page'; +import serverPage from './server-page'; const translations = { [NAMESPACES.COMMON]: common, [NAMESPACES.INDEX_PAGE]: indexPage, [NAMESPACES.NOT_FOUND_PAGE]: notFoundPage, + ...serverPage, }; export default translations; diff --git a/src/libs/i18n/pl/server-page/common.ts b/src/libs/i18n/pl/server-page/common.ts new file mode 100644 index 0000000..51e10b3 --- /dev/null +++ b/src/libs/i18n/pl/server-page/common.ts @@ -0,0 +1,23 @@ +const translations = { + pageLayout: { + sidebar: { + routes: { + dashboard: 'Dashboard', + }, + serverInfo: { + numberOfPlayers_0: '{{num}} gracz', + numberOfPlayers_1: '{{num}} graczy', + numberOfPlayers_2: '{{num}} graczy', + numberOfTribes_0: '{{num}} plemiÄ™', + numberOfTribes_1: '{{num}} plemiona', + numberOfTribes_2: '{{num}} plemion', + numberOfVillages_0: '{{num}} wioska', + numberOfVillages_1: '{{num}} wioski', + numberOfVillages_2: '{{num}} wiosek', + dataUpdatedAt: 'Dane ostatnio zaktualizowane {{date}}', + }, + }, + }, +}; + +export default translations; diff --git a/src/libs/i18n/pl/server-page/index.ts b/src/libs/i18n/pl/server-page/index.ts new file mode 100644 index 0000000..eacf4bb --- /dev/null +++ b/src/libs/i18n/pl/server-page/index.ts @@ -0,0 +1,8 @@ +import * as NAMESPACES from '@config/namespaces'; +import common from './common'; + +const translations = { + [NAMESPACES.SERVER_PAGE.COMMON]: common, +}; + +export default translations; diff --git a/src/theme/createTheme.ts b/src/theme/createTheme.ts index e94491c..db0230d 100644 --- a/src/theme/createTheme.ts +++ b/src/theme/createTheme.ts @@ -21,6 +21,7 @@ const createTheme = (): Theme => { }, MuiAppBar: { color: 'default', + elevation: 0, }, }, }) diff --git a/yarn.lock b/yarn.lock index d8fab8f..6990530 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3321,7 +3321,7 @@ clone-deep@^4.0.1: kind-of "^6.0.2" shallow-clone "^3.0.0" -clsx@^1.0.4: +clsx@^1.0.4, clsx@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/clsx/-/clsx-1.1.1.tgz#98b3134f9abbdf23b2663491ace13c5c03a73188" integrity sha512-6/bPho624p3S2pMyvP5kKBPXnI3ufHLObBFCfgx+LkeR5lg2XYy2hqZqUf45ypD8COn2bhgGJSUE+l5dhNBieA==