on 91efb05 help sign in
bridge/src/views/Point/Point.js
359 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';
39function InviteForm({
40 showInviteForm,
41 setShowInviteForm,
42 acceptedInvites,
43 acceptedPoints,
44 availableInvites,
45 goCohort,
46 pendingPoints,
47 sentInvites,
48 showInvites,
49}) {
50 const _totalInvites =
51 sentInvites.getOrElse(0) + availableInvites.getOrElse(0);
52 const _pendingInvites = pendingPoints.getOrElse([]).length;
54 return (
55 <>
56 <Grid.Item cols={[1, 11]}>
57 Invite Group
58 <br />
59 </Grid.Item>
61 <Grid.Item
62 className={cn('t-right underline pointer-hover', {
63 gray4: sentInvites.getOrElse(0) === 0,
64 })}
65 onClick={goCohort}
66 cols={[11, 13]}>
67 View
68 </Grid.Item>
69 <Grid.Item full>
70 <Flex align="center">
71 <Flex.Item>
72 {acceptedInvites.getOrElse(0)} / {_totalInvites}
73 </Flex.Item>
74 {_pendingInvites > 0 && (
75 <Flex.Item as={Chip} className="bg-yellow1 yellow4">
76 {_pendingInvites} pending
77 </Flex.Item>
78 )}
79 </Flex>
80 </Grid.Item>
82 {showInvites && (
83 <>
84 <Grid.Item
85 full
86 as={BarGraph}
87 available={availableInvites}
88 sent={sentInvites}
89 accepted={acceptedInvites}
90 />
91 <Grid.Item
92 full
93 as={InviteSigilList}
94 pendingPoints={pendingPoints}
95 acceptedPoints={acceptedPoints}
96 />
97 </>
98 )}
99 {!showInvites && (
100 <>
101 <Grid.Item full className="b-gray4 b-dotted b1 self-center">
102 <div className="p4 pv8 t-center gray4">
103 Start your invite group by adding members
104 </div>
105 </Grid.Item>
106 </>
107 )}
108 {!showInviteForm && availableInvites.getOrElse(0) > 0 && (
109 <Grid.Item
110 full
111 solid
112 as={Button}
113 center
114 onClick={() => setShowInviteForm(true)}>
115 Add Members
116 </Grid.Item>
117 )}
118 {showInviteForm && <Inviter />}
119 <Grid.Item full className="mb2" />
120 </>
121 );
124export default function Point() {
125 const { pop, push, names } = useLocalRouter();
126 const { wallet, authToken } = useWallet();
127 const { pointCursor } = usePointCursor();
128 const point = need.point(pointCursor);
129 const { getDetails } = usePointCache();
131 const { api, getInvites } = useRoller();
132 const {
133 pendingTransactions,
134 nextRoll,
135 invites,
136 setCurrentPoint,
137 setPendingTransactions,
138 currentL2,
139 } = useRollerStore();
141 const pointSize = azimuth.getPointSize(point);
142 const details = need.details(getDetails(point));
143 const isStarOrGalaxy = pointSize !== azimuth.PointSize.Planet;
144 const networkRevision = convertToInt(details.keyRevisionNumber, 10);
145 const networkKeysNotSet =
146 !currentL2 && isStarOrGalaxy && networkRevision === 0;
148 const [showModal, setShowModal] = useState(networkKeysNotSet);
150 useEffect(() => {
151 if (networkKeysNotSet) {
152 setShowModal(true);
153 }
154 }, [networkKeysNotSet]);
156 useEffect(() => {
157 const loadL2Info = async () => {
158 const getTransactions = async () => {
159 const pointInfo = await api.getPoint(Number(point));
160 if (isDevelopment) {
161 console.log('POINT INFO', pointInfo);
162 }
163 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 isPlanet = azimuth.getPointSize(point) === azimuth.PointSize.Planet;
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.length;
239 return (
240 <View
241 pop={pop}
242 inset
243 className="point"
244 hideBack
245 header={
246 <L2PointHeader
247 hideTimer={!!numPending}
248 numInvites={invites.length}
249 hideInvites={networkKeysNotSet}
250 />
251 }>
252 <Greeting point={point} />
253 {!!numPending && (
254 <div className="transaction">
255 <Row className="title-row">
256 <div className="title">
257 {numPending} Planet{numPending > 1 ? 's' : ''} Spawned
258 </div>
259 <div className="rollup-timer">
260 <Icon icon="Clock" />
261 {nextRoll}
262 </div>
263 </Row>
264 <Row className="info-row">
265 <LayerIndicator layer={2} size="sm" />
266 <div className="date"></div>
267 </Row>
268 </div>
269 )}
270 <Passport
271 point={Just(point)}
272 address={Just(address)}
273 animationMode={'slide'}
274 />
275 <Grid gap={4}>
276 {isParent && (
277 <Grid.Item full as={Flex} justify="between">
278 <Card
279 title="Residency"
280 subtitle="Manage peers that you service"
281 onClick={goResidents}
282 />
283 </Grid.Item>
284 )}
285 {isPlanet && hasInvites && (
286 <InviteForm
287 showInviteForm={showInviteForm}
288 setShowInviteForm={setShowInviteForm}
289 acceptedInvites={acceptedInvites}
290 acceptedPoints={acceptedPoints}
291 availableInvites={availableInvites}
292 goCohort={goCohort}
293 pendingPoints={pendingPoints}
294 sentInvites={sentInvites}
295 showInvites={showInvites}
296 />
297 )}
298 {!loadedInvites && isPlanet && (
299 <Grid.Item className="mv2" full>
300 Invite Group <Blinky />
301 </Grid.Item>
302 )}
303 {/* {inviteButton} */}
304 <Grid.Item full as={Flex} justify="between">
305 <Card
306 title="ID"
307 subtitle="Identity and security settings"
308 icon={<Icon icon="User" />}
309 onClick={goUrbitID}
310 disabled={!canManage}
311 />
312 </Grid.Item>
313 <Grid.Item full as={Flex} justify="between">
314 <Card
315 title="OS"
316 subtitle="Urbit OS Settings"
317 icon={<Icon icon="Server" />}
318 onClick={goUrbitOS}
319 disabled={!canManage}
320 />
321 </Grid.Item>
322 {isParent && (
323 <>
324 <Grid.Item
325 full
326 as={ForwardButton}
327 disabled={!canSpawn}
328 onClick={goIssuePoint}>
329 Issue Point
330 </Grid.Item>
331 <Grid.Divider />
332 </>
333 )}
334 {senateButton}
335 </Grid>
336 <Modal show={showModal} hide={() => setShowModal(false)}>
337 <Box className="network-keys-modal">
338 <Box className="close" onClick={() => setShowModal(false)}>
339 &#215;
340 </Box>
341 <Box className="title">Network Keys Not Set</Box>
342 <Box className="message">
343 This point's network keys are not set. The network keys must be set
344 to spawn points or migrate to Layer 2. Please set them in Urbit OS
345 Settings.
346 </Box>
347 <Row className="buttons">
348 <Button className="cancel" onClick={() => setShowModal(false)}>
349 Cancel
350 </Button>
351 <Button className="migrate" onClick={goUrbitOS}>
352 Set Keys
353 </Button>
354 </Row>
355 </Box>
356 </Modal>
357 </View>
358 );