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...
- Axios
- React Router Dom
- 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;
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;
}
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> </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
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
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;
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
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
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
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)