Hide the Balance exercise

Welcome to the thread where you can discuss and ask all questions related to the exercise hide the balance :slight_smile:

App
  • Need to add a state variable for showBalance
  • Pass that state to the sub-components
  • Handle the click event to toggle the showBalance state
class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      balance: 10000,
      showBalance: false,
      coinData: [ /* etc */]
    }
    this.handleRefresh = this.handleRefresh.bind(this);
    this.handleToggleShowBalance = this.handleToggleShowBalance.bind(this);
  }

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

  render() {
    return (
      <Content>
        <AppHeader />
        <AccountBalance amount={this.state.balance}
            showBalance={this.state.showBalance}
            handleToggleShowBalance={this.handleToggleShowBalance}/>
        <CoinList coinData={this.state.coinData}
            handleRefresh={this.handleRefresh}
            showBalance={this.state.showBalance} />
      </Content>
    );
  }
}
AccountBalance
  • Conditionally add the element which displays the balance and insert it using { }
  • Create a styled component for the button
  • Attach the click handler passed down in the props to the onClick event of the button
const BtnBalance = styled.button`
    font-size: 1.4rem;
    margin: 1.5rem 0 1.5rem 5rem;
    background-color: rgb(20, 56, 97);
    color: #cccccc;
    border: 1px solid #cccccc;
    border-radius: 7px;
`;

export default class AccountBalance extends Component {
    render() {
        const buttonText = this.props.showBalance ?
            'Hide Balance' : 'Show Balance';

        let balance = this.props.showBalance ?
            <span>Balance: ${this.props.amount}</span>
            : null;

        return (
            <Section>
                {balance}
                <BtnBalance onClick={this.props.handleToggleShowBalance}>{buttonText}</BtnBalance>
            </Section>
        );
    }
}
CoinList
  • Conditionally add the <th> for the balance
  • Pass the showBalance prop state to the child Coin components
export default class CoinList extends Component {

  render() {
    const balance = this.props.showBalance ?
      <th>Balance</th> : null;
      
    return (
      <>
        <Table>
          <thead>
            <tr>
              <th>Name</th>
              <th>Ticker</th>
              {balance}
              <th>Price</th>
              <th>Actions</th>
            </tr>
          </thead>
          <tbody>
            {
              this.props.coinData.map(({ name, ticker, balance, price }) =>
                <Coin key={ticker}
                      handleRefresh={this.props.handleRefresh}
                      name={name}
                      ticker={ticker}
                      balance={balance}
                      showBalance={this.props.showBalance}
                      price={price} />)
            }
          </tbody>
        </Table>
      </>
    )
  }
}
Coin
  • Conditionally display the balance based on the showBalance prop
  • Only the render function changes so omitted the rest of this file
    render() {
        const balance = this.props.showBalance ?
            <Td>{this.props.balance}</Td> : null;
            
        return (
            <tr>
                <Td>{this.props.name}</Td>
                <Td>{this.props.ticker}</Td>
                {balance}
                <Td>${this.props.price}</Td>
                <Td>
                    <form action="#" method="POST">
                        <button onClick={this.handleRefresh}>Refresh</button>
                    </form>
                </Td>
            </tr>
        );
    }
3 Likes

Thanks for posting! Noticed I made an error using handleClick on the button instead of handleRefresh. Finally it works!

2 Likes

