ugh
This commit is contained in:
@@ -1,7 +1,6 @@
|
||||
'use client';
|
||||
|
||||
import { toast } from "@/components/ui/use-toast";
|
||||
import { normalizeApiUrl, getAuthToken, createApiHeaders } from "./api-utils";
|
||||
|
||||
type FetchMethod = 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH';
|
||||
|
||||
@@ -12,26 +11,61 @@ interface FetchOptions {
|
||||
headers?: HeadersInit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Client-side fetch utility that ensures all requests go through the Next.js API proxy
|
||||
*/
|
||||
// Helper function to get auth token from cookies
|
||||
function getAuthToken(): string | null {
|
||||
if (typeof document === 'undefined') return null; // Guard for SSR
|
||||
|
||||
return document.cookie
|
||||
.split('; ')
|
||||
.find(row => row.startsWith('Authorization='))
|
||||
?.split('=')[1] || null;
|
||||
}
|
||||
|
||||
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 the base API URL from environment or fallback
|
||||
const apiUrl = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:3001';
|
||||
|
||||
// Get auth token and prepare headers
|
||||
const requestHeaders = createApiHeaders(null, headers as Record<string, string>);
|
||||
// Ensure the endpoint starts with a slash
|
||||
const normalizedEndpoint = endpoint.startsWith('/') ? endpoint : `/${endpoint}`;
|
||||
|
||||
// For the specific case of internal-api.inboxi.ng - remove duplicate /api
|
||||
let url;
|
||||
if (apiUrl.includes('internal-api.inboxi.ng')) {
|
||||
// Special case for internal-api.inboxi.ng
|
||||
if (normalizedEndpoint.startsWith('/api/')) {
|
||||
url = `${apiUrl}${normalizedEndpoint.substring(4)}`; // Remove the /api part
|
||||
} else {
|
||||
url = `${apiUrl}${normalizedEndpoint}`;
|
||||
}
|
||||
} else {
|
||||
// Normal case for other environments
|
||||
url = `${apiUrl}${normalizedEndpoint}`;
|
||||
}
|
||||
|
||||
// Get auth token from cookies
|
||||
const authToken = getAuthToken();
|
||||
|
||||
// Prepare headers with authentication if token exists
|
||||
const requestHeaders: Record<string, string> = {
|
||||
'Content-Type': 'application/json',
|
||||
...(headers as Record<string, string>),
|
||||
};
|
||||
|
||||
if (authToken) {
|
||||
// Backend expects "Bearer TOKEN" format
|
||||
requestHeaders['Authorization'] = `Bearer ${authToken}`;
|
||||
console.log('Authorization header set to:', `Bearer ${authToken.substring(0, 10)}...`);
|
||||
}
|
||||
|
||||
// Log request details (useful for debugging)
|
||||
console.log('API Request:', {
|
||||
url,
|
||||
method,
|
||||
hasAuthToken: requestHeaders.has('Authorization')
|
||||
hasAuthToken: !!authToken
|
||||
});
|
||||
|
||||
const fetchOptions: RequestInit = {
|
||||
@@ -50,22 +84,24 @@ export async function fetchClient<T>(
|
||||
|
||||
if (!response.ok) {
|
||||
const errorData = await response.json().catch(() => ({}));
|
||||
const errorMessage = errorData.message || errorData.error || `Request failed with status ${response.status}`;
|
||||
const errorMessage = errorData.message || errorData.error || 'An error occurred';
|
||||
|
||||
throw new Error(errorMessage);
|
||||
}
|
||||
|
||||
// Handle 204 No Content responses
|
||||
if (response.status === 204) {
|
||||
return {} as T;
|
||||
}
|
||||
|
||||
return await response.json();
|
||||
const data = await response.json();
|
||||
return data;
|
||||
} catch (error) {
|
||||
console.error('API request failed:', error);
|
||||
|
||||
// Only show toast in browser environment
|
||||
// Only show toast if this is a client-side error (not during SSR)
|
||||
if (typeof window !== 'undefined') {
|
||||
const message = error instanceof Error ? error.message : 'Failed to connect to server';
|
||||
|
||||
toast({
|
||||
title: 'Error',
|
||||
description: message,
|
||||
|
||||
Reference in New Issue
Block a user