Hide the Balance exercise

finally I need to code more
App.js

handleRefreshBalance(){
    this.setState(function({name, ticker, price,balance, showBalance}){
      return {
        name,
        ticker,
        price, 
        balance,
        showBalance: !showBalance
      }
    })
  }

render() {
    return (
    <>
      <ExchangeHeader/>
      <AccountBalance amount = {this.state.balance} showBalance  = {this.state.showBalance}
      handleRefreshBalance = {this.handleRefreshBalance}/> 
      <CoinList coinData ={this.state.coinData} handleRefresh = {this.handleRefresh}
      showBalance = {this.state.showBalance}/> 
    </>
    )
  }
}

CoinList.jsx

import React, { Component } from 'react'
import Coin from '../Coin/Coin';

export default class CoinList extends Component {
  
  render() {
      return (
        <div>
          <table>
              <thead> 
                <tr>
                  <th>Name</th>
                  <th>Ticker</th>
                  <th>Price</th>
                  {this.props.showBalance ? <th>Balance</th> : null}
                  <th>Update</th>
                </tr>
              </thead>
            <tbody >
                { 
                this.props.coinData.map(({name, ticker, price, balance}) => <Coin key = {ticker} 
                handleRefresh = {this.props.handleRefresh}
                name = {name} 
                ticker = {ticker} 
                price = {price} 
                balance = {balance}
                showBalance = {this.props.showBalance}/>) 
                }
            </tbody>  
          </table> 
        </div>
        )
    }
}

Coin.jsx

export default class Coin extends Component {
    constructor(props){
        super(props);
            this.handleClick = this.handleClick.bind(this);
    }
    
    handleClick(event) {
        event.preventDefault();  
        this.props.handleRefresh(this.props.ticker);
    }
        
    render() {
        return ( 
            <Tr>
                <Td>{this.props.name}</Td>
                <Td>{this.props.ticker}</Td>
                <Td>${this.props.price}</Td>
                {this.props.showBalance ? <Td>${this.props.balance}</Td> : null }
                
                <Td>
                    <form action = "#" method = "POST"/>  
                        <button onClick={this.handleClick }>Refresh</button>
                </Td>
            </Tr>    
        );
    }
}

AccountBalance.jsx

export default class AccountBalance extends Component {
    render() {
        const buttonText = this.props.showBalance ?  'HideBalance' : 'ShowBalance'; 
        const amountText = this.props.showBalance ? `Amount = ${this.props.amount}` : ' '; 
        return (
            <Section>   
                <p>{amountText}</p> 
                <button onClick = {this.props.handleRefreshBalance} >{buttonText}</button>
           </Section>
            
        )
    }
}


2 Likes
App.js
import React from 'react';
import styled from 'styled-components';
import Header from './components/Header/Header.jsx';
import CoinList from './components/CoinList/CoinList';
import AccountBalance from './components/AccountBalance/AccountBalance'

const AppDiv = styled.div`
    text-align: center;
    background-color: darkblue;
    color: #cccccc
`;

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      balance: 10000,
      coinData: [
          {
            name: 'Bitcoin',
            ticker: 'BTC',
            balance: 1,
            price: 9999.99
          },
          {
            name: 'Ethereum',
            ticker: 'ETH',
            balance: 2,
            price: 299.99
          },
          {
            name: 'Tether',
            ticker: 'USDT',
            balance: 0.5,
            price: 1
          },
          {
            name: 'Ripple',
            ticker: 'XRP',
            balance: 1000,
            price: 0.2
          },
          {
            name: 'Bitcoin Cash',
            ticker: 'BCH',
            balance: 0,
            price: 298.99
          }
      ],
      showBalance: true
    }
    this.handleRefresh = this.handleRefresh.bind(this);
    this.handleToggleBalance = this.handleToggleBalance.bind(this);
  }
  handleRefresh(valueChangeTicker) {
    const newCoinData = this.state.coinData.map( function( {ticker, name, balance, price} ) {
      let newPrice = price;
      if ( valueChangeTicker === ticker ) {
        const randomPercentage = 0.995 + Math.random() * 0.01;
        newPrice = newPrice * randomPercentage
      };
      return {
        // ticker = ticker, name = name
        ticker,
        name,
        balance: balance,
        price: newPrice
      }
    });
    
    this.setState({ coinData: newCoinData })
  }

  handleToggleBalance() {
    this.setState({ showBalance: !this.state.showBalance });
  }

  render() {
    return (
      <AppDiv>
        <Header />
        <AccountBalance amount={this.state.balance} handleToggleBalance={this.handleToggleBalance} showBalance={this.state.showBalance} />
        <CoinList coinData={this.state.coinData} handleRefresh={this.handleRefresh} showBalance={this.state.showBalance} />
      </AppDiv>
    );
  }
  
}

