108 lines
3.6 KiB
TypeScript
108 lines
3.6 KiB
TypeScript
import { AdminApiClient } from '@/lib/api/admin/AdminApiClient';
|
|
import type { UserDto, DashboardStats, UserListResponse, ListUsersQuery } from '@/lib/api/admin/AdminApiClient';
|
|
import { Result } from '@/lib/contracts/Result';
|
|
import { ConsoleLogger } from '@/lib/infrastructure/logging/ConsoleLogger';
|
|
import { EnhancedErrorReporter } from '@/lib/infrastructure/EnhancedErrorReporter';
|
|
import { DomainError } from '@/lib/contracts/services/Service';
|
|
|
|
/**
|
|
* Admin Service - DTO Only
|
|
*
|
|
* Returns raw API DTOs. No ViewModels or UX logic.
|
|
* All client-side presentation logic must be handled by presenters/templates.
|
|
* @server-safe
|
|
*/
|
|
export class AdminService {
|
|
private apiClient: AdminApiClient;
|
|
|
|
constructor() {
|
|
const baseUrl = process.env.NEXT_PUBLIC_API_BASE_URL || 'http://localhost:3001';
|
|
const logger = new ConsoleLogger();
|
|
const errorReporter = new EnhancedErrorReporter(logger, {
|
|
showUserNotifications: false,
|
|
logToConsole: true,
|
|
reportToExternal: process.env.NODE_ENV === 'production',
|
|
});
|
|
this.apiClient = new AdminApiClient(baseUrl, errorReporter, logger);
|
|
}
|
|
|
|
/**
|
|
* Get dashboard statistics
|
|
*/
|
|
async getDashboardStats(): Promise<Result<DashboardStats, DomainError>> {
|
|
try {
|
|
const result = await this.apiClient.getDashboardStats();
|
|
return Result.ok(result);
|
|
} catch (error) {
|
|
console.error('AdminService.getDashboardStats failed:', error);
|
|
|
|
if (error instanceof Error) {
|
|
if (error.message.includes('403') || error.message.includes('401')) {
|
|
return Result.err({ type: 'notFound', message: 'Access denied' });
|
|
}
|
|
}
|
|
|
|
return Result.err({ type: 'serverError', message: 'Failed to fetch dashboard stats' });
|
|
}
|
|
}
|
|
|
|
/**
|
|
* List users with filtering and pagination
|
|
*/
|
|
async listUsers(query: ListUsersQuery = {}): Promise<Result<UserListResponse, DomainError>> {
|
|
try {
|
|
const result = await this.apiClient.listUsers(query);
|
|
return Result.ok(result);
|
|
} catch (error) {
|
|
console.error('AdminService.listUsers failed:', error);
|
|
|
|
if (error instanceof Error) {
|
|
if (error.message.includes('403') || error.message.includes('401')) {
|
|
return Result.err({ type: 'notFound', message: 'Access denied' });
|
|
}
|
|
}
|
|
|
|
return Result.err({ type: 'serverError', message: 'Failed to fetch users' });
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Update user status
|
|
*/
|
|
async updateUserStatus(userId: string, status: string): Promise<Result<UserDto, DomainError>> {
|
|
try {
|
|
const result = await this.apiClient.updateUserStatus(userId, status);
|
|
return Result.ok(result);
|
|
} catch (error) {
|
|
console.error('AdminService.updateUserStatus failed:', error);
|
|
|
|
if (error instanceof Error) {
|
|
if (error.message.includes('403') || error.message.includes('401')) {
|
|
return Result.err({ type: 'forbidden', message: 'Insufficient permissions' });
|
|
}
|
|
}
|
|
|
|
return Result.err({ type: 'serverError', message: 'Failed to update user status' });
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Delete a user (soft delete)
|
|
*/
|
|
async deleteUser(userId: string): Promise<Result<void, DomainError>> {
|
|
try {
|
|
await this.apiClient.deleteUser(userId);
|
|
return Result.ok(undefined);
|
|
} catch (error) {
|
|
console.error('AdminService.deleteUser failed:', error);
|
|
|
|
if (error instanceof Error) {
|
|
if (error.message.includes('403') || error.message.includes('401')) {
|
|
return Result.err({ type: 'forbidden', message: 'Insufficient permissions' });
|
|
}
|
|
}
|
|
|
|
return Result.err({ type: 'serverError', message: 'Failed to delete user' });
|
|
}
|
|
}
|
|
} |