Skip to content

Commit

Permalink
Finish the project
Browse files Browse the repository at this point in the history
  • Loading branch information
tomkovich committed Nov 28, 2022
0 parents commit c5d076c
Show file tree
Hide file tree
Showing 20 changed files with 1,738 additions and 0 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
.vscode
3 changes: 3 additions & 0 deletions images/arrow.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/arrows.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/bitcoin.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 5 additions & 0 deletions images/convert.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions images/equals.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/ethereum.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
11 changes: 11 additions & 0 deletions images/single.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
140 changes: 140 additions & 0 deletions index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>SuperPuper Currency Converter</title>

<link rel="stylesheet" href="./styles/styles.css" />

<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap"
rel="stylesheet"
/>
</head>
<body>
<main>
<div class="container">
<h1>Check live foreign currency exchange rates</h1>

<div class="main">
<div class="wrapper">
<div class="tabs">
<div class="tab active" data-tab="convert">
<div class="tab-icon">
<img src="./images/convert.svg" alt="" />
</div>
<div class="tab-title">Convert</div>
</div>

<div class="tab" data-tab="single">
<div class="tab-icon">
<img src="./images/single.svg" alt="" />
</div>
<div class="tab-title">Single</div>
</div>
</div>

<div class="content show" data-child="convert">
<form class="form">
<div class="form-inputs">
<div class="form-group">
<label for="amount">Amount</label>
<input
type="number"
name="amount"
id="amount"
required
placeholder="1.00"
/>
</div>

<div class="form-selects">
<div class="form-select">
<label for="from">From</label>
<select class="select" name="from" id="from" required>
<option value="" disabled selected hidden>
Choose currency
</option>
</select>
</div>

<div class="form-select__icon switch-currencies">
<img src="./images/arrows.png" alt="" />
</div>

<div class="form-select">
<label for="to">To</label>
<select class="select" name="to" id="to" required>
<option value="" disabled selected hidden>
Choose currency
</option>
</select>
</div>
</div>
</div>

<div class="form-info">
<div class="loader">
<span></span>
<span></span>
<span></span>
</div>

<div class="form-results">
<div class="form-result__item from" id="resultFrom"></div>

<div class="form-result__equals">
<img src="./images/equals.svg" alt="" />
</div>

<div class="form-result__item to" id="resultTo"></div>
</div>

<button type="submit" class="form-submit">Convert</button>
</div>

<div class="rate-information">
<div class="rate-conversion"></div>
<div class="rate-last"></div>
</div>
</form>
</div>

<div class="content" data-child="single">
<div class="currency-wrapper">
<div class="currency-single">
<select class="select" id="singleSelect">
<option value="" disabled selected hidden>
Choose currency
</option>
</select>

<div class="currency-single__item"></div>
</div>

<div class="currency-list"></div>
</div>

<div class="currency-add">
<button class="currency-add__button">Add currency</button>

<select class="select" id="addCurrencySelect">
<option value="" disabled selected hidden>
Choose currency
</option>
</select>
</div>
</div>
</div>
</div>
</div>
</main>

<script type="module" src="./js/index.js"></script>
<script type="module" src="./js/events.js"></script>
</body>
</html>
90 changes: 90 additions & 0 deletions js/convert.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import { renderResult } from "./markups.js";
import state from "./state.js";
import { convertTime, formatToCurrency, getFullTitle } from "./utils.js";
import variables from "./variables.js";

const { success, formResults, rateConversion, rateLast, toSelect, fromSelect } =
variables;

export const handleChange = ({ target: { value, name } }) => {
state.pair = {
...state.pair,
[name]: value,
};
};

export const handleInput = ({ target: { value, name } }) => {
state[name] = Number(value);
};

const insertResults = ({
base_code: baseCode,
target_code: targetCode,
conversion_rate: rate,
conversion_result: result,
time_last_update_utc: time,
}) => {
const from = {
code: baseCode,
amount: state.amount,
full: getFullTitle(state.codes, baseCode),
};

const to = {
code: targetCode,
amount: result,
full: getFullTitle(state.codes, targetCode),
};

resultFrom.innerHTML = renderResult(from);
resultTo.innerHTML = renderResult(to);

const baseValue = formatToCurrency(baseCode, 1);
const targetValue = formatToCurrency(targetCode, rate);

rateConversion.innerText = `${baseValue} = ${targetValue}`;
rateLast.innerText = `Last updated ${convertTime(time)}`;

formResults.classList.add("show");
};

