add input to the player daily stats ranking that allows changing the date
This commit is contained in:
parent
4d64201c51
commit
5849822fad
|
@ -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",
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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} />
|
||||
|
|
|
@ -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) =>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -13,7 +13,7 @@ function DailyPage() {
|
|||
useTitle(t('title', { key }));
|
||||
return (
|
||||
<Container>
|
||||
<Ranking t={t} server={key} />
|
||||
<Ranking t={t} />
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
},
|
||||
|
|
|
@ -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: '',
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
8
src/libs/date/addTimezoneOffset.ts
Normal file
8
src/libs/date/addTimezoneOffset.ts
Normal 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;
|
|
@ -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;
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -11,6 +11,7 @@ const translations = {
|
|||
scoreTotal: 'OD',
|
||||
},
|
||||
searchInputPlaceholder: 'Search player',
|
||||
createDateInputLabel: 'Date',
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
@ -11,6 +11,7 @@ const translations = {
|
|||
scoreTotal: 'Pokonani ogólnie',
|
||||
},
|
||||
searchInputPlaceholder: 'Wyszukaj gracza',
|
||||
createDateInputLabel: 'Data',
|
||||
},
|
||||
};
|
||||
|
||||
|
|
|
@ -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"
|
||||
|
|
Reference in New Issue
Block a user