fix(capacity): stabilize PTO flows and calendar consistency
Make PTO creation immediately approved, add PTO deletion, and ensure cache invalidation updates individual/team/revenue capacity consistently. Harden holiday duplicate handling (422), support PTO-day availability overrides without disabling edits, and align tests plus OpenSpec artifacts with the new behavior.
This commit is contained in:
@@ -8,6 +8,7 @@
|
||||
import { unwrapResponse } from '$lib/api/client';
|
||||
|
||||
const API_BASE_URL = import.meta.env.VITE_API_URL ?? '/api';
|
||||
export const GENERIC_SERVER_ERROR_MESSAGE = 'An unexpected server error occurred. Please try again.';
|
||||
|
||||
// Token storage keys
|
||||
const ACCESS_TOKEN_KEY = 'headroom_access_token';
|
||||
@@ -76,6 +77,22 @@ export class ApiError extends Error {
|
||||
}
|
||||
}
|
||||
|
||||
export function sanitizeApiErrorMessage(message?: string): string {
|
||||
if (!message) {
|
||||
return GENERIC_SERVER_ERROR_MESSAGE;
|
||||
}
|
||||
|
||||
const normalized = message.toLowerCase();
|
||||
const containsHtml = ['<!doctype', '<html', '<body', '<head'].some((fragment) =>
|
||||
normalized.includes(fragment)
|
||||
);
|
||||
const containsSql = ['sqlstate', 'illuminate\\', 'stack trace'].some((fragment) =>
|
||||
normalized.includes(fragment)
|
||||
);
|
||||
|
||||
return containsHtml || containsSql ? GENERIC_SERVER_ERROR_MESSAGE : message;
|
||||
}
|
||||
|
||||
// Queue for requests waiting for token refresh
|
||||
let isRefreshing = false;
|
||||
let refreshSubscribers: Array<(token: string) => void> = [];
|
||||
@@ -131,6 +148,7 @@ export async function apiRequest<T>(endpoint: string, options: ApiRequestOptions
|
||||
|
||||
// Prepare headers
|
||||
const headers: Record<string, string> = {
|
||||
Accept: 'application/json',
|
||||
'Content-Type': 'application/json',
|
||||
...options.headers,
|
||||
};
|
||||
@@ -229,7 +247,8 @@ async function handleResponse(response: Response): Promise<Response> {
|
||||
const payloadResponse = response.clone();
|
||||
const data = isJson ? await payloadResponse.json() : await payloadResponse.text();
|
||||
const errorData = typeof data === 'object' ? data : { message: data };
|
||||
const message = (errorData as { message?: string }).message || 'API request failed';
|
||||
const rawMessage = (errorData as { message?: string }).message || 'API request failed';
|
||||
const message = sanitizeApiErrorMessage(rawMessage);
|
||||
console.error('API error', {
|
||||
url: response.url,
|
||||
status: response.status,
|
||||
|
||||
Reference in New Issue
Block a user