NeahStable/hooks/use-rocketchat-calls.ts
2026-01-16 01:52:51 +01:00

200 lines
6.7 KiB
TypeScript

import { useEffect, useRef, useCallback, useState } from 'react';
import { useSession } from 'next-auth/react';
import { RocketChatCallListener, CallEvent } from '@/lib/services/rocketchat-call-listener';
import { useWidgetNotification } from './use-widget-notification';
import { logger } from '@/lib/logger';
import { IncomingCall } from '@/components/incoming-call-notification';
/**
* Hook to listen for incoming RocketChat calls and trigger notifications
*/
export function useRocketChatCalls() {
const { data: session } = useSession();
const { triggerNotification } = useWidgetNotification();
const listenerRef = useRef<RocketChatCallListener | null>(null);
const unsubscribeRef = useRef<(() => void) | null>(null);
const initializedRef = useRef(false);
const [incomingCall, setIncomingCall] = useState<IncomingCall | null>(null);
/**
* Get RocketChat credentials for the current user
*/
const getRocketChatCredentials = useCallback(async () => {
if (!session?.user?.id) {
console.log('[useRocketChatCalls] No session user ID');
return null;
}
try {
console.log('[useRocketChatCalls] Getting RocketChat credentials...');
// Extract base URL from environment
const baseUrl = process.env.NEXT_PUBLIC_IFRAME_PAROLE_URL?.split('/channel')[0];
if (!baseUrl) {
console.error('[useRocketChatCalls] RocketChat base URL not configured');
logger.error('[useRocketChatCalls] RocketChat base URL not configured');
return null;
}
// Get user's RocketChat ID and token
const tokenResponse = await fetch('/api/rocket-chat/user-token', {
credentials: 'include',
});
if (!tokenResponse.ok) {
const errorText = await tokenResponse.text();
console.error('[useRocketChatCalls] Failed to get user token', {
status: tokenResponse.status,
error: errorText,
});
logger.error('[useRocketChatCalls] Failed to get user token', {
status: tokenResponse.status,
});
return null;
}
const tokenData = await tokenResponse.json();
console.log('[useRocketChatCalls] ✅ Got credentials', {
userId: tokenData.userId,
hasToken: !!tokenData.authToken,
baseUrl,
});
return {
userId: tokenData.userId,
authToken: tokenData.authToken,
baseUrl,
};
} catch (error) {
console.error('[useRocketChatCalls] Error getting credentials', error);
logger.error('[useRocketChatCalls] Error getting credentials', { error });
return null;
}
}, [session?.user?.id]);
/**
* Initialize call listener
*/
const initializeListener = useCallback(async () => {
if (initializedRef.current || listenerRef.current) {
console.log('[useRocketChatCalls] Already initialized, skipping');
return;
}
console.log('[useRocketChatCalls] Initializing call listener...');
const credentials = await getRocketChatCredentials();
if (!credentials) {
console.warn('[useRocketChatCalls] Could not get credentials, skipping initialization');
logger.warn('[useRocketChatCalls] Could not get credentials, skipping initialization');
return;
}
try {
const listener = RocketChatCallListener.getInstance();
const success = await listener.initialize(
credentials.userId,
credentials.authToken,
credentials.baseUrl
);
console.log('[useRocketChatCalls] Listener initialization result:', success);
if (success) {
listenerRef.current = listener;
initializedRef.current = true;
// Subscribe to call events
const unsubscribe = listener.onCall((callEvent: CallEvent) => {
console.log('[useRocketChatCalls] 🎉 INCOMING CALL DETECTED!', {
from: callEvent.from.username,
roomId: callEvent.roomId,
roomName: callEvent.roomName,
});
logger.info('[useRocketChatCalls] Incoming call detected', {
from: callEvent.from.username,
roomId: callEvent.roomId,
});
// Show incoming call notification UI (Outlook-style rectangle)
setIncomingCall({
from: callEvent.from,
roomId: callEvent.roomId,
roomName: callEvent.roomName,
timestamp: callEvent.timestamp,
});
console.log('[useRocketChatCalls] 📞 Incoming call notification UI set', {
from: callEvent.from.username,
roomId: callEvent.roomId,
});
// Trigger notification badge
// For calls, we want to increment the existing count, not replace it
// So we fetch current count first, then increment
triggerNotification({
source: 'rocketchat',
count: 1, // This will be added to existing count in the registry
items: [
{
id: `call-${callEvent.roomId}-${Date.now()}`,
title: `📞 Appel entrant de ${callEvent.from.name || callEvent.from.username}`,
message: `Appel vidéo/audio dans ${callEvent.roomName || 'chat'}`,
link: `/parole?room=${callEvent.roomId}`,
timestamp: callEvent.timestamp,
metadata: {
type: 'call',
from: callEvent.from,
roomId: callEvent.roomId,
},
},
],
}).then(() => {
console.log('[useRocketChatCalls] ✅ Notification triggered successfully');
}).catch((error) => {
console.error('[useRocketChatCalls] ❌ Error triggering notification', error);
});
});
unsubscribeRef.current = unsubscribe;
console.log('[useRocketChatCalls] ✅ Call listener initialized and subscribed');
logger.debug('[useRocketChatCalls] Call listener initialized');
} else {
console.error('[useRocketChatCalls] ❌ Failed to initialize listener');
}
} catch (error) {
console.error('[useRocketChatCalls] Error initializing listener', error);
logger.error('[useRocketChatCalls] Error initializing listener', { error });
}
}, [getRocketChatCredentials, triggerNotification]);
/**
* Cleanup on unmount
*/
useEffect(() => {
if (session?.user?.id) {
initializeListener();
}
return () => {
if (unsubscribeRef.current) {
unsubscribeRef.current();
unsubscribeRef.current = null;
}
if (listenerRef.current) {
listenerRef.current.disconnect();
listenerRef.current = null;
}
initializedRef.current = false;
};
}, [session?.user?.id, initializeListener]);
return {
incomingCall,
setIncomingCall,
};
}