on df0c310 help sign in
bridge/src/views/Point/Point.tsx
216 lines 7.2 kB history raw
1import { useCallback, useEffect, useState, useRef } from 'react';
2import { Just } from 'folktale/maybe';
3import { Grid, Flex } from 'indigo-react';
4import { Box, Icon, Row, Button, Checkbox } from '@tlon/indigo-react';
6import { usePointCache } from 'store/pointCache';
7import { useWallet } from 'store/wallet';
8import { useRollerStore } from 'store/rollerStore';
9import { useTimerStore } from 'store/timerStore';
11import View from 'components/View';
12import Greeting from 'components/Greeting';
13import Passport from 'components/Passport';
14import L2PointHeader from 'components/L2/Headers/L2PointHeader';
15import Card from 'components/L2/Card';
17import * as need from 'lib/need';
18import { useLocalRouter } from 'lib/LocalRouter';
19import useRoller from 'lib/useRoller';
20import useSeenMissingKeys from 'lib/useSeenMissingKeys';
21import { useHasNetworkKeysSet } from 'lib/useHasNetworkKeysSet';
23import LoadingOverlay from 'components/L2/LoadingOverlay';
24import PendingTransaction from 'components/L2/PendingTransaction';
25import Modal from 'components/L2/Modal';
26import './Point.scss';
27import { TransactionRow } from 'views/Transactions/TransactionRow';
28import { useInvites } from 'views/Invite/useInvites';
30export default function Point() {
31 const { pop, push, names }: any = useLocalRouter();
32 const { wallet }: any = useWallet();
33 const { syncExtras }: any = usePointCache();
34 const { getPendingTransactions } = useRoller();
35 const { getInvites } = useInvites();
36 const { pendingTransactions, point, pendingL1ByPoint } = useRollerStore();
37 const { nextRoll } = useTimerStore();
38 const networkKeysSet = useHasNetworkKeysSet();
39 const [seenMissingKeys, setSeenMissingKeys] = useSeenMissingKeys();
40 const [showModal, setShowModal] = useState(false);
41 const [hideMessage, setHideMessage] = useState(false);
42 const [loading, setLoading] = useState(false);
44 const pointRef = useRef<number | null>(null);
46 const pendingL1Transactions = pendingL1ByPoint[point.value] || [];
48 const hideModal = useCallback(() => {
49 if (hideMessage) {
50 setSeenMissingKeys(true);
51 }
53 setShowModal(false);
54 }, [hideMessage, setShowModal, setSeenMissingKeys]);
56 useEffect(() => {
57 if (!pointRef.current || pointRef.current !== point.value) {
58 pointRef.current = point.value;
59 setShowModal(!point.networkKeysSet && !seenMissingKeys);
60 }
61 }, [seenMissingKeys, point]);
63 const loadL1Info = useCallback(async () => {
64 await syncExtras(point.value);
65 }, [point, syncExtras]);
67 const loadL2Info = useCallback(async () => {
68 const getTransactions = async () => {
69 setLoading(true);
70 getPendingTransactions();
71 if (point.isStar && (point.canSpawn || point.canManage)) {
72 getInvites();
73 }
74 setTimeout(() => setLoading(false), 100);
75 };
77 await getTransactions();
78 }, [getInvites, getPendingTransactions, setLoading]); // eslint-disable-line react-hooks/exhaustive-deps
80 useEffect(() => {
81 loadL1Info();
82 loadL2Info();
83 }, [point]); // eslint-disable-line react-hooks/exhaustive-deps
85 const { isParent, canManage, isSpawnProxy } = point;
87 const goUrbitOS = useCallback(() => {
88 if (hideMessage) setSeenMissingKeys(hideMessage);
90 push(names.URBIT_OS);
91 }, [push, names, hideMessage, setSeenMissingKeys]);
93 const goUrbitID = useCallback(() => push(names.URBIT_ID), [push, names]);
95 const goOps = useCallback(() => push(names.OPS), [push, names]);
97 const address = need.addressFromWallet(wallet);
98 const spawnedPending = pendingTransactions.filter(
99 ({ rawTx }) => rawTx?.tx?.type === 'spawn'
100 ).length;
101 const otherPending = pendingTransactions.filter(
102 ({ rawTx }) => rawTx?.tx?.type !== 'spawn'
103 );
105 return (
106 <View
107 pop={pop}
108 inset
109 className="point"
110 hideBack
111 header={<L2PointHeader hideInvites={!networkKeysSet} />}>
112 <Greeting point={point.value} />
113 {!!spawnedPending && (
114 <PendingTransaction
115 layer={2}
116 nextRoll={nextRoll}
117 title={`${spawnedPending} Planet${
118 spawnedPending > 1 ? 's' : ''
119 } Spawned`}
120 />
121 )}
122 {!!otherPending.length &&
123 otherPending.map(pendingTx => (
124 <TransactionRow
125 className="point-view"
126 key={pendingTx.time}
127 ship={point.patp}
128 type={pendingTx.rawTx?.tx?.type}
129 status="pending"
130 time={pendingTx.time}
131 />
132 ))}
133 {!!pendingL1Transactions.length &&
134 pendingL1Transactions.map((pendingTx, ind) => (
135 <TransactionRow
136 className="point-view"
137 key={pendingTx.time}
138 ship={point.patp}
139 type={pendingTx.type as string}
140 status="pending"
141 time={pendingTx.time}
142 hash={pendingTx.hash}
143 layer={1}
144 />
145 ))}
146 <Passport
147 point={Just(point.value)}
148 address={Just(address)}
149 animationMode={'slide'}
150 />
151 <Grid gap={4}>
152 {isParent && (
153 <Grid.Item full as={Flex} justify="between">
154 <Card
155 icon={(<Icon icon="ShipActivated" />) as any}
156 title={`${point.isStar ? 'Star' : 'Galaxy'} Ops`}
157 subtitle={
158 point.isStar
159 ? 'Residents, Requests, Spawn Planets'
160 : 'Residents, Requests, Spawn Stars, Vote'
161 }
162 onClick={goOps}
163 />
164 </Grid.Item>
165 )}
166 {(canManage || isSpawnProxy) && (
167 <Grid.Item full as={Flex} justify="between">
168 <Card
169 title="ID"
170 subtitle="Master Key, Passport, Proxy Addresses, etc"
171 icon={(<Icon icon="User" />) as any}
172 onClick={goUrbitID}
173 disabled={!(canManage || isSpawnProxy)}
174 />
175 </Grid.Item>
176 )}
177 {canManage && (
178 <Grid.Item full as={Flex} justify="between">
179 <Card
180 title="OS"
181 subtitle="Sponsor, Network Keys, Access Key"
182 icon={(<Icon icon="Server" />) as any}
183 onClick={goUrbitOS}
184 disabled={!canManage}
185 />
186 </Grid.Item>
187 )}
188 </Grid>
189 <Modal show={showModal} hide={hideModal}>
190 <Box className="network-keys-modal">
191 <Box className="title">No Network Keys Found</Box>
192 <Box className="message">
193 Network Keys are required to generate a Keyfile and use Landscape.
194 </Box>
195 <Row className="hide-row">
196 <Checkbox
197 className="checkbox"
198 selected={hideMessage}
199 onClick={() => setHideMessage(!hideMessage)}
200 />
201 <Box className="dont-show">Do not warn me again</Box>
202 </Row>
203 <Row className="buttons">
204 <Button className="cancel" onClick={hideModal}>
205 Cancel
206 </Button>
207 <Button className="migrate" onClick={goUrbitOS}>
208 Set Network Keys
209 </Button>
210 </Row>
211 </Box>
212 </Modal>
213 <LoadingOverlay loading={loading} />
214 </View>
215 );