on master help sign in
fix: minor updates from PR self-review
228dce8Matt Condon (shrugs)
src/form/SubmitButton.js+1−1
@@ -1,10 +1,10 @@
1import React from 'react';
1import React from 'react';
2import cn from 'classnames';
2import cn from 'classnames';
3+import { useFormState } from 'react-final-form';
3
4
4import { ForwardButton } from 'components/Buttons';
5import { ForwardButton } from 'components/Buttons';
5
6
6import { blinkIf } from 'components/Blinky';
7import { blinkIf } from 'components/Blinky';
7−import { useFormState } from 'react-final-form';
8
8
9export default function SubmitButton({
9export default function SubmitButton({
10 as: As = ForwardButton,
10 as: As = ForwardButton,
src/form/ValuesHandler.js+4−1
@@ -1,6 +1,9 @@
1import { useEffect } from 'react';
1import { useEffect } from 'react';
2import { useFormState, useForm } from 'react-final-form';
2import { useFormState, useForm } from 'react-final-form';
3
3
4+/**
5+ * ValuesHandler notifies callback function when form values change.
6+ */
4export default function ValuesHandler({ onValues }) {
7export default function ValuesHandler({ onValues }) {
5 const form = useForm();
8 const form = useForm();
6 const { valid, validating, values } = useFormState({
9 const { valid, validating, values } = useFormState({
@@ -13,7 +16,7 @@ export default function ValuesHandler({ onValues }) {
13
16
14 useEffect(() => {
17 useEffect(() => {
15 if (!validating) {
18 if (!validating) {
16− onValues && onValues({ valid: valid && !validating, values, form });
19+ onValues && onValues({ valid, values, form });
17 }
20 }
18 }, [form, onValues, valid, validating, values]);
21 }, [form, onValues, valid, validating, values]);
19
22
src/form/validators.js+9−7
@@ -29,6 +29,10 @@ const buildValidator = (validators = []) => async value => {
29 }
29 }
30};
30};
31
31
32+// maps a validator across an array of values
33+export const buildArrayValidator = validator => async values =>
34+ await Promise.all(values.map(validator));
35+
32// error object has errors if some of its fields are
36// error object has errors if some of its fields are
33// 1) an array with any defined values
37// 1) an array with any defined values
34// 2) any defined values
38// 2) any defined values
@@ -72,17 +76,15 @@ export const buildAddressValidator = () =>
72 ]);
76 ]);
73export const buildNumberValidator = (min = 0) =>
77export const buildNumberValidator = (min = 0) =>
74 buildValidator([validateGreaterThan(min)]);
78 buildValidator([validateGreaterThan(min)]);
75−export const buildEmailValidator = () =>
79+export const buildEmailValidator = (validators = []) =>
76− buildValidator([validateNotEmpty, validateEmail]);
80+ buildValidator([validateNotEmpty, validateEmail, ...validators]);
77−
78−// the default form validator just returns field-level validations
79−const kDefaultFormValidator = (values, errors) => errors;
80
81
81// the form validator is the composition of all of the field validators
82// the form validator is the composition of all of the field validators
82// plus an additional form validator function
83// plus an additional form validator function
83export const composeValidator = (
84export const composeValidator = (
84 fieldValidators = {},
85 fieldValidators = {},
86+ // the default form validator just returns field-level validations
85− formValidator = kDefaultFormValidator
87+ formValidator = (values, errors) => errors
86) => {
88) => {
87 const names = Object.keys(fieldValidators);
89 const names = Object.keys(fieldValidators);
88
90
@@ -105,7 +107,7 @@ export const composeValidator = (
105 );
107 );
106 };
108 };
107
109
108− // final-form `validate` function
110+ // the final-form `validate` function
109 return async values => {
111 return async values => {
110 // ask for field-level errors
112 // ask for field-level errors
111 const errors = await fieldLevelValidator(values);
113 const errors = await fieldLevelValidator(values);
src/indigo-react/components/SelectInput.js+1−1
@@ -15,7 +15,7 @@ export default function SelectInput({
15 className,
15 className,
16 mono = false,
16 mono = false,
17 options = [],
17 options = [],
18− disabled,
18+ disabled = false,
19}) {
19}) {
20 const {
20 const {
21 input,
21 input,
src/indigo-react/components/ToggleInput.js+1−1
@@ -13,7 +13,7 @@ export default function ToggleInput({
13 className,
13 className,
14
14
15 //
15 //
16− disabled,
16+ disabled = false,
17
17
18 ...rest
18 ...rest
19}) {
19}) {
src/views/Admin/AdminNetworkingKeys.js+3−5
@@ -168,8 +168,6 @@ export default function AdminNetworkingKeys() {
168 if (values.useNetworkSeed && errors.networkSeed) {
168 if (values.useNetworkSeed && errors.networkSeed) {
169 return errors;
169 return errors;
170 }
170 }
171−
172− return {};
173 }, []);
171 }, []);
174
172
175 const validate = useMemo(
173 const validate = useMemo(
@@ -236,16 +234,16 @@ export default function AdminNetworkingKeys() {
236 </Grid.Item>
234 </Grid.Item>
237 {key.matchWith({
235 {key.matchWith({
238 Nothing: () => (
236 Nothing: () => (
239− <Grid.Item full as="code" className="f5 gray4">
237+ <Grid.Item full as="code" className="f5 mono gray4">
240 Unset
238 Unset
241 </Grid.Item>
239 </Grid.Item>
242 ),
240 ),
243 Just: ({ value: key }) => (
241 Just: ({ value: key }) => (
244 <>
242 <>
245− <Grid.Item full as="code" className="f5 wrap">
243+ <Grid.Item full as="code" className="f5 mono wrap">
246 0x
244 0x
247 </Grid.Item>
245 </Grid.Item>
248− <Grid.Item full as="code" className="f5 wrap">
246+ <Grid.Item full as="code" className="f5 mono wrap">
249 {renderNetworkKey(key)}
247 {renderNetworkKey(key)}
250 </Grid.Item>
248 </Grid.Item>
251 </>
249 </>
src/views/Admin/AdminSetProxy.js−2
@@ -118,8 +118,6 @@ export default function AdminSetProxy() {
118 if (!values.unset && errors.address) {
118 if (!values.unset && errors.address) {
119 return errors;
119 return errors;
120 }
120 }
121−
122− return {};
123 }, []);
121 }, []);
124
122
125 const validate = useMemo(
123 const validate = useMemo(
src/views/Invite/InviteEmail.js+12−16
@@ -50,6 +50,7 @@ import {
50 buildEmailValidator,
50 buildEmailValidator,
51 composeValidator,
51 composeValidator,
52 hasErrors,
52 hasErrors,
53+ buildArrayValidator,
53} from 'form/validators';
54} from 'form/validators';
54import { FORM_ERROR } from 'final-form';
55import { FORM_ERROR } from 'final-form';
55import SubmitButton from 'form/SubmitButton';
56import SubmitButton from 'form/SubmitButton';
@@ -98,8 +99,6 @@ const buildAccessoryFor = (dones, errors) => name => {
98 return <AccessoryIcon.Pending />;
99 return <AccessoryIcon.Pending />;
99};
100};
100
101
101−const emailFormatValidator = buildEmailValidator();
102−
103export default function InviteEmail() {
102export default function InviteEmail() {
104 const { contracts, web3, networkType } = useNetwork();
103 const { contracts, web3, networkType } = useNetwork();
105 const { wallet, walletType, walletHdPath } = useWallet();
104 const { wallet, walletType, walletHdPath } = useWallet();
@@ -135,14 +134,8 @@ export default function InviteEmail() {
135 const isFailed = status === STATUS.FAILURE;
134 const isFailed = status === STATUS.FAILURE;
136 const isDone = status === STATUS.SUCCESS;
135 const isDone = status === STATUS.SUCCESS;
137
136
138− const validateEmail = useCallback(
137+ const validateHasReceived = useCallback(
139 async email => {
138 async email => {
140− // check individual email validity
141− const error = await emailFormatValidator(email);
142− if (error) {
143− return error;
144− }
145−
146 const hasReceived = await getHasReceived(email);
139 const hasReceived = await getHasReceived(email);
147 if (hasReceived) {
140 if (hasReceived) {
148 return HAS_RECEIVED_TEXT;
141 return HAS_RECEIVED_TEXT;
@@ -151,11 +144,6 @@ export default function InviteEmail() {
151 [getHasReceived]
144 [getHasReceived]
152 );
145 );
153
146
154− const validateEmails = useCallback(
155− async emails => await Promise.all(emails.map(validateEmail)),
156− [validateEmail]
157− );
158−
159 const validateForm = useCallback(async (values, errors) => {
147 const validateForm = useCallback(async (values, errors) => {
160 if (hasErrors(errors)) {
148 if (hasErrors(errors)) {
161 return errors;
149 return errors;
@@ -169,8 +157,16 @@ export default function InviteEmail() {
169 }, []);
157 }, []);
170
158
171 const validate = useMemo(
159 const validate = useMemo(
160+ () =>
172− () => composeValidator({ emails: validateEmails }, validateForm),
161+ composeValidator(
173− [validateEmails, validateForm]
162+ {
163+ emails: buildArrayValidator(
164+ buildEmailValidator([validateHasReceived])
165+ ),
166+ },
167+ validateForm
168+ ),
169+ [validateForm, validateHasReceived]
174 );
170 );
175
171
176 // progress is [0, .length] of invites or receipts, as we're generating them
172 // progress is [0, .length] of invites or receipts, as we're generating them
src/views/Login/Ledger.js+1−1
@@ -77,10 +77,10 @@ export default function Ledger({ className, goHome }) {
77 const chainCode = Buffer.from(info.chainCode, 'hex');
77 const chainCode = Buffer.from(info.chainCode, 'hex');
78 const pub = secp256k1.publicKeyConvert(publicKey, true);
78 const pub = secp256k1.publicKeyConvert(publicKey, true);
79 const hd = bip32.fromPublicKey(pub, chainCode);
79 const hd = bip32.fromPublicKey(pub, chainCode);
80+
80 setWallet(Just(hd));
81 setWallet(Just(hd));
81 setWalletHdPath(addHdPrefix(values.hdpath));
82 setWalletHdPath(addHdPrefix(values.hdpath));
82 } catch (error) {
83 } catch (error) {
83− setWallet(Nothing());
84 return { [FORM_ERROR]: error.message };
84 return { [FORM_ERROR]: error.message };
85 }
85 }
86 },
86 },
src/views/Login/PrivateKey.js+3−3
@@ -22,7 +22,7 @@ export default function PrivateKey({ className, goHome }) {
22 const validate = useMemo(
22 const validate = useMemo(
23 () =>
23 () =>
24 composeValidator({
24 composeValidator({
25− privatekey: buildHexValidator(64),
25+ privateKey: buildHexValidator(64),
26 }),
26 }),
27 []
27 []
28 );
28 );
@@ -30,7 +30,7 @@ export default function PrivateKey({ className, goHome }) {
30 const onValues = useCallback(
30 const onValues = useCallback(
31 ({ valid, values }) => {
31 ({ valid, values }) => {
32 if (valid) {
32 if (valid) {
33− const sec = Buffer.from(stripHexPrefix(values.privatekey), 'hex');
33+ const sec = Buffer.from(stripHexPrefix(values.privateKey), 'hex');
34 const newWallet = new EthereumWallet(sec);
34 const newWallet = new EthereumWallet(sec);
35 setWallet(Just(newWallet));
35 setWallet(Just(newWallet));
36 } else {
36 } else {
@@ -48,7 +48,7 @@ export default function PrivateKey({ className, goHome }) {
48 <Grid.Item
48 <Grid.Item
49 full
49 full
50 as={HexInput}
50 as={HexInput}
51− name="privatekey"
51+ name="privateKey"
52 label="Private key"
52 label="Private key"
53 />
53 />
54 <Grid.Item full as={FormError} />
54 <Grid.Item full as={FormError} />
src/views/Login/Trezor.js+10−11
@@ -60,22 +60,21 @@ export default function Trezor({ className, goHome }) {
60 appUrl: 'https://github.com/urbit/bridge',
60 appUrl: 'https://github.com/urbit/bridge',
61 });
61 });
62
62
63− const info = await TrezorConnect.getPublicKey({
63+ const { success, payload } = await TrezorConnect.getPublicKey({
64 path: values.hdpath,
64 path: values.hdpath,
65 });
65 });
66
66
67− if (info.success === true) {
67+ if (!success) {
68− const payload = info.payload;
69− const publicKey = Buffer.from(payload.publicKey, 'hex');
70− const chainCode = Buffer.from(payload.chainCode, 'hex');
71− const pub = secp256k1.publicKeyConvert(publicKey, true);
72− const hd = bip32.fromPublicKey(pub, chainCode);
73− setWallet(Just(hd));
74− setWalletHdPath(values.hdPath);
75− } else {
76− setWallet(Nothing());
77 return { [FORM_ERROR]: 'Failed to authenticate with your Trezor.' };
68 return { [FORM_ERROR]: 'Failed to authenticate with your Trezor.' };
78 }
69 }
70+
71+ const publicKey = Buffer.from(payload.publicKey, 'hex');
72+ const chainCode = Buffer.from(payload.chainCode, 'hex');
73+ const pub = secp256k1.publicKeyConvert(publicKey, true);
74+ const hd = bip32.fromPublicKey(pub, chainCode);
75+
76+ setWallet(Just(hd));
77+ setWalletHdPath(values.hdPath);
79 },
78 },
80 [setWallet, setWalletHdPath]
79 [setWallet, setWalletHdPath]
81 );
80 );