on master help sign in
Merge branch 'mino-transactions-emails' into mino-send-invites
commit66956f375d74932b23f21762fd6ed3257bcfb6fe authorFang <git@fang.io> dateFri 31 May 2019, 15:45 (7 years ago) parent696403ad587c96
2 files changed+84−25
src/bridge/lib/inviteMail.js+21−4 src/bridge/views/InvitesSend.js+63−21
src/bridge/lib/inviteMail.js+21−4
@@ -4,22 +4,39 @@
44// https://stackoverflow.com/a/53011185/1334324
55const baseUrl = 'https://localhost:3002'
66
7−function sendMail(recipient, ticket) {
7+function sendRequest(where, what) {
88 return new Promise((resolve, reject) => {
9− fetch(baseUrl + '/send-ticket', {
9+ fetch(baseUrl + where, {
1010 method: 'POST',
1111 cache: 'no-cache',
1212 headers: {
1313 'Content-Type': 'application/json'
1414 },
15− body: JSON.stringify({recipient,ticket}),
15+ body: JSON.stringify(what)
16+ })
17+ .then(response => {
18+ if (response.ok) {
19+ resolve(response.json());
20+ } else {
21+ reject(response);
22+ }
1623 })
17− .then(response => resolve(response.ok))
1824 .catch(reject);
1925 });
2026}
2127
28+async function hasReceived(recipient) {
29+ const res = await sendRequest('/has-received', {recipient});
30+ console.log('got fetch result', res);
31+ return res.hasReceived;
32+}
33+
34+function sendMail(recipient, ticket, tx) {
35+ return sendRequest('/send-ticket', {recipient,ticket,tx});
36+}
37+
2238export {
39+ hasReceived,
2340 sendMail
2441}
2542
src/bridge/views/InvitesSend.js+63−21
@@ -4,13 +4,26 @@ import * as ob from 'urbit-ob'
44import * as azimuth from 'azimuth-js'
55
66import { BRIDGE_ERROR } from '../lib/error'
7−import { sendMail } from '../lib/inviteMail'
8−import { Row, Col, Input, InnerLabel } from '../components/Base'
7+import { hasReceived, sendMail } from '../lib/inviteMail'
8+import { Row, Col, Warning, Button, H1, H3,
9+ Input, InnerLabel
10+} from '../components/Base'
911import StatelessTransaction from '../components/StatelessTransaction'
1012
1113// for wallet generation
1214import * as wg from '../../walletgen/lib/lib'
1315
16+// for transaction generation and signing
17+import {
18+ signTransaction,
19+ sendSignedTransaction,
20+ waitForTransactionConfirm,
21+ isTransactionConfirmed,
22+ hexify
23+} from '../lib/txn'
24+import * as tank from '../lib/tank'
25+import Tx from 'ethereumjs-tx'
26+
1427class InvitesSend extends React.Component {
1528
1629 constructor(props) {
@@ -22,7 +35,8 @@ class InvitesSend extends React.Component {
2235 haveInvited: Nothing(),
2336 randomPlanet: Nothing(),
2437 inviteWallet: Nothing(),
25− targetEmail: ''
38+ targetEmail: '',
39+ targetHasReceived: Nothing()
2640 }
2741
2842 this.findInvited = this.findInvited.bind(this);
@@ -30,8 +44,8 @@ class InvitesSend extends React.Component {
3044 this.generateWallet = this.generateWallet.bind(this);
3145 this.canGenerate = this.canGenerate.bind(this);
3246 this.handleEmailInput = this.handleEmailInput.bind(this);
33− this.txnConfirmation = this.txnConfirmation.bind(this);
3447 this.createUnsignedTxn = this.createUnsignedTxn.bind(this);
48+ this.beforeSend = this.beforeSend.bind(this);
3549 }
3650
3751 componentDidMount() {
@@ -102,19 +116,33 @@ class InvitesSend extends React.Component {
102116 }
103117
104118 handleEmailInput(email) {
105− //TODO simple .*@.*\..* email validation
106− this.setState({ targetEmail: email });
119+ let newState = { targetEmail: email };
120+ if (email.match(/.*@.*\...+/)) {
121+ hasReceived(email)
122+ .then(res => {
123+ console.log('hasReceived', res);
124+ this.setState({ targetHasReceived: Just(res) });
125+ });
126+ } else {
127+ newState.targetHasReceived = Nothing();
128+ }
129+ this.setState(newState);
107130 }
108131
109132 canGenerate() {
110133 //TODO and canSend()
111− let res = this.state.invitesAvailable.matchWith({
134+ let invites = this.state.invitesAvailable.matchWith({
112135 Nothing: () => false,
113− Just: invites => ((invites.value > 0)
114− && Just.hasInstance(this.state.randomPlanet)
115− && Just.hasInstance(this.state.inviteWallet))
136+ Just: invites => (invites.value > 0)
116137 });
117− return res;
138+ let alreadyGotInvited = this.state.targetHasReceived.matchWith({
139+ Nothing: () => false,
140+ Just: has => has.value
141+ });
142+ return invites
143+ && !alreadyGotInvited
144+ && Just.hasInstance(this.state.randomPlanet)
145+ && Just.hasInstance(this.state.inviteWallet);
118146 }
119147
120148 createUnsignedTxn() {
@@ -127,15 +155,13 @@ class InvitesSend extends React.Component {
127155 return Just(txn)
128156 }
129157
130− //TODO find a better way of making the user wait for submission success
131− // and email sending, so that we can catch failure cases and can
132− // always fall back to retrying or "please send them this"
133− txnConfirmation(txHash, confirmations) {
134− this.props.setTxnConfirmations(txHash, confirmations);
135− if (confirmations === 1) {
136− sendMail(this.state.targetEmail, this.state.inviteWallet.value.ticket)
137− .then(console.log);
138− }
158+ async beforeSend(stx) {
159+ const rawTx = hexify(stx.serialize());
160+ return await sendMail(
161+ this.state.targetEmail,
162+ this.state.inviteWallet.value.ticket,
163+ rawTx
164+ );
139165 }
140166
141167 render() {
@@ -163,6 +189,19 @@ class InvitesSend extends React.Component {
163189 })
164190 });
165191
192+ const recipientWarning = this.state.targetHasReceived.matchWith({
193+ Nothing: () => null,
194+ Just: hasReceived => {
195+ if (!hasReceived.value) return null;
196+ return (
197+ <Warning>
198+ <h3 className={'mb-2'}>{'Warning'}</h3>
199+ { 'That email address has already received an invite!' }
200+ </Warning>
201+ );
202+ }
203+ });
204+
166205 return (
167206 <Row>
168207 <Col>
@@ -181,6 +220,8 @@ class InvitesSend extends React.Component {
181220 </InnerLabel>
182221 </Input>
183222
223+ { recipientWarning }
224+
184225 <StatelessTransaction
185226 // Upper scope
186227 web3={this.props.web3}
@@ -189,8 +230,9 @@ class InvitesSend extends React.Component {
189230 walletType={this.props.walletType}
190231 walletHdPath={this.props.walletHdPath}
191232 networkType={this.props.networkType}
192− setTxnConfirmations={this.txnConfirmation}
233+ beforeSend={this.beforeSend}
193234 onSent={this.props.setTxnHashCursor}
235+ setTxnConfirmations={this.props.setTxnConfirmations}
194236 popRoute={this.props.popRoute}
195237 pushRoute={this.props.pushRoute}
196238 // Other