diff --git a/packages/design-system/src/SelectSearch.tsx b/packages/design-system/src/SelectSearch.tsx index 00758f84..279a2c2c 100644 --- a/packages/design-system/src/SelectSearch.tsx +++ b/packages/design-system/src/SelectSearch.tsx @@ -3,10 +3,10 @@ import Select, { Props as SelectProps, Styles } from 'react-select'; import { theme } from './theme'; -const selectStyles: Styles = { +export const selectStyles: Styles = { menu: (styles) => ({ ...styles, - background: theme.colors.purple[400], + background: theme.colors.dark, }), menuList: (styles) => ({ ...styles, diff --git a/packages/design-system/src/index.ts b/packages/design-system/src/index.ts index d40fbb0f..60fc065c 100644 --- a/packages/design-system/src/index.ts +++ b/packages/design-system/src/index.ts @@ -43,4 +43,4 @@ export { MetaBox } from './MetaBox'; export { MetaTag } from './MetaTag'; export { H1, P } from './typography'; export { ResponsiveText } from './ResponsiveText'; -export { SelectSearch } from './SelectSearch'; +export { SelectSearch, selectStyles } from './SelectSearch'; diff --git a/packages/design-system/src/theme.ts b/packages/design-system/src/theme.ts index f148a04c..2bfa7d97 100644 --- a/packages/design-system/src/theme.ts +++ b/packages/design-system/src/theme.ts @@ -31,6 +31,7 @@ export const theme: Theme = { '#__next': { background: 'dark', color: 'white', + minHeight: '100vh', }, }, }, diff --git a/packages/web/components/Player/PlayerFeatures.tsx b/packages/web/components/Player/PlayerFeatures.tsx index 9205fe72..fe8e657e 100644 --- a/packages/web/components/Player/PlayerFeatures.tsx +++ b/packages/web/components/Player/PlayerFeatures.tsx @@ -44,7 +44,7 @@ export const PlayerFeatures: React.FC = ({ player }) => { ? `${player.availability_hours} hr / week` : 'N/A' } - color="whiteAlpha.500" + color={player.availability_hours ? undefined : 'whiteAlpha.500'} /> diff --git a/packages/web/components/Player/PlayerTile.tsx b/packages/web/components/Player/PlayerTile.tsx new file mode 100644 index 00000000..595d8b70 --- /dev/null +++ b/packages/web/components/Player/PlayerTile.tsx @@ -0,0 +1,122 @@ +import { + Avatar, + Heading, + HStack, + MetaTag, + Text, + VStack, + Wrap, +} from '@metafam/ds'; +import { MetaLink } from 'components/Link'; +import { PlayerContacts } from 'components/Player/PlayerContacts'; +import { PlayerFragmentFragment } from 'graphql/autogen/types'; +import { SkillColors } from 'graphql/types'; +import React from 'react'; +import { getPlayerImage, getPlayerName } from 'utils/playerHelpers'; + +type Props = { + player: PlayerFragmentFragment; +}; + +const SHOW_MEMBERSHIPS = 4; +const SHOW_SKILLS = 4; + +export const PlayerTile: React.FC = ({ player }) => ( + + + + + {getPlayerName(player)} + + + + {player.playerType?.title ? ( + {player.playerType?.title.toUpperCase()} + ) : null} + {player.rank && ( + + {player.rank} + + )} + XP: {Math.floor(player.totalXp)} + + {player.Player_Skills.length ? ( + + + SKILLS + + + {player.Player_Skills.slice(0, SHOW_SKILLS).map(({ Skill }) => ( + + {Skill.name} + + ))} + {player.Player_Skills.length > SHOW_SKILLS && ( + + {`+${player.Player_Skills.length - SHOW_SKILLS}`} + + )} + + + ) : null} + + {player.daohausMemberships.length ? ( + + + MEMBER OF + + + {player.daohausMemberships + .slice(0, SHOW_MEMBERSHIPS) + .map((member) => ( + + {member.moloch.title} + + ))} + {player.daohausMemberships.length > SHOW_MEMBERSHIPS && ( + + {`+${player.daohausMemberships.length - SHOW_MEMBERSHIPS}`} + + )} + + + ) : null} + + {player.Accounts.length ? ( + + + CONTACT + + + + + + ) : null} + +); diff --git a/packages/web/components/PlayerList.tsx b/packages/web/components/PlayerList.tsx index 17bf8d90..4b62cf62 100644 --- a/packages/web/components/PlayerList.tsx +++ b/packages/web/components/PlayerList.tsx @@ -1,18 +1,7 @@ -import { - Avatar, - Heading, - HStack, - MetaTag, - SimpleGrid, - Text, - VStack, - Wrap, -} from '@metafam/ds'; -import { MetaLink } from 'components/Link'; -import { PlayerContacts } from 'components/Player/PlayerContacts'; +import { SimpleGrid } from '@metafam/ds'; +import { PlayerTile } from 'components/Player/PlayerTile'; import { PlayerFragmentFragment } from 'graphql/autogen/types'; import React from 'react'; -import { getPlayerImage, getPlayerName } from 'utils/playerHelpers'; type Props = { players: PlayerFragmentFragment[]; @@ -21,62 +10,7 @@ type Props = { export const PlayerList: React.FC = ({ players }) => ( {players.map((p) => ( - - - - - {getPlayerName(p)} - - - - - {p.rank} - - XP: {Math.floor(p.totalXp)} - - - {p.daohausMemberships.length ? ( - - - MEMBER OF - - - {p.daohausMemberships.map((member) => ( - - {member.moloch.title} - - ))} - - - ) : null} - - {p.Accounts.length ? ( - - - CONTACT - - - - - - ) : null} - + ))} ); diff --git a/packages/web/components/Setup/SetupAvailability.tsx b/packages/web/components/Setup/SetupAvailability.tsx index d4a7698d..db47a136 100644 --- a/packages/web/components/Setup/SetupAvailability.tsx +++ b/packages/web/components/Setup/SetupAvailability.tsx @@ -10,11 +10,10 @@ import { } from '@metafam/ds'; import { FlexContainer } from 'components/Container'; import { useSetupFlow } from 'contexts/SetupContext'; +import { useUpdatePlayerSkillsMutation } from 'graphql/autogen/types'; +import { useUser } from 'lib/hooks'; import React, { useEffect, useState } from 'react'; -import { useUpdatePlayerSkillsMutation } from '../../graphql/autogen/types'; -import { useUser } from '../../lib/hooks'; - export const SetupAvailability: React.FC = () => { const { onNextPress, diff --git a/packages/web/components/Setup/SetupDone.tsx b/packages/web/components/Setup/SetupDone.tsx index ea48d72f..80377127 100644 --- a/packages/web/components/Setup/SetupDone.tsx +++ b/packages/web/components/Setup/SetupDone.tsx @@ -1,16 +1,33 @@ -import { MetaButton, MetaHeading } from '@metafam/ds'; +import { MetaButton, MetaHeading, Stack } from '@metafam/ds'; import { FlexContainer } from 'components/Container'; +import { PlayerTile } from 'components/Player/PlayerTile'; +import { useUser } from 'lib/hooks'; import { useRouter } from 'next/router'; import React from 'react'; export const SetupDone: React.FC = () => { const router = useRouter(); + const { user } = useUser({ redirectTo: '/' }); return ( Game on! - router.push('/')} px={20} py={8} fontSize="xl"> - Play - + + + {user?.player && } + router.push('/')} + px={20} + py={8} + fontSize="xl" + > + Play + + ); }; diff --git a/packages/web/components/Setup/SetupPlayerType.tsx b/packages/web/components/Setup/SetupPlayerType.tsx index 5a6bd8b2..880db51f 100644 --- a/packages/web/components/Setup/SetupPlayerType.tsx +++ b/packages/web/components/Setup/SetupPlayerType.tsx @@ -7,11 +7,10 @@ import { } from '@metafam/ds'; import { FlexContainer } from 'components/Container'; import { useSetupFlow } from 'contexts/SetupContext'; +import { useUpdateAboutYouMutation } from 'graphql/autogen/types'; +import { useUser } from 'lib/hooks'; import React from 'react'; -import { useUpdateAboutYouMutation } from '../../graphql/autogen/types'; -import { useUser } from '../../lib/hooks'; - export const SetupPlayerType: React.FC = () => { const { onNextPress, @@ -29,23 +28,28 @@ export const SetupPlayerType: React.FC = () => { const handleNextPress = async () => { if (!user) return; - const { error } = await updateAboutYou({ - playerId: user.id, - input: { - enneagram: personalityType?.name, - playerTypeId: playerType?.id, - }, - }); - - if (error) { - console.warn(error); - toast({ - title: 'Error', - description: 'Unable to update Player Account. The octo is sad 😢', - status: 'error', - isClosable: true, + if ( + user.player?.EnneagramType?.name !== personalityType?.name || + user.player?.playerType?.id !== playerType?.id + ) { + const { error } = await updateAboutYou({ + playerId: user.id, + input: { + enneagram: personalityType?.name, + playerTypeId: playerType?.id, + }, }); - return; + + if (error) { + console.warn(error); + toast({ + title: 'Error', + description: 'Unable to update Player Account. The octo is sad 😢', + status: 'error', + isClosable: true, + }); + return; + } } onNextPress(); diff --git a/packages/web/components/Setup/SetupProfile.tsx b/packages/web/components/Setup/SetupProfile.tsx index 540575f4..2b3bb8a8 100644 --- a/packages/web/components/Setup/SetupProfile.tsx +++ b/packages/web/components/Setup/SetupProfile.tsx @@ -2,10 +2,45 @@ import BackgroundImage from 'assets/profile-background.jpg'; import { FlexContainer, PageContainer } from 'components/Container'; import { SetupHeader } from 'components/Setup/SetupHeader'; import { useSetupFlow } from 'contexts/SetupContext'; -import React from 'react'; +import { PersonalityTypes } from 'graphql/types'; +import { useUser } from 'lib/hooks'; +import React, { useEffect } from 'react'; export const SetupProfile: React.FC = () => { - const { step, screen, numTotalSteps, options } = useSetupFlow(); + const { + step, + screen, + numTotalSteps, + options, + setPersonalityType, + setPlayerType, + setAvailability, + setSkills, + } = useSetupFlow(); + const { user } = useUser({ redirectTo: '/' }); + useEffect(() => { + if (user?.player) { + if (user.player.availability_hours) { + setAvailability(user.player.availability_hours.toString()); + } + if (user.player.EnneagramType) { + setPersonalityType(PersonalityTypes[user.player.EnneagramType.name]); + } + if (user.player.playerType) { + setPlayerType(user.player.playerType); + } + if (user.player.Player_Skills && user.player.Player_Skills.length > 0) { + setSkills( + user.player.Player_Skills.map((s) => ({ + value: s.Skill.id, + label: s.Skill.name, + ...s.Skill, + })), + ); + } + } + }, [user, setAvailability, setPersonalityType, setPlayerType, setSkills]); + return ( {(step + 1) % numTotalSteps !== 0 && } diff --git a/packages/web/components/Setup/SetupSkills.tsx b/packages/web/components/Setup/SetupSkills.tsx index cc949398..2c8c69af 100644 --- a/packages/web/components/Setup/SetupSkills.tsx +++ b/packages/web/components/Setup/SetupSkills.tsx @@ -1,6 +1,14 @@ -import { MetaButton, MetaHeading, SelectSearch } from '@metafam/ds'; +import { + MetaButton, + MetaHeading, + MetaTheme, + SelectSearch, + selectStyles, +} from '@metafam/ds'; import { FlexContainer } from 'components/Container'; import { useSetupFlow } from 'contexts/SetupContext'; +import { SkillCategory_Enum } from 'graphql/autogen/types'; +import { SkillColors } from 'graphql/types'; import React from 'react'; import { SkillOption } from 'utils/skillHelpers'; @@ -13,6 +21,28 @@ export const SetupSkills: React.FC = () => { nextButtonLabel, } = useSetupFlow(); + const styles: typeof selectStyles = { + ...selectStyles, + multiValue: (s, { data }) => ({ + ...s, + background: SkillColors[data.category as SkillCategory_Enum], + color: MetaTheme.colors.white, + }), + multiValueLabel: (s, { data }) => ({ + ...s, + background: SkillColors[data.category as SkillCategory_Enum], + color: MetaTheme.colors.white, + }), + groupHeading: (s, { children }) => { + return { + ...s, + ...(selectStyles.groupHeading && + selectStyles.groupHeading(s, { children })), + background: SkillColors[children as SkillCategory_Enum], + }; + }, + }; + return ( @@ -21,6 +51,7 @@ export const SetupSkills: React.FC = () => { setSkills(value as Array)} options={skillsList} diff --git a/packages/web/contexts/Web3Context.tsx b/packages/web/contexts/Web3Context.tsx index 3cc93cd4..4469ea89 100644 --- a/packages/web/contexts/Web3Context.tsx +++ b/packages/web/contexts/Web3Context.tsx @@ -56,15 +56,18 @@ export const Web3ContextProvider: React.FC = ({ children }) => { const modalProvider = await web3Modal.connect(); const ethersProvider = new providers.Web3Provider(modalProvider); - let token = getTokenFromStore(); + const ethAddress = await ethersProvider.getSigner().getAddress(); + setAddress(ethAddress); - if (!token) { + let token = getTokenFromStore(); + if ( + !token || + did.getSignerAddress(token)?.toLowerCase() !== ethAddress.toLowerCase() + ) { token = await did.createToken(ethersProvider); } setTokenInStore(token); - - setAddress(await ethersProvider.getSigner().getAddress()); setProvider(ethersProvider); setAuthToken(token); setIsConnected(true); diff --git a/packages/web/graphql/getMe.ts b/packages/web/graphql/getMe.ts index 88e5a88b..b71c8f8d 100644 --- a/packages/web/graphql/getMe.ts +++ b/packages/web/graphql/getMe.ts @@ -1,6 +1,5 @@ import gql from 'fake-tag'; - -import { PlayerFragment } from './fragments'; +import { PlayerFragment } from 'graphql/fragments'; export const GetMeQuery = gql` query GetMe { diff --git a/packages/web/graphql/getPersonalityTypes.ts b/packages/web/graphql/getPersonalityTypes.ts index b4027716..5d9705c6 100644 --- a/packages/web/graphql/getPersonalityTypes.ts +++ b/packages/web/graphql/getPersonalityTypes.ts @@ -1,81 +1,3 @@ -import AchieverImage from 'assets/achiever.png'; -import ChallengerImage from 'assets/challenger.png'; -import EnthusiastImage from 'assets/enthusiast.png'; -import HelperImage from 'assets/helper.png'; -import IndividualistImage from 'assets/individualist.png'; -import InvestigatorImage from 'assets/investigator.png'; -import LoyalistImage from 'assets/loyalist.png'; -import PeacemakerImage from 'assets/peacemaker.png'; -import ReformerImage from 'assets/reformer.png'; -import { PersonalityType } from 'graphql/types'; +import { PersonalityTypes } from 'graphql/types'; -import { EnneagramType_Enum } from './autogen/types'; - -const personalityTypes: Array = [ - { - id: '1', - name: EnneagramType_Enum.Reformer, - label: 'The Reformer', - description: 'Principled, Purposeful, Self-Controlled, and Perfectionistic', - image: ReformerImage, - }, - { - id: '2', - name: EnneagramType_Enum.Helper, - label: 'The Helper', - description: 'Demonstrative, Generous, People-Pleasing, and Possessive', - image: HelperImage, - }, - { - id: '3', - name: EnneagramType_Enum.Achiever, - label: 'The Achiever', - description: 'Adaptive, Excelling, Driven, and Image-Conscious', - image: AchieverImage, - }, - { - id: '4', - name: EnneagramType_Enum.Individualist, - label: 'The Individualist', - description: 'Expressive, Dramatic, Self-Absorbed, and Temperamental', - image: IndividualistImage, - }, - { - id: '5', - name: EnneagramType_Enum.Investigator, - label: 'The Investigator', - description: 'Perceptive, Innovative, Secretive, and Isolated', - image: InvestigatorImage, - }, - { - id: '6', - name: EnneagramType_Enum.Loyalist, - label: 'The Loyalist', - description: 'Engaging, Responsible, Anxious, and Suspicious', - image: LoyalistImage, - }, - { - id: '7', - name: EnneagramType_Enum.Enthusiast, - label: 'The Enthusiast', - description: 'Spontaneous, Versatile, Distractible, and Scattered', - image: EnthusiastImage, - }, - { - id: '8', - name: EnneagramType_Enum.Challenger, - label: 'The Challenger', - description: 'Self-Confident, Decisive, Willful, and Confrontational', - image: ChallengerImage, - }, - { - id: '9', - name: EnneagramType_Enum.Peacemaker, - label: 'The Peacemaker', - description: 'Receptive, Reassuring, Agreeable, and Complacent', - image: PeacemakerImage, - }, -]; - -// TODO: fetch data from backend instead -export const getPersonalityTypes = () => personalityTypes; +export const getPersonalityTypes = () => Object.values(PersonalityTypes); diff --git a/packages/web/graphql/types.ts b/packages/web/graphql/types.ts index 0c66d43d..ed1e5e4a 100644 --- a/packages/web/graphql/types.ts +++ b/packages/web/graphql/types.ts @@ -1,4 +1,19 @@ -import { EnneagramType_Enum, Member, Moloch } from 'graphql/autogen/types'; +import { MetaTheme } from '@metafam/ds'; +import AchieverImage from 'assets/achiever.png'; +import ChallengerImage from 'assets/challenger.png'; +import EnthusiastImage from 'assets/enthusiast.png'; +import HelperImage from 'assets/helper.png'; +import IndividualistImage from 'assets/individualist.png'; +import InvestigatorImage from 'assets/investigator.png'; +import LoyalistImage from 'assets/loyalist.png'; +import PeacemakerImage from 'assets/peacemaker.png'; +import ReformerImage from 'assets/reformer.png'; +import { + EnneagramType_Enum, + Member, + Moloch, + SkillCategory_Enum, +} from 'graphql/autogen/types'; export type Skill = { id: string; @@ -17,3 +32,80 @@ export type PersonalityType = { export type Membership = Pick & { moloch: Pick; }; + +export const PersonalityTypes: { + [any: string]: PersonalityType; +} = { + [EnneagramType_Enum.Reformer]: { + id: '1', + name: EnneagramType_Enum.Reformer, + label: 'The Reformer', + description: 'Principled, Purposeful, Self-Controlled, and Perfectionistic', + image: ReformerImage, + }, + [EnneagramType_Enum.Helper]: { + id: '2', + name: EnneagramType_Enum.Helper, + label: 'The Helper', + description: 'Demonstrative, Generous, People-Pleasing, and Possessive', + image: HelperImage, + }, + [EnneagramType_Enum.Achiever]: { + id: '3', + name: EnneagramType_Enum.Achiever, + label: 'The Achiever', + description: 'Adaptive, Excelling, Driven, and Image-Conscious', + image: AchieverImage, + }, + [EnneagramType_Enum.Individualist]: { + id: '4', + name: EnneagramType_Enum.Individualist, + label: 'The Individualist', + description: 'Expressive, Dramatic, Self-Absorbed, and Temperamental', + image: IndividualistImage, + }, + [EnneagramType_Enum.Investigator]: { + id: '5', + name: EnneagramType_Enum.Investigator, + label: 'The Investigator', + description: 'Perceptive, Innovative, Secretive, and Isolated', + image: InvestigatorImage, + }, + [EnneagramType_Enum.Loyalist]: { + id: '6', + name: EnneagramType_Enum.Loyalist, + label: 'The Loyalist', + description: 'Engaging, Responsible, Anxious, and Suspicious', + image: LoyalistImage, + }, + [EnneagramType_Enum.Enthusiast]: { + id: '7', + name: EnneagramType_Enum.Enthusiast, + label: 'The Enthusiast', + description: 'Spontaneous, Versatile, Distractible, and Scattered', + image: EnthusiastImage, + }, + [EnneagramType_Enum.Challenger]: { + id: '8', + name: EnneagramType_Enum.Challenger, + label: 'The Challenger', + description: 'Self-Confident, Decisive, Willful, and Confrontational', + image: ChallengerImage, + }, + [EnneagramType_Enum.Peacemaker]: { + id: '9', + name: EnneagramType_Enum.Peacemaker, + label: 'The Peacemaker', + description: 'Receptive, Reassuring, Agreeable, and Complacent', + image: PeacemakerImage, + }, +}; + +export const SkillColors: Record = { + [SkillCategory_Enum.Community]: MetaTheme.colors.green['700'], + [SkillCategory_Enum.Design]: MetaTheme.colors.pink['700'], + [SkillCategory_Enum.Dev]: MetaTheme.colors.cyan['700'], + [SkillCategory_Enum.Engineering]: MetaTheme.colors.blue['700'], + [SkillCategory_Enum.Technologies]: MetaTheme.colors.gray['600'], + [SkillCategory_Enum.Strategy]: MetaTheme.colors.yellow['700'], +}; diff --git a/packages/web/lib/hooks.ts b/packages/web/lib/hooks.ts index 79ec4428..d15be3d6 100644 --- a/packages/web/lib/hooks.ts +++ b/packages/web/lib/hooks.ts @@ -1,9 +1,8 @@ +import { Web3Context } from 'contexts/Web3Context'; +import { useGetMeQuery } from 'graphql/autogen/types'; import { useRouter } from 'next/router'; import { useContext, useEffect } from 'react'; -import { Web3Context } from '../contexts/Web3Context'; -import { useGetMeQuery } from '../graphql/autogen/types'; - export const useWeb3 = () => useContext(Web3Context); type UseUserOpts = { diff --git a/packages/web/pages/player/[username].tsx b/packages/web/pages/player/[username].tsx index be5eac6a..0b1aca81 100644 --- a/packages/web/pages/player/[username].tsx +++ b/packages/web/pages/player/[username].tsx @@ -1,16 +1,20 @@ import { Container, + HStack, + Image, MetaBox, MetaTag, - MetaTheme, P, SimpleGrid, + Text, Wrap, } from '@metafam/ds'; +import { FlexContainer } from 'components/Container'; import { PlayerFeatures } from 'components/Player/PlayerFeatures'; import { PlayerHero } from 'components/Player/PlayerHero'; import { getPlayer } from 'graphql/getPlayer'; import { getPlayers } from 'graphql/getPlayers'; +import { PersonalityTypes, SkillColors } from 'graphql/types'; import { GetStaticPaths, GetStaticPropsContext, @@ -20,19 +24,8 @@ import Error from 'next/error'; import React from 'react'; import { getPlayerDescription } from 'utils/playerHelpers'; -import { SkillCategory_Enum } from '../../graphql/autogen/types'; - type Props = InferGetStaticPropsType; -const SkillColors: Record = { - [SkillCategory_Enum.Community]: MetaTheme.colors.green['700'], - [SkillCategory_Enum.Design]: MetaTheme.colors.pink['700'], - [SkillCategory_Enum.Dev]: MetaTheme.colors.cyan['700'], - [SkillCategory_Enum.Engineering]: MetaTheme.colors.blue['700'], - [SkillCategory_Enum.Technologies]: MetaTheme.colors.gray['600'], - [SkillCategory_Enum.Strategy]: MetaTheme.colors.yellow['700'], -}; - const PlayerPage: React.FC = ({ player }) => { if (!player) { return ; @@ -46,6 +39,24 @@ const PlayerPage: React.FC = ({ player }) => {

{getPlayerDescription(player)}

+ {player.EnneagramType ? ( + + {player.EnneagramType.name} + + + {player.EnneagramType.name} + + + {player.EnneagramType.description} + + + + ) : null}