@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
@if ($canHrSettings) {{ __('Clock-in rules') }} @endif @if ($tab === 'me') {{ __('Export') }} @endif
{{-- Clock bar, slim status + live timer + action ---------------------- --}}
$isClockedIn, 'bg-white ring-slate-200/70' => ! $isClockedIn, ])>
$isClockedIn, 'bg-slate-100 text-slate-500' => ! $isClockedIn, ])> @if ($isClockedIn)

{{ __('On the clock') }} @if ($isRemoteToday) {{ __('Remote') }} @endif

00:00:00

@else

{{ __('Not Clocked In') }} @if ($isRemoteToday) {{ __('Remote') }} @endif

{{ $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)

{{ __('Approved: :length · due in by :cutoff', [ 'length' => $myPartialLeave->lengthLabel(), 'cutoff' => $absentCutoff, ]) }}

@elseif ($canBookTimeOff) @endif
@endif
{{-- Both buttons route through `clockAction` so a geofenced workspace can take a position reading before the action fires. --}}
@if ($isClockedIn) @else @endif
{{-- What I'm working on: a quick note the team can see ------------------- --}} @if ($isClockedIn || $workUpdates->isNotEmpty())
@if ($workUpdates->isNotEmpty()) @php $latestUpdate = $workUpdates->first(); @endphp {{ $latestUpdate->body }} @if ($latestUpdate->subjectLabel()) {{ $latestUpdate->subjectLabel() }} @endif {{ $latestUpdate->created_at->timezone($tz)->format('H:i') }} @else {{ __('What are you working on today?') }} @if ($activityCheckOn){{ __('A quick line keeps the team up to date.') }}@endif @endif
@if ($showWorkUpdateForm)
{{ __('Post') }}
@if ($workUpdates->count() > 1)
    @foreach ($workUpdates->skip(1) as $u)
  • {{ $u->created_at->timezone($tz)->format('H:i') }} {{ $u->body }}@if ($u->subjectLabel()) · {{ $u->subjectLabel() }}@endif
  • @endforeach
@endif @endif
@endif {{-- Today's off-site application, while it is still live ---------------- --}} @if ($offsiteRequest && ! $offsiteRequest->revoked_at) @php $isPendingOffsite = $offsiteRequest->isPending(); @endphp
$isPendingOffsite, 'bg-rose-50 ring-rose-200' => $offsiteRequest->isRejected(), 'bg-emerald-50 ring-emerald-200' => $offsiteRequest->isApproved(), ])> $isPendingOffsite, 'bg-rose-100 text-rose-600' => $offsiteRequest->isRejected(), 'bg-emerald-100 text-emerald-600' => $offsiteRequest->isApproved(), ])>

@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

@endif {{-- Tabs ----------------------------------------------------------- --}}
count($tabs) < 2, ])> @foreach ($tabs as $key => $meta) @endforeach
@if ($tab === 'me') @php // Donut geometry (two arcs: regular + overtime). $C = 2 * M_PI * 54; $regLen = $C * ($summary['regularPct'] ?? 0) / 100; $otLen = $C * ($summary['overtimePct'] ?? 0) / 100; $leaveTabs = [ 'all' => __('All'), 'pending' => __('Pending'), 'approved' => __('Approved'), 'rejected' => __('Rejected'), 'cancelled' => __('Cancelled'), ]; // Today's ruling, if it is one the member can do something about. $todayRuling = $today && in_array($today->day_status, ['late', 'absent'], true) ? $today : null; $todayAppeal = $todayRuling ? $myAppeals->get($todayRuling->id) : null; @endphp {{-- Today's ruling, only when there is something to act on ------------ --}} @if ($todayRuling) @php $isAbsent = $todayRuling->day_status === 'absent'; @endphp
$isAbsent, 'bg-brand-yellow-50 ring-brand-yellow-200' => ! $isAbsent, ])>
$isAbsent, 'bg-brand-yellow-100 text-brand-yellow-700' => ! $isAbsent, ])>

$isAbsent, 'text-brand-yellow-900' => ! $isAbsent])> {{ $isAbsent ? __('Today is recorded as absent') : __('Today is recorded as late') }}

