worker view profile issue #13

Merged
mohanmd merged 1 commits from mohan into master 2026-06-23 13:55:30 +00:00
3 changed files with 74 additions and 54 deletions
Showing only changes of commit b95d76f00b - Show all commits

View File

@ -2690,7 +2690,7 @@
"Worker/Profile"
],
"summary": "Get Safety Report Reasons (Worker)",
"description": "Returns a list of active safety/moderation report reasons. Can filter reasons by target type (Chat or Review).",
"description": "Returns a list of active safety/moderation report reasons. Can filter reasons by target type (Chat or Support).",
"parameters": [
{
"name": "type",
@ -5130,7 +5130,7 @@
"Employer/Reviews"
],
"summary": "Get Safety Report Reasons (Employer)",
"description": "Returns a list of active safety/moderation report reasons. Can filter reasons by target type (Chat or Review).",
"description": "Returns a list of active safety/moderation report reasons. Can filter reasons by target type (Chat or Support).",
"parameters": [
{
"name": "type",

View File

@ -62,6 +62,16 @@ const locationData = {
}
};
const safeRender = (value) => {
if (value === null || value === undefined) return 'N/A';
if (typeof value === 'object') {
if (value.name) return String(value.name);
if (value.full_name) return String(value.full_name);
return JSON.stringify(value);
}
return String(value);
};
export default function WorkerManagement({ workers }) {
const [searchTerm, setSearchTerm] = useState('');
const [statusFilter, setStatusFilter] = useState('all');
@ -749,55 +759,55 @@ export default function WorkerManagement({ workers }) {
<div className="grid grid-cols-2 gap-3 text-xs">
<div>
<span className="text-[10px] font-black text-slate-400 uppercase tracking-wider block">Passport Number</span>
<span className="font-mono font-bold text-slate-800">{passportDoc.ocr_data?.passport_number || passportDoc.number || 'N/A'}</span>
<span className="font-mono font-bold text-slate-800">{safeRender(passportDoc.ocr_data?.passport_number || passportDoc.number)}</span>
</div>
<div>
<span className="text-[10px] font-black text-slate-400 uppercase tracking-wider block">Surname</span>
<span className="font-bold text-slate-800">{passportDoc.ocr_data?.surname || 'N/A'}</span>
<span className="font-bold text-slate-800">{safeRender(passportDoc.ocr_data?.surname)}</span>
</div>
<div>
<span className="text-[10px] font-black text-slate-400 uppercase tracking-wider block">Given Names</span>
<span className="font-bold text-slate-800">{passportDoc.ocr_data?.given_names || 'N/A'}</span>
<span className="font-bold text-slate-800">{safeRender(passportDoc.ocr_data?.given_names)}</span>
</div>
<div>
<span className="text-[10px] font-black text-slate-400 uppercase tracking-wider block">Sex</span>
<span className="font-bold text-slate-800">{passportDoc.ocr_data?.sex || 'N/A'}</span>
<span className="font-bold text-slate-800">{safeRender(passportDoc.ocr_data?.sex)}</span>
</div>
<div>
<span className="text-[10px] font-black text-slate-400 uppercase tracking-wider block">Date of Birth</span>
<span className="font-bold text-slate-800">{passportDoc.ocr_data?.date_of_birth || 'N/A'}</span>
<span className="font-bold text-slate-800">{safeRender(passportDoc.ocr_data?.date_of_birth)}</span>
</div>
<div>
<span className="text-[10px] font-black text-slate-400 uppercase tracking-wider block">Place of Birth</span>
<span className="font-bold text-slate-800">{passportDoc.ocr_data?.place_of_birth || 'N/A'}</span>
<span className="font-bold text-slate-800">{safeRender(passportDoc.ocr_data?.place_of_birth)}</span>
</div>
<div>
<span className="text-[10px] font-black text-slate-400 uppercase tracking-wider block">Nationality</span>
<span className="font-bold text-slate-800">{passportDoc.ocr_data?.nationality || 'N/A'}</span>
<span className="font-bold text-slate-800">{safeRender(passportDoc.ocr_data?.nationality)}</span>
</div>
<div>
<span className="text-[10px] font-black text-slate-400 uppercase tracking-wider block">Issuing Country</span>
<span className="font-bold text-slate-800">{passportDoc.ocr_data?.issuing_country || 'N/A'}</span>
<span className="font-bold text-slate-800">{safeRender(passportDoc.ocr_data?.issuing_country)}</span>
</div>
<div>
<span className="text-[10px] font-black text-slate-400 uppercase tracking-wider block">Date of Issue</span>
<span className="font-bold text-slate-800">{passportDoc.ocr_data?.date_of_issue || passportDoc.issue_date || 'N/A'}</span>
<span className="font-bold text-slate-800">{safeRender(passportDoc.ocr_data?.date_of_issue || passportDoc.issue_date)}</span>
</div>
<div>
<span className="text-[10px] font-black text-slate-400 uppercase tracking-wider block">Date of Expiry</span>
<span className="font-bold text-slate-800">{passportDoc.ocr_data?.date_of_expiry || passportDoc.expiry_date || 'N/A'}</span>
<span className="font-bold text-slate-800">{safeRender(passportDoc.ocr_data?.date_of_expiry || passportDoc.expiry_date)}</span>
</div>
<div>
<span className="text-[10px] font-black text-slate-400 uppercase tracking-wider block">Authority</span>
<span className="font-bold text-slate-800">{passportDoc.ocr_data?.authority || 'N/A'}</span>
<span className="font-bold text-slate-800">{safeRender(passportDoc.ocr_data?.authority)}</span>
</div>
<div>
<span className="text-[10px] font-black text-slate-400 uppercase tracking-wider block">Document Type</span>
<span className="font-bold text-slate-800">{passportDoc.ocr_data?.document_type || 'N/A'}</span>
<span className="font-bold text-slate-800">{safeRender(passportDoc.ocr_data?.document_type)}</span>
</div>
<div>
<span className="text-[10px] font-black text-slate-400 uppercase tracking-wider block">Personal Number</span>
<span className="font-mono font-bold text-slate-800">{passportDoc.ocr_data?.personal_number || 'N/A'}</span>
<span className="font-mono font-bold text-slate-800">{safeRender(passportDoc.ocr_data?.personal_number)}</span>
</div>
</div>
{passportDoc.file_path && (
@ -835,89 +845,89 @@ export default function WorkerManagement({ workers }) {
<div className="grid grid-cols-2 gap-3 text-xs">
<div>
<span className="text-[10px] font-black text-slate-400 uppercase tracking-wider block">Entry Permit No</span>
<span className="font-mono font-bold text-slate-800">{visaDoc.ocr_data?.entry_permit_no || 'N/A'}</span>
<span className="font-mono font-bold text-slate-800">{safeRender(visaDoc.ocr_data?.entry_permit_no)}</span>
</div>
<div>
<span className="text-[10px] font-black text-slate-400 uppercase tracking-wider block">UID No</span>
<span className="font-mono font-bold text-slate-800">{visaDoc.ocr_data?.uid_no || 'N/A'}</span>
<span className="font-mono font-bold text-slate-800">{safeRender(visaDoc.ocr_data?.uid_no)}</span>
</div>
<div>
<span className="text-[10px] font-black text-slate-400 uppercase tracking-wider block">File Number</span>
<span className="font-mono font-bold text-slate-800">{visaDoc.ocr_data?.file_number || visaDoc.number || 'N/A'}</span>
<span className="font-mono font-bold text-slate-800">{safeRender(visaDoc.ocr_data?.file_number || visaDoc.number)}</span>
</div>
<div>
<span className="text-[10px] font-black text-slate-400 uppercase tracking-wider block">ID Number</span>
<span className="font-mono font-bold text-slate-800">{visaDoc.ocr_data?.id_number || 'N/A'}</span>
<span className="font-mono font-bold text-slate-800">{safeRender(visaDoc.ocr_data?.id_number)}</span>
</div>
<div>
<span className="text-[10px] font-black text-slate-400 uppercase tracking-wider block">Full Name</span>
<span className="font-bold text-slate-800">{visaDoc.ocr_data?.full_name || 'N/A'}</span>
<span className="font-bold text-slate-800">{safeRender(visaDoc.ocr_data?.full_name)}</span>
</div>
<div>
<span className="text-[10px] font-black text-slate-400 uppercase tracking-wider block">Name</span>
<span className="font-bold text-slate-800">{visaDoc.ocr_data?.name || 'N/A'}</span>
<span className="font-bold text-slate-800">{safeRender(visaDoc.ocr_data?.name)}</span>
</div>
<div>
<span className="text-[10px] font-black text-slate-400 uppercase tracking-wider block">Visa Type</span>
<span className="font-bold text-slate-800">{visaDoc.ocr_data?.visa_type || 'N/A'}</span>
<span className="font-bold text-slate-800">{safeRender(visaDoc.ocr_data?.visa_type)}</span>
</div>
<div>
<span className="text-[10px] font-black text-slate-400 uppercase tracking-wider block">Profession</span>
<span className="font-bold text-slate-800">{visaDoc.ocr_data?.profession || 'N/A'}</span>
<span className="font-bold text-slate-800">{safeRender(visaDoc.ocr_data?.profession)}</span>
</div>
<div>
<span className="text-[10px] font-black text-slate-400 uppercase tracking-wider block">Sponsor Name</span>
<span className="font-bold text-slate-800">{visaDoc.ocr_data?.sponsor_name || 'N/A'}</span>
<span className="font-bold text-slate-800">{safeRender(visaDoc.ocr_data?.sponsor_name)}</span>
</div>
<div>
<span className="text-[10px] font-black text-slate-400 uppercase tracking-wider block">Nationality</span>
<span className="font-bold text-slate-800">{visaDoc.ocr_data?.nationality || 'N/A'}</span>
<span className="font-bold text-slate-800">{safeRender(visaDoc.ocr_data?.nationality)}</span>
</div>
<div>
<span className="text-[10px] font-black text-slate-400 uppercase tracking-wider block">Country</span>
<span className="font-bold text-slate-800">{visaDoc.ocr_data?.country || 'N/A'}</span>
<span className="font-bold text-slate-800">{safeRender(visaDoc.ocr_data?.country)}</span>
</div>
<div>
<span className="text-[10px] font-black text-slate-400 uppercase tracking-wider block">Passport No</span>
<span className="font-mono font-bold text-slate-800">{visaDoc.ocr_data?.passport_no || 'N/A'}</span>
<span className="font-mono font-bold text-slate-800">{safeRender(visaDoc.ocr_data?.passport_no)}</span>
</div>
<div>
<span className="text-[10px] font-black text-slate-400 uppercase tracking-wider block">Passport Number</span>
<span className="font-mono font-bold text-slate-800">{visaDoc.ocr_data?.passport_number || 'N/A'}</span>
<span className="font-mono font-bold text-slate-800">{safeRender(visaDoc.ocr_data?.passport_number)}</span>
</div>
<div>
<span className="text-[10px] font-black text-slate-400 uppercase tracking-wider block">Date of Birth</span>
<span className="font-bold text-slate-800">{visaDoc.ocr_data?.date_of_birth || 'N/A'}</span>
<span className="font-bold text-slate-800">{safeRender(visaDoc.ocr_data?.date_of_birth)}</span>
</div>
<div>
<span className="text-[10px] font-black text-slate-400 uppercase tracking-wider block">Place of Birth</span>
<span className="font-bold text-slate-800">{visaDoc.ocr_data?.place_of_birth || 'N/A'}</span>
<span className="font-bold text-slate-800">{safeRender(visaDoc.ocr_data?.place_of_birth)}</span>
</div>
<div>
<span className="text-[10px] font-black text-slate-400 uppercase tracking-wider block">Place of Issue</span>
<span className="font-bold text-slate-800">{visaDoc.ocr_data?.place_of_issue || 'N/A'}</span>
<span className="font-bold text-slate-800">{safeRender(visaDoc.ocr_data?.place_of_issue)}</span>
</div>
<div>
<span className="text-[10px] font-black text-slate-400 uppercase tracking-wider block">Issue Date</span>
<span className="font-bold text-slate-800">{visaDoc.ocr_data?.issue_date || visaDoc.issue_date || 'N/A'}</span>
<span className="font-bold text-slate-800">{safeRender(visaDoc.ocr_data?.issue_date || visaDoc.issue_date)}</span>
</div>
<div>
<span className="text-[10px] font-black text-slate-400 uppercase tracking-wider block">Expiry Date</span>
<span className="font-bold text-slate-800">{visaDoc.ocr_data?.expiry_date || visaDoc.expiry_date || 'N/A'}</span>
<span className="font-bold text-slate-800">{safeRender(visaDoc.ocr_data?.expiry_date || visaDoc.expiry_date)}</span>
</div>
<div>
<span className="text-[10px] font-black text-slate-400 uppercase tracking-wider block">Accompanied By</span>
<span className="font-bold text-slate-800">{visaDoc.ocr_data?.accompanied_by || 'N/A'}</span>
<span className="font-bold text-slate-800">{safeRender(visaDoc.ocr_data?.accompanied_by)}</span>
</div>
<div>
<span className="text-[10px] font-black text-slate-400 uppercase tracking-wider block">Document Type</span>
<span className="font-bold text-slate-800">{visaDoc.ocr_data?.document_type || 'N/A'}</span>
<span className="font-bold text-slate-800">{safeRender(visaDoc.ocr_data?.document_type)}</span>
</div>
<div>
<span className="text-[10px] font-black text-slate-400 uppercase tracking-wider block">OCR Accuracy</span>
<span className="font-bold text-slate-800">{visaDoc.ocr_data?.ocr_accuracy || 'N/A'}</span>
<span className="font-bold text-slate-800">{safeRender(visaDoc.ocr_data?.ocr_accuracy)}</span>
</div>
</div>
{visaDoc.file_path && (

View File

@ -70,6 +70,16 @@ const getExpiryStatus = (expiryDate) => {
}
};
const safeRender = (value) => {
if (value === null || value === undefined) return 'N/A';
if (typeof value === 'object') {
if (value.name) return String(value.name);
if (value.full_name) return String(value.full_name);
return JSON.stringify(value);
}
return String(value);
};
export default function Show({ worker }) {
const { t } = useTranslation();
const passportDoc = worker.documents?.find(d => d.type === 'passport');
@ -442,39 +452,39 @@ export default function Show({ worker }) {
<div className="grid grid-cols-2 md:grid-cols-3 gap-y-4 gap-x-6">
<div>
<div className="text-[8px] font-black text-slate-400 uppercase tracking-tighter">{t('given_names', 'Given Names')}</div>
<div className="text-xs font-bold text-slate-800">{passportDoc.ocr_data.given_names || 'N/A'}</div>
<div className="text-xs font-bold text-slate-800">{safeRender(passportDoc.ocr_data.given_names)}</div>
</div>
<div>
<div className="text-[8px] font-black text-slate-400 uppercase tracking-tighter">{t('surname', 'Surname')}</div>
<div className="text-xs font-bold text-slate-800">{passportDoc.ocr_data.surname || 'N/A'}</div>
<div className="text-xs font-bold text-slate-800">{safeRender(passportDoc.ocr_data.surname)}</div>
</div>
<div>
<div className="text-[8px] font-black text-slate-400 uppercase tracking-tighter">{t('passport_number', 'Passport Number')}</div>
<div className="text-xs font-bold text-slate-800">{passportDoc.number}</div>
<div className="text-xs font-bold text-slate-800">{safeRender(passportDoc.ocr_data.passport_number || passportDoc.number)}</div>
</div>
<div>
<div className="text-[8px] font-black text-slate-400 uppercase tracking-tighter">{t('sex', 'Sex')}</div>
<div className="text-xs font-bold text-slate-800 uppercase">{passportDoc.ocr_data.sex || 'N/A'}</div>
<div className="text-xs font-bold text-slate-800 uppercase">{safeRender(passportDoc.ocr_data.sex)}</div>
</div>
<div>
<div className="text-[8px] font-black text-slate-400 uppercase tracking-tighter">{t('date_of_birth', 'Date of Birth')}</div>
<div className="text-xs font-bold text-slate-800">{passportDoc.ocr_data.date_of_birth || 'N/A'}</div>
<div className="text-xs font-bold text-slate-800">{safeRender(passportDoc.ocr_data.date_of_birth)}</div>
</div>
<div>
<div className="text-[8px] font-black text-slate-400 uppercase tracking-tighter">{t('place_of_birth', 'Place of Birth')}</div>
<div className="text-xs font-bold text-slate-800">{passportDoc.ocr_data.place_of_birth || 'N/A'}</div>
<div className="text-xs font-bold text-slate-800">{safeRender(passportDoc.ocr_data.place_of_birth)}</div>
</div>
<div>
<div className="text-[8px] font-black text-slate-400 uppercase tracking-tighter">{t('issue_date', 'Date of Issue')}</div>
<div className="text-xs font-bold text-slate-800">{passportDoc.issue_date || 'N/A'}</div>
<div className="text-xs font-bold text-slate-800">{safeRender(passportDoc.ocr_data.date_of_issue || passportDoc.issue_date)}</div>
</div>
<div>
<div className="text-[8px] font-black text-slate-400 uppercase tracking-tighter">{t('expiry_date', 'Date of Expiry')}</div>
<div className="text-xs font-bold text-emerald-600">{passportDoc.expiry_date || 'N/A'}</div>
<div className="text-xs font-bold text-emerald-600">{safeRender(passportDoc.ocr_data.date_of_expiry || passportDoc.expiry_date)}</div>
</div>
<div>
<div className="text-[8px] font-black text-slate-400 uppercase tracking-tighter">{t('issuing_country', 'Issuing Country')}</div>
<div className="text-xs font-bold text-slate-800">{passportDoc.ocr_data.issuing_country || 'N/A'}</div>
<div className="text-xs font-bold text-slate-800">{safeRender(passportDoc.ocr_data.issuing_country)}</div>
</div>
</div>
) : (
@ -558,39 +568,39 @@ export default function Show({ worker }) {
<div className="grid grid-cols-2 md:grid-cols-3 gap-y-4 gap-x-6">
<div>
<div className="text-[8px] font-black text-slate-400 uppercase tracking-tighter">{t('full_name', 'Full Name')}</div>
<div className="text-xs font-bold text-slate-800">{visaDoc.ocr_data.name || 'N/A'}</div>
<div className="text-xs font-bold text-slate-800">{safeRender(visaDoc.ocr_data.name)}</div>
</div>
<div>
<div className="text-[8px] font-black text-slate-400 uppercase tracking-tighter">{t('file_number', 'File Number')}</div>
<div className="text-xs font-bold text-slate-800">{visaDoc.number}</div>
<div className="text-xs font-bold text-slate-800">{safeRender(visaDoc.ocr_data.file_number || visaDoc.number)}</div>
</div>
<div>
<div className="text-[8px] font-black text-slate-400 uppercase tracking-tighter">{t('profession', 'Profession')}</div>
<div className="text-xs font-bold text-slate-800">{visaDoc.ocr_data.profession || worker.visa_status || 'N/A'}</div>
<div className="text-xs font-bold text-slate-800">{safeRender(visaDoc.ocr_data.profession || worker.visa_status)}</div>
</div>
<div>
<div className="text-[8px] font-black text-slate-400 uppercase tracking-tighter">{t('sponsor', 'Sponsor')}</div>
<div className="text-xs font-bold text-slate-800">{visaDoc.ocr_data.sponsor || 'N/A'}</div>
<div className="text-xs font-bold text-slate-800">{safeRender(visaDoc.ocr_data.sponsor || visaDoc.ocr_data.sponsor_name)}</div>
</div>
<div>
<div className="text-[8px] font-black text-slate-400 uppercase tracking-tighter">{t('passport_number', 'Passport Number')}</div>
<div className="text-xs font-bold text-slate-800">{visaDoc.ocr_data.passport_number || 'N/A'}</div>
<div className="text-xs font-bold text-slate-800">{safeRender(visaDoc.ocr_data.passport_number)}</div>
</div>
<div>
<div className="text-[8px] font-black text-slate-400 uppercase tracking-tighter">{t('place_of_issue', 'Place of Issue')}</div>
<div className="text-xs font-bold text-slate-800">{visaDoc.ocr_data.place_of_issue || 'N/A'}</div>
<div className="text-xs font-bold text-slate-800">{safeRender(visaDoc.ocr_data.place_of_issue)}</div>
</div>
<div>
<div className="text-[8px] font-black text-slate-400 uppercase tracking-tighter">{t('issue_date', 'Date of Issue')}</div>
<div className="text-xs font-bold text-slate-800">{visaDoc.issue_date || 'N/A'}</div>
<div className="text-xs font-bold text-slate-800">{safeRender(visaDoc.ocr_data.issue_date || visaDoc.issue_date)}</div>
</div>
<div>
<div className="text-[8px] font-black text-slate-400 uppercase tracking-tighter">{t('expiry_date', 'Date of Expiry')}</div>
<div className="text-xs font-bold text-emerald-600">{visaDoc.expiry_date || 'N/A'}</div>
<div className="text-xs font-bold text-emerald-600">{safeRender(visaDoc.ocr_data.expiry_date || visaDoc.expiry_date)}</div>
</div>
<div>
<div className="text-[8px] font-black text-slate-400 uppercase tracking-tighter">{t('accompanied_by', 'Accompanied By')}</div>
<div className="text-xs font-bold text-slate-800">{visaDoc.ocr_data.accompanied_by || 'N/A'}</div>
<div className="text-xs font-bold text-slate-800">{safeRender(visaDoc.ocr_data.accompanied_by)}</div>
</div>
</div>
) : (