DEV Community

Cover image for Currency Converter + Rates
Deepak Singh Kushwah
Deepak Singh Kushwah

Posted on

 

Currency Converter + Rates

Hello Developers,

This app is my new react project to learn about state + axios + routes in react js. It shows the exchage rates and convert currency value from one to other. I have used following packages to create this app...

  1. Axios
  2. React Router Dom
  3. React Bootstrap + Bootstrap

Use npm install and npm start to run this project

So to create this app, I have used following code.

App.js

import "bootstrap/dist/css/bootstrap.min.css";
import "./App.css";
import Navigation from "./components/shared/Navigation";
import { BrowserRouter as Router, Routes, Route } from "react-router-dom";
import CurrencyConverter from "./pages/CurrencyConverter";
import CurrencyRates from "./pages/CurrencyRates";
function App() {
  return (
    <div className="App">
      <Router>
        <Navigation />
        <div className="container">
          <Routes>
            <Route path="/" element={<CurrencyRates />} />
            <Route path="/currency-converter" element={<CurrencyConverter />} />
          </Routes>
        </div>
      </Router>
    </div>
  );
}

export default App;

Enter fullscreen mode Exit fullscreen mode

To style loader in this app, update App.css to following...

.loadingSpinnerContainer {
    position: fixed;
    top: 0;
    right: 0;
    bottom: 0;
    left: 0;
    background-color: rgba(0, 0, 0, 0.5);
    z-index: 5000;
    display: flex;
    justify-content: center;
    align-items: center;
  }

  .loadingSpinner {
    width: 64px;
    height: 64px;
    border: 8px solid;
    border-color: #00cc66 transparent #00cc66 transparent;
    border-radius: 50%;
    animation: spin 1.2s linear infinite;
  }
Enter fullscreen mode Exit fullscreen mode

Now we need to created pages to load currency exchange rates and converter. So i created pages folder in src. Add following files in pages folder.

pages/CurrencyConverter.jsx

import React, { useEffect, useState } from 'react'
import http from '../components/CustomAxios'
import Spinner from '../components/shared/Spinner';
function CurrencyConverter() {
  const [symbols, setSymbols] = useState([]);
  const [loading, setLoading] = useState(false);

  const [fromCurrency, setFromCurrency] = useState('');
  const [toCurrency, setToCurrency] = useState('');
  const [amount, setAmount] = useState(0);
  const [convertedAmount, setConvertedAmount] = useState(null);
  useEffect(() => {
    setLoading(true);
    const getSymbols = async () => {
      const sys = await http.get("/symbols");
      const data = await sys.data;
      let arr = Array.from(Object.keys(data.symbols), k => [`${k}`, data.symbols[k]]);
      setSymbols(arr);
      setLoading(false);
    };

    getSymbols();
  }, []);



  const handleSubmit = async (e) => {
    e.preventDefault();
    setLoading(true);

    const res = await http.get('/convert?from=' + fromCurrency + '&to=' + toCurrency + "&amount=" + amount + "&places=2");
    const data = await res.data;
    //console.log(data);
    setConvertedAmount(data.result);
    setLoading(false);
  }

  const handleSelectChange = (e) => {
    setConvertedAmount(null);
    if(e.target.id === 'toCurrency'){
      setToCurrency(e.target.value);
    }

    if(e.target.id === 'fromCurrency'){
      setFromCurrency(e.target.value);
    }
  }

  if (loading) {
    return <Spinner />
  }
  return (
    <>
      <h1>Convert Currency</h1>
      <form onSubmit={handleSubmit}>
        <table className='table table-borderless table-hover'>
          <tbody>
            <tr>
              <td width="30%">From Currency</td>
              <td width="70%">
                <select className='form-control' id="fromCurrency" onChange={handleSelectChange}>
                  {symbols.length > 0 && symbols.map((item) => (
                    <option value={item[0]} key={item[1].code}>{item[1].code} - {item[1].description}</option>
                  ))}
                </select>
              </td>
            </tr>
            <tr>
              <td>To Currency</td>
              <td>
                <select className='form-control' id="toCurrency" onChange={handleSelectChange}>
                  {symbols.length > 0 && symbols.map((item) => (
                    <option value={item[0]} key={item[1].code}>{item[1].code} - {item[1].description}</option>
                  ))}
                </select>
              </td>
            </tr>
            <tr>
              <td>Amount</td>
              <td><input className='form-control' type="number" onChange={(e) => setAmount(e.target.value)} /></td>
            </tr>
          </tbody>
          <tfoot>
            <tr>
              <td>&nbsp;</td>
              <td><button className='btn btn-primary' type="submit">Convert</button></td>
            </tr>
            {convertedAmount !== null &&
              <tr>
                <td>Converted Amount</td>
                <td>{toCurrency} {convertedAmount}</td>
              </tr>
            }
          </tfoot>

        </table>
      </form>
    </>
  )
}

