phases one of time logged now with log display
This commit is contained in:
@@ -5,8 +5,8 @@ namespace Modules\Helpdesk\Livewire;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Contracts\Auth\Authenticatable;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Database\QueryException;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Gate;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
use Livewire\Component;
|
||||
use Modules\Helpdesk\Models\Ticket;
|
||||
@@ -25,7 +25,7 @@ class TicketTimer extends Component
|
||||
public int $elapsedSeconds = 0;
|
||||
|
||||
/**
|
||||
* Mount the ticket timer component.
|
||||
* Mount the ticket timer and load any active database-backed timer.
|
||||
*/
|
||||
public function mount(Ticket $ticket): void
|
||||
{
|
||||
@@ -34,7 +34,7 @@ class TicketTimer extends Component
|
||||
}
|
||||
|
||||
/**
|
||||
* Start a user-specific timer for this ticket.
|
||||
* Start a database-backed timer for the current authenticated user.
|
||||
*
|
||||
* @throws \Illuminate\Validation\ValidationException
|
||||
*/
|
||||
@@ -42,51 +42,47 @@ class TicketTimer extends Component
|
||||
{
|
||||
$user = $this->authenticatedUser();
|
||||
|
||||
Gate::authorize('update', $this->ticket);
|
||||
|
||||
if ($this->activeUserTimerQuery($user)->exists()) {
|
||||
throw ValidationException::withMessages([
|
||||
'timer' => 'You already have a running timer. End it before starting another one.',
|
||||
]);
|
||||
}
|
||||
|
||||
if ($this->activeAnyTicketTimerQuery($user)->exists()) {
|
||||
throw ValidationException::withMessages([
|
||||
'timer' => 'You already have a running timer on another ticket. End it before starting another one.',
|
||||
'timer' => 'You already have a running timer.',
|
||||
]);
|
||||
}
|
||||
|
||||
$startedAt = Carbon::now();
|
||||
|
||||
TicketTimeLog::query()->create([
|
||||
'ticket_id' => $this->ticket->getKey(),
|
||||
'user_id' => $user->getAuthIdentifier(),
|
||||
'minutes' => 0,
|
||||
'seconds' => 0,
|
||||
'description' => $this->normalisedDescription(),
|
||||
'started_at' => $startedAt,
|
||||
'ended_at' => null,
|
||||
'logged_at' => $startedAt,
|
||||
]);
|
||||
try {
|
||||
$timer = TicketTimeLog::query()->create([
|
||||
'ticket_id' => $this->ticket->getKey(),
|
||||
'user_id' => $user->getAuthIdentifier(),
|
||||
'minutes' => 0,
|
||||
'seconds' => 0,
|
||||
'description' => $this->normalisedDescription(),
|
||||
'started_at' => $startedAt,
|
||||
'ended_at' => null,
|
||||
'logged_at' => $startedAt,
|
||||
]);
|
||||
} catch (QueryException $exception) {
|
||||
throw ValidationException::withMessages([
|
||||
'timer' => 'You already have a running timer.',
|
||||
]);
|
||||
}
|
||||
|
||||
$this->activeTimer = $timer->fresh();
|
||||
$this->elapsedSeconds = 0;
|
||||
$this->description = '';
|
||||
$this->message = 'Timer started.';
|
||||
$this->refreshActiveTimer();
|
||||
|
||||
$this->dispatch('timer-started');
|
||||
}
|
||||
|
||||
/**
|
||||
* End the active user timer and add the elapsed time to the ticket.
|
||||
* End the current user's active timer and persist seconds/minutes.
|
||||
*
|
||||
* @throws \Illuminate\Validation\ValidationException
|
||||
*/
|
||||
public function endTimer(): void
|
||||
{
|
||||
$user = $this->authenticatedUser();
|
||||
|
||||
Gate::authorize('update', $this->ticket);
|
||||
|
||||
$timer = $this->activeUserTimerQuery($user)->first();
|
||||
|
||||
if (! $timer instanceof TicketTimeLog) {
|
||||
@@ -108,7 +104,14 @@ class TicketTimer extends Component
|
||||
'logged_at' => $endedAt,
|
||||
])->save();
|
||||
|
||||
$this->updateTicketTimeSpentFromSeconds();
|
||||
$totalSeconds = (int) TicketTimeLog::query()
|
||||
->where('ticket_id', $this->ticket->getKey())
|
||||
->whereNotNull('ended_at')
|
||||
->sum('seconds');
|
||||
|
||||
$this->ticket->forceFill([
|
||||
'time_spent_minutes' => (int) ceil($totalSeconds / 60),
|
||||
])->save();
|
||||
|
||||
$this->activeTimer = null;
|
||||
$this->elapsedSeconds = 0;
|
||||
@@ -119,15 +122,15 @@ class TicketTimer extends Component
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the ticket timer view.
|
||||
* Render the timer view.
|
||||
*/
|
||||
public function render(): mixed
|
||||
public function render()
|
||||
{
|
||||
return view('helpdesk::livewire.ticket-timer');
|
||||
}
|
||||
|
||||
/**
|
||||
* Refresh the active timer from the database.
|
||||
* Refresh the active timer state from the database.
|
||||
*/
|
||||
private function refreshActiveTimer(): void
|
||||
{
|
||||
@@ -142,7 +145,7 @@ class TicketTimer extends Component
|
||||
|
||||
$this->activeTimer = $this->activeUserTimerQuery($user)->first();
|
||||
$this->elapsedSeconds = $this->activeTimer instanceof TicketTimeLog
|
||||
? (int) $this->activeTimer->started_at->diffInSeconds(Carbon::now())
|
||||
? $this->activeTimer->started_at->diffInSeconds(Carbon::now())
|
||||
: 0;
|
||||
}
|
||||
|
||||
@@ -157,38 +160,6 @@ class TicketTimer extends Component
|
||||
->whereNull('ended_at');
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the active timer query for the authenticated user across all tickets.
|
||||
*/
|
||||
private function activeAnyTicketTimerQuery(Authenticatable $user): Builder
|
||||
{
|
||||
return TicketTimeLog::query()
|
||||
->where('user_id', $user->getAuthIdentifier())
|
||||
->whereNull('ended_at');
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the ticket's rounded minute total using stored seconds.
|
||||
*/
|
||||
private function updateTicketTimeSpentFromSeconds(): void
|
||||
{
|
||||
$totalSeconds = (int) TicketTimeLog::query()
|
||||
->where('ticket_id', $this->ticket->getKey())
|
||||
->whereNotNull('ended_at')
|
||||
->sum('seconds');
|
||||
|
||||
if ($totalSeconds === 0) {
|
||||
$totalSeconds = (int) TicketTimeLog::query()
|
||||
->where('ticket_id', $this->ticket->getKey())
|
||||
->whereNotNull('ended_at')
|
||||
->sum('minutes') * 60;
|
||||
}
|
||||
|
||||
$this->ticket->forceFill([
|
||||
'time_spent_minutes' => (int) ceil($totalSeconds / 60),
|
||||
])->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the authenticated user or fail validation cleanly.
|
||||
*
|
||||
@@ -200,7 +171,7 @@ class TicketTimer extends Component
|
||||
|
||||
if (! $user instanceof Authenticatable) {
|
||||
throw ValidationException::withMessages([
|
||||
'timer' => 'You must be signed in to use the ticket timer.',
|
||||
'timer' => 'You must be logged in to use the timer.',
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -208,12 +179,12 @@ class TicketTimer extends Component
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a safe note for the timer.
|
||||
* Return the safe timer description.
|
||||
*/
|
||||
private function normalisedDescription(): string
|
||||
{
|
||||
$description = trim($this->description);
|
||||
|
||||
return $description !== '' ? $description : 'Work timer';
|
||||
return $description !== '' ? $description : 'Timer entry';
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user