326 lines
12 KiB
PHP
326 lines
12 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers\Api;
|
|
|
|
use App\Http\Controllers\Controller;
|
|
use Illuminate\Http\Request;
|
|
use App\Models\Worker;
|
|
use App\Models\User;
|
|
use App\Models\JobPost;
|
|
use App\Models\JobApplication;
|
|
use App\Models\JobOffer;
|
|
use App\Models\EmployerReview;
|
|
use Illuminate\Support\Facades\Validator;
|
|
use Carbon\Carbon;
|
|
|
|
class WorkerReviewController extends Controller
|
|
{
|
|
/**
|
|
* Add a new review for an employer.
|
|
* POST /api/workers/reviews
|
|
*/
|
|
public function addReview(Request $request)
|
|
{
|
|
/** @var Worker $worker */
|
|
$worker = $request->attributes->get('worker');
|
|
|
|
$validator = Validator::make($request->all(), [
|
|
'employer_id' => 'required|exists:users,id',
|
|
'job_id' => 'nullable|exists:job_posts,id',
|
|
'rating' => 'required|integer|min:1|max:5',
|
|
'title' => 'nullable|string|max:255',
|
|
'comment' => 'required|string|max:1000',
|
|
]);
|
|
|
|
if ($validator->fails()) {
|
|
return response()->json([
|
|
'success' => false,
|
|
'message' => 'Validation error.',
|
|
'errors' => $validator->errors()
|
|
], 422);
|
|
}
|
|
|
|
try {
|
|
$employerId = $request->employer_id;
|
|
$jobId = $request->job_id;
|
|
|
|
// 1. Validate confirmed hire and completed joining, and 3-month requirement
|
|
$hasConfirmedHire = false;
|
|
$joiningDate = null;
|
|
|
|
// Check standard JobApplication
|
|
$appQuery = JobApplication::where('worker_id', $worker->id)
|
|
->where('status', 'hired')
|
|
->whereNotNull('joining_confirmed_at')
|
|
->whereHas('jobPost', function ($query) use ($employerId, $jobId) {
|
|
$query->where('employer_id', $employerId);
|
|
if ($jobId) {
|
|
$query->where('id', $jobId);
|
|
}
|
|
});
|
|
|
|
$app = $appQuery->first();
|
|
if ($app) {
|
|
$hasConfirmedHire = true;
|
|
$joiningDate = Carbon::parse($app->joining_confirmed_at);
|
|
} else {
|
|
// Check direct JobOffer
|
|
$offerQuery = JobOffer::where('worker_id', $worker->id)
|
|
->where('employer_id', $employerId)
|
|
->where('status', 'accepted');
|
|
|
|
$offer = $offerQuery->first();
|
|
if ($offer) {
|
|
$hasConfirmedHire = true;
|
|
// For direct offers, we treat work_date or updated_at as joining date
|
|
$joiningDate = $offer->work_date ? Carbon::parse($offer->work_date) : $offer->updated_at;
|
|
}
|
|
}
|
|
|
|
if (!$hasConfirmedHire) {
|
|
return response()->json([
|
|
'success' => false,
|
|
'message' => 'You can only review employers with a confirmed hire and completed joining.'
|
|
], 403);
|
|
}
|
|
|
|
// Verify if completed configured months from joining date
|
|
$eligibilityMonths = (int) config('reminders.review_eligibility_months', 3);
|
|
if ($joiningDate->startOfDay()->diffInMonths(now()->startOfDay(), false) < $eligibilityMonths) {
|
|
return response()->json([
|
|
'success' => false,
|
|
'message' => "You can write a review only after {$eligibilityMonths} months from the joining date."
|
|
], 403);
|
|
}
|
|
|
|
// 2. Prevent duplicate reviews for the same job/employer combination
|
|
$existing = EmployerReview::where('worker_id', $worker->id)
|
|
->where('employer_id', $employerId)
|
|
->where('job_id', $jobId)
|
|
->first();
|
|
|
|
if ($existing) {
|
|
return response()->json([
|
|
'success' => false,
|
|
'message' => 'You have already submitted a review for this job/employer.'
|
|
], 422);
|
|
}
|
|
|
|
// 3. Create the review
|
|
$review = EmployerReview::create([
|
|
'worker_id' => $worker->id,
|
|
'employer_id' => $employerId,
|
|
'job_id' => $jobId,
|
|
'rating' => $request->rating,
|
|
'title' => $request->title,
|
|
'comment' => $request->comment,
|
|
]);
|
|
|
|
return response()->json([
|
|
'success' => true,
|
|
'message' => 'Review submitted successfully.',
|
|
'data' => [
|
|
'review' => $review
|
|
]
|
|
], 201);
|
|
|
|
} catch (\Exception $e) {
|
|
logger()->error('Worker Add Employer Review Failure: ' . $e->getMessage());
|
|
|
|
return response()->json([
|
|
'success' => false,
|
|
'message' => 'An error occurred while adding the review.',
|
|
'error' => app()->environment('local') ? $e->getMessage() : 'Internal Server Error'
|
|
], 500);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Edit/update an existing review.
|
|
* PUT /api/workers/reviews/{id}
|
|
*/
|
|
public function editReview(Request $request, $id)
|
|
{
|
|
/** @var Worker $worker */
|
|
$worker = $request->attributes->get('worker');
|
|
|
|
$validator = Validator::make($request->all(), [
|
|
'rating' => 'required|integer|min:1|max:5',
|
|
'title' => 'nullable|string|max:255',
|
|
'comment' => 'required|string|max:1000',
|
|
]);
|
|
|
|
if ($validator->fails()) {
|
|
return response()->json([
|
|
'success' => false,
|
|
'message' => 'Validation error.',
|
|
'errors' => $validator->errors()
|
|
], 422);
|
|
}
|
|
|
|
try {
|
|
$review = EmployerReview::where('id', $id)
|
|
->where('worker_id', $worker->id)
|
|
->first();
|
|
|
|
if (!$review) {
|
|
return response()->json([
|
|
'success' => false,
|
|
'message' => 'Review not found.'
|
|
], 404);
|
|
}
|
|
|
|
// Check if the edit window has expired
|
|
$editPeriodDays = (int) config('reminders.review_edit_period_days', 7);
|
|
if ($review->created_at->addDays($editPeriodDays)->isPast()) {
|
|
return response()->json([
|
|
'success' => false,
|
|
'message' => "The {$editPeriodDays}-day edit window for this review has expired."
|
|
], 403);
|
|
}
|
|
|
|
$review->update([
|
|
'rating' => $request->rating,
|
|
'title' => $request->title,
|
|
'comment' => $request->comment,
|
|
]);
|
|
|
|
return response()->json([
|
|
'success' => true,
|
|
'message' => 'Review updated successfully.',
|
|
'data' => [
|
|
'review' => $review
|
|
]
|
|
], 200);
|
|
|
|
} catch (\Exception $e) {
|
|
logger()->error('Worker Edit Employer Review Failure: ' . $e->getMessage());
|
|
|
|
return response()->json([
|
|
'success' => false,
|
|
'message' => 'An error occurred while updating the review.',
|
|
'error' => app()->environment('local') ? $e->getMessage() : 'Internal Server Error'
|
|
], 500);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* View a single review.
|
|
* GET /api/workers/reviews/{id}
|
|
*/
|
|
public function viewReview(Request $request, $id)
|
|
{
|
|
/** @var Worker $worker */
|
|
$worker = $request->attributes->get('worker');
|
|
|
|
try {
|
|
$review = EmployerReview::where('id', $id)
|
|
->where('worker_id', $worker->id)
|
|
->with(['employer.employerProfile', 'jobPost'])
|
|
->first();
|
|
|
|
if (!$review) {
|
|
return response()->json([
|
|
'success' => false,
|
|
'message' => 'Review not found.'
|
|
], 404);
|
|
}
|
|
|
|
$editPeriodDays = (int) config('reminders.review_edit_period_days', 7);
|
|
$editable = !$review->created_at->addDays($editPeriodDays)->isPast();
|
|
|
|
return response()->json([
|
|
'success' => true,
|
|
'data' => [
|
|
'review' => [
|
|
'id' => $review->id,
|
|
'employer_id' => $review->employer_id,
|
|
'employer_name' => $review->employer->name ?? 'Employer',
|
|
'job_id' => $review->job_id,
|
|
'job_title' => $review->jobPost->title ?? null,
|
|
'rating' => $review->rating,
|
|
'title' => $review->title,
|
|
'comment' => $review->comment,
|
|
'editable' => $editable,
|
|
'created_at' => $review->created_at->toIso8601String(),
|
|
'updated_at' => $review->updated_at->toIso8601String(),
|
|
]
|
|
]
|
|
], 200);
|
|
|
|
} catch (\Exception $e) {
|
|
logger()->error('Worker View Employer Review Failure: ' . $e->getMessage());
|
|
|
|
return response()->json([
|
|
'success' => false,
|
|
'message' => 'An error occurred while fetching the review.',
|
|
'error' => app()->environment('local') ? $e->getMessage() : 'Internal Server Error'
|
|
], 500);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get reviews written by this worker.
|
|
* GET /api/workers/reviews
|
|
*/
|
|
public function getReviews(Request $request)
|
|
{
|
|
/** @var Worker $worker */
|
|
$worker = $request->attributes->get('worker');
|
|
|
|
try {
|
|
$page = (int) $request->input('page', 1);
|
|
$perPage = (int) $request->input('per_page', 15);
|
|
|
|
$query = EmployerReview::where('worker_id', $worker->id)
|
|
->with(['employer.employerProfile', 'jobPost'])
|
|
->latest();
|
|
|
|
$total = $query->count();
|
|
$offset = ($page - 1) * $perPage;
|
|
|
|
$reviews = $query->skip($offset)->take($perPage)->get()
|
|
->map(function ($rev) {
|
|
$editPeriodDays = (int) config('reminders.review_edit_period_days', 7);
|
|
$editable = !$rev->created_at->addDays($editPeriodDays)->isPast();
|
|
|
|
return [
|
|
'id' => $rev->id,
|
|
'employer_id' => $rev->employer_id,
|
|
'employer_name' => $rev->employer->name ?? 'Employer',
|
|
'job_id' => $rev->job_id,
|
|
'job_title' => $rev->jobPost->title ?? null,
|
|
'rating' => $rev->rating,
|
|
'title' => $rev->title,
|
|
'comment' => $rev->comment,
|
|
'editable' => $editable,
|
|
'created_at' => $rev->created_at->toIso8601String(),
|
|
'updated_at' => $rev->updated_at->toIso8601String(),
|
|
];
|
|
});
|
|
|
|
return response()->json([
|
|
'success' => true,
|
|
'data' => [
|
|
'reviews' => $reviews,
|
|
'pagination' => [
|
|
'total' => $total,
|
|
'per_page' => $perPage,
|
|
'current_page' => $page,
|
|
'last_page' => max(1, (int) ceil($total / $perPage)),
|
|
]
|
|
]
|
|
], 200);
|
|
|
|
} catch (\Exception $e) {
|
|
logger()->error('Worker Get Employer Reviews Failure: ' . $e->getMessage());
|
|
|
|
return response()->json([
|
|
'success' => false,
|
|
'message' => 'An error occurred while fetching reviews.',
|
|
'error' => app()->environment('local') ? $e->getMessage() : 'Internal Server Error'
|
|
], 500);
|
|
}
|
|
}
|
|
}
|