on master help sign in
Everything but the invite code
commit51e0c25f43d0808f4b2f437a9af256aa227c8c0c authorWill Galebach <willbach@gmail.com> dateTue 12 Oct 2021, 12:58 (5 years ago) parent500886e
30 files changed+601−320
src/assets/metamask.png src/assets/metamask.svg+9 src/assets/wallet-connect.png src/assets/wallet-connect.svg+3 src/components/L2/Dropdowns/FeeDropdown.scss+15 src/components/L2/Dropdowns/FeeDropdown.tsx+48−11 src/components/L2/Headers/L2BackButton.scss+10 src/components/L2/Headers/L2BackButton.tsx+21 src/components/L2/Headers/L2BackHeader.scss+2−7 src/components/L2/Headers/L2BackHeader.tsx+9−3 src/components/L2/Modal.scss+9 src/components/L2/Window/BodyPane.tsx+3−2 src/components/L2/Window/HeaderPane.scss+5 src/indigo-react/components/Button.js+2−2 src/indigo-react/components/Input.js+1−1 src/lib/getSuggestedGasPrice.js+7−6 src/lib/router.js+1−1 src/lib/utils/invite.ts+5−2 src/style/shared/variables.scss+2 src/views/Invite/Cohort.tsx+3−3 src/views/Login.tsx+7−46 src/views/Login/LoginSelector.scss+78 src/views/Login/LoginSelector.tsx+117 src/views/Login/Metamask.js+10−4 src/views/Login/Mnemonic.js+36−30 src/views/Login/Other.js−75 src/views/Login/Other.tsx+77 src/views/Login/Ticket.js+59−56 src/views/Login/WalletConnect.tsx+62−62 src/views/Point/Point.scss−9
src/assets/metamask.pngnew file

Binary file not shown.

src/assets/metamask.svgnew file+9
@@ -0,0 +1,9 @@
1+<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
2+<rect width="24" height="24" fill="url(#pattern0)"/>
3+<defs>
4+<pattern id="pattern0" patternContentUnits="objectBoundingBox" width="1" height="1">
5+<use xlink:href="#image0" transform="scale(0.00444444)"/>
6+</pattern>
7+<image id="image0" width="225" height="225" xlink:href="data:image/png;base64,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"/>
8+</defs>
9+</svg>
src/assets/wallet-connect.pngnew file

Binary file not shown.

