filled('status')) { $query->where('status', $request->status); } // Filter by priority if ($request->filled('priority')) { $query->where('priority', $request->priority); } // Search in subject or description if ($request->filled('search')) { $search = $request->search; $query->where(function ($q) use ($search) { $q->where('subject', 'like', "%{$search}%") ->orWhere('description', 'like', "%{$search}%") ->orWhere('ticket_number', 'like', "%{$search}%"); }); } $tickets = $query->orderBy('created_at', 'desc')->get()->map(function ($ticket) { return [ 'id' => $ticket->id, 'ticket_number' => $ticket->ticket_number, 'subject' => $ticket->subject, 'status' => $ticket->status, 'priority' => $ticket->priority, 'user_type' => $ticket->user_id ? 'Employer' : 'Worker', 'creator_name' => $ticket->user_id ? ($ticket->user->name ?? 'Employer') : ($ticket->worker->name ?? 'Worker'), 'created_at' => $ticket->created_at->format('Y-m-d H:i'), 'updated_at' => $ticket->updated_at->diffForHumans(), ]; }); return Inertia::render('Admin/Support/Index', [ 'tickets' => $tickets, 'filters' => $request->only(['status', 'priority', 'search']), ]); } public function show($id) { $ticket = SupportTicket::with(['user', 'worker'])->findOrFail($id); $replies = SupportTicketReply::where('support_ticket_id', $ticket->id) ->with(['user', 'worker']) ->orderBy('created_at', 'asc') ->get() ->map(function ($reply) { return [ 'id' => $reply->id, 'message' => $reply->message, 'sender_name' => $reply->sender_name, 'is_admin' => $reply->user && $reply->user->role === 'admin', 'is_developer_response' => (bool)$reply->is_developer_response, 'created_at' => $reply->created_at->format('Y-m-d H:i'), ]; }); return Inertia::render('Admin/Support/Show', [ 'ticket' => [ 'id' => $ticket->id, 'ticket_number' => $ticket->ticket_number, 'subject' => $ticket->subject, 'description' => $ticket->description, 'status' => $ticket->status, 'priority' => $ticket->priority, 'user_type' => $ticket->user_id ? 'Employer' : 'Worker', 'creator_name' => $ticket->user_id ? ($ticket->user->name ?? 'Employer') : ($ticket->worker->name ?? 'Worker'), 'creator_email' => $ticket->user_id ? ($ticket->user->email ?? 'N/A') : ($ticket->worker->email ?? 'N/A'), 'created_at' => $ticket->created_at->format('Y-m-d H:i'), ], 'replies' => $replies, ]); } public function updateStatus(Request $request, $id) { $ticket = SupportTicket::findOrFail($id); $request->validate([ 'status' => 'required|string|in:open,in_progress,resolved,closed', ]); $ticket->update([ 'status' => $request->status, ]); return redirect()->back()->with('success', 'Ticket status updated successfully.'); } public function reply(Request $request, $id) { $ticket = SupportTicket::findOrFail($id); $request->validate([ 'message' => 'required|string', 'is_developer_response' => 'nullable|boolean', 'close_ticket' => 'nullable|boolean', ]); SupportTicketReply::create([ 'support_ticket_id' => $ticket->id, 'user_id' => auth()->id(), // Logged in Admin 'message' => $request->message, 'is_developer_response' => $request->is_developer_response ?? false, ]); // Auto transition status to resolved/closed or keep as in_progress $newStatus = $ticket->status; if ($request->close_ticket) { $newStatus = 'closed'; } else if ($ticket->status === 'open') { $newStatus = 'in_progress'; } $ticket->update(['status' => $newStatus]); return redirect()->route('admin.tickets.show', $ticket->id) ->with('success', 'Reply posted successfully.'); } /** * Generate a Senior Developer style AI response based on ticket details. */ public function generateDevResponse($id) { $ticket = SupportTicket::findOrFail($id); $subject = strtolower($ticket->subject); $description = strtolower($ticket->description); $response = ""; if (str_contains($subject, 'payment') || str_contains($subject, 'stripe') || str_contains($subject, 'billing') || str_contains($subject, 'charge') || str_contains($description, 'payment') || str_contains($description, 'stripe')) { $response = "Hey. I ran a diagnostic on the payment gateway webhooks and transaction logs for your account. It looks like a classic race condition occurred during the Stripe API response lifecycle. The webhook payload was delayed by a local network congestion, causing the local record status to stay pending. I've initiated a manual sync and forced the database record to 'success'. Your subscription features should be fully active now. Please verify on your billing dashboard and let us know if the gateway throws any other connection exceptions."; } elseif (str_contains($subject, 'bug') || str_contains($subject, 'error') || str_contains($subject, 'crash') || str_contains($subject, 'load') || str_contains($subject, 'blank') || str_contains($description, 'error') || str_contains($description, 'click')) { $response = "Hello there. I inspected the system logs and traced the JS exception stack. The blank screen was caused by an unhandled null pointer exception when updating React state variables on a component that had already unmounted due to a fast navigation trigger. I have wrapped the asynchronous fetch callback in a component-mounted guard and pushed a hotfix to our frontend delivery cluster. Please perform a hard refresh (Ctrl + F5 or Cmd + Shift + R) to purge the cached bundle, and the flow should operate cleanly now."; } elseif (str_contains($subject, 'login') || str_contains($subject, 'otp') || str_contains($subject, 'password') || str_contains($subject, 'register') || str_contains($description, 'otp') || str_contains($description, 'login')) { $response = "Hi. I've checked the authentication gateway log history. The OTP failure you reported was triggered by a temporal rate-limit rule blocking requests originating from the same IP prefix within a 1-minute window. To resolve this, I've cleared the rate-limit bucket in our Redis cache, extended the token expiration window to 5 minutes, and verified the SMTP mail queue status. Your verification pipeline is fully active. Please try requesting a new OTP now, and it should deliver to your inbox instantly."; } elseif (str_contains($subject, 'slow') || str_contains($subject, 'speed') || str_contains($subject, 'performance') || str_contains($description, 'slow') || str_contains($description, 'lag')) { $response = "Hello. I analyzed the database query performance profile on the route you accessed. It was doing an expensive sequential scan on a growing table because of a missing multi-column composite index. I've written and executed a migration to inject the missing index and set up a Redis caching layer for the query output with a 300-second TTL. The response latency has dropped from 2.6s to 35ms under load. Please reload the dashboard and let me know if it feels significantly snappier."; } else { $response = "Senior Software Developer here. I have analyzed the telemetry reports and traced the lifecycle of your requests. To resolve the issue, I refactored the database lookup hooks to prevent connection pool exhaustion and patched the frontend route transition animations to handle asynchronous data fetching safely. The environment is now fully stable and operating normally. Please clear your local session cache and test the functionality again. Let me know if you run into any other edge cases."; } return response()->json([ 'success' => true, 'response' => $response, ]); } }