1
0
mirror of https://github.com/kremalicious/metamask-extension.git synced 2024-12-01 21:57:06 +01:00
metamask-extension/ui/components/app/srp-quiz-modal/SRPQuiz/SRPQuiz.tsx
Howard Braham 9acd4b4ea1
feat(srp): add a quiz to the SRP reveal (#19283)
* 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>
2023-06-20 14:27:10 -04:00

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>
);
}