140 lines
3.9 KiB
JavaScript
140 lines
3.9 KiB
JavaScript
import { Link } from 'react-router-dom'
|
||
import { Button, FormGroup, ControlLabel, FormControl, HelpBlock } from 'react-bootstrap';
|
||
import React, { Component } from 'react';
|
||
import FieldGroup from './FieldGroup';
|
||
|
||
/**
|
||
* Class that renders a form to allow the user to create
|
||
* a tweet that is stored in the contract.
|
||
*
|
||
* @extends React.Component
|
||
*/
|
||
class DoTweet extends Component{
|
||
|
||
//#region Constructor
|
||
constructor(props, context) {
|
||
super(props, context);
|
||
|
||
// initial state
|
||
this.state = {
|
||
tweet: '',
|
||
tweetHasChanged: false,
|
||
isLoading: false,
|
||
error: ''
|
||
};
|
||
|
||
this.tweetInput = null;
|
||
}
|
||
//#endregion
|
||
|
||
//#region Component events
|
||
/**
|
||
* Handles the 'Tweet' button click event which
|
||
* sends a transaction to the contract to store a
|
||
* tweet for the current user.
|
||
*
|
||
* @returns {null}
|
||
*/
|
||
_handleClick = async (e) => {
|
||
|
||
// do not post tweet if there is a form error or user has not typed anything
|
||
if(this._getValidationState() === 'error' || !this.state.tweetHasChanged){
|
||
return e.preventDefault();
|
||
}
|
||
|
||
// show loading state
|
||
this.setState({ isLoading: true });
|
||
|
||
const { username, account, onAfterTweet } = this.props;
|
||
const tweet = DTwitter.methods.tweet(this.state.tweet);
|
||
|
||
try{
|
||
// estimate gas before sending tweet transaction
|
||
|
||
// send the tweet transaction plus a little extra gas in case the contract state
|
||
// has changed since we've done our gas estimate
|
||
|
||
// remove loading state
|
||
this.setState({ isLoading: false });
|
||
|
||
// tell parent we've updated a user and to re-fetch user details from the contract
|
||
onAfterTweet();
|
||
}
|
||
catch(err){
|
||
// remove loading state and show error message
|
||
this.setState({ isLoading: false, error: err.message });
|
||
}
|
||
}
|
||
|
||
/**
|
||
* When user changes an input value, record that in the state.
|
||
*
|
||
* @param {SyntheticEvent} cross-browser wrapper around the browser’s native event
|
||
*
|
||
* @return {null}
|
||
*/
|
||
_handleChange(e) {
|
||
let state = {tweetHasChanged: true};
|
||
state[e.target.name] = e.target.value;
|
||
this.setState(state);
|
||
}
|
||
//#endregion
|
||
|
||
//#region Helper methods
|
||
/**
|
||
* Validates the form. Return null for no state change,
|
||
* 'success' if valid, and error' if invalid.
|
||
*
|
||
* @return {string} null for no state change, 'success'
|
||
* if valid, and error' if invalid
|
||
*/
|
||
_getValidationState() {
|
||
return ((this.state.tweet === '' && !this.state.tweetHasChanged) || (this.state.tweet.length > 0 && this.state.tweet.length <= 140)) ? null : 'error';
|
||
}
|
||
//#endregion
|
||
|
||
//#region React lifecycle events
|
||
componentDidMount(){
|
||
// set focus to tweet textarea after render
|
||
if(this.tweetInput) this.tweetInput.focus();
|
||
}
|
||
|
||
render(){
|
||
|
||
const validationState = this._getValidationState();
|
||
const isValid = validationState !== 'error';
|
||
const { isLoading, error, tweet, tweetHasChanged } = this.state;
|
||
|
||
let feedback = !isValid ? 'Tweet must be 140 characters or less' : '';
|
||
if(this.state.error) feedback = error;
|
||
|
||
return (
|
||
<form>
|
||
<FieldGroup
|
||
type="text"
|
||
value={ tweet }
|
||
placeholder="140 characters or less..."
|
||
onChange={ (e) => this._handleChange(e) }
|
||
name="tweet"
|
||
componentClass="textarea"
|
||
hasFeedback={true}
|
||
validationState={validationState}
|
||
inputRef={(input) => { this.tweetInput = input; }}
|
||
/>
|
||
<Button
|
||
bsStyle="primary"
|
||
disabled={ !isValid || Boolean(error) || !tweetHasChanged }
|
||
onClick={ (!isValid || Boolean(error) || !tweetHasChanged) ? null : (e) => this._handleClick(e) }
|
||
>{isLoading ? 'Loading...' : 'Post tweet'}</Button>
|
||
<FormGroup
|
||
controlId="formBasicText"
|
||
validationState={ validationState }
|
||
>
|
||
<HelpBlock>{ feedback }</HelpBlock>
|
||
</FormGroup>
|
||
</form>
|
||
);
|
||
}
|
||
//#endregion
|
||
}
|
||
export default DoTweet |