@if ($todayAppeal?->status === 'pending') {{ __('Appeal pending') }} @elseif ($todayAppeal?->status === 'rejected') {{ __('Appeal rejected') }} @else @endif
@endif {{-- Metrics strip, all KPIs in one compact row ----------------------- --}} @php $tones = [ 'brand' => 'bg-brand-50 text-brand-700', 'accent' => 'bg-accent-50 text-accent-700', 'emerald' => 'bg-emerald-50 text-emerald-700', 'sky' => 'bg-sky-50 text-sky-700', 'amber' => 'bg-brand-yellow-50 text-brand-yellow-700', 'violet' => 'bg-accent-50 text-accent-700', ]; $metrics = [ ['label' => __('Today'), 'value' => $hm($todayMinutes), 'icon' => 'clock', 'tone' => 'brand'], ['label' => __('This Week'), 'value' => $hm($weekMinutes), 'icon' => 'chart-pie', 'tone' => 'accent'], ['label' => __('This Month'), 'value' => $hm($monthMinutes), 'icon' => 'calendar', 'tone' => 'emerald'], ['label' => __('Entitlement'), 'value' => (float) $balance['entitlement'] . 'd', 'icon' => 'gift', 'tone' => 'sky'], ['label' => __('Taken'), 'value' => (float) $balance['taken'] . 'd', 'icon' => 'calendar', 'tone' => 'amber'], ['label' => __('Remaining'), 'value' => (float) $balance['remaining'] . 'd', 'icon' => 'check-circle', 'tone' => 'emerald'], ['label' => __('Pending'), 'value' => (string) $pendingLeaveCount, 'icon' => 'document-text', 'tone' => 'violet'], ]; @endphp
@foreach ($metrics as $m)

{{ $m['label'] }}

{{ $m['value'] }}

@endforeach
{{-- My pay & overtime -------------------------------------------------- --}} @if (($myPay['breakdown'] ?? null)) @php $b = $myPay['breakdown']; $cur = $b['currency']; @endphp

{{ __('My Pay & Overtime') }}

{{ __('Only you and management can see this') }}

