@@ -1,6 +1,7 @@
1−import React from 'react';
1+import React, { useCallback } from 'react';
2import { Just, Nothing } from 'folktale/maybe';
2import { Just, Nothing } from 'folktale/maybe';
3import { Grid, H5, H1, HelpText, LinkButton, Flex } from 'indigo-react';
3import { Grid, H5, H1, HelpText, LinkButton, Flex } from 'indigo-react';
4+import { get } from 'lodash';
5import { useHistory } from 'store/history';
6import { useHistory } from 'store/history';
6import { useWallet } from 'store/wallet';
7import { useWallet } from 'store/wallet';
@@ -8,34 +9,33 @@ import { usePointCache } from 'store/pointCache';
8import { usePointCursor } from 'store/pointCursor';
9import { usePointCursor } from 'store/pointCursor';
10import * as need from 'lib/need';
11import * as need from 'lib/need';
11−import { ROUTE_NAMES } from 'lib/routeNames';
12import { isZeroAddress, abbreviateAddress } from 'lib/wallet';
12import { isZeroAddress, abbreviateAddress } from 'lib/wallet';
13import useIsEclipticOwner from 'lib/useIsEclipticOwner';
13import useIsEclipticOwner from 'lib/useIsEclipticOwner';
14import { useSyncKnownPoints } from 'lib/useSyncPoints';
14import { useSyncKnownPoints } from 'lib/useSyncPoints';
16import View from 'components/View';
16import View from 'components/View';
17−import FooterButton from 'components/FooterButton';
18import Blinky from 'components/Blinky';
17import Blinky from 'components/Blinky';
19import Passport from 'components/Passport';
18import Passport from 'components/Passport';
20import useRejectedIncomingPointTransfers from 'lib/useRejectedIncomingPointTransfers';
19import useRejectedIncomingPointTransfers from 'lib/useRejectedIncomingPointTransfers';
21import pluralize from 'lib/pluralize';
20import pluralize from 'lib/pluralize';
21+import Footer from 'components/Footer';
22+import { ForwardButton } from 'components/Buttons';
23−const getFromMaybe = (obj, key, defaultValue) =>
24+const maybeGetResult = (obj, key, defaultValue) =>
24 obj.matchWith({
25 obj.matchWith({
25 Nothing: () => defaultValue,
26 Nothing: () => defaultValue,
26 Just: p =>
27 Just: p =>
27 p.value.matchWith({
28 p.value.matchWith({
28− Ok: r => r.value[key],
29+ Ok: r => get(r.value, key, defaultValue),
29 Error: e => defaultValue,
30 Error: e => defaultValue,
33−const hasTransferProxy = (details, point) =>
34− !isZeroAddress(details.transferProxy);
34+const hasTransferProxy = details => !isZeroAddress(details.transferProxy);
36const PointList = function({ points, className, actions, ...rest }) {
36const PointList = function({ points, className, actions, ...rest }) {
37 const { setPointCursor } = usePointCursor();
37 const { setPointCursor } = usePointCursor();
38− const history = useHistory();
38+ const { push, names } = useHistory();
41 <Grid gap={3} className={className}>
41 <Grid gap={3} className={className}>
@@ -47,7 +47,7 @@ const PointList = function({ points, className, actions, ...rest }) {
47 className="clickable"
47 className="clickable"
48 onClick={() => {
48 onClick={() => {
49 setPointCursor(Just(point));
49 setPointCursor(Just(point));
50− history.push(history.names.POINT);
50+ push(names.POINT);
@@ -79,7 +79,7 @@ function ActionButtons({ actions = [] }) {
80export default function Points() {
80export default function Points() {
81 const { wallet } = useWallet();
81 const { wallet } = useWallet();
82− const history = useHistory();
82+ const { pop, push, names } = useHistory();
83 const { setPointCursor } = usePointCursor();
83 const { setPointCursor } = usePointCursor();
84 const { controlledPoints, getDetails } = usePointCache();
84 const { controlledPoints, getDetails } = usePointCache();
85 const isEclipticOwner = useIsEclipticOwner();
85 const isEclipticOwner = useIsEclipticOwner();
@@ -92,15 +92,15 @@ export default function Points() {
93 const loading = Nothing.hasInstance(controlledPoints);
93 const loading = Nothing.hasInstance(controlledPoints);
95− const ownedPoints = getFromMaybe(controlledPoints, 'ownedPoints', []);
95+ const ownedPoints = maybeGetResult(controlledPoints, 'ownedPoints', []);
96− const incomingPoints = getFromMaybe(
96+ const incomingPoints = maybeGetResult(
97 controlledPoints,
97 controlledPoints,
98 'incomingPoints',
98 'incomingPoints',
100 ).filter(point => !rejectedPoints.includes(point));
100 ).filter(point => !rejectedPoints.includes(point));
101− const managingPoints = getFromMaybe(controlledPoints, 'managingPoints', []);
101+ const managingPoints = maybeGetResult(controlledPoints, 'managingPoints', []);
102− const votingPoints = getFromMaybe(controlledPoints, 'votingPoints', []);
102+ const votingPoints = maybeGetResult(controlledPoints, 'votingPoints', []);
103− const spawningPoints = getFromMaybe(controlledPoints, 'spawningPoints', []);
103+ const spawningPoints = maybeGetResult(controlledPoints, 'spawningPoints', []);
104 const outgoingPoints = ownedPoints.filter(point =>
104 const outgoingPoints = ownedPoints.filter(point =>
105 getDetails(point).matchWith({
105 getDetails(point).matchWith({
106 Nothing: () => false,
106 Nothing: () => false,
@@ -115,7 +115,8 @@ export default function Points() {
115 ...spawningPoints,
115 ...spawningPoints,
118+ const displayEmptyState =
118− const isEmpty = incomingPoints.length === 0 && multipassPoints.length === 0;
119+ !loading && incomingPoints.length === 0 && multipassPoints.length === 0;
120 // sync display details for known points
121 // sync display details for known points
121 useSyncKnownPoints([
122 useSyncKnownPoints([
@@ -126,9 +127,19 @@ export default function Points() {
126 ...spawningPoints,
127 ...spawningPoints,
130+ const goCreateGalaxy = useCallback(() => push(names.CREATE_GALAXY), [
131+ names.CREATE_GALAXY,
135+ const goViewPoint = useCallback(() => push(names.VIEW_POINT), [
130− <View>
141+ <View pop={pop} inset>
131− <Grid className="mt6">
142+ <Grid>
132 <Grid.Item full as={H1} className="f6 mono gray4 mb4">
143 <Grid.Item full as={H1} className="f6 mono gray4 mb4">
133 {abbreviateAddress(address)}
144 {abbreviateAddress(address)}
134 </Grid.Item>
145 </Grid.Item>
@@ -139,7 +150,7 @@ export default function Points() {
139 </Grid.Item>
150 </Grid.Item>
142− {isEmpty && (
153+ {displayEmptyState && (
143 <Grid.Item full as={HelpText} className="mt8 t-center">
154 <Grid.Item full as={HelpText} className="mt8 t-center">
144 No points to display. This wallet is not the owner or proxy for any
155 No points to display. This wallet is not the owner or proxy for any
@@ -166,7 +177,7 @@ export default function Points() {
166 text: 'Accept',
177 text: 'Accept',
167 onClick: () => {
178 onClick: () => {
168 setPointCursor(Just(point));
179 setPointCursor(Just(point));
169− history.push(history.names.ACCEPT_TRANSFER);
180+ push(names.ACCEPT_TRANSFER);
@@ -204,7 +215,7 @@ export default function Points() {
204 onClick: () => {
215 onClick: () => {
205 setPointCursor(Just(point));
216 setPointCursor(Just(point));
206 // TODO: deep linking to fix this duplicate route
217 // TODO: deep linking to fix this duplicate route
207− history.push(history.names.CANCEL_TRANSFER);
218+ push(names.CANCEL_TRANSFER);
@@ -224,13 +235,30 @@ export default function Points() {
224 </Grid.Item>
235 </Grid.Item>
227− {isEclipticOwner && (
241+ {isEclipticOwner && (
228− <FooterButton
242+ <>
229− detail="You have the authority to create a new Galaxy."
246+ detail="You have the authority to create a new Galaxy."
230− onClick={() => history.push(ROUTE_NAMES.CREATE_GALAXY)}>
247+ onClick={goCreateGalaxy}>
231− Create a galaxy
248+ Create a galaxy
232− </FooterButton>
249+ </Grid.Item>
233− )}
250+ <Grid.Divider />
256+ detail="View a point"
257+ onClick={goViewPoint}>