Refactor monolithic modules and harden booking, email, and auth infrastructure.
Split oversized frontend API client, email service, and admin/booking pages into focused modules while preserving import surfaces, and add Redis-backed queues, stale booking cleanup, stronger auth, and scale deployment configs. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,90 @@
|
||||
import { fetchApi } from './client';
|
||||
import type { EmailTemplate, EmailVariable, EmailLog, EmailStats, Pagination } from './types';
|
||||
|
||||
export const emailsApi = {
|
||||
// Templates
|
||||
getTemplates: () => fetchApi<{ templates: EmailTemplate[] }>('/api/emails/templates'),
|
||||
|
||||
getTemplate: (id: string) => fetchApi<{ template: EmailTemplate }>(`/api/emails/templates/${id}`),
|
||||
|
||||
createTemplate: (data: Partial<EmailTemplate>) =>
|
||||
fetchApi<{ template: EmailTemplate; message: string }>('/api/emails/templates', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify(data),
|
||||
}),
|
||||
|
||||
updateTemplate: (id: string, data: Partial<EmailTemplate>) =>
|
||||
fetchApi<{ template: EmailTemplate; message: string }>(`/api/emails/templates/${id}`, {
|
||||
method: 'PUT',
|
||||
body: JSON.stringify(data),
|
||||
}),
|
||||
|
||||
deleteTemplate: (id: string) =>
|
||||
fetchApi<{ message: string }>(`/api/emails/templates/${id}`, { method: 'DELETE' }),
|
||||
|
||||
getTemplateVariables: (slug: string) =>
|
||||
fetchApi<{ variables: EmailVariable[] }>(`/api/emails/templates/${slug}/variables`),
|
||||
|
||||
// Sending
|
||||
sendToEvent: (eventId: string, data: {
|
||||
templateSlug: string;
|
||||
customVariables?: Record<string, any>;
|
||||
recipientFilter?: 'all' | 'confirmed' | 'pending' | 'checked_in';
|
||||
}) =>
|
||||
fetchApi<{ success: boolean; queuedCount: number; error?: string }>(
|
||||
`/api/emails/send/event/${eventId}`,
|
||||
{
|
||||
method: 'POST',
|
||||
body: JSON.stringify(data),
|
||||
}
|
||||
),
|
||||
|
||||
sendCustom: (data: {
|
||||
to: string;
|
||||
toName?: string;
|
||||
subject: string;
|
||||
bodyHtml: string;
|
||||
bodyText?: string;
|
||||
eventId?: string;
|
||||
}) =>
|
||||
fetchApi<{ success: boolean; logId?: string; error?: string }>('/api/emails/send/custom', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify(data),
|
||||
}),
|
||||
|
||||
preview: (data: {
|
||||
templateSlug: string;
|
||||
variables?: Record<string, any>;
|
||||
locale?: string;
|
||||
}) =>
|
||||
fetchApi<{ subject: string; bodyHtml: string }>('/api/emails/preview', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify(data),
|
||||
}),
|
||||
|
||||
// Logs
|
||||
getLogs: (params?: { eventId?: string; status?: string; search?: string; limit?: number; offset?: number }) => {
|
||||
const query = new URLSearchParams();
|
||||
if (params?.eventId) query.set('eventId', params.eventId);
|
||||
if (params?.status) query.set('status', params.status);
|
||||
if (params?.search) query.set('search', params.search);
|
||||
if (params?.limit) query.set('limit', params.limit.toString());
|
||||
if (params?.offset) query.set('offset', params.offset.toString());
|
||||
return fetchApi<{ logs: EmailLog[]; pagination: Pagination }>(`/api/emails/logs?${query}`);
|
||||
},
|
||||
|
||||
getLog: (id: string) => fetchApi<{ log: EmailLog }>(`/api/emails/logs/${id}`),
|
||||
|
||||
resendLog: (id: string) =>
|
||||
fetchApi<{ success: boolean; error?: string }>(`/api/emails/logs/${id}/resend`, {
|
||||
method: 'POST',
|
||||
}),
|
||||
|
||||
getStats: (eventId?: string) => {
|
||||
const query = eventId ? `?eventId=${eventId}` : '';
|
||||
return fetchApi<{ stats: EmailStats }>(`/api/emails/stats${query}`);
|
||||
},
|
||||
|
||||
seedTemplates: () =>
|
||||
fetchApi<{ message: string }>('/api/emails/seed-templates', { method: 'POST' }),
|
||||
};
|
||||
Reference in New Issue
Block a user