feat: Implement agent messaging and settings pages with new components and icons.

This commit is contained in:
pradeepkumar
2026-01-18 23:58:25 +05:30
parent 48c4b564e5
commit c5ed8fb1aa
28 changed files with 1703 additions and 12 deletions

View File

@@ -0,0 +1,3 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M12 5V19M12 19L5 12M12 19L19 12" stroke="#00293d" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 230 B

View File

@@ -0,0 +1,3 @@
<svg width="8" height="14" viewBox="0 0 8 14" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M1 1L7 7L1 13" stroke="#00293D" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 208 B

View File

@@ -0,0 +1,4 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M11 4H4C3.46957 4 2.96086 4.21071 2.58579 4.58579C2.21071 4.96086 2 5.46957 2 6V20C2 20.5304 2.21071 21.0391 2.58579 21.4142C2.96086 21.7893 3.46957 22 4 22H18C18.5304 22 19.0391 21.7893 19.4142 21.4142C19.7893 21.0391 20 20.5304 20 20V13" stroke="#00293d" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M18.5 2.50001C18.8978 2.10219 19.4374 1.87869 20 1.87869C20.5626 1.87869 21.1022 2.10219 21.5 2.50001C21.8978 2.89784 22.1213 3.4374 22.1213 4.00001C22.1213 4.56262 21.8978 5.10219 21.5 5.50001L12 15L8 16L9 12L18.5 2.50001Z" stroke="#00293d" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 756 B

View File

@@ -0,0 +1,6 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<circle cx="12" cy="12" r="10" stroke="#e58625" stroke-width="2"/>
<path d="M8 14C8 14 9.5 16 12 16C14.5 16 16 14 16 14" stroke="#e58625" stroke-width="2" stroke-linecap="round"/>
<circle cx="9" cy="9" r="1" fill="#e58625"/>
<circle cx="15" cy="9" r="1" fill="#e58625"/>
</svg>

After

Width:  |  Height:  |  Size: 382 B

View File

@@ -0,0 +1,5 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x="3" y="3" width="18" height="18" rx="2" stroke="#e58625" stroke-width="2"/>
<circle cx="8.5" cy="8.5" r="1.5" fill="#e58625"/>
<path d="M21 15L16 10L5 21" stroke="#e58625" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 355 B

View File

@@ -0,0 +1,6 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x="2" y="5" width="20" height="14" rx="2" stroke="#e58625" stroke-width="2"/>
<path d="M7 12H6C5.44772 12 5 11.5523 5 11V10C5 9.44772 5.44772 9 6 9H8V15H6C5.44772 15 5 14.5523 5 14V13C5 12.4477 5.44772 12 6 12H7" stroke="#e58625" stroke-width="1.5" stroke-linecap="round"/>
<path d="M11 9V15" stroke="#e58625" stroke-width="1.5" stroke-linecap="round"/>
<path d="M14 9H18M14 9V15M14 12H17" stroke="#e58625" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 592 B

View File

@@ -0,0 +1,4 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M11 19C15.4183 19 19 15.4183 19 11C19 6.58172 15.4183 3 11 3C6.58172 3 3 6.58172 3 11C3 15.4183 6.58172 19 11 19Z" stroke="#00293d" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M21 21L16.65 16.65" stroke="#00293d" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 426 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 20C11.1 20 12 19.1 12 18H8C8 19.1 8.9 20 10 20ZM16 14V9C16 5.93 14.36 3.36 11.5 2.68V2C11.5 1.17 10.83 0.5 10 0.5C9.17 0.5 8.5 1.17 8.5 2V2.68C5.63 3.36 4 5.92 4 9V14L2 16V17H18V16L16 14Z" fill="currentColor"/>
</svg>

After

Width:  |  Height:  |  Size: 327 B

View File

@@ -0,0 +1,3 @@
<svg width="18" height="20" viewBox="0 0 18 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M15.75 7H14.625V5C14.625 2.2425 12.3825 0 9.625 0C6.8675 0 4.625 2.2425 4.625 5V7H3.5C2.4 7 1.5 7.9 1.5 9V18C1.5 19.1 2.4 20 3.5 20H15.75C16.85 20 17.75 19.1 17.75 18V9C17.75 7.9 16.85 7 15.75 7ZM9.625 15C8.525 15 7.625 14.1 7.625 13C7.625 11.9 8.525 11 9.625 11C10.725 11 11.625 11.9 11.625 13C11.625 14.1 10.725 15 9.625 15ZM12.675 7H6.575V5C6.575 3.3425 7.9175 2 9.625 2C11.3325 2 12.675 3.3425 12.675 5V7Z" fill="currentColor"/>
</svg>

After

Width:  |  Height:  |  Size: 545 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 1L3 4.5V9.5C3 14.025 6.15 18.275 10 19.5C13.85 18.275 17 14.025 17 9.5V4.5L10 1ZM10 9.99H15C14.575 13.34 12.61 16.325 10 17.435V10H5V5.65L10 3.2V9.99Z" fill="currentColor"/>
</svg>

After

Width:  |  Height:  |  Size: 290 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 10C12.0711 10 13.75 8.32107 13.75 6.25C13.75 4.17893 12.0711 2.5 10 2.5C7.92893 2.5 6.25 4.17893 6.25 6.25C6.25 8.32107 7.92893 10 10 10ZM10 11.875C7.08125 11.875 1.25 13.3438 1.25 16.25V17.5H18.75V16.25C18.75 13.3438 12.9188 11.875 10 11.875Z" fill="currentColor"/>
</svg>

After

Width:  |  Height:  |  Size: 383 B

View File

@@ -1,4 +1,3 @@
<svg width="19" height="19" viewBox="0 0 19 19" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M9.30942 16.8689C12.8162 15.6602 15.3158 12.8503 15.7079 9.27257C15.8166 7.71948 15.8074 6.16038 15.6803 4.60868C15.6636 4.36407 15.5563 4.13448 15.3793 3.96481C15.2023 3.79513 14.9684 3.69756 14.7233 3.69118C13.1369 3.64232 11.2929 3.37785 9.86821 1.97446C9.71943 1.82752 9.51873 1.74512 9.30961 1.74512C9.10049 1.74512 8.89979 1.82752 8.75101 1.97446C7.3259 3.37785 5.48198 3.64232 3.89594 3.69118C3.65084 3.69756 3.41692 3.79513 3.23993 3.96481C3.06294 4.13448 2.9556 4.36407 2.93889 4.60868C2.81168 6.16037 2.80234 7.71947 2.91096 9.27257C3.30302 12.8503 5.80268 15.6602 9.30942 16.8689Z" stroke="#E58625" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M9.04859 12.0218L10.6637 9.30727H7.94922L9.56434 6.59277" stroke="#E58625" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<svg width="17" height="18" viewBox="0 0 17 18" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M0 2.59997L8.43919 0V18C2.41085 15.6 0 11 0 8.4V2.59997ZM16.8784 2.59997L8.43919 0V18C14.4675 15.6 16.8784 11 16.8784 8.4V2.59997Z" fill="#E58625"/>
</svg>

