460 lines
19 KiB
PHP
460 lines
19 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\Worker;
|
|
use App\Models\WorkerCategory;
|
|
use App\Models\Shortlist;
|
|
use App\Models\JobOffer;
|
|
use App\Models\Review;
|
|
use App\Models\ProfileView;
|
|
|
|
class WorkerController 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;
|
|
|
|
$dbWorkers = Worker::with(['category', 'skills', 'documents'])
|
|
->where('status', '!=', 'Hired')
|
|
->where('status', '!=', 'hidden')
|
|
->get();
|
|
|
|
$workers = $dbWorkers->map(function ($w) {
|
|
$isPending = str_contains(strtolower($w->passport_status), 'pending');
|
|
if ($isPending || $w->status === 'hidden' || $w->status === 'Hired') {
|
|
return null;
|
|
}
|
|
|
|
// Map languages from database comma-separated string
|
|
$langs = $w->language ? array_map('trim', explode(',', $w->language)) : ['English'];
|
|
|
|
// Preferred job types: full-time / part-time / live-in / live-out
|
|
$jobTypes = ['full-time', 'part-time', 'live-in', 'live-out'];
|
|
$preferredJobType = $w->preferred_job_type ?? $jobTypes[$w->id % 4];
|
|
|
|
// Emirates ID verification status (now dynamic passport status)
|
|
$emiratesIdStatus = $w->emirates_id_status;
|
|
|
|
// Map skills dynamically from database
|
|
$mappedSkills = $w->skills->pluck('name')->toArray();
|
|
if (empty($mappedSkills)) {
|
|
$mappedSkills = ['cooking', 'cleaning'];
|
|
}
|
|
|
|
// Visa status
|
|
$visaStatus = $w->visa_status;
|
|
|
|
// Optional profile photos
|
|
$photos = [
|
|
'https://images.unsplash.com/photo-1573496359142-b8d87734a5a2?auto=format&fit=crop&q=80&w=200',
|
|
'https://images.unsplash.com/photo-1534528741775-53994a69daeb?auto=format&fit=crop&q=80&w=200',
|
|
'https://images.unsplash.com/photo-1544005313-94ddf0286df2?auto=format&fit=crop&q=80&w=200',
|
|
null // Test optional photo placeholder
|
|
];
|
|
$photo = $photos[$w->id % 4];
|
|
|
|
$dbReviews = \App\Models\Review::where('worker_id', $w->id)->get();
|
|
$reviewsCount = $dbReviews->count();
|
|
$rating = $reviewsCount > 0 ? round($dbReviews->avg('rating'), 1) : 0.0;
|
|
|
|
return [
|
|
'id' => $w->id,
|
|
'name' => $w->name,
|
|
'phone' => $w->phone,
|
|
'gender' => $w->gender ?? 'Female',
|
|
'nationality' => $w->nationality,
|
|
'photo' => $photo,
|
|
'emirates_id_status' => $emiratesIdStatus,
|
|
'passport_status' => $w->passport_status,
|
|
'category' => $w->category ? $w->category->name : 'Domestic Worker',
|
|
'skills' => $mappedSkills,
|
|
'visa_status' => $visaStatus,
|
|
'experience' => $w->experience,
|
|
'salary' => (int) $w->salary,
|
|
'religion' => $w->religion,
|
|
'languages' => $langs,
|
|
'age' => $w->age,
|
|
'verified' => (bool) $w->verified,
|
|
'preferred_job_type' => $preferredJobType,
|
|
'live_in_out' => $w->live_in_out ?? 'Live-in',
|
|
'bio' => $w->bio,
|
|
'rating' => $rating,
|
|
'reviews_count' => $reviewsCount,
|
|
'preferred_location' => $w->preferred_location,
|
|
'in_country' => (bool) $w->in_country,
|
|
];
|
|
})->filter()->values()->toArray();
|
|
|
|
// Apply request 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);
|
|
|
|
$workers = array_values(array_filter($workers, function ($c) use ($locsArray) {
|
|
if (!isset($c['preferred_location'])) return false;
|
|
$wLoc = strtolower($c['preferred_location']);
|
|
foreach ($locsArray as $l) {
|
|
if (str_contains($wLoc, $l)) {
|
|
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);
|
|
|
|
$workers = array_values(array_filter($workers, 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);
|
|
|
|
$workers = array_values(array_filter($workers, 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);
|
|
|
|
$workers = array_values(array_filter($workers, 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->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) {
|
|
$workers = array_values(array_filter($workers, 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) {
|
|
$workers = array_values(array_filter($workers, 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);
|
|
|
|
$workers = array_values(array_filter($workers, 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;
|
|
}));
|
|
}
|
|
|
|
|
|
$shortlistedIds = Shortlist::where('employer_id', $employerId)->pluck('worker_id')->toArray();
|
|
|
|
$dbCategories = WorkerCategory::pluck('name')->toArray();
|
|
$dbNationalities = Worker::distinct()->pluck('nationality')->toArray();
|
|
|
|
$filtersMetadata = [
|
|
'categories' => array_merge(['All Categories'], $dbCategories),
|
|
'nationalities' => array_merge(['All Nationalities'], $dbNationalities),
|
|
'experienceLevels' => ['All Experience', '1-2 Years', '3-5 Years', '5+ Years'],
|
|
'religions' => ['All Religions', 'Christian', 'Muslim', 'Hindu', 'Buddhist'],
|
|
'languages' => ['All Languages', 'English', 'Arabic', 'Hindi', 'Tagalog'],
|
|
'workTypes' => ['All Types', 'full-time', 'part-time', 'live-in', 'live-out'],
|
|
'skills' => ['All Skills', 'cooking', 'driving', 'childcare', 'cleaning', 'elderly care', 'gardening'],
|
|
'visaStatuses' => ['All Visa Statuses', 'Residence Visa', 'Tourist Visa', 'Employment Visa', 'Cancelled Visa', 'Own Visa'],
|
|
];
|
|
|
|
return Inertia::render('Employer/Workers/Index', [
|
|
'initialWorkers' => $workers,
|
|
'initialShortlistedIds' => $shortlistedIds,
|
|
'filtersMetadata' => $filtersMetadata,
|
|
]);
|
|
}
|
|
|
|
public function show($id)
|
|
{
|
|
$w = Worker::with(['category', 'skills', 'documents'])->findOrFail($id);
|
|
|
|
$isPending = str_contains(strtolower($w->passport_status), 'pending');
|
|
if ($w->status === 'hidden' || $isPending) {
|
|
abort(404);
|
|
}
|
|
|
|
// Record employer profile view (Requirement 3)
|
|
$user = $this->resolveCurrentUser();
|
|
if ($user) {
|
|
ProfileView::updateOrCreate(
|
|
['employer_id' => $user->id, 'worker_id' => $w->id],
|
|
['updated_at' => now()]
|
|
);
|
|
}
|
|
|
|
$langs = $w->language ? array_map('trim', explode(',', $w->language)) : ['English'];
|
|
|
|
// Preferred job types: full-time / part-time / live-in / live-out
|
|
$jobTypes = ['full-time', 'part-time', 'live-in', 'live-out'];
|
|
$preferredJobType = $jobTypes[$w->id % 4];
|
|
|
|
$emiratesIdStatus = $w->emirates_id_status;
|
|
|
|
// Map skills dynamically from database
|
|
$mappedSkills = $w->skills->pluck('name')->toArray();
|
|
if (empty($mappedSkills)) {
|
|
$mappedSkills = ['cooking', 'cleaning'];
|
|
}
|
|
|
|
$photos = [
|
|
'https://images.unsplash.com/photo-1573496359142-b8d87734a5a2?auto=format&fit=crop&q=80&w=200',
|
|
'https://images.unsplash.com/photo-1534528741775-53994a69daeb?auto=format&fit=crop&q=80&w=200',
|
|
'https://images.unsplash.com/photo-1544005313-94ddf0286df2?auto=format&fit=crop&q=80&w=200',
|
|
null
|
|
];
|
|
$photo = $photos[$w->id % 4];
|
|
|
|
// Fetch dynamic database reviews (Requirement 1)
|
|
$dbReviews = Review::where('worker_id', $w->id)->with('employer')->latest()->get();
|
|
$reviews = $dbReviews->map(function ($rev) {
|
|
return [
|
|
'id' => $rev->id,
|
|
'employer_name' => $rev->employer->name ?? 'Employer',
|
|
'rating' => $rev->rating,
|
|
'date' => $rev->created_at->format('M d, Y'),
|
|
'comment' => $rev->comment,
|
|
];
|
|
})->toArray();
|
|
|
|
$reviewsCount = count($reviews);
|
|
$rating = $reviewsCount > 0 ? round($dbReviews->avg('rating'), 1) : 0;
|
|
|
|
$simDb = Worker::with('category')
|
|
->where('id', '!=', $w->id)
|
|
->where('status', '!=', 'Hired')
|
|
->where('status', '!=', 'hidden')
|
|
->limit(3)
|
|
->get();
|
|
$similarWorkers = $simDb->map(function ($sw) {
|
|
$isPending = str_contains(strtolower($sw->passport_status), 'pending');
|
|
if ($isPending || $sw->status === 'hidden' || $sw->status === 'Hired') {
|
|
return null;
|
|
}
|
|
|
|
return [
|
|
'id' => $sw->id,
|
|
'name' => $sw->name,
|
|
'nationality' => $sw->nationality,
|
|
'category' => $sw->category ? $sw->category->name : 'Helper',
|
|
'salary' => (int) $sw->salary,
|
|
'rating' => 4.7,
|
|
'verified' => (bool) $sw->verified,
|
|
];
|
|
})->filter()->values()->toArray();
|
|
|
|
$visaStatus = $w->visa_status;
|
|
|
|
$worker = [
|
|
'id' => $w->id,
|
|
'name' => $w->name,
|
|
'phone' => $w->phone,
|
|
'gender' => $w->gender ?? 'Female',
|
|
'nationality' => $w->nationality,
|
|
'photo' => $photo,
|
|
'emirates_id_status' => $emiratesIdStatus,
|
|
'passport_status' => $w->passport_status,
|
|
'category' => $w->category ? $w->category->name : 'Domestic Worker',
|
|
'skills' => $mappedSkills,
|
|
'visa_status' => $visaStatus,
|
|
'experience' => $w->experience,
|
|
'experience_years' => 5,
|
|
'salary' => (int) $w->salary,
|
|
'religion' => $w->religion,
|
|
'languages' => $langs,
|
|
'age' => $w->age,
|
|
'verified' => (bool) $w->verified,
|
|
'preferred_job_type' => $preferredJobType,
|
|
'live_in_out' => $w->live_in_out ?? 'Live-in',
|
|
'bio' => $w->bio,
|
|
'rating' => $rating,
|
|
'reviews_count' => $reviewsCount,
|
|
'reviews' => $reviews,
|
|
'similar_workers' => $similarWorkers,
|
|
];
|
|
|
|
return Inertia::render('Employer/Workers/Show', [
|
|
'worker' => $worker,
|
|
]);
|
|
}
|
|
|
|
public function sendOffer(Request $request, $id)
|
|
{
|
|
$request->validate([
|
|
'work_date' => 'required|date',
|
|
'location' => 'required|string|max:255',
|
|
'salary' => 'required|numeric|min:0',
|
|
'notes' => 'nullable|string|max:1000',
|
|
]);
|
|
|
|
$user = $this->resolveCurrentUser();
|
|
$employerId = $user ? $user->id : 2;
|
|
|
|
$worker = Worker::findOrFail($id);
|
|
|
|
JobOffer::create([
|
|
'employer_id' => $employerId,
|
|
'worker_id' => $worker->id,
|
|
'work_date' => $request->work_date,
|
|
'location' => $request->location,
|
|
'salary' => $request->salary,
|
|
'notes' => $request->notes,
|
|
'status' => 'pending',
|
|
]);
|
|
|
|
return redirect()->route('employer.hiring.success', ['id' => $id])
|
|
->with('success', 'Hiring offer has been successfully dispatched to the worker!');
|
|
}
|
|
|
|
public function markHired(Request $request, $id)
|
|
{
|
|
$user = $this->resolveCurrentUser();
|
|
$employerId = $user ? $user->id : 2;
|
|
|
|
$worker = Worker::findOrFail($id);
|
|
$worker->update([
|
|
'status' => 'Hired',
|
|
]);
|
|
|
|
// Check if there is an existing job offer for this employer and worker
|
|
$offer = JobOffer::where('employer_id', $employerId)
|
|
->where('worker_id', $worker->id)
|
|
->first();
|
|
|
|
if ($offer) {
|
|
$offer->update(['status' => 'accepted']);
|
|
} else {
|
|
// Also check if there's an existing job application
|
|
$jobIds = \App\Models\JobPost::where('employer_id', $employerId)->pluck('id');
|
|
$application = \App\Models\JobApplication::whereIn('job_id', $jobIds)
|
|
->where('worker_id', $worker->id)
|
|
->first();
|
|
|
|
if ($application) {
|
|
$application->update(['status' => 'hired']);
|
|
} else {
|
|
// Create a new direct job offer with status accepted
|
|
JobOffer::create([
|
|
'employer_id' => $employerId,
|
|
'worker_id' => $worker->id,
|
|
'work_date' => now()->format('Y-m-d'),
|
|
'location' => 'Dubai',
|
|
'salary' => $worker->salary,
|
|
'notes' => 'Direct sponsoring matching finalized.',
|
|
'status' => 'accepted',
|
|
]);
|
|
}
|
|
}
|
|
|
|
return back()->with('success', 'Worker successfully marked as Hired!');
|
|
}
|
|
}
|