export default CurrencyConverter
Enter fullscreen mode Exit fullscreen mode

pages/CurrencyRates.jsx

import React, { useEffect, useState } from 'react'
import ExchangeRate from '../components/ExchangeRate'
import http from '../components/CustomAxios'
function CurrencyRates() {
  const [rates, setRates] = useState([]);
  const [baseCurrency, setBaseCurrency] = useState('Eur');
  const [loading, setLoading] = useState(true);
  const [exchangeDate, setExchangeDate] = useState('');
  useEffect(() => {
    const getRates = async () => {

      const response = await http.get('/latest?places=2');
      const data = await response.data;
      //console.log(data);
      let arr = Array.from(Object.keys(data.rates), k => [`${k}`, data.rates[k]]);
      //console.log(arr);
      setRates(arr);
      setLoading(false);
      setBaseCurrency(data.base);
      setExchangeDate(data.date);
    }
    getRates();

  }, [])
  return (
    <>
      <h1>Daily Exchange Rates</h1>
      <div className='text-bold'>
        <span className='float-start'><strong>Base Currency: {baseCurrency}</strong></span>
        <span className='float-end'><strong>Date: {exchangeDate}</strong></span>
        <br />
      </div>
      <ExchangeRate rates={rates} loading={loading} />
    </>

  )
}

export default CurrencyRates
Enter fullscreen mode Exit fullscreen mode

Now we create some components in src/components folder. First is to initlize the axios with base url. I am using "exchangerate.host" website API's for currency services app.

components/CustomAxios.js

import axios from "axios";
const http = axios.create({
    baseURL: 'https://api.exchangerate.host'
});

export default http;
Enter fullscreen mode Exit fullscreen mode

Next we create ExchangeRate.jsx file to show all rates from api.

components/ExchangeRate.jsx

import React from 'react'
import Spinner from './shared/Spinner';

function ExchangeRate({ rates, loading }) {
    if (loading) {
        return <Spinner/>;
    }
    const listing = rates.length > 0 && (
        <div className="row row-cols-5 mt-3">
            {rates.map(item => (
                <div className="col mt-3 mb-1" key={item[0]}>
                    <div className="card bg-dark">
                        <div className="card-body">
                            <div className="card-text text-white">
                                {item[0]} - {item[1]}
                            </div>
                        </div>
                    </div>
                </div>
            ))}
        </div>
    )
    return (
        <>

            {listing}
        </>
    );

}

export default ExchangeRate
Enter fullscreen mode Exit fullscreen mode

Now to load navigation and spinner, create new folder in src/components named "shared" and in src named src/assets. For loader image, you can use any image name in src/assets folder. I've used 'loadeing.gif' name. Update your image name in spinner component

components/shared/Spinner.jsx

import React from 'react'
import spinner from "../../assets/loading.gif";
function Spinner() {
    return (
        <div className='loadingSpinnerContainer'>
            <img src={spinner} alt="Loading..." width="200px" height="200px" />
        </div>
    )
}

export default Spinner
Enter fullscreen mode Exit fullscreen mode

components/shared/Navigation.jsx

import React from 'react'
import { Container, Nav, Navbar, NavDropdown } from 'react-bootstrap'
import { NavLink } from 'react-router-dom'

function Navigation() {
    return (
        <Navbar bg="dark"  variant="dark" expand="lg">
            <Container>
                <Navbar.Brand href="#home">Currency Services</Navbar.Brand>
                <Navbar.Toggle aria-controls="basic-navbar-nav" />
                <Navbar.Collapse id="basic-navbar-nav">
                    <Nav className="me-auto">
                        <NavLink className="nav-link" to="/">Home</NavLink>
                        <NavLink className="nav-link" to="/currency-converter">Currency Converter</NavLink>
                        {/**
                        <NavDropdown title="Dropdown" id="basic-nav-dropdown">
                            <NavDropdown.Item href="#action/3.1">Action</NavDropdown.Item>
                            <NavDropdown.Item href="#action/3.2">Another action</NavDropdown.Item>
                            <NavDropdown.Item href="#action/3.3">Something</NavDropdown.Item>
                            <NavDropdown.Divider />
                            <NavDropdown.Item href="#action/3.4">Separated link</NavDropdown.Item>
                        </NavDropdown> 
                        */}
                    </Nav>
                </Navbar.Collapse>
            </Container>
        </Navbar>

    )
}

export default Navigation
Enter fullscreen mode Exit fullscreen mode

You can get the full source code at following location.

https://bitbucket.org/deepaksinghkushwah/currencyservices/src/master/

Hope you like this app.

Top comments (0)

This post blew up on DEV in 2020:

js visualized

🚀⚙️ JavaScript Visualized: the JavaScript Engine

As JavaScript devs, we usually don't have to deal with compilers ourselves. However, it's definitely good to know the basics of the JavaScript engine and see how it handles our human-friendly JS code, and turns it into something machines understand! 🥳

Happy coding!