add input to the player daily stats ranking that allows changing the date

This commit is contained in:
Dawid Wysokiński 2020-12-28 11:54:13 +01:00
parent 4d64201c51
commit 5849822fad
18 changed files with 108 additions and 59 deletions

View File

@ -18,6 +18,7 @@
"@types/react-dom": "^16.9.8",
"clsx": "^1.1.1",
"date-fns": "^2.16.1",
"date-fns-tz": "^1.0.12",
"graphql": "^15.4.0",
"i18next": "^19.8.3",
"i18next-browser-languagedetector": "^6.0.1",

View File

@ -12,7 +12,7 @@ export type Props = TextFieldProps & {
onResetValue?: () => void;
};
function SearchInput({ value, onResetValue, style, ...rest }: Props) {
function SearchInput({ value, onResetValue, ...rest }: Props) {
const input = useRef<HTMLInputElement | null>(null);
return (
@ -20,7 +20,6 @@ function SearchInput({ value, onResetValue, style, ...rest }: Props) {
{...rest}
value={value}
inputRef={input}
style={{ backgroundColor: 'rgba(0, 0, 0, 0.1)', ...(style ? style : {}) }}
InputProps={{
startAdornment: (
<InputAdornment

View File

@ -1,5 +1,5 @@
import React from 'react';
import { format } from 'date-fns';
import { format, isValid } from 'date-fns';
import { useQuery } from '@apollo/client';
import {
useQueryParams,
@ -66,6 +66,7 @@ function LatestSavedEnnoblements({ t, server }: Props) {
return (
<TextField
type="date"
size="small"
key={id}
label={t('latestSavedEnnoblements.inputs.' + id)}
defaultValue={
@ -74,7 +75,8 @@ function LatestSavedEnnoblements({ t, server }: Props) {
: undefined
}
onChange={e => {
setQuery({ [id]: new Date(e.target.value) });
const date = new Date(e.target.value);
setQuery({ [id]: isValid(date) ? date : undefined });
}}
InputLabelProps={{
shrink: true,

View File

@ -59,10 +59,10 @@ function IndexPage() {
<ODRankingTribes server={key} t={t} />
</Grid>
<Grid item xs={12} md={6}>
<TodaysBestStatsPlayers server={key} t={t} />
<TodaysBestStatsPlayers t={t} />
</Grid>
<Grid item xs={12} md={6}>
<TodaysBestStatsTribes server={key} t={t} />
<TodaysBestStatsTribes t={t} />
</Grid>
<Grid item xs={12} md={6}>
<RecentlyDeletedPlayers server={key} t={t} />

View File

@ -1,6 +1,6 @@
import React, { useRef, useState } from 'react';
import { subHours } from 'date-fns';
import React, { useState } from 'react';
import { useQuery } from '@apollo/client';
import useServer from '@features/ServerPage/libs/ServerContext/useServer';
import formatNumber from '@utils/formatNumber';
import { SERVER_PAGE } from '@config/routes';
import { DAILY_PLAYER_STATS } from './queries';
@ -19,12 +19,11 @@ import { DailyPlayerStatsQueryVariables } from '@libs/graphql/types';
import { DailyPlayerStatsList, DailyPlayerStatsRecord, Mode } from './types';
export interface Props {
server: string;
t: TFunction;
}
function TodaysBestStatsPlayers({ server, t }: Props) {
const createDateGT = useRef(subHours(new Date(), 30));
function TodaysBestStatsPlayers({ t }: Props) {
const server = useServer();
const [mode, setMode] = useState<Mode>('scoreAtt');
const { loading: loadingData, data } = useQuery<
DailyPlayerStatsList,
@ -35,9 +34,9 @@ function TodaysBestStatsPlayers({ server, t }: Props) {
limit: LIMIT,
sort: [mode + ' DESC'],
filter: {
createDateGT: createDateGT.current,
createDate: server.historyUpdatedAt,
},
server,
server: server.key,
},
});
const records = data?.dailyPlayerStats?.items ?? [];
@ -49,7 +48,7 @@ function TodaysBestStatsPlayers({ server, t }: Props) {
<Typography variant="h4">
<Link
to={SERVER_PAGE.RANKING_PAGE.PLAYER_PAGE.DAILY_PAGE}
params={{ key: server }}
params={{ key: server.key }}
>
{t('todaysBestStatsPlayers.title')}
</Link>
@ -108,7 +107,10 @@ function TodaysBestStatsPlayers({ server, t }: Props) {
valueFormatter:
index === 0
? (record: DailyPlayerStatsRecord) => (
<PlayerProfileLink player={record.player} server={server} />
<PlayerProfileLink
player={record.player}
server={server.key}
/>
)
: index === 1
? (record: DailyPlayerStatsRecord) =>

View File

@ -1,6 +1,6 @@
import React, { useRef, useState } from 'react';
import { subHours } from 'date-fns';
import React, { useState } from 'react';
import { useQuery } from '@apollo/client';
import useServer from '@features/ServerPage/libs/ServerContext/useServer';
import formatNumber from '@utils/formatNumber';
import { SERVER_PAGE } from '@config/routes';
import { DAILY_TRIBE_STATS } from './queries';
@ -18,12 +18,11 @@ import { DailyTribeStatsQueryVariables } from '@libs/graphql/types';
import { DailyTribeStatsList, DailyTribeStatsRecord, Mode } from './types';
export interface Props {
server: string;
t: TFunction;
}
function TodaysBestStatsTribes({ server, t }: Props) {
const createDateGT = useRef(subHours(new Date(), 30));
function TodaysBestStatsTribes({ t }: Props) {
const server = useServer();
const [mode, setMode] = useState<Mode>('scoreAtt');
const { loading: loadingData, data } = useQuery<
DailyTribeStatsList,
@ -34,9 +33,9 @@ function TodaysBestStatsTribes({ server, t }: Props) {
limit: LIMIT,
sort: [mode + ' DESC'],
filter: {
createDateGT: createDateGT.current,
createDate: server.historyUpdatedAt,
},
server,
server: server.key,
},
});
const records = data?.dailyTribeStats?.items ?? [];
@ -48,7 +47,7 @@ function TodaysBestStatsTribes({ server, t }: Props) {
<Typography variant="h4">
<Link
to={SERVER_PAGE.RANKING_PAGE.TRIBE_PAGE.DAILY_PAGE}
params={{ key: server }}
params={{ key: server.key }}
>
{t('todaysBestStatsTribes.title')}
</Link>
@ -105,7 +104,7 @@ function TodaysBestStatsTribes({ server, t }: Props) {
? (record: DailyTribeStatsRecord) => (
<Link
to={SERVER_PAGE.TRIBE_PAGE.INDEX_PAGE}
params={{ key: server, id: record.tribe.id }}
params={{ key: server.key, id: record.tribe.id }}
>
{record.tribe.tag}
</Link>

View File

@ -13,7 +13,7 @@ function DailyPage() {
useTitle(t('title', { key }));
return (
<Container>
<Ranking t={t} server={key} />
<Ranking t={t} />
</Container>
);
}

View File

@ -1,19 +1,23 @@
import React, { useState } from 'react';
import { format, isValid } from 'date-fns';
import {
useQueryParams,
NumberParam,
withDefault,
StringParam,
DateTimeParam,
} from 'use-query-params';
import { useDebouncedCallback } from 'use-debounce';
import useUpdateEffect from '@libs/useUpdateEffect';
import useScrollToElement from '@libs/useScrollToElement';
import useServer from '@features/ServerPage/libs/ServerContext/useServer';
import SortParam from '@libs/serialize-query-params/SortParam';
import useStats from './useStats';
import { validateRowsPerPage } from '@common/Table/helpers';
import { COLUMNS, LIMIT, DEFAULT_SORT } from './constants';
import { Paper } from '@material-ui/core';
import { makeStyles } from '@material-ui/core/styles';
import { Paper, TextField } from '@material-ui/core';
import Table from '@common/Table/Table';
import TableToolbar from '@common/Table/TableToolbar';
import SearchInput from '@common/Form/SearchInput';
@ -23,16 +27,19 @@ import { TFunction } from 'i18next';
import { DailyPlayerStatsRecord } from './types';
export interface Props {
server: string;
t: TFunction;
}
function Ranking({ server, t }: Props) {
function Ranking({ t }: Props) {
const classes = useStyles();
const server = useServer();
const defaultDate = new Date(server.historyUpdatedAt);
const [query, setQuery] = useQueryParams({
page: withDefault(NumberParam, 0),
limit: withDefault(NumberParam, LIMIT),
q: withDefault(StringParam, ''),
sort: withDefault(SortParam, DEFAULT_SORT),
createDate: withDefault(DateTimeParam, defaultDate),
});
const limit = validateRowsPerPage(query.limit);
const [q, setQ] = useState(query.q);
@ -47,14 +54,32 @@ function Ranking({ server, t }: Props) {
const { dailyStats, total, loading } = useStats(
query.page,
limit,
server,
server.key,
query.q,
query.sort.toString()
query.sort.toString(),
query.createDate
);
return (
<Paper>
<TableToolbar style={{ justifyContent: 'flex-end' }}>
<TableToolbar className={classes.tableToolbar}>
<TextField
type="date"
size="small"
label={t('ranking.createDateInputLabel')}
defaultValue={
query.createDate && query.createDate instanceof Date
? format(query.createDate, 'yyyy-MM-dd')
: undefined
}
onChange={e => {
const date = new Date(e.target.value);
setQuery({ createDate: isValid(date) ? date : undefined });
}}
InputLabelProps={{
shrink: true,
}}
/>
<SearchInput
variant="outlined"
size="small"
@ -82,7 +107,7 @@ function Ranking({ server, t }: Props) {
}
if (index === 1) {
newCol.valueFormatter = (record: DailyPlayerStatsRecord) => (
<PlayerProfileLink player={record.player} server={server} />
<PlayerProfileLink player={record.player} server={server.key} />
);
}
return newCol;
@ -115,4 +140,22 @@ function Ranking({ server, t }: Props) {
);
}
const useStyles = makeStyles(theme => ({
tableToolbar: {
justifyContent: 'flex-end',
flexWrap: 'wrap',
'& > *': {
margin: theme.spacing(0.5),
[theme.breakpoints.down(700)]: {
marginLeft: 0,
marginRight: 0,
width: '100%',
},
},
[theme.breakpoints.down(700)]: {
flexDirection: 'column',
},
},
}));
export default Ranking;

View File

@ -1,6 +1,4 @@
import { useMemo } from 'react';
import { useQuery } from '@apollo/client';
import useServer from '@features/ServerPage/libs/ServerContext/useServer';
import { DAILY_PLAYER_STATS } from './queries';
import { DailyPlayerStatsQueryVariables } from '@libs/graphql/types';
@ -12,17 +10,18 @@ export type QueryResult = {
total: number;
};
export type Options = {
addTimezoneOffsetToCreateDate?: boolean;
};
const usePlayers = (
page: number,
limit: number,
server: string,
q: string,
sort: string
sort: string,
createDate: Date
): QueryResult => {
const { historyUpdatedAt } = useServer();
const createDateGTE = useMemo<string>(() => {
return historyUpdatedAt.toString().split('T')[0] + 'T00:00:00Z';
}, [historyUpdatedAt]);
const { loading: loadingStats, data } = useQuery<
DailyStats,
DailyPlayerStatsQueryVariables
@ -37,7 +36,7 @@ const usePlayers = (
exists: true,
nameIEQ: '%' + q + '%',
},
createDateGTE,
createDate,
},
server,
},

View File

@ -7,9 +7,9 @@ const ctx = createContext<Server>({
numberOfPlayers: 0,
numberOfTribes: 0,
numberOfVillages: 0,
dataUpdatedAt: new Date(0),
historyUpdatedAt: new Date(0),
statsUpdatedAt: new Date(0),
dataUpdatedAt: new Date(0).toJSON(),
historyUpdatedAt: new Date(0).toJSON(),
statsUpdatedAt: new Date(0).toJSON(),
status: SERVER_STATUS.OPEN,
version: {
code: '',

View File

@ -3,7 +3,6 @@ import { gql } from '@apollo/client';
export const SERVERS = gql`
query servers($filter: ServerFilter, $limit: Int) {
servers(filter: $filter, limit: $limit) {
total
items {
key
numberOfPlayers

View File

@ -7,9 +7,9 @@ export type Server = {
numberOfPlayers: number;
numberOfTribes: number;
numberOfVillages: number;
dataUpdatedAt: string | Date;
historyUpdatedAt: string | Date;
statsUpdatedAt: string | Date;
dataUpdatedAt: string;
historyUpdatedAt: string;
statsUpdatedAt: string;
version: {
code: string;
host: string;

View File

@ -0,0 +1,8 @@
import { addMinutes } from 'date-fns';
const addTimezoneOffset = (d: Date): Date => {
const offset = d.getTimezoneOffset();
return addMinutes(d, -1 * offset);
};
export default addTimezoneOffset;

View File

@ -1,12 +0,0 @@
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;

View File

@ -70,6 +70,7 @@ export type DailyPlayerStatsFilter = {
createDateGT?: Date | string;
createDateGTE?: Date | string;
createDateLTE?: Date | string;
createDate?: Date | string;
playerFilter?: PlayerFilter;
playerID?: number[];
};
@ -141,6 +142,7 @@ export type LiveEnnoblementsQueryVariables = {
export type DailyTribeStatsFilter = {
createDateGT?: Date | string;
createDateGTE?: Date | string;
createDate?: Date | string;
tribeID?: number[];
tribeFilter?: TribeFilter;
};

View File

@ -11,6 +11,7 @@ const translations = {
scoreTotal: 'OD',
},
searchInputPlaceholder: 'Search player',
createDateInputLabel: 'Date',
},
};

View File

@ -11,6 +11,7 @@ const translations = {
scoreTotal: 'Pokonani ogólnie',
},
searchInputPlaceholder: 'Wyszukaj gracza',
createDateInputLabel: 'Data',
},
};

View File

@ -4225,6 +4225,11 @@ data-urls@^2.0.0:
whatwg-mimetype "^2.3.0"
whatwg-url "^8.0.0"
date-fns-tz@^1.0.12:
version "1.0.12"
resolved "https://registry.yarnpkg.com/date-fns-tz/-/date-fns-tz-1.0.12.tgz#2d680e1099767775cff7a30eac34362d52639fed"
integrity sha512-Ca+9pjGkU90XDHnclfSjz9o7g/ZqyYyYI0aCYmbf65P75oy8gktuaRslO3UPXl3ADgAnF9/KCykQkpU3/xvtWQ==
date-fns@^2.16.1:
version "2.16.1"
resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.16.1.tgz#05775792c3f3331da812af253e1a935851d3834b"