export default App;


AccountBalance.jsx
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import styled from 'styled-components';

const Section = styled.section`
    font-size: 2rem;
    text-align: left;
    padding: 1.5rem 0 1.5rem 5rem;
    color: greenyellow;
`;

export default class AccountBalance extends Component {
  constructor(props) {
    super(props);
    this.handleClick = this.handleClick.bind(this)
  }
//there's a problem with toggling the state
  state = {
    showBalance: true
  };

  handleClick(event) {
    event.preventDefault();
    this.props.handleToggleBalance();
  }

    render() {
        // if balance is shown, present a button to 'hide balance'.
        // otherwise, present a button to 'show balance'
        const buttonText = this.props.showBalance ? 'Hide Balance' : 'Show Balance';
        const toggleBalance = this.props.showBalance ?
        <><strong> Balance: </strong> ${this.props.amount}</>
        : null;
        return (
            <Section>
                {toggleBalance}
                <button onClick={this.handleClick}>{buttonText} </button>
            </Section>
        );
    }
}


AccountBalance.propTypes = {
    amount: PropTypes.number.isRequired
}

Coin.jsx
import React, { Component } from 'react'
import PropTypes from 'prop-types';
import styled from 'styled-components';

const TableData = styled.td`
    border: 1px solid #cccccc;
    width: 25vh;
`;

export default class Coin extends Component {
    constructor(props) {
        super(props);
        this.handleClick = this.handleClick.bind(this);
    }
    
    handleClick(event) {
        // We want to prevent the default action of
        // re-submitting the form upon clicking 'refresh'
        event.preventDefault();

        this.props.handleRefresh(this.props.ticker);
/*
        const randomPercentage = 0.995 + Math.random() * 0.01;
        this.setState( function(oldState) {
            return {
                price: oldState.price * randomPercentage
            };
        });
*/
    }

    render() {
        const toggleBalance = this.props.showBalance ?
        <TableData>{this.props.balance}</TableData>
        : null;

        return (
            <tr>
                <TableData>{this.props.name}</TableData>
                <TableData>{this.props.ticker}</TableData>
                {toggleBalance}
                <TableData>${this.props.price}</TableData>
                <TableData>
                    <form action="#" method="POST">
                        <button onClick={this.handleClick}>Refresh</button>
                    </form>
                </TableData>
            </tr>
        );
    }
}

Coin.propTypes = {
    name: PropTypes.string.isRequired,
    ticker: PropTypes.string.isRequired,
    price: PropTypes.number.isRequired
}

CoinList.jsx
import React, { Component } from 'react'
import Coin from '../Coin/Coin';
import styled from 'styled-components';

const CoinTable = styled.table`
    margin: 50px auto 50px auto;
    display: inline-block;
    font-size: 1.4rem;
`;

export default class CoinList extends Component {
    render() {
      const toggleBalance = this.props.showBalance ?
      <th>Balance</th>
      : null;

        return (
            <CoinTable>
            <thead>
              <tr>
                <th>Name</th>
                <th>Ticker</th>
                {toggleBalance}
                <th>Price</th>
                <th>Actions</th>
              </tr>
            </thead>
            <tbody>
              {
                /* Abbreviating the following code:
                    ({name, ticker, price, balance}) =>
                    <Coin key-{value.ticker} name={name} ticker={ticker} price={price}
                    balance={balance} />
                */
                this.props.coinData.map( value =>
                   <Coin key={value.ticker}
                       handleRefresh={this.props.handleRefresh}
                       {...value}
                       showBalance={this.props.showBalance} />
                )
              }
            </tbody>
          </CoinTable>
        )
    }
}

I’m still sticking to a methodology of simple graphics and functionality for now. It feels suitable for other projects going forward. Get the minimum viable product/app up and running, then improve graphics, UI and functionality - mainly graphics and UI - once the app is complete. I don’t envison styling taking too long, though I recognize it is a vital part of the production process, and requires just as much precision in its execution as the programming itself.

