![]() 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/public_html/src/components/ |
'use client';
import React, { useState, useEffect } from 'react';
import { motion, AnimatePresence } from 'framer-motion';
import { formatDistanceToNow } from 'date-fns';
import {
Wifi,
WifiOff,
Clock,
Activity,
Zap
} from 'lucide-react';
interface UserStatus {
userId: string;
status: 'online' | 'away' | 'offline';
timestamp: number;
}
interface RealTimeStatusIndicatorProps {
userId: string;
showDetails?: boolean;
showPulse?: boolean;
}
const RealTimeStatusIndicator: React.FC<RealTimeStatusIndicatorProps> = ({
userId,
showDetails = true,
showPulse = true
}) => {
const [status, setStatus] = useState<UserStatus | null>(null);
const [isLive, setIsLive] = useState(false);
const [lastUpdate, setLastUpdate] = useState<number | null>(null);
// Simulate real-time status updates (in real implementation, this would come from WebSocket)
useEffect(() => {
// Simulate initial status
const initialStatus: UserStatus = {
userId,
status: Math.random() > 0.5 ? 'online' : 'away',
timestamp: Date.now()
};
setStatus(initialStatus);
setLastUpdate(Date.now());
// Simulate status changes
const interval = setInterval(() => {
const shouldChangeStatus = Math.random() < 0.05; // 5% chance every 10 seconds
if (shouldChangeStatus) {
const newStatus: UserStatus = {
userId,
status: ['online', 'away', 'offline'][Math.floor(Math.random() * 3)] as UserStatus['status'],
timestamp: Date.now()
};
setStatus(newStatus);
setLastUpdate(Date.now());
setIsLive(true);
// Hide live indicator after 2 seconds
setTimeout(() => setIsLive(false), 2000);
}
}, 10000);
return () => clearInterval(interval);
}, [userId]);
const getStatusIcon = (status: UserStatus['status']) => {
switch (status) {
case 'online':
return <Wifi className="h-4 w-4 text-green-500" />;
case 'away':
return <Clock className="h-4 w-4 text-yellow-500" />;
case 'offline':
return <WifiOff className="h-4 w-4 text-gray-400" />;
default:
return <Activity className="h-4 w-4 text-gray-400" />;
}
};
const getStatusText = (status: UserStatus['status']) => {
switch (status) {
case 'online':
return 'Online';
case 'away':
return 'Away';
case 'offline':
return 'Offline';
default:
return 'Unknown';
}
};
const getStatusColor = (status: UserStatus['status']) => {
switch (status) {
case 'online':
return 'text-green-600 bg-green-50 border-green-200';
case 'away':
return 'text-yellow-600 bg-yellow-50 border-yellow-200';
case 'offline':
return 'text-gray-500 bg-gray-50 border-gray-200';
default:
return 'text-gray-500 bg-gray-50 border-gray-200';
}
};
const getPulseColor = (status: UserStatus['status']) => {
switch (status) {
case 'online':
return 'bg-green-500';
case 'away':
return 'bg-yellow-500';
case 'offline':
return 'bg-gray-400';
default:
return 'bg-gray-400';
}
};
if (!status) {
return (
<div className="flex items-center gap-2 text-gray-400">
<Activity className="h-4 w-4 animate-spin" />
<span className="text-sm">Loading status...</span>
</div>
);
}
return (
<div className="flex items-center gap-2">
{/* Status Indicator */}
<div className="relative">
<div className="flex items-center gap-2">
{getStatusIcon(status.status)}
{/* Pulse indicator for online status */}
{showPulse && status.status === 'online' && (
<motion.div
className={`w-2 h-2 rounded-full ${getPulseColor(status.status)}`}
animate={{
scale: [1, 1.2, 1],
opacity: [1, 0.7, 1]
}}
transition={{
duration: 2,
repeat: Infinity,
ease: "easeInOut"
}}
/>
)}
</div>
</div>
{/* Status Details */}
{showDetails && (
<div className="flex items-center gap-2">
<span className={`text-sm font-medium ${getStatusColor(status.status).split(' ')[0]}`}>
{getStatusText(status.status)}
</span>
{/* Live indicator */}
{isLive && (
<motion.div
initial={{ opacity: 0, scale: 0.8 }}
animate={{ opacity: 1, scale: 1 }}
exit={{ opacity: 0, scale: 0.8 }}
className="flex items-center gap-1"
>
<Zap className="h-3 w-3 text-green-500 animate-pulse" />
<span className="text-xs text-green-600">Live</span>
</motion.div>
)}
{/* Last update time */}
{lastUpdate && (
<span className="text-xs text-gray-400">
{formatDistanceToNow(lastUpdate, { addSuffix: true })}
</span>
)}
</div>
)}
</div>
);
};
export default RealTimeStatusIndicator;