src/assets/wallet-connect.svgnew file+3
@@ -0,0 +1,3 @@
1+<svg width="24" height="16" viewBox="0 0 24 16" fill="none" xmlns="http://www.w3.org/2000/svg">
2+<path d="M4.9133 3.51903C8.82718 -0.312985 15.1728 -0.312985 19.0867 3.51903L19.5578 3.98022C19.7535 4.17182 19.7535 4.48247 19.5578 4.67407L17.9464 6.25171C17.8486 6.34751 17.6899 6.34751 17.5921 6.25171L16.9439 5.61706C14.2135 2.94375 9.78657 2.94375 7.05614 5.61706L6.36196 6.29672C6.26412 6.39252 6.10547 6.39252 6.00763 6.29672L4.39629 4.71908C4.20059 4.52748 4.20059 4.21683 4.39629 4.02523L4.9133 3.51903ZM22.4191 6.78176L23.8532 8.18586C24.0489 8.37746 24.0489 8.68811 23.8532 8.87971L17.3868 15.211C17.1911 15.4026 16.8738 15.4026 16.6781 15.211C16.6781 15.211 16.6781 15.211 16.6781 15.211L12.0886 10.7175C12.0397 10.6696 11.9604 10.6696 11.9115 10.7175C11.9115 10.7175 11.9115 10.7175 11.9115 10.7175L7.32207 15.211C7.12638 15.4026 6.80909 15.4026 6.6134 15.211C6.6134 15.211 6.61339 15.211 6.61339 15.211L0.146771 8.87963C-0.0489235 8.68803 -0.0489235 8.37738 0.146771 8.18578L1.58087 6.78168C1.77656 6.59008 2.09385 6.59008 2.28954 6.78168L6.8791 11.2752C6.92802 11.3231 7.00734 11.3231 7.05626 11.2752C7.05626 11.2752 7.05626 11.2752 7.05627 11.2752L11.6456 6.78168C11.8413 6.59007 12.1586 6.59006 12.3543 6.78166C12.3543 6.78166 12.3543 6.78167 12.3543 6.78167L16.9438 11.2752C16.9927 11.3231 17.0721 11.3231 17.121 11.2752L21.7105 6.78176C21.9062 6.59016 22.2234 6.59016 22.4191 6.78176Z" fill="#3B99FC"/>
3+</svg>
src/components/L2/Dropdowns/FeeDropdown.scss+15
@@ -19,12 +19,27 @@
1919 justify-content: space-between;
2020 align-items: center;
2121 cursor: pointer;
22+ line-height: 20px;
2223
2324 padding: 8px 12px 8px 16px;
2425
2526 &:hover {
2627 opacity: 0.8;
2728 }
29+
30+ .label {
31+ margin-right: 32px;
32+ }
33+
34+ .custom-input {
35+ font-family: "Inter", -apple-system, BlinkMacSystemFont, Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji";
36+ text-align: right;
37+ height: 32px;
38+ }
39+
40+ .unit {
41+ margin-left: 4px;
42+ }
2843 }
2944 }
3045 }
src/components/L2/Dropdowns/FeeDropdown.tsx+48−11
@@ -1,5 +1,5 @@
1−import React, { useCallback, useEffect, useState } from 'react';
2−import { Box, Row } from '@tlon/indigo-react';
1+import React, { useCallback, useEffect, useState, FormEvent } from 'react';
2+import { Box, Row, StatelessTextInput } from '@tlon/indigo-react';
33import { DEFAULT_GAS_PRICE_GWEI } from 'lib/constants';
44import useGasPrice from 'lib/useGasPrice';
55
@@ -10,20 +10,49 @@ const PRICE_LABELS = ['Fast', 'Average', 'Slow'];
1010
1111export interface GasPrice {
1212 price: number;
13− wait: number;
13+ wait: string;
1414}
1515
16−const formatPriceWait = ({ price, wait }: GasPrice) =>
17− `${price} gwei (${Math.round(wait * 100) / 100} min)`;
16+export const formatWait = (wait: number) => Math.round(wait * 100) / 100;
17+export const formatDisplay = ({ price, wait }: GasPrice) =>
18+ `${price} gwei (${wait} min)`;
1819
19−const FeeDropdown = ({ setGasPrice }: { setGasPrice: (g: number) => void }) => {
20+export default function FeeDropdown({
21+ setGasPrice,
22+}: {
23+ setGasPrice: (g: number) => void;
24+}) {
2025 const { suggestedGasPrices } = useGasPrice(DEFAULT_GAS_PRICE_GWEI);
2126
22− const [open, setOpen] = useState<boolean>(false);
27+ const [open, setOpen] = useState(false);
28+ const [custom, setCustom] = useState<string>('0');
2329 const [selected, setSelected] = useState<GasPrice>(
2430 suggestedGasPrices.average
2531 );
2632
33+ const handleCustom = (e: FormEvent) => {
34+ const cleanedValue = e.target.value.replace(/[^0-9]/g, '');
35+ const cleanedNum = Number(cleanedValue);
36+ setCustom(cleanedValue);
37+ setGasPrice(cleanedNum);
38+
39+ let customWait = 'Unknown';
40+
41+ const { fast, average, low } = suggestedGasPrices;
42+
43+ if (cleanedNum < low.price) {
44+ customWait = `> ${low.wait}`;
45+ } else if (cleanedNum < average.price) {
46+ customWait = `~${low.wait}`;
47+ } else if (cleanedNum < fast.price) {
48+ customWait = `~${average.wait}`;
49+ } else {
50+ customWait = `< ${fast.wait}`;
51+ }
52+
53+ setSelected({ price: cleanedValue, wait: customWait });
54+ };
55+
2756 useEffect(() => {
2857 setSelected(suggestedGasPrices.average);
2958 }, [suggestedGasPrices]);
@@ -41,7 +70,7 @@ const FeeDropdown = ({ setGasPrice }: { setGasPrice: (g: number) => void }) => {
4170 <Dropdown
4271 className="fee-dropdown"
4372 open={open}
44− value={formatPriceWait(selected)}
73+ value={formatDisplay(selected)}
4574 toggleOpen={() => setOpen(!open)}>
4675 <Box className="prices">
4776 {Object.values(suggestedGasPrices).map(
@@ -50,13 +79,21 @@ const FeeDropdown = ({ setGasPrice }: { setGasPrice: (g: number) => void }) => {
5079 className="price"
5180 onClick={selectPrice(value)}
5281 key={value.wait}>
53− {PRICE_LABELS[ind]}: {formatPriceWait(value)}
82+ {PRICE_LABELS[ind]}: {formatDisplay(value)}
5483 </Row>
5584 )
5685 )}
86+ <Row className="price">
87+ <Box className="label">Custom:</Box>
88+ <StatelessTextInput
89+ value={custom}
90+ className="custom-input"
91+ placeholder="0"
92+ onChange={handleCustom}
93+ />
94+ <Box className="unit">gwei</Box>
95+ </Row>
5796 </Box>
5897 </Dropdown>
5998 );
6099};
61−
62−export default FeeDropdown;
src/components/L2/Headers/L2BackButton.scssnew file+10
@@ -0,0 +1,10 @@
1+@import 'style/shared/variables.scss';
2+
3+svg.back-button {
4+ padding: 6px 9px;
5+ width: 14px;
6+ height: 20px;
7+ background-color: $washed-gray;
8+ border-radius: $medium-border-radius;
9+ cursor: pointer;
10+}
src/components/L2/Headers/L2BackButton.tsxnew file+21
@@ -0,0 +1,21 @@
1+import React from 'react';
2+import { Icon } from '@tlon/indigo-react';
3+import './L2BackButton.scss';
4+
5+interface L2BackButtonProps {
6+ onBack?: () => void;
7+ className?: string;
8+}
9+
10+export default function L2BackButton({
11+ onBack,
12+ className = '',
13+}: L2BackButtonProps) {
14+ return (
15+ <Icon
16+ className={`back-button ${className}`}
17+ icon="ChevronWest"
18+ onClick={onBack}
19+ />
20+ );
21+}
src/components/L2/Headers/L2BackHeader.scss+2−7
@@ -8,13 +8,8 @@
88 font-size: 14px;
99 margin: 48px 0px 8px;
1010
11− svg.back-button {
12− padding: 6px 9px;
13− width: 14px;
14− height: 20px;
15− background-color: $washed-gray;
16− border-radius: $medium-border-radius;
17− cursor: pointer;
11+ .login-margins {
12+ margin: 0px 0px 16px;
1813 }
1914
2015 .rollup-timer {
src/components/L2/Headers/L2BackHeader.tsx+9−3
@@ -12,13 +12,19 @@ import { toBN } from 'web3-utils';
1212import BN from 'bn.js';
1313import { isDevelopment } from 'lib/flags';
1414import { ReactComponent as Wallet } from 'assets/wallet.svg';
15+import L2BackButton from './L2BackButton';
1516
1617export interface L2BackHeaderProps {
1718 back?: () => void;
1819 hideBalance?: boolean;
20+ className: string;
1921}
2022
21−const L2BackHeader = ({ back, hideBalance = false }: L2BackHeaderProps) => {
23+const L2BackHeader = ({
24+ back,
25+ className = '',
26+ hideBalance = false,
27+}: L2BackHeaderProps) => {
2228 const { config } = useRoller();
2329 const { nextRoll, currentL2 } = useRollerStore(store => store);
2430 const { pop }: any = useHistory();
@@ -62,8 +68,8 @@ const L2BackHeader = ({ back, hideBalance = false }: L2BackHeaderProps) => {
6268 const hasBalance = Number(ethBalance.toString()) !== 0;
6369
6470 return (
65− <Row className="l2-back-header">
66− <Icon className="back-button" icon="ChevronWest" onClick={goBack} />
71+ <Row className={`l2-back-header ${className}`}>
72+ <L2BackButton onBack={goBack} />
6773 {currentL2 && !hideBalance ? (
6874 <Row className="rollup-timer">
6975 <Icon icon="Clock" />
src/components/L2/Modal.scss+9
@@ -11,4 +11,13 @@
1111 flex-direction: column;
1212 justify-content: center;
1313 align-items: center;
14+
15+ .close {
16+ position: absolute;
17+ top: 3px;
18+ right: 8px;
19+ font-size: 18px;
20+ font-weight: 200;
21+ cursor: pointer;
22+ }
1423}
src/components/L2/Window/BodyPane.tsx+3−2
@@ -5,10 +5,11 @@ import './BodyPane.scss';
55
66export interface BodyPaneProps {
77 children: React.ReactNode;
8+ className?: string;
89}
910
10−const BodyPane = ({ children }: BodyPaneProps) => {
11− return <Box className="body-pane">{children}</Box>;
11+const BodyPane = ({ children, className = '' }: BodyPaneProps) => {
12+ return <Box className={`body-pane ${className}`}>{children}</Box>;
1213};
1314
1415export default BodyPane;
src/components/L2/Window/HeaderPane.scss+5
@@ -19,6 +19,11 @@
1919 justify-content: space-between;
2020 align-items: center;
2121
22+ svg {
23+ height: 16px;
24+ width: 16px;
25+ }
26+
2227 .header-button {
2328 background-color: black;
2429 color: white;
src/indigo-react/components/Button.js+2−2
@@ -34,9 +34,9 @@ export default function Button({
3434 tabIndex={!disabled ? 0 : undefined}
3535 onKeyPress={handleKeyPress}
3636 className={cn(
37− 'rel pointer pv4 truncate flex-row justify-between us-none',
37+ 'rel pointer pv2 truncate flex-row justify-between us-none r4',
3838 {
39− p4: solid,
39+ p2: solid,
4040 },
4141 {
4242 'bg-green3': success && !disabled,
src/indigo-react/components/Input.js+1−1
@@ -86,7 +86,7 @@ export default function Input({
8686 // NOTE: 1.15 from input line-height, 24px = 12px * 2 (from p3 styling)
8787 style={type === 'textarea' ? { minHeight: 'calc(1.5rem * 3)' } : {}}
8888 className={cn(
89− 'b b1 p3 outline-none bs-none',
89+ 'b b1 p3 outline-none bs-none r4',
9090 { mono },
9191 {
9292 'bg-white': !disabled,
src/lib/getSuggestedGasPrice.js+7−6
@@ -1,5 +1,6 @@
11import { NETWORK_TYPES } from './network';
22import { DEFAULT_GAS_PRICE_GWEI, MAX_GAS_PRICE_GWEI } from './constants';
3+import { formatWait } from 'components/L2/Dropdowns/FeeDropdown';
34
45// ethgasstation returns values in floating point, one order of magitude
56// more than gwei. see: https://docs.ethgasstation.info
@@ -9,15 +10,15 @@ const minGas = gas => Math.min(Math.ceil(gas / 10), MAX_GAS_PRICE_GWEI);
910export const defaultGasValues = value => ({
1011 fast: {
1112 price: value,
12− wait: 1,
13+ wait: '1',
1314 },
1415 average: {
1516 price: value,
16− wait: 1,
17+ wait: '1',
1718 },
1819 low: {
1920 price: value,
20− wait: 1,
21+ wait: '1',
2122 },
2223});
2324
@@ -46,15 +47,15 @@ export default async function getSuggestedGasPrice(networkType) {
4647 return {
4748 fast: {
4849 price: minGas(json.fast),
49− wait: json.fastWait,
50+ wait: formatWait(json.fastWait),
5051 },
5152 average: {
5253 price: minGas(json.average),
53− wait: json.avgWait,
54+ wait: formatWait(json.avgWait),
5455 },
5556 low: {
5657 price: minGas(json.safeLow),
57− wait: json.safeLowWait,
58+ wait: formatWait(json.safeLowWait),
5859 },
5960 };
6061 } catch (e) {
src/lib/router.js+1−1
@@ -1,6 +1,6 @@
11import Disclaimer from 'views/Disclaimer';
22import Login from 'views/Login';
3−import Other from 'views/Login/Other.js';
3+import Other from 'views/Login/Other';
44import Senate from 'views/Point/Senate';
55import Documents from 'views/Senate/Documents';
66import Upgrades from 'views/Senate/Upgrades';
src/lib/utils/invite.ts+5−2
@@ -10,8 +10,11 @@ export const generateUrl = (ticket: string, planet: number) => {
1010 return 'No Ticket or Ship';
1111};
1212
13−export const generateCsvLine = (ticket: string, planet: number) =>
14− `${ob.patp(planet)},${generateUrl(ticket, planet)}\n`;
13+export const generateCsvLine = (ind: number, ticket: string, planet: number) =>
14+ `${ind + 1},${ob.patp(planet)},${generateUrl(
15+ ticket,
16+ planet
17+ )},${planet},${ticket}\n`;
1518
1619export const generateCsvName = (defaultName: string, point: number) =>
1720 `${ob.patp(point).slice(1)}_${defaultName}`;
src/style/shared/variables.scss+2
@@ -11,3 +11,5 @@ $dark-gray: rgba(102, 102, 102, 1);
1111$rollup-yellow: rgba(255, 199, 0, 1);
1212$accept-green: rgba(0, 159, 101, 1);
1313$warning-red: rgb(242, 33, 33);
14+$light-gray-border: 1px solid $light-gray;
15+$activate-blue: rgba(33, 157, 255, 1);
src/views/Invite/Cohort.tsx+3−3
@@ -203,9 +203,9 @@ export default function InviteCohort() {
203203 const invites = await getInvites(currentL2, page, true);
204204 if (invites) {
205205 const csv = invites.reduce(
206− (csvData, { ticket, planet }) =>
207− (csvData += generateCsvLine(ticket, planet)),
208− 'Planet,Invite URL\n'
206+ (csvData, { ticket, planet }, ind) =>
207+ (csvData += generateCsvLine(ind, ticket, planet)),
208+ 'Number,Planet,Invite URL,Point,Ticket\n'
209209 );
210210 const hiddenElement = document.createElement('a');
211211 hiddenElement.href = `data:text/csv;charset=utf-8,${encodeURIComponent(
src/views/Login.tsx+7−46
@@ -1,5 +1,5 @@
11import React, { useCallback, useState } from 'react';
2−import { Grid, Text, Button, Flex, LinkButton } from 'indigo-react';
2+import { Grid, Text, Flex } from 'indigo-react';
33
44import { versionLabel } from 'lib/flags';
55
@@ -10,22 +10,16 @@ import { COMMANDS, useFlowCommand } from 'lib/flowCommand';
1010import View from 'components/View';
1111import Footer from 'components/Footer';
1212
13−import Ticket from './Login/Ticket';
1413import Other from './Login/Other';
1514
1615export default function Login() {
1716 // globals
18− const { push, names } = useHistory();
19− const flow = useFlowCommand();
17+ const { push, names }: any = useHistory();
18+ const flow: any = useFlowCommand();
2019
2120 // inputs
2221 const [isOther, setisOther] = useState(false);
2322
24− const goToActivate = useCallback(() => push(names.ACTIVATE), [
25− push,
26− names.ACTIVATE,
27− ]);
28−
2923 const goHome = useCallback(() => {
3024 if (!flow) {
3125 push(names.POINTS);
@@ -70,50 +64,17 @@ export default function Login() {
7064 <View inset>
7165 <Grid>
7266 <Grid.Item full as={Text} className="flex justify-center mt9 mb7">
73− <Grid.Item as={Text} className="gray3">
74− Urbit ID /&nbsp;
67+ <Grid.Item as={Text}>Bridge /&nbsp;</Grid.Item>
68+ <Grid.Item className="fw-bold" as={Text}>
69+ Log In
7570 </Grid.Item>
76− <Grid.Item as={Text}>Login</Grid.Item>
7771 </Grid.Item>
7872 {flow && (
7973 <Grid.Item full as={Text} className="t-center mb4">
8074 {flowDescription(flow)}
8175 </Grid.Item>
8276 )}
83− <Grid.Item full as={isOther ? Other : Ticket} goHome={goHome} />
84− {!isOther && (
85− <>
86− <Grid.Item full className="t-center mv4 gray4">
87− or
88− </Grid.Item>
89− <Grid.Item
90− full
91− as={Button}
92− className="b-solid b1 b-black"
93− center
94− onClick={() => setisOther(true)}>
95− Metamask, Mnemonic, Hardware Wallet...
96− </Grid.Item>
97− {!flow && (
98− <Grid.Item
99− full
100− onClick={goToActivate}
101− className="mv10 t-center f6">
102− <span className="gray4">New Urbit ID? </span>
103− <LinkButton>Activate</LinkButton>
104− </Grid.Item>
105− )}
106− </>
107− )}
108− {isOther && (
109− <Grid.Item
110− as={LinkButton}
111− onClick={() => setisOther(false)}
112− full
113− className="t-center underline f6 mt8">
114− Back
115− </Grid.Item>
116− )}
77+ <Grid.Item full as={Other} goHome={goHome} className="login-selector" />
11778 </Grid>
11879
11980 <Footer>
src/views/Login/LoginSelector.scssnew file+78
@@ -0,0 +1,78 @@
1+@import 'style/shared/variables.scss';
2+
3+.login-selector {
4+ width: 100%;
5+ min-height: 300px;
6+
7+ .login-menu-item {
8+ padding: 16px 16px;
9+ font-size: 14px;
10+ font-weight: 600;
11+ line-height: 24px;
12+ border-radius: $medium-border-radius;
13+ border: $light-gray-border;
14+ cursor: pointer;
15+ margin-top: 12px;
16+ display: flex;
17+ justify-content: space-between;
18+ align-items: center;
19+
20+ &:first-of-type {
21+ margin-top: 48px;
22+ }
23+
24+ svg {
25+ height: 18px;
26+ width: 16px;
27+ }
28+
29+ svg.logo-icon {
30+ height: 24px;
31+ width: 24px;
32+ }
33+ }
34+
35+ button.activate {
36+ font-size: 14px;
37+ color: white;
38+ font-weight: 600;
39+ background-color: $activate-blue;
40+ margin-top: 12px;
41+ height: 56px;
42+ border: none;
43+ border-radius: $medium-border-radius;
44+ font-family: $default-font;
45+ }
46+
47+ .unsupported-info {
48+ font-size: 14px;
49+ line-height: 18px;
50+ margin-top: 16px;
51+ font-family: $default-font;
52+ text-align: center;
53+ cursor: pointer;
54+
55+ svg {
56+ margin-bottom: -3px;
57+ margin-right: 4px;
58+ height: 16px;
59+ width: 16px;
60+ }
61+ }
62+
63+ .info-modal-content {
64+ position: relative;
65+ background-color: white;
66+ height: 302px;
67+ width: 320px;
68+ border-radius: $large-border-radius;
69+ font-family: $default-font;
70+ padding: 16px 48px 16px 16px;
71+ font-size: 14px;
72+ line-height: 24px;
73+
74+ display: flex;
75+ flex-direction: column;
76+ justify-content: space-between;
77+ }
78+}
src/views/Login/LoginSelector.tsxnew file+117
@@ -0,0 +1,117 @@
1+import React, { useCallback, useState } from 'react';
2+import cn from 'classnames';
3+import { Grid } from 'indigo-react';
4+import Window from 'components/L2/Window/Window';
5+import HeaderPane from 'components/L2/Window/HeaderPane';
6+import BodyPane from 'components/L2/Window/BodyPane';
7+import { Box, Button, Icon, Row, Text } from '@tlon/indigo-react';
8+import L2BackHeader from 'components/L2/Headers/L2BackHeader';
9+
10+import './LoginSelector.scss';
11+import { useHistory } from 'store/history';
12+import Modal from 'components/L2/Modal';
13+import L2BackButton from 'components/L2/Headers/L2BackButton';
14+
15+interface LoginSelectorProps {
16+ className: string;
17+ views: { [key: string]: React.ReactNode };
18+ options: {
19+ text: string;
20+ value: string;
21+ menuIcon: React.ReactNode;
22+ headerIcon: React.ReactNode;
23+ }[];
24+ currentTab?: string;
25+ setCurrentTab: (tab?: string) => void;
26+}
27+
28+export default function LoginSelector({
29+ className,
30+ views,
31+ options,
32+ currentTab,
33+ setCurrentTab,
34+ // Tab props
35+ ...rest
36+}: LoginSelectorProps) {
37+ const { push, names }: any = useHistory();
38+ const [showModal, setShowModal] = useState(false);
39+
40+ const goToActivate = useCallback(() => push(names.ACTIVATE), [
41+ push,
42+ names.ACTIVATE,
43+ ]);
44+
45+ if (!currentTab) {
46+ return (
47+ <Grid className={className}>
48+ {options.map((option, i) => (
49+ <React.Fragment key={option.value}>
50+ <Grid.Item
51+ full
52+ className={cn('f5 pv3 rel pointer login-menu-item')}
53+ onClick={() => setCurrentTab(option.value)}>
54+ {option.text}
55+ {option.menuIcon}
56+ </Grid.Item>
57+ </React.Fragment>
58+ ))}
59+ <Grid.Item full className="activate" as={Button} onClick={goToActivate}>
60+ Activate a Planet
61+ </Grid.Item>
62+ <Grid.Item
63+ full
64+ className="unsupported-info"
65+ as={Text}
66+ onClick={() => setShowModal(true)}>
67+ <Icon icon="Info" />I have a wallet type not supported here
68+ </Grid.Item>
69+ <Modal show={showModal} hide={() => setShowModal(false)}>
70+ <Box className="info-modal-content">
71+ <Box className="close" onClick={() => setShowModal(false)}>
72+ &#215;
73+ </Box>
74+ <span>
75+ <span className="fw-bold">Other Wallet Types</span> <br />
76+ All other wallet types are now supported via Metamask or
77+ WalletConnect.
78+ <br />
79+ <br />
80+ If you are you using a{' '}
81+ <span className="fw-bold">
82+ Hardware Wallet, Ethereum Keystore, Ethereum Private Key
83+ </span>{' '}
84+ please use Metamask going forward.
85+ <br />
86+ <br />
87+ If you are using a{' '}
88+ <span className="fw-bold">non-custodial wallet</span> or{' '}
89+ <span className="fw-bold">mobile wallet</span>, please use
90+ WalletConnect going forward.
91+ </span>
92+ </Box>
93+ </Modal>
94+ </Grid>
95+ );
96+ }
97+
98+ const Tab = views[currentTab];
99+ const currentOption = options.find(({ value }) => value === currentTab);
100+
101+ return (
102+ <Box display="flex" flexDirection="column">
103+ <L2BackButton className="mb4" onBack={() => setCurrentTab(undefined)} />
104+ <Window>
105+ <HeaderPane>
106+ <Row className="header-row">
107+ <h5>{currentOption?.text}</h5>
108+ {currentOption?.headerIcon}
109+ </Row>
110+ </HeaderPane>
111+ <BodyPane className="login-body-pane">
112+ <Grid.Item full as={Tab} {...rest} className="login-selector" />
113+ </BodyPane>
114+ </Window>
115+ </Box>
116+ );
117+}
src/views/Login/Metamask.js+10−4
@@ -74,10 +74,16 @@ function Login({ onSubmit, goHome }) {
7474 </Grid.Item>
7575 <BridgeForm onSubmit={onSubmit} afterSubmit={goHome}>
7676 {({ handleSubmit }) => (
77− <Grid.Item full as={SubmitButton} handleSubmit={handleSubmit}>
78− Login
79− {window.ethereum.selectedAddress &&
80− ' as ' + abbreviateAddress(window.ethereum.selectedAddress)}
77+ <Grid.Item full className="flex-col justify-end">
78+ <Grid.Item
79+ center
80+ full
81+ as={SubmitButton}
82+ handleSubmit={handleSubmit}>
83+ Login
84+ {window.ethereum.selectedAddress &&
85+ ' as ' + abbreviateAddress(window.ethereum.selectedAddress)}
86+ </Grid.Item>
8187 </Grid.Item>
8288 )}
8389 </BridgeForm>
src/views/Login/Mnemonic.js+36−30
@@ -71,52 +71,58 @@ export default function Mnemonic({ className, goHome }) {
7171 };
7272
7373 return (
74− <Grid className={cn('mt4', className)}>
74+ <Grid className={cn(className)}>
7575 <BridgeForm
7676 validate={validate}
7777 onValues={onValues}
7878 afterSubmit={goHome}
7979 initialValues={initialValues}>
8080 {({ handleSubmit }) => (
81− <>
82− <Grid.Item
83− full
84− as={MnemonicInput}
85− name="mnemonic"
86− label="BIP39 Mnemonic"
87− />
81+ <Grid.Item full className="flex-col justify-between">
82+ <Grid.Item full>
83+ <Grid.Item full as={MnemonicInput} name="mnemonic" />
8884
89− <Grid.Item
90− full
91− as={CheckboxInput}
92− name="anyMnemonic"
93− label="Skip mnemonic validation"
94− />
85+ <Grid.Item
86+ full
87+ as={CheckboxInput}
88+ name="anyMnemonic"
89+ label="Skip passphrase validation"
90+ />
91+
92+ <Condition when="useAdvanced" is={true}>
93+ <Grid.Item
94+ full
95+ as={PassphraseInput}
96+ name="passphrase"
97+ label="Passphrase"
98+ />
99+
100+ <Grid.Item
101+ full
102+ as={HdPathInput}
103+ name="hdpath"
104+ label="HD Path"
105+ />
106+ </Condition>
95107
96− <Condition when="useAdvanced" is={true}>
97108 <Grid.Item
98109 full
99− as={PassphraseInput}
100− name="passphrase"
101− label="Passphrase"
110+ as={CheckboxInput}
111+ name="useAdvanced"
112+ label="Passphrase & HD Path"
102113 />
103114
104− <Grid.Item full as={HdPathInput} name="hdpath" label="HD Path" />
105− </Condition>
115+ <Grid.Item full as={FormError} />
116+ </Grid.Item>
106117
107118 <Grid.Item
108119 full
109− as={CheckboxInput}
110− name="useAdvanced"
111− label="Passphrase & HD Path"
112− />
113−
114− <Grid.Item full as={FormError} />
115−
116− <Grid.Item full as={SubmitButton} handleSubmit={handleSubmit}>
117− Login
120+ as={SubmitButton}
121+ handleSubmit={handleSubmit}
122+ center>
123+ Log In
118124 </Grid.Item>
119− </>
125+ </Grid.Item>
120126 )}
121127 </BridgeForm>
122128 </Grid>
src/views/Login/Other.jsdeleted−75
@@ -1,75 +0,0 @@
1−import React, { useState, useMemo } from 'react';
2−import { Grid } from 'indigo-react';
3−
4−import useBreakpoints from 'lib/useBreakpoints';
5−
6−import Accordion from 'components/Accordion';
7−
8−import PrivateKey from './PrivateKey';
9−import Keystore from './Keystore';
10−import Ledger from './Ledger';
11−import Metamask from './Metamask';
12−import Trezor from './Trezor';
13−import Mnemonic from './Mnemonic';
14−import WalletConnect from './WalletConnect';
15−
16−const NAMES = {
17− PRIVATE_KEY: 'PRIVATE_KEY',
18− KEYSTORE: 'KEYSTORE',
19− LEDGER: 'LEDGER',
20− TREZOR: 'TREZOR',
21− METAMASK: 'METAMASK',
22− MNEMONIC: 'MNEMONIC',
23− WALLET_CONNECT: 'WALLET_CONNECT',
24−};
25−
26−const VIEWS = {
27− [NAMES.PRIVATE_KEY]: PrivateKey,
28− [NAMES.KEYSTORE]: Keystore,
29− [NAMES.LEDGER]: Ledger,
30− [NAMES.TREZOR]: Trezor,
31− [NAMES.METAMASK]: Metamask,
32− [NAMES.MNEMONIC]: Mnemonic,
33− [NAMES.WALLET_CONNECT]: WalletConnect,
34−};
35−
36−const OPTIONS = [
37− { text: 'Metamask', value: NAMES.METAMASK },
38− { text: 'Mnemonic (BIP 39)', value: NAMES.MNEMONIC },
39− { text: 'Ledger', value: NAMES.LEDGER },
40− { text: 'Trezor', value: NAMES.TREZOR },
41− { text: 'Ethereum Private Key', value: NAMES.PRIVATE_KEY },
42− { text: 'Ethereum Keystore', value: NAMES.KEYSTORE },
43− { text: 'WalletConnect', value: NAMES.WALLET_CONNECT },
44−];
45−
46−const isHardware = name => !![NAMES.TREZOR, NAMES.LEDGER].find(n => n === name);
47−
48−export default function Other({ className, ...rest }) {
49− const [currentTab, setCurrentTab] = useState(undefined);
50−
51− const hardwareAllowed = useBreakpoints([false, true, true]);
52− const options = useMemo(
53− () =>
54− OPTIONS.map(o =>
55− !isHardware(o.value)
56− ? o
57− : { ...o, disabled: !hardwareAllowed && ' not available on mobile' }
58− ),
59− [hardwareAllowed]
60− );
61− return (
62− <>
63− <Grid.Divider />
64− <Accordion
65− className={className}
66− views={VIEWS}
67− options={options}
68− currentTab={currentTab}
69− onTabChange={setCurrentTab}
70− //
71− {...rest}
72− />
73− </>
74− );
75−}
src/views/Login/Other.tsxnew file+77
@@ -0,0 +1,77 @@
1+import React, { useState } from 'react';
2+import { Icon } from '@tlon/indigo-react';
3+
4+import Metamask from './Metamask';
5+import Ticket from './Ticket';
6+import Mnemonic from './Mnemonic';
7+import WalletConnect from './WalletConnect';
8+import LoginSelector from './LoginSelector';
9+import { ReactComponent as MetamaskIcon } from 'assets/metamask.svg';
10+import { ReactComponent as WalletConnectIcon } from 'assets/wallet-connect.svg';
11+
12+const NAMES = {
13+ METAMASK: 'METAMASK',
14+ MNEMONIC: 'MNEMONIC',
15+ WALLET_CONNECT: 'WALLET_CONNECT',
16+ MASTER_TICKET: 'MASTER_TICKET',
17+};
18+
19+const VIEWS = {
20+ [NAMES.METAMASK]: Metamask,
21+ [NAMES.MNEMONIC]: Mnemonic,
22+ [NAMES.WALLET_CONNECT]: WalletConnect,
23+ [NAMES.MASTER_TICKET]: Ticket,
24+};
25+
26+const rightArrowIcon = <Icon icon="ChevronEast" />;
27+const settingsIcon = <Icon icon="Gear" />;
28+
29+const OPTIONS = [
30+ {
31+ text: 'Master Key',
32+ value: NAMES.MASTER_TICKET,
33+ menuIcon: rightArrowIcon,
34+ headerIcon: settingsIcon,
35+ },
36+ {
37+ text: 'Metamask',
38+ value: NAMES.METAMASK,
39+ menuIcon: <MetamaskIcon className="logo-icon" />,
40+ headerIcon: settingsIcon,
41+ },
42+ {
43+ text: 'WalletConnect',
44+ value: NAMES.WALLET_CONNECT,
45+ menuIcon: <WalletConnectIcon className="logo-icon" />,
46+ headerIcon: settingsIcon,
47+ },
48+ {
49+ text: 'Recovery Phrase',
50+ value: NAMES.MNEMONIC,
51+ menuIcon: rightArrowIcon,
52+ headerIcon: settingsIcon,
53+ },
54+];
55+
56+interface OtherProps {
57+ className: string;
58+ goHome: () => void;
59+}
60+
61+export default function Other({ className, ...rest }: OtherProps) {
62+ const [currentTab, setCurrentTab] = useState<string | undefined>(undefined);
63+
64+ return (
65+ <>
66+ <LoginSelector
67+ className={className}
68+ views={VIEWS}
69+ options={OPTIONS}
70+ currentTab={currentTab}
71+ setCurrentTab={setCurrentTab}
72+ //
73+ {...rest}
74+ />
75+ </>
76+ );
77+}
src/views/Login/Ticket.js+59−56
@@ -209,66 +209,69 @@ export default function Ticket({ className, goHome }) {
209209 validate={validate}
210210 onSubmit={onSubmit}
211211 afterSubmit={goHome}
212+ className="flex-col justify-between"
212213 initialValues={initialValues}>
213214 {({ handleSubmit, values, submitting }) => (
214− <>
215− <Grid.Item full as={PointInput} name="point" />
215+ <Grid.Item full className="flex-col justify-between">
216+ <Grid.Item full>
217+ <Grid.Item full as={PointInput} name="point" />
216218
217− <Condition when="useShards" is={false}>
218− <Grid.Item
219− full
220− as={TicketInput}
221− hidden={values.ticketHidden}
222− labelAccessory={<AdvancedOptions />}
223− accessory={<TicketInputAccessory name="ticketHidden" />}
224− className="mt3"
225− name="ticket"
226− label="Master Ticket"
227− />
228− </Condition>
219+ <Condition when="useShards" is={false}>
220+ <Grid.Item
221+ full
222+ as={TicketInput}
223+ hidden={values.ticketHidden}
224+ labelAccessory={<AdvancedOptions />}
225+ accessory={<TicketInputAccessory name="ticketHidden" />}
226+ className="mt3"
227+ name="ticket"
228+ label="Master Ticket"
229+ />
230+ </Condition>
229231
230− <Condition when="useShards" is={true}>
231− <Grid.Item
232− full
233− as={TicketInput}
234− accessory={<TicketInputAccessory name="ticketHidden" />}
235− hidden={values.ticketHidden}
236− labelAccessory={<AdvancedOptions />}
237− className="mt3"
238− name="shard1"
239− label="Shard 1"
240− />
241− <Grid.Item
242− full
243− as={TicketInput}
244− accessory={<TicketInputAccessory name="ticketHidden" />}
245− hidden={values.ticketHidden}
246− className="mt3"
247− name="shard2"
248− label="Shard 2"
249− />
250− <Grid.Item
251− full
252− as={TicketInput}
253− className="mt3"
254− accessory={<TicketInputAccessory name="ticketHidden" />}
255− hidden={values.ticketHidden}
256− name="shard3"
257− label="Shard 3"
258− />
259− </Condition>
232+ <Condition when="useShards" is={true}>
233+ <Grid.Item
234+ full
235+ as={TicketInput}
236+ accessory={<TicketInputAccessory name="ticketHidden" />}
237+ hidden={values.ticketHidden}
238+ labelAccessory={<AdvancedOptions />}
239+ className="mt3"
240+ name="shard1"
241+ label="Shard 1"
242+ />
243+ <Grid.Item
244+ full
245+ as={TicketInput}
246+ accessory={<TicketInputAccessory name="ticketHidden" />}
247+ hidden={values.ticketHidden}
248+ className="mt3"
249+ name="shard2"
250+ label="Shard 2"
251+ />
252+ <Grid.Item
253+ full
254+ as={TicketInput}
255+ className="mt3"
256+ accessory={<TicketInputAccessory name="ticketHidden" />}
257+ hidden={values.ticketHidden}
258+ name="shard3"
259+ label="Shard 3"
260+ />
261+ </Condition>
260262
261− <Condition when="usePassphrase" is={true}>
262− <Grid.Item
263− full
264− as={PassphraseInput}
265− className="mt3"
266− name="passphrase"
267− label="Wallet Passphrase"
268− />
269− </Condition>
263+ <Condition when="usePassphrase" is={true}>
264+ <Grid.Item
265+ full
266+ as={PassphraseInput}
267+ className="mt3"
268+ name="passphrase"
269+ label="Wallet Passphrase"
270+ />
271+ </Condition>
270272
271− <Grid.Item full as={FormError} />
273+ <Grid.Item full as={FormError} />
274+ </Grid.Item>
272275
273276 <Grid.Item
274277 full
@@ -280,10 +283,10 @@ export default function Ticket({ className, goHome }) {
280283 ? 'Logging in...'
281284 : isWarning
282285 ? 'Login Anyway'
283− : 'Login'
286+ : 'Log In'
284287 }
285288 </Grid.Item>
286− </>
289+ </Grid.Item>
287290 )}
288291 </BridgeForm>
289292 </Grid>
src/views/Login/WalletConnect.tsx+62−62
@@ -30,71 +30,71 @@ const WalletConnectLogin = ({ className, goHome }) => {
3030
3131 return (
3232 connector && (
33− <>
34− <Grid className={className}>
35− {!isConnected() && (
36− <Grid.Item full as={LegacyText} className="f6 gray4 mb3">
37− Note that WalletConnect is a young protocol, not all wallets may
38− work fully
39− </Grid.Item>
40− )}
41−
42− {isConnected() && peerMeta && (
43− <Grid.Item full className="f6 gray5 mt3 mb3">
44− <Grid>
45− <Grid.Item style={{ gridArea: 'auto / 3 / auto / 5' }}>
46− {peerIcon ? (
47− <Image src={peerIcon} />
48− ) : (
49− <LegacyText>Icon Unavailable</LegacyText>
50− )}
51− </Grid.Item>
52− <Grid.Item
53− className={'flex-col align-center justify-center'}
54− style={{ gridArea: 'auto / 6 / auto / 11' }}>
55− <LegacyText as="div">{peerMeta.name}</LegacyText>
56− <LegacyText as="div">
57− {address ? abbreviateAddress(address) : null}
58− </LegacyText>
59− <RestartButton
60− as="a"
61− className={'gray3'}
62− onClick={disconnect}>
63− disconnect
64− </RestartButton>
65− </Grid.Item>
66− </Grid>
67− </Grid.Item>
68− )}
33+ <Grid className={className}>
34+ {!isConnected() && (
35+ <Grid.Item full as={LegacyText} className="f6 gray4 mb3">
36+ Note that WalletConnect is a young protocol, not all wallets may
37+ work fully
38+ </Grid.Item>
39+ )}
6940
70− <BridgeForm onSubmit={onSubmit} afterSubmit={goHome}>
71− {({ handleSubmit, submitting }) => (
72− <>
73− {isConnected() ? (
74− <>
75− <Grid.Item full as={FormError} />
76−
77− <Grid.Item
78− full
79− as={SubmitButton}
80− handleSubmit={handleSubmit}>
81− {submitting
82− ? 'Please check your WalletConnect wallet'
83− : 'Authenticate'}
84− </Grid.Item>
85− </>
41+ {isConnected() && peerMeta && (
42+ <Grid.Item full className="f6 gray5 mt3 mb3">
43+ <Grid>
44+ <Grid.Item style={{ gridArea: 'auto / 3 / auto / 5' }}>
45+ {peerIcon ? (
46+ <Image src={peerIcon} />
8647 ) : (
87− <>
88− <Grid.Item full as={ForwardButton} solid onClick={connect}>
89− {'Connect'}
90− </Grid.Item>
91− </>
48+ <LegacyText>Icon Unavailable</LegacyText>
9249 )}
93− </>
94− )}
95− </BridgeForm>
96− </Grid>
97− </>
50+ </Grid.Item>
51+ <Grid.Item
52+ className={'flex-col align-center justify-center'}
53+ style={{ gridArea: 'auto / 6 / auto / 11' }}>
54+ <LegacyText as="div">{peerMeta.name}</LegacyText>
55+ <LegacyText as="div">
56+ {address ? abbreviateAddress(address) : null}
57+ </LegacyText>
58+ <RestartButton
59+ as="a"
60+ className={'gray3'}
61+ onClick={disconnect}>
62+ disconnect
63+ </RestartButton>
64+ </Grid.Item>
65+ </Grid>
66+ </Grid.Item>
67+ )}
68+
69+ <BridgeForm onSubmit={onSubmit} afterSubmit={goHome}>
70+ {({ handleSubmit, submitting }) => (
71+ <Grid.Item full className="flex-col justify-end">
72+ {isConnected() ? (
73+ <>
74+ <Grid.Item full as={FormError} />
75+
76+ <Grid.Item full as={SubmitButton} handleSubmit={handleSubmit}>
77+ {submitting
78+ ? 'Please check your WalletConnect wallet'
79+ : 'Authenticate'}
80+ </Grid.Item>
81+ </>
82+ ) : (
83+ <>
84+ <Grid.Item
85+ full
86+ center
87+ as={ForwardButton}
88+ solid
89+ onClick={connect}>
90+ {'Connect'}
91+ </Grid.Item>
92+ </>
93+ )}
94+ </Grid.Item>
95+ )}
96+ </BridgeForm>
97+ </Grid>
9898 )
9999 );
100100};
src/views/Point/Point.scss−9
@@ -58,15 +58,6 @@
5858 position: relative;
5959 width: 368px;
6060
61− .close {
62− position: absolute;
63− top: 3px;
64− right: 8px;
65− font-size: 18px;
66− font-weight: 200;
67− cursor: pointer;
68− }
69−
7061 .title {
7162 font-weight: 700;
7263 margin-bottom: 8px;