diff --git a/Modules/Helpdesk/Controllers/TicketTimeLogController.php b/Modules/Helpdesk/Controllers/TicketTimeLogController.php deleted file mode 100644 index 1f627b2c..00000000 --- a/Modules/Helpdesk/Controllers/TicketTimeLogController.php +++ /dev/null @@ -1,35 +0,0 @@ -authorize('update', $ticket); - - $validated = $request->validate([ - 'minutes' => ['required', 'integer', 'min:1', 'max:1440'], - 'description' => ['nullable', 'string', 'max:1000'], - ]); - - $ticket->timeLogs()->create([ - 'user_id' => $request->user()?->id, - 'minutes' => (int) $validated['minutes'], - 'description' => $validated['description'] ?? null, - 'logged_at' => now(), - ]); - - return back()->with('ticket-action-updated', 'Time logged successfully.'); - } -} diff --git a/Modules/Helpdesk/Helpdesk/Http/Controllers/TicketTimeLogController.php b/Modules/Helpdesk/Helpdesk/Http/Controllers/TicketTimeLogController.php deleted file mode 100644 index 1f627b2c..00000000 --- a/Modules/Helpdesk/Helpdesk/Http/Controllers/TicketTimeLogController.php +++ /dev/null @@ -1,35 +0,0 @@ -authorize('update', $ticket); - - $validated = $request->validate([ - 'minutes' => ['required', 'integer', 'min:1', 'max:1440'], - 'description' => ['nullable', 'string', 'max:1000'], - ]); - - $ticket->timeLogs()->create([ - 'user_id' => $request->user()?->id, - 'minutes' => (int) $validated['minutes'], - 'description' => $validated['description'] ?? null, - 'logged_at' => now(), - ]); - - return back()->with('ticket-action-updated', 'Time logged successfully.'); - } -} diff --git a/Modules/Helpdesk/Helpdesk/Models/TimeLog.php b/Modules/Helpdesk/Helpdesk/Models/TimeLog.php deleted file mode 100644 index 9df473b3..00000000 --- a/Modules/Helpdesk/Helpdesk/Models/TimeLog.php +++ /dev/null @@ -1,41 +0,0 @@ - */ - protected $fillable = [ - 'ticket_id', - 'user_id', - 'minutes', - 'description', - 'logged_at', - ]; - - /** @var array */ - protected $casts = [ - 'minutes' => 'integer', - 'logged_at' => 'datetime', - ]; - - /** @return BelongsTo */ - public function ticket(): BelongsTo - { - return $this->belongsTo(Ticket::class, 'ticket_id'); - } - - /** @return BelongsTo */ - public function user(): BelongsTo - { - return $this->belongsTo(User::class, 'user_id'); - } -} diff --git a/Modules/Helpdesk/Helpdesk/Tests/Feature/TicketTimeLogTest.php b/Modules/Helpdesk/Helpdesk/Tests/Feature/TicketTimeLogTest.php deleted file mode 100644 index 6c6e3831..00000000 --- a/Modules/Helpdesk/Helpdesk/Tests/Feature/TicketTimeLogTest.php +++ /dev/null @@ -1,55 +0,0 @@ -create(); - $ticket = Ticket::factory()->create(); - - $this->actingAs($user) - ->post(route('helpdesk.tickets.time-logs.store', $ticket), [ - 'minutes' => 45, - 'description' => 'Investigated the issue and updated the ticket.', - ]) - ->assertRedirect(); - - $this->assertDatabaseHas('helpdesk_time_logs', [ - 'ticket_id' => $ticket->id, - 'user_id' => $user->id, - 'minutes' => 45, - 'description' => 'Investigated the issue and updated the ticket.', - ]); - } - - /** - * It rejects invalid logged minutes. - */ - public function test_ticket_time_log_requires_valid_minutes(): void - { - $user = User::factory()->create(); - $ticket = Ticket::factory()->create(); - - $this->actingAs($user) - ->from(route('helpdesk.tickets.show', $ticket)) - ->post(route('helpdesk.tickets.time-logs.store', $ticket), [ - 'minutes' => 0, - ]) - ->assertRedirect(route('helpdesk.tickets.show', $ticket)) - ->assertSessionHasErrors('minutes'); - } -} diff --git a/Modules/Helpdesk/Helpdesk/database/migrations/2026_06_22_000001_create_helpdesk_time_logs_table.php b/Modules/Helpdesk/Helpdesk/database/migrations/2026_06_22_000001_create_helpdesk_time_logs_table.php deleted file mode 100644 index e1932242..00000000 --- a/Modules/Helpdesk/Helpdesk/database/migrations/2026_06_22_000001_create_helpdesk_time_logs_table.php +++ /dev/null @@ -1,41 +0,0 @@ -id(); - $table->foreignId('ticket_id')->constrained('helpdesk_tickets')->cascadeOnDelete(); - $table->foreignId('user_id')->constrained('users')->cascadeOnDelete(); - $table->unsignedInteger('minutes'); - $table->text('description')->nullable(); - $table->timestamp('logged_at')->useCurrent(); - $table->timestamps(); - - $table->index(['ticket_id', 'logged_at']); - $table->index(['user_id', 'logged_at']); - }); - } - - /** - * Reverse the migrations. - */ - public function down(): void - { - Schema::dropIfExists('helpdesk_time_logs'); - } -}; diff --git a/Modules/Helpdesk/Helpdesk/resources/views/partials/time-log-form.blade.php b/Modules/Helpdesk/Helpdesk/resources/views/partials/time-log-form.blade.php deleted file mode 100644 index 4b26baf5..00000000 --- a/Modules/Helpdesk/Helpdesk/resources/views/partials/time-log-form.blade.php +++ /dev/null @@ -1,42 +0,0 @@ -
- @csrf - - - -
- - - -
- - - - @error('minutes') -

