attributes->get('worker'); $query = JobPost::where('status', 'active') ->with(['employer.employerProfile', 'skills']); if ($worker) { $workerProfession = trim($worker->main_profession); $workerSkillIds = $worker->skills->pluck('id')->toArray(); if ($workerProfession !== '' || !empty($workerSkillIds)) { $query->where(function($q) use ($workerProfession, $workerSkillIds) { if ($workerProfession !== '') { $q->where(\Illuminate\Support\Facades\DB::raw('LOWER(main_profession)'), strtolower($workerProfession)); } if (!empty($workerSkillIds)) { $q->orWhereHas('skills', function ($q2) use ($workerSkillIds) { $q2->whereIn('skills.id', $workerSkillIds); }); } }); } } $jobs = $query->latest() ->get() ->map(function ($job) { return [ 'id' => $job->id, 'title' => $job->title, 'main_profession' => $job->main_profession, 'skills' => $job->skills->pluck('name')->toArray(), 'location' => $job->location, 'salary' => (int) $job->salary, 'workers_needed' => $job->workers_needed, 'job_type' => $job->job_type, 'start_date' => $job->start_date ? $job->start_date->format('Y-m-d') : null, 'description' => $job->description, 'requirements' => $job->requirements, 'company_name' => $job->employer->employerProfile->company_name ?? 'Private Sponsor', 'posted_by' => $job->employer->name ?? 'Private Sponsor', 'posted_at' => $job->created_at->toIso8601String(), ]; }); return response()->json([ 'success' => true, 'data' => [ 'jobs' => $jobs ] ]); } /** * API to retrieve job details. * GET /api/workers/jobs/{id} */ public function jobDetails($id) { $job = JobPost::where('status', 'active') ->with(['employer.employerProfile', 'skills']) ->find($id); if (!$job) { return response()->json([ 'success' => false, 'message' => 'Job not found.' ], 404); } return response()->json([ 'success' => true, 'data' => [ 'job' => [ 'id' => $job->id, 'title' => $job->title, 'main_profession' => $job->main_profession, 'skills' => $job->skills->pluck('name')->toArray(), 'location' => $job->location, 'salary' => (int) $job->salary, 'workers_needed' => $job->workers_needed, 'job_type' => $job->job_type, 'start_date' => $job->start_date ? $job->start_date->format('Y-m-d') : null, 'description' => $job->description, 'requirements' => $job->requirements, 'company_name' => $job->employer->employerProfile->company_name ?? 'Private Sponsor', 'posted_by' => $job->employer->name ?? 'Private Sponsor', 'posted_at' => $job->created_at->toIso8601String(), ] ] ]); } /** * API for workers to apply for a job. * POST /api/workers/jobs/{id}/apply */ public function applyJob(Request $request, $id) { /** @var Worker $worker */ $worker = $request->attributes->get('worker'); $job = JobPost::where('status', 'active')->find($id); if (!$job) { return response()->json([ 'success' => false, 'message' => 'Job not found.' ], 404); } // Prevent duplicate applications $exists = JobApplication::where('worker_id', $worker->id) ->where('job_id', $job->id) ->exists(); if ($exists) { return response()->json([ 'success' => false, 'message' => 'You have already applied for this job.' ], 409); } $application = JobApplication::create([ 'worker_id' => $worker->id, 'job_id' => $job->id, 'status' => 'applied' ]); $employer = $job->employer; if ($employer) { $employer->notify(new \App\Notifications\GenericNotification( "New Job Application", "A worker (" . ($worker->name ?? 'Candidate') . ") has applied for your job: " . ($job->title ?? 'Job Post'), [ 'type' => 'job_application_submitted', 'job_id' => $job->id, 'application_id' => $application->id, ] )); } return response()->json([ 'success' => true, 'message' => 'Successfully applied for the job.', 'data' => [ 'application' => $application ] ], 201); } /** * API for workers to view their applied jobs. * GET /api/workers/applied-jobs */ public function appliedJobs(Request $request) { /** @var Worker $worker */ $worker = $request->attributes->get('worker'); $applications = JobApplication::where('worker_id', $worker->id) ->with(['jobPost.employer.employerProfile']) ->latest() ->get() ->map(function ($app) { $job = $app->jobPost; return [ 'application_id' => $app->id, 'status' => $app->status, 'applied_at' => $app->created_at->toIso8601String(), 'job' => $job ? [ 'id' => $job->id, 'title' => $job->title, 'location' => $job->location, 'salary' => (int) $job->salary, 'job_type' => $job->job_type, 'company_name' => $job->employer->employerProfile->company_name ?? 'Private Sponsor', 'posted_by' => $job->employer->name ?? 'Private Sponsor', ] : null ]; }); return response()->json([ 'success' => true, 'data' => [ 'applications' => $applications ] ]); } private function checkJobAccess($employerId) { $sub = \Illuminate\Support\Facades\DB::table('subscriptions') ->where('user_id', $employerId) ->where('status', 'active') ->latest('id') ->first(); $planId = $sub ? $sub->plan_id : 'basic'; return $planId !== 'basic'; } /** * API for employers to list their jobs. * GET /api/employers/jobs */ public function employerListJobs(Request $request) { /** @var User $employer */ $employer = $request->attributes->get('employer'); if (!$this->checkJobAccess($employer->id)) { return response()->json([ 'success' => false, 'message' => 'Your current plan does not support the Job Apply module. Please upgrade to a Premium plan to access this feature.' ], 403); } $jobs = JobPost::where('employer_id', $employer->id) ->with(['applications']) ->latest() ->get() ->map(function ($job) { return [ 'id' => $job->id, 'title' => $job->title, 'location' => $job->location, 'salary' => (int) $job->salary, 'workers_needed' => $job->workers_needed, 'job_type' => $job->job_type, 'start_date' => $job->start_date ? $job->start_date->format('Y-m-d') : null, 'description' => $job->description, 'requirements' => $job->requirements, 'applied_count' => $job->applications->count(), 'posted_at' => $job->created_at->toIso8601String(), 'status' => $job->status, ]; }); return response()->json([ 'success' => true, 'data' => [ 'jobs' => $jobs ] ]); } /** * API for employers to create a job. * POST /api/employers/jobs */ public function employerCreateJob(Request $request) { /** @var User $employer */ $employer = $request->attributes->get('employer'); if (!$this->checkJobAccess($employer->id)) { return response()->json([ 'success' => false, 'message' => 'Your current plan does not support the Job Apply module. Please upgrade to a Premium plan to access this feature.' ], 403); } $validator = Validator::make($request->all(), [ 'title' => 'required|string|max:255', 'main_profession' => 'required|string|max:255', 'skills' => 'required', 'workers_needed' => 'required|integer|min:1', 'location' => 'required|string|max:255', 'salary' => 'required|numeric|min:0', 'job_type' => 'required|string|in:Full Time,Part Time,Contract', 'start_date' => 'required|date', 'description' => 'required|string|max:1000', 'requirements' => 'nullable|string', ]); if ($validator->fails()) { return response()->json([ 'success' => false, 'message' => 'Validation error.', 'errors' => $validator->errors() ], 422); } $job = JobPost::create([ 'employer_id' => $employer->id, 'title' => $request->title, 'main_profession' => $request->main_profession, 'workers_needed' => $request->workers_needed, 'job_type' => $request->job_type, 'location' => $request->location, 'salary' => $request->salary, 'start_date' => $request->start_date, 'description' => $request->description, 'requirements' => $request->requirements, 'status' => 'active', ]); // Sync skills $skillsInput = $request->skills; $skillIds = []; if (is_array($skillsInput)) { foreach ($skillsInput as $skillNameOrId) { if (is_numeric($skillNameOrId)) { $skillIds[] = (int)$skillNameOrId; } else { $skill = \App\Models\Skill::firstOrCreate(['name' => trim($skillNameOrId)]); $skillIds[] = $skill->id; } } } else if (is_string($skillsInput)) { $skillsArray = array_filter(array_map('trim', explode(',', $skillsInput))); foreach ($skillsArray as $name) { $skill = \App\Models\Skill::firstOrCreate(['name' => $name]); $skillIds[] = $skill->id; } } $job->skills()->sync($skillIds); return response()->json([ 'success' => true, 'message' => 'Job posted successfully.', 'data' => [ 'job' => [ 'id' => $job->id, 'title' => $job->title, 'main_profession' => $job->main_profession, 'skills' => $job->skills()->pluck('name')->toArray(), 'location' => $job->location, 'salary' => (int) $job->salary, 'workers_needed' => $job->workers_needed, 'job_type' => $job->job_type, 'start_date' => $job->start_date ? $job->start_date->format('Y-m-d') : null, 'description' => $job->description, 'requirements' => $job->requirements, 'posted_at' => $job->created_at->toIso8601String(), 'status' => $job->status, ] ] ], 201); } /** * API for employers to retrieve details of a specific job. * GET /api/employers/jobs/{id} */ public function employerJobDetail(Request $request, $id) { /** @var User $employer */ $employer = $request->attributes->get('employer'); if (!$this->checkJobAccess($employer->id)) { return response()->json([ 'success' => false, 'message' => 'Your current plan does not support the Job Apply module. Please upgrade to a Premium plan to access this feature.' ], 403); } $job = JobPost::where('employer_id', $employer->id) ->with(['applications']) ->find($id); if (!$job) { return response()->json([ 'success' => false, 'message' => 'Job not found or unauthorized.' ], 404); } return response()->json([ 'success' => true, 'data' => [ 'job' => [ 'id' => $job->id, 'title' => $job->title, 'location' => $job->location, 'salary' => (int) $job->salary, 'workers_needed' => $job->workers_needed, 'job_type' => $job->job_type, 'start_date' => $job->start_date ? $job->start_date->format('Y-m-d') : null, 'description' => $job->description, 'requirements' => $job->requirements, 'applied_count' => $job->applications->count(), 'posted_at' => $job->created_at->toIso8601String(), 'status' => $job->status, ] ] ]); } /** * API for employers to update a specific job. * POST /api/employers/jobs/{id}/update */ public function employerUpdateJob(Request $request, $id) { /** @var User $employer */ $employer = $request->attributes->get('employer'); if (!$this->checkJobAccess($employer->id)) { return response()->json([ 'success' => false, 'message' => 'Your current plan does not support the Job Apply module. Please upgrade to a Premium plan to access this feature.' ], 403); } $job = JobPost::where('employer_id', $employer->id)->find($id); if (!$job) { return response()->json([ 'success' => false, 'message' => 'Job not found or unauthorized.' ], 404); } if ($job->applications()->exists()) { return response()->json([ 'success' => false, 'message' => 'This job cannot be edited because workers have already applied for it.' ], 422); } $validator = Validator::make($request->all(), [ 'title' => 'required|string|max:255', 'main_profession' => 'required|string|max:255', 'skills' => 'required', 'workers_needed' => 'required|integer|min:1', 'location' => 'required|string|max:255', 'salary' => 'required|numeric|min:0', 'job_type' => 'required|string|in:Full Time,Part Time,Contract', 'start_date' => 'required|date', 'description' => 'required|string|max:1000', 'requirements' => 'nullable|string', 'status' => 'required|string|in:active,closed,draft', ]); if ($validator->fails()) { return response()->json([ 'success' => false, 'message' => 'Validation error.', 'errors' => $validator->errors() ], 422); } $job->update([ 'title' => $request->title, 'main_profession' => $request->main_profession, 'workers_needed' => $request->workers_needed, 'job_type' => $request->job_type, 'location' => $request->location, 'salary' => $request->salary, 'start_date' => $request->start_date, 'description' => $request->description, 'requirements' => $request->requirements, 'status' => strtolower($request->status), ]); // Sync skills $skillsInput = $request->skills; $skillIds = []; if (is_array($skillsInput)) { foreach ($skillsInput as $skillNameOrId) { if (is_numeric($skillNameOrId)) { $skillIds[] = (int)$skillNameOrId; } else { $skill = \App\Models\Skill::firstOrCreate(['name' => trim($skillNameOrId)]); $skillIds[] = $skill->id; } } } else if (is_string($skillsInput)) { $skillsArray = array_filter(array_map('trim', explode(',', $skillsInput))); foreach ($skillsArray as $name) { $skill = \App\Models\Skill::firstOrCreate(['name' => $name]); $skillIds[] = $skill->id; } } $job->skills()->sync($skillIds); return response()->json([ 'success' => true, 'message' => 'Job updated successfully.', 'data' => [ 'job' => [ 'id' => $job->id, 'title' => $job->title, 'main_profession' => $job->main_profession, 'skills' => $job->skills()->pluck('name')->toArray(), 'location' => $job->location, 'salary' => (int) $job->salary, 'workers_needed' => $job->workers_needed, 'job_type' => $job->job_type, 'start_date' => $job->start_date ? $job->start_date->format('Y-m-d') : null, 'description' => $job->description, 'requirements' => $job->requirements, 'posted_at' => $job->created_at->toIso8601String(), 'status' => $job->status, ] ] ]); } /** * API for employers to delete a job. * DELETE /api/employers/jobs/{id} */ public function employerDeleteJob(Request $request, $id) { /** @var User $employer */ $employer = $request->attributes->get('employer'); if (!$this->checkJobAccess($employer->id)) { return response()->json([ 'success' => false, 'message' => 'Your current plan does not support the Job Apply module. Please upgrade to a Premium plan to access this feature.' ], 403); } $job = JobPost::where('employer_id', $employer->id)->find($id); if (!$job) { return response()->json([ 'success' => false, 'message' => 'Job not found or unauthorized.' ], 404); } $job->delete(); return response()->json([ 'success' => true, 'message' => 'Job deleted successfully.' ]); } /** * API for employers to view applicants for each job. * GET /api/employers/jobs/{id}/applicants */ public function employerJobApplicants(Request $request, $id) { /** @var User $employer */ $employer = $request->attributes->get('employer'); if (!$this->checkJobAccess($employer->id)) { return response()->json([ 'success' => false, 'message' => 'Your current plan does not support the Job Apply module. Please upgrade to a Premium plan to access this feature.' ], 403); } $job = JobPost::where('employer_id', $employer->id)->find($id); if (!$job) { return response()->json([ 'success' => false, 'message' => 'Job not found or unauthorized.' ], 404); } $query = JobApplication::where('job_id', $job->id) ->with(['worker.skills']); // Search filter: name, nationality if ($request->filled('search')) { $search = $request->search; $query->whereHas('worker', function($q) use ($search) { $q->where('name', 'like', "%{$search}%") ->orWhere('nationality', 'like', "%{$search}%"); }); } // Status filter if ($request->filled('status')) { $query->where('status', strtolower($request->status)); } $sortBy = $request->input('sort_by', 'created_at'); $sortOrder = $request->input('sort_order', 'desc'); if ($sortBy === 'created_at' || $sortBy === 'applied_at') { $query->orderBy('created_at', $sortOrder === 'asc' ? 'asc' : 'desc'); } $applicants = $query->get()->map(function ($app) use ($employer) { $w = $app->worker; if (!$w) return null; // Check if worker is saved in Saved Workers (Shortlist) $isSaved = \App\Models\Shortlist::where('employer_id', $employer->id) ->where('worker_id', $w->id) ->exists(); return [ 'application_id' => $app->id, 'status' => $app->status, 'notes' => $app->notes, 'status_history' => $app->status_history ?: [], 'applied_at' => $app->created_at->toIso8601String(), 'is_saved' => $isSaved, 'worker' => [ 'id' => $w->id, 'name' => $w->name, 'nationality' => $w->nationality, 'salary' => (int) $w->salary, 'preferred_location' => $w->preferred_location, 'preferred_job_type' => $w->preferred_job_type, 'visa_status' => $w->visa_status, 'experience' => $w->experience, 'skills' => $w->skills->pluck('name')->toArray(), ] ]; })->filter()->values(); return response()->json([ 'success' => true, 'data' => [ 'job' => [ 'id' => $job->id, 'title' => $job->title, ], 'applicants' => $applicants ] ]); } /** * API for employers to update application status. * POST /api/employers/applications/{id}/status */ public function employerUpdateApplicationStatus(Request $request, $id) { /** @var User $employer */ $employer = $request->attributes->get('employer'); if (!$this->checkJobAccess($employer->id)) { return response()->json([ 'success' => false, 'message' => 'Your current plan does not support the Job Apply module. Please upgrade to a Premium plan to access this feature.' ], 403); } $validator = Validator::make($request->all(), [ 'status' => 'required|string|in:applied,shortlisted,contacted,interview scheduled,interview_scheduled,selected,rejected,hired,hire_requested', 'notes' => 'nullable|string', ]); if ($validator->fails()) { return response()->json([ 'success' => false, 'message' => 'Validation error.', 'errors' => $validator->errors() ], 422); } $application = JobApplication::where('id', $id) ->whereHas('jobPost', function($q) use ($employer) { $q->where('employer_id', $employer->id); })->first(); if (!$application) { return response()->json([ 'success' => false, 'message' => 'Job application not found or unauthorized.' ], 404); } $dbStatus = strtolower($request->status); if ($dbStatus === 'hired') { $dbStatus = 'hire_requested'; } // Contact Limit check: if moving to 'shortlisted', 'contacted', 'interview_scheduled', 'selected', 'hired', 'hire_requested' $contactStatuses = ['shortlisted', 'contacted', 'interview_scheduled', 'selected', 'hired', 'hire_requested']; if (in_array($dbStatus, $contactStatuses)) { if (!User::canContactWorker($employer->id, $application->worker_id)) { $activeSub = \App\Models\Subscription::where('user_id', $employer->id)->where('status', 'active')->first(); $planId = $activeSub ? $activeSub->plan_id : 'basic'; $plan = \App\Models\Plan::find($planId); $maxContacts = $plan ? $plan->max_contact_people : 10; return response()->json([ 'success' => false, 'message' => 'You have reached your contacted workers limit of ' . $maxContacts . ' under your active plan. Please upgrade or renew your subscription to contact more workers.' ], 403); } } $notes = $request->input('notes'); // Update application status & history $history = $application->status_history ?: []; $history[] = [ 'status' => $dbStatus, 'timestamp' => now()->toIso8601String(), 'notes' => $notes, ]; $updateData = [ 'status' => $dbStatus, 'status_history' => $history, ]; if ($notes !== null) { $updateData['notes'] = $notes; } $application->update($updateData); // If shortlisted, automatically add to Saved Workers (Shortlist table) if not already saved if ($dbStatus === 'shortlisted') { $exists = \App\Models\Shortlist::where('employer_id', $employer->id) ->where('worker_id', $application->worker_id) ->exists(); if (!$exists) { \App\Models\Shortlist::create([ 'employer_id' => $employer->id, 'worker_id' => $application->worker_id, ]); } } if ($dbStatus === 'rejected') { if ($application->worker) { $application->worker->update(['status' => 'active']); } } // Trigger notifications $this->triggerStatusNotification($application, $dbStatus); return response()->json([ 'success' => true, 'message' => 'Application status updated successfully.', 'data' => [ 'application' => $application->fresh() ] ]); } /** * API for workers to view details of a specific job application. * GET /api/workers/applied-jobs/{id} */ public function appliedJobDetail(Request $request, $id) { /** @var Worker $worker */ $worker = $request->attributes->get('worker'); $application = JobApplication::where('worker_id', $worker->id) ->with(['jobPost.employer.employerProfile']) ->find($id); if (!$application) { return response()->json([ 'success' => false, 'message' => 'Application not found.' ], 404); } $job = $application->jobPost; return response()->json([ 'success' => true, 'data' => [ 'application' => [ 'id' => $application->id, 'status' => $application->status, 'status_history' => $application->status_history ?: [], 'applied_at' => $application->created_at->toIso8601String(), 'job' => $job ? [ 'id' => $job->id, 'title' => $job->title, 'location' => $job->location, 'salary' => (int) $job->salary, 'job_type' => $job->job_type, 'description' => $job->description, 'requirements' => $job->requirements, 'company_name' => $job->employer->employerProfile->company_name ?? 'Private Sponsor', 'posted_by' => $job->employer->name ?? 'Private Sponsor', 'posted_at' => $job->created_at->toIso8601String(), ] : null ] ] ]); } /** * API for workers to withdraw their job application. * POST /api/workers/applied-jobs/{id}/withdraw */ public function withdrawApplication(Request $request, $id) { /** @var Worker $worker */ $worker = $request->attributes->get('worker'); $application = JobApplication::where('worker_id', $worker->id)->find($id); if (!$application) { return response()->json([ 'success' => false, 'message' => 'Application not found.' ], 404); } if (strtolower($application->status) !== 'applied') { return response()->json([ 'success' => false, 'message' => 'You can only withdraw applications that are still in "Applied" status.' ], 400); } $application->delete(); return response()->json([ 'success' => true, 'message' => 'Application successfully withdrawn.' ]); } /** * API for workers to confirm a hire request. * POST /api/workers/applied-jobs/{id}/confirm-hire */ public function confirmHire(Request $request, $id) { /** @var Worker $worker */ $worker = $request->attributes->get('worker'); $application = JobApplication::where('worker_id', $worker->id)->find($id); if (!$application) { return response()->json([ 'success' => false, 'message' => 'Application not found.' ], 404); } if (strtolower($application->status) !== 'hire_requested') { return response()->json([ 'success' => false, 'message' => 'This application is not pending confirmation.' ], 400); } // Update application status $history = $application->status_history ?: []; $history[] = [ 'status' => 'hired', 'timestamp' => now()->toIso8601String(), 'notes' => 'Hiring confirmed by worker.', ]; $application->update([ 'status' => 'hired', 'status_history' => $history, 'joining_confirmed_at' => now(), ]); // Update worker status $worker->update([ 'status' => 'Hired', 'availability' => 'Hired' ]); // Create/update the JobOffer record to satisfy the Worker Employer List API $job = $application->jobPost; $employer = $job ? $job->employer : null; if ($employer) { \App\Models\JobOffer::updateOrCreate( [ 'employer_id' => $employer->id, 'worker_id' => $worker->id, ], [ 'work_date' => $job->start_date ?? now(), 'location' => $job->location ?? 'Dubai', 'salary' => $job->salary ?? 0, 'status' => 'accepted', 'notes' => $application->notes ?? 'Hired through Job Application', ] ); // Notify Employer: Hire confirmation $employer->notify(new \App\Notifications\GenericNotification( "Hire Confirmation", "Worker " . ($worker->name ?? "Candidate") . " has confirmed the hiring for '" . ($job->title ?? 'Job Post') . "'.", [ 'type' => 'hire_confirmation', 'job_id' => $job->id, 'application_id' => $application->id, ] )); } // Notify Worker: Hired $worker->notify(new \App\Notifications\GenericNotification( "Congratulations! You've been Hired", "You are now officially hired for: '" . ($job->title ?? 'Job Post') . "'.", [ 'type' => 'hired', 'job_id' => $job->id, 'application_id' => $application->id, ] )); return response()->json([ 'success' => true, 'message' => 'Hiring confirmed successfully.', 'data' => [ 'application' => $application->fresh() ] ]); } /** * API for workers to decline a hire request. * POST /api/workers/applied-jobs/{id}/decline-hire */ public function declineHire(Request $request, $id) { /** @var Worker $worker */ $worker = $request->attributes->get('worker'); $application = JobApplication::where('worker_id', $worker->id)->find($id); if (!$application) { return response()->json([ 'success' => false, 'message' => 'Application not found.' ], 404); } if (strtolower($application->status) !== 'hire_requested') { return response()->json([ 'success' => false, 'message' => 'This application is not pending confirmation.' ], 400); } // Update application status back to declined $history = $application->status_history ?: []; $history[] = [ 'status' => 'declined', 'timestamp' => now()->toIso8601String(), 'notes' => 'Hiring declined by worker.', ]; $application->update([ 'status' => 'declined', 'status_history' => $history, ]); $job = $application->jobPost; $employer = $job ? $job->employer : null; if ($employer) { // Notify Employer: Hire declined $employer->notify(new \App\Notifications\GenericNotification( "Hire Request Declined", "Worker " . ($worker->name ?? "Candidate") . " has declined the hiring request for '" . ($job->title ?? 'Job Post') . "'.", [ 'type' => 'hire_declined', 'job_id' => $job->id, 'application_id' => $application->id, ] )); } return response()->json([ 'success' => true, 'message' => 'Hiring request declined successfully.', 'data' => [ 'application' => $application->fresh() ] ]); } /** * Dispatch FCM Push Notification & In-app database notifications. */ private function triggerStatusNotification($application, $status) { $worker = $application->worker; $job = $application->jobPost; $employer = $job ? $job->employer : null; // When a new application is submitted: notify employer if ($status === 'applied') { if ($employer) { $employer->notify(new \App\Notifications\GenericNotification( "New Job Application", "A candidate has applied for your job: " . ($job->title ?? 'Job Post'), [ 'type' => 'job_application_submitted', 'job_id' => $job->id, 'application_id' => $application->id, ] )); } return; } // When status is updated: notify worker if ($worker) { $title = "Job Application Update"; $body = ""; $type = 'job_application_status_update'; switch (strtolower($status)) { case 'shortlisted': $body = "You have been shortlisted for the job: " . ($job->title ?? 'Job Post'); $type = 'shortlisted'; break; case 'review': case 'reviewing': $body = "Your application is under review for the job: " . ($job->title ?? 'Job Post'); $type = 'review'; break; case 'contacted': $body = "An employer wants to contact you regarding the job: " . ($job->title ?? 'Job Post'); $type = 'contacted'; break; case 'interview scheduled': case 'interview_scheduled': $body = "An interview has been scheduled for the job: " . ($job->title ?? 'Job Post'); $type = 'interview_scheduled'; break; case 'selected': $body = "Congratulations! You have been selected for the job: " . ($job->title ?? 'Job Post'); $type = 'selected'; break; case 'rejected': $body = "Your application for the job: " . ($job->title ?? 'Job Post') . " has been reviewed and rejected."; $type = 'rejected'; break; case 'hire_requested': $title = "Action Required: Confirm Hiring"; $body = "An employer wants to hire you for the job: " . ($job->title ?? 'Job Post') . ". Please confirm."; $type = 'hire_request'; break; case 'hired': $body = "Congratulations! You have been hired for the job: " . ($job->title ?? 'Job Post'); $type = 'hired'; break; default: $body = "Your application status for the job: " . ($job->title ?? 'Job Post') . " has changed to " . ucfirst($status); break; } $worker->notify(new \App\Notifications\GenericNotification( $title, $body, [ 'type' => $type, 'job_id' => $job->id ?? '', 'application_id' => $application->id, 'status' => $status, ] )); } } }