feat: Implement custom scrollbar, refine agent profile edit navigation, and enhance quick link scrolling on the agent edit page.
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import Image from 'next/image';
|
import Image from 'next/image';
|
||||||
|
import Link from 'next/link';
|
||||||
import { Tag } from './Tag';
|
import { Tag } from './Tag';
|
||||||
|
|
||||||
interface ProfileCardProps {
|
interface ProfileCardProps {
|
||||||
@@ -47,14 +48,14 @@ export function ProfileCard({
|
|||||||
</span>
|
</span>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
<button className="p-1 hover:bg-gray-100 rounded transition-colors">
|
<Link href="/agent/edit" className="p-1 hover:bg-gray-100 rounded transition-colors">
|
||||||
<Image
|
<Image
|
||||||
src="/assets/icons/edit-pencil-orange-icon.svg"
|
src="/assets/icons/edit-pencil-orange-icon.svg"
|
||||||
alt="Edit name"
|
alt="Edit profile"
|
||||||
width={16}
|
width={16}
|
||||||
height={16}
|
height={16}
|
||||||
/>
|
/>
|
||||||
</button>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
<p className="text-[#00293d] text-sm mb-2 font-fractul">{title}</p>
|
<p className="text-[#00293d] text-sm mb-2 font-fractul">{title}</p>
|
||||||
<div className="flex items-center justify-center lg:justify-start gap-4 text-sm text-[#00293d] font-fractul">
|
<div className="flex items-center justify-center lg:justify-start gap-4 text-sm text-[#00293d] font-fractul">
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
|
|
||||||
import { useSession } from 'next-auth/react';
|
import { useSession } from 'next-auth/react';
|
||||||
import Image from 'next/image';
|
import Image from 'next/image';
|
||||||
import Link from 'next/link';
|
|
||||||
|
|
||||||
// Import components from component folder
|
// Import components from component folder
|
||||||
import {
|
import {
|
||||||
@@ -104,17 +103,14 @@ export default function AgentDashboard() {
|
|||||||
<div className="absolute inset-0 bg-gradient-to-t from-black/50 via-black/20 to-transparent pointer-events-none" />
|
<div className="absolute inset-0 bg-gradient-to-t from-black/50 via-black/20 to-transparent pointer-events-none" />
|
||||||
</div>
|
</div>
|
||||||
{/* Edit Icon - Top Right Outside */}
|
{/* Edit Icon - Top Right Outside */}
|
||||||
<Link
|
<button className="absolute -top-3 -right-3 w-9 h-9 bg-white rounded-[10px] shadow-md flex items-center justify-center hover:bg-gray-50 transition-colors">
|
||||||
href="/agent/edit"
|
|
||||||
className="absolute -top-3 -right-3 w-9 h-9 bg-white rounded-[10px] shadow-md flex items-center justify-center hover:bg-gray-50 transition-colors"
|
|
||||||
>
|
|
||||||
<Image
|
<Image
|
||||||
src="/assets/icons/edit-icon.svg"
|
src="/assets/icons/edit-icon.svg"
|
||||||
alt="Edit profile"
|
alt="Edit profile image"
|
||||||
width={20}
|
width={20}
|
||||||
height={20}
|
height={20}
|
||||||
/>
|
/>
|
||||||
</Link>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Status Buttons */}
|
{/* Status Buttons */}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import { useState } from 'react';
|
import { useEffect, useState, useRef } from 'react';
|
||||||
|
|
||||||
const links = [
|
const links = [
|
||||||
{ id: 'basic-info', label: 'Basic Information' },
|
{ id: 'basic-info', label: 'Basic Information' },
|
||||||
@@ -20,14 +20,65 @@ const links = [
|
|||||||
{ id: 'availability', label: 'Availability' },
|
{ id: 'availability', label: 'Availability' },
|
||||||
];
|
];
|
||||||
|
|
||||||
export function QuickLinks() {
|
interface QuickLinksProps {
|
||||||
|
scrollContainerRef: React.RefObject<HTMLDivElement | null>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function QuickLinks({ scrollContainerRef }: QuickLinksProps) {
|
||||||
const [activeLink, setActiveLink] = useState('basic-info');
|
const [activeLink, setActiveLink] = useState('basic-info');
|
||||||
|
const isClickScrolling = useRef(false);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const container = scrollContainerRef.current;
|
||||||
|
if (!container) return;
|
||||||
|
|
||||||
|
const handleScroll = () => {
|
||||||
|
if (isClickScrolling.current) return;
|
||||||
|
|
||||||
|
const containerRect = container.getBoundingClientRect();
|
||||||
|
const containerTop = containerRect.top;
|
||||||
|
|
||||||
|
let currentSection = 'basic-info';
|
||||||
|
|
||||||
|
for (const link of links) {
|
||||||
|
const element = document.getElementById(link.id);
|
||||||
|
if (element) {
|
||||||
|
const rect = element.getBoundingClientRect();
|
||||||
|
// Check if the section is near the top of the container
|
||||||
|
if (rect.top <= containerTop + 100) {
|
||||||
|
currentSection = link.id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setActiveLink(currentSection);
|
||||||
|
};
|
||||||
|
|
||||||
|
container.addEventListener('scroll', handleScroll);
|
||||||
|
return () => container.removeEventListener('scroll', handleScroll);
|
||||||
|
}, [scrollContainerRef]);
|
||||||
|
|
||||||
const scrollToSection = (id: string) => {
|
const scrollToSection = (id: string) => {
|
||||||
setActiveLink(id);
|
const container = scrollContainerRef.current;
|
||||||
const element = document.getElementById(id);
|
const element = document.getElementById(id);
|
||||||
if (element) {
|
|
||||||
element.scrollIntoView({ behavior: 'smooth', block: 'start' });
|
if (element && container) {
|
||||||
|
isClickScrolling.current = true;
|
||||||
|
setActiveLink(id);
|
||||||
|
|
||||||
|
const containerRect = container.getBoundingClientRect();
|
||||||
|
const elementRect = element.getBoundingClientRect();
|
||||||
|
const scrollTop = container.scrollTop + (elementRect.top - containerRect.top) - 20;
|
||||||
|
|
||||||
|
container.scrollTo({
|
||||||
|
top: scrollTop,
|
||||||
|
behavior: 'smooth'
|
||||||
|
});
|
||||||
|
|
||||||
|
// Reset the flag after scroll animation completes
|
||||||
|
setTimeout(() => {
|
||||||
|
isClickScrolling.current = false;
|
||||||
|
}, 500);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import { useState } from 'react';
|
import { useState, useRef } from 'react';
|
||||||
import { useRouter } from 'next/navigation';
|
import { useRouter } from 'next/navigation';
|
||||||
import Image from 'next/image';
|
import Image from 'next/image';
|
||||||
import {
|
import {
|
||||||
@@ -108,6 +108,7 @@ const initialFormData = {
|
|||||||
export default function EditProfilePage() {
|
export default function EditProfilePage() {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const [formData, setFormData] = useState(initialFormData);
|
const [formData, setFormData] = useState(initialFormData);
|
||||||
|
const scrollContainerRef = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
const handleCancel = () => {
|
const handleCancel = () => {
|
||||||
router.push('/agent/dashboard');
|
router.push('/agent/dashboard');
|
||||||
@@ -124,16 +125,14 @@ export default function EditProfilePage() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex gap-6">
|
<div className="flex gap-6 h-[calc(100vh-180px)]">
|
||||||
{/* Left Sidebar - Quick Links */}
|
{/* Left Sidebar - Quick Links */}
|
||||||
<div className="w-[220px] flex-shrink-0 hidden lg:block">
|
<div className="w-[220px] flex-shrink-0 hidden lg:block h-full overflow-y-auto scrollbar-thin">
|
||||||
<div className="sticky top-6">
|
<QuickLinks scrollContainerRef={scrollContainerRef} />
|
||||||
<QuickLinks />
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Main Content */}
|
{/* Main Content - Scrollable */}
|
||||||
<div className="flex-1 space-y-6">
|
<div ref={scrollContainerRef} className="flex-1 space-y-6 overflow-y-auto pr-2 scrollbar-thin scrollbar-thumb-gray-300 scrollbar-track-transparent">
|
||||||
{/* Basic Information */}
|
{/* Basic Information */}
|
||||||
<div className="bg-white rounded-[20px] p-6">
|
<div className="bg-white rounded-[20px] p-6">
|
||||||
<FormSection id="basic-info" icon="/assets/icons/user-icon.svg" title="Basic Information">
|
<FormSection id="basic-info" icon="/assets/icons/user-icon.svg" title="Basic Information">
|
||||||
|
|||||||
@@ -95,3 +95,27 @@ html {
|
|||||||
background-color: var(--color-primary-light);
|
background-color: var(--color-primary-light);
|
||||||
color: var(--color-primary-dark);
|
color: var(--color-primary-dark);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Custom Scrollbar Styles */
|
||||||
|
.scrollbar-thin::-webkit-scrollbar {
|
||||||
|
width: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.scrollbar-thin::-webkit-scrollbar-track {
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.scrollbar-thin::-webkit-scrollbar-thumb {
|
||||||
|
background-color: #d1d5db;
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.scrollbar-thin::-webkit-scrollbar-thumb:hover {
|
||||||
|
background-color: #9ca3af;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Firefox scrollbar */
|
||||||
|
.scrollbar-thin {
|
||||||
|
scrollbar-width: thin;
|
||||||
|
scrollbar-color: #d1d5db transparent;
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user