diff --git a/app/Http/Controllers/Admin/DashboardController.php b/app/Http/Controllers/Admin/DashboardController.php index 7a236da..d49fadb 100644 --- a/app/Http/Controllers/Admin/DashboardController.php +++ b/app/Http/Controllers/Admin/DashboardController.php @@ -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 ], ]; diff --git a/app/Http/Controllers/Api/EmployerAuthController.php b/app/Http/Controllers/Api/EmployerAuthController.php index 3602f33..c83faea 100644 --- a/app/Http/Controllers/Api/EmployerAuthController.php +++ b/app/Http/Controllers/Api/EmployerAuthController.php @@ -115,7 +115,7 @@ public function register(Request $request) \Illuminate\Support\Facades\Cache::put('employer_otp_' . $request->email, [ 'code' => $otp, - 'expires_at' => now()->addMinutes(10) + 'expires_at' => now()->addMinutes(10)->timestamp ], 600); // Create inactive User @@ -196,10 +196,25 @@ public function verify(Request $request) 'errors' => $validator->errors() ], 422); } - $cachedData = \Illuminate\Support\Facades\Cache::get('employer_otp_' . $request->email); - if (!$cachedData || $cachedData['code'] !== $request->otp || now()->gt($cachedData['expires_at'])) { + if (!$cachedData || !isset($cachedData['code']) || !isset($cachedData['expires_at'])) { + return response()->json([ + 'success' => false, + 'message' => 'Invalid or expired verification code.' + ], 400); + } + + // Handle any dirty/legacy cache objects gracefully + if (is_object($cachedData['expires_at']) || $cachedData['expires_at'] instanceof \__PHP_Incomplete_Class) { + \Illuminate\Support\Facades\Cache::forget('employer_otp_' . $request->email); + return response()->json([ + 'success' => false, + 'message' => 'Session expired. Please request a new verification code.' + ], 400); + } + + if ($cachedData['code'] !== $request->otp || now()->timestamp > $cachedData['expires_at']) { return response()->json([ 'success' => false, 'message' => 'Invalid or expired verification code.' diff --git a/database/seeders/AdminSeeder.php b/database/seeders/AdminSeeder.php new file mode 100644 index 0000000..95c51da --- /dev/null +++ b/database/seeders/AdminSeeder.php @@ -0,0 +1,29 @@ +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(), + ]); + } + } +} diff --git a/public/uploads/documents/1779818367_passport_passport.png b/public/uploads/documents/1779818367_passport_passport.png new file mode 100644 index 0000000..909c66d Binary files /dev/null and b/public/uploads/documents/1779818367_passport_passport.png differ diff --git a/public/uploads/documents/1779818367_visa_visa.png b/public/uploads/documents/1779818367_visa_visa.png new file mode 100644 index 0000000..909c66d Binary files /dev/null and b/public/uploads/documents/1779818367_visa_visa.png differ diff --git a/public/uploads/documents/1779818419_passport_passport.png b/public/uploads/documents/1779818419_passport_passport.png new file mode 100644 index 0000000..909c66d Binary files /dev/null and b/public/uploads/documents/1779818419_passport_passport.png differ diff --git a/public/uploads/documents/1779818419_visa_visa.png b/public/uploads/documents/1779818419_visa_visa.png new file mode 100644 index 0000000..909c66d Binary files /dev/null and b/public/uploads/documents/1779818419_visa_visa.png differ diff --git a/public/uploads/documents/1779818589_passport_passport.png b/public/uploads/documents/1779818589_passport_passport.png new file mode 100644 index 0000000..909c66d Binary files /dev/null and b/public/uploads/documents/1779818589_passport_passport.png differ diff --git a/public/uploads/documents/1779818589_visa_visa.png b/public/uploads/documents/1779818589_visa_visa.png new file mode 100644 index 0000000..909c66d Binary files /dev/null and b/public/uploads/documents/1779818589_visa_visa.png differ diff --git a/resources/js/Pages/Admin/Employers/Index.jsx b/resources/js/Pages/Admin/Employers/Index.jsx index 8a3c5d4..1b2ac83 100644 --- a/resources/js/Pages/Admin/Employers/Index.jsx +++ b/resources/js/Pages/Admin/Employers/Index.jsx @@ -177,7 +177,7 @@ export default function SponsorsIndex({ sponsors, filters = {} }) {
- Total Sponsors + Total Employers

{sponsors.total || 0}