{{ __('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
@if (($myPay['owed'] ?? collect())->isNotEmpty())

{{ __('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.') }}

@endif

{{ __('Overtime pay') }} = {{ __('OT hours') }} × {{ __('Hourly rate') }} × {{ rtrim(rtrim(number_format($b['overtime_multiplier'], 2), '0'), '.') }}

@endif {{-- Row 3, leave list + summary ------------------------------------- --}}
{{-- My leave requests --}}

{{ __('My Leave Requests') }}

{{ __('Apply for Leave') }}
{{-- Same segmented control as every other filter strip in the app. --}}
@foreach ($leaveTabs as $key => $label) @endforeach
@if ($myLeave->isEmpty())
@else
@foreach ($myLeave as $leave) @endforeach
{{ __('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 {{ ucfirst($leave->status) }} @if ($leave->status === 'rejected' && $leave->blocked_reason){{ $leave->blocked_reason }}@endif @if (in_array($leave->status, ['pending', 'approved'], true)) @endif
@endif
{{-- Attendance summary --}}

{{ __('Attendance Summary') }}

{{ __('This Month') }}
@if (($summary['workedMinutes'] ?? 0) > 0) @endif
{{ $hm($summary['workedMinutes']) }} {{ __('Total Worked') }}
{{ __('Regular Hours') }} {{ $hm($summary['regularMinutes']) }} ({{ $summary['regularPct'] }}%)
{{ __('Overtime') }} {{ $hm($summary['overtimeMinutes']) }} ({{ $summary['overtimePct'] }}%)
{{ __('Late Arrivals') }} {{ $hm($summary['lateMinutes']) }}
{{ __('Early Departures') }} {{ $hm($summary['earlyMinutes']) }}

{{ __('Work Days') }}

{{ $summary['workDays'] }}

{{ __('Avg/Day') }}

{{ $hm($summary['avgMinutes']) }}

{{ __('Overtime') }}

{{ $hm($summary['overtimeMinutes']) }}

{{ __('Attendance') }}

{{ $summary['attendancePct'] }}%

{{-- Row 4, recent days --------------------------------------------- --}}

{{ __('Recent Days') }}

@if ($recent->isEmpty())
@else
@foreach ($recent as $r) @endforeach
{{ __('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 {{ $badgeLabel }} @if ($r->day_status_corrected_at) {{ __('corrected') }} @elseif ($r->marked_absent_at && $r->clock_in_at) {{ __('arrived after cut-off') }} @endif @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
@if ($canReadTeam)
@endif @endif
{{-- HOURS: PLANNED vs CLOCKED --}} @elseif ($tab === 'hours') @php // One colour scale for the whole tab, so a bar, a chip and a // percentage never disagree about whether a number is good. $tone = fn (int $pct) => match (true) { $pct >= 100 => ['bg-emerald-500', 'text-emerald-700', 'bg-emerald-50 ring-emerald-200'], $pct >= 90 => ['bg-sky-500', 'text-sky-700', 'bg-sky-50 ring-sky-200'], $pct >= 70 => ['bg-amber-500', 'text-amber-700', 'bg-amber-50 ring-amber-200'], default => ['bg-rose-500', 'text-rose-700', 'bg-rose-50 ring-rose-200'], }; $grains = [ 'day' => ['label' => __('Daily'), 'icon' => 'calendar'], 'week' => ['label' => __('Weekly'), 'icon' => 'calendar-days'], 'month' => ['label' => __('Monthly'), 'icon' => 'table-cells'], ]; $totals = $hours['totals']; $onePerson = ! $teamWide || $h_user_id; $headcount = count($hours['people']); $whose = $teamWide ? ($h_user_id ? ($members->firstWhere('id', (int) $h_user_id)?->name ?? __('One employee')) : __('Everyone')) : __('You'); // The standard day/week/month is one person's. Quoting it beside // a whole-team total would read as though three people between // them owed eight hours, so the footnote follows the scope. $glanceCards = [ ['key' => 'day', 'label' => __('Today'), 'sub' => $onePerson ? __('against a :n h day', ['n' => $standardDay]) : trans_choice('{1} :count person, :n h each|[2,*] :count people, :n h each', $headcount, ['count' => $headcount, 'n' => $standardDay])], ['key' => 'week', 'label' => __('This week'), 'sub' => $onePerson ? __('against :n h a week', ['n' => $weeklyHours]) : trans_choice('{1} :count person, :n h each|[2,*] :count people, :n h each', $headcount, ['count' => $headcount, 'n' => $weeklyHours])], ['key' => 'month', 'label' => __('This month'), 'sub' => $onePerson ? __('against ~:n h a month', ['n' => $monthlyHours]) : trans_choice('{1} :count person, ~:n h each|[2,*] :count people, ~:n h each', $headcount, ['count' => $headcount, 'n' => $monthlyHours])], ]; @endphp
{{-- At a glance: the three questions, always the same three, whatever range the breakdown below is set to. --}}
@foreach ($glanceCards as $card) @php $g = $glance[$card['key']]; $pct = (int) $g['pct']; [$bar, $text, $chip] = $tone($pct); $behind = (int) $g['gap']; @endphp

{{ $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

{{ $pct }}%

@if ($g['expected'] <= 0) {{ __('Nothing expected — non-working time.') }} @elseif ($behind > 0) {{ __(':n h short', ['n' => $hrs($behind)]) }} · {{ $card['sub'] }} @else {{ $g['surplus'] > 0 ? __(':n h over', ['n' => $hrs($g['surplus'])]) : __('On target') }} · {{ $card['sub'] }} @endif

@endforeach
{{-- The breakdown ------------------------------------------ --}}

{{ __('Planned vs clocked') }}

{{ __(':who · :from to :to', [ 'who' => $whose, 'from' => $hours['from']->format('d M Y'), 'to' => $hours['to']->format('d M Y'), ]) }}

@foreach ($grains as $key => $meta) @endforeach
{{ __('Export CSV') }}
@if ($teamWide)
@endif
{{ __('Reset') }}
{{-- Range totals, the one line a director reads first --}}
{{ __('Expected') }} {{ $hrs($totals['expected']) }}h {{ __('Clocked') }} {{ $hrs($totals['worked']) }}h {{ __('On leave') }} {{ $hrs($totals['leave']) }}h {{ __('Overtime') }} {{ $hrs($totals['overtime']) }}h {{ __('Gap') }} {{ $totals['gap'] > 0 ? '−'.$hrs($totals['gap']).'h' : __('none') }} {{ __('Days present') }} {{ $totals['days_present'] }} / {{ $totals['days_expected'] }}
@if (empty($hours['buckets']))
@else
@foreach (array_reverse($hours['buckets']) as $b) @php [$bar, $text, $chip] = $tone((int) $b['pct']); @endphp @endforeach
{{ $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
{{ $b['pct'] }}%
@endif
{{-- Per person, only when there is more than one of them ---- --}} @if (count($hours['people']) > 1)

{{ __('By employee') }}

{{ __('The same range, one row per person.') }}

@foreach ($hours['people'] as $p) @php [$bar, $text, $chip] = $tone((int) $p['pct']); @endphp @endforeach
{{ __('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
{{ $p['pct'] }}%
@endif
{{-- TODAY: THE ROSTER --}} @elseif ($tab === 'today') @php $statusMeta = [ 'in' => ['label' => __('On the clock'), 'color' => 'emerald'], 'out' => ['label' => __('Clocked out'), 'color' => 'sky'], 'absent' => ['label' => __('Not clocked in'), 'color' => 'rose'], 'leave' => ['label' => __('On leave'), 'color' => 'amber'], 'off' => ['label' => __('Non-working day'), 'color' => 'slate'], ]; @endphp

{{ $rosterIsToday ? __('Who is in today') : __('Roster for :date', ['date' => $rosterDay->format('D d M Y')]) }}

{{ $rosterDay->format('l d M Y') }} @if ($rosterIsWorkingDay) · {{ __('day starts :time', ['time' => $expectedIn]) }} @else · {{ __('non-working day') }} @endif

{{ __('Export') }} @if ($canCorrect) {{ __('Manual entry') }} @endif
{{-- Status counts --}}
@foreach (['in', 'out', 'absent', 'leave'] as $key) $key === 'in', 'bg-sky-500' => $key === 'out', 'bg-rose-500' => $key === 'absent', 'bg-amber-500' => $key === 'leave', ])> {{ $statusMeta[$key]['label'] }} {{ $rosterTotals[$key] }} @endforeach @if ($rosterTotals['late'] > 0) {{ trans_choice('{1} :count arrived late|[2,*] :count arrived late', $rosterTotals['late'], ['count' => $rosterTotals['late']]) }} @endif {{ __('Team hours logged') }} {{ round($rosterTotals['worked_minutes'] / 60, 1) }}h
@if (! $roster)
@else
@foreach ($roster as $row) @endforeach
{{ __('Employee') }} {{ __('Status') }} {{ __('In') }} {{ __('Out') }} {{ __('Hours') }} {{ __('Note') }}
{{ $row['name'] }} {{ $statusMeta[$row['status']]['label'] }} {{ $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) {{ __('Remote') }} @elseif ($row['off_network']) {{ $row['off_site'] && $row['distance_label'] ? __(':d away', ['d' => $row['distance_label']]) : __('off-site') }} @elseif ($row['distance_label']) {{ $row['distance_label'] }} @endif @if ($row['source'] === 'manual') {{ __('manual entry') }} @endif @if ($canCorrect) @endif
@endif
{{-- ATTENDANCE HISTORY --}} {{-- THE TEAM'S CLOCK RECORDS --}} @elseif ($tab === 'records')

{{ __('Attendance') }}

{{ __('Every clock record for the team.') }}

{{-- Ledger vs timesheet grid. Same segmented control as every other in-card filter strip in the app. --}} @php $historyViews = ['list' => ['label' => __('Records'), 'icon' => 'queue-list'], 'month' => ['label' => __('Month grid'), 'icon' => 'table-cells']]; @endphp
@foreach ($historyViews as $key => $meta) @endforeach
{{ __('Export CSV') }} @if ($canCorrect) {{ __('Add a day') }} @endif
{{-- Filters. The grid is a whole month at a time, so the date range and capture-method filters only belong on the ledger. --}}
@if ($f_view === 'month')
{{ $grid['month']->format('F Y') }} {{ __('This month') }}
@else
{{ __('Reset') }}
@endif
@php // One vocabulary for both halves of this tab: the grid cells // and the ledger badges must never disagree about what a // colour means. $cellTone = [ 'present' => ['bg-emerald-50 text-emerald-700 ring-emerald-200', __('Present')], 'late' => ['bg-amber-50 text-amber-700 ring-amber-200', __('Late')], 'absent' => ['bg-rose-50 text-rose-700 ring-rose-200', __('Absent')], 'leave' => ['bg-indigo-50 text-indigo-700 ring-indigo-200', __('On leave')], 'off' => ['bg-slate-50 text-slate-300 ring-slate-100', __('Non-working day')], 'none' => ['bg-white text-slate-300 ring-slate-200', __('No record')], 'future' => ['bg-white text-slate-200 ring-slate-100', __('Still to come')], ]; @endphp @if ($f_view === 'month') {{-- Legend, so a wall of coloured cells is readable --}}
@foreach (['present', 'late', 'absent', 'leave', 'off'] as $key) {{ $cellTone[$key][1] }} @endforeach {{ __('Remote day') }} @if ($canCorrect) {{ __('Click any day to edit it.') }} @endif
@if (empty($grid['rows']))
@else
@foreach ($grid['days'] as $day) @endforeach @foreach ($grid['rows'] as $row) @foreach ($row['cells'] as $cell) @php $tone = $cellTone[$cell['status']] ?? $cellTone['none']; @endphp @endforeach @endforeach
{{ __('Employee') }} {{ $day['dow'] }} {{ $day['day'] }} {{ __('Days') }} {{ __('Hours') }} {{ __('OT') }} {{ __('Late') }} {{ __('Absent') }}
{{ $row['name'] }}@if (($row['work_mode'] ?? 'office') !== 'office') {{ $row['work_mode'] === 'remote' ? __('Remote') : __('Hybrid') }}@endif {{ $row['days_worked'] }} {{ $row['hours'] }}h {{ $row['overtime'] }}h {{ $row['late'] }} {{ $row['absent'] }}
@endif @else {{-- Filtered totals --}}
{{ __('Days') }} {{ $historyTotals['days'] }} {{ __('People') }} {{ $historyTotals['people'] }} {{ __('Hours worked') }} {{ $historyTotals['workedHours'] }}h {{ __('Overtime') }} {{ $historyTotals['overtimeHours'] }}h
@if ($records->isEmpty())
@else
@foreach ($records as $r) @endforeach
{{ __('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'){{ __('open') }}@endif {{ $r->worked_hours }}h {{ $r->overtime_hours }}h @php $rulingColor = ['present' => 'emerald', 'late' => 'amber', 'absent' => 'rose'][$r->day_status] ?? 'slate'; @endphp {{ ucfirst($r->day_status) }} @if ($r->day_status_corrected_at) @endif {{ $r->source }} @if ($r->is_remote) {{ __('Remote') }} @endif @unless ($r->gatePassed()) @endunless @if ($r->gatePassed() && $r->clockInDistanceLabel()) {{ $r->clockInDistanceLabel() }} @endif @if ($canCorrect)
@endif
{{ $records->links() }}
@endif @endif
{{-- LEAVE --}} {{-- ATTENDANCE APPEALS --}} @elseif ($tab === 'appeals') @php $ruling = ['present' => 'emerald', 'late' => 'amber', 'absent' => 'rose']; @endphp

{{ __('Pending appeals') }}

{{ __('Staff asking for a late or absent day to be recorded as present.') }}

@if ($pendingAppeals->isEmpty())
@else
    @foreach ($pendingAppeals as $appeal)
  • {{ $appeal->user?->name }} · {{ $appeal->business_date->format('D d M Y') }} {{ ucfirst($appeal->from_status) }}

    @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 }}

    @if ($canCorrect)
    {{ __('Approve') }} {{ __('Reject') }}
    @endif
  • @endforeach
@endif

{{ __('Recently decided') }}

@if ($decidedAppeals->isEmpty())
{{ __('No decisions yet.') }}
@else
    @foreach ($decidedAppeals as $appeal)
  • {{ $appeal->user?->name }} · {{ $appeal->business_date->format('d M Y') }} {{ __('by :who', ['who' => $appeal->decider?->name ?? __('a director')]) }} @if ($appeal->decision_note)— {{ $appeal->decision_note }}@endif {{ ucfirst($appeal->status) }}
  • @endforeach
@endif
{{-- OVERTIME / LEAVE CASH --}} {{-- OFF-SITE CLOCK-IN --}} @elseif ($tab === 'offsite') {{-- The queue: people who tried to clock in away from the shop and applied. Approving one also clocks them in, backdated. --}} @if ($offsiteRequests->isNotEmpty())

{{ __('Waiting to be let on the clock') }} {{ $offsiteRequests->count() }}

@foreach ($offsiteRequests as $req)

{{ $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

@if ($canOverride)
{{ __('Approve & clock in') }}
@endif
@endforeach
@endif

{{ __('Off-site clock-in overrides') }}

{{ __('One employee, one day, away from the shop.') }}

@if ($canOverride) {{ __('Grant override') }} @endif
@if ($overrides->isEmpty())
@else
@foreach ($overrides as $ov) @endforeach
{{ __('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()){{ __('Declined') }} @elseif ($ov->revoked_at){{ __('Revoked') }} @else{{ __('Active') }}@endif @if ($canOverride && ! $ov->revoked_at && ! $ov->isRejected()) @endif
@endif
@endif
@if ($tab === 'me') {{-- Apply-leave modal ----------------------------------------------- --}} {{ $leave_mode === 'partial' ? __('Apply for time off') : __('Apply for leave') }}
{{-- Whole days, or a few hours of one day. Same form, and the same approval queue; only the shape of the ask differs. --}}
@foreach (['days' => __('Whole days'), 'partial' => __('A few hours')] as $key => $label) @endforeach
@if ($leave_mode === 'partial')
@else
@endif
{{ __('Cancel') }} {{ __('Submit request') }}
{{-- Appeal a late / absent day --------------------------------------- --}} {{ __('Appeal an attendance record') }} @php $appealRecord = $appeal_record_id ? $recent->firstWhere('id', $appeal_record_id) : null; @endphp
@if ($appealRecord)

{{ $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') }}

@php [$badgeColor, $badgeLabel] = $dayBadge[$appealRecord->day_status] ?? $dayBadge['present']; @endphp {{ $badgeLabel }}
@endif
{{ __('Cancel') }} {{ __('Send appeal') }} {{ __('Sending…') }}
@endif {{-- The team-facing dialogs. Drawn only for whoever can act on them, so a regular employee never ships the override and correction forms. --}} @if ($canManageHr || $canOverride || $canCorrect) {{-- Reject attendance appeal --}} {{ __('Reject attendance appeal') }} {{ __('Cancel') }} {{ __('Reject') }} {{-- Declining an off-site request. A reason is required here, unlike an appeal: the person is standing somewhere waiting to start work. --}} {{ __('Decline off-site request') }} {{ __('Cancel') }} {{ __('Decline') }} {{-- Override modal --}} {{ __('Grant clock-in override') }}
{{ __('Cancel') }} {{ __('Grant') }}
{{-- Manual correction modal --}} {{ $corr_record_id ? __('Edit attendance day') : __('Manual attendance entry') }}
{{-- Locked once a day is on file: moving a record to another person would silently overwrite THEIR day. Delete and re-key instead. --}}
@if ($corr_ruling !== 'absent')
@endif
@if ($corr_record_id) @endif
{{ __('Cancel') }} {{ __('Save') }} {{ __('Saving…') }}
@endif