mirror of
https://github.com/ilyakooo0/urbit.git
synced 2024-11-28 19:55:53 +03:00
btc: improved transitions and error handling for startup modals
This commit is contained in:
parent
a9706c7ece
commit
e3c20a2901
@ -7,6 +7,7 @@ import {
|
||||
Icon,
|
||||
Row,
|
||||
Input,
|
||||
LoadingSpinner,
|
||||
} from '@tlon/indigo-react';
|
||||
|
||||
import { isValidPatp } from 'urbit-ob';
|
||||
@ -16,8 +17,12 @@ export default class ProviderModal extends Component {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
potentialProvider: null,
|
||||
checkingProvider: false,
|
||||
providerFailed: false,
|
||||
ready: false,
|
||||
provider: null,
|
||||
connecting: false,
|
||||
}
|
||||
|
||||
this.checkProvider = this.checkProvider.bind(this);
|
||||
@ -28,20 +33,27 @@ export default class ProviderModal extends Component {
|
||||
// TODO: loading states
|
||||
let provider = e.target.value;
|
||||
let ready = false;
|
||||
let checkingProvider = false;
|
||||
let potentialProvider = this.state.potentialProvider;
|
||||
|
||||
if (isValidPatp(provider)) {
|
||||
let command = {
|
||||
"check-provider": provider
|
||||
}
|
||||
potentialProvider = provider;
|
||||
checkingProvider = true;
|
||||
this.props.api.btcWalletCommand(command);
|
||||
setTimeout(() => {
|
||||
this.setState({providerFailed: true, checkingProvider: false});
|
||||
}, 5000);
|
||||
}
|
||||
this.setState({provider, ready});
|
||||
this.setState({provider, ready, checkingProvider, potentialProvider});
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps, prevState){
|
||||
if (!this.state.ready){
|
||||
if (this.props.providerPerms[this.state.provider]) {
|
||||
this.setState({ready: true});
|
||||
this.setState({ready: true, checkingProvider: false, providerFailed: false});
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -52,16 +64,35 @@ export default class ProviderModal extends Component {
|
||||
"set-provider": this.state.provider
|
||||
}
|
||||
this.props.api.btcWalletCommand(command);
|
||||
this.setState({connecting: true});
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
let workingNode = (!this.state.ready) ? null :
|
||||
<Box mt={3}>
|
||||
<Text fontSize="14px" color="green">
|
||||
{this.state.provider} is a working provider node
|
||||
</Text>
|
||||
</Box>
|
||||
|
||||
let workingNode = null;
|
||||
let workingColor = null;
|
||||
let workingBg = null;
|
||||
if (this.state.ready) {
|
||||
workingColor = "green";
|
||||
workingBg = "veryLightGreen"
|
||||
workingNode =
|
||||
<Box mt={3}>
|
||||
<Text fontSize="14px" color="green">
|
||||
{this.state.provider} is a working provider node
|
||||
</Text>
|
||||
</Box>
|
||||
} else if (this.state.providerFailed) {
|
||||
workingColor = "red";
|
||||
workingBg = "veryLightRed"
|
||||
workingNode =
|
||||
<Box mt={3}>
|
||||
<Text fontSize="14px" color="red">
|
||||
{this.state.potentialProvider} is not a working provider node
|
||||
</Text>
|
||||
</Box>
|
||||
}
|
||||
|
||||
return (
|
||||
<Box
|
||||
width="100%"
|
||||
@ -84,29 +115,37 @@ export default class ProviderModal extends Component {
|
||||
Provider Node
|
||||
</Text>
|
||||
</Box>
|
||||
<StatelessTextInput
|
||||
fontSize="14px"
|
||||
type="text"
|
||||
name="masterTicket"
|
||||
placeholder="e.g. ~zod"
|
||||
autoCapitalize="none"
|
||||
autoCorrect="off"
|
||||
mono
|
||||
backgroundColor={this.state.ready ? "veryLightGreen": null}
|
||||
color={this.state.ready ? "green": null}
|
||||
borderColor={this.state.ready ? "green": null}
|
||||
onChange={this.checkProvider}
|
||||
/>
|
||||
<Row alignItems="center">
|
||||
<StatelessTextInput
|
||||
mr={2}
|
||||
width="256px"
|
||||
fontSize="14px"
|
||||
type="text"
|
||||
name="masterTicket"
|
||||
placeholder="e.g. ~zod"
|
||||
autoCapitalize="none"
|
||||
autoCorrect="off"
|
||||
mono
|
||||
backgroundColor={workingBg}
|
||||
color={workingColor}
|
||||
borderColor={workingColor}
|
||||
onChange={this.checkProvider}
|
||||
/>
|
||||
{(this.state.checkingProvider) ? <LoadingSpinner/> : null}
|
||||
</Row>
|
||||
{workingNode}
|
||||
<Button
|
||||
mt={3}
|
||||
primary
|
||||
disabled={!this.state.ready}
|
||||
children="Set Peer Node"
|
||||
fontSize="14px"
|
||||
style={{cursor: this.state.ready ? "pointer" : "default"}}
|
||||
onClick={() => {this.submitProvider(this.state.provider)}}
|
||||
/>
|
||||
<Row alignItems="center" mt={3}>
|
||||
<Button
|
||||
mr={2}
|
||||
primary
|
||||
disabled={!this.state.ready}
|
||||
children="Set Peer Node"
|
||||
fontSize="14px"
|
||||
style={{cursor: this.state.ready ? "pointer" : "default"}}
|
||||
onClick={() => {this.submitProvider(this.state.provider)}}
|
||||
/>
|
||||
{(this.state.connecting) ? <LoadingSpinner/> : null}
|
||||
</Row>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ import {
|
||||
Icon,
|
||||
Row,
|
||||
Input,
|
||||
LoadingSpinner,
|
||||
} from '@tlon/indigo-react';
|
||||
|
||||
const kg = require('urbit-key-generation');
|
||||
@ -24,7 +25,7 @@ function bip44To84(network, xpub) {
|
||||
return bs58check.encode(data);
|
||||
}
|
||||
|
||||
const NETWORK = "testnet" // "bitcoin"
|
||||
const NETWORK = 'testnet'
|
||||
const DERIVATIONS = {
|
||||
bitcoin: "m/84'/0'/0'",
|
||||
testnet: "m/84'/1'/0'",
|
||||
@ -40,7 +41,8 @@ export default class WalletModal extends Component {
|
||||
mode: 'masterTicket',
|
||||
masterTicket: '',
|
||||
xpub: '',
|
||||
ready: false,
|
||||
readyToSubmit: false,
|
||||
processingSubmission: false,
|
||||
}
|
||||
this.checkTicket = this.checkTicket.bind(this);
|
||||
this.checkXPub = this.checkXPub.bind(this);
|
||||
@ -51,14 +53,14 @@ export default class WalletModal extends Component {
|
||||
checkTicket(e){
|
||||
// TODO: port over bridge ticket validation logic
|
||||
let masterTicket = e.target.value;
|
||||
let ready = (masterTicket.length > 0);
|
||||
this.setState({masterTicket, ready});
|
||||
let readyToSubmit = (masterTicket.length > 0);
|
||||
this.setState({masterTicket, readyToSubmit});
|
||||
}
|
||||
|
||||
checkXPub(e){
|
||||
let xpub = e.target.value;
|
||||
let ready = (xpub.length > 0);
|
||||
this.setState({xpub, ready});
|
||||
let readyToSubmit = (xpub.length > 0);
|
||||
this.setState({xpub, readyToSubmit});
|
||||
}
|
||||
|
||||
submitMasterTicket(ticket){
|
||||
@ -91,9 +93,15 @@ export default class WalletModal extends Component {
|
||||
}
|
||||
}
|
||||
api.btcWalletCommand(command);
|
||||
this.setState({processingSubmission: true});
|
||||
}
|
||||
|
||||
render() {
|
||||
const buttonDisabled = (!this.state.readyToSubmit || this.state.processingSubmission );
|
||||
const inputDisabled = this.state.processingSubmission;
|
||||
const processingSpinner = (!this.state.processingSubmission) ? null :
|
||||
<LoadingSpinner/>
|
||||
|
||||
if (this.state.mode === 'masterTicket'){
|
||||
return (
|
||||
<Box
|
||||
@ -118,31 +126,41 @@ export default class WalletModal extends Component {
|
||||
Master Key
|
||||
</Text>
|
||||
</Box>
|
||||
<StatelessTextInput
|
||||
value={this.state.masterTicket}
|
||||
fontSize="14px"
|
||||
type="password"
|
||||
name="masterTicket"
|
||||
obscure={value => value.replace(/[^~-]+/g, '••••••')}
|
||||
placeholder="••••••-••••••-••••••-••••••"
|
||||
autoCapitalize="none"
|
||||
autoCorrect="off"
|
||||
onChange={this.checkTicket}
|
||||
/>
|
||||
<Row alignItems="center">
|
||||
<StatelessTextInput
|
||||
mr={2}
|
||||
width="256px"
|
||||
value={this.state.masterTicket}
|
||||
disabled={inputDisabled}
|
||||
fontSize="14px"
|
||||
type="password"
|
||||
name="masterTicket"
|
||||
obscure={value => value.replace(/[^~-]+/g, '••••••')}
|
||||
placeholder="••••••-••••••-••••••-••••••"
|
||||
autoCapitalize="none"
|
||||
autoCorrect="off"
|
||||
onChange={this.checkTicket}
|
||||
/>
|
||||
{(!inputDisabled) ? null : <LoadingSpinner/>}
|
||||
</Row>
|
||||
<Box mt={3} mb={3}>
|
||||
<Text fontSize="14px" fontWeight="regular" color="gray"
|
||||
style={{cursor: "pointer"}}
|
||||
onClick={() => { this.setState({mode: 'xpub', xpub: ''})}}
|
||||
<Text fontSize="14px" fontWeight="regular"
|
||||
color={(inputDisabled) ? "lighterGray" : "gray"}
|
||||
style={{cursor: (inputDisabled) ? "default" : "pointer"}}
|
||||
onClick={() => {
|
||||
if (inputDisabled) return;
|
||||
this.setState({mode: 'xpub', xpub: '', masterTicket: '', readyToSubmit: false})
|
||||
}}
|
||||
>
|
||||
Manually import your extended public key ->
|
||||
</Text>
|
||||
</Box>
|
||||
<Button
|
||||
primary
|
||||
disabled={!this.state.ready}
|
||||
disabled={buttonDisabled}
|
||||
children="Next Step"
|
||||
fontSize="14px"
|
||||
style={{cursor: this.state.ready ? "pointer" : "default"}}
|
||||
style={{cursor: buttonDisabled ? "default" : "pointer"}}
|
||||
onClick={() => {this.submitMasterTicket(this.state.masterTicket)}}
|
||||
/>
|
||||
</Box>
|
||||
@ -172,6 +190,7 @@ export default class WalletModal extends Component {
|
||||
</Box>
|
||||
<StatelessTextInput
|
||||
value={this.state.xpub}
|
||||
disabled={inputDisabled}
|
||||
fontSize="14px"
|
||||
type="password"
|
||||
name="xpub"
|
||||
@ -189,11 +208,11 @@ export default class WalletModal extends Component {
|
||||
fontSize="14px"
|
||||
mr={2}
|
||||
style={{cursor: "pointer"}}
|
||||
onClick={() => {this.setState({mode: 'masterTicket', xpub: ''})}}
|
||||
onClick={() => {this.setState({mode: 'masterTicket', masterTicket: '', xpub: '', readyToSubmit: false})}}
|
||||
/>
|
||||
<Button
|
||||
primary
|
||||
disabled={!this.state.ready}
|
||||
disabled={buttonDisabled}
|
||||
children="Next Step"
|
||||
fontSize="14px"
|
||||
style={{cursor: this.state.ready ? "pointer" : "default"}}
|
||||
|
Loading…
Reference in New Issue
Block a user