mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-30 11:08:12 +00:00
feat: add the support to the client
This commit is contained in:
@@ -0,0 +1,36 @@
|
||||
import type { Passenger } from '@edr/types';
|
||||
|
||||
import { apiClient } from '@/lib/api-client';
|
||||
|
||||
type ConversationDto = Passenger.PassengerSupportConversationDto;
|
||||
type MessageDto = Passenger.PassengerSupportMessageDto;
|
||||
type ListResult = Passenger.PassengerSupportConversationListResult;
|
||||
|
||||
export interface ListParams {
|
||||
status?: string;
|
||||
search?: string;
|
||||
}
|
||||
|
||||
/** Passenger backoffice (agent) support-chat REST calls (client unwraps envelope). */
|
||||
export const supportApi = {
|
||||
listConversations: (params: ListParams = {}) =>
|
||||
apiClient.get<ListResult>('/support/agent/conversations', { params }),
|
||||
listMessages: (id: string) =>
|
||||
apiClient.get<MessageDto[]>(`/support/agent/conversations/${id}/messages`),
|
||||
sendMessage: (id: string, text: string) =>
|
||||
apiClient.post<MessageDto>(
|
||||
`/support/agent/conversations/${id}/messages`,
|
||||
{ text },
|
||||
),
|
||||
setStatus: (id: string, status: string) =>
|
||||
apiClient.patch<ConversationDto>(
|
||||
`/support/agent/conversations/${id}/status`,
|
||||
{ status },
|
||||
),
|
||||
markRead: (id: string) =>
|
||||
apiClient.post<{ unreadCount: number }>(
|
||||
`/support/agent/conversations/${id}/read`,
|
||||
),
|
||||
unreadCount: () =>
|
||||
apiClient.get<{ unreadCount: number }>('/support/agent/unread-count'),
|
||||
};
|
||||
@@ -0,0 +1,65 @@
|
||||
'use client';
|
||||
|
||||
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
|
||||
|
||||
import { supportApi, type ListParams } from './supportApi';
|
||||
|
||||
export const SUPPORT_CONVERSATIONS_KEY = ['support', 'conversations'];
|
||||
export const SUPPORT_UNREAD_KEY = ['support', 'unread'];
|
||||
export const supportMessagesKey = (id: string) => ['support', 'messages', id];
|
||||
|
||||
export function useConversations(params: ListParams = {}) {
|
||||
return useQuery({
|
||||
queryKey: [...SUPPORT_CONVERSATIONS_KEY, params],
|
||||
queryFn: () => supportApi.listConversations(params),
|
||||
});
|
||||
}
|
||||
|
||||
export function useMessages(conversationId: string | null) {
|
||||
return useQuery({
|
||||
queryKey: supportMessagesKey(conversationId ?? ''),
|
||||
queryFn: () => supportApi.listMessages(conversationId as string),
|
||||
enabled: !!conversationId,
|
||||
});
|
||||
}
|
||||
|
||||
export function useUnreadCount(enabled = true) {
|
||||
return useQuery({
|
||||
queryKey: SUPPORT_UNREAD_KEY,
|
||||
queryFn: () => supportApi.unreadCount(),
|
||||
enabled,
|
||||
refetchInterval: 60_000,
|
||||
});
|
||||
}
|
||||
|
||||
export function useSendMessage(conversationId: string) {
|
||||
const qc = useQueryClient();
|
||||
return useMutation({
|
||||
mutationFn: (text: string) => supportApi.sendMessage(conversationId, text),
|
||||
onSuccess: () => {
|
||||
qc.invalidateQueries({ queryKey: supportMessagesKey(conversationId) });
|
||||
qc.invalidateQueries({ queryKey: SUPPORT_CONVERSATIONS_KEY });
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
export function useSetStatus() {
|
||||
const qc = useQueryClient();
|
||||
return useMutation({
|
||||
mutationFn: ({ id, status }: { id: string; status: string }) =>
|
||||
supportApi.setStatus(id, status),
|
||||
onSuccess: () =>
|
||||
qc.invalidateQueries({ queryKey: SUPPORT_CONVERSATIONS_KEY }),
|
||||
});
|
||||
}
|
||||
|
||||
export function useMarkRead() {
|
||||
const qc = useQueryClient();
|
||||
return useMutation({
|
||||
mutationFn: (id: string) => supportApi.markRead(id),
|
||||
onSuccess: () => {
|
||||
qc.invalidateQueries({ queryKey: SUPPORT_CONVERSATIONS_KEY });
|
||||
qc.invalidateQueries({ queryKey: SUPPORT_UNREAD_KEY });
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
'use client';
|
||||
|
||||
import { Passenger } from '@edr/types';
|
||||
import { useQueryClient } from '@tanstack/react-query';
|
||||
import { useEffect, useRef } from 'react';
|
||||
import { io } from 'socket.io-client';
|
||||
|
||||
import {
|
||||
SUPPORT_CONVERSATIONS_KEY,
|
||||
SUPPORT_UNREAD_KEY,
|
||||
supportMessagesKey,
|
||||
} from './useSupport';
|
||||
|
||||
const SOCKET_ORIGIN = String(
|
||||
process.env.NEXT_PUBLIC_API_URL || 'http://localhost:4000',
|
||||
).replace(/\/api\/?$/, '');
|
||||
|
||||
/**
|
||||
* Subscribes the signed-in agent to live support pushes for the whole shared
|
||||
* inbox. Any new message / conversation change refreshes the thread, the inbox
|
||||
* list, and the unread badge; `onMessage` fires for optional toasts.
|
||||
*/
|
||||
export function useSupportSocket(
|
||||
enabled: boolean,
|
||||
onMessage?: (event: Passenger.PassengerSupportMessageEvent) => void,
|
||||
) {
|
||||
const qc = useQueryClient();
|
||||
const onMessageRef = useRef(onMessage);
|
||||
onMessageRef.current = onMessage;
|
||||
|
||||
useEffect(() => {
|
||||
if (!enabled || typeof window === 'undefined') return;
|
||||
const token = localStorage.getItem('auth_token');
|
||||
if (!token) return;
|
||||
|
||||
const socket = io(
|
||||
`${SOCKET_ORIGIN}/${Passenger.PASSENGER_SUPPORT_WS_NAMESPACE}`,
|
||||
{
|
||||
auth: { token },
|
||||
transports: ['websocket'],
|
||||
withCredentials: true,
|
||||
},
|
||||
);
|
||||
|
||||
socket.on(
|
||||
Passenger.PASSENGER_SUPPORT_WS_EVENTS.MESSAGE_NEW,
|
||||
(event: Passenger.PassengerSupportMessageEvent) => {
|
||||
qc.invalidateQueries({
|
||||
queryKey: supportMessagesKey(event.message.conversationId),
|
||||
});
|
||||
qc.invalidateQueries({ queryKey: SUPPORT_CONVERSATIONS_KEY });
|
||||
qc.invalidateQueries({ queryKey: SUPPORT_UNREAD_KEY });
|
||||
onMessageRef.current?.(event);
|
||||
},
|
||||
);
|
||||
|
||||
socket.on(Passenger.PASSENGER_SUPPORT_WS_EVENTS.CONVERSATION_UPDATED, () => {
|
||||
qc.invalidateQueries({ queryKey: SUPPORT_CONVERSATIONS_KEY });
|
||||
qc.invalidateQueries({ queryKey: SUPPORT_UNREAD_KEY });
|
||||
});
|
||||
|
||||
return () => {
|
||||
socket.off();
|
||||
socket.disconnect();
|
||||
};
|
||||
}, [enabled, qc]);
|
||||
}
|
||||
Reference in New Issue
Block a user