on master help sign in
Merge branch 'master' into hosting-rc
a965851Liam Fitzgerald
package-lock.json+1−1
@@ -1,6 +1,6 @@
1{
1{
2 "name": "bridge",
2 "name": "bridge",
3− "version": "2.3.3",
3+ "version": "2.3.5",
4 "lockfileVersion": 1,
4 "lockfileVersion": 1,
5 "requires": true,
5 "requires": true,
6 "dependencies": {
6 "dependencies": {
package.json+1−1
@@ -1,6 +1,6 @@
1{
1{
2 "name": "bridge",
2 "name": "bridge",
3− "version": "2.3.3",
3+ "version": "2.3.5",
4 "description": "An application for interacting with Azimuth",
4 "description": "An application for interacting with Azimuth",
5 "repository": {
5 "repository": {
6 "type": "git",
6 "type": "git",
src/assets/secret-hidden.svgnew file+17
@@ -0,0 +1,17 @@
1+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
2+<rect width="16" height="16" fill="white"/>
3+<path fill-rule="evenodd" clip-rule="evenodd" d="M8 13C13.0495 13 16 8 16 8C16 8 13.0495 3 8 3C2.95054 3 0 8 0 8C0 8 2.95054 13 8 13ZM8 10C9.10457 10 10 9.10457 10 8C10 6.89543 9.10457 6 8 6C6.89543 6 6 6.89543 6 8C6 9.10457 6.89543 10 8 10Z" fill="black"/>
4+<g filter="url(#filter0_d)">
5+<path d="M2 2.70588L2.70588 2L14 13.2941L13.2941 14L2 2.70588Z" fill="black"/>
6+</g>
7+<defs>
8+<filter id="filter0_d" x="1" y="2" width="13" height="12" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
9+<feFlood flood-opacity="0" result="BackgroundImageFix"/>
10+<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"/>
11+<feOffset dx="-1"/>
12+<feColorMatrix type="matrix" values="0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 1 0"/>
13+<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow"/>
14+<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow" result="shape"/>
15+</filter>
16+</defs>
17+</svg>
src/assets/secret-show.svgnew file+4
@@ -0,0 +1,4 @@
1+<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
2+<rect width="16" height="16" fill="white"/>
3+<path fill-rule="evenodd" clip-rule="evenodd" d="M8 13C13.0495 13 16 8 16 8C16 8 13.0495 3 8 3C2.95054 3 0 8 0 8C0 8 2.95054 13 8 13ZM8 10C9.10457 10 10 9.10457 10 8C10 6.89543 9.10457 6 8 6C6.89543 6 6 6.89543 6 8C6 9.10457 6.89543 10 8 10Z" fill="#B1B2B3"/>
4+</svg>
src/form/Inputs.js+4−3
@@ -18,6 +18,7 @@ const PLACEHOLDER_HD_PATH = DEFAULT_HD_PATH;
18const PLACEHOLDER_MNEMONIC =
18const PLACEHOLDER_MNEMONIC =
19 'example crew supreme gesture quantum web media hazard theory mercy wing kitten';
19 'example crew supreme gesture quantum web media hazard theory mercy wing kitten';
20const PLACEHOLDER_TICKET = '~sampel-ticlyt-migfun-falmel';
20const PLACEHOLDER_TICKET = '~sampel-ticlyt-migfun-falmel';
21+const PLACEHOLDER_PASSWORD = '••••••-••••••-••••••-••••••';
21const PLACEHOLDER_ADDRESS = '0x';
22const PLACEHOLDER_ADDRESS = '0x';
22const PLACEHOLDER_HEX = '0x';
23const PLACEHOLDER_HEX = '0x';
23const PLACEHOLDER_PRIVATE_KEY =
24const PLACEHOLDER_PRIVATE_KEY =
@@ -26,7 +27,7 @@ const PLACEHOLDER_EMAIL = 'email@example.com';
26
27
27const formatPat = buildFormatter([downcase, ensurePatFormat]);
28const formatPat = buildFormatter([downcase, ensurePatFormat]);
28
29
29−export function TicketInput({ name, ...rest }) {
30+export function TicketInput({ name, hidden, ...rest }) {
30 const {
31 const {
31 meta: { valid, error, validating, touched, active },
32 meta: { valid, error, validating, touched, active },
32 } = useField(name, {
33 } = useField(name, {
@@ -41,10 +42,10 @@ export function TicketInput({ name, ...rest }) {
41
42
42 return (
43 return (
43 <Input
44 <Input
44− type="text"
45+ type={hidden ? 'password' : 'text'}
45 name={name}
46 name={name}
46 obscure={value => value.replace(/[^~-]+/g, '••••••')}
47 obscure={value => value.replace(/[^~-]+/g, '••••••')}
47− placeholder={PLACEHOLDER_TICKET}
48+ placeholder={hidden ? PLACEHOLDER_PASSWORD : PLACEHOLDER_TICKET}
48 autoCapitalize="none"
49 autoCapitalize="none"
49 autoCorrect="off"
50 autoCorrect="off"
50 accessory={
51 accessory={
src/indigo-react/components/CheckboxInput.js+14−4
@@ -9,6 +9,9 @@ export default function CheckboxInput({
9 name,
9 name,
10 label,
10 label,
11 className,
11 className,
12+ style,
13+ inline = false,
14+ white = false,
12
15
13 disabled,
16 disabled,
14}) {
17}) {
@@ -23,7 +26,8 @@ export default function CheckboxInput({
23 <Flex
26 <Flex
24 row
27 row
25 align="center"
28 align="center"
26− className={cn(className, 'mv2', {
29+ className={cn(className, {
30+ mv2: !inline,
27 black: !disabled,
31 black: !disabled,
28 gray4: disabled,
32 gray4: disabled,
29 })}
33 })}
@@ -39,19 +43,25 @@ export default function CheckboxInput({
39 <Flex.Item
43 <Flex.Item
40 flex
44 flex
41 as="label"
45 as="label"
46+ className={cn(
47+ { mr3: !inline },
42− className="f6 mr3 lh-tall us-none pointer flex-row align-center"
48+ 'f6 lh-tall us-none pointer flex-row align-center'
49+ )}
43 htmlFor={name}>
50 htmlFor={name}>
44 <Flex
51 <Flex
45 justify="center"
52 justify="center"
46 align="center"
53 align="center"
47− className={cn('b1 p1 mr3', {
54+ className={cn('b1 p1', {
55+ mr3: !inline,
56+ mr1: inline,
48 'bg-gray1': disabled,
57 'bg-gray1': disabled,
49− 'bg-black white b-black': !disabled && input.value,
58+ 'bg-black white b-black': !disabled && (input.value || white),
50 'bg-white black b-black': !disabled && !input.value,
59 'bg-white black b-black': !disabled && !input.value,
51 })}
60 })}
52 style={{
61 style={{
53 height: '14px',
62 height: '14px',
54 width: '14px',
63 width: '14px',
64+ ...style,
55 }}>
65 }}>
56 {input.value && '✓'}
66 {input.value && '✓'}
57 </Flex>
67 </Flex>
src/indigo-react/components/Input.js+9−4
@@ -11,6 +11,7 @@ export default function Input({
11 label,
11 label,
12 className,
12 className,
13 accessory,
13 accessory,
14+ labelAccessory,
14 disabled = false,
15 disabled = false,
15 mono = false,
16 mono = false,
16 obscure,
17 obscure,
@@ -65,13 +66,17 @@ export default function Input({
65 }),
66 }),
66 }}>
67 }}>
67 <Flex.Item
68 <Flex.Item
68− as="label"
69+ as={Flex}
70+ justify="between"
71+ align="center"
69 className={cn('f6 lh-tall', {
72 className={cn('f6 lh-tall', {
70 black: !disabled,
73 black: !disabled,
71 gray4: disabled,
74 gray4: disabled,
72− })}
75+ })}>
73− htmlFor={name}>
76+ <Flex.Item as="label" justify htmlFor={name}>
74− {label}
77+ {label}
78+ </Flex.Item>
79+ {labelAccessory && <Flex.Item>{labelAccessory}</Flex.Item>}
75 </Flex.Item>
80 </Flex.Item>
76 <Flex.Item as={Flex} row className="rel">
81 <Flex.Item as={Flex} row className="rel">
77 <Flex.Item
82 <Flex.Item
src/indigo-react/components/ToggleInput.js+4−1
@@ -11,6 +11,7 @@ export default function ToggleInput({
11 label,
11 label,
12 inverseLabel,
12 inverseLabel,
13 inverseColor = 'black',
13 inverseColor = 'black',
14+ small = false,
14 className,
15 className,
15
16
16 //
17 //
@@ -55,7 +56,9 @@ export default function ToggleInput({
55 htmlFor={name}>
56 htmlFor={name}>
56 <LinkButton
57 <LinkButton
57 disabled={disabled}
58 disabled={disabled}
58− className={cn('f5', {
59+ className={cn({
60+ f5: !small,
61+ f6: small,
59 black: !input.checked,
62 black: !input.checked,
60 [inverseColor]: input.checked,
63 [inverseColor]: input.checked,
61 })}>
64 })}>
src/lib/routeNames.js+1
@@ -8,6 +8,7 @@ export const ROUTE_NAMES = {
8 SENATE: Symbol('SENATE'),
8 SENATE: Symbol('SENATE'),
9 //
9 //
10 LOGIN: Symbol('LOGIN'),
10 LOGIN: Symbol('LOGIN'),
11+ LOGIN_OTHER: Symbol('OTHER'),
11 REDOWNLOAD: Symbol('REDOWNLOAD'),
12 REDOWNLOAD: Symbol('REDOWNLOAD'),
12 RETICKET: Symbol('RETICKET'),
13 RETICKET: Symbol('RETICKET'),
13 PERMISSIONS: Symbol('PERMISSIONS'),
14 PERMISSIONS: Symbol('PERMISSIONS'),
src/lib/router.js+2
@@ -1,5 +1,6 @@
1import Disclaimer from 'views/Disclaimer';
1import Disclaimer from 'views/Disclaimer';
2import Login from 'views/Login.js';
2import Login from 'views/Login.js';
3+import Other from 'views/Login/Other.js';
3import Senate from 'views/Senate';
4import Senate from 'views/Senate';
4import CreateGalaxy from 'views/CreateGalaxy';
5import CreateGalaxy from 'views/CreateGalaxy';
5import IssueChild from 'views/IssueChild';
6import IssueChild from 'views/IssueChild';
@@ -24,6 +25,7 @@ export const ROUTES = {
24 [ROUTE_NAMES.DISCLAIMER]: Disclaimer,
25 [ROUTE_NAMES.DISCLAIMER]: Disclaimer,
25 [ROUTE_NAMES.ACTIVATE]: Activate,
26 [ROUTE_NAMES.ACTIVATE]: Activate,
26 [ROUTE_NAMES.LOGIN]: Login,
27 [ROUTE_NAMES.LOGIN]: Login,
28+ [ROUTE_NAMES.LOGIN_OTHER]: Other,
27 [ROUTE_NAMES.POINTS]: Points,
29 [ROUTE_NAMES.POINTS]: Points,
28 [ROUTE_NAMES.POINT]: Point,
30 [ROUTE_NAMES.POINT]: Point,
29 [ROUTE_NAMES.CREATE_GALAXY]: CreateGalaxy,
31 [ROUTE_NAMES.CREATE_GALAXY]: CreateGalaxy,
src/lib/starRelease.js+29−22
@@ -75,36 +75,43 @@ export async function getConditional(contracts, address) {
75 return { total: 0, available: 0, withdrawn: 0, batchLimits: [] };
75 return { total: 0, available: 0, withdrawn: 0, batchLimits: [] };
76 }
76 }
77
77
78− const forfeited = await conditionalSR.getForfeited(contracts, address);
79 const total = remaining.length;
78 const total = remaining.length;
80 let balance = total;
79 let balance = total;
81
80
82− const withdrawLimits = await batches.reduce(async (p, _, idx) => {
81+ // does not account for forfeiting or withdrawl
83− const acc = await p;
82+ const limits = await Promise.all(
84− if (forfeited[idx] || balance === 0) {
83+ batches.map((_, idx) =>
85− return [...acc, 0];
86− }
87− const limit = await conditionalSR.getWithdrawLimit(contracts, address, idx);
84+ conditionalSR.getWithdrawLimit(contracts, address, idx)
88− if (limit <= balance) {
85+ )
89− balance -= limit;
86+ );
90− return [...acc, limit];
91− }
92− const remaining = balance;
93− balance = 0;
94
87
95− return [...acc, remaining];
88+ const withdrawn = await conditionalSR.getWithdrawn(contracts, address);
96− }, Promise.resolve([]));
97
89
98− const available = withdrawLimits.reduce((acc, val) => acc + val, 0);
90+ const forfeited = await conditionalSR.getForfeited(contracts, address);
99
91
100− const withdrawnAmounts = await conditionalSR.getWithdrawn(contracts, address);
92+ const batchLimits = [];
101
93
102− const withdrawn = withdrawnAmounts.reduce((acc, val) => acc + val, 0);
94+ for (let i = 0; i < limits.length; i++) {
103− const batchLimits = withdrawLimits.map(
95+ // skip batch if forfeited or no stars left
104− (limit, idx) => limit - withdrawnAmounts[idx]
96+ if (forfeited[i] || balance === 0) {
105− );
97+ batchLimits.push(0);
98+ continue;
99+ }
100+ const availableInBatch = limits[i] - withdrawn[i];
101+ if (balance < availableInBatch) {
102+ batchLimits.push(balance);
103+ balance = 0;
104+ continue;
105+ }
106+ batchLimits.push(availableInBatch);
107+ balance = balance - availableInBatch;
108+ }
109+
110+ const withdrawnTotal = withdrawn.reduce((acc, val) => acc + val, 0);
111+ const available =
112+ batchLimits.reduce((acc, val) => acc + val, 0) + withdrawnTotal;
106
113
107− return { total, available, withdrawn, batchLimits };
114+ return { total, available, withdrawn: withdrawnTotal, batchLimits };
108}
115}
109
116
110export async function getLinear(contracts, address) {
117export async function getLinear(contracts, address) {
src/views/Login.js+46−31
@@ -1,5 +1,5 @@
1import React, { useCallback, useState } from 'react';
1import React, { useCallback, useState } from 'react';
2−import { P, H4, Grid } from 'indigo-react';
2+import { P, H4, H5, Grid, Text, Button, Flex, LinkButton } from 'indigo-react';
3
3
4import { version } from '../../package.json';
4import { version } from '../../package.json';
5
5
@@ -45,9 +45,7 @@ export default function Login() {
45 const { walletType } = useWallet();
45 const { walletType } = useWallet();
46
46
47 // inputs
47 // inputs
48− const [currentTab, setCurrentTab] = useState(
48+ const [isOther, setisOther] = useState(false);
49− walletTypeToViewName(walletType)
50− );
51
49
52 const goToActivate = useCallback(() => push(names.ACTIVATE), [
50 const goToActivate = useCallback(() => push(names.ACTIVATE), [
53 push,
51 push,
@@ -61,37 +59,54 @@ export default function Login() {
61 return (
59 return (
62 <View inset>
60 <View inset>
63 <Grid>
61 <Grid>
64− <Grid.Item full as={Crumbs} routes={[{ text: 'Bridge' }]} />
62+ <Grid.Item full as={Text} className="flex justify-center mt9 mb7">
65− <Grid.Item full as={H4} className="mt4">
63+ <Grid.Item as={Text} className="gray3">
66− Login
64+ Urbit ID /&nbsp;
65+ </Grid.Item>
67− </Grid.Item>
66+ <Grid.Item as={Text}>Login</Grid.Item>
68−
69− <Grid.Item
70− full
71− as={Tabs}
72− className="mt1"
73− // Tabs
74− views={VIEWS}
75− options={OPTIONS}
76− currentTab={currentTab}
77− onTabChange={setCurrentTab}
78− // Tab extra
79− goHome={goHome}
80− />
81− <Grid.Item full as={P} className="f6">
82− Version {version}
83 </Grid.Item>
67 </Grid.Item>
68+ {isOther && <Grid.Item full as={Other} goHome={goHome} />}
69+ {!isOther && <Grid.Item full as={Ticket} goHome={goHome} />}
70+ {!isOther && (
71+ <>
72+ <Grid.Item full className="t-center mv4 gray4">
73+ or
74+ </Grid.Item>
75+ <Grid.Item
76+ full
77+ as={Button}
78+ className="b-solid b1 b-black"
79+ center
80+ onClick={() => setisOther(true)}>
81+ Metamask, Mnemonic, Hardware Wallet...
82+ </Grid.Item>
83+ <Grid.Item full onClick={goToActivate} className="mv10 t-center f6">
84+ <span className="gray4">New Urbit ID? </span>
85+ <LinkButton>Activate</LinkButton>
86+ </Grid.Item>
87+ </>
88+ )}
89+ {isOther && (
90+ <Grid.Item
91+ as={LinkButton}
92+ onClick={() => setisOther(false)}
93+ full
94+ className="t-center underline f6 mt8">
95+ Back
96+ </Grid.Item>
97+ )}
84 </Grid>
98 </Grid>
85
99
86 <Footer>
100 <Footer>
87− <Grid>
101+ <Flex className="mb8 f6" justify="between">
88− <Grid.Divider />
102+ <Flex.Item
89− <Grid.Item full as={ForwardButton} onClick={goToActivate}>
103+ as="a"
90− Activate
104+ href="https://github.com/urbit/bridge/releases"
105+ className="us-none pointer">
106+ <span className="underline">Offline</span> ↗
91− </Grid.Item>
107+ </Flex.Item>
92− <Grid.Divider />
108+ <Flex.Item className="gray4">v{version}</Flex.Item>
93− <Grid.Item full as={OfflineButton} />
109+ </Flex>
94− </Grid>
95 </Footer>
110 </Footer>
96 </View>
111 </View>
97 );
112 );
src/views/Login/Keystore.js+2−2
@@ -1,6 +1,6 @@
1import React, { useCallback, useMemo } from 'react';
1import React, { useCallback, useMemo } from 'react';
2import { Just } from 'folktale/maybe';
2import { Just } from 'folktale/maybe';
3−import { P, Grid } from 'indigo-react';
3+import { Text, Grid } from 'indigo-react';
4import * as keythereum from 'keythereum';
4import * as keythereum from 'keythereum';
5
5
6import { useWallet } from 'store/wallet';
6import { useWallet } from 'store/wallet';
@@ -56,7 +56,7 @@ export default function Keystore({ className, goHome }) {
56
56
57 return (
57 return (
58 <Grid className={className}>
58 <Grid className={className}>
59− <Grid.Item full as={P}>
59+ <Grid.Item full as={Text} className="f6 gray4 mb3">
60 Please upload your Ethereum keystore file. If your keystore file is
60 Please upload your Ethereum keystore file. If your keystore file is
61 encrypted with a password, you'll also need to enter that below.
61 encrypted with a password, you'll also need to enter that below.
62 </Grid.Item>
62 </Grid.Item>
src/views/Login/Ledger.js+1−4
@@ -150,10 +150,7 @@ export default function Ledger({ className, goHome }) {
150
150
151 const renderHTTPS = () => (
151 const renderHTTPS = () => (
152 <>
152 <>
153− <Grid.Item full as={H5}>
153+ <Grid.Item full as={Text} className="f6 gray4 mb3">
154− Authenticate With Your Ledger
155− </Grid.Item>
156− <Grid.Item full as={Text} className="f6 mb3">
157 Connect and authenticate to your Ledger, and then open the "Ethereum"
154 Connect and authenticate to your Ledger, and then open the "Ethereum"
158 application. If you're running on older firmware, make sure the "browser
155 application. If you're running on older firmware, make sure the "browser
159 support" option is turned on. To sign transactions, you'll also need to
156 support" option is turned on. To sign transactions, you'll also need to
src/views/Login/Metamask.js+1−4
@@ -47,10 +47,7 @@ function Unsupported() {
47function Login({ onSubmit, goHome }) {
47function Login({ onSubmit, goHome }) {
48 return (
48 return (
49 <>
49 <>
50− <Grid.Item full as={H5}>
50+ <Grid.Item full as={Text} className="f6 gray4 mb3">
51− Authenticate with Metamask
52− </Grid.Item>
53− <Grid.Item full as={Text} className="f6 mb3">
54 If you wish to login with a different wallet, please change it in the
51 If you wish to login with a different wallet, please change it in the
55 Metamask extension
52 Metamask extension
56 </Grid.Item>
53 </Grid.Item>
src/views/Login/Mnemonic.js+1−1
@@ -113,7 +113,7 @@ export default function Mnemonic({ className, goHome }) {
113 <Grid.Item full as={FormError} />
113 <Grid.Item full as={FormError} />
114
114
115 <Grid.Item full as={SubmitButton} handleSubmit={handleSubmit}>
115 <Grid.Item full as={SubmitButton} handleSubmit={handleSubmit}>
116− Continue
116+ Login
117 </Grid.Item>
117 </Grid.Item>
118 </>
118 </>
119 )}
119 )}
src/views/Login/Other.js+15−10
@@ -1,7 +1,9 @@
1import React, { useState, useMemo } from 'react';
1import React, { useState, useMemo } from 'react';
2+import { Grid } from 'indigo-react';
2
3
3import useBreakpoints from 'lib/useBreakpoints';
4import useBreakpoints from 'lib/useBreakpoints';
4
5
6+import View from 'components/View';
5import Accordion from 'components/Accordion';
7import Accordion from 'components/Accordion';
6
8
7import PrivateKey from './PrivateKey';
9import PrivateKey from './PrivateKey';
@@ -30,10 +32,10 @@ const VIEWS = {
30};
32};
31
33
32const OPTIONS = [
34const OPTIONS = [
35+ { text: 'Metamask', value: NAMES.METAMASK },
33 { text: 'Mnemonic (BIP 39)', value: NAMES.MNEMONIC },
36 { text: 'Mnemonic (BIP 39)', value: NAMES.MNEMONIC },
34 { text: 'Ledger', value: NAMES.LEDGER },
37 { text: 'Ledger', value: NAMES.LEDGER },
35 { text: 'Trezor', value: NAMES.TREZOR },
38 { text: 'Trezor', value: NAMES.TREZOR },
36− { text: 'Metamask', value: NAMES.METAMASK },
37 { text: 'Ethereum Private Key', value: NAMES.PRIVATE_KEY },
39 { text: 'Ethereum Private Key', value: NAMES.PRIVATE_KEY },
38 { text: 'Ethereum Keystore', value: NAMES.KEYSTORE },
40 { text: 'Ethereum Keystore', value: NAMES.KEYSTORE },
39];
41];
@@ -54,14 +56,17 @@ export default function Other({ className, ...rest }) {
54 [hardwareAllowed]
56 [hardwareAllowed]
55 );
57 );
56 return (
58 return (
59+ <>
60+ <Grid.Divider />
57− <Accordion
61+ <Accordion
58− className={className}
62+ className={className}
59− views={VIEWS}
63+ views={VIEWS}
60− options={options}
64+ options={options}
61− currentTab={currentTab}
65+ currentTab={currentTab}
62− onTabChange={setCurrentTab}
66+ onTabChange={setCurrentTab}
63− //
67+ //
64− {...rest}
68+ {...rest}
65− />
69+ />
70+ </>
66 );
71 );
67}
72}
src/views/Login/PrivateKey.js+1−1
@@ -53,7 +53,7 @@ export default function PrivateKey({ className, goHome }) {
53 />
53 />
54 <Grid.Item full as={FormError} />
54 <Grid.Item full as={FormError} />
55 <Grid.Item full as={SubmitButton} handleSubmit={handleSubmit}>
55 <Grid.Item full as={SubmitButton} handleSubmit={handleSubmit}>
56− Continue
56+ Login
57 </Grid.Item>
57 </Grid.Item>
58 </>
58 </>
59 )}
59 )}
src/views/Login/Ticket.js+81−35
@@ -3,7 +3,13 @@ import { Just } from 'folktale/maybe';
3import cn from 'classnames';
3import cn from 'classnames';
4import * as azimuth from 'azimuth-js';
4import * as azimuth from 'azimuth-js';
5import * as kg from 'urbit-key-generation';
5import * as kg from 'urbit-key-generation';
6+import {
7+ Grid,
8+ CheckboxInput,
9+ Flex,
10+ ToggleInput,
11+ AccessoryIcon,
6−import { Grid, CheckboxInput, Flex, ToggleInput } from 'indigo-react';
12+} from 'indigo-react';
7import { FORM_ERROR } from 'final-form';
13import { FORM_ERROR } from 'final-form';
8
14
9import { useNetwork } from 'store/network';
15import { useNetwork } from 'store/network';
@@ -31,6 +37,56 @@ import FormError from 'form/FormError';
31import SubmitButton from 'form/SubmitButton';
37import SubmitButton from 'form/SubmitButton';
32import { WARNING } from 'form/helpers';
38import { WARNING } from 'form/helpers';
33
39
40+import { ReactComponent as SecretShowIcon } from 'assets/secret-show.svg';
41+import { ReactComponent as SecretHideIcon } from 'assets/secret-hidden.svg';
42+
43+function AdvancedOptions() {
44+ return (
45+ <Flex.Item as={Flex}>
46+ <Condition when="useAdvanced" is={true}>
47+ <Flex.Item
48+ as={CheckboxInput}
49+ inline
50+ white
51+ className="mr4"
52+ name="usePassphrase"
53+ label="Passphrase"
54+ style={{ boxSizing: 'border-box' }}
55+ />
56+ <Flex.Item
57+ as={CheckboxInput}
58+ inline
59+ white
60+ className="mr4"
61+ name="useShards"
62+ label="Shards"
63+ style={{ boxSizing: 'border-box' }}
64+ />
65+ </Condition>
66+ <Flex.Item
67+ as={ToggleInput}
68+ name="useAdvanced"
69+ label="Settings"
70+ small
71+ inverseLabel="Close"
72+ />
73+ </Flex.Item>
74+ );
75+}
76+
77+function TicketInputAccessory({ name }) {
78+ return (
79+ <AccessoryIcon>
80+ <ToggleInput
81+ name={name}
82+ className="mt1"
83+ inverseLabel={<SecretShowIcon />}
84+ label={<SecretHideIcon />}
85+ />
86+ </AccessoryIcon>
87+ );
88+}
89+
34export default function Ticket({ className, goHome }) {
90export default function Ticket({ className, goHome }) {
35 useLoginView(WALLET_TYPES.TICKET);
91 useLoginView(WALLET_TYPES.TICKET);
36
92
@@ -124,7 +180,7 @@ export default function Ticket({ className, goHome }) {
124 shard1: buildPatqValidator(),
180 shard1: buildPatqValidator(),
125 shard2: buildPatqValidator(),
181 shard2: buildPatqValidator(),
126 shard3: buildPatqValidator(),
182 shard3: buildPatqValidator(),
127− showTicket: buildCheckboxValidator(),
183+ ticketHidden: buildCheckboxValidator(),
128 passphrase: buildPassphraseValidator(),
184 passphrase: buildPassphraseValidator(),
129 },
185 },
130 validateForm
186 validateForm
@@ -137,14 +193,14 @@ export default function Ticket({ className, goHome }) {
137 point: impliedPoint || '',
193 point: impliedPoint || '',
138 usePasshrase: false,
194 usePasshrase: false,
139 useShards: false,
195 useShards: false,
140− showTicket: true,
196+ ticketHidden: true,
141 useAdvanced: false,
197 useAdvanced: false,
142 }),
198 }),
143 [impliedPoint]
199 [impliedPoint]
144 );
200 );
145
201
146 return (
202 return (
147− <Grid className={cn('mt4', className)}>
203+ <Grid className={className}>
148 <BridgeForm
204 <BridgeForm
149 validate={validate}
205 validate={validate}
150 onSubmit={onSubmit}
206 onSubmit={onSubmit}
@@ -158,7 +214,10 @@ export default function Ticket({ className, goHome }) {
158 <Grid.Item
214 <Grid.Item
159 full
215 full
160 as={TicketInput}
216 as={TicketInput}
161− type={values.showTicket ? 'text' : 'password'}
217+ hidden={values.ticketHidden}
218+ labelAccessory={<AdvancedOptions />}
219+ accessory={<TicketInputAccessory name="ticketHidden" />}
220+ className="mt3"
162 name="ticket"
221 name="ticket"
163 label="Master Ticket"
222 label="Master Ticket"
164 />
223 />
@@ -168,32 +227,38 @@ export default function Ticket({ className, goHome }) {
168 <Grid.Item
227 <Grid.Item
169 full
228 full
170 as={TicketInput}
229 as={TicketInput}
171− type={values.showTicket ? 'text' : 'password'}
230+ accessory={<TicketInputAccessory name="ticketHidden" />}
231+ hidden={values.ticketHidden}
232+ labelAccessory={<AdvancedOptions />}
233+ className="mt3"
172 name="shard1"
234 name="shard1"
173 label="Shard 1"
235 label="Shard 1"
174 />
236 />
175 <Grid.Item
237 <Grid.Item
176 full
238 full
177 as={TicketInput}
239 as={TicketInput}
178− type={values.showTicket ? 'text' : 'password'}
240+ accessory={<TicketInputAccessory name="ticketHidden" />}
241+ hidden={values.ticketHidden}
242+ className="mt3"
179 name="shard2"
243 name="shard2"
180 label="Shard 2"
244 label="Shard 2"
181 />
245 />
182 <Grid.Item
246 <Grid.Item
183 full
247 full
184 as={TicketInput}
248 as={TicketInput}
185− type={values.showTicket ? 'text' : 'password'}
249+ className="mt3"
250+ accessory={<TicketInputAccessory name="ticketHidden" />}
251+ hidden={values.ticketHidden}
186 name="shard3"
252 name="shard3"
187 label="Shard 3"
253 label="Shard 3"
188 />
254 />
189 </Condition>
255 </Condition>
190
256
191− <Grid.Item full as={CheckboxInput} name="showTicket" label="Show" />
192−
193 <Condition when="usePassphrase" is={true}>
257 <Condition when="usePassphrase" is={true}>
194 <Grid.Item
258 <Grid.Item
195 full
259 full
196 as={PassphraseInput}
260 as={PassphraseInput}
261+ className="mt3"
197 name="passphrase"
262 name="passphrase"
198 label="Wallet Passphrase"
263 label="Wallet Passphrase"
199 />
264 />
@@ -201,38 +266,19 @@ export default function Ticket({ className, goHome }) {
201
266
202 <Grid.Item full as={FormError} />
267 <Grid.Item full as={FormError} />
203
268
269+ <Grid.Item
270+ full
271+ as={SubmitButton}
272+ center
204− <Grid.Item full as={SubmitButton} handleSubmit={handleSubmit}>
273+ handleSubmit={handleSubmit}>
205 {isWarning =>
274 {isWarning =>
206 submitting
275 submitting
207 ? 'Logging in...'
276 ? 'Logging in...'
208 : isWarning
277 : isWarning
209 ? 'Login Anyway'
278 ? 'Login Anyway'
210− : 'Continue'
279+ : 'Login'
211 }
280 }
212 </Grid.Item>
281 </Grid.Item>
213−
214− <Grid.Item full as={Flex} justify="between">
215− <Flex.Item
216− as={ToggleInput}
217− name="useAdvanced"
218− label="Advanced"
219− inverseLabel="Hide"
220− />
221− <Condition when="useAdvanced" is={true}>
222− <Flex.Item as={Flex}>
223− <Flex.Item
224− as={CheckboxInput}
225− name="usePassphrase"
226− label="Passphrase"
227− />
228− <Flex.Item
229− as={CheckboxInput}
230− name="useShards"
231− label="Shards"
232− />
233− </Flex.Item>
234− </Condition>
235− </Grid.Item>
236 </>
282 </>
237 )}
283 )}
238 </BridgeForm>
284 </BridgeForm>
src/views/Login/Trezor.js+1−5
@@ -94,11 +94,7 @@ export default function Trezor({ className, goHome }) {
94
94
95 return (
95 return (
96 <Grid className={className}>
96 <Grid className={className}>
97− <Grid.Item full as={H5}>
97+ <Grid.Item full as={Text} className="f6 gray4 mb3">
98− Authenticate With Your Trezor
99− </Grid.Item>
100−
101− <Grid.Item full as={Text} className="f6 mb3">
102 Connect and authenticate to your Trezor. If you'd like to use a custom
98 Connect and authenticate to your Trezor. If you'd like to use a custom
103 derivation path, you may enter it below.
99 derivation path, you may enter it below.
104 </Grid.Item>
100 </Grid.Item>