on dedd4b5 help sign in
bridge/src/views/Point.js
332 lines 9.1 kB history raw
1import React, { useCallback, useEffect, useState } from 'react';
2import cn from 'classnames';
3import { Just } from 'folktale/maybe';
4import { Grid, Flex, Button } from 'indigo-react';
5import { Icon, Row } from '@tlon/indigo-react';
6import { azimuth } from 'azimuth-js';
8import { usePointCursor } from 'store/pointCursor';
9import { useWallet } from 'store/wallet';
10import { usePointCache } from 'store/pointCache';
11import { useRollerStore } from 'store/roller';
13import View from 'components/View';
14import Greeting from 'components/Greeting';
15import Passport from 'components/Passport';
16import Blinky from 'components/Blinky';
17import BarGraph from 'components/BarGraph';
18import Chip from 'components/Chip';
19import InviteSigilList from 'components/InviteSigilList';
20import { ForwardButton } from 'components/Buttons';
21import L2PointHeader from 'components/L2/Headers/L2PointHeader';
22import LayerIndicator from 'components/L2/LayerIndicator';
23import Card from 'components/L2/Card';
25import * as need from 'lib/need';
26import useInvites from 'lib/useInvites';
27import { useSyncExtras } from 'lib/useSyncPoints';
28import useCurrentPermissions from 'lib/useCurrentPermissions';
29import { useLocalRouter } from 'lib/LocalRouter';
30import Inviter from 'views/Invite/Inviter';
31import useRoller from 'lib/useRoller';
33import './Point.scss';
35function InviteForm({
36 showInviteForm,
37 setShowInviteForm,
38 acceptedInvites,
39 acceptedPoints,
40 availableInvites,
41 goCohort,
42 pendingPoints,
43 sentInvites,
44 showInvites,
45}) {
46 const _totalInvites =
47 sentInvites.getOrElse(0) + availableInvites.getOrElse(0);
48 const _pendingInvites = pendingPoints.getOrElse([]).length;
50 return (
51 <>
52 <Grid.Item cols={[1, 11]}>
53 Invite Group
54 <br />
55 </Grid.Item>
57 <Grid.Item
58 className={cn('t-right underline pointer-hover', {
59 gray4: sentInvites.getOrElse(0) === 0,
60 })}
61 onClick={goCohort}
62 cols={[11, 13]}>
63 View
64 </Grid.Item>
65 <Grid.Item full>
66 <Flex align="center">
67 <Flex.Item>
68 {acceptedInvites.getOrElse(0)} / {_totalInvites}
69 </Flex.Item>
70 {_pendingInvites > 0 && (
71 <Flex.Item as={Chip} className="bg-yellow1 yellow4">
72 {_pendingInvites} pending
73 </Flex.Item>
74 )}
75 </Flex>
76 </Grid.Item>
78 {showInvites && (
79 <>
80 <Grid.Item
81 full
82 as={BarGraph}
83 available={availableInvites}
84 sent={sentInvites}
85 accepted={acceptedInvites}
86 />
87 <Grid.Item
88 full
89 as={InviteSigilList}
90 pendingPoints={pendingPoints}
91 acceptedPoints={acceptedPoints}
92 />
93 </>
94 )}
95 {!showInvites && (
96 <>
97 <Grid.Item full className="b-gray4 b-dotted b1 self-center">
98 <div className="p4 pv8 t-center gray4">
99 Start your invite group by adding members
100 </div>
101 </Grid.Item>
102 </>
103 )}
104 {!showInviteForm && availableInvites.getOrElse(0) > 0 && (
105 <Grid.Item
106 full
107 solid
108 as={Button}
109 center
110 onClick={() => setShowInviteForm(true)}>
111 Add Members
112 </Grid.Item>
113 )}
114 {showInviteForm && <Inviter />}
115 <Grid.Item full className="mb2" />
116 </>
117 );
120export default function Point() {
121 const { pop, push, names } = useLocalRouter();
122 const { wallet, authToken } = useWallet();
123 const { pointCursor } = usePointCursor();
124 const point = need.point(pointCursor);
126 const { getResidents } = usePointCache();
127 const { api, getInvites } = useRoller();
128 const {
129 pendingTransactions,
130 nextRoll,
131 invites,
132 recentlyCompleted,
133 setCurrentPoint,
134 setPendingTransactions,
135 } = useRollerStore();
137 const [loaded, setLoaded] = useState(false);
139 useEffect(() => {
140 const loadL2Info = async () => {
141 const getTransactions = async () => {
142 const pointInfo = await api.getPoint(Number(point));
143 setCurrentPoint(pointInfo);
145 getInvites();
146 };
148 if (!loaded) {
149 getTransactions();
150 setLoaded(true);
151 }
152 };
154 loadL2Info();
155 }, [api, point, authToken, setPendingTransactions, loaded]); // eslint-disable-line
157 const { residentCount, requestCount } = getResidents(point);
159 const {
160 isParent,
161 isActiveOwner,
162 canManage,
163 canSpawn,
164 canVote,
165 } = useCurrentPermissions();
167 // L1 invites
168 const l1Invites = useInvites(point);
169 const {
170 availableInvites,
171 sentInvites,
172 acceptedInvites,
173 pendingPoints,
174 acceptedPoints,
175 } = l1Invites;
177 const showInvites = !(
178 acceptedInvites.getOrElse(0) === 0 && sentInvites.getOrElse(0) === 0
179 );
181 const hasInvites = showInvites || availableInvites.getOrElse(0) !== 0;
183 const loadedInvites = Just.hasInstance(availableInvites);
184 //
185 // availableInvites.getOrElse(0) === 0
187 const goSenate = useCallback(() => push(names.SENATE), [push, names]);
189 const goCohort = useCallback(() => push(names.INVITE_COHORT), [push, names]);
191 const goUrbitOS = useCallback(() => push(names.URBIT_OS), [push, names]);
193 const goUrbitID = useCallback(() => push(names.URBIT_ID), [push, names]);
195 const goResidents = useCallback(() => push(names.RESIDENTS), [push, names]);
197 const goIssuePoint = useCallback(() => push(names.ISSUE_CHILD), [
198 names.ISSUE_CHILD,
199 push,
200 ]);
202 const isPlanet = azimuth.getPointSize(point) === azimuth.PointSize.Planet;
204 const [showInviteForm, setShowInviteForm] = useState(false);
206 const senateButton = (() => {
207 if (azimuth.getPointSize(point) !== azimuth.PointSize.Galaxy) {
208 return null;
209 }
210 return (
211 <>
212 <Grid.Item
213 full
214 as={ForwardButton}
215 disabled={!canVote}
216 onClick={goSenate}>
217 Senate
218 </Grid.Item>
219 <Grid.Divider />
220 </>
221 );
222 })();
224 // sync the current cursor
225 useSyncExtras([point]);
227 const address = need.addressFromWallet(wallet);
229 const _requestCount = requestCount.getOrElse(0);
230 const numPending = pendingTransactions.length;
232 return (
233 <View
234 pop={pop}
235 inset
236 className="point"
237 header={
238 <L2PointHeader hideTimer={!!numPending} numInvites={invites.length} />
239 }>
240 <Greeting point={point} />
241 {!!numPending && (
242 <div className="transaction">
243 <Row className="title-row">
244 <div className="title">
245 {numPending} Planet{numPending > 1 ? 's' : ''} Spawned
246 </div>
247 <div className="rollup-timer">{nextRoll}</div>
248 </Row>
249 <Row className="info-row">
250 <LayerIndicator layer={2} size="sm" />
251 <div className="date"></div>
252 </Row>
253 </div>
254 )}
255 <Passport
256 point={Just(point)}
257 address={Just(address)}
258 animationMode={'slide'}
259 />
260 <Grid gap={4}>
261 {isParent && (
262 <Grid.Item full as={Flex} justify="between">
263 <Card
264 title="Residency"
265 subtitle="Manage peers that you service"
266 onClick={goResidents}
267 />
268 </Grid.Item>
269 )}
270 {isPlanet && hasInvites && (
271 <InviteForm
272 showInviteForm={showInviteForm}
273 setShowInviteForm={setShowInviteForm}
274 acceptedInvites={acceptedInvites}
275 acceptedPoints={acceptedPoints}
276 availableInvites={availableInvites}
277 goCohort={goCohort}
278 pendingPoints={pendingPoints}
279 sentInvites={sentInvites}
280 showInvites={showInvites}
281 />
282 )}
283 {!loadedInvites && isPlanet && (
284 <Grid.Item className="mv2" full>
285 Invite Group <Blinky />
286 </Grid.Item>
287 )}
288 {/* {inviteButton} */}
289 <Grid.Item full as={Flex} justify="between">
290 <Card
291 title="ID"
292 subtitle="Identity and security settings"
293 icon={<Icon icon="User" />}
294 onClick={goUrbitID}
295 disabled={!canManage}
296 />
297 </Grid.Item>
298 <Grid.Item full as={Flex} justify="between">
299 <Card
300 title="OS"
301 subtitle="Urbit OS Settings"
302 icon={<Icon icon="Server" />}
303 onClick={goUrbitOS}
304 disabled={!canManage}
305 />
306 </Grid.Item>
307 {/* <Grid.Item
308 full
309 as={ForwardButton}
310 disabled={!canBitcoin}
311 className="mt1"
312 detail="Bitcoin management"
313 onClick={goBitcoin}>
314 Bitcoin
315 </Grid.Item> */}
316 {/* {isParent && (
317 <>
318 <Grid.Item
319 full
320 as={ForwardButton}
321 disabled={!canSpawn}
322 onClick={goIssuePoint}>
323 Issue Point
324 </Grid.Item>
325 <Grid.Divider />
326 </>
327 )} */}
328 {senateButton}
329 </Grid>
330 </View>
331 );