<!--MOBILE USERS: view in debug mode for best performance -->


<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.2.1/css/bootstrap.min.css" integrity="sha384-GJzZqFGwb1QTTN6wy59ffF1BuGJpLSa9DkKMp0DgiMDm4iYMj70gZWKYbI706tWS" crossorigin="anonymous">
<div id="app"></div>
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.6/umd/popper.min.js" integrity="sha384-wHAiFfRlMFy6i5SRaxvfOCifBUQy1xHdJ/yoi7FRNXMRBu5WHdZYu1hA6ZOblgut" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.2.1/js/bootstrap.min.js" integrity="sha384-B0UglyR+jN6CkvvICOB2joaf5I4l3gm9GU6Hc1og6Ls7i6U/mkkaduKaBhlAXv9k" crossorigin="anonymous"></script>
.profileThumb{
  min-width: 50px;
}

.iconStyling{
  font-size: 1.25rem;
  cursor: pointer;
}

.desktopWidth{
  max-width: 1024px;
  margin: auto;
}

.replyDisplay{
  background-color: rgb(250,250,250);
}

.fixedMenuFix{
  margin-top: 4em
}

.btn{
  span{
  font-weight: bold;
    color: white;
  }
}
View Compiled
class App extends React.Component{
  constructor(props){
    super(props)
    
    this.state = {
      allPosts: [{
        title: 'LOADING',
        body: 'LOADING',
        name: 'LOADING',
        username: '@LOADING'
      }],
      
      userPosts: []
    }
    // The following function (this.sortPosts) is the Fisher-Yates (aka Knuth) Shuffle found in JS at
    // https://stackoverflow.com/questions/2450954/how-to-randomize-shuffle-a-javascript-array
    this.sortPosts = this.sortPosts.bind(this)
    this.matchAccounts = this.matchAccounts.bind(this)
    this.userPost = this.userPost.bind(this)
    
    this.loaded = false
    this.postDataWithoutUserInfo = []
    this.newUserPosts = []
  }
  
  componentDidMount(){
    
    if(this.loaded === false){
      fetch('https://jsonplaceholder.typicode.com/posts')
      .then(response => response.json())
      .then(json => this.sortPosts(json))
      .then(()=>{
        return fetch('https://jsonplaceholder.typicode.com/users')
      })
      .then(response => response.json())
      .then(json => this.matchAccounts(json))
      .then(json => this.setState({ allPosts: json }))
      .catch(error=>console.log(error))
    }
    
    this.loaded = true
  }
  
  sortPosts(array){
    var currentIndex = array.length, temporaryValue, randomIndex;

    // While there remain elements to shuffle...
    while (0 !== currentIndex) {
      
      // Pick a remaining element...
      randomIndex = Math.floor(Math.random() * currentIndex);
      currentIndex -= 1;

      // And swap it with the current element.
      temporaryValue = array[currentIndex];
      array[currentIndex] = array[randomIndex];
      array[randomIndex] = temporaryValue;
    }
    
    this.postDataWithoutUserInfo = array;
    return array;
  }
  
  matchAccounts(userData){
    let completeFeedData = []
    for(let i = 0; i < this.postDataWithoutUserInfo.length; i++){
      for(let j = 0; j < userData.length; j++){
        if(this.postDataWithoutUserInfo[i].userId === userData[j].id){

          completeFeedData.push({...this.postDataWithoutUserInfo[i], ...userData[j]})
        }
      }
    }
 
    return completeFeedData
  }
  
  userPost(post){
    let totalLength = this.state.allPosts.length + this.state.userPosts.length
    let newPostData = {
      userId: 11,
      id: totalLength + 2,
      name: 'You',
      username: 'codepen_user',
      body: post,
      userPost: true
    }
    
   this.newUserPosts.unshift(newPostData)
    
    this.setState({
      userPosts: this.newUserPosts
    })
  }
  render(){
    
    return(
      
    <div>
      <Userbar />
      <div className="container">
        <div className="row">
          <div className="col">
            <CreatePost post={this.userPost}/>
          </div>
        </div>
      </div>
      
      <div className="container">
        <UserFeed postData={this.state.userPosts} />
        <Feed postData={this.state.allPosts} />
      </div>
     
   </div>
    )
  }
}

