mirror of
https://github.com/Dvorinka/MyClubServer.git
synced 2026-06-04 10:42:57 +00:00
upload
This commit is contained in:
@@ -0,0 +1,93 @@
|
||||
import { api } from '../api';
|
||||
|
||||
export interface ContactMessage {
|
||||
id: string;
|
||||
name: string;
|
||||
email: string;
|
||||
subject?: string;
|
||||
message: string;
|
||||
source?: string;
|
||||
ipAddress?: string;
|
||||
userAgent?: string;
|
||||
isRead: boolean;
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
}
|
||||
|
||||
export interface ContactMessagesResponse {
|
||||
data: ContactMessage[];
|
||||
total: number;
|
||||
page: number;
|
||||
limit: number;
|
||||
totalPages: number;
|
||||
}
|
||||
|
||||
export const getContactMessages = async (params?: {
|
||||
page?: number;
|
||||
limit?: number;
|
||||
search?: string;
|
||||
isRead?: boolean;
|
||||
sortBy?: string;
|
||||
sortOrder?: 'asc' | 'desc';
|
||||
}): Promise<ContactMessagesResponse> => {
|
||||
// Backend returns { data: ContactMessage[], pagination: { total, page, limit, pages, has_more } }
|
||||
const response = await api.get<{ data: ContactMessage[]; pagination: { total: number; page: number; limit: number; pages: number } }>(
|
||||
'/admin/contact-messages',
|
||||
{ params }
|
||||
);
|
||||
const r = response.data;
|
||||
// Normalize possible snake_case fields coming from backend to camelCase expected by UI
|
||||
const normalized = (r.data as any[]).map((m) => ({
|
||||
id: String(m.id),
|
||||
name: m.name,
|
||||
email: m.email,
|
||||
subject: m.subject,
|
||||
message: m.message,
|
||||
source: m.source,
|
||||
ipAddress: m.ipAddress ?? m.ip_address,
|
||||
userAgent: m.userAgent ?? m.user_agent,
|
||||
isRead: m.isRead ?? m.is_read ?? false,
|
||||
createdAt: m.createdAt ?? m.created_at,
|
||||
updatedAt: m.updatedAt ?? m.updated_at,
|
||||
})) as ContactMessage[];
|
||||
return {
|
||||
data: normalized,
|
||||
total: r.pagination.total,
|
||||
page: r.pagination.page,
|
||||
limit: r.pagination.limit,
|
||||
totalPages: r.pagination.pages,
|
||||
};
|
||||
};
|
||||
|
||||
export const getContactMessage = async (id: string) => {
|
||||
// Backend returns the message object directly
|
||||
const response = await api.get<ContactMessage>(`/admin/contact-messages/${id}`);
|
||||
return response.data;
|
||||
};
|
||||
|
||||
export const markAsRead = async (id: string) => {
|
||||
// Backend returns only a message string; caller doesn't need data
|
||||
await api.patch(
|
||||
`/admin/contact-messages/${id}/read`,
|
||||
{ isRead: true }
|
||||
);
|
||||
};
|
||||
|
||||
export const deleteMessage = async (id: string) => {
|
||||
await api.delete(`/admin/contact-messages/${id}`);
|
||||
};
|
||||
|
||||
export const deleteMultipleMessages = async (ids: Array<string | number>) => {
|
||||
// Backend expects a raw JSON array []int in the body. Convert to numbers.
|
||||
const numericIds = ids.map((v) => (typeof v === 'string' ? Number(v) : v));
|
||||
await api.delete('/admin/contact-messages', { data: numericIds });
|
||||
};
|
||||
|
||||
export const forwardMessage = async (id: string, toEmail: string) => {
|
||||
await api.post(`/admin/contact-messages/${id}/forward`, { to_email: toEmail });
|
||||
};
|
||||
|
||||
export const forwardAllMessages = async (toEmail: string) => {
|
||||
const response = await api.post('/admin/contact-messages/forward-all', { to_email: toEmail });
|
||||
return response.data;
|
||||
};
|
||||
@@ -0,0 +1,165 @@
|
||||
import { api } from '../api';
|
||||
|
||||
export interface NewsletterSubscriber {
|
||||
id: number;
|
||||
email: string;
|
||||
is_active: boolean;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
}
|
||||
|
||||
export interface NewsletterSendData {
|
||||
subject: string;
|
||||
content: string; // backend accepts either 'content' or 'body'
|
||||
}
|
||||
|
||||
export const getNewsletterSubscribers = async (): Promise<NewsletterSubscriber[]> => {
|
||||
const response = await api.get<NewsletterSubscriber[]>(`/admin/newsletter/subscribers`);
|
||||
return response.data;
|
||||
};
|
||||
|
||||
export const sendNewsletter = async (data: NewsletterSendData): Promise<{ message: string }> => {
|
||||
// Backend will accept either 'content' or 'body'. We send 'content'.
|
||||
const response = await api.post<{ message: string }>(
|
||||
`/admin/newsletter/send`,
|
||||
{
|
||||
subject: data.subject,
|
||||
content: data.content,
|
||||
},
|
||||
// Increase timeout to 60s to accommodate SMTP and bulk send delays
|
||||
{ timeout: 60000 }
|
||||
);
|
||||
return response.data;
|
||||
};
|
||||
|
||||
export const sendNewsletterTest = async (email?: string): Promise<{ message: string; recipient: string }> => {
|
||||
const payload = email ? { email } : {};
|
||||
// Allow more time for SMTP connection during test sends
|
||||
const response = await api.post<{ message: string; recipient: string }>(
|
||||
`/admin/newsletter/test`,
|
||||
payload,
|
||||
{ timeout: 60000 }
|
||||
);
|
||||
return response.data;
|
||||
};
|
||||
|
||||
export type NewsletterTestType = 'newsletter' | 'welcome' | 'welcome_back' | 'blogs' | 'events' | 'matches' | 'scores' | 'weekly';
|
||||
export interface NewsletterTestPayload {
|
||||
email?: string;
|
||||
emails?: string[];
|
||||
type?: NewsletterTestType;
|
||||
}
|
||||
|
||||
export type AdminSmtpTestPayload = {
|
||||
host: string;
|
||||
port: number;
|
||||
username?: string;
|
||||
password?: string;
|
||||
from: string;
|
||||
to: string;
|
||||
subject?: string;
|
||||
body?: string;
|
||||
use_tls?: boolean;
|
||||
};
|
||||
|
||||
export const adminSendSmtpTest = async (payload: AdminSmtpTestPayload): Promise<{ ok: boolean; message?: string; error?: string }> => {
|
||||
const res = await api.post('/admin/newsletter/smtp-test', payload, { timeout: 60000 });
|
||||
return res.data;
|
||||
};
|
||||
|
||||
export const sendNewsletterTestAdvanced = async (payload: NewsletterTestPayload): Promise<{ message: string; recipients?: string[]; recipient?: string; type: string }> => {
|
||||
// Allow more time for SMTP connection during test sends
|
||||
const response = await api.post<{ message: string; recipients?: string[]; recipient?: string; type: string }>(
|
||||
`/admin/newsletter/test`,
|
||||
payload,
|
||||
{ timeout: 60000 }
|
||||
);
|
||||
return response.data;
|
||||
};
|
||||
|
||||
export interface NewsletterStatus {
|
||||
total_subscribers: number;
|
||||
active_subscribers: number;
|
||||
sample_recipients: string[];
|
||||
interval_minutes: number;
|
||||
next_approximate: string;
|
||||
newsletter_enabled?: boolean;
|
||||
}
|
||||
|
||||
export const getNewsletterStatus = async (): Promise<NewsletterStatus> => {
|
||||
const response = await api.get<NewsletterStatus>(`/admin/newsletter/status`);
|
||||
return response.data as any;
|
||||
};
|
||||
|
||||
export type DigestType = 'blogs' | 'events' | 'matches' | 'scores' | 'weekly';
|
||||
|
||||
export const sendNewsletterDigest = async (type: DigestType, competitions?: string): Promise<{ message: string; recipients: number; type: string }> => {
|
||||
const response = await api.post(`/admin/newsletter/send-digest`, { type, competitions });
|
||||
return response.data;
|
||||
};
|
||||
|
||||
export const setNewsletterAutomation = async (enabled: boolean): Promise<{ newsletter_enabled: boolean }> => {
|
||||
const response = await api.patch(`/admin/newsletter/enable`, { enabled });
|
||||
return response.data;
|
||||
};
|
||||
|
||||
export interface NewsletterPreviewPayload {
|
||||
preferences?: Record<string, boolean> & { competitions?: string };
|
||||
}
|
||||
export interface NewsletterPreviewResponse {
|
||||
subject: string;
|
||||
html: string;
|
||||
}
|
||||
|
||||
export const previewNewsletter = async (payload: NewsletterPreviewPayload): Promise<NewsletterPreviewResponse> => {
|
||||
const response = await api.post<NewsletterPreviewResponse>(`/admin/newsletter/preview`, payload);
|
||||
return response.data;
|
||||
};
|
||||
|
||||
export interface EmailStatRow {
|
||||
id: number;
|
||||
created_at: string;
|
||||
subject: string;
|
||||
recipient: string;
|
||||
type: string;
|
||||
status: string;
|
||||
opens: number;
|
||||
clicks: number;
|
||||
spam: number;
|
||||
unsubs: number;
|
||||
}
|
||||
|
||||
export const getRecentEmailStats = async (): Promise<EmailStatRow[]> => {
|
||||
const response = await api.get<{ data: EmailStatRow[] }>(`/admin/newsletter/stats/recent`);
|
||||
return response.data?.data || [];
|
||||
};
|
||||
|
||||
export interface EmailEventRow {
|
||||
id: number;
|
||||
created_at: string;
|
||||
email_log_id: number;
|
||||
event_type: string;
|
||||
meta?: Record<string, any>;
|
||||
}
|
||||
|
||||
export const getEmailEventsForLog = async (id: number): Promise<EmailEventRow[]> => {
|
||||
const response = await api.get<{ data: EmailEventRow[] }>(`/admin/newsletter/stats/${id}/events`);
|
||||
return response.data?.data || [];
|
||||
};
|
||||
|
||||
export const deleteSubscriber = async (id: number): Promise<void> => {
|
||||
await api.delete(`/admin/newsletter/subscribers/${id}`);
|
||||
};
|
||||
|
||||
export const toggleSubscriberStatus = async (id: number, isActive: boolean): Promise<NewsletterSubscriber> => {
|
||||
const response = await api.patch<NewsletterSubscriber>(
|
||||
`/admin/newsletter/subscribers/${id}/status`,
|
||||
{ is_active: isActive }
|
||||
);
|
||||
return response.data;
|
||||
};
|
||||
|
||||
export const updateSubscriberPreferences = async (id: number, preferences: Record<string, boolean>) => {
|
||||
const response = await api.patch<NewsletterSubscriber>(`/admin/newsletter/subscribers/${id}/preferences`, preferences);
|
||||
return response.data;
|
||||
};
|
||||
@@ -0,0 +1,18 @@
|
||||
import api from '../../services/api';
|
||||
|
||||
export type PrefetchStatus = {
|
||||
lastUpdated?: string;
|
||||
intervalMinutes: number;
|
||||
fastMode: boolean;
|
||||
nextApproximate: string;
|
||||
};
|
||||
|
||||
export async function getPrefetchStatus(): Promise<PrefetchStatus> {
|
||||
const { data } = await api.get('/admin/prefetch/status');
|
||||
return data as PrefetchStatus;
|
||||
}
|
||||
|
||||
export async function triggerPrefetch(): Promise<{ message: string }>{
|
||||
const { data } = await api.post('/admin/prefetch/trigger');
|
||||
return data as { message: string };
|
||||
}
|
||||
Reference in New Issue
Block a user