on master help sign in
Placeholder PointHome page for new Point management/overview
3901e19Fang
src/bridge/lib/routeNames.js+1
@@ -7,6 +7,7 @@ export const ROUTE_NAMES = {
7 INVITES_MANAGE: Symbol('INVITES_MANAGE'),
7 INVITES_MANAGE: Symbol('INVITES_MANAGE'),
8 //
8 //
9 LOGIN: Symbol('LOGIN'),
9 LOGIN: Symbol('LOGIN'),
10+ POINT_HOME: Symbol('POINT_HOME'),
10 //
11 //
11 ACCEPT_TRANSFER: Symbol('ACCEPT_TRANSFER'),
12 ACCEPT_TRANSFER: Symbol('ACCEPT_TRANSFER'),
12 CANCEL_TRANSFER: Symbol('CANCEL_TRANSFER'),
13 CANCEL_TRANSFER: Symbol('CANCEL_TRANSFER'),
src/bridge/lib/router.js+4
@@ -7,6 +7,7 @@ import InviteTicket from '../views/InviteTicket';
7import InvitesSend from '../views/InvitesSend.js';
7import InvitesSend from '../views/InvitesSend.js';
8import InvitesManage from '../views/InvitesManage.js';
8import InvitesManage from '../views/InvitesManage.js';
9import Login from '../views/Login.js';
9import Login from '../views/Login.js';
10+import PointHome from '../views/PointHome.js';
10import AcceptTransfer from '../views/AcceptTransfer';
11import AcceptTransfer from '../views/AcceptTransfer';
11import CancelTransfer from '../views/CancelTransfer';
12import CancelTransfer from '../views/CancelTransfer';
12import CreateGalaxy from '../views/CreateGalaxy';
13import CreateGalaxy from '../views/CreateGalaxy';
@@ -44,6 +45,7 @@ const ROUTES = {
44 [ROUTE_NAMES.INVITES_SEND]: InvitesSend,
45 [ROUTE_NAMES.INVITES_SEND]: InvitesSend,
45 [ROUTE_NAMES.INVITES_MANAGE]: InvitesManage,
46 [ROUTE_NAMES.INVITES_MANAGE]: InvitesManage,
46 [ROUTE_NAMES.LOGIN]: Login,
47 [ROUTE_NAMES.LOGIN]: Login,
48+ [ROUTE_NAMES.POINT_HOME]: PointHome,
47 [ROUTE_NAMES.ACCEPT_TRANSFER]: AcceptTransfer,
49 [ROUTE_NAMES.ACCEPT_TRANSFER]: AcceptTransfer,
48 [ROUTE_NAMES.CANCEL_TRANSFER]: CancelTransfer,
50 [ROUTE_NAMES.CANCEL_TRANSFER]: CancelTransfer,
49 [ROUTE_NAMES.NETWORK]: Network,
51 [ROUTE_NAMES.NETWORK]: Network,
@@ -83,6 +85,8 @@ export const getRouteBreadcrumb = ({
83 return 'Send invites';
85 return 'Send invites';
84 case ROUTE_NAMES.INVITES_MANAGE:
86 case ROUTE_NAMES.INVITES_MANAGE:
85 return 'Manage invites';
87 return 'Manage invites';
88+ case ROUTE_NAMES.POINT_HOME:
89+ return 'Overview: ' + ob.patp(need.pointCursor({ pointCursor }));
86 case ROUTE_NAMES.NETWORK:
90 case ROUTE_NAMES.NETWORK:
87 return renderNetworkType(networkType);
91 return renderNetworkType(networkType);
88 case ROUTE_NAMES.WALLET:
92 case ROUTE_NAMES.WALLET:
src/bridge/views/Login.js+6−4
@@ -16,6 +16,7 @@ import {
16import * as need from '../lib/need';
16import * as need from '../lib/need';
17import { compose } from '../lib/lib';
17import { compose } from '../lib/lib';
18import { urbitWalletFromTicket } from '../lib/wallet';
18import { urbitWalletFromTicket } from '../lib/wallet';
19+import { ROUTE_NAMES } from '../lib/routeNames';
19import { withHistory } from '../store/history';
20import { withHistory } from '../store/history';
20import { withNetwork } from '../store/network';
21import { withNetwork } from '../store/network';
21
22
@@ -98,10 +99,11 @@ class Login extends React.Component {
98 return Just.hasInstance(this.state.wallet);
99 return Just.hasInstance(this.state.wallet);
99 }
100 }
100
101
101− continue() {
102+ if (Just.hasInstance(this.props.pointCursor)) {
102− //TODO slightly different for other login methods
103− this.props.setUrbitWallet(this.state.wallet);
104− //TODO history.popAndPush(ROUTE_NAMES.POINT_HOME);
103+ this.props.history.popAndPush(ROUTE_NAMES.POINT_HOME);
104+ } else {
105+ this.props.history.popAndPush(ROUTE_NAMES.SHIPS);
106+ }
105 }
107 }
106
108
107 render() {
109 render() {
src/bridge/views/PointHome.jsnew file+148
@@ -0,0 +1,148 @@
1+import { Just, Nothing } from 'folktale/maybe';
2+import React from 'react';
3+import { pour } from 'sigil-js';
4+import * as ob from 'urbit-ob';
5+import * as azimuth from 'azimuth-js';
6+import * as need from '../lib/need';
7+
8+import PointList from '../components/PointList';
9+import ReactSVGComponents from '../components/ReactSVGComponents';
10+import KeysAndMetadata from './Point/KeysAndMetadata';
11+import Actions from './Point/Actions';
12+import { Row, Col, H1, H3 } from '../components/Base';
13+
14+import { compose } from '../lib/lib';
15+import { ROUTE_NAMES } from '../lib/routeNames';
16+
17+import { withHistory } from '../store/history';
18+import { withNetwork } from '../store/network';
19+import { withPointCursor } from '../store/pointCursor';
20+import { withPointCache } from '../store/pointCache';
21+
22+class PointHome extends React.Component {
23+ constructor(props) {
24+ super(props);
25+
26+ this.state = {
27+ birthday: Nothing(),
28+ spawned: [],
29+ invites: Nothing(),
30+ };
31+ }
32+
33+ componentDidMount() {
34+ this.cachePoints();
35+ this.updateBirthday();
36+ }
37+
38+ //TODO can probably re-use this to implement point switching
39+ componentDidUpdate(prevProps) {
40+ //
41+ // NB (jtobin)
42+ //
43+ // When a link in the 'issued points' component is clicked, we don't
44+ // actually leave the Point component, and componentDidMount will not fire
45+ // again. But, we can force a call to cachePoints here.
46+ //
47+ const oldCursor = prevProps.pointCursor.getOrElse(true);
48+ const newCursor = this.props.pointCursor.getOrElse(true);
49+
50+ if (oldCursor !== newCursor) {
51+ this.cachePoints();
52+ }
53+ }
54+
55+ cachePoints() {
56+ const { web3, contracts, pointCursor, addToPointCache } = this.props;
57+
58+ web3.chain(_ =>
59+ contracts.chain(ctrcs =>
60+ pointCursor.chain(point => {
61+ azimuth.azimuth
62+ .getPoint(ctrcs, point)
63+ .then(details => addToPointCache({ [point]: details }));
64+ azimuth.delegatedSending
65+ .getTotalUsableInvites(ctrcs, point)
66+ .then(count => this.setState({ invites: Just(count) }));
67+ this.updateSpawned(ctrcs, point);
68+ })
69+ )
70+ );
71+ }
72+
73+ async updateBirthday(blockNumber) {
74+ const birthBlock = await azimuth.azimuth.getActivationBlock(
75+ need.contracts(this.props),
76+ need.pointCursor(this.props)
77+ );
78+ if (birthBlock === 0) {
79+ this.setState({ birthday: Nothing() });
80+ } else {
81+ const block = await need.web3(this.props).eth.getBlock(birthBlock);
82+ this.setState({ birthday: Just(new Date(block.timestamp * 1000)) });
83+ }
84+ }
85+
86+ updateSpawned = contracts => {
87+ const { pointCursor } = this.props;
88+
89+ pointCursor.matchWith({
90+ Nothing: _ => {},
91+ Just: point => {
92+ azimuth.azimuth
93+ .getSpawned(contracts, point.value)
94+ .then(spawned => this.setState({ spawned }));
95+ },
96+ });
97+ };
98+
99+ render() {
100+ const { web3, history, wallet, setPointCursor, pointCache } = this.props;
101+
102+ const point = need.pointCursor(this.props);
103+
104+ const pointDetails =
105+ point in pointCache ? Just(pointCache[point]) : Nothing();
106+
107+ const name = ob.patp(point);
108+
109+ const sigil = pour({
110+ patp: name,
111+ renderer: ReactSVGComponents,
112+ size: 256,
113+ });
114+
115+ const online = Just.hasInstance(web3);
116+
117+ const authenticated = Just.hasInstance(wallet);
118+
119+ return (
120+ <Row>
121+ <Col>
122+ <div className={'mt-12 pt-6'}>{sigil}</div>
123+ <H1>
124+ <code>{name}</code>
125+ </H1>
126+ {authenticated ? (
127+ <Actions
128+ online={online}
129+ wallet={wallet}
130+ point={point}
131+ pointDetails={pointDetails}
132+ invites={this.state.invites}
133+ />
134+ ) : null}
135+
136+ {online ? <KeysAndMetadata pointDetails={pointDetails} /> : <div />}
137+ </Col>
138+ </Row>
139+ );
140+ }
141+}
142+
143+export default compose(
144+ withNetwork,
145+ withHistory,
146+ withPointCursor,
147+ withPointCache
148+)(PointHome);