From 1bb49f7a5c6d7dc68bcd608199a3cb2a8e48e4d9 Mon Sep 17 00:00:00 2001 From: asiaznik Date: Thu, 1 Feb 2024 18:24:45 +0100 Subject: [PATCH] feat(trading): team card --- .../competitions/competitions-home.tsx | 145 ++++++++------ .../competitions/update-team-button.tsx | 12 +- .../components/competitions/team-card.tsx | 189 ++++++++++++++++++ .../components/competitions/team-stats.tsx | 15 +- apps/trading/lib/hooks/Teams.graphql | 21 +- apps/trading/lib/hooks/__generated__/Teams.ts | 29 ++- apps/trading/lib/hooks/use-my-team.ts | 37 ++++ 7 files changed, 360 insertions(+), 88 deletions(-) create mode 100644 apps/trading/components/competitions/team-card.tsx create mode 100644 apps/trading/lib/hooks/use-my-team.ts diff --git a/apps/trading/client-pages/competitions/competitions-home.tsx b/apps/trading/client-pages/competitions/competitions-home.tsx index 24217c02e..dd0332711 100644 --- a/apps/trading/client-pages/competitions/competitions-home.tsx +++ b/apps/trading/client-pages/competitions/competitions-home.tsx @@ -16,6 +16,8 @@ import { CompetitionsLeaderboard } from '../../components/competitions/competiti import { useTeams } from '../../lib/hooks/use-teams'; import take from 'lodash/take'; import { usePageTitle } from '../../lib/hooks/use-page-title'; +import { TeamCard } from '../../components/competitions/team-card'; +import { useMyTeam } from '../../lib/hooks/use-my-team'; export const CompetitionsHome = () => { const t = useT(); @@ -33,6 +35,13 @@ export const CompetitionsHome = () => { const { data: teamsData, loading: teamsLoading } = useTeams(); + const { + team: myTeam, + stats: myTeamStats, + games: myTeamGames, + rank: myTeamRank, + } = useMyTeam(); + return ( @@ -43,68 +52,82 @@ export const CompetitionsHome = () => {

- {/** Get started */} -

{t('Get started')}

+ {/** Team card */} + {myTeam ? ( + <> +

{t('My team')}

+
+ +
+ + ) : ( + <> + {/** Get started */} +

{t('Get started')}

- - { - e.preventDefault(); - navigate(Links.COMPETITIONS_CREATE_TEAM()); - }} - data-testid="create-public-team-button" - > - {t('Create a public team')} - - } - /> - { - e.preventDefault(); - navigate(Links.COMPETITIONS_CREATE_TEAM_SOLO()); - }} - data-testid="create-private-team-button" - > - {t('Create a private team')} - - } - /> - { - e.preventDefault(); - navigate(Links.COMPETITIONS_TEAMS()); - }} - data-testid="choose-team-button" - > - {t('Choose a team')} - - } - /> - + + { + e.preventDefault(); + navigate(Links.COMPETITIONS_CREATE_TEAM()); + }} + > + {t('Create a public team')} + + } + /> + { + e.preventDefault(); + navigate(Links.COMPETITIONS_CREATE_TEAM_SOLO()); + }} + > + {t('Create a private team')} + + } + /> + { + e.preventDefault(); + navigate(Links.COMPETITIONS_TEAMS()); + }} + > + {t('Choose a team')} + + } + /> + + + )} {/** List of available games */}

{t('Games')}

