@@ -101,7 +101,7 @@ export default function InviteEmail() {
101101 const { syncInvites, getInvites } = usePointCache();
102102 const { pointCursor } = usePointCursor();
103103 const point = need.point(pointCursor);
104− const { getHasRecieved, syncHasReceivedForEmail, sendMail } = useMailer();
104+ const { getHasReceived, syncHasReceivedForEmail, sendMail } = useMailer();
105105
106106 const { availableInvites } = getInvites(point);
107107 const maxInvitesToSend = availableInvites.matchWith({
@@ -142,14 +142,14 @@ export default function InviteEmail() {
142142 () =>
143143 inputConfigs.map(config => {
144144 config.disabled = !canInput;
145− const hasReceivedError = getHasRecieved(config.name).matchWith({
145+ const hasReceivedError = getHasReceived(config.name).matchWith({
146146 Nothing: () => null, // loading
147147 Just: p => p.value && HAS_RECEIVED_TEXT,
148148 });
149149 config.error = hasReceivedError || errors[config.name];
150150 return config;
151151 }),
152− [inputConfigs, errors, canInput, getHasRecieved]
152+ [inputConfigs, errors, canInput, getHasReceived]
153153 );
154154
155155 // construct the state of the set of inputs we're rendering below
@@ -187,6 +187,27 @@ export default function InviteEmail() {
187187 throw new Error('Internal Error: Missing Contracts/Web3/Wallet');
188188 }
189189
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+
190211 const nonce = await _web3.eth.getTransactionCount(_wallet.address);
191212 const chainId = await _web3.eth.net.getId();
192213 const planets = await azimuth.delegatedSending.getPlanetsToSend(
@@ -207,7 +228,6 @@ export default function InviteEmail() {
207228 );
208229 }
209230
210− let errorCount = 0;
211231 clearInvites();
212232 // NB(shrugs) - must be processed in serial because main thread, etc
213233 for (let i = 0; i < inputs.length; i++) {
@@ -318,12 +338,18 @@ export default function InviteEmail() {
318338 }
319339
320340 try {
321− await sendMail(invite.email, invite.ticket, invite.rawTx);
341+ const success = await sendMail(
342+ invite.email,
343+ invite.ticket,
344+ invite.rawTx
345+ );
346+ if (!success) throw new Error('Failed to send mail');
322347 } catch (error) {
323348 console.error(error);
324349 errorCount++;
350+ //TODO make sure this actually gets displayed
325351 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}`,
327353 });
328354 }
329355