Rapport-Laravel/resources/views/team2unitsreport/report.blade.php

331 lines
14 KiB
PHP

@extends('layouts.vertical-individual', ['page_title' => $title ?? 'Ciphaler / SB Units Report'])
@section('css')
<style>
body .account-pages > .container {
max-width: 100%;
padding-left: 0;
padding-right: 0;
}
.team2-units-report-page .row {
--bs-gutter-x: 0;
margin-left: 0;
margin-right: 0;
}
.team2-units-report-page .card {
border-left: 0;
border-right: 0;
border-radius: 0;
margin-bottom: 0;
}
.team2-units-report-page .card-body {
padding-left: 0;
padding-right: 0;
}
.team2-units-report-page .page-header {
padding-left: 12px;
padding-right: 12px;
}
.team2-units-report-table th,
.team2-units-report-table td {
white-space: nowrap;
vertical-align: middle;
border: 1px solid #dee2e6;
}
.team2-units-report-table thead th {
text-align: center;
background: #f8f9fa;
}
.team2-units-report-table .doctor-col {
position: sticky;
left: 0;
z-index: 2;
background: #fff;
min-width: 220px;
}
.team2-units-report-table .meta-col {
min-width: 120px;
}
.team2-units-report-table thead .doctor-col {
z-index: 3;
background: #f8f9fa;
}
.team2-units-report-scroll {
overflow-x: auto;
}
.team2-units-report-pagination {
padding: 12px 16px;
border-top: 1px solid #dee2e6;
background: #fff;
position: sticky;
bottom: 0;
z-index: 5;
}
.team2-units-report-pagination-top {
border-top: 0;
border-bottom: 1px solid #dee2e6;
}
.team2-units-report-pagination .pagination {
margin-bottom: 0;
}
#team2-units-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;
}
#team2-units-report-loader.is-visible {
display: flex;
}
#team2-units-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);
$totalDoctors = (int) ($pagination->total ?? 0);
$search = trim((string) ($search ?? ''));
$type = $type ?? 'ciphaler';
$pageQuery = http_build_query(array_filter([
'type' => $type,
'per_page' => $perPage,
'search' => $search !== '' ? $search : null,
'token' => !empty($token ?? '') ? $token : null,
], fn ($value) => $value !== null && $value !== ''));
$pageBase = $base_url . '/report?' . $pageQuery;
$metaColumnCount = 3;
@endphp
<div id="team2-units-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="team2-units-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">
Doctor units from April 2026 through the current month.
Showing {{ $typeLabel ?? strtoupper($type) }} metrics
({{ collect($metrics)->pluck('label')->implode(', ') }}).
Cells after April are colored vs the previous month:
<span class="badge bg-success">up</span>
<span class="badge bg-danger">down</span>.
</p>
@if ($totalDoctors > 0)
<p class="text-muted mb-0 small">
Showing {{ count($doctors) }} of {{ number_format($totalDoctors) }} doctors
(page {{ $currentPage }} of {{ max($totalPages, 1) }})
@if ($search !== '')
matching "{{ $search }}"
@endif
</p>
@elseif ($search !== '')
<p class="text-muted mb-0 small">No doctors 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="team2-search-form" class="d-flex align-items-center gap-2 team2-units-report-nav-form">
<input type="hidden" name="page" value="1">
<input type="hidden" name="type" value="{{ $type }}">
<input type="hidden" name="per_page" value="{{ $perPage }}">
@if (!empty($token ?? ''))
<input type="hidden" name="token" value="{{ $token }}">
@endif
<label for="team2-report-search" class="form-label mb-0 small text-muted">Search</label>
<input type="search" name="search" id="team2-report-search" class="form-control form-control-sm" style="width: 220px;" value="{{ $search }}" placeholder="Doctor, MSL, user, zone...">
<button type="submit" class="btn btn-outline-secondary btn-sm">Apply</button>
@if ($search !== '')
<a href="{{ $base_url }}/report?{{ http_build_query(array_filter(['type' => $type, 'per_page' => $perPage, 'token' => !empty($token ?? '') ? $token : null])) }}" class="btn btn-link btn-sm text-decoration-none">Clear</a>
@endif
</form>
<form method="get" action="{{ $base_url }}/report" id="team2-per-page-form" class="d-flex align-items-center gap-2 team2-units-report-nav-form">
<input type="hidden" name="page" value="1">
<input type="hidden" name="type" value="{{ $type }}">
@if (!empty($token ?? ''))
<input type="hidden" name="token" value="{{ $token }}">
@endif
@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(['type' => $type, 'search' => $search !== '' ? $search : null, 'token' => !empty($token ?? '') ? $token : null])) }}" class="btn btn-dark btn-sm">
Export All
</a>
</div>
</div>
<div class="row">
<div class="col-12">
<div class="card">
@include('team2unitsreport._pagination', ['paginationPosition' => 'team2-units-report-pagination-top'])
<div class="card-body team2-units-report-scroll">
<table class="table table-sm table-bordered team2-units-report-table mb-0">
<thead>
<tr>
<th class="doctor-col" rowspan="2">Doctor Name</th>
<th class="meta-col" rowspan="2">MSL Code</th>
<th class="meta-col" rowspan="2">User</th>
@foreach ($months as $month)
<th colspan="{{ count($metrics) }}">{{ $month->label ?? $month->key }}</th>
@endforeach
</tr>
<tr>
@foreach ($months as $month)
@foreach ($metrics as $metric)
<th>{{ $metric->label ?? $metric->id }}</th>
@endforeach
@endforeach
</tr>
</thead>
<tbody>
@forelse ($doctors as $doctor)
<tr>
<td class="doctor-col">{{ $doctor->name }}</td>
<td class="meta-col">{{ $doctor->msl_code ?? '-' }}</td>
<td class="meta-col">{{ $doctor->user ?? '-' }}</td>
@foreach ($months as $monthIndex => $month)
@php
$monthKey = $month->key ?? '';
$doctorData = $data->{$doctor->id} ?? null;
$monthData = is_object($doctorData) ? ($doctorData->{$monthKey} ?? null) : null;
$prevMonthKey = $monthIndex > 0 ? ($months[$monthIndex - 1]->key ?? '') : '';
$prevMonthData = ($prevMonthKey !== '' && is_object($doctorData))
? ($doctorData->{$prevMonthKey} ?? null)
: null;
@endphp
@foreach ($metrics as $metric)
@php
$metricId = $metric->id ?? '';
$value = is_object($monthData) ? ($monthData->{$metricId} ?? null) : null;
$cellClass = 'text-center';
if ($monthIndex > 0 && $value !== null && $value !== '' && is_numeric($value)) {
$prevValue = is_object($prevMonthData) ? ($prevMonthData->{$metricId} ?? null) : null;
if ($prevValue !== null && $prevValue !== '' && is_numeric($prevValue)) {
$currentNum = (float) $value;
$prevNum = (float) $prevValue;
if ($currentNum > $prevNum) {
$cellClass .= ' table-success';
} elseif ($currentNum < $prevNum) {
$cellClass .= ' table-danger';
}
}
}
@endphp
<td class="{{ $cellClass }}">{{ $value !== null && $value !== '' ? $value : '-' }}</td>
@endforeach
@endforeach
</tr>
@empty
<tr>
<td colspan="{{ $metaColumnCount + (count($months) * max(count($metrics), 1)) }}" class="text-center text-muted">
@if ($search !== '')
No doctors found matching "{{ $search }}".
@else
No doctor data found.
@endif
</td>
</tr>
@endforelse
</tbody>
</table>
</div>
@include('team2unitsreport._pagination')
</div>
</div>
</div>
</div>
@endsection
@section('script-bottom')
<script>
(function () {
var loader = document.getElementById('team2-units-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('.team2-units-report-pagination a.page-link[href]:not([href="#"])');
if (link) {
showLoader();
}
});
var searchForm = document.getElementById('team2-search-form');
if (searchForm) {
searchForm.addEventListener('submit', function () {
showLoader();
});
}
var perPageForm = document.getElementById('team2-per-page-form');
if (perPageForm) {
perPageForm.addEventListener('change', function (event) {
if (event.target && event.target.name === 'per_page') {
showLoader();
}
});
}
})();
</script>
@endsection