Загрузка данных
async function calculateConversion(source = 'from') {
const requestId = ++conversionRequestId;
const from = getCurrencyValue(fromSelect);
const to = getCurrencyValue(toSelect);
if (!from || !to) {
return;
}
let amount;
let apiFrom;
let apiTo;
if (source === 'from') {
amount = Number(amountInput.value);
apiFrom = from;
apiTo = to;
} else {
amount = Number(toAmountDisplay.value.replace(/\s/g, '').replace(',', '.'));
apiFrom = to;
apiTo = from;
}
// Если поле пустое или введено некорректное значение
if (!Number.isFinite(amount) || amount <= 0) {
if (source === 'from') {
toAmountDisplay.value = '';
mainResultEl.textContent = '—';
} else {
amountInput.value = '';
mainResultEl.textContent = '—';
}
mainCurrencyEl.textContent = getCurrencyShortLabel(to);
if (mainChangeEl) {
mainChangeEl.textContent = '';
}
return;
}
// Если выбраны одинаковые валюты
if (from === to) {
if (source === 'from') {
toAmountDisplay.value = formatter.format(amount);
} else {
amountInput.value = formatter.format(amount);
}
mainResultEl.textContent = formatNumber(amount, 4);
mainCurrencyEl.textContent = getCurrencyShortLabel(to);
if (mainChangeEl) {
mainChangeEl.textContent =
`1 ${getCurrencyShortLabel(from)} = 1 ${getCurrencyShortLabel(to)}`;
mainChangeEl.className = 'result-change';
}
return;
}
const targetInput = source === 'from'
? toAmountDisplay
: amountInput;
targetInput.classList.add('loading');
try {
const data = await apiFetch(
`/convert?from_curr=${encodeURIComponent(apiFrom)}&to_curr=${encodeURIComponent(apiTo)}&amount=${encodeURIComponent(amount)}`
);
// Пока запрос выполнялся, пользователь мог изменить поле.
// Старый ответ в таком случае игнорируем.
if (requestId !== conversionRequestId) {
return;
}
const result = Number(data.result);
const rate = Number(data.rate);
if (!Number.isFinite(result) || !Number.isFinite(rate)) {
throw new Error('Сервер вернул некорректный результат');
}
if (source === 'from') {
toAmountDisplay.value = formatter.format(result);
} else {
amountInput.value = formatter.format(result);
}
mainResultEl.textContent = formatNumber(
source === 'from' ? result : amount,
4
);
mainCurrencyEl.textContent = getCurrencyShortLabel(to);
if (mainChangeEl) {
mainChangeEl.textContent =
`1 ${getCurrencyShortLabel(from)} = ${formatNumber(
source === 'from' ? rate : 1 / rate,
6
)} ${getCurrencyShortLabel(to)}`;
mainChangeEl.className = 'result-change';
}
} catch (error) {
if (requestId !== conversionRequestId) {
return;
}
console.error(error);
if (source === 'from') {
toAmountDisplay.value = 'Ошибка';
} else {
amountInput.value = 'Ошибка';
}
mainResultEl.textContent = '—';
if (mainChangeEl) {
mainChangeEl.textContent = error.message;
}
} finally {
if (requestId === conversionRequestId) {
targetInput.classList.remove('loading');
}
}
}