@@ -1,198 +1,178 @@
1−import React from 'react';
1+import React, { useCallback, useEffect, useState } from 'react';
2−import { Just, Nothing } from 'folktale/maybe';
2+import { Nothing, Just } from 'folktale/maybe';
3+import cn from 'classnames';
4+import { Grid, Text, Input } from 'indigo-react';
3import * as azimuth from 'azimuth-js';
5import * as azimuth from 'azimuth-js';
4−import * as ob from 'urbit-ob';
5−import * as need from '../lib/need';
7−import { Button } from '../components/old/Base';
8−import { H1, P, Anchor } from '../components/old/Base';
15−} from '../components/old/Base';
16−import StatelessTransaction from '../components/old/StatelessTransaction';
18−import { NETWORK_TYPES } from '../lib/network';
19−import { canDecodePatp } from '../lib/txn';
21−import { isValidAddress, isZeroAddress } from '../lib/wallet';
23−import { isValidGalaxy, compose } from '../lib/lib';
24−import { withNetwork } from '../store/network';
25−import { withWallet } from '../store/wallet';
26−import View from 'components/View';
28−const buttonTriState = status => {
29− if (status === null) return 'blue';
30− if (status === false) return 'yellow';
31− if (status === true) return 'green';
34−const buttonTriStateText = status => {
35− if (status === null) return 'Confirm Galaxy Availablility';
36− if (status === false) return 'Galaxy is Not Available';
37− if (status === true) return 'Galaxy is Available';
40−class CreateGalaxy extends React.Component {
44− const galaxyOwner = need.addressFromWallet(props.wallet);
47− galaxyOwner: galaxyOwner,
52− this.handleAddressInput = this.handleAddressInput.bind(this);
53− this.handleGalaxyNameInput = this.handleGalaxyNameInput.bind(this);
54− this.confirmAvailability = this.confirmAvailability.bind(this);
55− this.createUnsignedTxn = this.createUnsignedTxn.bind(this);
56− this.statelessRef = React.createRef();
59− handleGalaxyNameInput = galaxyName => {
60− this.setState({ galaxyName, isAvailable: null });
61− this.statelessRef.current.clearTxn();
64− handleAddressInput = galaxyOwner => {
65− this.setState({ galaxyOwner });
66− this.statelessRef.current.clearTxn();
69− createUnsignedTxn = () => {
7+import { useNetwork } from 'store/network';
70− const { state, props } = this;
8+import { useHistory } from 'store/history';
71− if (isValidAddress(state.galaxyOwner) === false) return Nothing();
9+import { usePointCache } from 'store/pointCache';
72− if (state.isAvailable === false) return Nothing();
73− if (canDecodePatp(state.galaxyName) === false) return Nothing();
74− if (isValidGalaxy(state.galaxyName) === false) return Nothing();
76− const validContracts = need.contracts(props.contracts);
11+import * as need from 'lib/need';
12+import { useAddressInput, useGalaxyInput } from 'lib/useInputs';
13+import useEthereumTransaction from 'lib/useEthereumTransaction';
14+import { GAS_LIMITS } from 'lib/constants';
15+import patp2dec from 'lib/patp2dec';
78− const galaxyDec = ob.patp2dec(state.galaxyName);
17+import ViewHeader from 'components/ViewHeader';
79−
18+import MiniBackButton from 'components/MiniBackButton';
19+import InlineEthereumTransaction from 'components/InlineEthereumTransaction';
20+import View from 'components/View';
21+import { isZeroAddress } from 'lib/wallet';
23+function useCreateGalaxy() {
24+ const { contracts } = useNetwork();
25+ const { syncKnownPoint } = usePointCache();
27+ const _contracts = need.contracts(contracts);
29+ const [galaxy, setGalaxy] = useState();
32+ construct: _construct,
37+ } = useEthereumTransaction(GAS_LIMITS.DEFAULT);
39+ const construct = useCallback(
80− const txn = azimuth.ecliptic.createGalaxy(
42+ _construct(azimuth.ecliptic.createGalaxy(_contracts, galaxy, owner));
81− validContracts,
43+ },
82− galaxyDec,
44+ [_construct, _contracts]
83− state.galaxyOwner
45+ );
49+ syncKnownPoint(galaxy);
51+ }, [confirmed, galaxy, syncKnownPoint]);
86− return Just(txn);
53+ return {
89− confirmAvailability = async () => {
62+export default function CreateGalaxy() {
90− const { state, props } = this;
63+ const { pop } = useHistory();
64+ const { contracts } = useNetwork();
65+ const _contracts = need.contracts(contracts);
67+ const [error, setError] = useState();
68+ const [isAvailable, setIsAvailable] = useState(Nothing());
76+ } = useCreateGalaxy();
80+ { pass: validGalaxyName, syncPass: syncValidGalaxyName, value: galaxyName },
81+ // ^ we use value: here so our effect runs onChange
83+ disabled: inputsLocked,
87+ isAvailable.matchWith({
88+ Nothing: () => 'Loading availabiliy...', // TODO: make async loading?
89+ Just: p => (p.value ? undefined : 'This galaxy is already owned'),
93+ const [ownerInput, { pass: validOwner, data: owner }] = useAddressInput({
95+ label: `Ethereum Address`,
96+ disabled: inputsLocked,
100+ if (validGalaxyName && validOwner) {
101+ construct(patp2dec(galaxyName), owner);
105+ }, [owner, construct, unconstruct, validGalaxyName, validOwner, galaxyName]);
92− if (canDecodePatp(state.galaxyName) === false) {
107+ useEffect(() => {
93− this.setState({ isAvailable: false });
108+ if (!syncValidGalaxyName || inputsLocked) {
97− const validContracts = need.contracts(props.contracts);
112+ setIsAvailable(Nothing());
99− const galaxyDec = ob.patp2dec(state.galaxyName);
114+ let cancelled = false;
101− const currentOwner = await azimuth.azimuth.getOwner(
118+ const currentOwner = await azimuth.azimuth.getOwner(
102− validContracts,
119+ _contracts,
103− galaxyDec
120+ patp2dec(galaxyName)
106− const available = isZeroAddress(currentOwner);
123+ const isAvailable = isZeroAddress(currentOwner);
108− this.setState({ isAvailable: available });
125+ if (cancelled) {
111− render() {
129+ setIsAvailable(Just(isAvailable));
112− const { props, state } = this;
130+ } catch (error) {
113−
131+ console.error(error);
114− const validAddress = isValidAddress(state.galaxyOwner);
132+ setError(error.message);
115− const validGalaxy = isValidGalaxy(state.galaxyName);
133+ setIsAvailable(Just(false));
117− const canGenerate =
135+ })();
118− validAddress === true &&
136+
119− validGalaxy === true &&
137+ return () => (cancelled = true);
120− state.isAvailable === true;
138+ }, [
122− const esvisible =
140+ galaxyName,
123− props.networkType === NETWORK_TYPES.ROPSTEN ||
141+ inputsLocked,
124− props.networkType === NETWORK_TYPES.MAINNET;
142+ setIsAvailable,
125−
143+ syncValidGalaxyName,
126− const esdomain =
144+ ]);
127− props.networkType === NETWORK_TYPES.ROPSTEN
145+
128− ? 'ropsten.etherscan.io'
146+ return (
129− : 'etherscan.io';
147+ <View inset>
131− return (
149+ <Grid.Item full as={MiniBackButton} onClick={() => pop()} />
151+ <Grid.Item full as={ViewHeader}>
133− <H1> {'Create a Galaxy'} </H1>
152+ Create a Galaxy
136− {'Enter the galaxy to create and the address that will own ' +
155+ {confirmed && (
137− 'it (defaulting to this account, if not provided).'}
156+ <Grid.Item
140− <GalaxyInput
159+ className={cn('f5', {
141− className="mono"
160+ green3: confirmed,
142− prop-size="lg"
161+ })}>
143− prop-format="innerLabel"
162+ {galaxyName} has been created and is owned by {owner}.
144− autoFocus
163+ </Grid.Item>
145− placeholder="e.g. ~zod"
164+ )}
146− value={state.galaxyName}
165+
147− onChange={v => this.handleGalaxyNameInput(v)}>
166+ <Grid.Item full as={Input} {...galaxyNameInput} className="mt4" />
148− <InnerLabel>{'Galaxy Name'}</InnerLabel>
167+ <Grid.Item full as={Input} {...ownerInput} className="mb4" />
150− className="tr-0 mt-05 mr-0 abs"
169+ <Grid.Item
151− patp={state.galaxyName}
170+ full
152− size={68}
171+ as={InlineEthereumTransaction}
153− margin={8}
172+ {...bind}
154− />
173+ onReturn={() => pop()}
158− className="mono mt-8"
160− prop-format="innerLabel"
161− value={state.galaxyOwner}
162− onChange={v => this.handleAddressInput(v)}>
163− <InnerLabel>{'Address that will own this galaxy'}</InnerLabel>
164− <ShowBlockie className={'mt-1'} address={state.galaxyOwner} />
170− prop-disabled={!validAddress || !esvisible}
172− href={`https://${esdomain}/address/${state.galaxyOwner}`}>
173− {'View on Etherscan ↗'}
179− prop-color={buttonTriState(state.isAvailable)}
180− disabled={!validGalaxy}
181− onClick={() => this.confirmAvailability()}>
182− {buttonTriStateText(state.isAvailable)}
185− <StatelessTransaction
186− ref={this.statelessRef}
187− canGenerate={canGenerate}
188− createUnsignedTxn={this.createUnsignedTxn}
195−export default compose(