'use client'; import { useMemo } from 'react'; import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'; import { toast } from 'sonner'; import { ticketService } from '@/services/api'; import type { AssignTicketPayload, ReviewRepairPayload, SubmitRepairPayload, SubmitRepairUploadPayload, TicketDetail, TicketListParams, TicketStatus, } from '@/types'; import { ticketKeys } from '../queries/ticketKeys'; const TICKET_TABLE_REFRESH_MS = 5 * 60 * 1000; interface UseTicketsQueryParams { skip: number; limit: number; status?: TicketStatus | 'all'; chainageId?: string; } function buildTicketListParams({ skip, limit, status, chainageId, }: UseTicketsQueryParams): TicketListParams { return { skip, limit, status: status === 'all' ? undefined : status, chainage_id: chainageId || undefined, }; } export function useTicketsQuery(params: UseTicketsQueryParams) { const { skip, limit, status, chainageId } = params; const listParams = useMemo( () => buildTicketListParams({ skip, limit, status, chainageId }), [chainageId, limit, skip, status], ); return useQuery({ queryKey: ticketKeys.list(listParams), queryFn: () => ticketService.getTickets(listParams), staleTime: TICKET_TABLE_REFRESH_MS, refetchInterval: TICKET_TABLE_REFRESH_MS, }); } export function useTicketDetailQuery(ticketId: string | undefined) { return useQuery({ queryKey: ticketKeys.detail(ticketId ?? ''), queryFn: () => ticketService.getTicketDetail(ticketId as string), enabled: Boolean(ticketId), }); } export function useAssignableTicketUsersQuery(enabled: boolean) { return useQuery({ queryKey: ticketKeys.assignableUsers(), queryFn: () => ticketService.getAssignableUsers(), enabled, }); } function mergeTicketDetailResponse( current: TicketDetail | undefined, next: TicketDetail, ) { if (!current) return next; return { ...current, ...next, history: next.history ?? current.history, }; } export function useAssignTicketMutation(ticketId: string) { const queryClient = useQueryClient(); return useMutation({ mutationFn: (payload: AssignTicketPayload) => ticketService.assignTicket(ticketId, payload), onSuccess: (ticket) => { toast.success('Ticket assigned'); queryClient.setQueryData( ticketKeys.detail(ticketId), (current) => mergeTicketDetailResponse(current, ticket), ); queryClient.invalidateQueries({ queryKey: ticketKeys.lists() }); }, onError: () => toast.error('Failed to assign ticket'), }); } export function useStartTicketMutation(ticketId: string) { const queryClient = useQueryClient(); return useMutation({ mutationFn: () => ticketService.startTicket(ticketId), onSuccess: (ticket) => { toast.success('Ticket started'); queryClient.setQueryData( ticketKeys.detail(ticketId), (current) => mergeTicketDetailResponse(current, ticket), ); queryClient.invalidateQueries({ queryKey: ticketKeys.lists() }); }, onError: () => toast.error('Failed to start ticket'), }); } export function useSubmitRepairMutation(ticketId: string) { const queryClient = useQueryClient(); return useMutation({ mutationFn: (payload: SubmitRepairPayload) => ticketService.submitRepair(ticketId, payload), onSuccess: (ticket) => { toast.success('Repair submitted'); queryClient.setQueryData( ticketKeys.detail(ticketId), (current) => mergeTicketDetailResponse(current, ticket), ); queryClient.invalidateQueries({ queryKey: ticketKeys.lists() }); }, onError: () => toast.error('Failed to submit repair'), }); } export function useSubmitRepairUploadMutation(ticketId: string) { const queryClient = useQueryClient(); return useMutation({ mutationFn: (payload: SubmitRepairUploadPayload) => ticketService.submitRepairUpload(ticketId, payload), onSuccess: (ticket) => { toast.success('Repair evidence uploaded'); queryClient.setQueryData( ticketKeys.detail(ticketId), (current) => mergeTicketDetailResponse(current, ticket), ); queryClient.invalidateQueries({ queryKey: ticketKeys.lists() }); }, onError: () => toast.error('Failed to upload repair evidence'), }); } export function useReviewRepairMutation(ticketId: string) { const queryClient = useQueryClient(); return useMutation({ mutationFn: (payload: ReviewRepairPayload) => ticketService.reviewRepair(ticketId, payload), onSuccess: (ticket, payload) => { toast.success( payload.action === 'approve' ? 'Repair approved' : 'Repair rejected', ); queryClient.setQueryData( ticketKeys.detail(ticketId), (current) => mergeTicketDetailResponse(current, ticket), ); queryClient.invalidateQueries({ queryKey: ticketKeys.lists() }); }, onError: () => toast.error('Failed to review repair'), }); } export function useCloseTicketMutation(ticketId: string) { const queryClient = useQueryClient(); return useMutation({ mutationFn: () => ticketService.closeTicket(ticketId), onSuccess: (ticket) => { toast.success('Ticket closed'); queryClient.setQueryData( ticketKeys.detail(ticketId), (current) => mergeTicketDetailResponse(current, ticket), ); queryClient.invalidateQueries({ queryKey: ticketKeys.lists() }); }, onError: () => toast.error('Failed to close ticket'), }); }