//App.js
class App extends React.Component {
constructor(props){
super(props);
this.state = {
showBalance:false,
balance: 10000,
coinData: [ …

this.handleRefresh=this.handleRefresh.bind(this);
this.handleShowBalance=this.handleShowBalance.bind(this);
}
handleShowBalance(){
this.setState(
{showBalance:! this.state.showBalance}
);
}
render(){
return (



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

);
}
//CoinList.jsx
class CoinList extends Component {
render() {
const balanceDisplay= this.props.showBalance ? Balance: ‘’;
return (





{balanceDisplay}





{this.props.coinData.map(({name, ticker,balance, price}) => (
<Coin key={ticker}
showBalance={this.props.showBalance }
handleRefresh={this.props.handleRefresh}
name={name}
ticker={ticker}
balance={balance}
price={price}
/>
))}

Name Ticker Price Action
    );
}

}
// Coins.jsx
render() {
const balanceDisplay= this.props.showBalance ? {this.props.balance}: ‘’;

    return(        
      <tr> 
        <Td> {this.props.name}   </Td> 
        <Td> {this.props.ticker} </Td>
             {balanceDisplay}    
        <Td>${this.props.price}  </Td>
        <Td>
           <form action='#' method= 'POST'>
          <button onClick= {this.handleClick}>refresh</button>
          </form>  
        </Td>
      </tr>
    ) ;   
}

//AccountBalance
class AccountBalance extends Component {
render() {
const buttonText= this.props.showBalance ? ‘hide balance’ : ‘show balance’;
const balanceDisplay= this.props.showBalance ? <>Balance: $ {this.props.amount} </> : ‘’;
return (


{balanceDisplay}


{buttonText}


) ;
}
}

1 Like

Next to your balance, there is a button. Upon pressing this button, hide this balance. Also hide the balance column in the table.
When the balance is hidden, if you press the same button, show both the USD balance as well as the coin balances column.

We use a handleclick function to prevent default behavior of button action in AccountBalance.
We set a show state in App.js and we make passing this state from parent to child as props. The toggling function in App.js manages the show state and it’s passed to the child via props to be triggered by the button
Then, in render functions we use a conditional expression with the show state to display or not the information

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


const DivApp = 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: [
        {
          name: "Bitcoin",
          ticker: 'BTC',
          balance: 0.5,
          price: 9999.9
        },
        {
          name: "Ethereum",
          ticker: 'ETH',
          balance: 32,
          price: 274.9
        },
        {
          name: "Tether",
          ticker: 'USDT',
          balance: 0,
          price: 1
        },
        {
          name: "Ripple",
          ticker: 'XRP',
          balance: 1000,
          price: 0.2
        },
        {
          name: "Bitcoin Cash",
          ticker: 'BCH',
          balance: 0,
          price: 298.99
        },
        {
          name: "Bthereum",
          ticker: 'BTH',
          balance: 0.5,
          price: 274.9
        },
        {
          name: "Cthereum",
          ticker: 'CTH',
          balance: 0.5,
          price: 274.9
        }
      ],
      showBalance: true
    }
    this.handleRefresh = this.handleRefresh.bind(this);
    this.handleToggleBalance = this.handleToggleBalance.bind(this);
  }

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

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

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

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

export default App;

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

const Section = styled.section`
    /*border: 1px solid red;*/
    margin: 20px auto 0 auto;
    padding-left: 1.5 rem 0 1.5rem 5rem;
    width: 98vw;
    max-width: 780px;
    font-size: 2rem;
    text-align: left;
`;

const Button = styled.button`
    margin: 10px auto 0 auto;
    float: right;
    border: none;
    background-color: #282c34;
    color: #61dafb;
    font-size: 1.4rem;
    :active {
        background: #0053ba;
    }
    :hover {
        border: 1px solid #cccccc;
        border-radius: 3px;
        cursor: pointer;
    }
`;

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

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

        this.props.handleToggleBalance();
    }

    render() {
        const buttonText = this.props.showBalance ? 'Hide Balance' : 'Show Balance';

        const toggleBalance = this.props.showBalance ?
         <span><strong>Balance : </strong>$ {this.props.amount}</span> : null;

        return (
            <Section className="balance">
                {toggleBalance}
                <Button onClick={this.handleClick}>{buttonText}</Button>
            </Section>
        );
    }
}

AccountBalance.propTypes = {
    amount: PropTypes.number.isRequired
}
CoinList.jsx
import React, { Component } from 'react';
import Coin from '../Coins/Coin';
import styled from 'styled-components';


const Table = 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 (
            <Table> 
            <thead>
              <tr>
                <th>Name</th>
                <th>Ticker</th>
                {toggleBalance}
                <th>Price</th>
                <th>Action</th>
              </tr>
            </thead>
            <tbody>
              {
                this.props.coinData.map( ({name, ticker, balance, price}) =>
                  <Coin key={ticker} name={name} 
                  handleRefresh={this.props.handleRefresh}
                  ticker={ticker}
                  showBalance={this.props.showBalance}
                  balance={balance}
                  price={price} 
                  />
                )
              }
            </tbody>
          </Table>
        )
    }
}
Coin.jsx
import React, { Component } from 'react';
//import './Coin.css';
import PropTypes from 'prop-types';
import styled from 'styled-components';
 