EDIT: Github Link

2 Likes
  • App.js
class App extends React.Component {
  state = {
    balance: 10000,
    showBalance: true,
    coinData: [
      {
        // key: uuidv4(),
        name: 'Bitcoin',
        ticker: 'BTC',
        balance: 0.5,
        price: 9999.99
      },
      {
        // key: uuidv4(),
        name: 'Ethereum',
        ticker: 'ETH',
        balance: 32,
        price: 299.99
      },
      {
        // key: uuidv4(),
        name: 'Tether',
        ticker: 'USDT',
        balance: 0,
        price: 1.00
      },
      {
        // key: uuidv4(),
        name: 'Ripple',
        ticker: 'XRP',
        balance: 1000,
        price: 0.2
      },
      {
        // key: uuidv4(),
        name: 'Bitcoin Cash',
        ticker: 'BCH',
        balance: 0,
        price: 298.99
      }
    ]
  }


  handleBalanceVisibilityChange = () => {
    this.setState(function(oldState) {
      return{
        ...oldState,
        showBalance: !oldState.showBalance
      }
    });
  }

  handleRefresh = (valueChangeTicker) => {
    const newCoinData = this.state.coinData.map((values) => {
      let newValues = {...values};
      if (valueChangeTicker === newValues.ticker) {
        const randomPercentage = 0.995 + Math.random() * 0.01;
        newValues.price *= randomPercentage;
      }
      return newValues
    });
    this.setState({coinData: newCoinData});
  }

  render(){
    return (
      <Div className="App">

        <CoinHeader />
        <AccountBalance
            amount={this.state.balance}
            showBalance={this.state.showBalance}
            handleBalanceVisibilityChange={this.handleBalanceVisibilityChange}
          />
        <CoinList
            coinData={this.state.coinData}
            showBalance={this.state.showBalance}
            handleRefresh={this.handleRefresh}
          />

      </Div>
    );
  }
}
  • accountBalance
export default class AccountBalance extends Component {
  render() {
    const buttonText = this.props.showBalance ? 'Hide Balance' : 'Show Balance';
    let content = null;

    if (this.props.showBalance) {
        content = <>Balance: ${this.props.amount}</>
    }

    return (
      <>
        <Section>
          {content}
          <button onClick={this.props.handleBalanceVisibilityChange}>{buttonText}</button>
        </Section>
      </>
    );
  }
}
  • coin
{this.props.showBalance ? <Td>${this.props.balance}</Td> : null}
  • coinList
