feat(trading): team profile improvements (#6054)

Co-authored-by: Dariusz Majcherczyk <dariusz.majcherczyk@gmail.com>
This commit is contained in:
Art 2024-03-20 18:17:05 +01:00 committed by GitHub
parent 204871b81c
commit 62ecaaa9ce
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 153 additions and 15 deletions

View File

@ -9,6 +9,10 @@ import {
Button,
VegaIcon,
VegaIconNames,
Tooltip,
TradingAnchorButton,
Intent,
CopyWithTooltip,
} from '@vegaprotocol/ui-toolkit';
import { TransferStatus, type Asset } from '@vegaprotocol/types';
import classNames from 'classnames';
@ -18,6 +22,7 @@ import {
addDecimalsFormatNumberQuantum,
formatNumber,
getDateTimeFormat,
removePaginationWrapper,
} from '@vegaprotocol/utils';
import {
useTeam,
@ -52,6 +57,7 @@ import {
ActiveRewardCard,
DispatchMetricInfo,
} from '../../components/rewards-container/reward-card';
import { usePartyProfilesQuery } from '../../components/vega-wallet-connect-button/__generated__/PartyProfiles';
export const CompetitionsTeam = () => {
const t = useT();
@ -140,11 +146,25 @@ const TeamPage = ({
const t = useT();
const [showGames, setShowGames] = useState(true);
const createdAt = new Date(team.createdAt);
const closedIndicator = team.closed ? (
<div className="border rounded border-vega-clight-300 dark:border-vega-cdark-300 px-1 pt-[1px] flex items-baseline gap-1">
<VegaIcon name={VegaIconNames.LOCK} size={10} />
<span>{t('Private')}</span>
</div>
) : (
<div className="border rounded border-vega-clight-300 dark:border-vega-cdark-300 px-1 pt-[1px] flex items-baseline gap-1">
<VegaIcon name={VegaIconNames.GLOBE} size={10} />
<span>{t('Public')}</span>
</div>
);
return (
<LayoutWithGradient>
<header className="flex gap-3 lg:gap-4 pt-5 lg:pt-10">
<TeamAvatar teamId={team.teamId} imgUrl={team.avatarUrl} />
<div className="flex flex-col items-start gap-1 lg:gap-3">
<div className="flex flex-col items-start gap-1 lg:gap-2">
<h1
className="calt text-2xl lg:text-3xl xl:text-5xl"
data-testid="team-name"
@ -154,6 +174,38 @@ const TeamPage = ({
<div className="flex gap-2">
<JoinTeam team={team} partyTeam={partyTeam} refetch={refetch} />
<UpdateTeamButton team={team} />
{team.teamUrl && team.teamUrl.length > 0 && (
<Tooltip description={t("Visit the team's page.")}>
<span>
<TradingAnchorButton
intent={Intent.Info}
target="_blank"
referrerPolicy="no-referrer"
href={team.teamUrl}
>
<VegaIcon name={VegaIconNames.OPEN_EXTERNAL} size={16} />
</TradingAnchorButton>
</span>
</Tooltip>
)}
<CopyWithTooltip
description={t('Copy this page url.')}
text={globalThis.location.href}
>
<button className="h-10 w-7">
<VegaIcon name={VegaIconNames.COPY} size={16} />
</button>
</CopyWithTooltip>
</div>
<div className="flex gap-2 items-baseline text-xs text-muted font-alpha calt">
{closedIndicator}
<div className="">
{t('Created at')}:{' '}
<span className="text-vega-cdark-600 dark:text-vega-clight-600 ">
{getDateTimeFormat().format(createdAt)}
</span>{' '}
({t('epoch')}: {team.createdAtEpoch})
</div>
</div>
</div>
</header>
@ -331,13 +383,30 @@ const Games = ({
const Members = ({ members }: { members?: Member[] }) => {
const t = useT();
const partyIds = members?.map((m) => m.referee) || [];
const { data: profilesData } = usePartyProfilesQuery({
variables: {
partyIds,
},
skip: partyIds.length === 0,
});
const profiles = removePaginationWrapper(
profilesData?.partiesProfilesConnection?.edges
);
if (!members?.length) {
return <p>{t('No members')}</p>;
}
const data = orderBy(
members.map((m) => ({
referee: <RefereeLink pubkey={m.referee} isCreator={m.isCreator} />,
referee: (
<RefereeLink
pubkey={m.referee}
isCreator={m.isCreator}
profiles={profiles}
/>
),
rewards: formatNumber(m.totalQuantumRewards),
volume: formatNumber(m.totalQuantumVolume),
gamesPlayed: formatNumber(m.totalGamesPlayed),
@ -351,7 +420,7 @@ const Members = ({ members }: { members?: Member[] }) => {
return (
<Table
columns={[
{ name: 'referee', displayName: t('Member ID') },
{ name: 'referee', displayName: t('Member') },
{ name: 'rewards', displayName: t('Rewards earned') },
{ name: 'volume', displayName: t('Total volume') },
{ name: 'gamesPlayed', displayName: t('Games played') },
@ -373,21 +442,43 @@ const Members = ({ members }: { members?: Member[] }) => {
const RefereeLink = ({
pubkey,
isCreator,
profiles,
}: {
pubkey: string;
isCreator: boolean;
profiles?: { partyId: string; alias: string }[];
}) => {
const t = useT();
const linkCreator = useLinks(DApp.Explorer);
const link = linkCreator(EXPLORER_PARTIES.replace(':id', pubkey));
const alias = profiles?.find((p) => p.partyId === pubkey)?.alias;
return (
<>
<div className="flex items-baseline gap-2">
<Link to={link} target="_blank" className="underline underline-offset-4">
{truncateMiddle(pubkey)}
</Link>{' '}
<span className="text-muted text-xs">{isCreator ? t('Owner') : ''}</span>
</>
{alias || truncateMiddle(pubkey)}
</Link>
{!alias && (
<Tooltip
description={t(
'You can set your pubkey alias by using the key selector in the top right corner.'
)}
>
<button className="text-muted text-xs">
<VegaIcon name={VegaIconNames.QUESTION_MARK} size={14} />
</button>
</Tooltip>
)}
{alias && (
<span className="text-muted text-xs">{truncateMiddle(pubkey)}</span>
)}
{isCreator && (
<span className="text-muted text-xs border border-vega-clight-300 dark:border-vega-cdark-300 rounded px-1 py-[1px]">
{t('Owner')}
</span>
)}
</div>
);
};

View File

@ -70,6 +70,12 @@ export const JoinButton = ({
}) => {
const t = useT();
/**
* A team cannot be joined (closed) when set as such
* and the currently connected pubkey is not whitelisted.
*/
const isTeamClosed = team.closed && !team.allowList.includes(pubKey || '');
if (!pubKey || isReadOnly) {
return (
<Tooltip description={t('Connect your wallet to join the team')}>
@ -79,8 +85,9 @@ export const JoinButton = ({
</Tooltip>
);
}
// Party is the creator of a team
else if (partyTeam && partyTeam.referrer === pubKey) {
if (partyTeam && partyTeam.referrer === pubKey) {
// Party is the creator of THIS team
if (partyTeam.teamId === team.teamId) {
return (
@ -105,8 +112,24 @@ export const JoinButton = ({
);
}
}
// Party is in a team, but not this one
else if (partyTeam && partyTeam.teamId !== team.teamId) {
if (partyTeam && partyTeam.teamId !== team.teamId) {
// This team is closed.
if (isTeamClosed) {
return (
<Tooltip description={t('You cannot join a private team')}>
<Button
intent={Intent.Primary}
data-testid="switch-team-button"
disabled={true}
>
{t('Switch team')}{' '}
</Button>
</Tooltip>
);
}
// This team is open.
return (
<Button
onClick={() => onJoin('switch')}
@ -117,8 +140,9 @@ export const JoinButton = ({
</Button>
);
}
// Joined. Current party is already in this team
else if (partyTeam && partyTeam.teamId === team.teamId) {
if (partyTeam && partyTeam.teamId === team.teamId) {
return (
<Button intent={Intent.None} disabled={true}>
<span className="flex items-center gap-2">
@ -131,6 +155,17 @@ export const JoinButton = ({
);
}
// This team is closed.
if (isTeamClosed) {
return (
<Tooltip description={t('You cannot join a closed team')}>
<Button intent={Intent.Primary} disabled={true}>
{t('Join team')}
</Button>
</Tooltip>
);
}
// This team is open.
return (
<Button onClick={() => onJoin('join')} intent={Intent.Primary}>
{t('Join team')}

View File

@ -67,7 +67,7 @@ export const CompetitionsLeaderboard = ({
),
earned: num(td.totalQuantumRewards),
games: num(td.totalGamesPlayed),
status: td.closed ? t('Closed') : t('Open'),
status: td.closed ? t('Private') : t('Public'),
volume: num(td.totalQuantumVolume),
};
})}

View File

@ -242,6 +242,7 @@ def test_team_page_games_table(team_page: Tuple[Page, str, str, VegaServiceNull]
expect(page.get_by_test_id("games-toggle")).to_have_text("Results (10)")
expect(page.get_by_test_id("rank-0")).to_have_text("1")
expect(page.get_by_test_id("epoch-0")).to_have_text("19")
expect(page.get_by_test_id("endtime-0")).to_be_visible()
expect(page.get_by_test_id("type-0")).to_have_text(
"Price maker fees paid • tDAI "
)
@ -256,6 +257,9 @@ def test_team_page_members_table(team_page: Tuple[Page, str, str, VegaServiceNul
page.get_by_test_id("members-toggle").click()
expect(page.get_by_test_id("members-toggle")).to_have_text("Members (4)")
expect(page.get_by_test_id("referee-0")).to_be_visible()
expect(page.get_by_test_id("icon-question-mark").nth(0)).to_be_visible()
expect(page.get_by_test_id("referee-3").locator(".text-muted").nth(1)
).to_have_text("Owner")
expect(page.get_by_test_id("joinedAt-0")).to_be_visible()
expect(page.get_by_test_id("joinedAtEpoch-0")).to_have_text("9")
@ -263,6 +267,8 @@ def test_team_page_members_table(team_page: Tuple[Page, str, str, VegaServiceNul
def test_team_page_headline(team_page: Tuple[Page, str, str, VegaServiceNull]):
page, team_name, team_id, vega = team_page
expect(page.get_by_test_id("team-name")).to_have_text(team_name)
expect(page.get_by_test_id("icon-open-external").nth(1)).to_be_visible()
expect(page.get_by_test_id("icon-copy")).to_be_visible()
expect(page.get_by_test_id("members-count-stat")).to_have_text("4")
expect(page.get_by_test_id("total-games-stat")).to_have_text("1")
@ -295,7 +301,7 @@ def test_leaderboard(competitions_page: Tuple[Page, str, VegaServiceNull]):
page.get_by_test_id("rank-1").locator(".text-vega-clight-500")
).to_have_count(1)
expect(page.get_by_test_id("team-1")).to_have_text(team_name)
expect(page.get_by_test_id("status-1")).to_have_text("Open")
expect(page.get_by_test_id("status-1")).to_have_text("Public")
# FIXME: the numbers are different we need to clarify this with the backend
# expect(competitions_page.get_by_test_id("earned-1")).to_have_text("160")
@ -320,7 +326,6 @@ def test_game_card(competitions_page: Tuple[Page, str, VegaServiceNull]):
"Price maker fees paid • tDAI"
)
expect(game_1.get_by_test_id("assessed-over")).to_have_text("15 epochs")
page.pause()
expect(game_1.get_by_test_id("scope")).to_have_text("Eligible")
expect(game_1.get_by_test_id("staking-requirement")).to_have_text("-")
expect(game_1.get_by_test_id("average-position")).to_have_text("-")

View File

@ -18,6 +18,7 @@
"Anyone with the referral link can apply it to their key(s) of choice via an on chain transaction": "Anyone with the referral link can apply it to their key(s) of choice via an on chain transaction",
"Are you sure you want to join team: {{team}}": "Are you sure you want to join team: {{team}}",
"As a team creator, you cannot switch teams": "As a team creator, you cannot switch teams",
"You cannot join a private team": "You cannot join a private team",
"Assessed over": "Assessed over",
"Asset (1)": "Asset (1)",
"Assets": "Assets",
@ -213,6 +214,8 @@
"Market triggers cancellation or governance vote has passed to cancel": "Market triggers cancellation or governance vote has passed to cancel",
"Markets": "Markets",
"Member ID": "Member ID",
"Member": "Member",
"You can set your pubkey alias by using the key selector in the top right corner.": "You can set your pubkey alias by using the key selector in the top right corner.",
"Members": "Members",
"Members ({{count}})": "Members ({{count}})",
"Menu": "Menu",
@ -496,5 +499,9 @@
"{{distance}} ago": "{{distance}} ago",
"{{entity}} scope": "{{entity}} scope",
"{{instrumentCode}} liquidity provision": "{{instrumentCode}} liquidity provision",
"{{reward}}x": "{{reward}}x"
"{{reward}}x": "{{reward}}x",
"Private": "Private",
"Public": "Public",
"Copy this page url.": "Copy this page url.",
"Visit the team's page.": "Visit the team's page."
}