Files
openhuman/src/services/apiClient.ts
T
Steven Enamakel 5d76837dff Add Telegram connection indicator and integrate into Home component
- Introduced TelegramConnectionIndicator component to display real-time connection status to Telegram, enhancing user feedback.
- Integrated TelegramConnectionIndicator into the Home component, providing users with immediate visibility of their Telegram connection status.
- Updated App component to include TelegramProvider, ensuring proper context for the new connection indicator.

These changes improve the user experience by providing clear indications of Telegram connectivity within the application.
2026-01-28 05:56:56 +05:30

160 lines
3.8 KiB
TypeScript

import { BACKEND_URL } from '../utils/config';
import type { ApiError } from '../types/api';
import { store } from '../store';
type HttpMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
interface RequestOptions {
method?: HttpMethod;
body?: unknown;
headers?: Record<string, string>;
requireAuth?: boolean;
}
/**
* API Client for making requests to the backend
* Handles authentication, error handling, and response typing
*/
class ApiClient {
private baseUrl: string;
constructor(baseUrl: string) {
this.baseUrl = baseUrl;
}
/**
* Get the current JWT token from Redux store
*/
private getToken(): string | null {
return store.getState().auth.token;
}
/**
* Build headers for the request
*/
private buildHeaders(options: RequestOptions): HeadersInit {
const headers: Record<string, string> = {
'Content-Type': 'application/json',
...options.headers,
};
// Add authorization header if auth is required
if (options.requireAuth !== false) {
const token = this.getToken();
if (token) {
headers.Authorization = `Bearer ${token}`;
}
}
return headers;
}
/**
* Make an API request
*/
private async request<T>(
endpoint: string,
options: RequestOptions = {}
): Promise<T> {
const { method = 'GET', body, requireAuth = true } = options;
const url = `${this.baseUrl}${endpoint}`;
const headers = this.buildHeaders({ ...options, requireAuth });
const config: RequestInit = {
method,
headers,
};
if (body && method !== 'GET') {
config.body = JSON.stringify(body);
}
try {
const response = await fetch(url, config);
// Handle non-JSON responses
const contentType = response.headers.get('content-type');
if (!contentType || !contentType.includes('application/json')) {
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return {} as T;
}
const data = await response.json();
// Handle error responses
if (!response.ok) {
const error: ApiError = data.error
? { success: false, error: data.error, message: data.message }
: { success: false, error: `HTTP ${response.status}: ${response.statusText}` };
throw error;
}
return data as T;
} catch (error) {
// Re-throw API errors as-is
if (error && typeof error === 'object' && 'error' in error) {
throw error;
}
// Wrap network/other errors
throw {
success: false,
error: error instanceof Error ? error.message : 'Unknown error occurred',
} as ApiError;
}
}
/**
* GET request
*/
async get<T>(endpoint: string, options?: Omit<RequestOptions, 'method' | 'body'>): Promise<T> {
return this.request<T>(endpoint, { ...options, method: 'GET' });
}
/**
* POST request
*/
async post<T>(
endpoint: string,
body?: unknown,
options?: Omit<RequestOptions, 'method' | 'body'>
): Promise<T> {
return this.request<T>(endpoint, { ...options, method: 'POST', body });
}
/**
* PUT request
*/
async put<T>(
endpoint: string,
body?: unknown,
options?: Omit<RequestOptions, 'method' | 'body'>
): Promise<T> {
return this.request<T>(endpoint, { ...options, method: 'PUT', body });
}
/**
* PATCH request
*/
async patch<T>(
endpoint: string,
body?: unknown,
options?: Omit<RequestOptions, 'method' | 'body'>
): Promise<T> {
return this.request<T>(endpoint, { ...options, method: 'PATCH', body });
}
/**
* DELETE request
*/
async delete<T>(endpoint: string, options?: Omit<RequestOptions, 'method' | 'body'>): Promise<T> {
return this.request<T>(endpoint, { ...options, method: 'DELETE' });
}
}
// Export singleton instance
export const apiClient = new ApiClient(BACKEND_URL);