![]() Server : Apache/2 System : Linux server-15-235-50-60 5.15.0-164-generic #174-Ubuntu SMP Fri Nov 14 20:25:16 UTC 2025 x86_64 User : gositeme ( 1004) PHP Version : 8.2.29 Disable Function : exec,system,passthru,shell_exec,proc_close,proc_open,dl,popen,show_source,posix_kill,posix_mkfifo,posix_getpwuid,posix_setpgid,posix_setsid,posix_setuid,posix_setgid,posix_seteuid,posix_setegid,posix_uname Directory : /home/gositeme/domains/lavocat.ca/private_html/src/hooks/ |
import { useState, useEffect, useCallback } from 'react';
import { useSession } from 'next-auth/react';
import { useWebSocket } from '@/context/EnhancedWebSocketContext';
interface ProfileInteraction {
type: 'follow' | 'unfollow' | 'friend_request' | 'friend_accept' | 'endorse' | 'message' | 'profile_view';
fromUserId: string;
fromUserName: string;
fromUserAvatar?: string;
toUserId: string;
timestamp: number;
data?: any;
}
interface UserStatus {
userId: string;
status: 'online' | 'away' | 'offline';
timestamp: number;
}
interface ProfileView {
viewerId: string;
viewerName: string;
timestamp: number;
}
export function useRealTimeProfile(userId: string) {
const { data: session } = useSession();
const { ws, connected, sendMessage } = useWebSocket();
const [interactions, setInteractions] = useState<ProfileInteraction[]>([]);
const [userStatus, setUserStatus] = useState<UserStatus | null>(null);
const [profileViews, setProfileViews] = useState<ProfileView[]>([]);
const [isOnline, setIsOnline] = useState(false);
const [lastActivity, setLastActivity] = useState<number | null>(null);
const [notifications, setNotifications] = useState<Array<{
id: string;
type: string;
message: string;
userId?: string;
userName?: string;
timestamp: Date;
}>>([]);
// Send profile interaction
const sendProfileInteraction = useCallback(async (
type: ProfileInteraction['type'],
targetUserId: string,
data?: any
) => {
if (!connected || !session?.user?.id) return;
try {
await sendMessage('PROFILE_INTERACTION', {
type,
toUserId: targetUserId,
data
});
// Add to local interactions immediately for optimistic UI
const interaction: ProfileInteraction = {
type,
fromUserId: session.user.id,
fromUserName: session.user.name || 'Unknown',
fromUserAvatar: session.user.image || undefined,
toUserId: targetUserId,
timestamp: Date.now(),
data
};
setInteractions(prev => [interaction, ...prev.slice(0, 49)]); // Keep last 50 interactions
} catch (error) {
console.error('Error sending profile interaction:', error);
}
}, [connected, session, sendMessage]);
// Track profile view
const trackProfileView = useCallback(async (targetUserId: string) => {
if (!connected || !session?.user?.id || session.user.id === targetUserId) return;
try {
await sendMessage('PROFILE_VIEW', { targetUserId });
} catch (error) {
console.error('Error tracking profile view:', error);
}
}, [connected, session, sendMessage]);
// Update online status
const updateOnlineStatus = useCallback(async (status: 'online' | 'away' | 'offline') => {
if (!connected) return;
try {
await sendMessage('ONLINE_STATUS', { status });
setIsOnline(status === 'online');
} catch (error) {
console.error('Error updating online status:', error);
}
}, [connected, sendMessage]);
// Listen for real-time events
useEffect(() => {
if (!ws || !connected) return;
const handleProfileInteraction = (event: MessageEvent) => {
try {
const message = JSON.parse(event.data);
if (message.type === 'PROFILE_INTERACTION' && message.data.toUserId === userId) {
const interaction = message.data;
setInteractions(prev => [interaction, ...prev.slice(0, 49)]);
// Create notification for profile interactions
const newNotification = {
id: `notification_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,
type: interaction.type,
message: getNotificationMessage(interaction),
userId: interaction.fromUserId,
userName: interaction.fromUserName,
timestamp: new Date(interaction.timestamp)
};
setNotifications(prev => [newNotification, ...prev.slice(0, 4)]);
// Trigger main notification system update
const event = new CustomEvent('notification-updated');
window.dispatchEvent(event);
}
if (message.type === 'PROFILE_ACTIVITY' && message.data.toUserId === userId) {
// Update activity feed
setLastActivity(message.data.timestamp);
}
} catch (error) {
console.error('Error parsing profile interaction message:', error);
}
};
const handleUserStatusUpdate = (event: MessageEvent) => {
try {
const message = JSON.parse(event.data);
if (message.type === 'USER_STATUS_UPDATE' && message.data.userId === userId) {
setUserStatus(message.data);
setIsOnline(message.data.status === 'online');
}
} catch (error) {
console.error('Error parsing user status message:', error);
}
};
const handleProfileViewed = (event: MessageEvent) => {
try {
const message = JSON.parse(event.data);
if (message.type === 'PROFILE_VIEWED' && session?.user?.id === userId) {
setProfileViews(prev => [message.data, ...prev.slice(0, 19)]); // Keep last 20 views
}
} catch (error) {
console.error('Error parsing profile viewed message:', error);
}
};
ws.addEventListener('message', handleProfileInteraction);
ws.addEventListener('message', handleUserStatusUpdate);
ws.addEventListener('message', handleProfileViewed);
// Track profile view when component mounts
if (session?.user?.id && session.user.id !== userId) {
trackProfileView(userId);
}
// Set initial online status
updateOnlineStatus('online');
return () => {
ws.removeEventListener('message', handleProfileInteraction);
ws.removeEventListener('message', handleUserStatusUpdate);
ws.removeEventListener('message', handleProfileViewed);
// Set offline status when component unmounts
updateOnlineStatus('offline');
};
}, [ws, connected, userId, session, trackProfileView, updateOnlineStatus]);
// Handle page visibility changes
useEffect(() => {
const handleVisibilityChange = () => {
if (document.hidden) {
updateOnlineStatus('away');
} else {
updateOnlineStatus('online');
}
};
document.addEventListener('visibilitychange', handleVisibilityChange);
return () => document.removeEventListener('visibilitychange', handleVisibilityChange);
}, [updateOnlineStatus]);
// Helper function to get notification message
const getNotificationMessage = (interaction: ProfileInteraction) => {
switch (interaction.type) {
case 'follow':
return `${interaction.fromUserName} started following you`;
case 'friend_request':
return `${interaction.fromUserName} sent you a friend request`;
case 'endorse':
const endorsementText = interaction.data?.text || 'endorsed your profile';
return `${interaction.fromUserName} ${endorsementText}`;
case 'message':
return `${interaction.fromUserName} sent you a message`;
case 'profile_view':
return `${interaction.fromUserName} viewed your profile`;
default:
return `${interaction.fromUserName} interacted with your profile`;
}
};
return {
// State
interactions,
userStatus,
profileViews,
isOnline,
lastActivity,
notifications,
// Actions
sendProfileInteraction,
trackProfileView,
updateOnlineStatus,
// Utilities
connected,
hasRecentActivity: lastActivity ? Date.now() - lastActivity < 300000 : false // 5 minutes
};
}