// FRAZIER Finance OS — API client + small formatters shared across pages. const FIN_API = 'api/fin.php'; async function finApi(action, opts = {}) { const url = `${FIN_API}?action=${encodeURIComponent(action)}&_t=${Date.now()}${opts.query ? '&' + opts.query : ''}`; const body = opts.body ? opts.body : undefined; const res = await fetch(url, { method: body ? 'POST' : 'GET', credentials: 'same-origin', headers: Object.assign({ 'Cache-Control': 'no-cache' }, body ? { 'Content-Type': 'application/json' } : {}), cache: 'no-store', body: body ? JSON.stringify(body) : undefined, }); const text = await res.text(); let data; try { data = JSON.parse(text); } catch (e) { data = { error: 'bad_json', detail: text.slice(0, 200) }; } if (!res.ok || data.error) { const err = new Error(data.detail || data.error || `HTTP ${res.status}`); err.code = data.error; err.payload = data; err.status = res.status; throw err; } return data; } // Rupiah, no decimals — "Rp xxx" per the product spec, every home card. function finIDR(n) { const v = Number(n) || 0; return 'Rp ' + Math.round(v).toLocaleString('id-ID'); } function finMonthLabel(iso) { // iso: 'YYYY-MM' or a full date string. const d = new Date((String(iso || '').length <= 7 ? iso + '-01' : iso) + 'T00:00:00'); if (isNaN(d.getTime())) return String(iso || ''); return d.toLocaleDateString('en-GB', { month: 'long', year: 'numeric' }); } Object.assign(window, { finApi, finIDR, finMonthLabel, FIN_API });