2026-05-15 17:40:21 +05:30

342 lines
19 KiB
JavaScript

import React, { useState, useMemo } from 'react';
import { Head, Link } from '@inertiajs/react';
import EmployerLayout from '../../../Layouts/EmployerLayout';
import {
Search,
SlidersHorizontal,
CheckCircle2,
MapPin,
Briefcase,
DollarSign,
Calendar,
Bookmark,
RotateCcw,
HeartHandshake,
Globe2,
Sparkles,
Filter
} from 'lucide-react';
export default function Index({ initialWorkers, filtersMetadata }) {
const [searchQuery, setSearchQuery] = useState('');
const [selectedCategory, setSelectedCategory] = useState('All Categories');
const [selectedNationality, setSelectedNationality] = useState('All Nationalities');
const [selectedAvailability, setSelectedAvailability] = useState('All Availabilities');
const [selectedExperience, setSelectedExperience] = useState('All Experience');
const [selectedReligion, setSelectedReligion] = useState('All Religions');
const [maxSalary, setMaxSalary] = useState(3000);
const [shortlistedIds, setShortlistedIds] = useState([101, 103]);
const toggleShortlist = (id) => {
if (shortlistedIds.includes(id)) {
setShortlistedIds(shortlistedIds.filter(i => i !== id));
} else {
setShortlistedIds([...shortlistedIds, id]);
}
};
const resetFilters = () => {
setSearchQuery('');
setSelectedCategory('All Categories');
setSelectedNationality('All Nationalities');
setSelectedAvailability('All Availabilities');
setSelectedExperience('All Experience');
setSelectedReligion('All Religions');
setMaxSalary(3000);
};
const filteredWorkers = useMemo(() => {
return initialWorkers.filter(worker => {
// Search Query
if (searchQuery.trim() !== '') {
const query = searchQuery.toLowerCase();
const matchName = worker.name.toLowerCase().includes(query);
const matchBio = worker.bio.toLowerCase().includes(query);
const matchSkills = worker.skills.some(s => s.toLowerCase().includes(query));
if (!matchName && !matchBio && !matchSkills) return false;
}
// Category
if (selectedCategory !== 'All Categories' && worker.category !== selectedCategory) {
return false;
}
// Nationality
if (selectedNationality !== 'All Nationalities' && worker.nationality !== selectedNationality) {
return false;
}
// Availability
if (selectedAvailability !== 'All Availabilities' && worker.availability !== selectedAvailability) {
return false;
}
// Experience
if (selectedExperience !== 'All Experience' && worker.experience !== selectedExperience) {
return false;
}
// Religion
if (selectedReligion !== 'All Religions' && worker.religion !== selectedReligion) {
return false;
}
// Salary Bracket
if (worker.salary > maxSalary) {
return false;
}
return true;
});
}, [
initialWorkers,
searchQuery,
selectedCategory,
selectedNationality,
selectedAvailability,
selectedExperience,
selectedReligion,
maxSalary
]);
return (
<EmployerLayout title="Find Domestic Workers">
<Head title="Find Workers - Employer Portal" />
<div className="space-y-6 select-none">
{/* Search & Top Filters Bar */}
<div className="bg-white p-6 rounded-2xl border border-slate-200 shadow-sm space-y-4">
<div className="flex flex-col lg:flex-row lg:items-center justify-between gap-4">
{/* Search Input */}
<div className="relative flex-1">
<Search className="absolute left-3.5 top-1/2 -translate-y-1/2 w-5 h-5 text-slate-400" />
<input
type="text"
value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)}
placeholder="Search by name, bio, or skills (e.g., Cooking, Childcare, Arabic)..."
className="w-full pl-11 pr-4 py-3 rounded-xl border border-slate-300 text-sm focus:outline-none focus:ring-2 focus:ring-[#185FA5]/20 focus:border-[#185FA5]"
/>
</div>
{/* Reset Filters CTA */}
<button
type="button"
onClick={resetFilters}
className="flex items-center justify-center space-x-2 px-4 py-3 rounded-xl border border-slate-200 hover:bg-slate-50 text-xs font-semibold text-slate-600 transition-colors flex-shrink-0"
>
<RotateCcw className="w-4 h-4 text-slate-400" />
<span>Reset Filters</span>
</button>
</div>
{/* Detailed Filters Grid */}
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-5 gap-3 pt-4 border-t border-slate-100">
{/* Category Dropdown */}
<div>
<label className="block text-[11px] font-semibold text-slate-500 uppercase tracking-wider mb-1">Category</label>
<select
value={selectedCategory}
onChange={(e) => setSelectedCategory(e.target.value)}
className="w-full px-3 py-2 rounded-xl border border-slate-200 text-xs bg-slate-50/50 focus:bg-white focus:outline-none focus:border-[#185FA5]"
>
{filtersMetadata.categories.map(cat => (
<option key={cat} value={cat}>{cat}</option>
))}
</select>
</div>
{/* Nationality Dropdown */}
<div>
<label className="block text-[11px] font-semibold text-slate-500 uppercase tracking-wider mb-1">Nationality</label>
<select
value={selectedNationality}
onChange={(e) => setSelectedNationality(e.target.value)}
className="w-full px-3 py-2 rounded-xl border border-slate-200 text-xs bg-slate-50/50 focus:bg-white focus:outline-none focus:border-[#185FA5]"
>
{filtersMetadata.nationalities.map(nat => (
<option key={nat} value={nat}>{nat}</option>
))}
</select>
</div>
{/* Availability Dropdown */}
<div>
<label className="block text-[11px] font-semibold text-slate-500 uppercase tracking-wider mb-1">Availability</label>
<select
value={selectedAvailability}
onChange={(e) => setSelectedAvailability(e.target.value)}
className="w-full px-3 py-2 rounded-xl border border-slate-200 text-xs bg-slate-50/50 focus:bg-white focus:outline-none focus:border-[#185FA5]"
>
{filtersMetadata.availabilities.map(av => (
<option key={av} value={av}>{av}</option>
))}
</select>
</div>
{/* Experience Dropdown */}
<div>
<label className="block text-[11px] font-semibold text-slate-500 uppercase tracking-wider mb-1">Experience</label>
<select
value={selectedExperience}
onChange={(e) => setSelectedExperience(e.target.value)}
className="w-full px-3 py-2 rounded-xl border border-slate-200 text-xs bg-slate-50/50 focus:bg-white focus:outline-none focus:border-[#185FA5]"
>
{filtersMetadata.experienceLevels.map(exp => (
<option key={exp} value={exp}>{exp}</option>
))}
</select>
</div>
{/* Max Salary Slider */}
<div>
<div className="flex items-center justify-between mb-1 text-[11px]">
<span className="font-semibold text-slate-500 uppercase tracking-wider">Max Salary</span>
<span className="font-bold text-[#185FA5]">{maxSalary} AED</span>
</div>
<input
type="range"
min="1200"
max="3000"
step="100"
value={maxSalary}
onChange={(e) => setMaxSalary(Number(e.target.value))}
className="w-full h-2 bg-slate-200 rounded-lg appearance-none cursor-pointer accent-[#185FA5]"
/>
</div>
</div>
</div>
{/* Results Header */}
<div className="flex items-center justify-between px-1">
<div className="text-xs font-semibold text-slate-500">
Showing <span className="text-slate-900 font-bold">{filteredWorkers.length}</span> domestic workers matching your criteria
</div>
<div className="flex items-center space-x-2 text-xs font-medium text-slate-600">
<Filter className="w-3.5 h-3.5 text-[#185FA5]" />
<span>OCR Vetted & Legal</span>
</div>
</div>
{/* Workers Grid */}
{filteredWorkers.length > 0 ? (
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
{filteredWorkers.map((worker) => {
const isShortlisted = shortlistedIds.includes(worker.id);
return (
<div key={worker.id} className="bg-white rounded-2xl border border-slate-200 shadow-sm hover:shadow-md transition-all flex flex-col overflow-hidden group">
{/* Card Header Banner */}
<div className="bg-slate-50 p-6 border-b border-slate-100 flex items-start justify-between relative">
<div className="flex items-center space-x-3">
<div className="w-14 h-14 rounded-full bg-blue-100 text-[#185FA5] flex items-center justify-center font-bold text-xl border border-blue-200 shadow-inner flex-shrink-0">
{worker.name.charAt(0)}
</div>
<div className="truncate">
<div className="font-bold text-base text-slate-900 group-hover:text-[#185FA5] transition-colors truncate flex items-center space-x-1.5">
<span>{worker.name}</span>
{worker.verified && <CheckCircle2 className="w-4 h-4 text-emerald-600 flex-shrink-0" />}
</div>
<div className="flex items-center space-x-1.5 text-xs text-slate-500 mt-0.5">
<Globe2 className="w-3.5 h-3.5 text-slate-400" />
<span>{worker.nationality}</span>
</div>
</div>
</div>
{/* Shortlist Toggle Button */}
<button
type="button"
onClick={() => toggleShortlist(worker.id)}
className={`p-2 rounded-xl transition-all ${
isShortlisted
? 'bg-blue-50 text-[#185FA5] hover:bg-blue-100'
: 'bg-white text-slate-400 hover:text-[#185FA5] border border-slate-200'
}`}
>
<Bookmark className={`w-5 h-5 ${isShortlisted ? 'fill-[#185FA5]' : ''}`} />
</button>
</div>
{/* Card Body */}
<div className="p-6 flex-1 flex flex-col justify-between space-y-4">
<div className="space-y-4">
{/* Top Skill Pill & Salary */}
<div className="flex items-center justify-between text-xs">
<span className="px-2.5 py-1 bg-blue-50 text-[#185FA5] font-bold rounded-lg border border-blue-100">
{worker.category}
</span>
<div className="flex items-center space-x-1 font-bold text-slate-800">
<DollarSign className="w-4 h-4 text-emerald-600" />
<span>{worker.salary} AED / mo</span>
</div>
</div>
{/* Bio Snippet */}
<p className="text-xs text-slate-600 line-clamp-2 leading-relaxed">
"{worker.bio}"
</p>
{/* Details Grid */}
<div className="grid grid-cols-2 gap-2 p-3 bg-slate-50 rounded-xl text-[11px] text-slate-600 font-medium">
<div className="flex items-center space-x-1.5">
<Briefcase className="w-3.5 h-3.5 text-slate-400" />
<span>Exp: {worker.experience}</span>
</div>
<div className="flex items-center space-x-1.5 truncate">
<Calendar className="w-3.5 h-3.5 text-slate-400" />
<span className="truncate">Avail: {worker.availability}</span>
</div>
<div className="flex items-center space-x-1.5">
<HeartHandshake className="w-3.5 h-3.5 text-slate-400" />
<span>{worker.religion}</span>
</div>
<div className="flex items-center space-x-1.5 truncate">
<Sparkles className="w-3.5 h-3.5 text-slate-400" />
<span className="truncate">Age: {worker.age} yrs</span>
</div>
</div>
{/* Skill Tags */}
<div className="flex flex-wrap gap-1.5">
{worker.skills.map(s => (
<span key={s} className="text-[10px] bg-slate-100 text-slate-600 px-2 py-0.5 rounded-md font-semibold">
{s}
</span>
))}
</div>
</div>
{/* View Profile Button */}
<Link
href={`/employer/workers/${worker.id}`}
className="w-full bg-[#185FA5] hover:bg-[#144f8a] text-white rounded-xl h-10 font-bold text-xs flex items-center justify-center transition-colors shadow-sm"
>
View Full Profile
</Link>
</div>
</div>
);
})}
</div>
) : (
<div className="text-center py-16 bg-white rounded-2xl border border-slate-200 shadow-sm space-y-3">
<SlidersHorizontal className="w-12 h-12 text-slate-300 mx-auto" />
<div className="text-base font-bold text-slate-800">No workers match your filter criteria</div>
<p className="text-xs text-slate-500 max-w-sm mx-auto">
Try adjusting your salary slider, broadening your category selection, or resetting all filters.
</p>
<button
type="button"
onClick={resetFilters}
className="mt-2 bg-[#185FA5] text-white px-5 py-2.5 rounded-xl text-xs font-bold shadow-sm hover:bg-[#144f8a] transition-colors"
>
Reset All Filters
</button>
</div>
)}
</div>
</EmployerLayout>
);
}