767 lines
52 KiB
JavaScript
767 lines
52 KiB
JavaScript
import React, { useState } from 'react';
|
|
import { Head, Link, router } from '@inertiajs/react';
|
|
import EmployerLayout from '../../../Layouts/EmployerLayout';
|
|
import { useTranslation } from '../../../lib/LanguageContext';
|
|
import {
|
|
CheckCircle2,
|
|
Globe2,
|
|
Briefcase,
|
|
DollarSign,
|
|
Calendar,
|
|
HeartHandshake,
|
|
Languages,
|
|
MessageSquare,
|
|
Bookmark,
|
|
ArrowLeft,
|
|
Sparkles,
|
|
FileText,
|
|
ShieldCheck,
|
|
Search,
|
|
Star,
|
|
Share2,
|
|
Flag,
|
|
X,
|
|
UserCheck,
|
|
AlertTriangle,
|
|
User
|
|
} from 'lucide-react';
|
|
import { toast } from 'sonner';
|
|
|
|
const getLanguageFlag = (lang) => {
|
|
const flags = {
|
|
'English': '🇬🇧',
|
|
'Arabic': '🇦🇪',
|
|
'Tagalog': '🇵🇭',
|
|
'Hindi': '🇮🇳',
|
|
'Swahili': '🇰🇪',
|
|
'French': '🇫🇷',
|
|
'Indonesian': '🇮🇩'
|
|
};
|
|
return flags[lang] || '🌐';
|
|
};
|
|
|
|
export default function Show({ worker }) {
|
|
const { t } = useTranslation();
|
|
const [showReportModal, setShowReportModal] = useState(false);
|
|
const [reportReason, setReportReason] = useState('');
|
|
const [reportDetails, setReportDetails] = useState('');
|
|
const [isShortlisted, setIsShortlisted] = useState(false);
|
|
|
|
// Hiring flow states
|
|
const [availabilityStatus, setAvailabilityStatus] = useState(worker.availability_status);
|
|
const [showHiredModal, setShowHiredModal] = useState(false);
|
|
|
|
// Reviews state
|
|
const [showReviewModal, setShowReviewModal] = useState(false);
|
|
const [newRating, setNewRating] = useState(5);
|
|
const [newComment, setNewComment] = useState('');
|
|
const [workerReviews, setWorkerReviews] = useState(worker.reviews || []);
|
|
|
|
const handleShare = () => {
|
|
navigator.clipboard.writeText(window.location.href);
|
|
toast.success(t('profile_link_copied', 'Profile link copied to clipboard!'), {
|
|
description: t('profile_link_copied_desc', 'You can now share this URL with your family or sponsor contacts.')
|
|
});
|
|
};
|
|
|
|
const handleReportSubmit = (e) => {
|
|
e.preventDefault();
|
|
if (!reportReason) {
|
|
toast.error(t('select_report_reason', 'Please select a reason for reporting.'));
|
|
return;
|
|
}
|
|
|
|
toast.success(t('report_submitted', 'Worker report submitted successfully'), {
|
|
description: t('report_submitted_desc', "Our admin compliance team will investigate this worker's credentials within 24 hours.")
|
|
});
|
|
setShowReportModal(false);
|
|
setReportReason('');
|
|
setReportDetails('');
|
|
};
|
|
|
|
const handleReviewSubmit = (e) => {
|
|
e.preventDefault();
|
|
if (!newComment.trim()) {
|
|
toast.error(t('add_comment', 'Please add a comment.'));
|
|
return;
|
|
}
|
|
|
|
const newReview = {
|
|
id: Date.now(),
|
|
employer_name: t('you_verified_sponsor', 'You (Verified Sponsor)'),
|
|
rating: newRating,
|
|
date: t('today', 'Today'),
|
|
comment: newComment,
|
|
};
|
|
|
|
setWorkerReviews([newReview, ...workerReviews]);
|
|
toast.success(t('review_posted', 'Review posted successfully!'), {
|
|
description: t('review_posted_desc', 'Your trust feedback is live and helps other sponsors hire securely.')
|
|
});
|
|
setShowReviewModal(false);
|
|
setNewComment('');
|
|
};
|
|
|
|
const handleToggleShortlist = () => {
|
|
setIsShortlisted(!isShortlisted);
|
|
router.post('/employer/shortlist/toggle', { worker_id: worker.id }, {
|
|
preserveScroll: true,
|
|
onSuccess: () => {
|
|
toast.success(isShortlisted ? t('removed_from_shortlist', 'Removed from Shortlist') : t('added_to_shortlist', 'Added to Shortlist'));
|
|
}
|
|
});
|
|
};
|
|
|
|
const handleMarkHired = () => {
|
|
setAvailabilityStatus('Hired');
|
|
setShowHiredModal(true);
|
|
toast.success(t('marked_hired', 'Worker successfully marked as Hired!'), {
|
|
description: t('marked_hired_desc', 'Sponsorship direct match finalized. Please leave an anonymous trust review!')
|
|
});
|
|
};
|
|
|
|
return (
|
|
<EmployerLayout title={t('candidate_profile_detail', 'Candidate Profile Detail')}>
|
|
<Head title={`${worker.name} - ${worker.category} Profile`} />
|
|
|
|
<div className="space-y-6 select-none w-full pb-16">
|
|
|
|
{/* Back Link */}
|
|
<div className="flex items-center justify-between">
|
|
<Link
|
|
href="/employer/workers"
|
|
className="inline-flex items-center space-x-2 text-xs font-black text-slate-500 hover:text-[#185FA5] transition-colors"
|
|
>
|
|
<ArrowLeft className="w-4 h-4" />
|
|
<span>{t('back_to_find_workers', 'BACK TO FIND WORKERS')}</span>
|
|
</Link>
|
|
|
|
{/* Quick Profile Actions */}
|
|
<div className="flex items-center space-x-2">
|
|
<button
|
|
onClick={handleShare}
|
|
className="p-2.5 bg-white border border-slate-200 hover:bg-slate-50 rounded-xl text-slate-500 hover:text-[#185FA5] transition-colors flex items-center space-x-1 text-xs font-bold shadow-xs"
|
|
title="Share Profile link"
|
|
>
|
|
<Share2 className="w-4 h-4" />
|
|
<span className="hidden sm:inline">{t('share_profile', 'Share Profile')}</span>
|
|
</button>
|
|
|
|
<button
|
|
onClick={() => setShowReportModal(true)}
|
|
className="p-2.5 bg-white border border-slate-200 hover:bg-rose-50 rounded-xl text-slate-400 hover:text-rose-600 transition-colors flex items-center space-x-1 text-xs font-bold shadow-xs"
|
|
title="Report Abuse / Terms violations"
|
|
>
|
|
<Flag className="w-4 h-4" />
|
|
<span className="hidden sm:inline">{t('report_worker', 'Report Worker')}</span>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="bg-white rounded-3xl border border-slate-200 shadow-sm overflow-hidden">
|
|
{/* Header Card with Clean Premium White BG */}
|
|
<div className="bg-white p-8 text-slate-900 border-b border-slate-200 flex flex-col sm:flex-row items-start sm:items-center justify-between gap-6 relative overflow-hidden">
|
|
<div className="absolute -right-10 -bottom-10 w-48 h-48 bg-slate-50 rounded-full blur-2xl pointer-events-none" />
|
|
|
|
<div className="flex items-center space-x-5 z-10">
|
|
<div className="w-20 h-20 rounded-2xl bg-slate-50 text-[#185FA5] flex items-center justify-center font-black text-3xl shadow-sm border border-slate-200 flex-shrink-0 overflow-hidden relative">
|
|
{worker.photo ? (
|
|
<img src={worker.photo} alt={worker.name} className="w-full h-full object-cover" />
|
|
) : (
|
|
<User className="w-10 h-10 text-slate-400" />
|
|
)}
|
|
</div>
|
|
<div className="space-y-1.5">
|
|
<div className="flex items-center space-x-2">
|
|
<h1 className="text-2xl sm:text-3xl font-extrabold tracking-tight text-slate-900">{worker.name}</h1>
|
|
{worker.verified && (
|
|
<span className="inline-flex items-center px-2 py-0.5 rounded-full text-[9px] font-black uppercase tracking-wider bg-emerald-500 text-white shadow-xs gap-1 animate-pulse" title="OCR Verified via UAE PDPL Compliant Pipeline">
|
|
<CheckCircle2 className="w-3.5 h-3.5" />
|
|
<span>{t('verified')}</span>
|
|
</span>
|
|
)}
|
|
|
|
{/* Availability Status Badge */}
|
|
<span className={`px-2.5 py-0.5 text-[8px] font-black rounded-lg uppercase tracking-wider border ${
|
|
availabilityStatus === 'Active' ? 'bg-emerald-50 text-emerald-700 border-emerald-200' :
|
|
availabilityStatus === 'Hired' ? 'bg-blue-50 text-blue-700 border-blue-200' :
|
|
'bg-slate-100 text-slate-600 border-slate-200'
|
|
}`}>
|
|
{availabilityStatus}
|
|
</span>
|
|
</div>
|
|
|
|
{/* Emirates ID verification status bar & Visa Status */}
|
|
<div className="flex flex-wrap gap-2">
|
|
<div className="flex items-center space-x-1.5 bg-emerald-50 px-2.5 py-1 rounded-lg text-emerald-700 border border-emerald-100 text-[9px] font-black uppercase tracking-wider w-fit">
|
|
<ShieldCheck className="w-3.5 h-3.5 text-emerald-600" />
|
|
<span>{worker.emirates_id_status}</span>
|
|
</div>
|
|
{worker.visa_status && (worker.visa_status.toLowerCase().includes('tourist') || worker.visa_status.toLowerCase().includes('visit')) ? (
|
|
<div className="flex items-center space-x-1.5 bg-amber-50 px-2.5 py-1 rounded-lg text-amber-800 border border-amber-200 text-[9px] font-black uppercase tracking-wider w-fit shadow-xs">
|
|
<AlertTriangle className="w-3.5 h-3.5 text-amber-600 animate-bounce" />
|
|
<span>{worker.visa_status} ({t('warning', 'Warning')}: {t('visit_visa', 'Visit Visa')})</span>
|
|
</div>
|
|
) : worker.visa_status && worker.visa_status.toLowerCase().includes('cancelled') ? (
|
|
<div className="flex items-center space-x-1.5 bg-rose-50 px-2.5 py-1 rounded-lg text-rose-800 border border-rose-200 text-[9px] font-black uppercase tracking-wider w-fit shadow-xs animate-pulse">
|
|
<AlertTriangle className="w-3.5 h-3.5 text-rose-600" />
|
|
<span>{worker.visa_status} ({t('warning', 'Warning')}: {t('cancelled', 'Cancelled')})</span>
|
|
</div>
|
|
) : (
|
|
<div className="flex items-center space-x-1.5 bg-blue-50 px-2.5 py-1 rounded-lg text-blue-700 border border-blue-100 text-[9px] font-black uppercase tracking-wider w-fit">
|
|
<span>{worker.visa_status}</span>
|
|
</div>
|
|
)}
|
|
</div>
|
|
|
|
<div className="flex flex-wrap items-center gap-2.5 text-slate-500 text-xs font-bold">
|
|
<span className="flex items-center space-x-1">
|
|
<Globe2 className="w-3.5 h-3.5 text-slate-400" />
|
|
<span>{worker.nationality}</span>
|
|
</span>
|
|
<span>•</span>
|
|
<span>{worker.age} {t('years_old', 'Years Old')}</span>
|
|
<span>•</span>
|
|
<span className="bg-blue-50 text-[#185FA5] border border-blue-100 px-2 py-0.5 rounded text-[10px] uppercase font-black tracking-widest">{worker.category}</span>
|
|
</div>
|
|
<div className="flex items-center space-x-1 text-amber-500 font-bold text-xs">
|
|
<Star className="w-3.5 h-3.5 fill-amber-500 text-amber-500" />
|
|
<span className="text-slate-700">{worker.rating} / 5.0 ({workerReviews.length} {t('reviews', 'reviews')})</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Sponsor Actions Block */}
|
|
<div className="flex flex-wrap items-center gap-3 z-10 w-full sm:w-auto justify-end">
|
|
<button
|
|
type="button"
|
|
onClick={handleToggleShortlist}
|
|
className={`p-3 rounded-xl transition-all border ${
|
|
isShortlisted
|
|
? 'bg-blue-50 border-blue-200 text-[#185FA5]'
|
|
: 'bg-white hover:bg-slate-50 border-slate-200 text-slate-400 hover:text-[#185FA5]'
|
|
}`}
|
|
title="Shortlist Worker"
|
|
>
|
|
<Bookmark className={`w-5 h-5 ${isShortlisted ? 'fill-[#185FA5]' : ''}`} />
|
|
</button>
|
|
|
|
{/* Stage 3 Connect: Start In-App Chat */}
|
|
<Link
|
|
href={`/employer/messages/start/${worker.id}`}
|
|
className="bg-white border border-slate-250 hover:bg-slate-50 px-6 py-3 rounded-xl font-bold text-sm shadow-xs transition-colors flex items-center justify-center space-x-2 text-slate-700 flex-1 sm:flex-initial"
|
|
>
|
|
<MessageSquare className="w-4 h-4 text-slate-500" />
|
|
<span>{t('start_direct_chat', 'Start Direct Chat')}</span>
|
|
</Link>
|
|
|
|
{/* Stage 4 Hire: Mark Hired (Finalize Hiring Direct Flow) */}
|
|
<button
|
|
type="button"
|
|
onClick={handleMarkHired}
|
|
className="bg-emerald-600 hover:bg-emerald-700 text-white border border-emerald-700 px-8 py-3 rounded-xl font-black text-sm shadow-md transition-all flex items-center justify-center space-x-2 flex-1 sm:flex-initial scale-105 active:scale-100"
|
|
>
|
|
<CheckCircle2 className="w-4 h-4 text-white" />
|
|
<span>{t('mark_hired_action', 'Mark Hired')}</span>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Main Details Grid */}
|
|
<div className="p-8 grid grid-cols-1 lg:grid-cols-3 gap-8">
|
|
{/* Left Column: Quick Stats */}
|
|
<div className="space-y-6">
|
|
<div className="bg-slate-50 p-6 rounded-2xl border border-slate-200 space-y-4">
|
|
<h3 className="font-black text-xs text-slate-500 uppercase tracking-widest">{t('sponsorship_details', 'Sponsorship Details')}</h3>
|
|
|
|
<div className="flex items-center justify-between pb-3 border-b border-slate-200">
|
|
<div className="flex items-center space-x-2 text-xs text-slate-600 font-bold">
|
|
<DollarSign className="w-4 h-4 text-emerald-600" />
|
|
<span>{t('salary_expectations', 'Salary Expectations')}</span>
|
|
</div>
|
|
<span className="font-extrabold text-slate-900 text-sm">{worker.salary} {t('aed', 'AED')} / {t('mo', 'mo')}</span>
|
|
</div>
|
|
|
|
<div className="flex items-center justify-between pb-3 border-b border-slate-200">
|
|
<div className="flex items-center space-x-2 text-xs text-slate-600 font-bold">
|
|
<Calendar className="w-4 h-4 text-[#185FA5]" />
|
|
<span>{t('availability_status', 'Availability Status')}</span>
|
|
</div>
|
|
<span className="font-black text-[#185FA5] bg-blue-50 px-2 py-0.5 rounded text-xs border border-blue-100">
|
|
{availabilityStatus}
|
|
</span>
|
|
</div>
|
|
|
|
<div className="flex items-center justify-between pb-3 border-b border-slate-200">
|
|
<div className="flex items-center space-x-2 text-xs text-slate-600 font-bold">
|
|
<Briefcase className="w-4 h-4 text-amber-600" />
|
|
<span>{t('work_experience', 'Work Experience')}</span>
|
|
</div>
|
|
<span className="font-extrabold text-slate-900 text-xs">{worker.experience}</span>
|
|
</div>
|
|
|
|
<div className="flex items-center justify-between pb-3 border-b border-slate-200">
|
|
<div className="flex items-center space-x-2 text-xs text-slate-600 font-bold">
|
|
<Sparkles className="w-4 h-4 text-purple-600" />
|
|
<span>{t('preferred_job_type', 'Preferred Job Type')}</span>
|
|
</div>
|
|
<span className="font-black text-slate-900 text-xs uppercase">{worker.preferred_job_type}</span>
|
|
</div>
|
|
|
|
<div className="flex items-center justify-between pb-3 border-b border-slate-200">
|
|
<div className="flex items-center space-x-2 text-xs text-slate-655 font-bold">
|
|
<ShieldCheck className="w-4 h-4 text-emerald-600" />
|
|
<span>{t('emirates_id_vetting', 'Emirates ID Vetting')}</span>
|
|
</div>
|
|
<span className="font-bold text-emerald-700 text-xs uppercase">{worker.emirates_id_status}</span>
|
|
</div>
|
|
|
|
<div className="flex items-center justify-between pb-3 border-b border-slate-200">
|
|
<div className="flex items-center space-x-2 text-xs text-slate-600 font-bold">
|
|
<FileText className="w-4 h-4 text-blue-600" />
|
|
<span>{t('visa_status', 'Visa Status')}</span>
|
|
</div>
|
|
<span className="font-bold text-blue-700 text-xs uppercase">{worker.visa_status}</span>
|
|
</div>
|
|
|
|
<div className="flex items-center justify-between">
|
|
<div className="flex items-center space-x-2 text-xs text-slate-600 font-bold">
|
|
<CheckCircle2 className="w-4 h-4 text-emerald-600" />
|
|
<span>{t('medical_health_test', 'Medical Health Test')}</span>
|
|
</div>
|
|
<span className="font-black text-emerald-700 bg-emerald-50 px-2.5 py-0.5 rounded text-[10px] uppercase border border-emerald-200">
|
|
{t('passed_certified', 'PASSED CERTIFIED')}
|
|
</span>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Languages Spoken with visual flags */}
|
|
<div className="bg-slate-50 p-6 rounded-2xl border border-slate-200 space-y-3">
|
|
<div className="flex items-center space-x-2 font-bold text-sm text-slate-800">
|
|
<Languages className="w-4 h-4 text-[#185FA5]" />
|
|
<span>{t('languages_spoken', 'Languages Spoken')}</span>
|
|
</div>
|
|
<div className="flex flex-wrap gap-2">
|
|
{worker.languages?.map(lang => (
|
|
<span key={lang} className="bg-white border border-slate-200 text-slate-800 px-3 py-1 rounded-xl text-xs font-extrabold shadow-xs uppercase flex items-center space-x-1.5">
|
|
<span>{getLanguageFlag(lang)}</span>
|
|
<span>{lang}</span>
|
|
</span>
|
|
))}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Right Column: Bio & Skills */}
|
|
<div className="lg:col-span-2 space-y-8">
|
|
{/* Professional Summary */}
|
|
<div className="space-y-3">
|
|
<h3 className="font-extrabold text-base text-slate-900">{t('professional_summary', 'Professional Summary')}</h3>
|
|
<p className="text-sm text-slate-600 leading-relaxed bg-slate-50 p-6 rounded-2xl border border-slate-200 italic">
|
|
"{worker.bio}"
|
|
</p>
|
|
</div>
|
|
|
|
{/* Verified Skills & Competencies */}
|
|
<div className="space-y-4">
|
|
<h3 className="font-extrabold text-base text-slate-900">{t('verified_skills_competencies', 'Verified Skills & Competencies')}</h3>
|
|
<div className="grid grid-cols-1 sm:grid-cols-2 gap-3">
|
|
{worker.skills?.map(skill => (
|
|
<div key={skill} className="flex items-center space-x-3 p-3.5 bg-white border border-slate-200 rounded-xl shadow-xs">
|
|
<CheckCircle2 className="w-5 h-5 text-emerald-600 flex-shrink-0" />
|
|
<span className="font-bold text-xs text-slate-800 uppercase tracking-wide">{skill}</span>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</div>
|
|
|
|
{/* Verified Documents Section */}
|
|
<div className="space-y-4">
|
|
<h3 className="font-extrabold text-base text-slate-900 flex items-center space-x-2">
|
|
<ShieldCheck className="w-5 h-5 text-emerald-600" />
|
|
<span>{t('verified_legal_docs', 'Verified Legal Documents (UAE MOHRE Vetted)')}</span>
|
|
</h3>
|
|
|
|
<div className="grid grid-cols-1 lg:grid-cols-3 gap-6">
|
|
{/* Document Card: Passport */}
|
|
<div className="bg-white border border-slate-200 rounded-2xl overflow-hidden shadow-xs hover:shadow-sm">
|
|
<div className="bg-slate-50 px-4 py-3 border-b border-slate-100 flex items-center justify-between">
|
|
<span className="text-[10px] font-black text-slate-500 uppercase tracking-widest">{t('passport_verified', 'Passport (Verified)')}</span>
|
|
<FileText className="w-4 h-4 text-slate-400" />
|
|
</div>
|
|
<div className="p-4 flex space-x-4">
|
|
<div className="w-20 h-28 bg-slate-100 rounded-lg flex-shrink-0 border border-slate-200 flex flex-col items-center justify-center p-2 relative group cursor-zoom-in">
|
|
<Search className="w-5 h-5 text-slate-300" />
|
|
<span className="absolute bottom-1 text-[7px] font-bold text-slate-400 uppercase">{t('click_zoom', 'Click zoom')}</span>
|
|
</div>
|
|
|
|
<div className="flex-1 space-y-2">
|
|
<div>
|
|
<div className="text-[8px] font-black text-slate-400 uppercase tracking-tighter">{t('document_id', 'Document ID')}</div>
|
|
<div className="text-xs font-bold text-slate-800">L82739102-UAE</div>
|
|
</div>
|
|
<div className="grid grid-cols-2 gap-1">
|
|
<div>
|
|
<div className="text-[8px] font-black text-slate-400 uppercase tracking-tighter">{t('issue_date', 'Issue')}</div>
|
|
<div className="text-[10px] font-bold text-slate-800">12 Jan 2021</div>
|
|
</div>
|
|
<div>
|
|
<div className="text-[8px] font-black text-slate-400 uppercase tracking-tighter">{t('expiry_date', 'Expiry')}</div>
|
|
<div className="text-[10px] font-bold text-emerald-600">11 Jan 2031</div>
|
|
</div>
|
|
</div>
|
|
<div>
|
|
<div className="text-[8px] font-black text-slate-400 uppercase tracking-tighter">{t('ocr_match', 'OCR Match')}</div>
|
|
<div className="flex items-center space-x-2 mt-0.5">
|
|
<div className="flex-1 h-1 bg-slate-100 rounded-full overflow-hidden">
|
|
<div className="h-full bg-emerald-500 w-[95%]" />
|
|
</div>
|
|
<span className="text-[9px] font-bold text-emerald-600">95%</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Document Card: Emirates ID */}
|
|
<div className="bg-white border border-slate-200 rounded-2xl overflow-hidden shadow-xs hover:shadow-sm">
|
|
<div className="bg-slate-50 px-4 py-3 border-b border-slate-100 flex items-center justify-between">
|
|
<span className="text-[10px] font-black text-slate-500 uppercase tracking-widest">{t('emirates_id_pdpl', 'Emirates ID (PDPL Compliant)')}</span>
|
|
<ShieldCheck className="w-4 h-4 text-emerald-500" />
|
|
</div>
|
|
<div className="p-4 flex space-x-4">
|
|
<div className="w-20 h-28 bg-slate-950 rounded-lg flex-shrink-0 border border-slate-800 flex flex-col items-center justify-center p-1.5 text-center relative shadow-inner">
|
|
<ShieldCheck className="w-6 h-6 text-emerald-500 mb-1 animate-pulse" />
|
|
<span className="text-[6px] font-black text-emerald-500 uppercase tracking-tighter block">{t('scan_purged', 'Scan Purged')}</span>
|
|
<span className="text-[5px] font-medium text-slate-400 mt-1 leading-tight block">{t('uae_pdpl_compliant', 'UAE PDPL compliant')}</span>
|
|
</div>
|
|
|
|
<div className="flex-1 space-y-2">
|
|
<div>
|
|
<div className="text-[8px] font-black text-slate-400 uppercase tracking-tighter">{t('verification_type', 'Verification Type')}</div>
|
|
<div className="text-xs font-black text-slate-800">{t('emirates_id_ocr', 'Emirates ID OCR')}</div>
|
|
</div>
|
|
<div>
|
|
<div className="text-[8px] font-black text-slate-400 uppercase tracking-tighter">{t('status', 'Status')}</div>
|
|
<div className="flex items-center space-x-1 mt-0.5">
|
|
<CheckCircle2 className="w-3.5 h-3.5 text-emerald-600 flex-shrink-0" />
|
|
<span className="text-[9px] font-black text-emerald-700 uppercase tracking-wider">{worker.emirates_id_status}</span>
|
|
</div>
|
|
</div>
|
|
<div>
|
|
<div className="text-[8px] font-black text-slate-400 uppercase tracking-tighter">{t('physical_scan_storage', 'Physical Scan Storage')}</div>
|
|
<span className="text-[7px] font-mono text-emerald-600 bg-emerald-50 px-1 py-0.5 rounded font-black uppercase tracking-wider block w-fit border border-emerald-100">{t('permanently_purged', 'Permanently Purged')}</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Document Card: Visa */}
|
|
<div className="bg-white border border-slate-200 rounded-2xl overflow-hidden shadow-xs hover:shadow-sm">
|
|
<div className="bg-slate-50 px-4 py-3 border-b border-slate-100 flex items-center justify-between">
|
|
<span className="text-[10px] font-black text-slate-500 uppercase tracking-widest">{t('entry_visa_verified', 'Entry Visa (Verified)')}</span>
|
|
{worker.visa_status && (worker.visa_status.toLowerCase().includes('tourist') || worker.visa_status.toLowerCase().includes('visit') || worker.visa_status.toLowerCase().includes('cancelled')) ? (
|
|
<AlertTriangle className="w-4 h-4 text-amber-500 animate-pulse" />
|
|
) : (
|
|
<ShieldCheck className="w-4 h-4 text-emerald-500" />
|
|
)}
|
|
</div>
|
|
<div className="p-4 flex space-x-4">
|
|
<div className="w-20 h-28 bg-slate-100 rounded-lg flex-shrink-0 border border-slate-200 flex flex-col items-center justify-center p-2 relative group cursor-zoom-in">
|
|
<Search className="w-5 h-5 text-slate-300" />
|
|
<span className="absolute bottom-1 text-[7px] font-bold text-slate-400 uppercase">{t('click_zoom', 'Click zoom')}</span>
|
|
</div>
|
|
|
|
<div className="flex-1 space-y-2">
|
|
<div>
|
|
<div className="text-[8px] font-black text-slate-400 uppercase tracking-tighter">{t('visa_category', 'Visa Category')}</div>
|
|
<div className="text-xs font-bold text-slate-800">{worker.visa_status}</div>
|
|
</div>
|
|
<div>
|
|
<div className="text-[8px] font-black text-slate-400 uppercase tracking-tighter">{t('vetting_status', 'Vetting status')}</div>
|
|
<div className="flex items-center space-x-1.5 mt-0.5">
|
|
{worker.visa_status && (worker.visa_status.toLowerCase().includes('tourist') || worker.visa_status.toLowerCase().includes('visit')) ? (
|
|
<span className="inline-flex items-center bg-amber-50 border border-amber-200 text-[8px] font-black uppercase text-amber-700 px-1.5 py-0.5 rounded tracking-wide">
|
|
{t('transfer_required', 'Transfer Required')}
|
|
</span>
|
|
) : worker.visa_status && worker.visa_status.toLowerCase().includes('cancelled') ? (
|
|
<span className="inline-flex items-center bg-rose-50 border border-rose-200 text-[8px] font-black uppercase text-rose-700 px-1.5 py-0.5 rounded tracking-wide animate-pulse">
|
|
{t('needs_regularization', 'Needs Regularization')}
|
|
</span>
|
|
) : (
|
|
<>
|
|
<CheckCircle2 className="w-3.5 h-3.5 text-emerald-600" />
|
|
<span className="text-[9px] font-bold text-slate-700">{t('clear_records', 'Clear Records')}</span>
|
|
</>
|
|
)}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Star Ratings & Trust Review logs */}
|
|
<div className="bg-white p-8 rounded-3xl border border-slate-200 shadow-sm space-y-6">
|
|
<div className="flex items-center justify-between border-b border-slate-150 pb-4">
|
|
<div className="space-y-1">
|
|
<h3 className="font-extrabold text-base text-slate-900">{t('sponsor_reviews_star_ratings', 'Sponsor Reviews & Star Ratings')}</h3>
|
|
<p className="text-xs text-slate-500 font-medium">{t('reviews_posted_by_sponsors_desc', 'Ratings can only be posted by verified sponsors who completed verified direct hiring.')}</p>
|
|
</div>
|
|
<button
|
|
onClick={() => setShowReviewModal(true)}
|
|
className="bg-[#185FA5] hover:bg-[#144f8a] text-white px-5 py-2.5 rounded-xl text-xs font-bold shadow-xs transition-colors"
|
|
>
|
|
{t('post_trust_review', 'Post a Trust Review')}
|
|
</button>
|
|
</div>
|
|
|
|
{/* Reviews List */}
|
|
<div className="space-y-4">
|
|
{workerReviews.map((review) => (
|
|
<div key={review.id} className="p-6 bg-slate-50 rounded-2xl border border-slate-150 space-y-3">
|
|
<div className="flex items-center justify-between">
|
|
<div>
|
|
<span className="font-extrabold text-slate-900 text-xs block">{review.employer_name}</span>
|
|
<span className="text-[10px] text-slate-400 font-bold block mt-0.5">{review.date}</span>
|
|
</div>
|
|
<div className="flex items-center space-x-1">
|
|
{[...Array(5)].map((_, i) => (
|
|
<Star
|
|
key={i}
|
|
className={`w-3.5 h-3.5 ${i < review.rating ? 'text-amber-550 fill-amber-400 text-amber-500' : 'text-slate-200'}`}
|
|
/>
|
|
))}
|
|
</div>
|
|
</div>
|
|
<p className="text-xs text-slate-650 leading-relaxed italic">
|
|
"{review.comment}"
|
|
</p>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</div>
|
|
|
|
{/* Similar Recommendations Slider */}
|
|
<div className="space-y-4">
|
|
<h3 className="font-extrabold text-base text-slate-900">{t('similar_recommended_workers', 'Similar Recommended Workers')}</h3>
|
|
<div className="grid grid-cols-1 md:grid-cols-3 gap-6">
|
|
{worker.similar_workers?.map((sim) => (
|
|
<div key={sim.id} className="bg-white p-5 rounded-2xl border border-slate-200 shadow-xs space-y-4">
|
|
<div className="flex items-center justify-between">
|
|
<div>
|
|
<h4 className="font-extrabold text-sm text-slate-900">{sim.name}</h4>
|
|
<p className="text-[10px] text-slate-500 font-bold">{sim.nationality} • {sim.category}</p>
|
|
</div>
|
|
<span className="bg-blue-50 text-[#185FA5] px-2 py-0.5 border border-blue-100 rounded text-[9px] font-black uppercase">
|
|
{sim.availability_status}
|
|
</span>
|
|
</div>
|
|
<div className="flex items-center justify-between pt-2 border-t border-slate-100">
|
|
<span className="font-black text-slate-800 text-xs">{sim.salary} {t('aed', 'AED')}/{t('mo', 'mo')}</span>
|
|
<Link
|
|
href={`/employer/workers/${sim.id}`}
|
|
className="text-[#185FA5] font-black text-xs hover:underline flex items-center space-x-1"
|
|
>
|
|
<span>{t('view_profile', 'View Profile')}</span>
|
|
<span>→</span>
|
|
</Link>
|
|
</div>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Stage 4/5 Hired Flow Success Modal Overlay */}
|
|
{showHiredModal && (
|
|
<div className="fixed inset-0 bg-slate-900/60 backdrop-blur-xs flex items-center justify-center p-4 z-50 animate-fade-in">
|
|
<div className="bg-white rounded-3xl w-full max-w-md p-6 relative animate-zoom-in space-y-6 border border-slate-200 shadow-2xl">
|
|
|
|
<div className="text-center space-y-3">
|
|
<div className="w-16 h-16 bg-emerald-50 text-emerald-600 rounded-full flex items-center justify-center mx-auto shadow-inner">
|
|
<CheckCircle2 className="w-8 h-8" />
|
|
</div>
|
|
<h4 className="font-extrabold text-lg text-slate-900">{t('direct_sponsoring_finalized', 'Direct Sponsoring Finalized!')}</h4>
|
|
<p className="text-xs text-slate-500 leading-relaxed">
|
|
{t('hired_under_sponsorship_desc', '{name} is successfully marked as Hired under your sponsorship! This direct matching conforms exactly with Stage 4 of our UAE MOHRE zero-middlemen flow.').replace('{name}', worker.name)}
|
|
</p>
|
|
</div>
|
|
|
|
<div className="p-4 bg-blue-50/50 rounded-2xl border border-blue-100/50 space-y-2">
|
|
<span className="text-[9px] font-black text-[#185FA5] uppercase tracking-widest block">{t('next_step_post_hire_review', 'Next Step: Stage 5 Post-Hire Review')}</span>
|
|
<p className="text-[11px] text-slate-700 leading-relaxed font-bold">
|
|
{t('help_community_post_review', "Help the UAE community hire safely by posting an anonymous review describing {name}'s childcare, cooking, driving, or domestic skills.").replace('{name}', worker.name)}
|
|
</p>
|
|
</div>
|
|
|
|
<div className="flex flex-col space-y-2 text-xs font-bold">
|
|
<button
|
|
onClick={() => {
|
|
setShowHiredModal(false);
|
|
setShowReviewModal(true);
|
|
}}
|
|
className="w-full bg-[#185FA5] hover:bg-[#144f8a] text-white py-3 rounded-xl flex items-center justify-center space-x-2"
|
|
>
|
|
<Star className="w-4 h-4 fill-white" />
|
|
<span>{t('leave_trust_review', 'Leave a Trust Review')}</span>
|
|
</button>
|
|
<Link
|
|
href="/employer/workers"
|
|
className="w-full bg-slate-50 border border-slate-200 hover:bg-slate-100 text-slate-700 py-3 rounded-xl flex items-center justify-center"
|
|
>
|
|
{t('back_to_worker_directory', 'Back to Worker Directory')}
|
|
</Link>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
)}
|
|
|
|
{/* Report Abuse Modal Overlay */}
|
|
{showReportModal && (
|
|
<div className="fixed inset-0 bg-slate-900/60 backdrop-blur-xs flex items-center justify-center p-4 z-50 animate-fade-in">
|
|
<form onSubmit={handleReportSubmit} className="bg-white rounded-3xl w-full max-w-md p-6 relative animate-zoom-in space-y-4 border border-slate-200 shadow-2xl">
|
|
<button
|
|
type="button"
|
|
onClick={() => setShowReportModal(false)}
|
|
className="absolute top-4 right-4 text-slate-400 hover:text-slate-600"
|
|
>
|
|
<X className="w-5 h-5" />
|
|
</button>
|
|
|
|
<div className="flex items-center space-x-2 text-rose-600">
|
|
<AlertTriangle className="w-5 h-5" />
|
|
<h4 className="font-black text-sm uppercase">{t('report_abuse_violation', 'Report Vetting Abuse / Terms Violation')}</h4>
|
|
</div>
|
|
|
|
<p className="text-xs text-slate-500 leading-relaxed">
|
|
{t('zero_tolerance_abuse_desc', 'We maintain zero-tolerance for fake documentation, independent recruiters trading cash, or incorrect contact details.')}
|
|
</p>
|
|
|
|
<div className="space-y-3">
|
|
<div className="space-y-1">
|
|
<label className="text-[10px] font-black text-slate-400 uppercase tracking-widest">{t('reason', 'Reason')}</label>
|
|
<select
|
|
value={reportReason}
|
|
onChange={(e) => setReportReason(e.target.value)}
|
|
className="w-full p-2.5 border border-slate-300 rounded-xl text-xs font-bold text-slate-700 bg-slate-50 focus:outline-none"
|
|
>
|
|
<option value="">{t('select_reason', 'Select a reason...')}</option>
|
|
<option value="fees">{t('reason_fees', 'Worker / agent requested hiring commission fees')}</option>
|
|
<option value="profile">{t('reason_profile', 'Profile details / passport did not match actual person')}</option>
|
|
<option value="contact">{t('reason_contact', 'Invalid phone number / unreachable')}</option>
|
|
<option value="other">{t('reason_other', 'Other compliance violations')}</option>
|
|
</select>
|
|
</div>
|
|
|
|
<div className="space-y-1">
|
|
<label className="text-[10px] font-black text-slate-400 uppercase tracking-widest">{t('additional_context_details', 'Additional context details')}</label>
|
|
<textarea
|
|
rows="3"
|
|
value={reportDetails}
|
|
onChange={(e) => setReportDetails(e.target.value)}
|
|
placeholder={t('provide_specifics_placeholder', 'Provide detailed specifics of what happened...')}
|
|
className="w-full p-2.5 border border-slate-300 rounded-xl text-xs focus:outline-none"
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="flex justify-end space-x-2 pt-2 text-xs font-bold">
|
|
<button
|
|
type="button"
|
|
onClick={() => setShowReportModal(false)}
|
|
className="px-4 py-2 border border-slate-200 hover:bg-slate-50 rounded-lg"
|
|
>
|
|
{t('cancel', 'Cancel')}
|
|
</button>
|
|
<button
|
|
type="submit"
|
|
className="px-4 py-2 bg-rose-600 text-white hover:bg-rose-700 rounded-lg shadow-sm"
|
|
>
|
|
{t('submit_compliance_report', 'Submit Compliance Report')}
|
|
</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
)}
|
|
|
|
{/* Trust Review Modal Overlay */}
|
|
{showReviewModal && (
|
|
<div className="fixed inset-0 bg-slate-900/60 backdrop-blur-xs flex items-center justify-center p-4 z-50 animate-fade-in">
|
|
<form onSubmit={handleReviewSubmit} className="bg-white rounded-3xl w-full max-w-md p-6 relative animate-zoom-in space-y-4 border border-slate-200 shadow-2xl">
|
|
<button
|
|
type="button"
|
|
onClick={() => setShowReviewModal(false)}
|
|
className="absolute top-4 right-4 text-slate-400 hover:text-slate-600"
|
|
>
|
|
<X className="w-5 h-5" />
|
|
</button>
|
|
|
|
<div className="flex items-center space-x-2 text-[#185FA5]">
|
|
<Star className="w-5 h-5 text-amber-500 fill-amber-500" />
|
|
<h4 className="font-black text-sm uppercase">{t('submit_performance_review', 'Submit a Verified Performance Review')}</h4>
|
|
</div>
|
|
|
|
<p className="text-xs text-slate-500 leading-relaxed">
|
|
{t('feedback_helps_sponsors_desc', 'Your feedback helps other sponsors make secure and direct hiring choices.')}
|
|
</p>
|
|
|
|
<div className="space-y-3">
|
|
<div className="space-y-1">
|
|
<label className="text-[10px] font-black text-slate-400 uppercase tracking-widest block">{t('star_rating', 'Star Rating')}</label>
|
|
<div className="flex items-center space-x-1.5">
|
|
{[1, 2, 3, 4, 5].map((star) => (
|
|
<button
|
|
key={star}
|
|
type="button"
|
|
onClick={() => setNewRating(star)}
|
|
className="p-1 hover:scale-110 transition-transform"
|
|
>
|
|
<Star
|
|
className={`w-8 h-8 ${star <= newRating ? 'text-amber-500 fill-amber-500' : 'text-slate-200'}`}
|
|
/>
|
|
</button>
|
|
))}
|
|
</div>
|
|
</div>
|
|
|
|
<div className="space-y-1">
|
|
<label className="text-[10px] font-black text-slate-400 uppercase tracking-widest">{t('share_your_experience', 'Share Your Experience')}</label>
|
|
<textarea
|
|
rows="3"
|
|
value={newComment}
|
|
onChange={(e) => setNewComment(e.target.value)}
|
|
placeholder={t('share_experience_placeholder', 'Tell other sponsors about childcare skills, cleaning, cooking style, driving safety, etc...')}
|
|
className="w-full p-2.5 border border-slate-300 rounded-xl text-xs focus:outline-none"
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="flex justify-end space-x-2 pt-2 text-xs font-bold">
|
|
<button
|
|
type="button"
|
|
onClick={() => setShowReviewModal(false)}
|
|
className="px-4 py-2 border border-slate-200 hover:bg-slate-50 rounded-lg"
|
|
>
|
|
{t('cancel', 'Cancel')}
|
|
</button>
|
|
<button
|
|
type="submit"
|
|
className="px-4 py-2 bg-[#185FA5] text-white hover:bg-[#144f8a] rounded-lg shadow-sm"
|
|
>
|
|
{t('post_trust_review_action', 'Post Trust Review')}
|
|
</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
)}
|
|
|
|
</EmployerLayout>
|
|
);
|
|
}
|