check()) { $role = auth()->user()->role; if ($role === 'employer') { return redirect()->route('employer.dashboard'); } if ($role === 'admin') { return redirect()->route('admin.dashboard'); } } // Fallback: check custom session key (registration flow / legacy) $sessionUser = session('user'); if ($sessionUser) { $role = is_array($sessionUser) ? ($sessionUser['role'] ?? null) : ($sessionUser->role ?? null); if ($role === 'employer') { return redirect()->route('employer.dashboard'); } if ($role === 'admin') { return redirect()->route('admin.dashboard'); } } // Not logged in — send to admin login as default return redirect()->route('admin.login'); }); // Admin Auth Routes Route::get('/admin/login', [AdminAuthController::class, 'showLogin'])->name('admin.login'); Route::post('/admin/login', [AdminAuthController::class, 'login'])->name('admin.login.submit'); Route::post('/admin/logout', [AdminAuthController::class, 'logout'])->name('admin.logout'); // Admin Protected Routes Route::prefix('admin')->middleware(['admin'])->group(function () { Route::get('/dashboard', [\App\Http\Controllers\Admin\DashboardController::class, 'index'])->name('admin.dashboard'); Route::post('/verifications/approve', [\App\Http\Controllers\Admin\DashboardController::class, 'approveVerification'])->name('admin.verifications.approve'); Route::post('/verifications/reject', [\App\Http\Controllers\Admin\DashboardController::class, 'rejectVerification'])->name('admin.verifications.reject'); Route::get('/workers', [\App\Http\Controllers\Admin\WorkerController::class, 'index'])->name('admin.workers'); Route::post('/workers/{worker}/toggle-status', [\App\Http\Controllers\Admin\WorkerController::class, 'toggleStatus'])->name('admin.workers.toggle-status'); Route::post('/workers/{worker}/availability-override', [\App\Http\Controllers\Admin\WorkerController::class, 'availabilityOverride'])->name('admin.workers.availability-override'); Route::post('/workers/{worker}/flag-fraud', [\App\Http\Controllers\Admin\WorkerController::class, 'flagFraud'])->name('admin.workers.flag-fraud'); Route::post('/workers/{worker}/update-profile', [\App\Http\Controllers\Admin\WorkerController::class, 'updateProfile'])->name('admin.workers.update-profile'); Route::get('/workers/verifications', [\App\Http\Controllers\Admin\WorkerVerificationController::class, 'index'])->name('admin.workers.verifications'); Route::post('/workers/{worker}/verify', [\App\Http\Controllers\Admin\WorkerVerificationController::class, 'verify'])->name('admin.workers.verify'); // Employer Management Routes Route::get('/employers', [\App\Http\Controllers\Admin\EmployerController::class, 'index'])->name('admin.employers'); Route::get('/employers/export', [\App\Http\Controllers\Admin\EmployerController::class, 'export'])->name('admin.employers.export'); Route::post('/employers/{id}/verify', [\App\Http\Controllers\Admin\EmployerController::class, 'verify'])->name('admin.employers.verify'); Route::post('/employers/{id}/suspend', [\App\Http\Controllers\Admin\EmployerController::class, 'suspend'])->name('admin.employers.suspend'); Route::post('/employers/{id}/activate', [\App\Http\Controllers\Admin\EmployerController::class, 'activate'])->name('admin.employers.activate'); Route::post('/employers/{id}/update', [\App\Http\Controllers\Admin\EmployerController::class, 'update'])->name('admin.employers.update'); Route::delete('/employers/{id}', [\App\Http\Controllers\Admin\EmployerController::class, 'delete'])->name('admin.employers.delete'); // Charity Organization Management Routes Route::get('/charity-organizations', [\App\Http\Controllers\Admin\SponsorController::class, 'index'])->name('admin.charity-organizations'); Route::get('/charity-organizations/export', [\App\Http\Controllers\Admin\SponsorController::class, 'export'])->name('admin.charity-organizations.export'); Route::post('/charity-organizations/{id}/verify', [\App\Http\Controllers\Admin\SponsorController::class, 'verify'])->name('admin.charity-organizations.verify'); Route::post('/charity-organizations/{id}/suspend', [\App\Http\Controllers\Admin\SponsorController::class, 'suspend'])->name('admin.charity-organizations.suspend'); Route::post('/charity-organizations/{id}/activate', [\App\Http\Controllers\Admin\SponsorController::class, 'activate'])->name('admin.charity-organizations.activate'); Route::post('/charity-organizations/{id}/update', [\App\Http\Controllers\Admin\SponsorController::class, 'update'])->name('admin.charity-organizations.update'); Route::delete('/charity-organizations/{id}', [\App\Http\Controllers\Admin\SponsorController::class, 'delete'])->name('admin.charity-organizations.delete'); Route::get('/subscriptions', function () { $plans = \App\Models\Plan::all()->map(function ($plan) { $plan->usage_count = \App\Models\Sponsor::where('subscription_plan', $plan->id) ->where('subscription_status', 'active') ->count(); return $plan; }); return Inertia::render('Admin/Subscriptions/Index', [ 'plans' => $plans ]); })->name('admin.subscriptions'); Route::post('/subscriptions', function (\Illuminate\Http\Request $request) { $data = $request->validate([ 'id' => 'required|string|unique:plans,id', 'name' => 'required|string|max:255', 'price' => 'required|numeric|min:0', 'duration' => 'required|string', 'features' => 'required|array', 'max_contact_people' => 'nullable|integer', 'unlimited_contacts' => 'required|boolean', 'enable_job_apply' => 'required|boolean', 'status' => 'nullable|string|in:Active,Disabled', ]); \App\Models\Plan::create([ 'id' => $data['id'], 'name' => $data['name'], 'price' => $data['price'], 'duration' => $data['duration'], 'features' => $data['features'], 'status' => $data['status'] ?? 'Active', 'max_contact_people' => $data['unlimited_contacts'] ? null : $data['max_contact_people'], 'unlimited_contacts' => $data['unlimited_contacts'], 'enable_job_apply' => $data['enable_job_apply'], ]); return redirect()->back(); })->name('admin.subscriptions.store'); Route::post('/subscriptions/{id}/update', function (\Illuminate\Http\Request $request, $id) { $plan = \App\Models\Plan::findOrFail($id); $data = $request->validate([ 'name' => 'required|string|max:255', 'price' => 'required|numeric|min:0', 'duration' => 'required|string', 'features' => 'required|array', 'max_contact_people' => 'nullable|integer', 'unlimited_contacts' => 'required|boolean', 'enable_job_apply' => 'required|boolean', 'status' => 'required|string|in:Active,Disabled', ]); if ($data['status'] === 'Disabled') { $usageCount = \App\Models\Sponsor::where('subscription_plan', $plan->id) ->where('subscription_status', 'active') ->count(); if ($usageCount > 0) { return redirect()->back()->withErrors([ 'status' => "Cannot disable plan. {$usageCount} " . ($usageCount === 1 ? 'person is' : 'people are') . " using this plan." ]); } } $plan->update([ 'name' => $data['name'], 'price' => $data['price'], 'duration' => $data['duration'], 'features' => $data['features'], 'status' => $data['status'], 'max_contact_people' => $data['unlimited_contacts'] ? null : $data['max_contact_people'], 'unlimited_contacts' => $data['unlimited_contacts'], 'enable_job_apply' => $data['enable_job_apply'], ]); return redirect()->back(); })->name('admin.subscriptions.update'); Route::delete('/subscriptions/{id}', function ($id) { $plan = \App\Models\Plan::findOrFail($id); $usageCount = \App\Models\Sponsor::where('subscription_plan', $plan->id) ->where('subscription_status', 'active') ->count(); if ($usageCount > 0) { return redirect()->back()->withErrors([ 'status' => "Cannot delete plan. {$usageCount} " . ($usageCount === 1 ? 'person is' : 'people are') . " using this plan." ]); } $plan->delete(); return redirect()->back(); })->name('admin.subscriptions.delete'); Route::get('/payments', function () { $payments = \Illuminate\Support\Facades\DB::table('subscriptions') ->leftJoin('users', 'subscriptions.user_id', '=', 'users.id') ->select('subscriptions.*', 'users.name as user_name', 'users.email as user_email') ->orderBy('subscriptions.created_at', 'desc') ->get() ->map(function($sub) { $planLabel = ucfirst($sub->plan_id) . ' Sponsor Pass'; $status = $sub->status === 'active' ? 'Completed' : (ucfirst($sub->status) ?: 'Completed'); $startsAt = $sub->starts_at ?? $sub->created_at; $expiresAt = $sub->expires_at ?? date('Y-m-d H:i:s', strtotime($startsAt . ' +1 month')); return [ 'id' => 'PAY-' . str_pad($sub->id, 3, '0', STR_PAD_LEFT), 'employer' => $sub->user_name ?: 'System Guest / Sponsor', 'plan' => $planLabel, 'amount' => (float)$sub->amount_aed, 'method' => 'PayTabs Gateway', 'date' => date('Y-m-d', strtotime($startsAt)), 'status' => $status, 'period' => date('M Y', strtotime($startsAt)) . ' - ' . date('M Y', strtotime($expiresAt)), ]; }); $totalRevenue = \Illuminate\Support\Facades\DB::table('subscriptions')->where('status', 'active')->sum('amount_aed'); $activeSubs = \Illuminate\Support\Facades\DB::table('subscriptions')->where('status', 'active')->count(); $failedPayments = \Illuminate\Support\Facades\DB::table('subscriptions')->where('status', 'failed')->count(); $avgTicket = \Illuminate\Support\Facades\DB::table('subscriptions')->where('status', 'active')->avg('amount_aed') ?: 0; $stats = [ 'total_revenue' => number_format($totalRevenue, 2), 'active_subscriptions' => $activeSubs, 'failed_payments' => $failedPayments, 'average_ticket' => number_format($avgTicket, 2), ]; return Inertia::render('Admin/Payments/Index', [ 'payments' => $payments, 'stats' => $stats ]); })->name('admin.payments'); Route::post('/payments/{id}/refund', [\App\Http\Controllers\Admin\AdminExtraController::class, 'refundPayment'])->name('admin.payments.refund'); Route::get('/master-data/skills', function () { $skills = \App\Models\Skill::all()->map(function ($skill) { return [ 'id' => $skill->id, 'name' => $skill->name, 'image_url' => $skill->image_path ? asset('storage/' . $skill->image_path) : null, 'worker_count' => \DB::table('worker_skills')->where('skill_id', $skill->id)->count(), 'status' => 'Active', ]; }); return Inertia::render('Admin/MasterData/WorkerSkills', [ 'skills' => $skills ]); })->name('admin.skills'); Route::post('/master-data/skills', function (\Illuminate\Http\Request $request) { $request->validate([ 'name' => 'required|string|max:255|unique:skills,name', 'image' => 'nullable|image|max:2048', ]); $imagePath = null; if ($request->hasFile('image')) { $imagePath = $request->file('image')->store('skills', 'public'); } \App\Models\Skill::create([ 'name' => strtolower($request->name), 'image_path' => $imagePath, ]); return redirect()->back(); })->name('admin.skills.store'); Route::post('/master-data/skills/{id}/update', function (\Illuminate\Http\Request $request, $id) { $request->validate([ 'name' => 'required|string|max:255|unique:skills,name,' . $id, 'image' => 'nullable|image|max:2048', ]); $skill = \App\Models\Skill::findOrFail($id); $imagePath = $skill->image_path; if ($request->hasFile('image')) { if ($imagePath) { \Storage::disk('public')->delete($imagePath); } $imagePath = $request->file('image')->store('skills', 'public'); } $skill->update([ 'name' => strtolower($request->name), 'image_path' => $imagePath, ]); return redirect()->back(); })->name('admin.skills.update'); Route::delete('/master-data/skills/{id}', function ($id) { $skill = \App\Models\Skill::findOrFail($id); if ($skill->image_path) { \Storage::disk('public')->delete($skill->image_path); } \DB::table('worker_skills')->where('skill_id', $id)->delete(); $skill->delete(); return redirect()->back(); })->name('admin.skills.delete'); Route::get('/master-data/reasons', function () { \DB::table('report_reasons')->whereIn('type', ['Both', 'Review'])->update(['type' => 'Chat']); $reasons = \App\Models\ReportReason::orderBy('id', 'desc')->get()->map(function ($reason) { return [ 'id' => $reason->id, 'reason' => $reason->reason, 'status' => $reason->status, 'type' => $reason->type, ]; }); return Inertia::render('Admin/MasterData/ReportReasons', [ 'reasons' => $reasons ]); })->name('admin.reasons'); Route::post('/master-data/reasons', function (\Illuminate\Http\Request $request) { $request->validate([ 'reason' => 'required|string|max:255|unique:report_reasons,reason', 'type' => 'required|string|in:Chat,Support', ]); \App\Models\ReportReason::create([ 'reason' => $request->reason, 'type' => $request->type, 'status' => 'Active', ]); return redirect()->back(); })->name('admin.reasons.store'); Route::post('/master-data/reasons/{id}/update', function (\Illuminate\Http\Request $request, $id) { $request->validate([ 'reason' => 'required|string|max:255|unique:report_reasons,reason,' . $id, 'status' => 'required|string|in:Active,Inactive', 'type' => 'required|string|in:Chat,Support', ]); $reason = \App\Models\ReportReason::findOrFail($id); $reason->update([ 'reason' => $request->reason, 'status' => $request->status, 'type' => $request->type, ]); return redirect()->back(); })->name('admin.reasons.update'); Route::delete('/master-data/reasons/{id}', function ($id) { $reason = \App\Models\ReportReason::findOrFail($id); $reason->delete(); return redirect()->back(); })->name('admin.reasons.delete'); Route::get('/events', [\App\Http\Controllers\Admin\AdminExtraController::class, 'announcements'])->name('admin.events'); Route::post('/events/create', [\App\Http\Controllers\Admin\AdminExtraController::class, 'storeAnnouncement'])->name('admin.events.store'); Route::post('/events/{id}/approve', [\App\Http\Controllers\Admin\AdminExtraController::class, 'approveAnnouncement'])->name('admin.events.approve'); Route::post('/events/{id}/reject', [\App\Http\Controllers\Admin\AdminExtraController::class, 'rejectAnnouncement'])->name('admin.events.reject'); Route::delete('/events/{id}', [\App\Http\Controllers\Admin\AdminExtraController::class, 'deleteAnnouncement'])->name('admin.events.delete'); // New Modules Added Route::get('/safety', [\App\Http\Controllers\Admin\AdminExtraController::class, 'safety'])->name('admin.safety'); Route::post('/safety/reports/{id}/resolve', [\App\Http\Controllers\Admin\AdminExtraController::class, 'resolveSafetyReport'])->name('admin.safety.resolve-report'); // Disputes have been consolidated into Help & Support module // Route::get('/disputes', [\App\Http\Controllers\Admin\AdminExtraController::class, 'disputes'])->name('admin.disputes'); // Route::post('/disputes/{id}/resolve', [\App\Http\Controllers\Admin\AdminExtraController::class, 'resolveDispute'])->name('admin.disputes.resolve'); // Route::post('/disputes/{id}/add-note', [\App\Http\Controllers\Admin\AdminExtraController::class, 'addDisputeNote'])->name('admin.disputes.add-note'); Route::get('/analytics', [\App\Http\Controllers\Admin\AdminExtraController::class, 'analytics'])->name('admin.analytics'); Route::get('/audit-logs', [\App\Http\Controllers\Admin\AdminExtraController::class, 'auditLogs'])->name('admin.audit-logs'); // Admin FAQs Management Route::get('/faqs', [\App\Http\Controllers\Admin\FaqController::class, 'index'])->name('admin.faqs'); Route::post('/faqs', [\App\Http\Controllers\Admin\FaqController::class, 'store'])->name('admin.faqs.store'); Route::post('/faqs/{id}', [\App\Http\Controllers\Admin\FaqController::class, 'update'])->name('admin.faqs.update'); Route::delete('/faqs/{id}', [\App\Http\Controllers\Admin\FaqController::class, 'destroy'])->name('admin.faqs.destroy'); // Admin Support Tickets Route::get('/tickets', [\App\Http\Controllers\Admin\SupportTicketController::class, 'index'])->name('admin.tickets.index'); Route::get('/tickets/{id}', [\App\Http\Controllers\Admin\SupportTicketController::class, 'show'])->name('admin.tickets.show'); Route::post('/tickets/{id}/reply', [\App\Http\Controllers\Admin\SupportTicketController::class, 'reply'])->name('admin.tickets.reply'); Route::post('/tickets/{id}/status', [\App\Http\Controllers\Admin\SupportTicketController::class, 'updateStatus'])->name('admin.tickets.update-status'); Route::post('/tickets/{id}/generate-dev-response', [\App\Http\Controllers\Admin\SupportTicketController::class, 'generateDevResponse'])->name('admin.tickets.generate-dev-response'); }); // Public Stats Route Route::get('/stats', function () { $totalWorkerProfiles = \App\Models\Worker::count(); $totalHiredAll = \App\Models\JobOffer::where('status', 'accepted')->count() + \App\Models\JobApplication::where('status', 'hired')->count(); $driver = \Illuminate\Support\Facades\DB::getDriverName(); $formatExpr = $driver === 'sqlite' ? "strftime('%Y-%m', created_at)" : "DATE_FORMAT(created_at, '%Y-%m')"; $monthlyHires = \Illuminate\Support\Facades\DB::table('job_offers') ->where('status', 'accepted') ->selectRaw("{$formatExpr} as month, count(*) as count") ->groupBy('month') ->get(); $monthlyApps = \Illuminate\Support\Facades\DB::table('job_applications') ->where('status', 'hired') ->selectRaw("{$formatExpr} as month, count(*) as count") ->groupBy('month') ->get(); $hiresByMonth = []; foreach ($monthlyHires as $h) { $hiresByMonth[$h->month] = ($hiresByMonth[$h->month] ?? 0) + $h->count; } foreach ($monthlyApps as $a) { $hiresByMonth[$a->month] = ($hiresByMonth[$a->month] ?? 0) + $a->count; } $avgMonthlyHires = count($hiresByMonth) > 0 ? (array_sum($hiresByMonth) / count($hiresByMonth)) : 0; $avgMonthlyHires = max(550, round($avgMonthlyHires)); return Inertia::render('Employer/PublicStats', [ 'total_workers' => max(3000, $totalWorkerProfiles), 'avg_hires' => (int)$avgMonthlyHires, 'total_hires_all' => max(100, $totalHiredAll) ]); })->name('public.stats'); // Employer Auth Routes — guest-only pages redirect logged-in employers to dashboard Route::middleware('employer.guest')->group(function () { Route::get('/employer/login', [\App\Http\Controllers\Employer\EmployerAuthController::class, 'showLogin'])->name('employer.login'); Route::get('/employer/register', [\App\Http\Controllers\Employer\EmployerAuthController::class, 'showRegister'])->name('employer.register'); Route::get('/employer/forgot-password', function () { return Inertia::render('Employer/Auth/ForgotPassword'); })->name('employer.forgot-password'); }); // Employer Auth POST/flow routes (no guest guard — mid-registration steps allowed) Route::post('/employer/login', [\App\Http\Controllers\Employer\EmployerAuthController::class, 'login'])->name('employer.login.submit'); Route::post('/employer/register', [\App\Http\Controllers\Employer\EmployerAuthController::class, 'register'])->name('employer.register.submit'); Route::get('/employer/verify-email', [\App\Http\Controllers\Employer\EmployerAuthController::class, 'showVerifyEmail'])->name('employer.verify-email'); Route::post('/employer/verify-email', [\App\Http\Controllers\Employer\EmployerAuthController::class, 'verifyEmail'])->name('employer.verify-email.submit')->middleware('throttle:5,1'); Route::post('/employer/resend-otp', [\App\Http\Controllers\Employer\EmployerAuthController::class, 'resendOtp'])->name('employer.resend-otp')->middleware('throttle:3,1'); Route::get('/employer/upload-emirates-id', [\App\Http\Controllers\Employer\EmployerAuthController::class, 'showUploadEmiratesId'])->name('employer.upload-emirates-id'); Route::post('/employer/upload-emirates-id', [\App\Http\Controllers\Employer\EmployerAuthController::class, 'uploadEmiratesId'])->name('employer.upload-emirates-id.submit'); Route::post('/employer/confirm-emirates-id', [\App\Http\Controllers\Employer\EmployerAuthController::class, 'confirmEmiratesId'])->name('employer.confirm-emirates-id.submit'); Route::get('/employer/register-payment', [\App\Http\Controllers\Employer\EmployerAuthController::class, 'showRegisterPayment'])->name('employer.register-payment'); Route::post('/employer/register-payment', [\App\Http\Controllers\Employer\EmployerAuthController::class, 'storeRegisterPayment'])->name('employer.register-payment.submit'); Route::get('/employer/create-password', [\App\Http\Controllers\Employer\EmployerAuthController::class, 'showCreatePassword'])->name('employer.create-password'); Route::post('/employer/create-password', [\App\Http\Controllers\Employer\EmployerAuthController::class, 'createPassword'])->name('employer.create-password.submit'); Route::post('/employer/logout', [\App\Http\Controllers\Employer\EmployerAuthController::class, 'logout'])->name('employer.logout'); Route::get('/employer/pending-verification', function () { return Inertia::render('Employer/Auth/PendingVerification'); })->name('employer.pending-verification'); Route::post('/employer/forgot-password', [\App\Http\Controllers\Employer\EmployerAuthController::class, 'forgotPassword'])->name('employer.forgot-password.submit'); Route::post('/employer/reset-password', [\App\Http\Controllers\Employer\EmployerAuthController::class, 'resetPassword'])->name('employer.reset-password.submit'); // Employer Protected Routes Route::prefix('employer')->middleware(['employer'])->group(function () { Route::get('/dashboard', [\App\Http\Controllers\Employer\DashboardController::class, 'index'])->name('employer.dashboard'); Route::get('/workers', [\App\Http\Controllers\Employer\WorkerController::class, 'index'])->name('employer.workers'); Route::get('/workers/{id}', [\App\Http\Controllers\Employer\WorkerController::class, 'show'])->name('employer.workers.show'); Route::get('/workers/{id}/hire', function ($id) { $worker = \App\Models\Worker::findOrFail($id); $workerData = [ 'id' => $worker->id, 'name' => $worker->name, 'nationality' => $worker->nationality, 'category' => $worker->preferred_job_type ?? 'Domestic Worker', 'salary' => (int) $worker->salary, ]; return Inertia::render('Employer/Hiring/Confirm', ['worker' => $workerData]); })->name('employer.hiring.confirm'); Route::post('/workers/{id}/hire', [\App\Http\Controllers\Employer\WorkerController::class, 'sendOffer'])->name('employer.workers.send-offer'); Route::post('/workers/{id}/mark-hired', [\App\Http\Controllers\Employer\WorkerController::class, 'markHired'])->name('employer.workers.mark-hired'); Route::get('/workers/{id}/hire/success', function ($id) { $worker = \App\Models\Worker::findOrFail($id); $workerData = [ 'id' => $worker->id, 'name' => $worker->name, ]; return Inertia::render('Employer/Hiring/Success', ['worker' => $workerData]); })->name('employer.hiring.success'); // Job Management Route::get('/jobs', [\App\Http\Controllers\Employer\JobController::class, 'index'])->name('employer.jobs'); Route::get('/jobs/create', [\App\Http\Controllers\Employer\JobController::class, 'create'])->name('employer.jobs.create'); Route::post('/jobs/create', [\App\Http\Controllers\Employer\JobController::class, 'store'])->name('employer.jobs.store'); Route::get('/jobs/all-applicants', [\App\Http\Controllers\Employer\JobController::class, 'allApplicants'])->name('employer.jobs.all-applicants'); Route::get('/jobs/shortlisted', [\App\Http\Controllers\Employer\JobController::class, 'shortlistedApplicants'])->name('employer.jobs.shortlisted'); Route::get('/jobs/{id}/edit', [\App\Http\Controllers\Employer\JobController::class, 'edit'])->name('employer.jobs.edit'); Route::post('/jobs/{id}/edit', [\App\Http\Controllers\Employer\JobController::class, 'update'])->name('employer.jobs.update'); Route::delete('/jobs/{id}', [\App\Http\Controllers\Employer\JobController::class, 'destroy'])->name('employer.jobs.destroy'); Route::get('/jobs/{id}', [\App\Http\Controllers\Employer\JobController::class, 'show'])->name('employer.jobs.show'); Route::post('/jobs/{id}/close', [\App\Http\Controllers\Employer\JobController::class, 'close'])->name('employer.jobs.close'); Route::get('/jobs/{id}/applicants', [\App\Http\Controllers\Employer\JobController::class, 'applicants'])->name('employer.jobs.applicants'); Route::get('/subscription', function () { $sess = session('user'); $sessId = is_array($sess) ? ($sess['id'] ?? null) : ($sess->id ?? null); $user = $sessId ? \App\Models\User::find($sessId) : \App\Models\User::where('role', 'employer')->first(); $sub = $user ? \Illuminate\Support\Facades\DB::table('subscriptions')->where('user_id', $user->id)->where('status', 'active')->latest('id')->first() : null; $dbPlans = \App\Models\Plan::where('status', 'Active')->get(); if ($dbPlans->isEmpty()) { $plans = [ [ 'id' => 'basic', 'name' => 'Basic Search', 'price' => '99 AED', 'period' => 'month', 'features' => ['Browse 500+ verified workers', 'Shortlist up to 10 candidates', 'Standard OCR verification'], 'popular' => false, ], [ 'id' => 'premium', 'name' => 'Premium Employer Pass', 'price' => '199 AED', 'period' => 'month', 'features' => ['Unlimited shortlisting', 'Direct candidate messaging', 'Priority interview scheduling', 'Dedicated support'], 'popular' => true, ], [ 'id' => 'vip', 'name' => 'VIP Concierge', 'price' => '499 AED', 'period' => 'month', 'features' => ['All Premium features', 'Assigned recruitment manager', 'Background medical verification guarantee', 'Free replacement within 30 days'], 'popular' => false, ], ]; } else { $plans = $dbPlans->map(function ($p) { $features = is_string($p->features) ? json_decode($p->features, true) : $p->features; return [ 'id' => $p->id, 'name' => $p->name, 'price' => round($p->price) . ' AED', 'period' => strtolower($p->duration) === 'monthly' ? 'month' : (strtolower($p->duration) === 'yearly' ? 'year' : 'period'), 'features' => $features ?: [], 'popular' => $p->id === 'premium', ]; })->toArray(); } $planName = 'Premium Employer Pass'; $expiresAt = '2026-12-31'; if ($sub) { $expiresAt = date('Y-m-d', strtotime($sub->expires_at)); $associatedPlan = \App\Models\Plan::find($sub->plan_id); $planName = $associatedPlan ? $associatedPlan->name : (ucfirst($sub->plan_id) . ' Pass'); } $invoices = []; if ($user) { $invoices = \Illuminate\Support\Facades\DB::table('subscriptions') ->leftJoin('plans', 'subscriptions.plan_id', '=', 'plans.id') ->where('subscriptions.user_id', $user->id) ->orderBy('subscriptions.created_at', 'desc') ->select('subscriptions.*', 'plans.name as plan_name') ->get() ->map(function($s) { $planLabel = $s->plan_name ?: (ucfirst($s->plan_id) . ' Pass'); $subStatus = strtolower($s->status); if ($subStatus !== 'active' && $subStatus !== 'pending' && $subStatus !== 'expired') { $subStatus = 'expired'; } return [ 'id' => 'INV-' . date('Y', strtotime($s->created_at)) . '-' . str_pad($s->id, 3, '0', STR_PAD_LEFT), 'plan_name' => $planLabel, 'purchase_date' => date('M d, Y', strtotime($s->created_at)), 'activation_date' => $s->starts_at ? date('M d, Y', strtotime($s->starts_at)) : 'N/A', 'expiry_date' => $s->expires_at ? date('M d, Y', strtotime($s->expires_at)) : 'N/A', 'amount' => round($s->amount_aed) . ' AED', 'payment_status' => 'Paid', 'status' => ucfirst($subStatus), ]; })->toArray(); } return Inertia::render('Employer/Subscription', [ 'currentPlan' => $planName, 'expiresAt' => $expiresAt, 'plans' => $plans, 'invoices' => $invoices ]); })->name('employer.subscription'); Route::get('/subscription/invoice/{id}/download', function ($id) { $dbId = 1; if (preg_match('/-(\d+)$/', $id, $matches)) { $dbId = (int)$matches[1]; } $sub = \Illuminate\Support\Facades\DB::table('subscriptions') ->where('id', $dbId) ->first(); $amountAed = $sub ? $sub->amount_aed : 199; $totalStr = round($amountAed) . '.00 AED'; $vatAed = round($amountAed * 0.05, 2); $subtotalAed = round($amountAed - $vatAed, 2); $vatStr = number_format($vatAed, 2) . ' AED'; $subtotalStr = number_format($subtotalAed, 2) . ' AED'; $planId = $sub ? $sub->plan_id : 'premium'; $planName = $planId === 'premium' ? 'Premium Employer Pass' : (ucfirst($planId) . ' Pass'); $date = $sub ? date('Y-m-d', strtotime($sub->created_at)) : date('Y-m-d'); $sponsorName = str_replace(['(', ')'], '', auth()->user()->name ?? 'Sponsor'); $sponsorEmail = str_replace(['(', ')'], '', auth()->user()->email ?? ''); $streamContent = "0.094 0.373 0.647 rg 0 742 400 100 re f\n" . "0.1 0.1 0.1 rg 400 742 195 100 re f\n" . // Left header text: Migrant name "BT\n/F2 26 Tf\n1 1 1 rg\n40 790 Td\n(Migrant) Tj\nET\n" . "BT\n/F1 10 Tf\n1 1 1 rg\n40 770 Td\n(SPONSOR PORTAL) Tj\nET\n" . // Right header text "BT\n/F2 26 Tf\n1 1 1 rg\n430 790 Td\n(Invoice) Tj\nET\n" . "BT\n/F1 10 Tf\n1 1 1 rg\n430 770 Td\n(Status: Paid) Tj\nET\n" . // From & To section "BT\n/F2 12 Tf\n0.2 0.2 0.2 rg\n40 690 Td\n(From:) Tj\nET\n" . "BT\n/F1 10 Tf\n0.4 0.4 0.4 rg\n40 670 Td\n(DirectMarket Portal) Tj\nET\n" . "BT\n/F1 10 Tf\n0.4 0.4 0.4 rg\n40 655 Td\n(Address: MOHRE Sponsor Services, Dubai, UAE) Tj\nET\n" . "BT\n/F1 10 Tf\n0.4 0.4 0.4 rg\n40 640 Td\n(Email: support@directmarket.ae) Tj\nET\n" . "BT\n/F2 12 Tf\n0.2 0.2 0.2 rg\n320 690 Td\n(To:) Tj\nET\n" . "BT\n/F1 10 Tf\n0.4 0.4 0.4 rg\n320 670 Td\n(" . $sponsorName . ") Tj\nET\n" . "BT\n/F1 10 Tf\n0.4 0.4 0.4 rg\n320 655 Td\n(Email: " . $sponsorEmail . ") Tj\nET\n" . "BT\n/F1 10 Tf\n0.4 0.4 0.4 rg\n320 640 Td\n(Verification: Approved) Tj\nET\n" . // Table Header "0.094 0.373 0.647 rg 40 580 360 25 re f\n" . "0.1 0.1 0.1 rg 400 580 155 25 re f\n" . "BT\n/F2 10 Tf\n1 1 1 rg\n50 588 Td\n(# Item) Tj\n110 0 Td\n(Description) Tj\nET\n" . "BT\n/F2 10 Tf\n1 1 1 rg\n410 588 Td\n(Unit Cost) Tj\n80 0 Td\n(Total) Tj\nET\n" . // Row 1 "0.96 0.96 0.96 rg 40 550 515 25 re f\n" . "BT\n/F1 10 Tf\n0.2 0.2 0.2 rg\n50 558 Td\n(1 Sponsor Pass) Tj\n110 0 Td\n(" . $planName . " Tier) Tj\nET\n" . "BT\n/F1 10 Tf\n0.2 0.2 0.2 rg\n410 558 Td\n(" . $totalStr . ") Tj\n80 0 Td\n(" . $totalStr . ") Tj\nET\n" . "0.8 0.8 0.8 RG 40 550 m 555 550 l S\n" . // Summary block "BT\n/F2 10 Tf\n0.3 0.3 0.3 rg\n350 510 Td\n(Subtotal) Tj\n140 0 Td\n(" . $subtotalStr . ") Tj\nET\n" . "0.9 0.9 0.9 RG 350 500 m 555 500 l S\n" . "BT\n/F2 10 Tf\n0.3 0.3 0.3 rg\n350 480 Td\n(VAT (5%)) Tj\n140 0 Td\n(" . $vatStr . ") Tj\nET\n" . "0.9 0.9 0.9 RG 350 470 m 555 470 l S\n" . "0.094 0.373 0.647 rg 350 435 205 25 re f\n" . "BT\n/F2 10 Tf\n1 1 1 rg\n360 443 Td\n(Total) Tj\n130 0 Td\n(" . $totalStr . ") Tj\nET\n" . // Date & Disclaimer "BT\n/F2 10 Tf\n0.2 0.2 0.2 rg\n40 370 Td\n(Date: " . $date . ") Tj\nET\n" . "BT\n/F2 10 Tf\n0.094 0.373 0.647 rg\n40 330 Td\n(Important:) Tj\nET\n" . "BT\n/F1 9 Tf\n0.4 0.4 0.4 rg\n40 310 Td\n(This is an electronically generated invoice and does not require a physical signature.) Tj\nET\n" . "BT\n/F1 9 Tf\n0.4 0.4 0.4 rg\n40 295 Td\n(Please read all terms and policies on www.directmarket.ae for refunds or queries.) Tj\nET\n" . // Footer Waves "0.1 0.1 0.1 rg 0 0 m 0 50 l 150 25 450 75 595 40 c 595 0 l f\n" . "0.094 0.373 0.647 rg 0 0 m 0 35 l 200 55 400 20 595 50 c 595 0 l f\n"; $pdf = "%PDF-1.4\n" . "1 0 obj <> endobj\n" . "2 0 obj <> endobj\n" . "3 0 obj <> endobj\n" . "4 0 obj <>>> endobj\n" . "5 0 obj <> stream\n" . $streamContent . "\nendstream\nendobj\n" . "6 0 obj <> endobj\n" . "7 0 obj <> endobj\n" . "xref\n" . "0 8\n" . "0000000000 65535 f \n" . "trailer <>\n" . "startxref\n" . "%%EOF\n"; return response($pdf) ->header('Content-Type', 'application/pdf') ->header('Content-Disposition', 'attachment; filename="Invoice-' . $id . '.pdf"'); })->name('employer.subscription.invoice.download'); Route::post('/subscription/purchase', [\App\Http\Controllers\Employer\PaymentController::class, 'purchase'])->name('employer.subscription.purchase'); Route::get('/messages', [\App\Http\Controllers\Employer\MessageController::class, 'index'])->name('employer.messages'); Route::get('/messages/{id}', [\App\Http\Controllers\Employer\MessageController::class, 'show'])->name('employer.messages.show'); Route::post('/messages/{id}/send', [\App\Http\Controllers\Employer\MessageController::class, 'send'])->name('employer.messages.send'); Route::get('/messages/start/{workerId}', [\App\Http\Controllers\Employer\MessageController::class, 'startConversation'])->name('employer.messages.start'); Route::get('/shortlist', [\App\Http\Controllers\Employer\ShortlistController::class, 'index'])->name('employer.shortlist'); Route::post('/shortlist/toggle', [\App\Http\Controllers\Employer\ShortlistController::class, 'toggle'])->name('employer.shortlist.toggle'); Route::post('/shortlist/{id}/remove', [\App\Http\Controllers\Employer\ShortlistController::class, 'remove'])->name('employer.shortlist.remove'); Route::get('/candidates', [\App\Http\Controllers\Employer\CandidateController::class, 'index'])->name('employer.candidates'); Route::post('/candidates/{id}/status', [\App\Http\Controllers\Employer\CandidateController::class, 'updateStatus'])->name('employer.candidates.status'); Route::get('/events', [\App\Http\Controllers\Employer\AnnouncementController::class, 'index'])->name('employer.events'); Route::post('/events/create', [\App\Http\Controllers\Employer\AnnouncementController::class, 'store'])->name('employer.events.store'); Route::get('/profile', [\App\Http\Controllers\Employer\ProfileController::class, 'index'])->name('employer.profile'); Route::get('/profile/edit', [\App\Http\Controllers\Employer\ProfileController::class, 'edit'])->name('employer.profile.edit'); Route::post('/profile/update', [\App\Http\Controllers\Employer\ProfileController::class, 'update'])->name('employer.profile.update'); Route::get('/payments', [\App\Http\Controllers\Employer\PaymentController::class, 'index'])->name('employer.payments'); // Employer Support Tickets Route::get('/support', [\App\Http\Controllers\Employer\SupportTicketController::class, 'index'])->name('employer.support.index'); Route::get('/support/create', [\App\Http\Controllers\Employer\SupportTicketController::class, 'create'])->name('employer.support.create'); Route::post('/support/create', [\App\Http\Controllers\Employer\SupportTicketController::class, 'store'])->name('employer.support.store'); Route::get('/support/{id}', [\App\Http\Controllers\Employer\SupportTicketController::class, 'show'])->name('employer.support.show'); Route::post('/support/{id}/reply', [\App\Http\Controllers\Employer\SupportTicketController::class, 'reply'])->name('employer.support.reply'); }); Route::get('/api/documentation', function () { return view('swagger'); })->name('api.documentation'); Route::redirect('/api/documention', '/api/documentation');