export default class CoinList extends Component {
  render() {
    return (
      <Table>
        <thead>
          <tr>
            <th>Name</th>
            <th>Ticker</th>
            <th>Price</th>
            {this.props.showBalance ? <th>Balance</th> : null}
            <th>Actions</th>
          </tr>
        </thead>
        <tbody>
        {
          this.props.coinData.map(({key, name, ticker, price, balance}) =>
              <Coin key={ticker}
                    handleRefresh={this.props.handleRefresh}
                    name={name}
                    ticker={ticker}
                    showBalance={this.props.showBalance}
                    balance={balance}
                    price={price}
              />
            )
        }
1 Like

Had fun doing the exercise :slight_smile:

App.js

class App extends React.Component {

  constructor(props){
    super(props);
    this.state= 
      balance: 10000,
      isPrivate: true,
      coinData: [
        {
          name: "Bitcoin",
          ticker: "BTC",
          coinBalance: 0.5,
          price: 31078.19
        },
        {
          name: "Ethereum",
          ticker: "ETH",
          coinBalance: 1.5,
          price: 1180.88
        },
        {
          name: "Tether",
          ticker: "USDT",
          coinBalance: 15.5,
          price: 0.99
        },
        {
          name: "Polkadot",
          ticker: "DOT",
          coinBalance: 0.8,
          price: 17.11
        },
        {
          name: "XRP",
          ticker: "XRP",
          coinBalance: 2,
          price: 0.25
        }
      ]
    }
    this.handleRefresh = this.handleRefresh.bind(this);
    this.setPrivacy = this.setPrivacy.bind(this);
  }
  setPrivacy(){
    this.setState(oldState => ({
      isPrivate: !oldState.isPrivate
    }));
    }
               //handleRefresh() goes here

  render(){
    return (
      <AppDiv>
        <HeaderDesign/>
        <Banner/>
        <ViewBalance balance={this.state.balance}
                     setPrivacy={this.setPrivacy}
                     isPrivate={this.state.isPrivate}/>
        <CoinList coinData={this.state.coinData}
                  isPrivate={this.state.isPrivate}
                  handleRefresh={this.handleRefresh}/>
      </AppDiv>
    );
  }
}
export default App;

AccountBalance.jsx

export default class ViewBalance extends Component{
    constructor(props){
        super(props);
        this.handleChange = this.handleChange.bind(this)
    }
    handleChange(){
        this.props.setPrivacy();
    }
    render() {
        const buttonText = this.props.isPrivate ? "Hide Balance" : "Show Balance";
        return (
            <AccountBalDiv>
                {
                    this.props.isPrivate ?
                <>
                    <CurrentBal>Current Balance</CurrentBal>
                        <BalanceSection>
                            <TinyDollarSign>$</TinyDollarSign>
                            <BalanceFig>{this.props.balance}</BalanceFig>
                        </BalanceSection>
                </>
                    :
                    null
                }
                <div>
                <button onClick={this.handleChange}>{buttonText}</button>
                </div>
        </AccountBalDiv>
        );
    }
}

Coin.js

{
                    this.props.isPrivate ? (<TableTD>{this.props.coinBalance}</TableTD>) :
                    (<TableTD>Balance hidden</TableTD>)
}

CoinList.js

{
                    this.props.coinData.map( value =>
                      <CoinDetails key={value.ticker}
                                    handleRefresh = {this.props.handleRefresh}
                                    name={value.name}
                                    ticker={value.ticker}
                                    coinBalance={value.coinBalance}
                                    isPrivate={this.props.isPrivate}
                                    price={value.price}/>
                    )
                  }
3 Likes

App

class App extends React.Component {
  
  constructor(props) {
    super(props);
    this.state = {
      visible: true,
      balance: 10000,
      coinData: [{
        
        name: 'Bitcoin',
        ticker: 'BTC',
        price:  35470.8,
        balance: 0.5
      }, 
      {
        name: 'Ethereum',
        ticker: 'ETH',
        price:  1453.6,
        balance: 32
      },
      {
        name: 'Tether',
        ticker: 'USDT',
        price:  0.99,
        balance: 0
      },
      {
        name: 'Polkadot',
        ticker: 'DOT',
        price:  17.8,
        balance: 100
      },
      {
        name: 'DuckDaoDimm',
        ticker: 'DDIM',
        price:  61.4,
        balance: 25
      }
     ]
    }
    this.handleRefresh = this.handleRefresh.bind(this);
    this.handleHide = this.handleHide.bind(this);
  }
  handleRefresh(nTicker){
     const newCoinData = this.state.coinData.map(function({ticker,name,price,balance}){
        let newPrice = price;
        if (nTicker === ticker) {
          const randomPercentage = 0.995 + Math.random() * 0.01;
          newPrice = newPrice * randomPercentage;
        }
        return {
          ticker,
          name,
          price: newPrice,
          balance
        }
     });

     this.setState({ coinData: newCoinData});
    }

    handleHide(val){
      this.setState({ visible: val});
     }
  render() {
  return (
    <DivApp className="App">
      <ExchangeHeader/>
      <AccountBalance amount={this.state.balance} showBalance={this.state.visible} handleHide={this.handleHide}/>
      <CoinList visible={this.state.visible} coinData={this.state.coinData} handleRefresh={this.handleRefresh} />
    </DivApp>
  );

 }
}

export default App;

AccountBalance

export default class AccountBalance extends Component {
    constructor(props) {
        super(props);   
        this.handleClickOff = this.handleClickOff.bind(this);
        this.handleClickOn = this.handleClickOn.bind(this);
    }

    handleClickOff(event){

        event.preventDefault();
    
        this.props.handleHide(false);
    }

    handleClickOn(event){

        event.preventDefault();
    
        this.props.handleHide(true);
     }

    render() {
        const show = this.props.showBalance;
        const buttonText = show ? 'Hide Balance' : 'Show Balance';
        if(show){
            return (
                <Section>
                 Balance: ${this.props.amount}  
                 <button onClick={this.handleClickOff}>{buttonText}</button>
                </Section>
            )
        }
        if(!show){
        return (
            <Section>
             * 
             <button onClick={this.handleClickOn}>{buttonText}</button>
            </Section>
        )
    }
    }
}

AccountBalance.propTypes = {
    amount: PropTypes.number.isRequired
}

CoinList

export default class CoinList extends Component {
    render() {
        return (          
        <Table className="coin-table">
        <thead>
          <tr>
            <th>Name</th>
            <th>Ticker</th>
            <th>Price</th>
            <th>Balance</th>
            <th>Actions</th>
          </tr>
        </thead>
        <tbody>
        {
        
        this.props.coinData.map( ({name, ticker, price, balance}) => 
        <Coin key={ticker} 
              handleRefresh={this.props.handleRefresh}
              name={name} 
              ticker={ticker} 
              price={price}
              balance ={this.props.visible ? balance : "*"} />
          )
        }
        </tbody>
      </Table>
            
        )
    }
}

3 Likes

App

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      balance: 10000,
      showBalance: true,
      coinData: [
        {
          name: "Bitcoin",
          ticker: "BTC",
          balance: 0.5,
          price: 9999.99
        },
        {
          name: "Ethereum",
          ticker: "ETH",
          balance: 32.0,
          price: 299.99
        },
        {
          name: "Tether",
          ticker: "USDT",
          balance: 0,
          price: 1.0
        },
        {
          name: "Ripple",
          ticker: "XRP",
          balance: 1000,
          price: 0.2
        },
        {
          name: "Bitcoin Cash",
          ticker: "BCH",
          balance: 0,
          price: 298.99
        }
      ]
    }
    this.handleRefresh = this.handleRefresh.bind(this);
    this.handleHideBalance = this.handleHideBalance.bind(this);
  }

    handleHideBalance() {
      this.setState(function (oldState)  {
        return {
          ...oldState,
          showBalance: !oldState.showBalance
        }

      });
    }
  

  handleRefresh(valueChangeTicker) {
   const newCoinData = this.state.coinData.map( function( {ticker, name, price, balance} ) {
     let newPrice = price;
    if (valueChangeTicker === ticker) {
      const randomPercentage = 0.995 + Math.random() * 0.01;
      newPrice = newPrice * randomPercentage;
      }
      return {
        ticker,
        name,
        price: newPrice,
        balance,
        
      }
   });
    
   this.setState({coinData: newCoinData});
  }
  render() {
    return (
      <Div>
          <ExchangeHeader/>
          <AccountBalance amount={this.state.balance} 
                          showBalance={this.state.showBalance} 
                          handleHideBalance={this.handleHideBalance} />
          <CoinList coinData={this.state.coinData} 
                    showBalance= {this.state.showBalance}
                    handleRefresh={this.handleRefresh}/>
      </Div>
    );
    
  }
 
  
}

