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:

1 Like
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>
        );
    }
7 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}


) ;
}
}

2 Likes

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
}
 
2 Likes
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;
2 Likes

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…?

2 Likes

Good job with the solution!

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

1 Like

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
}
1 Like

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

2 Likes

I’ve deliberately missed out some of the details to shorten the code. Just included the bits that had changes in. I struggled with this and had to get some pointers from previous posts here to get started, but got my head around it as I went through.

App
class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      balance: 10000,
      showBalance: false,
      coinData: [etc]
    }
    this.handleRefresh = this.handleRefresh.bind(this);
    this.handleToggleBalance = this.handleToggleBalance.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() * 0.01;
        newPrice = newPrice * randomPercentage;
      }
      return {
        ticker,
        name,
        price: newPrice
      }
    });

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

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

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

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

        return (
            <Section>
             {balanceToggle}
             <button onClick={this.props.handleToggleBalance}>{buttonText}</button>
            </Section>
        );
    }
}

AccountBalance.propTypes = {
    amount: PropTypes.number.isRequired
}
CoinList
export default class CoinList extends Component {
    render() {
        let balanceToggle = this.props.showBalance ? <th> Balance </th> : null;
        return (
            <Table>
            <thead>
                <tr>
                    <th>Name</th>
                    <th>Ticker</th>
                    <th>Price</th>
                    {balanceToggle}
                    <th>Action</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() {
        let balanceToggle = this.props.showBalance ? <Td> {this.props.balance} </Td> : null;
        return (
            <tr>
                <Td>{this.props.name}</Td>
                <Td>{this.props.ticker}</Td>
                <Td>${this.props.price}</Td>
                {balanceToggle}
                <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

It was a challenging task, but now the lecture is more clear :slight_smile: Looking forward to the next one.

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

  handleVisibilityChange(){
    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,
        balance,
        price: newPrice      }
    });

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

  render() {
    return (
      <StyledDiv>
        <AppHeader/>
        <AccountBalance amount={this.state.balance} 
            showBalance={this.state.showBalance} 
            handleVisibilityChange={this.handleVisibilityChange}/>
        <CoinList coinData={this.state.coinData} 
            showBalance = {this.state.showBalance}
            handleRefresh={this.handleRefresh}/>
      </StyledDiv>
  );
  } 
}
CoinList
export default class CoinList extends Component {
    render() {
        return (
            <table className="coin-table">
            <thead>
            <tr>
                <th>Name</th>
                <th>Ticker</th>
                <th>Price</th>
                {this.props.showBalance ? <th>Balance</th> : null}
                <th>Action</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} 
                    showBalance={this.props.showBalance}
                    balance={balance} 
                    />
                )
            }
            </tbody>
        </table>
        )
    }
}
Coin
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>
                <TableData>{this.props.name}</TableData>
                <TableData>{this.props.ticker}</TableData>
                <TableData>${this.props.price}</TableData>
                {this.props.showBalance ? <TableData>{this.props.balance}</TableData> : null}
                <TableData>
                    <form action="#" >
                        <button onClick={this.handleClick}>Refresh</button>
                    </form>
                </TableData>
            </tr>
        );
    }
}
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.handleVisibilityChange}>{buttonText}</button>
            </Section>
        )
    }
}
3 Likes

There’s way too many screenshots and not sure how to organise them cleanly so instead I’ll put my github repo here for you to review:

https://github.com/CatalystJesal/coin-exchange/tree/master/src/components

The one thing I wanted to do is to make the button not move to take the position of the hidden text balance when I hide it. I tried different CSS but I failed at doing that, I’m really not that good when it comes to positioning elements the way I would like them. I spent more time on trying to position my balance button than showing/hiding balances part of the exercise. :sob:

EDIT

I updated my code on github as I realised you decided to hide the column entirely and the balance header for both the account balance and coin balance column, so now I’ve done the same. I use to have it where “Balance:” part stayed and the column of coin balances remained but only the values would clear from the column.

2 Likes

As a developer, you will work implementing designs of other people. I also suggest researching a bit of CSS layouting (Flexbox, Grid), because this course is not meant to teach you web styling, and it’s hard to know what you don’t yet know if no-one told you it’s experience with flexbox and grid is what you need rather than position: absolute, relative or inline-block display mode etc.

3 Likes

In AccountBalance.jsx:

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

In CoinList.jsx:

<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>

In Coin.jsx:

