Changer de devise dans l'interface
1) Principes
1. D'abord le sens, puis l'IU. Séparez la devise du compte (vérité comptable) de la devise d'affichage (commodité) et de la devise de transaction (conversion réelle de l'argent).
2. Aucune ambiguïté. Montrez le code + symbole au risque de confusion ('US $', 'CA $', 'MXN', 'R $'). Pour les ₴/₸/₼, ajoutez toujours du code en détail.
3. L'honnêteté des cours. Vous pouvez voir : la source du cours, le moment de la dernière mise à jour, si les commissions/sprade sont incluses.
4. Stabilité de l'entrée. Le changement de devise ne doit pas « sauter » la valeur d'entrée sans consentement explicite (en particulier dans les formulaires de taux/dépôts).
5. Localisation des formats. Séparateurs, espaces, devise - par emplacement de l'utilisateur ; précision - par devise.
2) Modèles de commutation
Affichage (display-only) : tous les calculs restent dans la devise du compte, l'IU affiche l'équivalent dans la devise sélectionnée. Utilisez pour le catalogue, le profil, les analyses.
Hybride (soft convert) : afficher dans la devise sélectionnée + confirmer l'opération dans la devise du compte (montrer les deux).
Opération (hard convert) : l'utilisateur change la devise de l'opération (dépôt/retrait/pari). J'ai besoin de cours explicites, de commissions, de temps de fixation.
Règle : par défaut, display-only, et activez la conversion « rigide » uniquement dans les flux appropriés (caisse, retrait, virement).
3) Contrôles et hébergement
Commutateur de devise dans le chapeau/dans le panneau de profil (icône « ₴/€/$ » ou code de devise).
Sélecteur : recherche par code/titre/symbole ; les devises choisies/fréquentes sont en haut.
À l'intérieur des formulaires (dépôt/mise) : sélecteur compact à droite du champ de somme, à côté de l'indice « ≈ équivalent en XXX ».
Modèle mobile : bottom sheet avec liste et entrée pour filtrer.
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) Formatage et précision
Unités mineures : stockez les sommes en unités minimales entières (centimes, cents, satoshi).
Décimales par devise :- 0: JPY, KRW, CLP
- 2: USD, EUR, UAH, TRY
- 3 + : quelques devises ZAR (2), KWD (3), crypto (4-8)
- Crypto-monnaies : affichez jusqu'à 8 caractères (précision dynamique, mais avec une bordure inférieure pour la lisibilité).
- Nombres tabulaires : 'font-variant-numeric : tabular-nums ;' pour aligner les colonnes.
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) Cours et mises à jour
Source : enregistrer le fournisseur de cours (tarif interne/banque/FX-API).
Cache : mettez à jour les cours à une fréquence raisonnable (par exemple, toutes les 60 à 300 secondes) + mises à jour incrémentielles à la demande.
Temps de fixation : afficher 'mis à jour N min back' et le temps de fixation lors de la conception de l'opération.
Sprad/commission : montrez une ligne explicite : "Taux de change 1 USD = 36,60 UAH (sprad 1 inclus. 5%)».
Arrondissements : bancaire ou ordinaire - sélectionnez une chose et fixez-la dans la politique.
6) UX du texte et des explications
Équivalent : « ≈ 52,10 € » - à côté de la somme, la couleur atténuée est mise à jour en temps réel.
Clauses légales : « Le cours effectif et la commission seront fixés à l'étape de confirmation ».
Codes longs : utilisez tooltips/ligne secondaire : « US $ - US $ ».
Conversion dans le panier : ne changez pas le « total » sans explication ; montrez la ligne de conversion.
7) Accessibilité (A11y)
'role =' listbox/option 'au sélecteur de devises.
Prise en charge du clavier : flèches, Entrée, Type-ahead par code/titre.
Lecture pour SR : « Devise d'affichage : UAH - hryvnia ukrainienne ».
La couleur ≠ le seul porteur de sens (il y a toujours du code/texte).
RTL : nombres/codes dans 'dir =' ltr 'à l'intérieur des lignes arabes.
8) Performance et mise en cache
Les cours sont en mémoire + localStorage avec TTL (par exemple, 5 min).
Mises à jour de batch : recalculer les équivalents en paquets (requestAnimationFrame, debouns 100-200 ms).
Ne déclenchez pas le relais supplémentaire de la liste lorsque le cap <seuil varie (par exemple 0,1 %).
9) Spécificité iGaming
La monnaie du compte est la déclaration de base (dépôts, bilan, historique).
Monnaie du taux : généralement = monnaie du compte ; Si l'autre est spécifié, montrez le double bloc : « Débité X XXX en USD (≈ Y YYY en UAH) ».
Fixation au moment du calcul : les gains sont convertis au taux de change au moment du calcul et non à la mise - cela doit être visible dans les détails du coupon/historique.
Dépôt/retrait : taux et frais PSP/banque - par une ligne distincte ; ETA par méthode.
Limites du jeu responsable : définies dans la devise du compte ; Si l'IU est dans une autre monnaie, affichez les deux valeurs.
Tournois et prix : la monnaie du prize pool est fixée ; à l'affichage, l'équivalent est indicatif, marqué.
10) Anti-modèles
Changement « magique » de la valeur dans le champ de saisie lors du changement de devise - sans consentement explicite.
Utilisation d'un seul caractère « $ » sans code de pays.
La commission cachée est au courant (pas de ligne sur le sprade).
Mélanger le local et la monnaie (formater selon 'en-US' pour 'UAH').
Précision rigide « 2 signes » pour JPY/KRW ou « 8 signes » pour toutes les crypto-monnaies.
Recalculer les transactions historiques « rétroactivement » au taux de change actuel - sans « recalculer ».
11) Tokens de système de conception (exemple)
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) Snappets
Commutateur de devise (React, contexte + 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>;
}
Double affichage (conversion opérationnelle)
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étriques
FX latency : temps entre le changement de devise et la mise à jour de tous les champs (objectif ≤ 150 ms).
Taux correctness : proportion d'appels au saphport pour les « montants incorrects » (<0,2 %).
Display vs account mismatch : événements où l'utilisateur confond les devises (nous baissons avec des indices).
CTR conseils de cours : clics sur « En savoir plus sur le cours/commission ».
Abandon de la caisse à la conversion : proportion d'échec associée à une variation « soudaine » du montant.
14) Liste de vérification QA
Sens et transparence
- La monnaie du compte et/ou de l'opération est visible partout.
- Pour $, le code du pays (US $, CA $, etc.) est indiqué.
- Il y a une ligne sur le cours, la date de mise à jour et le sprade/commission.
Format et précision
- Décimales par devise (JPY = 0, KWD = 3, crypto = jusqu'à 8).
- Le nombre local/monnaie correspond à la langue UI.
- Les opérations historiques ne sont pas recalculées « au taux de change actuel » sans être notées.
Comportement
- Changer de devise ne change pas l'entrée sans confirmation.
- L'équivalent « ≈ » est mis à jour en douceur et rapidement.
- Le sélecteur de devises clavier est disponible, Type-ahead fonctionne.
iGaming-spécificité
- Sur le coupon : le débit/gain et leur monnaie sont signés, le taux de fixation est indiqué.
- À la caisse : les commissions PSP/banque sont visibles séparément.
- Limites : les deux grandeurs (compte et affichage) sont affichées.
RTL/A11y
- Les codes/montants sont lus correctement dans RTL ("dir =" ltr "pour les nombres).
- Le contraste et les indicateurs de focus correspondent à AA.
15) Documentation dans le système de conception
Composants : 'CurrencySwitch', 'Money', 'FxNote', 'DualAmount'.
Stratégie de précision/arrondi et une seule fonction de mise en forme.
Règles : « quand display-only », « quand hard-convert », « comment montrer le sprade ».
Répertoire des monnaies : code, symbole, chiffres, conflits régionaux de caractères.
Galerie Do/Don't : « $ sans code », entrée automatique, commandes cachées.
Résumé succinct
Changer de devise n'est pas seulement un sélecteur « ₴/€/$ ». C'est un modèle clair de l'argent (la monnaie de compte vs affiche vs opération), un taux de change honnête avec une commission, un format correct sur le site et un comportement prudent des champs de saisie. Fixez les règles dans le système de conception, automatisez le formatage et la mise en cache des cours - et les utilisateurs travailleront en toute confiance avec les montants sans douter des chiffres et sans perdre de l'argent sur les sprades « invisibles ».