export default App;

CoinList

 {this.props.showBalance ? <th>Balance</th> : null}
                <th>Actions</th>  
               </tr> 
            </thead>
            <tbody>
              {
                this.props.coinData.map( ({name, ticker, price, balance}) => 
                <Coin   key={ticker} 
                        handleRefresh={this.props.handleRefresh}
                        showBalance={this.props.showBalance}
                        name={name} 
                        ticker={ticker}
                        balance={balance} 
                        price={price} />
                )
              }
           </tbody>
          </Table>
        )
    }

Coin

 render() {
       
        return (
                <tr>
                    <Td>{this.props.name}</Td>
                    <Td>{this.props.ticker}</Td>
                    <Td>${this.props.price}</Td>
                     {this.props.showBalance ? <Td>${this.props.balance}</Td> : null}
                    <Td>
                        <form action="#" method="POST">
                        <button onClick={this.handleClick}>Refresh</button>
                        </form>
                        
                    </Td>
                </tr>
            );
    }
}

Coin.propTypes = {
    name: PropTypes.string.isRequired,
    ticker: PropTypes.string.isRequired,
    price: PropTypes.number.isRequired,
    balance: PropTypes.number.isRequired
}

AccountBalance

export default class AccountBalance extends Component {
    
    render() {
        const buttonText = this.props.showBalance ? "Hide Balance" : "Show Balance"
        let content = null;
        if (this. props.showBalance) {
            content = <>Balance: ${this.props.amount}</>
        }
        return (
            <Section>
             {content}
             <button onClick={this.props.handleHideBalance}>{buttonText}</button> 
            </Section>
        );
    }
    
}



