diff --git a/database/seeders/DatabaseSeeder.php b/database/seeders/DatabaseSeeder.php index 4607c0e..eb2979c 100644 --- a/database/seeders/DatabaseSeeder.php +++ b/database/seeders/DatabaseSeeder.php @@ -49,8 +49,8 @@ public function run(): void 'sender_id' => 2, 'text' => 'Hello, are you available for an interview?', 'created_at' => now(), - 'updated_at' => now(), ], + 'updated_at' => now(), [ 'conversation_id' => $conversationId, 'sender_type' => 'worker', diff --git a/resources/js/Layouts/EmployerLayout.jsx b/resources/js/Layouts/EmployerLayout.jsx index fc393f6..ffbf206 100644 --- a/resources/js/Layouts/EmployerLayout.jsx +++ b/resources/js/Layouts/EmployerLayout.jsx @@ -26,10 +26,12 @@ import { DropdownMenuLabel, DropdownMenuSeparator } from '@/components/ui/dropdown-menu'; +import { useTranslation, languages } from '../lib/LanguageContext'; export default function EmployerLayout({ children, title, fullPage = false }) { const { url, props } = usePage(); const { auth, unread_messages_count, flash } = props; + const { locale, setLocale, t } = useTranslation(); useEffect(() => { if (flash?.success) { @@ -40,12 +42,12 @@ export default function EmployerLayout({ children, title, fullPage = false }) { } if (flash?.first_login) { // Elegant first login celebratory alert - toast.success('🎉 Welcome to Marketplace!', { - description: 'Your employer profile is verified and active with 30 days of Premium Access.', + toast.success(`🎉 ${t('welcome_title', 'Welcome to Marketplace!')}`, { + description: t('welcome_desc', 'Your employer profile is verified and active with 30 days of Premium Access.'), duration: 6000, }); } - }, [flash]); + }, [flash, t]); const user = auth?.user || { name: 'Guest', @@ -58,22 +60,22 @@ export default function EmployerLayout({ children, title, fullPage = false }) { const isSubActive = user.subscription_status === 'active'; const navItems = [ - { name: 'Dashboard', href: '/employer/dashboard', icon: LayoutDashboard }, - { name: 'Find Workers', href: '/employer/workers', icon: Search }, - { name: 'Shortlist', href: '/employer/shortlist', icon: Bookmark }, - { name: 'Candidates', href: '/employer/candidates', icon: UserCheck }, - { name: 'Messages', href: '/employer/messages', icon: MessageSquare, badge: unread_messages_count }, - { name: 'Charity Events', href: '/employer/announcements', icon: Heart }, - { name: 'Subscription', href: '/employer/subscription', icon: CreditCard }, - { name: 'My Profile', href: '/employer/profile', icon: User }, + { name: 'Dashboard', translationKey: 'dashboard', href: '/employer/dashboard', icon: LayoutDashboard }, + { name: 'Find Workers', translationKey: 'find_workers', href: '/employer/workers', icon: Search }, + { name: 'Shortlist', translationKey: 'shortlist', href: '/employer/shortlist', icon: Bookmark }, + { name: 'Candidates', translationKey: 'candidates', href: '/employer/candidates', icon: UserCheck }, + { name: 'Messages', translationKey: 'messages', href: '/employer/messages', icon: MessageSquare, badge: unread_messages_count }, + { name: 'Charity Events', translationKey: 'charity_events', href: '/employer/announcements', icon: Heart }, + { name: 'Subscription', translationKey: 'subscription', href: '/employer/subscription', icon: CreditCard }, + { name: 'My Profile', translationKey: 'my_profile', href: '/employer/profile', icon: User }, ]; const mobileTabs = [ - { name: 'Search', href: '/employer/workers', icon: Search }, - { name: 'Shortlist', href: '/employer/shortlist', icon: Bookmark }, - { name: 'Candidates', href: '/employer/candidates', icon: UserCheck }, - { name: 'Messages', href: '/employer/messages', icon: MessageSquare, badge: unread_messages_count }, - { name: 'Profile', href: '/employer/profile', icon: User }, + { name: 'Search', translationKey: 'search', href: '/employer/workers', icon: Search }, + { name: 'Shortlist', translationKey: 'shortlist', href: '/employer/shortlist', icon: Bookmark }, + { name: 'Candidates', translationKey: 'candidates', href: '/employer/candidates', icon: UserCheck }, + { name: 'Messages', translationKey: 'messages', href: '/employer/messages', icon: MessageSquare, badge: unread_messages_count }, + { name: 'Profile', translationKey: 'profile', href: '/employer/profile', icon: User }, ]; return ( @@ -83,13 +85,13 @@ export default function EmployerLayout({ children, title, fullPage = false }) {
- You need an active subscription to contact workers. + {t('sub_warning', 'You need an active subscription to contact workers.')}
- Subscribe now + {t('subscribe_now', 'Subscribe now')}
@@ -102,7 +104,7 @@ export default function EmployerLayout({ children, title, fullPage = false }) {
M
- Employer Portal + {t('employer_portal', 'Employer Portal')}
@@ -130,7 +132,7 @@ export default function EmployerLayout({ children, title, fullPage = false }) {
M
- Employer Portal + {t('employer_portal', 'Employer Portal')}
{/* Subscription Status Pill */} @@ -139,14 +141,14 @@ export default function EmployerLayout({ children, title, fullPage = false }) {
- Active until {user.subscription_expires_at || 'Dec 31'} + {t('active_until', 'Active until')} {user.subscription_expires_at || 'Dec 31'}
) : (
- Expired — Renew now + {t('expired_renew', 'Expired — Renew now')}
)} @@ -171,7 +173,7 @@ export default function EmployerLayout({ children, title, fullPage = false }) { >
- {item.name} + {t(item.translationKey, item.name)}
{item.badge > 0 && ( @@ -193,16 +195,48 @@ export default function EmployerLayout({ children, title, fullPage = false }) {
- {title || 'Overview'} + {title ? t(title.toLowerCase().replace(/\s+/g, '_'), title) : t('overview', 'Overview')}
- {/* Language Switcher */} -
- - -
+ {/* Language Switcher Dropdown */} + + + + + + Select Language + + {languages.map((lang) => ( + setLocale(lang.code)} + className={`flex items-center justify-between px-2.5 py-2 text-xs font-bold rounded-lg cursor-pointer transition-all ${ + locale === lang.code + ? 'bg-[#185FA5]/10 text-[#185FA5] font-black' + : 'text-slate-600 hover:bg-slate-50 hover:text-slate-900' + }`} + > +
+ {lang.flag} + {lang.nativeName} +
+ {locale === lang.code && ( +
+ )} + + ))} + + {/* Chat/Notifications */} @@ -216,7 +250,7 @@ export default function EmployerLayout({ children, title, fullPage = false }) { - My Account + {t('my_account', 'My Account')} - Profile Settings + {t('profile_settings', 'Profile Settings')} - Subscription + {t('subscription', 'Subscription')} @@ -247,7 +281,7 @@ export default function EmployerLayout({ children, title, fullPage = false }) { className="w-full flex items-center space-x-2 text-xs font-bold text-rose-600 cursor-pointer" > - Sign Out + {t('sign_out', 'Sign Out')} @@ -258,7 +292,9 @@ export default function EmployerLayout({ children, title, fullPage = false }) {
{title && !fullPage && ( -

{title}

+

+ {title ? t(title.toLowerCase().replace(/\s+/g, '_'), title) : ''} +

)} {children}
@@ -288,7 +324,7 @@ export default function EmployerLayout({ children, title, fullPage = false }) { )}
- {tab.name} + {t(tab.translationKey, tab.name)} ); })} diff --git a/resources/js/Pages/Employer/Announcements.jsx b/resources/js/Pages/Employer/Announcements.jsx index 5965bad..42f50be 100644 --- a/resources/js/Pages/Employer/Announcements.jsx +++ b/resources/js/Pages/Employer/Announcements.jsx @@ -1,6 +1,7 @@ import React, { useState, useEffect } from 'react'; import { Head, useForm } from '@inertiajs/react'; import EmployerLayout from '../../Layouts/EmployerLayout'; +import { useTranslation } from '../../lib/LanguageContext'; import { Megaphone, Send, @@ -30,6 +31,7 @@ import { } from '@/components/ui/dialog'; export default function Announcements({ initialAnnouncements }) { + const { t } = useTranslation(); const [isDialogOpen, setIsDialogOpen] = useState(false); const [searchTerm, setSearchTerm] = useState(''); const [toastMessage, setToastMessage] = useState(null); @@ -69,8 +71,8 @@ export default function Announcements({ initialAnnouncements }) { reset(); setIsDialogOpen(false); showToast( - '💖 COMMUNITY CHARITY EVENT POSTED!', - '🔔 Instant Push Notification sent to all workers in Dubai! ⏰ Morning-of reminder notification scheduled successfully.' + t('community_charity_event_posted', 'COMMUNITY CHARITY EVENT POSTED!'), + t('community_charity_event_posted_desc', 'Instant Push Notification sent to all workers in Dubai! Morning-of reminder notification scheduled successfully.') ); } }); @@ -82,8 +84,8 @@ export default function Announcements({ initialAnnouncements }) { ); return ( - - + + {toastMessage && (
@@ -92,7 +94,7 @@ export default function Announcements({ initialAnnouncements }) {
{toastMessage}
- {toastSub &&

{toastSub}

} + {toastSub &&

{toastSub}

}
)} @@ -104,11 +106,11 @@ export default function Announcements({ initialAnnouncements }) {
- Dubai Community Support Drives + {t('dubai_community_support_drives', 'Dubai Community Support Drives')}
-

Free Medical Checks, Food Drives & Support Services

+

{t('free_medical_checks_title', 'Free Medical Checks, Food Drives & Support Services')}

- Organizing a support program? Share community campaigns directly. The platform will automatically push an **instant pop-up notification** to workers, followed by a **morning-of event reminder** to keep attendance strong. + {t('free_medical_checks_desc', 'Organizing a support program? Share community campaigns directly. The platform will automatically push an instant pop-up notification to workers, followed by a morning-of event reminder to keep attendance strong.')}

@@ -118,7 +120,7 @@ export default function Announcements({ initialAnnouncements }) { setSearchTerm(e.target.value)} className="w-full pl-12 pr-4 py-3 bg-slate-50 border-none rounded-2xl text-sm font-bold focus:ring-2 focus:ring-blue-100 transition-all outline-none" @@ -129,15 +131,15 @@ export default function Announcements({ initialAnnouncements }) {
- Post Charity Event + {t('post_charity_event', 'Post Charity Event')} - Broadcast a support program, medical camp, or distribution drive to the worker community. + {t('broadcast_support_program_desc', 'Broadcast a support program, medical camp, or distribution drive to the worker community.')}
@@ -146,12 +148,12 @@ export default function Announcements({ initialAnnouncements }) {
- Charity Drive Metadata (Dubai Support) + {t('charity_drive_metadata', 'Charity Drive Metadata (Dubai Support)')}
- +
- + setNewAnnouncement({ ...newAnnouncement, event_time: e.target.value })} className="w-full px-3 py-2 bg-white border border-slate-200 rounded-xl text-xs font-bold focus:ring-2 focus:ring-rose-100 outline-none" @@ -174,11 +176,11 @@ export default function Announcements({ initialAnnouncements }) {
- + setNewAnnouncement({ ...newAnnouncement, provided_items: e.target.value })} className="w-full px-3.5 py-2.5 bg-white border border-slate-200 rounded-xl text-xs font-bold focus:ring-2 focus:ring-rose-100 outline-none" @@ -186,11 +188,11 @@ export default function Announcements({ initialAnnouncements }) {
- + setNewAnnouncement({ ...newAnnouncement, location_details: e.target.value })} className="w-full px-3.5 py-2.5 bg-white border border-slate-200 rounded-xl text-xs font-bold focus:ring-2 focus:ring-rose-100 outline-none mb-2" @@ -198,7 +200,7 @@ export default function Announcements({ initialAnnouncements }) { setNewAnnouncement({ ...newAnnouncement, location_pin: e.target.value })} className="w-full px-3.5 py-2.5 bg-white border border-slate-200 rounded-xl text-xs font-bold focus:ring-2 focus:ring-rose-100 outline-none" @@ -207,26 +209,26 @@ export default function Announcements({ initialAnnouncements }) {
- + setNewAnnouncement({ ...newAnnouncement, title: e.target.value })} className="w-full px-5 py-3.5 bg-slate-50 border-none rounded-2xl text-sm font-bold focus:ring-2 focus:ring-blue-100 transition-all outline-none" - placeholder="e.g. Free Dental checkup by Emirates Charity" + placeholder={t('title_placeholder', 'e.g. Free Dental checkup by Emirates Charity')} />
- +
@@ -237,7 +239,7 @@ export default function Announcements({ initialAnnouncements }) { className="w-full bg-rose-600 hover:bg-rose-700 text-white py-4 rounded-2xl text-xs font-black uppercase tracking-widest flex items-center justify-center space-x-2 transition-all shadow-lg shadow-rose-200/50" > - Publish Charity Event + {t('publish_charity_event', 'Publish Charity Event')} @@ -251,8 +253,8 @@ export default function Announcements({ initialAnnouncements }) {
-

No announcements

-

You haven't posted any announcements yet

+

{t('no_announcements_title', 'No Announcements')}

+

{t('no_announcements_desc', "You haven't posted any announcements yet")}

) : ( filteredAnnouncements.map((ann) => { @@ -269,7 +271,7 @@ export default function Announcements({ initialAnnouncements }) {
- COMMUNITY CHARITY DRIVE + {t('community_charity_drive', 'COMMUNITY CHARITY DRIVE')}
@@ -279,7 +281,7 @@ export default function Announcements({ initialAnnouncements }) {
- Push & Reminder Scheduled + {t('push_reminder_scheduled', 'Push & Reminder Scheduled')}
@@ -298,7 +300,7 @@ export default function Announcements({ initialAnnouncements }) {
-
Provided Packages
+
{t('provided_packages', 'Provided Packages')}
{details.provided_items}
@@ -308,7 +310,7 @@ export default function Announcements({ initialAnnouncements }) {
-
Event Timing
+
{t('event_timing', 'Event Timing')}
{details.event_date} • {details.event_time}
@@ -321,7 +323,7 @@ export default function Announcements({ initialAnnouncements }) {
-
Event Location Address
+
{t('event_location_address', 'Event Location Address')}
{details.location_details}
{details.location_pin && ( @@ -332,7 +334,7 @@ export default function Announcements({ initialAnnouncements }) { className="px-3.5 py-2 bg-rose-600 hover:bg-rose-700 text-white rounded-xl text-[10px] font-black uppercase tracking-wider flex items-center space-x-1 w-fit transition-colors shrink-0 shadow-sm" > - View Map Location Pin + {t('view_map_location_pin', 'View Map Location Pin')} )}
diff --git a/resources/js/Pages/Employer/Dashboard.jsx b/resources/js/Pages/Employer/Dashboard.jsx index 2d1244e..58907f9 100644 --- a/resources/js/Pages/Employer/Dashboard.jsx +++ b/resources/js/Pages/Employer/Dashboard.jsx @@ -1,6 +1,7 @@ import React from 'react'; import { Head, Link } from '@inertiajs/react'; import EmployerLayout from '../../Layouts/EmployerLayout'; +import { useTranslation } from '../../lib/LanguageContext'; import { Bookmark, MessageSquare, @@ -38,10 +39,11 @@ export default function Dashboard({ }) { const isSubActive = employer.subscription_status === 'active'; const isExpiringSoon = stats.days_remaining <= 7; + const { t } = useTranslation(); return ( - - + +
{/* 1. Alerts & Warning Banners */} @@ -52,15 +54,15 @@ export default function Dashboard({
-

Your Sponsor Subscription Pass Has Expired!

-

Direct communication, candidate dossiers, and messaging are locked. Renew your annual sponsor subscription now to resume hiring.

+

{t('expired_pass_title', 'Your Sponsor Subscription Pass Has Expired!')}

+

{t('expired_pass_desc', 'Direct communication, candidate dossiers, and messaging are locked. Renew your annual sponsor subscription now to resume hiring.')}

- Renew Subscription + {t('renew_sub', 'Renew Subscription')} @@ -73,15 +75,17 @@ export default function Dashboard({
-

Your Premium Sponsor Pass is expiring soon!

-

Only {stats.days_remaining} days left. Renew now to avoid losing contact access to 500+ verified candidates.

+

{t('expiring_pass_title', 'Your Premium Sponsor Pass is expiring soon!')}

+

+ {t('expiring_pass_desc', 'Only {days} days left. Renew now to avoid losing contact access to 500+ verified candidates.').replace('{days}', stats.days_remaining)} +

- Renew Now + {t('renew_now', 'Renew Now')} @@ -95,17 +99,17 @@ export default function Dashboard({
- Subscription Status: {employer.subscription_status} + {t('sub_status', 'Subscription Status')}: {employer.subscription_status} | - {stats.days_remaining} Days Left + {stats.days_remaining} {t('days_left', 'Days Left')}

- Welcome Back, {employer.name} + {t('welcome_back', 'Welcome Back')}, {employer.name}

- Hire direct, MOHRE-compliant domestic workers with zero middleman commissions. Browse our updated database of candidates with OCR passport checks. + {t('welcome_desc_dash', 'Hire direct, MOHRE-compliant domestic workers with zero middleman commissions. Browse our updated database of candidates with OCR passport checks.')}

@@ -115,7 +119,7 @@ export default function Dashboard({ className="bg-white text-[#185FA5] hover:bg-slate-100 px-6 py-3.5 rounded-xl font-bold text-xs shadow-md transition-all flex items-center justify-center space-x-2 group" > - Browse 500+ Verified Workers + {t('browse_workers', 'Browse 500+ Verified Workers')} @@ -134,12 +138,12 @@ export default function Dashboard({
-
Sponsor Pass Tier
+
{t('sponsor_pass_tier', 'Sponsor Pass Tier')}
{employer.plan_name}
-
Renews: {employer.subscription_expires_at}
+
{t('renews', 'Renews')}: {employer.subscription_expires_at}
- Manage billing & invoices + {t('manage_billing', 'Manage billing & invoices')} @@ -155,12 +159,12 @@ export default function Dashboard({
-
Pending Job Offers
+
{t('pending_job_offers', 'Pending Job Offers')}
{stats.pending_offers}
-
Direct recruitment proposals
+
{t('direct_recruitment', 'Direct recruitment proposals')}
- View hiring workflow + {t('view_hiring', 'View hiring workflow')} @@ -176,12 +180,12 @@ export default function Dashboard({
-
Total Hired Workers
+
{t('total_hired_workers', 'Total Hired Workers')}
{stats.hired_count}
-
Direct contracts initiated
+
{t('direct_contracts', 'Direct contracts initiated')}
- Track active staff + {t('track_active_staff', 'Track active staff')} @@ -197,12 +201,12 @@ export default function Dashboard({
-
Shortlisted Candidates
+
{t('shortlisted_candidates', 'Shortlisted Candidates')}
{stats.shortlisted_count}
-
Bookmark list for interviews
+
{t('bookmark_list', 'Bookmark list for interviews')}
- Open shortlist book + {t('open_shortlist', 'Open shortlist book')} @@ -215,45 +219,45 @@ export default function Dashboard({
-

Discover Insights & Market Stats

+

{t('discover_insights', 'Discover Insights & Market Stats')}

{/* Dubai General Market Stats */}
-
Dubai General Market Insights
+
{t('dubai_insights', 'Dubai General Market Insights')}
1,284
-
Hired using app in Dubai
+
{t('hired_dubai', 'Hired using app in Dubai')}
-
Cooking, Care, Driving
-
Top Skills Hired
+
{t('cooking_care', 'Cooking, Care, Driving')}
+
{t('top_skills', 'Top Skills Hired')}
1.4%
-
Turnover rate
+
{t('turnover_rate', 'Turnover rate')}
{/* Your own activity */}
-
Your Sponsor Activity Stats
+
{t('sponsor_activity', 'Your Sponsor Activity Stats')}
14
-
Workers Contacted
+
{t('workers_contacted', 'Workers Contacted')}
{stats.shortlisted_count}
-
Shortlisted
+
{t('shortlist', 'Shortlist')}
{stats.hired_count}
-
Secure Hires
+
{t('secure_hires', 'Secure Hires')}
@@ -263,8 +267,8 @@ export default function Dashboard({ {/* Quick Actions Panel (Col 4) */}
-

Quick Actions

-

Speed up your sponsorship process.

+

{t('quick_actions', 'Quick Actions')}

+

{t('speed_up', 'Speed up your sponsorship process.')}

@@ -276,8 +280,8 @@ export default function Dashboard({
-
Find Baby Care & Nannies
-
Browse premium verified nannies
+
{t('find_nannies', 'Find Baby Care & Nannies')}
+
{t('browse_nannies', 'Browse premium verified nannies')}
@@ -292,17 +296,17 @@ export default function Dashboard({
- Direct WhatsApp Support + {t('whatsapp_support', 'Direct WhatsApp Support')}
-
Chat with a recruitment manager
+
{t('chat_manager', 'Chat with a recruitment manager')}
- 100% Legal UAE Agency-Free Platform + {t('legal_platform', '100% Legal UAE Agency-Free Platform')}
@@ -316,10 +320,10 @@ export default function Dashboard({
-

Recommended for You

+

{t('recommended_for_you', 'Recommended for You')}

- Browse all + {t('browse_all', 'Browse all')}
@@ -364,14 +368,14 @@ export default function Dashboard({ href={`/employer/workers/${worker.id}`} className="px-3 py-1.5 bg-[#185FA5] hover:bg-[#144f8a] text-white text-[10px] font-black rounded-lg transition-colors shadow-xs" > - View Profile + {t('view_profile', 'View Profile')} )) ) : (
- No workers currently recommended. Update profile details. + {t('no_recommended', 'No workers currently recommended. Update profile details.')}
)} @@ -382,10 +386,10 @@ export default function Dashboard({
-

Active Shortlist ({shortlisted_workers.length})

+

{t('active_shortlist', 'Active Shortlist')} ({shortlisted_workers.length})

- View book + {t('view_book', 'View book')}
@@ -408,14 +412,14 @@ export default function Dashboard({
-
Category:
+
{t('category', 'Category')}:
{worker.category || 'General Helper'}
- AVAILABILITY: + {t('availability', 'Availability')}: {worker.availability} @@ -425,7 +429,7 @@ export default function Dashboard({ href={`/employer/workers/${worker.id}`} className="w-full mt-2 bg-white hover:bg-slate-50 text-[#185FA5] border border-slate-200 text-center rounded-lg py-1.5 text-[10px] font-black flex items-center justify-center transition-colors" > - Open Profile + {t('open_profile', 'Open Profile')}
))} @@ -433,7 +437,7 @@ export default function Dashboard({ ) : (
-
Shortlist candidates to compare their documents side-by-side
+
{t('shortlist_candidates_desc', 'Shortlist candidates to compare their documents side-by-side')}
)} @@ -443,10 +447,10 @@ export default function Dashboard({
-

Recent Chats

+

{t('recent_chats', 'Recent Chats')}

- All channels + {t('all_channels', 'All channels')}
@@ -482,7 +486,7 @@ export default function Dashboard({ )) ) : (
- No recent chat logs found. Find workers to start conversing. + {t('no_chats', 'No recent chat logs found. Find workers to start conversing.')}
)} @@ -496,10 +500,10 @@ export default function Dashboard({
-

Community Charity Drives

+

{t('charity_drives', 'Community Charity Drives')}

- Live Events + {t('live_events', 'Live Events')}
@@ -507,7 +511,7 @@ export default function Dashboard({ {announcements?.map((ann) => (
- ❤️ Charity Drive + ❤️ {t('charity_drive', 'Charity Drive')} {ann.created_at}
@@ -519,11 +523,11 @@ export default function Dashboard({
🎁 - {ann.provided_items} + {t('provided_items', 'Provided Items')}: {ann.provided_items}
📅 - {ann.event_date} + {t('event_date', 'Event Date')}: {ann.event_date}
@@ -534,7 +538,7 @@ export default function Dashboard({ rel="noopener noreferrer" className="w-full bg-white hover:bg-rose-50 text-rose-600 border border-rose-200 text-center rounded-lg py-1.5 text-[10px] font-black flex items-center justify-center space-x-1 transition-colors" > - 📍 Open Google Maps Location Pin + 📍 {t('open_maps', 'Open Google Maps Location Pin')} )}
@@ -549,9 +553,9 @@ export default function Dashboard({
-

UAE Tadbeer & MOHRE Compliant

+

{t('mohre_compliant', 'UAE Tadbeer & MOHRE Compliant')}

- Our direct contract system aligns automatically with the Ministry of Human Resources and Emiratisation guidelines. Fully legal, zero agent fees, complete transparency. + {t('mohre_desc', 'Our direct contract system aligns automatically with the Ministry of Human Resources and Emiratisation guidelines. Fully legal, zero agent fees, complete transparency.')}

@@ -561,7 +565,7 @@ export default function Dashboard({ rel="noreferrer" className="text-xs font-bold text-emerald-400 hover:text-emerald-300 flex items-center space-x-1" > - Visit MOHRE UAE website + {t('visit_mohre', 'Visit MOHRE UAE website')}
diff --git a/resources/js/Pages/Employer/Messages/Index.jsx b/resources/js/Pages/Employer/Messages/Index.jsx index 6eda9e9..5b5826f 100644 --- a/resources/js/Pages/Employer/Messages/Index.jsx +++ b/resources/js/Pages/Employer/Messages/Index.jsx @@ -2,11 +2,14 @@ import React from 'react'; import { Head, Link } from '@inertiajs/react'; import EmployerLayout from '../../../Layouts/EmployerLayout'; import { MessageSquare, CheckCircle2, ChevronRight, Search, Plus } from 'lucide-react'; +import { useTranslation } from '../../../lib/LanguageContext'; export default function Index({ conversations }) { + const { t } = useTranslation(); + return ( - - + +
{/* Header Actions */} @@ -15,7 +18,7 @@ export default function Index({ conversations }) {
@@ -24,7 +27,7 @@ export default function Index({ conversations }) { className="bg-white hover:bg-slate-50 border border-slate-200 text-[#185FA5] px-4 py-2.5 rounded-2xl text-sm font-bold shadow-sm transition-all flex items-center justify-center space-x-2 whitespace-nowrap" > - New Conversation + {t('new_conversation', 'New Conversation')} @@ -32,10 +35,10 @@ export default function Index({ conversations }) {
-

Active Threads

+

{t('active_threads', 'Active Threads')}

- {conversations?.length || 0} Total + {t('total_count', '{count} Total').replace('{count}', conversations?.length || 0)}
@@ -96,15 +99,15 @@ export default function Index({ conversations }) {
-
No active messages
+
{t('no_active_messages', 'No active messages')}

- When you message workers or schedule interviews, your conversation threads will appear here. + {t('no_active_messages_desc', 'When you message workers or schedule interviews, your conversation threads will appear here.')}

- Find Workers + {t('find_workers', 'Find Workers')} )} diff --git a/resources/js/Pages/Employer/Messages/Show.jsx b/resources/js/Pages/Employer/Messages/Show.jsx index 63910c1..28cf270 100644 --- a/resources/js/Pages/Employer/Messages/Show.jsx +++ b/resources/js/Pages/Employer/Messages/Show.jsx @@ -1,6 +1,7 @@ import React, { useState, useEffect, useRef } from 'react'; import { Head, Link, router } from '@inertiajs/react'; import EmployerLayout from '../../../Layouts/EmployerLayout'; +import { useTranslation } from '../../../lib/LanguageContext'; import { Send, ArrowLeft, @@ -29,6 +30,7 @@ import { import { toast } from 'sonner'; export default function Show({ conversation, initialMessages, conversations = [] }) { + const { t } = useTranslation(); const [messages, setMessages] = useState(initialMessages || []); const [input, setInput] = useState(''); const [isTyping, setIsTyping] = useState(false); @@ -69,7 +71,7 @@ export default function Show({ conversation, initialMessages, conversations = [] id: Date.now(), sender: 'employer', text: text, - time: 'Just Now', + time: t('just_now', 'Just Now'), read: false }; setMessages(prev => [...prev, newMsg]); @@ -81,8 +83,8 @@ export default function Show({ conversation, initialMessages, conversations = [] preserveScroll: true, onSuccess: () => { // Show immediate confirmation of the push alert popping up on worker mobile app - toast.success(`🔔 Direct Mobile Push Notification sent!`, { - description: `Popped up instantly on ${conversation.worker_name}'s mobile device.`, + toast.success(t('direct_push_sent', 'Direct Mobile Push Notification sent!'), { + description: t('popped_up_instantly_desc', "Popped up instantly on {name}'s mobile device.").replace('{name}', conversation.worker_name), duration: 4500, }); @@ -94,13 +96,13 @@ export default function Show({ conversation, initialMessages, conversations = [] const autoReply = { id: Date.now() + 1, sender: 'worker', - text: "Thank you for your response! I have reviewed your offer proposal and am looking forward to our video interview.", - time: 'Just Now' + text: t('auto_reply_text', "Thank you for your response! I have reviewed your offer proposal and am looking forward to our video interview."), + time: t('just_now', 'Just Now') }; setMessages(prev => [...prev, autoReply]); // Pop up a clear message received notification for the sponsor - toast.info(`✉️ New message from ${conversation.worker_name}!`, { + toast.info(t('new_message_from', 'New message from {name}!').replace('{name}', conversation.worker_name), { description: autoReply.text, duration: 5000 }); @@ -122,41 +124,41 @@ export default function Show({ conversation, initialMessages, conversations = [] const newFile = { name: file.name, size: (file.size / 1024).toFixed(1) + ' KB', - date: 'Today' + date: t('today', 'Today') }; setUploadedFiles([...uploadedFiles, newFile]); - toast.success("📎 Document attached successfully!"); + toast.success(t('document_attached', 'Document attached successfully!')); setShowAttachmentModal(false); // Optimistically insert attachment message - sendMsg(`[Document Attached: ${file.name}]`); + sendMsg(`[${t('document_attached_msg', 'Document Attached')}: ${file.name}]`); }; const chips = [ - "Are you available for a video interview today?", - "What is your final expected salary?", - "Can you transfer your visa immediately?" + t('chip_interview', "Are you available for a video interview today?"), + t('chip_salary', "What is your final expected salary?"), + t('chip_visa', "Can you transfer your visa immediately?") ]; return ( - +
{/* Conversation List Sidebar (Desktop) */}
-
Compliance Profile
+
{t('compliance_profile', 'Compliance Profile')}
{[ - { label: 'Visa Transfer', value: 'Transferable', icon: Briefcase, color: 'text-blue-500' }, - { label: 'Medical Status', value: 'Cleared', icon: ShieldCheck, color: 'text-emerald-500' }, - { label: 'Passport OCR', value: 'Verified', icon: FileText, color: 'text-slate-500' } + { label: t('visa_transfer', 'Visa Transfer'), value: t('transferable', 'Transferable'), icon: Briefcase, color: 'text-blue-500' }, + { label: t('medical_status', 'Medical Status'), value: t('cleared', 'Cleared'), icon: ShieldCheck, color: 'text-emerald-500' }, + { label: t('passport_ocr', 'Passport OCR'), value: t('verified', 'Verified'), icon: FileText, color: 'text-slate-500' } ].map((item, i) => (
@@ -416,7 +418,7 @@ export default function Show({ conversation, initialMessages, conversations = [] className="w-full bg-[#185FA5] hover:bg-[#144f8a] text-white py-3 rounded-xl text-xs font-black uppercase tracking-widest flex items-center justify-center space-x-1.5 shadow-xs" > - Open Worker Profile + {t('open_worker_profile', 'Open Worker Profile')}
@@ -435,14 +437,14 @@ export default function Show({ conversation, initialMessages, conversations = [] -

Attach Verified Sponsor Documents

+

{t('attach_sponsor_documents', 'Attach Verified Sponsor Documents')}

- Upload sponsor papers, employment agreements, or work descriptions to review securely. + {t('attach_documents_desc', 'Upload sponsor papers, employment agreements, or work descriptions to review securely.')}

- -
Select files or drag here
+ +
{t('select_files_drag', 'Select files or drag here')}
PDF, JPG, PNG (Max 5MB)
setShowAttachmentModal(false)} className="px-4 py-2 border border-slate-200 hover:bg-slate-50 rounded-xl" > - Close + {t('close', 'Close')}
diff --git a/resources/js/Pages/Employer/Profile.jsx b/resources/js/Pages/Employer/Profile.jsx index ec4de0b..644af8b 100644 --- a/resources/js/Pages/Employer/Profile.jsx +++ b/resources/js/Pages/Employer/Profile.jsx @@ -1,6 +1,7 @@ import React, { useState } from 'react'; import { Head, useForm } from '@inertiajs/react'; import EmployerLayout from '../../Layouts/EmployerLayout'; +import { useTranslation } from '../../lib/LanguageContext'; import { User, CheckCircle2, @@ -24,6 +25,7 @@ import { import { toast } from 'sonner'; export default function Profile({ employerProfile }) { + const { t } = useTranslation(); const { data: profile, setData, post, processing, errors } = useForm({ name: employerProfile?.name || '', company_name: employerProfile?.company_name || '', @@ -51,34 +53,29 @@ export default function Profile({ employerProfile }) { preserveScroll: true, onSuccess: () => { setSaved(true); - toast.success("🛡️ Profile updated successfully", { - description: "Household sponsor preferences and vetted credentials synchronized successfully." + toast.success(`🛡️ ${t('profile_updated_successfully', 'Profile updated successfully')}`, { + description: t('profile_updated_successfully_desc', 'Household sponsor preferences and vetted credentials synchronized successfully.') }); setTimeout(() => setSaved(false), 3000); }, onError: (errs) => { - toast.error("Failed to update profile", { - description: Object.values(errs)[0] || "Please check the form fields." + toast.error(t('profile_update_failed', 'Failed to update profile'), { + description: Object.values(errs)[0] || t('check_form_fields', 'Please check the form fields.') }); } }); }; const tabs = [ - { id: 'personal', label: 'Personal', icon: User }, - { id: 'security', label: 'Security & Password', icon: Lock }, - { id: 'billing', label: 'Billing & Receipts', icon: CreditCard }, - { id: 'notifications', label: 'Notifications Hub', icon: Bell }, - ]; - - const pastHires = [ - { id: 1, name: 'Rhea Joy', category: 'Childcare / Nanny', nationality: 'Philippines', date: 'Jan 15, 2025', status: 'Active Contract' }, - { id: 2, name: 'Priya Sharma', category: 'Housekeeper', nationality: 'India', date: 'Jul 10, 2024', status: 'Completed / Expiry' } + { id: 'personal', label: t('tab_personal', 'Personal'), icon: User }, + { id: 'security', label: t('tab_security', 'Security & Password'), icon: Lock }, + { id: 'billing', label: t('tab_billing', 'Billing & Receipts'), icon: CreditCard }, + { id: 'notifications', label: t('tab_notifications', 'Notifications Hub'), icon: Bell }, ]; return ( - - + +
{/* Left Side: Navigation Tabs */} @@ -128,11 +125,11 @@ export default function Profile({ employerProfile }) {
- Emirates ID Vetted + {t('emirates_id_vetted', 'Emirates ID Vetted')} - Direct Sponsor Portal + {t('direct_sponsor_portal', 'Direct Sponsor Portal')}
@@ -145,13 +142,13 @@ export default function Profile({ employerProfile }) { {activeTab === 'personal' && (
-

Personal details

-

Manage sponsor bio and credentials

+

{t('personal_details_header', 'Personal details')}

+

{t('personal_details_desc', 'Manage sponsor bio and credentials')}

- +
- +
- +
- +
- +
- +
- +
-

Emirates ID Verification

-

Regulatory compliance credentials

+

{t('emirates_id_verification_header', 'Emirates ID Verification')}

+

{t('emirates_id_verification_desc', 'Regulatory compliance credentials')}

{employerProfile?.verification_status === 'approved' && employerProfile?.emirates_id_front && employerProfile?.emirates_id_back ? ( @@ -268,10 +265,10 @@ export default function Profile({ employerProfile }) {
-

Emirates ID Verified

-

Vetted under MOHRE Guidelines

+

{t('emirates_id_verified_status', 'Emirates ID Verified')}

+

{t('mohre_guidelines', 'Vetted under MOHRE Guidelines')}

- Your Emirates ID has been verified successfully. Your account is active for direct hiring. + {t('emirates_id_verified_desc', 'Your Emirates ID has been verified successfully. Your account is active for direct hiring.')}

@@ -281,10 +278,10 @@ export default function Profile({ employerProfile }) {
-

Verification Pending Audit

-

Audit Queue

+

{t('verification_pending_status', 'Verification Pending Audit')}

+

{t('audit_queue', 'Audit Queue')}

- Your Emirates ID document uploads are currently under review. Audits are typically completed within 24 hours. + {t('verification_pending_desc', 'Your Emirates ID document uploads are currently under review. Audits are typically completed within 24 hours.')}

@@ -294,10 +291,10 @@ export default function Profile({ employerProfile }) {
-

Emirates ID Verification Required

-

Action Needed

+

{t('verification_required_status', 'Emirates ID Verification Required')}

+

{t('action_needed', 'Action Needed')}

- Please upload high-resolution color scans of your Emirates ID to verify your identity and activate full hiring features. + {t('verification_required_desc', 'Please upload high-resolution color scans of your Emirates ID to verify your identity and activate full hiring features.')}

@@ -306,7 +303,7 @@ export default function Profile({ employerProfile }) { {/* File Upload Fields */}
- + setData('emirates_id_front', e.target.files[0])} @@ -316,7 +313,7 @@ export default function Profile({ employerProfile }) {
- + setData('emirates_id_back', e.target.files[0])} @@ -329,18 +326,18 @@ export default function Profile({ employerProfile }) { {/* Uploaded Documents Details */} {(employerProfile?.emirates_id_front || employerProfile?.emirates_id_back) && (
-

Uploaded Credentials Scans

+

{t('uploaded_credentials_scans', 'Uploaded Credentials Scans')}

{employerProfile?.emirates_id_front && (
-
+
ID -
-
-
Emirates ID (Front)
-
{employerProfile.emirates_id_front.split('/').pop()}
-
+
+
+
{t('emirates_id_front_side', 'Emirates ID (Front Side)')}
+
{employerProfile.emirates_id_front.split('/').pop()}
+
- View Scan + {t('view_scan', 'View Scan')}
)} {employerProfile?.emirates_id_back && (
-
+
ID -
-
-
Emirates ID (Back)
-
{employerProfile.emirates_id_back.split('/').pop()}
-
+
+
+
{t('emirates_id_back_side', 'Emirates ID (Back Side)')}
+
{employerProfile.emirates_id_back.split('/').pop()}
+
- View Scan + {t('view_scan', 'View Scan')}
)} @@ -383,38 +380,38 @@ export default function Profile({ employerProfile }) { {activeTab === 'security' && (
-

Security & Password

-

Keep your sponsor account secure

+

{t('security_password_header', 'Security & Password')}

+

{t('security_password_desc', 'Keep your sponsor account secure')}

- + setProfile({ ...profile, current_password: e.target.value })} + onChange={(e) => setData('current_password', e.target.value)} className="w-full px-4 py-3 bg-slate-50 border-none rounded-2xl text-xs font-bold focus:ring-2 focus:ring-blue-100 transition-all outline-none" />
- + setProfile({ ...profile, new_password: e.target.value })} + onChange={(e) => setData('new_password', e.target.value)} className="w-full px-4 py-3 bg-slate-50 border-none rounded-2xl text-xs font-bold focus:ring-2 focus:ring-blue-100 transition-all outline-none" />
- + setProfile({ ...profile, new_password_confirmation: e.target.value })} + onChange={(e) => setData('new_password_confirmation', e.target.value)} className="w-full px-4 py-3 bg-slate-50 border-none rounded-2xl text-xs font-bold focus:ring-2 focus:ring-blue-100 transition-all outline-none" />
@@ -425,8 +422,8 @@ export default function Profile({ employerProfile }) { {activeTab === 'billing' && (
-

Billing & Receipts

-

Manage active sponsorship access

+

{t('tab_billing', 'Billing & Receipts')}

+

{t('available_subscription_tiers_desc', 'Upgrade or cancel anytime. All contracts compliant with UAE Tadbeer MOHRE guides.')}

{/* Current Plan Card */} @@ -435,16 +432,16 @@ export default function Profile({ employerProfile }) {
- Current Plan + {t('current_plan', 'Current Plan')}

Premium Employer

- Active + {t('active_status', 'Active')}
-
Next Payment
+
{t('next_payment', 'Next Payment')}
Jun 15, 2026
@@ -456,26 +453,26 @@ export default function Profile({ employerProfile }) { {/* Transaction History */}
-

Recent Transactions

+

{t('recent_transactions', 'Recent Transactions')}

- - - - + + + + {[ { date: 'May 01, 2026', desc: 'Premium Monthly Subscription', amount: '199 AED' }, { date: 'Apr 01, 2026', desc: 'Premium Monthly Subscription', amount: '199 AED' } - ].map((t, i) => ( + ].map((transaction, i) => ( - - - + + +
DateDescriptionAmountReceipt{t('date_header', 'Date')}{t('description_header', 'Description')}{t('amount_header', 'Amount')}{t('receipt_header', 'Receipt')}
{t.date}{t.desc}{t.amount}{transaction.date}{transaction.desc}{transaction.amount} diff --git a/resources/js/Pages/Employer/SelectedCandidates.jsx b/resources/js/Pages/Employer/SelectedCandidates.jsx index 4fe85e9..8395f74 100644 --- a/resources/js/Pages/Employer/SelectedCandidates.jsx +++ b/resources/js/Pages/Employer/SelectedCandidates.jsx @@ -1,6 +1,7 @@ import React, { useState, useEffect } from 'react'; import { Head, Link, router } from '@inertiajs/react'; import EmployerLayout from '../../Layouts/EmployerLayout'; +import { useTranslation } from '../../lib/LanguageContext'; import { CheckCircle2, Globe2, @@ -31,6 +32,7 @@ import { } from '@/components/ui/dropdown-menu'; export default function SelectedCandidates({ selectedWorkers }) { + const { t } = useTranslation(); const [workers, setWorkers] = useState((selectedWorkers || []).filter(w => w.status !== 'Searching')); const [searchTerm, setSearchTerm] = useState(''); @@ -50,35 +52,35 @@ export default function SelectedCandidates({ selectedWorkers }) { const stats = [ { - label: 'Total Candidates', + label: t('total_candidates', 'Total Candidates'), count: workers.length, icon: Users, color: 'text-slate-600', bg: 'bg-slate-50' }, { - label: 'Reviewing', + label: t('reviewing', 'Reviewing'), count: workers.filter(w => w.status === 'Reviewing' || !w.status).length, icon: Search, color: 'text-amber-600', bg: 'bg-amber-50' }, { - label: 'Offer Sent', + label: t('offer_sent', 'Offer Sent'), count: workers.filter(w => w.status === 'Offer Sent').length, icon: Send, color: 'text-blue-600', bg: 'bg-blue-50' }, { - label: 'Hired', + label: t('hired', 'Hired'), count: workers.filter(w => w.status === 'Hired').length, icon: CheckCircle2, color: 'text-emerald-600', bg: 'bg-emerald-50' }, { - label: 'Rejected', + label: t('rejected', 'Rejected'), count: workers.filter(w => w.status === 'Rejected').length, icon: UserCheck, color: 'text-rose-600', @@ -87,15 +89,15 @@ export default function SelectedCandidates({ selectedWorkers }) { ]; return ( - - + +
{/* Header Section */}
-

Candidates

-

Manage your workforce recruitment pipeline

+

{t('candidates_pipeline', 'Candidates')}

+

{t('candidates_pipeline_desc', 'Manage your workforce recruitment pipeline')}

@@ -121,7 +123,7 @@ export default function SelectedCandidates({ selectedWorkers }) { setSearchTerm(e.target.value)} @@ -146,12 +148,12 @@ export default function SelectedCandidates({ selectedWorkers }) { - - - - - - + + + + + + @@ -191,25 +193,28 @@ export default function SelectedCandidates({ selectedWorkers }) { worker.status === 'Offer Sent' ? 'bg-blue-500' : 'bg-amber-500' }`} /> - {(worker.status || 'Reviewing').toUpperCase()} + {worker.status === 'Hired' ? t('hired', 'Hired').toUpperCase() : + worker.status === 'Rejected' ? t('rejected', 'Rejected').toUpperCase() : + worker.status === 'Offer Sent' ? t('offer_sent', 'Offer Sent').toUpperCase() : + t('reviewing', 'Reviewing').toUpperCase()} - Change Status + {t('change_status_label', 'Change Status')} changeStatus(worker.id, 'Reviewing')} className="text-xs font-bold text-slate-600 focus:text-amber-700 focus:bg-amber-50 rounded-lg cursor-pointer"> - Reviewing + {t('reviewing', 'Reviewing')} changeStatus(worker.id, 'Offer Sent')} className="text-xs font-bold text-slate-600 focus:text-blue-700 focus:bg-blue-50 rounded-lg cursor-pointer"> - Offer Sent + {t('offer_sent', 'Offer Sent')} changeStatus(worker.id, 'Hired')} className="text-xs font-bold text-slate-600 focus:text-emerald-700 focus:bg-emerald-50 rounded-lg cursor-pointer"> - Hired + {t('hired', 'Hired')} changeStatus(worker.id, 'Rejected')} className="text-xs font-bold text-rose-600 focus:text-rose-700 focus:bg-rose-50 rounded-lg cursor-pointer"> - Rejected + {t('rejected', 'Rejected')} @@ -237,7 +242,7 @@ export default function SelectedCandidates({ selectedWorkers }) { @@ -249,7 +254,10 @@ export default function SelectedCandidates({ selectedWorkers }) { {/* Pagination Footer */}
- Showing 1 to {workers.length} of {workers.length} candidates + {t('showing_candidates', 'Showing {start} to {end} of {total} candidates') + .replace('{start}', 1) + .replace('{end}', workers.length) + .replace('{total}', workers.length)}
diff --git a/resources/js/Pages/Employer/Shortlist.jsx b/resources/js/Pages/Employer/Shortlist.jsx index 14dcb95..a496619 100644 --- a/resources/js/Pages/Employer/Shortlist.jsx +++ b/resources/js/Pages/Employer/Shortlist.jsx @@ -1,6 +1,7 @@ import React, { useState, useMemo } from 'react'; import { Head, Link, router } from '@inertiajs/react'; import EmployerLayout from '../../Layouts/EmployerLayout'; +import { useTranslation } from '../../lib/LanguageContext'; import { CheckCircle2, Globe2, @@ -34,6 +35,7 @@ const getLanguageFlag = (lang) => { }; export default function Shortlist({ shortlistedWorkers }) { + const { t } = useTranslation(); const [workers, setWorkers] = useState(shortlistedWorkers || []); // Comparison & Quick Preview State @@ -56,7 +58,7 @@ export default function Shortlist({ shortlistedWorkers }) { setComparisonIds(comparisonIds.filter(i => i !== id)); } else { if (comparisonIds.length >= 3) { - alert('You can compare a maximum of 3 candidates.'); + alert(t('max_compare_alert', 'You can compare a maximum of 3 candidates.')); return; } setComparisonIds([...comparisonIds, id]); @@ -68,19 +70,21 @@ export default function Shortlist({ shortlistedWorkers }) { }, [workers, comparisonIds]); return ( - - + +

- You have {workers.length} candidates saved for review + {t('candidates_saved', 'You have {count} candidates saved for review').split('{count}')[0]} + {workers.length} + {t('candidates_saved', 'You have {count} candidates saved for review').split('{count}')[1]}

- Browse more workers + {t('browse_more', 'Browse more workers')}
@@ -110,7 +114,7 @@ export default function Shortlist({ shortlistedWorkers }) { {worker.verified && ( - Verified + {t('verified', 'Verified')} )}
@@ -124,12 +128,12 @@ export default function Shortlist({ shortlistedWorkers }) { {worker.visa_status && (worker.visa_status.toLowerCase().includes('tourist') || worker.visa_status.toLowerCase().includes('visit')) ? (
- {worker.visa_status} (Warning) + {worker.visa_status} ({t('warning', 'Warning')})
) : worker.visa_status && worker.visa_status.toLowerCase().includes('cancelled') ? (
- {worker.visa_status} (Warning) + {worker.visa_status} ({t('warning', 'Warning')})
) : (
@@ -161,7 +165,7 @@ export default function Shortlist({ shortlistedWorkers }) { type="button" onClick={() => removeWorker(worker.id)} className="p-2 bg-rose-50 text-rose-600 hover:bg-rose-100 rounded-xl transition-colors border border-rose-100" - title="Remove from shortlist" + title={t('remove_from_shortlist', 'Remove from shortlist')} > @@ -203,7 +207,7 @@ export default function Shortlist({ shortlistedWorkers }) { {/* Core exact platform Skills List */}
-
Platform Skills
+
{t('platform_skills', 'Platform Skills')}
{worker.skills?.map(skill => ( @@ -215,7 +219,7 @@ export default function Shortlist({ shortlistedWorkers }) { {/* Languages Badges with Visual Flags */}
-
Languages Spoken
+
{t('languages_spoken', 'Languages Spoken')}
{worker.languages?.map(lang => ( @@ -236,7 +240,7 @@ export default function Shortlist({ shortlistedWorkers }) { className="w-full bg-slate-50 border border-slate-200 hover:bg-slate-100 text-slate-700 rounded-xl h-10 font-bold text-xs flex items-center justify-center transition-colors space-x-1" > - Quick Preview + {t('quick_preview', 'Quick Preview')}
@@ -257,14 +261,14 @@ export default function Shortlist({ shortlistedWorkers }) { href={`/employer/workers/${worker.id}`} className="w-full bg-slate-100 hover:bg-slate-200 text-slate-700 rounded-xl h-10 font-bold text-xs flex items-center justify-center transition-colors" > - Open Profile + {t('open_profile', 'Open Profile')} - Message + {t('message', 'Message')}
@@ -276,15 +280,15 @@ export default function Shortlist({ shortlistedWorkers }) { ) : (
-
Your shortlist is empty
+
{t('shortlist_empty', 'Your shortlist is empty')}

- Explore candidate profiles and add them to your saved shortlist. + {t('shortlist_empty_desc', 'Explore candidate profiles and add them to your saved shortlist.')}

- Find Workers Now + {t('find_workers_now', 'Find Workers Now')}
)} @@ -295,14 +299,14 @@ export default function Shortlist({ shortlistedWorkers }) {
-

Comparing Workers ({comparedWorkers.length} of 3)

+

{t('comparing_workers', 'Comparing Workers')} ({comparedWorkers.length} of 3)

@@ -393,17 +397,17 @@ export default function Shortlist({ shortlistedWorkers }) {

) : (

- No bio details provided. + {t('no_bio_provided', 'No bio details provided.')}

)}
-
Expectations
+
{t('expectations', 'Expectations')}
{previewWorker.salary} AED / mo
-
Languages
+
{t('languages', 'Languages')}
{previewWorker.languages?.map(lang => ( @@ -414,7 +418,7 @@ export default function Shortlist({ shortlistedWorkers }) {
-
Availability Status
+
{t('availability_status_label', 'Availability Status')}
-
Job Preference
+
{t('job_preference', 'Job Preference')}
{previewWorker.preferred_job_type}
{/* Core Platform Skills inside Quick Preview */}
-
Platform Skills
+
{t('platform_skills', 'Platform Skills')}
{previewWorker.skills?.map(skill => ( @@ -447,13 +451,13 @@ export default function Shortlist({ shortlistedWorkers }) { className="flex-1 border border-rose-200 hover:bg-rose-50 text-rose-600 rounded-xl h-11 text-xs font-bold flex items-center justify-center space-x-2" > - Remove Shortlist + {t('remove_shortlist', 'Remove Shortlist')} - View Full Details + {t('view_full_details', 'View Full Details')}
diff --git a/resources/js/Pages/Employer/Subscription.jsx b/resources/js/Pages/Employer/Subscription.jsx index 14d13e9..e77114b 100644 --- a/resources/js/Pages/Employer/Subscription.jsx +++ b/resources/js/Pages/Employer/Subscription.jsx @@ -1,6 +1,7 @@ import React, { useState } from 'react'; import { Head } from '@inertiajs/react'; import EmployerLayout from '../../Layouts/EmployerLayout'; +import { useTranslation } from '../../lib/LanguageContext'; import { CreditCard, CheckCircle2, @@ -22,6 +23,7 @@ import { import { toast } from 'sonner'; export default function Subscription({ currentPlan, expiresAt, plans }) { + const { t } = useTranslation(); const [selectedPlan, setSelectedPlan] = useState(null); const [showPayTabsModal, setShowPayTabsModal] = useState(false); const [showSuccess, setShowSuccess] = useState(false); @@ -53,7 +55,7 @@ export default function Subscription({ currentPlan, expiresAt, plans }) { e.preventDefault(); if (cardNumber.length < 16) { - toast.error("💳 Invalid card number format"); + toast.error(`💳 ${t('invalid_card_format', 'Invalid card number format')}`); return; } @@ -71,8 +73,8 @@ export default function Subscription({ currentPlan, expiresAt, plans }) { }; setInvoices([newInvoice, ...invoices]); - toast.success(`🎉 Payment Approved by PayTabs!`, { - description: `Successfully subscribed to ${selectedPlan.name}. Premium access limits updated instantly.`, + toast.success(`🎉 ${t('payment_approved', 'Payment Approved by PayTabs!')}`, { + description: t('successfully_subscribed_desc', 'Successfully subscribed to {plan}. Premium access limits updated instantly.').replace('{plan}', selectedPlan.name), duration: 5000, }); @@ -87,8 +89,8 @@ export default function Subscription({ currentPlan, expiresAt, plans }) { const triggerFailedPaymentSimulation = () => { setSimulatedFailedState(true); - toast.warning("Simulated billing failure triggered!", { - description: "An automatic system warning will now request payment retry options." + toast.warning(t('simulated_billing_failure_triggered', 'Simulated billing failure triggered!'), { + description: t('simulated_billing_failure_desc', 'An automatic system warning will now request payment retry options.') }); }; @@ -100,14 +102,14 @@ export default function Subscription({ currentPlan, expiresAt, plans }) { }; const downloadReceipt = (invoiceId) => { - toast.success(`📄 Invoice ${invoiceId} generated`, { - description: "Direct MOHRE Sponsor receipt downloaded in PDF format successfully." + toast.success(`📄 ${t('invoice_generated', 'Invoice {id} generated').replace('{id}', invoiceId)}`, { + description: t('invoice_download_desc', 'Direct MOHRE Sponsor receipt downloaded in PDF format successfully.') }); }; return ( - - + +
@@ -119,8 +121,8 @@ export default function Subscription({ currentPlan, expiresAt, plans }) {
-

Your recurrent subscription billing has FAILED!

-

Card renewal on May 22 failed due to insufficient funds. Retry using PayTabs to avoid profile lockout.

+

{t('recurrent_billing_failed', 'Your recurrent subscription billing has FAILED!')}

+

{t('recurrent_billing_failed_desc', 'Card renewal failed due to insufficient funds. Retry using PayTabs to avoid profile lockout.')}

)} @@ -140,10 +142,10 @@ export default function Subscription({ currentPlan, expiresAt, plans }) {
-
Active Plan Pass
+
{t('active_plan_pass', 'Active Plan Pass')}

{activePlan}

- Renewing via auto-payment on {expiresAt} + {t('renewing_auto_payment_on', 'Renewing via auto-payment on')} {expiresAt}

@@ -154,11 +156,11 @@ export default function Subscription({ currentPlan, expiresAt, plans }) { className="text-[10px] font-black text-slate-400 hover:text-slate-600 underline" title="Simulate card failure to test retry mechanism" > - Simulate Billing Failure + {t('simulate_billing_failure', 'Simulate Billing Failure')}
- Verified Sponsor Status + {t('verified_sponsor_status', 'Verified Sponsor Status')}
@@ -166,15 +168,15 @@ export default function Subscription({ currentPlan, expiresAt, plans }) { {showSuccess && (
- Sponsor Pass updated successfully! PayTabs transaction logged. + {t('sponsor_pass_updated', 'Sponsor Pass updated successfully! PayTabs transaction logged.')}
)} {/* Available Plan Tiers Pricing Grid */}
-

Available Subscription Tiers

-

Upgrade or cancel anytime. All contracts compliant with UAE Tadbeer MOHRE guides.

+

{t('available_subscription_tiers', 'Available Subscription Tiers')}

+

{t('available_subscription_tiers_desc', 'Upgrade or cancel anytime. All contracts compliant with UAE Tadbeer MOHRE guides.')}

@@ -192,7 +194,7 @@ export default function Subscription({ currentPlan, expiresAt, plans }) { > {plan.popular && (
- Most Popular Tier + {t('most_popular_tier', 'Most Popular Tier')}
)} @@ -225,7 +227,7 @@ export default function Subscription({ currentPlan, expiresAt, plans }) { : 'bg-[#185FA5] hover:bg-[#144f8a] text-white' }`} > - {isCurrent ? 'Current Active Tier ✓' : 'Select Plan Tier'} + {isCurrent ? t('current_active_tier', 'Current Active Tier ✓') : t('select_plan_tier', 'Select Plan Tier')}
@@ -241,9 +243,9 @@ export default function Subscription({ currentPlan, expiresAt, plans }) {
-

Billing Payment Receipts

+

{t('billing_payment_receipts', 'Billing Payment Receipts')}

- Tax Compliant invoices + {t('tax_compliant_invoices', 'Tax Compliant invoices')}
@@ -283,13 +285,13 @@ export default function Subscription({ currentPlan, expiresAt, plans }) { {/* Sponsor Billing Details Form */}
-

Corporate Details

-

Update tax invoicing options.

+

{t('corporate_details', 'Corporate Details')}

+

{t('update_tax_invoicing', 'Update tax invoicing options.')}

- +
- +
@@ -334,21 +336,21 @@ export default function Subscription({ currentPlan, expiresAt, plans }) {
- PayTabs Secured Checkout + {t('paytabs_secured_checkout', 'PayTabs Secured Checkout')}
- Gateway v4.0 + {t('gateway_version', 'Gateway v4.0')}
{/* Order Summary */}
- Order description + {t('order_description', 'Order description')}
{selectedPlan.name} Subscription
- Total amount + {t('total_amount', 'Total amount')}
{selectedPlan.price}
@@ -357,7 +359,7 @@ export default function Subscription({ currentPlan, expiresAt, plans }) {
- +
- +
- +
- + - 256-bit PCI DSS Cryptography Protected + {t('pci_dss_cryptography', '256-bit PCI DSS Cryptography Protected')}
@@ -419,7 +421,7 @@ export default function Subscription({ currentPlan, expiresAt, plans }) { type="submit" className="w-full bg-red-600 hover:bg-red-700 text-white py-3.5 rounded-2xl font-black text-xs uppercase tracking-widest shadow-lg shadow-red-500/10 flex items-center justify-center space-x-2" > - Authorize Payment + {t('authorize_payment', 'Authorize Payment')} diff --git a/resources/js/Pages/Employer/Workers/Index.jsx b/resources/js/Pages/Employer/Workers/Index.jsx index 9cf641f..a6a1c0f 100644 --- a/resources/js/Pages/Employer/Workers/Index.jsx +++ b/resources/js/Pages/Employer/Workers/Index.jsx @@ -1,6 +1,7 @@ import React, { useState, useMemo, useEffect } from 'react'; import { Head, Link, router } from '@inertiajs/react'; import EmployerLayout from '../../../Layouts/EmployerLayout'; +import { useTranslation } from '../../../lib/LanguageContext'; import { Search, SlidersHorizontal, @@ -42,6 +43,7 @@ const getLanguageFlag = (lang) => { }; export default function Index({ initialWorkers = [], initialShortlistedIds = [], filtersMetadata = {} }) { + const { t } = useTranslation(); // Basic Filters const [searchQuery, setSearchQuery] = useState(''); const [selectedCategory, setSelectedCategory] = useState('All Categories'); @@ -247,8 +249,8 @@ export default function Index({ initialWorkers = [], initialShortlistedIds = [], }, [initialWorkers, comparisonIds]); return ( - - + +
@@ -260,11 +262,11 @@ export default function Index({ initialWorkers = [], initialShortlistedIds = [],
- No Middlemen Platform + {t('no_middlemen_platform')}
-

Find Verified Candidates

-

Instantly connect with UAE vetted, background-checked domestic workers.

+

{t('find_verified_candidates')}

+

{t('connect_vetted_workers_desc')}

@@ -279,7 +281,7 @@ export default function Index({ initialWorkers = [], initialShortlistedIds = [], type="text" value={searchQuery} onChange={(e) => setSearchQuery(e.target.value)} - placeholder="Search by name, skills, bio (e.g. Cooking, Childcare, Gardening, Driving)..." + placeholder={t('search_by_name_skills_bio')} className="w-full pl-11 pr-4 py-3 rounded-xl border border-slate-300 text-sm focus:outline-none focus:ring-2 focus:ring-[#185FA5]/20 focus:border-[#185FA5]" />
@@ -294,11 +296,11 @@ export default function Index({ initialWorkers = [], initialShortlistedIds = [], onChange={(e) => setSortBy(e.target.value)} className="bg-transparent focus:outline-none cursor-pointer" > - - - - - + + + + +
@@ -308,7 +310,7 @@ export default function Index({ initialWorkers = [], initialShortlistedIds = [], className="flex items-center justify-center space-x-1.5 px-4 py-2.5 rounded-xl border border-slate-200 hover:bg-slate-50 text-xs font-semibold text-slate-600 transition-colors" > - Reset + {t('reset')}
@@ -317,7 +319,7 @@ export default function Index({ initialWorkers = [], initialShortlistedIds = [],
{/* Nationality */}
- + setSelectedAvailability(e.target.value)} @@ -417,7 +419,7 @@ export default function Index({ initialWorkers = [], initialShortlistedIds = [], {/* Visa Status */}
- + @@ -456,11 +458,13 @@ export default function Index({ initialWorkers = [], initialShortlistedIds = [], {/* Listing metadata bar */}
- Found {filteredWorkers.length} domestic workers matching search + {t('found_workers_matching').split('{count}')[0]} + {filteredWorkers.length} + {t('found_workers_matching').split('{count}')[1]}
- MOHRE UAE Direct Sponsoring Active + {t('direct_sponsoring_active')}
@@ -492,7 +496,7 @@ export default function Index({ initialWorkers = [], initialShortlistedIds = [], {worker.verified && ( - Verified + {t('verified')} )}
@@ -506,12 +510,12 @@ export default function Index({ initialWorkers = [], initialShortlistedIds = [], {worker.visa_status && (worker.visa_status.toLowerCase().includes('tourist') || worker.visa_status.toLowerCase().includes('visit')) ? (
- {worker.visa_status} (Warning) + {worker.visa_status} ({t('warning', 'Warning')})
) : worker.visa_status && worker.visa_status.toLowerCase().includes('cancelled') ? (
- {worker.visa_status} (Warning) + {worker.visa_status} ({t('warning', 'Warning')})
) : (
@@ -524,7 +528,7 @@ export default function Index({ initialWorkers = [], initialShortlistedIds = [], {worker.nationality} - {worker.age} yrs + {worker.age} {t('yrs', 'yrs')}
@@ -564,8 +568,8 @@ export default function Index({ initialWorkers = [], initialShortlistedIds = [],
- {worker.salary} AED - /mo + {worker.salary} {t('aed', 'AED')} + /{t('mo', 'mo')}
@@ -574,7 +578,7 @@ export default function Index({ initialWorkers = [], initialShortlistedIds = [],
- Exp: {worker.experience} + {t('experience', 'Exp')}: {worker.experience}
@@ -582,13 +586,13 @@ export default function Index({ initialWorkers = [], initialShortlistedIds = [],
- {worker.rating} ({worker.reviews_count} reviews) + {worker.rating} ({worker.reviews_count} {t('reviews', 'reviews')})
{/* Core exact platform Skills List */}
-
Platform Skills
+
{t('platform_skills', 'Platform Skills')}
{worker.skills?.map(skill => ( @@ -600,7 +604,7 @@ export default function Index({ initialWorkers = [], initialShortlistedIds = [], {/* Languages Badges with Visual Flags */}
-
Languages Spoken
+
{t('languages_spoken', 'Languages Spoken')}
{worker.languages?.map(lang => ( @@ -621,7 +625,7 @@ export default function Index({ initialWorkers = [], initialShortlistedIds = [], className="w-full bg-slate-50 border border-slate-200 hover:bg-slate-100 text-slate-700 rounded-xl h-10 font-bold text-xs flex items-center justify-center transition-colors space-x-1" > - Quick Preview + {t('quick_preview')}
@@ -641,7 +645,7 @@ export default function Index({ initialWorkers = [], initialShortlistedIds = [], href={`/employer/workers/${worker.id}`} className="w-full bg-[#185FA5] hover:bg-[#144f8a] text-white rounded-xl h-10 font-bold text-xs flex items-center justify-center transition-colors shadow-xs" > - Open Full Profile + {t('open_full_profile')}
@@ -652,16 +656,16 @@ export default function Index({ initialWorkers = [], initialShortlistedIds = [], ) : (
-

No candidates match your filters

+

{t('no_candidates_matching')}

- Try adjusting your salary limit, adding additional languages, or broadening nationality preferences. + {t('adjust_filters_desc')}

)} @@ -673,7 +677,7 @@ export default function Index({ initialWorkers = [], initialShortlistedIds = [], onClick={() => setVisibleCount(visibleCount + 6)} className="bg-white border border-slate-200 hover:bg-slate-50 text-[#185FA5] px-8 py-3 rounded-xl text-xs font-bold transition-all shadow-xs" > - Load More Workers + {t('load_more_workers')}
)} @@ -684,14 +688,16 @@ export default function Index({ initialWorkers = [], initialShortlistedIds = [],
-

Comparing Workers ({comparedWorkers.length} of 3)

+

+ {t('comparing_workers_count').replace('{count}', comparedWorkers.length)} +

@@ -720,14 +726,14 @@ export default function Index({ initialWorkers = [], initialShortlistedIds = [],
-
Salary: {w.salary} AED
-
Age: {w.age} yrs
-
Job Type: {w.preferred_job_type}
-
Status: {w.availability_status}
+
{t('salary', 'Salary')}: {w.salary} {t('aed', 'AED')}
+
{t('age', 'Age')}: {w.age} {t('yrs', 'yrs')}
+
{t('job_type', 'Job Type')}: {w.preferred_job_type}
+
{t('status', 'Status')}: {w.availability_status}
-
Skills
+
{t('skills')}
{w.skills?.map(skill => ( @@ -781,11 +787,11 @@ export default function Index({ initialWorkers = [], initialShortlistedIds = [],
-
Expectations
-
{previewWorker.salary} AED / mo
+
{t('expectations', 'Expectations')}
+
{previewWorker.salary} {t('aed', 'AED')} / {t('mo', 'mo')}
-
Languages
+
{t('languages_spoken', 'Languages')}
{previewWorker.languages?.map(lang => ( @@ -796,7 +802,7 @@ export default function Index({ initialWorkers = [], initialShortlistedIds = [],
-
Availability Status
+
{t('availability_status', 'Availability Status')}
-
Job Preference
+
{t('job_preference', 'Job Preference')}
{previewWorker.preferred_job_type}
{/* Core Platform Skills inside Quick Preview */}
-
Platform Skills
+
{t('platform_skills', 'Platform Skills')}
{previewWorker.skills?.map(skill => ( @@ -829,13 +835,13 @@ export default function Index({ initialWorkers = [], initialShortlistedIds = [], className="flex-1 border border-slate-200 hover:bg-slate-50 rounded-xl h-11 text-xs font-bold text-slate-700 flex items-center justify-center space-x-2" > - {shortlistedIds.includes(previewWorker.id) ? 'Shortlisted ✓' : 'Add to Shortlist'} + {shortlistedIds.includes(previewWorker.id) ? t('shortlisted', 'Shortlisted ✓') : t('add_to_shortlist', 'Add to Shortlist')} - View Full Details + {t('view_full_details', 'View Full Details')}
@@ -861,7 +867,7 @@ export default function Index({ initialWorkers = [], initialShortlistedIds = [], onClick={() => setShowPresetModal(false)} className="px-4 py-2 border border-slate-200 hover:bg-slate-50 rounded-lg" > - Cancel + {t('cancel', 'Cancel')}
@@ -175,7 +177,7 @@ export default function Show({ worker }) { {worker.verified && ( - Verified + {t('verified')} )} @@ -198,12 +200,12 @@ export default function Show({ worker }) { {worker.visa_status && (worker.visa_status.toLowerCase().includes('tourist') || worker.visa_status.toLowerCase().includes('visit')) ? (
- {worker.visa_status} (Warning: Visit Visa) + {worker.visa_status} ({t('warning', 'Warning')}: {t('visit_visa', 'Visit Visa')})
) : worker.visa_status && worker.visa_status.toLowerCase().includes('cancelled') ? (
- {worker.visa_status} (Warning: Cancelled) + {worker.visa_status} ({t('warning', 'Warning')}: {t('cancelled', 'Cancelled')})
) : (
@@ -218,13 +220,13 @@ export default function Show({ worker }) { {worker.nationality} - {worker.age} Years Old + {worker.age} {t('years_old', 'Years Old')} {worker.category}
- {worker.rating} / 5.0 ({workerReviews.length} reviews) + {worker.rating} / 5.0 ({workerReviews.length} {t('reviews', 'reviews')})
@@ -250,7 +252,7 @@ export default function Show({ worker }) { className="bg-white border border-slate-250 hover:bg-slate-50 px-6 py-3 rounded-xl font-bold text-sm shadow-xs transition-colors flex items-center justify-center space-x-2 text-slate-700 flex-1 sm:flex-initial" > - Start Direct Chat + {t('start_direct_chat', 'Start Direct Chat')} {/* Stage 4 Hire: Mark Hired (Finalize Hiring Direct Flow) */} @@ -260,7 +262,7 @@ export default function Show({ worker }) { className="bg-emerald-600 hover:bg-emerald-700 text-white border border-emerald-700 px-8 py-3 rounded-xl font-black text-sm shadow-md transition-all flex items-center justify-center space-x-2 flex-1 sm:flex-initial scale-105 active:scale-100" > - Mark Hired + {t('mark_hired_action', 'Mark Hired')} @@ -270,20 +272,20 @@ export default function Show({ worker }) { {/* Left Column: Quick Stats */}
-

Sponsorship Details

+

{t('sponsorship_details', 'Sponsorship Details')}

- Salary Expectations + {t('salary_expectations', 'Salary Expectations')}
- {worker.salary} AED / mo + {worker.salary} {t('aed', 'AED')} / {t('mo', 'mo')}
- Availability Status + {t('availability_status', 'Availability Status')}
{availabilityStatus} @@ -293,7 +295,7 @@ export default function Show({ worker }) {
- Work Experience + {t('work_experience', 'Work Experience')}
{worker.experience}
@@ -301,7 +303,7 @@ export default function Show({ worker }) {
- Preferred Job Type + {t('preferred_job_type', 'Preferred Job Type')}
{worker.preferred_job_type}
@@ -309,7 +311,7 @@ export default function Show({ worker }) {
- Emirates ID Vetting + {t('emirates_id_vetting', 'Emirates ID Vetting')}
{worker.emirates_id_status}
@@ -317,7 +319,7 @@ export default function Show({ worker }) {
- Visa Status + {t('visa_status', 'Visa Status')}
{worker.visa_status}
@@ -325,10 +327,10 @@ export default function Show({ worker }) {
- Medical Health Test + {t('medical_health_test', 'Medical Health Test')}
- PASSED CERTIFIED + {t('passed_certified', 'PASSED CERTIFIED')}
@@ -337,7 +339,7 @@ export default function Show({ worker }) {
- Languages Spoken + {t('languages_spoken', 'Languages Spoken')}
{worker.languages?.map(lang => ( @@ -354,7 +356,7 @@ export default function Show({ worker }) {
{/* Professional Summary */}
-

Professional Summary

+

{t('professional_summary', 'Professional Summary')}

"{worker.bio}"

@@ -362,7 +364,7 @@ export default function Show({ worker }) { {/* Verified Skills & Competencies */}
-

Verified Skills & Competencies

+

{t('verified_skills_competencies', 'Verified Skills & Competencies')}

{worker.skills?.map(skill => (
@@ -377,39 +379,39 @@ export default function Show({ worker }) {

- Verified Legal Documents (UAE MOHRE Vetted) + {t('verified_legal_docs', 'Verified Legal Documents (UAE MOHRE Vetted)')}

{/* Document Card: Passport */}
- Passport (Verified) + {t('passport_verified', 'Passport (Verified)')}
- Click zoom + {t('click_zoom', 'Click zoom')}
-
Document ID
+
{t('document_id', 'Document ID')}
L82739102-UAE
-
Issue
+
{t('issue_date', 'Issue')}
12 Jan 2021
-
Expiry
+
{t('expiry_date', 'Expiry')}
11 Jan 2031
-
OCR Match
+
{t('ocr_match', 'OCR Match')}
@@ -424,31 +426,31 @@ export default function Show({ worker }) { {/* Document Card: Emirates ID */}
- Emirates ID (PDPL Compliant) + {t('emirates_id_pdpl', 'Emirates ID (PDPL Compliant)')}
- Scan Purged - UAE PDPL compliant + {t('scan_purged', 'Scan Purged')} + {t('uae_pdpl_compliant', 'UAE PDPL compliant')}
-
Verification Type
-
Emirates ID OCR
+
{t('verification_type', 'Verification Type')}
+
{t('emirates_id_ocr', 'Emirates ID OCR')}
-
Status
+
{t('status', 'Status')}
{worker.emirates_id_status}
-
Physical Scan Storage
- Permanently Purged +
{t('physical_scan_storage', 'Physical Scan Storage')}
+ {t('permanently_purged', 'Permanently Purged')}
@@ -457,7 +459,7 @@ export default function Show({ worker }) { {/* Document Card: Visa */}
- Entry Visa (Verified) + {t('entry_visa_verified', 'Entry Visa (Verified)')} {worker.visa_status && (worker.visa_status.toLowerCase().includes('tourist') || worker.visa_status.toLowerCase().includes('visit') || worker.visa_status.toLowerCase().includes('cancelled')) ? ( ) : ( @@ -467,29 +469,29 @@ export default function Show({ worker }) {
- Click zoom + {t('click_zoom', 'Click zoom')}
-
Visa Category
+
{t('visa_category', 'Visa Category')}
{worker.visa_status}
-
Vetting status
+
{t('vetting_status', 'Vetting status')}
{worker.visa_status && (worker.visa_status.toLowerCase().includes('tourist') || worker.visa_status.toLowerCase().includes('visit')) ? ( - Transfer Required + {t('transfer_required', 'Transfer Required')} ) : worker.visa_status && worker.visa_status.toLowerCase().includes('cancelled') ? ( - Needs Regularization + {t('needs_regularization', 'Needs Regularization')} ) : ( <> - Clear Records + {t('clear_records', 'Clear Records')} )}
@@ -508,14 +510,14 @@ export default function Show({ worker }) {
-

Sponsor Reviews & Star Ratings

-

Ratings can only be posted by verified sponsors who completed verified direct hiring.

+

{t('sponsor_reviews_star_ratings', 'Sponsor Reviews & Star Ratings')}

+

{t('reviews_posted_by_sponsors_desc', 'Ratings can only be posted by verified sponsors who completed verified direct hiring.')}

@@ -547,7 +549,7 @@ export default function Show({ worker }) { {/* Similar Recommendations Slider */}
-

Similar Recommended Workers

+

{t('similar_recommended_workers', 'Similar Recommended Workers')}

{worker.similar_workers?.map((sim) => (
@@ -561,12 +563,12 @@ export default function Show({ worker }) {
- {sim.salary} AED/mo + {sim.salary} {t('aed', 'AED')}/{t('mo', 'mo')} - View Profile + {t('view_profile', 'View Profile')}
@@ -585,16 +587,16 @@ export default function Show({ worker }) {
-

Direct Sponsoring Finalized!

+

{t('direct_sponsoring_finalized', 'Direct Sponsoring Finalized!')}

- {worker.name} is successfully marked as Hired under your sponsorship! This direct matching conforms exactly with Stage 4 of our UAE MOHRE zero-middlemen flow. + {t('hired_under_sponsorship_desc', '{name} is successfully marked as Hired under your sponsorship! This direct matching conforms exactly with Stage 4 of our UAE MOHRE zero-middlemen flow.').replace('{name}', worker.name)}

- Next Step: Stage 5 Post-Hire Review + {t('next_step_post_hire_review', 'Next Step: Stage 5 Post-Hire Review')}

- Help the UAE community hire safely by posting an anonymous review describing {worker.name}'s childcare, cooking, driving, or domestic skills. + {t('help_community_post_review', "Help the UAE community hire safely by posting an anonymous review describing {name}'s childcare, cooking, driving, or domestic skills.").replace('{name}', worker.name)}

@@ -607,13 +609,13 @@ export default function Show({ worker }) { className="w-full bg-[#185FA5] hover:bg-[#144f8a] text-white py-3 rounded-xl flex items-center justify-center space-x-2" > - Leave a Trust Review + {t('leave_trust_review', 'Leave a Trust Review')} - Back to Worker Directory + {t('back_to_worker_directory', 'Back to Worker Directory')}
@@ -634,36 +636,36 @@ export default function Show({ worker }) {
-

Report Vetting Abuse / Terms Violation

+

{t('report_abuse_violation', 'Report Vetting Abuse / Terms Violation')}

- We maintain zero-tolerance for fake documentation, independent recruiters trading cash, or incorrect contact details. + {t('zero_tolerance_abuse_desc', 'We maintain zero-tolerance for fake documentation, independent recruiters trading cash, or incorrect contact details.')}

- +
- +
CandidateSelectedCategorySalaryStatusActions{t('candidate_header', 'Candidate')}{t('selected_header', 'Selected')}{t('category_header', 'Category')}{t('salary_header', 'Salary')}{t('status_header', 'Status')}{t('actions_header', 'Actions')}
-
No candidates found
+
{t('no_candidates_found', 'No candidates found')}