Files
Kent-logistics-Laravel/resources/views/admin/reports.blade.php
2026-03-17 19:14:47 +05:30

1044 lines
49 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

@php
/** @var bool $isPdf */
$isPdf = $isPdf ?? false;
@endphp
@if($isPdf)
{{-- ========== PDF MODE (mpdf साठी) ========== --}}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title></title>
<style>
@page {
margin: 10mm 8mm 10mm 8mm;
header: none;
footer: none;
}
:root { --admin-font: "Inter", sans-serif; }
html, body {
margin: 0;
padding: 0;
font-family: var(--admin-font);
font-size: 12px;
}
body, input, select, textarea, button, table, th, td {
font-family: var(--admin-font);
}
.report-container {
background: #ffffff;
padding: 16px 18px;
border-radius: 10px;
border: 1px solid #e5e7eb;
}
.report-header {
display: flex;
align-items: center;
gap: 12px;
margin-bottom: 10px;
padding-bottom: 10px;
border-bottom: 1px solid #e5e7eb;
}
.header-logo { height: 45px; width: auto; }
.report-title { font-size: 18px; font-weight: 700; color: #1a202c; margin: 0; line-height: 1.2; }
.report-company { font-size: 11px; color: #718096; font-weight: 500; margin-top: 2px; }
.stats-container {
margin: 10px 0 8px 0;
}
.stats-table {
width: 100%;
border-collapse: separate;
border-spacing: 5px;
}
.stats-table > tbody > tr > td {
width: 33.33%;
padding: 0;
border: none;
background: transparent;
vertical-align: top;
}
.stat-card-wrap {
border-radius: 10px;
overflow: hidden;
}
.stat-inner {
width: 100%;
border-collapse: collapse;
}
.stat-strip {
width: 5px;
padding: 0;
}
.stat-content {
padding: 8px 10px;
vertical-align: middle;
}
.strip-info { background: #3b82f6; }
.strip-purple { background: #8b5cf6; }
.strip-default { background: #4f46e5; }
.strip-success { background: #10b981; }
.strip-danger { background: #ef4444; }
.strip-warning { background: #f59e0b; }
.bg-info { background: linear-gradient(135deg, #eff6ff 0%, #dbeafe 100%); }
.bg-purple { background: linear-gradient(135deg, #faf5ff 0%, #f3e8ff 100%); }
.bg-default { background: linear-gradient(135deg, #f8f9ff 0%, #f0f4ff 100%); }
.bg-success { background: linear-gradient(135deg, #ecfdf5 0%, #d1fae5 100%); }
.bg-danger { background: linear-gradient(135deg, #fef2f2 0%, #fee2e2 100%); }
.bg-warning { background: linear-gradient(135deg, #fffbeb 0%, #fef3c7 100%); }
.stat-icon-box {
display: inline-block;
width: 30px;
height: 30px;
border-radius: 7px;
text-align: center;
line-height: 30px;
margin-right: 8px;
vertical-align: middle;
font-size: 13px;
}
.icon-info { background: rgba(59,130,246,0.12); color: #3b82f6; }
.icon-purple { background: rgba(139,92,246,0.12); color: #8b5cf6; }
.icon-default { background: rgba(79,70,229,0.12); color: #4f46e5; }
.icon-success { background: rgba(16,185,129,0.12); color: #10b981; }
.icon-danger { background: rgba(239,68,68,0.12); color: #ef4444; }
.icon-warning { background: rgba(245,158,11,0.12); color: #f59e0b; }
.stat-text { display: inline-block; vertical-align: middle; }
.stat-value { font-size: 15px; font-weight: 700; color: #1a202c; line-height: 1.2; display: block; }
.stat-label { font-size: 9px; color: #718096; font-weight: 600; display: block; margin-top: 2px; }
.table-container {
margin-top: 6px;
}
.report-table {
width: 100%;
border-collapse: collapse;
font-size: 10px;
}
.report-table thead {
background: #ffffff;
}
.report-table th {
padding: 6px 4px;
text-align: center;
font-size: 9px;
font-weight: 600;
border: 0.5px solid #e5e7eb;
white-space: nowrap;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: #ffffff !important;
}
.report-table td {
padding: 5px 4px;
font-size: 9px;
color: #374151;
border: 0.5px solid #e5e7eb;
text-align: center;
white-space: nowrap;
}
.amt-cell { font-weight: 600; }
.amt-payable { color: #1e40af; }
.amt-paid { color: #059669; }
.amt-remaining{ color: #dc2626; }
.amt-gst { color: #d97706; }
.amt-base { color: #374151; }
.count-badge {
display: inline-block;
background: #eff6ff;
color: #1d4ed8;
font-weight: 700;
font-size: 9px;
padding: 1px 6px;
border-radius: 12px;
border: 0.5px solid #bfdbfe;
}
.status-badge {
display: inline-block;
font-size: 8px;
font-weight: 700;
padding: 3px 6px;
border-radius: 10px;
text-transform: uppercase;
letter-spacing: 0.3px;
}
.status-paid { background: #dcfce7; color: #166534; border: 0.5px solid #bbf7d0; }
.status-pending { background: #fef3c7; color: #92400e; border: 0.5px solid #fde68a; }
.status-overdue { background: #fee2e2; color: #991b1b; border: 0.5px solid #fecaca; }
.status-paying { background: #dbeafe; color: #1e40af; border: 0.5px solid #bfdbfe; }
.empty-state { text-align: center; padding: 20px 10px; color: #6b7280; }
.empty-state h3 { margin: 0 0 4px 0; font-size: 12px; }
.empty-state p { margin: 0; font-size: 10px; }
</style>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css">
</head>
<body>
<div class="report-container">
{{-- HEADER --}}
<div class="report-header">
<img src="{{ public_path('images/kent_logo2.png') }}" class="header-logo" alt="Logo">
<div>
<div class="report-title">KENT International Pvt. Ltd.</div>
<div class="report-company">Container Report</div>
</div>
</div>
{{-- STATS CARDS --}}
@php
$totalContainers = $reports->count();
$totalInvoices = $reports->sum('total_invoices');
$totalPayable = $reports->sum('total_payable');
$totalPaid = $reports->sum('total_paid');
$totalRemaining = $reports->sum('total_remaining');
$overdueCount = $reports->where('container_status','overdue')->count();
@endphp
<div class="stats-container">
<table class="stats-table">
{{-- Row 1 --}}
<tr>
{{-- Total Containers --}}
<td>
<div class="stat-card-wrap">
<table class="stat-inner">
<tr>
<td class="stat-strip strip-info">&nbsp;</td>
<td class="stat-content bg-info">
<span class="stat-icon-box icon-info">
<i class="fas fa-box"></i>
</span>
<span class="stat-text">
<span class="stat-value">{{ $totalContainers }}</span>
<span class="stat-label">Total Containers</span>
</span>
</td>
</tr>
</table>
</div>
</td>
{{-- Total Invoices --}}
<td>
<div class="stat-card-wrap">
<table class="stat-inner">
<tr>
<td class="stat-strip strip-purple">&nbsp;</td>
<td class="stat-content bg-purple">
<span class="stat-icon-box icon-purple">
<i class="fas fa-file-invoice"></i>
</span>
<span class="stat-text">
<span class="stat-value">{{ $totalInvoices }}</span>
<span class="stat-label">Total Invoices</span>
</span>
</td>
</tr>
</table>
</div>
</td>
{{-- Total Payable --}}
<td>
<div class="stat-card-wrap">
<table class="stat-inner">
<tr>
<td class="stat-strip strip-default">&nbsp;</td>
<td class="stat-content bg-default">
<span class="stat-icon-box icon-default">
<i class="fas fa-rupee-sign"></i>
</span>
<span class="stat-text">
<span class="stat-value">{{ number_format($totalPayable, 0) }}</span>
<span class="stat-label">Total Payable</span>
</span>
</td>
</tr>
</table>
</div>
</td>
</tr>
{{-- Row 2 --}}
<tr>
{{-- Total Paid --}}
<td>
<div class="stat-card-wrap">
<table class="stat-inner">
<tr>
<td class="stat-strip strip-success">&nbsp;</td>
<td class="stat-content bg-success">
<span class="stat-icon-box icon-success">
<i class="fas fa-check-circle"></i>
</span>
<span class="stat-text">
<span class="stat-value">{{ number_format($totalPaid, 0) }}</span>
<span class="stat-label">Total Paid</span>
</span>
</td>
</tr>
</table>
</div>
</td>
{{-- Total Remaining --}}
<td>
<div class="stat-card-wrap">
<table class="stat-inner">
<tr>
<td class="stat-strip strip-danger">&nbsp;</td>
<td class="stat-content bg-danger">
<span class="stat-icon-box icon-danger">
<i class="fas fa-hourglass-half"></i>
</span>
<span class="stat-text">
<span class="stat-value">{{ number_format($totalRemaining, 0) }}</span>
<span class="stat-label">Total Remaining</span>
</span>
</td>
</tr>
</table>
</div>
</td>
{{-- Overdue Containers --}}
<td>
<div class="stat-card-wrap">
<table class="stat-inner">
<tr>
<td class="stat-strip strip-warning">&nbsp;</td>
<td class="stat-content bg-warning">
<span class="stat-icon-box icon-warning">
<i class="fas fa-exclamation-triangle"></i>
</span>
<span class="stat-text">
<span class="stat-value">{{ $overdueCount }}</span>
<span class="stat-label">Overdue Containers</span>
</span>
</td>
</tr>
</table>
</div>
</td>
</tr>
</table>
</div>
{{-- TABLE --}}
<div class="table-container">
<table class="report-table">
<thead>
<tr>
<th>Sr.</th>
<th>Container No</th>
<th>Container Date</th>
<th>Total Mark Nos</th>
<th>Total Customers</th>
<th>Total Invoices</th>
<th>Invoice Amount<br>(Before GST)</th>
<th>GST Amount</th>
<th>Payable Amount<br>(Incl. GST)</th>
<th>Paid Amount</th>
<th>Remaining Amount</th>
<th>Container Status</th>
</tr>
</thead>
<tbody>
@forelse($reports as $i => $r)
@php $cs = strtolower($r->container_status); @endphp
<tr>
<td style="color:#9ca3af;font-weight:600;">{{ $i + 1 }}</td>
<td style="font-weight:700;color:#1e40af;">{{ $r->container_number }}</td>
<td>
{{ $r->container_date ? \Carbon\Carbon::parse($r->container_date)->format('d-m-Y') : '-' }}
</td>
<td><span class="count-badge">{{ $r->total_mark_nos }}</span></td>
<td><span class="count-badge">{{ $r->total_customers }}</span></td>
<td>
<span class="count-badge" style="background:#f3e8ff;color:#6d28d9;border-color:#ddd6fe;">
{{ $r->total_invoices }}
</span>
</td>
<td class="amt-cell amt-base">{{ number_format($r->total_invoice_amount, 2) }}</td>
<td class="amt-cell amt-gst">{{ number_format($r->total_gst_amount, 2) }}</td>
<td class="amt-cell amt-payable">{{ number_format($r->total_payable, 2) }}</td>
<td class="amt-cell amt-paid">{{ number_format($r->total_paid, 2) }}</td>
<td class="amt-cell amt-remaining">{{ number_format($r->total_remaining, 2) }}</td>
<td>
<span class="status-badge
@if($cs === 'paid') status-paid
@elseif($cs === 'overdue') status-overdue
@elseif($cs === 'paying') status-paying
@else status-pending
@endif">
{{ ucfirst($cs) }}
</span>
</td>
</tr>
@empty
<tr>
<td colspan="12">
<div class="empty-state">
<h3>No Container Reports Found</h3>
<p>No containers with invoices found.</p>
</div>
</td>
</tr>
@endforelse
</tbody>
</table>
</div>
</div>
</body>
</html>
@else
{{-- ========== NORMAL UI MODE (Browser साठी) ========== --}}
@extends('admin.layouts.app')
@section('page-title', 'Container Report')
@section('content')
<style>
:root { --admin-font: "Inter", sans-serif; }
html, body { overflow-x: hidden !important; }
body, input, select, textarea, button, table, th, td {
font-family: var(--admin-font);
}
.report-container {
background: #ffffff;
padding: 25px;
border-radius: 16px;
box-shadow: 0 8px 32px rgba(0,0,0,0.08);
margin: 20px auto;
max-width: 100%;
border: 1px solid #f0f0f0;
}
.report-header {
display: flex;
align-items: center;
gap: 18px;
margin-bottom: 20px;
padding-bottom: 20px;
border-bottom: 2px solid #f8f9fa;
}
.header-icon {
width: 55px; height: 55px;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
border-radius: 14px;
display: flex; align-items: center; justify-content: center;
box-shadow: 0 6px 20px rgba(102,126,234,0.3);
}
.header-icon i { font-size: 24px; color: white; }
.report-title { font-size: 24px; font-weight: 700; color: #1a202c; margin-bottom: 4px; }
.report-subtitle { font-size: 14px; color: #718096; font-weight: 500; }
.stats-container {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
gap: 12px;
margin: 20px 0;
}
.stat-card {
padding: 14px 16px;
border-radius: 12px;
border-left: 4px solid #4f46e5;
background: linear-gradient(135deg, #f8f9ff 0%, #f0f4ff 100%);
box-shadow: 0 2px 8px rgba(0,0,0,0.05);
display: flex; align-items: center; gap: 12px;
}
.stat-card.success { border-left-color: #10b981; background: linear-gradient(135deg,#ecfdf5,#d1fae5); }
.stat-card.warning { border-left-color: #f59e0b; background: linear-gradient(135deg,#fffbeb,#fef3c7); }
.stat-card.danger { border-left-color: #ef4444; background: linear-gradient(135deg,#fef2f2,#fee2e2); }
.stat-card.info { border-left-color: #3b82f6; background: linear-gradient(135deg,#eff6ff,#dbeafe); }
.stat-card.purple { border-left-color: #8b5cf6; background: linear-gradient(135deg,#faf5ff,#f3e8ff); }
.stat-card.teal { border-left-color: #14b8a6; background: linear-gradient(135deg,#f0fdfa,#ccfbf1); }
.stat-icon {
width: 42px; height: 42px; border-radius: 10px;
display: flex; align-items: center; justify-content: center;
background: rgba(79,70,229,0.1); flex-shrink: 0;
}
.stat-icon i { font-size: 17px; color: #4f46e5; }
.stat-card.success .stat-icon { background: rgba(16,185,129,0.1); }
.stat-card.success .stat-icon i { color: #10b981; }
.stat-card.warning .stat-icon { background: rgba(245,158,11,0.1); }
.stat-card.warning .stat-icon i { color: #f59e0b; }
.stat-card.danger .stat-icon { background: rgba(239,68,68,0.1); }
.stat-card.danger .stat-icon i { color: #ef4444; }
.stat-card.info .stat-icon { background: rgba(59,130,246,0.1); }
.stat-card.info .stat-icon i { color: #3b82f6; }
.stat-card.purple .stat-icon { background: rgba(139,92,246,0.1); }
.stat-card.purple .stat-icon i { color: #8b5cf6; }
.stat-card.teal .stat-icon { background: rgba(20,184,166,0.1); }
.stat-card.teal .stat-icon i { color: #14b8a6; }
.stat-value { font-size: 20px; font-weight: 700; color: #1a202c; line-height: 1.2; }
.stat-label { font-size: 11px; color: #718096; font-weight: 500; }
.filter-section {
background: #f8fafc; border-radius: 12px;
padding: 18px 20px; margin-bottom: 20px;
border: 1px solid #e2e8f0;
}
.filter-row { display: flex; gap: 15px; flex-wrap: wrap; align-items: flex-end; }
.filter-group { display: flex; flex-direction: column; gap: 6px; min-width: 170px; flex: 1; }
.filter-label {
font-size: 12px; font-weight: 600; color: #374151;
display: flex; align-items: center; gap: 5px;
}
.filter-control {
padding: 9px 11px; border-radius: 8px;
border: 1.5px solid #e5e7eb; background: #fff;
font-size: 13px; color: #1f2937;
transition: all 0.2s;
}
.filter-control:focus { outline: none; border-color: #4f46e5; box-shadow: 0 0 0 3px rgba(79,70,229,0.12); }
.table-container {
overflow-x: auto;
border-radius: 12px;
border: 1px solid #e5e7eb;
background: white;
box-shadow: 0 4px 12px rgba(0,0,0,0.05);
margin-top: 10px;
-webkit-overflow-scrolling: touch;
}
.report-table {
width: 100%;
border-collapse: separate;
border-spacing: 0;
min-width: 1400px;
font-size: 13px;
}
.report-table thead {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
position: sticky; top: 0; z-index: 10;
}
.report-table th {
padding: 14px 16px;
text-align: center;
font-size: 12px;
font-weight: 600;
color: #fff;
white-space: nowrap;
min-width: 110px;
}
.report-table td {
padding: 12px 16px;
font-size: 13px;
color: #374151;
border-bottom: 1px solid #f3f4f6;
vertical-align: middle;
white-space: nowrap;
text-align: center;
}
.report-table tbody tr:hover { background: #f8faff; }
.amt-cell { font-weight: 600; font-family: 'JetBrains Mono', monospace; }
.amt-payable { color: #1e40af; }
.amt-paid { color: #059669; }
.amt-remaining{ color: #dc2626; }
.amt-gst { color: #d97706; }
.amt-base { color: #374151; }
.count-badge {
display: inline-flex; align-items: center; justify-content: center;
background: #eff6ff; color: #1d4ed8;
font-weight: 700; font-size: 13px;
padding: 3px 10px; border-radius: 20px;
border: 1px solid #bfdbfe;
min-width: 32px;
}
.status-badge {
display: inline-flex; align-items: center; gap: 5px;
font-size: 11px; font-weight: 700;
padding: 5px 12px; border-radius: 20px;
text-transform: uppercase; letter-spacing: 0.4px;
white-space: nowrap;
}
.status-paid { background: #dcfce7; color: #166534; border: 1px solid #bbf7d0; }
.status-pending { background: #fef3c7; color: #92400e; border: 1px solid #fde68a; }
.status-overdue { background: #fee2e2; color: #991b1b; border: 1px solid #fecaca; }
.status-paying { background: #dbeafe; color: #1e40af; border: 1px solid #bfdbfe; }
.empty-state { text-align: center; padding: 50px 20px; color: #6b7280; }
.empty-icon {
width: 60px; height: 60px; background: #f8f9fa;
border-radius: 50%; display: flex; align-items: center;
justify-content: center; margin: 0 auto 15px;
border: 2px dashed #e5e7eb;
}
.empty-icon i { font-size: 24px; color: #9ca3af; }
.pagination-container {
display: flex; justify-content: space-between; align-items: center;
margin-top: 15px; padding: 12px 0; border-top: 1px solid #eef3fb;
}
.pagination-info { font-size: 13px; color: #9ba5bb; font-weight: 600; }
.pagination-controls { display: flex; align-items: center; gap: 8px; }
.pagination-img-btn {
background: #fff; border: 1px solid #e3eaf6;
border-radius: 6px; cursor: pointer;
display: flex; align-items: center; justify-content: center;
min-width: 36px; height: 32px;
}
.pagination-img-btn[disabled] { opacity: 0.4; cursor: not-allowed; }
.pagination-page-btn {
background: #fff; border: 1px solid #e3eaf6; color: #1a2951;
padding: 5px 11px; border-radius: 6px; font-size: 13px;
font-weight: 600; cursor: pointer; min-width: 34px;
}
.pagination-page-btn.active { background: #1a2951; color: #fff; border-color: #1a2951; }
.pagination-pages { display: flex; gap: 4px; align-items: center; }
@media (max-width: 768px) {
.report-container { padding: 15px; }
.report-table { min-width: 1400px; }
}
</style>
<div class="report-container">
{{-- HEADER --}}
<div class="report-header">
<div class="header-icon">
<i class="fas fa-boxes"></i>
</div>
<div>
<h1 class="report-title">Container Report</h1>
<p class="report-subtitle">Container-wise invoice summary amounts, payments & status</p>
</div>
<div class="ms-auto d-flex gap-2">
<a href="{{ route('admin.reports.containers.excel') }}"
id="excelBtn"
class="btn btn-sm btn-success"
style="border-radius:8px;font-weight:600;">
<i class="fas fa-file-excel me-1"></i> Excel
</a>
<a href="{{ route('admin.reports.containers.pdf') }}"
id="pdfBtn"
class="btn btn-sm btn-danger"
style="border-radius:8px;font-weight:600;">
<i class="fas fa-file-pdf me-1"></i> PDF
</a>
</div>
</div>
{{-- STATS CARDS --}}
<div class="stats-container">
<div class="stat-card info">
<div class="stat-icon"><i class="fas fa-box"></i></div>
<div>
<div class="stat-value" id="statTotalContainers">{{ count($reports) }}</div>
<div class="stat-label">Total Containers</div>
</div>
</div>
<div class="stat-card purple">
<div class="stat-icon"><i class="fas fa-file-invoice"></i></div>
<div>
<div class="stat-value" id="statTotalInvoices">{{ $reports->sum('total_invoices') }}</div>
<div class="stat-label">Total Invoices</div>
</div>
</div>
<div class="stat-card">
<div class="stat-icon"><i class="fas fa-rupee-sign"></i></div>
<div>
<div class="stat-value" id="statTotalPayable">
{{ number_format($reports->sum('total_payable'), 0) }}
</div>
<div class="stat-label">Total Payable</div>
</div>
</div>
<div class="stat-card success">
<div class="stat-icon"><i class="fas fa-check-circle"></i></div>
<div>
<div class="stat-value" id="statTotalPaid">
{{ number_format($reports->sum('total_paid'), 0) }}
</div>
<div class="stat-label">Total Paid</div>
</div>
</div>
<div class="stat-card danger">
<div class="stat-icon"><i class="fas fa-hourglass-half"></i></div>
<div>
<div class="stat-value" id="statTotalRemaining">
{{ number_format($reports->sum('total_remaining'), 0) }}
</div>
<div class="stat-label">Total Remaining</div>
</div>
</div>
<div class="stat-card warning">
<div class="stat-icon"><i class="fas fa-exclamation-triangle"></i></div>
<div>
<div class="stat-value" id="statOverdue">
{{ $reports->where('container_status', 'overdue')->count() }}
</div>
<div class="stat-label">Overdue Containers</div>
</div>
</div>
</div>
{{-- FILTERS --}}
<div class="filter-section">
<div class="filter-row">
<div class="filter-group">
<label class="filter-label"><i class="fas fa-calendar-alt"></i> From Date</label>
<input type="date" class="filter-control" id="fromDate">
</div>
<div class="filter-group">
<label class="filter-label"><i class="fas fa-calendar-check"></i> To Date</label>
<input type="date" class="filter-control" id="toDate">
</div>
<div class="filter-group">
<label class="filter-label"><i class="fas fa-flag"></i> Status</label>
<select class="filter-control" id="statusFilter">
<option value="">All Status</option>
<option value="paid">Paid</option>
<option value="paying">Paying</option>
<option value="pending">Pending</option>
<option value="overdue">Overdue</option>
</select>
</div>
</div>
</div>
{{-- TABLE --}}
<div class="table-container">
<table class="report-table">
<thead>
<tr>
<th>#</th>
<th>Container No</th>
<th>Container Date</th>
<th>Total Mark Nos</th>
<th>Total Customers</th>
<th>Total Invoices</th>
<th>Invoice Amount<br><small style="font-weight:400;opacity:.8;">(Before GST)</small></th>
<th>GST Amount</th>
<th>Payable Amount<br><small style="font-weight:400;opacity:.8;">(Incl. GST)</small></th>
<th>Paid Amount</th>
<th>Remaining Amount</th>
<th>Container Status</th>
</tr>
</thead>
<tbody id="reportTableBody">
@forelse($reports as $i => $r)
@php $cs = strtolower($r->container_status); @endphp
<tr data-status="{{ strtolower($r->container_status) }}"
data-date="{{ $r->container_date }}">
<td class="text-muted fw-600">{{ $i + 1 }}</td>
<td style="font-weight:700;color:#1e40af;">{{ $r->container_number }}</td>
<td>{{ $r->container_date ? \Carbon\Carbon::parse($r->container_date)->format('d-m-Y') : '-' }}</td>
<td><span class="count-badge">{{ $r->total_mark_nos }}</span></td>
<td><span class="count-badge">{{ $r->total_customers }}</span></td>
<td><span class="count-badge" style="background:#f3e8ff;color:#6d28d9;border-color:#ddd6fe;">{{ $r->total_invoices }}</span></td>
<td class="amt-cell amt-base">{{ number_format($r->total_invoice_amount, 2) }}</td>
<td class="amt-cell amt-gst">{{ number_format($r->total_gst_amount, 2) }}</td>
<td class="amt-cell amt-payable">{{ number_format($r->total_payable, 2) }}</td>
<td class="amt-cell amt-paid">{{ number_format($r->total_paid, 2) }}</td>
<td class="amt-cell amt-remaining">{{ number_format($r->total_remaining, 2) }}</td>
<td>
<span class="status-badge
@if($cs === 'paid') status-paid
@elseif($cs === 'overdue') status-overdue
@elseif($cs === 'paying') status-paying
@else status-pending
@endif">
@if($cs === 'paid') <i class="fas fa-check-circle"></i>
@elseif($cs === 'overdue') <i class="fas fa-exclamation-circle"></i>
@elseif($cs === 'paying') <i class="fas fa-spinner"></i>
@else <i class="fas fa-clock"></i>
@endif
{{ ucfirst($cs) }}
</span>
</td>
</tr>
@empty
<tr>
<td colspan="12">
<div class="empty-state">
<div class="empty-icon"><i class="fas fa-inbox"></i></div>
<h3>No Container Reports Found</h3>
<p>No containers with invoices found.</p>
</div>
</td>
</tr>
@endforelse
</tbody>
</table>
</div>
{{-- PAGINATION --}}
<div class="pagination-container">
<div class="pagination-info" id="pageInfo">
Showing 1{{ min(15, count($reports)) }} of {{ count($reports) }} entries
</div>
<div class="pagination-controls">
<button class="pagination-img-btn" id="prevPageBtn" disabled>
<svg width="16" height="16" viewBox="0 0 16 16" fill="none">
<path d="M10 12L6 8L10 4" stroke="currentColor" stroke-width="2"
stroke-linecap="round" stroke-linejoin="round"/>
</svg>
</button>
<div class="pagination-pages" id="paginationPages"></div>
<button class="pagination-img-btn" id="nextPageBtn"
{{ count($reports) <= 15 ? 'disabled' : '' }}>
<svg width="16" height="16" viewBox="0 0 16 16" fill="none">
<path d="M6 4L10 8L6 12" stroke="currentColor" stroke-width="2"
stroke-linecap="round" stroke-linejoin="round"/>
</svg>
</button>
</div>
</div>
</div>
<script>
const allReports = @json($reports);
const ITEMS_PER_PAGE = 15;
let filteredReports = [...allReports];
let currentPage = 1;
const pdfBaseUrl = "{{ route('admin.reports.containers.pdf') }}";
const excelBaseUrl = "{{ route('admin.reports.containers.excel') }}";
const fmt = (n) => Number(n || 0).toLocaleString('en-IN', { minimumFractionDigits: 2, maximumFractionDigits: 2 });
const fmtDate = (d) => d ? new Date(d).toLocaleDateString('en-GB') : '-';
// ── Filter values ──────────────────────────────────────────────
function getFilterValues() {
return {
from_date : document.getElementById('fromDate').value || '',
to_date : document.getElementById('toDate').value || '',
status : document.getElementById('statusFilter').value || '',
};
}
// ── Build URL with current filter params ───────────────────────
function buildUrl(base) {
const f = getFilterValues();
const params = new URLSearchParams();
if (f.from_date) params.set('from_date', f.from_date);
if (f.to_date) params.set('to_date', f.to_date);
if (f.status) params.set('status', f.status);
const qs = params.toString();
return qs ? base + '?' + qs : base;
}
// ── Update PDF & Excel button hrefs whenever filter changes ────
function updateDownloadLinks() {
document.getElementById('pdfBtn').href = buildUrl(pdfBaseUrl);
document.getElementById('excelBtn').href = buildUrl(excelBaseUrl);
}
// ── Status badge HTML ──────────────────────────────────────────
function statusBadgeHtml(status) {
const s = (status || '').toLowerCase();
const map = {
paid: { cls: 'status-paid', icon: 'fa-check-circle', label: 'Paid' },
overdue: { cls: 'status-overdue', icon: 'fa-exclamation-circle', label: 'Overdue' },
paying: { cls: 'status-paying', icon: 'fa-spinner', label: 'Paying' },
pending: { cls: 'status-pending', icon: 'fa-clock', label: 'Pending' },
};
const c = map[s] || map.pending;
return `<span class="status-badge ${c.cls}"><i class="fas ${c.icon}"></i> ${c.label}</span>`;
}
// ── Render table ───────────────────────────────────────────────
function renderTable() {
const tbody = document.getElementById('reportTableBody');
if (!tbody) return;
tbody.innerHTML = '';
if (filteredReports.length === 0) {
tbody.innerHTML = `<tr><td colspan="12">
<div class="empty-state">
<div class="empty-icon"><i class="fas fa-inbox"></i></div>
<h3>No Container Reports Found</h3>
<p>No containers match the selected filters.</p>
</div></td></tr>`;
updateStats();
return;
}
const start = (currentPage - 1) * ITEMS_PER_PAGE;
const slice = filteredReports.slice(start, start + ITEMS_PER_PAGE);
slice.forEach((r, idx) => {
const tr = document.createElement('tr');
tr.setAttribute('data-status', (r.container_status || '').toLowerCase());
tr.setAttribute('data-date', r.container_date || '');
tr.innerHTML = `
<td class="text-muted fw-600">${start + idx + 1}</td>
<td style="font-weight:700;color:#1e40af;">${r.container_number || '-'}</td>
<td>${fmtDate(r.container_date)}</td>
<td><span class="count-badge">${r.total_mark_nos || 0}</span></td>
<td><span class="count-badge">${r.total_customers || 0}</span></td>
<td><span class="count-badge" style="background:#f3e8ff;color:#6d28d9;border-color:#ddd6fe;">${r.total_invoices || 0}</span></td>
<td class="amt-cell amt-base">₹${fmt(r.total_invoice_amount)}</td>
<td class="amt-cell amt-gst">₹${fmt(r.total_gst_amount)}</td>
<td class="amt-cell amt-payable">₹${fmt(r.total_payable)}</td>
<td class="amt-cell amt-paid">₹${fmt(r.total_paid)}</td>
<td class="amt-cell amt-remaining">₹${fmt(r.total_remaining)}</td>
<td>${statusBadgeHtml(r.container_status)}</td>
`;
tbody.appendChild(tr);
});
updateStats();
renderPagination();
}
// ── Update stat cards ──────────────────────────────────────────
function updateStats() {
document.getElementById('statTotalContainers').textContent = filteredReports.length;
document.getElementById('statTotalInvoices').textContent = filteredReports.reduce((s,r) => s + Number(r.total_invoices||0), 0);
const tp = filteredReports.reduce((s,r) => s + Number(r.total_payable||0), 0);
const tpd = filteredReports.reduce((s,r) => s + Number(r.total_paid||0), 0);
const tr = filteredReports.reduce((s,r) => s + Number(r.total_remaining||0), 0);
document.getElementById('statTotalPayable').textContent = '₹' + Math.round(tp).toLocaleString('en-IN');
document.getElementById('statTotalPaid').textContent = '₹' + Math.round(tpd).toLocaleString('en-IN');
document.getElementById('statTotalRemaining').textContent = '₹' + Math.round(tr).toLocaleString('en-IN');
const overdue = filteredReports.filter(r => (r.container_status||'').toLowerCase() === 'overdue').length;
document.getElementById('statOverdue').textContent = overdue;
}
// ── Pagination ─────────────────────────────────────────────────
function renderPagination() {
const total = filteredReports.length;
const totalPages = Math.ceil(total / ITEMS_PER_PAGE);
const start = ((currentPage - 1) * ITEMS_PER_PAGE) + 1;
const end = Math.min(currentPage * ITEMS_PER_PAGE, total);
document.getElementById('pageInfo').textContent = `Showing ${start}${end} of ${total} entries`;
const prevBtn = document.getElementById('prevPageBtn');
const nextBtn = document.getElementById('nextPageBtn');
prevBtn.disabled = (currentPage === 1);
nextBtn.disabled = (currentPage === totalPages || totalPages === 0);
const pagesDiv = document.getElementById('paginationPages');
pagesDiv.innerHTML = '';
if (totalPages <= 1) return;
const range = 2;
const showPages = [];
if (totalPages <= 7) {
for (let i = 1; i <= totalPages; i++) showPages.push(i);
} else {
showPages.push(1);
if (currentPage > range + 2) showPages.push('...');
for (let i = Math.max(2, currentPage - range); i <= Math.min(totalPages - 1, currentPage + range); i++) {
showPages.push(i);
}
if (currentPage < totalPages - range - 1) showPages.push('...');
showPages.push(totalPages);
}
showPages.forEach(p => {
if (p === '...') {
const span = document.createElement('span');
span.textContent = '...';
span.style.padding = '0 4px';
span.style.color = '#9ca3af';
pagesDiv.appendChild(span);
} else {
const btn = document.createElement('button');
btn.className = 'pagination-page-btn' + (p === currentPage ? ' active' : '');
btn.textContent = p;
btn.addEventListener('click', () => { currentPage = p; renderTable(); });
pagesDiv.appendChild(btn);
}
});
}
document.getElementById('prevPageBtn')?.addEventListener('click', () => {
if (currentPage > 1) { currentPage--; renderTable(); }
});
document.getElementById('nextPageBtn')?.addEventListener('click', () => {
const totalPages = Math.ceil(filteredReports.length / ITEMS_PER_PAGE);
if (currentPage < totalPages) { currentPage++; renderTable(); }
});
// ── Apply filters ──────────────────────────────────────────────
function applyFilters() {
const f = getFilterValues();
filteredReports = allReports.filter(r => {
if (f.from_date && r.container_date && r.container_date < f.from_date) return false;
if (f.to_date && r.container_date && r.container_date > f.to_date) return false;
if (f.status && (r.container_status || '').toLowerCase() !== f.status) return false;
return true;
});
currentPage = 1;
renderTable();
updateDownloadLinks(); // ← PDF/Excel URL filter सकट update होतो
}
document.getElementById('fromDate')?.addEventListener('change', applyFilters);
document.getElementById('toDate')?.addEventListener('change', applyFilters);
document.getElementById('statusFilter')?.addEventListener('change', applyFilters);
document.addEventListener('DOMContentLoaded', () => {
renderTable();
updateDownloadLinks();
});
</script>
@endsection
@endif