Spaces:
Sleeping
Sleeping
| // βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| // src/lib/api/adminUserManagementApi.ts | |
| // User Management API for Admin Dashboard | |
| // Based on the official API documentation - completely independent from adminApi | |
| // βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| import { getApiBaseUrl } from './config'; | |
| const BASE_URL = getApiBaseUrl(); | |
| const TOKEN_KEY = 'authToken'; | |
| // βββ Custom Error Class βββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| export class UserManagementApiError extends Error { | |
| readonly status: number; | |
| readonly path: string; | |
| constructor( | |
| status: number, | |
| message: string, | |
| path: string, | |
| ) { | |
| super(`[${status}] ${path} β ${message}`); | |
| this.status = status; | |
| this.path = path; | |
| this.name = 'UserManagementApiError'; | |
| } | |
| } | |
| // βββ Shared helper ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| function getHeaders(): HeadersInit { | |
| const token = localStorage.getItem(TOKEN_KEY) ?? ''; | |
| return { | |
| 'Content-Type': 'application/json', | |
| ...(token ? { Authorization: `Bearer ${token}` } : {}), | |
| }; | |
| } | |
| async function request<T>(path: string, options?: RequestInit): Promise<T> { | |
| const url = `${BASE_URL}${path}`; | |
| // Guard: expired token | |
| const token = localStorage.getItem(TOKEN_KEY); | |
| if (token) { | |
| try { | |
| const payload = JSON.parse(atob(token.split('.')[1])); | |
| if (payload?.exp && payload.exp * 1000 < Date.now()) { | |
| localStorage.removeItem(TOKEN_KEY); | |
| throw new UserManagementApiError(401, 'Session expired β please log in again', path); | |
| } | |
| } catch (e) { | |
| if (e instanceof UserManagementApiError) throw e; | |
| localStorage.removeItem(TOKEN_KEY); | |
| } | |
| } | |
| try { | |
| const res = await fetch(url, { | |
| ...options, | |
| headers: { ...getHeaders(), ...options?.headers }, | |
| }); | |
| // Handle 204 No Content | |
| if (res.status === 204) { | |
| return null as T; | |
| } | |
| if (!res.ok) { | |
| const message = await res.text().catch(() => res.statusText); | |
| throw new UserManagementApiError(res.status, message, path); | |
| } | |
| const text = await res.text(); | |
| if (!text.trim()) { | |
| return null as T; | |
| } | |
| try { | |
| return JSON.parse(text) as T; | |
| } catch { | |
| return text as unknown as T; | |
| } | |
| } catch (error) { | |
| if (error instanceof UserManagementApiError) throw error; | |
| throw new Error(`Network error while calling ${path}`); | |
| } | |
| } | |
| // βββ Response Types βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| export interface UserManagementStatsDto { | |
| totalUsers: number; | |
| totalSheikhs: number; | |
| totalStudents: number; | |
| blockedUsers: number; | |
| } | |
| export interface StudentDtoAdmin { | |
| id: number; | |
| name: string; | |
| email: string; | |
| registrationDate: string; | |
| streak: number; | |
| totalSessions: number; | |
| status: 'ACTIVE' | 'BLOCKED' | 'INACTIVE'; | |
| } | |
| export interface SheikhDtoAdmin { | |
| id: number; | |
| name: string; | |
| email: string; | |
| registrationDate: string; | |
| numberOfSessions: number; | |
| totalRevenue: number; | |
| averageRating: number; | |
| status: 'ACTIVE' | 'BLOCKED' | 'PENDING' | 'APPROVED' | 'REJECTED'; | |
| } | |
| export type UserDtoAdmin = StudentDtoAdmin | SheikhDtoAdmin; | |
| export interface DetailedStudentView { | |
| id: number; | |
| name: string; | |
| email: string; | |
| registrationDate: string; | |
| streak: number; | |
| sessionCount: number; | |
| country: string; | |
| numberOfCompletedSessions: number; | |
| totalSpentTime: number; | |
| } | |
| export interface DetailedSheikhView { | |
| id: number; | |
| name: string; | |
| email: string; | |
| country: string; | |
| experienceYears: number; | |
| bio: string; | |
| specialization: string; | |
| hourlyRate: number; | |
| status: 'PENDING' | 'APPROVED' | 'REJECTED' | 'ACTIVE' | 'BLOCKED'; | |
| registrationDate: string; | |
| averageRating: number; | |
| numberOfCompletedSessions: number; | |
| numberOfStudents: number; | |
| numberofReviews: number; | |
| sessionCount: number; | |
| totalEarnings: number; | |
| } | |
| export interface SessionHistoryDto { | |
| sessionId: number; | |
| sheikhName: string; | |
| studentName: string; | |
| date: string; | |
| status: 'COMPLETED' | 'CANCELLED' | 'PENDING' | 'SCHEDULED'; | |
| price: number; | |
| durationInMinutes: number; | |
| rate: number; | |
| } | |
| export interface SheikhProfileResponse { | |
| sheikhProfile: DetailedSheikhView; | |
| sessionHistories: SessionHistoryDto[]; | |
| } | |
| export interface StudentProfileResponse { | |
| studentProfile: DetailedStudentView; | |
| sessionHistories: SessionHistoryDto[]; | |
| } | |
| // βββ API Functions ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| /** | |
| * GET /api/admin/user-management/stats | |
| * Retrieves comprehensive statistics about all users in the platform. | |
| */ | |
| export async function fetchUserManagementStats(): Promise<UserManagementStatsDto> { | |
| return request<UserManagementStatsDto>('/api/admin/user-management/stats'); | |
| } | |
| /** | |
| * GET /api/admin/user-management/students | |
| * Retrieves a list of all students with basic information. | |
| */ | |
| export async function fetchAllStudents(): Promise<StudentDtoAdmin[]> { | |
| return request<StudentDtoAdmin[]>('/api/admin/user-management/students'); | |
| } | |
| /** | |
| * GET /api/admin/user-management/sheikhs | |
| * Retrieves a list of all sheikhs with basic information. | |
| */ | |
| export async function fetchAllSheikhs(): Promise<SheikhDtoAdmin[]> { | |
| return request<SheikhDtoAdmin[]>('/api/admin/user-management/sheikhs'); | |
| } | |
| /** | |
| * GET /api/admin/user-management/users | |
| * Retrieves a combined list of all users (students and sheikhs). | |
| */ | |
| export async function fetchAllUsers(): Promise<UserDtoAdmin[]> { | |
| return request<UserDtoAdmin[]>('/api/admin/user-management/users'); | |
| } | |
| /** | |
| * POST /api/admin/user-management/block-user | |
| * Blocks a user account, preventing them from accessing the platform. | |
| * @param userId - ID of the user to block | |
| */ | |
| export async function blockUser(userId: number): Promise<void> { | |
| return request<void>(`/api/admin/user-management/block-user?userId=${userId}`, { | |
| method: 'POST', | |
| }); | |
| } | |
| /** | |
| * POST /api/admin/user-management/unblock-user | |
| * Unblocks a previously blocked user account. | |
| * @param userId - ID of the user to unblock | |
| */ | |
| export async function unblockUser(userId: number): Promise<void> { | |
| return request<void>(`/api/admin/user-management/unblock-user?userId=${userId}`, { | |
| method: 'POST', | |
| }); | |
| } | |
| /** | |
| * GET /api/admin/user-management/sheikh-profile | |
| * Retrieves detailed profile information for a specific sheikh including session history. | |
| * @param userId - Sheikh's ID | |
| */ | |
| export async function fetchSheikhProfile(userId: number): Promise<SheikhProfileResponse> { | |
| return request<SheikhProfileResponse>(`/api/admin/user-management/sheikh-profile?userId=${userId}`); | |
| } | |
| /** | |
| * GET /api/admin/user-management/student-profile | |
| * Retrieves detailed profile information for a specific student including session history. | |
| * @param userId - Student's ID | |
| */ | |
| export async function fetchStudentProfile(userId: number): Promise<StudentProfileResponse> { | |
| return request<StudentProfileResponse>(`/api/admin/user-management/student-profile?userId=${userId}`); | |
| } | |
| // βββ Convenience: load all user management data βββββββββββββββββββββββββββββββ | |
| export interface UserManagementData { | |
| stats: UserManagementStatsDto; | |
| students: StudentDtoAdmin[]; | |
| sheikhs: SheikhDtoAdmin[]; | |
| users: UserDtoAdmin[]; | |
| } | |
| export async function fetchUserManagementData(): Promise<{ | |
| data: Partial<UserManagementData>; | |
| errors: Record<string, string>; | |
| }> { | |
| const [statsResult, studentsResult, sheikhsResult, usersResult] = await Promise.allSettled([ | |
| fetchUserManagementStats(), | |
| fetchAllStudents(), | |
| fetchAllSheikhs(), | |
| fetchAllUsers(), | |
| ]); | |
| const data: Partial<UserManagementData> = {}; | |
| const errors: Record<string, string> = {}; | |
| if (statsResult.status === 'fulfilled') { | |
| data.stats = statsResult.value; | |
| } else { | |
| errors.stats = statsResult.reason?.message ?? 'Failed to load statistics'; | |
| } | |
| if (studentsResult.status === 'fulfilled') { | |
| data.students = studentsResult.value; | |
| } else { | |
| errors.students = studentsResult.reason?.message ?? 'Failed to load students'; | |
| } | |
| if (sheikhsResult.status === 'fulfilled') { | |
| data.sheikhs = sheikhsResult.value; | |
| } else { | |
| errors.sheikhs = sheikhsResult.reason?.message ?? 'Failed to load sheikhs'; | |
| } | |
| if (usersResult.status === 'fulfilled') { | |
| data.users = usersResult.value; | |
| } else { | |
| errors.users = usersResult.reason?.message ?? 'Failed to load users'; | |
| } | |
| return { data, errors }; | |
| } | |
| // βββ Default export βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| const adminUserManagementApi = { | |
| fetchUserManagementStats, | |
| fetchAllStudents, | |
| fetchAllSheikhs, | |
| fetchAllUsers, | |
| blockUser, | |
| unblockUser, | |
| fetchSheikhProfile, | |
| fetchStudentProfile, | |
| fetchUserManagementData, | |
| UserManagementApiError, | |
| }; | |
| export default adminUserManagementApi; |