on master help sign in
feat: standardize onSubmit for ActivateCode, Login/Ticket & Keystore

to allow the form to be submitted even with submit errors, we check the dirtySinceLastSubmit value. see the following issues for more deets: - https://github.com/final-form/react-final-form/issues/403 - https://github.com/final-form/react-final-form/issues/547 - etc etc there are a few others that I couldn't re-find this change means that SubmitButton needed extra logic, so we removed ContinueButton in favor of having that logic live in one place (no idea why I wrote ContinueButton in the first place tbh)

commitaed1af0c7689654921a3b2b9c0b7eb81160391e8 authorMatt Condon (shrugs) <mattgcondon@gmail.com> dateMon 12 Aug 2019, 17:25 (7 years ago) parent302442c
10 files changed+79−100
src/form/FormError.js+9−3 src/form/SubmitButton.js+16−10 src/views/Activate/ActivateCode.js+1−1 src/views/Login/ContinueButton.js−26 src/views/Login/Keystore.js+3−3 src/views/Login/Ledger.js+2−2 src/views/Login/Mnemonic.js+4−2 src/views/Login/PrivateKey.js+4−2 src/views/Login/Ticket.js+38−49 src/views/Login/Trezor.js+2−2
src/form/FormError.js+9−3
@@ -4,13 +4,19 @@ import { ErrorText } from 'indigo-react';
44import { FORM_ERROR } from 'final-form';
55
66export default function FormError(props) {
7− const { submitError, errors } = useFormState({
8− subscription: { submitError: true, errors: true },
7+ const { submitError, errors, dirtySinceLastSubmit } = useFormState({
8+ subscription: {
9+ submitError: true,
10+ errors: true,
11+ dirtySinceLastSubmit: true,
12+ },
913 });
1014
1115 const formError = errors[FORM_ERROR];
16+ const showFormError = !!formError;
17+ const showSubmitError = !!submitError && !dirtySinceLastSubmit;
1218
13− return submitError || formError ? (
19+ return showSubmitError || showFormError ? (
1420 <ErrorText {...props}>{submitError || formError}</ErrorText>
1521 ) : null;
1622}
src/form/SubmitButton.js+16−10
@@ -13,24 +13,30 @@ export default function SubmitButton({
1313 handleSubmit,
1414 ...rest
1515}) {
16− const { valid, validating, submitting, submitError } = useFormState({
17− subscription: {
18− valid: true,
19− validating: true,
20− submitting: true,
21− submitError: true,
22− },
23− });
16+ const {
17+ valid,
18+ validating,
19+ submitting,
20+ hasValidationErrors,
21+ hasSubmitErrors,
22+ dirtySinceLastSubmit,
23+ } = useFormState();
24+
25+ const canSubmit =
26+ (valid || (hasSubmitErrors && dirtySinceLastSubmit)) &&
27+ !validating &&
28+ !hasValidationErrors &&
29+ !submitting;
2430
2531 return (
2632 <As
2733 className={cn('mt4', className)}
28− disabled={!valid || validating || submitting}
34+ disabled={!canSubmit}
2935 accessory={blinkIf(validating || submitting)}
3036 onClick={handleSubmit}
3137 solid
3238 {...rest}>
33− {submitError ? 'Error submitting' : children}
39+ {children}
3440 </As>
3541 );
3642}
src/views/Activate/ActivateCode.js+1−1
@@ -71,7 +71,7 @@ export default function ActivateCode() {
7171 // set our state on submission
7272 const onSubmit = useCallback(
7373 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
7575
7676 const _contracts = need.contracts(contracts);
7777 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 {
1515 buildUploadValidator,
1616} from 'form/validators';
1717import UploadInput from 'form/UploadInput';
18−import ContinueButton from './ContinueButton';
18+import SubmitButton from 'form/SubmitButton';
1919import BridgeForm from 'form/BridgeForm';
2020import { FORM_ERROR } from 'final-form';
2121import FormError from 'form/FormError';
@@ -44,7 +44,7 @@ export default function Keystore({ className, goHome }) {
4444 const wallet = new EthereumWallet(privateKey);
4545 setWallet(Just(wallet));
4646 } catch (error) {
47− console.error(error);
47+ // console.error(error);
4848 return {
4949 [FORM_ERROR]:
5050 "Couldn't decrypt wallet. You may have entered an incorrect password.",
@@ -81,7 +81,7 @@ export default function Keystore({ className, goHome }) {
8181
8282 <Grid.Item full as={FormError} />
8383
84− <Grid.Item full as={ContinueButton} handleSubmit={handleSubmit}>
84+ <Grid.Item full as={SubmitButton} handleSubmit={handleSubmit}>
8585 Decrypt
8686 </Grid.Item>
8787 </>
src/views/Login/Ledger.js+2−2
@@ -27,7 +27,7 @@ import {
2727} from 'form/validators';
2828import BridgeForm from 'form/BridgeForm';
2929import FormError from 'form/FormError';
30−import ContinueButton from './ContinueButton';
30+import SubmitButton from 'form/SubmitButton';
3131import Condition from 'form/Condition';
3232import { FORM_ERROR } from 'final-form';
3333import { HdPathInput } from 'form/Inputs';
@@ -206,7 +206,7 @@ export default function Ledger({ className, goHome }) {
206206
207207 <Grid.Item full as={FormError} />
208208
209− <Grid.Item full as={ContinueButton} handleSubmit={handleSubmit}>
209+ <Grid.Item full as={SubmitButton} handleSubmit={handleSubmit}>
210210 Authenticate
211211 </Grid.Item>
212212 </>
src/views/Login/Mnemonic.js+4−2
@@ -18,7 +18,7 @@ import {
1818import BridgeForm from 'form/BridgeForm';
1919import Condition from 'form/Condition';
2020import FormError from 'form/FormError';
21−import ContinueButton from './ContinueButton';
21+import SubmitButton from 'form/SubmitButton';
2222
2323export default function Mnemonic({ className, goHome }) {
2424 useLoginView(WALLET_TYPES.MNEMONIC);
@@ -99,7 +99,9 @@ export default function Mnemonic({ className, goHome }) {
9999
100100 <Grid.Item full as={FormError} />
101101
102− <Grid.Item full as={ContinueButton} handleSubmit={handleSubmit} />
102+ <Grid.Item full as={SubmitButton} handleSubmit={handleSubmit}>
103+ Continue
104+ </Grid.Item>
103105 </>
104106 )}
105107 </BridgeForm>
src/views/Login/PrivateKey.js+4−2
@@ -12,7 +12,7 @@ import BridgeForm from 'form/BridgeForm';
1212import { HexInput } from 'form/Inputs';
1313import { buildHexValidator, composeValidator } from 'form/validators';
1414
15−import ContinueButton from './ContinueButton';
15+import SubmitButton from 'form/SubmitButton';
1616
1717export default function PrivateKey({ className, goHome }) {
1818 useLoginView(WALLET_TYPES.PRIVATE_KEY);
@@ -52,7 +52,9 @@ export default function PrivateKey({ className, goHome }) {
5252 label="Private key"
5353 />
5454 <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>
5658 </>
5759 )}
5860 </BridgeForm>
src/views/Login/Ticket.js+38−49
@@ -29,7 +29,7 @@ import {
2929} from 'form/validators';
3030import FormError from 'form/FormError';
3131
32−import ContinueButton from './ContinueButton';
32+import SubmitButton from 'form/SubmitButton';
3333import useSetState from 'lib/useSetState';
3434
3535export default function Ticket({ className, goHome }) {
@@ -41,16 +41,38 @@ export default function Ticket({ className, goHome }) {
4141 const impliedPoint = useImpliedPoint();
4242 const [warnings, addWarning] = useSetState();
4343
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;
4569
46− const validateFormAsync = useCallback(
47− async (values, ticket) => {
4870 try {
4971 const _contracts = need.contracts(contracts);
5072 const point = patp2dec(values.point);
5173
5274 await timeout(16); // allow ui events to flush
53− cachedUrbitWallet.current = await urbitWalletFromTicket(
75+ const urbitWallet = await urbitWalletFromTicket(
5476 ticket,
5577 point,
5678 values.passphrase
@@ -60,23 +82,27 @@ export default function Ticket({ className, goHome }) {
6082 azimuth.azimuth.isOwner(
6183 _contracts,
6284 point,
63− cachedUrbitWallet.current.ownership.keys.address
85+ urbitWallet.ownership.keys.address
6486 ),
6587 azimuth.azimuth.isTransferProxy(
6688 _contracts,
6789 point,
68− cachedUrbitWallet.current.ownership.keys.address
90+ urbitWallet.ownership.keys.address
6991 ),
7092 ]);
7193
7294 const noPermissions = !isOwner && !isTransferProxy;
7395 // notify the user, but allow login regardless
96+ // TODO: how should the warning work now that we generate onSubmit?
7497 if (noPermissions) {
7598 addWarning({
7699 point:
77100 'This wallet is not the owner or transfer proxy for this point.',
78101 });
79102 }
103+
104+ setUrbitWallet(Just(urbitWallet));
105+ setPointCursor(Just(patp2dec(values.point)));
80106 } catch (error) {
81107 console.error(error);
82108 return {
@@ -86,34 +112,7 @@ export default function Ticket({ className, goHome }) {
86112 };
87113 }
88114 },
89− [addWarning, contracts]
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]
115+ [addWarning, contracts, setPointCursor, setUrbitWallet]
117116 );
118117
119118 const validate = useMemo(
@@ -134,18 +133,6 @@ export default function Ticket({ className, goHome }) {
134133 [validateForm]
135134 );
136135
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−
149136 const initialValues = useMemo(
150137 () => ({
151138 point: impliedPoint || '',
@@ -159,7 +146,7 @@ export default function Ticket({ className, goHome }) {
159146 <Grid className={cn('mt4', className)}>
160147 <BridgeForm
161148 validate={validate}
162− onValues={onValues}
149+ onSubmit={onSubmit}
163150 afterSubmit={goHome}
164151 initialValues={initialValues}>
165152 {({ handleSubmit }) => (
@@ -210,7 +197,9 @@ export default function Ticket({ className, goHome }) {
210197
211198 <Grid.Item full as={FormError} />
212199
213− <Grid.Item full as={ContinueButton} handleSubmit={handleSubmit} />
200+ <Grid.Item full as={SubmitButton} handleSubmit={handleSubmit}>
201+ Continue
202+ </Grid.Item>
214203 </>
215204 )}
216205 </BridgeForm>
src/views/Login/Trezor.js+2−2
@@ -22,7 +22,7 @@ import BridgeForm from 'form/BridgeForm';
2222import Condition from 'form/Condition';
2323import FormError from 'form/FormError';
2424
25−import ContinueButton from './ContinueButton';
25+import SubmitButton from 'form/SubmitButton';
2626import { FORM_ERROR } from 'final-form';
2727import { HdPathInput } from 'form/Inputs';
2828
@@ -136,7 +136,7 @@ export default function Trezor({ className, goHome }) {
136136
137137 <Grid.Item full as={FormError} />
138138
139− <Grid.Item full as={ContinueButton} handleSubmit={handleSubmit}>
139+ <Grid.Item full as={SubmitButton} handleSubmit={handleSubmit}>
140140 Authenticate
141141 </Grid.Item>
142142 </>