class Userbar extends React.Component{
  render(){
    return(
      <nav className="navbar fixed-top navbar-expand-sm navbar-dark bg-danger">
        <a className="navbar-brand" href="#"><i className="fas fa-user"></i></a>
        <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#userLinks" aria-controls="userLinks" aria-expanded="false" aria-label="Toggle navigation">
    <span class="navbar-toggler-icon"></span>
  </button>
        <div className="collapse navbar-collapse" id="userLinks">
          <ul className="navbar-nav ml-auto">
            <li className="nav-item active"><a className="nav-link" href="#">Feed</a></li>
            <li className="nav-item"><a className="nav-link" href="#">Messages</a></li>
            <li className="nav-item"><a className="nav-link" href="#">Notifications</a></li>
            <li className="nav-item"><a className="nav-link" href="#">Settings</a></li>
          </ul>
        </div>
       </nav>
    )
  }
}

class CreatePost extends React.Component{
  constructor(props){
    super(props)
    
    this.state = {
      postText: ''
    }
    
    this.updatePostText = this.updatePostText.bind(this)
    this.submitPostText = this.submitPostText.bind(this)
  }
  
  updatePostText(e){
    this.setState({
      postText: e.target.value
    })
  }
  
  submitPostText(){
    if(this.state.postText.length > 0){
      this.props.post(this.state.postText)
      document.getElementById('postField').value = ''

      this.setState({
        postText: ''
      })
    }
  }
  
  render(){
    return(
     <div className="mb-2 fixedMenuFix">
      <input id="postField" onChange={this.updatePostText} type="text" className="form-control"  placeholder="What's up?"/>
      <button onClick={this.submitPostText} className="btn btn-large btn-warning btn-block"><span>Post</span></button>
     </div>
    )
  }
}

class UserFeed extends React.Component{
  render(){
    if(this.props.postData.length > 0){
    return(
      <div>
          {this.props.postData.map((post, key)=>
            <Post postData={post} key={post.id} />
          )}
      </div>
    )
    } else {
      return(
        <div></div>
      )
    }
  }
}

class Feed extends React.Component{
  render(){
      
      return(
        <div>
          {this.props.postData.map((post, key) => 
           <Post postData={post} key={post.id}/>
          )}
        </div>
      )
   
  }
}

class Post extends React.Component{
  constructor(props){
    super(props)
    
    this.state = {
      replyWindowStyling: {display: 'none'},
      replies: []
    }
    
    this.replyWindowOpen = this.replyWindowOpen.bind(this)
    this.addReply = this.addReply.bind(this)
    
    this.postReplies = []
  }
  
  replyWindowOpen(){

    if(this.state.replyWindowStyling.display === 'none'){
      this.setState({
        replyWindowStyling: {
          display: 'flex',
          flexWrap: 'wrap'
        }
      })
    } else {
      this.setState({
        replyWindowStyling: {display: 'none'}
      })
    }
  }
  
  addReply(reply){
    let replyData = {
      name: 'You',
      username: 'codepen_user',
      replyID: this.postReplies.length,
      text: reply,
      userID: 11
    }
    
    this.postReplies.push(replyData)
    this.setState({
      replies: this.postReplies
    })
  }
  render(){
    return(
      <div className="row mx-auto justify-content-start border mt-1 p-2 w-100 align-items-center">
        <PostContent postData={this.props.postData} />
        <PostInput replyWindowOpen={this.replyWindowOpen}/>
        <ReplyWindow post={this.addReply} replies={this.state.replies} inlineStyling={this.state.replyWindowStyling} replyName={this.props.postData.username}/>
      </div>
    )
  }
}

class PostContent extends React.Component{
  render(){
    let imageSrc = "https://picsum.photos/50?image" + String(this.props.postData.userId)
    return(
      <div>
        <div className="col-12 d-flex align-items-center">
          <img className={"profileThumb"} src={imageSrc}/>
          <h3 className="font-weight-bold ml-2 mb-1 d-inline-block">{this.props.postData.name}</h3>
          <a href="#" className="ml-2 text-muted">@{this.props.postData.username}</a>
        </div>
        <div className="col-12">
          <p className="mb-0">{this.props.postData.body}</p>
        </div>
     </div>
    )
  }
}

