![]() 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/pages/profile/ |
import React, { useState, Fragment } from 'react';
import { GetServerSideProps } from 'next';
import Head from 'next/head';
import Image from 'next/image';
import Link from 'next/link';
import { getServerSession } from 'next-auth/next';
import { authOptions } from '../../lib/auth';
import { prisma } from '../../lib/prisma';
import { motion } from 'framer-motion';
import {
Star, Badge, DollarSign, Award, Users, TrendingUp,
MapPin, Briefcase, Calendar, Phone, Globe, Linkedin,
MessageCircle, Heart, Trophy, Shield, ArrowLeft
} from 'lucide-react';
import ImageModal from '../../components/ui/ImageModal';
import LayoutWithSidebar from '../../components/LayoutWithSidebar';
import LawyerRatingStars from '../../components/LawyerRatingStars';
import HireLawyerButton from '../../components/HireLawyerButton';
import BusinessAffiliationsSection from '../../components/BusinessAffiliationsSection';
import EnhancedShareButton from '../../components/EnhancedShareButton';
import OpenGraphMeta from '../../components/OpenGraphMeta';
import StructuredData, { createLawyerStructuredData, createBreadcrumbStructuredData } from '../../components/StructuredData';
import BarreauBadge from '../../components/BarreauBadge';
import ProfileInteractionPanel from '../../components/ProfileInteractionPanel';
import ProfileActivityFeed from '../../components/ProfileActivityFeed';
import ProfileTestimonials from '../../components/ProfileTestimonials';
// Modern features imports
import RealTimeStatusIndicator from '../../components/RealTimeStatusIndicator';
import RealTimeNotificationToast from '../../components/RealTimeNotificationToast';
import { useRealTimeProfile } from '../../hooks/useRealTimeProfile';
import { useProfileData } from '../../hooks/useProfileData';
import { useProfileActivity } from '../../hooks/useProfileActivity';
import { useTestimonials } from '../../hooks/useTestimonials';
import {
useFollowUser,
useFriendActions,
useEndorseUser,
useMessageUser,
useShareProfile,
useReportUser
} from '../../hooks/useSocialActions';
import ActivityFeed from '../../components/ActivityFeed';
import AchievementsPanel from '../../components/AchievementsPanel';
import TestimonialsPanel from '../../components/TestimonialsPanel';
import RealTimeActivityFeed from '../../components/RealTimeActivityFeed';
import AchievementSystem from '../../components/AchievementSystem';
import AdvancedPrivacySettings from '../../components/AdvancedPrivacySettings';
import ProfileTestingSuite from '../../components/ProfileTestingSuite';
import DarkModeToggle from '../../components/DarkModeToggle';
interface SocietyDegree {
id: string;
degreeNumber: number;
name: string;
title: string;
track: string;
symbol: string;
color: string;
lodgeLevel: string;
isSecret: boolean;
}
interface UserDegree {
id: string;
achievedAt: string;
ceremonyDate?: string | null;
ceremonyCompleted: boolean;
progressPercentage: number;
degree: SocietyDegree;
}
interface Lodge {
id: string;
name: string;
track: string;
lodgeLevel: string;
isSecret: boolean;
}
interface LodgeMembership {
id: string;
role: string;
isActive: boolean;
joinedDate: string;
lodge: Lodge;
}
interface PublicProfile {
id: string;
username: string;
name: string;
email: string;
role: string;
profilePicture?: string | null;
bio?: string | null;
title?: string | null;
specialization?: string | null;
yearsOfExperience?: number | null;
education?: string | null;
officeLocation?: string | null;
linkedinUrl?: string | null;
websiteUrl?: string | null;
availability?: string | null;
pronouns?: string | null;
language: string;
createdAt: string;
// NEW: Lawyer-specific fields
hourlyRate?: number | null;
proBono?: boolean | null;
averageRating?: number | null;
totalCases?: number | null;
wonCases?: number | null;
lostCases?: number | null;
winRate?: number | null;
totalBadges?: number | null;
isVerified?: boolean | null;
verificationStatus?: string | null;
xpPoints?: number | null;
level?: number | null;
boldnessRating?: number | null;
transparencyRating?: number | null;
workPhone?: string | null;
// NEW: Society fields
degrees?: UserDegree[];
lodgeMemberships?: LodgeMembership[];
reviewsWritten?: number | null;
forumPosts?: number | null;
helpedOthers?: number | null;
observationHours?: number | null;
reformProposals?: number | null;
wisdomScore?: number | null;
civicEngagement?: number | null;
showOnlineStatus?: boolean; // Added for status indicator
showFriends?: boolean;
showEmail?: boolean;
allowMessages?: boolean;
}
interface PublicProfilePageProps {
profile: PublicProfile;
currentUser?: {
id: string | null;
username: string | null;
name: string | null;
email: string | null;
role: string | null;
} | null;
error?: string;
}
const PublicProfilePage: React.FC<PublicProfilePageProps> = ({ profile, currentUser, error }) => {
// Guard clause to handle error or undefined profile
if (error || !profile) {
return (
<LayoutWithSidebar>
<div className="min-h-screen bg-gradient-to-br from-gray-50 to-gray-100 flex items-center justify-center">
<div className="text-center">
<h1 className="text-4xl font-bold text-gray-900 mb-4">Profile Not Found</h1>
<p className="text-gray-600 mb-8">{error || 'The requested profile could not be found.'}</p>
<Link href="/" className="text-blue-600 hover:text-blue-800 underline">
Return to Homepage
</Link>
</div>
</div>
</LayoutWithSidebar>
);
}
const [selectedImage, setSelectedImage] = React.useState<string | null>(null);
// Modern hooks integration
const { notifications } = useRealTimeProfile(profile.id);
const { user: profileData, stats, activeCases, pastCases, caseApplications, friends, mutualFriends, isLoading: profileLoading, error: profileError } = useProfileData(profile.id);
const { activities, achievements, badges, isLoading: activityLoading, error: activityError } = useProfileActivity(profile.id);
const { testimonials, reviews, isLoading: testimonialsLoading, error: testimonialsError } = useTestimonials(profile.id);
const { followUser, isLoading: isFollowing } = useFollowUser();
const { sendFriendRequest, isLoading: isFriendLoading } = useFriendActions();
const { endorseUser, isLoading: isEndorsing } = useEndorseUser();
const { sendMessage, isLoading: isMessaging } = useMessageUser();
const { shareProfile, isLoading: isSharing } = useShareProfile();
const { reportUser, isLoading: isReporting } = useReportUser();
const [showShareModal, setShowShareModal] = useState(false);
const [showReportModal, setShowReportModal] = useState(false);
const [showAdvancedPrivacy, setShowAdvancedPrivacy] = useState(false);
const [showTestingSuite, setShowTestingSuite] = useState(false);
const [showAchievements, setShowAchievements] = useState(false);
// Check if current user is viewing their own profile
const isOwnProfile = currentUser && currentUser.id && currentUser.username &&
(currentUser.id === profile.id || currentUser.username === profile.username);
// Handle social actions
const handleSocialAction = async (action: string) => {
switch (action) {
case 'follow':
const followResult = await followUser(profile.id);
if (followResult.success) {
console.log(followResult.message);
}
break;
case 'friend':
const friendResult = await sendFriendRequest(profile.id);
if (friendResult.success) {
console.log(friendResult.message);
}
break;
case 'endorse':
const endorseResult = await endorseUser(profile.id, 'Great professional');
if (endorseResult.success) {
console.log(endorseResult.message);
}
break;
case 'message':
window.location.href = `/messages?recipient=${profile.id}`;
break;
case 'share':
setShowShareModal(true);
break;
case 'report':
setShowReportModal(true);
break;
}
};
const getRoleIcon = (role: string) => {
switch (role) {
case 'ADMIN':
return 'βοΈ';
case 'LAWYER':
return 'π©ββοΈ';
default:
return 'π€';
}
};
const getRoleName = (role: string) => {
switch (role) {
case 'ADMIN':
return 'Legal Administrator';
case 'LAWYER':
return 'Lawyer';
default:
return 'Client';
}
};
const getStatusColor = (availability?: string) => {
switch (availability) {
case 'Available':
return 'bg-green-400';
case 'Busy':
return 'bg-yellow-400';
case 'Away':
return 'bg-orange-400';
case 'Do Not Disturb':
return 'bg-red-400';
default:
return 'bg-gray-400';
}
};
const getInitials = (name: string) => {
return name
.split(' ')
.map(n => n[0])
.join('')
.toUpperCase()
.slice(0, 2);
};
// Main render
return (
<>
<OpenGraphMeta
title={`${profile.name} - ${profile.title || getRoleName(profile.role)} - LibertΓ© MΓͺme en Prison`}
description={profile.bio || `Professional profile of ${profile.name}, ${profile.title || getRoleName(profile.role)}. ${profile.specialization ? `Specializing in ${profile.specialization}.` : ''} ${profile.yearsOfExperience ? `${profile.yearsOfExperience} years of experience.` : ''}`}
url={`/profile/${profile.username}`}
type="profile"
author={profile.name}
image={profile.profilePicture || undefined}
tags={[
profile.role.toLowerCase(),
'legal professional',
profile.specialization || 'law',
profile.officeLocation || 'legal services'
]}
twitterCreator={profile.linkedinUrl ? `@${profile.linkedinUrl.split('/').pop()}` : undefined}
/>
{profile.role === 'LAWYER' && (
<StructuredData
type="lawyer"
data={createLawyerStructuredData(profile)}
/>
)}
<StructuredData
type="breadcrumb"
data={createBreadcrumbStructuredData([
{ name: 'Home', url: '/' },
{ name: 'Profiles', url: '/profiles' },
{ name: profile.name, url: `/profile/${profile.username}` }
])}
/>
<LayoutWithSidebar>
{/* Real-time notifications */}
{/* <RealTimeNotificationToast notifications={notifications} /> */}
{/* Dark Mode Toggle */}
<DarkModeToggle />
<div className="min-h-screen bg-gradient-to-br from-purple-50 via-pink-50 to-blue-50 dark:from-gray-900 dark:via-purple-900 dark:to-blue-900 transition-colors duration-300">
{/* REVAMPED HERO SECTION */}
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.8 }}
className="relative w-full max-w-4xl mx-auto mt-8 mb-12"
>
{/* Enhanced background with multiple layers */}
<div className="absolute inset-0 h-64 rounded-3xl bg-gradient-to-br from-purple-600 via-pink-500 to-blue-500 shadow-2xl z-0 dark:from-purple-700 dark:via-pink-600 dark:to-blue-600" />
<div className="absolute inset-0 rounded-3xl bg-gradient-to-t from-black/20 to-transparent z-0" />
{/* Floating elements */}
<div className="absolute top-4 right-4 z-10">
<motion.div
animate={{ rotate: 360 }}
transition={{ duration: 20, repeat: Infinity, ease: "linear" }}
className="w-16 h-16 rounded-full bg-white/10 backdrop-blur-sm border border-white/20"
/>
</div>
<div className="absolute bottom-4 left-4 z-10">
<motion.div
animate={{ scale: [1, 1.2, 1] }}
transition={{ duration: 3, repeat: Infinity }}
className="w-12 h-12 rounded-full bg-white/10 backdrop-blur-sm border border-white/20"
/>
</div>
<div className="relative z-10 pt-12 pb-8 px-8">
{/* Profile header with enhanced layout */}
<div className="flex flex-col lg:flex-row items-center lg:items-start gap-8">
{/* Profile picture with enhanced styling */}
<motion.div
initial={{ scale: 0.8, opacity: 0 }}
animate={{ scale: 1, opacity: 1 }}
transition={{ delay: 0.3, duration: 0.6 }}
className="relative group"
>
<div className="w-40 h-40 rounded-full border-4 border-white shadow-2xl overflow-hidden hover:scale-105 transition-transform duration-300 cursor-pointer relative">
<img src={profile.profilePicture || '/default-avatar.png'} alt={profile.name} className="w-full h-full object-cover" />
<div className="absolute inset-0 bg-gradient-to-t from-black/20 to-transparent opacity-0 group-hover:opacity-100 transition-opacity" />
</div>
{/* Status indicator */}
<motion.div
animate={{
scale: profile.showOnlineStatus || isOwnProfile ? [1, 1.2, 1] : 1
}}
transition={{
duration: 2,
repeat: profile.showOnlineStatus || isOwnProfile ? Infinity : 0
}}
className={`absolute bottom-4 right-4 w-6 h-6 rounded-full border-4 border-white ${profile.showOnlineStatus || isOwnProfile ? 'bg-green-400' : 'bg-gray-400'}`}
/>
</motion.div>
{/* Profile info */}
<div className="flex-1 text-center lg:text-left">
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ delay: 0.4, duration: 0.6 }}
className="mb-4"
>
<div className="flex items-center justify-center lg:justify-start gap-3 mb-2">
<h1 className="text-4xl lg:text-5xl font-black text-white drop-shadow-lg">{profile.name}</h1>
{profile.isVerified && (
<motion.div
initial={{ scale: 0, rotate: -180 }}
animate={{ scale: 1, rotate: 0 }}
transition={{ delay: 0.6, type: "spring", stiffness: 200 }}
className="bg-blue-500 rounded-full p-2 shadow-lg"
title="Verified"
>
<span className="text-white text-lg">β</span>
</motion.div>
)}
</div>
{/* Role and title */}
<div className="mb-4">
<h2 className="text-xl lg:text-2xl font-bold text-white/90 mb-2">
{profile.title || getRoleName(profile.role)}
</h2>
<p className="text-lg text-white/80 font-medium">
Representative and initiator of the Bordeaux Prison Case
</p>
</div>
{/* Location and contact info */}
<div className="flex flex-wrap justify-center lg:justify-start gap-4 mb-6">
<motion.div
whileHover={{ scale: 1.05 }}
className="flex items-center gap-2 bg-white/20 backdrop-blur-sm px-4 py-2 rounded-full"
>
<span className="text-white text-lg">π</span>
<span className="text-white font-medium">MontrΓ©al</span>
</motion.div>
{profile.workPhone && (
<motion.div
whileHover={{ scale: 1.05 }}
className="flex items-center gap-2 bg-white/20 backdrop-blur-sm px-4 py-2 rounded-full"
>
<span className="text-white text-lg">π</span>
<span className="text-white font-medium">{profile.workPhone}</span>
</motion.div>
)}
<motion.div
whileHover={{ scale: 1.05 }}
className="flex items-center gap-2 bg-white/20 backdrop-blur-sm px-4 py-2 rounded-full"
>
<span className="text-white text-lg">π§</span>
<span className="text-white font-medium">{profile.email}</span>
</motion.div>
</div>
</motion.div>
{/* Enhanced stats */}
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ delay: 0.5, duration: 0.6 }}
className="grid grid-cols-3 gap-6 mb-6"
>
<motion.div
whileHover={{ scale: 1.05, y: -5 }}
className="bg-white/20 backdrop-blur-sm rounded-xl p-4 text-center"
>
<div className="text-2xl font-bold text-white">{stats?.followers || 0}</div>
<div className="text-sm text-white/80 font-medium">Followers</div>
</motion.div>
<motion.div
whileHover={{ scale: 1.05, y: -5 }}
className="bg-white/20 backdrop-blur-sm rounded-xl p-4 text-center"
>
<div className="text-2xl font-bold text-white">{stats?.endorsements || 0}</div>
<div className="text-sm text-white/80 font-medium">Endorsements</div>
</motion.div>
<motion.div
whileHover={{ scale: 1.05, y: -5 }}
className="bg-white/20 backdrop-blur-sm rounded-xl p-4 text-center"
>
<div className="text-2xl font-bold text-white">{stats?.mutualFriends || 0}</div>
<div className="text-sm text-white/80 font-medium">Mutual</div>
</motion.div>
</motion.div>
</div>
</div>
{/* Enhanced action buttons */}
{!isOwnProfile && (
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ delay: 0.6, duration: 0.6 }}
className="flex flex-wrap justify-center gap-4 mt-8"
>
<motion.button
whileHover={{ scale: 1.05, y: -3 }}
whileTap={{ scale: 0.95 }}
onClick={() => handleSocialAction('follow')}
disabled={isFollowing}
className="bg-gradient-to-r from-blue-500 to-blue-600 hover:from-blue-600 hover:to-blue-700 text-white px-6 py-3 rounded-xl shadow-lg transition-all text-base font-bold disabled:opacity-50 flex items-center gap-2"
>
<span>{isFollowing ? 'β' : '+'}</span>
{isFollowing ? 'Following' : 'Follow'}
</motion.button>
<motion.button
whileHover={{ scale: 1.05, y: -3 }}
whileTap={{ scale: 0.95 }}
onClick={() => handleSocialAction('message')}
disabled={isMessaging}
className="bg-gradient-to-r from-pink-500 to-pink-600 hover:from-pink-600 hover:to-pink-700 text-white px-6 py-3 rounded-xl shadow-lg transition-all text-base font-bold flex items-center gap-2"
>
<span>π¬</span>
Message
</motion.button>
<motion.button
whileHover={{ scale: 1.05, y: -3 }}
whileTap={{ scale: 0.95 }}
onClick={() => handleSocialAction('endorse')}
disabled={isEndorsing}
className="bg-gradient-to-r from-yellow-400 to-yellow-500 hover:from-yellow-500 hover:to-yellow-600 text-white px-6 py-3 rounded-xl shadow-lg transition-all text-base font-bold flex items-center gap-2"
>
<span>β</span>
Endorse
</motion.button>
<motion.button
whileHover={{ scale: 1.05, y: -3 }}
whileTap={{ scale: 0.95 }}
onClick={() => handleSocialAction('share')}
disabled={isSharing}
className="bg-gradient-to-r from-gray-500 to-gray-600 hover:from-gray-600 hover:to-gray-700 text-white px-6 py-3 rounded-xl shadow-lg transition-all text-base font-bold flex items-center gap-2"
>
<span>π€</span>
Share
</motion.button>
</motion.div>
)}
</div>
</motion.div>
{/* PROFESSIONAL BADGES & CERTIFICATIONS */}
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ delay: 0.9, duration: 0.6 }}
className="max-w-3xl mx-auto mb-8"
>
<div className="bg-white dark:bg-gray-800 rounded-2xl shadow-lg p-6 border border-gray-100 dark:border-gray-700">
<h3 className="text-lg font-bold text-gray-900 dark:text-white mb-4 flex items-center gap-2">
<span className="text-yellow-600">π
</span> Professional Credentials
</h3>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
{/* Barreau Badge */}
<motion.div
whileHover={{ scale: 1.05, y: -5 }}
className="bg-gradient-to-br from-blue-50 to-blue-100 dark:from-blue-900 dark:to-blue-800 rounded-xl p-4 border border-blue-200 dark:border-blue-700"
>
<div className="flex items-center gap-3">
<div className="w-12 h-12 bg-blue-500 rounded-full flex items-center justify-center">
<span className="text-white text-xl">βοΈ</span>
</div>
<div>
<div className="font-bold text-blue-900 dark:text-blue-100">Barreau du QuΓ©bec</div>
<div className="text-sm text-blue-700 dark:text-blue-300">Licensed Attorney</div>
</div>
</div>
</motion.div>
{/* Case Experience Badge */}
<motion.div
whileHover={{ scale: 1.05, y: -5 }}
className="bg-gradient-to-br from-purple-50 to-purple-100 dark:from-purple-900 dark:to-purple-800 rounded-xl p-4 border border-purple-200 dark:border-purple-700"
>
<div className="flex items-center gap-3">
<div className="w-12 h-12 bg-purple-500 rounded-full flex items-center justify-center">
<span className="text-white text-xl">ποΈ</span>
</div>
<div>
<div className="font-bold text-purple-900 dark:text-purple-100">Prison Law Expert</div>
<div className="text-sm text-purple-700 dark:text-purple-300">Specialized Cases</div>
</div>
</div>
</motion.div>
{/* Experience Badge */}
<motion.div
whileHover={{ scale: 1.05, y: -5 }}
className="bg-gradient-to-br from-green-50 to-green-100 dark:from-green-900 dark:to-green-800 rounded-xl p-4 border border-green-200 dark:border-green-700"
>
<div className="flex items-center gap-3">
<div className="w-12 h-12 bg-green-500 rounded-full flex items-center justify-center">
<span className="text-white text-xl">β</span>
</div>
<div>
<div className="font-bold text-green-900 dark:text-green-100">10+ Years</div>
<div className="text-sm text-green-700 dark:text-green-300">Legal Experience</div>
</div>
</div>
</motion.div>
</div>
</div>
</motion.div>
{/* ABOUT & CONTACT (single card) */}
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ delay: 0.8, duration: 0.6 }}
className="max-w-3xl mx-auto mb-8"
>
<div className="bg-white dark:bg-gray-800 rounded-2xl shadow-lg p-6 flex flex-col md:flex-row md:items-center md:justify-between gap-6 border border-gray-100 dark:border-gray-700">
<div>
<h2 className="text-lg font-bold text-gray-900 dark:text-white mb-2 flex items-center gap-2">
<span className="text-blue-600 dark:text-blue-400">βΉοΈ</span> About
</h2>
<p className="text-gray-700 dark:text-gray-300 mb-2 leading-relaxed">
{profile.bio || 'No bio provided.'}
</p>
<motion.div
whileHover={{ x: 5 }}
className="flex items-center gap-2 text-gray-600 dark:text-gray-400 mb-1"
>
<span>π</span>
<span>{profile.officeLocation || 'Location not set'}</span>
</motion.div>
</div>
<div>
<h2 className="text-lg font-bold text-gray-900 dark:text-white mb-2 flex items-center gap-2">
<span className="text-green-600 dark:text-green-400">π</span> Contact
</h2>
<motion.div
whileHover={{ x: 5 }}
className="flex items-center gap-2 text-gray-600 dark:text-gray-400 mb-1"
>
<span>π§</span>
<a href={`mailto:${profile.email}`} className="hover:underline hover:text-blue-600 dark:hover:text-blue-400 transition-colors">
{profile.email}
</a>
</motion.div>
{profile.workPhone && (
<motion.div
whileHover={{ x: 5 }}
className="flex items-center gap-2 text-gray-600 dark:text-gray-400 mb-1"
>
<span>π</span>
<span>{profile.workPhone}</span>
</motion.div>
)}
</div>
</div>
</motion.div>
{/* ENHANCED STATISTICS DASHBOARD */}
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ delay: 1.0, duration: 0.6 }}
className="max-w-3xl mx-auto mb-8"
>
<div className="bg-gradient-to-r from-purple-100 via-pink-50 to-blue-100 dark:from-purple-900 dark:via-pink-900 dark:to-blue-900 rounded-2xl shadow-lg p-6">
<h3 className="text-lg font-bold text-gray-900 dark:text-white mb-6 flex items-center gap-2">
<span>π</span> Professional Statistics
</h3>
{/* Main Stats Grid */}
<div className="grid grid-cols-2 md:grid-cols-4 gap-4 mb-6">
<motion.div
whileHover={{ scale: 1.05 }}
className="bg-white/80 dark:bg-gray-800/80 backdrop-blur-sm rounded-xl p-4 text-center"
>
<div className="text-2xl font-bold text-purple-700 dark:text-purple-300">{profile.totalCases || 0}</div>
<div className="text-sm text-gray-600 dark:text-gray-400 font-medium">Total Cases</div>
</motion.div>
<motion.div
whileHover={{ scale: 1.05 }}
className="bg-white/80 dark:bg-gray-800/80 backdrop-blur-sm rounded-xl p-4 text-center"
>
<div className="text-2xl font-bold text-green-700 dark:text-green-300">{profile.wonCases || 0}</div>
<div className="text-sm text-gray-600 dark:text-gray-400 font-medium">Won Cases</div>
</motion.div>
<motion.div
whileHover={{ scale: 1.05 }}
className="bg-white/80 dark:bg-gray-800/80 backdrop-blur-sm rounded-xl p-4 text-center"
>
<div className="text-2xl font-bold text-blue-700 dark:text-blue-300">{profile.averageRating || 0}</div>
<div className="text-sm text-gray-600 dark:text-gray-400 font-medium">Rating</div>
</motion.div>
<motion.div
whileHover={{ scale: 1.05 }}
className="bg-white/80 dark:bg-gray-800/80 backdrop-blur-sm rounded-xl p-4 text-center"
>
<div className="text-2xl font-bold text-yellow-700 dark:text-yellow-300">{profile.level || 1}</div>
<div className="text-sm text-gray-600 dark:text-gray-400 font-medium">Level</div>
</motion.div>
</div>
{/* Experience Progress */}
<div className="bg-white/80 dark:bg-gray-800/80 backdrop-blur-sm rounded-xl p-4 mb-4">
<div className="flex items-center justify-between mb-2">
<span className="font-semibold text-gray-900 dark:text-white">Experience Progress</span>
<span className="text-sm text-gray-600 dark:text-gray-400">{profile.xpPoints || 0} / {(profile.level || 1) * 1000} XP</span>
</div>
<div className="w-full bg-gray-200 dark:bg-gray-700 rounded-full h-3">
<motion.div
initial={{ width: 0 }}
animate={{ width: `${Math.min((profile.xpPoints || 0) % 1000 / 10, 100)}%` }}
transition={{ duration: 1, delay: 0.5 }}
className="h-3 bg-gradient-to-r from-purple-400 to-blue-400 rounded-full"
/>
</div>
</div>
{/* Achievements Preview */}
<div className="bg-white/80 dark:bg-gray-800/80 backdrop-blur-sm rounded-xl p-4">
<h4 className="font-semibold text-gray-900 dark:text-white mb-3 flex items-center gap-2">
<span>π</span> Recent Achievements
</h4>
<div className="grid grid-cols-2 md:grid-cols-3 gap-3">
{achievements && achievements.length > 0 ? achievements.slice(0, 3).map((ach, idx) => (
<motion.div
key={ach.id || idx}
whileHover={{ scale: 1.05 }}
className="bg-gradient-to-br from-yellow-50 to-orange-50 dark:from-yellow-900 dark:to-orange-900 rounded-lg p-3 text-center border border-yellow-200 dark:border-yellow-700"
>
<div className="text-2xl mb-1">{ach.icon || 'β'}</div>
<div className="font-semibold text-gray-800 dark:text-gray-200 text-sm">{ach.name}</div>
</motion.div>
)) : (
<div className="col-span-full text-center text-gray-500 dark:text-gray-400 py-4">
No achievements yet. Start your journey!
</div>
)}
</div>
</div>
</div>
</motion.div>
{/* LIVE ACTIVITY FEED (single, modern card) */}
<div className="max-w-3xl mx-auto mb-8">
<div className="bg-white dark:bg-gray-800 rounded-2xl shadow-lg p-6">
<h3 className="text-lg font-bold text-gray-900 dark:text-white mb-4 flex items-center gap-2"><span>π’</span> Live Activity</h3>
<div className="divide-y divide-gray-200 dark:divide-gray-700">
{(activities && activities.length > 0) ? activities.slice(0, 7).map((activity, idx) => (
<div key={activity.id || idx} className="flex items-center gap-3 py-3">
<div className="w-10 h-10 rounded-full bg-gradient-to-br from-purple-300 to-blue-200 flex items-center justify-center text-xl">
{activity.icon || 'π'}
</div>
<div className="flex-1">
<div className="font-semibold text-gray-800 dark:text-gray-200">{activity.title}</div>
<div className="text-xs text-gray-500 dark:text-gray-400">{activity.timestamp ? new Date(activity.timestamp).toLocaleString() : ''}</div>
</div>
</div>
)) : <div className="text-center text-gray-400 dark:text-gray-500 py-6">No recent activity</div>}
</div>
</div>
</div>
{/* QUICK ACTION CARDS */}
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ delay: 1.1, duration: 0.6 }}
className="max-w-3xl mx-auto mb-8"
>
<div className="bg-white dark:bg-gray-800 rounded-2xl shadow-lg p-6 border border-gray-100 dark:border-gray-700">
<h3 className="text-lg font-bold text-gray-900 dark:text-white mb-6 flex items-center gap-2">
<span className="text-purple-600">β‘</span> Quick Actions
</h3>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
{/* Schedule Consultation */}
<motion.button
whileHover={{ scale: 1.05, y: -5 }}
whileTap={{ scale: 0.95 }}
onClick={() => window.location.href = `/calendar?user=${profile.username}`}
className="bg-gradient-to-br from-blue-500 to-blue-600 hover:from-blue-600 hover:to-blue-700 text-white p-4 rounded-xl shadow-lg transition-all"
>
<div className="flex items-center gap-3">
<div className="w-10 h-10 bg-white/20 rounded-full flex items-center justify-center">
<span className="text-xl">π
</span>
</div>
<div className="text-left">
<div className="font-bold">Schedule Consultation</div>
<div className="text-sm opacity-90">Book a meeting</div>
</div>
</div>
</motion.button>
{/* Request Case Review */}
<motion.button
whileHover={{ scale: 1.05, y: -5 }}
whileTap={{ scale: 0.95 }}
onClick={() => window.location.href = `/hire?lawyer=${profile.username}`}
className="bg-gradient-to-br from-green-500 to-green-600 hover:from-green-600 hover:to-green-700 text-white p-4 rounded-xl shadow-lg transition-all"
>
<div className="flex items-center gap-3">
<div className="w-10 h-10 bg-white/20 rounded-full flex items-center justify-center">
<span className="text-xl">π</span>
</div>
<div className="text-left">
<div className="font-bold">Request Review</div>
<div className="text-sm opacity-90">Get case evaluation</div>
</div>
</div>
</motion.button>
{/* Send Message */}
<motion.button
whileHover={{ scale: 1.05, y: -5 }}
whileTap={{ scale: 0.95 }}
onClick={() => handleSocialAction('message')}
className="bg-gradient-to-br from-pink-500 to-pink-600 hover:from-pink-600 hover:to-pink-700 text-white p-4 rounded-xl shadow-lg transition-all"
>
<div className="flex items-center gap-3">
<div className="w-10 h-10 bg-white/20 rounded-full flex items-center justify-center">
<span className="text-xl">π¬</span>
</div>
<div className="text-left">
<div className="font-bold">Send Message</div>
<div className="text-sm opacity-90">Direct contact</div>
</div>
</div>
</motion.button>
{/* View Cases */}
<motion.button
whileHover={{ scale: 1.05, y: -5 }}
whileTap={{ scale: 0.95 }}
onClick={() => window.location.href = `/cases?lawyer=${profile.username}`}
className="bg-gradient-to-br from-purple-500 to-purple-600 hover:from-purple-600 hover:to-purple-700 text-white p-4 rounded-xl shadow-lg transition-all"
>
<div className="flex items-center gap-3">
<div className="w-10 h-10 bg-white/20 rounded-full flex items-center justify-center">
<span className="text-xl">βοΈ</span>
</div>
<div className="text-left">
<div className="font-bold">View Cases</div>
<div className="text-sm opacity-90">See past work</div>
</div>
</div>
</motion.button>
{/* Download CV */}
<motion.button
whileHover={{ scale: 1.05, y: -5 }}
whileTap={{ scale: 0.95 }}
onClick={() => window.open('/api/users/cv', '_blank')}
className="bg-gradient-to-br from-yellow-500 to-yellow-600 hover:from-yellow-600 hover:to-yellow-700 text-white p-4 rounded-xl shadow-lg transition-all"
>
<div className="flex items-center gap-3">
<div className="w-10 h-10 bg-white/20 rounded-full flex items-center justify-center">
<span className="text-xl">π</span>
</div>
<div className="text-left">
<div className="font-bold">Download CV</div>
<div className="text-sm opacity-90">Professional resume</div>
</div>
</div>
</motion.button>
{/* Share Profile */}
<motion.button
whileHover={{ scale: 1.05, y: -5 }}
whileTap={{ scale: 0.95 }}
onClick={() => handleSocialAction('share')}
className="bg-gradient-to-br from-gray-500 to-gray-600 hover:from-gray-600 hover:to-gray-700 text-white p-4 rounded-xl shadow-lg transition-all"
>
<div className="flex items-center gap-3">
<div className="w-10 h-10 bg-white/20 rounded-full flex items-center justify-center">
<span className="text-xl">π€</span>
</div>
<div className="text-left">
<div className="font-bold">Share Profile</div>
<div className="text-sm opacity-90">Spread the word</div>
</div>
</div>
</motion.button>
</div>
</div>
</motion.div>
{/* PROFILE INTERACTION PANEL */}
<div className="max-w-3xl mx-auto mb-8">
<ProfileInteractionPanel
profileId={profile.id}
profileName={profile.name}
isOwnProfile={!!isOwnProfile}
isOnline={!!profile.showOnlineStatus || !!isOwnProfile}
onStartMessage={() => handleSocialAction('message')}
onScheduleMeeting={() => {
// Open scheduling modal or redirect to calendar
window.location.href = `/calendar?user=${profile.username}`;
}}
/>
</div>
{/* ROLE-SPECIFIC QUICK ACTIONS */}
{!isOwnProfile && (
<div className="max-w-3xl mx-auto mb-8">
<div className="bg-white dark:bg-gray-800 rounded-2xl shadow-lg p-6">
<h3 className="text-lg font-bold text-gray-900 dark:text-white mb-4 flex items-center gap-2">
<span>β‘</span> Quick Actions for {profile.name}
</h3>
{/* Role-based quick actions */}
{profile.role === 'LAWYER' && (
<div className="grid grid-cols-1 md:grid-cols-3 gap-4">
<button
onClick={() => window.location.href = `/hire?lawyer=${profile.username}`}
className="flex items-center p-4 border border-gray-200 dark:border-gray-700 rounded-lg hover:bg-gray-50 dark:hover:bg-gray-700 transition-colors"
>
<span className="text-2xl mr-3">πΌ</span>
<div className="text-left">
<div className="font-medium text-gray-900 dark:text-gray-100">Hire Lawyer</div>
<div className="text-sm text-gray-500 dark:text-gray-400">Start legal consultation</div>
</div>
</button>
<button
onClick={() => window.location.href = `/cases?lawyer=${profile.username}`}
className="flex items-center p-4 border border-gray-200 dark:border-gray-700 rounded-lg hover:bg-gray-50 dark:hover:bg-gray-700 transition-colors"
>
<span className="text-2xl mr-3">βοΈ</span>
<div className="text-left">
<div className="font-medium text-gray-900 dark:text-gray-100">View Cases</div>
<div className="text-sm text-gray-500 dark:text-gray-400">See their work</div>
</div>
</button>
<button
onClick={() => window.location.href = `/calendar?user=${profile.username}`}
className="flex items-center p-4 border border-gray-200 dark:border-gray-700 rounded-lg hover:bg-gray-50 dark:hover:bg-gray-700 transition-colors"
>
<span className="text-2xl mr-3">π
</span>
<div className="text-left">
<div className="font-medium text-gray-900 dark:text-gray-100">Schedule Meeting</div>
<div className="text-sm text-gray-500 dark:text-gray-400">Book consultation</div>
</div>
</button>
</div>
)}
{profile.role === 'SUPERADMIN' && (
<div className="grid grid-cols-1 md:grid-cols-3 gap-4">
<button
onClick={() => window.location.href = `/class-action`}
className="flex items-center p-4 border border-gray-200 rounded-lg hover:bg-gray-50 transition-colors"
>
<span className="text-2xl mr-3">ποΈ</span>
<div className="text-left">
<div className="font-medium text-gray-900">Class Action</div>
<div className="text-sm text-gray-500">Join legal action</div>
</div>
</button>
<button
onClick={() => window.location.href = `/contact`}
className="flex items-center p-4 border border-gray-200 rounded-lg hover:bg-gray-50 transition-colors"
>
<span className="text-2xl mr-3">π</span>
<div className="text-left">
<div className="font-medium text-gray-900">Contact Representative</div>
<div className="text-sm text-gray-500">Get legal help</div>
</div>
</button>
<button
onClick={() => window.location.href = `/resources`}
className="flex items-center p-4 border border-gray-200 rounded-lg hover:bg-gray-50 transition-colors"
>
<span className="text-2xl mr-3">π</span>
<div className="text-left">
<div className="font-medium text-gray-900">Legal Resources</div>
<div className="text-sm text-gray-500">Access materials</div>
</div>
</button>
</div>
)}
{profile.role === 'CLIENT' && (
<div className="grid grid-cols-1 md:grid-cols-3 gap-4">
<button
onClick={() => window.location.href = `/client/dashboard`}
className="flex items-center p-4 border border-gray-200 rounded-lg hover:bg-gray-50 transition-colors"
>
<span className="text-2xl mr-3">π€</span>
<div className="text-left">
<div className="font-medium text-gray-900">Client Portal</div>
<div className="text-sm text-gray-500">Access dashboard</div>
</div>
</button>
<button
onClick={() => window.location.href = `/hire/new-case`}
className="flex items-center p-4 border border-gray-200 rounded-lg hover:bg-gray-50 transition-colors"
>
<span className="text-2xl mr-3">π</span>
<div className="text-left">
<div className="font-medium text-gray-900">Create Case</div>
<div className="text-sm text-gray-500">Start legal process</div>
</div>
</button>
<button
onClick={() => window.location.href = `/messages`}
className="flex items-center p-4 border border-gray-200 rounded-lg hover:bg-gray-50 transition-colors"
>
<span className="text-2xl mr-3">π¬</span>
<div className="text-left">
<div className="font-medium text-gray-900">Messages</div>
<div className="text-sm text-gray-500">View communications</div>
</div>
</button>
</div>
)}
{/* Default actions for other roles */}
{!['LAWYER', 'SUPERADMIN', 'CLIENT'].includes(profile.role) && (
<div className="grid grid-cols-1 md:grid-cols-3 gap-4">
<button
onClick={() => handleSocialAction('message')}
className="flex items-center p-4 border border-gray-200 rounded-lg hover:bg-gray-50 transition-colors"
>
<span className="text-2xl mr-3">π¬</span>
<div className="text-left">
<div className="font-medium text-gray-900">Send Message</div>
<div className="text-sm text-gray-500">Start conversation</div>
</div>
</button>
<button
onClick={() => handleSocialAction('follow')}
className="flex items-center p-4 border border-gray-200 rounded-lg hover:bg-gray-50 transition-colors"
>
<span className="text-2xl mr-3">π₯</span>
<div className="text-left">
<div className="font-medium text-gray-900">Follow</div>
<div className="text-sm text-gray-500">Stay connected</div>
</div>
</button>
<button
onClick={() => handleSocialAction('endorse')}
className="flex items-center p-4 border border-gray-200 rounded-lg hover:bg-gray-50 transition-colors"
>
<span className="text-2xl mr-3">β</span>
<div className="text-left">
<div className="font-medium text-gray-900">Endorse</div>
<div className="text-sm text-gray-500">Show support</div>
</div>
</button>
</div>
)}
</div>
</div>
)}
{/* OWN PROFILE QUICK ACTIONS */}
{isOwnProfile && (
<div className="max-w-3xl mx-auto mb-8">
<div className="bg-white rounded-2xl shadow-lg p-6">
<h3 className="text-lg font-bold text-gray-900 mb-4 flex items-center gap-2">
<span>β‘</span> Your Quick Actions
</h3>
{/* Role-based quick actions for own profile */}
{profile.role === 'SUPERADMIN' && (
<div className="grid grid-cols-1 md:grid-cols-3 gap-4">
<button
onClick={() => window.location.href = `/admin/dashboard`}
className="flex items-center p-4 border border-gray-200 rounded-lg hover:bg-gray-50 transition-colors"
>
<span className="text-2xl mr-3">π</span>
<div className="text-left">
<div className="font-medium text-gray-900">Admin Dashboard</div>
<div className="text-sm text-gray-500">System management</div>
</div>
</button>
<button
onClick={() => window.location.href = `/admin/cases`}
className="flex items-center p-4 border border-gray-200 rounded-lg hover:bg-gray-50 transition-colors"
>
<span className="text-2xl mr-3">βοΈ</span>
<div className="text-left">
<div className="font-medium text-gray-900">Case Management</div>
<div className="text-sm text-gray-500">Oversee all cases</div>
</div>
</button>
<button
onClick={() => window.location.href = `/admin/users`}
className="flex items-center p-4 border border-gray-200 rounded-lg hover:bg-gray-50 transition-colors"
>
<span className="text-2xl mr-3">π₯</span>
<div className="text-left">
<div className="font-medium text-gray-900">User Management</div>
<div className="text-sm text-gray-500">Manage users</div>
</div>
</button>
</div>
)}
{profile.role === 'LAWYER' && (
<div className="grid grid-cols-1 md:grid-cols-3 gap-4">
<button
onClick={() => window.location.href = `/lawyer/dashboard`}
className="flex items-center p-4 border border-gray-200 rounded-lg hover:bg-gray-50 transition-colors"
>
<span className="text-2xl mr-3">πΌ</span>
<div className="text-left">
<div className="font-medium text-gray-900">Lawyer Dashboard</div>
<div className="text-sm text-gray-500">Manage cases</div>
</div>
</button>
<button
onClick={() => window.location.href = `/lawyer/cases`}
className="flex items-center p-4 border border-gray-200 rounded-lg hover:bg-gray-50 transition-colors"
>
<span className="text-2xl mr-3">π</span>
<div className="text-left">
<div className="font-medium text-gray-900">My Cases</div>
<div className="text-sm text-gray-500">View assignments</div>
</div>
</button>
<button
onClick={() => window.location.href = `/lawyer/consultations`}
className="flex items-center p-4 border border-gray-200 rounded-lg hover:bg-gray-50 transition-colors"
>
<span className="text-2xl mr-3">π¬</span>
<div className="text-left">
<div className="font-medium text-gray-900">Consultations</div>
<div className="text-sm text-gray-500">Client meetings</div>
</div>
</button>
</div>
)}
{profile.role === 'CLIENT' && (
<div className="grid grid-cols-1 md:grid-cols-3 gap-4">
<button
onClick={() => window.location.href = `/client/dashboard`}
className="flex items-center p-4 border border-gray-200 rounded-lg hover:bg-gray-50 transition-colors"
>
<span className="text-2xl mr-3">π€</span>
<div className="text-left">
<div className="font-medium text-gray-900">Client Dashboard</div>
<div className="text-sm text-gray-500">View your cases</div>
</div>
</button>
<button
onClick={() => window.location.href = `/hire/new-case`}
className="flex items-center p-4 border border-gray-200 rounded-lg hover:bg-gray-50 transition-colors"
>
<span className="text-2xl mr-3">π</span>
<div className="text-left">
<div className="font-medium text-gray-900">Create New Case</div>
<div className="text-sm text-gray-500">Start legal process</div>
</div>
</button>
<button
onClick={() => window.location.href = `/messages`}
className="flex items-center p-4 border border-gray-200 rounded-lg hover:bg-gray-50 transition-colors"
>
<span className="text-2xl mr-3">π¬</span>
<div className="text-left">
<div className="font-medium text-gray-900">Messages</div>
<div className="text-sm text-gray-500">View communications</div>
</div>
</button>
</div>
)}
{/* Default actions for other roles */}
{!['SUPERADMIN', 'LAWYER', 'CLIENT'].includes(profile.role) && (
<div className="grid grid-cols-1 md:grid-cols-3 gap-4">
<button
onClick={() => window.location.href = `/user/dashboard`}
className="flex items-center p-4 border border-gray-200 rounded-lg hover:bg-gray-50 transition-colors"
>
<span className="text-2xl mr-3">π </span>
<div className="text-left">
<div className="font-medium text-gray-900">User Dashboard</div>
<div className="text-sm text-gray-500">Main dashboard</div>
</div>
</button>
<button
onClick={() => window.location.href = `/messages`}
className="flex items-center p-4 border border-gray-200 rounded-lg hover:bg-gray-50 transition-colors"
>
<span className="text-2xl mr-3">π¬</span>
<div className="text-left">
<div className="font-medium text-gray-900">Messages</div>
<div className="text-sm text-gray-500">View communications</div>
</div>
</button>
<button
onClick={() => window.location.href = `/profile/edit`}
className="flex items-center p-4 border border-gray-200 rounded-lg hover:bg-gray-50 transition-colors"
>
<span className="text-2xl mr-3">βοΈ</span>
<div className="text-left">
<div className="font-medium text-gray-900">Edit Profile</div>
<div className="text-sm text-gray-500">Update information</div>
</div>
</button>
</div>
)}
</div>
</div>
)}
{/* PRIVACY/SETTINGS (if own profile) */}
{isOwnProfile && (
<div className="max-w-3xl mx-auto mb-8">
<div className="bg-white dark:bg-gray-800 rounded-2xl shadow-lg p-6 flex flex-col gap-4">
<h2 className="text-lg font-bold text-gray-900 dark:text-white mb-2">Privacy & Settings</h2>
<div className="flex flex-col gap-2">
<label className="flex items-center gap-2">
<input type="checkbox" checked={!!profile.showOnlineStatus} onChange={() => {}} />
<span className="text-gray-700 dark:text-gray-300">Show my online status</span>
</label>
<label className="flex items-center gap-2">
<input type="checkbox" checked={!!profile.showFriends} onChange={() => {}} />
<span className="text-gray-700 dark:text-gray-300">Show my friends list</span>
</label>
<label className="flex items-center gap-2">
<input type="checkbox" checked={!!profile.showEmail} onChange={() => {}} />
<span className="text-gray-700 dark:text-gray-300">Show my email address</span>
</label>
<label className="flex items-center gap-2">
<input type="checkbox" checked={!!profile.allowMessages} onChange={() => {}} />
<span className="text-gray-700 dark:text-gray-300">Allow messages from others</span>
</label>
</div>
</div>
</div>
)}
{/* ADDITIONAL COMPONENTS */}
<div className="max-w-3xl mx-auto mb-8">
{/* Activity Feed */}
<div className="bg-white dark:bg-gray-800 rounded-2xl shadow-lg p-6 mb-6">
<h3 className="text-lg font-bold text-gray-900 dark:text-white mb-4 flex items-center gap-2">
<span>π’</span> Recent Activity
</h3>
<ActivityFeed activities={activities || []} isLoading={activityLoading} error={activityError} />
</div>
{/* Testimonials */}
<div className="bg-white dark:bg-gray-800 rounded-2xl shadow-lg p-6 mb-6">
<h3 className="text-lg font-bold text-gray-900 dark:text-white mb-4 flex items-center gap-2">
<span>π¬</span> Testimonials & Reviews
</h3>
<TestimonialsPanel testimonials={testimonials || []} reviews={reviews || []} isLoading={testimonialsLoading} error={testimonialsError} />
</div>
{/* Achievements - Temporarily disabled due to type issues */}
{/* <div className="bg-white dark:bg-gray-800 rounded-2xl shadow-lg p-6 mb-6">
<h3 className="text-lg font-bold text-gray-900 dark:text-white mb-4 flex items-center gap-2">
<span>π</span> Achievements & Badges
</h3>
<AchievementsPanel achievements={achievements || []} badges={badges || []} isLoading={activityLoading} error={activityError} />
</div> */}
</div>
{/* FLOATING EDIT PROFILE BUTTON (if own profile) */}
{isOwnProfile && (
<button
onClick={() => window.location.href = `/profile/edit`}
className="fixed bottom-8 right-8 z-50 bg-gradient-to-r from-purple-500 to-pink-500 text-white px-6 py-3 rounded-full shadow-lg text-lg font-bold hover:scale-105 transition-all"
>
Edit Profile
</button>
)}
</div>
</LayoutWithSidebar>
</>
);
};
export default PublicProfilePage;
export const getServerSideProps: GetServerSideProps = async (context) => {
const { username } = context.params as { username: string };
const session = await getServerSession(context.req, context.res, authOptions);
try {
// Find user by username
const user = await prisma.user.findUnique({
where: { username },
include: {
degrees: {
include: {
degree: true
}
},
lodgeMemberships: {
include: {
lodge: true
}
}
}
});
if (!user) {
return {
notFound: true
};
}
// Transform user data for the profile page, converting undefined to null for serialization
const profile: PublicProfile = {
id: user.id,
username: user.username || '',
name: user.name || '',
email: user.email || '',
role: user.role || '',
profilePicture: user.profilePicture || null,
bio: user.bio || null,
title: user.title || null,
specialization: user.specialization || null,
yearsOfExperience: user.yearsOfExperience || null,
education: user.education || null,
officeLocation: user.officeLocation || null,
linkedinUrl: user.linkedinUrl || null,
websiteUrl: user.websiteUrl || null,
availability: user.availability || null,
pronouns: user.pronouns || null,
language: user.language || 'en',
createdAt: user.createdAt.toISOString(),
hourlyRate: user.hourlyRate || null,
proBono: user.proBono || null,
averageRating: user.averageRating || null,
totalCases: user.totalCases || null,
wonCases: user.wonCases || null,
lostCases: user.lostCases || null,
winRate: user.winRate || null,
totalBadges: user.totalBadges || null,
isVerified: user.isVerified || null,
verificationStatus: user.verificationStatus || null,
xpPoints: user.xpPoints || null,
level: user.level || null,
boldnessRating: user.boldnessRating || null,
transparencyRating: user.transparencyRating || null,
workPhone: user.workPhone || null,
degrees: user.degrees?.map(d => ({
id: d.id,
achievedAt: d.achievedAt.toISOString(),
ceremonyDate: d.ceremonyDate?.toISOString() || null,
ceremonyCompleted: d.ceremonyCompleted,
progressPercentage: d.progressPercentage,
degree: {
id: d.degree.id,
degreeNumber: d.degree.degreeNumber,
name: d.degree.name,
title: d.degree.title || '',
track: d.degree.track,
symbol: d.degree.symbol || "",
color: d.degree.color || "",
lodgeLevel: d.degree.lodgeLevel,
isSecret: d.degree.isSecret
}
})) || [],
lodgeMemberships: user.lodgeMemberships?.map(lm => ({
id: lm.id,
role: lm.role,
isActive: lm.isActive,
joinedDate: lm.joinedDate.toISOString(),
lodge: {
id: lm.lodge.id,
name: lm.lodge.name,
track: lm.lodge.track,
lodgeLevel: lm.lodge.lodgeLevel,
isSecret: lm.lodge.isSecret
}
})) || [],
reviewsWritten: user.reviewsWritten || null,
forumPosts: user.forumPosts || null,
helpedOthers: user.helpedOthers || null,
observationHours: user.observationHours || null,
reformProposals: user.reformProposals || null,
wisdomScore: user.wisdomScore || null,
civicEngagement: user.civicEngagement || null,
showOnlineStatus: user.showOnlineStatus || false,
showFriends: user.showFriends || false,
showEmail: user.showEmail || false,
allowMessages: user.allowMessages || false
};
return {
props: {
profile,
currentUser: session?.user ? {
id: session.user.id,
username: session.user.username || null,
name: session.user.name || null,
email: session.user.email || null,
role: session.user.role || null
} : null
}
};
} catch (error) {
console.error('Error fetching profile:', error);
return {
props: {
error: 'Failed to load profile'
}
};
}
};