@@ -0,0 +1,226 @@
1+import { Just, Nothing } from 'folktale/maybe'
2+import React from 'react'
3+import { pour } from 'sigil-js'
4+import * as ob from 'urbit-ob'
5+import * as azimuth from 'azimuth-js'
6+
7+import { addressFromSecp256k1Public, EthereumWallet } from '../lib/wallet'
8+import { ROUTE_NAMES } from '../lib/router'
9+
10+import PointList from '../components/PointList'
11+import ReactSVGComponents from '../components/ReactSVGComponents'
12+import KeysAndMetadata from './Point/KeysAndMetadata'
13+import Actions from './Point/Actions'
14+import { BRIDGE_ERROR } from '../lib/error'
15+import { Row, Col, Warning, Button, H1, H3 } from '../components/Base'
16+
17+// for wallet generation
18+import * as wg from '../../walletgen/lib/lib'
19+import PaperCollateralRenderer from 'PaperCollateralRenderer'
20+import JSZip from 'jszip'
21+import saveAs from 'file-saver'
22+
23+class InviteWallet extends React.Component {
24+
25+ constructor(props) {
26+ super(props)
27+
28+ this.state = {
29+ loaded: false,
30+ point: Nothing(),
31+ wallet: Nothing(),
32+ paper: Nothing(),
33+ downloaded: false
34+ }
35+
36+ this.download = this.download.bind(this)
37+ this.proceed = this.proceed.bind(this)
38+ }
39+
40+ componentDidMount() {
41+ const { web3, wallet, contracts, setPointCursor } = this.props
42+
43+ web3.chain(_ =>
44+ contracts.chain(ctrcs =>
45+ wallet.chain(async wal => {
46+ const addr = addressFromSecp256k1Public(wal.publicKey);
47+ console.log('fetching incoming for', addr)
48+ const incoming = await azimuth.azimuth.getTransferringFor(ctrcs, addr)
49+ console.log('incoming', incoming)
50+
51+ let point = Nothing();
52+ if (incoming.length > 0) {
53+ let pointNum = parseInt(incoming[0]);
54+ point = Just(pointNum);
55+ this.generateWallet(pointNum);
56+ if (incoming.length > 1) {
57+ //TODO notify user "...and others / ticket reusable"
58+ }
59+ }
60+ this.setState({loaded: true, point: point})
61+ })))
62+ }
63+
64+ componentDidUpdate(prevProps) {
65+ //
66+ }
67+
68+ async generateWallet(point) {
69+ const ticket = await wg.makeTicket(point);
70+ const wallet = await wg.generateWallet(point, ticket);
71+ this.setState({ wallet: Just(wallet) });
72+ }
73+
74+ download() {
75+ const zip = new JSZip();
76+ //TODO the categories here aren't explained in bridge at all...
77+
78+ const bin0 = this.state.paper.filter(item => item.bin === '0');
79+ const bin1 = this.state.paper.filter(item => item.bin === '1');
80+ const bin2 = this.state.paper.filter(item => item.bin === '2');
81+ const bin3 = this.state.paper.filter(item => item.bin === '3');
82+ const bin4 = this.state.paper.filter(item => item.bin === '4');
83+
84+ const bin0Folder = zip.folder("0. Public");
85+ const bin1Folder = zip.folder("1. Very High Friction Custody");
86+ const bin2Folder = zip.folder("2. High Friction Custody");
87+ const bin3Folder = zip.folder("3. Medium Friction Custody");
88+ const bin4Folder = zip.folder("4. Low Friction Custody");
89+
90+ bin0.forEach(item => bin0Folder.file(`${item.pageTitle}.png`, item.png))
91+ bin1.forEach(item => bin1Folder.file(`${item.pageTitle}.png`, item.png));
92+ bin2.forEach(item => bin2Folder.file(`${item.pageTitle}.png`, item.png));
93+ bin3.forEach(item => bin3Folder.file(`${item.pageTitle}.png`, item.png));
94+ bin4.forEach(item => bin4Folder.file(`${item.pageTitle}.png`, item.png));
95+
96+ zip.generateAsync({type:"blob"}).then((content) => {
97+ saveAs(content, 'urbit-wallet.zip');
98+ this.setState({ downloaded: true });
99+ });
100+ }
101+
102+ proceed() {
103+ this.props.pushRoute(ROUTE_NAMES.INVITE_VERIFY, {
104+ ticket: this.state.wallet.value.ticket,
105+ point: parseInt(this.state.point.value)
106+ });
107+ }
108+
109+ render() {
110+
111+ const { loaded, point, wallet, paper, downloaded } = this.state;
112+
113+ let loading;
114+ if (!loaded) {
115+ loading = ( <div>{ 'Loading...' }</div> );
116+ }
117+
118+ let balanceWarning;
119+ if (loaded && Nothing.hasInstance(point)) {
120+ balanceWarning = (
121+ <Warning>
122+ <h3 className={'mb-2'}>{'Warning'}</h3>
123+ {
124+ 'This invite has no claimable balance.'
125+ }
126+ </Warning>
127+ );
128+ }
129+
130+ let pointOverview;
131+ if (loaded && Just.hasInstance(point)) {
132+ const name = ob.patp(point.value);
133+ const sigil = pour({
134+ patp: name,
135+ renderer: ReactSVGComponents,
136+ size: 256
137+ });
138+ pointOverview = (
139+ //TODO Passport display component
140+ <>
141+ <div className={'mt-12 pt-6'}>
142+ { sigil }
143+ </div>
144+ <H3><code>{ name }</code></H3>
145+ </>
146+ );
147+ }
148+
149+ let downloadButtonContents = 'Download wallet';
150+ if ( Nothing.hasInstance(this.state.wallet) ||
151+ Nothing.hasInstance(this.state.paper) ) {
152+ downloadButtonContents = (
153+ <>
154+ <span className="btn-spinner"></span>
155+ {'Generating wallet...'}
156+ </>
157+ );
158+ }
159+
160+ let downloadButton;
161+ let nextButton;
162+ if (loaded) {
163+ downloadButton = (
164+ <Button
165+ className={'mt-8'}
166+ prop-size={'lg wide'}
167+ disabled={( Nothing.hasInstance(this.state.wallet) ||
168+ Nothing.hasInstance(this.state.paper) )}
169+ onClick={this.download}
170+ >
171+ <span className="relative">
172+ { downloadButtonContents }
173+ </span>
174+ </Button>
175+ );
176+
177+ nextButton = (
178+ <Button
179+ className={'mt-8'}
180+ prop-size={'lg wide'}
181+ disabled={!this.state.downloaded}
182+ onClick={this.proceed}
183+ >
184+ {'Proceed'}
185+ </Button>
186+ );
187+ }
188+
189+ let paperRenderer;
190+ if ( Just.hasInstance(this.state.wallet) &&
191+ Nothing.hasInstance(this.state.paper) ) {
192+ console.log('rendering for', point.value)
193+ paperRenderer = (
194+ <PaperCollateralRenderer
195+ wallet={{[point.value]: wallet.value}}
196+ className={'extremely-hidden'}
197+ callback={data => {
198+ console.log('got paper', data);
199+ this.setState({isRendering: false, paper: data})
200+ }}
201+ mode={'REGISTRATION'} />
202+ );
203+ }
204+
205+ return (
206+ <Row>
207+ <Col>
208+
209+ { loading }
210+ { balanceWarning }
211+ { pointOverview }
212+
213+ <p>{'TODO copy. you need a wallet to receive the point into. download it below. also explanation of wallet files/storage'}</p>
214+
215+ { downloadButton }
216+ { nextButton }
217+
218+ { paperRenderer }
219+
220+ </Col>
221+ </Row>
222+ )
223+ }
224+}
225+
226+export default InviteWallet