on 70004bb help sign in
bridge/src/views/Point/Point.js
311 lines 8.6 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 { 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';
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 { api, getInvites } = useRoller();
127 const {
128 pendingTransactions,
129 nextRoll,
130 invites,
131 setCurrentPoint,
132 setPendingTransactions,
133 } = useRollerStore();
135 const [loaded, setLoaded] = useState(false);
137 useEffect(() => {
138 const loadL2Info = async () => {
139 const getTransactions = async () => {
140 const pointInfo = await api.getPoint(Number(point));
141 setCurrentPoint(pointInfo);
143 getInvites(isL2(pointInfo.dominion));
144 };
146 if (!loaded) {
147 getTransactions();
148 setLoaded(true);
149 }
150 };
152 loadL2Info();
153 }, [api, point, authToken, setPendingTransactions, loaded]); // eslint-disable-line
155 const { isParent, canManage, canSpawn, canVote } = useCurrentPermissions();
157 // L1 invites
158 const l1Invites = useInvites(point);
159 const {
160 availableInvites,
161 sentInvites,
162 acceptedInvites,
163 pendingPoints,
164 acceptedPoints,
165 } = l1Invites;
167 const showInvites = !(
168 acceptedInvites.getOrElse(0) === 0 && sentInvites.getOrElse(0) === 0
169 );
171 const hasInvites = showInvites || availableInvites.getOrElse(0) !== 0;
173 const loadedInvites = Just.hasInstance(availableInvites);
174 //
175 // availableInvites.getOrElse(0) === 0
177 const goSenate = useCallback(() => push(names.SENATE), [push, names]);
179 const goCohort = useCallback(() => push(names.INVITE_COHORT), [push, names]);
181 const goUrbitOS = useCallback(() => push(names.URBIT_OS), [push, names]);
183 const goUrbitID = useCallback(() => push(names.URBIT_ID), [push, names]);
185 const goResidents = useCallback(() => push(names.RESIDENTS), [push, names]);
187 const goIssuePoint = useCallback(() => push(names.ISSUE_CHILD), [
188 names.ISSUE_CHILD,
189 push,
190 ]);
192 const isPlanet = azimuth.getPointSize(point) === azimuth.PointSize.Planet;
194 const [showInviteForm, setShowInviteForm] = useState(false);
196 const senateButton = (() => {
197 if (azimuth.getPointSize(point) !== azimuth.PointSize.Galaxy) {
198 return null;
199 }
200 return (
201 <>
202 <Grid.Item
203 full
204 as={ForwardButton}
205 disabled={!canVote}
206 onClick={goSenate}>
207 Senate
208 </Grid.Item>
209 <Grid.Divider />
210 </>
211 );
212 })();
214 // sync the current cursor
215 useSyncExtras([point]);
217 const address = need.addressFromWallet(wallet);
218 const numPending = pendingTransactions.length;
220 return (
221 <View
222 pop={pop}
223 inset
224 className="point"
225 header={
226 <L2PointHeader hideTimer={!!numPending} numInvites={invites.length} />
227 }>
228 <Greeting point={point} />
229 {!!numPending && (
230 <div className="transaction">
231 <Row className="title-row">
232 <div className="title">
233 {numPending} Planet{numPending > 1 ? 's' : ''} Spawned
234 </div>
235 <div className="rollup-timer">{nextRoll}</div>
236 </Row>
237 <Row className="info-row">
238 <LayerIndicator layer={2} size="sm" />
239 <div className="date"></div>
240 </Row>
241 </div>
242 )}
243 <Passport
244 point={Just(point)}
245 address={Just(address)}
246 animationMode={'slide'}
247 />
248 <Grid gap={4}>
249 {isParent && (
250 <Grid.Item full as={Flex} justify="between">
251 <Card
252 title="Residency"
253 subtitle="Manage peers that you service"
254 onClick={goResidents}
255 />
256 </Grid.Item>
257 )}
258 {isPlanet && hasInvites && (
259 <InviteForm
260 showInviteForm={showInviteForm}
261 setShowInviteForm={setShowInviteForm}
262 acceptedInvites={acceptedInvites}
263 acceptedPoints={acceptedPoints}
264 availableInvites={availableInvites}
265 goCohort={goCohort}
266 pendingPoints={pendingPoints}
267 sentInvites={sentInvites}
268 showInvites={showInvites}
269 />
270 )}
271 {!loadedInvites && isPlanet && (
272 <Grid.Item className="mv2" full>
273 Invite Group <Blinky />
274 </Grid.Item>
275 )}
276 {/* {inviteButton} */}
277 <Grid.Item full as={Flex} justify="between">
278 <Card
279 title="ID"
280 subtitle="Identity and security settings"
281 icon={<Icon icon="User" />}
282 onClick={goUrbitID}
283 disabled={!canManage}
284 />
285 </Grid.Item>
286 <Grid.Item full as={Flex} justify="between">
287 <Card
288 title="OS"
289 subtitle="Urbit OS Settings"
290 icon={<Icon icon="Server" />}
291 onClick={goUrbitOS}
292 disabled={!canManage}
293 />
294 </Grid.Item>
295 {isParent && (
296 <>
297 <Grid.Item
298 full
299 as={ForwardButton}
300 disabled={!canSpawn}
301 onClick={goIssuePoint}>
302 Issue Point
303 </Grid.Item>
304 <Grid.Divider />
305 </>
306 )}
307 {senateButton}
308 </Grid>
309 </View>
310 );