// 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 });