All files / src/services speakerOutreachService.ts

100% Statements 8/8
100% Branches 0/0
100% Functions 4/4
100% Lines 8/8

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 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91                                        1x                                           10x         7x                       3x       2x                               2x 4x           1x        
/**
 * Speaker Outreach Service (Story 5.3)
 *
 * HTTP client for Speaker Outreach Tracking APIs
 * Features:
 * - Record speaker outreach attempt (POST /api/v1/events/{eventCode}/speakers/{speakerId}/outreach)
 * - Get speaker outreach history (GET /api/v1/events/{eventCode}/speakers/{speakerId}/outreach)
 * - Bulk record outreach for multiple speakers
 * - JWT authentication via interceptors
 * - Error handling with correlation IDs
 */
 
import apiClient from '@/services/api/apiClient';
import type {
  OutreachHistory,
  RecordOutreachRequest,
  OutreachHistoryResponse,
} from '@/types/speakerOutreach.types';
 
// API base path
const EVENTS_API_PATH = '/events';
 
/**
 * Speaker Outreach Service
 *
 * Handles all HTTP requests for speaker outreach tracking
 */
class SpeakerOutreachService {
  /**
   * Record speaker outreach attempt (AC2-3)
   *
   * @param eventCode Event code (e.g., "BATbern56")
   * @param speakerId Speaker UUID
   * @param request Outreach data (contact method, date, notes)
   * @returns Created outreach history entry
   * @throws Error if speaker not found, invalid state, or unauthorized
   */
  async recordOutreach(
    eventCode: string,
    speakerId: string,
    request: RecordOutreachRequest
  ): Promise<OutreachHistoryResponse> {
    const response = await apiClient.post<OutreachHistoryResponse>(
      `${EVENTS_API_PATH}/${eventCode}/speakers/${speakerId}/outreach`,
      request
    );
 
    return response.data;
  }
 
  /**
   * Get speaker outreach history (AC4)
   *
   * @param eventCode Event code (e.g., "BATbern56")
   * @param speakerId Speaker UUID
   * @returns Chronological list of outreach attempts (most recent first)
   * @throws Error if speaker not found or unauthorized
   */
  async getOutreachHistory(eventCode: string, speakerId: string): Promise<OutreachHistory[]> {
    const response = await apiClient.get<OutreachHistory[]>(
      `${EVENTS_API_PATH}/${eventCode}/speakers/${speakerId}/outreach`
    );
 
    return response.data;
  }
 
  /**
   * Bulk record outreach for multiple speakers (AC6)
   *
   * @param eventCode Event code (e.g., "BATbern56")
   * @param speakerIds Array of speaker UUIDs
   * @param request Outreach data (same contact method/date/notes for all)
   * @throws Error if any speaker not found or in invalid state
   */
  async bulkRecordOutreach(
    eventCode: string,
    speakerIds: string[],
    request: RecordOutreachRequest
  ): Promise<void> {
    await Promise.all(
      speakerIds.map((speakerId) => this.recordOutreach(eventCode, speakerId, request))
    );
  }
}
 
// Export singleton instance
export const speakerOutreachService = new SpeakerOutreachService();
 
// Export class for testing
export default SpeakerOutreachService;