on master help sign in
Make /views/Login/Shards functional/stateless
d2c2674Fang
src/views/Login/Shards.js+70−191
@@ -1,78 +1,28 @@
1import { Just, Nothing } from 'folktale/maybe';
1import { Just, Nothing } from 'folktale/maybe';
2−import React from 'react';
2+import React, { useState } from 'react';
3−import { Button } from '../../components/old/Base';
3+import * as kg from 'urbit-key-generation/dist/index';
4+
5+import View from '../../components/View';
4import {
6import {
5− InnerLabel,
6− ValidatedSigil,
7 PointInput,
7 PointInput,
8− ShardInput,
8+ TicketInput,
9− InputCaption,
9+ PassphraseInput,
10− Input,
11−} from '../../components/old/Base';
10+} from '../../components/Inputs';
12−import { Row, Col, H1, P } from '../../components/old/Base';
11+import { ForwardButton } from '../../components/Buttons';
13−import * as kg from 'urbit-key-generation/dist/index';
14−import * as ob from 'urbit-ob';
15
12
16import { urbitWalletFromTicket } from '../../lib/wallet';
13import { urbitWalletFromTicket } from '../../lib/wallet';
17−import { compose } from '../../lib/lib';
18−import { withWallet } from '../../store/wallet';
14+import { useWallet } from '../../store/wallet';
19−
20−const placeholder = len => {
21− let bytes = window.crypto.getRandomValues(new Uint8Array(len));
22− let hex = bytes.reduce(
23− (acc, byt) => acc + byt.toString(16).padStart(2, '0'),
24− ''
25− );
26− return ob.hex2patq(hex);
27−};
28−
29−const SHARDS = {
30− SHARD1: Symbol('SHARD1'),
31− SHARD2: Symbol('SHARD2'),
32− SHARD3: Symbol('SHARD3'),
33−};
34−
35−class Shards extends React.Component {
36− constructor(props) {
37− super(props);
38
15
39− this.state = {
16+export default function Shards({ loginCompleted }) {
40− shard1: '',
17+ const { wallet, setUrbitWallet } = useWallet();
41− shard2: '',
42− shard3: '',
43− passphrase: '',
44− pointName: '',
45− };
46
18
47− this.pointPlaceholder = placeholder(4);
19+ const [shard1, setShard1] = useState('');
48− this.ticketPlaceholder = placeholder(16);
20+ const [shard2, setShard2] = useState('');
21+ const [shard3, setShard3] = useState('');
22+ const [passphrase, setPassphrase] = useState('');
23+ const [pointName, setPointName] = useState('');
49
24
50− this.handlePassphraseInput = this.handlePassphraseInput.bind(this);
25+ const walletFromShards = async () => {
51− this.handleShardInput = this.handleShardInput.bind(this);
52− this.handlePointNameInput = this.handlePointNameInput.bind(this);
53− }
54−
55− handleShardInput(shard, input) {
56− if (shard === SHARDS.SHARD1) {
57− this.setState({ shard1: input });
58− } else if (shard === SHARDS.SHARD2) {
59− this.setState({ shard2: input });
60− } else if (shard === SHARDS.SHARD3) {
61− this.setState({ shard3: input });
62− }
63− }
64−
65− handlePassphraseInput(passphrase) {
66− this.setState({ passphrase });
67− }
68−
69− handlePointNameInput(pointName) {
70− if (pointName.length < 15) {
71− this.setState({ pointName });
72− }
73− }
74−
75− async walletFromShards(shard1, shard2, shard3, pointName, passphrase) {
76 const s1 = shard1 === '' ? undefined : shard1;
26 const s1 = shard1 === '' ? undefined : shard1;
77 const s2 = shard2 === '' ? undefined : shard2;
27 const s2 = shard2 === '' ? undefined : shard2;
78 const s3 = shard3 === '' ? undefined : shard3;
28 const s3 = shard3 === '' ? undefined : shard3;
@@ -86,129 +36,58 @@ class Shards extends React.Component {
86
36
87 if (ticket !== undefined) {
37 if (ticket !== undefined) {
88 const uhdw = await urbitWalletFromTicket(ticket, pointName, passphrase);
38 const uhdw = await urbitWalletFromTicket(ticket, pointName, passphrase);
89− this.props.setUrbitWallet(Just(uhdw));
39+ setUrbitWallet(Just(uhdw));
90 }
40 }
91− }
41+ };
92−
42+
93− render() {
94− const { wallet } = this.props;
95− const { shard1, shard2, shard3, pointName, passphrase } = this.state;
96−
97− const phPoint = this.pointPlaceholder;
98− const phTick = this.ticketPlaceholder;
99−
100− const shards = [shard1, shard2, shard3];
43+ const shards = [shard1, shard2, shard3];
101− const ready = shards.filter(x => x !== '').length > 1;
44+ const ready = shards.filter(x => x !== '').length > 1;
102−
45+
103− return (
46+ return (
104− <Row>
47+ <View>
105− <Col>
106− <H1>{'Authenticate'}</H1>
107−
108− <P>
109− {`Enter your point and at least two of your three Urbit master
48+ Enter your point and at least two of your three Urbit master ticket shards
110− ticket shards here. The index of the input field needs to
49+ here. The index of the input field needs to match the index of the shard.
111− match the index of the shard.`}
112− </P>
113−
114− <PointInput
50+ <PointInput
115− className="mono mt-8"
51+ name="point"
116− prop-size="lg"
52+ label="Point"
117− prop-format="innerLabel"
118− type="text"
119− autoFocus
120− placeholder={`e.g. ${phPoint}`}
121− value={pointName}
122− onChange={this.handlePointNameInput}>
123− <InnerLabel>{'Point'}</InnerLabel>
124− <ValidatedSigil
125− className={'tr-0 mt-05 mr-0 abs'}
126− patp={pointName}
53+ initialValue={pointName}
127− size={68}
54+ onValue={setPointName}
128− margin={8}
55+ autoFocus
129− />
56+ />
130− </PointInput>
57+ <TicketInput
131−
132− <ShardInput
133− className="mono mt-8"
134− prop-size="md"
135− prop-format="innerLabel"
136− type="text"
137− name="shard1"
58+ name="shard1"
138− placeholder={`e.g. ${phTick}`}
59+ label="Shard 1"
139− value={shard1}
60+ initialValue={shard1}
140− onChange={inp => this.handleShardInput(SHARDS.SHARD1, inp)}>
61+ onValue={setShard1}></TicketInput>
141− <InnerLabel>{'Shard 1'}</InnerLabel>
62+ <TicketInput
142− </ShardInput>
143−
144− <ShardInput
145− className="mono mt-8"
146− prop-size="md"
147− prop-format="innerLabel"
148− type="text"
149− name="shard2"
63+ name="shard2"
150− placeholder={`e.g. ${phTick}`}
64+ label="Shard 2"
151− value={shard2}
65+ initialValue={shard2}
152− onChange={inp => this.handleShardInput(SHARDS.SHARD2, inp)}>
66+ onValue={setShard2}></TicketInput>
153− <InnerLabel>{'Shard 2'}</InnerLabel>
67+ <TicketInput
154− </ShardInput>
155−
156− <ShardInput
157− className="mono mt-8"
158− prop-size="md"
159− prop-format="innerLabel"
160− type="text"
161− name="shard3"
68+ name="shard3"
162− placeholder={`e.g. ${phTick}`}
69+ label="Shard 3"
163− value={shard3}
70+ initialValue={shard3}
164− onChange={inp => this.handleShardInput(SHARDS.SHARD3, inp)}>
71+ onValue={setShard3}></TicketInput>
165− <InnerLabel>{'Shard 3'}</InnerLabel>
166− </ShardInput>
167−
168− <InputCaption>
169− {'If your wallet requires a passphrase, you may enter it below.'}
72+ If your wallet requires a passphrase, you may enter it below.
170− </InputCaption>
73+ <PassphraseInput
171−
172− <Input
173− className="pt-8"
174− prop-size="md"
175− prop-format="innerLabel"
176− name="passphrase"
74+ name="passphrase"
177− type="password"
75+ label="(Optional) Wallet Passphrase"
178− value={passphrase}
76+ initialValue={passphrase}
179− autocomplete="off"
77+ onValue={setPassphrase}
180− onChange={this.handlePassphraseInput}>
78+ />
181− <InnerLabel>{'Passphrase'}</InnerLabel>
79+ <ForwardButton
182− </Input>
80+ className={'mt3'}
183−
184− <Button
185− disabled={!ready}
81+ disabled={!ready}
186− className={'mt-8'}
187− prop-size={'lg wide'}
188− // prop-color={this.buttonTriState(wallet)}
189− onClick={() =>
190− this.walletFromShards(
82+ onClick={walletFromShards}>
191− shard1,
192− shard2,
193− shard3,
194− pointName,
195− passphrase
196− )
197− }>
198− {'Unlock Wallet →'}
83+ {'Unlock Wallet →'}
199− </Button>
84+ </ForwardButton>
200−
85+ <ForwardButton
201− <Button
202− className={'mt-4'}
86+ className={'mt3'}
203− prop-size={'xl wide'}
204− disabled={Nothing.hasInstance(wallet)}
87+ disabled={Nothing.hasInstance(wallet)}
205− onClick={this.props.loginCompleted}>
88+ onClick={loginCompleted}>
206− {'Continue →'}
89+ {'Continue →'}
207− </Button>
90+ </ForwardButton>
208− </Col>
91+ </View>
209− </Row>
210− );
92+ );
211− }
212}
93}
213−
214−export default compose(withWallet)(Shards);