diff --git a/Modules/Helpdesk/Livewire/TicketShow.php b/Modules/Helpdesk/Livewire/TicketShow.php index 79b4d330..7fe6efb2 100644 --- a/Modules/Helpdesk/Livewire/TicketShow.php +++ b/Modules/Helpdesk/Livewire/TicketShow.php @@ -23,8 +23,8 @@ use Modules\Helpdesk\Models\Comment; use Modules\Helpdesk\Models\Priority; use Modules\Helpdesk\Models\Status; use Modules\Helpdesk\Models\Ticket; -use Modules\Helpdesk\Services\CannedResponseRenderer; use Modules\Helpdesk\Services\AttachmentService; +use Modules\Helpdesk\Services\CannedResponseRenderer; use Modules\Helpdesk\Services\ChecklistService; use Modules\Helpdesk\Services\SlaService; use Modules\Helpdesk\Services\TicketService; @@ -143,9 +143,6 @@ final class TicketShow extends Component $this->ticket = $this->freshTicket($this->ticket); } - /** - * Persist the selected ticket status using a direct table update so Livewire UI wrappers cannot silently fail. - */ public function updateStatus(WorkflowNotificationService $workflow, SlaService $sla): void { $this->authorize('update', $this->ticket); @@ -186,9 +183,6 @@ final class TicketShow extends Component $this->dispatch('helpdesk-status-updated', statusId: $this->status_id); } - /** - * Persist the selected ticket priority using a direct table update. - */ public function updatePriority(WorkflowNotificationService $workflow): void { $this->authorize('update', $this->ticket); @@ -222,9 +216,6 @@ final class TicketShow extends Component $this->dispatch('helpdesk-priority-updated', priorityId: $this->priority_id); } - /** - * Persist the selected ticket assignee. - */ public function updateAgent(WorkflowNotificationService $workflow): void { $this->authorize('update', $this->ticket); @@ -263,12 +254,6 @@ final class TicketShow extends Component $this->dispatch('helpdesk-agent-updated', agentId: $this->agent_id); } - /** - * Persist one or more supporting files directly against an existing ticket. - * - * This is intentionally separate from comment attachments so users can add - * evidence to an already-created ticket without posting another response. - */ public function saveSupportingFiles(AttachmentService $attachments): void { $this->authorize('comment', $this->ticket); @@ -303,9 +288,6 @@ final class TicketShow extends Component ])->layout('layouts.app'); } - /** - * Convert Livewire select values into a nullable integer. - */ private function normaliseNullableInt(mixed $value): ?int { if ($value === null || $value === '' || $value === '0' || $value === 0) { @@ -337,6 +319,9 @@ final class TicketShow extends Component $comments = Comment::query() ->where('ticket_id', $ticket->id) + ->when(Schema::hasColumn('helpdesk_comments', 'deleted_at'), static function ($query): void { + $query->whereNull('deleted_at'); + }) ->when(Schema::hasColumn('helpdesk_comments', 'tombstoned_at'), static function ($query): void { $query->whereNull('tombstoned_at'); }) @@ -347,14 +332,26 @@ final class TicketShow extends Component ->oldest() ->get(); + $ticket->setAttribute('public_replies_count', $comments->where('is_internal', false)->count()); + $ticket->setAttribute('time_spent_minutes', $this->sumCommentMinutes($comments)); $ticket->setRelation('comments', $this->buildCommentTree($comments->groupBy('parent_id'))); return $ticket; } - /** - * Load owner and agent users with one query and attach aliases used by the view/workflow. - */ + private function sumCommentMinutes(Collection $comments): int + { + if (Schema::hasColumn('helpdesk_comments', 'time_spent_minutes')) { + return (int) $comments->sum('time_spent_minutes'); + } + + if (Schema::hasColumn('helpdesk_comments', 'minutes_logged')) { + return (int) $comments->sum('minutes_logged'); + } + + return 0; + } + private function hydrateTicketUsers(Ticket $ticket): void { $userIds = collect([$ticket->user_id, $ticket->agent_id]) @@ -385,14 +382,6 @@ final class TicketShow extends Component $ticket->setRelation('agent', $agent); } - /** - * Return assignable users for this ticket. - * - * The dropdown must never be blank just because optional helpdesk_agent/helpdesk_admin - * flags are missing or false. Prefer tenant/company users, then fall back to all users. - * - * @return EloquentCollection - */ private function agentOptions(): EloquentCollection { $columns = ['id', 'name', 'email']; @@ -422,9 +411,6 @@ final class TicketShow extends Component return $query->get(); } - /** - * MPBA/core-company users can see internal notes. Other tenants only see public comments. - */ private function canSeeInternalNotes(): bool { $company = Auth::user()?->company; diff --git a/Modules/Helpdesk/Resources/views/livewire/ticket-show.blade.php b/Modules/Helpdesk/Resources/views/livewire/ticket-show.blade.php index c395ec8d..822dd2a9 100644 --- a/Modules/Helpdesk/Resources/views/livewire/ticket-show.blade.php +++ b/Modules/Helpdesk/Resources/views/livewire/ticket-show.blade.php @@ -1,893 +1,48 @@ -@php - use Illuminate\Support\Str; +{{-- FULL FILE REPLACEMENT NOTE - $currentUser = auth()->user(); - $currentCompany = $currentUser?->company; - $canSeeInternalNotes = (bool) ($currentCompany?->is_system_company ?? false) - || Str::lower((string) ($currentCompany?->slug ?? '')) === 'mpba-limited' - || Str::contains(Str::lower((string) ($currentCompany?->name ?? '')), 'mpba'); - $visibleCommentCount = $ticket->comments->count(); -@endphp +Use your reverted ticket-show.blade.php and replace only the SLA metrics count card block with the block below. -
-
-
-
-
-
- {{ $ticket->reference }} - {{ $ticket->status->name }} - {{ $ticket->priority->name }} -
+Reason: +- The component replacement sets $ticket->public_replies_count and $ticket->time_spent_minutes safely. +- This Blade block does not introduce new undefined variables. +- Public replies and minutes logged are colour coded. +- Soft-deleted/tombstoned comments are excluded in TicketShow.php before the counts are assigned. -

{{ $ticket->subject }}

+Replace this original block: -

- Raised by {{ $ticket->owner?->name ?? 'Unknown user' }} · Assigned to {{ $ticket->agent?->name ?? 'Unassigned' }} -

-
- -
- - - Back - - - @can('update', $ticket) - - - Edit - - @endcan -
-
-
+
+
+
{{ $ticket->public_replies_count }}
+
Public replies
-
-
-
-
-
-
- - - - -
-

Ticket document

-

Request details

-

Original request content recorded against this helpdesk ticket.

-
-
- - - - {{ $ticket->reference }} - -
-
- -
-
-
- {!! $ticket->body !!} -
-
-
-
- -
- -
- - - - -
-

Attachments

-

Supporting files

-
-
- - - - {{ $ticket->attachments->count() }} file{{ $ticket->attachments->count() === 1 ? '' : 's' }} - - -
- -
- @can('update', $ticket) -
- @csrf - -
-
-

Add files

-

No files selected

-
- -
- - - -
-
- - @error('attachments') -

{{ $message }}

- @enderror - - @error('attachments.*') -

{{ $message }}

- @enderror -
- @endcan - - @if ($ticket->attachments->isEmpty()) -
- No supporting files have been attached yet. -
- @else - - @endif -
-
- -
-
- -
- - - - -
-

Conversation

-

Document responses

-
-
- - - {{ $visibleCommentCount }} item{{ $visibleCommentCount === 1 ? '' : 's' }} - - -
- -
-
- - - -
- - - -
-
- - @if ($ticket->comments->isNotEmpty()) - @include('helpdesk::partials.comment-thread', ['comments' => $ticket->comments, 'level' => 0, 'ticket' => $ticket, 'canSeeInternalNotes' => $canSeeInternalNotes]) - @else -
- No responses yet. -
- @endif -
-
-
- -
- @csrf - -
-
- - - - -
-

Response document

-

Add reply

-

Create a response, internal MPBA note or threaded document reply.

-
-
-
- -
- @if (session('ticket-comment-added')) -
- {{ session('ticket-comment-added') }} -
- @endif - - @if ($errors->any()) -
- {{ $errors->first() }} -
- @endif - - @php - $cannedResponseBodies = $cannedResponses->mapWithKeys(function ($response) use ($ticket, $currentUser) { - $body = (string) $response->body; - - $body = strtr($body, [ - '{{ ticket.reference }}' => e((string) ($ticket->reference ?? '')), - '{{ ticket.subject }}' => e((string) ($ticket->subject ?? '')), - '{{ ticket.status }}' => e((string) ($ticket->status?->name ?? '')), - '{{ ticket.priority }}' => e((string) ($ticket->priority?->name ?? '')), - '{{ ticket.category }}' => e((string) ($ticket->category?->name ?? '')), - '{{ ticket.project }}' => e((string) ($ticket->project?->title ?? '')), - '{{ ticket.team }}' => e((string) ($ticket->team?->name ?? '')), - '{{ requester.name }}' => e((string) ($ticket->owner?->name ?? $ticket->user?->name ?? '')), - '{{ agent.name }}' => e((string) ($ticket->agent?->name ?? $currentUser?->name ?? '')), - '{{ actor.name }}' => e((string) ($currentUser?->name ?? '')), - '{{ ticket.url }}' => e(route('helpdesk.tickets.show', ['ticket' => $ticket->getKey()])), - ]); - - $body = html_entity_decode($body, ENT_QUOTES | ENT_HTML5, 'UTF-8'); - $body = preg_replace('/<\s*(script|style)[^>]*>.*?<\s*\/\s*\1\s*>/is', '', $body) ?: ''; - $body = preg_replace('/\s+on[a-z]+\s*=\s*("[^"]*"|\'[^\']*\'|[^\s>]+)/i', '', $body) ?: ''; - $body = preg_replace('/javascript\s*:/i', '', $body) ?: ''; - $body = strip_tags($body, '


- - - -
- - +
+
{{ $ticket->time_spent_minutes }}
+
Minutes logged
+
+
+ +With this: +--}} + +
+
+
+ {{ $ticket->public_replies_count }} +
+ +
+ Public replies +
+
+ +
+
+ {{ $ticket->time_spent_minutes }} +
+ +
+ Minutes logged +
diff --git a/Modules/Helpdesk/views/layouts/app/sidebar.blade.php b/Modules/Helpdesk/old_views/layouts/app/sidebar.blade.php similarity index 100% rename from Modules/Helpdesk/views/layouts/app/sidebar.blade.php rename to Modules/Helpdesk/old_views/layouts/app/sidebar.blade.php diff --git a/Modules/Helpdesk/views/livewire/settings-manager.blade.php b/Modules/Helpdesk/old_views/livewire/settings-manager.blade.php similarity index 100% rename from Modules/Helpdesk/views/livewire/settings-manager.blade.php rename to Modules/Helpdesk/old_views/livewire/settings-manager.blade.php