on 58fbcd2 help sign in
bridge/src/views/Points.js
265 lines 7.8 kB history raw
1import React, { useCallback } from 'react';
2import { Just, Nothing } from 'folktale/maybe';
3import { Grid, H5, H1, HelpText, LinkButton, Flex } from 'indigo-react';
4import { get } from 'lodash';
6import { useHistory } from 'store/history';
7import { useWallet } from 'store/wallet';
8import { usePointCache } from 'store/pointCache';
9import { usePointCursor } from 'store/pointCursor';
11import * as need from 'lib/need';
12import { isZeroAddress, abbreviateAddress } from 'lib/wallet';
13import useIsEclipticOwner from 'lib/useIsEclipticOwner';
14import { useSyncKnownPoints } from 'lib/useSyncPoints';
16import View from 'components/View';
17import Blinky from 'components/Blinky';
18import Passport from 'components/Passport';
19import useRejectedIncomingPointTransfers from 'lib/useRejectedIncomingPointTransfers';
20import pluralize from 'lib/pluralize';
21import Footer from 'components/Footer';
22import { ForwardButton } from 'components/Buttons';
24const maybeGetResult = (obj, key, defaultValue) =>
25 obj.matchWith({
26 Nothing: () => defaultValue,
27 Just: p =>
28 p.value.matchWith({
29 Ok: r => get(r.value, key, defaultValue),
30 Error: e => defaultValue,
31 }),
32 });
34const hasTransferProxy = details => !isZeroAddress(details.transferProxy);
36const PointList = function({ points, className, actions, ...rest }) {
37 const { setPointCursor } = usePointCursor();
38 const { push, names } = useHistory();
40 return (
41 <Grid gap={3} className={className}>
42 {points.map((point, i) => (
43 <Grid.Item half={(i % 2) + 1} key={point}>
44 <Flex col>
45 <Passport.Mini
46 point={point}
47 className="clickable"
48 onClick={() => {
49 setPointCursor(Just(point));
50 push(names.POINT);
51 }}
52 {...rest}
53 />
54 {actions && (
55 <Flex.Item className="mt2">{actions(point, i)}</Flex.Item>
56 )}
57 </Flex>
58 </Grid.Item>
59 ))}
60 </Grid>
61 );
62};
64function ActionButtons({ actions = [] }) {
65 return (
66 <Flex row>
67 {actions.map(action => (
68 <Flex.Item
69 key={action.text}
70 as={LinkButton}
71 className="mr3"
72 onClick={action.onClick}>
73 {action.text}
74 </Flex.Item>
75 ))}
76 </Flex>
77 );
80export default function Points() {
81 const { wallet } = useWallet();
82 const { pop, push, names } = useHistory();
83 const { setPointCursor } = usePointCursor();
84 const { controlledPoints, getDetails } = usePointCache();
85 const isEclipticOwner = useIsEclipticOwner();
86 const [
87 rejectedPoints,
88 addRejectedPoint,
89 ] = useRejectedIncomingPointTransfers();
91 const address = need.addressFromWallet(wallet);
93 const loading = Nothing.hasInstance(controlledPoints);
95 const ownedPoints = maybeGetResult(controlledPoints, 'ownedPoints', []);
96 const incomingPoints = maybeGetResult(
97 controlledPoints,
98 'incomingPoints',
99 []
100 ).filter(point => !rejectedPoints.includes(point));
101 const managingPoints = maybeGetResult(controlledPoints, 'managingPoints', []);
102 const votingPoints = maybeGetResult(controlledPoints, 'votingPoints', []);
103 const spawningPoints = maybeGetResult(controlledPoints, 'spawningPoints', []);
104 const outgoingPoints = ownedPoints.filter(point =>
105 getDetails(point).matchWith({
106 Nothing: () => false,
107 Just: p => hasTransferProxy(p.value),
108 })
109 );
111 const multipassPoints = [
112 ...ownedPoints.filter(p => !outgoingPoints.includes(p)),
113 ...managingPoints,
114 ...votingPoints,
115 ...spawningPoints,
116 ];
118 const displayEmptyState =
119 !loading && incomingPoints.length === 0 && multipassPoints.length === 0;
121 // sync display details for known points
122 useSyncKnownPoints([
123 ...ownedPoints,
124 ...incomingPoints,
125 ...managingPoints,
126 ...votingPoints,
127 ...spawningPoints,
128 ]);
130 const goCreateGalaxy = useCallback(() => push(names.CREATE_GALAXY), [
131 names.CREATE_GALAXY,
132 push,
133 ]);
135 const goViewPoint = useCallback(() => push(names.VIEW_POINT), [
136 names.VIEW_POINT,
137 push,
138 ]);
140 return (
141 <View pop={pop} inset>
142 <Grid>
143 <Grid.Item full as={H1} className="f6 mono gray4 mb4">
144 {abbreviateAddress(address)}
145 </Grid.Item>
147 {loading && (
148 <Grid.Item full as={HelpText} className="mt8 t-center">
149 <Blinky /> Loading...
150 </Grid.Item>
151 )}
153 {displayEmptyState && (
154 <Grid.Item full as={HelpText} className="mt8 t-center">
155 No points to display. This wallet is not the owner or proxy for any
156 points.
157 </Grid.Item>
158 )}
160 {incomingPoints.length > 0 && (
161 <Grid.Item full as={Grid} gap={1} className="mb6">
162 <Grid.Item full as={H5}>
163 {pluralize(
164 incomingPoints.length,
165 'Incoming Transfer',
166 'Incoming Transfers'
167 )}
168 </Grid.Item>
169 <Grid.Item
170 full
171 as={PointList}
172 points={incomingPoints}
173 actions={(point, i) => (
174 <ActionButtons
175 actions={[
176 {
177 text: 'Accept',
178 onClick: () => {
179 setPointCursor(Just(point));
180 push(names.ACCEPT_TRANSFER);
181 },
182 },
183 {
184 text: 'Reject',
185 onClick: () => {
186 addRejectedPoint(point);
187 },
188 },
189 ]}
190 />
191 )}
192 inverted
193 />
194 </Grid.Item>
195 )}
197 {outgoingPoints.length > 0 && (
198 <Grid.Item full as={Grid} gap={1} className="mb6">
199 <Grid.Item full as={H5}>
200 {pluralize(
201 outgoingPoints.length,
202 'Outgoing Transfer',
203 'Outgoing Transfers'
204 )}
205 </Grid.Item>
206 <Grid.Item
207 full
208 as={PointList}
209 points={outgoingPoints}
210 actions={(point, i) => (
211 <ActionButtons
212 actions={[
213 {
214 text: 'Cancel',
215 onClick: () => {
216 setPointCursor(Just(point));
217 // TODO: deep linking to fix this duplicate route
218 push(names.CANCEL_TRANSFER);
219 },
220 },
221 ]}
222 />
223 )}
224 inverted
225 />
226 </Grid.Item>
227 )}
229 {multipassPoints.length > 0 && (
230 <Grid.Item full as={Grid} gap={1}>
231 <Grid.Item full as={H5}>
232 {pluralize(multipassPoints.length, 'Multipass', 'Multipasses')}
233 </Grid.Item>
234 <Grid.Item full as={PointList} points={multipassPoints} />
235 </Grid.Item>
236 )}
238 <Footer>
239 <Grid>
240 <Grid.Divider />
241 {isEclipticOwner && (
242 <>
243 <Grid.Item
244 full
245 as={ForwardButton}
246 detail="You have the authority to create a new Galaxy."
247 onClick={goCreateGalaxy}>
248 Create a galaxy
249 </Grid.Item>
250 <Grid.Divider />
251 </>
252 )}
253 <Grid.Item
254 full
255 as={ForwardButton}
256 detail="View a point"
257 onClick={goViewPoint}>
258 View a point
259 </Grid.Item>
260 </Grid>
261 </Footer>
262 </Grid>
263 </View>
264 );