mohan #5

Merged
mohanmd merged 46 commits from mohan into master 2026-06-15 09:13:23 +00:00
12 changed files with 154 additions and 33 deletions
Showing only changes of commit 75c047aa70 - Show all commits

View File

@ -45,8 +45,8 @@ public function index()
'VIP Concierge' => \App\Models\Sponsor::where('subscription_plan', 'vip')->count()
],
'worker_availability' => [
'Available Now' => \App\Models\Worker::where('availability_status', 'available')->count() ?: 640,
'Engaged / Contracted' => \App\Models\Worker::where('availability_status', 'hired')->count() ?: 480,
'Available Now' => \App\Models\Worker::where('status', 'active')->count() ?: 640,
'Engaged / Contracted' => \App\Models\Worker::where('status', 'hired')->count() ?: 480,
'In Interview' => 300
],
];

View File

@ -0,0 +1,29 @@
<?php
namespace Database\Seeders;
use Illuminate\Database\Seeder;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Hash;
class AdminSeeder extends Seeder
{
/**
* Run the database seeds.
*/
public function run(): void
{
$exists = DB::table('users')->where('email', 'admin@example.com')->exists();
if (!$exists) {
DB::table('users')->insert([
'name' => 'Admin User',
'email' => 'admin@example.com',
'password' => Hash::make('password'),
'role' => 'admin',
'created_at' => now(),
'updated_at' => now(),
]);
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 B

View File

@ -177,7 +177,7 @@ export default function SponsorsIndex({ sponsors, filters = {} }) {
<div className="grid grid-cols-1 md:grid-cols-4 gap-5">
<div className="bg-white p-5 rounded-2xl border border-slate-200 shadow-sm flex items-center justify-between">
<div>
<span className="text-[10px] font-black text-slate-400 uppercase tracking-widest block mb-1">Total Sponsors</span>
<span className="text-[10px] font-black text-slate-400 uppercase tracking-widest block mb-1">Total Employers</span>
<h3 className="text-2xl font-black text-slate-900">{sponsors.total || 0}</h3>
</div>
<div className="p-3 bg-teal-50 rounded-xl">
@ -186,7 +186,7 @@ export default function SponsorsIndex({ sponsors, filters = {} }) {
</div>
<div className="bg-white p-5 rounded-2xl border border-slate-200 shadow-sm flex items-center justify-between">
<div>
<span className="text-[10px] font-black text-slate-400 uppercase tracking-widest block mb-1">Active Passes</span>
<span className="text-[10px] font-black text-slate-400 uppercase tracking-widest block mb-1">Active Plans</span>
<h3 className="text-2xl font-black text-blue-600">
{sponsors.data.filter(s => s.subscription_status === 'active').length}
</h3>
@ -197,7 +197,7 @@ export default function SponsorsIndex({ sponsors, filters = {} }) {
</div>
<div className="bg-white p-5 rounded-2xl border border-slate-200 shadow-sm flex items-center justify-between">
<div>
<span className="text-[10px] font-black text-slate-400 uppercase tracking-widest block mb-1">Pending Vetting</span>
<span className="text-[10px] font-black text-slate-400 uppercase tracking-widest block mb-1">Pending Approval</span>
<h3 className="text-2xl font-black text-amber-500">
{sponsors.data.filter(s => !s.is_verified).length}
</h3>
@ -208,7 +208,7 @@ export default function SponsorsIndex({ sponsors, filters = {} }) {
</div>
<div className="bg-white p-5 rounded-2xl border border-slate-200 shadow-sm flex items-center justify-between">
<div>
<span className="text-[10px] font-black text-slate-400 uppercase tracking-widest block mb-1">Suspended Registry</span>
<span className="text-[10px] font-black text-slate-400 uppercase tracking-widest block mb-1">Suspended Accounts</span>
<h3 className="text-2xl font-black text-rose-600">
{sponsors.data.filter(s => s.status === 'suspended').length}
</h3>

View File

@ -331,19 +331,32 @@ export default function Verifications({ verifications, status }) {
<FileText className="w-4 h-4 text-[#0F6E56]" />
<span>Scanned Passport Scan Document</span>
</h3>
<div
onClick={() => setLightboxImage(selectedItem?.document_images[0])}
className="relative rounded-xl overflow-hidden border border-slate-200 bg-slate-100 cursor-zoom-in shadow-inner aspect-[4/3] max-h-72 group"
>
<img
src={selectedItem?.document_images[0]}
alt="Verification Scan"
className="w-full h-full object-cover group-hover:scale-102 transition-transform duration-300"
/>
<div className="absolute inset-0 bg-black/40 opacity-0 group-hover:opacity-100 transition-opacity flex items-center justify-center text-white text-xs font-black uppercase tracking-wider backdrop-blur-[1px]">
<ZoomIn className="w-4.5 h-4.5 mr-1" /> Click to Zoom Document
{selectedItem?.document_type?.toLowerCase().includes('emirates') || selectedItem?.document_type?.toLowerCase().includes('eid') || selectedItem?.document_type?.toLowerCase().includes('id') ? (
<div className="relative rounded-xl overflow-hidden border border-slate-200 bg-slate-950 flex flex-col items-center justify-center p-6 text-center aspect-[4/3] max-h-72 shadow-inner">
<ShieldCheck className="w-12 h-12 text-emerald-500 mb-3 animate-pulse" />
<div className="text-xs font-black text-white uppercase tracking-wider">Raw Scan Deleted (PDPL Law)</div>
<div className="text-[10px] text-slate-400 mt-2 font-medium leading-relaxed">
To comply strictly with UAE Personal Data Protection Law (PDPL), raw Emirates ID images are immediately destroyed post-OCR. Vetted metadata has been securely preserved.
</div>
<div className="mt-4 bg-emerald-600 text-white font-black text-[8px] tracking-wider uppercase border-none px-2.5 py-1 rounded">
[DELETED_FOR_PDPL_COMPLIANCE]
</div>
</div>
</div>
) : (
<div
onClick={() => setLightboxImage(selectedItem?.document_images[0])}
className="relative rounded-xl overflow-hidden border border-slate-200 bg-slate-100 cursor-zoom-in shadow-inner aspect-[4/3] max-h-72 group"
>
<img
src={selectedItem?.document_images[0]}
alt="Verification Scan"
className="w-full h-full object-cover group-hover:scale-102 transition-transform duration-300"
/>
<div className="absolute inset-0 bg-black/40 opacity-0 group-hover:opacity-100 transition-opacity flex items-center justify-center text-white text-xs font-black uppercase tracking-wider backdrop-blur-[1px]">
<ZoomIn className="w-4.5 h-4.5 mr-1" /> Click to Zoom Document
</div>
</div>
)}
<p className="text-[10px] text-slate-400 font-bold text-center uppercase tracking-wide">
Type: {selectedItem?.document_type}
</p>

View File

@ -489,7 +489,12 @@ export default function Index({ initialWorkers = [], initialShortlistedIds = [],
<div className="truncate">
<div className="font-extrabold 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" />}
{worker.verified && (
<span className="inline-flex items-center px-1.5 py-0.5 rounded-full text-[8px] font-black uppercase tracking-wider bg-emerald-500 text-white shadow-xs gap-0.5 animate-pulse" title="OCR Verified">
<CheckCircle2 className="w-3 h-3" />
<span>Verified</span>
</span>
)}
</div>
{/* Emirates ID Status Verification Badge & Visa Status */}
@ -498,9 +503,21 @@ export default function Index({ initialWorkers = [], initialShortlistedIds = [],
<ShieldCheck className="w-3 h-3 text-emerald-600 flex-shrink-0" />
<span>{worker.emirates_id_status}</span>
</div>
<div className="flex items-center space-x-1 text-[9px] font-black uppercase text-blue-700 bg-blue-50 px-1.5 py-0.5 rounded border border-blue-100">
<span>{worker.visa_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 text-[9px] font-black uppercase text-amber-700 bg-amber-50 px-1.5 py-0.5 rounded border border-amber-200">
<AlertTriangle className="w-3 h-3 text-amber-600 flex-shrink-0 animate-bounce" />
<span>{worker.visa_status} (Warning)</span>
</div>
) : worker.visa_status && worker.visa_status.toLowerCase().includes('cancelled') ? (
<div className="flex items-center space-x-1 text-[9px] font-black uppercase text-rose-700 bg-rose-50 px-1.5 py-0.5 rounded border border-rose-200 animate-pulse">
<AlertTriangle className="w-3 h-3 text-rose-600 flex-shrink-0" />
<span>{worker.visa_status} (Warning)</span>
</div>
) : (
<div className="flex items-center space-x-1 text-[9px] font-black uppercase text-blue-700 bg-blue-50 px-1.5 py-0.5 rounded border border-blue-100">
<span>{worker.visa_status}</span>
</div>
)}
</div>
<div className="flex items-center space-x-1.5 text-xs text-slate-500 mt-1">

View File

@ -173,8 +173,9 @@ export default function Show({ worker }) {
<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="bg-emerald-500 text-white p-0.5 rounded-full shadow-sm animate-pulse" title="OCR Verified">
<CheckCircle2 className="w-4 h-4" />
<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>Verified</span>
</span>
)}
@ -194,9 +195,21 @@ export default function Show({ worker }) {
<ShieldCheck className="w-3.5 h-3.5 text-emerald-600" />
<span>{worker.emirates_id_status}</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>
{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} (Warning: 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} (Warning: 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">
@ -367,7 +380,7 @@ export default function Show({ worker }) {
<span>Verified Legal Documents (UAE MOHRE Vetted)</span>
</h3>
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
<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">
@ -408,11 +421,48 @@ export default function Show({ worker }) {
</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">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">Scan Purged</span>
<span className="text-[5px] font-medium text-slate-400 mt-1 leading-tight block">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">Verification Type</div>
<div className="text-xs font-black text-slate-800">Emirates ID OCR</div>
</div>
<div>
<div className="text-[8px] font-black text-slate-400 uppercase tracking-tighter">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">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">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">Entry Visa (Verified)</span>
<ShieldCheck className="w-4 h-4 text-emerald-500" />
{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">
@ -422,14 +472,26 @@ export default function Show({ worker }) {
<div className="flex-1 space-y-2">
<div>
<div className="text-[8px] font-black text-slate-400 uppercase tracking-tighter">Emirates ID status</div>
<div className="text-xs font-bold text-slate-800">{worker.emirates_id_status}</div>
<div className="text-[8px] font-black text-slate-400 uppercase tracking-tighter">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">Vetting status</div>
<div className="flex items-center space-x-1.5 mt-0.5">
<CheckCircle2 className="w-3.5 h-3.5 text-emerald-600" />
<span className="text-[9px] font-bold text-slate-700">Clear Records</span>
{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">
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">
Needs Regularization
</span>
) : (
<>
<CheckCircle2 className="w-3.5 h-3.5 text-emerald-600" />
<span className="text-[9px] font-bold text-slate-700">Clear Records</span>
</>
)}
</div>
</div>
</div>