T.ME/BIBIL_0DAY
CasperSecurity


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/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Current File : /home/gositeme/domains/lavocat.ca/public_html/src/components/RealTimeActivityFeed.tsx
'use client';

import React, { useState, useEffect } from 'react';
import { motion, AnimatePresence } from 'framer-motion';
import { formatDistanceToNow } from 'date-fns';
import { 
  Users, 
  MessageSquare, 
  ThumbsUp, 
  UserPlus, 
  Eye, 
  Star,
  Activity,
  Zap
} from 'lucide-react';

interface ActivityItem {
  id: string;
  type: 'follow' | 'unfollow' | 'friend_request' | 'friend_accept' | 'endorse' | 'message' | 'profile_view';
  fromUserId: string;
  fromUserName: string;
  fromUserAvatar?: string;
  toUserId: string;
  timestamp: number;
  data?: any;
}

interface RealTimeActivityFeedProps {
  userId: string;
  maxItems?: number;
  showLiveIndicator?: boolean;
}

const RealTimeActivityFeed: React.FC<RealTimeActivityFeedProps> = ({ 
  userId, 
  maxItems = 10,
  showLiveIndicator = true 
}) => {
  const [activities, setActivities] = useState<ActivityItem[]>([]);
  const [isLive, setIsLive] = useState(false);
  const [lastUpdate, setLastUpdate] = useState<number | null>(null);

  // Simulate real-time updates (in real implementation, this would come from WebSocket)
  useEffect(() => {
    const interval = setInterval(() => {
      // Simulate new activity
      const shouldAddActivity = Math.random() < 0.1; // 10% chance every 5 seconds
      
      if (shouldAddActivity) {
        const newActivity: ActivityItem = {
          id: `activity_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,
          type: ['follow', 'endorse', 'profile_view', 'message'][Math.floor(Math.random() * 4)] as ActivityItem['type'],
          fromUserId: `user_${Math.random().toString(36).substr(2, 9)}`,
          fromUserName: `User ${Math.floor(Math.random() * 1000)}`,
          toUserId: userId,
          timestamp: Date.now(),
          data: {}
        };

        setActivities(prev => [newActivity, ...prev.slice(0, maxItems - 1)]);
        setLastUpdate(Date.now());
        setIsLive(true);
        
        // Hide live indicator after 3 seconds
        setTimeout(() => setIsLive(false), 3000);
      }
    }, 5000);

    return () => clearInterval(interval);
  }, [userId, maxItems]);

  const getActivityIcon = (type: ActivityItem['type']) => {
    switch (type) {
      case 'follow':
        return <Users className="h-4 w-4 text-blue-500" />;
      case 'friend_request':
        return <UserPlus className="h-4 w-4 text-green-500" />;
      case 'endorse':
        return <ThumbsUp className="h-4 w-4 text-purple-500" />;
      case 'message':
        return <MessageSquare className="h-4 w-4 text-orange-500" />;
      case 'profile_view':
        return <Eye className="h-4 w-4 text-gray-500" />;
      default:
        return <Activity className="h-4 w-4 text-gray-500" />;
    }
  };

  const getActivityText = (activity: ActivityItem) => {
    switch (activity.type) {
      case 'follow':
        return `${activity.fromUserName} started following you`;
      case 'friend_request':
        return `${activity.fromUserName} sent you a friend request`;
      case 'endorse':
        return `${activity.fromUserName} endorsed you`;
      case 'message':
        return `${activity.fromUserName} sent you a message`;
      case 'profile_view':
        return `${activity.fromUserName} viewed your profile`;
      default:
        return `${activity.fromUserName} interacted with your profile`;
    }
  };

  const getActivityColor = (type: ActivityItem['type']) => {
    switch (type) {
      case 'follow':
        return 'bg-blue-50 border-blue-200';
      case 'friend_request':
        return 'bg-green-50 border-green-200';
      case 'endorse':
        return 'bg-purple-50 border-purple-200';
      case 'message':
        return 'bg-orange-50 border-orange-200';
      case 'profile_view':
        return 'bg-gray-50 border-gray-200';
      default:
        return 'bg-gray-50 border-gray-200';
    }
  };

  return (
    <div className="space-y-4">
      {/* Live Indicator */}
      {showLiveIndicator && (
        <div className="flex items-center gap-2 text-sm text-gray-600">
          <div className="flex items-center gap-1">
            <Zap className={`h-3 w-3 ${isLive ? 'text-green-500 animate-pulse' : 'text-gray-400'}`} />
            <span>{isLive ? 'Live' : 'Real-time'}</span>
          </div>
          {lastUpdate && (
            <span className="text-xs text-gray-400">
              Last update: {formatDistanceToNow(lastUpdate, { addSuffix: true })}
            </span>
          )}
        </div>
      )}

      {/* Activity List */}
      <div className="space-y-3">
        <AnimatePresence>
          {activities.map((activity, index) => (
            <motion.div
              key={activity.id}
              initial={{ opacity: 0, y: -10, scale: 0.95 }}
              animate={{ opacity: 1, y: 0, scale: 1 }}
              exit={{ opacity: 0, y: -10, scale: 0.95 }}
              transition={{ 
                duration: 0.3, 
                delay: index * 0.1,
                type: "spring",
                stiffness: 300
              }}
              className={`p-3 rounded-lg border ${getActivityColor(activity.type)} transition-all hover:shadow-sm`}
            >
              <div className="flex items-start gap-3">
                <div className="flex-shrink-0">
                  {activity.fromUserAvatar ? (
                    <img 
                      src={activity.fromUserAvatar} 
                      alt={activity.fromUserName}
                      className="w-8 h-8 rounded-full object-cover"
                    />
                  ) : (
                    <div className="w-8 h-8 rounded-full bg-gray-200 flex items-center justify-center">
                      {getActivityIcon(activity.type)}
                    </div>
                  )}
                </div>
                
                <div className="flex-1 min-w-0">
                  <div className="flex items-center gap-2">
                    <span className="font-medium text-gray-900 truncate">
                      {activity.fromUserName}
                    </span>
                    {getActivityIcon(activity.type)}
                  </div>
                  <p className="text-sm text-gray-600 mt-1">
                    {getActivityText(activity)}
                  </p>
                  <p className="text-xs text-gray-400 mt-1">
                    {formatDistanceToNow(activity.timestamp, { addSuffix: true })}
                  </p>
                </div>

                {/* New indicator for recent activities */}
                {Date.now() - activity.timestamp < 30000 && (
                  <div className="flex-shrink-0">
                    <div className="w-2 h-2 bg-green-500 rounded-full animate-pulse"></div>
                  </div>
                )}
              </div>
            </motion.div>
          ))}
        </AnimatePresence>

        {/* Empty State */}
        {activities.length === 0 && (
          <div className="text-center py-8 text-gray-500">
            <Activity className="h-12 w-12 mx-auto mb-3 text-gray-300" />
            <p className="text-sm">No recent activity</p>
            <p className="text-xs mt-1">Activity will appear here in real-time</p>
          </div>
        )}
      </div>

      {/* Activity Stats */}
      {activities.length > 0 && (
        <div className="pt-4 border-t border-gray-200">
          <div className="flex justify-between text-xs text-gray-500">
            <span>{activities.length} recent activities</span>
            <span>Real-time updates enabled</span>
          </div>
        </div>
      )}
    </div>
  );
};

export default RealTimeActivityFeed; 

CasperSecurity Mini