const MERCHANT_TOKEN_KEY = "merchant_token"; const MERCHANT_ID_KEY = "merchant_id"; const MERCHANT_USER_KEY = "merchant_user"; const MERCHANT_AUTH_MODE_KEY = "merchant_auth_mode"; function merchantFormatMoney(value) { const number = Number(value || 0); if (!Number.isFinite(number)) { return "Rp 0"; } return new Intl.NumberFormat("id-ID", { style: "currency", currency: "IDR", maximumFractionDigits: 0 }).format(number); } function merchantFormatDateTime(value) { if (!value) { return "-"; } const date = new Date(value); if (Number.isNaN(date.getTime())) { return value; } return new Intl.DateTimeFormat("en-GB", { dateStyle: "medium", timeStyle: "short" }).format(date); } function merchantBuildQuery(query) { const search = new URLSearchParams(); Object.entries(query || {}).forEach(([key, val]) => { if (val !== undefined && val !== null && val !== "") { search.append(key, String(val)); } }); return search.toString(); } async function merchantFetch(path, options = {}) { const token = localStorage.getItem(MERCHANT_TOKEN_KEY); const merchantId = localStorage.getItem(MERCHANT_ID_KEY); const { method = "GET", query, body, headers: extraHeaders = {}, auth = true } = options; const suffix = merchantBuildQuery(query || {}); const headers = { ...extraHeaders }; if (auth) { if (!token) { throw new Error("MERCHANT_AUTH_MISSING"); } headers.Authorization = `Bearer ${token}`; if (merchantId) { headers["X-Merchant-Id"] = merchantId; } } if (method !== "GET" && body !== undefined) { headers["Content-Type"] = "application/json"; } const response = await fetch(suffix ? `${path}?${suffix}` : path, { method, headers, body: method === "GET" || body === undefined ? undefined : JSON.stringify(body) }); const raw = await response.text(); let payload; try { payload = raw ? JSON.parse(raw) : {}; } catch (error) { payload = {}; } if (!response.ok) { throw new Error(payload?.message || payload?.error || `Request failed with status ${response.status}`); } return payload?.data !== undefined ? payload.data : payload; } window.MerchantUIAPI = { MERCHANT_TOKEN_KEY, MERCHANT_ID_KEY, setSession: ({ token, merchant, user, auth_mode }) => { localStorage.setItem(MERCHANT_TOKEN_KEY, token); localStorage.setItem(MERCHANT_ID_KEY, merchant.id); if (user) { localStorage.setItem(MERCHANT_USER_KEY, JSON.stringify(user)); } if (auth_mode) { localStorage.setItem(MERCHANT_AUTH_MODE_KEY, auth_mode); } }, clearSession: () => { localStorage.removeItem(MERCHANT_TOKEN_KEY); localStorage.removeItem(MERCHANT_ID_KEY); localStorage.removeItem(MERCHANT_USER_KEY); localStorage.removeItem(MERCHANT_AUTH_MODE_KEY); }, getSessionUser: () => { try { return JSON.parse(localStorage.getItem(MERCHANT_USER_KEY) || "null"); } catch (_error) { return null; } }, getAuthMode: () => localStorage.getItem(MERCHANT_AUTH_MODE_KEY), requireSession: () => { const token = localStorage.getItem(MERCHANT_TOKEN_KEY); const merchantId = localStorage.getItem(MERCHANT_ID_KEY); if (!token || !merchantId) { window.location.href = "/ui/merchant-login"; throw new Error("MERCHANT_AUTH_MISSING"); } return { token, merchantId }; }, login: async ({ username, password }) => { const data = await merchantFetch("/merchant/login", { method: "POST", auth: false, body: { username, password } }); if (data?.token && data?.merchant) { window.MerchantUIAPI.setSession(data); } return data; }, getProfile: async () => { const profile = await merchantFetch("/merchant/profile"); return profile?.merchant || profile; }, getSettlementSummary: () => merchantFetch("/merchant/settlement-summary"), listSettlementBatches: (query) => merchantFetch("/merchant/settlement-batches", { query }), getSettlementBatch: (id) => merchantFetch(`/merchant/settlement-batches/${id}`), formatMoney: merchantFormatMoney, formatDateTime: merchantFormatDateTime };