@php $tz = config('app.display_timezone'); $today = now($tz)->startOfDay(); $watchDays = \App\Services\Crm\Health\AccountHealth::CONTACT_WATCH_DAYS; $parts = \App\Services\Crm\Health\AccountHealth::PARTS; $initials = function (string $name): string { $words = array_values(array_filter(preg_split('/\s+/', trim($name)) ?: [])); $letters = ''; foreach (array_slice($words, 0, 2) as $word) { $letters .= mb_strtoupper(mb_substr($word, 0, 1)); } return $letters !== '' ? $letters : '?'; }; $chips = ['bg-sky-100 text-sky-700', 'bg-violet-100 text-violet-700', 'bg-amber-100 text-amber-800', 'bg-emerald-100 text-emerald-700', 'bg-rose-100 text-rose-700', 'bg-indigo-100 text-indigo-700']; $chip = fn (string $name): string => $chips[abs(crc32($name)) % count($chips)]; $cards = [ 'at_risk' => ['label' => __('At risk'), 'icon' => 'exclamation-triangle', 'hint' => __('Needs intervention'), 'wrap' => 'bg-rose-50 text-rose-600', 'border' => 'border-rose-300'], 'watch' => ['label' => __('Watch'), 'icon' => 'eye', 'hint' => __('Monitor closely'), 'wrap' => 'bg-amber-50 text-amber-600', 'border' => 'border-amber-300'], 'healthy' => ['label' => __('Healthy'), 'icon' => 'heart', 'hint' => __('Signals are positive'), 'wrap' => 'bg-emerald-50 text-emerald-600', 'border' => 'border-emerald-300'], 'unknown' => ['label' => __('Insufficient history'), 'icon' => 'server-stack', 'hint' => __('More data needed'), 'wrap' => 'bg-slate-100 text-slate-500', 'border' => 'border-slate-300'], ]; $pills = [ '' => __('All accounts'), 'at_risk' => __('At risk'), 'watch' => __('Watch'), 'healthy' => __('Healthy'), 'unknown' => __('Insufficient history'), ]; $contactOf = function ($account) use ($tz, $today, $watchDays): array { if (! $account->last_activity_at) { return ['tone' => 'bg-amber-400', 'label' => __('No contact logged'), 'date' => null]; } $when = \Illuminate\Support\Carbon::parse($account->last_activity_at)->timezone($tz); $days = (int) $today->diffInDays($when->copy()->startOfDay(), true); $label = match (true) { $days === 0 => __('Today'), $days === 1 => __('Yesterday'), default => trans_choice('{1}:count day ago|[2,*]:count days ago', $days, ['count' => number_format($days)]), }; return [ 'tone' => $days > $watchDays ? 'bg-amber-400' : 'bg-emerald-500', 'label' => $label, 'date' => $days > 1 ? $when->format('j M Y') : null, ]; }; @endphp
@if ($lastChecked) {{ __('Checked :when', ['when' => \Illuminate\Support\Carbon::parse($lastChecked, 'UTC')->timezone($tz)->format('j M Y, H:i')]) }} {{ __('Updated daily') }} @else {{ __('Not checked yet') }} @endif {{ __('How health works') }} @if ($canRefresh) {{ __('Refresh checks') }} {{ __('Checking…') }} @endif
@foreach ($cards as $key => $m) @endforeach
@if ($counts['unknown'] > 0)

{{ trans_choice('{1}:count account needs more history|[2,*]:count accounts need more history', $counts['unknown'], ['count' => number_format($counts['unknown'])]) }}

{{ __('At least two measurable signals are needed before a health label is assigned.') }}

@endif

{{ __('Accounts') }}

{{ trans_choice('{0}:count organisations|{1}:count organisation|[2,*]:count organisations', $total, ['count' => number_format($total)]) }}

@if ($seesTeam)
@foreach (['mine' => __('My accounts'), 'team' => __('Whole team')] as $key => $text) @endforeach
@endif
@if ($seesTeam && $scope === 'team') @endif
@foreach ($pills as $key => $text) @php $count = $key === '' ? $total : $counts[$key]; @endphp @endforeach
@forelse ($accounts as $account) @php $contact = $contactOf($account); $why = collect($account->health_signals ?? [])->reject(fn ($s) => ($s['status'] ?? '') === 'unknown')->pluck('label')->filter()->values(); $missing = $contact['label'] === __('No contact logged'); @endphp @empty
@endforelse

@if ($accounts->total() === 0) {{ __('Showing 0 accounts') }} @else {{ __('Showing :from–:to of :total', ['from' => number_format($accounts->firstItem()), 'to' => number_format($accounts->lastItem()), 'total' => number_format($accounts->total())]) }} @endif

{{ __('Contact missing') }} {{ __('Contact recorded') }}

@if ($accounts->hasPages())
{{ $accounts->links() }}
@endif

{{ __('Build a clearer picture') }}

@if ($noContact > 0)

{{ trans_choice('{1}:count account has no logged contact|[2,*]:count accounts have no logged contact', $noContact, ['count' => number_format($noContact)]) }}

{{ __('Recent contact helps us identify changes in activity early.') }}

@if ($canLog) @endif
@endif @if ($counts['unknown'] > 0)

{{ trans_choice('{1}:count account needs more measurable history|[2,*]:count accounts need more measurable history', $counts['unknown'], ['count' => number_format($counts['unknown'])]) }}

{{ __('At least two measurable signals are needed before a health label is assigned.') }}

@endif @if ($noContact === 0 && $counts['unknown'] === 0)

{{ __('Every account in this view has a contact on file and enough history for a label.') }}

@endif

{{ __('Health signals') }}

@foreach ($parts as $part)
{{ __($part['label']) }}
@endforeach

{{ __('Each signal includes a reason. Missing data is left out.') }}

{{ __('How the label is decided') }}
    @foreach (\App\Services\Crm\Health\AccountHealth::RULES as $rule)
  • {{ __($rule) }}
  • @endforeach

{{ __('Ordering is late past their usual gap and at risk past 1.5 times it. Paying is at risk with anything overdue by more than :days days. Feedback is at risk at 2.5 out of 5 or less. Spend is at risk when down by half on the year before. Contact alone never makes an account at risk. A part with nothing to go on is left out.', ['days' => \App\Services\Crm\Health\AccountHealth::LONG_OVERDUE_DAYS]) }}

@if ($rulesTick > 0)
@endif
@if ($canLog) @endif