Comutarea valutelor în interfață
1) Principii
1. În primul rând sensul, apoi UI. Moneda separată a contului (adevărul contabil) din moneda de afișare (comoditate) și moneda tranzacției (conversia reală a banilor).
2. Ambiguitate zero. Afișați codul + simbolul cu risc de confuzie ('US $', 'CA $', 'MXN', 'R $'). Pentru ₴/₸/₼, adăugați întotdeauna codul în detalii.
3. Integritatea cursului. Puteți vedea: sursa cursului, momentul ultimei actualizări, dacă sunt incluse comisioane/spread.
4. Stabilitatea intrării. Schimbarea valutei nu ar trebui să „sară” valorile de intrare fără consimțământ explicit (în special în formularele de rată/depozit).
5. Localizarea formatelor. Delimitatoare, spatii, semn valutar - prin user locale; precizie - după valută.
2) Modele de comutare
Display-only - Toate calculele rămân în moneda contului, UI arată echivalentul în moneda selectată. Utilizare pentru catalog, profil, dimensiune.
Hibrid (soft convert): afișați în moneda selectată + confirmarea tranzacției în moneda contului (afișați ambele).
Operare (hard convert): utilizatorul modifică moneda tranzacției (depozit/retragere/rată). Avem nevoie de cursuri explicite, comisioane, timp de fixare.
Regula: implicit - afiseaza numai, si activeaza conversia „hard” numai in fluxurile corespunzatoare (numerar, retragere, transfer de fonduri).
3) Controale și plasare
Comutatorul valutar din panoul antet/profil (pictograma „₴/€/$” sau codul valutar).
Selector: căutare după cod/nume/simbol; valute selectate/frecvente - top.
În interiorul formularelor (depozit/rată): selector compact la dreapta câmpului suma, lângă indiciu „≈ echivalent în XXX”.
Model mobil: foaie de jos cu o listă și intrare pentru filtrare.
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) Formatare și precizie
Unități minore: Depozitați cantități în unități minime întregi (bănuți, cenți, satoshi).
Zecimale după valută:- 0: JPY, KRW, CLP
- 2: USD, EUR, UAH, TRY
- 3 +: unele valute ZAR (2), KWD (3), cripto (4-8)
- Criptomonede: Afișați până la 8 caractere (precizie dinamică, dar cu o limită mai mică pentru lizibilitate).
- Cifre tabel: 'font-variant-numeric: tabular-nums;' pentru alinierea coloanelor.
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) Cursuri și actualizări
Sursa: fixați furnizorul cursului (prețuri interne/bancă/FX-API).
Cache: Actualizați cursurile cu frecvență rezonabilă (de ex. la fiecare 60-300 secunde) + actualizări incrementale la cerere.
Timp de fixare: Afișați „actualizat N minute în urmă” și timpul de fixare la finalizarea comenzii.
Spread/Commission: Arată o linie explicită: "Rata 1 USD = 36. 60 UAH (Spread 1 inclus. 5%)».
Rotunjire: bancă sau obișnuită - selectați una și fixați-o în politică.
6) Textul și explicațiile UX
Echivalent: "≈ 52. 10 €" - lângă suma, culoarea dezactivată, actualizată în timp real.
Avertismente juridice: „Rata efectivă și comisionul vor fi înregistrate în etapa de confirmare”.
Coduri lungi: utilizați vârfuri de instrumente/șir secundar: „US $ - dolar american”.
Conversia în coș: nu schimbați „totalul” fără explicații; arată linia de renumărare.
7) Disponibilitate (A11y)
'role = "listbox/option" "la selectorul de valută.
Suport pentru tastatură: săgeți, Enter, Type-award după cod/nume.
Citirea pentru SR: „Moneda de afișare: UAH - hrivna ucraineană”.
Culoarea ≠ singurul mediu de sens (există întotdeauna cod/text).
RTL: numere/coduri în „dir =” ltr „” în interiorul șirurilor arabe.
8) Performanță și cache
Cursuri - în memorie + localStorage cu TTL (de exemplu, 5 minute).
Actualizări lot: recalcula echivalente în loturi (requestAnimationFrame, debunks 100-200 ms).
Nu declanșați o listă suplimentară atunci când cursul fluctuează <pragul (de exemplu, 0. 1%).
9) Specificul iGaming
Moneda contului - raportare de bază (depozite, sold, istoric).
Valuta cursului: de obicei = moneda contului; dacă este specificat altul, afișați un bloc dublu: „Debitat X XXX în USD (≈ Y YYY în UAH)”.
Fixarea decontării: Câștigurile sunt convertite la rata la momentul decontării, nu la pariuri - acest lucru trebuie văzut în detaliile cuponului/istoricului.
Depozit/retragere: rata și comisionul PSP/bancă - într-o linie separată; ETA prin metoda.
Limitele jocului responsabil: definite în moneda contului; În cazul în care UI este într-o monedă diferită, arată ambele valori.
Turnee și premii: moneda fondului de premiere este fixă; când este afișat, echivalentul este aproximativ, marcat.
10) Antipattern
Modificarea valorii „magice” în câmpul de intrare la comutarea monedei - fără consimțământ explicit.
Utilizarea unui caracter „$” fără cod de țară.
comision ascuns în știu (nici o linie despre răspândire).
Amestecarea locală și valută (formatul prin "en-Us' pentru" UAH ").
Precizie grea de „2 caractere” pentru JPY/KRW sau „8 caractere” pentru toate cryptocurrencies.
Recalcularea tranzacțiilor istorice „retroactiv” la cursul de schimb curent - fără marca „recalculare”.
11) Proiectarea tokenurilor sistemului (exemplu)
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) Fragmente
Comutator valutar (Reacție, context + 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>;
}
Dual Display (Conversie operaţională)
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ăsurători
FX latență: timp de la trecerea valutei la actualizarea tuturor câmpurilor (țintă ≤ 150 ms).
Rata de corectitudine: cota de apeluri pentru a sprijini „sume incorecte” (<0. 2%).
Afișare vs nepotrivire cont: evenimente în care utilizatorul confundă valute (indicii mai mici).
Sfaturi curs CTR: clicuri pe „Mai multe despre curs/comision”.
Reducere de numerar la conversie: ponderea eșecurilor asociate cu o schimbare „bruscă” a sumei.
14) Lista de verificare QA
Semnificație și transparență
- Moneda contului și/sau tranzacției este vizibilă peste tot.
- $ arată codul de țară (US $, CA $, etc.).
- Există o linie despre rata, data de actualizare și spread/comision.
Formatul și precizia
- Zecimale după valută (JPY = 0, KWD = 3, cripto = până la 8).
- Numărul/moneda locală corespunde limbii UI.
- Tranzacțiile istorice nu sunt recalculate „la cursul de schimb curent” fără marcare.
Comportament
- Trecerea la monedă nu modifică intrarea fără confirmare.
- Echivalentul „≈” este actualizat fără probleme și rapid.
- Selectorul valutar este accesibil tastaturii, funcționează Type-away.
Specificul iGaming
- În cupon: taxa/câștig și moneda lor sunt semnate, rata de fixare este indicată.
- La till: taxele PSP/bancare sunt văzute separat.
- În limite: ambele valori sunt afișate (cont și afișate).
RTL/A11y
- Codurile/sumele sunt citite corect în RTL ('dir = "ltr" "pentru numere).
- Indicatorii de contrast și de focalizare corespund AA.
15) Documentația în sistemul de proiectare
Componente: 'CurrencySwitch', 'Money', 'FxNote', 'DualSount'.
Politica de precizie/rotunjire și funcția de formatare unică.
Reguli: „când afișați numai”, „când convertiți greu”, „cum să arătați răspândirea”.
Referință valută: cod, simbol, cifre, coliziuni regionale de caractere.
Galerie Do/Don' t: „$ fără cod”, intrare salt auto, comisioane ascunse.
Scurt rezumat
Schimbarea valutelor nu este doar un selector ₴/€/$. Acesta este un model clar de bani (cont valută vs afișare vs operațiune), rata corectă cu comision, formatarea corectă prin locale și comportamentul atent al câmpurilor de intrare. Fixați regulile în sistemul de proiectare, automatizați formatarea și cachingul cursurilor - iar utilizatorii vor lucra cu încredere cu sume, fără a se îndoi de numere și fără a pierde bani pe spread-uri „invizibile”.