mirror of
https://github.com/MetaFam/TheGame.git
synced 2026-04-02 03:00:32 -04:00
Skills Selector (#124)
* skills map in context * using react-select * removed sudo from package.json * fixed lint and format issues
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
{
|
||||
"printWidth": 80,
|
||||
"singleQuote": true,
|
||||
"trailingComma": "all"
|
||||
"trailingComma": "all",
|
||||
"arrowParens": "always"
|
||||
}
|
||||
|
||||
@@ -39,6 +39,8 @@ services:
|
||||
dockerfile: ./docker/backend/Dockerfile
|
||||
target: base
|
||||
command: yarn backend:dev
|
||||
ports:
|
||||
- 4000:4000
|
||||
volumes:
|
||||
- ./packages/@types:/usr/src/app/packages/@types
|
||||
- ./packages/backend:/usr/src/app/packages/backend
|
||||
|
||||
@@ -51,6 +51,7 @@
|
||||
"@types/node": "^14.6.4",
|
||||
"@types/react": "^16.9.43",
|
||||
"@types/react-dom": "^16.9.8",
|
||||
"@types/react-select": "^3.0.20",
|
||||
"@typescript-eslint/eslint-plugin": "3.9.1",
|
||||
"@typescript-eslint/parser": "3.6.0",
|
||||
"eslint": "6.8.0",
|
||||
|
||||
@@ -25,8 +25,9 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@chakra-ui/core": "next",
|
||||
"@chakra-ui/icons": "next",
|
||||
"@chakra-ui/theme": "next",
|
||||
"@chakra-ui/icons": "next"
|
||||
"react-select": "^3.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.10.5",
|
||||
|
||||
73
packages/design-system/src/SelectSearch.tsx
Normal file
73
packages/design-system/src/SelectSearch.tsx
Normal file
@@ -0,0 +1,73 @@
|
||||
import React from 'react';
|
||||
import Select, { Props as SelectProps, Styles } from 'react-select';
|
||||
|
||||
import { theme } from './theme';
|
||||
|
||||
const selectStyles: Styles = {
|
||||
menu: (styles) => ({
|
||||
...styles,
|
||||
background: theme.colors.purple[400],
|
||||
}),
|
||||
noOptionsMessage: (styles) => ({
|
||||
...styles,
|
||||
color: theme.colors.white,
|
||||
}),
|
||||
input: (styles) => ({
|
||||
...styles,
|
||||
color: theme.colors.white,
|
||||
}),
|
||||
groupHeading: (styles) => ({
|
||||
...styles,
|
||||
color: theme.colors.white,
|
||||
}),
|
||||
option: (styles) => ({
|
||||
...styles,
|
||||
background: theme.colors.dark,
|
||||
':hover': {
|
||||
backgroundColor: theme.colors.purpleTag,
|
||||
color: theme.colors.white,
|
||||
},
|
||||
}),
|
||||
control: (styles) => ({
|
||||
...styles,
|
||||
background: theme.colors.dark,
|
||||
border: theme.colors.dark,
|
||||
}),
|
||||
multiValue: (styles) => ({
|
||||
...styles,
|
||||
background: theme.colors.purpleTag,
|
||||
color: theme.colors.white,
|
||||
}),
|
||||
multiValueLabel: (styles) => ({
|
||||
...styles,
|
||||
background: theme.colors.purpleTag,
|
||||
color: theme.colors.white,
|
||||
}),
|
||||
multiValueRemove: (styles) => ({
|
||||
...styles,
|
||||
color: theme.colors.white,
|
||||
cursor: 'pointer',
|
||||
':hover': {
|
||||
color: theme.colors.blueLight,
|
||||
},
|
||||
}),
|
||||
clearIndicator: (styles) => ({
|
||||
...styles,
|
||||
color: theme.colors.white,
|
||||
cursor: 'pointer',
|
||||
':hover': {
|
||||
color: theme.colors.blueLight,
|
||||
},
|
||||
}),
|
||||
dropdownIndicator: (styles) => ({
|
||||
...styles,
|
||||
color: theme.colors.white,
|
||||
cursor: 'pointer',
|
||||
':hover': {
|
||||
color: theme.colors.blueLight,
|
||||
},
|
||||
}),
|
||||
};
|
||||
export const SelectSearch: React.FC<SelectProps> = (props) => (
|
||||
<Select styles={selectStyles} {...props} />
|
||||
);
|
||||
@@ -40,3 +40,4 @@ export { MetaBox } from './MetaBox';
|
||||
export { MetaTag } from './MetaTag';
|
||||
export { H1, P } from './typography';
|
||||
export { ResponsiveText } from './ResponsiveText';
|
||||
export { SelectSearch } from './SelectSearch';
|
||||
|
||||
@@ -3,6 +3,8 @@ import { FlexContainer } from 'components/Container';
|
||||
import { SetupContext } from 'contexts/SetupContext';
|
||||
import React, { useContext } from 'react';
|
||||
|
||||
import { SetupSkills } from './SetupSkills';
|
||||
|
||||
export const SetupProfession: React.FC = () => {
|
||||
const { useProgress } = useContext(SetupContext);
|
||||
const numProgressSteps = 3;
|
||||
@@ -10,9 +12,7 @@ export const SetupProfession: React.FC = () => {
|
||||
|
||||
return (
|
||||
<FlexContainer flex={1}>
|
||||
{currentProgress === 0 && (
|
||||
<MetaHeading mb={10}>What are your superpowers?</MetaHeading>
|
||||
)}
|
||||
{currentProgress === 0 && <SetupSkills />}
|
||||
{currentProgress === 1 && <MetaHeading mb={10}>Availability</MetaHeading>}
|
||||
{currentProgress === 2 && <MetaHeading mb={10}>Memberships</MetaHeading>}
|
||||
<MetaButton onClick={onNextPress}>Next Step</MetaButton>
|
||||
|
||||
22
packages/web/components/Setup/SetupSkills.tsx
Normal file
22
packages/web/components/Setup/SetupSkills.tsx
Normal file
@@ -0,0 +1,22 @@
|
||||
import { MetaHeading, SelectSearch } from '@metafam/ds';
|
||||
import { FlexContainer } from 'components/Container';
|
||||
import { SetupContext } from 'contexts/SetupContext';
|
||||
import React, { useContext } from 'react';
|
||||
import { SkillOption } from 'utils/skillHelpers';
|
||||
|
||||
export const SetupSkills: React.FC = () => {
|
||||
const { skillsList, skills, setSkills } = useContext(SetupContext);
|
||||
|
||||
return (
|
||||
<FlexContainer mb={10} align="stretch">
|
||||
<MetaHeading mb={10}>What are your superpowers?</MetaHeading>
|
||||
<SelectSearch
|
||||
isMulti
|
||||
value={skills}
|
||||
onChange={(value) => setSkills(value as Array<SkillOption>)}
|
||||
options={skillsList}
|
||||
placeholder="ADD YOUR SKILLS"
|
||||
/>
|
||||
</FlexContainer>
|
||||
);
|
||||
};
|
||||
@@ -1,4 +1,5 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { CategoryOption, SkillOption } from 'utils/skillHelpers';
|
||||
|
||||
type SetupContextType = {
|
||||
useProgress: (numProgressSteps: number) => [number, () => void];
|
||||
@@ -7,6 +8,9 @@ type SetupContextType = {
|
||||
setStep: React.Dispatch<React.SetStateAction<number>>;
|
||||
setProgress: React.Dispatch<React.SetStateAction<number>>;
|
||||
numTotalSteps: number;
|
||||
skills: Array<SkillOption>;
|
||||
setSkills: React.Dispatch<React.SetStateAction<Array<SkillOption>>>;
|
||||
skillsList: Array<CategoryOption>;
|
||||
};
|
||||
|
||||
export const SetupContext = React.createContext<SetupContextType>({
|
||||
@@ -16,9 +20,19 @@ export const SetupContext = React.createContext<SetupContextType>({
|
||||
setStep: () => undefined,
|
||||
setProgress: () => undefined,
|
||||
numTotalSteps: 0,
|
||||
skills: [],
|
||||
setSkills: () => undefined,
|
||||
skillsList: [],
|
||||
});
|
||||
|
||||
export const SetupContextProvider: React.FC = ({ children }) => {
|
||||
type Props = {
|
||||
skillsList: Array<CategoryOption>;
|
||||
};
|
||||
|
||||
export const SetupContextProvider: React.FC<Props> = ({
|
||||
children,
|
||||
skillsList,
|
||||
}) => {
|
||||
const [step, setStep] = useState<number>(0);
|
||||
const [progress, setProgress] = useState<number>(0.5);
|
||||
const numTotalSteps = 3;
|
||||
@@ -44,6 +58,8 @@ export const SetupContextProvider: React.FC = ({ children }) => {
|
||||
return [currentProgress, onNextPress];
|
||||
};
|
||||
|
||||
const [skills, setSkills] = useState<Array<SkillOption>>([]);
|
||||
|
||||
return (
|
||||
<SetupContext.Provider
|
||||
value={{
|
||||
@@ -53,6 +69,9 @@ export const SetupContextProvider: React.FC = ({ children }) => {
|
||||
setStep,
|
||||
setProgress,
|
||||
numTotalSteps,
|
||||
skills,
|
||||
setSkills,
|
||||
skillsList,
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
|
||||
38
packages/web/graphql/getSkills.ts
Normal file
38
packages/web/graphql/getSkills.ts
Normal file
@@ -0,0 +1,38 @@
|
||||
import gql from 'fake-tag';
|
||||
|
||||
import { GetSkillsQuery } from './autogen/types';
|
||||
import { client } from './client';
|
||||
|
||||
const skillsQuery = gql`
|
||||
query GetSkills {
|
||||
Skill(
|
||||
order_by: { Player_Skills_aggregate: { count: desc }, category: asc }
|
||||
) {
|
||||
id
|
||||
name
|
||||
category
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export interface Skill {
|
||||
id: string;
|
||||
name: string;
|
||||
category: string;
|
||||
}
|
||||
|
||||
export const getSkills = async (): Promise<Skill[]> => {
|
||||
const { data, error } = await client
|
||||
.query<GetSkillsQuery>(skillsQuery)
|
||||
.toPromise();
|
||||
|
||||
if (!data) {
|
||||
if (error) {
|
||||
throw error;
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
return data.Skill;
|
||||
};
|
||||
@@ -4,16 +4,11 @@ import { SetupHeader } from 'components/Setup/SetupHeader';
|
||||
import { SetupPersonality } from 'components/Setup/SetupPersonality';
|
||||
import { SetupProfession } from 'components/Setup/SetupProfession';
|
||||
import { SetupContext, SetupContextProvider } from 'contexts/SetupContext';
|
||||
import { getSkills } from 'graphql/getSkills';
|
||||
import { InferGetStaticPropsType } from 'next';
|
||||
import BackgroundImage from 'public/images/profile-background.jpg';
|
||||
import React, { useContext } from 'react';
|
||||
|
||||
export const getStaticProps = async () => {
|
||||
return {
|
||||
props: {
|
||||
hidePageHeader: true,
|
||||
},
|
||||
};
|
||||
};
|
||||
import { parseSkills } from 'utils/skillHelpers';
|
||||
|
||||
const ProfileSetup: React.FC = () => {
|
||||
const { step, numTotalSteps } = useContext(SetupContext);
|
||||
@@ -27,8 +22,22 @@ const ProfileSetup: React.FC = () => {
|
||||
);
|
||||
};
|
||||
|
||||
const ProfileSetupWithContext: React.FC = () => (
|
||||
<SetupContextProvider>
|
||||
export const getStaticProps = async () => {
|
||||
const skills = await getSkills();
|
||||
const skillsList = parseSkills(skills);
|
||||
|
||||
return {
|
||||
props: {
|
||||
skillsList,
|
||||
hidePageHeader: true,
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
export type Props = InferGetStaticPropsType<typeof getStaticProps>;
|
||||
|
||||
const ProfileSetupWithContext: React.FC<Props> = ({ skillsList }) => (
|
||||
<SetupContextProvider skillsList={skillsList}>
|
||||
<ProfileSetup />
|
||||
</SetupContextProvider>
|
||||
);
|
||||
|
||||
33
packages/web/utils/skillHelpers.ts
Normal file
33
packages/web/utils/skillHelpers.ts
Normal file
@@ -0,0 +1,33 @@
|
||||
import { Skill } from 'graphql/getSkills';
|
||||
|
||||
export type SkillMap = {
|
||||
[category: string]: CategoryOption;
|
||||
};
|
||||
|
||||
export type SkillOption = Skill & {
|
||||
value: string;
|
||||
label: string;
|
||||
};
|
||||
|
||||
export type CategoryOption = {
|
||||
label: string;
|
||||
options: Array<SkillOption>;
|
||||
};
|
||||
|
||||
export const parseSkills = (skills: Array<Skill>): Array<CategoryOption> => {
|
||||
const skillsMap: SkillMap = {};
|
||||
skills.map((skill) => {
|
||||
if (!(skill.category in skillsMap)) {
|
||||
skillsMap[skill.category] = {
|
||||
label: skill.category,
|
||||
options: [],
|
||||
};
|
||||
}
|
||||
return skillsMap[skill.category].options?.push({
|
||||
value: skill.id,
|
||||
label: skill.name,
|
||||
...skill,
|
||||
});
|
||||
});
|
||||
return Object.values(skillsMap);
|
||||
};
|
||||
54
yarn.lock
54
yarn.lock
@@ -2124,7 +2124,7 @@
|
||||
resolved "https://registry.yarnpkg.com/@egoist/vue-to-react/-/vue-to-react-1.1.0.tgz#83c884b8608e8ee62e76c03e91ce9c26063a91ad"
|
||||
integrity sha512-MwfwXHDh6ptZGLEtNLPXp2Wghteav7mzpT2Mcwl3NZWKF814i5hhHnNkVrcQQEuxUroSWQqzxLkMKSb+nhPang==
|
||||
|
||||
"@emotion/cache@^10.0.27":
|
||||
"@emotion/cache@^10.0.27", "@emotion/cache@^10.0.9":
|
||||
version "10.0.29"
|
||||
resolved "https://registry.yarnpkg.com/@emotion/cache/-/cache-10.0.29.tgz#87e7e64f412c060102d589fe7c6dc042e6f9d1e0"
|
||||
integrity sha512-fU2VtSVlHiF27empSbxi1O2JFdNWZO+2NFHfwO0pxgTep6Xa3uGb+3pVKfLww2l/IBGLNEZl5Xf/++A4wAYDYQ==
|
||||
@@ -2146,7 +2146,19 @@
|
||||
"@emotion/sheet" "0.9.4"
|
||||
"@emotion/utils" "0.11.3"
|
||||
|
||||
"@emotion/css@^10.0.27":
|
||||
"@emotion/core@^10.0.9":
|
||||
version "10.0.35"
|
||||
resolved "https://registry.yarnpkg.com/@emotion/core/-/core-10.0.35.tgz#513fcf2e22cd4dfe9d3894ed138c9d7a859af9b3"
|
||||
integrity sha512-sH++vJCdk025fBlRZSAhkRlSUoqSqgCzYf5fMOmqqi3bM6how+sQpg3hkgJonj8GxXM4WbD7dRO+4tegDB9fUw==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.5.5"
|
||||
"@emotion/cache" "^10.0.27"
|
||||
"@emotion/css" "^10.0.27"
|
||||
"@emotion/serialize" "^0.11.15"
|
||||
"@emotion/sheet" "0.9.4"
|
||||
"@emotion/utils" "0.11.3"
|
||||
|
||||
"@emotion/css@^10.0.27", "@emotion/css@^10.0.9":
|
||||
version "10.0.27"
|
||||
resolved "https://registry.yarnpkg.com/@emotion/css/-/css-10.0.27.tgz#3a7458198fbbebb53b01b2b87f64e5e21241e14c"
|
||||
integrity sha512-6wZjsvYeBhyZQYNrGoR5yPMYbMBNEnanDrqmsqS1mzDm1cOTu12shvl2j4QHNS36UaTE0USIJawCH9C8oW34Zw==
|
||||
@@ -6115,7 +6127,7 @@
|
||||
"@types/history" "*"
|
||||
"@types/react" "*"
|
||||
|
||||
"@types/react-dom@^16.8.3", "@types/react-dom@^16.9.8":
|
||||
"@types/react-dom@*", "@types/react-dom@^16.8.3", "@types/react-dom@^16.9.8":
|
||||
version "16.9.8"
|
||||
resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-16.9.8.tgz#fe4c1e11dfc67155733dfa6aa65108b4971cb423"
|
||||
integrity sha512-ykkPQ+5nFknnlU6lDd947WbQ6TE3NNzbQAkInC2EKY1qeYdTKp7onFusmYZb+ityzx2YviqT6BXSu+LyWWJwcA==
|
||||
@@ -6146,6 +6158,15 @@
|
||||
"@types/history" "*"
|
||||
"@types/react" "*"
|
||||
|
||||
"@types/react-select@^3.0.20":
|
||||
version "3.0.20"
|
||||
resolved "https://registry.yarnpkg.com/@types/react-select/-/react-select-3.0.20.tgz#1cbedcb145a910602ef192698235cd2d9debdd04"
|
||||
integrity sha512-yKFcq773jsUV5C1nYb0KeQCboo8tCo4ngcM3mi9fmC0CTGJeIuV/mfxaWtmv7i7HetQtki4p7h1YpP8wBy9gWw==
|
||||
dependencies:
|
||||
"@types/react" "*"
|
||||
"@types/react-dom" "*"
|
||||
"@types/react-transition-group" "*"
|
||||
|
||||
"@types/react-syntax-highlighter@11.0.4":
|
||||
version "11.0.4"
|
||||
resolved "https://registry.yarnpkg.com/@types/react-syntax-highlighter/-/react-syntax-highlighter-11.0.4.tgz#d86d17697db62f98046874f62fdb3e53a0bbc4cd"
|
||||
@@ -6160,7 +6181,7 @@
|
||||
dependencies:
|
||||
"@types/react" "*"
|
||||
|
||||
"@types/react-transition-group@4.4.0", "@types/react-transition-group@^4.2.0":
|
||||
"@types/react-transition-group@*", "@types/react-transition-group@4.4.0", "@types/react-transition-group@^4.2.0":
|
||||
version "4.4.0"
|
||||
resolved "https://registry.yarnpkg.com/@types/react-transition-group/-/react-transition-group-4.4.0.tgz#882839db465df1320e4753e6e9f70ca7e9b4d46d"
|
||||
integrity sha512-/QfLHGpu+2fQOqQaXh8MG9q03bFENooTb/it4jr5kKaZlDQfWvjqWZg48AwzPVMBHlRuTRAY7hRHCEOXz5kV6w==
|
||||
@@ -19240,7 +19261,7 @@ memdown@~3.0.0:
|
||||
ltgt "~2.2.0"
|
||||
safe-buffer "~5.1.1"
|
||||
|
||||
memoize-one@5.1.1:
|
||||
memoize-one@5.1.1, memoize-one@^5.0.0:
|
||||
version "5.1.1"
|
||||
resolved "https://registry.yarnpkg.com/memoize-one/-/memoize-one-5.1.1.tgz#047b6e3199b508eaec03504de71229b8eb1d75c0"
|
||||
integrity sha512-HKeeBpWvqiVJD57ZUAsJNm71eHTykffzcLZVYWiVfQeI1rJtuEaS7hQiEpWfVVk18donPwJEcFKIkCmPJNOhHA==
|
||||
@@ -23499,6 +23520,13 @@ react-icons@^3.11.0, react-icons@^3.9.0:
|
||||
dependencies:
|
||||
camelcase "^5.0.0"
|
||||
|
||||
react-input-autosize@^2.2.2:
|
||||
version "2.2.2"
|
||||
resolved "https://registry.yarnpkg.com/react-input-autosize/-/react-input-autosize-2.2.2.tgz#fcaa7020568ec206bc04be36f4eb68e647c4d8c2"
|
||||
integrity sha512-jQJgYCA3S0j+cuOwzuCd1OjmBmnZLdqQdiLKRYrsMMzbjUrVDS5RvJUDwJqA7sKuksDuzFtm6hZGKFu7Mjk5aw==
|
||||
dependencies:
|
||||
prop-types "^15.5.8"
|
||||
|
||||
react-inspector@^4.0.0:
|
||||
version "4.0.1"
|
||||
resolved "https://registry.yarnpkg.com/react-inspector/-/react-inspector-4.0.1.tgz#0f888f78ff7daccbc7be5d452b20c96dc6d5fbb8"
|
||||
@@ -23687,6 +23715,20 @@ react-scripts@3.4.3:
|
||||
optionalDependencies:
|
||||
fsevents "2.1.2"
|
||||
|
||||
react-select@^3.1.0:
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/react-select/-/react-select-3.1.0.tgz#ab098720b2e9fe275047c993f0d0caf5ded17c27"
|
||||
integrity sha512-wBFVblBH1iuCBprtpyGtd1dGMadsG36W5/t2Aj8OE6WbByDg5jIFyT7X5gT+l0qmT5TqWhxX+VsKJvCEl2uL9g==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.4.4"
|
||||
"@emotion/cache" "^10.0.9"
|
||||
"@emotion/core" "^10.0.9"
|
||||
"@emotion/css" "^10.0.9"
|
||||
memoize-one "^5.0.0"
|
||||
prop-types "^15.6.0"
|
||||
react-input-autosize "^2.2.2"
|
||||
react-transition-group "^4.3.0"
|
||||
|
||||
react-sizeme@^2.6.7:
|
||||
version "2.6.12"
|
||||
resolved "https://registry.yarnpkg.com/react-sizeme/-/react-sizeme-2.6.12.tgz#ed207be5476f4a85bf364e92042520499455453e"
|
||||
@@ -23743,7 +23785,7 @@ react-textarea-autosize@^7.1.0:
|
||||
"@babel/runtime" "^7.1.2"
|
||||
prop-types "^15.6.0"
|
||||
|
||||
react-transition-group@4.4.1, react-transition-group@^4.4.0, react-transition-group@^4.4.1:
|
||||
react-transition-group@4.4.1, react-transition-group@^4.3.0, react-transition-group@^4.4.0, react-transition-group@^4.4.1:
|
||||
version "4.4.1"
|
||||
resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-4.4.1.tgz#63868f9325a38ea5ee9535d828327f85773345c9"
|
||||
integrity sha512-Djqr7OQ2aPUiYurhPalTrVy9ddmFCCzwhqQmtN+J3+3DzLO209Fdr70QrN8Z3DsglWql6iY1lDWAfpFiBtuKGw==
|
||||
|
||||
Reference in New Issue
Block a user