render() {
      if (this.props.showBalance === true) {
        return (
            <tr>
              <CoinRow>{this.props.name}</CoinRow>
              <CoinRow>{this.props.ticker}</CoinRow>
              <CoinRow>${this.props.price}</CoinRow>
              <CoinRow>{this.props.balance}</CoinRow>
              <CoinRow>
                <form action="#" method="POST">
                  <Button onClick = {this.handleClick}>Refresh</Button>
                </form>
              </CoinRow>
            </tr>
          );
      }
      else {
        return (
          <tr>
            <CoinRow>{this.props.name}</CoinRow>
            <CoinRow>{this.props.ticker}</CoinRow>
            <CoinRow>${this.props.price}</CoinRow>
            <CoinRow></CoinRow>
            <CoinRow>
              <form action="#" method="POST">
                <Button onClick = {this.handleClick}>Refresh</Button>
              </form>
            </CoinRow>
          </tr>
        );
      }
    }
}

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

In App.js:

this.state = {
      balance: 10000,
      showBalance: true,
      coinData: [ ... ]
}
this.handleRefresh = this.handleRefresh.bind(this);
this.handleToggle = this.handleToggle.bind(this)
handleToggle() {
    if (this.state.showBalance === true) {
      this.setState ({
        showBalance: false
      });
    }
    else {
      this.setState ({
        showBalance: true
      });
    }
  }

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

I have a lot of code written twice because of the if & else statements. There probably is a shorter way.

2 Likes

Goal: Implement functionality to toggle the main and the individual coin balances.

Listed are only changes necessary for this update with comments in the code:

App.js
...
class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      balance: 10000,
      showBalance: false, //added bool so condition can be passed on
      coinData: [...]
    }
    this.handleRefresh = this.handleRefresh.bind(this);
    this.handleBalanceDisplay = this.handleBalanceDisplay.bind(this);
    //add binding
  }

  handleBalanceDisplay() {
    this.setState({showBalance: !this.state.showBalance});//switch bool
  }

  handleRefresh(valueChangeTicker) {...}

  render() {
    return (
      <Div className="App">
        <ExchangeHeader/>
        <AccountBalance amount={this.state.balance} 
                        showBalance={this.state.showBalance} //added prop
                        handleBalanceDisplay={this.handleBalanceDisplay}/> 
                        //added prop
        <CoinList coinData={this.state.coinData} 
                  showBalance={this.state.showBalance}
                  handleRefresh={this.handleRefresh}/>
      </Div>
    );
  }
}
...
AccountBalance.jsx
...
const Button = styled.button`
    font-size: 1.6rem;
    margin: 1.5rem 0 1.5rem 5rem;
    background-color: #282c34;
    color: #fff;
    border: 1px solid #fff;
    border-radius: 5px;
`; //styled button

export default class AccountBalance extends Component {
    render() {
        const buttonText = this.props.showBalance ? 
                           'Hide Balance' : 'Show Balance';
                           //conditional display of button text
        let balance = this.props.showBalance ? 
                      <span>Account Balance: ${this.props.amount}</span> : null; 
                      //conditional display of balance

        return (
            <Section>
                {balance}
                <Button onClick={this.props.handleBalanceDisplay}>
                    {buttonText}
                </Button>
            </Section>
        );//replace elements with objects
    }
}
...
CoinList.jsx
...

export default class CoinList extends Component {
    render() {
        const coinBalance = this.props.showBalance ?
                            <th>Balance</th> : null; 
                            //make display of table header conditional

        return (
            <Table>
            <thead>
              <tr>
                <th>Name</th>
                <th>Ticker</th>
                <th>Price</th>
                {coinBalance}
                <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} 
                        showBalance={this.props.showBalance}
                        balance={balance}
                        price={price}/>
                )
              }
            </tbody>
          </Table>
        )
    }// replace elements with conditional objects
}
Coin.jsx
...

const Button = styled.button`
    font-size: 1.0rem;
    margin: 0.5rem 0 0.5rem 0;
    background-color: #282c34;
    color: #fff;
    border: 1px solid #fff;
    border-radius: 5px;
`;//styled buttons

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() {
        const coinBalance = this.props.showBalance ?
                            <Td>{this.props.balance} {this.props.ticker}</Td> : null;
                            //conditional display of the coin balance

        return (
            <tr>
              <Td>{this.props.name}</Td>
              <Td>{this.props.ticker}</Td>
              <Td>${this.props.price}</Td>
              {coinBalance}
              <Td>
                <form action='#' method='POST'>
                  <Button onClick={this.handleClick}>Refresh
                  </Button>
                </form>
              </Td>
            </tr>
        );//replace elements with conditional objects
      }
}
...


2 Likes

