mirror of
https://github.com/kremalicious/metamask-extension.git
synced 2024-12-01 21:57:06 +01:00
9acd4b4ea1
* feat(srp): add a quiz to the SRP reveal * fixed the popover header centering * lint fixes * converted from `ui/components/ui/popover` to `ui/components/component-library/modal` * responded to @darkwing review * added unit tests * renamed the folder to 'srp-quiz-modal' * responded to Monte's review * using i18n-helper in the test suite * small improvement to JSXDict comments * wrote a new webdriver.holdMouseDownOnElement() to assist with testing the "Hold to reveal SRP" button * Updating layout and some storybook naming and migrating to tsx * Apply suggestions from @georgewrmarshall Co-authored-by: George Marshall <george.marshall@consensys.net> * Unit test searches by data-testid instead of by text * new layout and copy for the Settings->Security page * now with 100% test coverage for /ui/pages/settings/security-tab fixes #16871 fixes #18140 * e2e tests to reveal SRP after quiz * e2e- Fix lint, remove unneeded extras * @coreyjanssen and @georgewrmarshall compromise Co-authored-by: George Marshall <george.marshall@consensys.net> Co-authored-by: Corey Janssen <corey.janssen@consensys.net> * trying isRequired again * transparent background on PNG * [e2e] moving functions to helpers and adding testid for SRP reveal quiz (#19481) * moving functions to helpers and adding testid * fix lint error * took out the IPFS gateway fixes * lint fix * translations of SRP Reveal Quiz * new Spanish translation from Guto * Update describe for e2e tests * Apply suggestion from @georgewrmarshall Co-authored-by: George Marshall <george.marshall@consensys.net> * fixed the Tab key problem --------- Co-authored-by: georgewrmarshall <george.marshall@consensys.net> Co-authored-by: Plasma Corral <32695229+plasmacorral@users.noreply.github.com> Co-authored-by: Corey Janssen <corey.janssen@consensys.net>
299 lines
8.7 KiB
TypeScript
299 lines
8.7 KiB
TypeScript
/* eslint-disable @typescript-eslint/no-var-requires, @typescript-eslint/no-require-imports, import/no-commonjs */
|
|
import React, { useCallback, useContext, useEffect, useState } from 'react';
|
|
import { useHistory } from 'react-router-dom';
|
|
import {
|
|
MetaMetricsEventCategory,
|
|
MetaMetricsEventKeyType,
|
|
MetaMetricsEventName,
|
|
} from '../../../../../shared/constants/metametrics';
|
|
import { MetaMetricsContext } from '../../../../contexts/metametrics';
|
|
import {
|
|
BlockSize,
|
|
Display,
|
|
FlexDirection,
|
|
IconColor,
|
|
TextAlign,
|
|
} from '../../../../helpers/constants/design-system';
|
|
import { REVEAL_SEED_ROUTE } from '../../../../helpers/constants/routes';
|
|
import ZENDESK_URLS from '../../../../helpers/constants/zendesk-url';
|
|
import { useI18nContext } from '../../../../hooks/useI18nContext';
|
|
import {
|
|
BUTTON_SIZES,
|
|
BUTTON_VARIANT,
|
|
Icon,
|
|
IconName,
|
|
IconSize,
|
|
Modal,
|
|
ModalContent,
|
|
ModalHeader,
|
|
ModalOverlay,
|
|
} from '../../../component-library';
|
|
import QuizContent from '../QuizContent';
|
|
import { JSXDict, QuizStage } from '../types';
|
|
|
|
const wrongAnswerIcon = (
|
|
<Icon
|
|
size={IconSize.Xl}
|
|
name={IconName.Warning}
|
|
color={IconColor.errorDefault}
|
|
textAlign={TextAlign.Center}
|
|
width={BlockSize.OneTwelfth}
|
|
/>
|
|
);
|
|
|
|
const rightAnswerIcon = (
|
|
<Icon
|
|
size={IconSize.Xl}
|
|
name={IconName.Confirmation}
|
|
color={IconColor.successDefault}
|
|
textAlign={TextAlign.Center}
|
|
width={BlockSize.OneTwelfth}
|
|
/>
|
|
);
|
|
|
|
const openSupportArticle = (): void => {
|
|
global.platform.openTab({
|
|
url: ZENDESK_URLS.PASSWORD_AND_SRP_ARTICLE,
|
|
});
|
|
};
|
|
|
|
export default function SRPQuiz(props: any) {
|
|
const [stage, setStage] = useState<QuizStage>(QuizStage.introduction);
|
|
|
|
const trackEvent = useContext(MetaMetricsContext);
|
|
const history = useHistory();
|
|
const t = useI18nContext();
|
|
|
|
// This should not be a state variable, because it's derivable from the state variable `stage`
|
|
// (Making it a state variable forces the component to render twice)
|
|
let title = '';
|
|
|
|
// Using a dictionary of JSX elements eliminates the need for a switch statement
|
|
const stages: JSXDict = {};
|
|
|
|
stages[QuizStage.introduction] = () => {
|
|
title = t('srpSecurityQuizTitle');
|
|
return (
|
|
<QuizContent
|
|
image={'images/reveal-srp.png'}
|
|
content={t('srpSecurityQuizIntroduction')}
|
|
buttons={[
|
|
{
|
|
label: t('srpSecurityQuizGetStarted'),
|
|
onClick: () => setStage(QuizStage.questionOne),
|
|
variant: BUTTON_VARIANT.PRIMARY,
|
|
size: BUTTON_SIZES.LG,
|
|
'data-testid': 'srp-quiz-get-started',
|
|
},
|
|
{
|
|
label: t('learnMoreUpperCase'),
|
|
onClick: openSupportArticle,
|
|
variant: BUTTON_VARIANT.LINK,
|
|
'data-testid': 'srp-quiz-learn-more',
|
|
},
|
|
]}
|
|
/>
|
|
);
|
|
};
|
|
|
|
stages[QuizStage.questionOne] = () => {
|
|
title = `1 ${t('ofTextNofM')} 2`;
|
|
return (
|
|
<QuizContent
|
|
content={t('srpSecurityQuizQuestionOneQuestion')}
|
|
buttons={[
|
|
{
|
|
label: t('srpSecurityQuizQuestionOneWrongAnswer'),
|
|
onClick: () => setStage(QuizStage.wrongAnswerQuestionOne),
|
|
variant: BUTTON_VARIANT.SECONDARY,
|
|
size: BUTTON_SIZES.LG,
|
|
'data-testid': 'srp-quiz-wrong-answer',
|
|
},
|
|
{
|
|
label: t('srpSecurityQuizQuestionOneRightAnswer'),
|
|
onClick: () => setStage(QuizStage.rightAnswerQuestionOne),
|
|
variant: BUTTON_VARIANT.SECONDARY,
|
|
size: BUTTON_SIZES.LG,
|
|
'data-testid': 'srp-quiz-right-answer',
|
|
},
|
|
{
|
|
label: t('learnMoreUpperCase'),
|
|
onClick: openSupportArticle,
|
|
variant: BUTTON_VARIANT.LINK,
|
|
},
|
|
]}
|
|
/>
|
|
);
|
|
};
|
|
|
|
stages[QuizStage.rightAnswerQuestionOne] = () => {
|
|
title = `1 ${t('ofTextNofM')} 2`;
|
|
return (
|
|
<QuizContent
|
|
icon={rightAnswerIcon}
|
|
content={t('srpSecurityQuizQuestionOneRightAnswerTitle')}
|
|
moreContent={t('srpSecurityQuizQuestionOneRightAnswerDescription')}
|
|
buttons={[
|
|
{
|
|
label: t('continue'),
|
|
onClick: () => setStage(QuizStage.questionTwo),
|
|
variant: BUTTON_VARIANT.PRIMARY,
|
|
size: BUTTON_SIZES.LG,
|
|
'data-testid': 'srp-quiz-continue',
|
|
},
|
|
{
|
|
label: t('learnMoreUpperCase'),
|
|
onClick: openSupportArticle,
|
|
variant: BUTTON_VARIANT.LINK,
|
|
},
|
|
]}
|
|
/>
|
|
);
|
|
};
|
|
|
|
stages[QuizStage.wrongAnswerQuestionOne] = () => {
|
|
title = `1 ${t('ofTextNofM')} 2`;
|
|
return (
|
|
<QuizContent
|
|
icon={wrongAnswerIcon}
|
|
content={t('srpSecurityQuizQuestionOneWrongAnswerTitle')}
|
|
moreContent={t('srpSecurityQuizQuestionOneWrongAnswerDescription')}
|
|
buttons={[
|
|
{
|
|
label: t('tryAgain'),
|
|
onClick: () => setStage(QuizStage.questionOne),
|
|
variant: BUTTON_VARIANT.PRIMARY,
|
|
size: BUTTON_SIZES.LG,
|
|
'data-testid': 'srp-quiz-try-again',
|
|
},
|
|
{
|
|
label: t('learnMoreUpperCase'),
|
|
onClick: openSupportArticle,
|
|
variant: BUTTON_VARIANT.LINK,
|
|
},
|
|
]}
|
|
/>
|
|
);
|
|
};
|
|
|
|
stages[QuizStage.questionTwo] = () => {
|
|
title = `2 ${t('ofTextNofM')} 2`;
|
|
return (
|
|
<QuizContent
|
|
content={t('srpSecurityQuizQuestionTwoQuestion')}
|
|
buttons={[
|
|
{
|
|
label: t('srpSecurityQuizQuestionTwoRightAnswer'),
|
|
onClick: () => setStage(QuizStage.rightAnswerQuestionTwo),
|
|
variant: BUTTON_VARIANT.SECONDARY,
|
|
size: BUTTON_SIZES.LG,
|
|
'data-testid': 'srp-quiz-right-answer',
|
|
},
|
|
{
|
|
label: t('srpSecurityQuizQuestionTwoWrongAnswer'),
|
|
onClick: () => setStage(QuizStage.wrongAnswerQuestionTwo),
|
|
variant: BUTTON_VARIANT.SECONDARY,
|
|
size: BUTTON_SIZES.LG,
|
|
'data-testid': 'srp-quiz-wrong-answer',
|
|
},
|
|
{
|
|
label: t('learnMoreUpperCase'),
|
|
onClick: openSupportArticle,
|
|
variant: BUTTON_VARIANT.LINK,
|
|
},
|
|
]}
|
|
/>
|
|
);
|
|
};
|
|
|
|
stages[QuizStage.rightAnswerQuestionTwo] = () => {
|
|
title = `2 ${t('ofTextNofM')} 2`;
|
|
return (
|
|
<QuizContent
|
|
icon={rightAnswerIcon}
|
|
content={t('srpSecurityQuizQuestionTwoRightAnswerTitle')}
|
|
moreContent={t('srpSecurityQuizQuestionTwoRightAnswerDescription')}
|
|
buttons={[
|
|
{
|
|
label: t('continue'),
|
|
onClick: () => history.push(REVEAL_SEED_ROUTE),
|
|
variant: BUTTON_VARIANT.PRIMARY,
|
|
size: BUTTON_SIZES.LG,
|
|
'data-testid': 'srp-quiz-continue',
|
|
},
|
|
{
|
|
label: t('learnMoreUpperCase'),
|
|
onClick: openSupportArticle,
|
|
variant: BUTTON_VARIANT.LINK,
|
|
},
|
|
]}
|
|
/>
|
|
);
|
|
};
|
|
|
|
stages[QuizStage.wrongAnswerQuestionTwo] = () => {
|
|
title = `2 ${t('ofTextNofM')} 2`;
|
|
return (
|
|
<QuizContent
|
|
icon={wrongAnswerIcon}
|
|
content={t('srpSecurityQuizQuestionTwoWrongAnswerTitle')}
|
|
moreContent={t('srpSecurityQuizQuestionTwoWrongAnswerDescription')}
|
|
buttons={[
|
|
{
|
|
label: t('tryAgain'),
|
|
onClick: () => setStage(QuizStage.questionTwo),
|
|
variant: BUTTON_VARIANT.PRIMARY,
|
|
size: BUTTON_SIZES.LG,
|
|
'data-testid': 'srp-quiz-try-again',
|
|
},
|
|
{
|
|
label: t('learnMoreUpperCase'),
|
|
onClick: openSupportArticle,
|
|
variant: BUTTON_VARIANT.LINK,
|
|
},
|
|
]}
|
|
/>
|
|
);
|
|
};
|
|
|
|
// trackEvent shortcut specific to the SRP quiz
|
|
const trackEventSrp = useCallback((location) => {
|
|
trackEvent(
|
|
{
|
|
category: MetaMetricsEventCategory.Keys,
|
|
event: MetaMetricsEventName.KeyExportSelected,
|
|
properties: {
|
|
key_type: MetaMetricsEventKeyType.Srp,
|
|
location,
|
|
},
|
|
},
|
|
{},
|
|
);
|
|
}, []);
|
|
|
|
useEffect(() => {
|
|
trackEventSrp(`stage_${stage}`); // Call MetaMetrics based on the current stage
|
|
}, [stage]); // Only call this when the stage changes
|
|
|
|
const quizContent = stages[stage](); // Pick the content using the right stage from the JSXDict
|
|
|
|
return (
|
|
<Modal isOpen={props.isOpen} onClose={props.onClose}>
|
|
<ModalOverlay />
|
|
<ModalContent
|
|
modalDialogProps={{
|
|
display: Display.Flex,
|
|
flexDirection: FlexDirection.Column,
|
|
gap: 4,
|
|
}}
|
|
>
|
|
<ModalHeader onClose={props.onClose} data-testid="srp-quiz-header">
|
|
{title}
|
|
</ModalHeader>
|
|
<span data-testid={`srp_stage_${stage}`} />
|
|
{quizContent}
|
|
</ModalContent>
|
|
</Modal>
|
|
);
|
|
}
|