447 lines
19 KiB
PHP
447 lines
19 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers\Admin;
|
|
|
|
use App\Http\Controllers\Controller;
|
|
use Illuminate\Http\Request;
|
|
use Inertia\Inertia;
|
|
use Illuminate\Support\Facades\DB;
|
|
|
|
class AdminExtraController extends Controller
|
|
{
|
|
/**
|
|
* Safety & Moderation Dashboard
|
|
*/
|
|
public function safety()
|
|
{
|
|
$reports = [
|
|
[
|
|
'id' => 'REP-101',
|
|
'reporter' => 'Marina Cleaners (Employer)',
|
|
'reported_user' => 'Grace Omondi (Worker)',
|
|
'reason' => 'Profile details mismatch / False advertising',
|
|
'description' => 'The worker claims to have 4 years experience in childcare, but when interviewed, they stated they only did housekeeping.',
|
|
'status' => 'Pending Review',
|
|
'severity' => 'Medium',
|
|
'created_at' => '2026-05-22 14:30',
|
|
],
|
|
[
|
|
'id' => 'REP-102',
|
|
'reporter' => 'Siti Aminah (Worker)',
|
|
'reported_user' => 'Golden Hospitality (Employer)',
|
|
'reason' => 'Abusive message exchange',
|
|
'description' => 'Employer used inappropriate language during direct chat after worker declined an weekend offer.',
|
|
'status' => 'Escalated',
|
|
'severity' => 'High',
|
|
'created_at' => '2026-05-21 09:15',
|
|
],
|
|
[
|
|
'id' => 'REP-103',
|
|
'reporter' => 'System (Auto-Flag)',
|
|
'reported_user' => 'Amina Diop (Worker)',
|
|
'reason' => 'Suspicious document signature mismatch',
|
|
'description' => 'OCR matching detected that the signature and name on the Passport does not match the registration name.',
|
|
'status' => 'Under Investigation',
|
|
'severity' => 'High',
|
|
'created_at' => '2026-05-20 18:45',
|
|
],
|
|
[
|
|
'id' => 'REP-104',
|
|
'reporter' => 'Hassan Al Hosani (Employer)',
|
|
'reported_user' => 'Maria Santos (Worker)',
|
|
'reason' => 'No-show for interview',
|
|
'description' => 'Worker confirmed three consecutive video interviews but failed to join without notice.',
|
|
'status' => 'Resolved',
|
|
'severity' => 'Low',
|
|
'created_at' => '2026-05-18 11:00',
|
|
]
|
|
];
|
|
|
|
$rules = [
|
|
['id' => 1, 'name' => 'IP-Range Duplication Alert', 'trigger' => 'More than 3 worker accounts from the same IP', 'status' => 'Active'],
|
|
['id' => 2, 'name' => 'OCR Match Confidence Threshold', 'trigger' => 'Passport verification confidence below 75%', 'status' => 'Active'],
|
|
['id' => 3, 'name' => 'Keyword Abuse Filter', 'trigger' => 'Vulgar/abusive words in employer messages', 'status' => 'Active'],
|
|
['id' => 4, 'name' => 'Availability Change Spammer', 'trigger' => 'Toggling availability status > 10 times in 24 hrs', 'status' => 'Inactive'],
|
|
];
|
|
|
|
$moderationQueue = [
|
|
[
|
|
'id' => 'MOD-01',
|
|
'user' => 'Leila Bekri',
|
|
'type' => 'Worker Bio Update',
|
|
'content' => 'I am a highly skilled executive housekeeper and private chef with 8 years of luxury hospitality experience in Dubai. Contact me at +971-55-901-2384 for immediate placement.',
|
|
'flag' => 'Contains contact details (Phone number violation)',
|
|
'status' => 'Pending Approval'
|
|
],
|
|
[
|
|
'id' => 'MOD-02',
|
|
'user' => 'Fatima Zahra',
|
|
'type' => 'Worker Profile Photo',
|
|
'content' => 'https://images.unsplash.com/photo-1544717305-2782549b5136?q=80&w=600',
|
|
'flag' => 'Professional headshot check',
|
|
'status' => 'Approved'
|
|
]
|
|
];
|
|
|
|
return Inertia::render('Admin/Safety/Index', [
|
|
'reports' => $reports,
|
|
'rules' => $rules,
|
|
'moderation_queue' => $moderationQueue
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* Resolve a safety report
|
|
*/
|
|
public function resolveSafetyReport(Request $request, $id)
|
|
{
|
|
$request->validate([
|
|
'action' => 'required|string',
|
|
'admin_notes' => 'nullable|string'
|
|
]);
|
|
|
|
return back()->with('success', "Safety Report {$id} has been resolved successfully with action: " . strtoupper($request->action));
|
|
}
|
|
|
|
/**
|
|
* Disputes Management Module
|
|
*/
|
|
public function disputes()
|
|
{
|
|
$tickets = [
|
|
[
|
|
'id' => 'DISP-701',
|
|
'employer' => 'Marina Cleaners',
|
|
'worker' => 'Grace Omondi',
|
|
'subject' => 'Advance Payment Refund Dispute',
|
|
'amount_aed' => 499,
|
|
'status' => 'Open',
|
|
'created_at' => '2026-05-20',
|
|
'chat_logs' => [
|
|
['sender' => 'Employer', 'time' => '10:05 AM', 'message' => 'I paid you the advance of 499 AED for direct transport, but you did not report to work.'],
|
|
['sender' => 'Worker', 'time' => '10:12 AM', 'message' => 'The agency driver was delayed and did not bring the entry permit paper, so I could not travel.'],
|
|
['sender' => 'Employer', 'time' => '10:14 AM', 'message' => 'That is your responsibility, I need the refund or immediate attendance.'],
|
|
['sender' => 'Worker', 'time' => '10:20 AM', 'message' => 'I do not have the money anymore, the transport ticket was already bought and non-refundable.'],
|
|
],
|
|
'evidence' => [
|
|
['type' => 'Receipt', 'name' => 'payment_slip.pdf', 'url' => '#'],
|
|
['type' => 'Agreement', 'name' => 'hiring_agreement_signed.pdf', 'url' => '#'],
|
|
],
|
|
'admin_notes' => 'Awaiting confirmation of driver delay from the visa coordinator.'
|
|
],
|
|
[
|
|
'id' => 'DISP-702',
|
|
'employer' => 'Al Barari Real Estate',
|
|
'worker' => 'Maria Santos',
|
|
'subject' => 'Sudden Contract Termination',
|
|
'amount_aed' => 1299,
|
|
'status' => 'Under Investigation',
|
|
'created_at' => '2026-05-18',
|
|
'chat_logs' => [
|
|
['sender' => 'Employer', 'time' => '11:00 AM', 'message' => 'We must terminate the child care contract as we are relocating to the UK next month.'],
|
|
['sender' => 'Worker', 'time' => '11:05 AM', 'message' => 'But my contract states a 30-day notice period or 1 month salary in lieu of notice.'],
|
|
['sender' => 'Employer', 'time' => '11:08 AM', 'message' => ' Relocation is a force majeure event, we can only pay for days worked.'],
|
|
],
|
|
'evidence' => [
|
|
['type' => 'Contract', 'name' => 'relocation_uk_notice.pdf', 'url' => '#'],
|
|
],
|
|
'admin_notes' => 'Relocation relocates jurisdiction, review local UAE standard domestic contract clause 9.'
|
|
],
|
|
[
|
|
'id' => 'DISP-703',
|
|
'employer' => 'Golden Hospitality',
|
|
'worker' => 'Siti Aminah',
|
|
'subject' => 'Withheld Passport Allegation',
|
|
'amount_aed' => 0,
|
|
'status' => 'Resolved',
|
|
'created_at' => '2026-05-15',
|
|
'chat_logs' => [
|
|
['sender' => 'Worker', 'time' => '02:00 PM', 'message' => 'Please return my passport, I need to renew my visa this week.'],
|
|
['sender' => 'Employer', 'time' => '02:10 PM', 'message' => 'We kept it for safekeeping in the company safe, you can request it whenever you want.'],
|
|
],
|
|
'evidence' => [],
|
|
'admin_notes' => 'Contacted HR manager directly. Passport was handed back to the worker on May 17th. Verified and closed.'
|
|
]
|
|
];
|
|
|
|
return Inertia::render('Admin/Disputes/Index', [
|
|
'tickets' => $tickets
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* Resolve a Dispute Ticket
|
|
*/
|
|
public function resolveDispute(Request $request, $id)
|
|
{
|
|
$request->validate([
|
|
'resolution' => 'required|string',
|
|
'action_taken' => 'required|string',
|
|
]);
|
|
|
|
return back()->with('success', "Dispute ticket {$id} has been resolved successfully. Resolution: " . strtoupper($request->action_taken));
|
|
}
|
|
|
|
/**
|
|
* Add admin notes to a dispute
|
|
*/
|
|
public function addDisputeNote(Request $request, $id)
|
|
{
|
|
$request->validate([
|
|
'note' => 'required|string'
|
|
]);
|
|
|
|
return back()->with('success', "Internal admin note added to Dispute ticket {$id}.");
|
|
}
|
|
|
|
/**
|
|
* Notifications & Campaign Management
|
|
*/
|
|
public function notifications()
|
|
{
|
|
$campaigns = [
|
|
[
|
|
'id' => 1,
|
|
'channel' => 'Push Notification',
|
|
'recipient_type' => 'All Active Workers',
|
|
'title' => 'Availability Update Reminder',
|
|
'message' => 'Hi, please update your availability status in the app to remain visible to hiring employers this week!',
|
|
'sent_at' => '2026-05-22 10:00 AM',
|
|
'delivery_rate' => '94.2%',
|
|
'clicks' => '1,120 clicks'
|
|
],
|
|
[
|
|
'id' => 2,
|
|
'channel' => 'WhatsApp Notification',
|
|
'recipient_type' => 'Unverified Workers (Morocco & Philippines)',
|
|
'title' => 'Emirates ID Upload Alert',
|
|
'message' => 'Hello! Upload your Emirates ID to unlock direct hiring and premium salaries on the UAE Domestic Worker Marketplace. Click here: [Link]',
|
|
'sent_at' => '2026-05-20 02:30 PM',
|
|
'delivery_rate' => '98.5%',
|
|
'clicks' => '654 clicks'
|
|
],
|
|
[
|
|
'id' => 3,
|
|
'channel' => 'Push Notification',
|
|
'recipient_type' => 'Premium Employers',
|
|
'title' => 'Weekend Candidates Alert',
|
|
'message' => '12 new highly-rated verified housekeeping candidates joined today. Browse and schedule interviews now!',
|
|
'sent_at' => '2026-05-19 08:00 AM',
|
|
'delivery_rate' => '91.8%',
|
|
'clicks' => '420 clicks'
|
|
]
|
|
];
|
|
|
|
$whatsappTemplates = [
|
|
[
|
|
'name' => 'availability_checkin_trigger',
|
|
'category' => 'Utility',
|
|
'language' => 'English & Arabic',
|
|
'text' => 'Hi {{1}}, we noticed you haven\'t updated your job availability since last week. Are you still seeking work? Reply 1 for Yes, 2 for No.',
|
|
'status' => 'Approved'
|
|
],
|
|
[
|
|
'name' => 'employer_verification_passed',
|
|
'category' => 'Account Status',
|
|
'language' => 'English',
|
|
'text' => 'Dear {{1}}, congratulations! Your employer profile for {{2}} has been verified. You can now access full candidate dossiers. Browse workers here: {{3}}',
|
|
'status' => 'Approved'
|
|
],
|
|
[
|
|
'name' => 'dispute_escalation_alert',
|
|
'category' => 'Security',
|
|
'language' => 'English',
|
|
'text' => 'Important: A dispute ticket ({{1}}) has been initiated regarding contract {{2}}. An admin mediator will reach out shortly.',
|
|
'status' => 'Pending Approval'
|
|
]
|
|
];
|
|
|
|
return Inertia::render('Admin/Notifications/Index', [
|
|
'campaigns' => $campaigns,
|
|
'whatsapp_templates' => $whatsappTemplates
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* Broadcast notification campaign
|
|
*/
|
|
public function broadcastNotification(Request $request)
|
|
{
|
|
$request->validate([
|
|
'channel' => 'required|in:push,whatsapp,both',
|
|
'recipients' => 'required|string',
|
|
'title' => 'required|string|max:100',
|
|
'message' => 'required|string'
|
|
]);
|
|
|
|
return back()->with('success', "Notification campaign broadcasted successfully to all {$request->recipients} users!");
|
|
}
|
|
|
|
/**
|
|
* Payments, Revenue Reports & Refund Control
|
|
*/
|
|
public function refundPayment(Request $request, $id)
|
|
{
|
|
$request->validate([
|
|
'refund_reason' => 'required|string',
|
|
'amount' => 'required|numeric|min:1'
|
|
]);
|
|
|
|
return back()->with('success', "Refund of AED {$request->amount} initiated successfully for transaction {$id}. Refund reason: {$request->refund_reason}");
|
|
}
|
|
|
|
/**
|
|
* Interactive Reports & Analytics Hub
|
|
*/
|
|
public function analytics()
|
|
{
|
|
// Supply rich visual charts metadata
|
|
$userGrowth = [
|
|
['month' => 'Dec 25', 'workers' => 850, 'employers' => 210],
|
|
['month' => 'Jan 26', 'workers' => 990, 'employers' => 240],
|
|
['month' => 'Feb 26', 'workers' => 1100, 'employers' => 280],
|
|
['month' => 'Mar 26', 'workers' => 1250, 'employers' => 310],
|
|
['month' => 'Apr 26', 'workers' => 1350, 'employers' => 345],
|
|
['month' => 'May 26', 'workers' => 1420, 'employers' => 380]
|
|
];
|
|
|
|
$revenueBreakdown = [
|
|
['month' => 'Dec 25', 'basic' => 15000, 'premium' => 18000, 'vip' => 12000],
|
|
['month' => 'Jan 26', 'basic' => 16500, 'premium' => 19500, 'vip' => 13500],
|
|
['month' => 'Feb 26', 'basic' => 18000, 'premium' => 22000, 'vip' => 15000],
|
|
['month' => 'Mar 26', 'basic' => 19200, 'premium' => 25000, 'vip' => 18500],
|
|
['month' => 'Apr 26', 'basic' => 21000, 'premium' => 29000, 'vip' => 22000],
|
|
['month' => 'May 26', 'basic' => 22500, 'premium' => 32000, 'vip' => 24000]
|
|
];
|
|
|
|
$retentionRates = [
|
|
['cohort' => 'Month 1', 'rate' => 92],
|
|
['cohort' => 'Month 2', 'rate' => 84],
|
|
['cohort' => 'Month 3', 'rate' => 79],
|
|
['cohort' => 'Month 4', 'rate' => 74],
|
|
['cohort' => 'Month 5', 'rate' => 71],
|
|
['cohort' => 'Month 6', 'rate' => 68],
|
|
];
|
|
|
|
$hiringFunnel = [
|
|
['stage' => 'Profiles Browsed', 'count' => 12500],
|
|
['stage' => 'Chats Initiated', 'count' => 4820],
|
|
['stage' => 'Interviews Held', 'count' => 1860],
|
|
['stage' => 'Offers Extended', 'count' => 920],
|
|
['stage' => 'Workers Hired', 'count' => 610],
|
|
];
|
|
|
|
return Inertia::render('Admin/Analytics/Index', [
|
|
'user_growth' => $userGrowth,
|
|
'revenue_breakdown' => $revenueBreakdown,
|
|
'retention_rates' => $retentionRates,
|
|
'hiring_funnel' => $hiringFunnel
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* Global Database Searchable Audit Logs
|
|
*/
|
|
public function auditLogs(Request $request)
|
|
{
|
|
$searchTerm = $request->input('search', '');
|
|
$category = $request->input('category', 'all');
|
|
|
|
$allLogs = [
|
|
// Admin Action Logs
|
|
[
|
|
'id' => 'LOG-991',
|
|
'category' => 'admin_action',
|
|
'user' => 'SuperAdmin (support@marketplace.com)',
|
|
'action' => 'Suspended Employer account Golden Hospitality due to dispute findings',
|
|
'ip_address' => '192.168.1.1',
|
|
'timestamp' => '2026-05-23 16:45',
|
|
],
|
|
[
|
|
'id' => 'LOG-992',
|
|
'category' => 'admin_action',
|
|
'user' => 'Admin Vetting Officer',
|
|
'action' => 'Manually approved Worker Leila Bekri passport verification overriding OCR confidence',
|
|
'ip_address' => '192.168.1.5',
|
|
'timestamp' => '2026-05-23 15:20',
|
|
],
|
|
// Verification Logs
|
|
[
|
|
'id' => 'LOG-993',
|
|
'category' => 'verification',
|
|
'user' => 'System OCR engine',
|
|
'action' => 'Auto-OCR Passport verification SUCCESS for worker Fatima Zahra (Morocco) • Confidence 98%',
|
|
'ip_address' => 'Auto-Trigger',
|
|
'timestamp' => '2026-05-23 14:15',
|
|
],
|
|
[
|
|
'id' => 'LOG-994',
|
|
'category' => 'verification',
|
|
'user' => 'System OCR engine',
|
|
'action' => 'Auto-OCR Passport FLAG suspicious document detected for worker Grace Omondi',
|
|
'ip_address' => 'Auto-Trigger',
|
|
'timestamp' => '2026-05-23 13:42',
|
|
],
|
|
// Payment Logs
|
|
[
|
|
'id' => 'LOG-995',
|
|
'category' => 'payment',
|
|
'user' => 'Stripe Webhook',
|
|
'action' => 'Subscription PAYMENT charge of AED 499 COMPLETED. Employer: Al Barari Real Estate',
|
|
'ip_address' => 'Stripe Gateway',
|
|
'timestamp' => '2026-05-23 10:30',
|
|
],
|
|
[
|
|
'id' => 'LOG-996',
|
|
'category' => 'payment',
|
|
'user' => 'Stripe Webhook',
|
|
'action' => 'Subscription PAYMENT charge of AED 199 FAILED (Insufficient funds). Employer: Dubai Mall Services',
|
|
'ip_address' => 'Stripe Gateway',
|
|
'timestamp' => '2026-05-22 17:10',
|
|
],
|
|
// Dispute Logs
|
|
[
|
|
'id' => 'LOG-997',
|
|
'category' => 'dispute',
|
|
'user' => 'SuperAdmin (support@marketplace.com)',
|
|
'action' => 'Opened Dispute Ticket DISP-701 regarding Advance Refund between Marina Cleaners & Grace Omondi',
|
|
'ip_address' => '192.168.1.1',
|
|
'timestamp' => '2026-05-22 14:45',
|
|
],
|
|
// User Activity Logs
|
|
[
|
|
'id' => 'LOG-998',
|
|
'category' => 'user_activity',
|
|
'user' => 'Maria Santos (Worker)',
|
|
'action' => 'Logged in successfully via iOS Mobile App',
|
|
'ip_address' => '94.200.12.83 (Dubai)',
|
|
'timestamp' => '2026-05-23 17:02',
|
|
],
|
|
[
|
|
'id' => 'LOG-999',
|
|
'category' => 'user_activity',
|
|
'user' => 'Marina Cleaners (Employer)',
|
|
'action' => 'Browsed 14 worker candidate profiles & saved 3 shortlists',
|
|
'ip_address' => '91.74.203.11 (Abu Dhabi)',
|
|
'timestamp' => '2026-05-23 16:58',
|
|
]
|
|
];
|
|
|
|
// Filter search & category
|
|
$filtered = array_filter($allLogs, function ($log) use ($searchTerm, $category) {
|
|
$catMatches = $category === 'all' || $log['category'] === $category;
|
|
$searchMatches = empty($searchTerm) ||
|
|
stripos($log['user'], $searchTerm) !== false ||
|
|
stripos($log['action'], $searchTerm) !== false ||
|
|
stripos($log['id'], $searchTerm) !== false;
|
|
return $catMatches && $searchMatches;
|
|
});
|
|
|
|
return Inertia::render('Admin/AuditLogs/Index', [
|
|
'logs' => array_values($filtered),
|
|
'search' => $searchTerm,
|
|
'category' => $category,
|
|
]);
|
|
}
|
|
}
|