332 lines
14 KiB
PHP
332 lines
14 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\JobApplication;
|
|
use App\Models\JobPost;
|
|
use App\Models\JobOffer;
|
|
|
|
class CandidateController 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;
|
|
}
|
|
|
|
public function index(Request $request)
|
|
{
|
|
$user = $this->resolveCurrentUser();
|
|
$employerId = $user ? $user->id : 2;
|
|
|
|
// 1. Get job posts created by this employer
|
|
$jobIds = JobPost::where('employer_id', $employerId)->pluck('id');
|
|
|
|
// Fetch applications for those jobs
|
|
$applications = JobApplication::whereIn('job_id', $jobIds)
|
|
->with(['worker', 'jobPost'])
|
|
->get();
|
|
|
|
$selectedWorkers = $applications->map(function ($app) {
|
|
$w = $app->worker;
|
|
if (!$w) return null;
|
|
|
|
// Map DB status to UI friendly status
|
|
$status = 'Reviewing';
|
|
if ($app->status === 'hired') $status = 'Hired';
|
|
elseif ($app->status === 'rejected') $status = 'Rejected';
|
|
elseif ($app->status === 'shortlisted' || $app->status === 'offer_sent') $status = 'Offer Sent';
|
|
elseif ($app->status === 'applied') $status = 'Reviewing';
|
|
else $status = ucfirst($app->status);
|
|
|
|
return [
|
|
'id' => $app->id, // standard application id
|
|
'worker_id' => $w->id,
|
|
'name' => $w->name,
|
|
'nationality' => $w->nationality,
|
|
'salary' => (int)$w->salary,
|
|
'status' => $status,
|
|
'applied_at' => $app->created_at->format('M d, Y'),
|
|
'preferred_location' => $w->preferred_location,
|
|
'preferred_job_type' => $w->preferred_job_type,
|
|
'live_in_out' => $w->live_in_out,
|
|
'in_country' => (bool)$w->in_country,
|
|
'visa_status' => $w->visa_status,
|
|
];
|
|
})->filter()->values()->toArray();
|
|
|
|
// 2. Fetch direct hiring offers sent by this employer
|
|
$directOffers = JobOffer::where('employer_id', $employerId)
|
|
->with('worker')
|
|
->get();
|
|
|
|
$directWorkers = $directOffers->map(function ($offer) {
|
|
$w = $offer->worker;
|
|
if (!$w) return null;
|
|
|
|
// Map DB offer status to UI friendly status
|
|
$status = 'Offer Sent';
|
|
if ($offer->status === 'accepted') $status = 'Hired';
|
|
elseif ($offer->status === 'rejected') $status = 'Rejected';
|
|
elseif ($offer->status === 'pending') $status = 'Offer Sent';
|
|
|
|
return [
|
|
'id' => 'offer_' . $offer->id, // Unique string key prefix to prevent clashes
|
|
'worker_id' => $w->id,
|
|
'name' => $w->name,
|
|
'nationality' => $w->nationality,
|
|
'salary' => (int)$offer->salary,
|
|
'status' => $status,
|
|
'applied_at' => $offer->created_at->format('M d, Y'),
|
|
'preferred_location' => $w->preferred_location,
|
|
'preferred_job_type' => $w->preferred_job_type,
|
|
'live_in_out' => $w->live_in_out,
|
|
'in_country' => (bool)$w->in_country,
|
|
'visa_status' => $w->visa_status,
|
|
];
|
|
})->filter()->values()->toArray();
|
|
|
|
// Merge standard job applications with direct hiring offers for unified tracking
|
|
$mergedCandidates = array_merge($selectedWorkers, $directWorkers);
|
|
|
|
// Only display Hired candidates in the candidates pipeline
|
|
$mergedCandidates = array_values(array_filter($mergedCandidates, function ($w) {
|
|
return $w && $w['status'] === 'Hired';
|
|
}));
|
|
|
|
// Apply filters: preferred_location, job_type, live_in_out, nationality, in_country, visa_status
|
|
if ($request->filled('preferred_location')) {
|
|
$prefLoc = $request->preferred_location;
|
|
$locsArray = is_array($prefLoc) ? $prefLoc : array_filter(array_map('trim', explode(',', $prefLoc)));
|
|
$locsArray = array_map('strtolower', $locsArray);
|
|
|
|
$locationMapping = [
|
|
'dubai' => ['dubai', 'marina', 'barsha', 'nahda', 'jumeirah', 'deira', 'downtown', 'silicon', 'sports', 'motor', 'jlt', 'jbr', 'meydan', 'ranches', 'bay', 'mirdif', 'quoz'],
|
|
'abu dhabi' => ['abu dhabi', 'yas', 'khalifa', 'reem', 'saadiyat', 'raha', 'mussafah', 'zahiyah', 'karamah'],
|
|
'oman' => ['oman', 'muscat', 'salalah', 'sohar', 'nizwa', 'sur', 'ibri', 'rustaq']
|
|
];
|
|
|
|
$mergedCandidates = array_values(array_filter($mergedCandidates, function ($c) use ($locsArray, $locationMapping) {
|
|
if (!isset($c['preferred_location'])) return false;
|
|
$wLoc = strtolower($c['preferred_location']);
|
|
foreach ($locsArray as $l) {
|
|
if ($l === 'all') return true;
|
|
$allowedKeywords = $locationMapping[$l] ?? [$l];
|
|
foreach ($allowedKeywords as $keyword) {
|
|
if (str_contains($wLoc, $keyword)) {
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}));
|
|
}
|
|
|
|
$jobTypeParam = $request->input('job_type') ?? $request->input('preferred_job_type');
|
|
if ($jobTypeParam) {
|
|
$jobTypesArray = is_array($jobTypeParam) ? $jobTypeParam : array_filter(array_map('trim', explode(',', $jobTypeParam)));
|
|
$jobTypesArray = array_map('strtolower', $jobTypesArray);
|
|
|
|
$mergedCandidates = array_values(array_filter($mergedCandidates, function ($c) use ($jobTypesArray) {
|
|
if (!isset($c['preferred_job_type'])) return false;
|
|
$wJobType = strtolower($c['preferred_job_type']);
|
|
foreach ($jobTypesArray as $jt) {
|
|
if (str_contains($wJobType, $jt)) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}));
|
|
}
|
|
|
|
$accParam = $request->input('live_in_out') ?? $request->input('accommodation_type') ?? $request->input('accomadation_type');
|
|
if ($accParam) {
|
|
$accsArray = is_array($accParam) ? $accParam : array_filter(array_map('trim', explode(',', $accParam)));
|
|
$accsArray = array_map(function($val) {
|
|
return str_replace(['_', '-'], ' ', strtolower($val));
|
|
}, $accsArray);
|
|
|
|
$mergedCandidates = array_values(array_filter($mergedCandidates, function ($c) use ($accsArray) {
|
|
if (!isset($c['live_in_out'])) return false;
|
|
$wAcc = str_replace(['_', '-'], ' ', strtolower($c['live_in_out']));
|
|
foreach ($accsArray as $a) {
|
|
if (str_contains($wAcc, $a)) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}));
|
|
}
|
|
|
|
if ($request->filled('nationality')) {
|
|
$natInput = $request->nationality;
|
|
$natsArray = is_array($natInput) ? $natInput : array_filter(array_map('trim', explode(',', $natInput)));
|
|
$natsArray = array_map('strtolower', $natsArray);
|
|
|
|
$mergedCandidates = array_values(array_filter($mergedCandidates, function ($c) use ($natsArray) {
|
|
if (!isset($c['nationality'])) return false;
|
|
$wNat = strtolower($c['nationality']);
|
|
foreach ($natsArray as $n) {
|
|
if (str_contains($wNat, $n) || $wNat === $n) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}));
|
|
}
|
|
|
|
if ($request->filled('gender')) {
|
|
$gender = strtolower($request->gender);
|
|
$mergedCandidates = array_values(array_filter($mergedCandidates, function ($c) use ($gender) {
|
|
return isset($c['gender']) && strtolower($c['gender']) === $gender;
|
|
}));
|
|
}
|
|
|
|
if ($request->has('in_country')) {
|
|
$inCountryVal = $request->input('in_country');
|
|
if ($inCountryVal !== null && $inCountryVal !== '') {
|
|
$isInCountry = filter_var($inCountryVal, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE);
|
|
if ($isInCountry === null) {
|
|
$strVal = strtolower(trim($inCountryVal));
|
|
if ($strVal === 'in' || $strVal === 'in_country' || $strVal === 'yes') {
|
|
$isInCountry = true;
|
|
} elseif ($strVal === 'out' || $strVal === 'out_country' || $strVal === 'no') {
|
|
$isInCountry = false;
|
|
}
|
|
}
|
|
if ($isInCountry !== null) {
|
|
$mergedCandidates = array_values(array_filter($mergedCandidates, function ($c) use ($isInCountry) {
|
|
return isset($c['in_country']) && (bool)$c['in_country'] === $isInCountry;
|
|
}));
|
|
}
|
|
}
|
|
}
|
|
|
|
if ($request->has('out_country')) {
|
|
$outCountryVal = $request->input('out_country');
|
|
if ($outCountryVal !== null && $outCountryVal !== '') {
|
|
$isOutCountry = filter_var($outCountryVal, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE);
|
|
if ($isOutCountry === null) {
|
|
$strVal = strtolower(trim($outCountryVal));
|
|
if ($strVal === 'out' || $strVal === 'out_country' || $strVal === 'yes') {
|
|
$isOutCountry = true;
|
|
} elseif ($strVal === 'in' || $strVal === 'in_country' || $strVal === 'no') {
|
|
$isOutCountry = false;
|
|
}
|
|
}
|
|
if ($isOutCountry !== null) {
|
|
$mergedCandidates = array_values(array_filter($mergedCandidates, function ($c) use ($isOutCountry) {
|
|
return isset($c['in_country']) && (bool)$c['in_country'] !== $isOutCountry;
|
|
}));
|
|
}
|
|
}
|
|
}
|
|
|
|
$visaParam = $request->input('visa_status') ?? $request->input('next_visa_type') ?? $request->input('visa_type');
|
|
if ($visaParam) {
|
|
$visasArray = is_array($visaParam) ? $visaParam : array_filter(array_map('trim', explode(',', $visaParam)));
|
|
$visasArray = array_map('strtolower', $visasArray);
|
|
|
|
$mergedCandidates = array_values(array_filter($mergedCandidates, function ($c) use ($visasArray) {
|
|
if (!isset($c['visa_status'])) return false;
|
|
$isInCountry = isset($c['in_country']) && (bool)$c['in_country'];
|
|
if (!$isInCountry) {
|
|
return false;
|
|
}
|
|
$wVisa = strtolower($c['visa_status']);
|
|
foreach ($visasArray as $v) {
|
|
if (str_contains($wVisa, $v)) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}));
|
|
}
|
|
|
|
$nationalitiesResponse = app(\App\Http\Controllers\Api\WorkerAuthController::class)->nationalities(new \Illuminate\Http\Request(['per_page' => 500]));
|
|
$nationalitiesData = json_decode($nationalitiesResponse->getContent(), true);
|
|
$allNationalities = collect($nationalitiesData['data']['nationalities'] ?? [])->pluck('name')->filter()->toArray();
|
|
|
|
return Inertia::render('Employer/SelectedCandidates', [
|
|
'selectedWorkers' => $mergedCandidates,
|
|
'allNationalities' => $allNationalities,
|
|
]);
|
|
}
|
|
|
|
public function updateStatus(Request $request, $id)
|
|
{
|
|
$request->validate([
|
|
'status' => 'required|string|in:Reviewing,Offer Sent,Hired,Rejected',
|
|
]);
|
|
|
|
// If this is a direct hiring offer response
|
|
if (is_string($id) && str_starts_with($id, 'offer_')) {
|
|
$offerId = substr($id, 6);
|
|
$offer = JobOffer::findOrFail($offerId);
|
|
|
|
$dbStatus = 'pending';
|
|
if ($request->status === 'Hired') {
|
|
$dbStatus = 'accepted';
|
|
$offer->worker->update(['status' => 'Hired']);
|
|
} elseif ($request->status === 'Rejected') {
|
|
$dbStatus = 'rejected';
|
|
$offer->worker->update(['status' => 'active']);
|
|
} elseif ($request->status === 'Offer Sent') {
|
|
$dbStatus = 'pending';
|
|
}
|
|
|
|
$offer->update(['status' => $dbStatus]);
|
|
|
|
return back()->with('success', 'Direct candidate hiring offer status updated successfully to ' . $request->status);
|
|
}
|
|
|
|
// Standard job application status update
|
|
$app = JobApplication::findOrFail($id);
|
|
|
|
$dbStatus = 'applied';
|
|
if ($request->status === 'Hired') {
|
|
$dbStatus = 'hired';
|
|
if ($app->worker) {
|
|
$app->worker->update(['status' => 'Hired']);
|
|
}
|
|
} elseif ($request->status === 'Rejected') {
|
|
$dbStatus = 'rejected';
|
|
if ($app->worker) {
|
|
$app->worker->update(['status' => 'active']);
|
|
}
|
|
} elseif ($request->status === 'Offer Sent') {
|
|
$dbStatus = 'shortlisted';
|
|
} elseif ($request->status === 'Reviewing') {
|
|
$dbStatus = 'applied';
|
|
}
|
|
|
|
$app->update([
|
|
'status' => $dbStatus,
|
|
]);
|
|
|
|
return back()->with('success', 'Candidate application status updated successfully to ' . $request->status);
|
|
}
|
|
}
|