on master help sign in
feat: abstract basic mailer logic
commitb465a33d43836ec8589136da5260e76f7a525068 authorMatt Condon (shrugs) <mattgcondon@gmail.com> dateTue 25 Jun 2019, 18:24 (7 years ago) parent5c991af
2 files changed+57−11
src/lib/useMailer.js+44 src/views/Invite/InviteEmail.js+13−11
src/lib/useMailer.jsnew file+44
@@ -0,0 +1,44 @@
1+import { useCallback, useEffect } from 'react';
2+import Maybe from 'folktale/maybe';
3+
4+import { hasReceived, sendMail } from './inviteMail';
5+import useSetState from './useSetState';
6+
7+function useHasReceivedCache(emails = []) {
8+ const [cache, addToCache] = useSetState();
9+
10+ const getHasRecieved = useCallback(
11+ email => cache[email] || Maybe.Nothing(), //
12+ [cache]
13+ );
14+
15+ useEffect(() => {
16+ for (const email of emails) {
17+ if (Maybe.Just.hasInstance(getHasRecieved(email))) {
18+ // never update the cache after we know about it
19+ return;
20+ }
21+
22+ (async () => {
23+ addToCache({ [email]: await hasReceived(email) });
24+ })();
25+ }
26+ }, [emails, getHasRecieved, addToCache]);
27+
28+ return { getHasRecieved };
29+}
30+
31+export default function useMailer(emails) {
32+ const { getHasRecieved } = useHasReceivedCache(emails);
33+
34+ // prefix to avoid clobbering sendMail import
35+ const _sendMail = useCallback(async (email, ticket, rawTx) => {
36+ const mailSuccess = await sendMail(email, ticket, rawTx);
37+
38+ if (!mailSuccess) {
39+ throw new Error(`Internal mailing error when mailing ${email}`);
40+ }
41+ }, []);
42+
43+ return { getHasRecieved, sendMail: _sendMail };
44+}
src/views/Invite/InviteEmail.js+13−11
@@ -6,7 +6,6 @@ import { Grid, Flex, Input, IconButton, HelpText, Text } from 'indigo-react';
66import { uniq } from 'lodash';
77
88import * as need from 'lib/need';
9−import { hasReceived, sendMail } from 'lib/inviteMail';
109import * as wg from 'lib/walletgen';
1110
1211// for transaction generation and signing
@@ -35,6 +34,7 @@ import { usePointCache } from 'store/pointCache';
3534import { useWallet } from 'store/wallet';
3635import useSetState from 'lib/useSetState';
3736import pluralize from 'lib/pluralize';
37+import useMailer from 'lib/useMailer';
3838
3939const kStubMailer = process.env.REACT_APP_STUB_MAILER === 'true';
4040
@@ -89,10 +89,10 @@ const buildAccessoryFor = (dones, errors) => name => (
8989 </Flex>
9090);
9191
92−// TODO: refactor transactions + mailer into hooks
92+// TODO: how to handle dependency loop between inputConfigs and hasReceived?
93+// TODO: test with tank, successful txs
9394// TODO: put accessory inside of input
94−// TODO: implement hasReceived cache with useHasReceived
95−export default function NewInviteEmail() {
95+export default function InviteEmail() {
9696 // TODO: resumption after error?
9797 const { pop } = useLocalRouter();
9898 const { contracts, web3, networkType } = useNetwork();
@@ -115,10 +115,10 @@ export default function NewInviteEmail() {
115115 buildInputConfig
116116 );
117117
118− const [hovered, setHovered] = useSetState({});
119− const [invites, addInvite, clearInvites] = useSetState({});
120− const [receipts, addReceipt, clearReceipts] = useSetState({});
121− const [errors, addError, clearError] = useSetState({});
118+ const [hovered, setHovered] = useSetState();
119+ const [invites, addInvite, clearInvites] = useSetState();
120+ const [receipts, addReceipt, clearReceipts] = useSetState();
121+ const [errors, addError, clearError] = useSetState();
122122
123123 const [status, setStatus] = useState(STATUS.INPUT);
124124 const [needFunds, setNeedFunds] = useState(null);
@@ -136,13 +136,16 @@ export default function NewInviteEmail() {
136136 () =>
137137 inputConfigs.map(config => {
138138 config.disabled = !canInput;
139− console.log(config.name, errors[config.name]);
140139 config.error = errors[config.name];
141140 return config;
142141 }),
143142 [inputConfigs, errors, canInput]
144143 );
145144 const { inputs, pass } = useForm(dynamicConfigs);
145+ const emails = useMemo(() => inputs.map(i => i.data).filter(d => !!d), [
146+ inputs,
147+ ]);
148+ const { getHasRecieved, sendMail } = useMailer(emails);
146149
147150 const canAddInvite = canInput && inputs.length < maxInvitesToSend;
148151 const allPass = pass && !generalError;
@@ -379,13 +382,12 @@ export default function NewInviteEmail() {
379382 }, [canGenerate, canSend, onClickGenerate, onClickSend]);
380383
381384 useEffect(() => {
382− const emails = inputs.map(i => i.data).filter(d => !!d);
383385 if (uniq(emails).length !== emails.length) {
384386 setGeneralError(new Error(`Duplicate email.`));
385387 } else {
386388 setGeneralError(null);
387389 }
388− }, [inputs]);
390+ }, [emails]);
389391
390392 return (
391393 <Grid gap={12}>