@@ -0,0 +1,190 @@
1+import React, { useState, useMemo, useCallback, useEffect } from 'react';
2+import { Grid } from 'indigo-react';
3+import * as ob from 'urbit-ob';
4+import { azimuth, ecliptic } from 'azimuth-js';
5+
6+import { useNetwork } from 'store/network';
7+import { usePointCache } from 'store/pointCache';
8+
9+import { PointInput } from 'form/Inputs';
10+import FormError from 'form/FormError';
11+import BridgeForm from 'form/BridgeForm';
12+
13+import InlineEthereumTransaction from 'components/InlineEthereumTransaction';
14+import ViewHeader from 'components/ViewHeader';
15+import {
16+ composeValidator,
17+ buildPointValidator,
18+ hasErrors,
19+} from 'form/validators';
20+
21+import * as need from 'lib/need';
22+import { validateMinimumPatpByteLength } from 'lib/validators';
23+import { usePointCursor } from 'store/pointCursor';
24+import useEthereumTransaction from 'lib/useEthereumTransaction';
25+
26+function useChangeSponsor() {
27+ const { contracts } = useNetwork();
28+ const { pointCursor } = usePointCursor();
29+ const { syncOwnedPoint } = usePointCache();
30+
31+ const _contracts = need.contracts(contracts);
32+ const point = need.point(pointCursor);
33+
34+ return useEthereumTransaction(
35+ useCallback(sponsor => ecliptic.escape(_contracts, point, sponsor), [
36+ point,
37+ _contracts,
38+ ]),
39+ useCallback(() => {
40+ syncOwnedPoint(point);
41+ }, [syncOwnedPoint, point])
42+ );
43+}
44+
45+function ChangeSponsor({ onDone }) {
46+ const { contracts } = useNetwork();
47+
48+ const _contracts = need.contracts(contracts);
49+ const { construct, unconstruct, inputsLocked, bind } = useChangeSponsor();
50+
51+ const [newSponsor, setNewSponsor] = useState(false);
52+
53+ const validateFormAsync = useCallback(
54+ async values => {
55+ const sponsor = ob.patp2dec(values.sponsor);
56+ const details = await azimuth.getPoint(_contracts, sponsor);
57+ console.log(details);
58+ console.log(details.keyRevisionNumber);
59+
60+ if (details.keyRevisionNumber === 0) {
61+ return { sponsor: 'Sponsor is not online' };
62+ }
63+ },
64+ [_contracts]
65+ );
66+
67+ const validateForm = useCallback(
68+ (values, errors) => {
69+ if (hasErrors(errors)) {
70+ return errors;
71+ }
72+ return validateFormAsync(values);
73+ },
74+ [validateFormAsync]
75+ );
76+
77+ const validate = useMemo(
78+ () =>
79+ composeValidator(
80+ {
81+ sponsor: buildPointValidator(2, [validateMinimumPatpByteLength(2)]),
82+ },
83+ validateForm
84+ ),
85+ [validateForm]
86+ );
87+
88+ const onValues = useCallback(
89+ ({ valid, values }) => {
90+ if (valid) {
91+ construct(ob.patp2dec(values.sponsor));
92+ setNewSponsor(values.sponsor);
93+ } else {
94+ unconstruct();
95+ }
96+ },
97+ [construct, unconstruct]
98+ );
99+ return (
100+ <Grid>
101+ <Grid.Item full as={ViewHeader}>
102+ Change Sponsor
103+ </Grid.Item>
104+ <BridgeForm validate={validate} onValues={onValues}>
105+ {() => (
106+ <>
107+ <Grid.Item
108+ full
109+ as={PointInput}
110+ name="sponsor"
111+ disabled={inputsLocked}
112+ label="New sponsor"
113+ />
114+ <Grid.Item full as={FormError} />
115+ <Grid.Item
116+ full
117+ as={InlineEthereumTransaction}
118+ {...bind}
119+ onReturn={onDone}
120+ label="Request"
121+ />
122+ </>
123+ )}
124+ </BridgeForm>
125+ </Grid>
126+ );
127+}
128+
129+function useCancelEscape() {
130+ const { contracts } = useNetwork();
131+ const { pointCursor } = usePointCursor();
132+ const { syncOwnedPoint } = usePointCache();
133+
134+ const _contracts = need.contracts(contracts);
135+ const point = need.point(pointCursor);
136+
137+ return useEthereumTransaction(
138+ useCallback(() => ecliptic.cancelEscape(_contracts, point), [
139+ point,
140+ _contracts,
141+ ]),
142+ useCallback(() => syncOwnedPoint(point), [point, syncOwnedPoint])
143+ );
144+}
145+
146+function CurrentEscape({ onDone }) {
147+ const { construct, bind } = useCancelEscape();
148+
149+ useEffect(() => {
150+ construct();
151+ }, [construct]);
152+ return (
153+ <Grid>
154+ <Grid.Item full as={ViewHeader}>
155+ Currently requesting <span className="mono">~dopzod</span> as a new
156+ sponsor
157+ </Grid.Item>
158+ <Grid.Item
159+ full
160+ as={InlineEthereumTransaction}
161+ label="Cancel Request"
162+ {...bind}
163+ onReturn={onDone}
164+ />
165+ </Grid>
166+ );
167+}
168+
169+export default function UrbitOSChangeSponsor() {
170+ const { contracts } = useNetwork();
171+ const { pointCursor } = usePointCursor();
172+
173+ const point = need.point(pointCursor);
174+
175+ const { getDetails } = usePointCache();
176+
177+ const details = need.details(getDetails(point));
178+
179+ const [requested, setRequested] = useState(details.escapeRequested);
180+
181+ const onDone = useCallback(() => {
182+ setRequested(details.escapeRequested);
183+ }, [details, setRequested]);
184+
185+ return requested ? (
186+ <CurrentEscape onDone={onDone} />
187+ ) : (
188+ <ChangeSponsor onDone={onDone} />
189+ );
190+}