[WIP]: /server/:key/tribe/:id/members

- base version without translations and opt to compare members
This commit is contained in:
Dawid Wysokiński 2020-12-18 07:26:59 +01:00
parent 9a9c9113fe
commit 785657a518
10 changed files with 164 additions and 6 deletions

View File

@ -108,6 +108,7 @@ function Table<T extends object>({
? item[idFieldName] + '' ? item[idFieldName] + ''
: index : index
} }
index={index}
row={item} row={item}
actions={actions} actions={actions}
selected={isSelected(item)} selected={isSelected(item)}

View File

@ -14,6 +14,7 @@ export interface Props<T> {
selection: boolean; selection: boolean;
selected: boolean; selected: boolean;
size?: 'small' | 'medium'; size?: 'small' | 'medium';
index: number;
onSelect?: (row: T) => void; onSelect?: (row: T) => void;
} }
@ -25,6 +26,7 @@ function EnhancedTableRow<T extends object>({
selected = false, selected = false,
onSelect, onSelect,
size = 'medium', size = 'medium',
index,
}: Props<T>) { }: Props<T>) {
const handleSelect = () => { const handleSelect = () => {
if (onSelect) { if (onSelect) {
@ -65,7 +67,7 @@ function EnhancedTableRow<T extends object>({
align={col.align ? col.align : 'left'} align={col.align ? col.align : 'left'}
> >
{col.valueFormatter {col.valueFormatter
? col.valueFormatter(row) ? col.valueFormatter(row, index)
: col.type : col.type
? formatValue(val, col.type) ? formatValue(val, col.type)
: val} : val}

View File

@ -7,7 +7,7 @@ export type Column<T = any> = {
field: string; field: string;
label?: string; label?: string;
sortable?: boolean; sortable?: boolean;
valueFormatter?: (v: T) => React.ReactNode; valueFormatter?: (v: T, i: number) => React.ReactNode;
disablePadding?: boolean; disablePadding?: boolean;
type?: 'normal' | 'datetime' | 'date'; type?: 'normal' | 'datetime' | 'date';
align?: 'left' | 'right' | 'center'; align?: 'left' | 'right' | 'center';

View File

@ -1,4 +1,4 @@
export const DEFAULT_LANGUAGE = process.env.REACT_APP_DEFAULT_LANGUAGE ?? 'pl'; export const DEFAULT_LANGUAGE = process.env.REACT_APP_DEFAULT_LANGUAGE ?? 'en';
export const NAME = 'TWHelp'; export const NAME = 'TWHelp';
@ -9,7 +9,8 @@ export const SERVER_STATUS = {
OPEN: 'open' as ServerStatus, OPEN: 'open' as ServerStatus,
}; };
export const TWHELP = process.env.TWHelp ?? 'https://tribalwarshelp.com'; export const TWHELP =
process.env.REACT_APP_TWHELP ?? 'https://tribalwarshelp.com';
export const AUTHOR = 'Dawid Wysokiński'; export const AUTHOR = 'Dawid Wysokiński';

View File

@ -4,6 +4,7 @@ import { SERVER_PAGE } from '@config/routes';
import { Switch, Route, RouteProps } from 'react-router-dom'; import { Switch, Route, RouteProps } from 'react-router-dom';
import TribeProvider from './libs/TribePageContext/Provider'; import TribeProvider from './libs/TribePageContext/Provider';
import IndexPage from './features/IndexPage/IndexPage'; import IndexPage from './features/IndexPage/IndexPage';
import MembersPage from './features/MembersPage/MembersPage';
import HistoryPage from './features/HistoryPage/HistoryPage'; import HistoryPage from './features/HistoryPage/HistoryPage';
import EnnoblementsPage from './features/EnnoblementsPage/EnnoblementsPage'; import EnnoblementsPage from './features/EnnoblementsPage/EnnoblementsPage';
import TribeChangesPage from './features/TribeChangesPage/TribeChangesPage'; import TribeChangesPage from './features/TribeChangesPage/TribeChangesPage';
@ -23,6 +24,9 @@ function TribePage() {
<EnhancedRoute exact path={SERVER_PAGE.TRIBE_PAGE.INDEX_PAGE}> <EnhancedRoute exact path={SERVER_PAGE.TRIBE_PAGE.INDEX_PAGE}>
<IndexPage /> <IndexPage />
</EnhancedRoute> </EnhancedRoute>
<EnhancedRoute exact path={SERVER_PAGE.TRIBE_PAGE.MEMBERS_PAGE}>
<MembersPage />
</EnhancedRoute>
<EnhancedRoute exact path={SERVER_PAGE.TRIBE_PAGE.HISTORY_PAGE}> <EnhancedRoute exact path={SERVER_PAGE.TRIBE_PAGE.HISTORY_PAGE}>
<HistoryPage /> <HistoryPage />
</EnhancedRoute> </EnhancedRoute>

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 useTribe from '../../libs/TribePageContext/useTribe';
import { SERVER_PAGE } from '@config/namespaces';
import { Container } from '@material-ui/core';
import PageLayout from '../../common/PageLayout/PageLayout';
import Members from './components/Members/Members';
function MembersPage() {
const { key } = useServer();
const tribe = useTribe();
const { t } = useTranslation(SERVER_PAGE.TRIBE_PAGE.MEMBERS_PAGE);
useTitle(t('title', { key, tag: tribe.tag }));
return (
<PageLayout>
<Container>
<Members t={t} server={key} tribeID={tribe.id} />
</Container>
</PageLayout>
);
}
export default MembersPage;

View File

@ -0,0 +1,82 @@
import React from 'react';
import { useQuery } from '@apollo/client';
import { PLAYERS } from './queries';
import { Paper } from '@material-ui/core';
import Table from '@common/Table/Table';
import PlayerProfileLink from '@features/ServerPage/common/PlayerProfileLink/PlayerProfileLink';
import { TFunction } from 'i18next';
import { PlayersQueryVariables } from '@libs/graphql/types';
import { PlayersQuery, Player } from './types';
export interface Props {
server: string;
tribeID: number;
t: TFunction;
}
function Members({ t, server, tribeID }: Props) {
const { data: queryData, loading: queryLoading } = useQuery<
PlayersQuery,
PlayersQueryVariables
>(PLAYERS, {
fetchPolicy: 'cache-and-network',
variables: {
sort: ['rank ASC'],
filter: {
tribeID: [tribeID],
},
server,
},
});
const playersItems = queryData?.players?.items ?? [];
const loading = playersItems.length === 0 && queryLoading;
return (
<Paper>
<Table
columns={[
{
field: 'index',
label: '',
sortable: false,
valueFormatter: (_p: Player, i: number) => {
return i + 1 + '.';
},
},
{
field: 'name',
label: t('members.columns.name'),
sortable: false,
valueFormatter: (p: Player) => {
return <PlayerProfileLink player={p} server={server} />;
},
},
{
field: 'points',
label: t('members.columns.points'),
sortable: false,
valueFormatter: (p: Player) => {
return `${p.points.toLocaleString()} (#${p.rank})`;
},
},
{
field: 'totalVillages',
label: t('members.columns.totalVillages'),
sortable: false,
valueFormatter: (p: Player) => {
return p.totalVillages.toLocaleString();
},
},
]}
loading={loading}
data={playersItems}
size="small"
hideFooter
/>
</Paper>
);
}
export default Members;

View File

@ -0,0 +1,28 @@
import { gql } from '@apollo/client';
export const PLAYERS = gql`
query players(
$server: String!
$filter: PlayerFilter
$sort: [String!]
$limit: Int
$offset: Int
) {
players(
server: $server
filter: $filter
sort: $sort
limit: $limit
offset: $offset
) {
items {
id
name
rank
points
totalVillages
}
total
}
}
`;

View File

@ -0,0 +1,13 @@
import { List } from '@libs/graphql/types';
export type Player = {
id: number;
name: string;
rank: number;
points: number;
totalVillages: number;
};
export type PlayersQuery = {
players?: List<Player[]>;
};

View File

@ -39,6 +39,7 @@ export type ServerStatsQueryVariables = QueryVariablesWithServer<
export type PlayerFilter = { export type PlayerFilter = {
id?: number[]; id?: number[];
tribeID?: number[];
exists?: boolean; exists?: boolean;
tribeFilter?: TribeFilter; tribeFilter?: TribeFilter;
deletedAtGT?: Date | string; deletedAtGT?: Date | string;
@ -100,7 +101,7 @@ export type TribeHistoryQueryVariables = QueryVariablesWithServer<
TribeHistoryFilter TribeHistoryFilter
>; >;
export type TribeChangesFilter = { export type TribeChangeFilter = {
playerID?: number[]; playerID?: number[];
playerIDNEQ?: number[]; playerIDNEQ?: number[];
or?: { or?: {
@ -110,7 +111,7 @@ export type TribeChangesFilter = {
}; };
export type TribeChangesQueryVariables = QueryVariablesWithServer< export type TribeChangesQueryVariables = QueryVariablesWithServer<
TribeChangesFilter TribeChangeFilter
>; >;
export type EnnoblementFilter = { export type EnnoblementFilter = {