feat: introduce agent network page with sidebar, invitation cards, and new icons, while refactoring dashboard components and updating profile links.

This commit is contained in:
pradeepkumar
2026-01-18 23:43:44 +05:30
parent 74fe46335f
commit 48c4b564e5
11 changed files with 246 additions and 145 deletions

View File

@@ -95,7 +95,10 @@ export function ProfileCard({
/>
Message
</button>
<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/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"
>
<Image
src="/assets/icons/requests-dark-icon.svg"
alt="Requests"
@@ -103,7 +106,7 @@ export function ProfileCard({
height={13}
/>
Requests
</button>
</Link>
</div>
</div>

View File

@@ -1,141 +0,0 @@
'use client';
import Image from 'next/image';
import { Button } from '@/components/ui/Button';
import { Tag } from './Tag';
interface ProfileHeaderProps {
name: string;
isVerified: boolean;
title: string;
location: string;
memberSince: string;
bio: string;
expertise: string[];
}
export function ProfileHeader({
name,
isVerified,
title,
location,
memberSince,
bio,
expertise,
}: ProfileHeaderProps) {
const [firstName, lastName] = name.split(' ');
return (
<div className="bg-white rounded-[20px] border border-gray-200 p-6">
{/* Name and Actions Row */}
<div className="flex flex-col lg:flex-row lg:items-start lg:justify-between gap-4 mb-4">
<div>
{/* Name and Verification */}
<div className="flex items-center gap-2 mb-1">
<h1 className="text-[18px] text-[#00293d] font-[family-name:var(--font-fractul)]">
<span className="font-bold">{firstName}</span>{' '}
<span className="font-normal">{lastName}</span>
</h1>
{isVerified && (
<>
<Image
src="/assets/icons/verified-icon.svg"
alt="Verified"
width={15}
height={14}
/>
<span className="text-[14px] text-[#638559] font-medium font-serif">
(Verified Expert)
</span>
</>
)}
<button className="p-1 hover:bg-gray-100 rounded transition-colors">
<Image
src="/assets/icons/edit-pencil-orange-icon.svg"
alt="Edit name"
width={19}
height={19}
/>
</button>
</div>
{/* Title */}
<p className="text-[#00293d] text-sm mb-2">{title}</p>
{/* Location and Member Since */}
<div className="flex items-center gap-4 text-sm text-[#00293d]">
<span className="flex items-center gap-1 text-[#e58625] font-medium">
<Image
src="/assets/icons/location-icon.svg"
alt="Location"
width={16}
height={16}
/>
{location}
</span>
<span className="flex items-center gap-1">
<Image
src="/assets/icons/calendar-icon.svg"
alt="Calendar"
width={16}
height={16}
/>
Member Since {memberSince}
</span>
</div>
</div>
{/* Action Buttons */}
<div className="flex items-center gap-3">
<div className="relative overflow-visible">
<Button
variant="action"
size="sm"
leftIcon={
<Image
src="/assets/icons/message-icon.svg"
alt="Message"
width={16}
height={16}
/>
}
>
Message
</Button>
<span className="absolute -top-2 -right-2 w-3 h-3 bg-red-500 rounded-full border-2 border-white z-10"></span>
</div>
<div className="relative overflow-visible">
<Button
variant="action"
size="sm"
leftIcon={
<Image
src="/assets/icons/clipboard-icon.svg"
alt="Requests"
width={16}
height={16}
/>
}
>
Requests
</Button>
<span className="absolute -top-2 -right-2 w-3 h-3 bg-red-500 rounded-full border-2 border-white z-10"></span>
</div>
</div>
</div>
{/* Bio */}
<p className="text-[#00293d] text-sm leading-relaxed mb-4">{bio}</p>
{/* Expertise Tags */}
<div>
<p className="font-bold text-[#00293d] text-sm mb-2">Expertise:</p>
<div className="flex flex-wrap gap-2">
{expertise.map((tag, idx) => (
<Tag key={idx}>{tag}</Tag>
))}
</div>
</div>
</div>
);
}

View File

@@ -4,7 +4,6 @@ export { Tag } from './Tag';
export { InfoCard } from './InfoCard';
export { SpecializationCard } from './SpecializationCard';
export { ProfileSidebar } from './ProfileSidebar';
export { ProfileHeader } from './ProfileHeader';
export { ProfileCard } from './ProfileCard';
export { ExperienceSection } from './ExperienceSection';
export { SpecializationSection } from './SpecializationSection';

View File

@@ -0,0 +1,90 @@
'use client';
import Image from 'next/image';
interface InvitationCardProps {
id: string;
name: string;
avatar: string;
description: string;
mutualConnection?: string;
onAccept?: (id: string) => void;
onIgnore?: (id: string) => void;
}
export function InvitationCard({
id,
name,
avatar,
description,
mutualConnection,
onAccept,
onIgnore,
}: InvitationCardProps) {
return (
<div className="flex flex-col sm:flex-row items-start sm:items-center gap-4 py-4">
{/* Avatar */}
<div className="flex-shrink-0">
<Image
src={avatar}
alt={name}
width={80}
height={80}
className="rounded-full object-cover w-[80px] h-[80px]"
/>
</div>
{/* Content */}
<div className="flex-1 min-w-0">
{/* Name with verified icon */}
<div className="flex items-center gap-2 mb-1">
<h3 className="font-serif font-bold text-[14px] leading-[19px] text-[#00293D]">
{name}
</h3>
<Image
src="/assets/icons/shield-verified-icon.svg"
alt="Verified"
width={19}
height={19}
/>
</div>
{/* Description */}
<p className="font-serif font-normal text-[14px] leading-[19px] text-[#00293D] mb-1">
{description}
</p>
{/* Mutual Connection */}
{mutualConnection && (
<div className="flex items-center gap-2">
<Image
src="/assets/icons/chain-icon.svg"
alt="Connection"
width={18}
height={18}
/>
<span className="font-serif font-normal text-[14px] leading-[19px] text-[#00293D]">
Mutual Connection With {mutualConnection}
</span>
</div>
)}
</div>
{/* Action Buttons */}
<div className="flex items-center gap-3 flex-shrink-0">
<button
onClick={() => onIgnore?.(id)}
className="h-[27px] px-4 rounded-[15px] border border-[#00293d] font-serif font-light text-[14px] text-[#00293D] hover:bg-[#00293d]/5 transition-colors cursor-pointer"
>
Ignore
</button>
<button
onClick={() => onAccept?.(id)}
className="h-[27px] px-4 rounded-[15px] bg-[#e58625] font-fractul font-medium text-[14px] text-[#00293D] hover:bg-[#d47920] transition-colors cursor-pointer"
>
Accept
</button>
</div>
</div>
);
}

View File

@@ -0,0 +1,56 @@
'use client';
import Image from 'next/image';
import Link from 'next/link';
interface NavItem {
label: string;
href: string;
icon: string;
isActive?: boolean;
}
const navItems: NavItem[] = [
{
label: 'Connections',
href: '/agent/network/connections',
icon: '/assets/icons/people-icon.svg',
isActive: true,
},
];
export function NetworkSidebar() {
return (
<div className="border border-[#00293d] rounded-[7px] p-4 w-full lg:w-[280px] bg-white h-fit">
<h2 className="font-fractul font-medium text-[20px] leading-[24px] text-[#00293D] mb-4">
Manage my network
</h2>
<div className="w-full h-0 border-t border-[#00293d]/30 mb-4" />
<nav className="space-y-3">
{navItems.map((item) => (
<Link
key={item.href}
href={item.href}
className={`flex items-center gap-3 py-2 px-1 rounded transition-colors cursor-pointer ${
item.isActive
? 'text-[#00293D]'
: 'text-[#00293D]/70 hover:text-[#00293D]'
}`}
>
<Image
src={item.icon}
alt={item.label}
width={31}
height={31}
/>
<span className="font-serif font-normal text-[14px] leading-[19px]">
{item.label}
</span>
</Link>
))}
</nav>
</div>
);
}

View File

@@ -0,0 +1,81 @@
'use client';
import { NetworkSidebar } from './component/NetworkSidebar';
import { InvitationCard } from './component/InvitationCard';
// Mock data for invitations
const invitations = [
{
id: '1',
name: 'Sathish R',
avatar: '/assets/icons/user-placeholder-icon.svg',
description: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.',
mutualConnection: 'Anvar',
},
{
id: '2',
name: 'Ragunath',
avatar: '/assets/icons/user-placeholder-icon.svg',
description: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.',
mutualConnection: 'Anvar',
},
{
id: '3',
name: 'Sabari',
avatar: '/assets/icons/user-placeholder-icon.svg',
description: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.',
mutualConnection: 'Anvar',
},
];
export default function NetworkPage() {
const handleAccept = (id: string) => {
console.log('Accepted invitation:', id);
};
const handleIgnore = (id: string) => {
console.log('Ignored invitation:', id);
};
return (
<div className="flex flex-col lg:flex-row gap-6">
{/* Left Sidebar */}
<NetworkSidebar />
{/* 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]">
Manage my network
</h1>
</div>
{/* Invitations Card */}
<div className="border border-[#00293d]/10 rounded-[15px] bg-white">
{/* Invitations Header */}
<div className="flex items-center justify-between px-6 py-4 border-b border-[#00293d]/10">
<h2 className="font-fractul font-bold text-[14px] leading-[17px] text-[#00293D]">
Invitations ({invitations.length})
</h2>
<button className="font-fractul font-bold text-[14px] leading-[17px] text-[#00293D] hover:text-[#e58625] transition-colors cursor-pointer">
Show All
</button>
</div>
{/* Invitations List */}
<div className="px-6 divide-y divide-[#00293d]/10">
{invitations.map((invitation) => (
<InvitationCard
key={invitation.id}
{...invitation}
onAccept={handleAccept}
onIgnore={handleIgnore}
/>
))}
</div>
</div>
</div>
</div>
);
}

View File

@@ -17,7 +17,7 @@ export function Button({
className = '',
...props
}: ButtonProps) {
const baseStyles = 'font-medium transition-all duration-200 inline-flex items-center justify-center';
const baseStyles = 'font-medium transition-all duration-200 inline-flex items-center justify-center cursor-pointer';
const variants = {
primary: 'bg-[#f5a623] text-white hover:bg-[#e09620] active:bg-[#c98a1c] rounded-lg',