diff --git a/src/common/Table/Table.tsx b/src/common/Table/Table.tsx index 295f318..7f89a08 100644 --- a/src/common/Table/Table.tsx +++ b/src/common/Table/Table.tsx @@ -25,6 +25,7 @@ export interface Props { 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({ size, selected, onSelect, + getRowKey, }: Props) { const { t } = useTranslation(TABLE); @@ -100,7 +102,11 @@ function Table({ return ( + ); +} + +const useStyles = makeStyles(theme => ({ + dot: { + borderRadius: '50%', + width: theme.spacing(2), + height: theme.spacing(2), + }, +})); + +export default Dot; diff --git a/src/features/ServerPage/common/PlayerProfileLink/PlayerProfileLink.tsx b/src/features/ServerPage/common/PlayerProfileLink/PlayerProfileLink.tsx index dd97f6e..53fe787 100644 --- a/src/features/ServerPage/common/PlayerProfileLink/PlayerProfileLink.tsx +++ b/src/features/ServerPage/common/PlayerProfileLink/PlayerProfileLink.tsx @@ -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 ( {player.name} - {player.tribe && ( + {t && ( {` (`} - {player.tribe.tag} + {t.tag} ) diff --git a/src/features/ServerPage/features/PlayerPage/PlayerPage.tsx b/src/features/ServerPage/features/PlayerPage/PlayerPage.tsx index 8c6675c..a841740 100644 --- a/src/features/ServerPage/features/PlayerPage/PlayerPage.tsx +++ b/src/features/ServerPage/features/PlayerPage/PlayerPage.tsx @@ -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() { + + + diff --git a/src/features/ServerPage/features/PlayerPage/common/PageLayout/PageLayout.tsx b/src/features/ServerPage/features/PlayerPage/common/PageLayout/PageLayout.tsx index dc885a0..859c365 100644 --- a/src/features/ServerPage/features/PlayerPage/common/PageLayout/PageLayout.tsx +++ b/src/features/ServerPage/features/PlayerPage/common/PageLayout/PageLayout.tsx @@ -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]); diff --git a/src/features/ServerPage/features/PlayerPage/features/EnnoblementsPage/EnnoblementsPage.tsx b/src/features/ServerPage/features/PlayerPage/features/EnnoblementsPage/EnnoblementsPage.tsx new file mode 100644 index 0000000..5e5e919 --- /dev/null +++ b/src/features/ServerPage/features/PlayerPage/features/EnnoblementsPage/EnnoblementsPage.tsx @@ -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 ( + + + + + + ); +} + +export default EnnoblementsPage; diff --git a/src/features/ServerPage/features/PlayerPage/features/EnnoblementsPage/components/Ennoblements/Ennoblements.tsx b/src/features/ServerPage/features/PlayerPage/features/EnnoblementsPage/components/Ennoblements/Ennoblements.tsx new file mode 100644 index 0000000..470460d --- /dev/null +++ b/src/features/ServerPage/features/PlayerPage/features/EnnoblementsPage/components/Ennoblements/Ennoblements.tsx @@ -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 ( + + { + if ( + e.newOwner.id === playerID && + e.oldOwner && + e.oldOwner.id === playerID + ) { + return ; + } else if (e.oldOwner && e.oldOwner.id === playerID) { + return ; + } + return ; + }, + }, + { + field: 'ennobledAt', + label: t('ennoblements.columns.ennobledAt'), + sortable: false, + type: 'datetime', + }, + { + field: 'village', + label: t('ennoblements.columns.village'), + sortable: false, + valueFormatter: (e: Ennoblement) => { + return ( + + {buildVillageName(e.village.name, e.village.x, e.village.y)} + + ); + }, + }, + { + field: 'oldOwner', + label: t('ennoblements.columns.oldOwner'), + sortable: false, + valueFormatter: (e: Ennoblement) => { + if (e.oldOwner) { + return ( + + ); + } + return '-'; + }, + }, + { + field: 'newOwner', + label: t('ennoblements.columns.newOwner'), + sortable: false, + valueFormatter: (e: Ennoblement) => { + return ( + + ); + }, + }, + ]} + 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 }); + }); + }, + }} + /> + + ); +} + +export default Ennoblements; diff --git a/src/features/ServerPage/features/PlayerPage/features/EnnoblementsPage/components/Ennoblements/constants.ts b/src/features/ServerPage/features/PlayerPage/features/EnnoblementsPage/components/Ennoblements/constants.ts new file mode 100644 index 0000000..5fcdd4d --- /dev/null +++ b/src/features/ServerPage/features/PlayerPage/features/EnnoblementsPage/components/Ennoblements/constants.ts @@ -0,0 +1 @@ +export const LIMIT = 25; diff --git a/src/features/ServerPage/features/PlayerPage/features/EnnoblementsPage/components/Ennoblements/queries.ts b/src/features/ServerPage/features/PlayerPage/features/EnnoblementsPage/components/Ennoblements/queries.ts new file mode 100644 index 0000000..b4797e4 --- /dev/null +++ b/src/features/ServerPage/features/PlayerPage/features/EnnoblementsPage/components/Ennoblements/queries.ts @@ -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 + } + } +`; diff --git a/src/features/ServerPage/features/PlayerPage/features/EnnoblementsPage/components/Ennoblements/types.ts b/src/features/ServerPage/features/PlayerPage/features/EnnoblementsPage/components/Ennoblements/types.ts new file mode 100644 index 0000000..2b2440d --- /dev/null +++ b/src/features/ServerPage/features/PlayerPage/features/EnnoblementsPage/components/Ennoblements/types.ts @@ -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; +}; diff --git a/src/libs/graphql/types.ts b/src/libs/graphql/types.ts index 16b7622..f5a00de 100644 --- a/src/libs/graphql/types.ts +++ b/src/libs/graphql/types.ts @@ -67,6 +67,19 @@ export type TribeFilter = { export type TribesQueryVariables = QueryVariablesWithServer; +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; diff --git a/src/libs/i18n/en/server-page/player-page/common.ts b/src/libs/i18n/en/server-page/player-page/common.ts index 8b5c33e..46bd413 100644 --- a/src/libs/i18n/en/server-page/player-page/common.ts +++ b/src/libs/i18n/en/server-page/player-page/common.ts @@ -9,7 +9,7 @@ const translations = { indexPage: 'Profile', historyPage: 'History', tribeChanges: 'Tribe changes', - conquersPage: 'Conquers', + ennoblementsPage: 'Ennoblements', }, achievements: { playerRank: '#{{rank}} points', diff --git a/src/libs/i18n/en/server-page/player-page/ennoblements-page.ts b/src/libs/i18n/en/server-page/player-page/ennoblements-page.ts new file mode 100644 index 0000000..72727e5 --- /dev/null +++ b/src/libs/i18n/en/server-page/player-page/ennoblements-page.ts @@ -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; diff --git a/src/libs/i18n/en/server-page/player-page/history-page.ts b/src/libs/i18n/en/server-page/player-page/history-page.ts index 195faef..132810f 100644 --- a/src/libs/i18n/en/server-page/player-page/history-page.ts +++ b/src/libs/i18n/en/server-page/player-page/history-page.ts @@ -1,5 +1,5 @@ const translations = { - title: `{{key}} - {{name}}'s player history`, + title: `{{key}} - {{name}}'s history`, playerHistory: { columns: { createDate: 'Date', diff --git a/src/libs/i18n/en/server-page/player-page/index.ts b/src/libs/i18n/en/server-page/player-page/index.ts index 1024db8..c5d63c2 100644 --- a/src/libs/i18n/en/server-page/player-page/index.ts +++ b/src/libs/i18n/en/server-page/player-page/index.ts @@ -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; diff --git a/src/libs/i18n/pl/server-page/player-page/common.ts b/src/libs/i18n/pl/server-page/player-page/common.ts index dfbf94a..ec86326 100644 --- a/src/libs/i18n/pl/server-page/player-page/common.ts +++ b/src/libs/i18n/pl/server-page/player-page/common.ts @@ -9,7 +9,7 @@ const translations = { indexPage: 'Profil', historyPage: 'Historia', tribeChanges: 'Zmiany plemion', - conquersPage: 'Przejęcia', + ennoblementsPage: 'Przejęcia', }, achievements: { playerRank: '#{{rank}} punkty', diff --git a/src/libs/i18n/pl/server-page/player-page/ennoblements-page.ts b/src/libs/i18n/pl/server-page/player-page/ennoblements-page.ts new file mode 100644 index 0000000..6dfbeab --- /dev/null +++ b/src/libs/i18n/pl/server-page/player-page/ennoblements-page.ts @@ -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; diff --git a/src/libs/i18n/pl/server-page/player-page/index.ts b/src/libs/i18n/pl/server-page/player-page/index.ts index 1024db8..c5d63c2 100644 --- a/src/libs/i18n/pl/server-page/player-page/index.ts +++ b/src/libs/i18n/pl/server-page/player-page/index.ts @@ -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; diff --git a/src/utils/buildVillageName.ts b/src/utils/buildVillageName.ts new file mode 100644 index 0000000..fcf9615 --- /dev/null +++ b/src/utils/buildVillageName.ts @@ -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;