'use client'; import { useState, useEffect, useCallback, Suspense } from 'react'; import { useSearchParams } from 'next/navigation'; import Image from 'next/image'; import Link from 'next/link'; import { FilterModal, FilterState, clientSpecializations, loanTypes, propertyTypes, pricePoints } from '@/components/profiles/FilterModal'; import { agentsService, AgentType, PublicAgentProfile, SearchAgentsParams } from '@/services/agents.service'; import { uploadService } from '@/services/upload.service'; interface FilterSectionProps { title: string; options: string[]; selectedOptions: string[]; onToggle: (option: string) => void; showMore?: boolean; } function FilterSection({ title, options, selectedOptions, onToggle, showMore }: FilterSectionProps) { const [expanded, setExpanded] = useState(false); const displayOptions = expanded ? options : options.slice(0, 6); return (

{title}

{displayOptions.map((option) => ( ))}
{showMore && options.length > 6 && ( )}
); } interface ProfileCardProps { profile: PublicAgentProfile; } function ProfileCard({ profile }: ProfileCardProps) { const [showFullBio, setShowFullBio] = useState(false); const [avatarUrl, setAvatarUrl] = useState(null); const defaultImage = '/assets/demo_images/8f017153a7b4a239a4f0691234ef97dd55092282.jpg'; const truncatedBio = profile.bio && profile.bio.length > 150 ? profile.bio.slice(0, 150) + '...' : profile.bio || ''; // Fetch presigned URL for avatar if it's an S3 key useEffect(() => { const fetchAvatarUrl = async () => { if (profile.avatar && !profile.avatar.startsWith('http') && !profile.avatar.startsWith('/')) { try { const presignedUrl = await uploadService.getPresignedDownloadUrl(profile.avatar); setAvatarUrl(presignedUrl); } catch (error) { console.error('Failed to get avatar URL:', error); } } else if (profile.avatar) { setAvatarUrl(profile.avatar); } }; fetchAvatarUrl(); }, [profile.avatar]); const getProfileImageUrl = () => { if (avatarUrl) return avatarUrl; if (profile.avatar?.startsWith('/')) return profile.avatar; return defaultImage; }; // Format member since date const formatMemberSince = (dateString?: string) => { if (!dateString) return 'Member'; try { const date = new Date(dateString); return date.toLocaleDateString('en-US', { month: 'long', year: 'numeric' }); } catch { return 'Member'; } }; return (
{/* Profile Image */}
{/* eslint-disable-next-line @next/next/no-img-element */} {`${profile.firstName} { const target = e.target as HTMLImageElement; target.src = defaultImage; }} />
{/* Profile Info */}
{/* Header */}

{profile.firstName} {profile.lastName}

{profile.isVerified && ( Verified (Verified Expert) )}

{profile.agentType?.name || 'Real Estate Professional'}

{profile.rating && (
{profile.rating.toFixed(1)} Rating
)}
{/* Location & Member Since */}
{profile.serviceAreas && profile.serviceAreas.length > 0 && (
Location {profile.serviceAreas[0]}
)}
Member Since Member Since {formatMemberSince(profile.createdAt)}
{/* Bio */} {profile.bio && (

{showFullBio ? profile.bio : truncatedBio} {profile.bio.length > 150 && ( )}

)} {/* Specializations */} {profile.specializations && profile.specializations.length > 0 && (

Expertise:

{profile.specializations.map((tag, index) => ( {tag} ))}
)} {/* Languages */} {profile.languages && profile.languages.length > 0 && (
{profile.languages.map((lang, index) => ( {lang} ))}
)}
); } function ProfilesPageContent() { const searchParams = useSearchParams(); // State for API data const [agents, setAgents] = useState([]); const [agentTypes, setAgentTypes] = useState([]); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); const [totalPages, setTotalPages] = useState(1); const [currentPage, setCurrentPage] = useState(1); const [totalResults, setTotalResults] = useState(0); // State for search and filters const [searchQuery, setSearchQuery] = useState(''); const [activeTypeId, setActiveTypeId] = useState(null); const [listingType, setListingType] = useState<'agents' | 'lenders'>('agents'); const [isFilterModalOpen, setIsFilterModalOpen] = useState(false); const [filters, setFilters] = useState({ clientSpecialization: [], loanType: [], propertyType: [], pricePoint: [], specialInterests: [], popularFilters: [], }); // Initialize from URL params useEffect(() => { const type = searchParams.get('type'); const name = searchParams.get('name'); const location = searchParams.get('location'); if (type) setActiveTypeId(type); if (name) setSearchQuery(name); // Location is handled separately in search params }, [searchParams]); // Fetch agent types on mount useEffect(() => { const fetchAgentTypes = async () => { try { const types = await agentsService.getAgentTypes(); setAgentTypes(types); } catch (error) { console.error('Failed to fetch agent types:', error); } }; fetchAgentTypes(); }, []); // Fetch agents based on filters const fetchAgents = useCallback(async () => { try { setLoading(true); setError(null); const params: SearchAgentsParams = { page: currentPage, limit: 10, sortBy: 'createdAt', sortOrder: 'desc', }; // Add search query if (searchQuery) { params.search = searchQuery; } // Add agent type filter if (activeTypeId) { params.agentTypeId = activeTypeId; } // Add location from URL params const location = searchParams.get('location'); if (location) { // Try to set as city first params.city = location; } const response = await agentsService.searchAgents(params); setAgents(response.data); setTotalPages(response.totalPages); setTotalResults(response.total); } catch (err) { console.error('Failed to fetch agents:', err); setError('Failed to load agents. Please try again.'); } finally { setLoading(false); } }, [currentPage, searchQuery, activeTypeId, searchParams]); // Fetch agents when filters change useEffect(() => { fetchAgents(); }, [fetchAgents]); const toggleFilter = (category: string, option: string) => { setFilters(prev => ({ ...prev, [category]: (prev[category as keyof FilterState] || []).includes(option) ? (prev[category as keyof FilterState] || []).filter((o: string) => o !== option) : [...(prev[category as keyof FilterState] || []), option] })); }; const clearAllFilters = () => { setFilters({ clientSpecialization: [], loanType: [], propertyType: [], pricePoint: [], specialInterests: [], popularFilters: [], }); }; const applyFilters = () => { setIsFilterModalOpen(false); setCurrentPage(1); // Reset to first page when applying filters // Filters are applied via the fetchAgents effect }; const handleSearch = () => { setCurrentPage(1); fetchAgents(); }; const handleTypeChange = (typeId: string | null) => { setActiveTypeId(typeId); setCurrentPage(1); }; return (
{/* Left Sidebar */}
{/* Listing Type */}

Listing Type

{/* Filters */}

Filters

toggleFilter('clientSpecialization', option)} /> toggleFilter('loanType', option)} /> toggleFilter('propertyType', option)} showMore /> toggleFilter('pricePoint', option)} />
{/* Main Content */}
{/* Search Bar */}
setSearchQuery(e.target.value)} onKeyDown={(e) => e.key === 'Enter' && handleSearch()} className="w-full h-[44px] px-4 pr-12 rounded-[10px] border border-[#00293d]/20 bg-white font-serif text-[14px] text-[#00293d] placeholder:text-[#00293d]/50 focus:outline-none focus:border-[#e58625]" />
{/* Agent Type Tabs */}
{agentTypes.map((type) => ( ))}
{/* Results Count */} {!loading && (

{totalResults} {totalResults === 1 ? 'agent' : 'agents'} found

)} {/* Loading State */} {loading && (

Loading agents...

)} {/* Error State */} {error && !loading && (

{error}

)} {/* Empty State */} {!loading && !error && agents.length === 0 && (

No agents found

Try adjusting your search criteria or filters

)} {/* Profile Cards */} {!loading && !error && agents.length > 0 && (
{agents.map((profile) => ( ))}
)} {/* Pagination */} {!loading && !error && totalPages > 1 && (
Page {currentPage} of {totalPages}
)}
{/* Filter Modal */} setIsFilterModalOpen(false)} filters={filters} onToggleFilter={toggleFilter} onClearAll={clearAllFilters} onApply={applyFilters} />
); } export default function ProfilesPage() { return (

Loading...

}>
); }