feat: Add Billings & Payments and Testimonials settings pages for agent and user roles, and refactor notification settings form.

This commit is contained in:
pradeepkumar
2026-02-12 05:56:10 +05:30
parent a3880bf9a7
commit 4ddb7552db
15 changed files with 435 additions and 219 deletions

View File

@@ -0,0 +1,3 @@
<svg width="21" height="21" viewBox="0 0 21 21" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M2.625 7.875L10.5 18.375L18.375 7.875M2.625 7.875L5.25 2.625H15.75L18.375 7.875M2.625 7.875H18.375M7 2.625L5.25 7.875L10.5 18.375L15.75 7.875L14 2.625" stroke="#e58625" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 349 B

View File

@@ -0,0 +1,5 @@
<svg width="35" height="35" viewBox="0 0 35 35" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M17.5 3.5C9.768 3.5 3.5 9.768 3.5 17.5C3.5 25.232 9.768 31.5 17.5 31.5C25.232 31.5 31.5 25.232 31.5 17.5C31.5 9.768 25.232 3.5 17.5 3.5Z" stroke="#e58625" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M13.125 13.125C13.125 10.709 15.084 8.75 17.5 8.75C19.916 8.75 21.875 10.709 21.875 13.125C21.875 15.541 19.916 17.5 17.5 17.5V20.125" stroke="#e58625" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<circle cx="17.5" cy="24.5" r="1.5" fill="#e58625"/>
</svg>

After

Width:  |  Height:  |  Size: 613 B

View File

@@ -0,0 +1,5 @@
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M17.5 4.16667H2.5C1.80964 4.16667 1.25 4.72631 1.25 5.41667V14.5833C1.25 15.2737 1.80964 15.8333 2.5 15.8333H17.5C18.1904 15.8333 18.75 15.2737 18.75 14.5833V5.41667C18.75 4.72631 18.1904 4.16667 17.5 4.16667Z" stroke="#00293D" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M1.25 8.33333H18.75" stroke="#00293D" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M5 12.5H8.33333" stroke="#00293D" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 634 B

View File

@@ -0,0 +1,3 @@
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M10 1.66667L12.575 6.88334L18.3333 7.72501L14.1667 11.7833L15.15 17.5167L10 14.8083L4.85 17.5167L5.83333 11.7833L1.66667 7.72501L7.425 6.88334L10 1.66667Z" stroke="#00293D" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 353 B

View File

@@ -0,0 +1,4 @@
<svg width="21" height="21" viewBox="0 0 21 21" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M10.5 1.75C5.67 1.75 1.75 5.67 1.75 10.5C1.75 15.33 5.67 19.25 10.5 19.25C15.33 19.25 19.25 15.33 19.25 10.5C19.25 5.67 15.33 1.75 10.5 1.75Z" fill="#e58625"/>
<path d="M7 10.5L9.333 12.833L14 8.167" stroke="white" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 395 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 309 KiB

View File

@@ -0,0 +1,18 @@
'use client';
import { SettingsSidebar } from '@/components/settings';
import { SubscriptionForm } from '@/components/settings/SubscriptionForm';
export default function BillingsPage() {
return (
<div className="flex flex-col lg:flex-row gap-6">
{/* Left Sidebar */}
<SettingsSidebar basePath="/agent/settings" />
{/* Main Content */}
<div className="flex-1">
<SubscriptionForm />
</div>
</div>
);
}

View File

