on master help sign in
feat: put additional config updates through useForm
commit5c991af9f7c38fec2b0be86ed738feaf95b08a83 authorMatt Condon (shrugs) <mattgcondon@gmail.com> dateTue 25 Jun 2019, 18:06 (7 years ago) parentd49f060
3 files changed+67−49
src/indigo-react/lib/useForm.js+31−24 src/views/Invite/InviteEmail.js+34−23 src/views/Point.js+2−2
src/indigo-react/lib/useForm.js+31−24
@@ -111,47 +111,54 @@ export default function useForm(configs = []) {
111111 () =>
112112 configs.map(
113113 (config, i) =>
114− !validations[i].pass &&
115− hasBeenFocused[config.name] &&
116− !focused[config.name] &&
117− validations[i].error
114+ config.error ||
115+ (!validations[i].pass &&
116+ hasBeenFocused[config.name] &&
117+ !focused[config.name] &&
118+ validations[i].error)
118119 ),
119120 [configs, validations, hasBeenFocused, focused]
120121 );
121122
122123 // visibly tell the user that their input has passed if
123124 // 1) it has passed
124− // 2) they are or have interacted with the input before
125+ // 2) there are no errors
126+ // 3) they are or have interacted with the input before
125127 const visiblePasses = useMemo(
126128 () =>
127129 configs.map(
128130 (config, i) =>
129131 validations[i].pass &&
132+ !errors[i] &&
130133 (hasBeenFocused[config.name] || focused[config.name])
131134 ),
132− [configs, validations, hasBeenFocused, focused]
135+ [configs, validations, errors, hasBeenFocused, focused]
133136 );
134137
135138 const inputs = useMemo(
136139 () =>
137− configs.map((config, i) => ({
138− // Input props
139− data: datas[i],
140− pass: passes[i],
141− visiblyPassed: visiblePasses[i],
142− error: errors[i],
143− focused: focuses[i],
144− ...config,
145− autoFocus: config.autoFocus && !config.disabled,
146− // dom properties below:
147− bind: {
148− value: values[config.name] || config.initialValue,
149− onChange: onChange(config.name),
150− onFocus: onFocus(config.name),
151− onBlur: onBlur(config.name),
152− autoFocus: config.autoFocus && !config.disabled,
153− },
154− })),
140+ configs.map(
141+ ({ name, error, autoFocus, disabled, initialValue, ...rest }, i) => ({
142+ // Input props
143+ name,
144+ data: datas[i],
145+ pass: passes[i],
146+ visiblyPassed: visiblePasses[i],
147+ error: errors[i],
148+ focused: focuses[i],
149+ autoFocus: autoFocus && !disabled,
150+ disabled,
151+ ...rest,
152+ // dom properties below:
153+ bind: {
154+ value: values[name] || initialValue,
155+ onChange: onChange(name),
156+ onFocus: onFocus(name),
157+ onBlur: onBlur(name),
158+ autoFocus: autoFocus && !disabled,
159+ },
160+ })
161+ ),
155162 [
156163 configs,
157164 datas,
src/views/Invite/InviteEmail.js+34−23
@@ -1,6 +1,6 @@
1−import React, { useCallback, useEffect, useState } from 'react';
1+import React, { useCallback, useEffect, useMemo, useState } from 'react';
22import cn from 'classnames';
3−import Maybe, { Just, Nothing } from 'folktale/maybe';
3+import Maybe from 'folktale/maybe';
44import * as azimuth from 'azimuth-js';
55import { Grid, Flex, Input, IconButton, HelpText, Text } from 'indigo-react';
66import { uniq } from 'lodash';
@@ -90,7 +90,6 @@ const buildAccessoryFor = (dones, errors) => name => (
9090);
9191
9292// TODO: refactor transactions + mailer into hooks
93−// TODO: include input-specific error info in form elements
9493// TODO: put accessory inside of input
9594// TODO: implement hasReceived cache with useHasReceived
9695export default function NewInviteEmail() {
@@ -116,13 +115,7 @@ export default function NewInviteEmail() {
116115 buildInputConfig
117116 );
118117
119− const [hovered, _setHovered] = useState({});
120− const setHovered = (name, value) => () =>
121− _setHovered((value = { ...value, [name]: value }));
122−
123− // TODO: pass disabled, error info into the useForm hook?
124− const { inputs, pass } = useForm(inputConfigs);
125−
118+ const [hovered, setHovered] = useSetState({});
126119 const [invites, addInvite, clearInvites] = useSetState({});
127120 const [receipts, addReceipt, clearReceipts] = useSetState({});
128121 const [errors, addError, clearError] = useSetState({});
@@ -131,17 +124,29 @@ export default function NewInviteEmail() {
131124 const [needFunds, setNeedFunds] = useState(null);
132125 const [generalError, setGeneralError] = useState(null);
133126
134− const allPass = pass && !generalError;
135−
136127 const canInput = status === STATUS.INPUT;
137− const canGenerate = allPass && status === STATUS.INPUT;
138128 const canSend = status === STATUS.CAN_SEND;
139129 const isGenerating = status === STATUS.GENERATING;
140130 const isSending = status === STATUS.SENDING;
141131 const isFunding = status === STATUS.FUNDING;
142132 const isFailed = status === STATUS.FAILURE;
143133 const isDone = status === STATUS.SUCCESS;
134+
135+ const dynamicConfigs = useMemo(
136+ () =>
137+ inputConfigs.map(config => {
138+ config.disabled = !canInput;
139+ console.log(config.name, errors[config.name]);
140+ config.error = errors[config.name];
141+ return config;
142+ }),
143+ [inputConfigs, errors, canInput]
144+ );
145+ const { inputs, pass } = useForm(dynamicConfigs);
146+
144147 const canAddInvite = canInput && inputs.length < maxInvitesToSend;
148+ const allPass = pass && !generalError;
149+ const canGenerate = allPass && status === STATUS.INPUT;
145150
146151 const progress = isGenerating
147152 ? Object.keys(invites).length
@@ -211,7 +216,7 @@ export default function NewInviteEmail() {
211216 walletHdPath,
212217 networkType,
213218 // TODO: ^ make a useTransactionSigner to encapsulate this logic
214− txn: Just(inviteTx),
219+ txn: Maybe.Just(inviteTx),
215220 gasPrice: GAS_PRICE_GWEI.toString(),
216221 gasLimit: GAS_LIMIT.toString(),
217222 nonce: nonce + i,
@@ -230,7 +235,10 @@ export default function NewInviteEmail() {
230235
231236 if (errorCount > 0) {
232237 throw new Error(
233− `There were ${errorCount} errors while generating wallets.`
238+ `There ${pluralize(errorCount, 'was', 'were')} ${pluralize(
239+ errorCount,
240+ 'error'
241+ )} while generating wallets.`
234242 );
235243 }
236244 }, [
@@ -276,7 +284,7 @@ export default function NewInviteEmail() {
276284 try {
277285 const txHash = await sendSignedTransaction(
278286 _web3,
279− Just(invite.signedTx),
287+ Maybe.Just(invite.signedTx),
280288 tankWasUsed,
281289 () => {}
282290 );
@@ -288,7 +296,7 @@ export default function NewInviteEmail() {
288296 console.error(error);
289297 errorCount++;
290298 addError({
291− [input.name]: `Transaction Failure for ${invite.email}}`,
299+ [input.name]: `Transaction Failure for ${invite.email}`,
292300 });
293301 }
294302
@@ -308,7 +316,7 @@ export default function NewInviteEmail() {
308316 console.error(error);
309317 errorCount++;
310318 addError({
311− [input.name]: `Mailing Failure for ${invite.email}}`,
319+ [input.name]: `Mailing Failure for ${invite.email}`,
312320 });
313321 }
314322
@@ -319,7 +327,10 @@ export default function NewInviteEmail() {
319327 // if there are any receipt errors, throw a general error
320328 if (errorCount > 0) {
321329 throw new Error(
322− `There were ${errorCount} errors while sending transactions.`
330+ `There ${pluralize(errorCount, 'was', 'were')} ${pluralize(
331+ errorCount,
332+ 'error'
333+ )} while sending transactions.`
323334 );
324335 }
325336 }, [
@@ -368,7 +379,8 @@ export default function NewInviteEmail() {
368379 }, [canGenerate, canSend, onClickGenerate, onClickSend]);
369380
370381 useEffect(() => {
371− if (uniq(inputs.map(i => i.data)).length !== inputs.length) {
382+ const emails = inputs.map(i => i.data).filter(d => !!d);
383+ if (uniq(emails).length !== emails.length) {
372384 setGeneralError(new Error(`Duplicate email.`));
373385 } else {
374386 setGeneralError(null);
@@ -418,15 +430,14 @@ export default function NewInviteEmail() {
418430 key={input.name}
419431 as={Grid}
420432 gap={12}
421− onMouseEnter={setHovered(input.name, true)}
422− onMouseLeave={setHovered(input.name, false)}
433+ onMouseOver={() => setHovered({ [input.name]: true })}
434+ onMouseLeave={() => setHovered({ [input.name]: false })}
423435 full>
424436 <Grid.Item
425437 as={Input}
426438 cols={[1, 11]}
427439 {...input}
428440 accessory={accessoryFor(input.name)}
429− disabled={!canInput}
430441 />
431442 {!isFirst &&
432443 (input.focused || hovered[input.name]) &&
src/views/Point.js+2−2
@@ -48,9 +48,9 @@ export default function Point() {
4848 Boot Arvo
4949 </ForwardButton>
5050 </Grid.Item>
51− <Grid.Item full>
51+ {/* <Grid.Item full>
5252 <Actions />
53− </Grid.Item>
53+ </Grid.Item> */}
5454 </Grid>
5555
5656 <FooterButton onClick={goInvite}>