From fee74c377f528c6cc45e22ba02b21d1e3b1810cd Mon Sep 17 00:00:00 2001 From: shats Date: Sat, 6 Dec 2025 14:50:45 +0700 Subject: [PATCH] feat: Improve currency exchange rate fetching in BillingManager by adding a primary source from the Central Bank of Russia and a fallback to an alternative API, along with updates to currency formatting for better precision. --- frontend/src/BillingManager.jsx | 35 +++++++++++++++++++++++++++------ 1 file changed, 29 insertions(+), 6 deletions(-) diff --git a/frontend/src/BillingManager.jsx b/frontend/src/BillingManager.jsx index cbd5b2c..e98ebee 100644 --- a/frontend/src/BillingManager.jsx +++ b/frontend/src/BillingManager.jsx @@ -116,8 +116,28 @@ function BillingManager() { const fetchExchangeRates = async () => { setRatesLoading(true); try { - const response = await axios.get('https://api.exchangerate-api.com/v4/latest/USD'); - const rates = response.data.rates; + // Основной источник: ЦБ РФ (base = RUB) + const cbr = await axios.get('https://www.cbr-xml-daily.ru/latest.js'); + const rubPerUsd = cbr.data && cbr.data.rates?.USD ? 1 / Number(cbr.data.rates.USD) : null; + const rubPerEur = cbr.data && cbr.data.rates?.EUR ? 1 / Number(cbr.data.rates.EUR) : null; + + if (rubPerUsd) { + const eurPerUsd = rubPerEur ? rubPerUsd / rubPerEur : 1; + setExchangeRates({ + USD: 1, + EUR: eurPerUsd, // сколько EUR за 1 USD + RUB: rubPerUsd // сколько RUB за 1 USD + }); + return; + } + } catch (error) { + console.warn('ЦБ недоступен, пробуем резервный источник:', error?.message); + } + + try { + // Резервный источник: open.er-api + const response = await axios.get('https://open.er-api.com/v6/latest/USD'); + const rates = response.data?.rates || {}; setExchangeRates({ USD: 1, EUR: rates.EUR || 1, @@ -125,7 +145,8 @@ function BillingManager() { }); } catch (error) { console.error('Ошибка при загрузке курсов валют:', error); - setExchangeRates({ USD: 1, EUR: 0.85, RUB: 95 }); + // Фолбек на разумные значения + setExchangeRates({ USD: 1, EUR: 1.05, RUB: 95 }); } finally { setRatesLoading(false); } @@ -233,11 +254,12 @@ function BillingManager() { } function formatCurrency(amount, currency = 'USD') { - if (!amount) return '—'; + if (amount === undefined || amount === null || amount === '') return '—'; return new Intl.NumberFormat('ru-RU', { style: 'currency', currency: currency, - maximumFractionDigits: 0 + minimumFractionDigits: 2, + maximumFractionDigits: 2 }).format(amount); } @@ -246,7 +268,8 @@ function BillingManager() { return new Intl.NumberFormat('ru-RU', { style: 'currency', currency: 'RUB', - maximumFractionDigits: 0 + minimumFractionDigits: 2, + maximumFractionDigits: 2 }).format(rubAmount); }