mirror of
https://github.com/MetaFam/TheGame.git
synced 2026-01-13 16:37:58 -05:00
174 lines
5.8 KiB
TypeScript
174 lines
5.8 KiB
TypeScript
import {
|
|
Flex,
|
|
Heading,
|
|
HStack,
|
|
Link,
|
|
LoadingState,
|
|
MetaTag,
|
|
MetaTile,
|
|
MetaTileBody,
|
|
MetaTileHeader,
|
|
Text,
|
|
VStack,
|
|
Wrap,
|
|
WrapItem,
|
|
} from '@metafam/ds';
|
|
import type { Maybe } from '@metafam/utils';
|
|
import React, { useCallback, useEffect, useState } from 'react';
|
|
|
|
import { PatronRank } from '#components/Patron/PatronRank';
|
|
import { PlayerContacts } from '#components/Player/PlayerContacts';
|
|
import { PlayerProfilePicture } from '#components/Player/PlayerProfilePicture';
|
|
import { SkillsTags } from '#components/Quest/Skills';
|
|
import type { Player, Skill } from '#graphql/autogen/hasura-sdk';
|
|
import { getAllMemberships, GuildMembership } from '#graphql/getMemberships';
|
|
import type { Patron } from '#graphql/types';
|
|
import { usePlayerName } from '#lib/hooks/player/usePlayerName';
|
|
import { usePlayerURL } from '#lib/hooks/player/usePlayerURL';
|
|
import { getPlayerDescription } from '#utils/playerHelpers';
|
|
|
|
import { PlayerRank } from './PlayerRank';
|
|
import { DAOMembershipSmall } from './Section/PlayerLinks/PlayerMemberships';
|
|
|
|
type Props = {
|
|
player: Player;
|
|
isPatron?: boolean;
|
|
pSeedPrice?: Maybe<number>;
|
|
showSeasonalXP?: boolean;
|
|
index?: number;
|
|
};
|
|
|
|
export const PlayerTile: React.FC<Props> = ({
|
|
player,
|
|
isPatron = false,
|
|
pSeedPrice,
|
|
showSeasonalXP,
|
|
index,
|
|
}) => {
|
|
const description = getPlayerDescription(player);
|
|
const [memberships, setMemberships] = useState<GuildMembership[]>([]);
|
|
// default player name and url
|
|
const linkURL = usePlayerURL(player);
|
|
const playerName = usePlayerName(player);
|
|
|
|
const [loading, setLoading] = useState(true);
|
|
const daosRef = React.useRef<HTMLDivElement>(null);
|
|
const [limit, setLimit] = useState(12);
|
|
|
|
useEffect(() => {
|
|
getAllMemberships(player).then(({ all }) => {
|
|
setLoading(false);
|
|
setMemberships(all);
|
|
});
|
|
}, [player]);
|
|
|
|
const handleResize = useCallback(() => {
|
|
const width = daosRef.current?.scrollWidth;
|
|
setLimit(Math.max(8, Math.floor((width ?? 22) / 22)));
|
|
}, []);
|
|
|
|
useEffect(() => {
|
|
const elem = daosRef.current;
|
|
elem?.addEventListener('resize', handleResize);
|
|
return () => elem?.removeEventListener('resize', handleResize);
|
|
}, [handleResize]);
|
|
|
|
return (
|
|
<Link role="group" _hover={{ textDecoration: 'none' }} href={linkURL}>
|
|
<MetaTile minW={'300px'} height="full" width="full" cursor="pointer">
|
|
<MetaTileHeader>
|
|
{isPatron && typeof index === 'number' && pSeedPrice ? (
|
|
<PatronRank patron={player as Patron} {...{ pSeedPrice, index }} />
|
|
) : (
|
|
<PlayerRank {...{ player, showSeasonalXP }} />
|
|
)}
|
|
<PlayerProfilePicture {...{ player }} size="xl" />
|
|
<Flex px={3} w="full" pos="absolute" bottom={-6} zIndex={1}>
|
|
<Heading
|
|
size="lg"
|
|
color="white"
|
|
bgColor="whiteAlpha.100"
|
|
backdropFilter="blur(10px)"
|
|
lineHeight={1.8}
|
|
justifyContent="center"
|
|
px={3}
|
|
width="full"
|
|
textAlign="center"
|
|
borderRadius={10}
|
|
fontFamily="body"
|
|
fontWeight={400}
|
|
textShadow="0 0 8px var(--chakra-colors-blackAlpha-400)" // v. light shadow makes the text readable if the logo/avatar is white
|
|
>
|
|
{playerName}
|
|
</Heading>
|
|
</Flex>
|
|
</MetaTileHeader>
|
|
<MetaTileBody pos="relative" height="full">
|
|
<Flex direction="column" gap={2} mb="auto">
|
|
{description && (
|
|
<VStack spacing={1} align="stretch">
|
|
<Text textStyle="caption">About</Text>
|
|
<Text fontSize="sm" noOfLines={4}>
|
|
{description}
|
|
</Text>
|
|
</VStack>
|
|
)}
|
|
{!!player.skills?.length && (
|
|
<VStack spacing={2} align="stretch" mt={2}>
|
|
<Text textStyle="caption">Skills</Text>
|
|
<SkillsTags
|
|
skills={player.skills.map(({ Skill: s }) => s) as Skill[]}
|
|
/>
|
|
</VStack>
|
|
)}
|
|
</Flex>
|
|
|
|
<Flex justifyContent="space-between" pointerEvents="none">
|
|
<VStack spacing={2} align="stretch" ref={daosRef}>
|
|
{!!memberships.length && (
|
|
<>
|
|
<Text textStyle="caption">Member of</Text>
|
|
<HStack mt={2} position="relative" zIndex={1}>
|
|
{loading ? (
|
|
<LoadingState mb={6} />
|
|
) : (
|
|
<Wrap overflow="visible">
|
|
{memberships
|
|
.slice(
|
|
0,
|
|
memberships.length > limit ? limit - 1 : limit,
|
|
)
|
|
.map((membership) => (
|
|
<WrapItem key={membership.address ?? Math.random()}>
|
|
<DAOMembershipSmall {...{ membership }} />
|
|
</WrapItem>
|
|
))}
|
|
{memberships.length > limit && (
|
|
<WrapItem>
|
|
<MetaTag size="sm" fontWeight="normal" h={8}>
|
|
{`+${memberships.length - limit + 1}`}
|
|
</MetaTag>
|
|
</WrapItem>
|
|
)}
|
|
</Wrap>
|
|
)}
|
|
</HStack>
|
|
</>
|
|
)}
|
|
</VStack>
|
|
|
|
{!!player.accounts?.length && (
|
|
<VStack spacing={2}>
|
|
<Text textStyle="caption">Contact</Text>
|
|
<HStack mt={1} pointerEvents="all">
|
|
<PlayerContacts {...{ player }} disableBrightId />
|
|
</HStack>
|
|
</VStack>
|
|
)}
|
|
</Flex>
|
|
</MetaTileBody>
|
|
</MetaTile>
|
|
</Link>
|
|
);
|
|
};
|