Files
clinicpro/assets/admin/lib/api.ts
T
hamed 25701c09b7 feat(admin): add user and doctor management APIs and frontend form
- Updated security configuration to include new API route for file uploads.
- Added new endpoints in AdminApiController for user statistics, toggling user status, updating user roles, and managing user details.
- Implemented doctor statistics and management endpoints, including toggling doctor status and creating new doctors.
- Enhanced user listing with filtering options for roles and status.
- Introduced DoctorFormPage component for adding new doctors with specialties selection.
- Integrated react-leaflet for mapping functionalities and added necessary dependencies.
- Updated package.json and package-lock.json to include new dependencies.
2026-06-10 17:02:42 +03:30

84 lines
2.1 KiB
TypeScript

import { useAuthStore } from '../stores/authStore';
const BASE_URL = '';
function getToken(): string | null {
try {
const raw = localStorage.getItem('clinicpro-auth');
if (!raw) return null;
const parsed = JSON.parse(raw);
return parsed?.state?.token ?? null;
} catch {
return null;
}
}
export class ApiError extends Error {
constructor(
public status: number,
public code: string,
message: string,
) {
super(message);
}
}
async function request<T>(
path: string,
options: RequestInit = {},
): Promise<T> {
const token = getToken();
const headers: Record<string, string> = {
'Content-Type': 'application/json',
...(options.headers as Record<string, string>),
};
if (token) headers['Authorization'] = `Bearer ${token}`;
const res = await fetch(`${BASE_URL}${path}`, { ...options, headers });
if (!res.ok) {
if (res.status === 401) {
useAuthStore.getState().logout();
window.location.replace('/admin/login');
throw new ApiError(401, 'ERR_UNAUTHORIZED', 'نشست منقضی شده است');
}
const body = await res.json().catch(() => ({}));
const firstErr = body?.errors?.[0];
throw new ApiError(
res.status,
firstErr?.code ?? 'ERR_UNKNOWN',
firstErr?.message ?? 'خطای ناشناخته',
);
}
return res.json() as Promise<T>;
}
export const api = {
get: <T>(path: string) => request<T>(path),
post: <T>(path: string, body: unknown) =>
request<T>(path, { method: 'POST', body: JSON.stringify(body) }),
patch: <T>(path: string, body: unknown) =>
request<T>(path, { method: 'PATCH', body: JSON.stringify(body) }),
put: <T>(path: string, body: unknown) =>
request<T>(path, { method: 'PUT', body: JSON.stringify(body) }),
delete: <T>(path: string) => request<T>(path, { method: 'DELETE' }),
};
export interface ApiResponse<T> {
success: boolean;
data: T;
errors: { code: string; message: string; field?: string }[];
}
export interface PaginatedResponse<T> {
success: boolean;
data: T[];
meta: {
totalRecords: number;
totalPages: number;
currentPage: number;
};
errors: [];
}