🧭 Plan
Mini currency converter in JavaScript (exchange rate cache + offline fallback).
Length units converter in JavaScript (without API — only coefficients).
Single-file converter in Python (CLI) for practice "in the terminal".
UX trifles, tests and development ideas.
Goal: to understand the logic and build a working prototype without heavy frameworks.
💱 Currency converter (JavaScript, browser)
<!-- index.html -->
<div style="max-width:420px;margin:auto;font:16px/1.5 system-ui">
<h2>Конвертер валют</h2>
<label>Сумма: <input id="amount" type="number" step="0.01" value="100"></label><br><br>
<label>Из:
<select id="from">
<option>USD</option><option>EUR</option><option>RUB</option>
</select>
</label>
<label>В:
<select id="to">
<option>EUR</option><option>USD</option><option>RUB</option>
</select>
</label>
<button id="convert">Перевести</button>
<p id="out"></p>
</div>
<script>
const cache = { rates: null, ts: 0 };
// Offline stub: if the API is not available, we use fictitious rates
const fallbackRates = { "USD": 1, "EUR": 0.92, "RUB": 92.0 }; // 1 USD = 0.92 EUR, 92 RUB
async function getRates() {
const now = Date.now();
if (cache.rates && (now - cache.ts < 10 * 60 * 1000)) return cache.rates;
try {
// Replace with the real API of the courses; important: check CORS and the response format.
// Example:
// const res = await fetch("https://api.example.com/latest?base=USD");
// const data = await res.json(); const rates = data.rates;
// For the demo, we use a stub:
const rates = fallbackRates;
cache.rates = rates; cache.ts = now; return rates;
} catch (e) {
console.warn("API is not available, we use a stub", e);
return fallbackRates;
}
}
function formatMoney(value, code) {
// Simple formatting; for production, use Intl.NumberFormat
return `${value.toFixed(2)} ${code}`;
}
document.getElementById('convert').addEventListener('click', async () => {
const amount = parseFloat(document.getElementById('amount').value);
const from = document.getElementById('from').value;
const to = document.getElementById('to').value;
const out = document.getElementById('out');
if (Number.isNaN(amount) || amount < 0) {
out.textContent = "Please enter a valid amount (≥ 0).";
return;
}
if (from === to) {
out.textContent = formatMoney(amount, to);
return;
}
const rates = await getRates();
if (!rates[from] || !rates[to]) {
out.textContent = "The selected currency is not supported.";
return;
}
// We convert to the base currency (USD) and then to the target currency
const inUSD = amount / rates[from]; // how much USD in the original amount
const converted = inUSD * rates[to]; // translated into the target
out.textContent = formatMoney(converted, to);
});
</script>What's happening: we take the number, the currency "from", the currency "to", pull up the rates (from the API or from fallbackRates) and convert the amount through the base currency USD: from → USD → to.
10-minute cache:
cachestores the rates and time stamp to avoid spamming the API and speed up the response.Offline mode: if the network/server is unavailable, use
fallbackRates— the demo always works.Validation: we cut off
NaNand negative amounts, and in the case of "from=to" we simply show the original value.Formatting: The
formatMoneyfunction rounds to 2 digits. For production, takeIntl.NumberFormatunder the user's locale.
💡 Improvement: add auto recalculation for the event input and save the currency selection in localStorage.
📏 Unit converter (JavaScript, no API)
<!-- units.html -->
<div style="max-width:420px;margin:auto;font:16px/1.5 system-ui">
<h2>Конвертер единиц (длина)</h2>
<label>Значение: <input id="val" type="number" step="0.0001" value="1"></label><br><br>
<label>Из:
<select id="uFrom">
<option>m</option><option>cm</option><option>km</option><option>ft</option><option>in</option>
</select>
</label>
<label>В:
<select id="uTo">
<option>cm</option><option>m</option><option>km</option><option>ft</option><option>in</option>
</select>
</label>
<button id="go">Конвертировать</button>
<p id="res"></p>
</div>
<script>
// coefficients to METER
const length = {
m: 1,
cm: 0.01,
km: 1000,
ft: 0.3048,
in: 0.0254
};
function convert(value, from, to, table) {
if (!(from in table) || !(to in table)) throw new Error("Unit not supported");
const base = value * table[from]; // in meters
return base / table[to]; // to the target unit
}
document.getElementById('go').addEventListener('click', () => {
const value = parseFloat(document.getElementById('val').value);
const from = document.getElementById('uFrom').value;
const to = document.getElementById('uTo').value;
const res = document.getElementById('res');
if (Number.isNaN(value)) { res.textContent = "Enter a number."; return; }
if (from === to) { res.textContent = `${value} ${to}`; return; }
const out = convert(value, from, to, length);
res.textContent = `${out.toFixed(4)} ${to}`;
});
</script>Idea: one "base" unit is a meter. In the table, each unit has a coefficient of "how many meters in 1 unit". Then the formula is the same: value × coefficientFrom → meters → / coefficientTo.
Checking supported units: we throw an explicit error instead of a "silent"
NaN.Rounding: we do at the very end (
toFixed(4)) so as not to accumulate error.Extension: the "mass/volume/speed" categories work in the same way; temperature - through formulas, not coefficients.
💡 Take out the dictionaries of units in units.js and load them by the selected category.
🐍 Single-file converter (Python, CLI)
# convert.py
from dataclasses import dataclass
RATES = {"USD": 1.0, "EUR": 0.92, "RUB": 92.0} # replace with real ones if necessary
UNITS_LEN = {"m":1, "cm":0.01, "km":1000, "ft":0.3048, "in":0.0254}
@dataclass
class Result:
value: float
unit: str
def convert_currency(amount: float, from_code: str, to_code: str) -> Result:
if from_code not in RATES or to_code not in RATES:
raise ValueError("Currency is not supported")
in_usd = amount / RATES[from_code]
out = in_usd * RATES[to_code]
return Result(round(out, 2), to_code)
def convert_length(value: float, from_u: str, to_u: str) -> Result:
if from_u not in UNITS_LEN or to_u not in UNITS_LEN:
raise ValueError("Unit not supported")
base = value * UNITS_LEN[from_u]
out = base / UNITS_LEN[to_u]
return Result(round(out, 4), to_u)
def main():
print("Converter: 1) Currency 2) Length")
mode = input("Select mode (1/2): ").strip()
if mode == "1":
a = float(input("Amount: "))
fc = input("From currency (USD/EUR/RUB): ").strip().upper()
tc = input("In currency (USD/EUR/RUB): ").strip().upper()
res = convert_currency(a, fc, tc)
print(f"→ {res.value} {res.unit}")
elif mode == "2":
v = float(input("Value: "))
fu = input("From (m/cm/km/ft/in): ").strip()
tu = input("In (m/cm/km/ft/in): ").strip()
res = convert_length(v, fu, tu)
print(f"→ {res.value} {res.unit}")
else:
print("Unknown mode")
if __name__ == "__main__":
main()Approach: "pure" functions return Result and do not print — they are easy to test. In main() only input/output.
Currency conversion: the scheme is the same as in JS: we convert to USD, then to the target currency. Rounding only at the end.
Length conversion: we use the dictionary of coefficients to the meter. The formula remains the same for all units.
Money accuracy: if you need financial accuracy, use
decimal.Decimalinstead offloat.
💡 Move the conversion to a separate module and cover it with unit tests; leave the CLI thin.
UX little things that make it convenient
Auto recalculation for event
input(without button).Saving the "from/to" selection in
localStorage.Copying the result:
navigator.clipboard.writeText.For currencies —
Intl.NumberFormatunder the user's locale.
Tests and rakes
Round off at the very end; compare numbers with tolerance (epsilon).
Convert temperatures using formulas (not coefficients).
When working with the API, check CORS, limits, and refresh rate.
In Codice we make programming training fun and easy to understand: we have interesting courses with tasks that help you improve your skills step by step.
And we also have an active Telegram channel, where we discuss cool ideas, share experiences and analyze tasks together — learning becomes not only useful, but also fun.