AccountBalance.propTypes = {
       amount: PropTypes.number.isRequired
}
3 Likes

this was the hardest exercise i’ve had until now took me a lot of time to get this right.
This is the main App.js file:


import React from 'react';
import CoinList from './components/CoinList/CoinList';
import AccountBalance from './components/AccountBalance/AccountBalance'
import styled from 'styled-components';
import ExchangeHeader from './components/ExchangeHeader/ExchangeHeader';

const Div = styled.div`
  text-align: center;
  background-color: rgb(20, 56, 97);
  color: #cccccc;

`;

class App extends React.Component {
  constructor(props) {
      super(props);
      this.state = {
        balance: 10000,
        coinData:[
          {
        ]
      }
      this.handleRefresh = this.handleRefresh.bind(this);
      this.handleVisibilityChange = this.handleVisibilityChange.bind(this);
  }

  handleVisibilityChange(){
    this.setState( function(oldState) {
      return{
        ...oldState,
        showBalance: !oldState.showBalance
      }
    });
  }

  handleRefresh(valueChangeTicker){
    let newCoinData = this.state.coinData.map(function ( {ticker, name, price} ) {
      let newPrice = price;
      if ( valueChangeTicker === ticker ) {
        const randomPercentage = 0.995 + Math.random() * 0.01;
        newPrice = newPrice * randomPercentage;
      }
      return{
        ticker, 
        name, 
        price: newPrice
      }
    });    
    this.setState({ coinData: newCoinData })
  }


  render(){
    return (
      <Div className="App">
        <ExchangeHeader />
        <AccountBalance amount={this.state.balance} 
            showBalance={true} 
            handleVisibilityChange={this.handleVisibilityChange}/>
        <CoinList coinData={this.state.coinData} 
            handleRefresh={this.handleRefresh} 
            showBalance = {this.state.showBalance}/>
      </Div>
    );

  }
 
}

export default App;

this is the CoinList.jsx file:

import React, { Component } from 'react';
import Coin from '../Coin/Coin';
import styled from 'styled-components';

const Table = styled.table`
    margin: 25px auto 50px auto;
    display: inline-block;
    font-size: 1.4rem;                         
`;



export default class CoinList extends Component {
    render() {
        return (
            <Table>
            <thead>
                <tr>
                  <th>Name</th>
                  <th>Ticker</th>
                  <th>Price</th>
                  {this.props.showBalance ? <th>Balance</th> : null}
                  <th>Actions</th>
                </tr>
            </thead>
            <tbody>
              {
                this.props.coinData.map( ({name, ticker, price, balance}) => 
                  <Coin key={ticker} 
                      handleRefresh={this.props.handleRefresh} 
                      name={name} 
                      ticker={ticker} 
                      balance={balance}
                      showBalance={this.props.showBalance}
                      price={price} />
                )
              }
         
            </tbody>
          </Table>
        )
    }
}

This is the AccounBalance.jsx file:

import React, { Component } from 'react';
import PropTypes from 'prop-types';
import styled from 'styled-components';

const Section = styled.section`
    font-size: 2rem;
    text-align: left;
    padding: 2rem 3rem 0rem;
`;




export default class AccountBalance extends Component {

    render() {
        const buttonText = this.props.showBalance ? 'Hide Balance' : 'Show Balance';
        let content = null;
        if ( this.props.showBalance ) {
            content = <>Balance: $ {this.props.amount} </>
        }
        return (
            <Section >
             Balance: ${this.props.amount}   
             <button onClick={this.props.handleVisibilityChange}>{buttonText}</button>
            </Section>
        );
    }
}



AccountBalance.propTypes = { 
    amount: PropTypes.number.isRequired
  }

This is the Coin.jsx file:

import React, { Component } from 'react';
import propTypes from 'prop-types';
import styled from 'styled-components';


const Td = styled.td`
  border: 1px solid #cccccc;
  padding: 0.5rem 3rem 0.5rem;
`;


export default class Coin extends Component {
  constructor(props){
    super(props);
    this.handleClick = this.handleClick.bind(this);
  }

    handleClick(event) {
      //prevent the default action of submitting
      event.preventDefault();

      this.props.handleRefresh(this.props.ticker);

        /*
      const randomPercentage = 0.995 + Math.random() * 0.01;

        this.setState( function(oldState) {
          return{
            price: oldState.price * randomPercentage
          };
        });
      */
      }
      
