misc updates
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Modules\Helpdesk\Livewire;
|
||||
|
||||
use Carbon\Carbon;
|
||||
@@ -33,6 +35,14 @@ class TicketTimer extends Component
|
||||
$this->refreshActiveTimer();
|
||||
}
|
||||
|
||||
/**
|
||||
* Refresh the timer every poll cycle while the timer is running.
|
||||
*/
|
||||
public function refreshTimer(): void
|
||||
{
|
||||
$this->refreshActiveTimer();
|
||||
}
|
||||
|
||||
/**
|
||||
* Start a database-backed timer for the current authenticated user.
|
||||
*
|
||||
@@ -61,7 +71,7 @@ class TicketTimer extends Component
|
||||
'ended_at' => null,
|
||||
'logged_at' => $startedAt,
|
||||
]);
|
||||
} catch (QueryException $exception) {
|
||||
} catch (QueryException) {
|
||||
throw ValidationException::withMessages([
|
||||
'timer' => 'You already have a running timer.',
|
||||
]);
|
||||
@@ -94,7 +104,6 @@ class TicketTimer extends Component
|
||||
$endedAt = Carbon::now();
|
||||
$description = trim($this->description) !== '' ? trim($this->description) : $timer->description;
|
||||
$seconds = max(1, (int) $timer->started_at->diffInSeconds($endedAt));
|
||||
|
||||
$minutes = (int) ceil($seconds / 60);
|
||||
|
||||
$timer->forceFill([
|
||||
@@ -122,6 +131,22 @@ class TicketTimer extends Component
|
||||
$this->dispatch('timer-ended');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the currently elapsed timer duration.
|
||||
*/
|
||||
public function getElapsedTimeProperty(): string
|
||||
{
|
||||
return gmdate('H:i:s', $this->elapsedSeconds);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the current user has a running timer.
|
||||
*/
|
||||
public function getIsRunningProperty(): bool
|
||||
{
|
||||
return $this->activeTimer instanceof TicketTimeLog;
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the timer view.
|
||||
*/
|
||||
@@ -145,8 +170,9 @@ class TicketTimer extends Component
|
||||
}
|
||||
|
||||
$this->activeTimer = $this->activeUserTimerQuery($user)->first();
|
||||
|
||||
$this->elapsedSeconds = $this->activeTimer instanceof TicketTimeLog
|
||||
? $this->activeTimer->started_at->diffInSeconds(Carbon::now())
|
||||
? max(0, (int) $this->activeTimer->started_at->diffInSeconds(Carbon::now()))
|
||||
: 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,88 @@
|
||||
<section
|
||||
@if ($this->isRunning) wire:poll.1s="refreshTimer" @endif
|
||||
class="rounded-xl border border-emerald-700/70 bg-emerald-950/40 p-4 text-emerald-50 shadow-sm"
|
||||
data-helpdesk-ticket-timer
|
||||
>
|
||||
<div class="flex flex-col gap-4 sm:flex-row sm:items-start sm:justify-between">
|
||||
<div class="flex min-w-0 gap-3">
|
||||
<span class="inline-flex h-14 w-14 shrink-0 items-center justify-center rounded-xl bg-emerald-600 text-white">
|
||||
<i class="fa-solid fa-stopwatch text-xl" aria-hidden="true"></i>
|
||||
</span>
|
||||
|
||||
<div class="min-w-0">
|
||||
<h3 class="text-lg font-black text-emerald-50">Work timer</h3>
|
||||
|
||||
<p class="mt-1 max-w-sm text-sm font-semibold leading-6 text-emerald-100">
|
||||
Start a user-specific timer. It remains active if the browser is closed.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@if ($this->isRunning)
|
||||
<div
|
||||
class="shrink-0 rounded-xl bg-emerald-600 px-5 py-3 text-center text-white shadow-sm"
|
||||
data-helpdesk-running-timer
|
||||
data-dusk="ticket-running-timer-summary"
|
||||
>
|
||||
<div class="text-xs font-black uppercase tracking-[0.25em]">
|
||||
Running
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="mt-2 font-mono text-2xl font-black"
|
||||
data-dusk="ticket-running-elapsed-time"
|
||||
>
|
||||
{{ $this->elapsedTime }}
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
|
||||
@if ($message)
|
||||
<div class="mt-4 rounded-xl border border-emerald-700 bg-zinc-950 px-4 py-3 text-sm font-bold text-emerald-50">
|
||||
{{ $message }}
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<div class="mt-4 space-y-2">
|
||||
<label for="ticket-timer-description" class="block text-sm font-bold text-emerald-50">
|
||||
Timer note
|
||||
</label>
|
||||
|
||||
<textarea
|
||||
id="ticket-timer-description"
|
||||
wire:model="description"
|
||||
rows="3"
|
||||
placeholder="Optional work note"
|
||||
class="block w-full rounded-xl border border-emerald-700 bg-zinc-950 p-3 text-sm font-semibold text-emerald-50 shadow-sm placeholder:text-zinc-500 focus:border-emerald-400 focus:ring-emerald-400"
|
||||
></textarea>
|
||||
</div>
|
||||
|
||||
@error('timer')
|
||||
<p class="mt-3 text-sm font-bold text-red-300">{{ $message }}</p>
|
||||
@enderror
|
||||
|
||||
<div class="mt-4 flex flex-wrap gap-2">
|
||||
@if ($this->isRunning)
|
||||
<button
|
||||
type="button"
|
||||
wire:click="endTimer"
|
||||
wire:loading.attr="disabled"
|
||||
class="inline-flex items-center justify-center rounded-xl bg-red-600 px-4 py-3 text-sm font-black text-white shadow-sm transition hover:bg-red-700 disabled:cursor-not-allowed disabled:opacity-60"
|
||||
>
|
||||
<i class="fa-solid fa-stop mr-2" aria-hidden="true"></i>
|
||||
End timer
|
||||
</button>
|
||||
@else
|
||||
<button
|
||||
type="button"
|
||||
wire:click="startTimer"
|
||||
wire:loading.attr="disabled"
|
||||
class="inline-flex items-center justify-center rounded-xl bg-emerald-600 px-4 py-3 text-sm font-black text-white shadow-sm transition hover:bg-emerald-700 disabled:cursor-not-allowed disabled:opacity-60"
|
||||
>
|
||||
<i class="fa-solid fa-play mr-2" aria-hidden="true"></i>
|
||||
Start timer
|
||||
</button>
|
||||
@endif
|
||||
</div>
|
||||
</section>
|
||||
@@ -0,0 +1,3 @@
|
||||
@can('update', $ticket)
|
||||
@livewire('Modules\\Helpdesk\\Livewire\\TicketTimer', ['ticket' => $ticket], key('helpdesk-ticket-timer-'.$ticket->getKey()))
|
||||
@endcan
|
||||
Reference in New Issue
Block a user