@php $hm = function ($min) { $min = max(0, (int) round($min)); return intdiv($min, 60) . 'h ' . str_pad($min % 60, 2, '0', STR_PAD_LEFT) . 'm'; }; // Hours read better as a decimal once you are comparing three columns of // them; minutes are for the personal view, where every one of them is yours. $hrs = fn ($min) => round(max(0, (int) $min) / 60, 1); // The day's punctuality ruling, not the clock lifecycle: a day can be // closed and still be late. $dayBadge = [ 'present' => ['emerald', __('Present')], 'late' => ['amber', __('Late')], 'absent' => ['rose', __('Absent')], ]; $tabMeta = [ 'me' => ['label' => __('My attendance'), 'icon' => 'user-circle'], 'hours' => ['label' => __('Hours & gaps'), 'icon' => 'chart-pie'], 'today' => ['label' => __('Who is in'), 'icon' => 'users'], 'records' => ['label' => __('Records'), 'icon' => 'queue-list'], 'appeals' => ['label' => __('Appeals'), 'icon' => 'scale-balance'], 'offsite' => ['label' => __('Off-site'), 'icon' => 'shield-check'], ]; $tabs = array_intersect_key($tabMeta, array_flip($visibleTabs)); $subtitle = match ($tab) { 'hours' => __('What was meant to be worked, what was clocked, and the gap.'), 'today' => __('Who is in, out, late or on leave right now.'), 'records' => __('Every clock record for the team.'), 'appeals' => __('Staff asking for a late or absent day to be reconsidered.'), 'offsite' => __('Clocking in from away from the shop.'), default => __('Clock in, on site, track your hours and request leave.'), }; @endphp
{{ __('On the clock') }} @if ($isRemoteToday) {{ __('Remote') }} @endif
00:00:00
{{ __('Not Clocked In') }}
@if ($isRemoteToday)
{{ $today && $today->clock_in_at ? __('Welcome back.') : __('Day starts :start · on time until :cutoff', ['start' => $expectedStart, 'cutoff' => $absentCutoff]) }}
{{-- Not going to make it: book the hours rather than arrive late and appeal the ruling afterwards. Approved, the deadline above moves and the day is never marked late. --}} @if ($myPartialLeave)
@if ($isPendingOffsite) {{ __('Your off-site request is waiting for approval') }} @elseif ($offsiteRequest->isRejected()) {{ __('Your off-site request was declined') }} @else {{ __('You are cleared to work off-site today') }} @endif
@if ($isPendingOffsite) {{ __('Sent at :time.', [ 'time' => $offsiteRequest->requested_at?->timezone($tz)?->format('H:i'), ]) }} @elseif ($offsiteRequest->decision_note) {{ $offsiteRequest->decision_note }} @else {{ __('Clock in from where you are.') }} @endif
$isAbsent, 'text-brand-yellow-900' => ! $isAbsent])> {{ $isAbsent ? __('Today is recorded as absent') : __('Today is recorded as late') }}
{{ $m['label'] }}
{{ $m['value'] }}
{{ __('Daily rate') }}
{{ $cur }} {{ number_format($b['daily_rate'], 2) }}
= {{ __('Salary') }} ÷ {{ number_format($b['avg_days_per_month'], 2) }}
{{ __('Hourly rate') }}
{{ $cur }} {{ number_format($b['hourly_rate'], 2) }}
= {{ __('Salary') }} ÷ {{ number_format($b['avg_monthly_hours'], 2) }}
{{ __('Overtime (this month)') }}
{{ (float) $myPay['otHours'] }}h
{{ $cur }} {{ number_format($myPay['otEarnings'], 2) }} @ ×{{ rtrim(rtrim(number_format($b['overtime_multiplier'], 2), '0'), '.') }}
{{ __('Last payslip') }}
@if ($myPay['lastPayslip']){{ $cur }} {{ number_format($myPay['lastPayslip']['net'], 2) }}
{{ optional($myPay['lastPayslip']['period'])->format('M Y') }}
@else{{ __('None yet') }}
@endif{{ __('Salary owed to you: :cur :amt', ['cur' => $cur, 'amt' => number_format($myPay['owed']->sum(fn ($a) => $a->outstanding()), 2)]) }}
@foreach ($myPay['owed'] as $owed){{ $owed->periodLabel() }} ({{ number_format($owed->outstanding(), 2) }})@if (! $loop->last), @endif @endforeach · {{ __('earned and taxed already, to be paid on a later run or directly.') }}
{{ __('Overtime pay') }} = {{ __('OT hours') }} × {{ __('Hourly rate') }} × {{ rtrim(rtrim(number_format($b['overtime_multiplier'], 2), '0'), '.') }}
| {{ __('Type') }} | {{ __('Dates') }} | {{ __('Days') }} | {{ __('Status') }} | |
|---|---|---|---|---|
| {{ $leave->leaveType?->name }} | {{ $leave->isPartial() ? $leave->start_date->format('D d M Y') : $leave->start_date->format('d M') . ' – ' . $leave->end_date->format('d M Y') }} @if ($leave->isPartial()) {{ $leave->lengthLabel() }} @endif | {{ (float) $leave->requested_days }} |
@php $tone = match ($leave->status) { 'approved' => 'emerald', 'rejected' => 'rose', 'cancelled' => 'slate', default => 'amber' }; @endphp
|
@if (in_array($leave->status, ['pending', 'approved'], true)) @endif |
{{ __('Work Days') }}
{{ $summary['workDays'] }}
{{ __('Avg/Day') }}
{{ $hm($summary['avgMinutes']) }}
{{ __('Overtime') }}
{{ $hm($summary['overtimeMinutes']) }}
{{ __('Attendance') }}
{{ $summary['attendancePct'] }}%
| {{ __('Date') }} | {{ __('In') }} | {{ __('Out') }} | {{ __('Total Hours') }} | {{ __('Overtime') }} | {{ __('Status') }} | |
|---|---|---|---|---|---|---|
| {{ $r->business_date->format('D d M Y') }} | {{ $r->clock_in_at?->timezone($tz)?->format('H:i') ?? '—' }} | {{ $r->clock_out_at?->timezone($tz)?->format('H:i') ?? '—' }} | {{ $hm($r->worked_minutes) }} | @if ($r->overtime_minutes > 0){{ $hm($r->overtime_minutes) }}@else—@endif |
@php [$badgeColor, $badgeLabel] = $dayBadge[$r->day_status] ?? $dayBadge['present']; @endphp
|
@php $appeal = $myAppeals->get($r->id); @endphp @if ($appeal?->status === 'pending') @elseif ($appeal?->status === 'approved') {{ __('Appeal approved') }} @elseif ($appeal?->status === 'rejected') decision_note) title="{{ $appeal->decision_note }}" @endif>{{ __('Appeal rejected') }} @elseif (in_array($r->day_status, ['late', 'absent'], true)) @else — @endif |
{{ $card['label'] }}
{{ $hrs($g['worked']) }}h
{{ __('of :n h expected', ['n' => $hrs($g['expected'])]) }} @if ($g['leave'] > 0) · {{ __(':n h on leave', ['n' => $hrs($g['leave'])]) }} @endif
@if ($g['expected'] <= 0)
{{ __('Nothing expected — non-working time.') }}
@elseif ($behind > 0)
{{ __(':who · :from to :to', [ 'who' => $whose, 'from' => $hours['from']->format('d M Y'), 'to' => $hours['to']->format('d M Y'), ]) }}
| {{ $grains[$h_granularity]['label'] }} | {{ __('Expected') }} | {{ __('Clocked') }} | {{ __('Leave') }} | {{ __('OT') }} | {{ __('Gap') }} | {{ __('Attainment') }} |
|---|---|---|---|---|---|---|
| {{ $b['label'] }} @if ($b['sub']) {{ $b['sub'] }} @endif @if ($b['days_late'] > 0 || $b['days_absent'] > 0) @if ($b['days_late'] > 0){{ trans_choice('{1} :count late day|[2,*] :count late days', $b['days_late'], ['count' => $b['days_late']]) }}@endif @if ($b['days_late'] > 0 && $b['days_absent'] > 0)·@endif @if ($b['days_absent'] > 0){{ trans_choice('{1} :count absent day|[2,*] :count absent days', $b['days_absent'], ['count' => $b['days_absent']]) }}@endif @endif | {{ $hrs($b['expected']) }}h | {{ $hrs($b['worked']) }}h | {{ $b['leave'] > 0 ? $hrs($b['leave']).'h' : '—' }} | {{ $b['overtime'] > 0 ? $hrs($b['overtime']).'h' : '—' }} | @if ($b['gap'] > 0) −{{ $hrs($b['gap']) }}h @elseif ($b['surplus'] > 0) +{{ $hrs($b['surplus']) }}h @else — @endif |
|
{{ __('The same range, one row per person.') }}
| {{ __('Employee') }} | {{ __('Days') }} | {{ __('Expected') }} | {{ __('Clocked') }} | {{ __('Leave') }} | {{ __('Gap') }} | {{ __('Attainment') }} |
|---|---|---|---|---|---|---|
| @if ($p['days_absent'] > 0) {{ trans_choice('{1} :count absent|[2,*] :count absent', $p['days_absent'], ['count' => $p['days_absent']]) }} @endif | {{ $p['days_present'] }} / {{ $p['days_expected'] }} | {{ $hrs($p['expected']) }}h | {{ $hrs($p['worked']) }}h | {{ $p['leave'] > 0 ? $hrs($p['leave']).'h' : '—' }} | @if ($p['gap'] > 0) −{{ $hrs($p['gap']) }}h @elseif ($p['surplus'] > 0) +{{ $hrs($p['surplus']) }}h @else — @endif |
|
{{ $rosterDay->format('l d M Y') }} @if ($rosterIsWorkingDay) · {{ __('day starts :time', ['time' => $expectedIn]) }} @else · {{ __('non-working day') }} @endif
| {{ __('Employee') }} | {{ __('Status') }} | {{ __('In') }} | {{ __('Out') }} | {{ __('Hours') }} | {{ __('Note') }} | |
|---|---|---|---|---|---|---|
| {{ $row['name'] }} |
|
{{ $row['clock_in'] ?? '—' }} | {{ $row['clock_out'] ?? ($row['status'] === 'in' ? __('still in') : '—') }} | {{ $row['worked_minutes'] > 0 ? round($row['worked_minutes'] / 60, 1).'h' : '—' }} |
@if ($row['day_status'] === 'late')
{{ __('recorded late') }}
@elseif ($row['day_status'] === 'absent')
{{ __('recorded absent') }}
@endif
@if ($row['corrected'])
{{ __('corrected to present') }}
@elseif ($row['marked_absent'] && $row['clock_in'])
{{ __('arrived after cut-off') }}
@endif
@if ($row['late_minutes'] > 0)
{{ __(':n min late', ['n' => $row['late_minutes']]) }}
@endif
@if ($row['partial_leave'])
{{ __(':length approved', ['length' => $row['partial_leave']]) }}
@if ($row['due_in'])
· {{ __('due in :time', ['time' => $row['due_in']]) }}
@endif
@elseif ($row['leave_type'])
{{ $row['leave_type'] }}
@endif
@if ($row['remote'] ?? false)
|
@if ($canCorrect) @endif |
{{ __('Every clock record for the team.') }}
| {{ __('Employee') }} | @foreach ($grid['days'] as $day){{ $day['dow'] }} {{ $day['day'] }} | @endforeach{{ __('Days') }} | {{ __('Hours') }} | {{ __('OT') }} | {{ __('Late') }} | {{ __('Absent') }} |
|---|---|---|---|---|---|---|
| {{ $row['name'] }}@if (($row['work_mode'] ?? 'office') !== 'office') |
@foreach ($row['cells'] as $cell)
@php $tone = $cellTone[$cell['status']] ?? $cellTone['none']; @endphp
@endforeach | {{ $row['days_worked'] }} | {{ $row['hours'] }}h | {{ $row['overtime'] }}h | {{ $row['late'] }} | {{ $row['absent'] }} |
| {{ __('Employee') }} | {{ __('Date') }} | {{ __('In') }} | {{ __('Out') }} | {{ __('Worked') }} | {{ __('OT') }} | {{ __('Ruling') }} | {{ __('Source') }} | |
|---|---|---|---|---|---|---|---|---|
| {{ $r->user?->name }} | {{ $r->business_date->format('D d M Y') }} | {{ $r->clock_in_at?->timezone($tz)?->format('H:i') ?? '—' }} |
{{ $r->clock_out_at?->timezone($tz)?->format('H:i') ?? '—' }}
@if ($r->status === 'open') |
{{ $r->worked_hours }}h | {{ $r->overtime_hours }}h |
@php $rulingColor = ['present' => 'emerald', 'late' => 'amber', 'absent' => 'rose'][$r->day_status] ?? 'slate'; @endphp
|
|
@if ($canCorrect)
|
{{ __('Staff asking for a late or absent day to be recorded as present.') }}
{{ $appeal->user?->name }}
·
{{ $appeal->business_date->format('D d M Y') }}
@if ($appeal->record?->clock_in_at) {{ __('Clocked in :time.', ['time' => $appeal->record->clock_in_at->timezone($tz)->format('H:i')]) }} @else {{ __('No clock-in recorded.') }} @endif — {{ $appeal->reason }}
{{ $req->user?->name }} {{ __('asked at :time', ['time' => $req->requested_at?->timezone($tz)?->format('H:i')]) }} @if ($req->requestedDistanceLabel()) · {{ __(':d from the shop', ['d' => $req->requestedDistanceLabel()]) }} @endif
{{ $req->reason }}
{{ __('For :date', ['date' => $req->effective_date->format('D d M Y')]) }} @if ($req->requested_ip) · {{ $req->requested_ip }} @endif
{{ __('One employee, one day, away from the shop.') }}
| {{ __('Employee') }} | {{ __('Date') }} | {{ __('Reason') }} | {{ __('Granted by') }} | {{ __('Status') }} | |
|---|---|---|---|---|---|
| {{ $ov->user?->name }} | {{ $ov->effective_date->format('d M Y') }} | {{ $ov->reason }} @if ($ov->wasRequested()) {{ __('Applied for by :who', ['who' => $ov->user?->name]) }} @if ($ov->requestedDistanceLabel()) · {{ __(':d from the shop', ['d' => $ov->requestedDistanceLabel()]) }} @endif @if ($ov->auto_clocked_in) · {{ __('clocked in automatically') }} @endif @endif @if ($ov->decision_note) {{ $ov->decision_note }} @endif | {{ $ov->grantedBy?->name }} |
@if ($ov->isRejected()) |
@if ($canOverride && ! $ov->revoked_at && ! $ov->isRejected()) @endif |
{{ $appealRecord->business_date->format('D d M Y') }}
{{ $appealRecord->clock_in_at ? __('Clocked in :time', ['time' => $appealRecord->clock_in_at->timezone($tz)->format('H:i')]) : __('No clock-in recorded') }}