GH GambleHub

Переключение валют в интерфейсе

1) Принципы

1. Сначала смысл, потом UI. Отделяйте валюту аккаунта (бухгалтерская истина) от валюты отображения (удобство) и валюты операции (фактическая конвертация денег).
2. Нулевая двусмысленность. Показывайте код + символ при риске путаницы (`US$`, `CA$`, `MXN`, `R$`). Для ₴/₸/₼ — всегда добавляйте код в деталях.
3. Честность курсов. Видно: источник курса, момент последнего обновления, включены ли комиссии/спрэд.
4. Стабильность ввода. Переключение валюты не должно «прыгать» значения ввода без явного согласия (особенно в формах ставок/депозитов).
5. Локализация форматов. Разделители, пробелы, знак валюты — по локали пользователя; точность — по валюте.


2) Модели переключения

Отображение (display-only): все расчеты остаются в валюте аккаунта, UI показывает эквивалент в выбранной валюте. Используйте для каталога, профиля, аналитики.
Гибрид (soft convert): отображение в выбранной валюте + подтверждение операции в валюте аккаунта (показываем обе).
Операционная (hard convert): пользователь меняет валюту операции (депозит/вывод/ставка). Нужны явные курсы, комиссии, время фиксации.

Правило: по умолчанию — display-only, а «жесткую» конверсию включайте только в соответствующих потоках (касса, вывод, перевод средств).


3) Контролы и размещение

Переключатель валюты в шапке/на панели профиля (иконка «₴/€/$» или код валюты).
Селектор: поиск по коду/названию/символу; избранные/частые валюты — сверху.
Внутри форм (депозит/ставка): компактный селектор справа от поля суммы, рядом подсказка «≈ эквивалент в XXX».
Мобильный паттерн: bottom sheet со списком и вводом для фильтрации.

html
<button aria-haspopup="listbox" aria-expanded="false" class="currency-switch">UAH</button>
<ul role="listbox" class="currency-menu" hidden>
<li role="option" aria-selected="true">UAH — ₴</li>
<li role="option">USD — US$</li>
<li role="option">EUR — €</li>
<li role="option">TRY — ₺</li>
</ul>

4) Форматирование и точность

Минорные единицы: храните суммы в целых минимальных единицах (копейки, центы, сатоши).

Десятичные разряды по валюте:
  • 0: JPY, KRW, CLP
  • 2: USD, EUR, UAH, TRY
  • 3+: некоторые валюты ZAR (2), KWD (3), крипто (4–8)
  • Криптовалюты: показывайте до 8 знаков (динамическая точность, но с нижней границей для читабельности).
  • Табличные цифры: `font-variant-numeric: tabular-nums;` для выравнивания колонок.
Intl-сниппет:
js const fmt = (amountMinor, currency, locale) => {
const fraction = { JPY:0, KRW:0, KWD:3 }[currency]?? 2;
return new Intl.NumberFormat(locale, { style:'currency', currency, minimumFractionDigits:fraction, maximumFractionDigits:fraction })
.format(amountMinor / 10fraction);
};
fmt(200000, 'UAH', 'uk-UA'); // 2 000,00 ₴

5) Курсы и обновления

Источник: фиксируйте провайдера курса (внутренний прайсинг/банк/FX-API).
Кэш: обновляйте курсы с разумной частотой (напр., каждые 60–300 сек) + инкрементальные обновления по требованию.
Время фиксации: отображайте `обновлено N мин назад` и время фиксации при оформлении операции.
Спрэд/комиссия: показывайте явную строку: «Курс 1 USD = 36,60 UAH (включен спрэд 1.5%)».
Округления: банковское или обычное — выберите одно и зафиксируйте в политике.


6) UX текста и пояснений

Эквивалент: «≈ 52,10 €» — рядом с суммой, приглушенным цветом, обновляется в реальном времени.
Юридические оговорки: «Фактический курс и комиссия будут зафиксированы на шаге подтверждения».
Длинные коды: используйте tooltips/вторичную строку: «US$ — доллар США».
Конверсия в корзине: не меняйте «итого» без пояснения; показывайте строчку пересчета.


