diff --git a/app/Http/Controllers/Admin/WorkerController.php b/app/Http/Controllers/Admin/WorkerController.php index 1ac3ee6..f3a99f8 100644 --- a/app/Http/Controllers/Admin/WorkerController.php +++ b/app/Http/Controllers/Admin/WorkerController.php @@ -13,7 +13,7 @@ class WorkerController extends Controller */ public function index() { - $workers = \App\Models\Worker::with(['category', 'skills']) + $workers = \App\Models\Worker::with(['skills']) ->latest() ->get() ->map(function ($worker) { @@ -43,7 +43,6 @@ public function index() 'city' => $worker->city, 'area' => $worker->area, 'live_in_out' => $worker->live_in_out ?? 'Live-in', - 'category' => $worker->category ? $worker->category->name : 'N/A', 'experience' => $worker->experience, 'salary' => (int)$worker->salary, 'skills' => $mappedSkills, @@ -126,7 +125,6 @@ public function updateProfile(Request $request, $id) 'city' => 'nullable|string', 'area' => 'nullable|string', 'live_in_out' => 'nullable|string', - 'category' => 'required|string', 'experience' => 'required|string', 'salary' => 'nullable|numeric', 'bio' => 'nullable|string' @@ -134,10 +132,7 @@ public function updateProfile(Request $request, $id) $worker = \App\Models\Worker::findOrFail($id); - $category = \App\Models\WorkerCategory::where('name', $validated['category'])->first(); - if ($category) { - $worker->category_id = $category->id; - } + $worker->name = $validated['name']; $worker->phone = $validated['phone']; diff --git a/app/Http/Controllers/Api/EmployerAuthController.php b/app/Http/Controllers/Api/EmployerAuthController.php index 22a0768..7cbaf85 100644 --- a/app/Http/Controllers/Api/EmployerAuthController.php +++ b/app/Http/Controllers/Api/EmployerAuthController.php @@ -110,10 +110,22 @@ public function login(Request $request) } $user->update($userUpdateData); if ($sponsor) { - $sponsor->update([ + $sponsorUpdateData = [ 'api_token' => $apiToken, 'last_login_at' => now(), - ]); + ]; + if ($request->has('fcm_token')) { + $sponsorUpdateData['fcm_token'] = $request->fcm_token; + } + $sponsor->update($sponsorUpdateData); + } + + if ($request->filled('fcm_token')) { + \App\Services\FCMService::sendPushNotification( + $request->fcm_token, + 'Successful Login', + 'Welcome back to your Migrant employer account.' + ); } return response()->json([ @@ -127,10 +139,22 @@ public function login(Request $request) ], 200); } else { // Pure Sponsor account - $sponsor->update([ + $sponsorUpdateData = [ 'api_token' => $apiToken, 'last_login_at' => now(), - ]); + ]; + if ($request->has('fcm_token')) { + $sponsorUpdateData['fcm_token'] = $request->fcm_token; + } + $sponsor->update($sponsorUpdateData); + + if ($request->filled('fcm_token')) { + \App\Services\FCMService::sendPushNotification( + $request->fcm_token, + 'Successful Login', + 'Welcome back to your Migrant sponsor account.' + ); + } return response()->json([ 'success' => true, @@ -166,6 +190,7 @@ public function register(Request $request) 'name' => 'required|string|max:255', 'email' => 'required|string|email|max:255|unique:users,email', 'phone' => 'required|string|max:50', + 'fcm_token' => 'nullable|string|max:255', ]); if ($validator->fails()) { @@ -195,6 +220,7 @@ public function register(Request $request) 'role' => 'employer', 'subscription_status' => 'none', 'subscription_expires_at' => null, + 'fcm_token' => $request->fcm_token, ]); // Create pending Profile @@ -223,8 +249,17 @@ public function register(Request $request) 'is_verified' => false, 'otp_verified_at' => null, 'status' => 'inactive', + 'fcm_token' => $request->fcm_token, ]); + if ($request->filled('fcm_token')) { + \App\Services\FCMService::sendPushNotification( + $request->fcm_token, + 'Registration Initiated', + 'Your verification code has been sent to your email.' + ); + } + // Try sending email try { \Illuminate\Support\Facades\Mail::to($request->email)->send(new \App\Mail\EmployerOtpMail( @@ -257,6 +292,7 @@ public function verify(Request $request) $validator = Validator::make($request->all(), [ 'email' => 'required|email', 'otp' => 'required|string|size:6', + 'fcm_token' => 'nullable|string|max:255', ]); if ($validator->fails()) { @@ -293,11 +329,31 @@ public function verify(Request $request) try { // Update Sponsor verification status $sponsor = \App\Models\Sponsor::where('email', $request->email)->first(); + $user = User::where('email', $request->email)->where('role', 'employer')->first(); + $fcmToken = $request->fcm_token; + if ($sponsor) { - $sponsor->update([ + $sponsorUpdateData = [ 'is_verified' => true, 'otp_verified_at' => now(), - ]); + ]; + if ($fcmToken) { + $sponsorUpdateData['fcm_token'] = $fcmToken; + } + $sponsor->update($sponsorUpdateData); + } + + if ($user && $fcmToken) { + $user->update(['fcm_token' => $fcmToken]); + } + + $tokenToSend = $fcmToken ?? ($sponsor ? $sponsor->fcm_token : null) ?? ($user ? $user->fcm_token : null); + if ($tokenToSend) { + \App\Services\FCMService::sendPushNotification( + $tokenToSend, + 'Email Verified', + 'Proceed to payment selection.' + ); } // Clear Cache @@ -494,6 +550,7 @@ public function password(Request $request) $validator = Validator::make($request->all(), [ 'email' => 'required|email', 'password' => 'required|string|min:8|confirmed', + 'fcm_token' => 'nullable|string|max:255', ]); if ($validator->fails()) { @@ -526,16 +583,25 @@ public function password(Request $request) \Illuminate\Support\Facades\DB::transaction(function () use ($request, $user, $sponsor, $apiToken) { $hashedPassword = Hash::make($request->password); + $fcmToken = $request->fcm_token; - $user->update([ + $userUpdateData = [ 'password' => $hashedPassword, 'api_token' => $apiToken, - ]); + ]; + if ($fcmToken) { + $userUpdateData['fcm_token'] = $fcmToken; + } + $user->update($userUpdateData); - $sponsor->update([ + $sponsorUpdateData = [ 'password' => $hashedPassword, 'status' => 'active', - ]); + ]; + if ($fcmToken) { + $sponsorUpdateData['fcm_token'] = $fcmToken; + } + $sponsor->update($sponsorUpdateData); // Approve profile verification $profile = EmployerProfile::where('user_id', $user->id)->first(); @@ -546,6 +612,15 @@ public function password(Request $request) } }); + $tokenToSend = $request->fcm_token ?? ($user ? $user->fcm_token : null) ?? ($sponsor ? $sponsor->fcm_token : null); + if ($tokenToSend) { + \App\Services\FCMService::sendPushNotification( + $tokenToSend, + 'Welcome to Migrant', + 'Your employer registration has been completed successfully.' + ); + } + return response()->json([ 'success' => true, 'message' => 'Password created successfully. Registration finalized.', diff --git a/app/Http/Controllers/Api/EmployerMessageController.php b/app/Http/Controllers/Api/EmployerMessageController.php index 23fff0f..5f66ffe 100644 --- a/app/Http/Controllers/Api/EmployerMessageController.php +++ b/app/Http/Controllers/Api/EmployerMessageController.php @@ -83,7 +83,7 @@ public function getConversations(Request $request) try { $dbConversations = Conversation::where('employer_id', $employer->id) - ->with(['worker.category', 'messages']) + ->with(['worker', 'messages']) ->latest('updated_at') ->get(); @@ -99,7 +99,6 @@ public function getConversations(Request $request) 'id' => $conv->id, 'worker_id' => $conv->worker_id, 'worker_name' => $conv->worker->name ?? 'Candidate', - 'category' => $conv->worker->category->name ?? 'General Helper', 'nationality' => $conv->worker->nationality ?? 'Unknown', 'worker_status' => strtolower($conv->worker->status ?? 'active'), 'salary' => ($conv->worker->salary ?? $conv->worker->expected_salary ?? 2000) . ' AED', @@ -143,7 +142,7 @@ public function getMessages(Request $request, $id) try { $conv = Conversation::where('employer_id', $employer->id) ->where('id', $id) - ->with(['worker.category', 'messages']) + ->with(['worker', 'messages']) ->first(); if (!$conv) { @@ -175,7 +174,6 @@ public function getMessages(Request $request, $id) $conversationDetail = [ 'id' => $conv->id, 'worker_name' => $conv->worker->name ?? 'Candidate', - 'category' => $conv->worker->category->name ?? 'General Helper', 'nationality' => $conv->worker->nationality ?? 'Unknown', 'worker_status' => strtolower($conv->worker->status ?? 'active'), 'salary' => ($conv->worker->salary ?? $conv->worker->expected_salary ?? 2000) . ' AED', diff --git a/app/Http/Controllers/Api/EmployerProfileController.php b/app/Http/Controllers/Api/EmployerProfileController.php index 8a7e567..84a72d2 100644 --- a/app/Http/Controllers/Api/EmployerProfileController.php +++ b/app/Http/Controllers/Api/EmployerProfileController.php @@ -224,7 +224,7 @@ public function getDashboard(Request $request) ]; // Recent Announcements / Events - $dbAnnouncements = \App\Models\Announcement::where('status', 'approved')->latest()->limit(5)->get(); + $dbAnnouncements = \App\Models\Announcement::where('status', 'approved')->latest()->limit(2)->get(); $recentAnnouncements = $dbAnnouncements->map(function ($ann) { $body = $ann->body; $eventDate = null; diff --git a/app/Http/Controllers/Api/EmployerWorkerController.php b/app/Http/Controllers/Api/EmployerWorkerController.php index 8bd69cf..ac22b60 100644 --- a/app/Http/Controllers/Api/EmployerWorkerController.php +++ b/app/Http/Controllers/Api/EmployerWorkerController.php @@ -6,7 +6,6 @@ use Illuminate\Http\Request; use App\Models\User; use App\Models\Worker; -use App\Models\WorkerCategory; use App\Models\Shortlist; use App\Models\JobOffer; use App\Models\JobApplication; @@ -91,7 +90,7 @@ private function formatWorker(Worker $w) public function getWorkers(Request $request) { try { - $query = Worker::with(['category', 'skills', 'documents']) + $query = Worker::with(['skills', 'documents']) ->where('status', '!=', 'Hired') ->where('status', '!=', 'hidden'); @@ -355,11 +354,11 @@ public function getCandidates(Request $request) // Fetch Job Applications $jobIds = JobPost::where('employer_id', $employerId)->pluck('id'); $applicationsQuery = JobApplication::whereIn('job_id', $jobIds) - ->with(['worker.category', 'jobPost']); + ->with(['worker', 'jobPost']); // Fetch Direct Hiring Offers $directOffersQuery = JobOffer::where('employer_id', $employerId) - ->with('worker.category'); + ->with('worker'); // Apply search filter if provided if ($request->filled('search')) { @@ -841,7 +840,7 @@ public function getWorkerDetail(Request $request, $id) { /** @var User $employer */ $employer = $request->attributes->get('employer'); - $w = Worker::with(['category', 'skills', 'documents'])->find($id); + $w = Worker::with(['skills', 'documents'])->find($id); if (!$w) { return response()->json([ @@ -919,7 +918,7 @@ public function getWorkerDetail(Request $request, $id) } // Similar workers matching web view - $simDb = Worker::with('category') + $simDb = Worker::query() ->where('id', '!=', $w->id) ->where('status', '!=', 'Hired') ->where('status', '!=', 'hidden') @@ -1002,7 +1001,7 @@ public function getShortlist(Request $request) $perPage = (int)$request->input('per_page', 15); $shortlists = Shortlist::where('employer_id', $employer->id) - ->with(['worker.category', 'worker.skills']) + ->with(['worker.skills']) ->get(); $formattedWorkers = $shortlists->map(function ($s) { diff --git a/app/Http/Controllers/Api/SponsorAuthController.php b/app/Http/Controllers/Api/SponsorAuthController.php index 5660945..0efebd1 100644 --- a/app/Http/Controllers/Api/SponsorAuthController.php +++ b/app/Http/Controllers/Api/SponsorAuthController.php @@ -35,6 +35,7 @@ public function register(Request $request) 'address' => 'required|string|max:255', 'country_code' => 'required|string|max:10', 'license_expiry' => 'required|date_format:Y-m-d', + 'fcm_token' => 'nullable|string|max:255', ], [ 'mobile.unique' => 'This mobile number is already registered.', 'email.unique' => 'This email address is already registered.', @@ -98,9 +99,18 @@ public function register(Request $request) 'is_verified' => false, 'subscription_status' => 'none', 'api_token' => $apiToken, + 'fcm_token' => $request->fcm_token, ]); }); + if ($request->filled('fcm_token')) { + \App\Services\FCMService::sendPushNotification( + $request->fcm_token, + 'Welcome to Migrant', + 'Sponsor account registered successfully. Your license is pending admin review.' + ); + } + return response()->json([ 'success' => true, 'message' => 'Sponsor account registered successfully. Your license is pending admin review.', @@ -129,8 +139,9 @@ public function register(Request $request) public function login(Request $request) { $validator = Validator::make($request->all(), [ - 'mobile' => 'required|string', - 'password' => 'required|string', + 'mobile' => 'required|string', + 'password' => 'required|string', + 'fcm_token' => 'nullable|string|max:255', ]); if ($validator->fails()) { @@ -159,10 +170,22 @@ public function login(Request $request) // Rotate token on each login for security $apiToken = Str::random(80); - $sponsor->update([ + $updateData = [ 'api_token' => $apiToken, 'last_login_at' => now(), - ]); + ]; + if ($request->has('fcm_token')) { + $updateData['fcm_token'] = $request->fcm_token; + } + $sponsor->update($updateData); + + if ($request->filled('fcm_token')) { + \App\Services\FCMService::sendPushNotification( + $request->fcm_token, + 'Successful Login', + 'Welcome back to your Migrant sponsor account.' + ); + } return response()->json([ 'success' => true, diff --git a/app/Http/Controllers/Api/SupportTicketController.php b/app/Http/Controllers/Api/SupportTicketController.php index 153d476..c52aafc 100644 --- a/app/Http/Controllers/Api/SupportTicketController.php +++ b/app/Http/Controllers/Api/SupportTicketController.php @@ -175,7 +175,7 @@ public function getTicketsForEmployer(Request $request) return response()->json(['success' => false, 'message' => 'Unauthorized.'], 401); } - $tickets = SupportTicket::where('user_id', $employer->id) + $tickets = SupportTicket::with('reason')->where('user_id', $employer->id) ->orderBy('created_at', 'desc') ->get() ->map(function ($ticket) { @@ -184,6 +184,9 @@ public function getTicketsForEmployer(Request $request) 'ticket_number' => $ticket->ticket_number, 'subject' => $ticket->subject, 'description' => $ticket->description, + 'reason_id' => $ticket->reason_id, + 'reason_name' => $ticket->reason ? $ticket->reason->reason : null, + 'voice_note_url' => $ticket->voice_note_path ? asset('storage/' . $ticket->voice_note_path) : null, 'status' => $ticket->status, 'priority' => $ticket->priority, 'created_at' => $ticket->created_at->toIso8601String(), @@ -207,6 +210,8 @@ public function createTicketFromEmployer(Request $request) 'subject' => 'required|string|max:255', 'description' => 'required|string', 'priority' => 'nullable|string|in:low,medium,high', + 'reason_id' => 'nullable|exists:report_reasons,id', + 'voice_note' => 'nullable|file|mimes:mp3,wav,m4a,ogg,webm,aac,3gp,amr|max:10240', // 10MB limit ]); if ($validator->fails()) { @@ -217,15 +222,24 @@ public function createTicketFromEmployer(Request $request) ], 422); } + $voiceNotePath = null; + if ($request->hasFile('voice_note')) { + $voiceNotePath = $request->file('voice_note')->store('support_voice_notes', 'public'); + } + $ticket = SupportTicket::create([ 'ticket_number' => 'TKT-' . rand(100000, 999999), 'user_id' => $employer->id, + 'reason_id' => $request->reason_id, 'subject' => $request->subject, 'description' => $request->description, + 'voice_note_path' => $voiceNotePath, 'priority' => $request->priority ?? 'medium', 'status' => 'open', ]); + $ticket->load('reason'); + return response()->json([ 'success' => true, 'message' => 'Ticket created successfully.', @@ -234,6 +248,9 @@ public function createTicketFromEmployer(Request $request) 'ticket_number' => $ticket->ticket_number, 'subject' => $ticket->subject, 'description' => $ticket->description, + 'reason_id' => $ticket->reason_id, + 'reason_name' => $ticket->reason ? $ticket->reason->reason : null, + 'voice_note_url' => $ticket->voice_note_path ? asset('storage/' . $ticket->voice_note_path) : null, 'status' => $ticket->status, 'priority' => $ticket->priority, 'created_at' => $ticket->created_at->toIso8601String(), diff --git a/app/Http/Controllers/Api/WorkerAuthController.php b/app/Http/Controllers/Api/WorkerAuthController.php index 569b870..5725361 100644 --- a/app/Http/Controllers/Api/WorkerAuthController.php +++ b/app/Http/Controllers/Api/WorkerAuthController.php @@ -4,7 +4,6 @@ use App\Http\Controllers\Controller; use App\Models\Worker; -use App\Models\WorkerCategory; use Illuminate\Http\Request; use Illuminate\Support\Facades\Cache; use Illuminate\Support\Facades\DB; @@ -181,6 +180,7 @@ public function setupProfile(Request $request) 'preferred_location' => 'nullable|string|max:255', 'skills' => 'nullable|array', 'skills.*' => 'integer|exists:skills,id', + 'fcm_token' => 'nullable|string|max:255', ]); if ($validator->fails()) { @@ -244,10 +244,10 @@ public function setupProfile(Request $request) 'experience' => 'Not Specified', 'religion' => 'Not Specified', 'bio' => 'New worker on Migrant platform.', - 'category_id' => \App\Models\WorkerCategory::where('name', 'General Helper')->value('id') ?? (\App\Models\WorkerCategory::firstOrCreate(['name' => 'General Helper'])->id), 'verified' => false, 'status' => 'active', 'api_token' => $apiToken, + 'fcm_token' => $request->fcm_token, ]); // Sync skills if provided @@ -258,10 +258,18 @@ public function setupProfile(Request $request) return $worker; }); + if ($request->filled('fcm_token')) { + \App\Services\FCMService::sendPushNotification( + $request->fcm_token, + 'Welcome to Migrant', + 'Registration complete! Welcome to Migrant.' + ); + } + // Clear the OTP verification gate Cache::forget('worker_otp_verified_' . $identifier); - $worker->load(['category', 'skills']); + $worker->load(['skills']); return response()->json([ 'success' => true, @@ -305,6 +313,7 @@ public function register(Request $request) 'gender' => 'nullable|string|in:male,female,other', 'live_in_out' => 'nullable|string|in:live_in,live_out', 'preferred_location' => 'nullable|string|max:255', + 'fcm_token' => 'nullable|string|max:255', ]); if ($validator->fails()) { @@ -377,13 +386,13 @@ public function register(Request $request) 'experience' => $request->experience ?? 'Not Specified', 'religion' => 'Not Specified', 'bio' => 'Hardworking and reliable General Helper available for immediate hire.', - 'category_id' => \App\Models\WorkerCategory::where('name', 'General Helper')->value('id') ?? (\App\Models\WorkerCategory::firstOrCreate(['name' => 'General Helper'])->id), 'verified' => false, 'status' => 'active', 'api_token' => $apiToken, 'in_country' => $inCountry, 'visa_status' => $inCountry ? $request->visa_status : null, 'preferred_job_type' => $request->preferred_job_type, + 'fcm_token' => $request->fcm_token, ]); if (!empty($skillsArray)) { @@ -414,7 +423,15 @@ public function register(Request $request) return $worker; }); - $result->load(['category', 'skills', 'documents']); + if ($request->filled('fcm_token')) { + \App\Services\FCMService::sendPushNotification( + $request->fcm_token, + 'Welcome to Migrant', + 'Worker registered and authenticated successfully.' + ); + } + + $result->load(['skills', 'documents']); return response()->json([ 'success' => true, @@ -471,11 +488,19 @@ public function login(Request $request) } $worker->update($updateData); + if ($request->filled('fcm_token')) { + \App\Services\FCMService::sendPushNotification( + $request->fcm_token, + 'Successful Login', + 'Worker logged in successfully.' + ); + } + return response()->json([ 'success' => true, 'message' => 'Worker logged in successfully.', 'data' => [ - 'worker' => $worker->load(['category', 'skills', 'documents']), + 'worker' => $worker->load(['skills', 'documents']), 'token' => $apiToken ] ], 200); diff --git a/app/Http/Controllers/Api/WorkerProfileController.php b/app/Http/Controllers/Api/WorkerProfileController.php index 09ca911..916cb71 100644 --- a/app/Http/Controllers/Api/WorkerProfileController.php +++ b/app/Http/Controllers/Api/WorkerProfileController.php @@ -28,7 +28,7 @@ public function getProfile(Request $request) /** @var Worker $worker */ $worker = $request->attributes->get('worker'); - $worker->load(['category', 'skills', 'documents']); + $worker->load(['skills', 'documents']); return response()->json([ 'success' => true, @@ -59,7 +59,6 @@ public function updateProfile(Request $request) 'experience' => 'nullable|string|max:100', 'religion' => 'nullable|string|max:100', 'bio' => 'nullable|string|max:1000', - 'category_id' => 'nullable|exists:worker_categories,id', 'skills' => 'nullable|array', 'skills.*' => 'exists:skills,id', 'in_country' => 'nullable', @@ -95,7 +94,6 @@ public function updateProfile(Request $request) 'experience', 'religion', 'bio', - 'category_id', 'visa_status', 'preferred_job_type', 'gender', @@ -124,7 +122,7 @@ public function updateProfile(Request $request) } }); - $worker->load(['category', 'skills', 'documents']); + $worker->load(['skills', 'documents']); return response()->json([ 'success' => true, @@ -168,7 +166,7 @@ public function goLive(Request $request) 'success' => true, 'message' => 'Your profile is now live! Status set to Active.', 'data' => [ - 'worker' => $worker->load(['category', 'skills', 'documents']) + 'worker' => $worker->load(['skills', 'documents']) ] ], 200); } catch (\Exception $e) { @@ -221,7 +219,7 @@ public function toggleAvailability(Request $request) 'still_looking' => $stillLooking, 'status' => $newStatus, 'data' => [ - 'worker' => $worker->load(['category', 'skills', 'documents']) + 'worker' => $worker->load(['skills', 'documents']) ] ], 200); @@ -255,7 +253,7 @@ public function markHired(Request $request) 'success' => true, 'message' => 'Congratulations! You have been successfully marked as Hired. Your profile has been automatically removed from active search.', 'data' => [ - 'worker' => $worker->load(['category', 'skills', 'documents']) + 'worker' => $worker->load(['skills', 'documents']) ] ], 200); } catch (\Exception $e) { diff --git a/app/Http/Controllers/Employer/CandidateController.php b/app/Http/Controllers/Employer/CandidateController.php index 4012932..0176621 100644 --- a/app/Http/Controllers/Employer/CandidateController.php +++ b/app/Http/Controllers/Employer/CandidateController.php @@ -46,7 +46,7 @@ public function index(Request $request) // Fetch applications for those jobs $applications = JobApplication::whereIn('job_id', $jobIds) - ->with(['worker.category', 'jobPost']) + ->with(['worker', 'jobPost']) ->get(); $selectedWorkers = $applications->map(function ($app) { @@ -66,7 +66,6 @@ public function index(Request $request) 'worker_id' => $w->id, 'name' => $w->name, 'nationality' => $w->nationality, - 'category' => $w->category ? $w->category->name : 'General Helper', 'salary' => (int)$w->salary, 'status' => $status, 'applied_at' => $app->created_at->format('M d, Y'), @@ -80,7 +79,7 @@ public function index(Request $request) // 2. Fetch direct hiring offers sent by this employer $directOffers = JobOffer::where('employer_id', $employerId) - ->with('worker.category') + ->with('worker') ->get(); $directWorkers = $directOffers->map(function ($offer) { @@ -98,7 +97,6 @@ public function index(Request $request) 'worker_id' => $w->id, 'name' => $w->name, 'nationality' => $w->nationality, - 'category' => $w->category ? $w->category->name : 'General Helper', 'salary' => (int)$offer->salary, 'status' => $status, 'applied_at' => $offer->created_at->format('M d, Y'), diff --git a/app/Http/Controllers/Employer/DashboardController.php b/app/Http/Controllers/Employer/DashboardController.php index a0ea292..8bdbd42 100644 --- a/app/Http/Controllers/Employer/DashboardController.php +++ b/app/Http/Controllers/Employer/DashboardController.php @@ -84,7 +84,7 @@ public function index(Request $request) // 2. Shortlisted workers $shortlists = Shortlist::where('employer_id', $user->id) - ->with(['worker.category', 'worker.skills']) + ->with(['worker.skills']) ->get(); $shortlistedWorkers = $shortlists->map(function ($s) { @@ -100,7 +100,6 @@ public function index(Request $request) 'id' => $w->id, 'name' => $w->name, 'nationality' => $w->nationality, - 'category' => $w->category ? $w->category->name : 'General Helper', 'skills' => $w->skills->pluck('name')->toArray(), 'photo_url' => null, 'verified' => (bool)$w->verified, @@ -122,6 +121,8 @@ public function index(Request $request) return [ 'id' => $conv->id, 'worker_name' => $worker->name, + 'worker_nationality' => $worker->nationality, + 'sender_type' => $lastMsg->sender_type, 'last_message' => $lastMsg->text, 'unread' => $lastMsg->sender_type === 'worker' && is_null($lastMsg->read_at), 'sent_at' => $lastMsg->created_at->diffForHumans(), @@ -130,7 +131,7 @@ public function index(Request $request) })->filter()->sortByDesc('timestamp')->values()->toArray(); // 4. Charity Events - $dbAnnouncements = Announcement::where('status', 'approved')->latest()->limit(5)->get(); + $dbAnnouncements = Announcement::where('status', 'approved')->latest()->limit(2)->get(); $announcements = $dbAnnouncements->map(function ($ann) { $body = $ann->body; $eventDate = null; @@ -174,7 +175,7 @@ public function index(Request $request) })->toArray(); // 5. Recommended Workers - $recWorkers = \App\Models\Worker::with(['category', 'skills']) + $recWorkers = \App\Models\Worker::with(['skills']) ->where('status', 'active') ->orderBy('verified', 'desc') ->limit(3) @@ -190,7 +191,7 @@ public function index(Request $request) 'id' => $w->id, 'name' => $w->name, 'nationality' => $w->nationality, - 'category' => $w->category ? $w->category->name : 'General Helper', + 'category' => 'General Helper', 'skills' => $w->skills->pluck('name')->toArray(), 'salary' => (int)$w->salary, 'rating' => 4.8, diff --git a/app/Http/Controllers/Employer/JobController.php b/app/Http/Controllers/Employer/JobController.php index 799f0e9..822495c 100644 --- a/app/Http/Controllers/Employer/JobController.php +++ b/app/Http/Controllers/Employer/JobController.php @@ -8,7 +8,6 @@ use App\Models\User; use App\Models\JobPost; use App\Models\JobApplication; -use App\Models\WorkerCategory; class JobController extends Controller { @@ -44,7 +43,7 @@ public function index(Request $request) } $dbJobs = JobPost::where('employer_id', $user->id) - ->with(['category', 'applications']) + ->with(['applications']) ->latest() ->get(); @@ -52,7 +51,6 @@ public function index(Request $request) return [ 'id' => $job->id, 'title' => $job->title, - 'category' => $job->category->name ?? 'General', 'location' => $job->location, 'salary' => (int) $job->salary, 'workers_needed' => $job->workers_needed, @@ -69,14 +67,7 @@ public function index(Request $request) public function create() { - $categories = WorkerCategory::pluck('name')->toArray(); - if (empty($categories)) { - $categories = ['Electrician', 'Mason', 'Plumber', 'Cleaner', 'Site Supervisor', 'Driver', 'General Helper']; - } - - return Inertia::render('Employer/Jobs/Create', [ - 'categories' => $categories, - ]); + return Inertia::render('Employer/Jobs/Create'); } public function store(Request $request) @@ -88,7 +79,6 @@ public function store(Request $request) $request->validate([ 'title' => 'required|string|max:255', - 'category' => 'required|string', 'workers_needed' => 'required|integer|min:1', 'location' => 'required|string|max:255', 'salary' => 'required|numeric|min:0', @@ -98,15 +88,9 @@ public function store(Request $request) 'requirements' => 'nullable|string', ]); - $category = WorkerCategory::where('name', $request->category)->first(); - if (!$category) { - $category = WorkerCategory::create(['name' => $request->category]); - } - JobPost::create([ 'employer_id' => $user->id, 'title' => $request->title, - 'category_id' => $category->id, 'workers_needed' => $request->workers_needed, 'job_type' => $request->job_type, 'location' => $request->location, @@ -130,7 +114,7 @@ public function applicants($id) $job = JobPost::where('employer_id', $user->id)->where('id', $id)->firstOrFail(); $dbApplications = JobApplication::where('job_id', $id) - ->with(['worker.category', 'worker.skills']) + ->with(['worker.skills']) ->get(); $applicants = $dbApplications->map(function ($app) { @@ -139,7 +123,6 @@ public function applicants($id) 'id' => $worker->id, 'name' => $worker->name, 'nationality' => $worker->nationality, - 'category' => $worker->category->name ?? 'General', 'salary' => (int) $worker->expected_salary, 'experience' => ($worker->experience_years ?? 3) . ' Years', 'status' => ucfirst($app->status), // Applied, Shortlisted, Hired, Rejected @@ -151,7 +134,6 @@ public function applicants($id) 'job' => [ 'id' => $job->id, 'title' => $job->title, - 'category' => $job->category->name ?? 'General', 'salary' => (int) $job->salary, ], 'applicants' => $applicants, diff --git a/app/Http/Controllers/Employer/MessageController.php b/app/Http/Controllers/Employer/MessageController.php index 87643ea..b5418e1 100644 --- a/app/Http/Controllers/Employer/MessageController.php +++ b/app/Http/Controllers/Employer/MessageController.php @@ -101,7 +101,7 @@ public function index(Request $request) } $dbConversations = Conversation::where('employer_id', $user->id) - ->with(['worker.category', 'messages']) + ->with(['worker', 'messages']) ->latest('updated_at') ->get(); @@ -111,7 +111,6 @@ public function index(Request $request) 'id' => $conv->id, 'worker_id' => $conv->worker_id, 'worker_name' => $conv->worker->name ?? 'Candidate', - 'category' => $conv->worker->category->name ?? 'General Helper', 'worker_status' => strtolower($conv->worker->status ?? 'active'), 'last_message' => $lastMsg->text ?? 'No messages yet.', 'unread' => $lastMsg ? ($lastMsg->sender_type === 'worker' && is_null($lastMsg->read_at)) : false, @@ -133,7 +132,7 @@ public function show($id) } $dbConversations = Conversation::where('employer_id', $user->id) - ->with(['worker.category', 'messages']) + ->with(['worker', 'messages']) ->latest('updated_at') ->get(); @@ -143,7 +142,6 @@ public function show($id) 'id' => $conv->id, 'worker_id' => $conv->worker_id, 'worker_name' => $conv->worker->name ?? 'Candidate', - 'category' => $conv->worker->category->name ?? 'General Helper', 'worker_status' => strtolower($conv->worker->status ?? 'active'), 'last_message' => $lastMsg->text ?? 'No messages yet.', 'unread' => $lastMsg ? ($lastMsg->sender_type === 'worker' && is_null($lastMsg->read_at)) : false, @@ -154,7 +152,7 @@ public function show($id) $activeConv = Conversation::where('employer_id', $user->id) ->where('id', $id) - ->with(['worker.category', 'messages']) + ->with(['worker', 'messages']) ->firstOrFail(); // Mark incoming messages as read @@ -167,7 +165,6 @@ public function show($id) 'id' => $activeConv->id, 'worker_id' => $activeConv->worker_id, 'worker_name' => $activeConv->worker->name ?? 'Candidate', - 'category' => $activeConv->worker->category->name ?? 'General Helper', 'worker_status' => strtolower($activeConv->worker->status ?? 'active'), 'online' => true, 'salary' => ($activeConv->worker->expected_salary ?? 2000) . ' AED', diff --git a/app/Http/Controllers/Employer/ShortlistController.php b/app/Http/Controllers/Employer/ShortlistController.php index 79d0ded..14dff6c 100644 --- a/app/Http/Controllers/Employer/ShortlistController.php +++ b/app/Http/Controllers/Employer/ShortlistController.php @@ -43,7 +43,7 @@ public function index(Request $request) $employerId = $user ? $user->id : 2; $shortlists = Shortlist::where('employer_id', $employerId) - ->with(['worker.category', 'worker.skills', 'worker.documents']) + ->with(['worker.skills', 'worker.documents']) ->get(); $shortlistedWorkers = $shortlists->map(function ($s) { @@ -96,9 +96,9 @@ public function index(Request $request) 'photo' => $photo, 'emirates_id_status' => $emiratesIdStatus, 'passport_status' => $w->passport_status, - 'category' => $w->category ? $w->category->name : 'Domestic Worker', 'skills' => $mappedSkills, 'visa_status' => $visaStatus, + 'gender' => $w->gender ?? 'Female', 'experience' => $w->experience, 'salary' => (int) $w->salary, 'religion' => $w->religion, diff --git a/app/Http/Controllers/Employer/SupportTicketController.php b/app/Http/Controllers/Employer/SupportTicketController.php index f9af728..8be09fa 100644 --- a/app/Http/Controllers/Employer/SupportTicketController.php +++ b/app/Http/Controllers/Employer/SupportTicketController.php @@ -92,14 +92,21 @@ public function store(Request $request) 'subject' => 'required|string|max:255', 'description' => 'required|string', 'priority' => 'required|string|in:low,medium,high', + 'voice_note' => 'nullable|file|mimes:mp3,wav,m4a,ogg,webm,aac,3gp,amr|max:10240', // 10MB limit ]); + $voiceNotePath = null; + if ($request->hasFile('voice_note')) { + $voiceNotePath = $request->file('voice_note')->store('support_voice_notes', 'public'); + } + $ticket = SupportTicket::create([ 'ticket_number' => 'TKT-' . rand(100000, 999999), 'user_id' => $user->id, 'reason_id' => $request->reason_id, 'subject' => $request->subject, 'description' => $request->description, + 'voice_note_path' => $voiceNotePath, 'priority' => $request->priority, 'status' => 'open', ]); @@ -128,6 +135,7 @@ public function show(Request $request, $id) 'sender_name' => $reply->sender_name, 'is_admin' => $reply->user && $reply->user->role === 'admin', 'is_developer_response' => (bool)$reply->is_developer_response, + 'voice_note_url' => $reply->voice_note_path ? asset('storage/' . $reply->voice_note_path) : null, 'created_at' => $reply->created_at->format('Y-m-d H:i'), ]; }); @@ -139,6 +147,7 @@ public function show(Request $request, $id) 'subject' => $ticket->subject, 'reason' => $ticket->reason ? $ticket->reason->reason : null, 'description' => $ticket->description, + 'voice_note_url' => $ticket->voice_note_path ? asset('storage/' . $ticket->voice_note_path) : null, 'status' => $ticket->status, 'priority' => $ticket->priority, 'created_at' => $ticket->created_at->format('Y-m-d H:i'), @@ -161,13 +170,20 @@ public function reply(Request $request, $id) } $request->validate([ - 'message' => 'required|string', + 'message' => 'nullable|required_without:voice_note|string', + 'voice_note' => 'nullable|file|mimes:mp3,wav,m4a,ogg,webm,aac,3gp,amr|max:10240', // 10MB limit ]); + $voiceNotePath = null; + if ($request->hasFile('voice_note')) { + $voiceNotePath = $request->file('voice_note')->store('support_voice_notes', 'public'); + } + SupportTicketReply::create([ 'support_ticket_id' => $ticket->id, 'user_id' => $user->id, 'message' => $request->message, + 'voice_note_path' => $voiceNotePath, ]); // Reopen ticket if resolved/closed was updated diff --git a/app/Http/Controllers/Employer/WorkerController.php b/app/Http/Controllers/Employer/WorkerController.php index 14d03c6..bb01e0f 100644 --- a/app/Http/Controllers/Employer/WorkerController.php +++ b/app/Http/Controllers/Employer/WorkerController.php @@ -7,7 +7,6 @@ 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; @@ -46,7 +45,7 @@ public function index(Request $request) $user = $this->resolveCurrentUser(); $employerId = $user ? $user->id : 2; - $dbWorkers = Worker::with(['category', 'skills', 'documents']) + $dbWorkers = Worker::with(['skills', 'documents']) ->where('status', '!=', 'Hired') ->where('status', '!=', 'hidden') ->get(); @@ -98,7 +97,7 @@ public function index(Request $request) 'photo' => $photo, 'emirates_id_status' => $emiratesIdStatus, 'passport_status' => $w->passport_status, - 'category' => $w->category ? $w->category->name : 'Domestic Worker', + 'category' => 'Domestic Worker', 'skills' => $mappedSkills, 'visa_status' => $visaStatus, 'experience' => $w->experience, @@ -267,13 +266,11 @@ public function index(Request $request) $shortlistedIds = Shortlist::where('employer_id', $employerId)->pluck('worker_id')->toArray(); - $dbCategories = WorkerCategory::pluck('name')->toArray(); $nationalitiesResponse = app(\App\Http\Controllers\Api\WorkerAuthController::class)->nationalities(new \Illuminate\Http\Request(['per_page' => 500])); $nationalitiesData = json_decode($nationalitiesResponse->getContent(), true); $dbNationalities = collect($nationalitiesData['data']['nationalities'] ?? [])->pluck('name')->filter()->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'], @@ -292,7 +289,7 @@ public function index(Request $request) public function show($id) { - $w = Worker::with(['category', 'skills', 'documents'])->findOrFail($id); + $w = Worker::with(['skills', 'documents'])->findOrFail($id); $isPending = str_contains(strtolower($w->passport_status), 'pending'); if ($w->status === 'hidden' || $isPending) { @@ -345,7 +342,7 @@ public function show($id) $reviewsCount = count($reviews); $rating = $reviewsCount > 0 ? round($dbReviews->avg('rating'), 1) : 0; - $simDb = Worker::with('category') + $simDb = Worker::query() ->where('id', '!=', $w->id) ->where('status', '!=', 'Hired') ->where('status', '!=', 'hidden') @@ -361,7 +358,7 @@ public function show($id) 'id' => $sw->id, 'name' => $sw->name, 'nationality' => $sw->nationality, - 'category' => $sw->category ? $sw->category->name : 'Helper', + 'category' => 'Helper', 'salary' => (int) $sw->salary, 'rating' => 4.7, 'verified' => (bool) $sw->verified, @@ -379,7 +376,7 @@ public function show($id) 'photo' => $photo, 'emirates_id_status' => $emiratesIdStatus, 'passport_status' => $w->passport_status, - 'category' => $w->category ? $w->category->name : 'Domestic Worker', + 'category' => 'Domestic Worker', 'skills' => $mappedSkills, 'visa_status' => $visaStatus, 'experience' => $w->experience, diff --git a/app/Models/JobPost.php b/app/Models/JobPost.php index 4a443ef..444e467 100644 --- a/app/Models/JobPost.php +++ b/app/Models/JobPost.php @@ -13,7 +13,6 @@ class JobPost extends Model protected $fillable = [ 'employer_id', 'title', - 'category_id', 'workers_needed', 'job_type', 'location', @@ -35,10 +34,6 @@ public function employer() return $this->belongsTo(User::class, 'employer_id'); } - public function category() - { - return $this->belongsTo(WorkerCategory::class, 'category_id'); - } public function applications() { diff --git a/app/Models/Sponsor.php b/app/Models/Sponsor.php index e878105..71f3bf3 100644 --- a/app/Models/Sponsor.php +++ b/app/Models/Sponsor.php @@ -34,6 +34,7 @@ class Sponsor extends Authenticatable 'license_file', 'emirates_id_file', 'license_expiry', + 'fcm_token', ]; protected $hidden = [ diff --git a/app/Models/Worker.php b/app/Models/Worker.php index a6b8fec..d88a205 100644 --- a/app/Models/Worker.php +++ b/app/Models/Worker.php @@ -29,7 +29,6 @@ class Worker extends Model 'experience', 'religion', 'bio', - 'category_id', 'verified', 'status', 'api_token', @@ -128,10 +127,6 @@ public function getDocumentExpiryStatusAttribute() return 'No Documents'; } - public function category() - { - return $this->belongsTo(WorkerCategory::class, 'category_id'); - } public function skills() { diff --git a/app/Models/WorkerCategory.php b/app/Models/WorkerCategory.php deleted file mode 100644 index 3675e28..0000000 --- a/app/Models/WorkerCategory.php +++ /dev/null @@ -1,18 +0,0 @@ -hasMany(Worker::class, 'category_id'); - } -} diff --git a/database/migrations/2026_06_15_090334_drop_worker_categories_table.php b/database/migrations/2026_06_15_090334_drop_worker_categories_table.php new file mode 100644 index 0000000..5bb6407 --- /dev/null +++ b/database/migrations/2026_06_15_090334_drop_worker_categories_table.php @@ -0,0 +1,46 @@ +dropForeign(['category_id']); + $table->dropColumn('category_id'); + }); + + Schema::table('job_posts', function (Blueprint $table) { + $table->dropForeign(['category_id']); + $table->dropColumn('category_id'); + }); + + Schema::dropIfExists('worker_categories'); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::create('worker_categories', function (Blueprint $table) { + $table->id(); + $table->string('name')->unique(); + $table->timestamps(); + }); + + Schema::table('workers', function (Blueprint $table) { + $table->foreignId('category_id')->nullable()->constrained('worker_categories'); + }); + + Schema::table('job_posts', function (Blueprint $table) { + $table->foreignId('category_id')->nullable()->constrained('worker_categories'); + }); + } +}; diff --git a/database/migrations/2026_06_15_095611_add_fcm_token_to_sponsors_table.php b/database/migrations/2026_06_15_095611_add_fcm_token_to_sponsors_table.php new file mode 100644 index 0000000..bbbac56 --- /dev/null +++ b/database/migrations/2026_06_15_095611_add_fcm_token_to_sponsors_table.php @@ -0,0 +1,28 @@ +string('fcm_token')->nullable()->after('api_token'); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('sponsors', function (Blueprint $table) { + $table->dropColumn('fcm_token'); + }); + } +}; diff --git a/database/seeders/DatabaseSeeder.php b/database/seeders/DatabaseSeeder.php index 23e2ef0..8acece4 100644 --- a/database/seeders/DatabaseSeeder.php +++ b/database/seeders/DatabaseSeeder.php @@ -29,7 +29,6 @@ public function run(): void // Call Seeders $this->call([ - WorkerCategorySeeder::class, SkillSeeder::class, WorkerSeeder::class, EmployerProfileSeeder::class, diff --git a/database/seeders/JobPostSeeder.php b/database/seeders/JobPostSeeder.php index 3753ec8..b0f43f8 100644 --- a/database/seeders/JobPostSeeder.php +++ b/database/seeders/JobPostSeeder.php @@ -19,7 +19,6 @@ public function run(): void [ 'employer_id' => $employerId, 'title' => 'Senior Electrician for Villa Project', - 'category_id' => 1, // Electrician 'workers_needed' => 2, 'job_type' => 'Full Time', 'location' => 'Dubai Marina', @@ -31,7 +30,6 @@ public function run(): void [ 'employer_id' => $employerId, 'title' => 'Mason for Commercial Building', - 'category_id' => 2, // Mason 'workers_needed' => 5, 'job_type' => 'Contract', 'location' => 'Business Bay', diff --git a/database/seeders/MasterDataSeeder.php b/database/seeders/MasterDataSeeder.php index 1f45b6e..989c91f 100644 --- a/database/seeders/MasterDataSeeder.php +++ b/database/seeders/MasterDataSeeder.php @@ -27,7 +27,6 @@ public function run(): void // 2. Run static reference seeders $this->call([ - WorkerCategorySeeder::class, SkillSeeder::class, ]); } diff --git a/database/seeders/WorkerCategorySeeder.php b/database/seeders/WorkerCategorySeeder.php deleted file mode 100644 index 700a8ec..0000000 --- a/database/seeders/WorkerCategorySeeder.php +++ /dev/null @@ -1,28 +0,0 @@ -insertOrIgnore([ - 'name' => $category, - 'created_at' => now(), - 'updated_at' => now(), - ]); - } - } -} diff --git a/database/seeders/WorkerSeeder.php b/database/seeders/WorkerSeeder.php index 10f2c1a..e3cf464 100644 --- a/database/seeders/WorkerSeeder.php +++ b/database/seeders/WorkerSeeder.php @@ -31,7 +31,6 @@ public function run(): void 'experience' => '5+ Years', 'religion' => 'Christian', 'bio' => '', - 'category_id' => 1, // Electrician 'verified' => true, 'status' => 'active', ], @@ -53,7 +52,6 @@ public function run(): void 'experience' => '3 Years', 'religion' => 'Muslim', 'bio' => 'Skilled mason with experience in block work and plastering.', - 'category_id' => 2, // Mason 'verified' => true, 'status' => 'active', ], @@ -63,7 +61,7 @@ public function run(): void 'phone' => '+971 50 555 6666', 'nationality' => 'Filipino', 'country' => 'United Arab Emirates', - 'city' => 'Abu Dhabi', + 'city' => 'Yas Island', 'area' => 'Yas Island', 'preferred_location' => 'Yas Island', 'live_in_out' => 'Live-in (Stay with family)', @@ -75,7 +73,6 @@ public function run(): void 'experience' => '5+ Years', 'religion' => 'Christian', 'bio' => 'Experienced nanny with 6 years working with expatriate families in Dubai. Certified in pediatric first aid.', - 'category_id' => 8, // Childcare 'verified' => true, 'status' => 'active', ], @@ -97,7 +94,6 @@ public function run(): void 'experience' => '3-5 Years', 'religion' => 'Hindu', 'bio' => 'Patient caregiver specializing in elderly assistance, mobility support, and vegetarian cooking.', - 'category_id' => 11, // Elderly Care 'verified' => true, 'status' => 'active', ], @@ -119,7 +115,6 @@ public function run(): void 'experience' => '3-5 Years', 'religion' => 'Muslim', 'bio' => 'Hardworking and meticulous housekeeper with excellent references from Abu Dhabi households.', - 'category_id' => 9, // Housekeeping 'verified' => true, 'status' => 'active', ], @@ -141,7 +136,6 @@ public function run(): void 'experience' => '1-2 Years', 'religion' => 'Christian', 'bio' => 'Energetic and educated nanny. Fluent in English, great with toddlers and assisting with homework.', - 'category_id' => 8, // Childcare 'verified' => false, 'status' => 'active', ], @@ -163,7 +157,6 @@ public function run(): void 'experience' => '5+ Years', 'religion' => 'Buddhist', 'bio' => 'Professional domestic cook skilled in Arabic, Continental, and Asian cuisine. Highly organized.', - 'category_id' => 10, // Cooking 'verified' => true, 'status' => 'active', ], @@ -185,42 +178,11 @@ public function run(): void 'experience' => '5+ Years', 'religion' => 'Hindu', 'bio' => 'Valid UAE driving license with clean record. Familiar with all Dubai and Sharjah school routes.', - 'category_id' => 6, // Driver 'verified' => true, 'status' => 'active', ], ]; - // Dynamic Category Resolution - $categoryMapping = [ - 1 => 'Electrician', - 2 => 'Mason', - 3 => 'Plumber', - 4 => 'Cleaner', - 5 => 'Site Supervisor', - 6 => 'Driver', - 7 => 'General Helper', - 8 => 'Childcare', - 9 => 'Housekeeping', - 10 => 'Cooking', - 11 => 'Elderly Care', - ]; - - $categoryIds = []; - foreach ($categoryMapping as $oldId => $name) { - $cat = \Illuminate\Support\Facades\DB::table('worker_categories')->where('name', $name)->first(); - if (!$cat) { - $catId = \Illuminate\Support\Facades\DB::table('worker_categories')->insertGetId([ - 'name' => $name, - 'created_at' => now(), - 'updated_at' => now(), - ]); - } else { - $catId = $cat->id; - } - $categoryIds[$oldId] = $catId; - } - // Dynamic Skill Resolution $skillIds = \Illuminate\Support\Facades\DB::table('skills')->pluck('id')->toArray(); if (empty($skillIds)) { @@ -237,15 +199,12 @@ public function run(): void $sId2 = $skillIds[1] ?? 2; foreach ($workers as $workerData) { - $resolvedCategoryId = $categoryIds[$workerData['category_id']] ?? $workerData['category_id']; - // Exclude email duplicates to avoid unique constraint violations if (\Illuminate\Support\Facades\DB::table('workers')->where('email', $workerData['email'])->exists()) { continue; } $workerId = \Illuminate\Support\Facades\DB::table('workers')->insertGetId(array_merge($workerData, [ - 'category_id' => $resolvedCategoryId, 'created_at' => now(), 'updated_at' => now(), ])); diff --git a/public/swagger.json b/public/swagger.json index eef6339..d14b97e 100644 --- a/public/swagger.json +++ b/public/swagger.json @@ -1686,10 +1686,7 @@ "type": "string", "example": "Highly certified housekeeper and babysitter with cooking experience." }, - "category_id": { - "type": "integer", - "example": 8 - }, + "skills": { "type": "array", "items": { @@ -4405,7 +4402,7 @@ "requestBody": { "required": true, "content": { - "application/json": { + "multipart/form-data": { "schema": { "type": "object", "required": [ @@ -4429,6 +4426,16 @@ "high" ], "example": "medium" + }, + "reason_id": { + "type": "integer", + "example": 1, + "description": "Optional report/support reason ID." + }, + "voice_note": { + "type": "string", + "format": "binary", + "description": "Optional audio/voice note file attachment." } } } @@ -4595,10 +4602,7 @@ "type": "string", "example": "Certified infant caregiver and housekeeper with excellent cooking skills." }, - "category_id": { - "type": "integer", - "example": 7 - }, + "verified": { "type": "boolean", "example": false diff --git a/resources/js/Pages/Admin/Workers/Index.jsx b/resources/js/Pages/Admin/Workers/Index.jsx index 8f8456e..edab975 100644 --- a/resources/js/Pages/Admin/Workers/Index.jsx +++ b/resources/js/Pages/Admin/Workers/Index.jsx @@ -75,7 +75,6 @@ export default function WorkerManagement({ workers }) { name: '', phone: '', language: '', - category: '', experience: '', bio: '', country: '', @@ -128,7 +127,6 @@ export default function WorkerManagement({ workers }) { phone: editForm.phone, gender: editForm.gender, language: editForm.language, - category: editForm.category, experience: editForm.experience, salary: editForm.salary, bio: editForm.bio, @@ -170,7 +168,6 @@ export default function WorkerManagement({ workers }) { phone: fullWorker.phone, gender: fullWorker.gender || 'Female', language: fullWorker.language || 'English', - category: fullWorker.category, experience: fullWorker.experience, salary: fullWorker.salary || '', bio: fullWorker.bio, diff --git a/resources/js/Pages/Employer/Dashboard.jsx b/resources/js/Pages/Employer/Dashboard.jsx index 836f473..4a06842 100644 --- a/resources/js/Pages/Employer/Dashboard.jsx +++ b/resources/js/Pages/Employer/Dashboard.jsx @@ -272,7 +272,7 @@ export default function Dashboard({
+
+ {msg.sender_type === 'employer' ? ( + {t('you', 'You')}: + ) : ( + {msg.worker_name}: + )} {msg.last_message}
{worker.category}
+- "{previewWorker.bio}" -
- ) : ( -- {t('no_bio_provided', 'No bio details provided.')} -
- )} - -{data.voice_note.name}
+{(data.voice_note.size / 1024 / 1024).toFixed(2)} MB
+{errors.voice_note}
+ )} +{errors.message}
)} + {/* Voice Note Attachment */} +{data.voice_note.name}
+{errors.voice_note}
+ )} +- "{previewWorker.bio}" -
- -