Quran_Tech_Server / F_Pro /src /lib /api /adminUserManagementApi.ts
aboalaa147's picture
Initial deployment
eb6a2f9
Raw
History Blame Contribute Delete
9.76 kB
// ─────────────────────────────────────────────────────────────────────────────
// 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;