Before

Width:  |  Height:  |  Size: 938 B

After

Width:  |  Height:  |  Size: 261 B

View File

@@ -0,0 +1,3 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M12 2L15.09 8.26L22 9.27L17 14.14L18.18 21.02L12 17.77L5.82 21.02L7 14.14L2 9.27L8.91 8.26L12 2Z" stroke="#e58625" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 295 B

View File

@@ -0,0 +1,5 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<circle cx="12" cy="5" r="2" fill="#00293d"/>
<circle cx="12" cy="12" r="2" fill="#00293d"/>
<circle cx="12" cy="19" r="2" fill="#00293d"/>
</svg>

After

Width:  |  Height:  |  Size: 249 B

View File

@@ -86,7 +86,10 @@ export function ProfileCard({
{/* Action Buttons */}
<div className="flex items-center justify-center lg:justify-start gap-3">
<button className="flex items-center gap-2 px-4 py-1.5 bg-[#e58625] text-[#00293d] text-sm font-normal rounded-[15px] border border-[#00293d]/10 hover:bg-[#d47720] transition-colors font-serif">
<Link
href="/agent/message"
className="flex items-center gap-2 px-4 py-1.5 bg-[#e58625] text-[#00293d] text-sm font-normal rounded-[15px] border border-[#00293d]/10 hover:bg-[#d47720] transition-colors font-serif cursor-pointer"
>
<Image
src="/assets/icons/message-dark-icon.svg"
alt="Message"
@@ -94,7 +97,7 @@ export function ProfileCard({
height={13}
/>
Message
</button>
</Link>
<Link
href="/agent/network"
className="flex items-center gap-2 px-4 py-1.5 bg-[#e58625] text-[#00293d] text-sm font-normal rounded-[15px] border border-[#00293d]/10 hover:bg-[#d47720] transition-colors font-serif cursor-pointer"

View File

@@ -0,0 +1,116 @@
'use client';
import Image from 'next/image';
interface ChatHeaderProps {
name: string;
role: string;
lastSeen: string;
avatar: string;
isOnline?: boolean;
pronouns?: string;
expertise?: string[];
}
export function ChatHeader({
name,
role,
lastSeen,
avatar,
isOnline = false,
pronouns,
expertise = [],
}: ChatHeaderProps) {
return (
<div className="border-b border-[#00293d]/10 pb-4">
{/* Top row - Name, status, actions */}
<div className="flex items-center justify-between mb-3">
<div className="flex items-center gap-2">
<h2 className="font-fractul font-bold text-[14px] leading-[17px] text-[#00293D]">
{name}
</h2>
<span className={`w-2.5 h-2.5 rounded-full ${isOnline ? 'bg-green-500' : 'bg-gray-400'}`} />
<span className="font-serif font-normal text-[14px] leading-[19px] text-[#00293D]">
{role}
</span>
<span className="font-serif font-normal text-[14px] leading-[19px] text-[#00293D]">
{lastSeen}
</span>
</div>
<div className="flex items-center gap-2">
<button className="p-2 hover:bg-gray-100 rounded-lg transition-colors cursor-pointer">
<Image
src="/assets/icons/three-dots-icon.svg"
alt="More options"
width={24}
height={24}
/>
</button>
<button className="p-2 hover:bg-gray-100 rounded-lg transition-colors cursor-pointer">
<Image
src="/assets/icons/star-outline-icon.svg"
alt="Star conversation"
width={24}
height={24}
/>
</button>
</div>
</div>
{/* User profile row */}
<div className="flex items-start gap-3">
{/* Avatar */}
<div className="relative flex-shrink-0">
<div className="w-[50px] h-[50px] rounded-full overflow-hidden">
<Image
src={avatar}
alt={name}
width={50}
height={50}
className="w-full h-full object-cover"
/>
</div>
{isOnline && (
<div className="absolute bottom-0 right-0 w-3 h-3 bg-green-500 rounded-full border-2 border-white" />
)}
</div>
{/* User info */}
<div className="flex-1">
<div className="flex items-center gap-2 mb-1">
<span className="font-fractul font-bold text-[14px] leading-[17px] text-[#00293D]">
{name}
</span>
<Image
src="/assets/icons/shield-verified-icon.svg"
alt="Verified"
width={17}
height={18}
/>
{pronouns && (
<span className="font-fractul font-bold text-[14px] leading-[17px] text-[#00293D]">
({pronouns})
</span>
)}
</div>
{/* Expertise tags */}
{expertise.length > 0 && (
<div className="flex items-center gap-2 flex-wrap">
{expertise.map((tag, index) => (
<span key={index} className="flex items-center">
<span className="font-serif font-normal text-[14px] leading-[19px] text-[#00293D]">
{tag}
</span>
{index < expertise.length - 1 && (
<span className="mx-2 text-[#00293d]/30">|</span>
)}
</span>
))}
</div>
)}
</div>
</div>
</div>
);
}

View File

@@ -0,0 +1,65 @@
'use client';
import Image from 'next/image';
interface ConversationItemProps {
id: string;
name: string;
avatar: string;
lastMessage: string;
date: string;
isOnline?: boolean;
isSelected?: boolean;
onClick?: () => void;
}
export function ConversationItem({
id,
name,
avatar,
lastMessage,
date,
isOnline = false,
isSelected = false,
onClick,
}: ConversationItemProps) {
return (
<div
onClick={onClick}
className={`flex items-start gap-3 p-4 border border-[#00293d]/10 rounded-[15px] cursor-pointer transition-colors ${
isSelected ? 'bg-[#00293d]/5' : 'hover:bg-[#00293d]/5'
}`}
>
{/* Avatar with online indicator */}
<div className="relative flex-shrink-0">
<div className="w-[70px] h-[70px] rounded-full overflow-hidden">
<Image
src={avatar}
alt={name}
width={70}
height={70}
className="w-full h-full object-cover"
/>
</div>
{isOnline && (
<div className="absolute bottom-1 right-1 w-3 h-3 bg-green-500 rounded-full border-2 border-white" />
)}
</div>
{/* Content */}
<div className="flex-1 min-w-0">
<p className="font-fractul font-medium text-[14px] leading-[17px] text-[#00293D] mb-1">
{name}
</p>
<p className="font-serif font-normal text-[14px] leading-[19px] text-[#00293D] line-clamp-2">
{lastMessage}
</p>
</div>
{/* Date */}
<p className="font-serif font-normal text-[14px] leading-[19px] text-[#00293D] flex-shrink-0">
{date}
</p>
</div>
);
}

View File

@@ -0,0 +1,41 @@
'use client';
import Image from 'next/image';
import { ConversationItem } from './ConversationItem';
interface Conversation {
id: string;
name: string;
avatar: string;
lastMessage: string;
date: string;
isOnline?: boolean;
}
interface ConversationListProps {
conversations: Conversation[];
selectedId: string | null;
onSelect: (id: string) => void;
}
export function ConversationList({
conversations,
selectedId,
onSelect,
}: ConversationListProps) {
return (
<div className="border border-[#00293d]/10 rounded-[15px] bg-white h-full flex flex-col">
{/* Scrollable conversation list */}
<div className="flex-1 overflow-y-auto p-2 space-y-2">
{conversations.map((conversation) => (
<ConversationItem
key={conversation.id}
{...conversation}
isSelected={selectedId === conversation.id}
onClick={() => onSelect(conversation.id)}
/>
))}
</div>
</div>
);
}

View File

@@ -0,0 +1,98 @@
'use client';
import Image from 'next/image';
import { useState } from 'react';
interface MessageInputProps {
onSend?: (message: string) => void;
}
export function MessageInput({ onSend }: MessageInputProps) {
const [message, setMessage] = useState('');
const handleSend = () => {
if (message.trim() && onSend) {
onSend(message.trim());
setMessage('');
}
};
const handleKeyDown = (e: React.KeyboardEvent) => {
if (e.key === 'Enter' && !e.shiftKey) {
e.preventDefault();
handleSend();
}
};
return (
<div className="border border-[#00293d]/10 rounded-[20px] bg-white p-4">
{/* Text input area */}
<div className="border border-[#00293d]/10 rounded-[20px] p-4 mb-3">
<textarea
value={message}
onChange={(e) => setMessage(e.target.value)}
onKeyDown={handleKeyDown}
placeholder="Write a Message........"
className="w-full min-h-[120px] resize-none font-serif font-normal text-[14px] leading-[19px] text-[#00293D] placeholder-[#00293D]/50 focus:outline-none"
/>
</div>
{/* Action bar */}
<div className="flex items-center justify-between">
{/* Attachment buttons */}
<div className="flex items-center gap-3">
<button className="p-1.5 hover:bg-gray-100 rounded-lg transition-colors cursor-pointer">
<Image
src="/assets/icons/gallery-icon.svg"
alt="Add image"
width={24}
height={24}
/>
</button>
<button className="p-1.5 hover:bg-gray-100 rounded-lg transition-colors cursor-pointer">
<Image
src="/assets/icons/chain-icon.svg"
alt="Add link"
width={24}
height={24}
/>
</button>
<button className="p-1.5 hover:bg-gray-100 rounded-lg transition-colors cursor-pointer">
<Image
src="/assets/icons/gif-icon.svg"
alt="Add GIF"
width={24}
height={24}
/>
</button>
<button className="p-1.5 hover:bg-gray-100 rounded-lg transition-colors cursor-pointer">
<Image
src="/assets/icons/emoji-icon.svg"
alt="Add emoji"
width={24}
height={24}
/>
</button>
</div>
{/* Send button and more options */}
<div className="flex items-center gap-2">
<button
onClick={handleSend}
className="px-4 py-1.5 bg-[#e58625] text-[#00293d] font-serif font-normal text-[14px] leading-[19px] rounded-[15px] hover:bg-[#d47720] transition-colors cursor-pointer"
>
Send
</button>
<button className="p-1.5 hover:bg-gray-100 rounded-lg transition-colors cursor-pointer">
<Image
src="/assets/icons/three-dots-icon.svg"
alt="More options"
width={24}
height={24}
/>
</button>
</div>
</div>
</div>
);
}

View File

@@ -0,0 +1,4 @@
export { ConversationItem } from './ConversationItem';
export { ConversationList } from './ConversationList';
export { ChatHeader } from './ChatHeader';
export { MessageInput } from './MessageInput';

View File

@@ -0,0 +1,383 @@
'use client';
import { useState } from 'react';
import Image from 'next/image';
import { ChatHeader, MessageInput } from './component';
// Custom scrollbar styles
const customScrollbarStyles = `
.custom-scrollbar::-webkit-scrollbar {
width: 8px;
}
.custom-scrollbar::-webkit-scrollbar-track {
background: transparent;
}
.custom-scrollbar::-webkit-scrollbar-thumb {
background: rgba(0, 41, 61, 0.5);
border-radius: 10px;
}
.custom-scrollbar::-webkit-scrollbar-thumb:hover {
background: rgba(0, 41, 61, 0.7);
}
`;
// Mock data for conversations
const conversations = [
{
id: '1',
name: 'Pradeep Ram',
avatar: '/assets/icons/user-placeholder-icon.svg',
lastMessage: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.',
date: 'Dec 4',
isOnline: true,
},
{
id: '2',
name: 'Pradeep',
avatar: '/assets/icons/user-placeholder-icon.svg',
lastMessage: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.',
date: 'Dec 4',
isOnline: true,
},
{
id: '3',
name: 'Gokulraj',
avatar: '/assets/icons/user-placeholder-icon.svg',
lastMessage: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.',
date: 'Dec 4',
isOnline: true,
},
{
id: '4',
name: 'Suriya s',
avatar: '/assets/icons/user-placeholder-icon.svg',
lastMessage: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.',
date: 'Dec 4',
isOnline: true,
},
{
id: '5',
name: 'Sanjay',
avatar: '/assets/icons/user-placeholder-icon.svg',
lastMessage: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.',
date: 'Dec 4',
isOnline: true,
},
{
id: '6',
name: 'Pradeep Ram',
avatar: '/assets/icons/user-placeholder-icon.svg',
lastMessage: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.',
date: 'Dec 4',
isOnline: false,
},
{
id: '7',
name: 'Rahul Kumar',
avatar: '/assets/icons/user-placeholder-icon.svg',
lastMessage: 'Thanks for your help with the property listing!',
date: 'Dec 3',
isOnline: true,
},
{
id: '8',
name: 'Anita Singh',
avatar: '/assets/icons/user-placeholder-icon.svg',
lastMessage: 'Can we schedule a viewing for tomorrow?',
date: 'Dec 3',
isOnline: false,
},
{
id: '9',
name: 'Vikram Patel',
avatar: '/assets/icons/user-placeholder-icon.svg',
lastMessage: 'The documents have been submitted.',
date: 'Dec 2',
isOnline: true,
},
{
id: '10',
name: 'Meera Sharma',
avatar: '/assets/icons/user-placeholder-icon.svg',
lastMessage: 'Looking forward to our meeting next week.',
date: 'Dec 2',
isOnline: false,
},
{
id: '11',
name: 'Arjun Reddy',
avatar: '/assets/icons/user-placeholder-icon.svg',
lastMessage: 'Please send me the property details.',
date: 'Dec 1',
isOnline: true,
},
{
id: '12',
name: 'Sneha Nair',
avatar: '/assets/icons/user-placeholder-icon.svg',
lastMessage: 'I have a few questions about the contract.',
date: 'Dec 1',
isOnline: false,
},
];
// Mock data for selected user
const selectedUserData = {
name: 'Pradeep Ram',
role: 'Advisor',
lastSeen: '21h Ago',
avatar: '/assets/icons/user-placeholder-icon.svg',
isOnline: true,
pronouns: 'He/Him',
expertise: ['Sales', 'Analytics', 'Inspection', 'Residential', 'Commercial'],
};
// Mock messages data
const messages = [
{
id: '1',
senderId: '1',
text: 'Hi! I saw your profile and I think you might be a great fit for what I\'m looking for.',
timestamp: '10:30 AM',
isOwn: false,
},
{
id: '2',
senderId: 'me',
text: 'Hello! Thank you for reaching out. I\'d be happy to help. What kind of property are you looking for?',
timestamp: '10:32 AM',
isOwn: true,
},
{
id: '3',
senderId: '1',
text: 'I\'m looking for a residential property in the downtown area. Preferably a 3-bedroom apartment with modern amenities.',
timestamp: '10:35 AM',
isOwn: false,
},
{
id: '4',
senderId: 'me',
text: 'That sounds great! I have several listings that might interest you. Do you have a specific budget range in mind?',
timestamp: '10:38 AM',
isOwn: true,
},
{
id: '5',
senderId: '1',
text: 'My budget is around $500,000 to $700,000. I\'m also interested in properties with good investment potential.',
timestamp: '10:40 AM',
isOwn: false,
},
{
id: '6',
senderId: 'me',
text: 'Perfect! I have a few properties in that range. Would you like to schedule a viewing this weekend?',
timestamp: '10:42 AM',
isOwn: true,
},
{
id: '7',
senderId: '1',
text: 'Yes, that would be great! Saturday afternoon works best for me.',
timestamp: '10:45 AM',
isOwn: false,
},
{
id: '8',
senderId: 'me',
text: 'Saturday at 2 PM works for me. I\'ll send you the addresses and details of the properties we\'ll be visiting.',
timestamp: '10:48 AM',
isOwn: true,
},
{
id: '9',
senderId: '1',
text: 'Sounds perfect! Looking forward to it. Thank you for your quick response.',
timestamp: '10:50 AM',
isOwn: false,
},
{
id: '10',
senderId: 'me',
text: 'You\'re welcome! See you on Saturday. Feel free to reach out if you have any questions before then.',
timestamp: '10:52 AM',
isOwn: true,
},
];
export default function MessagePage() {
const [selectedConversation, setSelectedConversation] = useState<string | null>('1');
const [searchQuery, setSearchQuery] = useState('');
const handleSendMessage = (message: string) => {
console.log('Sending message:', message);
// In production, this would send the message to the API
};
const filteredConversations = conversations.filter((conv) =>
conv.name.toLowerCase().includes(searchQuery.toLowerCase())
);
return (
<>
<style>{customScrollbarStyles}</style>
<div className="border border-[#00293d]/10 rounded-[20px] bg-white overflow-hidden">
{/* Header */}
<div className="flex items-center gap-4 p-4 border-b border-[#00293d]/10">
<h1 className="font-fractul font-bold text-[18px] leading-[22px] text-[#00293D]">
Messaging
</h1>
{/* Search bar */}
<div className="flex-1 max-w-[600px]">
<div className="flex items-center gap-2 border border-[#00293d]/10 rounded-[15px] px-4 py-2">
<Image
src="/assets/icons/search-icon.svg"
alt="Search"
width={20}
height={20}
/>
<input
type="text"
value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)}
placeholder="Search Message"
className="flex-1 font-serif font-normal text-[18px] leading-[24px] text-[#00293D] placeholder-[#00293D]/50 focus:outline-none"
/>
</div>
</div>
{/* Header actions */}
<div className="flex items-center gap-2">
<button className="p-2 hover:bg-gray-100 rounded-lg transition-colors cursor-pointer">
<Image
src="/assets/icons/three-dots-icon.svg"
alt="More options"
width={24}
height={24}
/>
</button>
<button className="p-2 hover:bg-gray-100 rounded-lg transition-colors cursor-pointer">
<Image
src="/assets/icons/compose-icon.svg"
alt="Compose"
width={24}
height={24}
/>
</button>
</div>
</div>
{/* Main content */}
<div className="flex h-[700px]">
{/* Left sidebar - Conversation list */}
<div className="w-[380px] border-r border-[#00293d]/10 flex-shrink-0 overflow-hidden flex flex-col">
<div className="flex-1 overflow-y-auto p-2 space-y-2 custom-scrollbar">
{filteredConversations.map((conversation) => (
<div
key={conversation.id}
onClick={() => setSelectedConversation(conversation.id)}
className={`flex items-start gap-3 p-4 border border-[#00293d]/10 rounded-[15px] cursor-pointer transition-colors ${
selectedConversation === conversation.id ? 'bg-[#00293d]/5' : 'hover:bg-[#00293d]/5'
}`}
>
{/* Avatar with online indicator */}
<div className="relative flex-shrink-0">
<div className="w-[70px] h-[70px] rounded-full overflow-hidden">
<Image
src={conversation.avatar}
alt={conversation.name}
width={70}
height={70}
className="w-full h-full object-cover"
/>
</div>
{conversation.isOnline && (
<div className="absolute bottom-1 right-1 w-3 h-3 bg-green-500 rounded-full border-2 border-white" />
)}
</div>
{/* Content */}
<div className="flex-1 min-w-0">
<p className="font-fractul font-medium text-[14px] leading-[17px] text-[#00293D] mb-1">
{conversation.name}
</p>
<p className="font-serif font-normal text-[14px] leading-[19px] text-[#00293D] line-clamp-2">
{conversation.lastMessage}
</p>
</div>
{/* Date */}
<p className="font-serif font-normal text-[14px] leading-[19px] text-[#00293D] flex-shrink-0">
{conversation.date}
</p>
</div>
))}
</div>
</div>
{/* Right panel - Chat area */}
<div className="flex-1 flex flex-col p-4">
{selectedConversation ? (
<>
{/* Chat header */}
<ChatHeader {...selectedUserData} />
{/* Messages area */}
<div className="flex-1 overflow-y-auto py-4 relative custom-scrollbar">
<div className="space-y-4 px-2">
{messages.map((message) => (
<div
key={message.id}
className={`flex ${message.isOwn ? 'justify-end' : 'justify-start'}`}
>
<div
className={`max-w-[70%] rounded-[15px] px-4 py-3 ${
message.isOwn
? 'bg-[#e58625] text-[#00293D]'
: 'bg-[#00293d]/10 text-[#00293D]'
}`}
>
<p className="font-serif font-normal text-[14px] leading-[19px]">
{message.text}
</p>
<p
className={`font-serif font-normal text-[12px] leading-[16px] mt-1 ${
message.isOwn ? 'text-[#00293D]/70' : 'text-[#00293D]/50'
}`}
>
{message.timestamp}
</p>
</div>
</div>
))}
</div>
{/* Scroll to bottom button */}
<div className="absolute bottom-4 right-4">
<button className="w-[50px] h-[50px] bg-[#00293d]/10 rounded-full flex items-center justify-center hover:bg-[#00293d]/20 transition-colors cursor-pointer">
<Image
src="/assets/icons/arrow-down-icon.svg"
alt="Scroll to bottom"
width={20}
height={20}
/>
</button>
</div>
</div>
{/* Message input */}
<MessageInput onSend={handleSendMessage} />
</>
) : (
<div className="flex items-center justify-center h-full text-[#00293D]/50 font-serif">
Select a conversation to start messaging
</div>
)}
</div>
</div>
</div>
</>
);
}

View File

@@ -0,0 +1,133 @@
'use client';
import Image from 'next/image';
import Link from 'next/link';
import { usePathname } from 'next/navigation';
interface NavItem {
label: string;
href: string;
icon: string;
}
const navItems: NavItem[] = [
{
label: 'Profile Settings',
href: '/agent/settings',
icon: '/assets/icons/settings-profile-icon.svg',
},
{
label: 'Password Security',
href: '/agent/settings/password',
icon: '/assets/icons/settings-lock-icon.svg',
},
{
label: 'Notifications',
href: '/agent/settings/notifications',
icon: '/assets/icons/settings-bell-icon.svg',
},
{
label: 'Privacy',
href: '/agent/settings/privacy',
icon: '/assets/icons/settings-privacy-icon.svg',
},
];
interface SettingsSidebarProps {
profileImage?: string;
name?: string;
title?: string;
}
export function SettingsSidebar({
profileImage = '/assets/icons/user-placeholder-icon.svg',
name = 'Brain Nooland',
title = 'Top Real Estate Agent',
}: SettingsSidebarProps) {
const pathname = usePathname();
return (
<div className="w-full lg:w-[280px] bg-white rounded-[15px] border border-[#00293d]/10 overflow-hidden h-fit">
{/* Profile Section */}
<div className="p-6 flex flex-col items-center">
<div className="w-[80px] h-[80px] rounded-full overflow-hidden mb-3 border-2 border-[#e58625]">
<Image
src={profileImage}
alt={name}
width={80}
height={80}
className="w-full h-full object-cover"
/>
</div>
<h3 className="font-fractul font-bold text-[16px] leading-[19px] text-[#00293D]">
{name}
</h3>
<p className="font-serif font-normal text-[12px] leading-[16px] text-[#00293D]/70 mt-1">
{title}
</p>
</div>
{/* Divider */}
<div className="w-full h-[1px] bg-[#00293d]/10" />
{/* Categories Section */}
<div className="p-4">
{/* Categories Header */}
<div className="flex items-center justify-between mb-4 px-2">
<h4 className="font-fractul font-bold text-[14px] leading-[17px] text-[#00293D]">
Categories
</h4>
<Image
src="/assets/icons/chevron-right-icon.svg"
alt="Expand"
width={8}
height={14}
/>
</div>
{/* Navigation Items */}
<nav className="space-y-1">
{navItems.map((item) => {
const isActive = pathname === item.href;
return (
<Link
key={item.href}
href={item.href}
className={`flex items-center gap-3 py-3 px-3 rounded-[10px] transition-colors cursor-pointer ${
isActive
? 'bg-[#e58625]/10'
: 'hover:bg-[#00293d]/5'
}`}
>
<div
className={`w-5 h-5 flex items-center justify-center ${
isActive ? 'text-[#e58625]' : 'text-[#00293D]'
}`}
style={{ color: isActive ? '#e58625' : '#00293D' }}
>
<Image
src={item.icon}
alt={item.label}
width={20}
height={20}
className={isActive ? 'brightness-0 saturate-100' : ''}
style={isActive ? { filter: 'invert(48%) sepia(94%) saturate(1000%) hue-rotate(360deg) brightness(95%) contrast(85%)' } : {}}
/>
</div>
<span
className={`font-serif text-[14px] leading-[19px] ${
isActive
? 'font-medium text-[#e58625]'
: 'font-normal text-[#00293D]'
}`}
>
{item.label}
</span>
</Link>
);
})}
</nav>
</div>
</div>
);
}

View File

@@ -0,0 +1 @@
export { SettingsSidebar } from './SettingsSidebar';

View File

@@ -0,0 +1,206 @@
'use client';
import { useState } from 'react';
import { SettingsSidebar } from '../component/SettingsSidebar';
interface NotificationSetting {
id: string;
label: string;
description: string;
enabled: boolean;
}
export default function NotificationsPage() {
const [emailNotifications, setEmailNotifications] = useState<NotificationSetting[]>([
{
id: 'new_leads',
label: 'New Leads',
description: 'Get notified when you receive new leads',
enabled: true,
},
{
id: 'messages',
label: 'Messages',
description: 'Get notified when you receive new messages',
enabled: true,
},
{
id: 'connection_requests',
label: 'Connection Requests',
description: 'Get notified about new connection requests',
enabled: true,
},
{
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 [pushNotifications, setPushNotifications] = useState<NotificationSetting[]>([
{
id: 'push_messages',
label: 'Messages',
description: 'Push notifications for new messages',
enabled: true,
},
{
id: 'push_leads',
label: 'New Leads',
description: 'Push notifications for new leads',
enabled: true,
},
{
id: 'push_reminders',
label: 'Reminders',
description: 'Push notifications for scheduled reminders',
enabled: false,
},
]);
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
)
);
};
const handleSave = () => {
console.log('Saving notification settings:', {
emailNotifications,
pushNotifications,
});
};
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>
);
return (
<div className="flex flex-col lg:flex-row gap-6">
{/* Left Sidebar */}
<SettingsSidebar />
{/* 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>
{/* 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}
className="px-8 py-3 bg-[#e58625] text-white rounded-[15px] font-fractul font-medium text-[14px] hover:bg-[#d47920] transition-colors"
>
Save Changes
</button>
</div>
</div>
</div>
);
}

View File

@@ -0,0 +1,172 @@
'use client';
import { useState } from 'react';
import Image from 'next/image';
import { SettingsSidebar } from './component/SettingsSidebar';
export default function ProfileSettingsPage() {
const [formData, setFormData] = useState({
firstName: 'Brain',
lastName: 'Nooland',
email: 'brain.nooland@email.com',
phone: '+1 (555) 123-4567',
title: 'Top Real Estate Agent',
location: 'Los Angeles, CA',
});
const handleChange = (field: string, value: string) => {
setFormData((prev) => ({ ...prev, [field]: value }));
};
const handleSave = () => {
console.log('Saving profile settings:', formData);
};
return (
<div className="flex flex-col lg:flex-row gap-6">
{/* Left Sidebar */}
<SettingsSidebar
name={`${formData.firstName} ${formData.lastName}`}
title={formData.title}
/>
{/* 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]">
Profile Settings
</h1>
</div>
{/* Profile Settings Form */}
<div className="border border-[#00293d]/10 rounded-[15px] bg-white p-6">
{/* Profile Photo Section */}
<div className="flex items-center gap-6 mb-8 pb-6 border-b border-[#00293d]/10">
<div className="relative">
<div className="w-[100px] h-[100px] rounded-full overflow-hidden border-2 border-[#e58625]">
<Image
src="/assets/icons/user-placeholder-icon.svg"
alt="Profile"
width={100}
height={100}
className="w-full h-full object-cover"
/>
</div>
<button className="absolute bottom-0 right-0 w-8 h-8 bg-[#e58625] rounded-full flex items-center justify-center hover:bg-[#d47920] transition-colors">
<Image
src="/assets/icons/edit-icon.svg"
alt="Edit"
width={16}
height={16}
/>
</button>
</div>
<div>
<h3 className="font-fractul font-bold text-[16px] text-[#00293D] mb-1">
Profile Photo
</h3>
<p className="font-serif text-[12px] text-[#00293D]/60 mb-3">
JPG, GIF or PNG. Max size 2MB
</p>
<button className="px-4 py-2 border border-[#e58625] text-[#e58625] rounded-[15px] font-serif text-[12px] hover:bg-[#e58625]/10 transition-colors">
Upload New Photo
</button>
</div>
</div>
{/* Form Fields */}
<div className="space-y-6">
{/* Name Row */}
<div className="flex flex-col sm:flex-row gap-4">
<div className="flex-1">
<label className="block text-[12px] font-medium text-[#00293D]/70 font-serif mb-2">
First Name
</label>
<input
type="text"
value={formData.firstName}
onChange={(e) => handleChange('firstName', e.target.value)}
className="w-full h-[40px] px-4 border border-[#00293D]/20 rounded-[15px] text-[14px] font-serif text-[#00293D] focus:outline-none focus:border-[#E58625]"
/>
</div>
<div className="flex-1">
<label className="block text-[12px] font-medium text-[#00293D]/70 font-serif mb-2">
Last Name
</label>
<input
type="text"
value={formData.lastName}
onChange={(e) => handleChange('lastName', e.target.value)}
className="w-full h-[40px] px-4 border border-[#00293D]/20 rounded-[15px] text-[14px] font-serif text-[#00293D] focus:outline-none focus:border-[#E58625]"
/>
</div>
</div>
{/* Email */}
<div>
<label className="block text-[12px] font-medium text-[#00293D]/70 font-serif mb-2">
Email Address
</label>
<input
type="email"
value={formData.email}
onChange={(e) => handleChange('email', e.target.value)}
className="w-full h-[40px] px-4 border border-[#00293D]/20 rounded-[15px] text-[14px] font-serif text-[#00293D] focus:outline-none focus:border-[#E58625]"
/>
</div>
{/* Phone */}
<div>
<label className="block text-[12px] font-medium text-[#00293D]/70 font-serif mb-2">
Phone Number
</label>
<input
type="tel"
value={formData.phone}
onChange={(e) => handleChange('phone', e.target.value)}
className="w-full h-[40px] px-4 border border-[#00293D]/20 rounded-[15px] text-[14px] font-serif text-[#00293D] focus:outline-none focus:border-[#E58625]"
/>
</div>
{/* Title */}
<div>
<label className="block text-[12px] font-medium text-[#00293D]/70 font-serif mb-2">
Professional Title
</label>
<input
type="text"
value={formData.title}
onChange={(e) => handleChange('title', e.target.value)}
className="w-full h-[40px] px-4 border border-[#00293D]/20 rounded-[15px] text-[14px] font-serif text-[#00293D] focus:outline-none focus:border-[#E58625]"
/>
</div>
{/* Location */}
<div>
<label className="block text-[12px] font-medium text-[#00293D]/70 font-serif mb-2">
Location
</label>
<input
type="text"
value={formData.location}
onChange={(e) => handleChange('location', e.target.value)}
className="w-full h-[40px] px-4 border border-[#00293D]/20 rounded-[15px] text-[14px] font-serif text-[#00293D] focus:outline-none focus:border-[#E58625]"
/>
</div>
</div>
{/* Save Button */}
<div className="mt-8 flex justify-end">
<button
onClick={handleSave}
className="px-8 py-3 bg-[#e58625] text-white rounded-[15px] font-fractul font-medium text-[14px] hover:bg-[#d47920] transition-colors"
>
Save Changes
</button>
</div>
</div>
</div>
</div>
);
}

View File

@@ -0,0 +1,165 @@
'use client';
import { useState } from 'react';
import { SettingsSidebar } from '../component/SettingsSidebar';
export default function PasswordSecurityPage() {
const [formData, setFormData] = useState({
currentPassword: '',
newPassword: '',
confirmPassword: '',
});
const [showPasswords, setShowPasswords] = useState({
current: false,
new: false,
confirm: false,
});
const handleChange = (field: string, value: string) => {
setFormData((prev) => ({ ...prev, [field]: value }));
};
const toggleShowPassword = (field: 'current' | 'new' | 'confirm') => {
setShowPasswords((prev) => ({ ...prev, [field]: !prev[field] }));
};
const handleSave = () => {
if (formData.newPassword !== formData.confirmPassword) {
alert('Passwords do not match');
return;
}
console.log('Updating password');
};
return (
<div className="flex flex-col lg:flex-row gap-6">
{/* Left Sidebar */}
<SettingsSidebar />
{/* 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]">
Password Security
</h1>
</div>
{/* Password Form */}
<div className="border border-[#00293d]/10 rounded-[15px] bg-white p-6">
<div className="mb-6">
<h2 className="font-fractul font-bold text-[16px] text-[#00293D] mb-2">
Change Password
</h2>
<p className="font-serif text-[12px] text-[#00293D]/60">
Ensure your account is using a strong password to stay secure
</p>
</div>
{/* Form Fields */}
<div className="space-y-6 max-w-md">
{/* Current Password */}
<div>
<label className="block text-[12px] font-medium text-[#00293D]/70 font-serif mb-2">
Current Password
</label>
<div className="relative">
<input
type={showPasswords.current ? 'text' : 'password'}
value={formData.currentPassword}
onChange={(e) => handleChange('currentPassword', e.target.value)}
placeholder="Enter current password"
className="w-full h-[40px] px-4 pr-12 border border-[#00293D]/20 rounded-[15px] text-[14px] font-serif text-[#00293D] placeholder:text-[#00293D]/40 focus:outline-none focus:border-[#E58625]"
/>
<button
type="button"
onClick={() => toggleShowPassword('current')}
className="absolute right-4 top-1/2 -translate-y-1/2 text-[#00293D]/50 hover:text-[#00293D] cursor-pointer"
>
{showPasswords.current ? '🙈' : '👁️'}
</button>
</div>
</div>
{/* New Password */}
<div>
<label className="block text-[12px] font-medium text-[#00293D]/70 font-serif mb-2">
New Password
</label>
<div className="relative">
<input
type={showPasswords.new ? 'text' : 'password'}
value={formData.newPassword}
onChange={(e) => handleChange('newPassword', e.target.value)}
placeholder="Enter new password"
className="w-full h-[40px] px-4 pr-12 border border-[#00293D]/20 rounded-[15px] text-[14px] font-serif text-[#00293D] placeholder:text-[#00293D]/40 focus:outline-none focus:border-[#E58625]"
/>
<button
type="button"
onClick={() => toggleShowPassword('new')}
className="absolute right-4 top-1/2 -translate-y-1/2 text-[#00293D]/50 hover:text-[#00293D] cursor-pointer"
>
{showPasswords.new ? '🙈' : '👁️'}
</button>
</div>
<p className="text-[11px] text-[#00293D]/50 font-serif mt-1">
Minimum 8 characters with at least one uppercase, lowercase, and number
</p>
</div>
{/* Confirm Password */}
<div>
<label className="block text-[12px] font-medium text-[#00293D]/70 font-serif mb-2">
Confirm New Password
</label>
<div className="relative">
<input
type={showPasswords.confirm ? 'text' : 'password'}
value={formData.confirmPassword}
onChange={(e) => handleChange('confirmPassword', e.target.value)}
placeholder="Confirm new password"
className="w-full h-[40px] px-4 pr-12 border border-[#00293D]/20 rounded-[15px] text-[14px] font-serif text-[#00293D] placeholder:text-[#00293D]/40 focus:outline-none focus:border-[#E58625]"
/>
<button
type="button"
onClick={() => toggleShowPassword('confirm')}
className="absolute right-4 top-1/2 -translate-y-1/2 text-[#00293D]/50 hover:text-[#00293D] cursor-pointer"
>
{showPasswords.confirm ? '🙈' : '👁️'}
</button>
</div>
</div>
</div>
{/* Save Button */}
<div className="mt-8">
<button
onClick={handleSave}
className="px-8 py-3 bg-[#e58625] text-white rounded-[15px] font-fractul font-medium text-[14px] hover:bg-[#d47920] transition-colors"
>
Update Password
</button>
</div>
</div>
{/* Two-Factor Authentication Section */}
<div className="border border-[#00293d]/10 rounded-[15px] bg-white p-6 mt-4">
<div className="flex items-center justify-between">
<div>
<h2 className="font-fractul font-bold text-[16px] text-[#00293D] mb-2">
Two-Factor Authentication
</h2>
<p className="font-serif text-[12px] text-[#00293D]/60">
Add an extra layer of security to your account
</p>
</div>
<button className="px-6 py-2 border border-[#e58625] text-[#e58625] rounded-[15px] font-serif text-[12px] hover:bg-[#e58625]/10 transition-colors">
Enable 2FA
</button>
</div>
</div>
</div>
</div>
);
}

View File

@@ -0,0 +1,255 @@
'use client';
import { useState } from 'react';
import { SettingsSidebar } from '../component/SettingsSidebar';
interface PrivacySetting {
id: string;
label: string;
description: string;
value: string;
options: { value: string; label: string }[];
}
export default function PrivacyPage() {
const [privacySettings, setPrivacySettings] = useState<PrivacySetting[]>([
{
id: 'profile_visibility',
label: 'Profile Visibility',
description: 'Control who can see your profile',
value: 'public',
options: [
{ value: 'public', label: 'Public' },
{ value: 'connections', label: 'Connections Only' },
{ value: 'private', label: 'Private' },
],
},
{
id: 'contact_info',
label: 'Contact Information',
description: 'Control who can see your contact details',
value: 'connections',
options: [
{ value: 'public', label: 'Public' },
{ value: 'connections', label: 'Connections Only' },
{ value: 'private', label: 'Hidden' },
],
},
{
id: 'activity_status',
label: 'Activity Status',
description: 'Show when you are active on the platform',
value: 'public',
options: [
{ value: 'public', label: 'Everyone' },
{ value: 'connections', label: 'Connections Only' },
{ value: 'private', label: 'No One' },
],
},
]);
const [dataSettings, setDataSettings] = useState({
shareAnalytics: true,
personalizedAds: false,
thirdPartySharing: false,
});
const handlePrivacyChange = (id: string, value: string) => {
setPrivacySettings((prev) =>
prev.map((item) => (item.id === id ? { ...item, value } : item))
);
};
const handleDataSettingChange = (key: keyof typeof dataSettings) => {
setDataSettings((prev) => ({ ...prev, [key]: !prev[key] }));
};
const handleSave = () => {
console.log('Saving privacy settings:', { privacySettings, dataSettings });
};
const handleDeleteAccount = () => {
if (confirm('Are you sure you want to delete your account? This action cannot be undone.')) {
console.log('Deleting account');
}
};
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>
);
return (
<div className="flex flex-col lg:flex-row gap-6">
{/* Left Sidebar */}
<SettingsSidebar />
{/* 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]">
Privacy
</h1>
</div>
{/* Privacy Settings */}
<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">
Privacy Settings
</h2>
<p className="font-serif text-[12px] text-[#00293D]/60">
Control your privacy and visibility preferences
</p>
</div>
<div className="space-y-6">
{privacySettings.map((item) => (
<div
key={item.id}
className="pb-4 border-b border-[#00293d]/10 last:border-0"
>
<div className="flex flex-col sm:flex-row sm:items-center justify-between gap-3">
<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>
<select
value={item.value}
onChange={(e) => handlePrivacyChange(item.id, e.target.value)}
className="h-[36px] px-4 border border-[#00293D]/20 rounded-[10px] text-[13px] font-serif text-[#00293D] focus:outline-none focus:border-[#E58625] bg-white cursor-pointer"
>
{item.options.map((option) => (
<option key={option.value} value={option.value}>
{option.label}
</option>
))}
</select>
</div>
</div>
))}
</div>
</div>
{/* Data & Personalization */}
<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">
Data & Personalization
</h2>
<p className="font-serif text-[12px] text-[#00293D]/60">
Manage how your data is used
</p>
</div>
<div className="space-y-4">
<div className="flex items-center justify-between py-3 border-b border-[#00293d]/10">
<div>
<h3 className="font-serif font-medium text-[14px] text-[#00293D]">
Share Analytics
</h3>
<p className="font-serif text-[12px] text-[#00293D]/60">
Help improve our service by sharing usage data
</p>
</div>
<ToggleSwitch
enabled={dataSettings.shareAnalytics}
onToggle={() => handleDataSettingChange('shareAnalytics')}
/>
</div>
<div className="flex items-center justify-between py-3 border-b border-[#00293d]/10">
<div>
<h3 className="font-serif font-medium text-[14px] text-[#00293D]">
Personalized Ads
</h3>
<p className="font-serif text-[12px] text-[#00293D]/60">
See ads tailored to your interests
</p>
</div>
<ToggleSwitch
enabled={dataSettings.personalizedAds}
onToggle={() => handleDataSettingChange('personalizedAds')}
/>
</div>
<div className="flex items-center justify-between py-3">
<div>
<h3 className="font-serif font-medium text-[14px] text-[#00293D]">
Third-Party Data Sharing
</h3>
<p className="font-serif text-[12px] text-[#00293D]/60">
Allow sharing data with third-party partners
</p>
</div>
<ToggleSwitch
enabled={dataSettings.thirdPartySharing}
onToggle={() => handleDataSettingChange('thirdPartySharing')}
/>
</div>
</div>
</div>
{/* Danger Zone */}
<div className="border border-red-200 rounded-[15px] bg-red-50/50 p-6 mb-4">
<div className="mb-4">
<h2 className="font-fractul font-bold text-[16px] text-red-600 mb-2">
Danger Zone
</h2>
<p className="font-serif text-[12px] text-red-600/70">
Irreversible and destructive actions
</p>
</div>
<div className="flex flex-col sm:flex-row sm:items-center justify-between gap-4">
<div>
<h3 className="font-serif font-medium text-[14px] text-[#00293D]">
Delete Account
</h3>
<p className="font-serif text-[12px] text-[#00293D]/60">
Permanently delete your account and all data
</p>
</div>
<button
onClick={handleDeleteAccount}
className="px-6 py-2 border border-red-500 text-red-500 rounded-[15px] font-serif text-[12px] hover:bg-red-50 transition-colors"
>
Delete Account
</button>
</div>
</div>
{/* Save Button */}
<div className="flex justify-end">
<button
onClick={handleSave}
className="px-8 py-3 bg-[#e58625] text-white rounded-[15px] font-fractul font-medium text-[14px] hover:bg-[#d47920] transition-colors"
>
Save Changes
</button>
</div>
</div>
</div>
);
}

