Alternar moedas em interface
1) Princípios
1. Primeiro, depois a UI. Separe a moeda da conta (verdade contável) da moeda de exibição (conveniência) e da moeda da transação (conversão real do dinheiro).
2. Ambiguidade zero. Mostre o código + símbolo em caso de risco de confusão ('US $', 'CA $', 'MXN', 'R $'). Para ₴/₸/₼, adicione sempre o código em detalhes.
3. Honestidade dos cursos. A origem do curso, a última atualização, se as comissões estão incluídas ou não.
4. Estabilidade de digitação. A mudança de moeda não deve «saltar» os valores de entrada sem consentimento explícito (especialmente nas formas de taxa/depósito).
5. Localização de formatos. Separadores, espaços, sinalização de moeda - pelo local do usuário; Precisão em moeda.
2) Modelos de mudança
Exibição (display-only): todos os cálculos ficam na moeda da conta, a UI mostra o equivalente na moeda selecionada. Use para diretório, perfil, analistas.
Híbrido (soft convert): exibe na moeda selecionada + comprovante de transação na moeda da conta (exibindo ambas).
Operacional (hard convert): o usuário muda a moeda da transação (depósito/saída/taxa). Preciso de cursos, comissões, tempo de fixação.
A regra padrão é display-only e a conversão «rígida» só é incluída nos fluxos correspondentes (caixa, saída, transferência de fundos).
3) Controladores e colocação
Botão de moeda no chapéu/barra de perfil (ícone «₴/€/$» ou código de moeda).
Seletor: pesquisa de código/título/caracol; moedas escolhidas/frequentes - acima.
Dentro dos formulários (depósito/taxa): seletor compacto à direita do campo da quantia, ao lado da dica «≈ equivalente em XXX».
Pattern móvel: bottom sheet com lista e entrada para filtragem.
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) Formatação e precisão
Unidades menores: guarde os valores em unidades mínimas inteiras (cêntimos, centavos, satoshi).
Decimais na moeda:- 0: JPY, KRW, CLP
- 2: USD, EUR, UAH, TRY
- 3 +: algumas moedas ZAR (2), KWD (3), kripto (4-8)
- Criptomonetas: mostre até 8 caracteres (precisão dinâmica, mas com limite inferior para a lisura).
- Os números tabelados são 'fonte-variant-numérico: tabular-nums;' para alinhar as colunas.
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) Cursos e atualizações
Fonte: verifique o provedor de curso (banco/banco/FX-API).
Dinheiro: atualize os cursos com frequência razoável (por exemplo, a cada 60 a 300 segundos) + atualizações escalonadas sob demanda.
Hora de fixação: exibe 'atualizado N min' e hora de fixação durante a operação.
Spred/Comissão: Mostre uma linha explícita: "Curso 1 USD = 36,60 UAH (spred 1 incluído. 5%)».
Arredondados: bancário ou convencional - selecione um e anote na política.
6) OX texto e explicações
O equivalente a «≈ 52,10 €» - ao lado de uma quantia de cor abaixada, atualizado em tempo real.
Reservas legais: «O curso real e a comissão serão registrados no passo de confirmação».
Códigos longos: use tooltips/linha secundária: «US $ - dólar dos EUA».
Conversão na cesta: não mude o «total» sem explicação; mostre a linha de cálculo.
7) Disponibilidade (A11y)
'role =' listbox/opção 'no seletor de moedas.
Suporte para teclado: seta, Enter, Tipo-ahead por código/nome.
Leitura para SR: «Moeda de exibição UAH - hryvnia ucraniana».
A cor ≠ o único meio de sentido (sempre tem código/texto).
Os números/códigos em 'dir =' ltr 'dentro das linhas árabes.
8) Performance e armazenamento em dinheiro
Os cursos estão na memória + com TTL (por exemplo, 5 min).
Atualizações Batch: repare os equivalentes em pacotes (requestAnimationFrame, debouns 100-200 ms).
Não desencadeie o revender da lista quando a taxa de câmbio estiver oscilando (por exemplo, 0,1%).
9) Especificidades iGaming
A moeda da conta é um relatório básico (depósitos, saldo, histórico).
Taxa de câmbio: normalmente = moeda da conta; Se o outro for especificado, mostre um bloco duplo: «Descartado X XXX em USD (≈ Y YYY em UAH)».
Fixação no cálculo: os ganhos são convertidos de acordo com o curso no momento do cálculo, em vez de taxas - isso deve ser visto em detalhes do cupom/histórico.
Depósito/conclusão: curso e comissão PSP/banco - linha separada; ETA pelo método.
Os limites do jogo responsável são definidos na moeda da conta; Se a UI estiver em outra moeda, mostre ambos os valores.
Torneios e prêmios: a moeda do prémio é fixada; quando o equivalente é exibido, é indicativo, marcado.
10) Antipattern
Alteração de valor mágico no campo de entrada quando a moeda muda - sem consentimento explícito.
Usar um símbolo «$» sem código de país.
A comissão oculta está ciente (não há uma linha sobre o sprad).
Misture localização e moeda (formate em 'en-US' para 'UAH').
Precisão rígida de «2 caracteres» para JPY/KRW ou «8 caracteres» para todas as criptomonedas.
A recontagem de transações históricas «retroativas» no curso atual é sem a marca «recontagem».
11) Sistema de design de tokens (exemplo)
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) Snippets
Botão de câmbio (React, contexto + 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>;
}
Dupla exibição (conversão operacional)
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) Métricas
FX latency: tempo desde a mudança de moeda até a atualização de todos os campos (meta ≤ 150 ms).
Cortness rate: proporção de acessos por «quantias erradas» (<0,2%).
Display vs score mismatch: eventos onde o usuário confunde moedas (reduzindo as dicas).
CTR dicas do curso: clique em Mais informações sobre o curso/comissão.
Abandon de caixa na conversão, taxa de rejeição associada à variação «repentina» do valor.
14) QA-folha de cheque
Sentido e transparência
- A moeda da conta e/ou transação é visível em todo o lado.
- Para $ é mostrado o código de país (US $, CA $ etc.).
- Há uma linha sobre o curso, a data de atualização e a comissão.
Formato e precisão
- Decimais por moeda (JPY = 0, KWD = 3, crypto = até 8).
- O número/moeda local corresponde ao idioma UI.
- As transações históricas não foram contadas «no curso atual» sem marcação.
Comportamento
- A mudança de moeda não altera a entrada sem confirmação.
- O equivalente a «≈» é atualizado suavemente e rapidamente.
- O seletor de moedas está disponível e o Tipo-ahead funciona.
iGaming-especificidades
- No cupom: cancelamento/ganho e sua moeda estão assinados, o curso de fixação é especificado.
- Caixa: As comissões PSP/banco são vistas separadamente.
- Os limites exibem ambos os valores (conta e exibição).
RTL/A11y
- Os códigos/somas são lidos corretamente em «'dir =» ltr' para números).
- O contraste e os indicadores de foco correspondem a AA.
15) Documentação em design
Componentes: «CurrencySwitch», «Money», «FxNote», «DualAmount».
Política de precisão/arredondamento e função de formatação unificada.
As regras são «quando display-only», «quando hard-convert», «como exibir spray».
Guia de moedas: código, símbolo, descargas, conflitos de caracteres regionais.
Galeria Do/Don 't: «$ sem código», arquivamento automático, comissão oculta.
Resumo breve
A mudança de divisas não é apenas um seletor de ₴/€/$. É um modelo de dinheiro claro (moeda de conta vs operação de exibição de vs), um curso honesto com a comissão, formatação de localização correta e comportamento cuidadoso de campos de entrada. Fixe as regras em um sistema de design, automatize a formatação e o cachê dos cursos - e os usuários irão trabalhar com segurança com as quantias sem duvidar dos números e sem perder dinheiro em spraads «invisíveis».