const Td = styled.td`
    border: 1px solid #cccccc;
    width: 25vh;
`;

const Button = styled.button`
    height: 2rem;
    width: 100%;
    background-color: #282c34;
    color: #61dafb;
    border: none;
    font-size: 1rem;
    :active {
        background: #0053ba;
    }
    :hover {
        border: 1px solid #cccccc;
        border-radius: 3px;
        cursor: pointer;
    }
`;


export default class Coin extends Component {

    constructor(props) {
        super(props);
        this.handleClick = this.handleClick.bind(this);
    }
   

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

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

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

            return(
                <tr>
                  <Td>{this.props.name}</Td>
                  <Td>{this.props.ticker}</Td>
                  {toggleBalance}
                  <Td>${this.props.price}</Td>
                  <Td>
                      <form action="">
                          <Button onClick={this.handleClick}>Refresh</Button>
                      </form>
                  </Td>
                </tr>
              );

    }
}

Coin.propTypes = {
    name: PropTypes.string.isRequired,
    ticker: PropTypes.string.isRequired,
    price: PropTypes.number.isRequired
}
 
1 Like
AccountBalance
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;
`;

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


AccountBalance.propTypes = {
    amount: PropTypes.number.isRequired
}
Coin
render() {
    const balance = this.props.showBalance ? <><CoinRow>{this.props.balance}</CoinRow></> : '';
        return (
            <tr>
                <CoinRow>{this.props.name}</CoinRow>
                <CoinRow>{this.props.ticker}</CoinRow>
                { balance }
                <CoinRow>${this.props.price}</CoinRow>
                <CoinRow> <form action="#" method="POST" >
                    <button onClick={this.handleClick}>Refresh</button>
                    </form>
                </CoinRow>
            </tr>
        );
    }
}
CoinList
import React, { Component } from 'react'
import Coin from '../Coin/Coin';
import styled from 'styled-components';

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

export default class CoinList extends Component {
    render() {
      let balance = this.props.showBalance ? <th>Balance</th> : '';
        return (
          <Table>
            <thead>
              <tr>
                <th>Name</th>
                <th>Ticker</th>
                { balance }
                <th>Price</th>
                <th>Actions</th>
              </tr>
            </thead>
            <tbody>
              {
              this.props.coinData.map( ({name, ticker, balance, price}) =>
                <Coin key={ticker} handleRefresh={this.props.handleRefresh} 
                name={name} 
                ticker={ticker}
                showBalance={this.props.showBalance}
                balance={balance} 
                price={price} />
                  )
              }
            </tbody>
          </Table>
        )
    }
}
App
class App extends React.Component {
  constructor(props){
    super(props);
    this.state = {
      balance: 10000,
      showBalance: false,
      coinData: [
       //extraneous
    ]
    }
    this.handleRefresh = this.handleRefresh.bind(this);
    this.handleBalance = this.handleBalance.bind(this);
  }

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

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

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

export default App;
1 Like

I learned as much from the cheat codes and rubbernecking classmate’s solutions as I did from the lecture. Anyway I think it’s all working now…per my manual testing. I see hints of automated React testing frameworks in the template…?

1 Like

Good job with the solution!

I’d recommend sharing either your GitHub, or doing the coding in codesandbox.io and just sharing the link.

Yes, create-react-app includes testing set up. We didn’t cover it in the course, but automated testing (unit test, integration test, acceptance test) are important parts of software engineering. Here, you’d be able to write unit tests and integration tests between your components.

1 Like
App.js
import React from 'react';
import './App.css';
import CoinList from './components/CoinList';
import AccountBalance from "./components/AccountBalance";
import CoinHeader from './components/CoinHeader';
import styled from "styled-components";

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: 1000,
      showBalance: true,
      coinData: [
        {
          name: "Bitcoin",
          ticker: "BTC",
          balance: 0.5,
          price: 9999.99
        },
        {
          name: "Ethereum",
          ticker: "ETH",
          balance: 32,
          price: 299.99
        },
        {
          name: "Tether",
          ticker: "USDT",
          balance: 19,
          price: 1.0
        },
        {
          name: "Ripple",
          ticker: "XRP",
          balance: 3,
          price: 0.2
        },
        {
          name: "Bitcoin Cash",
          ticker: "BCH",
          balance: 0,
          price: 299.99
        }
      ]
    }
    this.handleRefresh = this.handleRefresh.bind(this);
    this.handleRefreshShowBalance = this.handleRefreshShowBalance.bind(this);
  }
  handleRefresh(valueChangedTicker) {
    const newCoinData = this.state.coinData.map(({name, ticker, balance, price}) => {
      let newPrice = price;
      if (valueChangedTicker === ticker) {
        const randomPercentage = 0.995 + Math.random() * 0.01;
        newPrice = newPrice * randomPercentage;
      }
      return {name, ticker, balance, price: newPrice}
    });
    this.setState({coinData:newCoinData});
  }
  handleRefreshShowBalance(valueChangedShowBalance) {
    this.setState({showBalance:valueChangedShowBalance});
  }
  render() {
    return (
      <Div>
        <CoinHeader />
        <AccountBalance 
          amount={this.state.balance} 
          handleRefreshShowBalance={this.handleRefreshShowBalance}
          showBalance={this.state.showBalance} />
        <CoinList 
          coinData={this.state.coinData} 
          handleRefresh={this.handleRefresh}
          showBalance={this.state.showBalance}  />
      </Div>
    );
  }
}

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

const Section = styled.section`
    border: 1px solid red;
    font-size: 2rem;
    text-align: center;
    passing: 1.5rem 0 1.5rem 5rem;
