huge refactor
This commit is contained in:
parent
819abb008f
commit
645af393f8
|
@ -11,7 +11,7 @@ export interface Props extends LineSvgProps {
|
|||
loading?: boolean;
|
||||
}
|
||||
|
||||
const LineChart = ({ data, loading, ...rest }: Props) => {
|
||||
const LineChart = ({ data, loading, yScale, xScale, ...rest }: Props) => {
|
||||
const { t } = useTranslation(LINE_CHART);
|
||||
|
||||
if (loading) {
|
||||
|
@ -37,6 +37,8 @@ const LineChart = ({ data, loading, ...rest }: Props) => {
|
|||
// tooltip={PointTooltip}
|
||||
data={data}
|
||||
{...rest}
|
||||
xScale={xScale?.type === 'time' ? { useUTC: false, ...xScale } : xScale}
|
||||
yScale={yScale?.type === 'time' ? { useUTC: false, ...yScale } : yScale}
|
||||
theme={darkTheme}
|
||||
/>
|
||||
);
|
||||
|
|
|
@ -8,7 +8,6 @@ function PointTooltip(props: PointTooltipProps | BarTooltipDatum) {
|
|||
'point' in props
|
||||
? `X: ${props.point.data.xFormatted}, Y: ${props.point.data.yFormatted}`
|
||||
: `${props.indexValue} - ${props.value}`;
|
||||
console.log(props);
|
||||
return (
|
||||
<Tooltip open placement="top" arrow title={title}>
|
||||
<div></div>
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
import React from 'react';
|
||||
import useDateUtils from '@libs/date/useDateUtils';
|
||||
import { AUTHOR } from '@config/app';
|
||||
|
||||
import useStyles from './styles';
|
||||
import { AppBar, Toolbar, Container, Typography } from '@material-ui/core';
|
||||
|
||||
export default function Header() {
|
||||
const dateUtils = useDateUtils();
|
||||
const classes = useStyles();
|
||||
|
||||
return (
|
||||
|
@ -12,7 +14,7 @@ export default function Header() {
|
|||
<Container>
|
||||
<Toolbar disableGutters className={classes.toolbar}>
|
||||
<Typography align="center" className={classes.copyright}>
|
||||
© {new Date().getFullYear()} {AUTHOR}
|
||||
© {dateUtils.getYear(dateUtils.date())} {AUTHOR}
|
||||
</Typography>
|
||||
</Toolbar>
|
||||
</Container>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import React from 'react';
|
||||
import { get, isString, isNumber } from 'lodash';
|
||||
import { format } from 'date-fns';
|
||||
import useDateUtils from '@libs/date/useDateUtils';
|
||||
import { DATE_FORMAT } from '@config/app';
|
||||
|
||||
import { TableRow, TableCell, Checkbox, Tooltip } from '@material-ui/core';
|
||||
|
@ -28,6 +28,8 @@ function EnhancedTableRow<T extends object>({
|
|||
size = 'medium',
|
||||
index,
|
||||
}: Props<T>) {
|
||||
const dateUtils = useDateUtils();
|
||||
|
||||
const handleSelect = () => {
|
||||
if (onSelect) {
|
||||
onSelect(row);
|
||||
|
@ -35,15 +37,30 @@ function EnhancedTableRow<T extends object>({
|
|||
};
|
||||
|
||||
const formatValue = (
|
||||
v: string | number,
|
||||
type: 'datetime' | 'date' | 'normal'
|
||||
v: string | number | Date,
|
||||
type: 'datetime' | 'dateutc' | 'date' | 'normal'
|
||||
) => {
|
||||
if ((isString(v) || isNumber(v)) && type === 'date') {
|
||||
return format(new Date(v), DATE_FORMAT.DAY_MONTH_AND_YEAR);
|
||||
if ((isString(v) || isNumber(v) || v instanceof Date) && type === 'date') {
|
||||
return dateUtils.format(
|
||||
dateUtils.date(v),
|
||||
DATE_FORMAT.DAY_MONTH_AND_YEAR
|
||||
);
|
||||
}
|
||||
if ((isString(v) || isNumber(v)) && type === 'datetime') {
|
||||
return format(
|
||||
new Date(v),
|
||||
if (
|
||||
(isString(v) || isNumber(v) || v instanceof Date) &&
|
||||
type === 'dateutc'
|
||||
) {
|
||||
return dateUtils.format(
|
||||
dateUtils.dateInTZ(v, 'UTC'),
|
||||
DATE_FORMAT.DAY_MONTH_AND_YEAR
|
||||
);
|
||||
}
|
||||
if (
|
||||
(isString(v) || isNumber(v) || v instanceof Date) &&
|
||||
type === 'datetime'
|
||||
) {
|
||||
return dateUtils.format(
|
||||
dateUtils.date(v),
|
||||
DATE_FORMAT.HOUR_MINUTES_SECONDS_DAY_MONTH_AND_YEAR
|
||||
);
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ export type Column<T = any> = {
|
|||
sortable?: boolean;
|
||||
valueFormatter?: (v: T, i: number) => React.ReactNode;
|
||||
disablePadding?: boolean;
|
||||
type?: 'normal' | 'datetime' | 'date';
|
||||
type?: 'normal' | 'dateutc' | 'datetime' | 'date';
|
||||
align?: 'left' | 'right' | 'center';
|
||||
};
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
export const DEFAULT_LANGUAGE = process.env.REACT_APP_DEFAULT_LANGUAGE ?? 'en';
|
||||
export const DEFAULT_LANGUAGE = process.env.REACT_APP_DEFAULT_LANGUAGE ?? 'pl';
|
||||
|
||||
export const NAME = 'TWHelp';
|
||||
|
||||
|
|
|
@ -5,6 +5,8 @@ import { Switch, Route } from 'react-router-dom';
|
|||
import { CssBaseline } from '@material-ui/core';
|
||||
import ScrollToTop from '@common/ScrollToTop/ScrollToTop';
|
||||
|
||||
import VersionProvider from '../libs/VersionContext/Provider';
|
||||
import DateUtilsProvider from '../libs/date/DateUtilsProvider';
|
||||
import IndexPage from './IndexPage/IndexPage';
|
||||
import NotFoundPage from './NotFoundPage/NotFoundPage';
|
||||
import SearchPage from './SearchPage/SearchPage';
|
||||
|
@ -13,20 +15,24 @@ import ServerPage from './ServerPage/ServerPage';
|
|||
function App() {
|
||||
return (
|
||||
<Fragment>
|
||||
<Switch>
|
||||
<Route path={ROUTES.INDEX_PAGE} exact>
|
||||
<IndexPage />
|
||||
</Route>
|
||||
<Route path={ROUTES.SEARCH_PAGE} exact>
|
||||
<SearchPage />
|
||||
</Route>
|
||||
<Route path={ROUTES.SERVER_PAGE.INDEX_PAGE}>
|
||||
<ServerPage />
|
||||
</Route>
|
||||
<Route path="*">
|
||||
<NotFoundPage />
|
||||
</Route>
|
||||
</Switch>
|
||||
<VersionProvider>
|
||||
<DateUtilsProvider>
|
||||
<Switch>
|
||||
<Route path={ROUTES.INDEX_PAGE} exact>
|
||||
<IndexPage />
|
||||
</Route>
|
||||
<Route path={ROUTES.SEARCH_PAGE} exact>
|
||||
<SearchPage />
|
||||
</Route>
|
||||
<Route path={ROUTES.SERVER_PAGE.INDEX_PAGE}>
|
||||
<ServerPage />
|
||||
</Route>
|
||||
<Route path="*">
|
||||
<NotFoundPage />
|
||||
</Route>
|
||||
</Switch>
|
||||
</DateUtilsProvider>
|
||||
</VersionProvider>
|
||||
<CssBaseline />
|
||||
<ScrollToTop />
|
||||
</Fragment>
|
||||
|
|
|
@ -76,7 +76,6 @@ function GridItem({ t, server, hideTooltip = true }: Props) {
|
|||
classes={{
|
||||
tooltip: classes.tooltip,
|
||||
}}
|
||||
arrow
|
||||
title={serverInfo}
|
||||
>
|
||||
<InfoIcon color="inherit" />
|
||||
|
|
|
@ -1,13 +1,11 @@
|
|||
import React from 'react';
|
||||
import useDateUtils from '@libs/date/useDateUtils';
|
||||
import useServer from '@features/ServerPage/libs/ServerContext/useServer';
|
||||
import useStyles from './useStyles';
|
||||
import formatDistanceToNow from '@libs/date/formatDistanceToNow';
|
||||
import formatNumber from '@utils/formatNumber';
|
||||
import extractVersionCodeFromHostname from '@utils/extractVersionCodeFromHostname';
|
||||
|
||||
import { Typography } from '@material-ui/core';
|
||||
|
||||
import { Locale } from '@libs/date/locales';
|
||||
import { TFunction } from 'i18next';
|
||||
|
||||
export interface Props {
|
||||
|
@ -21,6 +19,7 @@ const ServerInfo = ({ t }: Props) => {
|
|||
dataUpdatedAt,
|
||||
numberOfVillages,
|
||||
} = useServer();
|
||||
const dateUtils = useDateUtils();
|
||||
|
||||
const classes = useStyles();
|
||||
|
||||
|
@ -46,10 +45,7 @@ const ServerInfo = ({ t }: Props) => {
|
|||
</Typography>
|
||||
<Typography>
|
||||
{t('pageLayout.sidebar.serverInfo.dataUpdatedAt', {
|
||||
date: formatDistanceToNow(new Date(dataUpdatedAt), {
|
||||
locale: extractVersionCodeFromHostname(
|
||||
window.location.hostname
|
||||
) as Locale,
|
||||
date: dateUtils.formatDistanceToNow(new Date(dataUpdatedAt), {
|
||||
addSuffix: true,
|
||||
}),
|
||||
})}
|
||||
|
|
|
@ -6,6 +6,7 @@ import {
|
|||
withDefault,
|
||||
DateTimeParam,
|
||||
} from 'use-query-params';
|
||||
import useDateUtils from '@libs/date/useDateUtils';
|
||||
import useScrollToElement from '@libs/useScrollToElement';
|
||||
import { validateRowsPerPage } from '@common/Table/helpers';
|
||||
import { ENNOBLEMENTS } from './queries';
|
||||
|
@ -27,11 +28,12 @@ export interface Props {
|
|||
|
||||
function LatestSavedEnnoblements({ t, server }: Props) {
|
||||
const classes = useStyles();
|
||||
const now = useRef(new Date());
|
||||
const dateUtils = useDateUtils();
|
||||
const now = useRef(dateUtils.date());
|
||||
const [query, setQuery] = useQueryParams({
|
||||
page: withDefault(NumberParam, 0),
|
||||
limit: withDefault(NumberParam, LIMIT),
|
||||
ennobledAtGTE: withDefault(DateTimeParam, new Date(0)),
|
||||
ennobledAtGTE: withDefault(DateTimeParam, dateUtils.date(0)),
|
||||
ennobledAtLTE: withDefault(DateTimeParam, now.current),
|
||||
});
|
||||
const limit = validateRowsPerPage(query.limit);
|
||||
|
@ -46,8 +48,8 @@ function LatestSavedEnnoblements({ t, server }: Props) {
|
|||
offset: query.page * limit,
|
||||
sort: ['ennobledAt DESC'],
|
||||
filter: {
|
||||
ennobledAtGTE: query.ennobledAtGTE,
|
||||
ennobledAtLTE: query.ennobledAtLTE,
|
||||
ennobledAtGTE: dateUtils.zonedTimeToUTC(query.ennobledAtGTE),
|
||||
ennobledAtLTE: dateUtils.zonedTimeToUTC(query.ennobledAtLTE),
|
||||
},
|
||||
server,
|
||||
},
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import React, { useMemo } from 'react';
|
||||
import { useQuery } from '@apollo/client';
|
||||
import useDateUtils from '@libs/date/useDateUtils';
|
||||
import { STATISTICS } from './queries';
|
||||
import { LIMIT } from './constants';
|
||||
|
||||
|
@ -19,6 +20,7 @@ export interface Props {
|
|||
}
|
||||
|
||||
function PlayerStatistics({ server, t }: Props) {
|
||||
const dateUtils = useDateUtils();
|
||||
const { loading: loadingData, data: queryRes } = useQuery<
|
||||
ServerStats,
|
||||
ServerStatsQueryVariables
|
||||
|
@ -40,16 +42,18 @@ function PlayerStatistics({ server, t }: Props) {
|
|||
return [
|
||||
{
|
||||
id: t<string>('playerStatistics.players'),
|
||||
data: items.map(item => ({
|
||||
x: new Date(item.createDate),
|
||||
y: item.activePlayers,
|
||||
})),
|
||||
data: items.map(item => {
|
||||
return {
|
||||
x: dateUtils.dateInTZ(item.createDate, 'UTC'),
|
||||
y: item.activePlayers,
|
||||
};
|
||||
}),
|
||||
},
|
||||
];
|
||||
}, [items, loading, t]);
|
||||
}, [items, loading, t, dateUtils]);
|
||||
|
||||
return (
|
||||
<Paper size="large" style={{ overflow: 'hidden' }}>
|
||||
<Paper size="large" style={{ overflow: 'visible' }}>
|
||||
<TableToolbar>
|
||||
<Typography variant="h4">{t('playerStatistics.title')}</Typography>
|
||||
</TableToolbar>
|
||||
|
@ -70,7 +74,6 @@ function PlayerStatistics({ server, t }: Props) {
|
|||
}}
|
||||
xFormat="time:%Y-%m-%d"
|
||||
axisBottom={{
|
||||
tickSize: 0,
|
||||
tickValues: 'every 6 days',
|
||||
tickPadding: 5,
|
||||
tickRotation: 0,
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import React, { useState } from 'react';
|
||||
import { useQuery } from '@apollo/client';
|
||||
import useServer from '@features/ServerPage/libs/ServerContext/useServer';
|
||||
import useDateUtils from '@libs/date/useDateUtils';
|
||||
import formatNumber from '@utils/formatNumber';
|
||||
import { SERVER_PAGE } from '@config/routes';
|
||||
import { DAILY_PLAYER_STATS } from './queries';
|
||||
|
@ -24,6 +25,7 @@ export interface Props {
|
|||
|
||||
function TodaysBestStatsPlayers({ t }: Props) {
|
||||
const server = useServer();
|
||||
const dateUtils = useDateUtils();
|
||||
const [mode, setMode] = useState<Mode>('scoreAtt');
|
||||
const { loading: loadingData, data } = useQuery<
|
||||
DailyPlayerStatsList,
|
||||
|
@ -34,7 +36,7 @@ function TodaysBestStatsPlayers({ t }: Props) {
|
|||
limit: LIMIT,
|
||||
sort: [mode + ' DESC'],
|
||||
filter: {
|
||||
createDate: server.historyUpdatedAt,
|
||||
createDate: dateUtils.toJSON(dateUtils.date(server.historyUpdatedAt)),
|
||||
},
|
||||
server: server.key,
|
||||
},
|
||||
|
|
|
@ -16,7 +16,7 @@ export const COLUMNS: Column<DailyPlayerStatsRecord>[] = [
|
|||
field: 'createDate',
|
||||
label: 'todaysBestStatsPlayers.columns.createDate',
|
||||
sortable: false,
|
||||
type: 'date',
|
||||
type: 'dateutc',
|
||||
},
|
||||
];
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import React, { useState } from 'react';
|
||||
import { useQuery } from '@apollo/client';
|
||||
import useServer from '@features/ServerPage/libs/ServerContext/useServer';
|
||||
import useDateUtils from '@libs/date/useDateUtils';
|
||||
import formatNumber from '@utils/formatNumber';
|
||||
import { SERVER_PAGE } from '@config/routes';
|
||||
import { DAILY_TRIBE_STATS } from './queries';
|
||||
|
@ -23,6 +24,7 @@ export interface Props {
|
|||
|
||||
function TodaysBestStatsTribes({ t }: Props) {
|
||||
const server = useServer();
|
||||
const dateUtils = useDateUtils();
|
||||
const [mode, setMode] = useState<Mode>('scoreAtt');
|
||||
const { loading: loadingData, data } = useQuery<
|
||||
DailyTribeStatsList,
|
||||
|
@ -33,11 +35,12 @@ function TodaysBestStatsTribes({ t }: Props) {
|
|||
limit: LIMIT,
|
||||
sort: [mode + ' DESC'],
|
||||
filter: {
|
||||
createDate: server.historyUpdatedAt,
|
||||
createDate: dateUtils.toJSON(dateUtils.date(server.historyUpdatedAt)),
|
||||
},
|
||||
server: server.key,
|
||||
},
|
||||
});
|
||||
console.log(dateUtils.toJSON(dateUtils.date(server.historyUpdatedAt)));
|
||||
const records = data?.dailyTribeStats?.items ?? [];
|
||||
const loading = loadingData && records.length === 0;
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@ export const COLUMNS: Column<DailyTribeStatsRecord>[] = [
|
|||
field: 'createDate',
|
||||
label: 'todaysBestStatsTribes.columns.createDate',
|
||||
sortable: false,
|
||||
type: 'date',
|
||||
type: 'dateutc',
|
||||
},
|
||||
];
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import React, { useMemo } from 'react';
|
||||
import { useQuery } from '@apollo/client';
|
||||
import useDateUtils from '@libs/date/useDateUtils';
|
||||
import { STATISTICS } from './queries';
|
||||
import { LIMIT } from './constants';
|
||||
|
||||
|
@ -19,6 +20,7 @@ export interface Props {
|
|||
}
|
||||
|
||||
function TribeStatistics({ server, t }: Props) {
|
||||
const dateUtils = useDateUtils();
|
||||
const { loading: loadingData, data: queryRes } = useQuery<
|
||||
ServerStats,
|
||||
ServerStatsQueryVariables
|
||||
|
@ -40,16 +42,18 @@ function TribeStatistics({ server, t }: Props) {
|
|||
return [
|
||||
{
|
||||
id: t<string>('tribeStatistics.tribes'),
|
||||
data: items.map(item => ({
|
||||
x: new Date(item.createDate),
|
||||
y: item.activeTribes,
|
||||
})),
|
||||
data: items.map(item => {
|
||||
return {
|
||||
x: dateUtils.dateInTZ(item.createDate, 'UTC'),
|
||||
y: item.activeTribes,
|
||||
};
|
||||
}),
|
||||
},
|
||||
];
|
||||
}, [items, loading, t]);
|
||||
}, [items, loading, t, dateUtils]);
|
||||
|
||||
return (
|
||||
<Paper size="large" style={{ overflow: 'hidden' }}>
|
||||
<Paper size="large" style={{ overflow: 'visible' }}>
|
||||
<TableToolbar>
|
||||
<Typography variant="h4">{t('tribeStatistics.title')}</Typography>
|
||||
</TableToolbar>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import React, { useMemo } from 'react';
|
||||
import { subDays, isEqual as isEqualDate } from 'date-fns';
|
||||
import { useQuery } from '@apollo/client';
|
||||
import { useQueryParams, NumberParam, withDefault } from 'use-query-params';
|
||||
import useDateUtils from '@libs/date/useDateUtils';
|
||||
import useScrollToElement from '@libs/useScrollToElement';
|
||||
import { validateRowsPerPage } from '@common/Table/helpers';
|
||||
import formatNumber from '@utils/formatNumber';
|
||||
|
@ -27,6 +27,7 @@ export interface Props {
|
|||
}
|
||||
|
||||
function PlayerHistory({ t, server, playerID }: Props) {
|
||||
const dateUtils = useDateUtils();
|
||||
const [query, setQuery] = useQueryParams({
|
||||
page: withDefault(NumberParam, 0),
|
||||
limit: withDefault(NumberParam, LIMIT),
|
||||
|
@ -55,15 +56,21 @@ function PlayerHistory({ t, server, playerID }: Props) {
|
|||
const playerHistoryItems = useMemo(() => {
|
||||
const dailyPlayerStatsItems = queryData?.dailyPlayerStats?.items ?? [];
|
||||
return (queryData?.playerHistory?.items ?? []).map(phItem => {
|
||||
const dateOfTheDayBeforeDate = subDays(new Date(phItem.createDate), 1);
|
||||
const dateOfTheDayBeforeDate = dateUtils.subDays(
|
||||
dateUtils.date(phItem.createDate),
|
||||
1
|
||||
);
|
||||
return {
|
||||
...phItem,
|
||||
stats: dailyPlayerStatsItems.find(dpsItem =>
|
||||
isEqualDate(new Date(dpsItem.createDate), dateOfTheDayBeforeDate)
|
||||
dateUtils.isEqual(
|
||||
dateUtils.date(dpsItem.createDate),
|
||||
dateOfTheDayBeforeDate
|
||||
)
|
||||
),
|
||||
};
|
||||
});
|
||||
}, [queryData]);
|
||||
}, [queryData, dateUtils]);
|
||||
const loading = playerHistoryItems.length === 0 && queryLoading;
|
||||
const total = queryData?.playerHistory?.total ?? 0;
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import React from 'react';
|
||||
import { format } from 'date-fns';
|
||||
import useDateUtils from '@libs/date/useDateUtils';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import useTitle from '@libs/useTitle';
|
||||
import useServer from '@features/ServerPage/libs/ServerContext/useServer';
|
||||
|
@ -28,6 +28,7 @@ function IndexPage() {
|
|||
const { key } = useServer();
|
||||
const player = usePlayer();
|
||||
const { t } = useTranslation(SERVER_PAGE.PLAYER_PAGE.INDEX_PAGE);
|
||||
const dateUtils = useDateUtils();
|
||||
useTitle(t('title', { key, name: player.name }));
|
||||
|
||||
return (
|
||||
|
@ -39,8 +40,8 @@ function IndexPage() {
|
|||
{[
|
||||
{
|
||||
field: 'joinedAt',
|
||||
value: format(
|
||||
new Date(player.joinedAt),
|
||||
value: dateUtils.format(
|
||||
dateUtils.date(player.joinedAt),
|
||||
DATE_FORMAT.DAY_MONTH_AND_YEAR
|
||||
),
|
||||
},
|
||||
|
@ -83,32 +84,32 @@ function IndexPage() {
|
|||
{
|
||||
field: 'deletedAt',
|
||||
value: player.deletedAt
|
||||
? format(
|
||||
new Date(player.deletedAt),
|
||||
? dateUtils.format(
|
||||
dateUtils.date(player.deletedAt),
|
||||
DATE_FORMAT.DAY_MONTH_AND_YEAR
|
||||
)
|
||||
: '-',
|
||||
},
|
||||
{
|
||||
field: 'bestRank',
|
||||
subtitle: format(
|
||||
new Date(player.bestRankAt),
|
||||
subtitle: dateUtils.format(
|
||||
dateUtils.date(player.bestRankAt),
|
||||
DATE_FORMAT.HOUR_MINUTES_DAY_MONTH_AND_YEAR
|
||||
),
|
||||
value: player.bestRank,
|
||||
},
|
||||
{
|
||||
field: 'mostPoints',
|
||||
subtitle: format(
|
||||
new Date(player.mostPointsAt),
|
||||
subtitle: dateUtils.format(
|
||||
dateUtils.date(player.mostPointsAt),
|
||||
DATE_FORMAT.HOUR_MINUTES_DAY_MONTH_AND_YEAR
|
||||
),
|
||||
value: formatNumber('commas', player.mostPoints),
|
||||
},
|
||||
{
|
||||
field: 'mostVillages',
|
||||
subtitle: format(
|
||||
new Date(player.mostVillagesAt),
|
||||
subtitle: dateUtils.format(
|
||||
dateUtils.date(player.mostVillagesAt),
|
||||
DATE_FORMAT.HOUR_MINUTES_DAY_MONTH_AND_YEAR
|
||||
),
|
||||
value: formatNumber('commas', player.mostVillages),
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import React, { useState, useMemo } from 'react';
|
||||
import { useQuery } from '@apollo/client';
|
||||
import useDateUtils from '@libs/date/useDateUtils';
|
||||
import formatNumber from '@utils/formatNumber';
|
||||
import { PLAYER_HISTORY } from './queries';
|
||||
import { LIMIT } from './constants';
|
||||
|
@ -24,6 +25,7 @@ function Statistics({ t, server, playerID }: Props) {
|
|||
const [mode, setMode] = useState<Mode>('points');
|
||||
const theme = useTheme();
|
||||
const isMobileDevice = useMediaQuery(theme.breakpoints.down('sm'));
|
||||
const dateUtils = useDateUtils();
|
||||
const { data: queryRes, loading } = useQuery<
|
||||
PlayerHistory,
|
||||
PlayerHistoryQueryVariables
|
||||
|
@ -51,12 +53,12 @@ function Statistics({ t, server, playerID }: Props) {
|
|||
{
|
||||
id: t<string>('statistics.modes.' + mode),
|
||||
data: items.map(item => ({
|
||||
x: new Date(item.createDate),
|
||||
x: dateUtils.dateInTZ(item.createDate, 'UTC'),
|
||||
y: item[mode],
|
||||
})),
|
||||
},
|
||||
];
|
||||
}, [items, loading, t, mode]);
|
||||
}, [items, loading, t, mode, dateUtils]);
|
||||
const xyFormat = (v: string | number | Date) =>
|
||||
typeof v === 'string' || typeof v === 'number'
|
||||
? formatNumber('commas', v)
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
import React, { useState } from 'react';
|
||||
import React, { useState, useRef } from 'react';
|
||||
import {
|
||||
useQueryParams,
|
||||
NumberParam,
|
||||
withDefault,
|
||||
StringParam,
|
||||
DateTimeParam,
|
||||
DateParam,
|
||||
} from 'use-query-params';
|
||||
import { useDebouncedCallback } from 'use-debounce';
|
||||
import useDateUtils from '@libs/date/useDateUtils';
|
||||
import useUpdateEffect from '@libs/useUpdateEffect';
|
||||
import useScrollToElement from '@libs/useScrollToElement';
|
||||
import useServer from '@features/ServerPage/libs/ServerContext/useServer';
|
||||
|
@ -33,13 +34,14 @@ export interface Props {
|
|||
function Ranking({ t }: Props) {
|
||||
const classes = useStyles();
|
||||
const server = useServer();
|
||||
const defaultDate = new Date(server.historyUpdatedAt);
|
||||
const dateUtils = useDateUtils();
|
||||
const defaultDate = useRef(dateUtils.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),
|
||||
createDate: withDefault(DateParam, defaultDate.current),
|
||||
});
|
||||
const limit = validateRowsPerPage(query.limit);
|
||||
const [q, setQ] = useState(query.q);
|
||||
|
@ -58,7 +60,7 @@ function Ranking({ t }: Props) {
|
|||
server.key,
|
||||
query.q,
|
||||
query.sort.toString(),
|
||||
query.createDate
|
||||
dateUtils.toJSON(query.createDate)
|
||||
);
|
||||
|
||||
return (
|
||||
|
|
|
@ -16,7 +16,7 @@ const usePlayers = (
|
|||
server: string,
|
||||
q: string,
|
||||
sort: string,
|
||||
createDate: Date
|
||||
createDate: Date | string
|
||||
): QueryResult => {
|
||||
const { loading: loadingStats, data } = useQuery<
|
||||
DailyStats,
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
import React, { useState } from 'react';
|
||||
import React, { useState, useRef } from 'react';
|
||||
import {
|
||||
useQueryParams,
|
||||
NumberParam,
|
||||
withDefault,
|
||||
StringParam,
|
||||
DateTimeParam,
|
||||
DateParam,
|
||||
} from 'use-query-params';
|
||||
import { useDebouncedCallback } from 'use-debounce';
|
||||
import useDateUtils from '@libs/date/useDateUtils';
|
||||
import useUpdateEffect from '@libs/useUpdateEffect';
|
||||
import useScrollToElement from '@libs/useScrollToElement';
|
||||
import useServer from '@features/ServerPage/libs/ServerContext/useServer';
|
||||
|
@ -34,13 +35,14 @@ export interface Props {
|
|||
function Ranking({ t }: Props) {
|
||||
const classes = useStyles();
|
||||
const server = useServer();
|
||||
const defaultDate = new Date(server.historyUpdatedAt);
|
||||
const dateUtils = useDateUtils();
|
||||
const defaultDate = useRef(dateUtils.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),
|
||||
createDate: withDefault(DateParam, defaultDate.current),
|
||||
});
|
||||
const limit = validateRowsPerPage(query.limit);
|
||||
const [q, setQ] = useState(query.q);
|
||||
|
@ -59,7 +61,7 @@ function Ranking({ t }: Props) {
|
|||
server.key,
|
||||
query.q,
|
||||
query.sort.toString(),
|
||||
query.createDate
|
||||
dateUtils.toJSON(query.createDate)
|
||||
);
|
||||
|
||||
return (
|
||||
|
|
|
@ -16,7 +16,7 @@ const useTribes = (
|
|||
server: string,
|
||||
q: string,
|
||||
sort: string,
|
||||
createDate: Date
|
||||
createDate: Date | string
|
||||
): QueryResult => {
|
||||
const { loading: loadingStats, data } = useQuery<
|
||||
DailyStats,
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import React, { useMemo } from 'react';
|
||||
import { subDays, isEqual as isEqualDate } from 'date-fns';
|
||||
import { useQuery } from '@apollo/client';
|
||||
import { useQueryParams, NumberParam, withDefault } from 'use-query-params';
|
||||
import useDateUtils from '@libs/date/useDateUtils';
|
||||
import useScrollToElement from '@libs/useScrollToElement';
|
||||
import { validateRowsPerPage } from '@common/Table/helpers';
|
||||
import formatNumber from '@utils/formatNumber';
|
||||
|
@ -25,6 +25,7 @@ export interface Props {
|
|||
}
|
||||
|
||||
function TribeHistory({ t, server, tribeID }: Props) {
|
||||
const dateUtils = useDateUtils();
|
||||
const [query, setQuery] = useQueryParams({
|
||||
page: withDefault(NumberParam, 0),
|
||||
limit: withDefault(NumberParam, LIMIT),
|
||||
|
@ -53,15 +54,21 @@ function TribeHistory({ t, server, tribeID }: Props) {
|
|||
const tribeHistoryItems = useMemo(() => {
|
||||
const dailyTribeStatsItems = queryData?.dailyTribeStats?.items ?? [];
|
||||
return (queryData?.tribeHistory?.items ?? []).map(phItem => {
|
||||
const dateOfTheDayBeforeDate = subDays(new Date(phItem.createDate), 1);
|
||||
const dateOfTheDayBeforeDate = dateUtils.subDays(
|
||||
dateUtils.date(phItem.createDate),
|
||||
1
|
||||
);
|
||||
return {
|
||||
...phItem,
|
||||
stats: dailyTribeStatsItems.find(dpsItem =>
|
||||
isEqualDate(new Date(dpsItem.createDate), dateOfTheDayBeforeDate)
|
||||
dateUtils.isEqual(
|
||||
dateUtils.date(dpsItem.createDate),
|
||||
dateOfTheDayBeforeDate
|
||||
)
|
||||
),
|
||||
};
|
||||
});
|
||||
}, [queryData]);
|
||||
}, [queryData, dateUtils]);
|
||||
const loading = tribeHistoryItems.length === 0 && queryLoading;
|
||||
const total = queryData?.tribeHistory?.total ?? 0;
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import React from 'react';
|
||||
import { format } from 'date-fns';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import useDateUtils from '@libs/date/useDateUtils';
|
||||
import useTitle from '@libs/useTitle';
|
||||
import useServer from '@features/ServerPage/libs/ServerContext/useServer';
|
||||
import useTribe from '../../libs/TribePageContext/useTribe';
|
||||
|
@ -20,6 +20,7 @@ import {
|
|||
import Statistics from './components/Statistics/Statistics';
|
||||
|
||||
function IndexPage() {
|
||||
const dateUtils = useDateUtils();
|
||||
const classes = useStyles();
|
||||
const { key } = useServer();
|
||||
const tribe = useTribe();
|
||||
|
@ -35,8 +36,8 @@ function IndexPage() {
|
|||
{[
|
||||
{
|
||||
field: 'createdAt',
|
||||
value: format(
|
||||
new Date(tribe.createdAt),
|
||||
value: dateUtils.format(
|
||||
dateUtils.date(tribe.createdAt),
|
||||
DATE_FORMAT.DAY_MONTH_AND_YEAR
|
||||
),
|
||||
},
|
||||
|
@ -77,32 +78,32 @@ function IndexPage() {
|
|||
{
|
||||
field: 'deletedAt',
|
||||
value: tribe.deletedAt
|
||||
? format(
|
||||
new Date(tribe.deletedAt),
|
||||
? dateUtils.format(
|
||||
dateUtils.date(tribe.deletedAt),
|
||||
DATE_FORMAT.DAY_MONTH_AND_YEAR
|
||||
)
|
||||
: '-',
|
||||
},
|
||||
{
|
||||
field: 'bestRank',
|
||||
subtitle: format(
|
||||
new Date(tribe.bestRankAt),
|
||||
subtitle: dateUtils.format(
|
||||
dateUtils.date(tribe.bestRankAt),
|
||||
DATE_FORMAT.HOUR_MINUTES_DAY_MONTH_AND_YEAR
|
||||
),
|
||||
value: tribe.bestRank,
|
||||
},
|
||||
{
|
||||
field: 'mostPoints',
|
||||
subtitle: format(
|
||||
new Date(tribe.mostPointsAt),
|
||||
subtitle: dateUtils.format(
|
||||
dateUtils.date(tribe.mostPointsAt),
|
||||
DATE_FORMAT.HOUR_MINUTES_DAY_MONTH_AND_YEAR
|
||||
),
|
||||
value: formatNumber('commas', tribe.mostPoints),
|
||||
},
|
||||
{
|
||||
field: 'mostVillages',
|
||||
subtitle: format(
|
||||
new Date(tribe.mostVillagesAt),
|
||||
subtitle: dateUtils.format(
|
||||
dateUtils.date(tribe.mostVillagesAt),
|
||||
DATE_FORMAT.HOUR_MINUTES_DAY_MONTH_AND_YEAR
|
||||
),
|
||||
value: formatNumber('commas', tribe.mostVillages),
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import React, { useState, useMemo } from 'react';
|
||||
import { useQuery } from '@apollo/client';
|
||||
import useDateUtils from '@libs/date/useDateUtils';
|
||||
import formatNumber from '@utils/formatNumber';
|
||||
import { TRIBE_HISTORY } from './queries';
|
||||
import { LIMIT } from './constants';
|
||||
|
@ -23,6 +24,7 @@ export interface Props {
|
|||
function Statistics({ t, server, tribeID }: Props) {
|
||||
const [mode, setMode] = useState<Mode>('points');
|
||||
const theme = useTheme();
|
||||
const dateUtils = useDateUtils();
|
||||
const isMobileDevice = useMediaQuery(theme.breakpoints.down('sm'));
|
||||
const { data: queryRes, loading } = useQuery<
|
||||
TribeHistory,
|
||||
|
@ -51,12 +53,12 @@ function Statistics({ t, server, tribeID }: Props) {
|
|||
{
|
||||
id: t<string>('statistics.modes.' + mode),
|
||||
data: items.map(item => ({
|
||||
x: new Date(item.createDate),
|
||||
x: dateUtils.dateInTZ(item.createDate, 'UTC'),
|
||||
y: item[mode],
|
||||
})),
|
||||
},
|
||||
];
|
||||
}, [items, loading, t, mode]);
|
||||
}, [items, loading, t, mode, dateUtils]);
|
||||
const xyFormat = (v: string | number | Date) =>
|
||||
typeof v === 'string' || typeof v === 'number'
|
||||
? formatNumber('commas', v)
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import React, { useMemo, useState } from 'react';
|
||||
import { addDays, differenceInDays, format, isBefore } from 'date-fns';
|
||||
import useDateUtils from '@libs/date/useDateUtils';
|
||||
import useMembers from './useMembers';
|
||||
import formatNumber from '@utils/formatNumber';
|
||||
import { DATE_FORMAT } from '@config/app';
|
||||
|
@ -28,6 +28,7 @@ function Members({ t, server, tribeID }: Props) {
|
|||
server,
|
||||
HOW_MANY_DAYS_BACK
|
||||
);
|
||||
const dateUtils = useDateUtils();
|
||||
const columns = useMemo<Column<Player>[]>(() => {
|
||||
const columns: Column<Player>[] = [
|
||||
{
|
||||
|
@ -66,19 +67,24 @@ function Members({ t, server, tribeID }: Props) {
|
|||
|
||||
const maxDate =
|
||||
dailyPlayerStats.length > 0
|
||||
? new Date(dailyPlayerStats[0].createDate)
|
||||
? dateUtils.date(dailyPlayerStats[0].createDate)
|
||||
: null;
|
||||
const minDate =
|
||||
dailyPlayerStats.length > 0
|
||||
? new Date(dailyPlayerStats[dailyPlayerStats.length - 1].createDate)
|
||||
? dateUtils.date(
|
||||
dailyPlayerStats[dailyPlayerStats.length - 1].createDate
|
||||
)
|
||||
: null;
|
||||
|
||||
if (maxDate && minDate && isBefore(minDate, maxDate)) {
|
||||
let diff = differenceInDays(maxDate, minDate) + 1;
|
||||
if (maxDate && minDate && dateUtils.isBefore(minDate, maxDate)) {
|
||||
let diff = dateUtils.differenceInDays(maxDate, minDate) + 1;
|
||||
if (diff <= HOW_MANY_DAYS_BACK) {
|
||||
for (let i = 0; i < diff; i++) {
|
||||
const date = addDays(minDate, i);
|
||||
const formatted = format(date, DATE_FORMAT.DAY_MONTH_AND_YEAR);
|
||||
const date = dateUtils.addDays(minDate, i);
|
||||
const formatted = dateUtils.format(
|
||||
date,
|
||||
DATE_FORMAT.DAY_MONTH_AND_YEAR
|
||||
);
|
||||
columns.push({
|
||||
field: formatted,
|
||||
label: formatted,
|
||||
|
@ -86,7 +92,8 @@ function Members({ t, server, tribeID }: Props) {
|
|||
valueFormatter: (p: Player) => {
|
||||
const record = p.dailyPlayerStatsRecords
|
||||
? p.dailyPlayerStatsRecords.find(
|
||||
r => new Date(r.createDate).getTime() === date.getTime()
|
||||
r =>
|
||||
dateUtils.date(r.createDate).getTime() === date.getTime()
|
||||
)
|
||||
: undefined;
|
||||
return <ColouredNumber num={record ? record[mode] : 0} />;
|
||||
|
@ -116,7 +123,7 @@ function Members({ t, server, tribeID }: Props) {
|
|||
}
|
||||
|
||||
return columns;
|
||||
}, [dailyPlayerStats, t, server, mode]);
|
||||
}, [dailyPlayerStats, t, server, mode, dateUtils]);
|
||||
|
||||
return (
|
||||
<Paper>
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import React, { useRef, useMemo, useState } from 'react';
|
||||
import { subDays } from 'date-fns';
|
||||
import { useQueryParams, DateTimeParam, withDefault } from 'use-query-params';
|
||||
import { useApolloClient } from '@apollo/client';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import useDateUtils from '@libs/date/useDateUtils';
|
||||
import useTitle from '@libs/useTitle';
|
||||
import useServer from '../../libs/ServerContext/useServer';
|
||||
import useSide from './useSide';
|
||||
|
@ -34,11 +34,15 @@ import {
|
|||
} from './types';
|
||||
|
||||
function WarStatsPage() {
|
||||
const now = useRef(new Date());
|
||||
const dateUtils = useDateUtils();
|
||||
const now = useRef(dateUtils.date());
|
||||
const [isSubmitting, setIsSubmitting] = useState(false);
|
||||
const [results, setResults] = useState<ResultsT | null>(null);
|
||||
const [query, setQuery] = useQueryParams({
|
||||
ennobledAtGTE: withDefault(DateTimeParam, subDays(now.current, 1)),
|
||||
ennobledAtGTE: withDefault(
|
||||
DateTimeParam,
|
||||
dateUtils.subDays(now.current, 1)
|
||||
),
|
||||
ennobledAtLTE: withDefault(DateTimeParam, now.current),
|
||||
});
|
||||
const client = useApolloClient();
|
||||
|
@ -96,8 +100,8 @@ function WarStatsPage() {
|
|||
const sideTwoPlayerIDs = sideTwoPlayers.map(player => player.id);
|
||||
const sideTwoTribeIDs = sideTwoTribes.map(tribe => tribe.id);
|
||||
const defFilter = {
|
||||
ennobledAtGTE: query.ennobledAtGTE,
|
||||
ennobledAtLTE: query.ennobledAtLTE,
|
||||
ennobledAtGTE: dateUtils.zonedTimeToUTC(query.ennobledAtGTE),
|
||||
ennobledAtLTE: dateUtils.zonedTimeToUTC(query.ennobledAtLTE),
|
||||
};
|
||||
const { data } = await client.query<
|
||||
EnnoblementsQueryResult,
|
||||
|
|
|
@ -111,7 +111,6 @@ function Results({ data, server }: Props) {
|
|||
axisTop={null}
|
||||
axisRight={null}
|
||||
axisBottom={{
|
||||
tickSize: 0,
|
||||
tickPadding: 5,
|
||||
tickRotation: 0,
|
||||
format: isWidthDown750 ? () => '' : undefined,
|
||||
|
|
|
@ -4,15 +4,11 @@ import { ThemeProvider } from '@material-ui/styles';
|
|||
import { ApolloProvider } from '@apollo/client';
|
||||
import { BrowserRouter, Route } from 'react-router-dom';
|
||||
import { I18nextProvider } from 'react-i18next';
|
||||
import { MuiPickersUtilsProvider } from '@material-ui/pickers';
|
||||
import { QueryParamProvider } from 'use-query-params';
|
||||
import DateFnsUtils from '@date-io/date-fns';
|
||||
import App from './features/App';
|
||||
import createTheme from './theme/createTheme';
|
||||
import createGraphQLClient from './libs/graphql/createClient';
|
||||
import initI18N from './libs/i18n/init';
|
||||
import { getLocale } from './libs/date/locales';
|
||||
import extractVersionCodeFromHostname from './utils/extractVersionCodeFromHostname';
|
||||
import { URI as API_URI } from './config/api';
|
||||
import reportWebVitals from './reportWebVitals';
|
||||
|
||||
|
@ -21,16 +17,9 @@ const jsx = (
|
|||
<ThemeProvider theme={createTheme()}>
|
||||
<I18nextProvider i18n={initI18N()}>
|
||||
<ApolloProvider client={createGraphQLClient(API_URI)}>
|
||||
<MuiPickersUtilsProvider
|
||||
utils={DateFnsUtils}
|
||||
locale={getLocale(
|
||||
extractVersionCodeFromHostname(window.location.hostname)
|
||||
)}
|
||||
>
|
||||
<QueryParamProvider ReactRouterRoute={Route}>
|
||||
<App />
|
||||
</QueryParamProvider>
|
||||
</MuiPickersUtilsProvider>
|
||||
<QueryParamProvider ReactRouterRoute={Route}>
|
||||
<App />
|
||||
</QueryParamProvider>
|
||||
</ApolloProvider>
|
||||
</I18nextProvider>
|
||||
</ThemeProvider>
|
||||
|
|
65
src/libs/VersionContext/Provider.tsx
Normal file
65
src/libs/VersionContext/Provider.tsx
Normal file
|
@ -0,0 +1,65 @@
|
|||
import React, { useMemo } from 'react';
|
||||
import { useQuery } from '@apollo/client';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import extractVersionCodeFromHostname from '@utils/extractVersionCodeFromHostname';
|
||||
import { VERSIONS } from './queries';
|
||||
import Context from './context';
|
||||
import * as NAMESPACES from '@config/namespaces';
|
||||
|
||||
import { VersionsQueryVariables } from '@libs/graphql/types';
|
||||
import { VersionList } 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 { t } = useTranslation(NAMESPACES.COMMON);
|
||||
const versionCode = useMemo(() => {
|
||||
return extractVersionCodeFromHostname(window.location.hostname);
|
||||
}, []);
|
||||
const { loading: loadingVersion, data } = useQuery<
|
||||
VersionList,
|
||||
VersionsQueryVariables
|
||||
>(VERSIONS, {
|
||||
fetchPolicy: 'cache-first',
|
||||
variables: {
|
||||
limit: 1,
|
||||
filter: {
|
||||
code: [versionCode],
|
||||
},
|
||||
},
|
||||
});
|
||||
const version =
|
||||
data?.versions?.items && data.versions.items.length > 0
|
||||
? data.versions.items[0]
|
||||
: undefined;
|
||||
const loading = loadingVersion && !version;
|
||||
|
||||
if (loading) {
|
||||
return (
|
||||
<Spinner
|
||||
containerProps={{
|
||||
width: '100%',
|
||||
height: '100vh',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
}}
|
||||
description={t('versionContextProvider.loading')}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
if (!version) {
|
||||
return <NotFoundPage />;
|
||||
}
|
||||
|
||||
return <Context.Provider value={version}>{children}</Context.Provider>;
|
||||
}
|
||||
|
||||
export default Provider;
|
11
src/libs/VersionContext/context.ts
Normal file
11
src/libs/VersionContext/context.ts
Normal file
|
@ -0,0 +1,11 @@
|
|||
import { createContext } from 'react';
|
||||
import { Version } from './types';
|
||||
|
||||
const ctx = createContext<Version>({
|
||||
code: '',
|
||||
host: '',
|
||||
name: '',
|
||||
timezone: '',
|
||||
});
|
||||
|
||||
export default ctx;
|
324
src/libs/VersionContext/dateUtils.ts
Normal file
324
src/libs/VersionContext/dateUtils.ts
Normal file
|
@ -0,0 +1,324 @@
|
|||
import addDays from 'date-fns/addDays';
|
||||
import addMonths from 'date-fns/addMonths';
|
||||
import addYears from 'date-fns/addYears';
|
||||
import differenceInMilliseconds from 'date-fns/differenceInMilliseconds';
|
||||
import eachDayOfInterval from 'date-fns/eachDayOfInterval';
|
||||
import endOfDay from 'date-fns/endOfDay';
|
||||
import endOfWeek from 'date-fns/endOfWeek';
|
||||
import endOfYear from 'date-fns/endOfYear';
|
||||
import format from 'date-fns/format';
|
||||
import getHours from 'date-fns/getHours';
|
||||
import getSeconds from 'date-fns/getSeconds';
|
||||
import getYear from 'date-fns/getYear';
|
||||
import isAfter from 'date-fns/isAfter';
|
||||
import isBefore from 'date-fns/isBefore';
|
||||
import isEqual from 'date-fns/isEqual';
|
||||
import isSameDay from 'date-fns/isSameDay';
|
||||
import isSameYear from 'date-fns/isSameYear';
|
||||
import isSameMonth from 'date-fns/isSameMonth';
|
||||
import isSameHour from 'date-fns/isSameHour';
|
||||
import isValid from 'date-fns/isValid';
|
||||
import dateFnsParse from 'date-fns/parse';
|
||||
import setHours from 'date-fns/setHours';
|
||||
import setMinutes from 'date-fns/setMinutes';
|
||||
import setMonth from 'date-fns/setMonth';
|
||||
import setSeconds from 'date-fns/setSeconds';
|
||||
import setYear from 'date-fns/setYear';
|
||||
import startOfDay from 'date-fns/startOfDay';
|
||||
import startOfMonth from 'date-fns/startOfMonth';
|
||||
import endOfMonth from 'date-fns/endOfMonth';
|
||||
import startOfWeek from 'date-fns/startOfWeek';
|
||||
import startOfYear from 'date-fns/startOfYear';
|
||||
import { utcToZonedTime } from 'date-fns-tz';
|
||||
|
||||
import { Locale } from 'date-fns';
|
||||
import { IUtils } from '@date-io/core/IUtils';
|
||||
|
||||
export default class DateUtils implements IUtils<Date> {
|
||||
public static timezone?: string;
|
||||
|
||||
public locale?: Locale;
|
||||
|
||||
public yearFormat = 'yyyy';
|
||||
|
||||
public yearMonthFormat = 'MMMM yyyy';
|
||||
|
||||
public dateTime12hFormat = 'MMMM do hh:mm aaaa';
|
||||
|
||||
public dateTime24hFormat = 'MMMM do HH:mm';
|
||||
|
||||
public time12hFormat = 'hh:mm a';
|
||||
|
||||
public time24hFormat = 'HH:mm';
|
||||
|
||||
public dateFormat = 'MMMM do';
|
||||
|
||||
constructor({ locale }: { locale?: Locale } = {}) {
|
||||
this.locale = locale;
|
||||
}
|
||||
|
||||
public addDays(value: Date, count: number) {
|
||||
return addDays(value, count);
|
||||
}
|
||||
|
||||
public isValid(value: any) {
|
||||
return isValid(this.date(value));
|
||||
}
|
||||
|
||||
public getDiff(value: Date, comparing: Date | string) {
|
||||
return differenceInMilliseconds(value, this.date(comparing));
|
||||
}
|
||||
|
||||
public isAfter(value: Date, comparing: Date) {
|
||||
return isAfter(value, comparing);
|
||||
}
|
||||
|
||||
public isBefore(value: Date, comparing: Date) {
|
||||
return isBefore(value, comparing);
|
||||
}
|
||||
|
||||
public startOfDay(value: Date) {
|
||||
return startOfDay(value);
|
||||
}
|
||||
|
||||
public endOfDay(value: Date) {
|
||||
return endOfDay(value);
|
||||
}
|
||||
|
||||
public getHours(value: Date) {
|
||||
return getHours(value);
|
||||
}
|
||||
|
||||
public setHours(value: Date, count: number) {
|
||||
return setHours(value, count);
|
||||
}
|
||||
|
||||
public setMinutes(value: Date, count: number) {
|
||||
return setMinutes(value, count);
|
||||
}
|
||||
|
||||
public getSeconds(value: Date) {
|
||||
return getSeconds(value);
|
||||
}
|
||||
|
||||
public setSeconds(value: Date, count: number) {
|
||||
return setSeconds(value, count);
|
||||
}
|
||||
|
||||
public isSameDay(value: Date, comparing: Date) {
|
||||
return isSameDay(value, comparing);
|
||||
}
|
||||
|
||||
public isSameMonth(value: Date, comparing: Date) {
|
||||
return isSameMonth(value, comparing);
|
||||
}
|
||||
|
||||
public isSameYear(value: Date, comparing: Date) {
|
||||
return isSameYear(value, comparing);
|
||||
}
|
||||
|
||||
public isSameHour(value: Date, comparing: Date) {
|
||||
return isSameHour(value, comparing);
|
||||
}
|
||||
|
||||
public startOfMonth(value: Date) {
|
||||
return startOfMonth(value);
|
||||
}
|
||||
|
||||
public endOfMonth(value: Date) {
|
||||
return endOfMonth(value);
|
||||
}
|
||||
|
||||
public getYear(value: Date) {
|
||||
return getYear(value);
|
||||
}
|
||||
|
||||
public setYear(value: Date, count: number) {
|
||||
return setYear(value, count);
|
||||
}
|
||||
|
||||
public date(value?: any) {
|
||||
if (typeof value === 'undefined') {
|
||||
if (!DateUtils.timezone) {
|
||||
return new Date();
|
||||
}
|
||||
return utcToZonedTime(new Date(), DateUtils.timezone);
|
||||
}
|
||||
|
||||
if (value instanceof Date) {
|
||||
return value;
|
||||
}
|
||||
|
||||
if (!DateUtils.timezone) {
|
||||
return new Date(value);
|
||||
}
|
||||
return utcToZonedTime(value, DateUtils.timezone);
|
||||
}
|
||||
|
||||
public parse(value: string, formatString: string) {
|
||||
if (value === '') {
|
||||
return null;
|
||||
}
|
||||
|
||||
return dateFnsParse(value, formatString, this.date(), {
|
||||
locale: this.locale,
|
||||
});
|
||||
}
|
||||
|
||||
public format(date: Date, formatString: string) {
|
||||
return format(date, formatString, { locale: this.locale });
|
||||
}
|
||||
|
||||
public isEqual(date: any, comparing: any) {
|
||||
if (date === null && comparing === null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return isEqual(date, comparing);
|
||||
}
|
||||
|
||||
public isNull(date: Date) {
|
||||
return date === null;
|
||||
}
|
||||
|
||||
public isAfterDay(date: Date, value: Date) {
|
||||
return isAfter(date, endOfDay(value));
|
||||
}
|
||||
|
||||
public isBeforeDay(date: Date, value: Date) {
|
||||
return isBefore(date, startOfDay(value));
|
||||
}
|
||||
|
||||
public isBeforeYear(date: Date, value: Date) {
|
||||
return isBefore(date, startOfYear(value));
|
||||
}
|
||||
|
||||
public isAfterYear(date: Date, value: Date) {
|
||||
return isAfter(date, endOfYear(value));
|
||||
}
|
||||
|
||||
public formatNumber(numberToFormat: string) {
|
||||
return numberToFormat;
|
||||
}
|
||||
|
||||
public getMinutes(date: Date) {
|
||||
return date.getMinutes();
|
||||
}
|
||||
|
||||
public getMonth(date: Date) {
|
||||
return date.getMonth();
|
||||
}
|
||||
|
||||
public setMonth(date: Date, count: number) {
|
||||
return setMonth(date, count);
|
||||
}
|
||||
|
||||
public getMeridiemText(ampm: 'am' | 'pm') {
|
||||
return ampm === 'am' ? 'AM' : 'PM';
|
||||
}
|
||||
|
||||
public getNextMonth(date: Date) {
|
||||
return addMonths(date, 1);
|
||||
}
|
||||
|
||||
public getPreviousMonth(date: Date) {
|
||||
return addMonths(date, -1);
|
||||
}
|
||||
|
||||
public getMonthArray(date: Date) {
|
||||
const firstMonth = startOfYear(date);
|
||||
const monthArray = [firstMonth];
|
||||
|
||||
while (monthArray.length < 12) {
|
||||
const prevMonth = monthArray[monthArray.length - 1];
|
||||
monthArray.push(this.getNextMonth(prevMonth));
|
||||
}
|
||||
|
||||
return monthArray;
|
||||
}
|
||||
|
||||
public mergeDateAndTime(date: Date, time: Date) {
|
||||
return this.setMinutes(
|
||||
this.setHours(date, this.getHours(time)),
|
||||
this.getMinutes(time)
|
||||
);
|
||||
}
|
||||
|
||||
public getWeekdays() {
|
||||
const now = new Date();
|
||||
return eachDayOfInterval({
|
||||
start: startOfWeek(now, { locale: this.locale }),
|
||||
end: endOfWeek(now, { locale: this.locale }),
|
||||
}).map(day => this.format(day, 'EEEEEE'));
|
||||
}
|
||||
|
||||
public getWeekArray(date: Date) {
|
||||
const start = startOfWeek(startOfMonth(date), { locale: this.locale });
|
||||
const end = endOfWeek(endOfMonth(date), { locale: this.locale });
|
||||
|
||||
let count = 0;
|
||||
let current = start;
|
||||
const nestedWeeks: Date[][] = [];
|
||||
|
||||
while (isBefore(current, end)) {
|
||||
const weekNumber = Math.floor(count / 7);
|
||||
nestedWeeks[weekNumber] = nestedWeeks[weekNumber] || [];
|
||||
nestedWeeks[weekNumber].push(current);
|
||||
current = addDays(current, 1);
|
||||
count += 1;
|
||||
}
|
||||
|
||||
return nestedWeeks;
|
||||
}
|
||||
|
||||
public getYearRange(start: Date, end: Date) {
|
||||
const startDate = startOfYear(start);
|
||||
const endDate = endOfYear(end);
|
||||
const years: Date[] = [];
|
||||
|
||||
let current = startDate;
|
||||
while (isBefore(current, endDate)) {
|
||||
years.push(current);
|
||||
current = addYears(current, 1);
|
||||
}
|
||||
|
||||
return years;
|
||||
}
|
||||
|
||||
// displaying methpds
|
||||
public getCalendarHeaderText(date: Date) {
|
||||
return this.format(date, this.yearMonthFormat);
|
||||
}
|
||||
|
||||
public getYearText(date: Date) {
|
||||
return this.format(date, 'yyyy');
|
||||
}
|
||||
|
||||
public getDatePickerHeaderText(date: Date) {
|
||||
return this.format(date, 'EEE, MMM d');
|
||||
}
|
||||
|
||||
public getDateTimePickerHeaderText(date: Date) {
|
||||
return this.format(date, 'MMM d');
|
||||
}
|
||||
|
||||
public getMonthText(date: Date) {
|
||||
return this.format(date, 'MMMM');
|
||||
}
|
||||
|
||||
public getDayText(date: Date) {
|
||||
return this.format(date, 'd');
|
||||
}
|
||||
|
||||
public getHourText(date: Date, ampm: boolean) {
|
||||
return this.format(date, ampm ? 'hh' : 'HH');
|
||||
}
|
||||
|
||||
public getMinuteText(date: Date) {
|
||||
return this.format(date, 'mm');
|
||||
}
|
||||
|
||||
public getSecondText(date: Date) {
|
||||
return this.format(date, 'ss');
|
||||
}
|
||||
}
|
14
src/libs/VersionContext/queries.ts
Normal file
14
src/libs/VersionContext/queries.ts
Normal file
|
@ -0,0 +1,14 @@
|
|||
import { gql } from '@apollo/client';
|
||||
|
||||
export const VERSIONS = gql`
|
||||
query versions($filter: VersionFilter, $sort: [String!], $limit: Int) {
|
||||
versions(filter: $filter, sort: $sort, limit: $limit) {
|
||||
items {
|
||||
code
|
||||
host
|
||||
timezone
|
||||
name
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
12
src/libs/VersionContext/types.ts
Normal file
12
src/libs/VersionContext/types.ts
Normal file
|
@ -0,0 +1,12 @@
|
|||
import { List } from '@libs/graphql/types';
|
||||
|
||||
export type Version = {
|
||||
code: string;
|
||||
host: string;
|
||||
name: string;
|
||||
timezone: string;
|
||||
};
|
||||
|
||||
export type VersionList = {
|
||||
versions?: List<Version[]>;
|
||||
};
|
3
src/libs/VersionContext/useDateUtils.ts
Normal file
3
src/libs/VersionContext/useDateUtils.ts
Normal file
|
@ -0,0 +1,3 @@
|
|||
import { useUtils } from '@material-ui/pickers';
|
||||
|
||||
export default useUtils;
|
9
src/libs/VersionContext/useVersion.ts
Normal file
9
src/libs/VersionContext/useVersion.ts
Normal file
|
@ -0,0 +1,9 @@
|
|||
import { useContext } from 'react';
|
||||
import ctx from './context';
|
||||
import { Version } from './types';
|
||||
|
||||
const useVersion = (): Version => {
|
||||
return useContext(ctx);
|
||||
};
|
||||
|
||||
export default useVersion;
|
376
src/libs/date/DateUtils.ts
Normal file
376
src/libs/date/DateUtils.ts
Normal file
|
@ -0,0 +1,376 @@
|
|||
import addDays from 'date-fns/addDays';
|
||||
import addMonths from 'date-fns/addMonths';
|
||||
import addYears from 'date-fns/addYears';
|
||||
import subDays from 'date-fns/subDays';
|
||||
import differenceInMilliseconds from 'date-fns/differenceInMilliseconds';
|
||||
import eachDayOfInterval from 'date-fns/eachDayOfInterval';
|
||||
import endOfDay from 'date-fns/endOfDay';
|
||||
import endOfWeek from 'date-fns/endOfWeek';
|
||||
import endOfYear from 'date-fns/endOfYear';
|
||||
import format from 'date-fns/format';
|
||||
import getHours from 'date-fns/getHours';
|
||||
import getSeconds from 'date-fns/getSeconds';
|
||||
import getYear from 'date-fns/getYear';
|
||||
import isAfter from 'date-fns/isAfter';
|
||||
import isBefore from 'date-fns/isBefore';
|
||||
import isEqual from 'date-fns/isEqual';
|
||||
import isSameDay from 'date-fns/isSameDay';
|
||||
import isSameYear from 'date-fns/isSameYear';
|
||||
import isSameMonth from 'date-fns/isSameMonth';
|
||||
import isSameHour from 'date-fns/isSameHour';
|
||||
import isValid from 'date-fns/isValid';
|
||||
import dateFnsParse from 'date-fns/parse';
|
||||
import setHours from 'date-fns/setHours';
|
||||
import setMinutes from 'date-fns/setMinutes';
|
||||
import setMonth from 'date-fns/setMonth';
|
||||
import setSeconds from 'date-fns/setSeconds';
|
||||
import setYear from 'date-fns/setYear';
|
||||
import startOfDay from 'date-fns/startOfDay';
|
||||
import startOfMonth from 'date-fns/startOfMonth';
|
||||
import endOfMonth from 'date-fns/endOfMonth';
|
||||
import startOfWeek from 'date-fns/startOfWeek';
|
||||
import startOfYear from 'date-fns/startOfYear';
|
||||
import differenceInDays from 'date-fns/differenceInDays';
|
||||
import formatDistanceToNow from 'date-fns/formatDistanceToNow';
|
||||
import { utcToZonedTime, zonedTimeToUtc } from 'date-fns-tz';
|
||||
|
||||
import { Locale } from 'date-fns';
|
||||
import { IUtils } from '@date-io/core/IUtils';
|
||||
|
||||
export default class DateUtils implements IUtils<Date> {
|
||||
public static timezone?: string;
|
||||
|
||||
public locale?: Locale;
|
||||
|
||||
public yearFormat = 'yyyy';
|
||||
|
||||
public yearMonthFormat = 'MMMM yyyy';
|
||||
|
||||
public dateTime12hFormat = 'MMMM do hh:mm aaaa';
|
||||
|
||||
public dateTime24hFormat = 'MMMM do HH:mm';
|
||||
|
||||
public time12hFormat = 'hh:mm a';
|
||||
|
||||
public time24hFormat = 'HH:mm';
|
||||
|
||||
public dateFormat = 'MMMM do';
|
||||
|
||||
constructor({ locale }: { locale?: Locale } = {}) {
|
||||
this.locale = locale;
|
||||
}
|
||||
|
||||
public addDays(value: Date, count: number) {
|
||||
return addDays(value, count);
|
||||
}
|
||||
|
||||
public subDays(date: Date, amount: number): Date {
|
||||
return subDays(date, amount);
|
||||
}
|
||||
|
||||
public isValid(value: any) {
|
||||
return isValid(this.date(value));
|
||||
}
|
||||
|
||||
public getDiff(value: Date, comparing: Date | string) {
|
||||
return differenceInMilliseconds(value, this.date(comparing));
|
||||
}
|
||||
|
||||
public differenceInDays(dateLeft: Date, dateRight: Date): number {
|
||||
return differenceInDays(dateLeft, dateRight);
|
||||
}
|
||||
|
||||
public isAfter(value: Date, comparing: Date) {
|
||||
return isAfter(value, comparing);
|
||||
}
|
||||
|
||||
public isBefore(value: Date, comparing: Date) {
|
||||
return isBefore(value, comparing);
|
||||
}
|
||||
|
||||
public startOfDay(value: Date) {
|
||||
return startOfDay(value);
|
||||
}
|
||||
|
||||
public endOfDay(value: Date) {
|
||||
return endOfDay(value);
|
||||
}
|
||||
|
||||
public getHours(value: Date) {
|
||||
return getHours(value);
|
||||
}
|
||||
|
||||
public setHours(value: Date, count: number) {
|
||||
return setHours(value, count);
|
||||
}
|
||||
|
||||
public setMinutes(value: Date, count: number) {
|
||||
return setMinutes(value, count);
|
||||
}
|
||||
|
||||
public getSeconds(value: Date) {
|
||||
return getSeconds(value);
|
||||
}
|
||||
|
||||
public setSeconds(value: Date, count: number) {
|
||||
return setSeconds(value, count);
|
||||
}
|
||||
|
||||
public isSameDay(value: Date, comparing: Date) {
|
||||
return isSameDay(value, comparing);
|
||||
}
|
||||
|
||||
public isSameMonth(value: Date, comparing: Date) {
|
||||
return isSameMonth(value, comparing);
|
||||
}
|
||||
|
||||
public isSameYear(value: Date, comparing: Date) {
|
||||
return isSameYear(value, comparing);
|
||||
}
|
||||
|
||||
public isSameHour(value: Date, comparing: Date) {
|
||||
return isSameHour(value, comparing);
|
||||
}
|
||||
|
||||
public startOfMonth(value: Date) {
|
||||
return startOfMonth(value);
|
||||
}
|
||||
|
||||
public endOfMonth(value: Date) {
|
||||
return endOfMonth(value);
|
||||
}
|
||||
|
||||
public getYear(value: Date) {
|
||||
return getYear(value);
|
||||
}
|
||||
|
||||
public setYear(value: Date, count: number) {
|
||||
return setYear(value, count);
|
||||
}
|
||||
|
||||
public dateInTZ(value: any, timezone: string): Date {
|
||||
const date = new Date(value);
|
||||
return new Date(date.toLocaleString('en-US', { timeZone: timezone }));
|
||||
}
|
||||
|
||||
public date(value?: any) {
|
||||
if (typeof value === 'undefined') {
|
||||
if (!DateUtils.timezone) {
|
||||
return new Date();
|
||||
}
|
||||
return this.dateInTZ(new Date(), DateUtils.timezone);
|
||||
}
|
||||
|
||||
if (value instanceof Date) {
|
||||
return value;
|
||||
}
|
||||
|
||||
if (!DateUtils.timezone) {
|
||||
return new Date(value);
|
||||
}
|
||||
return this.dateInTZ(value, DateUtils.timezone);
|
||||
}
|
||||
|
||||
public parse(value: string, formatString: string) {
|
||||
if (value === '') {
|
||||
return null;
|
||||
}
|
||||
|
||||
return dateFnsParse(value, formatString, this.date(), {
|
||||
locale: this.locale,
|
||||
});
|
||||
}
|
||||
|
||||
public format(date: Date, formatString: string) {
|
||||
return format(date, formatString, { locale: this.locale });
|
||||
}
|
||||
|
||||
public toJSON(date: Date) {
|
||||
return (
|
||||
this.format(date, 'yyyy-MM-dd') +
|
||||
'T' +
|
||||
this.format(date, 'HH:mm:ss') +
|
||||
'Z'
|
||||
);
|
||||
}
|
||||
|
||||
public isEqual(date: any, comparing: any) {
|
||||
if (date === null && comparing === null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return isEqual(date, comparing);
|
||||
}
|
||||
|
||||
public isNull(date: Date) {
|
||||
return date === null;
|
||||
}
|
||||
|
||||
public isAfterDay(date: Date, value: Date) {
|
||||
return isAfter(date, endOfDay(value));
|
||||
}
|
||||
|
||||
public isBeforeDay(date: Date, value: Date) {
|
||||
return isBefore(date, startOfDay(value));
|
||||
}
|
||||
|
||||
public isBeforeYear(date: Date, value: Date) {
|
||||
return isBefore(date, startOfYear(value));
|
||||
}
|
||||
|
||||
public isAfterYear(date: Date, value: Date) {
|
||||
return isAfter(date, endOfYear(value));
|
||||
}
|
||||
|
||||
public formatNumber(numberToFormat: string) {
|
||||
return numberToFormat;
|
||||
}
|
||||
|
||||
public getMinutes(date: Date) {
|
||||
return date.getMinutes();
|
||||
}
|
||||
|
||||
public getMonth(date: Date) {
|
||||
return date.getMonth();
|
||||
}
|
||||
|
||||
public setMonth(date: Date, count: number) {
|
||||
return setMonth(date, count);
|
||||
}
|
||||
|
||||
public getMeridiemText(ampm: 'am' | 'pm') {
|
||||
return ampm === 'am' ? 'AM' : 'PM';
|
||||
}
|
||||
|
||||
public getNextMonth(date: Date) {
|
||||
return addMonths(date, 1);
|
||||
}
|
||||
|
||||
public getPreviousMonth(date: Date) {
|
||||
return addMonths(date, -1);
|
||||
}
|
||||
|
||||
public getMonthArray(date: Date) {
|
||||
const firstMonth = startOfYear(date);
|
||||
const monthArray = [firstMonth];
|
||||
|
||||
while (monthArray.length < 12) {
|
||||
const prevMonth = monthArray[monthArray.length - 1];
|
||||
monthArray.push(this.getNextMonth(prevMonth));
|
||||
}
|
||||
|
||||
return monthArray;
|
||||
}
|
||||
|
||||
public mergeDateAndTime(date: Date, time: Date) {
|
||||
return this.setMinutes(
|
||||
this.setHours(date, this.getHours(time)),
|
||||
this.getMinutes(time)
|
||||
);
|
||||
}
|
||||
|
||||
public getWeekdays() {
|
||||
const now = new Date();
|
||||
return eachDayOfInterval({
|
||||
start: startOfWeek(now, { locale: this.locale }),
|
||||
end: endOfWeek(now, { locale: this.locale }),
|
||||
}).map(day => this.format(day, 'EEEEEE'));
|
||||
}
|
||||
|
||||
public getWeekArray(date: Date) {
|
||||
const start = startOfWeek(startOfMonth(date), { locale: this.locale });
|
||||
const end = endOfWeek(endOfMonth(date), { locale: this.locale });
|
||||
|
||||
let count = 0;
|
||||
let current = start;
|
||||
const nestedWeeks: Date[][] = [];
|
||||
|
||||
while (isBefore(current, end)) {
|
||||
const weekNumber = Math.floor(count / 7);
|
||||
nestedWeeks[weekNumber] = nestedWeeks[weekNumber] || [];
|
||||
nestedWeeks[weekNumber].push(current);
|
||||
current = addDays(current, 1);
|
||||
count += 1;
|
||||
}
|
||||
|
||||
return nestedWeeks;
|
||||
}
|
||||
|
||||
public getYearRange(start: Date, end: Date) {
|
||||
const startDate = startOfYear(start);
|
||||
const endDate = endOfYear(end);
|
||||
const years: Date[] = [];
|
||||
|
||||
let current = startDate;
|
||||
while (isBefore(current, endDate)) {
|
||||
years.push(current);
|
||||
current = addYears(current, 1);
|
||||
}
|
||||
|
||||
return years;
|
||||
}
|
||||
|
||||
// displaying methpds
|
||||
public getCalendarHeaderText(date: Date) {
|
||||
return this.format(date, this.yearMonthFormat);
|
||||
}
|
||||
|
||||
public getYearText(date: Date) {
|
||||
return this.format(date, 'yyyy');
|
||||
}
|
||||
|
||||
public getDatePickerHeaderText(date: Date) {
|
||||
return this.format(date, 'EEE, MMM d');
|
||||
}
|
||||
|
||||
public getDateTimePickerHeaderText(date: Date) {
|
||||
return this.format(date, 'MMM d');
|
||||
}
|
||||
|
||||
public getMonthText(date: Date) {
|
||||
return this.format(date, 'MMMM');
|
||||
}
|
||||
|
||||
public getDayText(date: Date) {
|
||||
return this.format(date, 'd');
|
||||
}
|
||||
|
||||
public getHourText(date: Date, ampm: boolean) {
|
||||
return this.format(date, ampm ? 'hh' : 'HH');
|
||||
}
|
||||
|
||||
public getMinuteText(date: Date) {
|
||||
return this.format(date, 'mm');
|
||||
}
|
||||
|
||||
public getSecondText(date: Date) {
|
||||
return this.format(date, 'ss');
|
||||
}
|
||||
|
||||
public formatDistanceToNow(
|
||||
date: Date,
|
||||
opts: {
|
||||
includeSeconds?: boolean;
|
||||
addSuffix?: boolean;
|
||||
} = {}
|
||||
) {
|
||||
return formatDistanceToNow(date, {
|
||||
...opts,
|
||||
locale: this.locale,
|
||||
});
|
||||
}
|
||||
|
||||
public UTCToZonedTime(date: Date): Date {
|
||||
if (!DateUtils.timezone) {
|
||||
return date;
|
||||
}
|
||||
return utcToZonedTime(date, DateUtils.timezone);
|
||||
}
|
||||
|
||||
public zonedTimeToUTC(date: Date): Date {
|
||||
if (!DateUtils.timezone) {
|
||||
return date;
|
||||
}
|
||||
return zonedTimeToUtc(date, DateUtils.timezone);
|
||||
}
|
||||
}
|
30
src/libs/date/DateUtilsProvider.tsx
Normal file
30
src/libs/date/DateUtilsProvider.tsx
Normal file
|
@ -0,0 +1,30 @@
|
|||
import React, { useMemo } from 'react';
|
||||
import useVersion from '@libs/VersionContext/useVersion';
|
||||
import { getLocale } from './locales';
|
||||
import DateUtils from './DateUtils';
|
||||
|
||||
import { MuiPickersUtilsProvider } from '@material-ui/pickers';
|
||||
import Context from './context';
|
||||
|
||||
export interface Props {
|
||||
children: React.ReactNode;
|
||||
}
|
||||
|
||||
function DateUtilsProvider({ children }: Props) {
|
||||
const version = useVersion();
|
||||
const locale = useMemo(() => {
|
||||
return getLocale(version.code);
|
||||
}, [version.code]);
|
||||
const dateUtils = useMemo(() => {
|
||||
DateUtils.timezone = version.timezone;
|
||||
return new DateUtils({ locale });
|
||||
}, [version.timezone, locale]);
|
||||
|
||||
return (
|
||||
<MuiPickersUtilsProvider utils={DateUtils}>
|
||||
<Context.Provider value={dateUtils}>{children}</Context.Provider>
|
||||
</MuiPickersUtilsProvider>
|
||||
);
|
||||
}
|
||||
|
||||
export default DateUtilsProvider;
|
7
src/libs/date/context.ts
Normal file
7
src/libs/date/context.ts
Normal file
|
@ -0,0 +1,7 @@
|
|||
import { createContext } from 'react';
|
||||
import DateUtils from './DateUtils';
|
||||
|
||||
const ctx = createContext<DateUtils>(new DateUtils());
|
||||
ctx.displayName = 'DateUtilsProvider';
|
||||
|
||||
export default ctx;
|
8
src/libs/date/useDateUtils.ts
Normal file
8
src/libs/date/useDateUtils.ts
Normal file
|
@ -0,0 +1,8 @@
|
|||
import { useContext } from 'react';
|
||||
import ctx from './context';
|
||||
|
||||
const useDateUtils = () => {
|
||||
return useContext(ctx);
|
||||
};
|
||||
|
||||
export default useDateUtils;
|
|
@ -13,6 +13,9 @@ const translations = {
|
|||
closed: 'Closed',
|
||||
open: 'Open',
|
||||
},
|
||||
versionContextProvider: {
|
||||
loading: 'Loading...',
|
||||
},
|
||||
devNote: `This website is still under development and some things may be broken.`,
|
||||
mainLayout: {
|
||||
header: {
|
||||
|
|
|
@ -13,6 +13,9 @@ const translations = {
|
|||
closed: 'Zamknięty',
|
||||
open: 'Otwarty',
|
||||
},
|
||||
versionContextProvider: {
|
||||
loading: 'Ładowanie...',
|
||||
},
|
||||
devNote: `Strona jest ciągle w procesie tworzenia i mogą występować błędy.`,
|
||||
mainLayout: {
|
||||
header: {
|
||||
|
|
Reference in New Issue
Block a user