diff --git a/src/app/(agent)/agent/dashboard/page.tsx b/src/app/(agent)/agent/dashboard/page.tsx index 3188def..7af823f 100644 --- a/src/app/(agent)/agent/dashboard/page.tsx +++ b/src/app/(agent)/agent/dashboard/page.tsx @@ -3,7 +3,7 @@ import { useSession } from 'next-auth/react'; import Image from 'next/image'; -// Import components from component folder +// Import shared components import { InfoCard, ExperienceSection, @@ -12,7 +12,7 @@ import { TestimonialsSection, StatusButtons, ContactInfo, -} from './component'; +} from '@/components/profile'; // Mock agent data - in production, this would come from API const agentData = { @@ -132,6 +132,10 @@ export default function AgentDashboard() { memberSince={agentData.memberSince} bio={agentData.bio} expertise={agentData.expertise} + showEditButton={true} + editHref="/agent/edit" + messageHref="/agent/message" + requestsHref="/agent/network" /> {/* Experience Section */} diff --git a/src/app/(user)/user/profile/[id]/page.tsx b/src/app/(user)/user/profile/[id]/page.tsx new file mode 100644 index 0000000..10f4c8b --- /dev/null +++ b/src/app/(user)/user/profile/[id]/page.tsx @@ -0,0 +1,195 @@ +'use client'; + +import Image from 'next/image'; +import { useParams } from 'next/navigation'; + +// Import shared components +import { + InfoCard, + ExperienceSection, + ProfileCard, + SpecializationSection, + TestimonialsSection, + StatusButtons, + ContactInfo, +} from '@/components/profile'; + +// Mock agent data - in production, this would come from API based on id +const getAgentData = (id: string) => ({ + id, + name: 'Brian Neeland', + isVerified: true, + title: 'Licensed Real Estate Agent', + location: 'Colorado', + memberSince: 'March 2020', + bio: 'Brian brings eight years of hands-on experience helping clients confidently buy, sell, and invest in real estate. He combines strong analytical skills with deep market knowledge to identify the right opportunities and guide clients through every step of the process. With a data-driven approach and clear communication, Brian ensures smooth transactions and informed decisions tailored to each client\'s goals.', + expertise: ['Buyers', 'Sellers', 'Divorce', 'Luxury', 'Retirement', 'Historical', 'condo', 'Rural', 'FHA', 'Conventional', 'USDA', 'Retirement'], + email: 'brian@gmail.com', + phone: '+91*******7493', + profileImage: '/assets/demo_images/8f017153a7b4a239a4f0691234ef97dd55092282.jpg', + experience: { + years: '10+ years', + contracts: '10+ Contracts', + licensingAreas: ['Colorado Springs', 'Monument', 'Falcon', 'Castle Rock', 'Fountain', 'Momentum'], + expertiseYears: [ + { area: 'Colorado', years: '10 yrs' }, + { area: 'Falcon', years: '10 yrs' }, + { area: 'Colorado', years: '10 yrs' }, + { area: 'Colorado', years: '10 yrs' }, + ], + certifications: [ + { name: 'Certified Residential Specialist (CRS)', org: 'RESIDENTIAL REAL ESTATE COUNCIL' }, + { name: 'Certified Residential Specialist (CRS)', org: 'RESIDENTIAL REAL ESTATE COUNCIL' }, + ], + }, + availability: { + type: 'Full-time', + days: ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'], + }, + preferredWorkEnvironment: 'Preferred work environment includes on-site property visits, in-depth market research, client consultations, property tours, and active involvement in negotiations to ensure the best outcomes', + testimonialHighlight: "The most amazing experience I've had as a real estate professional is helping a family secure their dream home and seeing their happiness when they received the keys.", + specialization: { + types: ['Buyers', 'Sellers', 'First time Buyers', 'First time Sellers', 'Divorce'], + loanTypes: ['Conventional', 'FHA', 'VA', 'USDA'], + propertyTypes: ['SFR', 'Town home', 'Rural', 'Luxury', 'Condo'], + hobbies: ['Boating', 'Horses', 'RV', 'Automotive', 'Aviation'], + pricePoints: ['Under $100K', '$100K – $300K', '$300K – $500K', '$500K – $1M', '$1M and above'], + }, + testimonials: [ + { + id: 1, + text: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean commodo ligula eget dolor. Sed dignissim, nisl eget tincidunt vulputate, lacus justo bibendum ipsum, vitae tempus risus lorem at nunc. Integer sed arcu vitae risus feugiat vehicula. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas.', + author: 'Kenedy Kenney', + role: 'Chief Operations Officer', + rating: 5, + }, + { + id: 2, + text: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean commodo ligula eget dolor. Sed dignissim, nisl eget tincidunt vulputate, lacus justo bibendum ipsum, vitae tempus risus lorem at nunc. Integer sed arcu vitae risus feugiat vehicula. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas.', + author: 'Kenedy Kenney', + role: 'Chief Operations Officer', + rating: 5, + }, + { + id: 3, + text: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean commodo ligula eget dolor. Sed dignissim, nisl eget tincidunt vulputate, lacus justo bibendum ipsum, vitae tempus risus lorem at nunc. Integer sed arcu vitae risus feugiat vehicula. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas.', + author: 'Kenedy Kenney', + role: 'Chief Operations Officer', + rating: 5, + }, + ], +}); + +export default function AgentProfileView() { + const params = useParams(); + const id = params.id as string; + + // In production, fetch agent data based on id + const agentData = getAgentData(id); + const [firstName, lastName] = agentData.name.split(' '); + + return ( +
+ {/* Main Layout - Responsive: Column on mobile, Row on desktop */} +
+ {/* Left Sidebar - Status & Contact */} +
+ {/* Profile Image */} +
+
+ Profile + {/* Gradient Overlay */} +
+
+
+ + {/* Status Buttons */} + + + {/* Contact Info */} + +
+ + {/* Right Content - Profile Info + Experience + All Sections */} +
+ {/* Profile Card - No edit button for user view */} + + + {/* Experience Section */} + + + {/* Info Cards Section */} +
+ + } + content={ +
+

{agentData.availability.type}

+
+ {agentData.availability.days.map((day) => ( +

{day}

+ ))} +
+
+ } + /> + + } + content={

{agentData.preferredWorkEnvironment}

} + /> + + } + content={

“{agentData.testimonialHighlight}”

} + /> +
+ + {/* Specialization Section */} + + + {/* Testimonials Section */} + +
+
+
+ ); +} diff --git a/src/components/profile/ContactInfo.tsx b/src/components/profile/ContactInfo.tsx new file mode 100644 index 0000000..45797e4 --- /dev/null +++ b/src/components/profile/ContactInfo.tsx @@ -0,0 +1,67 @@ +'use client'; + +import { useState } from 'react'; +import Image from 'next/image'; + +interface ContactInfoProps { + email: string; + phone: string; +} + +// Helper function to mask email +function maskEmail(email: string): string { + const [localPart, domain] = email.split('@'); + if (!domain) return '********'; + const maskedLocal = localPart.slice(0, 2) + '********'; + return `${maskedLocal}@${domain}`; +} + +// Helper function to mask phone +function maskPhone(phone: string): string { + if (phone.length <= 4) return '********'; + return phone.slice(0, -4).replace(/./g, '*') + phone.slice(-4); +} + +export function ContactInfo({ email, phone }: ContactInfoProps) { + const [showEmail, setShowEmail] = useState(false); + const [showPhone, setShowPhone] = useState(false); + + return ( +
+
+ Email: + + {showEmail ? email : maskEmail(email)} + + +
+
+ Ph.No: + + {showPhone ? phone : maskPhone(phone)} + + +
+
+ ); +} diff --git a/src/components/profile/ExperienceSection.tsx b/src/components/profile/ExperienceSection.tsx new file mode 100644 index 0000000..6394579 --- /dev/null +++ b/src/components/profile/ExperienceSection.tsx @@ -0,0 +1,83 @@ +'use client'; + +import { Tag } from './Tag'; + +interface ExperienceData { + years: string; + contracts: string; + licensingAreas: string[]; + expertiseYears: { area: string; years: string }[]; + certifications: { name: string; org: string }[]; +} + +interface ExperienceSectionProps { + experience: ExperienceData; +} + +export function ExperienceSection({ experience }: ExperienceSectionProps) { + return ( +
+

Experience

+
+ {/* Left Column */} +
+
+

Years in Experience

+
    +
  • {experience.years}
  • +
+
+ {/* Horizontal divider */} +
+
+

Number of contract closed

+
    +
  • {experience.contracts}
  • +
+
+
+

Licensing & Areas

+
+ {experience.licensingAreas.map((area, idx) => ( + + {area} + + ))} + +3 More +
+
+
+ + {/* Divider - Hidden on mobile, visible on desktop */} +
+
+ + {/* Right Column */} +
+
+

Areas in expertise & Years

+
+ {experience.expertiseYears.slice(0, 4).map((item, idx) => ( + + {item.area} – {item.years} + + ))} + +3 More +
+
+
+

Certifications

+
    + {experience.certifications.map((cert, idx) => ( +
  • + {cert.name} +

    {cert.org}

    +
  • + ))} +
+
+
+
+
+ ); +} diff --git a/src/components/profile/InfoCard.tsx b/src/components/profile/InfoCard.tsx new file mode 100644 index 0000000..01ee92c --- /dev/null +++ b/src/components/profile/InfoCard.tsx @@ -0,0 +1,17 @@ +'use client'; + +interface InfoCardProps { + title: string; + content: React.ReactNode; + icon: React.ReactNode; +} + +export function InfoCard({ title, content, icon }: InfoCardProps) { + return ( +
+
{icon}
+ {title &&

{title}

} +
{content}
+
+ ); +} diff --git a/src/components/profile/ProfileCard.tsx b/src/components/profile/ProfileCard.tsx new file mode 100644 index 0000000..5caa88b --- /dev/null +++ b/src/components/profile/ProfileCard.tsx @@ -0,0 +1,172 @@ +'use client'; + +import Image from 'next/image'; +import Link from 'next/link'; +import { Tag } from './Tag'; + +interface ProfileCardProps { + firstName: string; + lastName: string; + isVerified: boolean; + title: string; + location: string; + memberSince: string; + bio: string; + expertise: string[]; + showEditButton?: boolean; + editHref?: string; + messageHref?: string; + requestsHref?: string; +} + +export function ProfileCard({ + firstName, + lastName, + isVerified, + title, + location, + memberSince, + bio, + expertise, + showEditButton = false, + editHref = '/agent/edit', + messageHref, + requestsHref, +}: ProfileCardProps) { + return ( +
+ {/* Name and Actions Row */} +
+
+
+

+ {firstName}{' '} + {lastName} +

+ {isVerified && ( + <> + Verified + + (Verified Expert) + + + )} + {showEditButton && ( + + Edit profile + + )} +
+

{title}

+
+ + Location + + {location} + + + + Calendar + + Member Since {memberSince} + + +
+
+ + {/* Action Buttons */} +
+ {messageHref ? ( + + Message + Message + + ) : ( + + )} + {requestsHref ? ( + + Connect + {showEditButton ? 'Requests' : 'Connect'} + + ) : ( + + )} +
+
+ + {/* Bio */} +

+ {bio} +

+ + {/* Expertise Tags */} +
+

+ Expertise: +

+
+ {expertise.map((tag, idx) => ( + {tag} + ))} +
+
+
+ ); +} diff --git a/src/components/profile/SpecializationCard.tsx b/src/components/profile/SpecializationCard.tsx new file mode 100644 index 0000000..5080388 --- /dev/null +++ b/src/components/profile/SpecializationCard.tsx @@ -0,0 +1,36 @@ +'use client'; + +import Image from 'next/image'; + +interface SpecializationCardProps { + title: string; + items: string[]; + icon: React.ReactNode; +} + +export function SpecializationCard({ title, items, icon }: SpecializationCardProps) { + return ( +
+
{icon}
+

{title}

+
+ {items.map((item, idx) => ( +

+ {item} +

+ ))} +
+
+ +
+
+ ); +} diff --git a/src/components/profile/SpecializationSection.tsx b/src/components/profile/SpecializationSection.tsx new file mode 100644 index 0000000..9c953b5 --- /dev/null +++ b/src/components/profile/SpecializationSection.tsx @@ -0,0 +1,91 @@ +'use client'; + +import Image from 'next/image'; +import { SpecializationCard } from './SpecializationCard'; + +interface SpecializationData { + types: string[]; + loanTypes: string[]; + propertyTypes: string[]; + hobbies: string[]; + pricePoints: string[]; +} + +interface SpecializationSectionProps { + specialization: SpecializationData; +} + +export function SpecializationSection({ specialization }: SpecializationSectionProps) { + return ( +
+
+

Specialization

+

Area Of Expertise and Focus

+
+
+ + } + /> + + } + /> + + } + /> +
+
+ + } + /> + + } + /> +
+
+ ); +} diff --git a/src/components/profile/StarRating.tsx b/src/components/profile/StarRating.tsx new file mode 100644 index 0000000..6617645 --- /dev/null +++ b/src/components/profile/StarRating.tsx @@ -0,0 +1,23 @@ +'use client'; + +import Image from 'next/image'; + +interface StarRatingProps { + rating: number; +} + +export function StarRating({ rating }: StarRatingProps) { + return ( +
+ {[1, 2, 3, 4, 5].map((star) => ( + {star + ))} +
+ ); +} diff --git a/src/components/profile/StatusButtons.tsx b/src/components/profile/StatusButtons.tsx new file mode 100644 index 0000000..408ee45 --- /dev/null +++ b/src/components/profile/StatusButtons.tsx @@ -0,0 +1,30 @@ +'use client'; + +interface StatusButtonsProps { + isAvailable?: boolean; +} + +export function StatusButtons({ isAvailable = true }: StatusButtonsProps) { + return ( +
+
+
+ + Available. +
+ +
+
+
+ + Unavailable. +
+ +
+
+ ); +} diff --git a/src/components/profile/Tag.tsx b/src/components/profile/Tag.tsx new file mode 100644 index 0000000..839cdd8 --- /dev/null +++ b/src/components/profile/Tag.tsx @@ -0,0 +1,22 @@ +'use client'; + +interface TagProps { + children: React.ReactNode; + variant?: 'default' | 'light' | 'orange'; +} + +export function Tag({ children, variant = 'default' }: TagProps) { + return ( + + {children} + + ); +} diff --git a/src/components/profile/TestimonialCard.tsx b/src/components/profile/TestimonialCard.tsx new file mode 100644 index 0000000..5088444 --- /dev/null +++ b/src/components/profile/TestimonialCard.tsx @@ -0,0 +1,34 @@ +'use client'; + +import Image from 'next/image'; +import { StarRating } from './StarRating'; + +interface TestimonialCardProps { + text: string; + author: string; + role: string; + rating: number; +} + +export function TestimonialCard({ text, author, role, rating }: TestimonialCardProps) { + return ( +
+
+ Quote +

I have been working with Lorem .

+
+

{text}

+
+ +

{author}

+

{role}

+
+
+ ); +} diff --git a/src/components/profile/TestimonialsSection.tsx b/src/components/profile/TestimonialsSection.tsx new file mode 100644 index 0000000..c91def0 --- /dev/null +++ b/src/components/profile/TestimonialsSection.tsx @@ -0,0 +1,38 @@ +'use client'; + +import { TestimonialCard } from './TestimonialCard'; + +interface Testimonial { + id: number; + text: string; + author: string; + role: string; + rating: number; +} + +interface TestimonialsSectionProps { + testimonials: Testimonial[]; +} + +export function TestimonialsSection({ testimonials }: TestimonialsSectionProps) { + return ( +
+

Testimonials

+
+

+ Clients rate our real estate services 4.9 out of 5 on average, based on recent client reviews. +

+
+ {testimonials.map((testimonial) => ( + + ))} +
+
+ ); +} diff --git a/src/components/profile/index.ts b/src/components/profile/index.ts new file mode 100644 index 0000000..b0bf67e --- /dev/null +++ b/src/components/profile/index.ts @@ -0,0 +1,12 @@ +// Shared Profile Components +export { StarRating } from './StarRating'; +export { Tag } from './Tag'; +export { InfoCard } from './InfoCard'; +export { SpecializationCard } from './SpecializationCard'; +export { ProfileCard } from './ProfileCard'; +export { ExperienceSection } from './ExperienceSection'; +export { SpecializationSection } from './SpecializationSection'; +export { TestimonialCard } from './TestimonialCard'; +export { TestimonialsSection } from './TestimonialsSection'; +export { StatusButtons } from './StatusButtons'; +export { ContactInfo } from './ContactInfo';