`;

export default class AccountBalance extends Component {
    constructor(props) {
        super(props);
        this.handleClick = this.handleClick.bind(this);
    }
    handleClick(event) {
        event.preventDefault();
        this.props.handleRefreshShowBalance(!this.props.showBalance);
    }
    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>
        );
    }
}

AccountBalance.propTypes = {
    amount: PropTypes.number.isRequired
}
CoinList.jsx
import React from 'react';
import Coin from './Coin';
import styled from "styled-components";

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

export default class CoinList extends React.Component {
    render() {
        let balanceHeader = this.props.showBalance ? <th>Balance</th> : null;
        return (
        <Table>
          <thead>
            <tr>
              <th>Name</th>
              <th>Ticker</th>
              <th>Price</th>
              {balanceHeader}
              <th>Action</th>
            </tr>
          </thead>
          <tbody>
            {
              this.props.coinData.map( ({name, ticker, balance, price}) => 
              <Coin 
                key={ticker}
                handleRefresh={this.props.handleRefresh}
                showBalance={this.props.showBalance}
                name={name}
                ticker={ticker}
                balance={balance}
                price={price}/>
            )
            }
          </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 #cccccc;
    width: 25vh;
`;

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

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() {
        let balanceCell = this.props.showBalance ? <Td>${this.props.balance}</Td> : <TdHidden>${this.props.balance}</TdHidden>;
        return (
            <tr>
                <Td>{this.props.name}</Td>
                <Td>{this.props.ticker}</Td>
                <Td>${this.props.price}</Td>
                {balanceCell}
                <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
}

used this code in the render()

// render function with a styled component depending on the showBlance flag
// show the balance or not.
render() {
const buttonText = this.props.showBalance ? ‘Hide Balance’ : ‘Show Balance’;
if (this.props.showBalance) {
return (

Balance: ${this.getAmount()}  
{buttonText}

);
} else {
return (

{buttonText}

)
}
}

render() {
if ( this.props.showBalance ) {
return (

{this.props.name}
{this.props.ticker}
${this.getPrice()}
{this.props.balance}

Refresh


)
} else {
return (

{this.props.name}
{this.props.ticker}
${this.getPrice()}

Refresh


)
}

}

and

1 Like