on master help sign in
- More styling touches on invite flow
1ec514bChris Johnson
src/bridge/components/Passport.js+45−44
@@ -6,6 +6,7 @@ import PropTypes from 'prop-types'
6import PaperCollateralRenderer from 'PaperCollateralRenderer'
6import PaperCollateralRenderer from 'PaperCollateralRenderer'
7import { Button } from './Base'
7import { Button } from './Base'
8
8
9+import { WALLET_STATES } from '../lib/invite'
9import { downloadWallet } from '../lib/invite'
10import { downloadWallet } from '../lib/invite'
10
11
11class Passport extends React.Component {
12class Passport extends React.Component {
@@ -58,8 +59,6 @@ class Passport extends React.Component {
58 }
59 }
59
60
60 getWalletStates() {
61 getWalletStates() {
61− console.log('walletStates = ', this.props.walletStates)
62−
63 let stateElems = this.props.walletStates.map(state => {
62 let stateElems = this.props.walletStates.map(state => {
64 return (
63 return (
65 <div className="flex justify-between">
64 <div className="flex justify-between">
@@ -106,57 +105,59 @@ class Passport extends React.Component {
106
105
107 let currentDate = this.getCurrentDate()
106 let currentDate = this.getCurrentDate()
108 let walletStates = this.getWalletStates()
107 let walletStates = this.getWalletStates()
108+ let paperReady = this.state.paper && this.props.walletStates.includes(WALLET_STATES.PAPER_READY)
109+ let downloadColor = paperReady ? 'green' : 'black'
109
110
110 return (
111 return (
111 <div>
112 <div>
113+ <div className="passport-border">
112− <div className={`passport ${wallet && 'passport-filled'}`}>
114+ <div className={`passport ${paperReady && 'passport-filled'}`}>
113− <div className="flex">
115+ <div className="flex">
114− <div className="passport-sigil">
116+ <div className="passport-sigil">
115− {sigil}
117+ {sigil}
118+ </div>
119+ <div className="passport-metadata ml-4">
120+ <div className="passport-label text-mono">Point</div>
121+ <div className="text-mono">{patp || '-'}</div>
122+
123+ <div className="passport-label gray-50 mt-6">Created on</div>
124+ <div className="passport-value">{patp ? currentDate : '-' }</div>
125+
126+ <div className="passport-label gray-50 mt-2">Invited by</div>
127+ <div className="passport-value">{this.props.invitedBy || '-'}</div>
128+ </div>
116 </div>
129 </div>
117− <div className="passport-metadata ml-4">
118− <div className="passport-label text-mono">Point</div>
119− <div className="text-mono">{patp || '-'}</div>
120
130
131+ <div className="mt-8">
132+ <div className="passport-label text-mono">Ethereum Address</div>
133+ <div className="passport-value">{ownershipAddress || 'Ungenerated'}</div>
134+
121− <div className="passport-label gray-50 mt-6">Created on</div>
135+ <div className="passport-label gray-50 mt-3">Master Ticket</div>
122− <div className="passport-value">{patp ? currentDate : '-' }</div>
136+ <div className="passport-value">{ownershipAddress ? this.masterScreen : 'Ungenerated'}</div>
123
137
124− <div className="passport-label gray-50 mt-2">Invited by</div>
138+ <div className="passport-label gray-50 mt-5">Managment Seed</div>
125− <div className="passport-value">{this.props.invitedBy || '-'}</div>
139+ <div className="passport-value">{ownershipAddress ? this.managementScreen : 'Ungenerated'}</div>
126 </div>
140 </div>
127− </div>
128
141
129− <div className="mt-8">
142+ {wallet &&
130− <div className="passport-label text-mono">Ethereum Address</div>
143+ <PaperCollateralRenderer
131− <div className="passport-value">{ownershipAddress || 'Ungenerated'}</div>
144+ wallet={{[this.props.point.value]: wallet}}
132−
145+ className={'extremely-hidden'}
133− <div className="passport-label gray-50 mt-3">Master Ticket</div>
146+ callback={data => {
134− <div className="passport-value">{ownershipAddress ? this.masterScreen : 'Ungenerated'}</div>
135−
136− <div className="passport-label gray-50 mt-5">Managment Seed</div>
137− <div className="passport-value">{ownershipAddress ? this.managementScreen : 'Ungenerated'}</div>
138−
139− <Button
140− disabled={ !this.state.paper }
147+ this.setState({paper: data})
141− className={ 'mt-8' }
148+ this.props.pushWalletState(WALLET_STATES.PAPER_READY)
142− prop-size={ 'lg wide' }
149+ }}
143− prop-color={ 'green' }
150+ mode={'REGISTRATION'} />
144− onClick={ this.download }
151+ }
145− >
146− { 'Download' }
147− </Button>
148 </div>
152 </div>
149−
153+ <Button
150− {wallet &&
154+ disabled={ !paperReady }
151− <PaperCollateralRenderer
155+ prop-size={ 'lg wide' }
152− wallet={{[this.props.point.value]: wallet}}
156+ prop-color={ downloadColor }
153− className={'extremely-hidden'}
157+ onClick={ this.download }
154− callback={data => {
158+ >
155− console.log('paper wallet generated')
159+ { 'Download' }
156− this.setState({paper: data})
160+ </Button>
157− }}
158− mode={'REGISTRATION'} />
159− }
160 </div>
161 </div>
161 <div className="passport-wallet-states mt-3">
162 <div className="passport-wallet-states mt-3">
162 {walletStates}
163 {walletStates}
src/bridge/lib/invite.js+18−1
@@ -14,6 +14,21 @@ import saveAs from 'file-saver'
14const NEXT_STEP_NUM = 6;
14const NEXT_STEP_NUM = 6;
15const SEED_LENGTH_BYTES = SEED_ENTROPY_BITS / 8
15const SEED_LENGTH_BYTES = SEED_ENTROPY_BITS / 8
16
16
17+const INVITE_STAGES = {
18+ INVITE_LOGIN: "invite login",
19+ INVITE_WALLET: "invite wallet",
20+ INVITE_VERIFY: "invite verify",
21+ INVITE_TRANSACTIONS: "invite transactions"
22+}
23+
24+const WALLET_STATES = {
25+ UNLOCKING: "Unlocking invite wallet",
26+ GENERATING: "Generating your wallet",
27+ GENERATED: "Wallet generation complete",
28+ PAPER_READY: "Paper collateral generated",
29+ DOWNLOADED: "Wallet downloaded"
30+}
31+
17async function generateWallet(point) {
32async function generateWallet(point) {
18 const makeTicket = point => {
33 const makeTicket = point => {
19
34
@@ -104,5 +119,7 @@ async function downloadWallet(paper) {
104
119
105export {
120export {
106 generateWallet,
121 generateWallet,
107− downloadWallet
122+ downloadWallet,
123+ INVITE_STAGES,
124+ WALLET_STATES
108}
125}
src/bridge/style/button.css+4
@@ -54,6 +54,10 @@ button[prop-type='solid'][prop-color='green']:focus {
54 box-shadow: 0 0 0 3px #C5FBE7;
54 box-shadow: 0 0 0 3px #C5FBE7;
55}
55}
56
56
57+button[prop-type='solid'][prop-color='green']:disabled {
58+ background-color: #C5FBE7;
59+}
60+
57button[prop-type='solid'][prop-color='yellow'] {
61button[prop-type='solid'][prop-color='yellow'] {
58 background-color: #F8C134;
62 background-color: #F8C134;
59 border-color: #F8C134;
63 border-color: #F8C134;
src/bridge/style/extend.css+4−1
@@ -499,7 +499,6 @@ code {
499**/
499**/
500
500
501.passport {
501.passport {
502− border: 1px solid #C5FBE7;
503 padding: 24px;
502 padding: 24px;
504}
503}
505
504
@@ -512,6 +511,10 @@ code {
512 background-color: #C5FBE7;
511 background-color: #C5FBE7;
513}
512}
514
513
514+.passport-border {
515+ border: 1px solid #C5FBE7;
516+}
517+
515.passport-block {
518.passport-block {
516 width: 8px;
519 width: 8px;
517 height: 8px;
520 height: 8px;
src/bridge/views/InviteLogin.js+33−23
@@ -10,6 +10,7 @@ import { ROUTE_NAMES } from '../lib/router'
10import { DEFAULT_HD_PATH, urbitWalletFromTicket,
10import { DEFAULT_HD_PATH, urbitWalletFromTicket,
11 walletFromMnemonic, addressFromSecp256k1Public } from '../lib/wallet'
11 walletFromMnemonic, addressFromSecp256k1Public } from '../lib/wallet'
12import { BRIDGE_ERROR } from '../lib/error'
12import { BRIDGE_ERROR } from '../lib/error'
13+import { INVITE_STAGES, WALLET_STATES } from '../lib/invite'
13import { generateWallet } from '../lib/invite'
14import { generateWallet } from '../lib/invite'
14
15
15const placeholder = (len) => {
16const placeholder = (len) => {
@@ -21,20 +22,6 @@ const placeholder = (len) => {
21 return ob.hex2patq(hex)
22 return ob.hex2patq(hex)
22}
23}
23
24
24−const INVITE_STAGES = {
25− INVITE_LOGIN: "invite login",
26− INVITE_WALLET: "invite wallet",
27− INVITE_VERIFY: "invite verify",
28− INVITE_TRANSACTIONS: "invite transactions"
29−}
30−
31−const WALLET_STATES = {
32− UNLOCKING: "Unlocking invite wallet",
33− GENERATING: "Generating your wallet",
34− GENERATED: "Wallet generation complete",
35− DOWNLOADED: "Wallet downloaded"
36−}
37−
38class InviteLogin extends React.Component {
25class InviteLogin extends React.Component {
39
26
40 constructor(props) {
27 constructor(props) {
@@ -46,7 +33,6 @@ class InviteLogin extends React.Component {
46 realPoint: Nothing(),
33 realPoint: Nothing(),
47 realWallet: Nothing(),
34 realWallet: Nothing(),
48 walletReady: false,
35 walletReady: false,
49− continueReady: true,
50 stage: INVITE_STAGES.INVITE_LOGIN,
36 stage: INVITE_STAGES.INVITE_LOGIN,
51 walletStates: []
37 walletStates: []
52 }
38 }
@@ -57,9 +43,16 @@ class InviteLogin extends React.Component {
57 this.handleInviteTicketInput = this.handleInviteTicketInput.bind(this)
43 this.handleInviteTicketInput = this.handleInviteTicketInput.bind(this)
58 this.handleVerifyTicketInput = this.handleVerifyTicketInput.bind(this)
44 this.handleVerifyTicketInput = this.handleVerifyTicketInput.bind(this)
59 this.confirmWalletDownload = this.confirmWalletDownload.bind(this)
45 this.confirmWalletDownload = this.confirmWalletDownload.bind(this)
46+ this.pushWalletState = this.pushWalletState.bind(this)
60 this.navigateLogin = this.navigateLogin.bind(this)
47 this.navigateLogin = this.navigateLogin.bind(this)
61 }
48 }
62
49
50+ pushWalletState(walletState) {
51+ this.setState({
52+ walletStates: this.state.walletStates.concat(walletState)
53+ })
54+ }
55+
63 navigateLogin() {
56 navigateLogin() {
64 this.props.popRoute()
57 this.props.popRoute()
65 this.props.pushRoute(ROUTE_NAMES.NETWORK)
58 this.props.pushRoute(ROUTE_NAMES.NETWORK)
@@ -75,13 +68,12 @@ class InviteLogin extends React.Component {
75
68
76 confirmWalletDownload() {
69 confirmWalletDownload() {
77 this.setState({
70 this.setState({
78− continueReady: true
71+ walletStates: this.state.walletStates.concat(WALLET_STATES.DOWNLOADED),
79 })
72 })
80 }
73 }
81
74
82 async unlockInviteWallet(inviteTicket) {
75 async unlockInviteWallet(inviteTicket) {
83 this.setState({
76 this.setState({
84− continueReady: false,
85 walletStates: this.state.walletStates.concat(WALLET_STATES.UNLOCKING),
77 walletStates: this.state.walletStates.concat(WALLET_STATES.UNLOCKING),
86 stage: INVITE_STAGES.INVITE_WALLET
78 stage: INVITE_STAGES.INVITE_WALLET
87 });
79 });
@@ -172,12 +164,20 @@ class InviteLogin extends React.Component {
172 case INVITE_STAGES.INVITE_WALLET:
164 case INVITE_STAGES.INVITE_WALLET:
173 return (
165 return (
174 <div>
166 <div>
175− <h1 className="fs-6 lh-8">Welcome</h1>
167+ <h1 className="fs-6 lh-8 mb-3">Passport</h1>
176 <p>A passport is your digital identity. You will use your passport to access your true computer, send payments, and administer your identity. So naturally, you must keep this secure.</p>
168 <p>A passport is your digital identity. You will use your passport to access your true computer, send payments, and administer your identity. So naturally, you must keep this secure.</p>
177 <p>After you’ve downloaded your passport, back up the ticket manually or store on a trusted device.</p>
169 <p>After you’ve downloaded your passport, back up the ticket manually or store on a trusted device.</p>
178 </div>
170 </div>
179 )
171 )
180 break
172 break
173+ case INVITE_STAGES.INVITE_VERIFY:
174+ return (
175+ <div>
176+ <h1 className="fs-6 lh-8 mb-3">Verify Passport</h1>
177+ <p>Afer you download your passport, verify your custody. Your passport should be a folder of image files. One of them is your Master Ticket. Open it and enter the 4 word phrase below (with hyphens).</p>
178+ </div>
179+ )
180+ break
181 }
181 }
182 }
182 }
183
183
@@ -185,18 +185,27 @@ class InviteLogin extends React.Component {
185 if (this.state.stage === INVITE_STAGES.INVITE_TRANSACTIONS) return null
185 if (this.state.stage === INVITE_STAGES.INVITE_TRANSACTIONS) return null
186
186
187 let clickHandler
187 let clickHandler
188− let btnColor
188+ let btnColor = this.state.walletStates.includes(WALLET_STATES.PAPER_READY)
189+ ? 'green'
190+ : 'black'
191+ let continueReady
189
192
190 switch(this.state.stage) {
193 switch(this.state.stage) {
191 case INVITE_STAGES.INVITE_LOGIN:
194 case INVITE_STAGES.INVITE_LOGIN:
192 clickHandler = () => {
195 clickHandler = () => {
193 this.unlockInviteWallet(this.state.inviteTicket)
196 this.unlockInviteWallet(this.state.inviteTicket)
194 }
197 }
195− btnColor = "black"
198+ continueReady = true
196 break
199 break
197− case INVITE_STAGES.INVITE_VERIFY:
198 case INVITE_STAGES.INVITE_WALLET:
200 case INVITE_STAGES.INVITE_WALLET:
199− btnColor = "green"
201+ clickHandler = () => {
202+ this.setState({
203+ stage: INVITE_STAGES.INVITE_VERIFY
204+ })
205+ }
206+ continueReady = this.state.walletStates.includes(WALLET_STATES.DOWNLOADED)
207+ break
208+ case INVITE_STAGES.INVITE_VERIFY:
200 break
209 break
201 }
210 }
202
211
@@ -205,7 +214,7 @@ class InviteLogin extends React.Component {
205 className={'mt-4'}
214 className={'mt-4'}
206 prop-size={'lg'}
215 prop-size={'lg'}
207 prop-color={btnColor}
216 prop-color={btnColor}
208− disabled={!this.state.continueReady}
217+ disabled={!continueReady}
209 onClick={clickHandler}
218 onClick={clickHandler}
210 >
219 >
211 { 'Continue →' }
220 { 'Continue →' }
@@ -258,6 +267,7 @@ class InviteLogin extends React.Component {
258 point={this.state.realPoint}
267 point={this.state.realPoint}
259 wallet={this.state.realWallet}
268 wallet={this.state.realWallet}
260 walletStates={this.state.walletStates}
269 walletStates={this.state.walletStates}
270+ pushWalletState={this.pushWalletState}
261 confirmWalletDownload={this.confirmWalletDownload}
271 confirmWalletDownload={this.confirmWalletDownload}
262 />
272 />
263 </Col>
273 </Col>