AppJs- Changes-
Add new state variable showBalance
this.state = {
showBalance : true,
}

handleBalanceDisplay(showBalanceFlag) {
let hideBalance = false;
hideBalance = showBalanceFlag ? false : true;
this.setState({
showBalance : hideBalance
});
}
render() {
return (





);
}

AccountBalance:-
hideBalance() {
this.props.handleBalanceDisplay(this.props.showBalance)
}

Balance ${this.props.amount} Hide Balance

Coin.JSX-New CoinRow
${this.props.balance}

CoinList.jsx - new property ‘showBalance’
)
}

1 Like
App.js
this.state = {
      balance: 10000,
      showBalance: true,
....
this.toggleBalance = this.toggleBalance.bind(this);
....
toggleBalance(changeShowBalance) {
    this.setState({ showBalance: !changeShowBalance });
}
handleRefresh(valueChangeTicker) {
    const newCoinData = this.state.coinData.map( ({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 });
}
.....
<AccountBalance amount={this.state.balance} showBalance={this.state.showBalance} toggleBalance={this.toggleBalance} />
<CoinList coinData={this.state.coinData} showBalance={this.state.showBalance} handleRefresh={this.handleRefresh} />
AccountBalance.jsx
this.handleBalance = this.handleBalance.bind(this);
...
handleBalance(event) {
        event.preventDefault();
        this.props.toggleBalance(this.props.showBalance);
}
...
export default class AccountBalance extends Component {
    constructor(props) {
        super(props);
        this.handleBalance = this.handleBalance.bind(this);
    }
    handleBalance(event) {
        event.preventDefault();
        this.props.toggleBalance(this.props.showBalance);
    }
    render() {
        const buttonText = this.props.showBalance ? "Hide Balance" : "Show Balance";
        const Balance = styled.span`
            border: 1px solid cyan;

            display: ${ this.props.showBalance ? "block" : "none" };
        `;
        return (
            <Section>
              <Balance showBalance={this.props.showBalance}>Balance: ${this.props.amount}</Balance>
                <form action="#" method="POST">
                    <button onClick={this.handleBalance}>{buttonText}</button>
                </form>
            </Section>
        );
    }
}
Coin.jsx
this.handleClick = this.handleClick.bind(this);
...
const CoinBalanceRow = styled.td`
            border: 1px solid #cccccc;
            width: 35vh;

            display: ${ this.props.showBalance ? "block" : "none" };
`;
...
<CoinBalanceRow showBalance={this.props.showBalance}>{this.props.balance}</CoinBalanceRow>
CoinList.jsx
const CoinBalanceTH = styled.td`
        width: 35vh;

        display: ${ this.props.showBalance ? "block" : "none" };
`;
...
<CoinBalanceTH>Balance</CoinBalanceTH>
...
{
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} />
              )
}
1 Like

I abbreviated the code in my dropdowns to show the code necessary for the Exercise - Hide the Balance.

App.js

Added showBalance to centralize state

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      showBalance: true,
      balance: 10000,
      coinData: [
        {
          name: 'Bitcoin',
          ticker: 'BTC',
          balance: 0.5,
          price: 9999.99
        },
...

Added binding and setState

      ]
    }
    this.handleRefresh = this.handleRefresh.bind(this);
    this.handleToggleShowBalance = this.handleToggleShowBalance.bind(this);
  }

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

Render showBalance from state.

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

Added event handler to button to toggle show balance
Added showBalance prop to showAccountBalance!

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

    handleClick(event){
        event.preventDefault();
        this.props.handleToggleShowBalance();
    }
    
    render() {
        const buttonText = this.props.showBalance ? 'Hide Balance' : 'Show Balance';
        const showAccountBalance = this.props.showBalance ? <span>Balance: ${this.props.amount} </span> : null;
        return (
            <Section>
              {showAccountBalance}
              <button onClick={this.handleClick} >{buttonText}</button>
            </Section>
        );
    }
}

...
Coin.jsx

Added showBalance prop as coinBalance

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

Added showBalance prop as coinBalance.
Passed showBalance prop to Coin

...
export default class CoinList extends Component {
    render() {
      let coinBalance = this.props.showBalance ? <th>Balance</th> : null;
        return (
            <Table>
            <thead>
              <tr>
                <th>Name</th>
                <th>Ticker</th>
                <th>Price</th>
                {coinBalance}
                <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} 
                showBalance={this.props.showBalance}
                balance={balance}
                price={price} />
                )
              }
            </tbody>
          </Table>
        );
    }
}

Show Balance

Hide Balance

1 Like