397 lines
18 KiB
PHP
397 lines
18 KiB
PHP
@extends('layouts.vertical-individual', ['page_title' => $title ?? 'Adherence Pack Ratio Report'])
|
|
|
|
@section('css')
|
|
<style>
|
|
body .account-pages > .container {
|
|
max-width: 100%;
|
|
padding-left: 0;
|
|
padding-right: 0;
|
|
}
|
|
|
|
.adherence-pack-ratio-report-page .row {
|
|
--bs-gutter-x: 0;
|
|
margin-left: 0;
|
|
margin-right: 0;
|
|
}
|
|
|
|
.adherence-pack-ratio-report-page .card {
|
|
border-left: 0;
|
|
border-right: 0;
|
|
border-radius: 0;
|
|
margin-bottom: 0;
|
|
}
|
|
|
|
.adherence-pack-ratio-report-page .card-body {
|
|
padding-left: 0;
|
|
padding-right: 0;
|
|
}
|
|
|
|
.adherence-pack-ratio-report-page .page-header {
|
|
padding-left: 12px;
|
|
padding-right: 12px;
|
|
}
|
|
|
|
.adherence-pack-ratio-report-table th,
|
|
.adherence-pack-ratio-report-table td {
|
|
white-space: nowrap;
|
|
vertical-align: middle;
|
|
border: 1px solid #dee2e6;
|
|
}
|
|
|
|
.adherence-pack-ratio-report-table thead th {
|
|
text-align: center;
|
|
background: #f8f9fa;
|
|
}
|
|
|
|
.adherence-pack-ratio-report-table td.ratio-up {
|
|
background-color: #d4edda;
|
|
color: #155724;
|
|
font-weight: 600;
|
|
}
|
|
|
|
.adherence-pack-ratio-report-table td.ratio-down {
|
|
background-color: #f8d7da;
|
|
color: #721c24;
|
|
font-weight: 600;
|
|
}
|
|
|
|
.adherence-pack-ratio-report-scroll {
|
|
overflow-x: auto;
|
|
container-type: inline-size;
|
|
}
|
|
|
|
.adherence-pack-ratio-report-table .tm-col {
|
|
position: sticky;
|
|
left: 0;
|
|
z-index: 2;
|
|
background: #fff;
|
|
min-width: 120px;
|
|
max-width: min(50cqw, 50vw);
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
}
|
|
|
|
.adherence-pack-ratio-report-table .meta-col {
|
|
min-width: 120px;
|
|
}
|
|
|
|
.adherence-pack-ratio-report-table thead .tm-col {
|
|
z-index: 3;
|
|
background: #f8f9fa;
|
|
}
|
|
|
|
.adherence-pack-ratio-report-pagination {
|
|
padding: 12px 16px;
|
|
border-top: 1px solid #dee2e6;
|
|
background: #fff;
|
|
position: sticky;
|
|
bottom: 0;
|
|
z-index: 5;
|
|
}
|
|
|
|
.adherence-pack-ratio-report-pagination-top {
|
|
border-top: 0;
|
|
border-bottom: 1px solid #dee2e6;
|
|
}
|
|
|
|
.adherence-pack-ratio-report-pagination .pagination {
|
|
margin-bottom: 0;
|
|
}
|
|
|
|
#adherence-pack-ratio-report-loader {
|
|
align-items: center;
|
|
background: rgba(255, 255, 255, 0.85);
|
|
display: none;
|
|
flex-direction: column;
|
|
gap: 12px;
|
|
height: 100%;
|
|
justify-content: center;
|
|
left: 0;
|
|
position: fixed;
|
|
top: 0;
|
|
width: 100%;
|
|
z-index: 9999;
|
|
}
|
|
|
|
#adherence-pack-ratio-report-loader.is-visible {
|
|
display: flex;
|
|
}
|
|
|
|
#adherence-pack-ratio-report-loader img {
|
|
height: 64px;
|
|
width: 64px;
|
|
}
|
|
</style>
|
|
@endsection
|
|
|
|
@section('content')
|
|
@php
|
|
$pagination = $pagination ?? (object) ['page' => 1, 'per_page' => 50, 'total' => 0, 'total_pages' => 0];
|
|
$currentPage = (int) ($pagination->page ?? 1);
|
|
$totalPages = (int) ($pagination->total_pages ?? 0);
|
|
$perPage = (int) ($perPage ?? $pagination->per_page ?? 50);
|
|
$totalTms = (int) ($pagination->total ?? 0);
|
|
$search = trim((string) ($search ?? ''));
|
|
$type = $type ?? 'dpi';
|
|
$quartersOnly = !empty($quartersOnly);
|
|
$quarters = $quarters ?? [];
|
|
$quarter_data = $quarter_data ?? (object) [];
|
|
$months = $months ?? [];
|
|
$metrics = $metrics ?? [];
|
|
$quartersAfterMonth = [];
|
|
if (!$quartersOnly) {
|
|
foreach ($quarters as $quarter) {
|
|
$afterMonth = $quarter->after_month ?? null;
|
|
if ($afterMonth) {
|
|
$quartersAfterMonth[$afterMonth][] = $quarter;
|
|
}
|
|
}
|
|
}
|
|
$pageQuery = http_build_query(array_filter([
|
|
'token' => $token,
|
|
'type' => $type,
|
|
'per_page' => $perPage,
|
|
'search' => $search,
|
|
]));
|
|
$pageBase = $base_url . '/report?' . $pageQuery;
|
|
$metaColumnCount = 1;
|
|
@endphp
|
|
<div id="adherence-pack-ratio-report-loader" class="is-visible" aria-live="polite" aria-busy="true">
|
|
<img src="/images/loader-large.gif" alt="">
|
|
<span class="text-muted">Loading report...</span>
|
|
</div>
|
|
<div class="adherence-pack-ratio-report-page">
|
|
<div class="row mb-3 page-header">
|
|
<div class="col-md-6">
|
|
<h4 class="page-title">{{ $title }}</h4>
|
|
<p class="text-muted mb-0">
|
|
Foracort Campaign adherence pack ratio from April 2026 through the current month.
|
|
@if ($quartersOnly)
|
|
Showing quarterly ratio columns only (Q1 %, Q2 %, …).
|
|
Green = equal/increasing vs previous quarter; Red = decreasing.
|
|
@else
|
|
Showing {{ $typeLabel ?? strtoupper($type) }} metrics
|
|
({{ collect($metrics)->pluck('label')->implode(', ') }}), plus quarterly ratio columns.
|
|
@endif
|
|
</p>
|
|
@if ($totalTms > 0)
|
|
<p class="text-muted mb-0 small">
|
|
Showing {{ count($tms) }} of {{ number_format($totalTms) }} TMs
|
|
(page {{ $currentPage }} of {{ max($totalPages, 1) }})
|
|
@if ($search !== '')
|
|
matching "{{ $search }}"
|
|
@endif
|
|
</p>
|
|
@elseif ($search !== '')
|
|
<p class="text-muted mb-0 small">No TMs found matching "{{ $search }}".</p>
|
|
@endif
|
|
</div>
|
|
<div class="col-md-6 d-flex justify-content-end align-items-center gap-2 flex-wrap">
|
|
<form method="get" action="{{ $base_url }}/report" id="adherence-search-form" class="d-flex align-items-center gap-2 adherence-pack-ratio-report-nav-form">
|
|
<input type="hidden" name="token" value="{{ $token }}">
|
|
<input type="hidden" name="type" value="{{ $type }}">
|
|
<input type="hidden" name="page" value="1">
|
|
<input type="hidden" name="per_page" value="{{ $perPage }}">
|
|
<label for="adherence-report-search" class="form-label mb-0 small text-muted">Search</label>
|
|
<input type="search" name="search" id="adherence-report-search" class="form-control form-control-sm" style="width: 220px;" value="{{ $search }}" placeholder="TM name, employee code, zone...">
|
|
<button type="submit" class="btn btn-outline-secondary btn-sm">Apply</button>
|
|
@if ($search !== '')
|
|
<a href="{{ $base_url }}/report?{{ http_build_query(['token' => $token, 'type' => $type, 'per_page' => $perPage]) }}" class="btn btn-link btn-sm text-decoration-none">Clear</a>
|
|
@endif
|
|
</form>
|
|
<form method="get" action="{{ $base_url }}/report" id="adherence-per-page-form" class="d-flex align-items-center gap-2 adherence-pack-ratio-report-nav-form">
|
|
<input type="hidden" name="token" value="{{ $token }}">
|
|
<input type="hidden" name="type" value="{{ $type }}">
|
|
<input type="hidden" name="page" value="1">
|
|
@if ($search !== '')
|
|
<input type="hidden" name="search" value="{{ $search }}">
|
|
@endif
|
|
<label for="per_page" class="form-label mb-0 small text-muted">Per page</label>
|
|
<select name="per_page" id="per_page" class="form-select form-select-sm" style="width: auto;" onchange="this.form.submit()">
|
|
@foreach ([25, 50, 100, 200] as $size)
|
|
<option value="{{ $size }}"@if($perPage === $size) selected @endif>{{ $size }}</option>
|
|
@endforeach
|
|
</select>
|
|
</form>
|
|
<a href="{{ $base_url }}/export?{{ http_build_query(array_filter(['token' => $token, 'type' => $type, 'search' => $search])) }}" class="btn btn-dark btn-sm">
|
|
Export All
|
|
</a>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row">
|
|
<div class="col-12">
|
|
<div class="card">
|
|
@include('adherencepackratioreport._pagination', ['paginationPosition' => 'adherence-pack-ratio-report-pagination-top'])
|
|
<div class="card-body adherence-pack-ratio-report-scroll">
|
|
<table class="table table-sm table-bordered adherence-pack-ratio-report-table mb-0">
|
|
<thead>
|
|
@if ($quartersOnly)
|
|
<tr>
|
|
<th class="tm-col">TM Name</th>
|
|
@foreach ($quarters as $quarter)
|
|
<th>Q{{ $quarter->q ?? preg_replace('/\D+/', '', $quarter->label ?? $quarter->key ?? '') }} %</th>
|
|
@endforeach
|
|
</tr>
|
|
@else
|
|
<tr>
|
|
<th class="tm-col" rowspan="2">TM Name</th>
|
|
@foreach ($months as $month)
|
|
<th colspan="{{ count($metrics) }}">{{ $month->label ?? $month->key }}</th>
|
|
@foreach ($quartersAfterMonth[$month->key ?? ''] ?? [] as $quarter)
|
|
<th rowspan="2">{{ preg_match('/%\s*$/', (string) ($quarter->label ?? '')) ? ($quarter->label ?? $quarter->key) : trim(($quarter->label ?? $quarter->key) . ' %') }}</th>
|
|
@endforeach
|
|
@endforeach
|
|
</tr>
|
|
<tr>
|
|
@foreach ($months as $month)
|
|
@foreach ($metrics as $metric)
|
|
<th>{{ $metric->label ?? $metric->id }}</th>
|
|
@endforeach
|
|
@endforeach
|
|
</tr>
|
|
@endif
|
|
</thead>
|
|
<tbody>
|
|
@forelse ($tms as $tm)
|
|
@php
|
|
$tmQuarterData = is_object($quarter_data) ? ($quarter_data->{$tm->id} ?? null) : null;
|
|
$parseRatio = function ($value) {
|
|
// Missing/blank values count as 0 for highlight comparisons only.
|
|
if ($value === null || $value === '' || $value === '-') {
|
|
return 0.0;
|
|
}
|
|
if (is_numeric($value)) {
|
|
return (float) $value;
|
|
}
|
|
$normalized = preg_replace('/[^0-9.\-]/', '', (string) $value);
|
|
return $normalized === '' || !is_numeric($normalized) ? 0.0 : (float) $normalized;
|
|
};
|
|
$prevQuarterRatio = null;
|
|
$hasPrevQuarter = false;
|
|
@endphp
|
|
<tr>
|
|
<td class="tm-col">{{ $tm->name ?? $tm->id }}</td>
|
|
@if ($quartersOnly)
|
|
@foreach ($quarters as $quarter)
|
|
@php
|
|
$quarterKey = $quarter->key ?? '';
|
|
$qValue = is_object($tmQuarterData) ? ($tmQuarterData->{$quarterKey} ?? null) : null;
|
|
$currentRatio = $parseRatio($qValue);
|
|
$ratioClass = '';
|
|
if ($hasPrevQuarter) {
|
|
$ratioClass = $currentRatio >= $prevQuarterRatio ? 'ratio-up' : 'ratio-down';
|
|
}
|
|
$prevQuarterRatio = $currentRatio;
|
|
$hasPrevQuarter = true;
|
|
@endphp
|
|
<td class="text-center {{ $ratioClass }}">{{ $qValue !== null && $qValue !== '' ? $qValue : '-' }}</td>
|
|
@endforeach
|
|
@else
|
|
@foreach ($months as $month)
|
|
@php
|
|
$monthKey = $month->key ?? '';
|
|
$tmData = $data->{$tm->id} ?? null;
|
|
$monthData = is_object($tmData) ? ($tmData->{$monthKey} ?? null) : null;
|
|
@endphp
|
|
@foreach ($metrics as $metric)
|
|
@php
|
|
$metricId = $metric->id ?? '';
|
|
$value = is_object($monthData) ? ($monthData->{$metricId} ?? null) : null;
|
|
@endphp
|
|
<td class="text-center">{{ $value !== null && $value !== '' ? $value : '-' }}</td>
|
|
@endforeach
|
|
@foreach ($quartersAfterMonth[$monthKey] ?? [] as $quarter)
|
|
@php
|
|
$quarterKey = $quarter->key ?? '';
|
|
$qValue = is_object($tmQuarterData) ? ($tmQuarterData->{$quarterKey} ?? null) : null;
|
|
$currentRatio = $parseRatio($qValue);
|
|
$ratioClass = '';
|
|
if ($hasPrevQuarter) {
|
|
$ratioClass = $currentRatio >= $prevQuarterRatio ? 'ratio-up' : 'ratio-down';
|
|
}
|
|
$prevQuarterRatio = $currentRatio;
|
|
$hasPrevQuarter = true;
|
|
@endphp
|
|
<td class="text-center {{ $ratioClass }}">{{ $qValue !== null && $qValue !== '' ? $qValue : '-' }}</td>
|
|
@endforeach
|
|
@endforeach
|
|
@endif
|
|
</tr>
|
|
@empty
|
|
<tr>
|
|
<td colspan="{{ $metaColumnCount + ($quartersOnly ? count($quarters) : (count($months) * max(count($metrics), 1) + count($quarters))) }}" class="text-center text-muted">
|
|
@if ($search !== '')
|
|
No TMs found matching "{{ $search }}".
|
|
@else
|
|
No TM data found.
|
|
@endif
|
|
</td>
|
|
</tr>
|
|
@endforelse
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
@include('adherencepackratioreport._pagination')
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
@endsection
|
|
|
|
@section('script-bottom')
|
|
<script>
|
|
(function () {
|
|
var loader = document.getElementById('adherence-pack-ratio-report-loader');
|
|
if (!loader) {
|
|
return;
|
|
}
|
|
|
|
function hideLoader() {
|
|
loader.classList.remove('is-visible');
|
|
loader.setAttribute('aria-busy', 'false');
|
|
}
|
|
|
|
function showLoader() {
|
|
loader.classList.add('is-visible');
|
|
loader.setAttribute('aria-busy', 'true');
|
|
}
|
|
|
|
if (document.readyState === 'loading') {
|
|
document.addEventListener('DOMContentLoaded', hideLoader, { once: true });
|
|
} else {
|
|
hideLoader();
|
|
}
|
|
|
|
window.addEventListener('pageshow', function (event) {
|
|
if (event.persisted) {
|
|
hideLoader();
|
|
}
|
|
});
|
|
|
|
document.addEventListener('click', function (event) {
|
|
var link = event.target.closest('.adherence-pack-ratio-report-pagination a.page-link[href]:not([href="#"])');
|
|
if (link) {
|
|
showLoader();
|
|
}
|
|
});
|
|
|
|
var searchForm = document.getElementById('adherence-search-form');
|
|
if (searchForm) {
|
|
searchForm.addEventListener('submit', function () {
|
|
showLoader();
|
|
});
|
|
}
|
|
|
|
var perPageForm = document.getElementById('adherence-per-page-form');
|
|
if (perPageForm) {
|
|
perPageForm.addEventListener('change', function (event) {
|
|
if (event.target && event.target.name === 'per_page') {
|
|
showLoader();
|
|
}
|
|
});
|
|
}
|
|
})();
|
|
</script>
|
|
@endsection
|