    render() {
        return (
          <tr>
              <Td>{this.props.name}</Td>
              <Td>{this.props.ticker}</Td>
              <Td>{this.props.price}</Td>
              {this.props.showBalance ? <Td>{this.props.balance}</Td> : null }
              <Td>
                <form action="#" method="POST">
                  <button onClick={this.handleClick}>Refresh</button>
                </form>
                
              </Td>

          </tr>
        );
      }
};

Coin.propTypes = { 
  name: propTypes.string.isRequired,
  ticker: propTypes.string.isRequired,
  price: propTypes.number.isRequired
};
2 Likes

App.js
import React from 'react'
import './App.css'
import AccountBalance from './components/AccountBalance/AccountBalance'
import CoinList from './components/CoinList/CoinList'
import Header from './components/Header/Header'

class App extends React.Component {
  
    constructor(props) {
      super(props)
      this.state = {
        balance: 1000,
        showBalance: false,
        coinData: [
          {
            name: "Bitcoin",
            ticker: "BTC",
            balance: 0.2,
            price: 48000
          },
          {
            name: "Ethereum",
            ticker: "ETH",
            balance: 1,
            price: 1800
          },
          {
            name: "Tether",
            ticker: "USDT",
            balance: 200,
            price: 1
          },
          {
            name: "Ripple",
            ticker: "XRP",
            balance: 100,
            price: 0.3 
          },
        ]
      }
      this.refreshPrice = this.refreshPrice.bind(this)
      this.toggleBalance = this.toggleBalance.bind(this)
    }

    toggleBalance() {
      //console.log("App.js: in toggleBalance()")
      const newShowBalance = !this.state.showBalance
      this.setState( {showBalance: newShowBalance} )
    }

    refreshPrice(targetTicker) {
      //const coin = this.state.coinData.find( ({ticker}) => ticker === targetTicker )
      //console.log(coin)

      // Zsolt Nagy solution: it follows IMMUTABILITY 'cause it make a copy of the changed object (coinData)
      
      const newCoinData = this.state.coinData.map ( ( {ticker, name, balance, price} ) => {
        let newPrice = price
        if ( targetTicker === ticker ) {
          const randomPercentage = 0.995 + Math.random() *0.01
          newPrice *= randomPercentage    
        }
        return {
          ticker,
          name,
          balance,
          price: newPrice
        }
      } )
      
      this.setState( {coinData: newCoinData} )
      

      /*
      // My solution: WRONG IT DOESN'T Follow IMMUTABILITY
      // You must avoid methods that mutate the array like push/splice/pop/shift and you must not change directly an item.
      
      const randomPercentage = 0.995 + Math.random() *0.01

      const coinIdx = this.state.coinData.findIndex( ({ticker}) => ticker === targetTicker )

      this.setState( ( {coinData} ) => { 
        coinData[coinIdx].price *= randomPercentage
        console.log(this.state)
        return coinData[coinIdx]
      })
      */
      

      /*
      // Old example for setState
      this.setState( 
         (oldState) => {
            return {
               price: oldState.price * randomPercentage
            }
         }
      )
      */

    }

