// Currency context + helpers. Rates are display-only mock; user-selectable. const CURRENCIES = { TWD: { sym: 'NT$', name: '新台幣', rate: 1 }, // base MYR: { sym: 'RM', name: '馬來西亞令吉', rate: 0.146 }, // 1 TWD ≈ 0.146 MYR HKD: { sym: 'HK$', name: '港幣', rate: 0.255 }, SGD: { sym: 'S$', name: '新加坡幣', rate: 0.044 }, CNY: { sym: '¥', name: '人民幣', rate: 0.236 }, USD: { sym: 'US$', name: '美元', rate: 0.033 }, }; const CurrencyCtx = React.createContext({ code: 'TWD', set: () => {} }); function CurrencyProvider({ children }) { const [code, setCode] = React.useState(() => { try { return localStorage.getItem('arl_ccy') || 'TWD'; } catch { return 'TWD'; } }); const set = (c) => { setCode(c); try { localStorage.setItem('arl_ccy', c); } catch {} }; return {children}; } // Format a TWD amount in the active currency function useMoney() { const { code } = React.useContext(CurrencyCtx); const c = CURRENCIES[code]; return (twd) => { const v = twd * c.rate; const fixed = v >= 100 ? Math.round(v) : v.toFixed(v >= 10 ? 0 : 1); const num = String(fixed).replace(/\B(?=(\d{3})+(?!\d))/g, ','); return { sym: c.sym, num, code }; }; } // Currency switcher component — fits in header / action bars function CurrencySwitch({ compact = false }) { const { code, set } = React.useContext(CurrencyCtx); const [open, setOpen] = React.useState(false); const ref = React.useRef(null); React.useEffect(() => { const fn = (e) => { if (!ref.current?.contains(e.target)) setOpen(false); }; document.addEventListener('click', fn); return () => document.removeEventListener('click', fn); }, []); return (
{open && (
幣別 · 全球華人
{Object.entries(CURRENCIES).map(([k, v]) => ( ))}
兌換率僅供參考 · 每日自動更新
)}
); } // Modal overlay primitive function Modal({ open, onClose, children, title }) { if (!open) return null; return (
e.stopPropagation()}> {title &&

{title}

} {children}
); } Object.assign(window, { CURRENCIES, CurrencyCtx, CurrencyProvider, useMoney, CurrencySwitch, Modal });