![]() 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 { useState, useEffect } from 'react';
import { useSession } from 'next-auth/react';
import { motion, AnimatePresence } from 'framer-motion';
import { X, Users, Eye, EyeOff, Shield, Lock, Settings } from 'lucide-react';
interface PrivacySettings {
showFriends: boolean;
showEmail: boolean;
showPhone: boolean;
showLocation: boolean;
allowMessages: boolean;
showOnlineStatus: boolean;
}
interface PrivacySettingsModalProps {
isOpen: boolean;
onClose: () => void;
}
const PrivacySettingsModal: React.FC<PrivacySettingsModalProps> = ({ isOpen, onClose }) => {
const { data: session } = useSession();
const [settings, setSettings] = useState<PrivacySettings>({
showFriends: true,
showEmail: false,
showPhone: false,
showLocation: false,
allowMessages: true,
showOnlineStatus: true,
});
const [isLoading, setIsLoading] = useState(false);
const [message, setMessage] = useState('');
useEffect(() => {
if (isOpen && session?.user?.id) {
fetchCurrentSettings();
}
}, [isOpen, session?.user?.id]);
const fetchCurrentSettings = async () => {
try {
const response = await fetch(`/api/users/${session?.user?.id}`);
if (response.ok) {
const userData = await response.json();
setSettings({
showFriends: userData.showFriends ?? true,
showEmail: userData.showEmail ?? false,
showPhone: userData.showPhone ?? false,
showLocation: userData.showLocation ?? false,
allowMessages: userData.allowMessages ?? true,
showOnlineStatus: userData.showOnlineStatus ?? true,
});
}
} catch (error) {
console.error('Error fetching privacy settings:', error);
}
};
const handleSave = async () => {
if (!session?.user?.id) return;
setIsLoading(true);
setMessage('');
try {
const response = await fetch(`/api/users/${session.user.id}`, {
method: 'PATCH',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(settings),
});
if (response.ok) {
setMessage('Privacy settings updated successfully!');
setTimeout(() => setMessage(''), 3000);
} else {
setMessage('Failed to update privacy settings. Please try again.');
}
} catch (error) {
console.error('Error updating privacy settings:', error);
setMessage('An error occurred. Please try again.');
} finally {
setIsLoading(false);
}
};
const toggleSetting = (key: keyof PrivacySettings) => {
setSettings(prev => ({
...prev,
[key]: !prev[key],
}));
};
const privacyOptions = [
{
key: 'showFriends' as keyof PrivacySettings,
label: 'Show Friends List',
description: 'Allow others to see your friends and connections',
icon: Users,
category: 'Profile Visibility',
},
{
key: 'showEmail' as keyof PrivacySettings,
label: 'Show Email Address',
description: 'Display your email address on your profile',
icon: Eye,
category: 'Contact Information',
},
{
key: 'showPhone' as keyof PrivacySettings,
label: 'Show Phone Number',
description: 'Display your phone number on your profile',
icon: Eye,
category: 'Contact Information',
},
{
key: 'showLocation' as keyof PrivacySettings,
label: 'Show Location',
description: 'Display your location on your profile',
icon: Eye,
category: 'Profile Visibility',
},
{
key: 'allowMessages' as keyof PrivacySettings,
label: 'Allow Direct Messages',
description: 'Let other users send you private messages',
icon: Lock,
category: 'Communication',
},
{
key: 'showOnlineStatus' as keyof PrivacySettings,
label: 'Show Online Status',
description: 'Display when you are online',
icon: Eye,
category: 'Profile Visibility',
},
];
const groupedOptions = privacyOptions.reduce((acc, option) => {
if (!acc[option.category]) {
acc[option.category] = [];
}
acc[option.category].push(option);
return acc;
}, {} as Record<string, typeof privacyOptions>);
return (
<AnimatePresence>
{isOpen && (
<div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 p-4">
<motion.div
initial={{ opacity: 0, scale: 0.95 }}
animate={{ opacity: 1, scale: 1 }}
exit={{ opacity: 0, scale: 0.95 }}
className="bg-white rounded-xl shadow-2xl max-w-2xl w-full max-h-[90vh] overflow-hidden"
>
{/* Header */}
<div className="flex items-center justify-between p-6 border-b border-gray-200">
<div className="flex items-center gap-3">
<div className="p-2 bg-blue-100 rounded-lg">
<Settings className="h-6 w-6 text-blue-600" />
</div>
<div>
<h2 className="text-xl font-semibold text-gray-900">Privacy Settings</h2>
<p className="text-sm text-gray-500">Control who can see your information</p>
</div>
</div>
<button
onClick={onClose}
className="p-2 hover:bg-gray-100 rounded-lg transition-colors"
>
<X className="h-5 w-5 text-gray-500" />
</button>
</div>
{/* Content */}
<div className="p-6 overflow-y-auto max-h-[60vh]">
{message && (
<div className={`mb-4 p-3 rounded-lg text-sm ${
message.includes('successfully')
? 'bg-green-50 text-green-700 border border-green-200'
: 'bg-red-50 text-red-700 border border-red-200'
}`}>
{message}
</div>
)}
<div className="space-y-6">
{Object.entries(groupedOptions).map(([category, options]) => (
<div key={category}>
<h3 className="text-lg font-medium text-gray-900 mb-3 flex items-center gap-2">
<Shield className="h-5 w-5 text-gray-600" />
{category}
</h3>
<div className="space-y-3">
{options.map((option) => {
const Icon = option.icon;
return (
<div
key={option.key}
className="flex items-center justify-between p-4 border border-gray-200 rounded-lg hover:bg-gray-50 transition-colors"
>
<div className="flex items-start gap-3 flex-1">
<div className="p-2 bg-gray-100 rounded-lg">
<Icon className="h-4 w-4 text-gray-600" />
</div>
<div className="flex-1">
<h4 className="font-medium text-gray-900">{option.label}</h4>
<p className="text-sm text-gray-500 mt-1">{option.description}</p>
</div>
</div>
<button
onClick={() => toggleSetting(option.key)}
className={`relative inline-flex h-6 w-11 items-center rounded-full transition-colors focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 ${
settings[option.key] ? 'bg-blue-600' : 'bg-gray-200'
}`}
>
<span
className={`inline-block h-4 w-4 transform rounded-full bg-white transition-transform ${
settings[option.key] ? 'translate-x-6' : 'translate-x-1'
}`}
/>
</button>
</div>
);
})}
</div>
</div>
))}
</div>
</div>
{/* Footer */}
<div className="flex items-center justify-end gap-3 p-6 border-t border-gray-200 bg-gray-50">
<button
onClick={onClose}
className="px-4 py-2 text-gray-700 bg-white border border-gray-300 rounded-lg hover:bg-gray-50 transition-colors"
>
Cancel
</button>
<button
onClick={handleSave}
disabled={isLoading}
className="px-6 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors disabled:opacity-50 disabled:cursor-not-allowed flex items-center gap-2"
>
{isLoading ? (
<>
<div className="w-4 h-4 border-2 border-white border-t-transparent rounded-full animate-spin" />
Saving...
</>
) : (
'Save Changes'
)}
</button>
</div>
</motion.div>
</div>
)}
</AnimatePresence>
);
};
export default PrivacySettingsModal;