7) Доступность (A11y)

`role="listbox/option"` у селектора валют.
Поддержка клавиатуры: стрелки, Enter, Type-ahead по коду/названию.
Чтение для SR: «Валюта отображения: UAH — украинская гривня».
Цвет ≠ единственный носитель смысла (всегда есть код/текст).
RTL: числа/коды в `dir="ltr"` внутри арабских строк.


8) Перформанс и кэширование

Курсы — в памяти + localStorage с TTL (например, 5 мин).
Батч-обновления: пересчитывайте эквиваленты пачками (requestAnimationFrame, дебаунс 100–200 мс).
Не триггерите лишний ререндер списка при колебаниях курса < порога (например, 0,1%).


9) Специфика iGaming

Валюта аккаунта — базовая отчетность (депозиты, баланс, история).
Валюта ставки: обычно = валюте аккаунта; если задана другая — покажите двойной блок: «Списано X XXX в USD (≈ Y YYY в UAH)».
Фиксация при расчете: выигрыши конвертируются по курсу на момент расчета, а не ставки — это должно быть видно в деталях купона/истории.
Депозит/вывод: курс и комиссия PSP/банка — отдельной строкой; ETA по методу.
Лимиты ответственной игры: определяются в валюте аккаунта; если UI в другой валюте — показывайте оба значения.
Турниры и призы: валюта призового фонда фиксируется; при отображении эквивалент — ориентировочный, с пометкой.


10) Антипаттерны

«Магическая» смена значения в поле ввода при переключении валюты — без явного согласия.
Использование одного символа «$» без кода страны.
Скрытая комиссия в курсе (нет строки про спрэд).
Перемешивание локали и валюты (форматируете по `en-US` для `UAH`).
Жесткая точность «2 знака» для JPY/KRW или «8 знаков» для всех криптовалют.
Пересчет исторических транзакций «задним числом» по текущему курсу — без отметки «пересчет».


11) Токены дизайн-системы (пример)

json
{
"currency": {
"default": "UAH",
"displayList": ["UAH","USD","EUR","TRY","PLN","BRL","MXN"],
"fractions": { "JPY":0, "KRW":0, "KWD":3, "BTC":8 },
"showCodeWithSymbol": ["USD","CAD","AUD","NZD"],
"approxPrefix": "≈ "
},
"format": {
"tabularNums": true,
"grouping": "locale",
"negative": "−"
},
"fx": {
"ttlSec": 300,
"changeThresholdPct": 0.1,
"showSpread": true
}
}

12) Сниппеты

Переключатель валюты (React, контекст + Intl)

tsx import { createContext, useContext, useState, useMemo } from 'react';

type Cur = 'UAH'    'USD'    'EUR'    'TRY';
const CurrencyCtx = createContext<{cur:Cur,set:(c:Cur)=>void, rate:(from:Cur,to:Cur)=>number}>({cur:'UAH',set:()=>{},rate:()=>1});

export function CurrencyProvider({children}:{children:React.ReactNode}){
const [cur, set] = useState<Cur>('UAH');
// fx: получить из кэша/апи; здесь — заглушка const table = { UAH:{USD:0.027,EUR:0.025,TRY:0.89,UAH:1}, USD:{UAH:36.6,EUR:0.93,TRY:33.0,USD:1}, EUR:{UAH:39.2,USD:1.07,TRY:35.4,EUR:1}, TRY:{UAH:1.12,USD:0.030,EUR:0.028,TRY:1} };
const rate = (from:Cur,to:Cur)=> table[from][to];
const value = useMemo(()=>({cur, set, rate}),[cur]);
return <CurrencyCtx.Provider value={value}>{children}</CurrencyCtx.Provider>;
}

export function useCurrency(){ return useContext(CurrencyCtx); }

