import { ref } from 'vue'; /** * Wallet store (module-level singleton so the header, shop, and composer all * share one balance). Credits are CENTI-CREDITS server-side; `displayBalance` * converts to a human "crédits" number. Live updates arrive via the WS `wallet` * frame, routed here through useMessages' realtime hook (applyWalletFrame). */ export interface WalletView { ip: string; balance: number; // centi-credits, or a huge sentinel in free mode freeMode: boolean; } const API_URL = import.meta.env.VITE_API_URL ?? 'http://localhost:3000'; const ip = ref(''); const balanceRaw = ref(0); // centi-credits const freeMode = ref(false); const loaded = ref(false); function apply(view: WalletView): void { ip.value = view.ip; balanceRaw.value = view.balance; freeMode.value = view.freeMode; loaded.value = true; } /** Called by the realtime `wallet` frame handler. */ export function applyWalletFrame(data: WalletView): void { apply(data); } async function fetchWallet(): Promise { try { const res = await fetch(`${API_URL}/api/wallet`); if (res.ok) apply((await res.json()) as WalletView); } catch { /* offline — keep last known */ } } async function topUp(): Promise { try { const res = await fetch(`${API_URL}/api/wallet/topup`, { method: 'POST' }); if (res.ok) apply((await res.json()) as WalletView); } catch { /* ignore */ } } /** Human-readable balance ("∞" in free mode, else credits with 2 decimals). */ function displayBalance(): string { if (freeMode.value) return '∞'; return (balanceRaw.value / 100).toLocaleString('fr-FR', { minimumFractionDigits: 2, maximumFractionDigits: 2, }); } export function useWallet() { return { ip, balanceRaw, freeMode, loaded, fetchWallet, topUp, displayBalance, }; }