feat: complete tOS project with HR, LEAN, Dashboard and Integrations modules
Full enterprise web operating system including: - Next.js 14 frontend with App Router, i18n (DE/EN), shadcn/ui - NestJS 10 backend with Prisma, JWT auth, Swagger docs - Keycloak 24 SSO with role-based access control - HR module (employees, time tracking, absences, org chart) - LEAN module (3S planning, morning meeting SQCDM, skill matrix) - Integrations module (PlentyONE, Zulip, Todoist, FreeScout, Nextcloud, ecoDMS, GembaDocs) - Dashboard with customizable drag & drop widget grid - Docker Compose infrastructure (PostgreSQL 16, Redis 7, Keycloak 24) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
120
apps/web/src/lib/api.ts
Normal file
120
apps/web/src/lib/api.ts
Normal file
@@ -0,0 +1,120 @@
|
||||
import { getSession } from 'next-auth/react';
|
||||
|
||||
const API_URL = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:3001/api';
|
||||
|
||||
/**
|
||||
* API client configuration
|
||||
*/
|
||||
interface RequestConfig extends RequestInit {
|
||||
params?: Record<string, string | number | boolean | undefined>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build URL with query parameters
|
||||
*/
|
||||
function buildUrl(endpoint: string, params?: RequestConfig['params']): string {
|
||||
const url = new URL(`${API_URL}${endpoint}`);
|
||||
|
||||
if (params) {
|
||||
Object.entries(params).forEach(([key, value]) => {
|
||||
if (value !== undefined) {
|
||||
url.searchParams.append(key, String(value));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return url.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Make an authenticated API request
|
||||
*/
|
||||
async function request<T>(endpoint: string, config: RequestConfig = {}): Promise<T> {
|
||||
const { params, ...init } = config;
|
||||
|
||||
// Get session for auth token
|
||||
const session = await getSession();
|
||||
|
||||
const headers: HeadersInit = {
|
||||
'Content-Type': 'application/json',
|
||||
...(init.headers || {}),
|
||||
};
|
||||
|
||||
// Add auth header if session exists
|
||||
if (session?.accessToken) {
|
||||
(headers as Record<string, string>)['Authorization'] = `Bearer ${session.accessToken}`;
|
||||
}
|
||||
|
||||
const response = await fetch(buildUrl(endpoint, params), {
|
||||
...init,
|
||||
headers,
|
||||
});
|
||||
|
||||
// Handle non-OK responses
|
||||
if (!response.ok) {
|
||||
const error = await response.json().catch(() => ({ message: 'An error occurred' }));
|
||||
throw new Error(error.message || `HTTP error ${response.status}`);
|
||||
}
|
||||
|
||||
// Handle empty responses
|
||||
const contentType = response.headers.get('content-type');
|
||||
if (contentType?.includes('application/json')) {
|
||||
return response.json();
|
||||
}
|
||||
|
||||
return {} as T;
|
||||
}
|
||||
|
||||
/**
|
||||
* API client with typed methods
|
||||
*/
|
||||
export const api = {
|
||||
/**
|
||||
* GET request
|
||||
*/
|
||||
get<T>(endpoint: string, config?: RequestConfig): Promise<T> {
|
||||
return request<T>(endpoint, { ...config, method: 'GET' });
|
||||
},
|
||||
|
||||
/**
|
||||
* POST request
|
||||
*/
|
||||
post<T>(endpoint: string, data?: unknown, config?: RequestConfig): Promise<T> {
|
||||
return request<T>(endpoint, {
|
||||
...config,
|
||||
method: 'POST',
|
||||
body: data ? JSON.stringify(data) : undefined,
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* PUT request
|
||||
*/
|
||||
put<T>(endpoint: string, data?: unknown, config?: RequestConfig): Promise<T> {
|
||||
return request<T>(endpoint, {
|
||||
...config,
|
||||
method: 'PUT',
|
||||
body: data ? JSON.stringify(data) : undefined,
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* PATCH request
|
||||
*/
|
||||
patch<T>(endpoint: string, data?: unknown, config?: RequestConfig): Promise<T> {
|
||||
return request<T>(endpoint, {
|
||||
...config,
|
||||
method: 'PATCH',
|
||||
body: data ? JSON.stringify(data) : undefined,
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* DELETE request
|
||||
*/
|
||||
delete<T>(endpoint: string, config?: RequestConfig): Promise<T> {
|
||||
return request<T>(endpoint, { ...config, method: 'DELETE' });
|
||||
},
|
||||
};
|
||||
|
||||
export default api;
|
||||
Reference in New Issue
Block a user