migrant-web/app/Http/Controllers/Api/EmployerProfileController.php

483 lines
20 KiB
PHP

<?php
namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller;
use App\Models\User;
use App\Models\EmployerProfile;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Validator;
class EmployerProfileController extends Controller
{
/**
* Get the authenticated employer's profile details.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\JsonResponse
*/
public function getProfile(Request $request)
{
/** @var User $employer */
$employer = $request->attributes->get('employer');
try {
$profile = $employer->employerProfile;
if (!$profile) {
$profile = EmployerProfile::create([
'user_id' => $employer->id,
'phone' => '+971 50 123 4567',
'address' => 'Dubai, UAE',
'verification_status' => 'approved',
]);
}
$employerProfile = [
'name' => $employer->name,
'email' => $employer->email,
'phone' => $profile->phone,
'country' => $profile->country,
'language' => $profile->language ?? 'English',
'notifications' => (bool)($profile->notifications ?? true),
'verification_status' => $profile->verification_status ?? 'approved',
'emirates_id' => [
'emirates_id_number' => $profile->emirates_id_number,
'name' => $profile->emirates_id_name,
'date_of_birth' => $profile->emirates_id_dob,
'issue_date' => $profile->emirates_id_issue_date,
'expiry_date' => $profile->emirates_id_expiry,
'employer' => $profile->emirates_id_employer,
'issue_place' => $profile->emirates_id_issue_place,
'occupation' => $profile->emirates_id_occupation,
'nationality' => $profile->emirates_id_nationality,
'gender' => $profile->emirates_id_gender,
],
];
return response()->json([
'success' => true,
'data' => [
'profile' => $employerProfile
]
], 200);
} catch (\Exception $e) {
logger()->error('Mobile Employer Get Profile Failure: ' . $e->getMessage());
return response()->json([
'success' => false,
'message' => 'An error occurred while fetching the profile.',
'error' => app()->environment('local') ? $e->getMessage() : 'Internal Server Error'
], 500);
}
}
/**
* Update the authenticated employer's profile details.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\JsonResponse
*/
public function updateProfile(Request $request)
{
/** @var User $employer */
$employer = $request->attributes->get('employer');
$sponsor = \App\Models\Sponsor::where('email', $employer->email)->first();
$validator = Validator::make($request->all(), [
'name' => 'required|string|max:255',
'email' => [
'required',
'string',
'email',
'max:255',
'unique:users,email,' . $employer->id,
$sponsor ? 'unique:sponsors,email,' . $sponsor->id : 'unique:sponsors,email',
],
'phone' => [
'required',
'string',
'max:255',
'unique:employer_profiles,phone,' . ($employer->employerProfile ? $employer->employerProfile->id : 'NULL'),
$sponsor ? 'unique:sponsors,mobile,' . $sponsor->id : 'unique:sponsors,mobile',
],
'address' => 'required|string|max:255',
'notifications' => 'nullable|boolean',
'fcm_token' => 'nullable|string|max:255',
// Emirates ID optional fields
'id_number' => 'nullable|string|max:255',
'card_number' => 'nullable|string|max:255',
'full_name' => 'nullable|string|max:255',
'date_of_birth' => 'nullable|string|max:255',
'nationality' => 'nullable|string|max:255',
'gender' => 'nullable|string|max:255',
'issue_date' => 'nullable|string|max:255',
'expiry_date' => 'nullable|string|max:255',
'occupation' => 'nullable|string|max:255',
'employer' => 'nullable|string|max:255',
'issuing_place' => 'nullable|string|max:255',
]);
$validator->after(function ($validator) use ($request) {
if ($request->has('full_name') && !$request->filled('full_name')) {
$validator->errors()->add('full_name', 'Failed to extract name from the Emirates ID. Please upload a clearer document.');
}
});
if ($validator->fails()) {
return response()->json([
'success' => false,
'message' => 'Validation error.',
'errors' => $validator->errors()
], 422);
}
try {
if ($request->filled('full_name')) {
$request->merge(['name' => $request->full_name]);
}
// Validate Emirates ID immutability — once set, it cannot be changed
if ($request->filled('id_number')) {
$existingProfile = $employer->employerProfile;
if ($existingProfile && $existingProfile->emirates_id_number && $existingProfile->emirates_id_number !== $request->id_number) {
return response()->json([
'success' => false,
'message' => 'Emirates ID mismatch. You cannot change your registered Emirates ID number.',
'errors' => [
'id_number' => ['Emirates ID mismatch.']
]
], 422);
}
}
// Find old email before update to locate the correct sponsor record
$oldEmail = $employer->getOriginal('email') ?? $employer->email;
// Update user table
$userData = [
'name' => $request->name,
'email' => $request->email,
];
if ($request->has('fcm_token')) {
$userData['fcm_token'] = $request->fcm_token;
}
$employer->update($userData);
// Sync with corresponding sponsor record if found
$matchingSponsor = \App\Models\Sponsor::where('email', $oldEmail)->first();
if ($matchingSponsor) {
$sponsorData = [
'full_name' => $request->name,
'email' => $request->email,
'mobile' => $request->phone,
'address' => $request->address,
];
if ($request->has('id_number')) {
$sponsorData['emirates_id'] = $request->id_number;
}
if ($request->has('card_number')) {
$sponsorData['emirates_id_card_number'] = $request->card_number;
}
if ($request->has('full_name')) {
$sponsorData['emirates_id_name'] = $request->full_name;
}
if ($request->has('date_of_birth')) {
$sponsorData['emirates_id_dob'] = $request->date_of_birth;
}
if ($request->has('nationality')) {
$sponsorData['nationality'] = $request->nationality;
}
if ($request->has('gender')) {
$sponsorData['emirates_id_gender'] = $request->gender;
}
if ($request->has('issue_date')) {
$sponsorData['emirates_id_issue_date'] = $request->issue_date;
}
if ($request->has('expiry_date')) {
$sponsorData['emirates_id_expiry'] = $request->expiry_date;
}
if ($request->has('occupation')) {
$sponsorData['emirates_id_occupation'] = $request->occupation;
}
if ($request->has('employer')) {
$sponsorData['emirates_id_employer'] = $request->employer;
}
if ($request->has('issuing_place')) {
$sponsorData['emirates_id_issue_place'] = $request->issuing_place;
}
$matchingSponsor->update($sponsorData);
}
// Update employer_profiles table
$profile = $employer->employerProfile;
if (!$profile) {
$profile = new EmployerProfile(['user_id' => $employer->id]);
}
$profile->address = $request->address;
$profile->phone = $request->phone;
$profile->notifications = $request->has('notifications') ? $request->notifications : ($profile->notifications ?? true);
if ($request->has('id_number')) {
$profile->emirates_id_number = $request->id_number;
}
if ($request->has('card_number')) {
$profile->emirates_id_card_number = $request->card_number;
}
if ($request->has('full_name')) {
$profile->emirates_id_name = $request->full_name;
}
if ($request->has('date_of_birth')) {
$profile->emirates_id_dob = $request->date_of_birth;
}
if ($request->has('nationality')) {
$profile->nationality = $request->nationality;
}
if ($request->has('gender')) {
$profile->emirates_id_gender = $request->gender;
}
if ($request->has('issue_date')) {
$profile->emirates_id_issue_date = $request->issue_date;
}
if ($request->has('expiry_date')) {
$profile->emirates_id_expiry = $request->expiry_date;
}
if ($request->has('occupation')) {
$profile->emirates_id_occupation = $request->occupation;
}
if ($request->has('employer')) {
$profile->emirates_id_employer = $request->employer;
}
if ($request->has('issuing_place')) {
$profile->emirates_id_issue_place = $request->issuing_place;
}
$profile->save();
$employerProfile = [
'name' => $employer->name,
'email' => $employer->email,
'phone' => $profile->phone,
'country' => $profile->country,
'language' => $profile->language,
'notifications' => (bool)$profile->notifications,
'verification_status' => $profile->verification_status ?? 'approved',
'emirates_id' => [
'emirates_id_number' => $profile->emirates_id_number,
'name' => $profile->emirates_id_name,
'date_of_birth' => $profile->emirates_id_dob,
'issue_date' => $profile->emirates_id_issue_date,
'expiry_date' => $profile->emirates_id_expiry,
'employer' => $profile->emirates_id_employer,
'issue_place' => $profile->emirates_id_issue_place,
'occupation' => $profile->emirates_id_occupation,
'nationality' => $profile->emirates_id_nationality,
'gender' => $profile->emirates_id_gender,
],
];
return response()->json([
'success' => true,
'message' => 'Profile updated successfully.',
'data' => [
'profile' => $employerProfile
]
], 200);
} catch (\Exception $e) {
logger()->error('Mobile Employer Update Profile Failure: ' . $e->getMessage());
return response()->json([
'success' => false,
'message' => 'An error occurred while updating the profile.',
'error' => app()->environment('local') ? $e->getMessage() : 'Internal Server Error'
], 500);
}
}
/**
* Get dashboard analytics and summary for employer.
*/
public function getDashboard(Request $request)
{
/** @var User $employer */
$employer = $request->attributes->get('employer');
try {
$contactedWorkersCount = \App\Models\Conversation::where('employer_id', $employer->id)->count();
$totalHiredWorkers = \App\Models\JobOffer::where('employer_id', $employer->id)->where('status', 'accepted')->count() +
\App\Models\JobApplication::whereHas('jobPost', function($q) use ($employer) {
$q->where('employer_id', $employer->id);
})->where('status', 'hired')->count();
$savedCandidates = \App\Models\Shortlist::where('employer_id', $employer->id)->count();
$totalWorkers = \App\Models\Worker::with('documents')
->where('status', '!=', 'Hired')
->where('status', '!=', 'hidden')
->get()
->filter(function ($w) {
return !str_contains(strtolower($w->passport_status), 'pending');
})
->count();
// Resolve plan
$sub = \Illuminate\Support\Facades\DB::table('subscriptions')
->where('user_id', $employer->id)
->where('status', 'active')
->latest('id')
->first();
$currentPlan = [
'plan_id' => $sub ? $sub->plan_id : 'premium',
'name' => $sub ? (ucfirst($sub->plan_id) . ' Pass') : 'Premium Employer Pass',
'status' => $sub ? $sub->status : 'active',
'starts_at' => $sub ? date('Y-m-d', strtotime($sub->starts_at)) : now()->subDays(6)->format('Y-m-d'),
'expires_at' => $sub ? date('Y-m-d', strtotime($sub->expires_at)) : now()->addDays(24)->format('Y-m-d'),
];
// Recent Announcements / Events
$dbAnnouncements = \App\Models\Announcement::where('status', 'approved')->latest()->limit(2)->get();
$recentAnnouncements = $dbAnnouncements->map(function ($ann) {
$body = $ann->body;
$eventDate = null;
$eventTime = null;
$locationDetails = null;
$locationPin = null;
$providedItems = null;
if (strpos($ann->body, '{"type":"Charity"') === 0) {
$decoded = json_decode($ann->body, true);
if ($decoded) {
$body = $decoded['content'] ?? $ann->body;
$eventDate = $decoded['event_date'] ?? null;
$eventTime = $decoded['event_time'] ?? null;
$locationDetails = $decoded['location_details'] ?? null;
$locationPin = $decoded['location_pin'] ?? null;
$providedItems = $decoded['provided_items'] ?? null;
}
} else {
$body = $ann->body;
$eventDate = $ann->created_at->addDays(2)->format('Y-m-d');
$eventTime = '9:00 AM - 3:00 PM';
$locationDetails = 'Al Quoz Community Center, Dubai';
$locationPin = 'https://maps.google.com';
$providedItems = 'Free Medical Checks & Food Supplies';
}
return [
'id' => $ann->id,
'title' => $ann->title,
'body' => $body,
'is_charity' => true,
'event_date' => $eventDate,
'event_time' => $eventTime,
'location_details' => $locationDetails,
'location_pin' => $locationPin,
'provided_items' => $providedItems,
'created_at' => $ann->created_at->toISOString(),
'time_ago' => $ann->created_at->diffForHumans(),
];
});
return response()->json([
'success' => true,
'data' => [
'stats' => [
'contacted_workers_count' => $contactedWorkersCount,
'total_hired_workers' => $totalHiredWorkers,
'saved_candidates' => $savedCandidates,
'total_workers' => $totalWorkers,
],
'current_plan' => $currentPlan,
'recent_announcements' => $recentAnnouncements,
'recent_events' => $recentAnnouncements, // alias for ease
]
], 200);
} catch (\Exception $e) {
logger()->error('Mobile Employer Get Dashboard Failure: ' . $e->getMessage());
return response()->json([
'success' => false,
'message' => 'An error occurred while fetching the dashboard statistics.',
'error' => app()->environment('local') ? $e->getMessage() : 'Internal Server Error'
], 500);
}
}
/**
* Change employer's password.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\JsonResponse
*/
public function changePassword(Request $request)
{
/** @var User $employer */
$employer = $request->attributes->get('employer');
$validator = Validator::make($request->all(), [
'current_password' => 'required|string',
'new_password' => 'required|string|min:8|confirmed',
]);
if ($validator->fails()) {
return response()->json([
'success' => false,
'message' => 'Validation error.',
'errors' => $validator->errors()
], 422);
}
if (!Hash::check($request->current_password, $employer->password)) {
return response()->json([
'success' => false,
'message' => 'Validation error.',
'errors' => [
'current_password' => ['The current password is incorrect.']
]
], 422);
}
try {
$hashedPassword = Hash::make($request->new_password);
// Update user table
$employer->update([
'password' => $hashedPassword
]);
// Sync with corresponding sponsor record if found
$matchingSponsor = \App\Models\Sponsor::where('email', $employer->email)->first();
if ($matchingSponsor) {
$matchingSponsor->update([
'password' => $hashedPassword
]);
}
return response()->json([
'success' => true,
'message' => 'Password changed successfully.'
], 200);
} catch (\Exception $e) {
logger()->error('Mobile Employer Change Password Failure: ' . $e->getMessage());
return response()->json([
'success' => false,
'message' => 'An error occurred while changing password.',
'error' => app()->environment('local') ? $e->getMessage() : 'Internal Server Error'
], 500);
}
}
}