@@ -1,35 +1,41 @@
1−import React, { useCallback, useMemo } from 'react';
1+import React, { useCallback, useMemo, useRef } from 'react';
2import { Just } from 'folktale/maybe';
2import { Just } from 'folktale/maybe';
3import * as azimuth from 'azimuth-js';
3import * as azimuth from 'azimuth-js';
4import { Grid, H4 } from 'indigo-react';
4import { Grid, H4 } from 'indigo-react';
5+import { FORM_ERROR } from 'final-form';
6import View from 'components/View';
7import View from 'components/View';
7import { ForwardButton } from 'components/Buttons';
8import { ForwardButton } from 'components/Buttons';
8import Passport from 'components/Passport';
9import Passport from 'components/Passport';
10+import WarningBox from 'components/WarningBox';
11+import FooterButton from 'components/FooterButton';
13+import { useNetwork } from 'store/network';
10import { useHistory } from 'store/history';
14import { useHistory } from 'store/history';
12import * as need from 'lib/need';
16import * as need from 'lib/need';
13import { ROUTE_NAMES } from 'lib/routeNames';
17import { ROUTE_NAMES } from 'lib/routeNames';
14−import FooterButton from 'components/FooterButton';
15import { DEFAULT_HD_PATH, walletFromMnemonic } from 'lib/wallet';
18import { DEFAULT_HD_PATH, walletFromMnemonic } from 'lib/wallet';
16−import { useNetwork } from 'store/network';
17import { generateWallet } from 'lib/invite';
19import { generateWallet } from 'lib/invite';
18import { generateTemporaryOwnershipWallet } from 'lib/walletgen';
20import { generateTemporaryOwnershipWallet } from 'lib/walletgen';
19−import { useActivateFlow } from './ActivateFlow';
20import { useLocalRouter } from 'lib/LocalRouter';
21import { useLocalRouter } from 'lib/LocalRouter';
21import useImpliedTicket from 'lib/useImpliedTicket';
22import useImpliedTicket from 'lib/useImpliedTicket';
22import timeout from 'lib/timeout';
23import timeout from 'lib/timeout';
23import useHasDisclaimed from 'lib/useHasDisclaimed';
24import useHasDisclaimed from 'lib/useHasDisclaimed';
24import useBreakpoints from 'lib/useBreakpoints';
25import useBreakpoints from 'lib/useBreakpoints';
25−import WarningBox from 'components/WarningBox';
27import BridgeForm from 'form/BridgeForm';
27import BridgeForm from 'form/BridgeForm';
28import SubmitButton from 'form/SubmitButton';
28import SubmitButton from 'form/SubmitButton';
29import { TicketInput } from 'form/Inputs';
29import { TicketInput } from 'form/Inputs';
30−import { composeValidator, buildPatqValidator } from 'form/validators';
32+ buildPatqValidator,
34+} from 'form/validators';
31import FormError from 'form/FormError';
35import FormError from 'form/FormError';
37+import { useActivateFlow } from './ActivateFlow';
32−import { FORM_ERROR } from 'final-form';
38+import { hasWarnings } from 'form/helpers';
34export default function ActivateCode() {
40export default function ActivateCode() {
35 const history = useHistory();
41 const history = useHistory();
@@ -37,6 +43,7 @@ export default function ActivateCode() {
37 const { contracts } = useNetwork();
43 const { contracts } = useNetwork();
38 const impliedTicket = useImpliedTicket();
44 const impliedTicket = useImpliedTicket();
39 const [hasDisclaimed] = useHasDisclaimed();
45 const [hasDisclaimed] = useHasDisclaimed();
46+ const warnings = useRef({});
42 setDerivedWallet,
49 setDerivedWallet,
@@ -61,11 +68,19 @@ export default function ActivateCode() {
61 if (!hasDisclaimed) {
68 if (!hasDisclaimed) {
62 push(names.DISCLAIMER);
69 push(names.DISCLAIMER);
64− }, [names, push, hasDisclaimed]);
71+ }, [hasDisclaimed, names.DISCLAIMER, names.PASSPORT, push]);
73+ const validateForm = useCallback((values, errors) => {
74+ warnings.current.ticket = null;
76+ if (hasErrors(errors)) {
66 const validate = useMemo(
81 const validate = useMemo(
67− () => composeValidator({ ticket: buildPatqValidator() }),
82+ () => composeValidator({ ticket: buildPatqValidator() }, validateForm),
71 // set our state on submission
86 // set our state on submission
@@ -92,10 +107,9 @@ export default function ActivateCode() {
93 if (incoming.length > 0) {
108 if (incoming.length > 0) {
94 if (incoming.length > 1) {
109 if (incoming.length > 1) {
95− // TODO: putting a warning here doesn't make sense since the user
110+ warnings.current.ticket =
96− // will be immediately redirected away — what do?
97− // 'This invite code has multiple points available.\n' +
111+ 'This invite code has multiple points available.\n' +
98− // "Once you've activated this point, activate the next with the same process.";
112+ "Once you've activated this point, activate the next with the same process.";
101 const point = parseInt(incoming[0], 10);
115 const point = parseInt(incoming[0], 10);
@@ -114,6 +128,14 @@ export default function ActivateCode() {
114 [contracts, setDerivedPoint, setDerivedWallet, setInviteWallet]
128 [contracts, setDerivedPoint, setDerivedWallet, setInviteWallet]
131+ const afterSubmit = useCallback(() => {
132+ if (hasWarnings(warnings.current)) {
117 const initialValues = useMemo(() => ({ ticket: impliedTicket || '' }), [
139 const initialValues = useMemo(() => ({ ticket: impliedTicket || '' }), [
118 impliedTicket,
140 impliedTicket,
@@ -128,9 +150,9 @@ export default function ActivateCode() {
128 <BridgeForm
150 <BridgeForm
129 validate={validate}
151 validate={validate}
130 onSubmit={onSubmit}
152 onSubmit={onSubmit}
131− afterSubmit={goToPassport}
153+ afterSubmit={afterSubmit}
132 initialValues={initialValues}>
154 initialValues={initialValues}>
133− {({ validating, submitting, handleSubmit }) => (
155+ {({ validating, submitting, submitSucceeded, handleSubmit }) => (
135 <Grid.Item
157 <Grid.Item
@@ -138,21 +160,33 @@ export default function ActivateCode() {
138 name="ticket"
160 name="ticket"
139 label="Activation Code"
161 label="Activation Code"
140 disabled={!activationAllowed}
162 disabled={!activationAllowed}
163+ warning={warnings.current.ticket}
143 <Grid.Item full as={FormError} />
166 <Grid.Item full as={FormError} />
168+ {submitSucceeded ? (
145− <Grid.Item
169+ <Grid.Item
174+ onClick={goToPassport}>
147− as={SubmitButton}
180+ as={SubmitButton}
148− className="mt4"
181+ className="mt4"
149− handleSubmit={handleSubmit}>
182+ handleSubmit={handleSubmit}>
150− {validating
183+ {validating
151− ? 'Deriving...'
184+ ? 'Deriving...'
152− : submitting
185+ : submitting
153− ? 'Generating...'
186+ ? 'Generating...'
155− </Grid.Item>
188+ </Grid.Item>
157 {!activationAllowed && (
191 {!activationAllowed && (
158 <Grid.Item full as={WarningBox} className="mt4">
192 <Grid.Item full as={WarningBox} className="mt4">
@@ -163,6 +197,7 @@ export default function ActivateCode() {
164 </BridgeForm>
198 </BridgeForm>
166 <FooterButton as={ForwardButton} onClick={goToLogin}>
201 <FooterButton as={ForwardButton} onClick={goToLogin}>
168 </FooterButton>
203 </FooterButton>