on master help sign in
feat: implement progress button for InviteEmail
4bfa4f1Matt Condon (shrugs)
src/components/InlineEthereumTransaction.js+2−1
@@ -111,7 +111,8 @@ export default function InlineEthereumTransaction({
111 <Grid.Item
111 <Grid.Item
112 full
112 full
113 as={ProgressButton}
113 as={ProgressButton}
114+ success
114− disabled={true}
115+ disabled
115 progress={confirmationProgress}>
116 progress={confirmationProgress}>
116 Sending Transaction
117 Sending Transaction
117 </Grid.Item>
118 </Grid.Item>
src/components/ProgressButton.js−2
@@ -7,14 +7,12 @@ export default function ProgressButton({
7 as: As = Button,
7 as: As = Button,
8 progress = 0.0,
8 progress = 0.0,
9 color = 'green4',
9 color = 'green4',
10− success = true,
11 ...rest
10 ...rest
12}) {
11}) {
13 return (
12 return (
14 <As
13 <As
15 {...rest}
14 {...rest}
16 solid
15 solid
17− success={success}
18 accessory={blinkIf(progress < 1.0, '->')}
16 accessory={blinkIf(progress < 1.0, '->')}
19 background={
17 background={
20 <span
18 <span
src/lib/useMailer.js+1
@@ -29,6 +29,7 @@ export default function useMailer() {
29 const _sendMail = useCallback(async (email, ticket, sender, rawTx) => {
29 const _sendMail = useCallback(async (email, ticket, sender, rawTx) => {
30 if (STUB_MAILER) {
30 if (STUB_MAILER) {
31 console.log(`${email} - ${ticket}`);
31 console.log(`${email} - ${ticket}`);
32+ await timeout(Math.random() * 1000); // simulate request with randomness
32 return true;
33 return true;
33 }
34 }
34
35
src/views/Invite/InviteEmail.js+77−25
@@ -57,6 +57,8 @@ import SubmitButton from 'form/SubmitButton';
57import FormError from 'form/FormError';
57import FormError from 'form/FormError';
58import { WARNING, onlyHasWarning } from 'form/helpers';
58import { WARNING, onlyHasWarning } from 'form/helpers';
59import useGasPrice from 'lib/useGasPrice';
59import useGasPrice from 'lib/useGasPrice';
60+import timeout from 'lib/timeout';
61+import { ForwardButton } from 'components/Buttons';
60
62
61const INITIAL_VALUES = { emails: [''] };
63const INITIAL_VALUES = { emails: [''] };
62
64
@@ -129,8 +131,8 @@ export default function InviteEmail() {
129
131
130 // derive booleans from status
132 // derive booleans from status
131 const canInput = status === STATUS.INPUT;
133 const canInput = status === STATUS.INPUT;
132− const canSend = status === STATUS.CAN_SEND;
133 const isGenerating = status === STATUS.GENERATING;
134 const isGenerating = status === STATUS.GENERATING;
135+ const canSend = status === STATUS.CAN_SEND;
134 const isSending = status === STATUS.SENDING;
136 const isSending = status === STATUS.SENDING;
135 const isFailed = status === STATUS.FAILURE;
137 const isFailed = status === STATUS.FAILURE;
136 const isDone = status === STATUS.SUCCESS;
138 const isDone = status === STATUS.SUCCESS;
@@ -174,6 +176,10 @@ export default function InviteEmail() {
174 : isSending
176 : isSending
175 ? Object.keys(receipts).length
177 ? Object.keys(receipts).length
176 : null;
178 : null;
179+ const percentProgress =
180+ progress !== null
181+ ? progress / Object.keys(cachedEmails.current).length
182+ : null;
177 const visualProgress = progress === null ? '-' : `${progress + 1}`;
183 const visualProgress = progress === null ? '-' : `${progress + 1}`;
178
184
179 // build a builder for the accessory to the input, depending on status
185 // build a builder for the accessory to the input, depending on status
@@ -245,8 +251,8 @@ export default function InviteEmail() {
245 nonce: nonce + i,
251 nonce: nonce + i,
246 // TODO: ^ make a useTransactionSigner to encapsulate this logic
252 // TODO: ^ make a useTransactionSigner to encapsulate this logic
247 txn: inviteTx,
253 txn: inviteTx,
248− gasPrice: gasPrice.toString(), // expects string gwei
254+ gasPrice: gasPrice.toFixed(), // expects string gwei
249− gasLimit: GAS_LIMIT.toString(),
255+ gasLimit: GAS_LIMIT.toFixed(),
250 });
256 });
251
257
252 const rawTx = hexify(signedTx.serialize());
258 const rawTx = hexify(signedTx.serialize());
@@ -302,7 +308,7 @@ export default function InviteEmail() {
302 _web3,
308 _web3,
303 point,
309 point,
304 _wallet.address,
310 _wallet.address,
305− toWei((gasPrice * GAS_LIMIT * emails.length).toString(), 'gwei'),
311+ toWei((gasPrice * GAS_LIMIT * emails.length).toFixed(), 'gwei'),
306 names.map(name => invites[name].rawTx),
312 names.map(name => invites[name].rawTx),
307 (address, minBalance, balance) =>
313 (address, minBalance, balance) =>
308 setNeedFunds({ address, minBalance, balance }),
314 setNeedFunds({ address, minBalance, balance }),
@@ -393,6 +399,8 @@ export default function InviteEmail() {
393 return errors;
399 return errors;
394 }
400 }
395
401
402+ await timeout(500); // wait for progress animation to complete.
403+
396 setStatus(STATUS.CAN_SEND);
404 setStatus(STATUS.CAN_SEND);
397 },
405 },
398 [generateInvites]
406 [generateInvites]
@@ -419,6 +427,70 @@ export default function InviteEmail() {
419 }
427 }
420 }, [isDone, syncInvites, point]);
428 }, [isDone, syncInvites, point]);
421
429
430+ const renderButton = ({ handleSubmit, fields }) => {
431+ if (canInput) {
432+ return (
433+ <Grid.Item
434+ full
435+ as={SubmitButton}
436+ handleSubmit={handleSubmit}
437+ accessory={`${visualProgress}/${fields.length}`}>
438+ {buttonText(status, fields.length)}
439+ </Grid.Item>
440+ );
441+ }
442+
443+ if (isGenerating) {
444+ return (
445+ <Grid.Item
446+ full
447+ as={ProgressButton}
448+ solid
449+ disabled
450+ className="mt4"
451+ accessory={`${visualProgress}/${fields.length}`}
452+ progress={percentProgress}
453+ color="black">
454+ {buttonText(status, fields.length)}
455+ </Grid.Item>
456+ );
457+ }
458+
459+ if (canSend) {
460+ return (
461+ <Grid.Item
462+ full
463+ as={ForwardButton}
464+ className="mt4"
465+ solid
466+ success
467+ accessory={`${visualProgress}/${fields.length}`}
468+ onClick={doSend}>
469+ {buttonText(status, fields.length)}
470+ </Grid.Item>
471+ );
472+ }
473+
474+ if (isSending) {
475+ return (
476+ <Grid.Item
477+ full
478+ as={ProgressButton}
479+ className="mt4"
480+ solid
481+ success
482+ disabled
483+ accessory={`${visualProgress}/${fields.length}`}
484+ progress={percentProgress}
485+ color={isGenerating ? 'black' : 'green4'}>
486+ {buttonText(status, fields.length)}
487+ </Grid.Item>
488+ );
489+ }
490+
491+ return null;
492+ };
493+
422 return (
494 return (
423 <Grid gap={3}>
495 <Grid gap={3}>
424 <BridgeForm
496 <BridgeForm
@@ -507,27 +579,7 @@ export default function InviteEmail() {
507 );
579 );
508 })}
580 })}
509
581
510− {canInput ? (
511− <Grid.Item
512− full
513− as={SubmitButton}
514− handleSubmit={handleSubmit}
582+ {renderButton({ handleSubmit, fields })}
515− accessory={`${visualProgress}/${fields.length}`}>
516− {buttonText(status, fields.length)}
517− </Grid.Item>
518− ) : (
519− <Grid.Item
520− full
521− as={ProgressButton}
522− className="mt4"
523− disabled={!canSend}
524− accessory={`${visualProgress}/${fields.length}`}
525− onClick={doSend}
526− success={canSend}
527− solid>
528− {buttonText(status, fields.length)}
529− </Grid.Item>
530− )}
531
583
532 {needFunds && (
584 {needFunds && (
533 <Grid.Item full>
585 <Grid.Item full>