diff --git a/src/App.tsx b/src/App.tsx index 3574907..21dc42f 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,6 +1,7 @@ -import { ClerkProvider } from '@clerk/clerk-react'; +import { ClerkProvider, useAuth } from '@clerk/clerk-react'; import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import { BrowserRouter, Routes, Route } from 'react-router-dom'; +import { useEffect } from 'react'; // Import Leaflet CSS import 'leaflet/dist/leaflet.css'; @@ -24,6 +25,10 @@ import { WhyCleanPage } from './pages'; +// Services +import { apiClient } from './services/api'; +import { reportService } from './services/reportService'; + const queryClient = new QueryClient({ defaultOptions: { queries: { @@ -39,11 +44,26 @@ if (!clerkPubKey) { throw new Error('Missing Clerk Publishable Key'); } +// Component to initialize API clients with auth token +function ApiInitializer({ children }: { children: React.ReactNode }) { + const { getToken } = useAuth(); + + useEffect(() => { + // Set up token getter for API clients + const tokenGetter = () => getToken(); + apiClient.setTokenGetter(tokenGetter); + reportService.setTokenGetter(tokenGetter); + }, [getToken]); + + return <>{children}; +} + function App() { return ( - + + {/* Public routes */} } /> @@ -134,6 +154,7 @@ function App() { /> + ); diff --git a/src/services/api.ts b/src/services/api.ts index d4565f7..f55ab78 100644 --- a/src/services/api.ts +++ b/src/services/api.ts @@ -1,4 +1,5 @@ // API service configuration and base client +import { useAuth } from '@clerk/clerk-react'; const API_BASE_URL = import.meta.env.VITE_API_BASE_URL || 'http://localhost:3000/api'; @@ -11,21 +12,30 @@ export interface ApiError { export class ApiClient { private baseUrl: string; + private getToken?: () => Promise; constructor(baseUrl: string = API_BASE_URL) { this.baseUrl = baseUrl; } + setTokenGetter(getToken: () => Promise) { + this.getToken = getToken; + } + private async request( endpoint: string, options: RequestInit = {} ): Promise { const url = `${this.baseUrl}${endpoint}`; + // Get auth token if available + const token = this.getToken ? await this.getToken() : null; + const response = await fetch(url, { ...options, headers: { 'Content-Type': 'application/json', + ...(token ? { Authorization: `Bearer ${token}` } : {}), ...options.headers, }, }); diff --git a/src/services/reportService.ts b/src/services/reportService.ts index 7ff5bda..4650bca 100644 --- a/src/services/reportService.ts +++ b/src/services/reportService.ts @@ -24,6 +24,12 @@ export interface UploadPhotoResponse { } class ReportService { + private getToken?: () => Promise; + + setTokenGetter(getToken: () => Promise) { + this.getToken = getToken; + } + /** * Upload a photo to the server */ @@ -31,8 +37,14 @@ class ReportService { const formData = new FormData(); formData.append('photo', file); + // Get auth token + const token = this.getToken ? await this.getToken() : null; + const response = await fetch(`${import.meta.env.VITE_API_BASE_URL || 'http://localhost:3005/api'}/reports/upload`, { method: 'POST', + headers: { + ...(token ? { Authorization: `Bearer ${token}` } : {}), + }, body: formData, });