diff --git a/app/Http/Controllers/Api/EmployerProfileController.php b/app/Http/Controllers/Api/EmployerProfileController.php
index 62ce416..e2c1559 100644
--- a/app/Http/Controllers/Api/EmployerProfileController.php
+++ b/app/Http/Controllers/Api/EmployerProfileController.php
@@ -54,6 +54,17 @@ public function getProfile(Request $request)
'occupation' => $profile->emirates_id_occupation,
'employer' => $profile->emirates_id_employer,
'issuing_place' => $profile->emirates_id_issue_place,
+ 'emirates_id' => [
+ 'emirates_id_number' => $profile->emirates_id_number,
+ 'name' => $profile->emirates_id_name,
+ 'date_of_birth' => $profile->emirates_id_dob,
+ 'nationality' => $profile->nationality,
+ 'issue_date' => $profile->emirates_id_issue_date,
+ 'expiry_date' => $profile->emirates_id_expiry,
+ 'employer' => $profile->emirates_id_employer,
+ 'issue_place' => $profile->emirates_id_issue_place,
+ 'occupation' => $profile->emirates_id_occupation,
+ ],
];
return response()->json([
@@ -270,6 +281,17 @@ public function updateProfile(Request $request)
'occupation' => $profile->emirates_id_occupation,
'employer' => $profile->emirates_id_employer,
'issuing_place' => $profile->emirates_id_issue_place,
+ 'emirates_id' => [
+ 'emirates_id_number' => $profile->emirates_id_number,
+ 'name' => $profile->emirates_id_name,
+ 'date_of_birth' => $profile->emirates_id_dob,
+ 'nationality' => $profile->nationality,
+ 'issue_date' => $profile->emirates_id_issue_date,
+ 'expiry_date' => $profile->emirates_id_expiry,
+ 'employer' => $profile->emirates_id_employer,
+ 'issue_place' => $profile->emirates_id_issue_place,
+ 'occupation' => $profile->emirates_id_occupation,
+ ],
];
return response()->json([
@@ -309,7 +331,14 @@ public function getDashboard(Request $request)
$savedCandidates = \App\Models\Shortlist::where('employer_id', $employer->id)->count();
- $totalWorkers = \App\Models\Worker::where('status', 'active')->count();
+ $totalWorkers = \App\Models\Worker::with('documents')
+ ->where('status', '!=', 'Hired')
+ ->where('status', '!=', 'hidden')
+ ->get()
+ ->filter(function ($w) {
+ return !str_contains(strtolower($w->passport_status), 'pending');
+ })
+ ->count();
// Resolve plan
$sub = \Illuminate\Support\Facades\DB::table('subscriptions')
diff --git a/app/Http/Controllers/Api/EmployerWorkerController.php b/app/Http/Controllers/Api/EmployerWorkerController.php
index 4db4198..705859f 100644
--- a/app/Http/Controllers/Api/EmployerWorkerController.php
+++ b/app/Http/Controllers/Api/EmployerWorkerController.php
@@ -92,7 +92,10 @@ private function formatWorker(Worker $w)
'documents' => $w->documents->map(function ($doc) {
$ocrData = $doc->ocr_data;
if ($doc->type === 'visa' && is_array($ocrData)) {
- unset($ocrData['sponsor']);
+ unset($ocrData['file_number']);
+ unset($ocrData['name']);
+ unset($ocrData['passport_number']);
+ unset($ocrData['accompanied_by']);
unset($ocrData['valid_until']);
}
return [
@@ -109,6 +112,10 @@ private function formatWorker(Worker $w)
'updated_at' => $doc->updated_at?->toISOString(),
];
})->toArray(),
+ 'category' => [
+ 'id' => 7,
+ 'name' => 'General Helper',
+ ],
];
}
@@ -396,11 +403,11 @@ public function getCandidates(Request $request)
// Fetch Job Applications
$jobIds = JobPost::where('employer_id', $employerId)->pluck('id');
$applicationsQuery = JobApplication::whereIn('job_id', $jobIds)
- ->with(['worker', 'jobPost']);
+ ->with(['worker.skills', 'worker.documents', 'jobPost']);
// Fetch Direct Hiring Offers
$directOffersQuery = JobOffer::where('employer_id', $employerId)
- ->with('worker');
+ ->with('worker.skills', 'worker.documents');
// Apply search filter if provided
if ($request->filled('search')) {
@@ -430,34 +437,15 @@ public function getCandidates(Request $request)
elseif ($app->status === 'applied') $status = 'Reviewing';
else $status = ucfirst($app->status);
- $langs = ($w->id % 2 === 0) ? ['English', 'Arabic'] : (($w->id % 3 === 0) ? ['English', 'Tagalog'] : ['English', 'Hindi', 'Arabic']);
- $skillsList = ['cooking', 'driving', 'childcare', 'cleaning', 'elderly care', 'gardening'];
- $mappedSkills = [
- $skillsList[$w->id % 6],
- $skillsList[($w->id + 2) % 6]
- ];
- $jobTypes = ['full-time', 'part-time', 'live-in', 'live-out'];
- $preferredJobType = $w->preferred_job_type ?? $jobTypes[$w->id % 4];
+ $formattedWorker = $this->formatWorker($w);
- return [
+ return array_merge($formattedWorker, [
'id' => $app->id,
'worker_id' => $w->id,
- 'name' => $w->name,
- 'nationality' => $w->nationality,
'status' => $status,
'applied_at' => $app->created_at->format('Y-m-d H:i:s'),
'type' => 'application',
- 'skills' => $mappedSkills,
- 'languages' => $langs,
- 'availability' => $w->availability ?? 'Immediate',
- 'preferred_location' => $w->preferred_location,
- 'area' => $w->area,
- 'preferred_job_type' => $preferredJobType,
- 'live_in_out' => $w->live_in_out,
- 'in_country' => (bool)$w->in_country,
- 'visa_status' => $w->visa_status,
- 'gender' => $w->gender,
- ];
+ ]);
})->filter()->values()->toArray();
// Fetch Direct Hiring Offers
@@ -472,34 +460,15 @@ public function getCandidates(Request $request)
elseif ($offer->status === 'rejected') $status = 'Rejected';
elseif ($offer->status === 'pending') $status = 'Offer Sent';
- $langs = ($w->id % 2 === 0) ? ['English', 'Arabic'] : (($w->id % 3 === 0) ? ['English', 'Tagalog'] : ['English', 'Hindi', 'Arabic']);
- $skillsList = ['cooking', 'driving', 'childcare', 'cleaning', 'elderly care', 'gardening'];
- $mappedSkills = [
- $skillsList[$w->id % 6],
- $skillsList[($w->id + 2) % 6]
- ];
- $jobTypes = ['full-time', 'part-time', 'live-in', 'live-out'];
- $preferredJobType = $w->preferred_job_type ?? $jobTypes[$w->id % 4];
+ $formattedWorker = $this->formatWorker($w);
- return [
+ return array_merge($formattedWorker, [
'id' => 'offer_' . $offer->id,
'worker_id' => $w->id,
- 'name' => $w->name,
- 'nationality' => $w->nationality,
'status' => $status,
'applied_at' => $offer->created_at->format('Y-m-d H:i:s'),
'type' => 'direct_offer',
- 'skills' => $mappedSkills,
- 'languages' => $langs,
- 'availability' => $w->availability ?? 'Immediate',
- 'preferred_location' => $w->preferred_location,
- 'area' => $w->area,
- 'preferred_job_type' => $preferredJobType,
- 'live_in_out' => $w->live_in_out,
- 'in_country' => (bool)$w->in_country,
- 'visa_status' => $w->visa_status,
- 'gender' => $w->gender,
- ];
+ ]);
})->filter()->values()->toArray();
// Merge and sort
@@ -1034,7 +1003,10 @@ public function getWorkerDetail(Request $request, $id)
'documents' => $w->documents->map(function ($doc) {
$ocrData = $doc->ocr_data;
if ($doc->type === 'visa' && is_array($ocrData)) {
- unset($ocrData['sponsor']);
+ unset($ocrData['file_number']);
+ unset($ocrData['name']);
+ unset($ocrData['passport_number']);
+ unset($ocrData['accompanied_by']);
unset($ocrData['valid_until']);
}
return [
diff --git a/app/Http/Controllers/Employer/WorkerController.php b/app/Http/Controllers/Employer/WorkerController.php
index e2c0371..8fe0a9f 100644
--- a/app/Http/Controllers/Employer/WorkerController.php
+++ b/app/Http/Controllers/Employer/WorkerController.php
@@ -390,6 +390,14 @@ public function show($id)
'in_country' => (bool) $w->in_country,
'preferred_location' => $w->preferred_location,
'documents' => $w->documents->map(function ($doc) {
+ $ocrData = $doc->ocr_data;
+ if ($doc->type === 'visa' && is_array($ocrData)) {
+ unset($ocrData['file_number']);
+ unset($ocrData['name']);
+ unset($ocrData['passport_number']);
+ unset($ocrData['accompanied_by']);
+ unset($ocrData['valid_until']);
+ }
return [
'id' => $doc->id,
'type' => $doc->type,
@@ -398,7 +406,7 @@ public function show($id)
'expiry_date' => $doc->expiry_date,
'ocr_accuracy' => $doc->ocr_accuracy,
'file_path' => $doc->file_path ? url($doc->file_path) : null,
- 'ocr_data' => $doc->ocr_data,
+ 'ocr_data' => $ocrData,
];
})->toArray(),
];
diff --git a/public/swagger.json b/public/swagger.json
index 8b48739..284d8cb 100644
--- a/public/swagger.json
+++ b/public/swagger.json
@@ -3897,6 +3897,48 @@
"issuing_place": {
"type": "string",
"example": "Dubai"
+ },
+ "emirates_id": {
+ "type": "object",
+ "description": "Consolidated Emirates ID details.",
+ "properties": {
+ "emirates_id_number": {
+ "type": "string",
+ "example": "784-1988-5310327-2"
+ },
+ "name": {
+ "type": "string",
+ "example": "Ahmad Bin Ahmed"
+ },
+ "date_of_birth": {
+ "type": "string",
+ "example": "1990-01-01"
+ },
+ "nationality": {
+ "type": "string",
+ "example": "Emirati"
+ },
+ "issue_date": {
+ "type": "string",
+ "example": "2023-04-11"
+ },
+ "expiry_date": {
+ "type": "string",
+ "example": "2028-04-11"
+ },
+ "employer": {
+ "type": "string",
+ "example": "Federal Authority"
+ },
+ "issue_place": {
+ "type": "string",
+ "example": "Abu Dhabi"
+ },
+ "occupation": {
+ "type": "string",
+ "example": "Manager"
+ }
+ }
}
}
}
@@ -4114,6 +4156,48 @@
"issuing_place": {
"type": "string",
"example": "Dubai"
+ },
+ "emirates_id": {
+ "type": "object",
+ "description": "Consolidated Emirates ID details.",
+ "properties": {
+ "emirates_id_number": {
+ "type": "string",
+ "example": "784-1988-5310327-2"
+ },
+ "name": {
+ "type": "string",
+ "example": "Ahmad Bin Ahmed"
+ },
+ "date_of_birth": {
+ "type": "string",
+ "example": "1990-01-01"
+ },
+ "nationality": {
+ "type": "string",
+ "example": "Emirati"
+ },
+ "issue_date": {
+ "type": "string",
+ "example": "2023-04-11"
+ },
+ "expiry_date": {
+ "type": "string",
+ "example": "2028-04-11"
+ },
+ "employer": {
+ "type": "string",
+ "example": "Federal Authority"
+ },
+ "issue_place": {
+ "type": "string",
+ "example": "Abu Dhabi"
+ },
+ "occupation": {
+ "type": "string",
+ "example": "Manager"
+ }
+ }
}
}
}
diff --git a/resources/js/Pages/Admin/Workers/Index.jsx b/resources/js/Pages/Admin/Workers/Index.jsx
index a34142c..a1ae972 100644
--- a/resources/js/Pages/Admin/Workers/Index.jsx
+++ b/resources/js/Pages/Admin/Workers/Index.jsx
@@ -805,10 +805,14 @@ export default function WorkerManagement({ workers }) {
Document Type
{safeRender(passportDoc.ocr_data?.document_type)}
-
- Personal Number
- {safeRender(passportDoc.ocr_data?.personal_number)}
-
+ {passportDoc.ocr_data?.personal_number &&
+ passportDoc.ocr_data?.personal_number !== 'N/A' &&
+ passportDoc.ocr_data?.personal_number !== (passportDoc.ocr_data?.passport_number || passportDoc.number) && (
+
+ Personal Number
+ {safeRender(passportDoc.ocr_data?.personal_number)}
+
+ )}
{passportDoc.file_path && (
@@ -840,6 +844,16 @@ export default function WorkerManagement({ workers }) {
);
}
+
+ const sponsorObj = visaDoc.ocr_data?.sponsor;
+ const isSponsorObj = sponsorObj && typeof sponsorObj === 'object' && !Array.isArray(sponsorObj);
+ const sponsorName = isSponsorObj
+ ? (sponsorObj.name || sponsorObj.sponsor_name || sponsorObj.full_name)
+ : (visaDoc.ocr_data?.sponsor_name || (typeof sponsorObj === 'string' ? sponsorObj : null));
+ const sponsorMobile = isSponsorObj
+ ? (sponsorObj.mobile || sponsorObj.mobile_number || sponsorObj.phone)
+ : null;
+
return (
@@ -851,22 +865,12 @@ export default function WorkerManagement({ workers }) {
UID No
{safeRender(visaDoc.ocr_data?.uid_no)}
-
- File Number
- {safeRender(visaDoc.ocr_data?.file_number || visaDoc.number)}
-
-
- ID Number
- {safeRender(visaDoc.ocr_data?.id_number)}
-
-
- Full Name
- {safeRender(visaDoc.ocr_data?.full_name)}
-
-
- Name
- {safeRender(visaDoc.ocr_data?.name)}
-
+ {visaDoc.ocr_data?.id_number && visaDoc.ocr_data?.id_number !== 'N/A' && (
+
+ ID Number
+ {safeRender(visaDoc.ocr_data?.id_number)}
+
+ )}
Visa Type
{safeRender(visaDoc.ocr_data?.visa_type)}
@@ -875,10 +879,18 @@ export default function WorkerManagement({ workers }) {
Profession
{safeRender(visaDoc.ocr_data?.profession)}
-
- Sponsor Name
- {safeRender(visaDoc.ocr_data?.sponsor_name)}
-
+ {sponsorName && (
+
+ Sponsor Name
+ {safeRender(sponsorName)}
+
+ )}
+ {sponsorMobile && (
+
+ Sponsor Mobile
+ {safeRender(sponsorMobile)}
+
+ )}
Nationality
@@ -888,14 +900,6 @@ export default function WorkerManagement({ workers }) {
Country
{safeRender(visaDoc.ocr_data?.country)}
-
- Passport No
- {safeRender(visaDoc.ocr_data?.passport_no)}
-
-
- Passport Number
- {safeRender(visaDoc.ocr_data?.passport_number)}
-
Date of Birth
{safeRender(visaDoc.ocr_data?.date_of_birth)}
@@ -917,10 +921,6 @@ export default function WorkerManagement({ workers }) {
{safeRender(visaDoc.ocr_data?.expiry_date || visaDoc.expiry_date)}
-
- Accompanied By
- {safeRender(visaDoc.ocr_data?.accompanied_by)}
-
Document Type
{safeRender(visaDoc.ocr_data?.document_type)}
diff --git a/resources/js/Pages/Employer/Dashboard.jsx b/resources/js/Pages/Employer/Dashboard.jsx
index fdfc23d..96506db 100644
--- a/resources/js/Pages/Employer/Dashboard.jsx
+++ b/resources/js/Pages/Employer/Dashboard.jsx
@@ -181,7 +181,6 @@ export default function Dashboard({
{t('total_hired_workers', 'Total Hired Workers')}
{stats.hired_count}
-
{t('direct_contracts', 'Direct contracts initiated')}
{t('track_active_staff', 'Track active staff')}
@@ -200,9 +199,8 @@ export default function Dashboard({
-
{t('shortlisted_candidates', 'Shortlisted Candidates')}
+
{t('saved_workers', 'Saved Workers')}
{stats.shortlisted_count}
-
{t('bookmark_list', 'Bookmark list for interviews')}
{t('open_shortlist', 'Open shortlist book')}
diff --git a/resources/js/Pages/Employer/SelectedCandidates.jsx b/resources/js/Pages/Employer/SelectedCandidates.jsx
index 43ddc4c..db2de5b 100644
--- a/resources/js/Pages/Employer/SelectedCandidates.jsx
+++ b/resources/js/Pages/Employer/SelectedCandidates.jsx
@@ -22,7 +22,7 @@ import {
DropdownMenuSeparator,
DropdownMenuTrigger
} from '@/components/ui/dropdown-menu';
-import FilterDrawer, { FilterSection, FilterSelect, FilterInput, FilterChips, FilterCheckboxList } from '../../Components/Employer/FilterDrawer';
+import FilterDrawer, { FilterSection, FilterSelect, FilterInput, FilterChips, FilterCheckboxList } from '../../components/Employer/FilterDrawer';
export default function SelectedCandidates({
selectedWorkers,
diff --git a/resources/js/Pages/Employer/Shortlist.jsx b/resources/js/Pages/Employer/Shortlist.jsx
index 80ca5d0..8f3e113 100644
--- a/resources/js/Pages/Employer/Shortlist.jsx
+++ b/resources/js/Pages/Employer/Shortlist.jsx
@@ -123,23 +123,7 @@ export default function Shortlist({ shortlistedWorkers }) {
{/* Passport Status Verification Badge & Visa Status */}
- {worker.visa_expiry_date ? (
-
-
- Visa Exp: {worker.visa_expiry_date}
-
- ) : (
-
-
- Visa Expiry Pending
-
- )}
+ {/* Removed visa expiry warning badge for cleaner UI */}
{worker.visa_status && (worker.visa_status.toLowerCase().includes('tourist') || worker.visa_status.toLowerCase().includes('visit')) ? (
diff --git a/resources/js/Pages/Employer/Workers/Index.jsx b/resources/js/Pages/Employer/Workers/Index.jsx
index 3222068..e9faae7 100644
--- a/resources/js/Pages/Employer/Workers/Index.jsx
+++ b/resources/js/Pages/Employer/Workers/Index.jsx
@@ -28,7 +28,7 @@ import {
ShieldCheck,
User
} from 'lucide-react';
-import FilterDrawer, { FilterSection, FilterSelect, FilterInput, FilterChips, FilterCheckboxList } from '../../../Components/Employer/FilterDrawer';
+import FilterDrawer, { FilterSection, FilterSelect, FilterInput, FilterChips, FilterCheckboxList } from '../../../components/Employer/FilterDrawer';
const getLanguageFlag = (lang) => {
const flags = {
@@ -704,17 +704,7 @@ export default function Index({ initialWorkers = [], initialShortlistedIds = [],
{worker.visa_status}
)}
- {worker.document_expiry_status && (
-
- 📅 {worker.document_expiry_status}
-
- )}
+ {/* Removed visa expiry status badge for cleaner UI */}
diff --git a/resources/js/Pages/Employer/Workers/Show.jsx b/resources/js/Pages/Employer/Workers/Show.jsx
index 97772df..69b3476 100644
--- a/resources/js/Pages/Employer/Workers/Show.jsx
+++ b/resources/js/Pages/Employer/Workers/Show.jsx
@@ -54,7 +54,7 @@ const getExpiryStatus = (expiryDate) => {
if (diffDays < 0) {
return {
- text: `Expired \${Math.abs(diffDays)} days ago`,
+ text: 'Expired',
color: 'text-rose-700 bg-rose-50 border-rose-200 font-black'
};
} else if (diffDays === 0) {
@@ -64,7 +64,7 @@ const getExpiryStatus = (expiryDate) => {
};
} else {
return {
- text: `Valid until \${expiryDate} (Expires in \${diffDays} days)`,
+ text: `Valid until ${expiryDate}`,
color: 'text-emerald-700 bg-emerald-50 border-emerald-150 font-black'
};
}
@@ -83,6 +83,7 @@ const safeRender = (value) => {
export default function Show({ worker }) {
const { t } = useTranslation();
const passportDoc = worker.documents?.find(d => d.type === 'passport');
+ const emiratesIdDoc = worker.documents?.find(d => d.type === 'emirates_id' || d.type === 'eid');
const visaDoc = worker.documents?.find(d => d.type === 'visa');
const [showReportModal, setShowReportModal] = useState(false);
@@ -434,8 +435,8 @@ export default function Show({ worker }) {
{(() => {
const expiryStatus = getExpiryStatus(passportDoc.expiry_date);
return (
-
- \${expiryStatus.text}
+
+ {expiryStatus.text}
);
})()}
@@ -474,6 +475,14 @@ export default function Show({ worker }) {
{t('place_of_birth', 'Place of Birth')}
{safeRender(passportDoc.ocr_data.place_of_birth)}
+
+
{t('nationality', 'Nationality')}
+
{safeRender(passportDoc.ocr_data.nationality || worker.nationality)}
+
+
+
{t('issuing_country', 'Issuing Country')}
+
{safeRender(passportDoc.ocr_data.issuing_country)}
+
{t('issue_date', 'Date of Issue')}
{safeRender(passportDoc.ocr_data.date_of_issue || passportDoc.issue_date)}
@@ -483,8 +492,12 @@ export default function Show({ worker }) {
{safeRender(passportDoc.ocr_data.date_of_expiry || passportDoc.expiry_date)}
-
{t('issuing_country', 'Issuing Country')}
-
{safeRender(passportDoc.ocr_data.issuing_country)}
+
{t('authority', 'Authority')}
+
{safeRender(passportDoc.ocr_data.authority)}
+
+
+
{t('document_type', 'Document Type')}
+
{safeRender(passportDoc.ocr_data.document_type || passportDoc.type || 'passport')}
) : (
@@ -537,6 +550,106 @@ export default function Show({ worker }) {
)}
+ {/* Document Card: Emirates ID */}
+ {emiratesIdDoc && (
+
+
+
+ {t('emirates_id_details', 'Emirates ID Details')}
+ {(() => {
+ const expiryStatus = getExpiryStatus(emiratesIdDoc.expiry_date);
+ return (
+
+ {expiryStatus.text}
+
+ );
+ })()}
+
+ {emiratesIdDoc.ocr_accuracy && (
+
+ {emiratesIdDoc.ocr_accuracy}% Match
+
+ )}
+
+
+
+ {emiratesIdDoc.ocr_data ? (
+
+
+
{t('emirates_id_number', 'Emirates ID Number')}
+
{safeRender(emiratesIdDoc.ocr_data.emirates_id_number || emiratesIdDoc.number)}
+
+
+
{t('full_name', 'Full Name')}
+
{safeRender(emiratesIdDoc.ocr_data.name || emiratesIdDoc.ocr_data.full_name)}
+
+
+
{t('nationality', 'Nationality')}
+
{safeRender(emiratesIdDoc.ocr_data.nationality)}
+
+
+
{t('date_of_birth', 'Date of Birth')}
+
{safeRender(emiratesIdDoc.ocr_data.date_of_birth || emiratesIdDoc.ocr_data.dob)}
+
+
+
{t('gender', 'Gender')}
+
{safeRender(emiratesIdDoc.ocr_data.gender || emiratesIdDoc.ocr_data.sex)}
+
+
+
{t('occupation', 'Occupation')}
+
{safeRender(emiratesIdDoc.ocr_data.occupation || emiratesIdDoc.ocr_data.profession)}
+
+
+
{t('employer', 'Employer')}
+
{safeRender(emiratesIdDoc.ocr_data.employer)}
+
+
+
{t('issue_date', 'Issue Date')}
+
{safeRender(emiratesIdDoc.ocr_data.issue_date || emiratesIdDoc.issue_date)}
+
+
+
{t('expiry_date', 'Expiry Date')}
+
{safeRender(emiratesIdDoc.ocr_data.expiry_date || emiratesIdDoc.expiry_date)}
+
+
+ ) : (
+
+
+
{t('document_id', 'Document ID')}
+
{emiratesIdDoc.number}
+
+
+
{t('issue_date', 'Issue')}
+
{emiratesIdDoc.issue_date || 'N/A'}
+
+
+
{t('expiry_date', 'Expiry')}
+
{emiratesIdDoc.expiry_date || 'N/A'}
+
+
+ )}
+
+
+
+
+ )}
+
{/* Document Card: Visa */}
{visaDoc ? (
@@ -544,10 +657,10 @@ export default function Show({ worker }) {
{t('visa_details', 'Entry Visa Details')}
{(() => {
- const expiryStatus = getExpiryStatus(passportDoc.expiry_date);
+ const expiryStatus = getExpiryStatus(visaDoc.expiry_date || worker.visa_expiry_date);
return (
-
- \${expiryStatus.text}
+
+ {expiryStatus.text}
);
})()}
@@ -564,46 +677,89 @@ export default function Show({ worker }) {
- {visaDoc.ocr_data ? (
-
-
-
{t('full_name', 'Full Name')}
-
{safeRender(visaDoc.ocr_data.name)}
+ {visaDoc.ocr_data ? (() => {
+ const sponsorObj = visaDoc.ocr_data?.sponsor;
+ const isSponsorObj = sponsorObj && typeof sponsorObj === 'object' && !Array.isArray(sponsorObj);
+ const sponsorName = isSponsorObj
+ ? (sponsorObj.name || sponsorObj.sponsor_name || sponsorObj.full_name)
+ : (visaDoc.ocr_data?.sponsor_name || (typeof sponsorObj === 'string' ? sponsorObj : null));
+ const sponsorMobile = isSponsorObj
+ ? (sponsorObj.mobile || sponsorObj.mobile_number || sponsorObj.phone)
+ : null;
+
+ return (
+
+
+
{t('entry_permit_no', 'Entry Permit No')}
+
{safeRender(visaDoc.ocr_data.entry_permit_no)}
+
+
+
{t('uid_no', 'UID No')}
+
{safeRender(visaDoc.ocr_data.uid_no)}
+
+
+
{t('id_number', 'ID Number')}
+
{safeRender(visaDoc.ocr_data.id_number || visaDoc.ocr_data.emirates_id_number)}
+
+
+
{t('visa_type', 'Visa Type')}
+
{safeRender(visaDoc.ocr_data.visa_type || 'ENTRY PERMIT')}
+
+
+
{t('profession', 'Profession')}
+
{safeRender(visaDoc.ocr_data.profession || worker.visa_status)}
+
+ {sponsorName && (
+
+
{t('sponsor_name', 'Sponsor Name')}
+
{safeRender(sponsorName)}
+
+ )}
+ {sponsorMobile && (
+
+
{t('sponsor_mobile', 'Sponsor Mobile')}
+
{safeRender(sponsorMobile)}
+
+ )}
+
+
{t('nationality', 'Nationality')}
+
{safeRender(visaDoc.ocr_data.nationality || worker.nationality)}
+
+
+
{t('country', 'Country')}
+
{safeRender(visaDoc.ocr_data.country || 'United Arab Emirates')}
+
+
+
{t('date_of_birth', 'Date of Birth')}
+
{safeRender(visaDoc.ocr_data.date_of_birth || visaDoc.ocr_data.dob)}
+
+
+
{t('place_of_birth', 'Place of Birth')}
+
{safeRender(visaDoc.ocr_data.place_of_birth)}
+
+
+
{t('place_of_issue', 'Place of Issue')}
+
{safeRender(visaDoc.ocr_data.place_of_issue)}
+
+
+
{t('issue_date', 'Issue Date')}
+
{safeRender(visaDoc.ocr_data.issue_date || visaDoc.issue_date)}
+
+
+
{t('expiry_date', 'Expiry Date')}
+
{safeRender(visaDoc.ocr_data.expiry_date || visaDoc.expiry_date)}
+
+
+
{t('document_type', 'Document Type')}
+
{safeRender(visaDoc.ocr_data.document_type || visaDoc.type || 'uae_visa')}
+
+
+
{t('ocr_accuracy', 'OCR Accuracy')}
+
{(visaDoc.ocr_accuracy || visaDoc.ocr_data?.ocr_accuracy || 99)}%
+
-
-
{t('file_number', 'File Number')}
-
{safeRender(visaDoc.ocr_data.file_number || visaDoc.number)}
-
-
-
{t('profession', 'Profession')}
-
{safeRender(visaDoc.ocr_data.profession || worker.visa_status)}
-
-
-
{t('sponsor', 'Sponsor')}
-
{safeRender(visaDoc.ocr_data.sponsor || visaDoc.ocr_data.sponsor_name)}
-
-
-
{t('passport_number', 'Passport Number')}
-
{safeRender(visaDoc.ocr_data.passport_number)}
-
-
-
{t('place_of_issue', 'Place of Issue')}
-
{safeRender(visaDoc.ocr_data.place_of_issue)}
-
-
-
{t('issue_date', 'Date of Issue')}
-
{safeRender(visaDoc.ocr_data.issue_date || visaDoc.issue_date)}
-
-
-
{t('expiry_date', 'Date of Expiry')}
-
{safeRender(visaDoc.ocr_data.expiry_date || visaDoc.expiry_date)}
-
-
-
{t('accompanied_by', 'Accompanied By')}
-
{safeRender(visaDoc.ocr_data.accompanied_by)}
-
-
- ) : (
+ );
+ })() : (
{t('document_id', 'Document ID')}
diff --git a/resources/js/components/Employer/FilterDrawer.jsx b/resources/js/components/Employer/FilterDrawer.jsx
index 4428b1b..26e7fab 100644
--- a/resources/js/components/Employer/FilterDrawer.jsx
+++ b/resources/js/components/Employer/FilterDrawer.jsx
@@ -1,4 +1,4 @@
-import React, { useEffect } from 'react';
+import * as React from 'react';
import { X, RotateCcw, SlidersHorizontal } from 'lucide-react';
/**
@@ -14,7 +14,7 @@ import { X, RotateCcw, SlidersHorizontal } from 'lucide-react';
*/
export default function FilterDrawer({ open, onClose, onReset, activeCount = 0, title = 'Filters', children }) {
// Lock body scroll when drawer is open
- useEffect(() => {
+ React.useEffect(() => {
if (open) {
document.body.style.overflow = 'hidden';
} else {
@@ -24,8 +24,8 @@ export default function FilterDrawer({ open, onClose, onReset, activeCount = 0,
}, [open]);
// Close on Escape key
- useEffect(() => {
- const handler = (e) => { if (e.key === 'Escape') onClose(); };
+ React.useEffect(() => {
+ const handler = (e) => { if (e.key === 'Escape' && typeof onClose === 'function') onClose(); };
window.addEventListener('keydown', handler);
return () => window.removeEventListener('keydown', handler);
}, [onClose]);
@@ -164,14 +164,15 @@ export function FilterInput({ id, value, onChange, placeholder }) {
* FilterChips — a row of selectable chip buttons for single-select options.
* options: [{ value, label }]
*/
-export function FilterChips({ options, selected, onChange }) {
+export function FilterChips({ options = [], selected, onChange }) {
+ const opts = options || [];
return (
- {options.map(opt => (
+ {opts.map(opt => (