on f3545aa help sign in
bridge/src/views/Point/Point.js
361 lines 10 kB history raw
1import React, { useCallback, useEffect, useState } from 'react';
2import cn from 'classnames';
3import { azimuth } from 'azimuth-js';
4import { Just } from 'folktale/maybe';
5import { Grid, Flex } from 'indigo-react';
6import { Box, Icon, Row, Button } from '@tlon/indigo-react';
8import { usePointCursor } from 'store/pointCursor';
9import { useWallet } from 'store/wallet';
10import { useRollerStore } from 'store/roller';
12import View from 'components/View';
13import Greeting from 'components/Greeting';
14import Passport from 'components/Passport';
15import Blinky from 'components/Blinky';
16import BarGraph from 'components/BarGraph';
17import Chip from 'components/Chip';
18import InviteSigilList from 'components/InviteSigilList';
19import { ForwardButton } from 'components/Buttons';
20import L2PointHeader from 'components/L2/Headers/L2PointHeader';
21import LayerIndicator from 'components/L2/LayerIndicator';
22import Card from 'components/L2/Card';
24import * as need from 'lib/need';
25import useInvites from 'lib/useInvites';
26import { useSyncExtras } from 'lib/useSyncPoints';
27import useCurrentPermissions from 'lib/useCurrentPermissions';
28import { useLocalRouter } from 'lib/LocalRouter';
29import Inviter from 'views/Invite/Inviter';
30import useRoller from 'lib/useRoller';
32import './Point.scss';
33import { isL2 } from 'lib/utils/roller';
34import { isDevelopment } from 'lib/flags';
35import { convertToInt } from 'lib/convertToInt';
36import { usePointCache } from 'store/pointCache';
37import Modal from 'components/L2/Modal';
38import { isPlanet } from 'lib/utils/point';
40function InviteForm({
41 showInviteForm,
42 setShowInviteForm,
43 acceptedInvites,
44 acceptedPoints,
45 availableInvites,
46 goCohort,
47 pendingPoints,
48 sentInvites,
49 showInvites,
50}) {
51 const _totalInvites =
52 sentInvites.getOrElse(0) + availableInvites.getOrElse(0);
53 const _pendingInvites = pendingPoints.getOrElse([]).length;
55 return (
56 <>
57 <Grid.Item cols={[1, 11]}>
58 Invite Group
59 <br />
60 </Grid.Item>
62 <Grid.Item
63 className={cn('t-right underline pointer-hover', {
64 gray4: sentInvites.getOrElse(0) === 0,
65 })}
66 onClick={goCohort}
67 cols={[11, 13]}>
68 View
69 </Grid.Item>
70 <Grid.Item full>
71 <Flex align="center">
72 <Flex.Item>
73 {acceptedInvites.getOrElse(0)} / {_totalInvites}
74 </Flex.Item>
75 {_pendingInvites > 0 && (
76 <Flex.Item as={Chip} className="bg-yellow1 yellow4">
77 {_pendingInvites} pending
78 </Flex.Item>
79 )}
80 </Flex>
81 </Grid.Item>
83 {showInvites && (
84 <>
85 <Grid.Item
86 full
87 as={BarGraph}
88 available={availableInvites}
89 sent={sentInvites}
90 accepted={acceptedInvites}
91 />
92 <Grid.Item
93 full
94 as={InviteSigilList}
95 pendingPoints={pendingPoints}
96 acceptedPoints={acceptedPoints}
97 />
98 </>
99 )}
100 {!showInvites && (
101 <>
102 <Grid.Item full className="b-gray4 b-dotted b1 self-center">
103 <div className="p4 pv8 t-center gray4">
104 Start your invite group by adding members
105 </div>
106 </Grid.Item>
107 </>
108 )}
109 {!showInviteForm && availableInvites.getOrElse(0) > 0 && (
110 <Grid.Item
111 full
112 solid
113 as={Button}
114 center
115 onClick={() => setShowInviteForm(true)}>
116 Add Members
117 </Grid.Item>
118 )}
119 {showInviteForm && <Inviter />}
120 <Grid.Item full className="mb2" />
121 </>
122 );
125export default function Point() {
126 const { pop, push, names } = useLocalRouter();
127 const { wallet, authToken } = useWallet();
128 const { pointCursor } = usePointCursor();
129 const point = need.point(pointCursor);
130 const { getDetails } = usePointCache();
132 const { api, getInvites } = useRoller();
133 const {
134 pendingTransactions,
135 nextRoll,
136 invites,
137 setCurrentPoint,
138 setPendingTransactions,
139 currentL2,
140 } = useRollerStore();
142 const pointSize = azimuth.getPointSize(point);
143 const details = need.details(getDetails(point));
144 const isStarOrGalaxy = pointSize !== azimuth.PointSize.Planet;
145 const networkRevision = convertToInt(details.keyRevisionNumber, 10);
146 const networkKeysNotSet =
147 !currentL2 && isStarOrGalaxy && networkRevision === 0;
149 const [showModal, setShowModal] = useState(networkKeysNotSet);
151 useEffect(() => {
152 if (networkKeysNotSet) {
153 setShowModal(true);
154 }
155 }, [networkKeysNotSet]);
157 useEffect(() => {
158 const loadL2Info = async () => {
159 const getTransactions = async () => {
160 const pointInfo = await api.getPoint(Number(point));
161 if (isDevelopment) {
162 console.log('POINT INFO', pointInfo);
163 }
164 setCurrentPoint(pointInfo);
165 getInvites(isL2(pointInfo.dominion));
166 };
168 getTransactions();
169 };
171 loadL2Info();
172 }, [api, point, authToken, setPendingTransactions]); // eslint-disable-line
174 const { isParent, canManage, canSpawn, canVote } = useCurrentPermissions();
176 // L1 invites
177 const l1Invites = useInvites(point);
178 const {
179 availableInvites,
180 sentInvites,
181 acceptedInvites,
182 pendingPoints,
183 acceptedPoints,
184 } = l1Invites;
186 const showInvites = !(
187 acceptedInvites.getOrElse(0) === 0 && sentInvites.getOrElse(0) === 0
188 );
190 const hasInvites = showInvites || availableInvites.getOrElse(0) !== 0;
192 const loadedInvites = Just.hasInstance(availableInvites);
193 //
194 // availableInvites.getOrElse(0) === 0
196 const goSenate = useCallback(() => push(names.SENATE), [push, names]);
198 const goCohort = useCallback(() => push(names.INVITE_COHORT), [push, names]);
200 const goUrbitOS = useCallback(() => push(names.URBIT_OS), [push, names]);
202 const goUrbitID = useCallback(() => push(names.URBIT_ID), [push, names]);
204 const goResidents = useCallback(() => push(names.RESIDENTS), [push, names]);
206 const goIssuePoint = useCallback(() => push(names.ISSUE_CHILD), [
207 names.ISSUE_CHILD,
208 push,
209 ]);
211 const planet = isPlanet(point);
213 const [showInviteForm, setShowInviteForm] = useState(false);
215 const senateButton = (() => {
216 if (azimuth.getPointSize(point) !== azimuth.PointSize.Galaxy) {
217 return null;
218 }
219 return (
220 <>
221 <Grid.Item
222 full
223 as={ForwardButton}
224 disabled={!canVote}
225 onClick={goSenate}>
226 Senate
227 </Grid.Item>
228 <Grid.Divider />
229 </>
230 );
231 })();
233 // sync the current cursor
234 useSyncExtras([point]);
236 const address = need.addressFromWallet(wallet);
237 const numPending = pendingTransactions.filter(
238 ({ rawTx }) => rawTx?.tx?.type === 'spawn'
239 ).length;
241 return (
242 <View
243 pop={pop}
244 inset
245 className="point"
246 hideBack
247 header={
248 <L2PointHeader
249 hideTimer={!!numPending}
250 numInvites={invites.length}
251 hideInvites={networkKeysNotSet}
252 />
253 }>
254 <Greeting point={point} />
255 {!!numPending && (
256 <div className="transaction">
257 <Row className="title-row">
258 <div className="title">
259 {numPending} Planet{numPending > 1 ? 's' : ''} Spawned
260 </div>
261 <div className="rollup-timer">
262 <Icon icon="Clock" />
263 {nextRoll}
264 </div>
265 </Row>
266 <Row className="info-row">
267 <LayerIndicator layer={2} size="sm" />
268 <div className="date"></div>
269 </Row>
270 </div>
271 )}
272 <Passport
273 point={Just(point)}
274 address={Just(address)}
275 animationMode={'slide'}
276 />
277 <Grid gap={4}>
278 {isParent && (
279 <Grid.Item full as={Flex} justify="between">
280 <Card
281 title="Residency"
282 subtitle="Manage peers that you service"
283 onClick={goResidents}
284 />
285 </Grid.Item>
286 )}
287 {planet && hasInvites && (
288 <InviteForm
289 showInviteForm={showInviteForm}
290 setShowInviteForm={setShowInviteForm}
291 acceptedInvites={acceptedInvites}
292 acceptedPoints={acceptedPoints}
293 availableInvites={availableInvites}
294 goCohort={goCohort}
295 pendingPoints={pendingPoints}
296 sentInvites={sentInvites}
297 showInvites={showInvites}
298 />
299 )}
300 {!loadedInvites && planet && (
301 <Grid.Item className="mv2" full>
302 Invite Group <Blinky />
303 </Grid.Item>
304 )}
305 {/* {inviteButton} */}
306 <Grid.Item full as={Flex} justify="between">
307 <Card
308 title="ID"
309 subtitle="Identity and security settings"
310 icon={<Icon icon="User" />}
311 onClick={goUrbitID}
312 disabled={!canManage}
313 />
314 </Grid.Item>
315 <Grid.Item full as={Flex} justify="between">
316 <Card
317 title="OS"
318 subtitle="Urbit OS Settings"
319 icon={<Icon icon="Server" />}
320 onClick={goUrbitOS}
321 disabled={!canManage}
322 />
323 </Grid.Item>
324 {isParent && (
325 <>
326 <Grid.Item
327 full
328 as={ForwardButton}
329 disabled={!canSpawn}
330 onClick={goIssuePoint}>
331 Issue Point
332 </Grid.Item>
333 <Grid.Divider />
334 </>
335 )}
336 {senateButton}
337 </Grid>
338 <Modal show={showModal} hide={() => setShowModal(false)}>
339 <Box className="network-keys-modal">
340 <Box className="close" onClick={() => setShowModal(false)}>
341 &#215;
342 </Box>
343 <Box className="title">Network Keys Not Set</Box>
344 <Box className="message">
345 This point's network keys are not set. The network keys must be set
346 to spawn points or migrate to Layer 2. Please set them in Urbit OS
347 Settings.
348 </Box>
349 <Row className="buttons">
350 <Button className="cancel" onClick={() => setShowModal(false)}>
351 Cancel
352 </Button>
353 <Button className="migrate" onClick={goUrbitOS}>
354 Set Keys
355 </Button>
356 </Row>
357 </Box>
358 </Modal>
359 </View>
360 );