@@ -1,7 +1,7 @@
1−import React, { useCallback, useEffect, useState } from 'react';
1+import React, { useCallback, useRef } from 'react';
2import { Just, Nothing } from 'folktale/maybe';
2import { Just, Nothing } from 'folktale/maybe';
3import * as azimuth from 'azimuth-js';
3import * as azimuth from 'azimuth-js';
4−import { Grid, Input, H4, ErrorText } from 'indigo-react';
4+import { Grid, H4 } from 'indigo-react';
6import View from 'components/View';
6import View from 'components/View';
7import { ForwardButton } from 'components/Buttons';
7import { ForwardButton } from 'components/Buttons';
@@ -9,12 +9,9 @@ import Passport from 'components/Passport';
10import { useHistory } from 'store/history';
10import { useHistory } from 'store/history';
12−import { useTicketInput } from 'lib/useInputs';
13import * as need from 'lib/need';
12import * as need from 'lib/need';
14import { ROUTE_NAMES } from 'lib/routeNames';
13import { ROUTE_NAMES } from 'lib/routeNames';
15−import { useSyncKnownPoints } from 'lib/useSyncPoints';
16import FooterButton from 'components/FooterButton';
14import FooterButton from 'components/FooterButton';
17−import { blinkIf } from 'components/Blinky';
18import { DEFAULT_HD_PATH, walletFromMnemonic } from 'lib/wallet';
15import { DEFAULT_HD_PATH, walletFromMnemonic } from 'lib/wallet';
19import { useNetwork } from 'store/network';
16import { useNetwork } from 'store/network';
20import { generateWallet } from 'lib/invite';
17import { generateWallet } from 'lib/invite';
@@ -22,111 +19,96 @@ import { generateTemporaryOwnershipWallet } from 'lib/walletgen';
22import { useActivateFlow } from './ActivateFlow';
19import { useActivateFlow } from './ActivateFlow';
23import { useLocalRouter } from 'lib/LocalRouter';
20import { useLocalRouter } from 'lib/LocalRouter';
24import useImpliedTicket from 'lib/useImpliedTicket';
21import useImpliedTicket from 'lib/useImpliedTicket';
22+import timeout from 'lib/timeout';
25import useHasDisclaimed from 'lib/useHasDisclaimed';
23import useHasDisclaimed from 'lib/useHasDisclaimed';
25+import BridgeForm from 'form/BridgeForm';
26+import SubmitButton from 'form/SubmitButton';
27+import { TicketInput } from 'form/Inputs';
27export default function ActivateCode() {
29export default function ActivateCode() {
28 const history = useHistory();
30 const history = useHistory();
29 const { names, push } = useLocalRouter();
31 const { names, push } = useLocalRouter();
30 const { contracts } = useNetwork();
32 const { contracts } = useNetwork();
31 const impliedTicket = useImpliedTicket();
33 const impliedTicket = useImpliedTicket();
32 const [hasDisclaimed] = useHasDisclaimed();
34 const [hasDisclaimed] = useHasDisclaimed();
33− const [generalError, setGeneralError] = useState();
35+
34− const [deriving, setDeriving] = useState(false);
36+ const cachedInviteWallet = useRef(Nothing());
37+ const cachedPoint = useRef();
37 setDerivedWallet,
40 setDerivedWallet,
38 setInviteWallet,
41 setInviteWallet,
39 derivedPoint,
42 derivedPoint,
40 setDerivedPoint,
43 setDerivedPoint,
41 } = useActivateFlow();
44 } = useActivateFlow();
43− const [ticketInput, { pass: validTicket, data: ticket }] = useTicketInput({
45− label: 'Activation Code',
46− initialValue: impliedTicket || '',
50 const goToLogin = useCallback(() => history.popAndPush(ROUTE_NAMES.LOGIN), [
46 const goToLogin = useCallback(() => history.popAndPush(ROUTE_NAMES.LOGIN), [
53 const goToPassport = useCallback(() => {
49 const goToPassport = useCallback(() => {
54 push(names.PASSPORT);
50 push(names.PASSPORT);
55 if (!hasDisclaimed) {
52 if (!hasDisclaimed) {
56 push(names.DISCLAIMER);
53 push(names.DISCLAIMER);
58 }, [names, push, hasDisclaimed]);
55 }, [names, push, hasDisclaimed]);
60− const pass = derivedWallet.matchWith({
57+ const validate = useCallback(
61− Nothing: () => false,
58+ async ticket => {
62− Just: () => true,
59+ await timeout(100); // allow the ui changes to flush before we lag it out
67 const _contracts = need.contracts(contracts);
61 const _contracts = need.contracts(contracts);
62+ const { seed } = await generateTemporaryOwnershipWallet(ticket);
64+ // TODO(fang): isn't all this accessible in the ownership object?
65+ const inviteWallet = walletFromMnemonic(seed, DEFAULT_HD_PATH);
66+ cachedInviteWallet.current = inviteWallet;
68+ const _inviteWallet = need.wallet(inviteWallet);
70+ const owned = await azimuth.azimuth.getOwnedPoints(
72+ _inviteWallet.address
74+ const transferring = await azimuth.azimuth.getTransferringFor(
76+ _inviteWallet.address
78+ const incoming = [...owned, ...transferring];
80+ if (incoming.length > 0) {
81+ if (incoming.length > 1) {
84+ // 'This invite code has multiple points available.\n' +
85+ // "Once you've activated this point, activate the next with the same process."
69− setDeriving(true);
89+ const point = parseInt(incoming[0], 10);
70− // when the ticket becomes valid, derive the point
90+ // setDerivedPoint(Just(point));
71− (async () => {
91+ cachedPoint.current = point;
72− const { seed } = await generateTemporaryOwnershipWallet(ticket);
92+ } else {
74− //TODO isn't all this accessible in the ownership object?
94+ 'Invite code has no claimable point.\n' +
75− const inviteWallet = walletFromMnemonic(seed, DEFAULT_HD_PATH);
95+ 'Check your invite code and try again?'
76− const _inviteWallet = need.wallet(inviteWallet);
78− const owned = await azimuth.azimuth.getOwnedPoints(
80− _inviteWallet.address
82− const transferring = await azimuth.azimuth.getTransferringFor(
84− _inviteWallet.address
86− const incoming = [...owned, ...transferring];
97+ }
88− let realPoint = Nothing();
99+ [contracts]
89− let wallet = Nothing();
91− if (incoming.length > 0) {
92− const pointNum = parseInt(incoming[0], 10);
93− realPoint = Just(pointNum);
94− wallet = Just(await generateWallet(pointNum));
96− if (incoming.length > 1) {
98− 'This invite code has multiple points available.\n' +
99− "Once you've activated this point, activate the next with the same process."
102− setGeneralError(false);
106− 'Invite code has no claimable point.\n' +
107− 'Check your invite code and try again?'
111− setDerivedPoint(realPoint);
102+ const onSubmit = useCallback(
112− setDerivedWallet(wallet);
103+ async values => {
113− setInviteWallet(inviteWallet);
104+ setInviteWallet(cachedInviteWallet.current);
117− setGeneralError(false);
123− setDerivedPoint,
105+ setDerivedPoint(Just(cachedPoint.current));
124− setDerivedWallet,
106+ setDerivedWallet(Just(await generateWallet(cachedPoint)));
128− // when we know the derived point, ensure we have the data to display it
108+ goToPassport();
129− useSyncKnownPoints([derivedPoint.getOrElse(null)].filter(p => p !== null));
109+ },
110+ [goToPassport, setDerivedPoint, setDerivedWallet, setInviteWallet]
132 <View inset>
114 <View inset>
@@ -135,23 +117,34 @@ export default function ActivateCode() {
135 <Grid.Item as={H4} className="mt3 mb2" full>
117 <Grid.Item as={H4} className="mt3 mb2" full>
137 </Grid.Item>
119 </Grid.Item>
122+ initialValues={{ ticket: impliedTicket || '' }}>
123+ {({ validating, submitting, handleSubmit }) => (
138− <Grid.Item as={Input} {...ticketInput} full />
125+ <Grid.Item
139− {generalError && (
126+ full
129+ label="Activation Code"
130+ config={{ validate }}
140− <Grid.Item full>
134+ <Grid.Item
141− <ErrorText>{generalError}</ErrorText>{' '}
135+ full
142− </Grid.Item>
136+ as={SubmitButton}
146− className="mt4"
137+ className="mt4"
147− disabled={!pass || deriving}
138+ handleSubmit={handleSubmit}>
148− accessory={blinkIf(deriving)}
139+ {validating
149− onClick={goToPassport}
152− {deriving && 'Deriving...'}
140+ ? 'Deriving...'
153− {!deriving && 'Go'}
141+ : submitting
154− </Grid.Item>
144+ </Grid.Item>
156 <FooterButton as={ForwardButton} onClick={goToLogin}>
149 <FooterButton as={ForwardButton} onClick={goToLogin}>