    render() {
      return (
        <div className="App">
          <Header />
          <AccountBalance amount={this.state.balance} showBalance={this.state.showBalance} toggleBalance={this.toggleBalance}/>
          <CoinList coinData={this.state.coinData} showBalance={this.state.showBalance} refreshPrice={this.refreshPrice} />
        </div>
      )
  }
  
}

// You could do like this for rendering Coin components
// this.state.coinData.map( value => <Coin key={value.ticker} {...value} /> )
// OR
// this.state.coinData.map( (value) => <Coin key={value.ticker} name={value.name} ticker={value.ticker} price={value.price} /> )
// OR
// this.state.coinData.map( ({name,ticker,price}) => <Coin key={ticker} name={name} ticker={ticker} price={price} /> )

export default App;

CoinList.jsx
import React, { Component } from 'react'
import './CoinList.css'
import Coin from '../Coin/Coin'

export default class CoinList extends Component {
   render() {
      //console.log('CoinList: this.props.showBalance=',this.props.showBalance)
      var balanceTH
      if (this.props.showBalance) {
         balanceTH = <th>Balance</th>
      } else {
         balanceTH = null
      }

      return (
         <table className="coin-table">
            <thead>
               <tr>
               <th>Name</th>
               <th>Ticker</th>
               <th>Price</th>
               {balanceTH}
               <th>Action</th>
               </tr>
            </thead>
            <tbody>
               {
               this.props.coinData.map( 
                  ({name, ticker, balance, price}) => 
                     <Coin 
                        key={ticker}
                        name={name} 
                        ticker={ticker}
                        balance={balance}
                        price={price} 
                        refreshPrice={this.props.refreshPrice}
                        showBalance={this.props.showBalance}
                     /> 
               )
               }
            </tbody>
         </table>
      )
   }
}
Coin.jsx
import React, { Component } from 'react'
import PropTypes from 'prop-types'
import styled from 'styled-components'

const Td = styled.td`
   border: 1px solid green;
   width: 25vh;
`

export default class Coin extends Component {
   constructor(props) {
      super(props)
      
      this.refreshPrice = this.refreshPrice.bind(this)
   }
   refreshPrice(event) {
      // event.preventDefault()
      this.props.refreshPrice(this.props.ticker)
   /*
      const randomPercentage = 0.995 + Math.random() *0.01
      this.setState( 
         (oldState) => {
            return {
               price: oldState.price * randomPercentage
            }
         }
      )
   */
   }

   render() {
      var balanceTd
      if ( this.props.showBalance) {
         balanceTd = <Td>{this.props.balance}</Td>
      } else {
         balanceTd = null
      }
      return (
         <tr>
            <Td>{this.props.name}</Td>
            <Td>{this.props.ticker}</Td>
            <Td>${this.props.price}</Td>
            {balanceTd}
            <Td><button onClick={this.refreshPrice}>Refresh</button></Td>
         </tr>
      )
   }
}

Coin.propTypes = {
   name: PropTypes.string.isRequired,
   ticker: PropTypes.string.isRequired,
   price: PropTypes.number.isRequired
}
AccountBalance.jsx
import React, { Component } from 'react'
import PropTypes from 'prop-types'
import styled from 'styled-components'

const Section = styled.section`
   font-size: 1.5rem;
   text-align: center;
   background-color: rgba(0, 0, 0, 0.952);
   color: yellowgreen;
   margin-top: 5px;
   margin-bottom: 5px;
   /*height: 150px;
   line-height: 150px; */
`

const Button = styled.button`
   font-size: 1.3rem;
   margin: 0rem 0 0rem 0.8rem;
   /*border: 1px solid #cccccc;*/
   /*border-radius: 7px;*/
   /*padding: 5px 0px 5px px;*/
   
`

export default class AccountBalance extends Component {
   constructor(props) {
      super(props)
      
      this.toggleBalance = this.toggleBalance.bind(this)
   }

   toggleBalance(event) {
      //console.log("AccountBalance: in toggleBalance()")
      this.props.toggleBalance()
   }
  
   render() {
      var balance
      var balanceButtonText
      if ( this.props.showBalance ) {
         balanceButtonText = 'Hide Balance'
         balance = `Balance ${this.props.amount} `
      } else {
         balanceButtonText = 'Show Balance'
         balance = null
      }
      
      return(
         <Section>
            {balance}
            <Button onClick={this.toggleBalance}>{balanceButtonText}</Button>
         </Section>
      )
   }
}

AccountBalance.propTypes = {
   amount: PropTypes.number.isRequired
}
2 Likes

Hi, I was able to make it work.
Have some question about show - hide functionallity.
Solution 1

render() {
    const buttonText = this.props.showBalance ? "Hide Balance" : "Show Balance";
    const balanceText = this.props.showBalance
      ? `Balance: $${this.props.amount}`
      : "";
    return (
      <>
        <Section>
          {balanceText}
          <button onClick={this.handleClick}>{buttonText}</button>
        </Section>
      </>
    );
  }

Solution 2

render() {
    const buttonText = this.props.showBalance ? "Hide Balance" : "Show Balance";
    return (
      <>
        <Section>
          {this.props.showBalance && `Balance: $${this.props.amount}`}
          <button onClick={this.handleClick}>{buttonText}</button>
        </Section>
      </>
    );
  }

Personally, I prefer option 2. It’s cleaner to read to me, but beside that. It’s any other difference? It’s anyone better than the other ? Thanks

2 Likes

Both are equally fine. It depends on the coder on what is preferred. :slight_smile:

1 Like