mirror of
https://github.com/pacnpal/thrilltrack-explorer.git
synced 2025-12-23 18:31:12 -05:00
Refactor code structure and remove redundant changes
This commit is contained in:
305
src-old/services/reports/reportsService.ts
Normal file
305
src-old/services/reports/reportsService.ts
Normal file
@@ -0,0 +1,305 @@
|
||||
/**
|
||||
* Reports Service - API client for Django Reports System
|
||||
* Provides abstraction layer between frontend and Django backend
|
||||
*/
|
||||
|
||||
import { supabase } from '@/integrations/supabase/client';
|
||||
import { handleError } from '@/lib/errorHandler';
|
||||
import { logger } from '@/lib/logger';
|
||||
import type {
|
||||
Report,
|
||||
SubmitReportData,
|
||||
LegacySubmitReportData,
|
||||
ReportFilters,
|
||||
PaginatedReports,
|
||||
ReportStats,
|
||||
UpdateReportStatusData,
|
||||
ServiceResponse,
|
||||
} from './types';
|
||||
import { mapSubmitReportToBackend } from './mappers';
|
||||
|
||||
/**
|
||||
* Reports Service Class
|
||||
* Handles all communication with Django Reports API endpoints
|
||||
*/
|
||||
class ReportsService {
|
||||
private baseUrl: string;
|
||||
|
||||
constructor() {
|
||||
// Use environment variable or fallback to relative path
|
||||
this.baseUrl = import.meta.env.VITE_DJANGO_API_URL || '/api/v1';
|
||||
logger.log('[ReportsService] Initialized with base URL:', this.baseUrl);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get authentication token from current Supabase session
|
||||
* @returns JWT token for Django API authentication
|
||||
* @throws Error if no active session
|
||||
*/
|
||||
private async getAuthToken(): Promise<string> {
|
||||
const { data: { session }, error } = await supabase.auth.getSession();
|
||||
|
||||
if (error) {
|
||||
logger.error('[ReportsService] Failed to get session', { error });
|
||||
throw new Error('Failed to retrieve authentication session');
|
||||
}
|
||||
|
||||
if (!session?.access_token) {
|
||||
logger.error('[ReportsService] No active session');
|
||||
throw new Error('Authentication required. Please sign in.');
|
||||
}
|
||||
|
||||
return session.access_token;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make authenticated request to Django API
|
||||
* @param endpoint - API endpoint path (e.g., '/reports/')
|
||||
* @param options - Fetch options
|
||||
* @returns Parsed JSON response
|
||||
* @throws Error with details from Django API
|
||||
*/
|
||||
private async request<T>(
|
||||
endpoint: string,
|
||||
options: RequestInit = {}
|
||||
): Promise<T> {
|
||||
const token = await this.getAuthToken();
|
||||
const url = `${this.baseUrl}${endpoint}`;
|
||||
|
||||
logger.log('[ReportsService] Making request', {
|
||||
method: options.method || 'GET',
|
||||
url,
|
||||
hasBody: !!options.body
|
||||
});
|
||||
|
||||
const response = await fetch(url, {
|
||||
...options,
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': `Bearer ${token}`,
|
||||
...options.headers,
|
||||
},
|
||||
});
|
||||
|
||||
// Handle non-JSON responses (e.g., 204 No Content)
|
||||
if (response.status === 204) {
|
||||
return undefined as T;
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
if (!response.ok) {
|
||||
// Django returns errors in { detail: "message" } format
|
||||
const errorMessage = data.detail || data.message || 'Request failed';
|
||||
logger.error('[ReportsService] Request failed', {
|
||||
status: response.status,
|
||||
error: errorMessage,
|
||||
url,
|
||||
});
|
||||
throw new Error(errorMessage);
|
||||
}
|
||||
|
||||
logger.log('[ReportsService] Request successful', {
|
||||
status: response.status,
|
||||
url
|
||||
});
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Submit a new report
|
||||
* @param data - Report submission data (supports legacy Supabase format)
|
||||
* @returns Created report
|
||||
*/
|
||||
async submitReport(
|
||||
data: SubmitReportData | LegacySubmitReportData
|
||||
): Promise<ServiceResponse<Report>> {
|
||||
try {
|
||||
// Handle both new format and legacy Supabase format
|
||||
const payload = 'reported_entity_type' in data
|
||||
? mapSubmitReportToBackend(data)
|
||||
: data;
|
||||
|
||||
const report = await this.request<Report>('/reports/', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify(payload),
|
||||
});
|
||||
|
||||
return { success: true, data: report };
|
||||
} catch (error) {
|
||||
const errorId = handleError(error, {
|
||||
action: 'Submit report',
|
||||
metadata: {
|
||||
entityType: 'entity_type' in data ? data.entity_type : data.reported_entity_type,
|
||||
reportType: data.report_type,
|
||||
},
|
||||
});
|
||||
|
||||
return {
|
||||
success: false,
|
||||
error: error instanceof Error ? error.message : 'Failed to submit report',
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* List reports with optional filters and pagination
|
||||
* @param filters - Optional filters (status, type, entity)
|
||||
* @param page - Page number (1-indexed)
|
||||
* @param pageSize - Number of items per page
|
||||
* @returns Paginated list of reports
|
||||
*/
|
||||
async listReports(
|
||||
filters: ReportFilters = {},
|
||||
page: number = 1,
|
||||
pageSize: number = 50
|
||||
): Promise<ServiceResponse<PaginatedReports>> {
|
||||
try {
|
||||
const params = new URLSearchParams({
|
||||
page: page.toString(),
|
||||
page_size: pageSize.toString(),
|
||||
});
|
||||
|
||||
// Add optional filters
|
||||
if (filters.status) params.append('status', filters.status);
|
||||
if (filters.report_type) params.append('report_type', filters.report_type);
|
||||
if (filters.entity_type) params.append('entity_type', filters.entity_type);
|
||||
if (filters.entity_id) params.append('entity_id', filters.entity_id);
|
||||
|
||||
const data = await this.request<PaginatedReports>(
|
||||
`/reports/?${params.toString()}`
|
||||
);
|
||||
|
||||
return { success: true, data };
|
||||
} catch (error) {
|
||||
const errorId = handleError(error, {
|
||||
action: 'List reports',
|
||||
metadata: { filters, page, pageSize },
|
||||
});
|
||||
|
||||
return {
|
||||
success: false,
|
||||
error: error instanceof Error ? error.message : 'Failed to list reports',
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a single report by ID
|
||||
* @param id - Report UUID
|
||||
* @returns Report details
|
||||
*/
|
||||
async getReport(id: string): Promise<ServiceResponse<Report>> {
|
||||
try {
|
||||
const report = await this.request<Report>(`/reports/${id}/`);
|
||||
return { success: true, data: report };
|
||||
} catch (error) {
|
||||
const errorId = handleError(error, {
|
||||
action: 'Get report',
|
||||
metadata: { reportId: id },
|
||||
});
|
||||
|
||||
return {
|
||||
success: false,
|
||||
error: error instanceof Error ? error.message : 'Failed to get report',
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update report status (moderators only)
|
||||
* @param id - Report UUID
|
||||
* @param status - New status
|
||||
* @param resolutionNotes - Optional resolution notes
|
||||
* @returns Updated report
|
||||
*/
|
||||
async updateReportStatus(
|
||||
id: string,
|
||||
status: string,
|
||||
resolutionNotes?: string
|
||||
): Promise<ServiceResponse<Report>> {
|
||||
try {
|
||||
const payload: UpdateReportStatusData = {
|
||||
status: status as any,
|
||||
resolution_notes: resolutionNotes,
|
||||
};
|
||||
|
||||
const report = await this.request<Report>(`/reports/${id}/`, {
|
||||
method: 'PATCH',
|
||||
body: JSON.stringify(payload),
|
||||
});
|
||||
|
||||
return { success: true, data: report };
|
||||
} catch (error) {
|
||||
const errorId = handleError(error, {
|
||||
action: 'Update report status',
|
||||
metadata: { reportId: id, newStatus: status },
|
||||
});
|
||||
|
||||
return {
|
||||
success: false,
|
||||
error: error instanceof Error ? error.message : 'Failed to update report',
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a report (moderators only)
|
||||
* @param id - Report UUID
|
||||
* @returns Success status
|
||||
*/
|
||||
async deleteReport(id: string): Promise<ServiceResponse<void>> {
|
||||
try {
|
||||
await this.request<void>(`/reports/${id}/`, {
|
||||
method: 'DELETE',
|
||||
});
|
||||
|
||||
return { success: true };
|
||||
} catch (error) {
|
||||
const errorId = handleError(error, {
|
||||
action: 'Delete report',
|
||||
metadata: { reportId: id },
|
||||
});
|
||||
|
||||
return {
|
||||
success: false,
|
||||
error: error instanceof Error ? error.message : 'Failed to delete report',
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get report statistics (moderators only)
|
||||
* @returns Report statistics
|
||||
*/
|
||||
async getStatistics(): Promise<ServiceResponse<ReportStats>> {
|
||||
try {
|
||||
const stats = await this.request<ReportStats>('/reports/stats/');
|
||||
return { success: true, data: stats };
|
||||
} catch (error) {
|
||||
const errorId = handleError(error, {
|
||||
action: 'Get report statistics',
|
||||
});
|
||||
|
||||
return {
|
||||
success: false,
|
||||
error: error instanceof Error ? error.message : 'Failed to get statistics',
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get base URL for debugging/testing
|
||||
* @returns Current base URL
|
||||
*/
|
||||
getBaseUrl(): string {
|
||||
return this.baseUrl;
|
||||
}
|
||||
}
|
||||
|
||||
// Export singleton instance
|
||||
export const reportsService = new ReportsService();
|
||||
|
||||
// Export class for testing
|
||||
export { ReportsService };
|
||||
Reference in New Issue
Block a user