diff --git a/app/Http/Controllers/Api/EmployerAuthController.php b/app/Http/Controllers/Api/EmployerAuthController.php
index 7cbaf85..c464a56 100644
--- a/app/Http/Controllers/Api/EmployerAuthController.php
+++ b/app/Http/Controllers/Api/EmployerAuthController.php
@@ -422,6 +422,11 @@ public function uploadEmiratesId(Request $request)
$extractedIdNumber = '784-' . rand(1970, 2005) . '-' . rand(1000000, 9999999) . '-' . rand(1, 9);
$extractedExpiry = now()->addYears(rand(2, 4))->toDateString();
+ // We are not storing this document, just extract data and delete this file
+ if (file_exists(public_path($filePath))) {
+ unlink(public_path($filePath));
+ }
+
// Update or create EmployerProfile
$profile = EmployerProfile::where('user_id', $user->id)->first();
if (!$profile) {
@@ -435,7 +440,7 @@ public function uploadEmiratesId(Request $request)
}
$profile->update([
- 'emirates_id_front' => $filePath,
+ 'emirates_id_front' => null,
'emirates_id_number' => $extractedIdNumber,
'emirates_id_expiry' => $extractedExpiry,
]);
@@ -443,7 +448,7 @@ public function uploadEmiratesId(Request $request)
// Sync with corresponding sponsor record if found
if ($sponsor) {
$sponsor->update([
- 'emirates_id_file' => $filePath,
+ 'emirates_id_file' => null,
]);
}
diff --git a/app/Http/Controllers/Employer/EmployerAuthController.php b/app/Http/Controllers/Employer/EmployerAuthController.php
index 73c1903..5495ede 100644
--- a/app/Http/Controllers/Employer/EmployerAuthController.php
+++ b/app/Http/Controllers/Employer/EmployerAuthController.php
@@ -85,7 +85,6 @@ public function register(Request $request)
'name' => 'required|string|max:255',
'email' => 'required|string|email|max:255',
'phone' => 'required|string|regex:/^[0-9]{7,15}$/',
- 'emirates_id_file' => 'nullable|file|mimes:jpeg,png,jpg,pdf|max:10240',
], [
'phone.regex' => 'The mobile number must be between 7 and 15 digits without any country code (e.g. 501234567).',
]);
@@ -99,19 +98,6 @@ public function register(Request $request)
], 409);
}
- // Store file if provided
- $emiratesIdPath = null;
- if ($request->hasFile('emirates_id_file')) {
- $destinationPath = public_path('uploads/licenses');
- if (!file_exists($destinationPath)) {
- mkdir($destinationPath, 0755, true);
- }
- $emiratesIdFile = $request->file('emirates_id_file');
- $emiratesIdFileName = time() . '_emirates_id_' . preg_replace('/[^a-zA-Z0-9_.-]/', '', $emiratesIdFile->getClientOriginalName());
- $emiratesIdFile->move($destinationPath, $emiratesIdFileName);
- $emiratesIdPath = 'uploads/licenses/' . $emiratesIdFileName;
- }
-
// 3. Generate 6-digit OTP, hash & store with 10-min expiry
$otp = (string) mt_rand(100000, 999999);
$hashedOtp = Hash::make($otp);
@@ -122,7 +108,6 @@ public function register(Request $request)
'name' => $request->name,
'email' => $request->email,
'phone' => $request->phone,
- 'emirates_id_file' => $emiratesIdPath,
],
'employer_otp' => [
'hash' => $hashedOtp,
@@ -208,8 +193,8 @@ public function verifyEmail(Request $request)
// Success - mark verified
session(['employer_email_verified' => true]);
- return redirect()->route('employer.register-payment')
- ->with('success', 'Email verified successfully! Please choose a subscription plan to continue.');
+ return redirect()->route('employer.upload-emirates-id')
+ ->with('success', 'Email verified successfully! Please upload your Emirates ID.');
}
public function resendOtp(Request $request)
@@ -258,13 +243,73 @@ public function resendOtp(Request $request)
]);
}
- public function showRegisterPayment()
+ public function showUploadEmiratesId()
{
if (!session()->has('pending_employer_registration') || !session('employer_email_verified')) {
return redirect()->route('employer.register')
->with('error', 'Please complete email verification first.');
}
+ return Inertia::render('Employer/Auth/UploadEmiratesId', [
+ 'email' => session('pending_employer_registration.email'),
+ ]);
+ }
+
+ public function uploadEmiratesId(Request $request)
+ {
+ if (!session()->has('pending_employer_registration') || !session('employer_email_verified')) {
+ return redirect()->route('employer.register')
+ ->with('error', 'Registration session expired. Please start over.');
+ }
+
+ $request->validate([
+ 'emirates_id_file' => 'required|file|mimes:jpeg,png,jpg,pdf|max:10240',
+ ], [
+ 'emirates_id_file.required' => 'Please upload a clear scan or image of your Emirates ID.',
+ 'emirates_id_file.mimes' => 'The Emirates ID document must be an image (jpg, jpeg, png) or a PDF file.',
+ 'emirates_id_file.max' => 'The document must not exceed 10MB.',
+ ]);
+
+ $filePath = null;
+ if ($request->hasFile('emirates_id_file')) {
+ $destinationPath = public_path('uploads/documents');
+ if (!file_exists($destinationPath)) {
+ mkdir($destinationPath, 0755, true);
+ }
+ $file = $request->file('emirates_id_file');
+ $fileName = time() . '_employer_eid_' . preg_replace('/[^a-zA-Z0-9_.-]/', '', $file->getClientOriginalName());
+ $file->move($destinationPath, $fileName);
+ $filePath = 'uploads/documents/' . $fileName;
+
+ // OCR Simulated extraction
+ $extractedIdNumber = '784-' . rand(1970, 2005) . '-' . rand(1000000, 9999999) . '-' . rand(1, 9);
+ $extractedExpiry = now()->addYears(rand(2, 4))->toDateString();
+
+ // We are not storing this document, just extract data and delete this file
+ if (file_exists(public_path($filePath))) {
+ unlink(public_path($filePath));
+ }
+ $filePath = null; // Ensure we don't save the path
+ }
+
+ $pending = session('pending_employer_registration');
+ $pending['emirates_id_file'] = null;
+ $pending['emirates_id_number'] = $extractedIdNumber;
+ $pending['emirates_id_expiry'] = $extractedExpiry;
+ session(['pending_employer_registration' => $pending]);
+ session(['employer_emirates_id_uploaded' => true]);
+
+ return redirect()->route('employer.register-payment')
+ ->with('success', 'Emirates ID uploaded and verified successfully.');
+ }
+
+ public function showRegisterPayment()
+ {
+ if (!session()->has('pending_employer_registration') || !session('employer_email_verified') || !session('employer_emirates_id_uploaded')) {
+ return redirect()->route('employer.register')
+ ->with('error', 'Please complete Emirates ID upload first.');
+ }
+
return Inertia::render('Employer/Auth/RegisterPayment', [
'email' => session('pending_employer_registration.email'),
'plans' => [
@@ -319,7 +364,7 @@ public function storeRegisterPayment(Request $request)
public function showCreatePassword()
{
- if (!session()->has('pending_employer_registration') || !session('employer_email_verified') || !session()->has('pending_employer_payment')) {
+ if (!session()->has('pending_employer_registration') || !session('employer_email_verified') || !session('employer_emirates_id_uploaded') || !session()->has('pending_employer_payment')) {
return redirect()->route('employer.register')
->with('error', 'Please complete payment step first.');
}
@@ -344,7 +389,7 @@ public function createPassword(Request $request)
'password.regex' => 'The password must contain at least 8 characters, including 1 uppercase, 1 lowercase, 1 number, and 1 special character.',
]);
- if (!session()->has('pending_employer_registration') || !session('employer_email_verified') || !session()->has('pending_employer_payment')) {
+ if (!session()->has('pending_employer_registration') || !session('employer_email_verified') || !session('employer_emirates_id_uploaded') || !session()->has('pending_employer_payment')) {
return redirect()->route('employer.register')
->with('error', 'Registration session expired. Please start over.');
}
@@ -371,6 +416,9 @@ public function createPassword(Request $request)
'verification_status' => 'approved',
'language' => 'English',
'notifications' => true,
+ 'emirates_id_front' => null, // We did not store the file
+ 'emirates_id_number' => $pending['emirates_id_number'] ?? null,
+ 'emirates_id_expiry' => $pending['emirates_id_expiry'] ?? null,
]);
// Create Sponsor
@@ -389,7 +437,7 @@ public function createPassword(Request $request)
'otp_verified_at' => now(),
'status' => 'active',
'last_login_at' => now(),
- 'emirates_id_file' => $pending['emirates_id_file'] ?? null,
+ 'emirates_id_file' => null, // We did not store the file
]);
// Create active subscription in database
@@ -425,6 +473,7 @@ public function createPassword(Request $request)
'pending_employer_registration',
'employer_otp',
'employer_email_verified',
+ 'employer_emirates_id_uploaded',
'pending_employer_payment'
]);
diff --git a/dummy_eid.pdf b/dummy_eid.pdf
new file mode 100644
index 0000000..641225e
--- /dev/null
+++ b/dummy_eid.pdf
@@ -0,0 +1 @@
+Dummy PDF Content
diff --git a/public/swagger.json b/public/swagger.json
index f614856..1d1d261 100644
--- a/public/swagger.json
+++ b/public/swagger.json
@@ -2377,7 +2377,7 @@
"Employer/Auth"
],
"summary": "Register Sponsor (Alias)",
- "description": "Legacy route matching the simplified sponsor registration (Name, Email, Phone).",
+ "description": "Legacy route matching the simplified sponsor registration (Name, Email, Phone) (Step 1).",
"security": [],
"requestBody": {
"required": true,
@@ -2474,7 +2474,7 @@
"Employer/Auth"
],
"summary": "Upload Emirates ID scan & Secure OCR Extract during Onboarding",
- "description": "Accepts an email and an Emirates ID scan file, performs automatic OCR extraction of card fields (ID number and expiry), updates the employer's profile fields, and associates the file with their sponsor record.",
+ "description": "Accepts an email and an Emirates ID scan file, performs automatic OCR extraction of card fields (ID number and expiry), updates the employer's profile fields, and associates the file with their sponsor record (Step 3 - REQUIRED). We are not storing this document, just extracting the data and deleting the file.",
"security": [],
"requestBody": {
"required": true,
@@ -2549,7 +2549,7 @@
"Employer/Auth"
],
"summary": "Sponsor Subscription Payment",
- "description": "Submits a successful plan selection and PayTabs payment confirmation (Step 3).",
+ "description": "Submits a successful plan selection and PayTabs payment confirmation (Step 4).",
"security": [],
"requestBody": {
"required": true,
@@ -2598,7 +2598,7 @@
"Employer/Auth"
],
"summary": "Create Sponsor Account Password",
- "description": "Configures and finalizes the portal login password to complete registration (Step 4). Returns bearer token.",
+ "description": "Configures and finalizes the portal login password to complete registration (Step 5). Returns bearer token.",
"security": [],
"requestBody": {
"required": true,
diff --git a/resources/js/Pages/Employer/Auth/CreatePassword.jsx b/resources/js/Pages/Employer/Auth/CreatePassword.jsx
index c5332f2..a3a5ae6 100644
--- a/resources/js/Pages/Employer/Auth/CreatePassword.jsx
+++ b/resources/js/Pages/Employer/Auth/CreatePassword.jsx
@@ -108,25 +108,26 @@ export default function CreatePassword() {
{[
{ step: 1, label: 'Register' },
{ step: 2, label: 'Verify' },
- { step: 3, label: 'Payment' },
- { step: 4, label: 'Password' }
+ { step: 3, label: 'Emirates ID' },
+ { step: 4, label: 'Payment' },
+ { step: 5, label: 'Password' }
].map((s) => (
- {Array.isArray(errors.emirates_id_file) ? errors.emirates_id_file[0] : errors.emirates_id_file} -
- )} -