on master help sign in
WIP: MasterKey reveal, presentation
3509775tomholford
src/form/formatters.js+10
@@ -86,3 +86,13 @@ export const ensureSigPrefix = s => {
86
86
87 return s.indexOf(SIG_PREFIX) !== 0 ? `${SIG_PREFIX}${s}` : s;
87 return s.indexOf(SIG_PREFIX) !== 0 ? `${SIG_PREFIX}${s}` : s;
88};
88};
89+
90+export const stripSigPrefix = s => {
91+ if (!s) {
92+ return s;
93+ }
94+
95+ return s.toLowerCase().indexOf(SIG_PREFIX) === 0
96+ ? s.slice(SIG_PREFIX.length)
97+ : s;
98+};
src/views/Activate/ActivateCode.tsx+2−1
@@ -134,7 +134,7 @@ export default function ActivateCode() {
134 async values => {
134 async values => {
135 setIsGenerating(true);
135 setIsGenerating(true);
136 setIsFaded(true);
136 setIsFaded(true);
137− await timeout(1400); // Allow the Master Key animation to run for one cycle
137+ await timeout(1900); // Allow the Master Key animation to run for one cycle
138
138
139 // Derive wallet
139 // Derive wallet
140 // TODO: fallback logic to first use implied values if present, otherwise form values?
140 // TODO: fallback logic to first use implied values if present, otherwise form values?
@@ -191,6 +191,7 @@ export default function ActivateCode() {
191 setDerivedPoint,
191 setDerivedPoint,
192 setDerivedWallet,
192 setDerivedWallet,
193 setInviteWallet,
193 setInviteWallet,
194+ setIsFaded,
194 ]
195 ]
195 );
196 );
196
197
src/views/Activate/ActivateMasterKey.tsx+18−24
@@ -1,17 +1,13 @@
1import React, { useMemo } from 'react';
1import React, { useMemo } from 'react';
2−import cn from 'classnames';
3−import { Grid } from 'indigo-react';
4
2
5import { LocalRouterProvider, useLocalRouter } from 'lib/LocalRouter';
3import { LocalRouterProvider, useLocalRouter } from 'lib/LocalRouter';
6
4
7import View from 'components/View';
5import View from 'components/View';
8−import Passport from 'components/Passport';
9
6
10import { useActivateFlow } from './ActivateFlow';
7import { useActivateFlow } from './ActivateFlow';
11−import useBreakpoints from 'lib/useBreakpoints';
12import useRouter from 'lib/useRouter';
8import useRouter from 'lib/useRouter';
13
9
14−import PassportDownload from './PassportDownload';
10+import MasterKeyDownload from './MasterKeyDownload';
15import PassportVerify from './PassportVerify';
11import PassportVerify from './PassportVerify';
16import PassportTransfer from './PassportTransfer';
12import PassportTransfer from './PassportTransfer';
17import { walletFromMnemonic } from 'lib/wallet';
13import { walletFromMnemonic } from 'lib/wallet';
@@ -28,12 +24,12 @@ const NAMES = {
28
24
29const VIEWS = {
25const VIEWS = {
30 [NAMES.REVEAL]: MasterKeyReveal,
26 [NAMES.REVEAL]: MasterKeyReveal,
31− [NAMES.DOWNLOAD]: PassportDownload,
27+ [NAMES.DOWNLOAD]: MasterKeyDownload,
32 [NAMES.VERIFY]: PassportVerify,
28 [NAMES.VERIFY]: PassportVerify,
33 [NAMES.TRANSFER]: PassportTransfer,
29 [NAMES.TRANSFER]: PassportTransfer,
34};
30};
35
31
36−export default function ActivatePassport() {
32+export default function ActivateMasterKey() {
37 const { derivedPoint, generated, derivedWallet } = useActivateFlow();
33 const { derivedPoint, generated, derivedWallet } = useActivateFlow();
38 // pull the reset function out of the 'activate' router
34 // pull the reset function out of the 'activate' router
39 const { reset: resetActivateRouter } = useLocalRouter();
35 const { reset: resetActivateRouter } = useLocalRouter();
@@ -43,24 +39,22 @@ export default function ActivatePassport() {
43 initialRoutes: [{ key: NAMES.REVEAL }],
39 initialRoutes: [{ key: NAMES.REVEAL }],
44 });
40 });
45
41
46− const gap = useBreakpoints([4, 4, 7]);
42+ // TODO
47− const marginTop = useBreakpoints([false, false, 8]);
48−
49 // addresses are not derived until we set[Urbit]Wallet(), so do that inline
43 // addresses are not derived until we set[Urbit]Wallet(), so do that inline
50− const address = useMemo(
44+ // const address = useMemo(
51− () =>
45+ // () =>
52− derivedWallet
46+ // derivedWallet
53− .chain(wallet =>
47+ // .chain(wallet =>
54− walletFromMnemonic(
48+ // walletFromMnemonic(
55− wallet.ownership.seed,
49+ // wallet.ownership.seed,
56− DEFAULT_HD_PATH,
50+ // DEFAULT_HD_PATH,
57− wallet.meta.passphrase
51+ // wallet.meta.passphrase
58− )
52+ // )
59− )
53+ // )
60− .map(wallet => publicToAddress(wallet.publicKey)),
54+ // .map(wallet => publicToAddress(wallet.publicKey)),
61− [derivedWallet]
55+ // [derivedWallet]
62− );
56+ // );
63− //~hobbyn-mismur-fonrux-datber
57+
64 return (
58 return (
65 <View inset>
59 <View inset>
66 <LocalRouterProvider value={router}>
60 <LocalRouterProvider value={router}>
src/views/Activate/MasterKeyDownload.tsxnew file+89
@@ -0,0 +1,89 @@
1+import React, { useCallback, useEffect, useMemo, useState } from 'react';
2+
3+import ActivateView from './ActivateView';
4+import ActivateHeader from './ActivateHeader';
5+import { MasterKey } from './MasterKey';
6+import { Box, Button, Icon } from '@tlon/indigo-react';
7+import ActivateParagraph from './ActivateParagraph';
8+import { ActivateSteps } from './ActivateSteps';
9+import { useActivateFlow } from './ActivateFlow';
10+import { timeout } from 'lib/timeout';
11+import MasterKeyPresenter from './MasterKeyPresenter';
12+
13+const MasterKeyDownload = () => {
14+ const { isFaded, setIsFaded } = useActivateFlow();
15+
16+ const header = useMemo(() => {
17+ return (
18+ <Box className={isFaded ? 'faded-in' : 'faded-out'}>
19+ <ActivateHeader copy={'Backup your Master Key.'} />
20+ <ActivateParagraph
21+ copy={
22+ 'Download your backup and store it somewhere safe, e.g. your security deposit box or password manager.'
23+ }
24+ />
25+ </Box>
26+ );
27+ }, [isFaded]);
28+
29+ const footer = useMemo(() => {
30+ return (
31+ <Box
32+ display="flex"
33+ flexDirection="column"
34+ flexWrap="nowrap"
35+ height={'100%'}
36+ className={isFaded ? 'faded-in' : 'faded-out'}
37+ justifyContent="flex-end">
38+ <Button
39+ onClick={() => console.log('reveal')}
40+ backgroundColor="black"
41+ color={'white'}
42+ padding={'16px'}
43+ fontFamily="Inter"
44+ height={'50px'}
45+ fontWeight={'400'}
46+ fontSize={'18px'}>
47+ Download Backup
48+ </Button>
49+ </Box>
50+ );
51+ }, [isFaded]);
52+
53+ const onViewTransition = useCallback(async () => {
54+ setIsFaded(true);
55+ await timeout(500); // Pause for UI fade animation
56+ }, [setIsFaded]);
57+
58+ useEffect(() => {
59+ // Fade in content
60+ onViewTransition();
61+ }, [onViewTransition]);
62+
63+ return (
64+ <>
65+ <ActivateView header={header} footer={footer}>
66+ <Box
67+ alignItems={'center'}
68+ display={'flex'}
69+ flexDirection={'column'}
70+ flexWrap={'nowrap'}
71+ height={'100%'}
72+ justifyContent={'center'}>
73+ <Box
74+ display={'flex'}
75+ flexDirection={'row'}
76+ flexWrap={'nowrap'}
77+ width={'80%'}
78+ height={'min-content'}
79+ justifyContent={'center'}>
80+ <MasterKeyPresenter />
81+ </Box>
82+ </Box>
83+ </ActivateView>
84+ <ActivateSteps currentStep={1} totalSteps={4} />
85+ </>
86+ );
87+};
88+
89+export default MasterKeyDownload;
src/views/Activate/MasterKeyPresenter.tsxnew file+51
@@ -0,0 +1,51 @@
1+import { Box, Text } from '@tlon/indigo-react';
2+import { stripSigPrefix } from 'form/formatters';
3+import useImpliedTicket from 'lib/useImpliedTicket';
4+import { useMemo } from 'react';
5+
6+type MasterKeyPresenterArgs = {
7+ className?: string;
8+};
9+
10+const MasterKeyPresenter = ({ className }: MasterKeyPresenterArgs) => {
11+ // TODO: use actual MK ticket :)
12+ const { impliedTicket } = useImpliedTicket();
13+
14+ const ticketSegments = useMemo(() => {
15+ return impliedTicket ? stripSigPrefix(impliedTicket).split('-') : null;
16+ }, [impliedTicket]);
17+
18+ return (
19+ <Box
20+ display={'flex'}
21+ flexDirection={'row'}
22+ flexWrap={'nowrap'}
23+ width={'80%'}
24+ height={'min-content'}
25+ justifyContent={'space-evenly'}
26+ className={className}>
27+ {ticketSegments &&
28+ ticketSegments.map((segment: string, i: number) => {
29+ return (
30+ <>
31+ <Box
32+ background={'rgba(0,0,0,0.05)'}
33+ padding={'12px 10px'}
34+ fontFamily={'Source Code Pro'}
35+ borderRadius={'5px'}
36+ border={'solid 1px gray'}>
37+ {segment}
38+ </Box>
39+ {i < ticketSegments.length - 1 ? (
40+ <Text alignSelf="center" color="gray" mx={1}>
41+ —
42+ </Text>
43+ ) : null}
44+ </>
45+ );
46+ })}
47+ </Box>
48+ );
49+};
50+
51+export default MasterKeyPresenter;
src/views/Activate/MasterKeyReveal.tsx+24−6
@@ -1,4 +1,4 @@
1−import React, { useEffect, useMemo, useState } from 'react';
1+import React, { useCallback, useEffect, useMemo, useState } from 'react';
2
2
3import ActivateView from './ActivateView';
3import ActivateView from './ActivateView';
4import ActivateHeader from './ActivateHeader';
4import ActivateHeader from './ActivateHeader';
@@ -7,9 +7,22 @@ import { Box, Button, Icon } from '@tlon/indigo-react';
7import ActivateParagraph from './ActivateParagraph';
7import ActivateParagraph from './ActivateParagraph';
8import { ActivateSteps } from './ActivateSteps';
8import { ActivateSteps } from './ActivateSteps';
9import { useActivateFlow } from './ActivateFlow';
9import { useActivateFlow } from './ActivateFlow';
10+import { timeout } from 'lib/timeout';
11+import { useLocalRouter } from 'lib/LocalRouter';
10
12
11const MasterKeyReveal = () => {
13const MasterKeyReveal = () => {
12 const { isFaded, setIsFaded } = useActivateFlow();
14 const { isFaded, setIsFaded } = useActivateFlow();
15+ const { push, names } = useLocalRouter();
16+
17+ const goToDownload = useCallback(() => {
18+ push(names.DOWNLOAD);
19+ }, [names.DOWNLOAD, push]);
20+
21+ const onRevealClick = useCallback(async () => {
22+ setIsFaded(false);
23+ await timeout(500); // Pause for UI fade animation
24+ goToDownload();
25+ }, [goToDownload, setIsFaded]);
13
26
14 const header = useMemo(() => {
27 const header = useMemo(() => {
15 return (
28 return (
@@ -34,7 +47,7 @@ const MasterKeyReveal = () => {
34 className={isFaded ? 'faded-in' : 'faded-out'}
47 className={isFaded ? 'faded-in' : 'faded-out'}
35 justifyContent="flex-end">
48 justifyContent="flex-end">
36 <Button
49 <Button
37− onClick={() => console.log('reveal')}
50+ onClick={onRevealClick}
38 backgroundColor="black"
51 backgroundColor="black"
39 color={'white'}
52 color={'white'}
40 padding={'16px'}
53 padding={'16px'}
@@ -52,13 +65,18 @@ const MasterKeyReveal = () => {
52 </Button>
65 </Button>
53 </Box>
66 </Box>
54 );
67 );
55− }, [isFaded]);
68+ }, [isFaded, onRevealClick]);
69+
70+ const onViewTransition = useCallback(async () => {
71+ await timeout(500); // Pause for UI fade animation
72+ setIsFaded(true);
73+ await timeout(500); // Pause for UI fade animation
74+ }, [setIsFaded]);
56
75
57 useEffect(() => {
76 useEffect(() => {
58 // Fade in content
77 // Fade in content
59− setIsFaded(true);
78+ onViewTransition();
60− // eslint-disable-next-line react-hooks/exhaustive-deps
61− }, []);
79+ }, [onViewTransition]);
62
80
63 return (
81 return (
64 <>
82 <>