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/private_html/src/components/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Current File : /home/gositeme/domains/lavocat.ca/private_html/src/components/ProfileInteractionPanel.tsx
import React, { useState, useEffect } from 'react';
import { useSession } from 'next-auth/react';
import { motion, AnimatePresence } from 'framer-motion';
import { 
  MessageCircle, 
  UserPlus, 
  UserMinus, 
  Star, 
  ThumbsUp, 
  Calendar,
  Clock,
  TrendingUp,
  Award,
  Heart,
  Share2,
  Bookmark,
  Eye,
  Users,
  Activity
} from 'lucide-react';
import toast from 'react-hot-toast';

interface ProfileInteractionPanelProps {
  profileId: string;
  profileName: string;
  isOwnProfile: boolean;
  isOnline?: boolean;
  onStartMessage?: () => void;
  onScheduleMeeting?: () => void;
}

interface UserStats {
  followers: number;
  following: number;
  endorsements: number;
  views: number;
  isFollowing: boolean;
  isEndorsed: boolean;
  mutualConnections: number;
}

const ProfileInteractionPanel: React.FC<ProfileInteractionPanelProps> = ({
  profileId,
  profileName,
  isOwnProfile,
  isOnline = false,
  onStartMessage,
  onScheduleMeeting
}) => {
  const { data: session } = useSession();
  const [stats, setStats] = useState<UserStats>({
    followers: 0,
    following: 0,
    endorsements: 0,
    views: 0,
    isFollowing: false,
    isEndorsed: false,
    mutualConnections: 0
  });
  const [loading, setLoading] = useState(false);
  const [showStats, setShowStats] = useState(false);

  useEffect(() => {
    if (!isOwnProfile && session?.user?.id) {
      fetchUserStats();
    }
  }, [profileId, session?.user?.id, isOwnProfile]);

  const fetchUserStats = async () => {
    try {
      const response = await fetch(`/api/profile/${profileId}/stats`);
      if (response.ok) {
        const data = await response.json();
        setStats(data);
      }
    } catch (error) {
      console.error('Error fetching profile stats:', error);
    }
  };

  const handleFollow = async () => {
    if (!session?.user?.id) {
      toast.error('Please log in to follow users');
      return;
    }

    setLoading(true);
    try {
      const response = await fetch(`/api/profile/${profileId}/follow`, {
        method: stats.isFollowing ? 'DELETE' : 'POST',
        headers: { 'Content-Type': 'application/json' }
      });

      if (response.ok) {
        setStats(prev => ({
          ...prev,
          isFollowing: !prev.isFollowing,
          followers: prev.isFollowing ? prev.followers - 1 : prev.followers + 1
        }));
        toast.success(stats.isFollowing ? `Unfollowed ${profileName}` : `Following ${profileName}`);
      } else {
        toast.error('Failed to update follow status');
      }
    } catch (error) {
      toast.error('Error updating follow status');
    } finally {
      setLoading(false);
    }
  };

  const handleEndorse = async () => {
    if (!session?.user?.id) {
      toast.error('Please log in to endorse users');
      return;
    }

    setLoading(true);
    try {
      const response = await fetch(`/api/profile/${profileId}/endorse`, {
        method: stats.isEndorsed ? 'DELETE' : 'POST',
        headers: { 'Content-Type': 'application/json' }
      });

      if (response.ok) {
        setStats(prev => ({
          ...prev,
          isEndorsed: !prev.isEndorsed,
          endorsements: prev.isEndorsed ? prev.endorsements - 1 : prev.endorsements + 1
        }));
        toast.success(stats.isEndorsed ? `Removed endorsement for ${profileName}` : `Endorsed ${profileName}`);
      } else {
        toast.error('Failed to update endorsement');
      }
    } catch (error) {
      toast.error('Error updating endorsement');
    } finally {
      setLoading(false);
    }
  };

  const handleShare = () => {
    if (navigator.share) {
      navigator.share({
        title: `${profileName}'s Profile`,
        text: `Check out ${profileName}'s professional profile`,
        url: window.location.href
      });
    } else {
      navigator.clipboard.writeText(window.location.href);
      toast.success('Profile link copied to clipboard!');
    }
  };

  const handleBookmark = () => {
    toast.success('Profile bookmarked!');
  };

  if (isOwnProfile) {
    return (
      <motion.div
        initial={{ opacity: 0, y: 20 }}
        animate={{ opacity: 1, y: 0 }}
        className="bg-white rounded-xl shadow-lg p-6 border border-gray-100"
      >
        <h3 className="text-lg font-semibold text-gray-900 mb-4 flex items-center">
          <Activity className="h-5 w-5 mr-2 text-blue-600" />
          Profile Analytics
        </h3>
        
        <div className="grid grid-cols-2 gap-4 mb-4">
          <div className="text-center p-3 bg-blue-50 rounded-lg">
            <div className="text-2xl font-bold text-blue-600">{stats.views}</div>
            <div className="text-sm text-gray-600">Profile Views</div>
          </div>
          <div className="text-center p-3 bg-green-50 rounded-lg">
            <div className="text-2xl font-bold text-green-600">{stats.followers}</div>
            <div className="text-sm text-gray-600">Followers</div>
          </div>
        </div>

        <div className="space-y-3">
          <button
            onClick={() => setShowStats(!showStats)}
            className="w-full flex items-center justify-center gap-2 px-4 py-2 bg-gray-100 hover:bg-gray-200 text-gray-700 rounded-lg transition-colors"
          >
            <TrendingUp className="h-4 w-4" />
            View Detailed Analytics
          </button>
        </div>
      </motion.div>
    );
  }

  return (
    <motion.div
      initial={{ opacity: 0, y: 20 }}
      animate={{ opacity: 1, y: 0 }}
      className="bg-white rounded-xl shadow-lg p-6 border border-gray-100"
    >
      <h3 className="text-lg font-semibold text-gray-900 mb-4 flex items-center">
        <Users className="h-5 w-5 mr-2 text-purple-600" />
        Connect with {profileName}
      </h3>

      {/* Primary Actions */}
      <div className="space-y-3 mb-6">
        <motion.button
          whileHover={{ scale: 1.02 }}
          whileTap={{ scale: 0.98 }}
          onClick={onStartMessage}
          disabled={loading}
          className={`w-full flex items-center justify-center gap-2 px-4 py-3 rounded-lg font-medium transition-all ${
            isOnline
              ? 'bg-gradient-to-r from-blue-600 to-purple-600 text-white shadow-lg hover:shadow-xl'
              : 'bg-blue-100 text-blue-700 hover:bg-blue-200'
          }`}
        >
          <MessageCircle className="h-4 w-4" />
          {isOnline ? 'Message Now' : 'Send Message'}
        </motion.button>

        <motion.button
          whileHover={{ scale: 1.02 }}
          whileTap={{ scale: 0.98 }}
          onClick={handleFollow}
          disabled={loading}
          className={`w-full flex items-center justify-center gap-2 px-4 py-3 rounded-lg font-medium transition-all ${
            stats.isFollowing
              ? 'bg-gray-100 text-gray-700 hover:bg-gray-200'
              : 'bg-purple-100 text-purple-700 hover:bg-purple-200'
          }`}
        >
          {stats.isFollowing ? (
            <>
              <UserMinus className="h-4 w-4" />
              Unfollow
            </>
          ) : (
            <>
              <UserPlus className="h-4 w-4" />
              Follow
            </>
          )}
        </motion.button>

        <motion.button
          whileHover={{ scale: 1.02 }}
          whileTap={{ scale: 0.98 }}
          onClick={onScheduleMeeting}
          disabled={loading}
          className="w-full flex items-center justify-center gap-2 px-4 py-3 bg-green-100 text-green-700 hover:bg-green-200 rounded-lg font-medium transition-all"
        >
          <Calendar className="h-4 w-4" />
          Schedule Meeting
        </motion.button>
      </div>

      {/* Secondary Actions */}
      <div className="grid grid-cols-2 gap-3 mb-6">
        <motion.button
          whileHover={{ scale: 1.02 }}
          whileTap={{ scale: 0.98 }}
          onClick={handleEndorse}
          disabled={loading}
          className={`flex items-center justify-center gap-2 px-3 py-2 rounded-lg text-sm font-medium transition-all ${
            stats.isEndorsed
              ? 'bg-yellow-100 text-yellow-700 hover:bg-yellow-200'
              : 'bg-gray-100 text-gray-700 hover:bg-gray-200'
          }`}
        >
          <Star className="h-4 w-4" />
          {stats.isEndorsed ? 'Endorsed' : 'Endorse'}
        </motion.button>

        <motion.button
          whileHover={{ scale: 1.02 }}
          whileTap={{ scale: 0.98 }}
          onClick={handleShare}
          className="flex items-center justify-center gap-2 px-3 py-2 bg-gray-100 text-gray-700 hover:bg-gray-200 rounded-lg text-sm font-medium transition-all"
        >
          <Share2 className="h-4 w-4" />
          Share
        </motion.button>
      </div>

      {/* Stats Overview */}
      <div className="border-t border-gray-200 pt-4">
        <div className="grid grid-cols-3 gap-4 text-center">
          <div>
            <div className="text-lg font-bold text-gray-900">{stats.followers}</div>
            <div className="text-xs text-gray-600">Followers</div>
          </div>
          <div>
            <div className="text-lg font-bold text-gray-900">{stats.endorsements}</div>
            <div className="text-xs text-gray-600">Endorsements</div>
          </div>
          <div>
            <div className="text-lg font-bold text-gray-900">{stats.mutualConnections}</div>
            <div className="text-xs text-gray-600">Mutual</div>
          </div>
        </div>
      </div>

      {/* Online Status */}
      {isOnline && (
        <div className="mt-4 flex items-center gap-2 text-sm text-green-600">
          <div className="w-2 h-2 bg-green-500 rounded-full animate-pulse"></div>
          Online now
        </div>
      )}
    </motion.div>
  );
};

export default ProfileInteractionPanel; 

CasperSecurity Mini