-
Notifications
You must be signed in to change notification settings - Fork 28
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Allow for send invoke calls from websites the user visits #27
Changes from 4 commits
05daccd
b732c14
05be85f
26b5fbf
50bc1ef
9d04029
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,13 +6,17 @@ import style from './Header.css' | |
|
||
export default class Header extends Component { | ||
render() { | ||
const { noMenu } = this.props | ||
|
||
return ( | ||
<div className={style.header}> | ||
<NetworkSwitcher /> | ||
<div className={style.titleBar}> | ||
<div className={style.menuNavWrapper}> | ||
<MainNav /> | ||
</div> | ||
{ noMenu || | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Rather than running this check inline in the JSP, you could break it out and keep your template code a little cleaner.
Then in the JSP, something like There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, I like it. |
||
<div className={style.menuNavWrapper}> | ||
<MainNav /> | ||
</div> | ||
} | ||
<div className={style.titleWrapper}> | ||
<span className={style.titleName}>NeoLink</span> | ||
</div> | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
import React, { Component } from 'react' | ||
import SendInvokeReadonly from '../SendInvoke/SendInvokeReadonly' | ||
|
||
import Header from '../../components/Header' | ||
import ContentWrapper from '../../components/ContentWrapper' | ||
|
||
import style from '../App/App.css' | ||
|
||
export default class PopupWindow extends Component { | ||
state = { | ||
transaction: null, | ||
success: false | ||
} | ||
|
||
componentDidMount () { | ||
this.port = chrome.runtime.connect({name: "popup"}) | ||
this.port.onMessage.addListener((message) => { | ||
if (message.operation === 'sendInvoke') { | ||
this.setState({ | ||
transaction: message.txInfo | ||
}) | ||
} | ||
}) | ||
} | ||
|
||
onSuccess = (response) => { | ||
this.port.postMessage({ msg: 'sendInvokeResponse', status: 'success', txid: response.txid }) | ||
} | ||
|
||
render () { | ||
const { transaction } = this.state | ||
|
||
return ( | ||
<div className={style.popup}> | ||
<Header noMenu /> | ||
<ContentWrapper> | ||
{ !transaction | ||
? <div>Loading</div> | ||
: <SendInvokeReadonly transaction={transaction} onSuccess={this.onSuccess} /> | ||
} | ||
</ContentWrapper> | ||
</div> | ||
) | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,13 @@ | ||
.transactionId { | ||
word-wrap: break-word; | ||
} | ||
.label { | ||
width:100%; | ||
font-weight: bold; | ||
} | ||
|
||
.successBox { | ||
width: 200px; | ||
} | ||
|
||
.entryItem { | ||
width: 80%; | ||
padding-bottom: 10px; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,122 @@ | ||
import React, { Component } from 'react' | ||
|
||
import { connect } from 'react-redux' | ||
|
||
import Button from 'preact-material-components/Button' | ||
import 'preact-material-components/Button/style.css' | ||
import 'preact-material-components/Theme/style.css' | ||
|
||
import { callInvoke } from '../../utils/neonWrappers'; | ||
|
||
import style from './SendInvoke.css' | ||
import globalStyle from '../../components/ContentWrapper/ContentWrapper.css' | ||
|
||
@connect( | ||
state => ({ | ||
network: state.network, | ||
account: state.account | ||
}) | ||
) | ||
|
||
export default class SendInvokeReadonly extends Component { | ||
state = { | ||
loading: false, | ||
errorMsg: '', | ||
txid: '' | ||
} | ||
|
||
handleSubmit = (event) => { | ||
event.preventDefault() | ||
const {network, account, transaction, onSuccess } = this.props | ||
|
||
this.setState({ | ||
loading: true, | ||
errorMsg: '', | ||
txid: '' | ||
}) | ||
|
||
const config = { | ||
scriptHash: transaction.scriptHash, | ||
operation: transaction.operation, | ||
arg1: transaction.args[0], | ||
arg2: transaction.args[1], | ||
amount: transaction.amount, | ||
assetType: transaction.type | ||
} | ||
|
||
callInvoke(network, account, config) | ||
.then((c) => { | ||
if (c.response.result === true) { | ||
this.setState({ | ||
loading: false, | ||
txid: c.response.txid | ||
}) | ||
|
||
if (onSuccess) { | ||
onSuccess(c.response) | ||
} | ||
} else { | ||
this.setState({ | ||
loading: false, | ||
errorMsg: 'Invoke failed' | ||
}) | ||
} | ||
}) | ||
.catch((e) => { | ||
console.log('e', e) | ||
this.setState({ | ||
loading: false, | ||
errorMsg: 'Invoke failed' | ||
}) | ||
}) | ||
} | ||
|
||
render() { | ||
const { loading, txid, errorMsg } = this.state | ||
const { transaction } = this.props | ||
|
||
return ( | ||
<div> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I pointed this out in my big issue the other day, but it's a nice way to break up your concerns if you keep your view JSX in a different component than the connected portion which deals with the redux store. This makes testing easier, separates the implementation from redux in case you want to use the component in a non-connected way, want to remove redux and use a different state management system, or want to keep your testing simple. This would also allow the component to be written as a stateless functional component which is really lightweight and easy to test. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Are you saying we should do something like neon-wallet does? That separates redux and I'm ok with that. Just haven't planned out how to organize everything quite yet. We could follow their pattern or do something a bit different. Or you're saying we should completely separate all jsx from even the react state? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, the way neon-wallet does it is fine! There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @austinhinderer and I have agreed we'll tackle this as part of refactoring when testing is in place. |
||
<form onSubmit={this.handleSubmit} style="padding-top:35px;"> | ||
<div className={style.entryItem}> | ||
<span className={style.label}>Script Hash:</span> | ||
<span className={globalStyle.infoText}>{ transaction.scriptHash }</span> | ||
</div> | ||
<div className={style.entryItem}> | ||
<span className={style.label}>Operation:</span> | ||
<span className={globalStyle.infoText}>{ transaction.operation }</span> | ||
</div> | ||
<div className={style.entryItem}> | ||
<span className={style.label}>Argument 1:</span> | ||
<span className={globalStyle.infoText}>{ transaction.args[0] }</span> | ||
</div> | ||
<div className={style.entryItem}> | ||
<span className={style.label}>Argument 2:</span> | ||
<span className={globalStyle.infoText}>{ transaction.args[1] }</span> | ||
</div> | ||
<div className={style.entryItem}> | ||
<span className={style.label}>Amount:</span> | ||
<span className={globalStyle.infoText}>{ transaction.amount }</span> | ||
</div> | ||
<div className={style.entryItem}> | ||
<span className={style.label}>Asset:</span> | ||
<span className={globalStyle.infoText}>{ transaction.type }</span> | ||
</div> | ||
<Button raised ripple disabled={this.state.loading || this.state.success}>Invoke</Button> | ||
</form> | ||
{ txid && | ||
<div className={style.successBox}> | ||
<div>Success!</div> | ||
<span className={globalStyle.infoText}>txid: { txid }</span> | ||
</div> | ||
} | ||
{ loading && | ||
<div>Loading...</div> | ||
} | ||
{ errorMsg !== '' && | ||
<div>ERROR: {errorMsg}</div> | ||
} | ||
</div> | ||
) | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This code might more clear if it was written in a more declarative way. Something like:
const { hasMenu = false } = this.props
. This way, we can be more truthy, and we don't need to add configuration to take away a thing we don't need, we only have to add add configuration for a thing we want.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good call. I'll update it.