mohan #12
@ -11,12 +11,89 @@
|
||||
class EmployerAnnouncementController extends Controller
|
||||
{
|
||||
/**
|
||||
* Get all announcements posted by this employer.
|
||||
* Get all approved announcements for employers.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function getAnnouncements(Request $request)
|
||||
{
|
||||
try {
|
||||
$page = (int)$request->input('page', 1);
|
||||
$perPage = (int)$request->input('per_page', 15);
|
||||
|
||||
$query = Announcement::with(['employer.employerProfile', 'sponsor'])->where('status', 'approved')->latest();
|
||||
$total = $query->count();
|
||||
$offset = ($page - 1) * $perPage;
|
||||
|
||||
$announcements = $query->skip($offset)->take($perPage)->get()
|
||||
->map(function ($announcement) {
|
||||
$postedBy = 'System';
|
||||
$organization = 'Migrant Support';
|
||||
|
||||
if ($announcement->sponsor_id) {
|
||||
$postedBy = $announcement->sponsor->full_name;
|
||||
$organization = $announcement->sponsor->organization_name;
|
||||
} elseif ($announcement->employer_id) {
|
||||
$postedBy = $announcement->employer->name;
|
||||
$organization = $announcement->employer->employerProfile->company_name ?? 'Employer';
|
||||
}
|
||||
|
||||
// Decode charity details if they exist in json
|
||||
$charityDetails = null;
|
||||
$content = $announcement->body;
|
||||
if (strpos($announcement->body, '{"type":"Charity"') === 0) {
|
||||
$decoded = json_decode($announcement->body, true);
|
||||
if ($decoded) {
|
||||
$charityDetails = $decoded;
|
||||
$content = $decoded['content'] ?? $announcement->body;
|
||||
}
|
||||
}
|
||||
|
||||
return [
|
||||
'id' => $announcement->id,
|
||||
'title' => $announcement->title,
|
||||
'body' => $content,
|
||||
'type' => $announcement->type,
|
||||
'employer_name' => $postedBy,
|
||||
'company_name' => $organization,
|
||||
'created_at' => $announcement->created_at->toISOString(),
|
||||
'time_ago' => $announcement->created_at->diffForHumans(),
|
||||
'charity_details' => $charityDetails,
|
||||
];
|
||||
});
|
||||
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
'data' => [
|
||||
'announcements' => $announcements,
|
||||
'pagination' => [
|
||||
'total' => $total,
|
||||
'per_page' => $perPage,
|
||||
'current_page' => $page,
|
||||
'last_page' => max(1, (int)ceil($total / $perPage)),
|
||||
]
|
||||
]
|
||||
], 200);
|
||||
|
||||
} catch (\Exception $e) {
|
||||
logger()->error('Mobile Employer Get All Announcements Failure: ' . $e->getMessage());
|
||||
|
||||
return response()->json([
|
||||
'success' => false,
|
||||
'message' => 'An error occurred while fetching announcements.',
|
||||
'error' => app()->environment('local') ? $e->getMessage() : 'Internal Server Error'
|
||||
], 500);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all announcements posted by this employer.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return \Illuminate\Http\JsonResponse
|
||||
*/
|
||||
public function getMyAnnouncements(Request $request)
|
||||
{
|
||||
/** @var User $employer */
|
||||
$employer = $request->attributes->get('employer');
|
||||
@ -57,7 +134,7 @@ public function getAnnouncements(Request $request)
|
||||
], 200);
|
||||
|
||||
} catch (\Exception $e) {
|
||||
logger()->error('Mobile Employer Get Announcements Failure: ' . $e->getMessage());
|
||||
logger()->error('Mobile Employer Get My Announcements Failure: ' . $e->getMessage());
|
||||
|
||||
return response()->json([
|
||||
'success' => false,
|
||||
|
||||
@ -3527,7 +3527,91 @@
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "List of posted charity events retrieved successfully."
|
||||
"description": "List of posted charity events retrieved successfully.",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"success": {
|
||||
"type": "boolean",
|
||||
"example": true
|
||||
},
|
||||
"data": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"announcements": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "integer",
|
||||
"example": 1
|
||||
},
|
||||
"title": {
|
||||
"type": "string",
|
||||
"example": "Holiday Notice"
|
||||
},
|
||||
"body": {
|
||||
"type": "string",
|
||||
"example": "Office will be closed tomorrow."
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"example": "info"
|
||||
},
|
||||
"employer_name": {
|
||||
"type": "string",
|
||||
"example": "Employer One"
|
||||
},
|
||||
"company_name": {
|
||||
"type": "string",
|
||||
"example": "Elite Services"
|
||||
},
|
||||
"created_at": {
|
||||
"type": "string",
|
||||
"format": "date-time",
|
||||
"example": "2026-06-23T10:13:17.000000Z"
|
||||
},
|
||||
"time_ago": {
|
||||
"type": "string",
|
||||
"example": "2 hours ago"
|
||||
},
|
||||
"charity_details": {
|
||||
"type": "object",
|
||||
"nullable": true
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"pagination": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"total": {
|
||||
"type": "integer",
|
||||
"example": 1
|
||||
},
|
||||
"per_page": {
|
||||
"type": "integer",
|
||||
"example": 15
|
||||
},
|
||||
"current_page": {
|
||||
"type": "integer",
|
||||
"example": 1
|
||||
},
|
||||
"last_page": {
|
||||
"type": "integer",
|
||||
"example": 1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -3628,7 +3712,85 @@
|
||||
"description": "Retrieves stats including contacted workers count, total hired workers, saved candidates, current plan details, and recent announcements or events.",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Employer dashboard stats retrieved successfully."
|
||||
"description": "Employer dashboard stats retrieved successfully.",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"success": {
|
||||
"type": "boolean",
|
||||
"example": true
|
||||
},
|
||||
"data": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"stats": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"contacted_workers_count": {
|
||||
"type": "integer",
|
||||
"example": 0
|
||||
},
|
||||
"total_hired_workers": {
|
||||
"type": "integer",
|
||||
"example": 0
|
||||
},
|
||||
"saved_candidates": {
|
||||
"type": "integer",
|
||||
"example": 0
|
||||
},
|
||||
"total_workers": {
|
||||
"type": "integer",
|
||||
"example": 15
|
||||
}
|
||||
}
|
||||
},
|
||||
"current_plan": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"plan_id": {
|
||||
"type": "string",
|
||||
"example": "premium"
|
||||
},
|
||||
"name": {
|
||||
"type": "string",
|
||||
"example": "Premium Pass"
|
||||
},
|
||||
"status": {
|
||||
"type": "string",
|
||||
"example": "active"
|
||||
},
|
||||
"starts_at": {
|
||||
"type": "string",
|
||||
"format": "date",
|
||||
"example": "2026-06-23"
|
||||
},
|
||||
"expires_at": {
|
||||
"type": "string",
|
||||
"format": "date",
|
||||
"example": "2026-07-23"
|
||||
}
|
||||
}
|
||||
},
|
||||
"recent_announcements": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object"
|
||||
}
|
||||
},
|
||||
"recent_events": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -5515,6 +5677,122 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/employers/my-announcements": {
|
||||
"get": {
|
||||
"tags": [
|
||||
"Employer/CharityEvents"
|
||||
],
|
||||
"summary": "Get My Posted Announcements/Charity Events (Employer)",
|
||||
"description": "Retrieves the list of announcements and charity events posted specifically by the logged-in employer.",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "page",
|
||||
"in": "query",
|
||||
"required": false,
|
||||
"description": "Page number.",
|
||||
"schema": {
|
||||
"type": "integer",
|
||||
"default": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "per_page",
|
||||
"in": "query",
|
||||
"required": false,
|
||||
"description": "Number of items per page.",
|
||||
"schema": {
|
||||
"type": "integer",
|
||||
"default": 15
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "List of my posted announcements retrieved successfully.",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"success": {
|
||||
"type": "boolean",
|
||||
"example": true
|
||||
},
|
||||
"data": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"announcements": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "integer",
|
||||
"example": 1
|
||||
},
|
||||
"title": {
|
||||
"type": "string",
|
||||
"example": "Holiday Notice"
|
||||
},
|
||||
"body": {
|
||||
"type": "string",
|
||||
"example": "Office will be closed tomorrow."
|
||||
},
|
||||
"type": {
|
||||
"type": "string",
|
||||
"example": "info"
|
||||
},
|
||||
"status": {
|
||||
"type": "string",
|
||||
"example": "pending"
|
||||
},
|
||||
"remarks": {
|
||||
"type": "string",
|
||||
"nullable": true
|
||||
},
|
||||
"created_at": {
|
||||
"type": "string",
|
||||
"format": "date-time",
|
||||
"example": "2026-06-23T10:13:17.000000Z"
|
||||
},
|
||||
"time_ago": {
|
||||
"type": "string",
|
||||
"example": "2 hours ago"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"pagination": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"total": {
|
||||
"type": "integer",
|
||||
"example": 1
|
||||
},
|
||||
"per_page": {
|
||||
"type": "integer",
|
||||
"example": 15
|
||||
},
|
||||
"current_page": {
|
||||
"type": "integer",
|
||||
"example": 1
|
||||
},
|
||||
"last_page": {
|
||||
"type": "integer",
|
||||
"example": 1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"components": {
|
||||
|
||||
@ -119,6 +119,7 @@
|
||||
|
||||
// Announcement Management
|
||||
Route::get('/employers/announcements', [EmployerAnnouncementController::class, 'getAnnouncements']);
|
||||
Route::get('/employers/my-announcements', [EmployerAnnouncementController::class, 'getMyAnnouncements']);
|
||||
Route::post('/employers/announcements', [EmployerAnnouncementController::class, 'createAnnouncement']);
|
||||
Route::delete('/employers/announcements/{id}', [EmployerAnnouncementController::class, 'deleteAnnouncement']);
|
||||
|
||||
|
||||
@ -103,9 +103,9 @@ public function test_worker_can_get_announcements()
|
||||
}
|
||||
|
||||
/**
|
||||
* Test employer can get only their posted announcements.
|
||||
* Test employer can get only their posted announcements via my-announcements.
|
||||
*/
|
||||
public function test_employer_can_get_posted_announcements()
|
||||
public function test_employer_can_get_my_announcements()
|
||||
{
|
||||
// Announcement by this employer
|
||||
Announcement::create([
|
||||
@ -131,13 +131,66 @@ public function test_employer_can_get_posted_announcements()
|
||||
|
||||
$response = $this->withHeaders([
|
||||
'Authorization' => 'Bearer ' . $this->employerToken,
|
||||
])->getJson('/api/employers/announcements');
|
||||
])->getJson('/api/employers/my-announcements');
|
||||
|
||||
$response->assertStatus(200);
|
||||
$this->assertCount(1, $response->json('data.announcements'));
|
||||
$this->assertEquals('Employer Ann', $response->json('data.announcements.0.title'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test employer can get all approved announcements.
|
||||
*/
|
||||
public function test_employer_can_get_all_approved_announcements()
|
||||
{
|
||||
// Approved announcement by this employer
|
||||
Announcement::create([
|
||||
'title' => 'Approved Ann 1',
|
||||
'body' => 'Message 1',
|
||||
'type' => 'info',
|
||||
'employer_id' => $this->employer->id,
|
||||
'status' => 'approved',
|
||||
]);
|
||||
|
||||
// Pending announcement by this employer
|
||||
Announcement::create([
|
||||
'title' => 'Pending Ann 1',
|
||||
'body' => 'Message 2',
|
||||
'type' => 'info',
|
||||
'employer_id' => $this->employer->id,
|
||||
'status' => 'pending',
|
||||
]);
|
||||
|
||||
// Approved announcement by another sponsor
|
||||
$sponsor = \App\Models\Sponsor::create([
|
||||
'full_name' => 'Sponsor Name',
|
||||
'email' => 'sponsor@example.com',
|
||||
'mobile' => '+971501112233',
|
||||
'organization_name' => 'Charity Org',
|
||||
'address' => 'Dubai',
|
||||
'role' => 'sponsor',
|
||||
'password' => bcrypt('password'),
|
||||
]);
|
||||
Announcement::create([
|
||||
'title' => 'Approved Ann 2',
|
||||
'body' => 'Message 3',
|
||||
'type' => 'info',
|
||||
'sponsor_id' => $sponsor->id,
|
||||
'status' => 'approved',
|
||||
]);
|
||||
|
||||
$response = $this->withHeaders([
|
||||
'Authorization' => 'Bearer ' . $this->employerToken,
|
||||
])->getJson('/api/employers/announcements');
|
||||
|
||||
$response->assertStatus(200);
|
||||
$this->assertCount(2, $response->json('data.announcements'));
|
||||
$titles = collect($response->json('data.announcements'))->pluck('title');
|
||||
$this->assertTrue($titles->contains('Approved Ann 1'));
|
||||
$this->assertTrue($titles->contains('Approved Ann 2'));
|
||||
$this->assertFalse($titles->contains('Pending Ann 1'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test employer can create a new announcement.
|
||||
*/
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user