{{ $message }}

- @enderror - - @error('description') -

{{ $message }}

- @enderror -
diff --git a/Modules/Helpdesk/Helpdesk/routes/time-logs.php b/Modules/Helpdesk/Helpdesk/routes/time-logs.php deleted file mode 100644 index b463afe9..00000000 --- a/Modules/Helpdesk/Helpdesk/routes/time-logs.php +++ /dev/null @@ -1,9 +0,0 @@ -name('tickets.time-logs.store'); diff --git a/Modules/Helpdesk/Http/Controllers/TicketTimeLogController.php b/Modules/Helpdesk/Http/Controllers/TicketTimeLogController.php index 1f627b2c..c670f68c 100644 --- a/Modules/Helpdesk/Http/Controllers/TicketTimeLogController.php +++ b/Modules/Helpdesk/Http/Controllers/TicketTimeLogController.php @@ -4,6 +4,7 @@ declare(strict_types=1); namespace Modules\Helpdesk\Http\Controllers; +use Illuminate\Auth\Access\AuthorizationException; use Illuminate\Http\RedirectResponse; use Illuminate\Http\Request; use Illuminate\Routing\Controller; @@ -12,24 +13,27 @@ use Modules\Helpdesk\Models\Ticket; final class TicketTimeLogController extends Controller { /** - * Store a time entry against the selected helpdesk ticket. + * Store logged time against the selected helpdesk ticket. + * + * @throws AuthorizationException */ public function store(Request $request, Ticket $ticket): RedirectResponse { - $this->authorize('update', $ticket); + if ($request->user()?->cannot('update', $ticket)) { + throw new AuthorizationException; + } $validated = $request->validate([ 'minutes' => ['required', 'integer', 'min:1', 'max:1440'], 'description' => ['nullable', 'string', 'max:1000'], ]); - $ticket->timeLogs()->create([ - 'user_id' => $request->user()?->id, - 'minutes' => (int) $validated['minutes'], - 'description' => $validated['description'] ?? null, - 'logged_at' => now(), + $ticket->increment('time_spent_minutes', (int) $validated['minutes'], [ + 'last_activity_at' => now(), ]); - return back()->with('ticket-action-updated', 'Time logged successfully.'); + return redirect() + ->route('helpdesk.tickets.show', $ticket) + ->with('ticket-action-updated', 'Time logged successfully.'); } } diff --git a/Modules/Helpdesk/Livewire/TicketShow.php b/Modules/Helpdesk/Livewire/TicketShow.php index 7bfcedf6..69f7a848 100644 --- a/Modules/Helpdesk/Livewire/TicketShow.php +++ b/Modules/Helpdesk/Livewire/TicketShow.php @@ -5,6 +5,7 @@ declare(strict_types=1); namespace Modules\Helpdesk\Livewire; use App\Models\User; +use Carbon\CarbonInterval; use Illuminate\Contracts\View\View; use Illuminate\Database\Eloquent\Collection as EloquentCollection; use Illuminate\Support\Collection; @@ -316,6 +317,7 @@ final class TicketShow extends Component ]) ?? $ticket; $this->hydrateTicketUsers($ticket); + $comments = $ticket->comments() ->active() ->when(! $this->canSeeInternalNotes(), static function ($query): void { @@ -324,26 +326,31 @@ final class TicketShow extends Component ->with(['user.company', 'attachments', 'replies.user.company', 'replies.attachments']) ->oldest() ->get(); - $ticket->setRelation('comments', $comments); + $ticket->setRelation('comments', $comments); $ticket->setAttribute('public_replies_count', $comments->where('is_internal', false)->count()); - $ticket->setAttribute('time_spent_minutes', $this->sumCommentMinutes($comments)); + $ticket->setAttribute('time_spent_minutes', (int) $ticket->getRawOriginal('time_spent_minutes')); $ticket->setRelation('comments', $this->buildCommentTree($comments->groupBy('parent_id'))); return $ticket; } - private function sumCommentMinutes(Collection $comments): int + + public function formattedTimeSpent(): string { - if (Schema::hasColumn('helpdesk_comments', 'time_spent_minutes')) { - return (int) $comments->sum('time_spent_minutes'); + $minutes = (int) $this->ticket->time_spent_minutes; + + if ($minutes < 1) { + return '0 minutes'; } - if (Schema::hasColumn('helpdesk_comments', 'minutes_logged')) { - return (int) $comments->sum('minutes_logged'); - } - - return 0; + return CarbonInterval::minutes($minutes) + ->cascade() + ->forHumans([ + 'short' => false, + 'parts' => 2, + 'join' => true, + ]); } private function hydrateTicketUsers(Ticket $ticket): void diff --git a/Modules/Helpdesk/Resources/views/livewire/ticket-show.blade.php b/Modules/Helpdesk/Resources/views/livewire/ticket-show.blade.php index 98166641..a091a383 100644 --- a/Modules/Helpdesk/Resources/views/livewire/ticket-show.blade.php +++ b/Modules/Helpdesk/Resources/views/livewire/ticket-show.blade.php @@ -32,136 +32,12 @@ Back + @can('update', $ticket) -
-
-
- - - -
-

Ticket controls

-

Log time, assignment, status and priority

-
-
-
- - @if (session('ticket-action-updated')) -
- {{ session('ticket-action-updated') }} -
- @endif - -
- @csrf - - - -
- - - -
- - - - @error('minutes') -

{{ $message }}

- @enderror - - @error('description') -

{{ $message }}

- @enderror -
- -
- @csrf - - - - - @error('agent_id') -

{{ $message }}

- @enderror - - -
- -
- @csrf - - - - - @error('status_id') -

{{ $message }}

- @enderror - - -
- -
- @csrf - - - - - @error('priority_id') -

{{ $message }}

- @enderror - - -
-
+ + + Edit + @endcan @@ -445,33 +321,29 @@ @can('update', $ticket) -
-
-
- -

- No files selected -

-
- - +
+
+
+ +

No files selected

- @error('comment_attachments') -

{{ $message }}

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

{{ $message }}

- @enderror +
+ @error('comment_attachments') +

{{ $message }}

+ @enderror + + @error('comment_attachments.*') +

{{ $message }}

+ @enderror +
+ @if ($canSeeInternalNotes)
+