All files / src/services/api partnerTopicsApi.ts

90.47% Statements 19/21
100% Branches 0/0
87.5% Functions 7/8
90.47% Lines 19/21

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 92 93 94 95 96 97 98 99                                                                                          9x 3x 2x       9x 3x 2x               9x           9x 3x       9x 3x       9x       2x 1x       9x 3x       9x       3x 2x    
/**
 * Partner Topics API Client
 * Story 8.2: Topic Suggestions & Voting — AC1–6
 *
 * All endpoints served by partner-coordination-service via API Gateway.
 * CRITICAL: Path is relative to baseURL (which already includes /api/v1).
 */
 
import apiClient from '@/services/api/apiClient';
 
// ─── Types ───────────────────────────────────────────────────────────────────
 
export interface TopicDTO {
  id: string;
  title: string;
  description?: string | null;
  /** Null for COMMUNITY (attendee) suggestions — Story 7.1. */
  suggestedByCompany?: string | null;
  voteCount: number;
  currentPartnerHasVoted: boolean;
  status: 'PROPOSED' | 'SELECTED' | 'DECLINED';
  plannedEvent?: string | null;
  createdAt: string;
  /**
   * PARTNER (Story 8.2) or COMMUNITY/attendee (Story 7.1). Backend always sends it;
   * optional here so pre-7.1 fixtures/callers still type-check (treated as PARTNER when absent).
   */
  source?: 'PARTNER' | 'COMMUNITY';
}
 
export interface TopicSuggestionRequest {
  title: string;
  description?: string | null;
  /** Organizer-only: submit on behalf of a specific partner company. */
  companyName?: string | null;
}
 
export interface TopicStatusUpdateRequest {
  status: 'SELECTED' | 'DECLINED';
  plannedEvent?: string | null;
}
 
// ─── API functions ────────────────────────────────────────────────────────────
 
/** List all topic suggestions sorted by vote count descending (PARTNER + ORGANIZER). */
export const getTopics = async (): Promise<TopicDTO[]> => {
  const response = await apiClient.get<TopicDTO[]>('/partners/topics');
  return response.data;
};
 
/** Submit a new topic suggestion (PARTNER only). */
export const suggestTopic = async (req: TopicSuggestionRequest): Promise<TopicDTO> => {
  const response = await apiClient.post<TopicDTO>('/partners/topics', req);
  return response.data;
};
 
/**
 * Submit a topic suggestion as a logged-in ATTENDEE ("Topics From the Floor", Story 7.1).
 * Flows into the same topic pool tagged source=COMMUNITY. Submit-only — there is no
 * attendee read endpoint.
 */
export const suggestTopicAsAttendee = async (req: TopicSuggestionRequest): Promise<TopicDTO> => {
  const response = await apiClient.post<TopicDTO>('/attendees/topics', req);
  return response.data;
};
 
/** Cast a vote on a topic — toggle on (PARTNER only). Idempotent. */
export const castVote = async (topicId: string): Promise<void> => {
  await apiClient.post(`/partners/topics/${topicId}/vote`);
};
 
/** Remove a vote from a topic — toggle off (PARTNER only). Idempotent. */
export const removeVote = async (topicId: string): Promise<void> => {
  await apiClient.delete(`/partners/topics/${topicId}/vote`);
};
 
/** Update a topic's title/description — own company's topics only (PARTNER). */
export const updateTopic = async (
  topicId: string,
  req: TopicSuggestionRequest
): Promise<TopicDTO> => {
  const response = await apiClient.patch<TopicDTO>(`/partners/topics/${topicId}`, req);
  return response.data;
};
 
/** Delete a topic — own company's topics only (PARTNER). */
export const deleteTopic = async (topicId: string): Promise<void> => {
  await apiClient.delete(`/partners/topics/${topicId}`);
};
 
/** Update topic status (ORGANIZER only). */
export const updateTopicStatus = async (
  topicId: string,
  req: TopicStatusUpdateRequest
): Promise<TopicDTO> => {
  const response = await apiClient.patch<TopicDTO>(`/partners/topics/${topicId}/status`, req);
  return response.data;
};