on master help sign in
feat: refactor top-level views to use new Button and Input components
bbf707aMatt Condon (shrugs)
src/components/Buttons.jsnew file+6
@@ -0,0 +1,6 @@
1+import React from 'react';
2+import { Button } from 'indigo-react';
3+
4+// TODO: use svg icons
5+export const ForwardButton = props => <Button icon="→" {...props} />;
6+export const DownloadButton = props => <Button icon="⬇" {...props} />;
src/components/InputSigil.jsnew file+49
@@ -0,0 +1,49 @@
1+import React from 'react';
2+import * as ob from 'urbit-ob';
3+
4+import Sigil from './Sigil';
5+
6+const selectColorway = (pass, fail, focused) => {
7+ if (pass) {
8+ return ['#FFFFFF', '#2AA779'];
9+ }
10+
11+ if (focused) {
12+ return ['#FFFFFF', '#4330FC'];
13+ }
14+
15+ if (fail) {
16+ return ['#FFFFFF', '#F8C134'];
17+ }
18+
19+ return ['#FFFFFF', '#7F7F7F'];
20+};
21+
22+export default function ValidatedSigil({
23+ className,
24+ patp,
25+ size,
26+ pass,
27+ error,
28+ focused,
29+ ...rest
30+}) {
31+ const colorway = selectColorway(pass, error, focused);
32+ const valid = ob.isValidPatp(patp);
33+
34+ return (
35+ <div className={className}>
36+ {valid ? (
37+ <Sigil patp={patp} size={size} colorway={colorway} {...rest} />
38+ ) : (
39+ <div
40+ className="bg-transparent"
41+ style={{
42+ width: size,
43+ height: size,
44+ }}
45+ />
46+ )}
47+ </div>
48+ );
49+}
src/components/Inputs.js+18−6
@@ -2,8 +2,13 @@ import React from 'react';
2import { Input } from 'indigo-react';
2import { Input } from 'indigo-react';
3import * as bip39 from 'bip39';
3import * as bip39 from 'bip39';
4
4
5−import { validateNotEmpty, validateMnemonic } from 'lib/validators';
6import { DEFAULT_HD_PATH } from 'lib/wallet';
5import { DEFAULT_HD_PATH } from 'lib/wallet';
6+import {
7+ validateNotEmpty,
8+ validateMnemonic,
9+ validatePoint,
10+} from 'lib/validators';
11+import { prependSig } from 'lib/transformers';
7
12
8const kExampleMnemonic = bip39.generateMnemonic();
13const kExampleMnemonic = bip39.generateMnemonic();
9
14
@@ -68,11 +73,18 @@ export function HdPathInput(props) {
68// transformers: [prependSig],
73// transformers: [prependSig],
69// });
74// });
70
75
71−// const PointInput = advancedInput({
76+export function PointInput(props) {
72−// WrappedComponent: Input,
77+ return (
78+ <Input
79+ type="text"
80+ placeholder="e.g. ~zod"
73−// validators: [validatePoint, validateNotEmpty],
81+ validators={[validatePoint, validateNotEmpty]}
74−// transformers: [prependSig],
82+ transformers={[prependSig]}
83+ mono
84+ {...props}
85+ />
75−// });
86+ );
87+}
76
88
77// const TicketInput = advancedInput({
89// const TicketInput = advancedInput({
78// WrappedComponent: Input,
90// WrappedComponent: Input,
src/components/old/ReactSVGComponents.js → src/components/ReactSVGComponents.jsrenamed

The content is the same.

src/components/Sigil.jsnew file+13
@@ -0,0 +1,13 @@
1+import { pour } from 'sigil-js';
2+
3+import ReactSVGComponents from './ReactSVGComponents';
4+
5+export default function Sigil({ patp, size, colorway, ...rest }) {
6+ return pour({
7+ renderer: ReactSVGComponents,
8+ patp,
9+ size,
10+ colorway,
11+ ...rest,
12+ });
13+}
src/components/old/Passport.js+1−1
@@ -1,7 +1,7 @@
1import React from 'react';
1import React from 'react';
2import { pour } from 'sigil-js';
2import { pour } from 'sigil-js';
3import * as ob from 'urbit-ob';
3import * as ob from 'urbit-ob';
4−import ReactSVGComponents from './ReactSVGComponents';
4+import ReactSVGComponents from '../ReactSVGComponents';
5import PropTypes from 'prop-types';
5import PropTypes from 'prop-types';
6import PaperCollateralRenderer from 'PaperCollateralRenderer';
6import PaperCollateralRenderer from 'PaperCollateralRenderer';
7import { Button } from './Base';
7import { Button } from './Base';
src/components/old/RenderedPoint.js+1−1
@@ -6,7 +6,7 @@ import { pour } from 'sigil-js';
6import * as ob from 'urbit-ob';
6import * as ob from 'urbit-ob';
7
7
8import { ROUTE_NAMES } from '../../lib/routeNames';
8import { ROUTE_NAMES } from '../../lib/routeNames';
9−import ReactSVGComponents from './ReactSVGComponents';
9+import ReactSVGComponents from '../ReactSVGComponents';
10
10
11const RenderedPoint = props => {
11const RenderedPoint = props => {
12 const { setPointCursor, routeHandler, point } = props;
12 const { setPointCursor, routeHandler, point } = props;
src/components/old/ValidatedSigil.js+1−1
@@ -3,7 +3,7 @@ import PropTypes from 'prop-types';
3
3
4import { pour } from 'sigil-js';
4import { pour } from 'sigil-js';
5import * as ob from 'urbit-ob';
5import * as ob from 'urbit-ob';
6−import ReactSVGComponents from './ReactSVGComponents';
6+import ReactSVGComponents from '../ReactSVGComponents';
7
7
8const isValidPatp = patp => {
8const isValidPatp = patp => {
9 let isValid = false;
9 let isValid = false;
src/indigo-react/components/Button.jsnew file+26
@@ -0,0 +1,26 @@
1+import React from 'react';
2+import cn from 'classnames';
3+
4+export default function Button({
5+ solid = false,
6+ className,
7+ icon,
8+ children,
9+ ...rest
10+}) {
11+ return (
12+ <a
13+ className={cn(
14+ 'pointer pv3 pl4 pr0 truncate flex-row justify-between',
15+ {
16+ 'white bg-black bg-gray6-hover': solid,
17+ 'black bg-gray1-hover': !solid,
18+ },
19+ className
20+ )}
21+ {...rest}>
22+ {children}
23+ <div className="ph4">{icon}</div>
24+ </a>
25+ );
26+}
src/indigo-react/components/Input.js+38−18
@@ -10,10 +10,10 @@ function useInput({
10 validators = [],
10 validators = [],
11 transformers = [],
11 transformers = [],
12 initialValue = '',
12 initialValue = '',
13− autofocus = false,
13+ autoFocus = false,
14}) {
14}) {
15 const [value, setValue] = useState(initialValue);
15 const [value, setValue] = useState(initialValue);
16− const [focused, setFocused] = useState(autofocus);
16+ const [focused, setFocused] = useState(autoFocus);
17 const [hasBeenFocused, setHasBeenFocused] = useState(false);
17 const [hasBeenFocused, setHasBeenFocused] = useState(false);
18
18
19 // NB(shrugs)
19 // NB(shrugs)
@@ -92,13 +92,13 @@ function useInput({
92
92
93 // only set error if it should be visible
93 // only set error if it should be visible
94 const error = !pass && hasBeenFocused && !focused && _error;
94 const error = !pass && hasBeenFocused && !focused && _error;
95− // whether or not the 'pass' effect should be shown
95+ // visibly tell the user that their input has passed if it has passed
96+ // and they are or have interacted with the input before
96− const visiblePass = pass && hasBeenFocused && !focused;
97+ const visiblyPassed = pass && (hasBeenFocused || focused);
97
98
98 return {
99 return {
99 pass,
100 pass,
100− // TODO: need a better name for `visiblePass`
101+ visiblyPassed,
101− visiblePass,
102 error,
102 error,
103 data,
103 data,
104 focused,
104 focused,
@@ -119,23 +119,42 @@ export default function Input({
119 initialValue = '',
119 initialValue = '',
120 className = '',
120 className = '',
121 validators = [],
121 validators = [],
122− onSuccess,
122+ transformers = [],
123− onFailure,
123+ onValue,
124+ onPass,
125+ onError,
126+ onFocus,
124 disabled = false,
127 disabled = false,
125 mono = false,
128 mono = false,
126− autofocus = false,
129+ autoFocus = false,
127 ...rest
130 ...rest
128}) {
131}) {
129− const { focused, pass, visiblePass, error, data, bind } = useInput({
132+ const { focused, pass, visiblyPassed, error, data, bind } = useInput({
130 validators,
133 validators,
134+ transformers,
131 initialValue,
135 initialValue,
132− autofocus,
136+ autoFocus,
133 });
137 });
134
138
139+ // notify parent of value only when passing
140+ useEffect(() => {
141+ pass && onValue && onValue(data);
142+ }, [pass, data, onValue]);
143+
144+ // notify parent of pass
145+ useEffect(() => {
146+ onPass && onPass(pass);
147+ }, [pass, onPass]);
148+
149+ // notify parent of error whenever error changes
150+ useEffect(() => {
151+ onError && onError(error);
152+ }, [error, onError]);
153+
154+ // notify parent of focus
135 useEffect(() => {
155 useEffect(() => {
136− onSuccess && onSuccess(data);
156+ onFocus && onFocus(focused);
137− onFailure && onFailure(error);
157+ }, [focused, onFocus]);
138− }, [pass, error, data, onSuccess, onFailure]);
139
158
140 return (
159 return (
141 <Grid>
160 <Grid>
@@ -159,15 +178,16 @@ export default function Input({
159 black: focused,
178 black: focused,
160 },
179 },
161 {
180 {
181+ 'b-green3': visiblyPassed,
162− 'b-black': focused,
182+ 'b-black': focused && !visiblyPassed,
183+ 'b-yellow3': !focused && !visiblyPassed && error,
163− 'b-gray3': !focused && !error && !visiblePass,
184+ 'b-gray3': !focused && !error && !visiblyPassed,
164− 'b-yellow3': !focused && error && !visiblePass,
165− 'b-green3': !focused && !error && visiblePass,
166 },
185 },
167 className
186 className
168 )}
187 )}
169 id={name}
188 id={name}
170 name={name}
189 name={name}
190+ autoFocus={autoFocus}
171 {...bind}
191 {...bind}
172 />
192 />
173 </Grid.Item>
193 </Grid.Item>
src/indigo-react/index.js+1
@@ -1,2 +1,3 @@
1export { default as IndigoApp } from './components/IndigoApp';
1export { default as IndigoApp } from './components/IndigoApp';
2export { default as Input } from './components/Input';
2export { default as Input } from './components/Input';
3+export { default as Button } from './components/Button';
src/lib/useLifecycle.jsnew file+6
@@ -0,0 +1,6 @@
1+import { useEffect } from 'react';
2+
3+// https://overreacted.io/a-complete-guide-to-useeffect/
4+export default function useLifecycle(fn) {
5+ return useEffect(fn, []);
6+}
src/lib/validators.js+2−2
@@ -17,7 +17,7 @@ export const simpleValidatorWrapper = config => {
17
17
18 // Run the validator and return the result.
18 // Run the validator and return the result.
19 return config.validator(config.prevMessage.data)
19 return config.validator(config.prevMessage.data)
20− ? newMessage(config.prevMessage.data, true, '')
20+ ? newMessage(config.prevMessage.data, true, null)
21 : newMessage(config.prevMessage.data, false, config.errorMessage);
21 : newMessage(config.prevMessage.data, false, config.errorMessage);
22};
22};
23
23
@@ -38,7 +38,7 @@ const newMessage = (data, pass, error) => ({
38});
38});
39
39
40// A validator that always passes.
40// A validator that always passes.
41−export const kDefaultValidator = data => newMessage(data, true, '');
41+export const kDefaultValidator = data => newMessage(data, true, null);
42
42
43// Validates a bip39 mnemonic
43// Validates a bip39 mnemonic
44export const validateMnemonic = m =>
44export const validateMnemonic = m =>
src/style/indigo-proposals.scss+12
@@ -11,3 +11,15 @@
11.lh-tall {
11.lh-tall {
12 line-height: 2;
12 line-height: 2;
13}
13}
14+
15+.bg-gray1-hover:hover {
16+ background-color: #f9f9f9;
17+}
18+
19+.bg-gray6-hover:hover {
20+ background-color: #333333;
21+}
22+
23+.bg-transparent {
24+ background-color: transparent;
25+}
src/views/Landing.js+18−37
@@ -1,62 +1,43 @@
1import React from 'react';
1import React from 'react';
2−import { Button } from '../components/old/Base';
3−import { Row, Col } from '../components/old/Base';
4import { H1, P } from '../components/old/Base';
2import { H1, P } from '../components/old/Base';
5
3
6import { ROUTE_NAMES } from '../lib/routeNames';
4import { ROUTE_NAMES } from '../lib/routeNames';
7import { useHistory } from '../store/history';
5import { useHistory } from '../store/history';
6+
8import View from 'components/View';
7import View from 'components/View';
8+import { ForwardButton } from 'components/Buttons';
9
9
10function Landing(props) {
10function Landing(props) {
11 const history = useHistory();
11 const history = useHistory();
12
12
13 return (
13 return (
14 <View>
14 <View>
15− <H1>{'Welcome'}</H1>
15+ <H1>Welcome</H1>
16
16
17 <P>
17 <P>
18− {'Bridge is a tool for managing and viewing assets on ' +
18+ Bridge is a tool for managing and viewing assets on Azimuth, the Urbit
19− 'Azimuth, the Urbit address space.'}
19+ address space.
20 </P>
20 </P>
21
21
22− <Button
23− prop-type="link"
24− prop-size="lg"
25− className={'mb-4 mt-8'}
26− onClick={() => history.push(ROUTE_NAMES.INVITE_TICKET)}>
22+ <ForwardButton onClick={() => history.push(ROUTE_NAMES.INVITE_TICKET)}>
27− {'Claim an invite →'}
23+ Claim an invite
28− </Button>
24+ </ForwardButton>
29
25
30− <P>{'If you were sent an Azimuth invite code, start here.'}</P>
26+ <P>If you were sent an Azimuth invite code, start here.</P>
31
27
32− <Button
33− prop-type="link"
34− prop-size="lg"
35− className={'mb-4 mt-8'}
36− onClick={() => history.push(ROUTE_NAMES.NETWORK)}>
28+ <ForwardButton onClick={() => history.push(ROUTE_NAMES.NETWORK)}>
37− {'Unlock a Wallet →'}
29+ Unlock a Wallet
38− </Button>
30+ </ForwardButton>
39
31
40 <P>
32 <P>
41− {'If you own Azimuth assets and want to manage them in some ' +
33+ If you own Azimuth assets and want to manage them in some way, start
42− "way, start here. You'll need either your Urbit ticket or a " +
34+ here. You'll need either your Urbit ticket or a keypair.
43− 'keypair.'}
44 </P>
35 </P>
45
36
46− {
47− <Row>
48− <Col>
49− <Button
50− prop-type={'link'}
51− prop-size={'lg'}
52− className={'mb-4 mt-8'}
53− onClick={() => history.push(ROUTE_NAMES.VIEW_SHIP)}>
37+ <ForwardButton onClick={() => history.push(ROUTE_NAMES.VIEW_SHIP)}>
54− {'View a point →'}
38+ View a point
55− </Button>
39+ </ForwardButton>
56− <P>{'View an Azimuth point without signing into a wallet.'}</P>
40+ <P>{'View an Azimuth point without signing into a wallet.'}</P>
57− </Col>
58− </Row>
59− }
60 </View>
41 </View>
61 );
42 );
62}
43}
src/views/Mnemonic.js+10−10
@@ -1,16 +1,15 @@
1import React, { useCallback, useEffect, useState } from 'react';
1import React, { useCallback, useEffect, useState } from 'react';
2import { Just, Nothing } from 'folktale/maybe';
2import { Just, Nothing } from 'folktale/maybe';
3
3
4−import { Button } from '../components/old/Base';
4+import View from 'components/View';
5+import { MnemonicInput, PassphraseInput, HdPathInput } from 'components/Inputs';
6+import { ForwardButton } from 'components/Buttons';
5
7
6import { ROUTE_NAMES } from 'lib/routeNames';
8import { ROUTE_NAMES } from 'lib/routeNames';
7import { useHistory } from 'store/history';
9import { useHistory } from 'store/history';
8import { walletFromMnemonic } from 'lib/wallet';
10import { walletFromMnemonic } from 'lib/wallet';
9import { useWallet } from 'store/wallet';
11import { useWallet } from 'store/wallet';
10
12
11−import View from 'components/View';
12−import { MnemonicInput, PassphraseInput, HdPathInput } from 'components/Inputs';
13−
14export default function Mnemonic() {
13export default function Mnemonic() {
15 const history = useHistory();
14 const history = useHistory();
16 const {
15 const {
@@ -47,28 +46,29 @@ export default function Mnemonic() {
47 name="mnemonic"
46 name="mnemonic"
48 label="BIP39 Mnemonic"
47 label="BIP39 Mnemonic"
49 initialValue={mnemonic}
48 initialValue={mnemonic}
50− onSuccess={_setAuthMnemonic}
49+ onValue={_setAuthMnemonic}
50+ autoFocus
51 />
51 />
52
52
53 <PassphraseInput
53 <PassphraseInput
54 name="passphrase"
54 name="passphrase"
55 label="(Optional) Wallet Passphrase"
55 label="(Optional) Wallet Passphrase"
56 initialValue={passphrase}
56 initialValue={passphrase}
57− onSuccess={setPassphrase}
57+ onValue={setPassphrase}
58 />
58 />
59
59
60 <HdPathInput
60 <HdPathInput
61 name="hdpath"
61 name="hdpath"
62 label="HD Path"
62 label="HD Path"
63 initialValue={walletHdPath}
63 initialValue={walletHdPath}
64− onSuccess={setWalletHdPath}
64+ onValue={setWalletHdPath}
65 />
65 />
66
66
67− <Button
67+ <ForwardButton
68 disabled={Nothing.hasInstance(wallet)}
68 disabled={Nothing.hasInstance(wallet)}
69 onClick={() => history.popAndPush(ROUTE_NAMES.SHIPS)}>
69 onClick={() => history.popAndPush(ROUTE_NAMES.SHIPS)}>
70− {'Continue →'}
70+ Continue
71− </Button>
71+ </ForwardButton>
72 </View>
72 </View>
73 );
73 );
74}
74}
src/views/Network.js+3−6
@@ -1,6 +1,6 @@
1import React from 'react';
1import React from 'react';
2+import { Button } from 'indigo-react';
2
3
3−import { Button } from '../components/old/Base';
4import { InnerLabelDropdown } from '../components/old/Base';
4import { InnerLabelDropdown } from '../components/old/Base';
5import { H1, P } from '../components/old/Base';
5import { H1, P } from '../components/old/Base';
6import { NETWORK_TYPES, renderNetworkType } from '../lib/network';
6import { NETWORK_TYPES, renderNetworkType } from '../lib/network';
@@ -46,17 +46,14 @@ function Network() {
46 </P>
46 </P>
47
47
48 <InnerLabelDropdown
48 <InnerLabelDropdown
49− className={'mt-6'}
50 title={'Node:'}
49 title={'Node:'}
51 handleUpdate={setNetworkType}
50 handleUpdate={setNetworkType}
52 options={kNetworkOptions}
51 options={kNetworkOptions}
53 currentSelectionTitle={renderNetworkType(networkType)}
52 currentSelectionTitle={renderNetworkType(networkType)}
54 />
53 />
55
54
56− <Button
57− className={'mt-10'}
58− onClick={() => history.push(ROUTE_NAMES.WALLET)}>
55+ <Button icon="→" onClick={() => history.push(ROUTE_NAMES.WALLET)}>
59− {'Continue →'}
56+ Continue
60 </Button>
57 </Button>
61 </View>
58 </View>
62 );
59 );
src/views/Point.js+1−1
@@ -6,7 +6,7 @@ import * as azimuth from 'azimuth-js';
6import * as need from '../lib/need';
6import * as need from '../lib/need';
7
7
8import PointList from '../components/old/PointList';
8import PointList from '../components/old/PointList';
9−import ReactSVGComponents from '../components/old/ReactSVGComponents';
9+import ReactSVGComponents from '../components/ReactSVGComponents';
10import KeysAndMetadata from './Point/KeysAndMetadata';
10import KeysAndMetadata from './Point/KeysAndMetadata';
11import Actions from './Point/Actions';
11import Actions from './Point/Actions';
12import { H1, H3 } from '../components/old/Base';
12import { H1, H3 } from '../components/old/Base';
src/views/ViewPoint.js+53−80
@@ -1,88 +1,61 @@
1+import React, { useState } from 'react';
1import Maybe from 'folktale/maybe';
2import Maybe from 'folktale/maybe';
2−import React from 'react';
3import * as ob from 'urbit-ob';
3import * as ob from 'urbit-ob';
4
4
5−import { Button } from '../components/old/Base';
6import { H1, P } from '../components/old/Base';
5import { H1, P } from '../components/old/Base';
7−import { InnerLabel, PointInput, ValidatedSigil } from '../components/old/Base';
8
6
9−import { ROUTE_NAMES } from '../lib/routeNames';
10−import { withHistory } from '../store/history';
7+import { useHistory } from 'store/history';
11−import { compose } from '../lib/lib';
12−import { withPointCursor } from '../store/pointCursor';
8+import { usePointCursor } from 'store/pointCursor';
13−import View from 'components/View';
14−
15−class ViewPoint extends React.Component {
16− constructor(props) {
17− super(props);
18−
19− this.state = {
20− pointName: '',
21− };
22−
23− this.handlePointInput = this.handlePointInput.bind(this);
24− }
25−
26− handlePointInput = pointName => {
27− if (pointName.length < 15) {
28− this.setState({ pointName });
29− }
30− };
31−
32− render() {
33− const { pointName } = this.state;
34− const { history, setPointCursor } = this.props;
35
9
36− // NB (jtobin):
10+import { ROUTE_NAMES } from 'lib/routeNames';
37− //
38− // could use a better patp parser in urbit-ob
39− let valid;
40− try {
41− valid = ob.isValidPatp(pointName);
42− } catch (err) {
43− valid = false;
44− }
45
11
12+import View from 'components/View';
13+import { ForwardButton } from 'components/Buttons';
14+import { PointInput } from 'components/Inputs';
15+import InputSigil from 'components/InputSigil';
16+
17+export default function ViewPoint() {
18+ const history = useHistory();
19+ const { setPointCursor } = usePointCursor();
20+ const [pointName, setPointName] = useState('');
21+ const [pass, setPass] = useState(false);
22+ const [error, setError] = useState();
23+ const [focused, setFocused] = useState(true);
24+
46− return (
25+ return (
47− <View>
26+ <View>
48− <H1>{'View a Point'}</H1>
27+ <H1>{'View a Point'}</H1>
49−
28+
50− <P>{'Enter a point name to view its public information.'}</P>
29+ <P>{'Enter a point name to view its public information.'}</P>
51−
30+
52− <PointInput
31+ <PointInput
53− autoFocus
32+ name="point"
54− prop-size="lg"
55− prop-format="innerLabel"
56− className="mono"
57− placeholder="e.g. ~zod"
58− onChange={this.handlePointInput}
59− value={pointName}>
60− <InnerLabel>{'Point Name'}</InnerLabel>
33+ label="Point Name"
61− <ValidatedSigil
34+ onValue={setPointName}
62− className={'tr-0 mt-05 mr-0 abs'}
35+ onPass={setPass}
36+ onError={setError}
37+ onFocus={setFocused}
38+ autoFocus
39+ />
40+
41+ <InputSigil
63− patp={pointName}
42+ patp={pointName}
64− show
65− size={68}
43+ size={68}
66− margin={8}
44+ margin={8}
67− />
45+ pass={pass}
68− </PointInput>
46+ focused={focused}
69−
47+ error={error}
70− <Button
48+ />
71− className={'mt-8'}
49+
50+ <ForwardButton
72− disabled={valid === false}
51+ disabled={error}
73− onClick={() => {
52+ onClick={() => {
74− setPointCursor(Maybe.Just(parseInt(ob.patp2dec(pointName), 10)));
53+ setPointCursor(Maybe.Just(parseInt(ob.patp2dec(pointName), 10)));
75− // ^ pointCursor expects native number type, not string
54+ // ^ pointCursor expects native number type, not string
76− history.popAndPush(ROUTE_NAMES.SHIP);
55+ history.popAndPush(ROUTE_NAMES.SHIP);
77− }}>
56+ }}>
78− {'Continue →'}
57+ Continue
79− </Button>
58+ </ForwardButton>
80− </View>
59+ </View>
81− );
60+ );
82− }
83}
61}
84−
85−export default compose(
86− withHistory,
87− withPointCursor
88−)(ViewPoint);
src/views/Wallet.js+88−97
@@ -1,110 +1,101 @@
1−import Maybe from 'folktale/maybe';
2import React from 'react';
1import React from 'react';
2+import Maybe from 'folktale/maybe';
3+
3−import { Button, H1, P } from '../components/old/Base';
4+import { H1, P } from '../components/old/Base';
4import { InnerLabelDropdown } from '../components/old/Base';
5import { InnerLabelDropdown } from '../components/old/Base';
5
6
7+import View from 'components/View';
8+import { ForwardButton } from 'components/Buttons';
9+
10+import { useHistory } from '../store/history';
11+import { useWallet } from '../store/wallet';
12+
6import { ROUTE_NAMES } from '../lib/routeNames';
13import { ROUTE_NAMES } from '../lib/routeNames';
7−import { withHistory } from '../store/history';
8import { WALLET_TYPES, renderWalletType } from '../lib/wallet';
14import { WALLET_TYPES, renderWalletType } from '../lib/wallet';
9−import { compose } from '../lib/lib';
15+import useLifecycle from 'lib/useLifecycle';
10−import { withWallet } from '../store/wallet';
11−import View from 'components/View';
12
16
13−class Wallet extends React.Component {
17+const kWalletOptions = [
14− componentDidMount() {
18+ {
15− const { setWallet } = this.props;
19+ title: 'Urbit Master Ticket',
16− setWallet(Maybe.Nothing());
20+ value: WALLET_TYPES.TICKET,
21+ },
22+ {
23+ title: 'Urbit Master Ticket (Shards)',
24+ value: WALLET_TYPES.SHARDS,
25+ },
26+ {
27+ type: 'divider',
28+ },
29+ {
30+ title: 'Ledger',
31+ value: WALLET_TYPES.LEDGER,
17− }
32+ },
33+ {
34+ title: 'Trezor',
35+ value: WALLET_TYPES.TREZOR,
36+ },
37+ {
38+ type: 'divider',
39+ },
40+ {
41+ title: 'BIP39 Mnemonic',
42+ value: WALLET_TYPES.MNEMONIC,
43+ },
44+ {
45+ title: 'Ethereum Private Key',
46+ value: WALLET_TYPES.PRIVATE_KEY,
47+ },
48+ {
49+ title: 'Ethereum Keystore File',
50+ value: WALLET_TYPES.KEYSTORE,
51+ },
52+];
18
53
19− getWalletOptions() {
54+export default function Wallet() {
20− return [
55+ const history = useHistory();
21− {
56+ const { setWallet, walletType, setWalletType } = useWallet();
22− title: 'Urbit Master Ticket',
23− value: WALLET_TYPES.TICKET,
24− },
25− {
26− title: 'Urbit Master Ticket (Shards)',
27− value: WALLET_TYPES.SHARDS,
28− },
29− {
30− type: 'divider',
31− },
32− {
33− title: 'Ledger',
34− value: WALLET_TYPES.LEDGER,
35− },
36− {
37− title: 'Trezor',
38− value: WALLET_TYPES.TREZOR,
39− },
40− {
41− type: 'divider',
42− },
43− {
44− title: 'BIP39 Mnemonic',
45− value: WALLET_TYPES.MNEMONIC,
46− },
47− {
48− title: 'Ethereum Private Key',
49− value: WALLET_TYPES.PRIVATE_KEY,
50− },
51− {
52− title: 'Ethereum Keystore File',
53− value: WALLET_TYPES.KEYSTORE,
54− },
55− ];
56− }
57
57
58− render() {
58+ // reset wallet when this component is mounted
59− const { props } = this;
59+ useLifecycle(() => setWallet(Maybe.Nothing()));
60− const walletOptions = this.getWalletOptions();
61
60
62− return (
61+ return (
63− <View>
62+ <View>
64− <H1>{'Unlock a Wallet'}</H1>
63+ <H1>Unlock a Wallet</H1>
65
64
66− <P>
65+ <P>
67− {`To manage your assets, you need to unlock a wallet.
66+ To manage your assets, you need to unlock a wallet. Please select how
68− Please select how you would like to access your wallet.`}
67+ you would like to access your wallet.
69− </P>
68+ </P>
70
69
71− <InnerLabelDropdown
70+ <InnerLabelDropdown
72− className={'mb-10 mt-6'}
73− title={'Wallet Type:'}
71+ title="Wallet Type:"
74− options={walletOptions}
72+ options={kWalletOptions}
75− handleUpdate={props.setWalletType}
73+ handleUpdate={setWalletType}
76− currentSelectionTitle={renderWalletType(props.walletType)}
74+ currentSelectionTitle={renderWalletType(walletType)}
77− />
75+ />
78
76
79− <Button
77+ <ForwardButton
80− className={'mt-10'}
81− onClick={() =>
78+ onClick={() =>
82− props.history.push(
79+ history.push(
83− props.walletType === WALLET_TYPES.MNEMONIC
80+ walletType === WALLET_TYPES.MNEMONIC
84− ? ROUTE_NAMES.MNEMONIC
81+ ? ROUTE_NAMES.MNEMONIC
85− : props.walletType === WALLET_TYPES.TICKET
82+ : walletType === WALLET_TYPES.TICKET
86− ? ROUTE_NAMES.TICKET
83+ ? ROUTE_NAMES.TICKET
87− : props.walletType === WALLET_TYPES.SHARDS
84+ : walletType === WALLET_TYPES.SHARDS
88− ? ROUTE_NAMES.SHARDS
85+ ? ROUTE_NAMES.SHARDS
89− : props.walletType === WALLET_TYPES.LEDGER
86+ : walletType === WALLET_TYPES.LEDGER
90− ? ROUTE_NAMES.LEDGER
87+ ? ROUTE_NAMES.LEDGER
91− : props.walletType === WALLET_TYPES.TREZOR
88+ : walletType === WALLET_TYPES.TREZOR
92− ? ROUTE_NAMES.TREZOR
89+ ? ROUTE_NAMES.TREZOR
93− : props.walletType === WALLET_TYPES.PRIVATE_KEY
90+ : walletType === WALLET_TYPES.PRIVATE_KEY
94− ? ROUTE_NAMES.PRIVATE_KEY
91+ ? ROUTE_NAMES.PRIVATE_KEY
95− : props.walletType === WALLET_TYPES.KEYSTORE
92+ : walletType === WALLET_TYPES.KEYSTORE
96− ? ROUTE_NAMES.KEYSTORE
93+ ? ROUTE_NAMES.KEYSTORE
97− : ROUTE_NAMES.DEFAULT
94+ : ROUTE_NAMES.DEFAULT
98− )
95+ )
99− }>
96+ }>
100− {'Continue →'}
97+ Continue
101− </Button>
98+ </ForwardButton>
102− </View>
99+ </View>
103− );
100+ );
104− }
105}
101}
106−
107−export default compose(
108− withHistory,
109− withWallet
110−)(Wallet);