feat(frontend): add apiFetch wrapper for automatic auth token injection
Centralizes auth token management into a reusable apiFetch() helper and getAuthHeaders() utility, eliminating inline Bearer token logic across all frontend files. Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
@@ -5,6 +5,7 @@
|
||||
import { cubicOut } from 'svelte/easing';
|
||||
import { browser } from '$app/environment';
|
||||
import { authStore } from '$lib/stores/auth.svelte';
|
||||
import { apiFetch } from '$lib/utils/api';
|
||||
import { Skeleton } from '$lib/components/ui/skeleton';
|
||||
import { Button } from '$lib/components/ui/button';
|
||||
import { Checkbox } from '$lib/components/ui/checkbox';
|
||||
@@ -138,9 +139,7 @@
|
||||
per_page: perPage.toString(),
|
||||
include_acknowledged: includeAcknowledged.toString()
|
||||
});
|
||||
const response = await fetch(`/api/admin/notifications?${params}`, {
|
||||
headers: { Authorization: `Bearer ${authStore.currentToken}` }
|
||||
});
|
||||
const response = await apiFetch(`/api/admin/notifications?${params}`);
|
||||
if (!response.ok) {
|
||||
throw new Error(`Failed: ${response.status}`);
|
||||
}
|
||||
@@ -155,21 +154,16 @@
|
||||
}
|
||||
|
||||
async function fetchBookingDetails(bookingId: string): Promise<Booking | null> {
|
||||
const response = await fetch(`/api/admin/bookings/${bookingId}`, {
|
||||
headers: { Authorization: `Bearer ${authStore.currentToken}` }
|
||||
});
|
||||
const response = await apiFetch(`/api/admin/bookings/${bookingId}`);
|
||||
if (!response.ok) return null;
|
||||
return response.json();
|
||||
}
|
||||
|
||||
async function handleAction(notification: Notification) {
|
||||
if (!notification.acknowledged_at) {
|
||||
await fetch(`/api/admin/notifications/${notification.id}/acknowledge`, {
|
||||
await apiFetch(`/api/admin/notifications/${notification.id}/acknowledge`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
Authorization: `Bearer ${authStore.currentToken}`
|
||||
}
|
||||
headers: { 'Content-Type': 'application/json' }
|
||||
});
|
||||
}
|
||||
|
||||
@@ -192,11 +186,8 @@
|
||||
}
|
||||
} else if (action === 'edit_approve' && notification.booking_id) {
|
||||
try {
|
||||
const response = await fetch(
|
||||
`/api/admin/bookings/${notification.booking_id}/edit-request`,
|
||||
{
|
||||
headers: { Authorization: `Bearer ${authStore.currentToken}` }
|
||||
}
|
||||
const response = await apiFetch(
|
||||
`/api/admin/bookings/${notification.booking_id}/edit-request`
|
||||
);
|
||||
if (response.ok) {
|
||||
const data = await response.json();
|
||||
@@ -219,12 +210,9 @@
|
||||
|
||||
async function handleAcknowledge(notification: Notification) {
|
||||
try {
|
||||
const response = await fetch(`/api/admin/notifications/${notification.id}/acknowledge`, {
|
||||
const response = await apiFetch(`/api/admin/notifications/${notification.id}/acknowledge`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
Authorization: `Bearer ${authStore.currentToken}`
|
||||
}
|
||||
headers: { 'Content-Type': 'application/json' }
|
||||
});
|
||||
if (!response.ok) {
|
||||
toast.error('Failed to acknowledge notification');
|
||||
@@ -351,6 +339,10 @@
|
||||
<svelte:head>
|
||||
<script>
|
||||
(function () {
|
||||
// Pre-hydration auth guard: reads localStorage directly because the Svelte
|
||||
// authStore hasn't initialized yet at this point (async+$state). This runs
|
||||
// synchronously in <svelte:head> before any rendering, preventing a flash
|
||||
// of protected content. The authStore handles post-hydration auth.
|
||||
try {
|
||||
var token = localStorage.getItem('authToken');
|
||||
if (!token) {
|
||||
|
||||
Reference in New Issue
Block a user