PatronTile

This commit is contained in:
vidvidvid
2022-11-08 20:54:11 +01:00
parent baeddea890
commit 68de7afe53
5 changed files with 96 additions and 179 deletions

View File

@@ -1,6 +1,7 @@
import { SimpleGrid } from '@metafam/ds';
import { Maybe } from '@metafam/utils';
import { PatronTile } from 'components/Patron/PatronTile';
import { PlayerTile } from 'components/Player/PlayerTile';
import { Player } from 'graphql/autogen/types';
import { Patron } from 'graphql/types';
import React from 'react';
@@ -15,8 +16,13 @@ export const PatronList: React.FC<Props> = ({ patrons, pSeedPrice }) => (
spacing="8"
autoRows="minmax(35rem, auto)"
>
{patrons.map((patron, index) => (
<PatronTile key={patron.id} {...{ patron, index, pSeedPrice }} />
{patrons.map((player, index) => (
<PlayerTile
player={player as Player}
pSeedPrice={pSeedPrice}
index={index}
isPatron
/>
))}
</SimpleGrid>
);

View File

@@ -0,0 +1,64 @@
import { Flex, MetaTag } from '@metafam/ds';
import { computeRank, Constants, Maybe } from '@metafam/utils';
import { utils } from 'ethers';
import { Player } from 'graphql/autogen/types';
import { Patron } from 'graphql/types';
import React, { useMemo } from 'react';
import { PATRON_RANKS, PATRONS_PER_RANK } from 'utils/patronHelpers';
type Props = {
patron: Patron;
index: number;
pSeedPrice: Maybe<number>;
};
export const PatronRank: React.FC<Props> = ({ index, patron, pSeedPrice }) => {
const player = patron as Player;
const patronRank = useMemo(
() => computeRank(index, PATRONS_PER_RANK, PATRON_RANKS),
[index],
);
const displayBalance = useMemo(() => {
const pSeedAmount = parseFloat(
utils.formatUnits(patron.pSeedBalance, Constants.PSEED_DECIMALS),
);
const pSeedBalance = `${Math.floor(pSeedAmount).toLocaleString()} pSEED`;
return pSeedPrice == null
? pSeedBalance
: `$${(pSeedAmount * pSeedPrice).toLocaleString(undefined, {
maximumFractionDigits: 0,
})}`;
}, [patron, pSeedPrice]);
return (
<Flex
flexDir="column"
gap={1}
pos="absolute"
left={-8}
p={3}
top={-8}
background="rgba(255, 255, 255, 0.1)"
backdropFilter="blur(10.5px)"
borderRadius="8px"
>
{patron.pSeedBalance != null && (
<MetaTag size="md">{displayBalance}</MetaTag>
)}
{patronRank && (
<MetaTag
backgroundColor={patronRank?.toLowerCase()}
size="md"
color="blackAlpha.600"
>
{patronRank}
</MetaTag>
)}
<MetaTag size="md">{`XP: ${Math.floor(
player.totalXP,
).toLocaleString()}`}</MetaTag>
</Flex>
);
};

View File

@@ -1,164 +0,0 @@
import {
Box,
getTimeZoneFor,
Heading,
HStack,
LinkBox,
LinkOverlay,
MetaTag,
MetaTile,
MetaTileBody,
MetaTileHeader,
Text,
VStack,
Wrap,
WrapItem,
} from '@metafam/ds';
import { computeRank, Constants, Maybe } from '@metafam/utils';
import { PlayerAvatar } from 'components/Player/PlayerAvatar';
import { PlayerContacts } from 'components/Player/PlayerContacts';
import { PlayerTileMemberships } from 'components/Player/PlayerTileMemberships';
import { SkillsTags } from 'components/Quest/Skills';
import { utils } from 'ethers';
import { Player, Skill } from 'graphql/autogen/types';
import { Patron } from 'graphql/types';
import NextLink from 'next/link';
import React, { useMemo } from 'react';
import { FaGlobe } from 'react-icons/fa';
import { PATRON_RANKS, PATRONS_PER_RANK } from 'utils/patronHelpers';
import {
getPlayerBanner,
getPlayerDescription,
getPlayerName,
getPlayerURL,
} from 'utils/playerHelpers';
type Props = {
patron: Patron;
index: number;
pSeedPrice: Maybe<number>;
};
const MAX_BIO_LENGTH = 240;
export const PatronTile: React.FC<Props> = ({ index, patron, pSeedPrice }) => {
const player = patron as Player;
const patronRank = useMemo(
() => computeRank(index, PATRONS_PER_RANK, PATRON_RANKS),
[index],
);
const { label: timeZone = null } = useMemo(
() =>
getTimeZoneFor({ location: player.profile?.timeZone ?? undefined }) ?? {
label: null,
offset: null,
},
[player.profile?.timeZone],
);
const displayDescription = useMemo(() => {
const description = getPlayerDescription(player);
return description && description.length > MAX_BIO_LENGTH
? `${description.substring(0, MAX_BIO_LENGTH - 9)}`
: description;
}, [player]);
const displayBalance = useMemo(() => {
const pSeedAmount = parseFloat(
utils.formatUnits(patron.pSeedBalance, Constants.PSEED_DECIMALS),
);
const pSeedBalance = `${Math.floor(pSeedAmount).toLocaleString()} pSEED`;
return pSeedPrice == null
? pSeedBalance
: `$${(pSeedAmount * pSeedPrice).toLocaleString(undefined, {
maximumFractionDigits: 0,
})}`;
}, [patron, pSeedPrice]);
return (
<LinkBox>
<MetaTile>
<Box
bgImage={`url(${getPlayerBanner(player)})`}
bgSize="cover"
bgPosition="center"
position="absolute"
top={0}
left={0}
w="100%"
h="4.5rem"
/>
<NextLink as={getPlayerURL(player)} href="/player/[username]" passHref>
<LinkOverlay>
<MetaTileHeader>
<VStack>
<PlayerAvatar player={player} size="xl" />
<Heading size="xs" color="white">
{getPlayerName(player)}
</Heading>
</VStack>
<Wrap w="100%" justify="center">
{patron.pSeedBalance != null && (
<WrapItem>
<MetaTag size="md">{displayBalance}</MetaTag>
</WrapItem>
)}
{patronRank && (
<WrapItem>
<MetaTag
backgroundColor={patronRank?.toLowerCase()}
size="md"
color="blackAlpha.600"
>
{patronRank}
</MetaTag>
</WrapItem>
)}
<WrapItem>
<MetaTag size="md">{`XP: ${Math.floor(
player.totalXP,
).toLocaleString()}`}</MetaTag>
</WrapItem>
</Wrap>
{timeZone && (
<HStack alignItems="center" w="auto" justify="center">
<FaGlobe color="blueLight" fontSize="0.875rem" />
<Text fontSize="sm">{timeZone || '―'}</Text>
</HStack>
)}
{displayDescription && (
<VStack spacing={2} align="stretch" pt="0.5rem">
<Text textStyle="caption">About</Text>
<Text fontSize="sm">{displayDescription}</Text>
</VStack>
)}
</MetaTileHeader>
</LinkOverlay>
</NextLink>
<MetaTileBody>
{player.skills?.length && (
<VStack spacing={2} align="stretch">
<Text textStyle="caption">SKILLS</Text>
<SkillsTags
skills={player.skills.map((s) => s.Skill) as Skill[]}
/>
</VStack>
)}
<PlayerTileMemberships player={player} />
{player.accounts?.length && (
<VStack spacing={2} align="stretch">
<Text textStyle="caption">CONTACT</Text>
<HStack mt="2">
<PlayerContacts player={player} />
</HStack>
</VStack>
)}
</MetaTileBody>
</MetaTile>
</LinkBox>
);
};

View File

@@ -5,23 +5,16 @@ import React from 'react';
type Props = {
players: Player[];
showSeasonalXP?: boolean;
};
export const PlayerList: React.FC<Props> = ({
players,
showSeasonalXP = false,
}) => (
export const PlayerList: React.FC<Props> = ({ players }) => (
<SimpleGrid
columns={[1, null, 2, 3]}
spacing={8}
autoRows="minmax(35rem, auto)"
>
{players.map((player, idx) => (
<PlayerTile
key={player.profile?.username ?? idx}
{...{ player, showSeasonalXP }}
/>
<PlayerTile key={player.profile?.username ?? idx} {...{ player }} />
))}
</SimpleGrid>
);

View File

@@ -11,12 +11,15 @@ import {
Text,
VStack,
} from '@metafam/ds';
import { Maybe } from '@metafam/utils';
import { PatronRank } from 'components/Patron/PatronRank';
import { PlayerContacts } from 'components/Player/PlayerContacts';
import { PlayerProfilePicture } from 'components/Player/PlayerProfilePicture';
import { PlayerTileMemberships } from 'components/Player/PlayerTileMemberships';
import { SkillsTags } from 'components/Quest/Skills';
import { Player, Skill } from 'graphql/autogen/types';
import { getAllMemberships, GuildMembership } from 'graphql/getMemberships';
import { Patron } from 'graphql/types';
import NextLink from 'next/link';
import React, { useEffect, useState } from 'react';
import {
@@ -30,12 +33,19 @@ import { DAOMembershipSmall } from './Section/PlayerMemberships';
type Props = {
player: Player;
showSeasonalXP?: boolean;
isPatron?: boolean;
pSeedPrice?: Maybe<number>;
index?: number;
};
const MAX_BIO_LENGTH = 240;
export const PlayerTile: React.FC<Props> = ({ player }) => {
export const PlayerTile: React.FC<Props> = ({
player,
isPatron = false,
pSeedPrice,
index,
}) => {
const description = getPlayerDescription(player);
const displayDescription =
(description?.length ?? 0) > MAX_BIO_LENGTH
@@ -68,7 +78,15 @@ export const PlayerTile: React.FC<Props> = ({ player }) => {
>
<MetaTileHeader>
<VStack pos="relative" h="full">
<PlayerRank {...{ player }} />
{isPatron && typeof index === 'number' && pSeedPrice ? (
<PatronRank
patron={player as Patron}
pSeedPrice={pSeedPrice}
index={index}
/>
) : (
<PlayerRank player={player} />
)}
<PlayerProfilePicture {...{ player }} size="xl" />
<Flex px={3} w="full" pos="absolute" bottom={-6} zIndex={1}>
<Heading