542 lines
20 KiB
PHP

<?php
namespace App\Http\Controllers\Employer;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Inertia\Inertia;
use App\Models\User;
use App\Models\JobPost;
use App\Models\JobApplication;
class JobController extends Controller
{
private function resolveCurrentUser()
{
$sess = session('user');
$sessId = is_array($sess) ? ($sess['id'] ?? null) : ($sess->id ?? null);
if (!$sessId) {
$user = User::where('role', 'employer')->first();
if ($user) {
session(['user' => (object)[
'id' => $user->id,
'name' => $user->name,
'email' => $user->email,
'role' => 'employer',
'subscription_status' => $user->subscription_status ?? 'active',
]]);
return $user;
}
} else {
return User::find($sessId);
}
return null;
}
private function checkJobAccess($user)
{
if (!$user) {
return false;
}
$sub = \Illuminate\Support\Facades\DB::table('subscriptions')
->where('user_id', $user->id)
->where('status', 'active')
->latest('id')
->first();
$planId = $sub ? $sub->plan_id : 'basic';
$associatedPlan = \App\Models\Plan::find($planId);
return $associatedPlan ? (bool)$associatedPlan->enable_job_apply : ($planId !== 'basic');
}
public function index(Request $request)
{
$user = $this->resolveCurrentUser();
if (!$user) {
return redirect()->route('employer.login');
}
if (!$this->checkJobAccess($user)) {
return redirect()->route('employer.subscription')
->with('error', 'Your current plan does not support the Job Apply module. Please upgrade to a Premium plan to access this feature.');
}
$dbJobs = JobPost::where('employer_id', $user->id)
->with(['applications'])
->latest()
->get();
$jobs = $dbJobs->map(function ($job) {
return [
'id' => $job->id,
'title' => $job->title,
'location' => $job->location,
'salary' => (int) $job->salary,
'workers_needed' => $job->workers_needed,
'applied_count' => $job->applications->count(),
'hired_count' => $job->applications->where('status', 'hired')->count(),
'posted_at' => $job->created_at->format('M d, Y'),
'status' => ucfirst($job->status), // Active, Closed, Draft
];
})->toArray();
return Inertia::render('Employer/Jobs/Index', [
'initialJobs' => $jobs,
]);
}
public function show($id)
{
$user = $this->resolveCurrentUser();
if (!$user) {
return redirect()->route('employer.login');
}
if (!$this->checkJobAccess($user)) {
return redirect()->route('employer.subscription')
->with('error', 'Your current plan does not support the Job Apply module. Please upgrade to a Premium plan to access this feature.');
}
$job = JobPost::where('employer_id', $user->id)
->with(['applications.worker'])
->where('id', $id)
->firstOrFail();
$jobData = [
'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('M d, Y') : null,
'description' => $job->description,
'requirements' => $job->requirements,
'status' => ucfirst($job->status),
'applied_count' => $job->applications->count(),
'hired_count' => $job->applications->where('status', 'hired')->count(),
'posted_at' => $job->created_at->format('M d, Y'),
];
return Inertia::render('Employer/Jobs/Show', [
'job' => $jobData,
]);
}
public function create()
{
$user = $this->resolveCurrentUser();
if (!$user) {
return redirect()->route('employer.login');
}
if (!$this->checkJobAccess($user)) {
return redirect()->route('employer.subscription')
->with('error', 'Your current plan does not support the Job Apply module. Please upgrade to a Premium plan to access this feature.');
}
$professions = \App\Models\Skill::orderBy('name')
->pluck('name')
->map(function ($name) {
return ucwords($name);
})
->unique()
->values()
->toArray();
if (empty($professions)) {
$professions = [
'Housekeeper', 'Nanny', 'Maid', 'Electrician', 'Mason', 'Plumber', 'Cleaner', 'Driver', 'Caregiver', 'Cook'
];
}
$skills = \App\Models\Skill::all()->map(function ($skill) {
return [
'id' => $skill->id,
'name' => $skill->name,
];
});
return Inertia::render('Employer/Jobs/Create', [
'professions' => $professions,
'availableSkills' => $skills,
]);
}
public function store(Request $request)
{
$user = $this->resolveCurrentUser();
if (!$user) {
return back()->withErrors(['general' => 'User session not found.']);
}
if (!$this->checkJobAccess($user)) {
return redirect()->route('employer.subscription')
->with('error', 'Your current plan does not support the Job Apply module. Please upgrade to a Premium plan to access this feature.');
}
$request->validate([
'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',
]);
$job = JobPost::create([
'employer_id' => $user->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 redirect()->route('employer.jobs')->with('success', 'Job posted successfully.');
}
public function applicants($id)
{
$user = $this->resolveCurrentUser();
if (!$user) {
return redirect()->route('employer.login');
}
if (!$this->checkJobAccess($user)) {
return redirect()->route('employer.subscription')
->with('error', 'Your current plan does not support the Job Apply module. Please upgrade to a Premium plan to access this feature.');
}
$job = JobPost::where('employer_id', $user->id)->where('id', $id)->firstOrFail();
$dbApplications = JobApplication::where('job_id', $id)
->with(['worker.skills'])
->get();
$applicants = $dbApplications->map(function ($app) use ($user) {
$worker = $app->worker;
if (!$worker) return null;
$isSaved = \App\Models\Shortlist::where('employer_id', $user->id)
->where('worker_id', $worker->id)
->exists();
return [
'id' => $worker->id,
'application_id' => $app->id,
'name' => $worker->name,
'nationality' => $worker->nationality,
'salary' => (int) $worker->salary,
'experience' => ($worker->experience_years ?? 3) . ' Years',
'status' => ucfirst($app->status), // Applied, Shortlisted, Hired, Rejected, etc.
'notes' => $app->notes,
'status_history' => $app->status_history ?: [],
'match_score' => $worker->match_score ?? 90,
'is_saved' => $isSaved,
];
})->filter()->values()->toArray();
return Inertia::render('Employer/Jobs/Applicants', [
'job' => [
'id' => $job->id,
'title' => $job->title,
'salary' => (int) $job->salary,
],
'applicants' => $applicants,
]);
}
public function edit($id)
{
$user = $this->resolveCurrentUser();
if (!$user) {
return redirect()->route('employer.login');
}
if (!$this->checkJobAccess($user)) {
return redirect()->route('employer.subscription')
->with('error', 'Your current plan does not support the Job Apply module. Please upgrade to a Premium plan to access this feature.');
}
$job = JobPost::where('employer_id', $user->id)->where('id', $id)->with('skills')->firstOrFail();
// Convert start_date format to Y-m-d for date input
$jobData = $job->toArray();
if ($job->start_date) {
$jobData['start_date'] = $job->start_date->format('Y-m-d');
}
// Add skills list
$jobData['skills'] = $job->skills->map(function ($s) {
return [
'id' => $s->id,
'name' => $s->name,
];
})->toArray();
$professions = \App\Models\Skill::orderBy('name')
->pluck('name')
->map(function ($name) {
return ucwords($name);
})
->unique()
->values()
->toArray();
if (empty($professions)) {
$professions = [
'Housekeeper', 'Nanny', 'Maid', 'Electrician', 'Mason', 'Plumber', 'Cleaner', 'Driver', 'Caregiver', 'Cook'
];
}
$skills = \App\Models\Skill::all()->map(function ($skill) {
return [
'id' => $skill->id,
'name' => $skill->name,
];
});
return Inertia::render('Employer/Jobs/Edit', [
'job' => $jobData,
'professions' => $professions,
'availableSkills' => $skills,
]);
}
public function update(Request $request, $id)
{
$user = $this->resolveCurrentUser();
if (!$user) {
return back()->withErrors(['general' => 'User session not found.']);
}
if (!$this->checkJobAccess($user)) {
return redirect()->route('employer.subscription')
->with('error', 'Your current plan does not support the Job Apply module. Please upgrade to a Premium plan to access this feature.');
}
$job = JobPost::where('employer_id', $user->id)->where('id', $id)->firstOrFail();
if ($job->applications()->exists()) {
return back()->withErrors(['general' => 'This job cannot be edited because workers have already applied for it.']);
}
$request->validate([
'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',
]);
$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 redirect()->route('employer.jobs')->with('success', 'Job updated successfully.');
}
public function destroy($id)
{
$user = $this->resolveCurrentUser();
if (!$user) {
return back()->withErrors(['general' => 'User session not found.']);
}
if (!$this->checkJobAccess($user)) {
return redirect()->route('employer.subscription')
->with('error', 'Your current plan does not support the Job Apply module. Please upgrade to a Premium plan to access this feature.');
}
$job = JobPost::where('employer_id', $user->id)->where('id', $id)->firstOrFail();
$job->delete();
return redirect()->route('employer.jobs')->with('success', 'Job deleted successfully.');
}
public function close($id)
{
$user = $this->resolveCurrentUser();
if (!$user) {
return back()->withErrors(['general' => 'User session not found.']);
}
if (!$this->checkJobAccess($user)) {
return redirect()->route('employer.subscription')
->with('error', 'Your current plan does not support the Job Apply module. Please upgrade to a Premium plan to access this feature.');
}
$job = JobPost::where('employer_id', $user->id)->where('id', $id)->firstOrFail();
$job->update(['status' => 'closed']);
return redirect()->route('employer.jobs.show', $id)->with('success', 'Job closed successfully.');
}
public function allApplicants(Request $request)
{
$user = $this->resolveCurrentUser();
if (!$user) {
return redirect()->route('employer.login');
}
if (!$this->checkJobAccess($user)) {
return redirect()->route('employer.subscription')
->with('error', 'Your current plan does not support the Job Apply module. Please upgrade to a Premium plan to access this feature.');
}
$jobIds = JobPost::where('employer_id', $user->id)->pluck('id');
$dbApplications = JobApplication::whereIn('job_id', $jobIds)
->with(['worker.skills', 'jobPost'])
->get();
$applicants = $dbApplications->map(function ($app) use ($user) {
$worker = $app->worker;
if (!$worker) return null;
$isSaved = \App\Models\Shortlist::where('employer_id', $user->id)
->where('worker_id', $worker->id)
->exists();
return [
'id' => $worker->id,
'application_id' => $app->id,
'name' => $worker->name,
'nationality' => $worker->nationality,
'salary' => (int) $worker->salary,
'experience' => ($worker->experience_years ?? 3) . ' Years',
'status' => ucfirst($app->status),
'notes' => $app->notes,
'status_history' => $app->status_history ?: [],
'match_score' => $worker->match_score ?? 90,
'is_saved' => $isSaved,
'job_title' => $app->jobPost->title ?? 'N/A',
'job_id' => $app->job_id,
];
})->filter()->values()->toArray();
return Inertia::render('Employer/Jobs/Applicants', [
'job' => null,
'applicants' => $applicants,
]);
}
public function shortlistedApplicants(Request $request)
{
$user = $this->resolveCurrentUser();
if (!$user) {
return redirect()->route('employer.login');
}
if (!$this->checkJobAccess($user)) {
return redirect()->route('employer.subscription')
->with('error', 'Your current plan does not support the Job Apply module. Please upgrade to a Premium plan to access this feature.');
}
$jobIds = JobPost::where('employer_id', $user->id)->pluck('id');
$dbApplications = JobApplication::whereIn('job_id', $jobIds)
->where('status', 'shortlisted')
->with(['worker.skills', 'jobPost'])
->get();
$applicants = $dbApplications->map(function ($app) use ($user) {
$worker = $app->worker;
if (!$worker) return null;
$isSaved = \App\Models\Shortlist::where('employer_id', $user->id)
->where('worker_id', $worker->id)
->exists();
return [
'id' => $worker->id,
'application_id' => $app->id,
'name' => $worker->name,
'nationality' => $worker->nationality,
'salary' => (int) $worker->salary,
'experience' => ($worker->experience_years ?? 3) . ' Years',
'status' => ucfirst($app->status),
'notes' => $app->notes,
'status_history' => $app->status_history ?: [],
'match_score' => $worker->match_score ?? 90,
'is_saved' => $isSaved,
'job_title' => $app->jobPost->title ?? 'N/A',
'job_id' => $app->job_id,
];
})->filter()->values()->toArray();
return Inertia::render('Employer/Jobs/Applicants', [
'job' => null,
'applicants' => $applicants,
'isShortlistedOnly' => true,
]);
}
}