diff --git a/frontend/src/api/index.ts b/frontend/src/api/index.ts index 9ec66c9b..50440df8 100644 --- a/frontend/src/api/index.ts +++ b/frontend/src/api/index.ts @@ -37,3 +37,4 @@ export { handoffsApi } from './handoffs' export { resolutionsApi } from './resolutions' export { deviceTypesApi } from './deviceTypes' export { networkDiagramsApi } from './networkDiagrams' +export { ticketsApi } from './tickets' diff --git a/frontend/src/api/integrations.ts b/frontend/src/api/integrations.ts index b60113d0..709a0bc6 100644 --- a/frontend/src/api/integrations.ts +++ b/frontend/src/api/integrations.ts @@ -1,6 +1,7 @@ import { apiClient } from './client' import type { PsaConnectionResponse, PsaConnectionCreate, PsaConnectionUpdate, PsaConnectionTestResponse } from '@/types' import type { PSABoard, TicketLinkResponse, PSATicketSearchResult, PSATicketInfo, PSATicketStatusItem, PsaPreviewResponse, PsaPostResponse, PsaPostLogEntry, PsaMemberResponse, PsaMemberMappingResponse, AutoMatchResult, FlowpilotSettings } from '@/types/integrations' +import type { TicketListResponse } from '@/types/tickets' export const integrationsApi = { getConnection: () => @@ -15,16 +16,16 @@ export const integrationsApi = { apiClient.post(`/integrations/psa/connections/${id}/test`).then(r => r.data), listBoards: () => apiClient.get('/integrations/psa/boards').then(r => r.data), - searchTickets: (params: { query?: string; board_id?: number; include_closed?: boolean }) => - apiClient.get('/integrations/psa/tickets/search', { params }).then(r => r.data), + searchTickets: (params: { query?: string; board_id?: number; include_closed?: boolean }): Promise => + apiClient.get('/integrations/psa/tickets/search', { params }).then(r => r.data), searchTicketsQueue: (params: { assigned_to_me?: boolean unassigned?: boolean board_ids?: string page?: number page_size?: number - }) => - apiClient.get('/integrations/psa/tickets/search', { params }).then(r => r.data), + }): Promise => + apiClient.get('/integrations/psa/tickets/search', { params }).then(r => r.data), getTicket: (id: string) => apiClient.get(`/integrations/psa/tickets/${id}`).then(r => r.data), getTicketStatuses: (ticketId: string) => diff --git a/frontend/src/api/tickets.ts b/frontend/src/api/tickets.ts new file mode 100644 index 00000000..fb049cb1 --- /dev/null +++ b/frontend/src/api/tickets.ts @@ -0,0 +1,48 @@ +import { apiClient } from './client' +import type { + PSAResource, + PSATicketCreated, + PSATicketStatusUpdate, + TicketCreationPayload, + AiParseResponse, + TicketListResponse, + PSAPriority, +} from '@/types/tickets' + +export const ticketsApi = { + listResources: (ticketId: number): Promise => + apiClient.get(`/integrations/psa/tickets/${ticketId}/resources`).then(r => r.data), + + addResource: (ticketId: number, memberId: number): Promise => + apiClient.post(`/integrations/psa/tickets/${ticketId}/resources?member_id=${memberId}`).then(r => r.data), + + removeResource: (ticketId: number, memberId: number): Promise => + apiClient.delete(`/integrations/psa/tickets/${ticketId}/resources/${memberId}`).then(() => undefined), + + updateStatus: (ticketId: number, statusId: number): Promise => + apiClient.patch(`/integrations/psa/tickets/${ticketId}/status?status_id=${statusId}`).then(r => r.data), + + createTicket: (payload: TicketCreationPayload): Promise => + apiClient.post('/integrations/psa/tickets', payload).then(r => r.data), + + aiParse: (prompt: string): Promise => + apiClient.post('/integrations/psa/tickets/ai-parse', { prompt }).then(r => r.data), + + listPriorities: (): Promise => + apiClient.get('/integrations/psa/priorities').then(r => r.data), + + searchTickets: (params: { + query?: string + board_id?: number | null + status_id?: number | null + include_closed?: boolean + assigned_to_me?: boolean + unassigned?: boolean + board_ids?: string + priority?: string | null + company_id?: number | null + page?: number + page_size?: number + }): Promise => + apiClient.get('/integrations/psa/tickets/search', { params }).then(r => r.data), +} diff --git a/frontend/src/components/dashboard/TicketQueue.tsx b/frontend/src/components/dashboard/TicketQueue.tsx index da667479..829537be 100644 --- a/frontend/src/components/dashboard/TicketQueue.tsx +++ b/frontend/src/components/dashboard/TicketQueue.tsx @@ -234,11 +234,11 @@ export function TicketQueue() { try { const results = await integrationsApi.searchTicketsQueue(params) if (append) { - setTickets((prev) => [...prev, ...results]) + setTickets((prev) => [...prev, ...results.items]) } else { - setTickets(results) + setTickets(results.items) } - setHasMore(results.length === PAGE_SIZE) + setHasMore(results.items.length === PAGE_SIZE) setError(null) } catch { setError('Failed to load tickets. Check your PSA connection.') diff --git a/frontend/src/components/session/TicketPickerModal.tsx b/frontend/src/components/session/TicketPickerModal.tsx index b7bf711d..6ae47001 100644 --- a/frontend/src/components/session/TicketPickerModal.tsx +++ b/frontend/src/components/session/TicketPickerModal.tsx @@ -56,7 +56,7 @@ export function TicketPickerModal({ open, onClose, sessionId, onLinked, onSelect query: query.trim(), include_closed: closed, }) - setSearchResults(results) + setSearchResults(results.items) setHasSearched(true) } catch (err: unknown) { const message =