diff --git a/public/assets/icons/gem-icon.svg b/public/assets/icons/gem-icon.svg new file mode 100644 index 0000000..affd25f --- /dev/null +++ b/public/assets/icons/gem-icon.svg @@ -0,0 +1,3 @@ + + + diff --git a/public/assets/icons/question-circle-icon.svg b/public/assets/icons/question-circle-icon.svg new file mode 100644 index 0000000..bfca41b --- /dev/null +++ b/public/assets/icons/question-circle-icon.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/public/assets/icons/settings-billing-icon.svg b/public/assets/icons/settings-billing-icon.svg new file mode 100644 index 0000000..fde5d8e --- /dev/null +++ b/public/assets/icons/settings-billing-icon.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/public/assets/icons/settings-testimonials-icon.svg b/public/assets/icons/settings-testimonials-icon.svg new file mode 100644 index 0000000..660de4b --- /dev/null +++ b/public/assets/icons/settings-testimonials-icon.svg @@ -0,0 +1,3 @@ + + + diff --git a/public/assets/icons/tick-circle-icon.svg b/public/assets/icons/tick-circle-icon.svg new file mode 100644 index 0000000..8173a38 --- /dev/null +++ b/public/assets/icons/tick-circle-icon.svg @@ -0,0 +1,4 @@ + + + + diff --git a/public/assets/images/need-help-illustration.png b/public/assets/images/need-help-illustration.png new file mode 100644 index 0000000..8e3affb Binary files /dev/null and b/public/assets/images/need-help-illustration.png differ diff --git a/public/assets/images/subscription-plan-illustration.png b/public/assets/images/subscription-plan-illustration.png new file mode 100644 index 0000000..47d9768 Binary files /dev/null and b/public/assets/images/subscription-plan-illustration.png differ diff --git a/src/app/(agent)/agent/settings/billings/page.tsx b/src/app/(agent)/agent/settings/billings/page.tsx new file mode 100644 index 0000000..2373da6 --- /dev/null +++ b/src/app/(agent)/agent/settings/billings/page.tsx @@ -0,0 +1,18 @@ +'use client'; + +import { SettingsSidebar } from '@/components/settings'; +import { SubscriptionForm } from '@/components/settings/SubscriptionForm'; + +export default function BillingsPage() { + return ( +
+ {/* Left Sidebar */} + + + {/* Main Content */} +
+ +
+
+ ); +} diff --git a/src/app/(agent)/agent/settings/notifications/page.tsx b/src/app/(agent)/agent/settings/notifications/page.tsx index 5f889e8..62d5bf0 100644 --- a/src/app/(agent)/agent/settings/notifications/page.tsx +++ b/src/app/(agent)/agent/settings/notifications/page.tsx @@ -2,21 +2,7 @@ import { SettingsSidebar, NotificationsForm } from '@/components/settings'; -interface NotificationSetting { - id: string; - label: string; - description: string; - enabled: boolean; -} - export default function NotificationsPage() { - const handleSave = (data: { - emailNotifications: NotificationSetting[]; - pushNotifications: NotificationSetting[]; - }) => { - console.log('Saving agent notification settings:', data); - }; - return (
{/* Left Sidebar */} @@ -24,14 +10,7 @@ export default function NotificationsPage() { {/* Main Content */}
- {/* Header Card */} -
-

- Notifications -

-
- - +
); diff --git a/src/app/(agent)/agent/settings/testimonials/page.tsx b/src/app/(agent)/agent/settings/testimonials/page.tsx new file mode 100644 index 0000000..86e37e4 --- /dev/null +++ b/src/app/(agent)/agent/settings/testimonials/page.tsx @@ -0,0 +1,25 @@ +'use client'; + +import { SettingsSidebar } from '@/components/settings'; + +export default function TestimonialsPage() { + return ( +
+ {/* Left Sidebar */} + + + {/* Main Content */} +
+
+

+ Add Testimonials +

+
+

+ Testimonials management coming soon. +

+
+
+
+ ); +} diff --git a/src/app/(user)/user/settings/notifications/page.tsx b/src/app/(user)/user/settings/notifications/page.tsx index e6ddda4..0afd5ee 100644 --- a/src/app/(user)/user/settings/notifications/page.tsx +++ b/src/app/(user)/user/settings/notifications/page.tsx @@ -2,21 +2,7 @@ import { SettingsSidebar, NotificationsForm } from '@/components/settings'; -interface NotificationSetting { - id: string; - label: string; - description: string; - enabled: boolean; -} - export default function UserNotificationsPage() { - const handleSave = (data: { - emailNotifications: NotificationSetting[]; - pushNotifications: NotificationSetting[]; - }) => { - console.log('Saving user notification settings:', data); - }; - return (
@@ -25,14 +11,7 @@ export default function UserNotificationsPage() { {/* Main Content */}
- {/* Header Card */} -
-

- Notifications -

-
- - +
diff --git a/src/components/settings/NotificationsForm.tsx b/src/components/settings/NotificationsForm.tsx index 97de864..9ab1794 100644 --- a/src/components/settings/NotificationsForm.tsx +++ b/src/components/settings/NotificationsForm.tsx @@ -4,72 +4,44 @@ import { useState, useEffect, useCallback } from 'react'; import { useSession } from 'next-auth/react'; import api from '@/services/api'; -interface NotificationSetting { +type DigestFrequency = 'instant' | 'daily' | 'weekly' | 'off'; + +interface NotificationCategory { id: string; label: string; description: string; - enabled: boolean; + email: boolean; + inApp: boolean; } interface NotificationsFormProps { onSave?: (data: { - emailNotifications: NotificationSetting[]; - pushNotifications: NotificationSetting[]; + notifications: NotificationCategory[]; + digestFrequency: DigestFrequency; }) => void; } -// Default notification settings (all disabled by default) -const DEFAULT_EMAIL_NOTIFICATIONS: NotificationSetting[] = [ +const DEFAULT_NOTIFICATIONS: NotificationCategory[] = [ { - id: 'new_leads', - label: 'New Leads', - description: 'Get notified when you receive new leads', - enabled: false, + id: 'new_lead_alerts', + label: 'New Lead Alerts', + description: 'Choose what you want to be notified about and how.', + email: true, + inApp: true, }, { - id: 'messages', - label: 'Messages', - description: 'Get notified when you receive new messages', - enabled: false, + id: 'message_updates', + label: 'Message Updates', + description: 'Notices about new messages from clients or other agents.', + email: false, + inApp: true, }, { - 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, + id: 'urgent_requests_tours', + label: 'Urgent Requests & Tours', + description: 'Immediate notifications for tour requests and time-sensitive items.', + email: true, + inApp: true, }, ]; @@ -80,10 +52,9 @@ export function NotificationsForm({ onSave }: NotificationsFormProps) { const [error, setError] = useState(null); const [success, setSuccess] = useState(null); - const [emailNotifications, setEmailNotifications] = useState(DEFAULT_EMAIL_NOTIFICATIONS); - const [pushNotifications, setPushNotifications] = useState(DEFAULT_PUSH_NOTIFICATIONS); + const [notifications, setNotifications] = useState(DEFAULT_NOTIFICATIONS); + const [digestFrequency, setDigestFrequency] = useState('instant'); - // Fetch saved preferences on mount const fetchPreferences = useCallback(async () => { if (!session) return; @@ -95,26 +66,26 @@ export function NotificationsForm({ onSave }: NotificationsFormProps) { 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.notifications) { + setNotifications((prev) => + prev.map((item) => { + const saved = savedPrefs.notifications[item.id]; + if (saved) { + return { + ...item, + email: saved.email ?? item.email, + inApp: saved.inApp ?? item.inApp, + }; + } + return item; + }) ); } - if (savedPrefs.push) { - setPushNotifications((prev) => - prev.map((item) => ({ - ...item, - enabled: savedPrefs.push[item.id] ?? item.enabled, - })) - ); + if (savedPrefs.digestFrequency) { + setDigestFrequency(savedPrefs.digestFrequency); } - } catch (err) { - // If no saved preferences, use defaults (all disabled) + } catch { console.log('No saved notification preferences found, using defaults'); } finally { setIsLoading(false); @@ -125,18 +96,10 @@ export function NotificationsForm({ onSave }: NotificationsFormProps) { fetchPreferences(); }, [fetchPreferences]); - const toggleEmailNotification = (id: string) => { - setEmailNotifications((prev) => + const toggleNotification = (id: string, type: 'email' | 'inApp') => { + setNotifications((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 + item.id === id ? { ...item, [type]: !item[type] } : item ) ); }; @@ -150,10 +113,15 @@ export function NotificationsForm({ onSave }: NotificationsFormProps) { 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 }), {}), + notifications: notifications.reduce( + (acc, item) => ({ + ...acc, + [item.id]: { email: item.email, inApp: item.inApp }, + }), + {} + ), + digestFrequency, }; await api.put(endpoint, preferences); @@ -161,10 +129,9 @@ export function NotificationsForm({ onSave }: NotificationsFormProps) { setSuccess('Notification preferences saved successfully!'); if (onSave) { - onSave({ emailNotifications, pushNotifications }); + onSave({ notifications, digestFrequency }); } - // Clear success message after 3 seconds setTimeout(() => setSuccess(null), 3000); } catch (err: unknown) { const error = err as { response?: { data?: { message?: string } } }; @@ -174,27 +141,55 @@ export function NotificationsForm({ onSave }: NotificationsFormProps) { } }; - const ToggleSwitch = ({ - enabled, + const handleCancel = () => { + setNotifications(DEFAULT_NOTIFICATIONS); + setDigestFrequency('instant'); + setError(null); + setSuccess(null); + }; + + const Checkbox = ({ + checked, onToggle, + label, }: { - enabled: boolean; + checked: boolean; onToggle: () => void; + label: string; }) => ( - + > + {checked && ( + + + + )} + + {label} + ); + const frequencyOptions: { value: DigestFrequency; label: string }[] = [ + { value: 'instant', label: 'Instant' }, + { value: 'daily', label: 'Daily' }, + { value: 'weekly', label: 'Weekly' }, + { value: 'off', label: 'Off' }, + ]; + if (isLoading) { return (
@@ -219,84 +214,103 @@ export function NotificationsForm({ onSave }: NotificationsFormProps) {
)} - {/* Email Notifications */} -
-
-

- Email Notifications -

-

- Manage your email notification preferences -

-
+ {/* Notification Preferences Card */} +
+ {/* Title */} +

+ Notification Preferences +

-
- {emailNotifications.map((item) => ( -
-
-

- {item.label} -

-

- {item.description} -

+ {/* Divider */} +
+ + {/* Notification Categories */} +
+ {notifications.map((item, index) => ( +
+
+
+

+ {item.label} +

+

+ {item.description} +

+
+
+ toggleNotification(item.id, 'email')} + label="Email" + /> + toggleNotification(item.id, 'inApp')} + label="In-App" + /> +
- toggleEmailNotification(item.id)} - /> + {index < notifications.length - 1 && ( +
+ )}
))}
-
- {/* Push Notifications */} -
-
-

- Push Notifications -

-

- Manage your push notification preferences + {/* Divider before Email Digest */} +

+ + {/* Email Digest Frequency */} +
+

+ Email Digest Frequency +

+

+ Choose how often you receive non-urgent email summaries

+ + {/* Frequency Tabs */} +
+ {frequencyOptions.map((option, index) => ( + + ))} +
-
- {pushNotifications.map((item) => ( -
-
-

- {item.label} -

-

- {item.description} -

-
- togglePushNotification(item.id)} - /> -
- ))} + {/* Action Buttons */} +
+ +
- - {/* Save Button */} -
- -
); } diff --git a/src/components/settings/SettingsSidebar.tsx b/src/components/settings/SettingsSidebar.tsx index b77d9a6..93abe5f 100644 --- a/src/components/settings/SettingsSidebar.tsx +++ b/src/components/settings/SettingsSidebar.tsx @@ -67,18 +67,15 @@ export function SettingsSidebar({ setProfileData({ name, title, avatarUrl }); } catch (err) { console.error('Failed to fetch profile for sidebar:', err); - // Keep session data as fallback } }, [session]); - // Fetch profile on mount useEffect(() => { if (session) { fetchProfile(); } }, [session, fetchProfile]); - // Listen for profile update events to refresh the sidebar useEffect(() => { const handleProfileUpdate = () => { if (session) { @@ -92,6 +89,8 @@ export function SettingsSidebar({ }; }, [session, fetchProfile]); + const isAgent = basePath === '/agent/settings'; + const navItems: NavItem[] = [ { label: 'Profile Settings', @@ -99,7 +98,7 @@ export function SettingsSidebar({ icon: '/assets/icons/settings-profile-icon.svg', }, { - label: 'Password Security', + label: 'Change Password', href: `${basePath}/password`, icon: '/assets/icons/settings-lock-icon.svg', }, @@ -113,10 +112,24 @@ export function SettingsSidebar({ href: `${basePath}/privacy`, icon: '/assets/icons/settings-privacy-icon.svg', }, + ...(isAgent + ? [ + { + label: 'Billings & Payments', + href: `${basePath}/billings`, + icon: '/assets/icons/settings-billing-icon.svg', + }, + { + label: 'Add Testimonials', + href: `${basePath}/testimonials`, + icon: '/assets/icons/settings-testimonials-icon.svg', + }, + ] + : []), ]; return ( -
+
{/* Profile Card */}
@@ -148,12 +161,12 @@ export function SettingsSidebar({
- {/* Categories Card */} + {/* Settings Navigation Card */}
- {/* Categories Header */} + {/* Settings Header */}

- Categories + Settings

+ {/* Page Title */} +
+

+ Subscription & Payments +

+

+ Manage Your billing cycles , upgrade your plan , or boost individual listings +

+
+ + {/* Annual Membership Plans */} +
+

+ Annual Membership Plans +

+ + {/* Plan Card */} +
+ {/* Best Value Ribbon */} +
+
+ Best Value +
+
+ +
+ {/* Left Side - Plan Details */} +
+ {/* Annual Subscription Badge */} +
+ + Annual Subscription + +
+ + {/* Plan Name */} +

+ Professional Annual Plan +

+ + {/* Plan Description */} +

+ Complete solutions for real estate agents and lenders to grow their business. +

+ + {/* Price */} +
+ $499 + / + Year +
+ + {/* CTA Button */} + +
+ + {/* Right Side - Features + Illustration */} +
+ {/* Features */} +
+

+ Include Features +

+ +
+ {PLAN_FEATURES.map((feature) => ( +
+ + + {feature.label} + +
+ ))} +
+
+ + {/* Illustration */} +
+
+ Professional plan +
+
+
+
+
+
+ + {/* Need Help Section */} +
+ {/* Left Side - Help Content */} +
+ {/* Question Icon */} +
+ Help +
+ + {/* Title */} +

+ Need Help ? +

+ + {/* Description */} +

+ Our billing experts are here to help you with any questions about your plan. +

+ + {/* Support Email */} + + support@example.com + + +
+ + {/* Right Side - Illustration */} +
+
+ Need help illustration +
+
+
+ + ); +} diff --git a/src/components/settings/index.ts b/src/components/settings/index.ts index 8b36518..1493c3d 100644 --- a/src/components/settings/index.ts +++ b/src/components/settings/index.ts @@ -5,3 +5,4 @@ export { PasswordSecurityForm } from './PasswordSecurityForm'; export { NotificationsForm } from './NotificationsForm'; export { PrivacyForm } from './PrivacyForm'; export { TwoFactorSettings } from './TwoFactorSettings'; +export { SubscriptionForm } from './SubscriptionForm';