299 lines
8.6 KiB
TypeScript
299 lines
8.6 KiB
TypeScript
/**
|
|
* Admin API
|
|
*
|
|
* Dedicated endpoints for admin-only operations that return ALL data from the database
|
|
* without organization filtering.
|
|
*
|
|
* All endpoints require ADMIN role.
|
|
*/
|
|
|
|
import { get, post, patch, del } from './client';
|
|
import type { BlogPost, BlogPostCategory, BlogPostStatus } from './blog';
|
|
import type {
|
|
UserResponse,
|
|
UserListResponse,
|
|
OrganizationResponse,
|
|
OrganizationListResponse,
|
|
BookingResponse,
|
|
BookingListResponse,
|
|
UpdateUserRequest,
|
|
} from '@/types/api';
|
|
|
|
// ==================== USERS ====================
|
|
|
|
/**
|
|
* Get ALL users from database (admin only)
|
|
* GET /api/v1/admin/users
|
|
* Returns all users regardless of status or organization
|
|
* Requires: ADMIN role
|
|
*/
|
|
export async function getAllUsers(): Promise<UserListResponse> {
|
|
return get<UserListResponse>('/api/v1/admin/users');
|
|
}
|
|
|
|
/**
|
|
* Get user by ID (admin only)
|
|
* GET /api/v1/admin/users/:id
|
|
* Requires: ADMIN role
|
|
*/
|
|
export async function getAdminUser(id: string): Promise<UserResponse> {
|
|
return get<UserResponse>(`/api/v1/admin/users/${id}`);
|
|
}
|
|
|
|
/**
|
|
* Update user (admin only)
|
|
* PATCH /api/v1/admin/users/:id
|
|
* Can update any user from any organization
|
|
* Requires: ADMIN role
|
|
*/
|
|
export async function updateAdminUser(id: string, data: UpdateUserRequest): Promise<UserResponse> {
|
|
return patch<UserResponse>(`/api/v1/admin/users/${id}`, data);
|
|
}
|
|
|
|
/**
|
|
* Delete user (admin only)
|
|
* DELETE /api/v1/admin/users/:id
|
|
* Permanently deletes user from database
|
|
* Requires: ADMIN role
|
|
*/
|
|
export async function deleteAdminUser(id: string): Promise<void> {
|
|
return del<void>(`/api/v1/admin/users/${id}`);
|
|
}
|
|
|
|
// ==================== ORGANIZATIONS ====================
|
|
|
|
/**
|
|
* Get ALL organizations from database (admin only)
|
|
* GET /api/v1/admin/organizations
|
|
* Returns all organizations regardless of status
|
|
* Requires: ADMIN role
|
|
*/
|
|
export async function getAllOrganizations(): Promise<OrganizationListResponse> {
|
|
return get<OrganizationListResponse>('/api/v1/admin/organizations');
|
|
}
|
|
|
|
/**
|
|
* Get organization by ID (admin only)
|
|
* GET /api/v1/admin/organizations/:id
|
|
* Requires: ADMIN role
|
|
*/
|
|
export async function getAdminOrganization(id: string): Promise<OrganizationResponse> {
|
|
return get<OrganizationResponse>(`/api/v1/admin/organizations/${id}`);
|
|
}
|
|
|
|
/**
|
|
* Verify SIRET for an organization via Pappers API (admin only)
|
|
* POST /api/v1/admin/organizations/:id/verify-siret
|
|
* Requires: ADMIN role
|
|
*/
|
|
export async function verifySiret(
|
|
organizationId: string
|
|
): Promise<{ verified: boolean; companyName?: string; address?: string; message: string }> {
|
|
return post(`/api/v1/admin/organizations/${organizationId}/verify-siret`, {});
|
|
}
|
|
|
|
/**
|
|
* Manually approve SIRET/SIREN for an organization (admin only)
|
|
* POST /api/v1/admin/organizations/:id/approve-siret
|
|
* Requires: ADMIN role
|
|
*/
|
|
export async function approveSiret(
|
|
organizationId: string
|
|
): Promise<{ approved: boolean; message: string; organizationName: string }> {
|
|
return post(`/api/v1/admin/organizations/${organizationId}/approve-siret`, {});
|
|
}
|
|
|
|
/**
|
|
* Reject SIRET/SIREN for an organization (admin only)
|
|
* POST /api/v1/admin/organizations/:id/reject-siret
|
|
* Requires: ADMIN role
|
|
*/
|
|
export async function rejectSiret(
|
|
organizationId: string
|
|
): Promise<{ rejected: boolean; message: string; organizationName: string }> {
|
|
return post(`/api/v1/admin/organizations/${organizationId}/reject-siret`, {});
|
|
}
|
|
|
|
// ==================== BOOKINGS ====================
|
|
|
|
/**
|
|
* Get ALL bookings from database (admin only)
|
|
* GET /api/v1/admin/bookings
|
|
* Returns all bookings from all organizations
|
|
* Requires: ADMIN role
|
|
*/
|
|
export async function getAllBookings(): Promise<BookingListResponse> {
|
|
return get<BookingListResponse>('/api/v1/admin/bookings');
|
|
}
|
|
|
|
/**
|
|
* Get booking by ID (admin only)
|
|
* GET /api/v1/admin/bookings/:id
|
|
* Requires: ADMIN role
|
|
*/
|
|
export async function getAdminBooking(id: string): Promise<BookingResponse> {
|
|
return get<BookingResponse>(`/api/v1/admin/bookings/${id}`);
|
|
}
|
|
|
|
/**
|
|
* Validate bank transfer for a booking (admin only)
|
|
* POST /api/v1/admin/bookings/:id/validate-transfer
|
|
* Confirms receipt of wire transfer and activates the booking
|
|
* Requires: ADMIN role
|
|
*/
|
|
export async function validateBankTransfer(
|
|
bookingId: string
|
|
): Promise<BookingResponse & { carrierEmailSent?: boolean }> {
|
|
return post<BookingResponse & { carrierEmailSent?: boolean }>(
|
|
`/api/v1/admin/bookings/${bookingId}/validate-transfer`,
|
|
{}
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Resend the booking request email to the carrier (admin only)
|
|
* POST /api/v1/admin/bookings/:id/resend-carrier-email
|
|
* Useful when the email failed at transfer validation.
|
|
* Requires: ADMIN role
|
|
*/
|
|
export async function resendCarrierEmail(bookingId: string): Promise<void> {
|
|
return post<void>(`/api/v1/admin/bookings/${bookingId}/resend-carrier-email`, {});
|
|
}
|
|
|
|
/**
|
|
* Delete a booking (admin only)
|
|
* DELETE /api/v1/admin/bookings/:id
|
|
* Permanently deletes a booking from the database
|
|
* Requires: ADMIN role
|
|
*/
|
|
export async function deleteAdminBooking(bookingId: string): Promise<void> {
|
|
return del<void>(`/api/v1/admin/bookings/${bookingId}`);
|
|
}
|
|
|
|
/**
|
|
* Delete a document from a booking (admin only)
|
|
* DELETE /api/v1/admin/bookings/:bookingId/documents/:documentId
|
|
* Bypasses ownership and status restrictions
|
|
* Requires: ADMIN role
|
|
*/
|
|
export async function deleteAdminDocument(bookingId: string, documentId: string): Promise<void> {
|
|
return del<void>(`/api/v1/admin/bookings/${bookingId}/documents/${documentId}`);
|
|
}
|
|
|
|
// ==================== DOCUMENTS ====================
|
|
|
|
/**
|
|
* Get ALL documents from all organizations (admin only)
|
|
* GET /api/v1/admin/documents
|
|
* Returns documents grouped by organization
|
|
* Requires: ADMIN role
|
|
*/
|
|
export async function getAllDocuments(): Promise<{
|
|
documents: any[];
|
|
total: number;
|
|
organizationCount: number;
|
|
}> {
|
|
return get('/api/v1/admin/documents');
|
|
}
|
|
|
|
/**
|
|
* Get documents for a specific organization (admin only)
|
|
* GET /api/v1/admin/organizations/:id/documents
|
|
* Requires: ADMIN role
|
|
*/
|
|
export async function getOrganizationDocuments(organizationId: string): Promise<{
|
|
organizationId: string;
|
|
organizationName: string;
|
|
documents: any[];
|
|
total: number;
|
|
}> {
|
|
return get(`/api/v1/admin/organizations/${organizationId}/documents`);
|
|
}
|
|
|
|
// ==================== BLOG ====================
|
|
|
|
export interface BlogFaqItem {
|
|
question: string;
|
|
answer: string;
|
|
}
|
|
|
|
export interface BlogPostSeoFields {
|
|
metaTitle?: string;
|
|
metaDescription?: string;
|
|
primaryKeyword?: string;
|
|
secondaryKeywords?: string[];
|
|
scheduledAt?: string;
|
|
// GEO (Generative Engine Optimisation)
|
|
aiSummary?: string | null;
|
|
faq?: BlogFaqItem[];
|
|
keyTakeaways?: string[];
|
|
aiEntities?: string[];
|
|
}
|
|
|
|
export interface CreateBlogPostRequest extends BlogPostSeoFields {
|
|
title: string;
|
|
slug: string;
|
|
excerpt: string;
|
|
content: string;
|
|
coverImageUrl?: string | null;
|
|
category: BlogPostCategory;
|
|
tags?: string[];
|
|
authorName: string;
|
|
}
|
|
|
|
export interface UpdateBlogPostRequest extends BlogPostSeoFields {
|
|
title?: string;
|
|
slug?: string;
|
|
excerpt?: string;
|
|
content?: string;
|
|
coverImageUrl?: string | null;
|
|
category?: BlogPostCategory;
|
|
tags?: string[];
|
|
authorName?: string;
|
|
status?: BlogPostStatus;
|
|
isFeatured?: boolean;
|
|
}
|
|
|
|
export async function getAllBlogPosts(params?: {
|
|
status?: BlogPostStatus;
|
|
category?: BlogPostCategory;
|
|
search?: string;
|
|
trashed?: boolean;
|
|
}): Promise<{ posts: BlogPost[]; total: number }> {
|
|
const query = new URLSearchParams();
|
|
if (params?.status) query.set('status', params.status);
|
|
if (params?.category) query.set('category', params.category);
|
|
if (params?.search) query.set('search', params.search);
|
|
if (params?.trashed) query.set('trashed', 'true');
|
|
const qs = query.toString();
|
|
return get(`/api/v1/admin/blog${qs ? `?${qs}` : ''}`);
|
|
}
|
|
|
|
export async function createBlogPost(data: CreateBlogPostRequest): Promise<BlogPost> {
|
|
return post<BlogPost>('/api/v1/admin/blog', data);
|
|
}
|
|
|
|
export async function updateBlogPost(id: string, data: UpdateBlogPostRequest): Promise<BlogPost> {
|
|
return patch<BlogPost>(`/api/v1/admin/blog/${id}`, data);
|
|
}
|
|
|
|
/** Move a post to the trash (soft delete). */
|
|
export async function deleteBlogPost(id: string): Promise<void> {
|
|
return del<void>(`/api/v1/admin/blog/${id}`);
|
|
}
|
|
|
|
/** Restore a post from the trash. */
|
|
export async function restoreBlogPost(id: string): Promise<BlogPost> {
|
|
return post<BlogPost>(`/api/v1/admin/blog/${id}/restore`, {});
|
|
}
|
|
|
|
/** Permanently delete a post from the trash. */
|
|
export async function permanentlyDeleteBlogPost(id: string): Promise<void> {
|
|
return del<void>(`/api/v1/admin/blog/${id}/permanent`);
|
|
}
|
|
|
|
/** Duplicate a post as a new draft. */
|
|
export async function duplicateBlogPost(id: string): Promise<BlogPost> {
|
|
return post<BlogPost>(`/api/v1/admin/blog/${id}/duplicate`, {});
|
|
}
|