[FEATURE]: add a new route - /server/:key/player/:id/ennoblements

This commit is contained in:
Dawid Wysokiński 2020-12-08 20:23:08 +01:00
parent 024130b8d3
commit 6839ffb700
22 changed files with 367 additions and 17 deletions

View File

@ -25,6 +25,7 @@ export interface Props<T> {
orderDirection?: OrderDirection;
selection?: boolean;
idFieldName?: string;
getRowKey?: (row: T, index: number) => string | number | null | undefined;
onRequestSort?: (
property: string,
orderDirection: OrderDirection
@ -56,6 +57,7 @@ function Table<T extends object>({
size,
selected,
onSelect,
getRowKey,
}: Props<T>) {
const { t } = useTranslation(TABLE);
@ -100,7 +102,11 @@ function Table<T extends object>({
return (
<TableRow
key={
isObjKey(item, idFieldName) ? item[idFieldName] + '' : index
getRowKey
? getRowKey(item, index)
: isObjKey(item, idFieldName)
? item[idFieldName] + ''
: index
}
row={item}
actions={actions}

View File

@ -17,5 +17,5 @@ export const DATE_FORMAT = {
MONTH_AND_YEAR: 'yyyy-MM',
DAY_MONTH_AND_YEAR: 'yyyy-MM-dd',
HOUR_MINUTES_DAY_MONTH_AND_YEAR: 'yyyy-MM-dd HH:mm',
HOUR_MINUTES_SECONDS_DAY_MONTH_AND_YEAR: 'yyyy-MM-dd HH:mm',
HOUR_MINUTES_SECONDS_DAY_MONTH_AND_YEAR: 'yyyy-MM-dd HH:mm:ss',
};

View File

@ -10,5 +10,6 @@ export const SERVER_PAGE = {
COMMON: 'server-page/player-page/common',
INDEX_PAGE: '/server-page/player-page/index-page',
HISTORY_PAGE: '/server-page/player-page/history-page',
ENNOBLEMENTS_PAGE: '/server-page/player-page/ennoblements-page',
},
};

View File

@ -7,13 +7,13 @@ export const SERVER_PAGE = {
INDEX_PAGE: '/server/:key/tribe/:id',
HISTORY_PAGE: '/server/:key/tribe/:id/history',
TRIBE_CHANGES_PAGE: '/server/:key/tribe/:id/tribe-changes',
CONQUERS_PAGE: '/server/:key/tribe/:id/conquers',
ENNOBLEMENTS_PAGE: '/server/:key/tribe/:id/ennoblements',
},
PLAYER_PAGE: {
INDEX_PAGE: '/server/:key/player/:id',
HISTORY_PAGE: '/server/:key/player/:id/history',
TRIBE_CHANGES_PAGE: '/server/:key/player/:id/tribe-changes',
CONQUERS_PAGE: '/server/:key/player/:id/conquers',
ENNOBLEMENTS_PAGE: '/server/:key/player/:id/ennoblements',
},
VILLAGE_PAGE: {
INDEX_PAGE: '/server/:key/village/:id',

View File

@ -0,0 +1,30 @@
import React from 'react';
import { Property } from 'csstype';
import { makeStyles } from '@material-ui/core/styles';
interface UseStylesProps {
backgroundColor?: Property.BackgroundColor;
}
interface Props extends UseStylesProps {}
function Dot({ backgroundColor }: Props) {
const classes = useStyles();
return (
<div
className={classes.dot}
style={{ backgroundColor: backgroundColor ?? 'green' }}
/>
);
}
const useStyles = makeStyles(theme => ({
dot: {
borderRadius: '50%',
width: theme.spacing(2),
height: theme.spacing(2),
},
}));
export default Dot;

View File

@ -2,21 +2,25 @@ import React from 'react';
import { SERVER_PAGE } from '@config/routes';
import Link from '@common/Link/Link';
export interface Tribe {
id: number;
tag: string;
}
export interface Player {
id: number;
name: string;
tribe?: {
id: number;
tag: string;
};
tribe?: Tribe;
}
export interface Props {
player: Player;
server: string;
tribe?: Tribe;
}
function PlayerProfileLink({ player, server }: Props) {
function PlayerProfileLink({ player, server, tribe }: Props) {
const t = tribe ? tribe : player.tribe ? player.tribe : undefined;
return (
<span>
<Link
@ -25,14 +29,14 @@ function PlayerProfileLink({ player, server }: Props) {
>
{player.name}
</Link>
{player.tribe && (
{t && (
<span>
{` (`}
<Link
to={SERVER_PAGE.TRIBE_PAGE.INDEX_PAGE}
params={{ key: server, id: player.tribe.id }}
params={{ key: server, id: t.id }}
>
{player.tribe.tag}
{t.tag}
</Link>
)
</span>

View File

@ -5,6 +5,7 @@ import { Switch, Route, RouteProps } from 'react-router-dom';
import PlayerProvider from './libs/PlayerPageContext/Provider';
import IndexPage from './features/IndexPage/IndexPage';
import HistoryPage from './features/HistoryPage/HistoryPage';
import EnnoblementsPage from './features/EnnoblementsPage/EnnoblementsPage';
import NotFoundPage from '../NotFoundPage/NotFoundPage';
const EnhancedRoute = ({ children, ...rest }: RouteProps) => {
@ -24,6 +25,9 @@ function PlayerPage() {
<EnhancedRoute exact path={SERVER_PAGE.PLAYER_PAGE.HISTORY_PAGE}>
<HistoryPage />
</EnhancedRoute>
<EnhancedRoute exact path={SERVER_PAGE.PLAYER_PAGE.ENNOBLEMENTS_PAGE}>
<EnnoblementsPage />
</EnhancedRoute>
<Route path="*">
<NotFoundPage />
</Route>

View File

@ -46,8 +46,8 @@ function PageLayout({ children }: Props) {
label: t('pageLayout.tabs.tribeChanges'),
},
{
to: ROUTES.SERVER_PAGE.PLAYER_PAGE.CONQUERS_PAGE,
label: t('pageLayout.tabs.conquersPage'),
to: ROUTES.SERVER_PAGE.PLAYER_PAGE.ENNOBLEMENTS_PAGE,
label: t('pageLayout.tabs.ennoblementsPage'),
},
];
}, [t]);

View File

@ -0,0 +1,26 @@
import React from 'react';
import { useTranslation } from 'react-i18next';
import useTitle from '@libs/useTitle';
import useServer from '@features/ServerPage/libs/ServerContext/useServer';
import usePlayer from '../../libs/PlayerPageContext/usePlayer';
import { SERVER_PAGE } from '@config/namespaces';
import { Container } from '@material-ui/core';
import PageLayout from '../../common/PageLayout/PageLayout';
import Ennoblements from './components/Ennoblements/Ennoblements';
function EnnoblementsPage() {
const { key } = useServer();
const player = usePlayer();
const { t } = useTranslation(SERVER_PAGE.PLAYER_PAGE.ENNOBLEMENTS_PAGE);
useTitle(t('title', { key, name: player.name }));
return (
<PageLayout>
<Container>
<Ennoblements t={t} server={key} playerID={player.id} />
</Container>
</PageLayout>
);
}
export default EnnoblementsPage;

View File

@ -0,0 +1,153 @@
import React from 'react';
import { useQuery } from '@apollo/client';
import { useQueryParams, NumberParam, withDefault } from 'use-query-params';
import { SERVER_PAGE } from '@config/routes';
import { ENNOBLEMENTS } from './queries';
import { LIMIT } from './constants';
import buildVillageName from '@utils/buildVillageName';
import { Paper } from '@material-ui/core';
import Table from '@common/Table/Table';
import Link from '@common/Link/Link';
import PlayerProfileLink from '@features/ServerPage/common/PlayerProfileLink/PlayerProfileLink';
import Dot from '@features/ServerPage/common/Dot/Dot';
import { TFunction } from 'i18next';
import { EnnoblementsQueryVariables } from '@libs/graphql/types';
import { Ennoblements as EnnoblementsT, Ennoblement } from './types';
export interface Props {
server: string;
playerID: number;
t: TFunction;
}
function Ennoblements({ t, server, playerID }: Props) {
const [query, setQuery] = useQueryParams({
page: withDefault(NumberParam, 0),
limit: withDefault(NumberParam, LIMIT),
});
const { data: queryData, loading: queryLoading } = useQuery<
EnnoblementsT,
EnnoblementsQueryVariables
>(ENNOBLEMENTS, {
fetchPolicy: 'cache-and-network',
variables: {
limit: query.limit,
offset: query.page * query.limit,
sort: ['ennobledAt DESC'],
filter: {
or: {
newOwnerID: [playerID],
oldOwnerID: [playerID],
},
},
server,
},
});
const ennoblements = queryData?.ennoblements?.items ?? [];
const loading = ennoblements.length === 0 && queryLoading;
const total = queryData?.ennoblements?.total ?? 0;
return (
<Paper>
<Table
columns={[
{
field: 'type',
label: '',
sortable: false,
valueFormatter: (e: Ennoblement) => {
if (
e.newOwner.id === playerID &&
e.oldOwner &&
e.oldOwner.id === playerID
) {
return <Dot backgroundColor="yellow" />;
} else if (e.oldOwner && e.oldOwner.id === playerID) {
return <Dot backgroundColor="red" />;
}
return <Dot backgroundColor="green" />;
},
},
{
field: 'ennobledAt',
label: t('ennoblements.columns.ennobledAt'),
sortable: false,
type: 'datetime',
},
{
field: 'village',
label: t('ennoblements.columns.village'),
sortable: false,
valueFormatter: (e: Ennoblement) => {
return (
<Link
to={SERVER_PAGE.VILLAGE_PAGE.INDEX_PAGE}
params={{ key: server, id: e.village.id }}
>
{buildVillageName(e.village.name, e.village.x, e.village.y)}
</Link>
);
},
},
{
field: 'oldOwner',
label: t('ennoblements.columns.oldOwner'),
sortable: false,
valueFormatter: (e: Ennoblement) => {
if (e.oldOwner) {
return (
<PlayerProfileLink
server={server}
player={e.oldOwner}
tribe={e.oldOwnerTribe}
/>
);
}
return '-';
},
},
{
field: 'newOwner',
label: t('ennoblements.columns.newOwner'),
sortable: false,
valueFormatter: (e: Ennoblement) => {
return (
<PlayerProfileLink
server={server}
player={e.newOwner}
tribe={e.newOwnerTribe}
/>
);
},
},
]}
loading={loading}
data={ennoblements}
size="small"
footerProps={{
page: loading ? 0 : query.page,
rowsPerPage: query.limit,
count: total,
onChangePage: page => {
if (window.scrollTo) {
window.scrollTo({ top: 0, behavior: `smooth` });
}
setQuery({ page });
},
onChangeRowsPerPage: rowsPerPage => {
if (window.scrollTo) {
window.scrollTo({ top: 0, behavior: `smooth` });
}
requestAnimationFrame(() => {
setQuery({ limit: rowsPerPage, page: 0 });
});
},
}}
/>
</Paper>
);
}
export default Ennoblements;

View File

@ -0,0 +1,46 @@
import { gql } from '@apollo/client';
export const ENNOBLEMENTS = gql`
query ennoblements(
$server: String!
$sort: [String!]
$limit: Int
$offset: Int
$filter: EnnoblementFilter
) {
ennoblements(
server: $server
filter: $filter
sort: $sort
limit: $limit
offset: $offset
) {
items {
village {
name
x
y
id
}
newOwner {
id
name
}
newOwnerTribe {
id
tag
}
oldOwner {
id
name
}
oldOwnerTribe {
id
tag
}
ennobledAt
}
total
}
}
`;

View File

@ -0,0 +1,31 @@
import { List } from '@libs/graphql/types';
export type Ennoblement = {
village: {
id: number;
name: string;
x: number;
y: number;
};
newOwner: {
id: number;
name: string;
};
newOwnerTribe?: {
id: number;
tag: string;
};
oldOwner?: {
id: number;
name: string;
};
oldOwnerTribe?: {
id: number;
tag: string;
};
ennobledAt: Date | string;
};
export type Ennoblements = {
ennoblements?: List<Ennoblement[]>;
};

View File

@ -67,6 +67,19 @@ export type TribeFilter = {
export type TribesQueryVariables = QueryVariablesWithServer<TribeFilter>;
export type EnnoblementFilter = {
or?: {
newOwnerID?: number[];
newOwnerTribeID?: number[];
oldOwnerID?: number[];
oldOwnerTribeID?: number[];
};
};
export type EnnoblementsQueryVariables = QueryVariablesWithServer<
EnnoblementFilter
>;
export type DailyPlayerStatsFilter = {
createDateGT?: Date | 'string';
player?: PlayerFilter;

View File

@ -9,7 +9,7 @@ const translations = {
indexPage: 'Profile',
historyPage: 'History',
tribeChanges: 'Tribe changes',
conquersPage: 'Conquers',
ennoblementsPage: 'Ennoblements',
},
achievements: {
playerRank: '#{{rank}} points',

View File

@ -0,0 +1,13 @@
const translations = {
title: `{{key}} - {{name}}'s ennoblements`,
ennoblements: {
columns: {
ennobledAt: 'Date',
village: 'Village',
oldOwner: 'Old owner',
newOwner: 'New owner',
},
},
};
export default translations;

View File

@ -1,5 +1,5 @@
const translations = {
title: `{{key}} - {{name}}'s player history`,
title: `{{key}} - {{name}}'s history`,
playerHistory: {
columns: {
createDate: 'Date',

View File

@ -2,11 +2,13 @@ import * as NAMESPACES from '@config/namespaces';
import common from './common';
import indexPage from './index-page';
import historyPage from './history-page';
import ennoblementsPage from './ennoblements-page';
const translations = {
[NAMESPACES.SERVER_PAGE.PLAYER_PAGE.COMMON]: common,
[NAMESPACES.SERVER_PAGE.PLAYER_PAGE.INDEX_PAGE]: indexPage,
[NAMESPACES.SERVER_PAGE.PLAYER_PAGE.HISTORY_PAGE]: historyPage,
[NAMESPACES.SERVER_PAGE.PLAYER_PAGE.ENNOBLEMENTS_PAGE]: ennoblementsPage,
};
export default translations;

View File

@ -9,7 +9,7 @@ const translations = {
indexPage: 'Profil',
historyPage: 'Historia',
tribeChanges: 'Zmiany plemion',
conquersPage: 'Przejęcia',
ennoblementsPage: 'Przejęcia',
},
achievements: {
playerRank: '#{{rank}} punkty',

View File

@ -0,0 +1,13 @@
const translations = {
title: `{{key}} - podboje gracza {{name}}`,
ennoblements: {
columns: {
ennobledAt: 'Data',
village: 'Wioska',
oldOwner: 'Stary właściciel',
newOwner: 'Nowy właściciel',
},
},
};
export default translations;

View File

@ -2,11 +2,13 @@ import * as NAMESPACES from '@config/namespaces';
import common from './common';
import indexPage from './index-page';
import historyPage from './history-page';
import ennoblementsPage from './ennoblements-page';
const translations = {
[NAMESPACES.SERVER_PAGE.PLAYER_PAGE.COMMON]: common,
[NAMESPACES.SERVER_PAGE.PLAYER_PAGE.INDEX_PAGE]: indexPage,
[NAMESPACES.SERVER_PAGE.PLAYER_PAGE.HISTORY_PAGE]: historyPage,
[NAMESPACES.SERVER_PAGE.PLAYER_PAGE.ENNOBLEMENTS_PAGE]: ennoblementsPage,
};
export default translations;

View File

@ -0,0 +1,5 @@
const buildVillageName = (name = '', x = 0, y = 0) => {
return `${name} (${x}|${y}) K${y.toString()[0] + x.toString()[0]}`;
};
export default buildVillageName;