1
0
mirror of https://github.com/kremalicious/metamask-extension.git synced 2024-12-02 06:07:06 +01:00
metamask-extension/ui/components/app/srp-quiz-modal/SRPQuiz/SRPQuiz.tsx

299 lines
8.7 KiB
TypeScript
Raw Normal View History

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 20:27:10 +02:00
/* 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>
);
}