feat(ticket): refine repair report and history timeline UI

This commit is contained in:
2026-06-19 11:22:41 +05:30
parent 8c3d19a429
commit a567a52e26
27 changed files with 1550 additions and 363 deletions

View File

@@ -9,6 +9,8 @@ import type {
AssignTicketPayload,
ReviewRepairPayload,
SubmitRepairPayload,
SubmitRepairUploadPayload,
TicketDetail,
TicketListParams,
TicketStatus,
} from '@/types';
@@ -60,11 +62,24 @@ export function useTicketDetailQuery(ticketId: string | undefined) {
export function useAssignableTicketUsersQuery(enabled: boolean) {
return useQuery({
queryKey: ticketKeys.assignableUsers(),
queryFn: ticketService.getAssignableUsers,
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();
@@ -73,7 +88,10 @@ export function useAssignTicketMutation(ticketId: string) {
ticketService.assignTicket(ticketId, payload),
onSuccess: (ticket) => {
toast.success('Ticket assigned');
queryClient.setQueryData(ticketKeys.detail(ticketId), ticket);
queryClient.setQueryData<TicketDetail>(
ticketKeys.detail(ticketId),
(current) => mergeTicketDetailResponse(current, ticket),
);
queryClient.invalidateQueries({ queryKey: ticketKeys.lists() });
},
onError: () => toast.error('Failed to assign ticket'),
@@ -87,7 +105,10 @@ export function useStartTicketMutation(ticketId: string) {
mutationFn: () => ticketService.startTicket(ticketId),
onSuccess: (ticket) => {
toast.success('Ticket started');
queryClient.setQueryData(ticketKeys.detail(ticketId), ticket);
queryClient.setQueryData<TicketDetail>(
ticketKeys.detail(ticketId),
(current) => mergeTicketDetailResponse(current, ticket),
);
queryClient.invalidateQueries({ queryKey: ticketKeys.lists() });
},
onError: () => toast.error('Failed to start ticket'),
@@ -102,13 +123,34 @@ export function useSubmitRepairMutation(ticketId: string) {
ticketService.submitRepair(ticketId, payload),
onSuccess: (ticket) => {
toast.success('Repair submitted');
queryClient.setQueryData(ticketKeys.detail(ticketId), ticket);
queryClient.setQueryData<TicketDetail>(
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<TicketDetail>(
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();
@@ -119,7 +161,10 @@ export function useReviewRepairMutation(ticketId: string) {
toast.success(
payload.action === 'approve' ? 'Repair approved' : 'Repair rejected',
);
queryClient.setQueryData(ticketKeys.detail(ticketId), ticket);
queryClient.setQueryData<TicketDetail>(
ticketKeys.detail(ticketId),
(current) => mergeTicketDetailResponse(current, ticket),
);
queryClient.invalidateQueries({ queryKey: ticketKeys.lists() });
},
onError: () => toast.error('Failed to review repair'),
@@ -133,7 +178,10 @@ export function useCloseTicketMutation(ticketId: string) {
mutationFn: () => ticketService.closeTicket(ticketId),
onSuccess: (ticket) => {
toast.success('Ticket closed');
queryClient.setQueryData(ticketKeys.detail(ticketId), ticket);
queryClient.setQueryData<TicketDetail>(
ticketKeys.detail(ticketId),
(current) => mergeTicketDetailResponse(current, ticket),
);
queryClient.invalidateQueries({ queryKey: ticketKeys.lists() });
},
onError: () => toast.error('Failed to close ticket'),