78 lines
2.0 KiB
TypeScript
78 lines
2.0 KiB
TypeScript
'use client';
|
|
|
|
import { toast } from "@/components/ui/use-toast";
|
|
import { normalizeApiUrl, getAuthToken, createApiHeaders } from "./api-utils";
|
|
|
|
type FetchMethod = 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH';
|
|
|
|
interface FetchOptions {
|
|
method?: FetchMethod;
|
|
body?: any;
|
|
cache?: RequestCache;
|
|
headers?: HeadersInit;
|
|
}
|
|
|
|
/**
|
|
* Client-side fetch utility that ensures all requests go through the Next.js API proxy
|
|
*/
|
|
export async function fetchClient<T>(
|
|
endpoint: string,
|
|
options: FetchOptions = {}
|
|
): Promise<T> {
|
|
const { method = 'GET', body, headers = {}, ...rest } = options;
|
|
|
|
// Normalize the endpoint to ensure it starts with /api/
|
|
const url = normalizeApiUrl(endpoint);
|
|
|
|
// Get auth token and prepare headers
|
|
const requestHeaders = createApiHeaders(null, headers as Record<string, string>);
|
|
|
|
// Log request details (useful for debugging)
|
|
console.log('API Request:', {
|
|
url,
|
|
method,
|
|
hasAuthToken: requestHeaders.has('Authorization')
|
|
});
|
|
|
|
const fetchOptions: RequestInit = {
|
|
method,
|
|
credentials: 'include',
|
|
headers: requestHeaders,
|
|
...rest,
|
|
};
|
|
|
|
if (body && method !== 'GET') {
|
|
fetchOptions.body = JSON.stringify(body);
|
|
}
|
|
|
|
try {
|
|
const response = await fetch(url, fetchOptions);
|
|
|
|
if (!response.ok) {
|
|
const errorData = await response.json().catch(() => ({}));
|
|
const errorMessage = errorData.message || errorData.error || `Request failed with status ${response.status}`;
|
|
throw new Error(errorMessage);
|
|
}
|
|
|
|
// Handle 204 No Content responses
|
|
if (response.status === 204) {
|
|
return {} as T;
|
|
}
|
|
|
|
return await response.json();
|
|
} catch (error) {
|
|
console.error('API request failed:', error);
|
|
|
|
// Only show toast in browser environment
|
|
if (typeof window !== 'undefined') {
|
|
const message = error instanceof Error ? error.message : 'Failed to connect to server';
|
|
toast({
|
|
title: 'Error',
|
|
description: message,
|
|
variant: 'destructive',
|
|
});
|
|
}
|
|
|
|
throw error;
|
|
}
|
|
}
|