@@ -1,4 +1,4 @@
1−import React, { useCallback, useState } from 'react';
1+import React, { useCallback, useState, useEffect } from 'react';
22import { Grid, Button, SelectInput } from 'indigo-react';
33import * as ob from 'urbit-ob';
44import { azimuth } from 'azimuth-js';
@@ -14,12 +14,15 @@ import {
1414 OutButton,
1515 ForwardButton,
1616 BootUrbitOSButton,
17+ GenerateButton,
1718} from 'components/Buttons';
1819import CopyButton from 'components/CopyButton';
1920import NetworkingKeys from 'components/NetworkingKeys';
2021
2122import BridgeForm from 'form/BridgeForm';
2223import { useLocalRouter } from 'lib/LocalRouter';
24+import { useHosting } from 'store/hosting';
25+import DownloadKeyfileButton from 'components/DownloadKeyfileButton';
2326
2427export default function UrbitOSHome() {
2528 const { pointCursor } = usePointCursor();
@@ -32,8 +35,6 @@ export default function UrbitOSHome() {
3235
3336 const sponsor = ob.patp(details.sponsor);
3437
35− const { code, notice } = useKeyfileGenerator();
36−
3738 const [showKeys, setShowKeys] = useState(false);
3839
3940 const showSponsor = azimuth.getPointSize(point) !== azimuth.PointSize.Galaxy;
@@ -53,13 +54,7 @@ export default function UrbitOSHome() {
5354 ]);
5455 return (
5556 <>
56− <Grid>
57− <Grid.Item full className="mv7">
58− Urbit OS
59− </Grid.Item>
60− <Grid.Divider />
61− <Grid.Item full as={BootUrbitOSButton} />
62− </Grid>
57+ <Hosting />
6358
6459 <Grid>
6560 <Grid.Item full className="mv7 f5">
@@ -80,15 +75,7 @@ export default function UrbitOSHome() {
8075 <Grid.Divider />
8176 </>
8277 )}
83− <Grid.Item
84− full
85− as={ForwardButton}
86− accessory={code && <CopyButton text={code} />}
87− detail={code || notice}
88− disabled={!code}
89− detailClassName="mono">
90− Login Code
91− </Grid.Item>
78+
9279 <Grid.Divider />
9380 <Grid.Item full as={ForwardButton} onClick={goNetworkingKeys}>
9481 Reset Networking Keys
@@ -109,52 +96,133 @@ export default function UrbitOSHome() {
10996
11097// eslint-disable-next-line
11198function Hosting() {
99+ const bind = useKeyfileGenerator();
100+ const { keyfile, code, notice } = bind;
101+ const ship = { connected: true }; //useHosting();
102+
103+ const { syncStatus } = ship;
104+
105+ const createShip = useCallback(() => ship.create(keyfile), [keyfile, ship]);
106+
112107 const name = useCurrentPointName();
113108 const options = [{ text: 'Tlon', value: 'tlon' }];
114109
115− const props = { name, options };
116− const connected = false;
117−
118− return (
119− <Grid gap={4}>
120− <Grid.Item full className="f5">
121− Urbit OS
122− </Grid.Item>
110+ const props = { name, options, ship };
123111
124− {(connected && <HostingConnected {...props} />) || (
125− <HostingDisconnected {...props} />
126− )}
127− </Grid>
128− );
129−}
112+ const renderMain = useCallback(() => {
113+ if (ship.connected) {
114+ return (
115+ <>
116+ <Grid.Item cols={[1, 9]} as={OutButton} solid success>
117+ Open OS
118+ </Grid.Item>
119+ <Grid.Item cols={[9, 13]} as={Button} className="b-black b1" center>
120+ Disconnect
121+ </Grid.Item>
122+ </>
123+ );
124+ }
125+ if (ship.missing || ship.booting) {
126+ return (
127+ <Grid.Item
128+ full
129+ as={GenerateButton}
130+ solid
131+ success
132+ disabled={ship.booting || !keyfile}
133+ loading={ship.booting}
134+ onClick={createShip}>
135+ Boot Urbit OS
136+ </Grid.Item>
137+ );
138+ }
139+ if (ship.running || ship.connecting) {
140+ return <HostingDisconnected {...props} />;
141+ }
142+ }, [
143+ ship.connected,
144+ ship.missing,
145+ ship.booting,
146+ ship.running,
147+ ship.connecting,
148+ keyfile,
149+ createShip,
150+ props,
151+ ]);
130152
131−function HostingConnected({ name, options }) {
132− return (
133− <BridgeForm initialValues={{ provider: 'tlon' }}>
134− {() => (
153+ const renderDetails = useCallback(() => {
154+ if (ship.connected) {
155+ return (
135156 <>
136157 <Grid.Item full>Status: Connected</Grid.Item>
137158 <Grid.Item cols={[1, 9]} className="gray4">
138159 <span className="mono">{name}</span> is connected to Tlon and has
139160 the IP address 127.0.0.1
140161 </Grid.Item>
141− <Grid.Item cols={[1, 9]} as={OutButton} solid success>
142− Open OS
162+ </>
163+ );
164+ }
165+ if (ship.running || ship.connected) {
166+ return (
167+ <>
168+ <Grid.Item full className="gray4">
169+ <span className="gray3">Status:</span> Disconnected
170+ <br />
171+ <span className="f6">Last connected: 4m ago</span>
143172 </Grid.Item>
144− <Grid.Item cols={[9, 13]} as={Button} className="b-black b1" center>
145− Disconnect
173+
174+ <Grid.Item full as={ForwardButton} solid>
175+ Connect
146176 </Grid.Item>
147− <Grid.Item
148− full
149− as={SelectInput}
150− name="provider"
151− label="Host Provider"
152− options={options}
153− disabled
154− />
155177 </>
156− )}
157− </BridgeForm>
178+ );
179+ }
180+ }, [name, ship]);
181+
182+ return (
183+ <>
184+ <Grid gap={4}>
185+ <Grid.Item full className="f5">
186+ Urbit OS
187+ </Grid.Item>
188+ <BridgeForm initialValues={{ provider: 'tlon' }}>
189+ {() => (
190+ <>
191+ {renderDetails()}
192+ {renderMain()}
193+ <Grid.Item
194+ full
195+ as={SelectInput}
196+ name="provider"
197+ label="Host Provider"
198+ options={options}
199+ disabled
200+ />
201+ </>
202+ )}
203+ </BridgeForm>
204+ </Grid>
205+ <Grid>
206+ <Grid.Item
207+ full
208+ as={DownloadKeyfileButton}
209+ {...bind}
210+ className="mt2"
211+ detail="A keyfile authenticates your Urbit ID to Urbit OS"
212+ />
213+ <Grid.Divider />
214+ <Grid.Item
215+ full
216+ className="mt2"
217+ as={ForwardButton}
218+ accessory={code && <CopyButton text={code} />}
219+ detail={code || notice}
220+ disabled={!code}
221+ detailClassName="mono">
222+ Login Code
223+ </Grid.Item>
224+ </Grid>
225+ </>
158226 );
159227}
160228