Files
motovaultpro/frontend/src/features/admin/api/admin.api.ts
Eric Gullickson 9043a581b1
All checks were successful
Deploy to Staging / Build Images (push) Successful in 4m31s
Deploy to Staging / Deploy to Staging (push) Successful in 37s
Deploy to Staging / Verify Staging (push) Successful in 6s
Deploy to Staging / Notify Staging Ready (push) Successful in 6s
Deploy to Staging / Notify Staging Failure (push) Has been skipped
feat: backup improvements
2026-01-01 13:57:36 -06:00

471 lines
15 KiB
TypeScript

/**
* @ai-summary API client functions for admin feature
* @ai-context Communicates with backend admin endpoints
*/
import { apiClient } from '../../../core/api/client';
import {
AdminAccessResponse,
AdminUser,
CreateAdminRequest,
AdminAuditLog,
CatalogMake,
CatalogModel,
CatalogYear,
CatalogTrim,
CatalogEngine,
CreateCatalogMakeRequest,
UpdateCatalogMakeRequest,
CreateCatalogModelRequest,
UpdateCatalogModelRequest,
CreateCatalogYearRequest,
UpdateCatalogYearRequest,
CreateCatalogTrimRequest,
UpdateCatalogTrimRequest,
CreateCatalogEngineRequest,
UpdateCatalogEngineRequest,
CatalogSearchResponse,
ImportPreviewResult,
ImportApplyResult,
CascadeDeleteResult,
EmailTemplate,
UpdateEmailTemplateRequest,
PreviewTemplateResponse,
// User management types
ManagedUser,
ListUsersResponse,
ListUsersParams,
UpdateUserTierRequest,
DeactivateUserRequest,
UpdateUserProfileRequest,
PromoteToAdminRequest,
// Backup types
BackupHistory,
BackupSchedule,
BackupSettings,
ListBackupsResponse,
CreateBackupRequest,
CreateScheduleRequest,
UpdateScheduleRequest,
RestorePreviewResponse,
ExecuteRestoreRequest,
} from '../types/admin.types';
export interface AuditLogsResponse {
logs: AdminAuditLog[];
total: number;
}
// Admin access verification
export const adminApi = {
// Verify admin access
verifyAccess: async (): Promise<AdminAccessResponse> => {
const response = await apiClient.get<AdminAccessResponse>('/admin/verify');
return response.data;
},
// Admin management
listAdmins: async (): Promise<AdminUser[]> => {
const response = await apiClient.get<AdminUser[]>('/admin/admins');
return response.data;
},
createAdmin: async (data: CreateAdminRequest): Promise<AdminUser> => {
const response = await apiClient.post<AdminUser>('/admin/admins', data);
return response.data;
},
revokeAdmin: async (auth0Sub: string): Promise<void> => {
await apiClient.patch(`/admin/admins/${auth0Sub}/revoke`);
},
reinstateAdmin: async (auth0Sub: string): Promise<void> => {
await apiClient.patch(`/admin/admins/${auth0Sub}/reinstate`);
},
// Audit logs
listAuditLogs: async (): Promise<AuditLogsResponse> => {
const response = await apiClient.get<AuditLogsResponse>('/admin/audit-logs');
return response.data;
},
// Catalog - Makes
listMakes: async (): Promise<CatalogMake[]> => {
const response = await apiClient.get<{ makes: CatalogMake[] }>('/admin/catalog/makes');
return response.data.makes;
},
createMake: async (data: CreateCatalogMakeRequest): Promise<CatalogMake> => {
const response = await apiClient.post<CatalogMake>('/admin/catalog/makes', data);
return response.data;
},
updateMake: async (id: string, data: UpdateCatalogMakeRequest): Promise<CatalogMake> => {
const response = await apiClient.put<CatalogMake>(`/admin/catalog/makes/${id}`, data);
return response.data;
},
deleteMake: async (id: string): Promise<void> => {
await apiClient.delete(`/admin/catalog/makes/${id}`);
},
// Catalog - Models
listModels: async (makeId: string): Promise<CatalogModel[]> => {
const response = await apiClient.get<{ models: CatalogModel[] }>(
`/admin/catalog/makes/${makeId}/models`
);
return response.data.models;
},
createModel: async (data: CreateCatalogModelRequest): Promise<CatalogModel> => {
const response = await apiClient.post<CatalogModel>('/admin/catalog/models', data);
return response.data;
},
updateModel: async (id: string, data: UpdateCatalogModelRequest): Promise<CatalogModel> => {
const response = await apiClient.put<CatalogModel>(`/admin/catalog/models/${id}`, data);
return response.data;
},
deleteModel: async (id: string): Promise<void> => {
await apiClient.delete(`/admin/catalog/models/${id}`);
},
// Catalog - Years
listYears: async (modelId: string): Promise<CatalogYear[]> => {
const response = await apiClient.get<{ years: CatalogYear[] }>(
`/admin/catalog/models/${modelId}/years`
);
return response.data.years;
},
createYear: async (data: CreateCatalogYearRequest): Promise<CatalogYear> => {
const response = await apiClient.post<CatalogYear>('/admin/catalog/years', data);
return response.data;
},
updateYear: async (id: string, data: UpdateCatalogYearRequest): Promise<CatalogYear> => {
const response = await apiClient.put<CatalogYear>(`/admin/catalog/years/${id}`, data);
return response.data;
},
deleteYear: async (id: string): Promise<void> => {
await apiClient.delete(`/admin/catalog/years/${id}`);
},
// Catalog - Trims
listTrims: async (yearId: string): Promise<CatalogTrim[]> => {
const response = await apiClient.get<{ trims: CatalogTrim[] }>(
`/admin/catalog/years/${yearId}/trims`
);
return response.data.trims;
},
createTrim: async (data: CreateCatalogTrimRequest): Promise<CatalogTrim> => {
const response = await apiClient.post<CatalogTrim>('/admin/catalog/trims', data);
return response.data;
},
updateTrim: async (id: string, data: UpdateCatalogTrimRequest): Promise<CatalogTrim> => {
const response = await apiClient.put<CatalogTrim>(`/admin/catalog/trims/${id}`, data);
return response.data;
},
deleteTrim: async (id: string): Promise<void> => {
await apiClient.delete(`/admin/catalog/trims/${id}`);
},
// Catalog - Engines
listEngines: async (trimId: string): Promise<CatalogEngine[]> => {
const response = await apiClient.get<{ engines: CatalogEngine[] }>(
`/admin/catalog/trims/${trimId}/engines`
);
return response.data.engines;
},
createEngine: async (data: CreateCatalogEngineRequest): Promise<CatalogEngine> => {
const response = await apiClient.post<CatalogEngine>('/admin/catalog/engines', data);
return response.data;
},
updateEngine: async (id: string, data: UpdateCatalogEngineRequest): Promise<CatalogEngine> => {
const response = await apiClient.put<CatalogEngine>(`/admin/catalog/engines/${id}`, data);
return response.data;
},
deleteEngine: async (id: string): Promise<void> => {
await apiClient.delete(`/admin/catalog/engines/${id}`);
},
// Catalog Search
searchCatalog: async (
query: string,
page: number = 1,
pageSize: number = 50
): Promise<CatalogSearchResponse> => {
const response = await apiClient.get<CatalogSearchResponse>('/admin/catalog/search', {
params: { q: query, page, pageSize },
});
return response.data;
},
// Catalog Import/Export
importPreview: async (file: File): Promise<ImportPreviewResult> => {
const formData = new FormData();
formData.append('file', file);
const response = await apiClient.post<ImportPreviewResult>(
'/admin/catalog/import/preview',
formData,
{
headers: { 'Content-Type': 'multipart/form-data' },
}
);
return response.data;
},
importApply: async (previewId: string): Promise<ImportApplyResult> => {
const response = await apiClient.post<ImportApplyResult>('/admin/catalog/import/apply', {
previewId,
});
return response.data;
},
exportCatalog: async (): Promise<Blob> => {
const response = await apiClient.get('/admin/catalog/export', {
responseType: 'blob',
});
return response.data;
},
// Cascade Delete
deleteMakeCascade: async (id: string): Promise<CascadeDeleteResult> => {
const response = await apiClient.delete<CascadeDeleteResult>(
`/admin/catalog/makes/${id}/cascade`
);
return response.data;
},
deleteModelCascade: async (id: string): Promise<CascadeDeleteResult> => {
const response = await apiClient.delete<CascadeDeleteResult>(
`/admin/catalog/models/${id}/cascade`
);
return response.data;
},
deleteYearCascade: async (id: string): Promise<CascadeDeleteResult> => {
const response = await apiClient.delete<CascadeDeleteResult>(
`/admin/catalog/years/${id}/cascade`
);
return response.data;
},
deleteTrimCascade: async (id: string): Promise<CascadeDeleteResult> => {
const response = await apiClient.delete<CascadeDeleteResult>(
`/admin/catalog/trims/${id}/cascade`
);
return response.data;
},
// Email Templates
emailTemplates: {
list: async (): Promise<EmailTemplate[]> => {
const response = await apiClient.get<EmailTemplate[]>('/admin/email-templates');
return response.data;
},
get: async (key: string): Promise<EmailTemplate> => {
const response = await apiClient.get<EmailTemplate>(`/admin/email-templates/${key}`);
return response.data;
},
update: async (key: string, data: UpdateEmailTemplateRequest): Promise<EmailTemplate> => {
const response = await apiClient.put<EmailTemplate>(`/admin/email-templates/${key}`, data);
return response.data;
},
preview: async (key: string, variables: Record<string, string>): Promise<PreviewTemplateResponse> => {
const response = await apiClient.post<PreviewTemplateResponse>(
`/admin/email-templates/${key}/preview`,
{ variables }
);
return response.data;
},
sendTest: async (key: string): Promise<{ message?: string; error?: string }> => {
const response = await apiClient.post<{ message?: string; error?: string }>(
`/admin/email-templates/${key}/test`
);
return response.data;
},
},
// User Management
users: {
list: async (params: ListUsersParams = {}): Promise<ListUsersResponse> => {
const response = await apiClient.get<ListUsersResponse>('/admin/users', { params });
return response.data;
},
get: async (auth0Sub: string): Promise<ManagedUser> => {
const response = await apiClient.get<ManagedUser>(
`/admin/users/${encodeURIComponent(auth0Sub)}`
);
return response.data;
},
updateTier: async (auth0Sub: string, data: UpdateUserTierRequest): Promise<ManagedUser> => {
const response = await apiClient.patch<ManagedUser>(
`/admin/users/${encodeURIComponent(auth0Sub)}/tier`,
data
);
return response.data;
},
deactivate: async (auth0Sub: string, data?: DeactivateUserRequest): Promise<ManagedUser> => {
const response = await apiClient.patch<ManagedUser>(
`/admin/users/${encodeURIComponent(auth0Sub)}/deactivate`,
data || {}
);
return response.data;
},
reactivate: async (auth0Sub: string): Promise<ManagedUser> => {
const response = await apiClient.patch<ManagedUser>(
`/admin/users/${encodeURIComponent(auth0Sub)}/reactivate`
);
return response.data;
},
updateProfile: async (auth0Sub: string, data: UpdateUserProfileRequest): Promise<ManagedUser> => {
const response = await apiClient.patch<ManagedUser>(
`/admin/users/${encodeURIComponent(auth0Sub)}/profile`,
data
);
return response.data;
},
promoteToAdmin: async (auth0Sub: string, data?: PromoteToAdminRequest): Promise<AdminUser> => {
const response = await apiClient.patch<AdminUser>(
`/admin/users/${encodeURIComponent(auth0Sub)}/promote`,
data || {}
);
return response.data;
},
hardDelete: async (auth0Sub: string, reason?: string): Promise<{ message: string }> => {
const response = await apiClient.delete<{ message: string }>(
`/admin/users/${encodeURIComponent(auth0Sub)}`,
{ params: reason ? { reason } : undefined }
);
return response.data;
},
},
// Backup & Restore
backups: {
// List backups with pagination
list: async (params: { page?: number; pageSize?: number } = {}): Promise<ListBackupsResponse> => {
const response = await apiClient.get<ListBackupsResponse>('/admin/backups', { params });
return response.data;
},
// Get backup details
get: async (id: string): Promise<BackupHistory> => {
const response = await apiClient.get<BackupHistory>(`/admin/backups/${id}`);
return response.data;
},
// Create manual backup
create: async (data: CreateBackupRequest = {}): Promise<BackupHistory> => {
const response = await apiClient.post<BackupHistory>('/admin/backups', data);
return response.data;
},
// Download backup file
download: async (id: string): Promise<Blob> => {
const response = await apiClient.get(`/admin/backups/${id}/download`, {
responseType: 'blob',
});
return response.data;
},
// Delete backup
delete: async (id: string): Promise<void> => {
await apiClient.delete(`/admin/backups/${id}`);
},
// Upload backup file
upload: async (file: File): Promise<BackupHistory> => {
const formData = new FormData();
formData.append('file', file);
const response = await apiClient.post<BackupHistory>('/admin/backups/upload', formData, {
headers: { 'Content-Type': 'multipart/form-data' },
});
return response.data;
},
// Preview restore
previewRestore: async (id: string): Promise<RestorePreviewResponse> => {
const response = await apiClient.post<RestorePreviewResponse>(
`/admin/backups/${id}/restore/preview`
);
return response.data;
},
// Execute restore
restore: async (id: string, options?: ExecuteRestoreRequest): Promise<{ message: string }> => {
const response = await apiClient.post<{ message: string }>(
`/admin/backups/${id}/restore`,
options
);
return response.data;
},
// Schedules
schedules: {
list: async (): Promise<BackupSchedule[]> => {
const response = await apiClient.get<BackupSchedule[]>('/admin/backups/schedules');
return response.data;
},
get: async (id: string): Promise<BackupSchedule> => {
const response = await apiClient.get<BackupSchedule>(`/admin/backups/schedules/${id}`);
return response.data;
},
create: async (data: CreateScheduleRequest): Promise<BackupSchedule> => {
const response = await apiClient.post<BackupSchedule>('/admin/backups/schedules', data);
return response.data;
},
update: async (id: string, data: UpdateScheduleRequest): Promise<BackupSchedule> => {
const response = await apiClient.put<BackupSchedule>(
`/admin/backups/schedules/${id}`,
data
);
return response.data;
},
delete: async (id: string): Promise<void> => {
await apiClient.delete(`/admin/backups/schedules/${id}`);
},
toggle: async (id: string): Promise<BackupSchedule> => {
const response = await apiClient.patch<BackupSchedule>(
`/admin/backups/schedules/${id}/toggle`
);
return response.data;
},
},
// Settings
settings: {
get: async (): Promise<BackupSettings> => {
const response = await apiClient.get<BackupSettings>('/admin/backups/settings');
return response.data;
},
update: async (data: Partial<BackupSettings>): Promise<BackupSettings> => {
const response = await apiClient.put<BackupSettings>('/admin/backups/settings', data);
return response.data;
},
},
},
};