add day-end and change item model
This commit is contained in:
@@ -47,7 +47,36 @@ export function readCsrfToken(): string | null {
|
||||
return match ? decodeURIComponent(match[1]) : null
|
||||
}
|
||||
|
||||
async function rawRequest(path: string, options: RequestOptions = {}): Promise<Response> {
|
||||
// erp_at is short-lived; erp_rt (a separate, refresh-route-scoped cookie) outlives it. Before
|
||||
// this, an expired erp_at surfaced as a bare 401 on whatever the user happened to click next
|
||||
// (confirming an invoice, recording a payment, ...) with no attempt to renew the session — this
|
||||
// dedupes concurrent 401s onto one /auth/refresh-token call so every caller gets one retry.
|
||||
let refreshPromise: Promise<boolean> | null = null
|
||||
|
||||
function refreshSession(): Promise<boolean> {
|
||||
if (!refreshPromise) {
|
||||
refreshPromise = fetch(`${API_BASE}/auth/refresh-token`, {
|
||||
method: "POST",
|
||||
credentials: "include",
|
||||
headers: { Accept: "application/json", "Content-Type": "application/json" },
|
||||
body: "{}",
|
||||
})
|
||||
.then((res) => res.ok)
|
||||
.catch(() => false)
|
||||
.finally(() => {
|
||||
refreshPromise = null
|
||||
})
|
||||
}
|
||||
return refreshPromise
|
||||
}
|
||||
|
||||
function redirectToLogin() {
|
||||
if (typeof window === "undefined") return
|
||||
const next = `${window.location.pathname}${window.location.search}`
|
||||
window.location.href = `/login?next=${encodeURIComponent(next)}`
|
||||
}
|
||||
|
||||
async function rawRequest(path: string, options: RequestOptions = {}, isRetry = false): Promise<Response> {
|
||||
const { body, ifMatch, idempotencyKey, csrf, headers, ...rest } = options
|
||||
const csrfToken = csrf ? readCsrfToken() : null
|
||||
// Multipart uploads (attendance files, staff documents) pass a FormData body — the
|
||||
@@ -70,6 +99,12 @@ async function rawRequest(path: string, options: RequestOptions = {}): Promise<R
|
||||
body: isFormData ? (body as FormData) : body !== undefined ? JSON.stringify(body) : undefined,
|
||||
})
|
||||
|
||||
if (response.status === 401 && !isRetry && !path.startsWith("/auth/")) {
|
||||
const refreshed = await refreshSession()
|
||||
if (refreshed) return rawRequest(path, options, true)
|
||||
redirectToLogin()
|
||||
}
|
||||
|
||||
if (!response.ok) {
|
||||
let problem: ProblemDetails
|
||||
try {
|
||||
|
||||
Reference in New Issue
Block a user