on master help sign in
feat: standardize onSubmit for ActivateCode, Login/Ticket & Keystore
aed1af0Matt Condon (shrugs)
src/form/FormError.js+9−3
@@ -4,13 +4,19 @@ import { ErrorText } from 'indigo-react';
4import { FORM_ERROR } from 'final-form';
4import { FORM_ERROR } from 'final-form';
5
5
6export default function FormError(props) {
6export default function FormError(props) {
7− const { submitError, errors } = useFormState({
7+ const { submitError, errors, dirtySinceLastSubmit } = useFormState({
8+ subscription: {
8− subscription: { submitError: true, errors: true },
9+ submitError: true,
10+ errors: true,
11+ dirtySinceLastSubmit: true,
12+ },
9 });
13 });
10
14
11 const formError = errors[FORM_ERROR];
15 const formError = errors[FORM_ERROR];
16+ const showFormError = !!formError;
17+ const showSubmitError = !!submitError && !dirtySinceLastSubmit;
12
18
13− return submitError || formError ? (
19+ return showSubmitError || showFormError ? (
14 <ErrorText {...props}>{submitError || formError}</ErrorText>
20 <ErrorText {...props}>{submitError || formError}</ErrorText>
15 ) : null;
21 ) : null;
16}
22}
src/form/SubmitButton.js+16−10
@@ -13,24 +13,30 @@ export default function SubmitButton({
13 handleSubmit,
13 handleSubmit,
14 ...rest
14 ...rest
15}) {
15}) {
16− const { valid, validating, submitting, submitError } = useFormState({
16+ const {
17− subscription: {
17+ valid,
18− valid: true,
18+ validating,
19+ submitting,
20+ hasValidationErrors,
21+ hasSubmitErrors,
22+ dirtySinceLastSubmit,
23+ } = useFormState();
24+
25+ const canSubmit =
26+ (valid || (hasSubmitErrors && dirtySinceLastSubmit)) &&
19− validating: true,
27+ !validating &&
20− submitting: true,
28+ !hasValidationErrors &&
21− submitError: true,
29+ !submitting;
22− },
23− });
24
30
25 return (
31 return (
26 <As
32 <As
27 className={cn('mt4', className)}
33 className={cn('mt4', className)}
28− disabled={!valid || validating || submitting}
34+ disabled={!canSubmit}
29 accessory={blinkIf(validating || submitting)}
35 accessory={blinkIf(validating || submitting)}
30 onClick={handleSubmit}
36 onClick={handleSubmit}
31 solid
37 solid
32 {...rest}>
38 {...rest}>
33− {submitError ? 'Error submitting' : children}
39+ {children}
34 </As>
40 </As>
35 );
41 );
36}
42}
src/views/Activate/ActivateCode.js+1−1
@@ -71,7 +71,7 @@ export default function ActivateCode() {
71 // set our state on submission
71 // set our state on submission
72 const onSubmit = useCallback(
72 const onSubmit = useCallback(
73 async values => {
73 async values => {
74− await timeout(100); // allow the ui changes to flush before we lag it out
74+ await timeout(16); // allow the ui changes to flush before we lag it out
75
75
76 const _contracts = need.contracts(contracts);
76 const _contracts = need.contracts(contracts);
77 const { seed } = await generateTemporaryOwnershipWallet(values.ticket);
77 const { seed } = await generateTemporaryOwnershipWallet(values.ticket);
src/views/Login/ContinueButton.jsdeleted−26
@@ -1,26 +0,0 @@
1−import React from 'react';
2−import cn from 'classnames';
3−import { useFormState } from 'react-final-form';
4−
5−import { ForwardButton } from 'components/Buttons';
6−import Blinky from 'components/Blinky';
7−
8−export default function ContinueButton({ className, children, handleSubmit }) {
9− const { valid, validating, submitting } = useFormState({
10− subscription: { valid: true, validating: true, submitting: true },
11− });
12−
13− const loading = validating || submitting;
14−
15− return (
16− <ForwardButton
17− solid
18− className={cn('mt2', className)}
19− loading={validating}
20− disabled={!valid || loading}
21− accessory={loading ? <Blinky /> : undefined}
22− onClick={handleSubmit}>
23− {children || 'Continue'}
24− </ForwardButton>
25− );
26−}
src/views/Login/Keystore.js+3−3
@@ -15,7 +15,7 @@ import {
15 buildUploadValidator,
15 buildUploadValidator,
16} from 'form/validators';
16} from 'form/validators';
17import UploadInput from 'form/UploadInput';
17import UploadInput from 'form/UploadInput';
18−import ContinueButton from './ContinueButton';
18+import SubmitButton from 'form/SubmitButton';
19import BridgeForm from 'form/BridgeForm';
19import BridgeForm from 'form/BridgeForm';
20import { FORM_ERROR } from 'final-form';
20import { FORM_ERROR } from 'final-form';
21import FormError from 'form/FormError';
21import FormError from 'form/FormError';
@@ -44,7 +44,7 @@ export default function Keystore({ className, goHome }) {
44 const wallet = new EthereumWallet(privateKey);
44 const wallet = new EthereumWallet(privateKey);
45 setWallet(Just(wallet));
45 setWallet(Just(wallet));
46 } catch (error) {
46 } catch (error) {
47− console.error(error);
47+ // console.error(error);
48 return {
48 return {
49 [FORM_ERROR]:
49 [FORM_ERROR]:
50 "Couldn't decrypt wallet. You may have entered an incorrect password.",
50 "Couldn't decrypt wallet. You may have entered an incorrect password.",
@@ -81,7 +81,7 @@ export default function Keystore({ className, goHome }) {
81
81
82 <Grid.Item full as={FormError} />
82 <Grid.Item full as={FormError} />
83
83
84− <Grid.Item full as={ContinueButton} handleSubmit={handleSubmit}>
84+ <Grid.Item full as={SubmitButton} handleSubmit={handleSubmit}>
85 Decrypt
85 Decrypt
86 </Grid.Item>
86 </Grid.Item>
87 </>
87 </>
src/views/Login/Ledger.js+2−2
@@ -27,7 +27,7 @@ import {
27} from 'form/validators';
27} from 'form/validators';
28import BridgeForm from 'form/BridgeForm';
28import BridgeForm from 'form/BridgeForm';
29import FormError from 'form/FormError';
29import FormError from 'form/FormError';
30−import ContinueButton from './ContinueButton';
30+import SubmitButton from 'form/SubmitButton';
31import Condition from 'form/Condition';
31import Condition from 'form/Condition';
32import { FORM_ERROR } from 'final-form';
32import { FORM_ERROR } from 'final-form';
33import { HdPathInput } from 'form/Inputs';
33import { HdPathInput } from 'form/Inputs';
@@ -206,7 +206,7 @@ export default function Ledger({ className, goHome }) {
206
206
207 <Grid.Item full as={FormError} />
207 <Grid.Item full as={FormError} />
208
208
209− <Grid.Item full as={ContinueButton} handleSubmit={handleSubmit}>
209+ <Grid.Item full as={SubmitButton} handleSubmit={handleSubmit}>
210 Authenticate
210 Authenticate
211 </Grid.Item>
211 </Grid.Item>
212 </>
212 </>
src/views/Login/Mnemonic.js+4−2
@@ -18,7 +18,7 @@ import {
18import BridgeForm from 'form/BridgeForm';
18import BridgeForm from 'form/BridgeForm';
19import Condition from 'form/Condition';
19import Condition from 'form/Condition';
20import FormError from 'form/FormError';
20import FormError from 'form/FormError';
21−import ContinueButton from './ContinueButton';
21+import SubmitButton from 'form/SubmitButton';
22
22
23export default function Mnemonic({ className, goHome }) {
23export default function Mnemonic({ className, goHome }) {
24 useLoginView(WALLET_TYPES.MNEMONIC);
24 useLoginView(WALLET_TYPES.MNEMONIC);
@@ -99,7 +99,9 @@ export default function Mnemonic({ className, goHome }) {
99
99
100 <Grid.Item full as={FormError} />
100 <Grid.Item full as={FormError} />
101
101
102− <Grid.Item full as={ContinueButton} handleSubmit={handleSubmit} />
102+ <Grid.Item full as={SubmitButton} handleSubmit={handleSubmit}>
103+ Continue
104+ </Grid.Item>
103 </>
105 </>
104 )}
106 )}
105 </BridgeForm>
107 </BridgeForm>
src/views/Login/PrivateKey.js+4−2
@@ -12,7 +12,7 @@ import BridgeForm from 'form/BridgeForm';
12import { HexInput } from 'form/Inputs';
12import { HexInput } from 'form/Inputs';
13import { buildHexValidator, composeValidator } from 'form/validators';
13import { buildHexValidator, composeValidator } from 'form/validators';
14
14
15−import ContinueButton from './ContinueButton';
15+import SubmitButton from 'form/SubmitButton';
16
16
17export default function PrivateKey({ className, goHome }) {
17export default function PrivateKey({ className, goHome }) {
18 useLoginView(WALLET_TYPES.PRIVATE_KEY);
18 useLoginView(WALLET_TYPES.PRIVATE_KEY);
@@ -52,7 +52,9 @@ export default function PrivateKey({ className, goHome }) {
52 label="Private key"
52 label="Private key"
53 />
53 />
54 <Grid.Item full as={FormError} />
54 <Grid.Item full as={FormError} />
55− <Grid.Item full as={ContinueButton} handleSubmit={handleSubmit} />
55+ <Grid.Item full as={SubmitButton} handleSubmit={handleSubmit}>
56+ Continue
57+ </Grid.Item>
56 </>
58 </>
57 )}
59 )}
58 </BridgeForm>
60 </BridgeForm>
src/views/Login/Ticket.js+38−49
@@ -29,7 +29,7 @@ import {
29} from 'form/validators';
29} from 'form/validators';
30import FormError from 'form/FormError';
30import FormError from 'form/FormError';
31
31
32−import ContinueButton from './ContinueButton';
32+import SubmitButton from 'form/SubmitButton';
33import useSetState from 'lib/useSetState';
33import useSetState from 'lib/useSetState';
34
34
35export default function Ticket({ className, goHome }) {
35export default function Ticket({ className, goHome }) {
@@ -41,16 +41,38 @@ export default function Ticket({ className, goHome }) {
41 const impliedPoint = useImpliedPoint();
41 const impliedPoint = useImpliedPoint();
42 const [warnings, addWarning] = useSetState();
42 const [warnings, addWarning] = useSetState();
43
43
44− const cachedUrbitWallet = useRef(Nothing());
44+ const validateForm = useCallback(
45+ (values, errors) => {
46+ if (errors.point) {
47+ addWarning({ point: null });
48+ return errors;
49+ }
50+
51+ if (values.useShards) {
52+ if (errors.shard1 || errors.shard2 || errors.shard3) {
53+ return errors;
54+ }
55+ } else {
56+ if (errors.ticket) {
57+ return errors;
58+ }
59+ }
60+ },
61+ [addWarning]
62+ );
63+
64+ const onSubmit = useCallback(
65+ async values => {
66+ const ticket = values.useShards
67+ ? kg.combine([values.shard1, values.shard2, values.shard3])
68+ : values.ticket;
45
69
46− const validateFormAsync = useCallback(
47− async (values, ticket) => {
48 try {
70 try {
49 const _contracts = need.contracts(contracts);
71 const _contracts = need.contracts(contracts);
50 const point = patp2dec(values.point);
72 const point = patp2dec(values.point);
51
73
52 await timeout(16); // allow ui events to flush
74 await timeout(16); // allow ui events to flush
53− cachedUrbitWallet.current = await urbitWalletFromTicket(
75+ const urbitWallet = await urbitWalletFromTicket(
54 ticket,
76 ticket,
55 point,
77 point,
56 values.passphrase
78 values.passphrase
@@ -60,23 +82,27 @@ export default function Ticket({ className, goHome }) {
60 azimuth.azimuth.isOwner(
82 azimuth.azimuth.isOwner(
61 _contracts,
83 _contracts,
62 point,
84 point,
63− cachedUrbitWallet.current.ownership.keys.address
85+ urbitWallet.ownership.keys.address
64 ),
86 ),
65 azimuth.azimuth.isTransferProxy(
87 azimuth.azimuth.isTransferProxy(
66 _contracts,
88 _contracts,
67 point,
89 point,
68− cachedUrbitWallet.current.ownership.keys.address
90+ urbitWallet.ownership.keys.address
69 ),
91 ),
70 ]);
92 ]);
71
93
72 const noPermissions = !isOwner && !isTransferProxy;
94 const noPermissions = !isOwner && !isTransferProxy;
73 // notify the user, but allow login regardless
95 // notify the user, but allow login regardless
96+ // TODO: how should the warning work now that we generate onSubmit?
74 if (noPermissions) {
97 if (noPermissions) {
75 addWarning({
98 addWarning({
76 point:
99 point:
77 'This wallet is not the owner or transfer proxy for this point.',
100 'This wallet is not the owner or transfer proxy for this point.',
78 });
101 });
79 }
102 }
103+
104+ setUrbitWallet(Just(urbitWallet));
105+ setPointCursor(Just(patp2dec(values.point)));
80 } catch (error) {
106 } catch (error) {
81 console.error(error);
107 console.error(error);
82 return {
108 return {
@@ -86,34 +112,7 @@ export default function Ticket({ className, goHome }) {
86 };
112 };
87 }
113 }
88 },
114 },
89− [addWarning, contracts]
115+ [addWarning, contracts, setPointCursor, setUrbitWallet]
90− );
91−
92− const validateForm = useCallback(
93− (values, errors) => {
94− if (errors.point) {
95− addWarning({ point: null });
96− return errors;
97− }
98−
99− let ticket;
100− if (values.useShards) {
101− if (errors.shard1 || errors.shard2 || errors.shard3) {
102− return errors;
103− }
104−
105− ticket = kg.combine([values.shard1, values.shard2, values.shard3]);
106− } else {
107− if (errors.ticket) {
108− return errors;
109− }
110−
111− ticket = values.ticket;
112− }
113−
114− return validateFormAsync(values, ticket);
115− },
116− [addWarning, validateFormAsync]
117 );
116 );
118
117
119 const validate = useMemo(
118 const validate = useMemo(
@@ -134,18 +133,6 @@ export default function Ticket({ className, goHome }) {
134 [validateForm]
133 [validateForm]
135 );
134 );
136
135
137− const onValues = useCallback(
138− ({ valid, values }) => {
139− if (valid) {
140− setUrbitWallet(Just(cachedUrbitWallet.current));
141− setPointCursor(Just(patp2dec(values.point)));
142− } else {
143− setUrbitWallet(Nothing());
144− }
145− },
146− [setPointCursor, setUrbitWallet]
147− );
148−
149 const initialValues = useMemo(
136 const initialValues = useMemo(
150 () => ({
137 () => ({
151 point: impliedPoint || '',
138 point: impliedPoint || '',
@@ -159,7 +146,7 @@ export default function Ticket({ className, goHome }) {
159 <Grid className={cn('mt4', className)}>
146 <Grid className={cn('mt4', className)}>
160 <BridgeForm
147 <BridgeForm
161 validate={validate}
148 validate={validate}
162− onValues={onValues}
149+ onSubmit={onSubmit}
163 afterSubmit={goHome}
150 afterSubmit={goHome}
164 initialValues={initialValues}>
151 initialValues={initialValues}>
165 {({ handleSubmit }) => (
152 {({ handleSubmit }) => (
@@ -210,7 +197,9 @@ export default function Ticket({ className, goHome }) {
210
197
211 <Grid.Item full as={FormError} />
198 <Grid.Item full as={FormError} />
212
199
213− <Grid.Item full as={ContinueButton} handleSubmit={handleSubmit} />
200+ <Grid.Item full as={SubmitButton} handleSubmit={handleSubmit}>
201+ Continue
202+ </Grid.Item>
214 </>
203 </>
215 )}
204 )}
216 </BridgeForm>
205 </BridgeForm>
src/views/Login/Trezor.js+2−2
@@ -22,7 +22,7 @@ import BridgeForm from 'form/BridgeForm';
22import Condition from 'form/Condition';
22import Condition from 'form/Condition';
23import FormError from 'form/FormError';
23import FormError from 'form/FormError';
24
24
25−import ContinueButton from './ContinueButton';
25+import SubmitButton from 'form/SubmitButton';
26import { FORM_ERROR } from 'final-form';
26import { FORM_ERROR } from 'final-form';
27import { HdPathInput } from 'form/Inputs';
27import { HdPathInput } from 'form/Inputs';
28
28
@@ -136,7 +136,7 @@ export default function Trezor({ className, goHome }) {
136
136
137 <Grid.Item full as={FormError} />
137 <Grid.Item full as={FormError} />
138
138
139− <Grid.Item full as={ContinueButton} handleSubmit={handleSubmit}>
139+ <Grid.Item full as={SubmitButton} handleSubmit={handleSubmit}>
140 Authenticate
140 Authenticate
141 </Grid.Item>
141 </Grid.Item>
142 </>
142 </>