on 44dc2fe help sign in
bridge/src/views/Point.js
240 lines 6.9 kB history raw
1import React, { useCallback, useState } from 'react';
2import { Just, Nothing } from 'folktale/maybe';
3import { Grid, Flex } from 'indigo-react';
4import { azimuth } from 'azimuth-js';
6import { usePointCursor } from 'store/pointCursor';
7import { useWallet } from 'store/wallet';
9import View from 'components/View';
10import Greeting from 'components/Greeting';
11import Passport from 'components/Passport';
12import { ForwardButton, BootUrbitOSButton } from 'components/Buttons';
13import CopyButton from 'components/CopyButton';
14import { matchBlinky } from 'components/Blinky';
15import DownloadSigilButton from 'components/DownloadSigilButton';
16import BarGraph from 'components/BarGraph';
17import Chip from 'components/Chip';
18import MaybeSigil from 'components/MaybeSigil';
19import InviteSigilList from 'components/InviteSigilList';
21import * as need from 'lib/need';
22import useInvites from 'lib/useInvites';
23import { useSyncOwnedPoints } from 'lib/useSyncPoints';
24import useCurrentPermissions from 'lib/useCurrentPermissions';
25import { useLocalRouter } from 'lib/LocalRouter';
26import useKeyfileGenerator from 'lib/useKeyfileGenerator';
28import InviteCohort from 'views/Invite/Cohort';
30export default function Point() {
31 const { pop, push, names } = useLocalRouter();
32 const { pointCursor } = usePointCursor();
34 const { wallet } = useWallet();
35 const point = need.point(pointCursor);
37 const { code, notice } = useKeyfileGenerator();
39 const {
40 isParent,
41 isActiveOwner,
42 canManage,
43 canSpawn,
44 } = useCurrentPermissions();
46 // fetch the invites for the current cursor
47 const invites = useInvites(point);
48 const {
49 availableInvites,
50 sentInvites,
51 acceptedInvites,
52 pendingPoints,
53 acceptedPoints,
54 } = invites;
56 const showInvites = !(
57 acceptedInvites.getOrElse(0) === 0 && sentInvites.getOrElse(0) === 0
58 );
60 const hasInvites = showInvites || availableInvites.getOrElse(0) !== 0;
62 const _totalInvites =
63 sentInvites.getOrElse(0) + availableInvites.getOrElse(0);
64 const _pendingInvites = pendingPoints.getOrElse([]).length;
65 //
66 // availableInvites.getOrElse(0) === 0
68 const goAdmin = useCallback(() => push(names.ADMIN), [push, names]);
70 const goInvite = useCallback(() => push(names.INVITE), [push, names]);
72 const goParty = useCallback(() => push(names.PARTY), [push, names]);
74 const goPartiesSetPoolSize = useCallback(
75 () => push(names.PARTY_SET_POOL_SIZE),
76 [push, names]
77 );
79 const goIssuePoint = useCallback(() => push(names.ISSUE_CHILD), [
80 names.ISSUE_CHILD,
81 push,
82 ]);
84 const isPlanet = azimuth.getPointSize(point) === azimuth.PointSize.Planet;
86 const [showInviteForm, setShowInviteForm] = useState(false);
88 const inviteButton = (() => {
89 switch (azimuth.getPointSize(point)) {
90 case azimuth.PointSize.Planet:
91 const availableInvitesText = matchBlinky(availableInvites);
92 return (
93 <>
94 <Grid.Item
95 full
96 as={ForwardButton}
97 disabled={!isActiveOwner}
98 onClick={goInvite}>
99 Invite <sup>{availableInvitesText}</sup>
100 </Grid.Item>
101 <Grid.Divider />
102 </>
103 );
104 //
105 case azimuth.PointSize.Star:
106 return (
107 <>
108 <Grid.Item
109 full
110 as={ForwardButton}
111 disabled={!isActiveOwner}
112 onClick={goPartiesSetPoolSize}>
113 Manage Invite Pools
114 </Grid.Item>
115 <Grid.Divider />
116 </>
117 );
118 //
119 default:
120 return null;
121 }
122 })();
124 // sync the current cursor
125 useSyncOwnedPoints([point]);
127 const address = need.addressFromWallet(wallet);
129 return (
130 <View pop={pop} inset>
131 <Greeting point={point} />
132 <Passport
133 point={Just(point)}
134 address={Just(address)}
135 animationMode={'slide'}
136 />
137 <Grid gap={3}>
138 {isPlanet && hasInvites && (
139 <>
140 <Grid.Item cols={[1, 11]}>
141 Invite Group
142 <br />
143 </Grid.Item>
145 <Grid.Item className="t-right" onClick={goParty} cols={[11, 13]}>
146 View
147 </Grid.Item>
148 <Grid.Item full>
149 <Flex align="center">
150 <Flex.Item>
151 {acceptedInvites.getOrElse(0)} / {_totalInvites}
152 </Flex.Item>
153 {_pendingInvites > 0 && (
154 <Flex.Item as={Chip} color="yellow">
155 {_pendingInvites.getOrElse([]).length} pending
156 </Flex.Item>
157 )}
158 </Flex>
159 </Grid.Item>
161 {showInvites && (
162 <>
163 <Grid.Item
164 full
165 as={BarGraph}
166 available={availableInvites}
167 sent={sentInvites}
168 accepted={acceptedInvites}
169 />
170 <Grid.Item
171 full
172 as={InviteSigilList}
173 pendingPoints={pendingPoints}
174 acceptedPoints={acceptedPoints}
175 />
176 </>
177 )}
178 {!showInvites && (
179 <>
180 <Grid.Item full className="b-gray4 b-dotted b1 self-center">
181 <div className="p4 pv8 t-center gray4">
182 Start your invite group by adding members
183 </div>
184 </Grid.Item>
185 </>
186 )}
187 {!showInviteForm && availableInvites.getOrElse(0) > 0 && (
188 <Grid.Item
189 full
190 solid
191 as={ForwardButton}
192 onClick={() => setShowInviteForm(true)}>
193 Add Members
194 </Grid.Item>
195 )}
196 {showInviteForm && <InviteCohort />}
197 </>
198 )}
199 </Grid>
200 <Grid className="pt2">
201 {inviteButton}
202 <Grid.Item
203 full
204 as={ForwardButton}
205 disabled={!canManage}
206 onClick={goAdmin}>
207 Admin
208 </Grid.Item>
209 <Grid.Divider />
211 {isParent && (
212 <>
213 <Grid.Item
214 full
215 as={ForwardButton}
216 disabled={!canSpawn}
217 onClick={goIssuePoint}>
218 Issue Point
219 </Grid.Item>
220 <Grid.Divider />
221 </>
222 )}
223 <Grid.Item full as={BootUrbitOSButton} />
224 <Grid.Divider />
225 <Grid.Item
226 full
227 as={ForwardButton}
228 accessory={code && <CopyButton text={code} />}
229 detail={code || notice}
230 disabled={!code}
231 detailClassName="mono">
232 Login Code
233 </Grid.Item>
234 <Grid.Divider />
235 <Grid.Item full as={DownloadSigilButton} point={point} />
236 <Grid.Divider />
237 </Grid>
238 </View>
239 );