@@ -1,43 +1,82 @@
1−import React, { useState } from 'react';
1+import React, { useCallback, useState } from 'react';
22import * as ob from 'urbit-ob';
3−import { Icon, Row, Box } from '@tlon/indigo-react';
3+import { azimuth } from 'azimuth-js';
4+import * as need from 'lib/need';
5+import { Icon, Row, Box, Button } from '@tlon/indigo-react';
46import { Just } from 'folktale/maybe';
57
68import Sigil from 'components/Sigil';
79import LayerIndicator from 'components/L2/LayerIndicator';
10+import CopiableAddressWrap from 'components/copiable/CopiableAddressWrap';
11+
812import { useWallet } from 'store/wallet';
913import { useHistory } from 'store/history';
1014import { usePointCursor } from 'store/pointCursor';
1115import { usePointCache } from 'store/pointCache';
1216import { clearInvitesStorage } from 'store/storage/roller';
13−import CopiableAddressWrap from 'components/copiable/CopiableAddressWrap';
14−import Dropdown from './Dropdown';
17+import { useRollerStore } from 'store/roller';
1518
16−import './AccountsDropdown.scss';
17−import { abbreviateAddress } from 'lib/utils/address';
1819import { PointLayer } from 'lib/types/PointLayer';
20+import { abbreviateAddress } from 'lib/utils/address';
21+
22+import Dropdown from './Dropdown';
23+import './AccountsDropdown.scss';
24+import Modal from '../Modal';
25+import { convertToInt } from 'lib/convertToInt';
1926
20−const AccountsDropdown = () => {
27+interface AccountsDropdownProps {
28+ showMigrate: boolean;
29+}
30+
31+const AccountsDropdown = ({ showMigrate = false }: AccountsDropdownProps) => {
2132 const [open, setOpen] = useState<boolean>(false);
2233 const walletInfo: any = useWallet();
2334 const { push, names, reset }: any = useHistory();
2435 const { setPointCursor }: any = usePointCursor();
2536 const { controlledPoints }: any = usePointCache();
37+ const { currentL2 } = useRollerStore();
38+ const { getDetails }: any = usePointCache();
39+ const { pointCursor }: any = usePointCursor();
40+ const point = pointCursor.getOrElse(null);
41+
42+ let networkKeysNotSet = true;
43+
44+ if (point) {
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;
50+ }
51+
52+ const [showModal, setShowModal] = useState(false);
2653
2754 const canBitcoin = Just.hasInstance(walletInfo.urbitWallet);
2855
29− const points = controlledPoints?.value?.value?.pointsWithLayers || [];
56+ const points = (controlledPoints?.value?.value?.pointsWithLayers || []).sort(
57+ (a: PointLayer, b: PointLayer) => a.point - b.point
58+ );
3059
3160 const currentAddress = walletInfo?.wallet?.value?.address || '';
3261 const displayAddress = abbreviateAddress(currentAddress);
3362
34− const selectPoint = (point: number) => () => {
35− setPointCursor(Just(point));
36− push(names.POINT);
37− setOpen(false);
38− };
39− const goToMigrate = () => push(names.MIGRATE);
40− const goToBitcoin = () => push(names.BITCOIN);
63+ const selectPoint = useCallback(
64+ (point: number) => () => {
65+ setPointCursor(Just(point));
66+ push(names.POINT);
67+ setOpen(false);
68+ },
69+ [push, names.POINT, setOpen, setPointCursor]
70+ );
71+ const goMigrate = useCallback(() => push(names.MIGRATE_L2), [
72+ names.MIGRATE_L2,
73+ push,
74+ ]);
75+ const goBitcoin = useCallback(() => push(names.BITCOIN), [
76+ names.BITCOIN,
77+ push,
78+ ]);
79+
4180 const onLogout = () => {
4281 clearInvitesStorage();
4382 reset();
@@ -74,16 +113,18 @@ const AccountsDropdown = () => {
74113 })}
75114 </Box>
76115 <Box className="divider" />
77− <Row className="entry" onClick={goToMigrate}>
78− <Box>Migrate</Box>
79− <Row className="layer-migration">
80− <LayerIndicator layer={1} size="sm" />
81− <Icon icon="ArrowEast" />
82− <LayerIndicator layer={2} size="sm" />
116+ {(showMigrate || (!currentL2 && !networkKeysNotSet)) && (
117+ <Row className="entry" onClick={() => setShowModal(true)}>
118+ <Box>Migrate</Box>
119+ <Row className="layer-migration">
120+ <LayerIndicator layer={1} size="sm" />
121+ <Icon icon="ArrowEast" />
122+ <LayerIndicator layer={2} size="sm" />
123+ </Row>
83124 </Row>
84− </Row>
125+ )}
85126 {canBitcoin && (
86− <Row className="entry" onClick={goToBitcoin}>
127+ <Row className="entry" onClick={goBitcoin}>
87128 <Box>Bitcoin</Box>
88129 <Icon icon="Bitcoin" />
89130 </Row>
@@ -92,6 +133,27 @@ const AccountsDropdown = () => {
92133 <Box>Logout</Box>
93134 <Icon icon="LogOut" />
94135 </Row>
136+ <Modal show={showModal} hide={() => setShowModal(false)}>
137+ <Box className="migrate-modal">
138+ <Box className="close" onClick={() => setShowModal(false)}>
139+ ×
140+ </Box>
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.
145+ </Box>
146+ <Box className="warning">Migrating to Layer 2 is irreversible.</Box>
147+ <Row className="buttons">
148+ <Button className="cancel" onClick={() => setShowModal(false)}>
149+ Cancel
150+ </Button>
151+ <Button className="migrate" onClick={goMigrate}>
152+ Migrate
153+ </Button>
154+ </Row>
155+ </Box>
156+ </Modal>
95157 </Dropdown>
96158 );
97159};