@@ -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 (
<div className="flex flex-col lg:flex-row gap-6">
{/* Left Sidebar */}
@@ -24,14 +10,7 @@ export default function NotificationsPage() {
{/* Main Content */}
<div className="flex-1">
{/* Header Card */}
<div className="border border-[#00293d]/10 rounded-[15px] px-6 py-4 mb-4 bg-white">
<h1 className="font-fractul font-bold text-[15px] leading-[18px] text-[#00293D]">
Notifications
</h1>
</div>
<NotificationsForm onSave={handleSave} />
<NotificationsForm />
</div>
</div>
);

View File

@@ -0,0 +1,25 @@
'use client';
import { SettingsSidebar } from '@/components/settings';
export default function TestimonialsPage() {
return (
<div className="flex flex-col lg:flex-row gap-6">
{/* Left Sidebar */}
<SettingsSidebar basePath="/agent/settings" />
{/* Main Content */}
<div className="flex-1">
<div className="border border-[#00293d]/10 rounded-[15px] bg-white p-6">
<h2 className="font-fractul font-bold text-[20px] text-[#00293D] mb-4">
Add Testimonials
</h2>
<div className="border-b border-[#00293D]/10 mb-6" />
<p className="font-serif text-[14px] text-[#00293D]/70">
Testimonials management coming soon.
</p>
</div>
</div>
</div>
);
}

View File

@@ -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 (
<div className="max-w-7xl mx-auto px-4 lg:px-8 py-6">
<div className="flex flex-col lg:flex-row gap-6">
@@ -25,14 +11,7 @@ export default function UserNotificationsPage() {
{/* Main Content */}
<div className="flex-1">
{/* Header Card */}
<div className="border border-[#00293d]/10 rounded-[15px] px-6 py-4 mb-4 bg-white">
<h1 className="font-fractul font-bold text-[15px] leading-[18px] text-[#00293D]">
Notifications
</h1>
</div>
<NotificationsForm onSave={handleSave} />
<NotificationsForm />
</div>
</div>
</div>

View File

@@ -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<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);
const [notifications, setNotifications] = useState<NotificationCategory[]>(DEFAULT_NOTIFICATIONS);
const [digestFrequency, setDigestFrequency] = useState<DigestFrequency>('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) => ({
if (savedPrefs.notifications) {
setNotifications((prev) =>
prev.map((item) => {
const saved = savedPrefs.notifications[item.id];
if (saved) {
return {
...item,
enabled: savedPrefs.email[item.id] ?? item.enabled,
}))
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;
}) => (
<label className="flex items-center gap-2 cursor-pointer">
<button
type="button"
onClick={onToggle}
className={`relative w-[44px] h-[24px] rounded-full transition-colors cursor-pointer ${
enabled ? 'bg-[#e58625]' : 'bg-[#00293D]/20'
className={`w-[16px] h-[16px] rounded-[2px] border flex items-center justify-center transition-colors ${
checked
? 'bg-[#00293D] border-[#00293D]'
: 'bg-white border-[#00293D]/30'
}`}
>
<div
className={`absolute top-[2px] w-[20px] h-[20px] rounded-full bg-white shadow transition-transform ${
enabled ? 'translate-x-[22px]' : 'translate-x-[2px]'
}`}
{checked && (
<svg width="10" height="8" viewBox="0 0 10 8" fill="none">
<path
d="M1 4L3.5 6.5L9 1"
stroke="white"
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
)}
</button>
<span className="font-serif text-[14px] text-[#00293D]">{label}</span>
</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 (
<div className="flex items-center justify-center py-12">
@@ -219,84 +214,103 @@ export function NotificationsForm({ onSave }: NotificationsFormProps) {
</div>
)}
{/* 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
{/* Notification Preferences Card */}
<div className="border border-[#00293d]/10 rounded-[15px] bg-white p-6">
{/* Title */}
<h2 className="font-fractul font-bold text-[20px] text-[#00293D] mb-4">
Notification Preferences
</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]">
{/* Divider */}
<div className="border-b border-[#00293D]/10 mb-6" />
{/* Notification Categories */}
<div className="space-y-0">
{notifications.map((item, index) => (
<div key={item.id}>
<div className="flex items-start justify-between py-4">
<div className="flex-1 pr-4">
<h3 className="font-fractul font-bold text-[14px] text-[#00293D] mb-1">
{item.label}
</h3>
<p className="font-serif text-[12px] text-[#00293D]/60">
<p className="font-serif text-[14px] text-[#00293D]/70">
{item.description}
</p>
</div>
<ToggleSwitch
enabled={item.enabled}
onToggle={() => toggleEmailNotification(item.id)}
<div className="flex items-center gap-8 flex-shrink-0">
<Checkbox
checked={item.email}
onToggle={() => toggleNotification(item.id, 'email')}
label="Email"
/>
<Checkbox
checked={item.inApp}
onToggle={() => toggleNotification(item.id, 'inApp')}
label="In-App"
/>
</div>
</div>
{index < notifications.length - 1 && (
<div className="border-b border-[#00293D]/10" />
)}
</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>
{/* Divider before Email Digest */}
<div className="border-b border-[#00293D]/10 mt-2 mb-6" />
<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}
{/* Email Digest Frequency */}
<div className="mb-8">
<h3 className="font-fractul font-bold text-[14px] text-[#00293D] mb-1">
Email Digest Frequency
</h3>
<p className="font-serif text-[12px] text-[#00293D]/60">
{item.description}
<p className="font-serif text-[14px] text-[#00293D]/70 mb-4">
Choose how often you receive non-urgent email summaries
</p>
</div>
<ToggleSwitch
enabled={item.enabled}
onToggle={() => togglePushNotification(item.id)}
/>
</div>
))}
</div>
</div>
{/* Save Button */}
<div className="flex justify-end">
{/* Frequency Tabs */}
<div className="inline-flex border border-[#00293D]/10 rounded-[7px] overflow-hidden">
{frequencyOptions.map((option, index) => (
<button
key={option.value}
type="button"
onClick={() => setDigestFrequency(option.value)}
className={`px-5 py-2 text-[14px] font-fractul transition-colors ${
digestFrequency === option.value
? 'bg-[#e58625] text-[#00293D] font-medium'
: 'bg-white text-[#00293D] hover:bg-[#00293D]/5'
} ${
index < frequencyOptions.length - 1
? 'border-r border-[#00293D]/10'
: ''
}`}
>
{option.label}
</button>
))}
</div>
</div>
{/* Action Buttons */}
<div className="flex justify-end gap-4 pt-4 border-t border-[#00293D]/10">
<button
type="button"
onClick={handleCancel}
className="px-10 py-3 border border-[#00293D]/10 rounded-[15px] font-fractul font-bold text-[14px] text-[#00293D] hover:bg-[#00293D]/5 transition-colors"
>
Cancel
</button>
<button
type="button"
onClick={handleSave}
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"
className="px-10 py-3 bg-[#e58625] rounded-[15px] font-fractul font-bold text-[14px] text-[#00293D] hover:bg-[#d47920] transition-colors disabled:opacity-50 disabled:cursor-not-allowed"
>
{isSaving ? 'Saving...' : 'Save Changes'}
</button>
</div>
</div>
</>
);
}

View File

@@ -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 (
<div className="w-full lg:w-[300px] space-y-4">
<div className="w-full lg:w-[300px] space-y-4 flex-shrink-0">
{/* Profile Card */}
<div className="bg-white rounded-[15px] border border-[#00293D]/20 p-5">
<div className="flex items-center gap-4">
@@ -148,12 +161,12 @@ export function SettingsSidebar({
</div>
</div>
{/* Categories Card */}
{/* Settings Navigation Card */}
<div className="bg-white rounded-[15px] border border-[#00293D]/20 overflow-hidden">
{/* Categories Header */}
{/* Settings Header */}
<div className="flex items-center justify-between px-5 py-4 border-b border-[#00293D]/10">
<h4 className="font-fractul font-bold text-[16px] leading-[19px] text-[#00293D]">
Categories
Settings
</h4>
<Image
src="/assets/icons/chevron-right-icon.svg"

View File

@@ -0,0 +1,167 @@
'use client';
import Image from 'next/image';
import Link from 'next/link';
interface PlanFeature {
icon: string;
label: string;
}
const PLAN_FEATURES: PlanFeature[] = [
{ icon: '/assets/icons/gem-icon.svg', label: 'Agent -Co-Marketing' },
{ icon: '/assets/icons/tick-circle-icon.svg', label: 'Priority 24/7 Support' },
{ icon: '/assets/icons/tick-circle-icon.svg', label: 'Whitelabel Client Portals' },
{ icon: '/assets/icons/tick-circle-icon.svg', label: 'Advanced CRM Tools & Analytics' },
];
export function SubscriptionForm() {
return (
<>
{/* Page Title */}
<div className="mb-6">
<h1 className="font-fractul font-bold text-[20px] text-[#00293D] mb-2">
Subscription & Payments
</h1>
<p className="font-serif text-[14px] text-[#00293D]/70">
Manage Your billing cycles , upgrade your plan , or boost individual listings
</p>
</div>
{/* Annual Membership Plans */}
<div className="mb-8">
<h2 className="font-fractul font-bold text-[20px] text-[#00293D] mb-4">
Annual Membership Plans
</h2>
{/* Plan Card */}
<div className="border border-[#00293D] rounded-[10px] p-8 relative overflow-hidden">
{/* Best Value Ribbon */}
<div className="absolute top-0 right-0 w-[100px] h-[100px] overflow-hidden">
<div className="absolute top-[18px] right-[-28px] bg-[#e58625] text-white text-[12px] font-fractul py-1 px-8 rotate-45 transform origin-center shadow-sm">
Best Value
</div>
</div>
<div className="flex flex-col lg:flex-row gap-8">
{/* Left Side - Plan Details */}
<div className="flex-1">
{/* Annual Subscription Badge */}
<div className="inline-block bg-[#e58625] rounded-[15px] px-4 py-2 mb-6">
<span className="font-serif text-[14px] text-white">
Annual Subscription
</span>
</div>
{/* Plan Name */}
<h3 className="font-fractul font-bold text-[20px] text-[#00293D] mb-3">
Professional Annual Plan
</h3>
{/* Plan Description */}
<p className="font-serif text-[14px] text-[#00293D] mb-6 max-w-[230px] leading-[22px]">
Complete solutions for real estate agents and lenders to grow their business.
</p>
{/* Price */}
<div className="mb-6">
<span className="font-fractul font-bold text-[35px] text-black">$499</span>
<span className="font-fractul font-bold text-[20px] text-black"> / </span>
<span className="font-fractul font-bold text-[20px] text-black/50">Year</span>
</div>
{/* CTA Button */}
<button className="bg-[#e58625] border border-[#e58625] text-white font-fractul font-bold text-[14px] px-10 py-4 rounded-[15px] hover:bg-[#d47920] transition-colors">
Get Premium Access
</button>
</div>
{/* Right Side - Features + Illustration */}
<div className="flex-1 flex flex-col lg:flex-row gap-6">
{/* Features */}
<div className="flex-1">
<h4 className="font-fractul font-bold text-[20px] text-[#00293D] mb-6">
Include Features
</h4>
<div className="space-y-5">
{PLAN_FEATURES.map((feature) => (
<div key={feature.label} className="flex items-center gap-3">
<Image
src={feature.icon}
alt=""
width={21}
height={21}
className="flex-shrink-0"
/>
<span className="font-serif text-[14px] text-black">
{feature.label}
</span>
</div>
))}
</div>
</div>
{/* Illustration */}
<div className="hidden lg:flex items-end justify-end">
<div className="w-[165px] h-[165px] rounded-full overflow-hidden">
<img
src="/assets/images/subscription-plan-illustration.png"
alt="Professional plan"
className="w-full h-full object-cover"
/>
</div>
</div>
</div>
</div>
</div>
</div>
{/* Need Help Section */}
<div className="border border-[#00293D]/70 rounded-[15px] p-8 flex flex-col lg:flex-row items-center gap-8">
{/* Left Side - Help Content */}
<div className="flex-1 text-center lg:text-left">
{/* Question Icon */}
<div className="flex justify-center lg:justify-start mb-3">
<Image
src="/assets/icons/question-circle-icon.svg"
alt="Help"
width={35}
height={35}
/>
</div>
{/* Title */}
<h3 className="font-fractul font-bold text-[20px] text-[#00293D] mb-3">
Need Help ?
</h3>
{/* Description */}
<p className="font-serif text-[14px] text-[#00293D] mb-4 max-w-[257px] mx-auto lg:mx-0 leading-[22px]">
Our billing experts are here to help you with any questions about your plan.
</p>
{/* Support Email */}
<Link
href="mailto:support@example.com"
className="font-serif font-bold text-[14px] text-[#e58625] underline hover:text-[#d47920] transition-colors"
>
support@example.com
<span className="inline-block ml-1 rotate-45">&nearr;</span>
</Link>
</div>
{/* Right Side - Illustration */}
<div className="hidden lg:block">
<div className="w-[261px] h-[261px] rounded-[57px] overflow-hidden">
<img
src="/assets/images/need-help-illustration.png"
alt="Need help illustration"
className="w-full h-full object-cover"
/>
</div>
</div>
</div>
</>
);
}

View File

@@ -5,3 +5,4 @@ export { PasswordSecurityForm } from './PasswordSecurityForm';
export { NotificationsForm } from './NotificationsForm';
export { PrivacyForm } from './PrivacyForm';
export { TwoFactorSettings } from './TwoFactorSettings';
export { SubscriptionForm } from './SubscriptionForm';