2026-07-07 14:16:17 +05:30

568 lines
37 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 {
User,
ShieldCheck,
Mail,
Phone,
Globe,
MapPin,
Home,
Edit3,
Calendar,
Briefcase,
Building,
FileText,
MessageSquare,
AlertCircle,
CheckCircle2,
Lock,
ExternalLink,
Compass,
FileSpreadsheet,
Eye,
Bell,
Camera,
Save,
XCircle
} from 'lucide-react';
import { toast } from 'sonner';
export default function Profile({ employerProfile }) {
const { t } = useTranslation();
const [showConfirmPopup, setShowConfirmPopup] = useState(false);
const handleEditClick = () => {
setShowConfirmPopup(true);
};
const handleConfirmEdit = () => {
setShowConfirmPopup(false);
router.get('/employer/profile/edit');
};
const handleCancelEdit = () => {
setShowConfirmPopup(false);
};
const [showRenewModal, setShowRenewModal] = useState(false);
const [frontFile, setFrontFile] = useState(null);
const [backFile, setBackFile] = useState(null);
const [frontPreview, setFrontPreview] = useState(null);
const [backPreview, setBackPreview] = useState(null);
const [isSubmitting, setIsSubmitting] = useState(false);
const expiryDateStr = employerProfile?.emirates_id?.expiry_date;
const isExpired = expiryDateStr ? new Date(expiryDateStr) <= new Date() : false;
const handleRenewalSubmit = (e) => {
e.preventDefault();
if (!frontFile || !backFile) {
toast.error(t('upload_both_sides', 'Please upload both front and back sides of your Emirates ID.'));
return;
}
setIsSubmitting(true);
router.post('/employer/profile/update', {
name: employerProfile.name,
email: employerProfile.email,
phone: employerProfile.phone,
emirates_id_front: frontFile,
emirates_id_back: backFile,
}, {
forceFormData: true,
onSuccess: () => {
toast.success(t('document_renewed', 'Emirates ID renewed successfully!'));
setShowRenewModal(false);
setFrontFile(null);
setBackFile(null);
setFrontPreview(null);
setBackPreview(null);
setIsSubmitting(false);
},
onError: (errs) => {
toast.error(Object.values(errs)[0] || t('renewal_failed', 'Failed to renew Emirates ID.'));
setIsSubmitting(false);
}
});
};
const toggleNotification = (type, currentVal) => {
router.post('/employer/profile/update', {
name: employerProfile.name,
email: employerProfile.email,
phone: employerProfile.phone,
email_notifications: type === 'email' ? !currentVal : employerProfile.email_notifications,
push_notifications: type === 'push' ? !currentVal : employerProfile.push_notifications,
}, {
preserveScroll: true,
onSuccess: () => {
toast.success(t('preferences_updated', 'Preferences updated successfully'));
}
});
};
const profilePhoto = employerProfile?.profile_photo_url;
return (
<EmployerLayout title={t('employer_profile_details', 'Profile Details')}>
<Head title={`${t('profile', 'Profile')} - ${t('employer_portal', 'Sponsor Portal')}`} />
<div className="max-w-5xl mx-auto pb-16 space-y-8 select-none animate-in fade-in duration-500">
{isExpired && (
<div className="bg-rose-50 border border-rose-200 rounded-3xl p-6 shadow-sm flex flex-col md:flex-row md:items-center justify-between gap-4 animate-in slide-in-from-top duration-300">
<div className="flex items-start gap-4">
<div className="p-3 bg-rose-100 text-rose-600 rounded-2xl">
<AlertCircle className="w-6 h-6 animate-pulse" />
</div>
<div className="space-y-1">
<h4 className="text-sm font-black text-rose-950 uppercase tracking-wide">Emirates ID Expired</h4>
<p className="text-xs text-rose-700/90 font-bold leading-normal">
Your Emirates ID card expired on <span className="font-extrabold">{employerProfile?.emirates_id?.expiry_date}</span>. Please upload a renewed document to maintain compliance and system access.
</p>
</div>
</div>
<button
onClick={() => setShowRenewModal(true)}
className="bg-rose-600 hover:bg-rose-700 text-white px-5 py-3 rounded-2xl text-xs font-black uppercase tracking-wider transition-all shadow-md shadow-rose-200/50 flex items-center justify-center gap-2 whitespace-nowrap self-start md:self-center"
>
<span>Renew Emirates ID</span>
</button>
</div>
)}
{/* Premium Banner & Cover Section */}
<div className="relative bg-white rounded-3xl border border-slate-200 shadow-sm overflow-hidden">
{/* Artistic Enterprise Gradient Header Cover */}
<div className="h-40 bg-gradient-to-r from-[#185FA5] via-[#2d7ad6] to-[#0f62ac] relative">
<div className="absolute inset-0 bg-[radial-gradient(circle_at_top_right,rgba(255,255,255,0.15),transparent)] pointer-events-none" />
<div className="absolute -bottom-8 left-8 flex items-center gap-2 text-white/10 select-none">
<Compass className="w-32 h-32 stroke-[0.5]" />
</div>
</div>
{/* Profile Header Details Row */}
<div className="px-8 pb-8 pt-4 relative flex flex-col md:flex-row items-center md:items-end justify-between gap-6">
<div className="flex flex-col md:flex-row items-center md:items-end gap-6 -mt-16 relative z-10 text-center md:text-left">
{/* Profile Image with Glow Ring */}
<div className="relative">
<div className="w-28 h-28 rounded-2xl bg-white p-1.5 shadow-xl border border-slate-100">
{profilePhoto ? (
<img
src={profilePhoto}
alt={employerProfile?.name}
className="w-full h-full rounded-xl object-cover"
/>
) : (
<div className="w-full h-full rounded-xl bg-gradient-to-br from-[#185FA5]/10 to-[#185FA5]/20 text-[#185FA5] flex items-center justify-center font-black text-4xl border border-blue-100">
{employerProfile?.name?.charAt(0)}
</div>
)}
</div>
<span className="absolute bottom-1 right-1 w-4 h-4 bg-emerald-500 rounded-full border-2 border-white shadow-sm" />
</div>
<div className="space-y-1.5 pb-2">
<div className="flex flex-wrap items-center justify-center md:justify-start gap-2.5">
<h2 className="text-2xl font-black text-slate-900 tracking-tight leading-none">{employerProfile?.name}</h2>
</div>
<p className="text-slate-500 font-bold text-xs">{employerProfile?.email}</p>
</div>
</div>
{/* Edit Button */}
<button
onClick={handleEditClick}
className="bg-[#185FA5] hover:bg-[#144f8a] text-white px-6 py-3.5 rounded-2xl text-xs font-black uppercase tracking-wider flex items-center space-x-2 transition-all shadow-lg shadow-blue-200/50 hover:shadow-blue-300/60 active:scale-95 group"
>
<Edit3 className="w-4 h-4 transition-transform group-hover:rotate-12" />
<span>{t('edit_profile_details', 'Edit Profile')}</span>
</button>
</div>
</div>
{/* Grid Layout: Left Details Column & Right Digital Card Column */}
<div className="grid grid-cols-1 lg:grid-cols-12 gap-8">
{/* Left Column: General & Invoicing Info (7/12 width) */}
<div className="lg:col-span-7 space-y-8">
{/* Account & Contact Settings */}
<div className="bg-white rounded-3xl border border-slate-200 p-8 shadow-sm space-y-6">
<div className="border-b border-slate-100 pb-4">
<h3 className="text-base font-black text-slate-900">{t('account_contact_info', 'Account & Contact Information')}</h3>
<p className="text-[10px] font-bold text-slate-400 uppercase tracking-widest mt-1">
{t('manage_contact_desc', 'Contact and notification channels')}
</p>
</div>
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
<div className="p-4 bg-slate-50 hover:bg-slate-100/50 rounded-2xl border border-slate-150 transition-colors">
<div className="flex items-center space-x-2 text-slate-400">
<User className="w-4 h-4 text-[#185FA5]" />
<span className="text-[9px] font-black uppercase tracking-wider">{t('full_name', 'Full Name')}</span>
</div>
<div className="text-xs font-black text-slate-800 mt-2">{employerProfile?.name}</div>
</div>
<div className="p-4 bg-slate-50 hover:bg-slate-100/50 rounded-2xl border border-slate-150 transition-colors">
<div className="flex items-center space-x-2 text-slate-400">
<Mail className="w-4 h-4 text-[#185FA5]" />
<span className="text-[9px] font-black uppercase tracking-wider">{t('email', 'Email Address')}</span>
</div>
<div className="text-xs font-black text-slate-800 mt-2 truncate" title={employerProfile?.email}>{employerProfile?.email}</div>
</div>
<div className="p-4 bg-slate-50 hover:bg-slate-100/50 rounded-2xl border border-slate-150 transition-colors">
<div className="flex items-center space-x-2 text-slate-400">
<Phone className="w-4 h-4 text-[#185FA5]" />
<span className="text-[9px] font-black uppercase tracking-wider">{t('phone', 'Phone Number')}</span>
</div>
<div className="text-xs font-black text-slate-800 mt-2">{employerProfile?.phone}</div>
</div>
<div className="p-4 bg-slate-50 hover:bg-slate-100/50 rounded-2xl border border-slate-150 transition-colors">
<div className="flex items-center space-x-2 text-slate-400">
<Home className="w-4 h-4 text-[#185FA5]" />
<span className="text-[9px] font-black uppercase tracking-wider">{t('property_type', 'Property Type')}</span>
</div>
<div className="text-xs font-black text-slate-800 mt-2">{employerProfile?.property_type || t('not_specified', 'Not Specified')}</div>
</div>
<div className="p-4 bg-slate-50 hover:bg-slate-100/50 rounded-2xl border border-slate-150 transition-colors sm:col-span-2">
<div className="flex items-center space-x-2 text-slate-400">
<MapPin className="w-4 h-4 text-[#185FA5]" />
<span className="text-[9px] font-black uppercase tracking-wider">{t('address', 'Address')}</span>
</div>
<div className="text-xs font-black text-slate-800 mt-2 leading-relaxed">{employerProfile?.address || t('not_specified', 'Not Specified')}</div>
</div>
</div>
</div>
{/* Notification Preferences & Integration Card */}
<div className="bg-white rounded-3xl border border-slate-200 p-8 shadow-sm space-y-6">
<div className="border-b border-slate-100 pb-4">
<h3 className="text-base font-black text-slate-900">{t('notification_preferences', 'Notification Preferences')}</h3>
</div>
{/* Preferences Toggles */}
<div className="space-y-4">
{/* Email Alerts Row */}
<div className="flex items-center justify-between p-4 bg-slate-50 rounded-2xl border border-slate-150 transition-all hover:bg-slate-100/50">
<div className="flex items-center gap-3">
<div className="p-2.5 bg-blue-550/10 text-[#185FA5] rounded-xl">
<Mail className="w-5 h-5" />
</div>
<div>
<h4 className="text-xs font-black text-slate-800">{t('email_alerts', 'Email Alerts')}</h4>
<p className="text-[10px] text-slate-400 font-bold uppercase tracking-wider mt-0.5">{t('email_alerts_sub', 'Invoices, updates & announcements')}</p>
</div>
</div>
<button
type="button"
onClick={() => toggleNotification('email', employerProfile?.email_notifications)}
className={`relative inline-flex h-6 w-11 items-center rounded-full transition-colors focus:outline-none ${
employerProfile?.email_notifications ? 'bg-[#185FA5]' : 'bg-slate-200'
}`}
>
<span
className={`inline-block h-4 w-4 transform rounded-full bg-white transition-transform ${
employerProfile?.email_notifications ? 'translate-x-6' : 'translate-x-1'
}`}
/>
</button>
</div>
{/* Push Notification Alerts Row */}
<div className="flex items-center justify-between p-4 bg-slate-50 rounded-2xl border border-slate-150 transition-all hover:bg-slate-100/50">
<div className="flex items-center gap-3">
<div className="p-2.5 bg-blue-550/10 text-[#185FA5] rounded-xl">
<Bell className="w-5 h-5" />
</div>
<div>
<h4 className="text-xs font-black text-slate-800">{t('push_alerts', 'Push Notifications')}</h4>
<p className="text-[10px] text-slate-400 font-bold uppercase tracking-wider mt-0.5">{t('push_alerts_sub', 'Live updates & mobile alerts')}</p>
</div>
</div>
<button
type="button"
onClick={() => toggleNotification('push', employerProfile?.push_notifications)}
className={`relative inline-flex h-6 w-11 items-center rounded-full transition-colors focus:outline-none ${
employerProfile?.push_notifications ? 'bg-[#185FA5]' : 'bg-slate-200'
}`}
>
<span
className={`inline-block h-4 w-4 transform rounded-full bg-white transition-transform ${
employerProfile?.push_notifications ? 'translate-x-6' : 'translate-x-1'
}`}
/>
</button>
</div>
</div>
</div>
</div>
{/* Right Column: Digital Emirates ID & Card Visual (5/12 width) */}
<div className="lg:col-span-5 space-y-8">
{/* Interactive Digital Emirates ID Widget */}
<div className="bg-white rounded-3xl border border-slate-200 p-8 shadow-sm space-y-6">
<div className="border-b border-slate-100 pb-4">
<h3 className="text-base font-black text-slate-900">{t('identity_card', 'Emirates ID Details')}</h3>
<p className="text-[10px] font-bold text-slate-400 uppercase tracking-widest mt-1">
{t('vetted_details_badge', 'Vetted MOHRE identity credentials')}
</p>
</div>
{/* Digital Emirates ID Visual */}
<div className="relative bg-gradient-to-br from-[#1b3d6c] to-[#0d223e] p-6 rounded-2xl text-white shadow-xl overflow-hidden aspect-[1.586/1] border border-white/5 flex flex-col justify-between">
{/* Sparkle Background Art */}
<div className="absolute top-0 right-0 w-36 h-36 bg-blue-500/15 rounded-full -mr-12 -mt-12 blur-3xl pointer-events-none" />
<div className="absolute bottom-0 left-0 w-36 h-36 bg-emerald-500/10 rounded-full -ml-12 -mb-12 blur-3xl pointer-events-none" />
{isExpired && (
<div className="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 border-4 border-rose-500/30 text-rose-500/30 font-black text-2xl uppercase tracking-widest px-4 py-2 rounded-xl rotate-12 select-none z-20 pointer-events-none">
Expired
</div>
)}
{/* Top Header */}
<div className="flex items-center justify-between z-10">
<div className="space-y-0.5">
<div className="text-[7px] font-black tracking-widest text-slate-400 uppercase">United Arab Emirates</div>
<div className="text-[10px] font-black tracking-wide text-white uppercase">Resident Identity Card</div>
</div>
<div className="w-7 h-5 bg-white/10 rounded border border-white/10 flex items-center justify-center">
<Globe className="w-3.5 h-3.5 text-slate-300" />
</div>
</div>
{/* Card Number & Name */}
<div className="space-y-2.5 z-10 my-4">
<div className="text-xs font-mono font-black tracking-widest text-white/95">
{employerProfile?.emirates_id?.emirates_id_number}
</div>
<div className="space-y-0.5">
<div className="text-[6px] font-black text-slate-400 uppercase tracking-wider">Name</div>
<div className="text-[11px] font-extrabold text-white truncate max-w-[240px]">
{employerProfile?.emirates_id?.name}
</div>
</div>
</div>
{/* Bottom Info Row */}
<div className="grid grid-cols-3 gap-2 pt-2 border-t border-white/10 z-10">
<div>
<span className="text-[5px] font-black text-slate-400 uppercase tracking-wider block">Nationality</span>
<span className="text-[9px] font-bold text-white block">{employerProfile?.emirates_id?.nationality}</span>
</div>
<div>
<span className="text-[5px] font-black text-slate-400 uppercase tracking-wider block">Expiry Date</span>
<span className={`text-[9px] font-bold block ${isExpired ? 'text-rose-400 font-extrabold animate-pulse' : 'text-white'}`}>
{employerProfile?.emirates_id?.expiry_date}
</span>
</div>
<div>
<span className="text-[5px] font-black text-slate-400 uppercase tracking-wider block">Occupation</span>
<span className="text-[9px] font-bold text-white block truncate">{employerProfile?.emirates_id?.occupation}</span>
</div>
</div>
</div>
{/* Renew Button below ID Card if expired */}
{isExpired && (
<button
onClick={() => setShowRenewModal(true)}
className="w-full bg-rose-600 hover:bg-rose-700 text-white py-3.5 rounded-2xl text-xs font-black uppercase tracking-wider flex items-center justify-center space-x-2 transition-all shadow-md shadow-rose-200"
>
<span>Renew Emirates ID</span>
</button>
)}
{/* Detailed Metadata Fields */}
<div className="space-y-4 pt-4 border-t border-slate-100 text-xs">
<div className="flex justify-between py-2 border-b border-slate-50">
<span className="font-bold text-slate-400 uppercase tracking-wider text-[9px]">{t('issue_place', 'Issue Place')}</span>
<span className="font-extrabold text-slate-700">{employerProfile?.emirates_id?.issue_place}</span>
</div>
<div className="flex justify-between py-2 border-b border-slate-50">
<span className="font-bold text-slate-400 uppercase tracking-wider text-[9px]">{t('issue_date', 'Issue Date')}</span>
<span className="font-extrabold text-slate-700">{employerProfile?.emirates_id?.issue_date}</span>
</div>
<div className="flex justify-between py-2 border-b border-slate-50">
<span className="font-bold text-slate-400 uppercase tracking-wider text-[9px]">{t('date_of_birth', 'Date of Birth')}</span>
<span className="font-extrabold text-slate-700">{employerProfile?.emirates_id?.date_of_birth}</span>
</div>
<div className="flex justify-between py-2">
<span className="font-bold text-slate-400 uppercase tracking-wider text-[9px]">{t('employer_agency', 'Sponsor')}</span>
<span className="font-extrabold text-[#185FA5] truncate max-w-[200px]" title={employerProfile?.emirates_id?.employer}>
{employerProfile?.emirates_id?.employer}
</span>
</div>
</div>
</div>
</div>
</div>
</div>
{/* Confirmation Dialog Popup Modal */}
{showConfirmPopup && (
<div className="fixed inset-0 bg-slate-900/60 backdrop-blur-sm z-50 flex items-center justify-center p-4">
<div className="bg-white rounded-3xl max-w-sm w-full p-8 border border-slate-100 shadow-2xl space-y-6 animate-in zoom-in-95 duration-200">
<div className="flex flex-col items-center text-center space-y-4">
<div className="p-4 bg-blue-50 text-[#185FA5] rounded-2xl">
<AlertCircle className="w-8 h-8" />
</div>
<div className="space-y-2">
<h3 className="text-base font-black text-slate-900">
{t('edit_profile_confirm_title', 'Edit Profile')}
</h3>
<p className="text-xs text-slate-500 font-medium leading-relaxed">
{t('edit_profile_confirm_body', 'Are you sure you want to edit your profile details?')}
</p>
</div>
</div>
<div className="flex gap-4">
<button
onClick={handleCancelEdit}
className="flex-1 px-4 py-3 border border-slate-200 hover:bg-slate-50 text-slate-650 rounded-xl text-xs font-black uppercase tracking-wider transition-colors outline-none"
>
{t('cancel', 'Cancel')}
</button>
<button
onClick={handleConfirmEdit}
className="flex-1 px-4 py-3 bg-[#185FA5] hover:bg-[#144f8a] text-white rounded-xl text-xs font-black uppercase tracking-wider transition-colors outline-none shadow-md shadow-blue-200/50"
>
{t('confirm', 'Confirm')}
</button>
</div>
</div>
</div>
)}
{/* Renew Emirates ID Modal */}
{showRenewModal && (
<div className="fixed inset-0 bg-slate-900/60 backdrop-blur-sm z-[9999] flex items-center justify-center p-4 animate-in fade-in duration-300">
<div className="bg-white rounded-3xl border border-slate-200 shadow-2xl max-w-xl w-full overflow-hidden animate-in zoom-in-95 duration-300">
{/* Modal Header */}
<div className="bg-gradient-to-r from-rose-600 to-rose-700 p-6 text-white relative">
<h3 className="text-base font-black uppercase tracking-wide">Renew Emirates ID</h3>
<p className="text-[10px] text-rose-100 font-bold uppercase tracking-wider mt-1">Upload both sides of your new document</p>
<button
onClick={() => setShowRenewModal(false)}
className="absolute top-6 right-6 text-rose-100 hover:text-white transition-colors"
>
<XCircle className="w-6 h-6" />
</button>
</div>
{/* Modal Form */}
<form onSubmit={handleRenewalSubmit} className="p-6 space-y-6">
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
{/* Front Side Upload */}
<div className="space-y-2">
<label className="text-[10px] font-black text-slate-500 uppercase tracking-wider block">Front Side</label>
<div className="border-2 border-dashed border-slate-200 hover:border-[#185FA5] rounded-2xl p-4 transition-all bg-slate-50/5 flex flex-col items-center justify-center min-h-[160px] relative overflow-hidden group">
{frontPreview ? (
<>
<img src={frontPreview} alt="Front ID Preview" className="absolute inset-0 w-full h-full object-cover" />
<div className="absolute inset-0 bg-slate-900/50 opacity-0 group-hover:opacity-100 transition-opacity flex items-center justify-center">
<span className="text-[10px] font-black uppercase tracking-wider text-white">Change Photo</span>
</div>
</>
) : (
<div className="flex flex-col items-center text-slate-400 space-y-2">
<Camera className="w-8 h-8 text-[#185FA5]/70" />
<span className="text-[10px] font-bold uppercase tracking-wider text-slate-500">Upload Front Side</span>
</div>
)}
<input
type="file"
accept="image/*"
onChange={(e) => {
const file = e.target.files[0];
if (file) {
setFrontFile(file);
setFrontPreview(URL.createObjectURL(file));
}
}}
className="absolute inset-0 opacity-0 cursor-pointer"
required
/>
</div>
</div>
{/* Back Side Upload */}
<div className="space-y-2">
<label className="text-[10px] font-black text-slate-500 uppercase tracking-wider block">Back Side</label>
<div className="border-2 border-dashed border-slate-200 hover:border-[#185FA5] rounded-2xl p-4 transition-all bg-slate-50/5 flex flex-col items-center justify-center min-h-[160px] relative overflow-hidden group">
{backPreview ? (
<>
<img src={backPreview} alt="Back ID Preview" className="absolute inset-0 w-full h-full object-cover" />
<div className="absolute inset-0 bg-slate-900/50 opacity-0 group-hover:opacity-100 transition-opacity flex items-center justify-center">
<span className="text-[10px] font-black uppercase tracking-wider text-white">Change Photo</span>
</div>
</>
) : (
<div className="flex flex-col items-center text-slate-400 space-y-2">
<Camera className="w-8 h-8 text-[#185FA5]/70" />
<span className="text-[10px] font-bold uppercase tracking-wider text-slate-500">Upload Back Side</span>
</div>
)}
<input
type="file"
accept="image/*"
onChange={(e) => {
const file = e.target.files[0];
if (file) {
setBackFile(file);
setBackPreview(URL.createObjectURL(file));
}
}}
className="absolute inset-0 opacity-0 cursor-pointer"
required
/>
</div>
</div>
</div>
{/* Actions */}
<div className="flex items-center justify-end gap-3 pt-4 border-t border-slate-100">
<button
type="button"
onClick={() => setShowRenewModal(false)}
className="px-5 py-3 border border-slate-200 hover:bg-slate-50 text-slate-650 rounded-xl text-xs font-black uppercase tracking-wider transition-colors outline-none"
>
Cancel
</button>
<button
type="submit"
disabled={isSubmitting}
className="bg-rose-600 hover:bg-rose-700 disabled:bg-rose-450 text-white px-6 py-3 rounded-xl text-xs font-black uppercase tracking-wider transition-all flex items-center gap-2 shadow-md shadow-rose-100"
>
{isSubmitting ? (
<>
<span className="w-4 h-4 border-2 border-white border-t-transparent rounded-full animate-spin" />
<span>Processing OCR...</span>
</>
) : (
<>
<Save className="w-4 h-4" />
<span>Upload & Renew</span>
</>
)}
</button>
</div>
</form>
</div>
</div>
)}
</EmployerLayout>
);
}