class PostInput extends React.Component{
  
  constructor(props){
    super(props)
    
    this.state = {
      liked: false,
      retweeted: false
    }
    
    this.toggleLike = this.toggleLike.bind(this)
    this.toggleRetweet = this.toggleRetweet.bind(this)
    let likeStyle = {}
    let rtStyle = {}
    this.likeClass = 'far fa-heart mr-4 iconStyling'
    this.rtClass = 'fas fa-retweet mr-4 iconStyling'
  }
  
  toggleLike(){
    
    if(this.state.liked){
      this.likeClass = this.likeClass.replace('fas', 'far')
      this.likeStyle = {}
      this.setState({
        liked: false
      })
    } else {
      this.likeClass = this.likeClass.replace('far', 'fas')
      this.likeStyle = {color: 'red'}
      this.setState({
        liked: true
      })
    }
  }
  
  toggleRetweet(){
    if(this.state.retweeted){
      this.rtStyle = {}
      this.setState({
        retweeted: false
      })
    } else {
      this.rtStyle = {color: 'green'}
      this.setState({
        retweeted: true
      })
    }
  }
  
  render(){
    return(
    <div className="col-sm-12 mt-1">
        <i style={this.likeStyle} onClick={this.toggleLike} className={this.likeClass}></i>
        <i style={this.rtStyle} onClick={this.toggleRetweet} className={this.rtClass}></i>
        <i onClick={this.props.replyWindowOpen} className="fas fa-reply iconStyling"></i>
    </div>

    )
  }
}

class ReplyWindow extends React.Component{
  
  render(){

    return(
     <div style={this.props.inlineStyling} className="w-100">
       <ReplyDisplay className="col-12" replies={this.props.replies}/>
       <ReplyField  replyName={this.props.replyName} post={this.props.post} />
     </div>
      )
  }
}

class ReplyDisplay extends React.Component{
  render(){
    if(this.props.replies.length > 0){
      return(
      <div className="col-sm-12 mt-2">
            {this.props.replies.map((reply, key) => 
              <Reply reply={reply} key={key} />
            )}
      </div>
      )
    } else {
      return(
      <div></div>
      )
    }
  }
}

class Reply extends React.Component{
  render(){
    return(
    <div className='border-top p-2 replyDisplay'>
        <div className="d-flex align-items-center">
          <img src={"https://picsum.photos/50?image" + String(this.props.reply.userID)}/>
          <h5 className="ml-2 font-weight-bold d-inline-block">{this.props.reply.name}</h5>
          <a href="#" className="ml-2 text-muted">@{this.props.reply.username}</a>
        </div>
        <p>{this.props.reply.text}</p>
    </div>
    )
  }
}

class ReplyField extends React.Component{
    constructor(props){
    super(props)
    
    this.state ={
      replyText: ''
    }
    
    this.updateReplyText = this.updateReplyText.bind(this)
    this.submitReply = this.submitReply.bind(this)
    this.id = 'replyField' + String(Math.floor(Math.random() * 100000))
  }
  
  updateReplyText(e){
    this.setState({
      replyText: e.target.value
    })
  }
  
  submitReply(){
    if(this.state.replyText.length > 0){
      this.props.post(this.state.replyText)
      document.getElementById(this.id).value = ''
      this.setState({
        replyText: ''
      })
    }
  }
  
  render(){
  
    return(
     <div className="col-sm-12 form-inline mt-1">
        <div className="input-group flex-grow-1">
         <div class="input-group-prepend">
          <div class="input-group-text">@{this.props.replyName}</div>
        </div>
         <input type="text" onChange={this.updateReplyText} id={this.id} className="form-control"  placeholder="Say something nice!"/>
        </div>
      <button className="btn btn-warning" onClick={this.submitReply}><span>Reply</span></button> 
    </div>
      )
  }
}
ReactDOM.render(<App /> ,document.getElementById('app'))


View Compiled
Run Pen

External CSS

  1. https://use.fontawesome.com/releases/v5.6.3/css/all.css

External JavaScript

  1. https://cdnjs.cloudflare.com/ajax/libs/react/16.7.0/umd/react.production.min.js
  2. https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.7.0/umd/react-dom.production.min.js
  3. https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.2.1/js/bootstrap.min.js