diff --git a/apps/trading/client-pages/competitions/update-team-button.tsx b/apps/trading/client-pages/competitions/update-team-button.tsx index b2a650fd6..0ea312f17 100644 --- a/apps/trading/client-pages/competitions/update-team-button.tsx +++ b/apps/trading/client-pages/competitions/update-team-button.tsx @@ -1,16 +1,24 @@ -import { useVegaWallet } from '@vegaprotocol/wallet'; import { type Team } from '../../lib/hooks/use-team'; +import { type ComponentProps } from 'react'; +import { useVegaWallet } from '@vegaprotocol/wallet'; import { Intent, TradingAnchorButton } from '@vegaprotocol/ui-toolkit'; import { Links } from '../../lib/links'; import { useT } from '../../lib/use-t'; -export const UpdateTeamButton = ({ team }: { team: Team }) => { +export const UpdateTeamButton = ({ + team, + size = 'medium', +}: { + team: Pick; + size?: ComponentProps['size']; +}) => { const t = useT(); const { pubKey, isReadOnly } = useVegaWallet(); if (pubKey && !isReadOnly && pubKey === team.referrer) { return ( { + const t = useT(); + + const lastGames = take( + orderBy( + games?.map((g) => ({ + rank: g.team.rank, + metric: g.team.rewardMetric, + epoch: g.epoch, + })), + (i) => i.epoch, + 'desc' + ), + 5 + ); + // const lastGames = MOCK_LAST_GAMES; + + return ( + +
+ +

+ {team.name} +

+ {games && } + + {t('Profile')} + + +
+ + {/** Tiles */} + +
+
+ + + + + +
+ + {lastGames.length > 0 && ( +
+
+ {t('Last {{games}} games result', { + replace: { games: lastGames.length }, + })} +
+
+ {lastGames.map((game, i) => ( + + + + ))} +
+
+ )} +
+
+ ); +}; + +/** + * Sets the english ordinal for rank (only if the current language is set to + * english) + */ +const RankLabel = ({ rank }: { rank: number }) => { + const i18n = useI18n(); + if (i18n.language.substring(0, 2) !== 'en') return rank.toString(); + + const r = rank.toString(); + let suffix = 'th'; + if (r.substring(r.length - 1) === '1') suffix = 'st'; + if (r.substring(r.length - 1) === '2') suffix = 'nd'; + if (r.substring(r.length - 1) === '3') suffix = 'rd'; + + return `${r}${suffix}`; +}; diff --git a/apps/trading/components/competitions/team-stats.tsx b/apps/trading/components/competitions/team-stats.tsx index d875e85e8..5904aafab 100644 --- a/apps/trading/components/competitions/team-stats.tsx +++ b/apps/trading/components/competitions/team-stats.tsx @@ -15,6 +15,7 @@ import { } from '../../lib/hooks/use-team'; import { useT } from '../../lib/use-t'; import { DispatchMetricLabels, type DispatchMetric } from '@vegaprotocol/types'; +import classNames from 'classnames'; export const TeamStats = ({ stats, @@ -102,7 +103,7 @@ const LatestResults = ({ games }: { games: TeamGame[] }) => { ); }; -const FavoriteGame = ({ games }: { games: TeamGame[] }) => { +export const FavoriteGame = ({ games }: { games: TeamGame[] }) => { const t = useT(); const rewardMetrics = games.map( @@ -142,7 +143,7 @@ const FavoriteGame = ({ games }: { games: TeamGame[] }) => { ); }; -const StatSection = ({ children }: { children: ReactNode }) => { +export const StatSection = ({ children }: { children: ReactNode }) => { return (
{children} @@ -150,11 +151,11 @@ const StatSection = ({ children }: { children: ReactNode }) => { ); }; -const StatSectionSeparator = () => { +export const StatSectionSeparator = () => { return
; }; -const StatList = ({ children }: { children: ReactNode }) => { +export const StatList = ({ children }: { children: ReactNode }) => { return (
{children} @@ -162,19 +163,21 @@ const StatList = ({ children }: { children: ReactNode }) => { ); }; -const Stat = ({ +export const Stat = ({ value, label, tooltip, valueTestId, + className, }: { value: ReactNode; label: ReactNode; tooltip?: string; valueTestId?: string; + className?: classNames.Argument; }) => { return ( -
+
{value}
diff --git a/apps/trading/lib/hooks/Teams.graphql b/apps/trading/lib/hooks/Teams.graphql index be308f3bf..b256c6a3c 100644 --- a/apps/trading/lib/hooks/Teams.graphql +++ b/apps/trading/lib/hooks/Teams.graphql @@ -1,15 +1,20 @@ +fragment TeamsFields on Team { + teamId + referrer + name + teamUrl + avatarUrl + createdAt + createdAtEpoch + closed + totalMembers +} + query Teams($teamId: ID, $partyId: ID) { teams(teamId: $teamId, partyId: $partyId) { edges { node { - teamId - referrer - name - teamUrl - avatarUrl - createdAt - createdAtEpoch - closed + ...TeamsFields } } } diff --git a/apps/trading/lib/hooks/__generated__/Teams.ts b/apps/trading/lib/hooks/__generated__/Teams.ts index 08b2f1432..ea610632b 100644 --- a/apps/trading/lib/hooks/__generated__/Teams.ts +++ b/apps/trading/lib/hooks/__generated__/Teams.ts @@ -3,33 +3,40 @@ import * as Types from '@vegaprotocol/types'; import { gql } from '@apollo/client'; import * as Apollo from '@apollo/client'; const defaultOptions = {} as const; +export type TeamsFieldsFragment = { __typename?: 'Team', teamId: string, referrer: string, name: string, teamUrl: string, avatarUrl: string, createdAt: any, createdAtEpoch: number, closed: boolean, totalMembers: number }; + export type TeamsQueryVariables = Types.Exact<{ teamId?: Types.InputMaybe; partyId?: Types.InputMaybe; }>; -export type TeamsQuery = { __typename?: 'Query', teams?: { __typename?: 'TeamConnection', edges: Array<{ __typename?: 'TeamEdge', node: { __typename?: 'Team', teamId: string, referrer: string, name: string, teamUrl: string, avatarUrl: string, createdAt: any, createdAtEpoch: number, closed: boolean } }> } | null }; - +export type TeamsQuery = { __typename?: 'Query', teams?: { __typename?: 'TeamConnection', edges: Array<{ __typename?: 'TeamEdge', node: { __typename?: 'Team', teamId: string, referrer: string, name: string, teamUrl: string, avatarUrl: string, createdAt: any, createdAtEpoch: number, closed: boolean, totalMembers: number } }> } | null }; +export const TeamsFieldsFragmentDoc = gql` + fragment TeamsFields on Team { + teamId + referrer + name + teamUrl + avatarUrl + createdAt + createdAtEpoch + closed + totalMembers +} + `; export const TeamsDocument = gql` query Teams($teamId: ID, $partyId: ID) { teams(teamId: $teamId, partyId: $partyId) { edges { node { - teamId - referrer - name - teamUrl - avatarUrl - createdAt - createdAtEpoch - closed + ...TeamsFields } } } } - `; + ${TeamsFieldsFragmentDoc}`; /** * __useTeamsQuery__ diff --git a/apps/trading/lib/hooks/use-my-team.ts b/apps/trading/lib/hooks/use-my-team.ts new file mode 100644 index 000000000..e05674a2c --- /dev/null +++ b/apps/trading/lib/hooks/use-my-team.ts @@ -0,0 +1,37 @@ +import { useVegaWallet } from '@vegaprotocol/wallet'; +import compact from 'lodash/compact'; +import first from 'lodash/first'; +import { useTeamsQuery } from './__generated__/Teams'; +import { useTeam } from './use-team'; +import { DEFAULT_AGGREGATION_EPOCHS } from './use-teams'; +import { useTeamsStatisticsQuery } from './__generated__/TeamsStatistics'; +import orderBy from 'lodash/orderBy'; + +export const useMyTeam = () => { + const { pubKey } = useVegaWallet(); + const { data: statsData } = useTeamsStatisticsQuery({ + variables: { + aggregationEpochs: DEFAULT_AGGREGATION_EPOCHS, + }, + fetchPolicy: 'cache-and-network', + }); + const allStats = orderBy( + compact(statsData?.teamsStatistics?.edges).map((e) => e.node), + (s) => Number(s.totalQuantumRewards) || 0, + 'desc' + ); + + const { data: partyTeams } = useTeamsQuery({ + variables: { + partyId: pubKey, + }, + skip: !pubKey, + fetchPolicy: 'cache-and-network', + }); + + const team = first(compact(partyTeams?.teams?.edges.map((n) => n.node))); + const rank = allStats.findIndex((t) => t.teamId === team?.teamId) + 1; + const { games, stats } = useTeam(team?.teamId); + + return { team, stats, games, rank }; +};