View File

@@ -47,31 +47,30 @@ export function AgentHeader({ userName, userEmail }: AgentHeaderProps) {
</nav>
{/* Right Side Icons */}
<div className="flex items-center gap-3">
<div className="flex items-center gap-4">
{/* Notification Bell */}
<button className="relative p-1 hover:opacity-80 transition-opacity">
<button className="relative w-6 h-6 flex items-center justify-center hover:opacity-80 transition-opacity">
<Image
src="/assets/notification-icon.svg"
alt="Notifications"
width={18}
height={21}
width={20}
height={22}
/>
{/* Notification Dot */}
<span className="absolute top-0 right-0 w-1.5 h-1.5 bg-red-500 rounded-full"></span>
<span className="absolute -top-0.5 -right-0.5 w-2 h-2 bg-red-500 rounded-full"></span>
</button>
{/* Profile Icon with Dropdown */}
<div className="relative">
<button
onClick={() => setShowProfileMenu(!showProfileMenu)}
className="w-6 h-6 rounded-full overflow-hidden hover:opacity-80 transition-opacity"
className="w-6 h-6 flex items-center justify-center hover:opacity-80 transition-opacity"
>
<Image
src="/assets/profile-icon.svg"
alt="Profile"
width={24}
height={24}
className="w-full h-full"
/>
</button>