166 lines
5.5 KiB
PHP
166 lines
5.5 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers\Api\Admin\Ticket;
|
|
|
|
use App\Http\Controllers\Controller;
|
|
use App\Events\TicketReplyCreated;
|
|
use App\Http\Resources\Api\Ticket\TicketResource;
|
|
use App\Http\Resources\Api\Ticket\TicketReplyResource;
|
|
use App\Models\Notification;
|
|
use App\Models\Ticket;
|
|
use App\Repositories\TicketReply\TicketReplyRepositoryInterface;
|
|
use Illuminate\Http\Request;
|
|
|
|
class TicketController extends Controller
|
|
{
|
|
public function __construct(
|
|
protected TicketReplyRepositoryInterface $ticketReplyRepository,
|
|
) {}
|
|
|
|
public function index(Request $request)
|
|
{
|
|
$filters = $request->validate([
|
|
'status' => ['nullable', 'array'],
|
|
'status.*' => ['string', 'in:open,pending,resolved,closed'],
|
|
'room' => ['nullable', 'string', 'max:50'],
|
|
'customer_id' => ['nullable', 'integer'],
|
|
'date_from' => ['nullable', 'date'],
|
|
'date_to' => ['nullable', 'date'],
|
|
'search' => ['nullable', 'string', 'max:255'],
|
|
]);
|
|
|
|
$query = Ticket::query()
|
|
->with(['customer'])
|
|
->latest('id')
|
|
->when($filters['status'] ?? null, fn ($q, $status) => $q->whereIn('status', $status))
|
|
->when($filters['room'] ?? null, fn ($q, $room) => $q->where('room', $room))
|
|
->when($filters['customer_id'] ?? null, fn ($q, $id) => $q->where('customer_id', $id))
|
|
->when($filters['date_from'] ?? null, fn ($q, $from) => $q->whereDate('created_at', '>=', $from))
|
|
->when($filters['date_to'] ?? null, fn ($q, $to) => $q->whereDate('created_at', '<=', $to))
|
|
->when($filters['search'] ?? null, fn ($q, $search) => $q->where(
|
|
fn ($q) => $q->where('subject', 'like', "%{$search}%")->orWhere('ticket_num', 'like', "%{$search}%")
|
|
));
|
|
|
|
$paginated = $query->paginate($request->input('per_page', 15));
|
|
|
|
return response()->json([
|
|
'error' => false,
|
|
'data' => [
|
|
'items' => TicketResource::collection($paginated->items()),
|
|
'total' => $paginated->total(),
|
|
'per_page' => $paginated->perPage(),
|
|
'current_page' => $paginated->currentPage(),
|
|
'last_page' => $paginated->lastPage(),
|
|
],
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* Show a ticket with its replies and customer info.
|
|
*/
|
|
public function show(string $ticket_num)
|
|
{
|
|
$ticket = Ticket::query()
|
|
->with(['reply.user', 'customer'])
|
|
->where('ticket_num', $ticket_num)
|
|
->first();
|
|
|
|
if (!$ticket) {
|
|
return response()->json([
|
|
'error' => true,
|
|
'message' => 'Ticket không tồn tại.',
|
|
], 404);
|
|
}
|
|
|
|
return response()->json([
|
|
'error' => false,
|
|
'data' => new TicketResource($ticket),
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* Update ticket status.
|
|
*/
|
|
public function updateStatus(Request $request, string $ticket_num)
|
|
{
|
|
$request->validate([
|
|
'status' => ['required', 'string', 'in:open,pending,resolved,closed'],
|
|
]);
|
|
|
|
$ticket = Ticket::query()->where('ticket_num', $ticket_num)->first();
|
|
|
|
if (!$ticket) {
|
|
return response()->json([
|
|
'error' => true,
|
|
'message' => 'Ticket không tồn tại.',
|
|
], 404);
|
|
}
|
|
|
|
$ticket->update(['status' => $request->input('status')]);
|
|
|
|
return response()->json([
|
|
'error' => false,
|
|
'message' => 'Trạng thái ticket đã được cập nhật.',
|
|
'data' => new TicketResource($ticket->fresh()),
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* Admin replies to a ticket.
|
|
*/
|
|
public function reply(Request $request, string $ticket_num)
|
|
{
|
|
$request->validate([
|
|
'message' => ['required', 'string'],
|
|
]);
|
|
|
|
$admin = auth('admin')->user();
|
|
|
|
$ticket = Ticket::query()->where('ticket_num', $ticket_num)->first();
|
|
|
|
if (!$ticket) {
|
|
return response()->json([
|
|
'error' => true,
|
|
'message' => 'Ticket không tồn tại.',
|
|
], 404);
|
|
}
|
|
|
|
$reply = $this->ticketReplyRepository->create([
|
|
'ticket_id' => $ticket->id,
|
|
'user_id' => $admin->id,
|
|
'message' => $request->input('message'),
|
|
'customer_id' => $ticket->customer_id,
|
|
]);
|
|
|
|
Notification::notifyCustomer($ticket->customer, [
|
|
'type' => 'ticket_reply',
|
|
'title' => 'Admin vừa phản hồi ticket của bạn',
|
|
'body' => $ticket->ticket_num . ' - ' . $ticket->subject,
|
|
'link' => '/tickets/' . $ticket->ticket_num,
|
|
'data' => [
|
|
'ticket_num' => $ticket->ticket_num,
|
|
'reply_id' => $reply->id,
|
|
],
|
|
]);
|
|
|
|
// Update ticket status to pending after admin reply
|
|
if ($ticket->status === 'open') {
|
|
$ticket->update(['status' => 'pending']);
|
|
}
|
|
|
|
$reply->load('user');
|
|
|
|
broadcast(new TicketReplyCreated(
|
|
ticketNum: $ticket->ticket_num,
|
|
customerId: $ticket->customer_id,
|
|
replyId: $reply->id,
|
|
));
|
|
|
|
return response()->json([
|
|
'error' => false,
|
|
'message' => 'Phản hồi đã được gửi.',
|
|
'data' => new TicketReplyResource($reply),
|
|
], 201);
|
|
}
|
|
}
|