@@ -186,7 +186,7 @@ export default function SponsorsIndex({ sponsors, filters = {} }) {
- Active Passes + Active Plans

{sponsors.data.filter(s => s.subscription_status === 'active').length}

@@ -197,7 +197,7 @@ export default function SponsorsIndex({ sponsors, filters = {} }) {
- Pending Vetting + Pending Approval

{sponsors.data.filter(s => !s.is_verified).length}

@@ -208,7 +208,7 @@ export default function SponsorsIndex({ sponsors, filters = {} }) {
- Suspended Registry + Suspended Accounts

{sponsors.data.filter(s => s.status === 'suspended').length}

diff --git a/resources/js/Pages/Admin/Workers/Verifications.jsx b/resources/js/Pages/Admin/Workers/Verifications.jsx index a059fc4..e53fd44 100644 --- a/resources/js/Pages/Admin/Workers/Verifications.jsx +++ b/resources/js/Pages/Admin/Workers/Verifications.jsx @@ -331,19 +331,32 @@ export default function Verifications({ verifications, status }) { Scanned Passport Scan Document -
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" - > - Verification Scan -
- Click to Zoom Document + {selectedItem?.document_type?.toLowerCase().includes('emirates') || selectedItem?.document_type?.toLowerCase().includes('eid') || selectedItem?.document_type?.toLowerCase().includes('id') ? ( +
+ +
Raw Scan Deleted (PDPL Law)
+
+ 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. +
+
+ [DELETED_FOR_PDPL_COMPLIANCE] +
-
+ ) : ( +
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" + > + Verification Scan +
+ Click to Zoom Document +
+
+ )}

Type: {selectedItem?.document_type}

diff --git a/resources/js/Pages/Employer/Workers/Index.jsx b/resources/js/Pages/Employer/Workers/Index.jsx index 9cb8548..3d511eb 100644 --- a/resources/js/Pages/Employer/Workers/Index.jsx +++ b/resources/js/Pages/Employer/Workers/Index.jsx @@ -489,7 +489,12 @@ export default function Index({ initialWorkers = [], initialShortlistedIds = [],
{worker.name} - {worker.verified && } + {worker.verified && ( + + + Verified + + )}
{/* Emirates ID Status Verification Badge & Visa Status */} @@ -498,9 +503,21 @@ export default function Index({ initialWorkers = [], initialShortlistedIds = [], {worker.emirates_id_status}
-
- {worker.visa_status} -
+ {worker.visa_status && (worker.visa_status.toLowerCase().includes('tourist') || worker.visa_status.toLowerCase().includes('visit')) ? ( +
+ + {worker.visa_status} (Warning) +
+ ) : worker.visa_status && worker.visa_status.toLowerCase().includes('cancelled') ? ( +
+ + {worker.visa_status} (Warning) +
+ ) : ( +
+ {worker.visa_status} +
+ )}
diff --git a/resources/js/Pages/Employer/Workers/Show.jsx b/resources/js/Pages/Employer/Workers/Show.jsx index 524c8c2..342ab65 100644 --- a/resources/js/Pages/Employer/Workers/Show.jsx +++ b/resources/js/Pages/Employer/Workers/Show.jsx @@ -173,8 +173,9 @@ export default function Show({ worker }) {

{worker.name}

{worker.verified && ( - - + + + Verified )} @@ -194,9 +195,21 @@ export default function Show({ worker }) { {worker.emirates_id_status}
-
- {worker.visa_status} -
+ {worker.visa_status && (worker.visa_status.toLowerCase().includes('tourist') || worker.visa_status.toLowerCase().includes('visit')) ? ( +
+ + {worker.visa_status} (Warning: Visit Visa) +
+ ) : worker.visa_status && worker.visa_status.toLowerCase().includes('cancelled') ? ( +
+ + {worker.visa_status} (Warning: Cancelled) +
+ ) : ( +
+ {worker.visa_status} +
+ )}
@@ -367,7 +380,7 @@ export default function Show({ worker }) { Verified Legal Documents (UAE MOHRE Vetted) -
+
{/* Document Card: Passport */}
@@ -408,11 +421,48 @@ export default function Show({ worker }) {
+ {/* Document Card: Emirates ID */} +
+
+ Emirates ID (PDPL Compliant) + +
+
+
+ + Scan Purged + UAE PDPL compliant +
+ +
+
+
Verification Type
+
Emirates ID OCR
+
+
+
Status
+
+ + {worker.emirates_id_status} +
+
+
+
Physical Scan Storage
+ Permanently Purged +
+
+
+
+ {/* Document Card: Visa */}
Entry Visa (Verified) - + {worker.visa_status && (worker.visa_status.toLowerCase().includes('tourist') || worker.visa_status.toLowerCase().includes('visit') || worker.visa_status.toLowerCase().includes('cancelled')) ? ( + + ) : ( + + )}
@@ -422,14 +472,26 @@ export default function Show({ worker }) {
-
Emirates ID status
-
{worker.emirates_id_status}
+
Visa Category
+
{worker.visa_status}
Vetting status
- - Clear Records + {worker.visa_status && (worker.visa_status.toLowerCase().includes('tourist') || worker.visa_status.toLowerCase().includes('visit')) ? ( + + Transfer Required + + ) : worker.visa_status && worker.visa_status.toLowerCase().includes('cancelled') ? ( + + Needs Regularization + + ) : ( + <> + + Clear Records + + )}