export function Money({minor, iso}:{minor:number, iso:Cur}){
const { cur, rate } = useCurrency();
const fraction = { JPY:0, KRW:0, KWD:3 }[cur as any]?? 2;
const v = (minor/10fraction) rate(iso, cur);
return <span style={{fontVariantNumeric:'tabular-nums'}}>{new Intl.NumberFormat(undefined,{style:'currency',currency:cur, minimumFractionDigits:fraction, maximumFractionDigits:fraction}).format(v)}</span>;
}

Двойное отображение (операционная конверсия)

html
<div class="amount">
<label>Сумма депозита</label>
<div class="row">
<input type="number" inputmode="decimal" aria-describedby="fxnote">
<select aria-label="Валюта операции">
<option>USD</option><option>EUR</option><option>UAH</option>
</select>
</div>
<small id="fxnote">≈ 2 000,00 ₴ · Курс будет зафиксирован на следующем шаге</small>
</div>

13) Метрики

FX latency: время от переключения валюты до обновления всех полей (цель ≤ 150 мс).
Correctness rate: доля обращений в саппорт по «неверным суммам» (< 0,2%).
Display vs account mismatch: события, где пользователь путает валюты (снижаем подсказками).
CTR подсказки курса: клики по «Подробнее о курсе/комиссии».
Абандон кассы при конверсии: доля отказов, связанная с «внезапным» изменением суммы.


14) QA-чек-лист

Смысл и прозрачность

  • Везде видна валюта аккаунта и/или операции.
  • Для $ показан код страны (US$, CA$ и т. п.).
  • Есть строка про курс, дату обновления и спрэд/комиссию.

Формат и точность

  • Десятичные разряды по валюте (JPY=0, KWD=3, crypto=до 8).
  • Локаль числа/валюты соответствует языку UI.
  • Исторические операции не пересчитаны «по текущему курсу» без пометки.

Поведение

  • Переключение валюты не меняет ввод без подтверждения.
  • Эквивалент «≈» обновляется плавно и быстро.
  • Селектор валют клавиатуро-доступен, работает Type-ahead.

iGaming-специфика

  • В купоне: списание/выигрыш и их валюта подписаны, курс фиксации указан.
  • В кассе: комиссии PSP/банка видны отдельно.
  • В лимитах: показываются обе величины (аккаунтная и отображаемая).

RTL/A11y

  • Коды/суммы читаются корректно в RTL (`dir="ltr"` для чисел).
  • Контраст и фокус-индикаторы соответствуют AA.

15) Документация в дизайн-системе

Компоненты: `CurrencySwitch`, `Money`, `FxNote`, `DualAmount`.
Политика точности/округлений и единая функция форматирования.
Правила: «когда display-only», «когда hard-convert», «как показывать спрэд».
Справочник валют: код, символ, разряды, региональные коллизии символов.
Галерея Do/Don’t: «$ без кода», автопрыжок ввода, скрытые комиссии.


Краткое резюме

Переключение валют — это не просто селектор «₴/€/$». Это ясная модель денег (аккаунтная валюта vs отображение vs операция), честный курс с комиссией, корректное форматирование по локали и бережное поведение полей ввода. Зафиксируйте правила в дизайн-системе, автоматизируйте форматирование и кэширование курсов — и пользователи будут уверенно работать с суммами, не сомневаясь в цифрах и не теряя деньги на «невидимых» спрэдах.

Contact

Свяжитесь с нами

Обращайтесь по любым вопросам или за поддержкой.Мы всегда готовы помочь!

Начать интеграцию

Email — обязателен. Telegram или WhatsApp — по желанию.

Ваше имя необязательно
Email необязательно
Тема необязательно
Сообщение необязательно
Telegram необязательно
@
Если укажете Telegram — мы ответим и там, в дополнение к Email.
WhatsApp необязательно
Формат: +код страны и номер (например, +380XXXXXXXXX).

Нажимая кнопку, вы соглашаетесь на обработку данных.