1import React, { useState, useCallback, useMemo } from 'react';
2import { Grid } from 'indigo-react';
3import { FORM_ERROR } from 'final-form';
4import * as ob from 'urbit-ob';
5import { uniq, zip, compact, isEqual } from 'lodash';
7import { usePointCursor } from 'store/pointCursor';
9import * as need from 'lib/need';
10import useMailer from 'lib/useMailer';
11import pluralize from 'lib/pluralize';
12import useInviter from 'lib/useInviter';
19} from 'form/validators';
20import EmailChipInput from 'form/EmailChipInput';
21import FormError from 'form/FormError';
22import SubmitButton from 'form/SubmitButton';
23import BridgeForm from 'form/BridgeForm';
25import NeedFundsNotice from 'components/NeedFundsNotice';
26import ProgressButton from 'components/ProgressButton';
28const HAS_RECEIVED_TEXT = 'This email has already received an invite.';
37const InviteMail = ({ setSubmitting }) => {
38 const { progress, txStatus, needFunds, generateInvites } = useInviter();
40 const { sendMail, getHasReceived } = useMailer();
42 const [status, setStatus] = useState(STATUS.INPUT);
44 const [count, setCount] = useState(0);
45 const canInput = status === STATUS.INPUT;
46 const isSending = txStatus === STATUS.SENDING || status === STATUS.SENDING;
47 const isDone = status === STATUS.SUCCESS;
48 const isFailed = status === STATUS.FAILED;
50 const { pointCursor } = usePointCursor();
51 const point = need.point(pointCursor);
53 const sendInvites = useCallback(
54 async (emails, invites) => {
55 const mailingErrors = compact(
57 zip(emails, invites).map(([email, invite]) =>
58 sendMail(email, invite.ticket, ob.patp(point), '', invite.rawTx)
61 () => `Sending ticket ${invite.ticket} to ${email} failed.`
66 if (mailingErrors.length) {
67 return { [FORM_ERROR]: mailingErrors };
73 const onSubmit = useCallback(
75 const emailCount = values.emails.length;
77 setStatus(STATUS.SENDING);
79 const { errors, invites } = await generateInvites(emailCount);
81 setStatus(STATUS.FAILED);
85 const mailErrors = await sendInvites(values.emails, invites);
87 console.log(mailErrors);
88 setStatus(STATUS.FAILED);
93 setStatus(STATUS.SUCCESS);
95 [generateInvites, setCount, setStatus, sendInvites]
98 const validateHasReceived = useCallback(
100 const hasReceived = await getHasReceived(email);
102 return HAS_RECEIVED_TEXT;
108 const buttonText = useCallback(() => {
111 return 'Add to Invite Group';
113 return `Sending ${pluralize(count, 'Invite')}...`;
115 return `✓ ${pluralize(count, 'Invite')} sent`;
122 const renderButton = useCallback(
126 <Grid.Item full as={SubmitButton} handleSubmit={handleSubmit}>
133 const percentProgress = progress / count;
142 progress={percentProgress}>
149 <Grid.Item full className="mt4 p3 bg-green3 white f5">
156 <Grid.Item full className="mt4 p3 bg-red3 white f5">
164 [buttonText, isDone, isFailed, isSending, canInput, count, progress]
167 const validateForm = useCallback((values, errors) => {
168 if (hasErrors(errors)) {
172 // check for email uniqenesss
173 const emails = values.emails.filter(d => !!d);
174 if (uniq(emails).length !== emails.length) {
175 return { [FORM_ERROR]: 'Duplicate email.' };
179 const validate = useMemo(
183 emails: buildArrayValidator(buildEmailValidator(validateHasReceived)),
187 [validateHasReceived, validateForm]
190 const initialValues = { emails: [] };
192 <Grid.Item full as={Grid}>
195 initialValues={initialValues}
196 initialValuesEqual={isEqual}
198 {({ handleSubmit, values }) => (
200 <Grid.Item full as={EmailChipInput} name="emails" className="mt4" />
201 {renderButton(handleSubmit)}
203 <Grid.Item full as={FormError} />
205 <Grid.Item full as={NeedFundsNotice} {...needFunds} />
214export default InviteMail;
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list