export const handleSubmit = async (e) => {
e?.preventDefault();

const {
url,
amount,
pair: { from, to },
} = state;

state.loading = true;

if (!amount || !from || !to) return;

try {
const response = await fetch(`${url}/pair/${from}/${to}/${amount}`);
const data = await response.json();

if (data.result === success) insertResults(data);

state.loading = false;
} catch (err) {
console.log(err);
}
};

export const switchCurrencies = () => {
const {
pair: { to, from },
} = state;

if (!to || !from) return;

state.pair = {
to: from,
from: to,
};

toSelect.value = from;
fromSelect.value = to;
};
31 changes: 31 additions & 0 deletions js/events.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { handleInput, handleSubmit, switchCurrencies } from "./convert.js";
import { fetchCodes, handleTabClick } from "./index.js";
import {
addCurrency,
handleActionClick,
handleAddSelectChange,
handleSingleSelectChange,
} from "./single.js";
import variables from "./variables.js";

const {
tabs,
form,
amountInput,
switchButton,
currentCurrency,
currentCurrencyList,
singleSelect,
addButton,
} = variables;

fetchCodes();
amountInput.addEventListener("keyup", handleInput);
form.addEventListener("submit", handleSubmit);
switchButton.addEventListener("click", switchCurrencies);
tabs.forEach((tab) => tab.addEventListener("click", handleTabClick));
currentCurrency.addEventListener("click", handleActionClick);
currentCurrencyList.addEventListener("click", handleActionClick);
singleSelect.addEventListener("change", handleSingleSelectChange);
addButton.addEventListener("click", addCurrency);
addCurrencySelect.addEventListener("change", handleAddSelectChange);
53 changes: 53 additions & 0 deletions js/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import variables from "./variables.js";
import state from "./state.js";

import { handleChange } from "./convert.js";
import { fetchLatest } from "./single.js";

const { selects, success, tabs } = variables;

const renderCodeList = () => {
selects.forEach((select) => {
state.codes.forEach(([code]) => {
const element = document.createElement("option");
element.value = code;
element.innerText = code;
select.insertAdjacentElement("beforeend", element);
});

const name = select.getAttribute("name");
name && select.addEventListener("change", handleChange);
});
};

export const fetchCodes = async () => {
try {
const response = await fetch(`${state.url}/codes`);
const data = await response.json();

if (data.result === success) {
state.codes = data.supported_codes;
renderCodeList();
fetchLatest();
}
} catch (err) {
console.log(err);
}
};

export const handleTabClick = ({ currentTarget: target }) => {
const { tab } = target.dataset;
const children = document.querySelectorAll(".content");

if (!tab || tab === state.currentTab) return;

tabs.forEach((item) => item.classList.remove("active"));
target.classList.add("active");

for (const child of children) {
if (child.dataset.child === tab) child.classList.add("show");
else child.classList.remove("show");
}

state.currentTab = tab;
};
44 changes: 44 additions & 0 deletions js/markups.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import state from "./state.js";
import { getFullTitle } from "./utils.js";

export const renderResult = ({ code, amount, full }) => {
return `<div class="form-result__item-icon icon">
<img src="./images/arrow.svg" alt="" />
</div>
<div class="form-result__item-titles">
<div class="form-result__item-title">${code}</div>
<div class="form-result__item-full">
${full}
</div>
</div>
<div class="form-result__item-value">${amount.toFixed(2)}</div>`;
};

const getCurrencyItemAction = (isBase) => {
const {
actions: { remove, change },
} = state;
const actionName = isBase ? change : remove;

return `<button data-action="${actionName}" class="currency-${actionName} currency-button">${actionName}</button>`;
};

export const renderCurrencyItem = ({ code, base_code: baseCode, rate = 1 }) => {
const isBase = code === baseCode;
const action = getCurrencyItemAction(isBase);
const full = getFullTitle(state.codes, code);

return `<div class="currency-item ${
isBase ? "currency-current" : ""
}" data-item="${code}">
<div class="currency-titles">
<div class="currency-title">${code}</div>
<div class="currency-full">${full}</div>
</div>
<div class="currency-amount">${rate.toFixed(2)}</div>
<div class="currency-action">${action}</div>
</div>`;
};
Loading

0 comments on commit c5d076c

Please sign in to comment.