@@ -1,35 +1,41 @@
1−import React, { useCallback, useMemo } from 'react';
1+import React, { useCallback, useMemo, useRef } from 'react';
22import { Just } from 'folktale/maybe';
33import * as azimuth from 'azimuth-js';
44import { Grid, H4 } from 'indigo-react';
5+import { FORM_ERROR } from 'final-form';
56
67import View from 'components/View';
78import { ForwardButton } from 'components/Buttons';
89import Passport from 'components/Passport';
10+import WarningBox from 'components/WarningBox';
11+import FooterButton from 'components/FooterButton';
912
13+import { useNetwork } from 'store/network';
1014import { useHistory } from 'store/history';
1115
1216import * as need from 'lib/need';
1317import { ROUTE_NAMES } from 'lib/routeNames';
14−import FooterButton from 'components/FooterButton';
1518import { DEFAULT_HD_PATH, walletFromMnemonic } from 'lib/wallet';
16−import { useNetwork } from 'store/network';
1719import { generateWallet } from 'lib/invite';
1820import { generateTemporaryOwnershipWallet } from 'lib/walletgen';
19−import { useActivateFlow } from './ActivateFlow';
2021import { useLocalRouter } from 'lib/LocalRouter';
2122import useImpliedTicket from 'lib/useImpliedTicket';
2223import timeout from 'lib/timeout';
2324import useHasDisclaimed from 'lib/useHasDisclaimed';
2425import useBreakpoints from 'lib/useBreakpoints';
25−import WarningBox from 'components/WarningBox';
2626
2727import BridgeForm from 'form/BridgeForm';
2828import SubmitButton from 'form/SubmitButton';
2929import { TicketInput } from 'form/Inputs';
30−import { composeValidator, buildPatqValidator } from 'form/validators';
30+import {
31+ composeValidator,
32+ buildPatqValidator,
33+ hasErrors,
34+} from 'form/validators';
3135import FormError from 'form/FormError';
32−import { FORM_ERROR } from 'final-form';
36+
37+import { useActivateFlow } from './ActivateFlow';
38+import { hasWarnings } from 'form/helpers';
3339
3440export default function ActivateCode() {
3541 const history = useHistory();
@@ -37,6 +43,7 @@ export default function ActivateCode() {
3743 const { contracts } = useNetwork();
3844 const impliedTicket = useImpliedTicket();
3945 const [hasDisclaimed] = useHasDisclaimed();
46+ const warnings = useRef({});
4047
4148 const {
4249 setDerivedWallet,
@@ -61,11 +68,19 @@ export default function ActivateCode() {
6168 if (!hasDisclaimed) {
6269 push(names.DISCLAIMER);
6370 }
64− }, [names, push, hasDisclaimed]);
71+ }, [hasDisclaimed, names.DISCLAIMER, names.PASSPORT, push]);
72+
73+ const validateForm = useCallback((values, errors) => {
74+ warnings.current.ticket = null;
75+
76+ if (hasErrors(errors)) {
77+ return errors;
78+ }
79+ }, []);
6580
6681 const validate = useMemo(
67− () => composeValidator({ ticket: buildPatqValidator() }),
68− []
82+ () => composeValidator({ ticket: buildPatqValidator() }, validateForm),
83+ [validateForm]
6984 );
7085
7186 // set our state on submission
@@ -92,10 +107,9 @@ export default function ActivateCode() {
92107
93108 if (incoming.length > 0) {
94109 if (incoming.length > 1) {
95− // TODO: putting a warning here doesn't make sense since the user
96− // will be immediately redirected away — what do?
97− // 'This invite code has multiple points available.\n' +
98− // "Once you've activated this point, activate the next with the same process.";
110+ warnings.current.ticket =
111+ 'This invite code has multiple points available.\n' +
112+ "Once you've activated this point, activate the next with the same process.";
99113 }
100114
101115 const point = parseInt(incoming[0], 10);
@@ -114,6 +128,14 @@ export default function ActivateCode() {
114128 [contracts, setDerivedPoint, setDerivedWallet, setInviteWallet]
115129 );
116130
131+ const afterSubmit = useCallback(() => {
132+ if (hasWarnings(warnings.current)) {
133+ return;
134+ }
135+
136+ goToPassport();
137+ }, [goToPassport]);
138+
117139 const initialValues = useMemo(() => ({ ticket: impliedTicket || '' }), [
118140 impliedTicket,
119141 ]);
@@ -128,9 +150,9 @@ export default function ActivateCode() {
128150 <BridgeForm
129151 validate={validate}
130152 onSubmit={onSubmit}
131− afterSubmit={goToPassport}
153+ afterSubmit={afterSubmit}
132154 initialValues={initialValues}>
133− {({ validating, submitting, handleSubmit }) => (
155+ {({ validating, submitting, submitSucceeded, handleSubmit }) => (
134156 <>
135157 <Grid.Item
136158 full
@@ -138,21 +160,33 @@ export default function ActivateCode() {
138160 name="ticket"
139161 label="Activation Code"
140162 disabled={!activationAllowed}
163+ warning={warnings.current.ticket}
141164 />
142165
143166 <Grid.Item full as={FormError} />
144167
145− <Grid.Item
146− full
147− as={SubmitButton}
148− className="mt4"
149− handleSubmit={handleSubmit}>
150− {validating
151− ? 'Deriving...'
152− : submitting
153− ? 'Generating...'
154− : 'Go'}
155− </Grid.Item>
168+ {submitSucceeded ? (
169+ <Grid.Item
170+ full
171+ as={ForwardButton}
172+ solid
173+ className="mt4"
174+ onClick={goToPassport}>
175+ Continue Activation
176+ </Grid.Item>
177+ ) : (
178+ <Grid.Item
179+ full
180+ as={SubmitButton}
181+ className="mt4"
182+ handleSubmit={handleSubmit}>
183+ {validating
184+ ? 'Deriving...'
185+ : submitting
186+ ? 'Generating...'
187+ : 'Go'}
188+ </Grid.Item>
189+ )}
156190
157191 {!activationAllowed && (
158192 <Grid.Item full as={WarningBox} className="mt4">
@@ -163,6 +197,7 @@ export default function ActivateCode() {
163197 )}
164198 </BridgeForm>
165199 </Grid>
200+
166201 <FooterButton as={ForwardButton} onClick={goToLogin}>
167202 Login
168203 </FooterButton>