All files / src/services/api newsletterApi.ts

100% Statements 22/22
100% Branches 10/10
100% Functions 5/5
100% Lines 20/20

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69                                        1x   1x       7x       7x 7x   7x 2x   7x       7x     1x 1x     1x     1x 1x     1x     1x 1x       1x 1x     1x    
/**
 * Newsletter API Service (Organizer-only endpoints)
 *
 * Separate from services/newsletterService.ts which handles public/user endpoints.
 *
 * Story 10.28: Newsletter Subscriber Management Page
 */
 
import apiClient from './apiClient';
import type { NewsletterSubscriberFilters } from '@/stores/newsletterSubscriberStore';
import type { components } from '@/types/generated/event-newsletter-api.types';
 
type SubscriberResponse = components['schemas']['SubscriberResponse'];
type PaginationMetadata = components['schemas']['PaginationMetadata'];
 
export interface PagedNewsletterSubscribersResponse {
  data: SubscriberResponse[];
  pagination: PaginationMetadata;
}
 
const NEWSLETTER_API_PATH = '/newsletter';
 
export const listNewsletterSubscribers = async (
  filters: NewsletterSubscriberFilters,
  pagination: { page: number; limit: number }
): Promise<PagedNewsletterSubscribersResponse> => {
  const params: Record<string, string | number> = {
    page: pagination.page,
    limit: pagination.limit,
  };
  if (filters.searchQuery?.trim()) params.search = filters.searchQuery;
  if (filters.status && filters.status !== 'all') params.status = filters.status;
  // ADR-013 ยง3: single `sort` vocabulary (e.g. `-subscribedAt`) instead of sortBy+sortDir.
  if (filters.sortBy)
    params.sort = filters.sortDir === 'asc' ? filters.sortBy : `-${filters.sortBy}`;
 
  const response = await apiClient.get<PagedNewsletterSubscribersResponse>(
    `${NEWSLETTER_API_PATH}/subscribers`,
    { params }
  );
  return response.data;
};
 
export const unsubscribeNewsletterSubscriber = async (id: string): Promise<SubscriberResponse> => {
  const response = await apiClient.post<SubscriberResponse>(
    `${NEWSLETTER_API_PATH}/subscribers/${id}/unsubscribe`
  );
  return response.data;
};
 
export const resubscribeNewsletterSubscriber = async (id: string): Promise<SubscriberResponse> => {
  const response = await apiClient.post<SubscriberResponse>(
    `${NEWSLETTER_API_PATH}/subscribers/${id}/resubscribe`
  );
  return response.data;
};
 
export const deleteNewsletterSubscriber = async (id: string): Promise<void> => {
  await apiClient.delete(`${NEWSLETTER_API_PATH}/subscribers/${id}`);
};
 
/** Story 10.29 AC8: Unsuppress a subscriber (clears bounce state). */
export const unsuppressNewsletterSubscriber = async (id: string): Promise<SubscriberResponse> => {
  const response = await apiClient.post<SubscriberResponse>(
    `${NEWSLETTER_API_PATH}/subscribers/${id}/unsuppress`
  );
  return response.data;
};