on master help sign in
Merge pull request #188 from urbit/email-fixes
b18b8edFang
src/components/old/StatelessTransaction.js+2−1
@@ -8,6 +8,7 @@ import { Button } from './Base';
8import { CheckboxButton, Input, InnerLabel, InnerLabelDropdown } from './Base';
8import { CheckboxButton, Input, InnerLabel, InnerLabelDropdown } from './Base';
9import { Warning } from './Base';
9import { Warning } from './Base';
10
10
11+import { GAS_LIMITS } from '../../lib/constants';
11import { BRIDGE_ERROR } from '../../lib/error';
12import { BRIDGE_ERROR } from '../../lib/error';
12import { ROUTE_NAMES } from '../../lib/routeNames';
13import { ROUTE_NAMES } from '../../lib/routeNames';
13import { compose } from '../../lib/lib';
14import { compose } from '../../lib/lib';
@@ -40,7 +41,7 @@ class StatelessTransaction extends React.Component {
40
41
41 this.state = {
42 this.state = {
42 gasPrice: '5',
43 gasPrice: '5',
43− gasLimit: '600000',
44+ gasLimit: GAS_LIMITS.DEFAULT.toString(),
44 showGasDetails: false,
45 showGasDetails: false,
45 userApproval: false,
46 userApproval: false,
46 chainId: '1',
47 chainId: '1',
src/indigo-react/index.js+1
@@ -2,6 +2,7 @@ export { default as IndigoApp } from './components/IndigoApp';
2export { default as Grid } from './components/Grid';
2export { default as Grid } from './components/Grid';
3export { default as Flex } from './components/Flex';
3export { default as Flex } from './components/Flex';
4export { default as Input } from './components/Input';
4export { default as Input } from './components/Input';
5+export { default as SelectInput } from './components/SelectInput';
5export { default as CheckboxInput } from './components/CheckboxInput';
6export { default as CheckboxInput } from './components/CheckboxInput';
6export { default as AccessoryIcon } from './components/AccessoryIcon';
7export { default as AccessoryIcon } from './components/AccessoryIcon';
7export { default as Button } from './components/Button';
8export { default as Button } from './components/Button';
src/lib/useMailer.js+6−10
@@ -9,14 +9,14 @@ const STUB_MAILER = process.env.REACT_APP_STUB_MAILER === 'true';
9function useHasReceivedCache() {
9function useHasReceivedCache() {
10 const [cache, addToCache] = useSetState();
10 const [cache, addToCache] = useSetState();
11
11
12− const getHasRecieved = useCallback(
12+ const getHasReceived = useCallback(
13 email => cache[email] || Nothing(), //
13 email => cache[email] || Nothing(), //
14 [cache]
14 [cache]
15 );
15 );
16
16
17 const syncHasReceivedForEmail = useCallback(
17 const syncHasReceivedForEmail = useCallback(
18 async email => {
18 async email => {
19− if (Just.hasInstance(getHasRecieved(email))) {
19+ if (Just.hasInstance(getHasReceived(email))) {
20 // never update the cache after we know about it
20 // never update the cache after we know about it
21 return;
21 return;
22 }
22 }
@@ -29,10 +29,10 @@ function useHasReceivedCache() {
29 const _hasReceived = await hasReceived(email);
29 const _hasReceived = await hasReceived(email);
30 addToCache({ [email]: Just(_hasReceived) });
30 addToCache({ [email]: Just(_hasReceived) });
31 },
31 },
32− [getHasRecieved, addToCache]
32+ [getHasReceived, addToCache]
33 );
33 );
34
34
35− return { getHasRecieved, syncHasReceivedForEmail };
35+ return { getHasReceived, syncHasReceivedForEmail };
36}
36}
37
37
38export default function useMailer(emails) {
38export default function useMailer(emails) {
@@ -43,14 +43,10 @@ export default function useMailer(emails) {
43 const _sendMail = useCallback(async (email, ticket, rawTx) => {
43 const _sendMail = useCallback(async (email, ticket, rawTx) => {
44 if (STUB_MAILER) {
44 if (STUB_MAILER) {
45 console.log(`${email} - ${ticket}`);
45 console.log(`${email} - ${ticket}`);
46− return;
46+ return true;
47 }
47 }
48
48
49− const mailSuccess = await sendMail(email, ticket, rawTx);
49+ return await sendMail(email, ticket, rawTx);
50−
51− if (!mailSuccess) {
52− throw new Error(`Internal mailing error when mailing ${email}`);
53− }
54 }, []);
50 }, []);
55
51
56 return { ...hasReceivedCache, sendMail: _sendMail };
52 return { ...hasReceivedCache, sendMail: _sendMail };
src/views/Invite/InviteEmail.js+32−6
@@ -101,7 +101,7 @@ export default function InviteEmail() {
101 const { syncInvites, getInvites } = usePointCache();
101 const { syncInvites, getInvites } = usePointCache();
102 const { pointCursor } = usePointCursor();
102 const { pointCursor } = usePointCursor();
103 const point = need.point(pointCursor);
103 const point = need.point(pointCursor);
104− const { getHasRecieved, syncHasReceivedForEmail, sendMail } = useMailer();
104+ const { getHasReceived, syncHasReceivedForEmail, sendMail } = useMailer();
105
105
106 const { availableInvites } = getInvites(point);
106 const { availableInvites } = getInvites(point);
107 const maxInvitesToSend = availableInvites.matchWith({
107 const maxInvitesToSend = availableInvites.matchWith({
@@ -142,14 +142,14 @@ export default function InviteEmail() {
142 () =>
142 () =>
143 inputConfigs.map(config => {
143 inputConfigs.map(config => {
144 config.disabled = !canInput;
144 config.disabled = !canInput;
145− const hasReceivedError = getHasRecieved(config.name).matchWith({
145+ const hasReceivedError = getHasReceived(config.name).matchWith({
146 Nothing: () => null, // loading
146 Nothing: () => null, // loading
147 Just: p => p.value && HAS_RECEIVED_TEXT,
147 Just: p => p.value && HAS_RECEIVED_TEXT,
148 });
148 });
149 config.error = hasReceivedError || errors[config.name];
149 config.error = hasReceivedError || errors[config.name];
150 return config;
150 return config;
151 }),
151 }),
152− [inputConfigs, errors, canInput, getHasRecieved]
152+ [inputConfigs, errors, canInput, getHasReceived]
153 );
153 );
154
154
155 // construct the state of the set of inputs we're rendering below
155 // construct the state of the set of inputs we're rendering below
@@ -187,6 +187,27 @@ export default function InviteEmail() {
187 throw new Error('Internal Error: Missing Contracts/Web3/Wallet');
187 throw new Error('Internal Error: Missing Contracts/Web3/Wallet');
188 }
188 }
189
189
190+ //TODO want to do this on-input, but that gets weird. see #188
191+ let errorCount = 0;
192+ await Promise.all(
193+ inputs.map(async input => {
194+ const email = input.data;
195+ const hasReceived = getHasReceived(email).matchWith({
196+ Nothing: () => false, // loading
197+ Just: p => p.value,
198+ });
199+ if (hasReceived) {
200+ errorCount++;
201+ addError({
202+ [input.name]: `${email} has already received an invite.`,
203+ });
204+ }
205+ })
206+ );
207+ if (errorCount > 0) {
208+ throw new Error(`Some of these already have a point!`);
209+ }
210+
190 const nonce = await _web3.eth.getTransactionCount(_wallet.address);
211 const nonce = await _web3.eth.getTransactionCount(_wallet.address);
191 const chainId = await _web3.eth.net.getId();
212 const chainId = await _web3.eth.net.getId();
192 const planets = await azimuth.delegatedSending.getPlanetsToSend(
213 const planets = await azimuth.delegatedSending.getPlanetsToSend(
@@ -207,7 +228,6 @@ export default function InviteEmail() {
207 );
228 );
208 }
229 }
209
230
210− let errorCount = 0;
211 clearInvites();
231 clearInvites();
212 // NB(shrugs) - must be processed in serial because main thread, etc
232 // NB(shrugs) - must be processed in serial because main thread, etc
213 for (let i = 0; i < inputs.length; i++) {
233 for (let i = 0; i < inputs.length; i++) {
@@ -318,12 +338,18 @@ export default function InviteEmail() {
318 }
338 }
319
339
320 try {
340 try {
341+ const success = await sendMail(
342+ invite.email,
321− await sendMail(invite.email, invite.ticket, invite.rawTx);
343+ invite.ticket,
344+ invite.rawTx
345+ );
346+ if (!success) throw new Error('Failed to send mail');
322 } catch (error) {
347 } catch (error) {
323 console.error(error);
348 console.error(error);
324 errorCount++;
349 errorCount++;
350+ //TODO make sure this actually gets displayed
325 addError({
351 addError({
326− [input.name]: `Mailing Failure for ${invite.email}`,
352+ [input.name]: `Mailing Failure for ${invite.email}, please send them this code manually: ${invite.ticket}`,
327 });
353 });
328 }
354 }
329
355