2026-01-20 12:37:22 +05:30
|
|
|
'use client';
|
|
|
|
|
|
2026-02-09 00:34:02 +05:30
|
|
|
import { useState, useEffect, useCallback } from 'react';
|
|
|
|
|
import { useSession } from 'next-auth/react';
|
|
|
|
|
import api from '@/services/api';
|
2026-01-20 12:37:22 +05:30
|
|
|
|
|
|
|
|
interface NotificationSetting {
|
|
|
|
|
id: string;
|
|
|
|
|
label: string;
|
|
|
|
|
description: string;
|
|
|
|
|
enabled: boolean;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
interface NotificationsFormProps {
|
|
|
|
|
onSave?: (data: {
|
|
|
|
|
emailNotifications: NotificationSetting[];
|
|
|
|
|
pushNotifications: NotificationSetting[];
|
|
|
|
|
}) => void;
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-09 00:34:02 +05:30
|
|
|
// Default notification settings (all disabled by default)
|
|
|
|
|
const DEFAULT_EMAIL_NOTIFICATIONS: NotificationSetting[] = [
|
|
|
|
|
{
|
|
|
|
|
id: 'new_leads',
|
|
|
|
|
label: 'New Leads',
|
|
|
|
|
description: 'Get notified when you receive new leads',
|
|
|
|
|
enabled: false,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
id: 'messages',
|
|
|
|
|
label: 'Messages',
|
|
|
|
|
description: 'Get notified when you receive new messages',
|
|
|
|
|
enabled: false,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
id: 'connection_requests',
|
|
|
|
|
label: 'Connection Requests',
|
|
|
|
|
description: 'Get notified about new connection requests',
|
|
|
|
|
enabled: false,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
id: 'property_updates',
|
|
|
|
|
label: 'Property Updates',
|
|
|
|
|
description: 'Get notified about property status changes',
|
|
|
|
|
enabled: false,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
id: 'marketing',
|
|
|
|
|
label: 'Marketing & Promotions',
|
|
|
|
|
description: 'Receive marketing emails and promotions',
|
|
|
|
|
enabled: false,
|
|
|
|
|
},
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
const DEFAULT_PUSH_NOTIFICATIONS: NotificationSetting[] = [
|
|
|
|
|
{
|
|
|
|
|
id: 'push_messages',
|
|
|
|
|
label: 'Messages',
|
|
|
|
|
description: 'Push notifications for new messages',
|
|
|
|
|
enabled: false,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
id: 'push_leads',
|
|
|
|
|
label: 'New Leads',
|
|
|
|
|
description: 'Push notifications for new leads',
|
|
|
|
|
enabled: false,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
id: 'push_reminders',
|
|
|
|
|
label: 'Reminders',
|
|
|
|
|
description: 'Push notifications for scheduled reminders',
|
|
|
|
|
enabled: false,
|
|
|
|
|
},
|
|
|
|
|
];
|
|
|
|
|
|
2026-01-20 12:37:22 +05:30
|
|
|
export function NotificationsForm({ onSave }: NotificationsFormProps) {
|
2026-02-09 00:34:02 +05:30
|
|
|
const { data: session } = useSession();
|
|
|
|
|
const [isLoading, setIsLoading] = useState(true);
|
|
|
|
|
const [isSaving, setIsSaving] = useState(false);
|
|
|
|
|
const [error, setError] = useState<string | null>(null);
|
|
|
|
|
const [success, setSuccess] = useState<string | null>(null);
|
|
|
|
|
|
|
|
|
|
const [emailNotifications, setEmailNotifications] = useState<NotificationSetting[]>(DEFAULT_EMAIL_NOTIFICATIONS);
|
|
|
|
|
const [pushNotifications, setPushNotifications] = useState<NotificationSetting[]>(DEFAULT_PUSH_NOTIFICATIONS);
|
|
|
|
|
|
|
|
|
|
// Fetch saved preferences on mount
|
|
|
|
|
const fetchPreferences = useCallback(async () => {
|
|
|
|
|
if (!session) return;
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
setIsLoading(true);
|
|
|
|
|
const role = (session?.user as any)?.role;
|
|
|
|
|
const endpoint = role === 'AGENT' ? '/agents/preferences/notifications' : '/users/preferences/notifications';
|
|
|
|
|
|
|
|
|
|
const response = await api.get(endpoint);
|
|
|
|
|
const savedPrefs = response.data?.data || response.data || {};
|
|
|
|
|
|
|
|
|
|
// Merge saved preferences with defaults
|
|
|
|
|
if (savedPrefs.email) {
|
|
|
|
|
setEmailNotifications((prev) =>
|
|
|
|
|
prev.map((item) => ({
|
|
|
|
|
...item,
|
|
|
|
|
enabled: savedPrefs.email[item.id] ?? item.enabled,
|
|
|
|
|
}))
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (savedPrefs.push) {
|
|
|
|
|
setPushNotifications((prev) =>
|
|
|
|
|
prev.map((item) => ({
|
|
|
|
|
...item,
|
|
|
|
|
enabled: savedPrefs.push[item.id] ?? item.enabled,
|
|
|
|
|
}))
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
} catch (err) {
|
|
|
|
|
// If no saved preferences, use defaults (all disabled)
|
|
|
|
|
console.log('No saved notification preferences found, using defaults');
|
|
|
|
|
} finally {
|
|
|
|
|
setIsLoading(false);
|
|
|
|
|
}
|
|
|
|
|
}, [session]);
|
|
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
fetchPreferences();
|
|
|
|
|
}, [fetchPreferences]);
|
2026-01-20 12:37:22 +05:30
|
|
|
|
|
|
|
|
const toggleEmailNotification = (id: string) => {
|
|
|
|
|
setEmailNotifications((prev) =>
|
|
|
|
|
prev.map((item) =>
|
|
|
|
|
item.id === id ? { ...item, enabled: !item.enabled } : item
|
|
|
|
|
)
|
|
|
|
|
);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const togglePushNotification = (id: string) => {
|
|
|
|
|
setPushNotifications((prev) =>
|
|
|
|
|
prev.map((item) =>
|
|
|
|
|
item.id === id ? { ...item, enabled: !item.enabled } : item
|
|
|
|
|
)
|
|
|
|
|
);
|
|
|
|
|
};
|
|
|
|
|
|
2026-02-09 00:34:02 +05:30
|
|
|
const handleSave = async () => {
|
|
|
|
|
setIsSaving(true);
|
|
|
|
|
setError(null);
|
|
|
|
|
setSuccess(null);
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
const role = (session?.user as any)?.role;
|
|
|
|
|
const endpoint = role === 'AGENT' ? '/agents/preferences/notifications' : '/users/preferences/notifications';
|
|
|
|
|
|
|
|
|
|
// Transform settings to API format
|
|
|
|
|
const preferences = {
|
|
|
|
|
email: emailNotifications.reduce((acc, item) => ({ ...acc, [item.id]: item.enabled }), {}),
|
|
|
|
|
push: pushNotifications.reduce((acc, item) => ({ ...acc, [item.id]: item.enabled }), {}),
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
await api.put(endpoint, preferences);
|
|
|
|
|
|
|
|
|
|
setSuccess('Notification preferences saved successfully!');
|
|
|
|
|
|
|
|
|
|
if (onSave) {
|
|
|
|
|
onSave({ emailNotifications, pushNotifications });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Clear success message after 3 seconds
|
|
|
|
|
setTimeout(() => setSuccess(null), 3000);
|
|
|
|
|
} catch (err: unknown) {
|
|
|
|
|
const error = err as { response?: { data?: { message?: string } } };
|
|
|
|
|
setError(error.response?.data?.message || 'Failed to save notification preferences. Please try again.');
|
|
|
|
|
} finally {
|
|
|
|
|
setIsSaving(false);
|
2026-01-20 12:37:22 +05:30
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const ToggleSwitch = ({
|
|
|
|
|
enabled,
|
|
|
|
|
onToggle,
|
|
|
|
|
}: {
|
|
|
|
|
enabled: boolean;
|
|
|
|
|
onToggle: () => void;
|
|
|
|
|
}) => (
|
|
|
|
|
<button
|
|
|
|
|
onClick={onToggle}
|
|
|
|
|
className={`relative w-[44px] h-[24px] rounded-full transition-colors cursor-pointer ${
|
|
|
|
|
enabled ? 'bg-[#e58625]' : 'bg-[#00293D]/20'
|
|
|
|
|
}`}
|
|
|
|
|
>
|
|
|
|
|
<div
|
|
|
|
|
className={`absolute top-[2px] w-[20px] h-[20px] rounded-full bg-white shadow transition-transform ${
|
|
|
|
|
enabled ? 'translate-x-[22px]' : 'translate-x-[2px]'
|
|
|
|
|
}`}
|
|
|
|
|
/>
|
|
|
|
|
</button>
|
|
|
|
|
);
|
|
|
|
|
|
2026-02-09 00:34:02 +05:30
|
|
|
if (isLoading) {
|
|
|
|
|
return (
|
|
|
|
|
<div className="flex items-center justify-center py-12">
|
|
|
|
|
<div className="animate-spin rounded-full h-8 w-8 border-b-2 border-[#e58625]"></div>
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-20 12:37:22 +05:30
|
|
|
return (
|
|
|
|
|
<>
|
2026-02-09 00:34:02 +05:30
|
|
|
{/* Error Message */}
|
|
|
|
|
{error && (
|
|
|
|
|
<div className="mb-4 p-3 bg-red-50 border border-red-200 rounded-[10px] text-red-700 text-[13px] font-serif">
|
|
|
|
|
{error}
|
|
|
|
|
</div>
|
|
|
|
|
)}
|
|
|
|
|
|
|
|
|
|
{/* Success Message */}
|
|
|
|
|
{success && (
|
|
|
|
|
<div className="mb-4 p-3 bg-green-50 border border-green-200 rounded-[10px] text-green-700 text-[13px] font-serif">
|
|
|
|
|
{success}
|
|
|
|
|
</div>
|
|
|
|
|
)}
|
|
|
|
|
|
2026-01-20 12:37:22 +05:30
|
|
|
{/* Email Notifications */}
|
|
|
|
|
<div className="border border-[#00293d]/10 rounded-[15px] bg-white p-6 mb-4">
|
|
|
|
|
<div className="mb-6">
|
|
|
|
|
<h2 className="font-fractul font-bold text-[16px] text-[#00293D] mb-2">
|
|
|
|
|
Email Notifications
|
|
|
|
|
</h2>
|
|
|
|
|
<p className="font-serif text-[12px] text-[#00293D]/60">
|
|
|
|
|
Manage your email notification preferences
|
|
|
|
|
</p>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div className="space-y-4">
|
|
|
|
|
{emailNotifications.map((item) => (
|
|
|
|
|
<div
|
|
|
|
|
key={item.id}
|
|
|
|
|
className="flex items-center justify-between py-3 border-b border-[#00293d]/10 last:border-0"
|
|
|
|
|
>
|
|
|
|
|
<div>
|
|
|
|
|
<h3 className="font-serif font-medium text-[14px] text-[#00293D]">
|
|
|
|
|
{item.label}
|
|
|
|
|
</h3>
|
|
|
|
|
<p className="font-serif text-[12px] text-[#00293D]/60">
|
|
|
|
|
{item.description}
|
|
|
|
|
</p>
|
|
|
|
|
</div>
|
|
|
|
|
<ToggleSwitch
|
|
|
|
|
enabled={item.enabled}
|
|
|
|
|
onToggle={() => toggleEmailNotification(item.id)}
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
))}
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
{/* Push Notifications */}
|
|
|
|
|
<div className="border border-[#00293d]/10 rounded-[15px] bg-white p-6 mb-4">
|
|
|
|
|
<div className="mb-6">
|
|
|
|
|
<h2 className="font-fractul font-bold text-[16px] text-[#00293D] mb-2">
|
|
|
|
|
Push Notifications
|
|
|
|
|
</h2>
|
|
|
|
|
<p className="font-serif text-[12px] text-[#00293D]/60">
|
|
|
|
|
Manage your push notification preferences
|
|
|
|
|
</p>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div className="space-y-4">
|
|
|
|
|
{pushNotifications.map((item) => (
|
|
|
|
|
<div
|
|
|
|
|
key={item.id}
|
|
|
|
|
className="flex items-center justify-between py-3 border-b border-[#00293d]/10 last:border-0"
|
|
|
|
|
>
|
|
|
|
|
<div>
|
|
|
|
|
<h3 className="font-serif font-medium text-[14px] text-[#00293D]">
|
|
|
|
|
{item.label}
|
|
|
|
|
</h3>
|
|
|
|
|
<p className="font-serif text-[12px] text-[#00293D]/60">
|
|
|
|
|
{item.description}
|
|
|
|
|
</p>
|
|
|
|
|
</div>
|
|
|
|
|
<ToggleSwitch
|
|
|
|
|
enabled={item.enabled}
|
|
|
|
|
onToggle={() => togglePushNotification(item.id)}
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
))}
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
{/* Save Button */}
|
|
|
|
|
<div className="flex justify-end">
|
|
|
|
|
<button
|
|
|
|
|
onClick={handleSave}
|
2026-02-09 00:34:02 +05:30
|
|
|
disabled={isSaving}
|
|
|
|
|
className="px-8 py-3 bg-[#e58625] text-white rounded-[15px] font-fractul font-medium text-[14px] hover:bg-[#d47920] transition-colors disabled:opacity-50 disabled:cursor-not-allowed"
|
2026-01-20 12:37:22 +05:30
|
|
|
>
|
2026-02-09 00:34:02 +05:30
|
|
|
{isSaving ? 'Saving...' : 'Save Changes'}
|
2026-01-20 12:37:22 +05:30
|
|
|
</button>
|
|
|
|
|
</div>
|
|
|
|
|
</>
|
|
|
|
|
);
|
|
|
|
|
}
|