/ src / components / Post.js
Post.js
  1  import {Card, CardActions, CardContent, CardHeader} from '@material-ui/core';
  2  import React, {Component} from 'react';
  3  import Blockies from 'react-blockies';
  4  import CircularProgress from '@material-ui/core/CircularProgress';
  5  import DownvoteIcon from '@material-ui/icons/ExpandMore';
  6  import IconButton from '@material-ui/core/IconButton';
  7  import MoreVertIcon from '@material-ui/icons/MoreVert';
  8  import PropTypes from 'prop-types';
  9  import Typography from '@material-ui/core/Typography';
 10  import UpvoteIcon from '@material-ui/icons/ExpandLess';
 11  import dateformat from 'dateformat';
 12  import markdownJS from "markdown";
 13  import {withStyles} from '@material-ui/core/styles';
 14  
 15  import EmbarkJS from '../embarkArtifacts/embarkjs';
 16  import DReddit from '../embarkArtifacts/contracts/DReddit';
 17  
 18  const markdown = markdownJS.markdown;
 19  
 20  const styles = theme => ({
 21      actions: {
 22        marginRight: theme.spacing.unit * 5,
 23        fontSize: 15,
 24        display: 'flex'
 25      },
 26      card: {
 27        margin: theme.spacing.unit,
 28        marginTop: theme.spacing.unit * 4,
 29        position: 'relative'
 30      },
 31      title: {
 32          borderBottom: '1px solid #ccc',
 33          color: '#666'
 34      },
 35      spinner: {
 36          position: 'absolute',
 37          right: theme.spacing.unit * 3
 38      }
 39  });  
 40  
 41  const ballot = {
 42      NONE: 0,
 43      UPVOTE: 1,
 44      DOWNVOTE: 2
 45  };
 46  
 47  const contains = (filterBy, content, title, date, owner) => {
 48    if(!filterBy) return true;
 49    filterBy = filterBy.trim().toLowerCase();
 50    if(filterBy === '') return true;
 51    return  content.toLowerCase().indexOf(filterBy) > -1 || 
 52          title.toLowerCase().indexOf(filterBy) > -1 || 
 53          date.indexOf(filterBy) > -1 || 
 54          owner.toLowerCase().indexOf(filterBy) > -1;
 55  };
 56  
 57  class Post extends Component {
 58  
 59      constructor(props){
 60          super(props);
 61  
 62          this.state = {
 63              title: '',
 64              content: '',
 65              isSubmitting: false,
 66              canVote: true,
 67              upvotes: props.upvotes,
 68              downvotes: props.downvotes
 69          };
 70      }
 71  
 72      componentDidMount(){
 73          EmbarkJS.onReady(() => {
 74              this._loadAttributes();
 75          });
 76      }
 77  
 78      _loadAttributes = async () => {
 79          // const ipfsHash = web3.utils.toAscii(this.props.description);
 80  
 81          const ipfsText = await EmbarkJS.Storage.get(this.props.description);
 82  
 83          const jsonContent = JSON.parse(ipfsText);
 84          const title = jsonContent.title;
 85          const content = jsonContent.content;
 86  
 87          const canVote = await DReddit.methods.canVote(this.props.id).call();
 88  
 89          this.setState({
 90              title,
 91              content,
 92              canVote
 93          });
 94      }
 95  
 96      _vote = choice => async event => {
 97          event.preventDefault();
 98          this.setState({isSubmitting: true});
 99  
100          const {vote} = DReddit.methods;
101          const toSend = vote(this.props.id, choice);
102          const estimatedGas = await toSend.estimateGas(); 
103          
104          await toSend.send({gas: estimatedGas + 1000});
105          
106          this.setState({
107              canVote: false,
108              upvotes: this.state.upvotes + (choice === ballot.UPVOTE ? 1 : 0),
109              downvotes: this.state.downvotes + (choice === ballot.DOWNVOTE ? 1 : 0)
110          });
111  
112          this.setState({isSubmitting: false});
113      }
114  
115      render(){
116          const {title, content, upvotes, downvotes, isSubmitting, canVote} = this.state;
117          const {creationDate, classes, owner, filterBy} = this.props;
118          const disabled = isSubmitting || !canVote;
119          const formattedDate = dateformat(new Date(creationDate * 1000), "yyyy-mm-dd HH:MM:ss");
120          const mdText = markdown.toHTML(content);
121  
122          const display = contains(filterBy, content, title, formattedDate, owner);
123  
124          return display&& <Card className={classes.card}>
125              <CardHeader title={owner} subheader={formattedDate}
126                  avatar={
127                      <Blockies seed={owner} size={7} scale={5} />
128                  }
129                  action={
130                  <IconButton>
131                      <MoreVertIcon />
132                  </IconButton>
133                } />
134              <CardContent>
135                  <Typography variant="h6"  className={classes.title}  gutterBottom>
136                  {title}
137                  </Typography>
138                  <Typography component="div" dangerouslySetInnerHTML={{__html: mdText}} />
139              </CardContent>
140              <CardActions disableActionSpacing>
141                  <IconButton className={classes.actions} disabled={disabled} onClick={this._vote(ballot.UPVOTE)}>
142                  <UpvoteIcon />
143                  {upvotes}
144                  </IconButton>
145                  <IconButton className={classes.actions} disabled={disabled} onClick={this._vote(ballot.DOWNVOTE)}>
146                  <DownvoteIcon />
147                  {downvotes}
148                  </IconButton>
149                  { isSubmitting && <CircularProgress size={14} className={classes.spinner} /> }
150            </CardActions>
151          </Card>;
152      }
153      
154  }
155  
156  Post.propTypes = {
157      filterBy: PropTypes.string,
158      upvotes: PropTypes.number.isRequired,
159      downvotes: PropTypes.number.isRequired,
160      classes: PropTypes.object.isRequired,
161      id: PropTypes.number.isRequired,
162      owner: PropTypes.string.isRequired,
163      creationDate: PropTypes.string.isRequired,
164      description: PropTypes.string.isRequired
165    };
166    
167  
168  export default withStyles(styles)(Post);