@@ -1,43 +1,82 @@
1−import React, { useState } from 'react';
1+import React, { useCallback, useState } from 'react';
2import * as ob from 'urbit-ob';
2import * as ob from 'urbit-ob';
3+import { azimuth } from 'azimuth-js';
4+import * as need from 'lib/need';
3−import { Icon, Row, Box } from '@tlon/indigo-react';
5+import { Icon, Row, Box, Button } from '@tlon/indigo-react';
4import { Just } from 'folktale/maybe';
6import { Just } from 'folktale/maybe';
6import Sigil from 'components/Sigil';
8import Sigil from 'components/Sigil';
7import LayerIndicator from 'components/L2/LayerIndicator';
9import LayerIndicator from 'components/L2/LayerIndicator';
10+import CopiableAddressWrap from 'components/copiable/CopiableAddressWrap';
8import { useWallet } from 'store/wallet';
12import { useWallet } from 'store/wallet';
9import { useHistory } from 'store/history';
13import { useHistory } from 'store/history';
10import { usePointCursor } from 'store/pointCursor';
14import { usePointCursor } from 'store/pointCursor';
11import { usePointCache } from 'store/pointCache';
15import { usePointCache } from 'store/pointCache';
12import { clearInvitesStorage } from 'store/storage/roller';
16import { clearInvitesStorage } from 'store/storage/roller';
13−import CopiableAddressWrap from 'components/copiable/CopiableAddressWrap';
17+import { useRollerStore } from 'store/roller';
14−import Dropdown from './Dropdown';
16−import './AccountsDropdown.scss';
17−import { abbreviateAddress } from 'lib/utils/address';
18import { PointLayer } from 'lib/types/PointLayer';
19import { PointLayer } from 'lib/types/PointLayer';
20+import { abbreviateAddress } from 'lib/utils/address';
22+import Dropdown from './Dropdown';
23+import './AccountsDropdown.scss';
24+import Modal from '../Modal';
25+import { convertToInt } from 'lib/convertToInt';
27+interface AccountsDropdownProps {
28+ showMigrate: boolean;
20−const AccountsDropdown = () => {
31+const AccountsDropdown = ({ showMigrate = false }: AccountsDropdownProps) => {
21 const [open, setOpen] = useState<boolean>(false);
32 const [open, setOpen] = useState<boolean>(false);
22 const walletInfo: any = useWallet();
33 const walletInfo: any = useWallet();
23 const { push, names, reset }: any = useHistory();
34 const { push, names, reset }: any = useHistory();
24 const { setPointCursor }: any = usePointCursor();
35 const { setPointCursor }: any = usePointCursor();
25 const { controlledPoints }: any = usePointCache();
36 const { controlledPoints }: any = usePointCache();
37+ const { currentL2 } = useRollerStore();
38+ const { getDetails }: any = usePointCache();
39+ const { pointCursor }: any = usePointCursor();
40+ const point = pointCursor.getOrElse(null);
42+ let networkKeysNotSet = true;
45+ const pointSize = azimuth.getPointSize(point);
46+ const details = need.details(getDetails(point));
47+ const isStarOrGalaxy = pointSize !== azimuth.PointSize.Planet;
48+ const networkRevision = convertToInt(details.keyRevisionNumber, 10);
49+ networkKeysNotSet = !currentL2 && isStarOrGalaxy && networkRevision === 0;
52+ const [showModal, setShowModal] = useState(false);
27 const canBitcoin = Just.hasInstance(walletInfo.urbitWallet);
54 const canBitcoin = Just.hasInstance(walletInfo.urbitWallet);
29− const points = controlledPoints?.value?.value?.pointsWithLayers || [];
56+ const points = (controlledPoints?.value?.value?.pointsWithLayers || []).sort(
57+ (a: PointLayer, b: PointLayer) => a.point - b.point
31 const currentAddress = walletInfo?.wallet?.value?.address || '';
60 const currentAddress = walletInfo?.wallet?.value?.address || '';
32 const displayAddress = abbreviateAddress(currentAddress);
61 const displayAddress = abbreviateAddress(currentAddress);
34− const selectPoint = (point: number) => () => {
63+ const selectPoint = useCallback(
64+ (point: number) => () => {
35− setPointCursor(Just(point));
65+ setPointCursor(Just(point));
36− push(names.POINT);
66+ push(names.POINT);
37− setOpen(false);
67+ setOpen(false);
39− const goToMigrate = () => push(names.MIGRATE);
69+ [push, names.POINT, setOpen, setPointCursor]
71+ const goMigrate = useCallback(() => push(names.MIGRATE_L2), [
40− const goToBitcoin = () => push(names.BITCOIN);
75+ const goBitcoin = useCallback(() => push(names.BITCOIN), [
41 const onLogout = () => {
80 const onLogout = () => {
42 clearInvitesStorage();
81 clearInvitesStorage();
@@ -74,16 +113,18 @@ const AccountsDropdown = () => {
76 <Box className="divider" />
115 <Box className="divider" />
116+ {(showMigrate || (!currentL2 && !networkKeysNotSet)) && (
77− <Row className="entry" onClick={goToMigrate}>
117+ <Row className="entry" onClick={() => setShowModal(true)}>
78− <Box>Migrate</Box>
118+ <Box>Migrate</Box>
79− <Row className="layer-migration">
119+ <Row className="layer-migration">
80− <LayerIndicator layer={1} size="sm" />
120+ <LayerIndicator layer={1} size="sm" />
81− <Icon icon="ArrowEast" />
121+ <Icon icon="ArrowEast" />
82− <LayerIndicator layer={2} size="sm" />
122+ <LayerIndicator layer={2} size="sm" />
85 {canBitcoin && (
126 {canBitcoin && (
86− <Row className="entry" onClick={goToBitcoin}>
127+ <Row className="entry" onClick={goBitcoin}>
87 <Box>Bitcoin</Box>
128 <Box>Bitcoin</Box>
88 <Icon icon="Bitcoin" />
129 <Icon icon="Bitcoin" />
@@ -92,6 +133,27 @@ const AccountsDropdown = () => {
92 <Box>Logout</Box>
133 <Box>Logout</Box>
93 <Icon icon="LogOut" />
134 <Icon icon="LogOut" />
136+ <Modal show={showModal} hide={() => setShowModal(false)}>
137+ <Box className="migrate-modal">
138+ <Box className="close" onClick={() => setShowModal(false)}>
141+ <Box className="title">Migrating to Layer 2</Box>
142+ <Box className="message">
143+ We've upgraded Bridge to support Layer 2 transactions. If you don't
144+ migrate now, you can always do it later.
146+ <Box className="warning">Migrating to Layer 2 is irreversible.</Box>
147+ <Row className="buttons">
148+ <Button className="cancel" onClick={() => setShowModal(false)}>
151+ <Button className="migrate" onClick={goMigrate}>
95 </Dropdown>
157 </Dropdown>