![]() 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/ |
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;