fix: bugs in EmbedUrl + SetupRoles

This commit is contained in:
dan13ram
2022-02-07 17:06:39 +05:30
committed by Scott Stevenson
parent 10f66448ea
commit e022573223
8 changed files with 391 additions and 362 deletions

View File

@@ -87,7 +87,6 @@ const LinkPreview: React.FC<LinkPreviewProps> = ({ url: inputUrl = '' }) => {
return (
<LinkBox
onClick={() => window.open(url ?? inputUrl, '_blank')}
minH="18rem"
w="100%"
h="100%"
@@ -95,9 +94,6 @@ const LinkPreview: React.FC<LinkPreviewProps> = ({ url: inputUrl = '' }) => {
backdropFilter="blur(7px)"
borderWidth={0}
overflow="hidden"
_hover={{
cursor: 'pointer',
}}
>
<Flex w="100%" h="100%" direction="column">
<Box

View File

@@ -131,7 +131,7 @@ export const ProfileSection: React.FC<ProfileSectionProps> = ({
{children}
</Box>
{boxType && (
<Modal {...{ isOpen, onClose }}>
<Modal isCentered scrollBehavior="inside" {...{ isOpen, onClose }}>
<ModalOverlay />
<ModalContent
maxW="80%"
@@ -169,12 +169,11 @@ export const ProfileSection: React.FC<ProfileSectionProps> = ({
p={4}
_focus={{ boxShadow: 'none' }}
/>
<ModalBody overflowY="auto" overflowX="hidden">
{!modal && !modalText && (
<EditSectionBox {...{ boxType, onClose }} />
)}
{modalText && modal}
</ModalBody>
{!modal && !modalText && (
<EditSectionBox {...{ boxType, onClose }} />
)}
{modalText && modal && <ModalBody>{modalText && modal}</ModalBody>}
{/* we should figure out how to unify modal footers (edit sections have their own,
look into EditSectionBox components - they have footers with 'save' and 'cancel' buttons) */}
{modalText && modal && (

View File

@@ -70,7 +70,7 @@ export const SetupAvailability: React.FC<SetupAvailabilityProps> = ({
<Text mb={10}>
What is your weekly availability for any kind of freelance work?
</Text>
<InputGroup borderColor="transparent" mb={10}>
<InputGroup borderColor="transparent" mb={10} maxW="20rem">
<InputLeftElement>
<span role="img" aria-label="clock">
🕛

View File

@@ -5,8 +5,10 @@ import {
Button,
Flex,
Image,
LoadingState,
MetaButton,
MetaHeading,
ModalBody,
ModalFooter,
Spinner,
Text,
@@ -26,7 +28,7 @@ import {
PersonalityInfo,
} from 'graphql/queries/enums/getPersonalityInfo';
import { useUser, useWeb3 } from 'lib/hooks';
import React, { ReactElement, useEffect, useState } from 'react';
import React, { ReactElement, useEffect, useMemo, useState } from 'react';
import { dispositionFor } from 'utils/playerHelpers';
export type SetupPersonalityTypeProps = {
@@ -39,34 +41,37 @@ export const SetupPersonalityType: React.FC<SetupPersonalityTypeProps> = ({
onClose,
}) => {
const { onNextPress, nextButtonLabel } = useSetupFlow();
const { user } = useUser();
const { fetching: fetchingUser, user } = useUser();
const { player } = user ?? {};
const { ceramic } = useWeb3();
const toast = useToast();
const [status, setStatus] = useState<Maybe<ReactElement | string>>(null);
const [colorMask, setColorMask] = useState<Maybe<number> | undefined>(
player?.profile?.colorMask,
);
const [colorMask, setColorMask] = useState<Maybe<number> | undefined>();
const [{ types, parts }, setPersonalityInfo] = useState<PersonalityInfo>({
types: {},
parts: [],
});
const isWizard = !isEdit;
const load = () => {
if (player) {
if (colorMask === undefined && player.profile?.colorMask != null) {
setColorMask(player.profile.colorMask);
}
useEffect(() => {
if (player?.profile?.colorMask != null) {
setColorMask(player.profile.colorMask);
}
};
useEffect(load, [player, colorMask]);
}, [colorMask, player]);
const [fetchingInfo, setFetchingInfo] = useState(true);
const fetching = useMemo(() => fetchingUser || fetchingInfo || !user, [
fetchingUser,
fetchingInfo,
user,
]);
useEffect(() => {
const fetchInfo = async () =>
setPersonalityInfo(await getPersonalityInfo());
fetchInfo();
fetchInfo().then(() => setFetchingInfo(false));
}, []);
const handleNextPress = async () => {
@@ -140,173 +145,187 @@ export const SetupPersonalityType: React.FC<SetupPersonalityTypeProps> = ({
});
};
return (
<FlexContainer mb={8}>
<Flex direction="column">
{isWizard && (
<MetaHeading mb={5} textAlign="center">
Person&#xAD;ality Type
</MetaHeading>
)}
<Text mb={10} color={isWizard ? 'current' : 'white'}>
Please select your personality components below. Not sure what type
you are?
<Text as="span"> Take </Text>
<MetaLink
href="//dysbulic.github.io/5-color-radar/#/explore/"
isExternal
>
a quick exam
</MetaLink>
<Text as="span"> or </Text>
<MetaLink
href="//dysbulic.github.io/5-color-radar/#/test/"
isExternal
>
a longer quiz
</MetaLink>
.
</Text>
</Flex>
<Wrap spacing={2} justify="center" maxW="70rem">
{Object.keys(types).length &&
Object.entries(BaseImages)
.reverse()
.map(([orig, image], idx) => {
const option = types[parseInt(orig, 10)];
const { mask = 0 } = option ?? {};
const selected = ((colorMask ?? 0) & mask) > 0;
return (
<WrapItem>
<Button
key={mask}
display="flex"
direction="row"
justifyContent="start"
p={6}
m={2}
h="auto"
w={{ base: '100%', md: 'auto' }}
spacing={4}
borderRadius={8}
cursor="pointer"
onClick={() => toggleMaskElement(mask)}
autoFocus={idx === 0} // Doesn't work
ref={(input) => {
if (idx === 0 && !input?.getAttribute('focused-once')) {
input?.focus();
input?.setAttribute('focused-once', 'true');
}
}}
onKeyPress={(e) => {
if (e.key === 'Enter') {
if (isWizard) handleNextPress();
if (isEdit) save();
e.preventDefault();
}
}}
transition="background 0.25s, filter 0.5s"
bgColor={selected ? 'purpleBoxDark' : 'purpleBoxLight'}
_hover={{
filter: 'hue-rotate(25deg)',
}}
_focus={{
borderColor: '#FFFFFF55',
outline: 'none',
}}
_active={{
bg: selected ? 'purpleBoxDark' : 'purpleBoxLight',
}}
borderWidth={2}
borderColor={selected ? 'purple.400' : 'transparent'}
>
<Image
w="100%"
maxW={16}
h={16}
mr={2}
src={image}
alt={option.name}
filter="drop-shadow(0px 0px 3px black)"
/>
<FlexContainer align="stretch" ml={2}>
<Text color="white" casing="uppercase" textAlign="left">
{option.name}
</Text>
<Text
color="blueLight"
fontWeight="normal"
whiteSpace="initial"
textAlign="left"
>
{option.description}
</Text>
</FlexContainer>
</Button>
</WrapItem>
);
})}
</Wrap>
<ColorBar
mask={colorMask ?? null}
mt={8}
w="min(90vw, 30rem)"
personalityInfo={{ types, parts }}
/>
{isEdit && onClose && (
<ModalFooter mt={6}>
<Wrap justify="center" align="center" flex={1}>
<WrapItem>
<MetaButton
isDisabled={!!status}
onClick={async () => {
await save();
onClose();
}}
>
{!status ? (
'Save Changes'
) : (
<Flex align="center">
<Spinner mr={3} />
{typeof status === 'string' ? (
<Text>{status}</Text>
) : (
status
)}
</Flex>
)}
</MetaButton>
</WrapItem>
<WrapItem>
<Button
variant="ghost"
onClick={onClose}
color="white"
_hover={{ bg: '#FFFFFF11' }}
_active={{ bg: '#FF000011' }}
>
Close
</Button>
</WrapItem>
</Wrap>
</ModalFooter>
)}
const setup = (
<FlexContainer mb={isWizard ? 8 : 0} spacing={isWizard ? 8 : 4}>
{isWizard && (
<MetaButton
onClick={handleNextPress}
mt={10}
isDisabled={colorMask === undefined}
isLoading={!!status}
loadingText={status?.toString() ?? undefined}
<MetaHeading textAlign="center">Person&#xAD;ality Type</MetaHeading>
)}
<Text color={isWizard ? 'current' : 'white'}>
Please select your personality components below. Not sure what type you
are?
<Text as="span"> Take </Text>
<MetaLink
href="//dysbulic.github.io/5-color-radar/#/explore/"
isExternal
>
{nextButtonLabel}
</MetaButton>
a quick exam
</MetaLink>
<Text as="span"> or </Text>
<MetaLink href="//dysbulic.github.io/5-color-radar/#/test/" isExternal>
a longer quiz
</MetaLink>
.
</Text>
{fetching ? (
<LoadingState />
) : (
<>
<Wrap spacing={2} justify="center" maxW="70rem">
{Object.keys(types).length &&
Object.entries(BaseImages)
.reverse()
.map(([orig, image], idx) => {
const option = types[parseInt(orig, 10)];
const { mask = 0 } = option ?? {};
const selected = ((colorMask ?? 0) & mask) > 0;
return (
<WrapItem>
<Button
key={mask}
display="flex"
direction="row"
justifyContent="start"
p={6}
m={2}
h="auto"
w={{ base: '100%', md: 'auto' }}
spacing={4}
borderRadius={8}
cursor="pointer"
onClick={() => toggleMaskElement(mask)}
autoFocus={idx === 0} // Doesn't work
ref={(input) => {
if (
idx === 0 &&
!input?.getAttribute('focused-once')
) {
input?.focus();
input?.setAttribute('focused-once', 'true');
}
}}
onKeyPress={(e) => {
if (e.key === 'Enter') {
if (isWizard) handleNextPress();
if (isEdit) save();
e.preventDefault();
}
}}
transition="background 0.25s, filter 0.5s"
bgColor={selected ? 'purpleBoxDark' : 'purpleBoxLight'}
_hover={{
filter: 'hue-rotate(25deg)',
}}
_focus={{
borderColor: '#FFFFFF55',
outline: 'none',
}}
_active={{
bg: selected ? 'purpleBoxDark' : 'purpleBoxLight',
}}
borderWidth={2}
borderColor={selected ? 'purple.400' : 'transparent'}
>
<Image
w="100%"
maxW={16}
h={16}
mr={2}
src={image}
alt={option.name}
filter="drop-shadow(0px 0px 3px black)"
/>
<FlexContainer align="stretch" ml={2}>
<Text
color="white"
casing="uppercase"
textAlign="left"
>
{option.name}
</Text>
<Text
color="blueLight"
fontWeight="normal"
whiteSpace="initial"
textAlign="left"
>
{option.description}
</Text>
</FlexContainer>
</Button>
</WrapItem>
);
})}
</Wrap>
<ColorBar
mask={colorMask ?? null}
mt={8}
w="min(90vw, 30rem)"
personalityInfo={{ types, parts }}
/>
{isWizard && (
<MetaButton
onClick={handleNextPress}
mt={10}
isDisabled={!colorMask}
isLoading={!!status}
loadingText={status?.toString() ?? undefined}
>
{nextButtonLabel}
</MetaButton>
)}
</>
)}
</FlexContainer>
);
return isWizard ? (
setup
) : (
<>
<ModalBody>{setup}</ModalBody>\
{isEdit && onClose && (
<FlexContainer>
<ModalFooter py={6}>
<Wrap justify="center" align="center" flex={1}>
<WrapItem>
<MetaButton
isDisabled={!!status}
onClick={async () => {
await save();
onClose();
}}
>
{!status ? (
'Save Changes'
) : (
<Flex align="center">
<Spinner mr={3} />
{typeof status === 'string' ? (
<Text>{status}</Text>
) : (
status
)}
</Flex>
)}
</MetaButton>
</WrapItem>
<WrapItem>
<Button
variant="ghost"
onClick={onClose}
color="white"
_hover={{ bg: '#FFFFFF11' }}
_active={{ bg: '#FF000011' }}
>
Close
</Button>
</WrapItem>
</Wrap>
</ModalFooter>
</FlexContainer>
)}
</>
);
};

View File

@@ -6,6 +6,7 @@ import {
Flex,
MetaButton,
MetaHeading,
ModalBody,
ModalFooter,
SimpleGrid,
Spinner,
@@ -114,7 +115,7 @@ export const SetupPlayerType: React.FC<Props> = ({ isEdit, onClose }) => {
}
};
return (
const setup = (
<FlexContainer mb={8}>
{isWizard && (
<MetaHeading mb={5} textAlign="center">
@@ -156,48 +157,6 @@ export const SetupPlayerType: React.FC<Props> = ({ isEdit, onClose }) => {
</FlexContainer>
))}
</SimpleGrid>
{isEdit && onClose && (
<ModalFooter mt={6}>
<Wrap justify="center" align="center" flex={1}>
<WrapItem>
<MetaButton
isDisabled={!!status}
onClick={async () => {
await save();
onClose();
}}
>
{!status ? (
'Save Changes'
) : (
<Flex align="center">
<Spinner mr={3} />
{typeof status === 'string' ? (
<Text>{status}</Text>
) : (
status
)}
</Flex>
)}
</MetaButton>
</WrapItem>
<WrapItem>
<Button
variant="ghost"
onClick={onClose}
color="white"
_hover={{ bg: '#FFFFFF11' }}
_active={{ bg: '#FF000011' }}
disabled={!!status}
>
Close
</Button>
</WrapItem>
</Wrap>
</ModalFooter>
)}
{isWizard && (
<MetaButton
onClick={handleNextPress}
@@ -211,4 +170,54 @@ export const SetupPlayerType: React.FC<Props> = ({ isEdit, onClose }) => {
)}
</FlexContainer>
);
return isWizard ? (
setup
) : (
<>
<ModalBody>{setup}</ModalBody>
{isEdit && onClose && (
<FlexContainer>
<ModalFooter py={6}>
<Wrap justify="center" align="center" flex={1}>
<WrapItem>
<MetaButton
isDisabled={!!status}
onClick={async () => {
await save();
onClose();
}}
>
{!status ? (
'Save Changes'
) : (
<Flex align="center">
<Spinner mr={3} />
{typeof status === 'string' ? (
<Text>{status}</Text>
) : (
status
)}
</Flex>
)}
</MetaButton>
</WrapItem>
<WrapItem>
<Button
variant="ghost"
onClick={onClose}
color="white"
_hover={{ bg: '#FFFFFF11' }}
_active={{ bg: '#FF000011' }}
disabled={!!status}
>
Close
</Button>
</WrapItem>
</Wrap>
</ModalFooter>
</FlexContainer>
)}
</>
);
};

View File

@@ -8,6 +8,7 @@ import {
LoadingState,
MetaButton,
MetaHeading,
ModalBody,
ModalFooter,
Spacer,
Text,
@@ -43,17 +44,18 @@ export const SetupRoles: React.FC<SetupRolesProps> = ({
const { fetching: fetchingUser, user } = useUser({
requestPolicy: 'network-only',
});
const [fetchingRoleChoices, setFetchingRoleChoices] = useState(false);
const [fetchingRoleChoices, setFetchingRoleChoices] = useState(true);
const [roleChoices, setRoleChoices] = useState<PlayerRole[]>(
inputRoleChoices,
);
useEffect(() => {
if (inputRoleChoices.length === 0 && roleChoices.length === 0) {
setFetchingRoleChoices(true);
getPlayerRoles().then((s) => {
setRoleChoices(s.filter(({ basic }) => basic));
setFetchingRoleChoices(false);
});
} else {
setFetchingRoleChoices(false);
}
}, [inputRoleChoices, roleChoices]);
const fetching = useMemo(() => fetchingUser || fetchingRoleChoices, [
@@ -134,12 +136,12 @@ export const SetupRoles: React.FC<SetupRolesProps> = ({
const isMobile = useBreakpointValue({ base: true, md: false });
return (
const setup = (
<FlexContainer
align="center"
mx={isWizard ? { base: 0, md: 8, lg: 16 } : 0}
mb={8}
color="white"
mb={isWizard ? 'auto' : 0}
>
{isWizard && (
<MetaHeading mb={{ base: 6, sm: 16 }} alignSelf="center">
@@ -147,56 +149,57 @@ export const SetupRoles: React.FC<SetupRolesProps> = ({
</MetaHeading>
)}
{fetching && <LoadingState />}
{!fetching && roles.length === 0 ? (
<Text mb={{ base: 6, sm: 10 }}>
Unlike other role-playing games, in MetaGame, anyone is free to play
multiple roles at the same time.
<br />
Players are required to specify their primary role, whereas any
secondary roles are optional.
</Text>
) : (
<Flex wrap="wrap" mb={{ base: 4, md: 16 }} w="100%">
{roles.map((r, i) => {
const choice = roleChoices.find(
(roleChoice) => roleChoice.role === r,
);
return (
choice && (
<>
<Box key={r} {...roleContainerStyles}>
<Text
color="cyan.500"
fontWeight="bold"
casing="uppercase"
my="2"
>
{i === 0 && 'Primary Role'}
{i > 0 && roles.length === 2 && 'Secondary Role'}
{i === 1 && roles.length > 2 && 'Secondary Roles'}
{/* we still need a placeholder */}
{!isMobile && roles.length > 2 && i > 1 && (
<span>&nbsp;</span>
)}
</Text>
{!fetching &&
(roles.length === 0 ? (
<Text mb={{ base: 6, sm: 10 }}>
Unlike other role-playing games, in MetaGame, anyone is free to play
multiple roles at the same time.
<br />
Players are required to specify their primary role, whereas any
secondary roles are optional.
</Text>
) : (
<Flex wrap="wrap" mb={{ base: 4, md: 16 }} w="100%">
{roles.map((r, i) => {
const choice = roleChoices.find(
(roleChoice) => roleChoice.role === r,
);
return (
choice && (
<>
<Box key={r} {...roleContainerStyles}>
<Text
color="cyan.500"
fontWeight="bold"
casing="uppercase"
my="2"
>
{i === 0 && 'Primary Role'}
{i > 0 && roles.length === 2 && 'Secondary Role'}
{i === 1 && roles.length > 2 && 'Secondary Roles'}
{/* we still need a placeholder */}
{!isMobile && roles.length > 2 && i > 1 && (
<span>&nbsp;</span>
)}
</Text>
<Role
role={choice}
selectionIndex={i}
numSelectedRoles={roles.length}
onSelect={handleSelection}
onRemove={handleRemoval}
/>
</Box>
{/* wrap after the primary */}
{i === 0 && <Box flexBasis="100%" />}
</>
)
);
})}
</Flex>
)}
{availableRoles.length > 0 && (
<Role
role={choice}
selectionIndex={i}
numSelectedRoles={roles.length}
onSelect={handleSelection}
onRemove={handleRemoval}
/>
</Box>
{/* wrap after the primary */}
{i === 0 && <Box flexBasis="100%" />}
</>
)
);
})}
</Flex>
))}
{availableRoles.length > 0 && !fetching && (
<>
<Text
alignSelf="flex-start"
@@ -217,44 +220,54 @@ export const SetupRoles: React.FC<SetupRolesProps> = ({
</>
)}
{isEdit && onClose && (
<ModalFooter mt={6}>
{isWizard && !fetching && (
<FlexContainer pb={8}>
<MetaButton
mr={3}
isLoading={loading}
loadingText="Saving…"
onClick={async () => {
await save();
onClose();
}}
onClick={handleNextPress}
isDisabled={roles.length < 1}
isLoading={updateRolesResult.fetching || loading}
loadingText="Saving"
>
Save Changes
{nextButtonLabel}
</MetaButton>
<Button
variant="ghost"
onClick={onClose}
color="white"
_hover={{ bg: '#FFFFFF11' }}
_active={{ bg: '#FF000011' }}
disabled={loading}
>
Close
</Button>
</ModalFooter>
)}
{isWizard && (
<MetaButton
onClick={handleNextPress}
isDisabled={roles.length < 1}
isLoading={updateRolesResult.fetching || loading}
loadingText="Saving"
>
{nextButtonLabel}
</MetaButton>
</FlexContainer>
)}
</FlexContainer>
);
return isWizard ? (
setup
) : (
<>
<ModalBody>{setup} </ModalBody>
{isEdit && onClose && (
<FlexContainer>
<ModalFooter py={8}>
<MetaButton
mr={3}
isLoading={loading}
loadingText="Saving…"
onClick={async () => {
await save();
onClose();
}}
>
Save Changes
</MetaButton>
<Button
variant="ghost"
onClick={onClose}
color="white"
_hover={{ bg: '#FFFFFF11' }}
_active={{ bg: '#FF000011' }}
disabled={loading}
>
Close
</Button>
</ModalFooter>
</FlexContainer>
)}
</>
);
};
type RoleProps = {

View File

@@ -3,6 +3,7 @@ import {
MetaButton,
MetaHeading,
MetaTheme,
ModalBody,
ModalFooter,
searchSelectStyles,
SelectSearch,
@@ -132,7 +133,7 @@ export const SetupSkills: React.FC<SetupSkillsProps> = ({
onNextPress();
}, [save, onNextPress]);
return (
const setup = (
<FlexContainer mb={8}>
{isWizard && (
<MetaHeading mb={5} textAlign="center">
@@ -151,31 +152,6 @@ export const SetupSkills: React.FC<SetupSkillsProps> = ({
placeholder="Add Your Skills…"
/>
</FlexContainer>
{isEdit && onClose && (
<ModalFooter mt={6}>
<MetaButton
mr={3}
isLoading={loading}
loadingText="Saving…"
onClick={async () => {
await save();
onClose();
}}
>
Save Changes
</MetaButton>
<Button
variant="ghost"
onClick={onClose}
color="white"
_hover={{ bg: '#FFFFFF11' }}
_active={{ bg: '#FF000011' }}
disabled={loading}
>
Close
</Button>
</ModalFooter>
)}
{isWizard && (
<MetaButton
@@ -189,4 +165,38 @@ export const SetupSkills: React.FC<SetupSkillsProps> = ({
)}
</FlexContainer>
);
return isWizard ? (
setup
) : (
<>
<ModalBody> {setup} </ModalBody>
{isEdit && onClose && (
<FlexContainer>
<ModalFooter py={6}>
<MetaButton
mr={3}
isLoading={loading}
loadingText="Saving…"
onClick={async () => {
await save();
onClose();
}}
>
Save Changes
</MetaButton>
<Button
variant="ghost"
onClick={onClose}
color="white"
_hover={{ bg: '#FFFFFF11' }}
_active={{ bg: '#FF000011' }}
disabled={loading}
>
Close
</Button>
</ModalFooter>
</FlexContainer>
)}
</>
);
};

View File

@@ -104,16 +104,6 @@ export const PlayerPage: React.FC<Props> = ({
export default PlayerPage;
const makeLayouts = (canEdit: boolean, layouts: Layouts): Layouts =>
Object.fromEntries(
Object.entries(layouts).map(([key, items]) => [
key,
items.map((item) =>
item.i === 'hero' ? { ...item, isResizable: canEdit } : item,
),
]),
);
const onRemoveBoxFromLayouts = (boxKey: string, layouts: Layouts): Layouts =>
Object.fromEntries(
Object.entries(layouts).map(([key, items]) => [
@@ -365,11 +355,6 @@ export const Grid: React.FC<Props> = ({
const wrapperSX = useMemo(() => gridConfig.wrapper(canEdit), [canEdit]);
const displayLayouts = useMemo(() => makeLayouts(canEdit, currentLayouts), [
canEdit,
currentLayouts,
]);
const onRemoveBox = useCallback(
(boxKey: string): void => {
const layoutData = {
@@ -481,10 +466,8 @@ export const Grid: React.FC<Props> = ({
)}
<ResponsiveGridLayout
className="gridItems"
onLayoutChange={(layoutItems, layouts) => {
handleLayoutChange(layoutItems, layouts);
}}
layouts={displayLayouts}
onLayoutChange={handleLayoutChange}
layouts={currentLayouts}
breakpoints={{ lg: 1180, md: 900, sm: 0 }}
cols={{ lg: 3, md: 2, sm: 1 }}
rowHeight={GRID_ROW_HEIGHT}