Files
Kent-logistics-Laravel/resources/views/admin/dashboard.blade.php
Utkarsh Khedkar 785f2564be changes
2026-03-13 23:06:19 +05:30

2197 lines
74 KiB
PHP
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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.

@extends('admin.layouts.app')
@section('page-title', 'Dashboard')
@section('content')
<style>
/* ===== GLOBAL STYLES (From Shipment) ===== */
:root {
--primary: #4361ee;
--primary-dark: #3a56d4;
--secondary: #f72585;
--success: #4cc9f0;
--warning: #f8961e;
--danger: #e63946;
--light: #f8f9fa;
--dark: #212529;
--gray: #6c757d;
--border: #e2e8f0;
--card-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
--hover-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
}
html, body {
overflow-x: hidden !important;
font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
background: #f4f7fc;
}
.container-fluid {
padding-left: 15px;
padding-right: 15px;
width: 100%;
}
/* ===== DASHBOARD TITLE (Shipment Style) ===== */
.dash-top-titlebox {
margin-bottom: 15px;
padding: 20px 0;
background: transparent;
}
.dash-title-main {
font-size: 1.8rem;
font-weight: 800;
color: #212529;
margin-bottom: 5px;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
font-family: 'Inter', sans-serif;
}
.dash-title-desc {
font-size: 1rem;
color: #6c757d;
font-weight: 500;
font-family: 'Inter', sans-serif;
}
/* ===== STATS CARDS (Shipment Style) ===== */
.stats-row-wrap {
margin-bottom: 30px;
}
.stats-row {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 15px;
margin-bottom: 15px;
}
@media (max-width: 1200px) {
.stats-row {
grid-template-columns: repeat(3, 1fr);
}
}
@media (max-width: 992px) {
.stats-row {
grid-template-columns: repeat(2, 1fr);
}
}
@media (max-width: 768px) {
.stats-row {
grid-template-columns: 1fr;
gap: 12px;
}
}
.stats-card {
background: white;
border-radius: 12px;
box-shadow: var(--card-shadow);
overflow: hidden;
position: relative;
display: flex;
align-items: center;
gap: 12px;
padding: 15px;
border: 1px solid rgba(232, 240, 253, 0.5);
transition: all 0.3s ease;
z-index: 1;
min-height: 80px;
width: 100%;
box-sizing: border-box;
}
.stats-card::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: linear-gradient(135deg, rgba(102, 126, 234, 0.05), rgba(118, 75, 162, 0.05));
z-index: 0;
}
.stats-card:hover {
transform: translateY(-3px);
box-shadow: var(--hover-shadow);
border-color: rgba(102, 126, 234, 0.2);
}
.stats-card > * {
position: relative;
z-index: 1;
}
.stats-icon {
font-size: 1.4rem;
width: 45px;
height: 45px;
border-radius: 10px;
display: flex;
align-items: center;
justify-content: center;
background: linear-gradient(135deg, #667eea, #764ba2);
color: white;
transition: all 0.3s ease;
box-shadow: 0 3px 10px rgba(102, 126, 234, 0.2);
flex-shrink: 0;
}
.stats-card:hover .stats-icon {
transform: scale(1.05) rotate(3deg);
box-shadow: 0 5px 15px rgba(102, 126, 234, 0.3);
}
.stats-label {
font-size: 12px;
color: #6c757d;
font-weight: 600;
letter-spacing: 0.3px;
text-transform: uppercase;
font-family: 'Inter', sans-serif;
margin-bottom: 4px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.stats-value {
font-size: 1.4rem;
font-weight: 700;
color: #212529;
font-family: 'Inter', sans-serif;
line-height: 1.2;
}
/* Stats card color variations */
.stats-card-blue .stats-icon {
background: linear-gradient(135deg, #4361ee, #3a0ca3);
}
.stats-card-green .stats-icon {
background: linear-gradient(135deg, #4cc9f0, #4895ef);
}
.stats-card-red .stats-icon {
background: linear-gradient(135deg, #f72585, #b5179e);
}
.stats-card-orng .stats-icon {
background: linear-gradient(135deg, #f8961e, #f3722c);
}
/* ===== ORDER MANAGEMENT SECTION (Shipment Style) ===== */
.order-mgmt-box {
background: white;
border-radius: 16px;
box-shadow: var(--card-shadow);
margin-bottom: 30px;
overflow: hidden;
width: 100%;
}
.order-mgmt-bar {
display: flex;
justify-content: space-between;
align-items: center;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
padding: 18px 25px;
border-radius: 16px 16px 0 0;
flex-wrap: wrap;
gap: 10px;
}
@media (max-width: 768px) {
.order-mgmt-bar {
flex-direction: column;
align-items: flex-start;
gap: 12px;
}
.create-order-btn {
width: 100%;
justify-content: center;
}
}
.order-mgmt-title {
font-size: 1.3rem;
font-weight: 700;
display: flex;
align-items: center;
gap: 10px;
font-family: 'Inter', sans-serif;
flex-wrap: wrap;
}
.order-mgmt-title i {
font-size: 1.1em;
}
.create-order-btn {
background: rgba(255, 255, 255, 0.2);
backdrop-filter: blur(10px);
color: white;
border: 1px solid rgba(255, 255, 255, 0.3);
padding: 8px 20px;
border-radius: 8px;
font-weight: 600;
display: flex;
align-items: center;
gap: 8px;
transition: all 0.3s ease;
font-family: 'Inter', sans-serif;
font-size: 14px;
white-space: nowrap;
}
.create-order-btn:hover {
background: rgba(255, 255, 255, 0.3);
transform: translateY(-2px);
box-shadow: 0 8px 15px rgba(0, 0, 0, 0.1);
}
.order-mgmt-main {
padding: 0;
background: white;
width: 100%;
}
/* ===== TABLE STYLES (Shipment Style) ===== */
.card {
border: none;
border-radius: 16px;
box-shadow: var(--card-shadow);
transition: all 0.3s ease;
overflow: hidden;
width: 100%;
}
.card:hover {
transform: translateY(-3px);
box-shadow: var(--hover-shadow);
}
.card-header {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
border: none;
padding: 13px 18px;
border-radius: 16px 16px 0 0 !important;
font-weight: 700;
font-family: 'Inter', sans-serif;
font-size: 1.1rem;
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 10px;
margin-top:30px;
}
.table-responsive {
border-radius: 0 0 16px 16px;
overflow-x: auto;
width: 100%;
-webkit-overflow-scrolling: touch;
}
.table {
margin: 0;
border-collapse: separate;
border-spacing: 0;
width: 100%;
min-width: 1400px;
}
/* TABLE HEADER BACKGROUND COLOR - DARK WITH CURVED SIDES */
.table thead tr {
background: linear-gradient(135deg, #2c3e50, #34495e) !important;
border-bottom: 2px solid #1a252f;
border-radius:16px 16px 0 0 !important;
}
.table thead th {
background: transparent !important;
border: none;
padding: 14px 10px;
font-weight: 700;
color: white !important;
text-align: center;
vertical-align: middle;
border-bottom: 2px solid #1a252f;
position: relative;
white-space: nowrap;
font-family: 'Inter', sans-serif;
font-size: 13px;
min-width: 100px;
}
/* Curve the first and last header cells */
.table thead th:first-child {
border-top-left-radius: 10px;
}
.table thead th:last-child {
border-top-right-radius: 10px;
}
/* Table row styling with curved sides */
.table tbody tr {
transition: all 0.3s ease;
position: relative;
}
.table tbody tr:first-child td:first-child {
border-top-left-radius: 8px;
}
.table tbody tr:first-child td:last-child {
border-top-right-radius: 8px;
}
.table tbody tr:last-child td:first-child {
border-bottom-left-radius: 8px;
}
.table tbody tr:last-child td:last-child {
border-bottom-right-radius: 8px;
}
.table tbody tr:hover {
background-color: #f8f9ff;
transform: scale(1.005);
box-shadow: 0 3px 10px rgba(0,0,0,0.08);
}
.table tbody td {
padding: 12px 10px;
text-align: center;
vertical-align: middle;
border-bottom: 1px solid var(--border);
font-weight: 500;
white-space: nowrap;
font-family: 'Inter', sans-serif;
font-size: 13px;
min-width: 100px;
position: relative;
}
/* REMOVED: Vertical borders from table cells */
.table tbody td {
border-left: none !important;
border-right: none !important;
}
.table tbody tr:last-child td {
border-bottom: none;
}
/* ===== STATUS BADGES (CUSTOM COLORS FOR EACH STATUS) ===== */
.badge {
padding: 6px 12px !important;
border-radius: 20px !important;
font-weight: 600 !important;
font-size: 12px !important;
border: 2px solid transparent !important;
min-width: 40px !important;
text-align: center !important;
display: inline-flex !important;
align-items: center;
justify-content: center;
gap: 5px;
line-height: 1.2 !important;
width: 140px !important;
height: 28px !important;
box-sizing: border-box !important;
}
/* Specific status badge colors */
.badge-order_placed {
background: linear-gradient(135deg, #e3f2fd, #bbdefb) !important;
color: #1565c0 !important;
border-color: #64b5f6 !important;
}
.badge-order_confirmed {
background: linear-gradient(135deg, #e8f5e9, #c8e6c9) !important;
color: #2e7d32 !important;
border-color: #81c784 !important;
}
.badge-supplier_warehouse {
background: linear-gradient(135deg, #fff3e0, #ffe0b2) !important;
color: #ef6c00 !important;
border-color: #ffb74d !important;
}
.badge-consolidate_warehouse {
background: linear-gradient(135deg, #f3e5f5, #e1bee7) !important;
color: #7b1fa2 !important;
border-color: #ba68c8 !important;
}
.badge-export_custom {
background: linear-gradient(135deg, #e8eaf6, #c5cae9) !important;
color: #303f9f !important;
border-color: #7986cb !important;
}
.badge-international_transit {
background: linear-gradient(135deg, #fef3c7, #fde68a) !important;
color: #d97706 !important;
border-color: #f59e0b !important;
}
.badge-arrived_india {
background: linear-gradient(135deg, #e0f7fa, #b2ebf2) !important;
color: #006064 !important;
border-color: #4dd0e1 !important;
}
.badge-import_custom {
background: linear-gradient(135deg, #f1f8e9, #dcedc8) !important;
color: #558b2f !important;
border-color: #9ccc65 !important;
}
.badge-warehouse {
background: linear-gradient(135deg, #f5f5f5, #eeeeee) !important;
color: #424242 !important;
border-color: #bdbdbd !important;
}
.badge-domestic_distribution {
background: linear-gradient(135deg, #e0f2f1, #b2dfdb) !important;
color: #00695c !important;
border-color: #4db6ac !important;
}
.badge-out_for_delivery {
background: linear-gradient(135deg, #e8f5e9, #c8e6c9) !important;
color: #1b5e20 !important;
border-color: #66bb6a !important;
}
.badge-delivered {
background: linear-gradient(135deg, #d1fae5, #a7f3d0) !important;
color: #065f46 !important;
border-color: #10b981 !important;
}
.badge-pending {
background: linear-gradient(135deg, #fff3e0, #ffe0b2) !important;
color: #ef6c00 !important;
border-color: #ffb74d !important;
}
/* Default fallback badge classes */
.badge.bg-secondary {
background: linear-gradient(135deg, #d1fae5, #a7f3d0) !important;
color: #065f46 !important;
border-color: #10b981 !important;
}
.badge.bg-info {
background: linear-gradient(135deg, #e3f2fd, #bbdefb) !important;
color: #1565c0 !important;
border-color: #64b5f6 !important;
}
.badge.bg-warning {
background: linear-gradient(135deg, #fff3e0, #ffe0b2) !important;
color: #ef6c00 !important;
border-color: #ffb74d !important;
}
.badge.bg-primary {
background: linear-gradient(135deg, #e8eaf6, #c5cae9) !important;
color: #303f9f !important;
border-color: #7986cb !important;
}
.badge.bg-success {
background: linear-gradient(135deg, #e8f5e9, #c8e6c9) !important;
color: #2e7d32 !important;
border-color: #81c784 !important;
}
.badge.bg-dark {
background: linear-gradient(135deg, #f5f5f5, #eeeeee) !important;
color: #424242 !important;
border-color: #bdbdbd !important;
}
.status-icon {
font-size: 11px;
}
/* Action buttons */
.btn-outline-primary {
border: 1px solid var(--primary);
color: var(--primary);
border-radius: 8px;
padding: 5px 10px;
font-weight: 600;
transition: all 0.3s ease;
font-size: 12px;
height: 30px;
display: inline-flex;
align-items: center;
justify-content: center;
min-width: 70px;
white-space: nowrap;
}
.btn-outline-primary:hover {
background: var(--primary);
color: white;
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(67, 97, 238, 0.3);
}
/* ===== CREATE ORDER MODAL STYLES ===== */
.create-order-modal {
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
background: #f8fafc;
display: none;
z-index: 9999;
overflow-y: auto;
}
.create-order-modal.show {
display: block;
}
.create-order-modal .modal-card {
background: #fff;
border-radius: 0;
box-shadow: none;
width: 100%;
max-width: 100%;
min-height: 100vh;
max-height: none;
overflow: visible;
}
.create-order-modal .modal-header {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
padding: 20px 25px;
border-radius: 0;
display: flex;
justify-content: space-between;
align-items: center;
flex-wrap: wrap;
gap: 10px;
}
.create-order-modal .modal-title {
font-size: 1.4rem;
font-weight: 700;
margin: 0;
font-family: 'Inter', sans-serif;
}
.create-order-modal .close-btn {
background: rgba(255, 255, 255, 0.2);
border: none;
color: white;
font-size: 1.5rem;
width: 35px;
height: 35px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
transition: background 0.3s;
}
.create-order-modal .close-btn:hover {
background: rgba(255, 255, 255, 0.3);
}
.create-order-modal .modal-body {
padding: 25px;
background: #f8fafc;
width: 100%;
box-sizing: border-box;
}
/* CREATE ORDER MODAL TABLE STYLES - NO HORIZONTAL SCROLL, SAME BOX SIZE */
.create-order-modal .table-wrapper {
width: 100%;
max-height: 400px;
overflow-y: auto;
overflow-x: hidden !important; /* NO HORIZONTAL SCROLL */
background: #fff;
border-radius: 12px;
box-shadow: 0 4px 20px rgba(0,0,0,0.08);
padding: 12px;
position: relative;
box-sizing: border-box;
}
.create-order-modal .table-wrapper .table {
margin-bottom: 0;
background: #fff;
width: 100% !important; /* FULL RESPONSIVE WIDTH */
font-size: 13px;
border-collapse: collapse;
table-layout: fixed; /* FIXED TABLE LAYOUT FOR CONSISTENT COLUMNS */
}
/* CREATE ORDER MODAL TABLE HEADER - DARK BACKGROUND WITH CURVED SIDES */
.create-order-modal .table thead tr {
background: linear-gradient(135deg, #34495e, #2c3e50) !important;
border-bottom: 2px solid #1a252f;
}
.create-order-modal .table thead th {
background: transparent !important;
border: none;
padding: 12px 8px !important;
font-weight: 700;
color: white !important;
text-align: center;
vertical-align: middle;
border-bottom: 2px solid #1a252f;
white-space: nowrap;
font-family: 'Inter', sans-serif;
font-size: 12px;
overflow: hidden;
text-overflow: ellipsis;
word-wrap: break-word;
}
/* Curve the first and last header cells */
.create-order-modal .table thead th:first-child {
border-top-left-radius: 8px;
}
.create-order-modal .table thead th:last-child {
border-top-right-radius: 8px;
}
/* FIXED COLUMN WIDTHS - ALL SAME SIZE */
.create-order-modal .table th,
.create-order-modal .table td {
width: 7.14% !important; /* 14 columns = ~7.14% each */
min-width: 70px !important;
max-width: 100px !important;
padding: 10px 6px !important;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
vertical-align: middle;
box-sizing: border-box;
text-align: center;
font-size: 12px;
}
/* REMOVED: Vertical borders from create order modal table */
.create-order-modal .table th,
.create-order-modal .table td {
border-left: none !important;
border-right: none !important;
border-bottom: 1px solid #e9ecef;
}
/* Make description column slightly wider */
.create-order-modal .table th:nth-child(2),
.create-order-modal .table td:nth-child(2) {
width: 12% !important;
min-width: 120px !important;
}
/* Make remove column smaller */
.create-order-modal .table th:nth-child(14),
.create-order-modal .table td:nth-child(14) {
width: 5% !important;
min-width: 60px !important;
}
.create-order-modal .table .items-input {
width: 100% !important;
padding: 6px 8px;
font-size: 12px;
border: 1px solid #ced4da;
border-radius: 5px;
transition: all 0.2s ease;
background: white;
box-sizing: border-box;
text-align: center;
min-height: 34px;
}
.create-order-modal .table .items-input:focus {
border-color: #80bdff;
box-shadow: 0 0 0 0.2rem rgba(0,123,255,.25);
outline: none;
}
.create-order-modal .table .bg-light {
background-color: #f8f9fa !important;
font-weight: 600;
}
.create-order-modal .remove-row-btn {
width: 30px;
height: 30px;
border-radius: 50%;
background: #dc3545;
color: white;
border: none;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
transition: all 0.2s ease;
font-size: 16px;
padding: 0;
margin: 0 auto;
}
.create-order-modal .remove-row-btn:hover {
background: #c82333;
transform: scale(1.1);
}
/* Form Styles in Modal */
.form-label {
font-weight: 600;
color: #5a6c7d;
margin-bottom: 8px;
font-size: 0.9rem;
}
.form-control, .form-select {
border-radius: 8px;
border: 1px solid #e2e8f0;
padding: 10px 14px;
font-size: 14px;
transition: all 0.3s ease;
background: #fafbfc;
color: #4a5568;
width: 100%;
box-sizing: border-box;
}
.form-control:focus, .form-select:focus {
border-color: #a3bffa;
box-shadow: 0 0 0 3px rgba(163, 191, 250, 0.2);
background: white;
}
/* ===== MODAL STYLES (Shipment Style) ===== */
.modal-content {
border-radius: 20px;
border: none;
box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);
overflow: hidden;
width: 100%;
}
.modal-header {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
border: none;
padding: 25px 30px 15px;
border-radius: 20px 20px 0 0;
position: relative;
}
.modal-header::after {
content: '';
position: absolute;
bottom: 0;
left: 5%;
width: 90%;
height: 1px;
background: rgba(255,255,255,0.2);
}
.modal-title {
font-weight: 700;
font-size: 1.5rem;
}
.btn-close {
filter: invert(1);
opacity: 0.8;
}
.btn-close:hover {
opacity: 1;
}
.modal-body {
padding: 25px 30px;
max-height: 70vh;
overflow-y: auto;
}
/* ===== PAGINATION STYLES ===== */
.pagination-container {
display: flex;
justify-content: space-between;
align-items: center;
margin-top: 15px;
padding: 12px 25px;
border-top: 1px solid #eef3fb;
flex-wrap: wrap;
gap: 10px;
width: 100%;
}
@media (max-width: 768px) {
.pagination-container {
flex-direction: column;
align-items: stretch;
}
.pagination-controls {
justify-content: center;
}
}
.pagination-info {
font-size: 13px;
color: #9ba5bb;
font-weight: 600;
white-space: nowrap;
}
.pagination-controls {
display: flex;
align-items: center;
gap: 8px;
flex-wrap: wrap;
}
.pagination-btn {
background: #fff;
border: 1px solid #e3eaf6;
color: #1a2951;
padding: 8px 12px;
border-radius: 6px;
font-size: 13px;
font-weight: 600;
cursor: pointer;
transition: all 0.3s ease;
display: flex;
align-items: center;
justify-content: center;
min-width: 40px;
height: 32px;
white-space: nowrap;
}
.pagination-btn:hover:not(:disabled) {
background: #1a2951;
color: white;
border-color: #1a2951;
}
.pagination-btn:disabled {
background: #f8fafc;
color: #cbd5e0;
border-color: #e2e8f0;
cursor: not-allowed;
opacity: 0.6;
}
.pagination-page-btn {
background: #fff;
border: 1px solid #e3eaf6;
color: #1a2951;
padding: 6px 12px;
border-radius: 6px;
font-size: 13px;
font-weight: 600;
cursor: pointer;
transition: all 0.3s ease;
min-width: 36px;
text-align: center;
white-space: nowrap;
}
.pagination-page-btn:hover {
background: #1a2951;
color: white;
border-color: #1a2951;
}
.pagination-page-btn.active {
background: #1a2951;
color: white;
border-color: #1a2951;
}
.pagination-pages {
display: flex;
gap: 4px;
align-items: center;
flex-wrap: wrap;
}
.pagination-ellipsis {
color: #9ba5bb;
font-size: 13px;
padding: 0 4px;
}
.pagination-img-btn {
background: #fff;
border: 1px solid #e3eaf6;
border-radius: 6px;
cursor: pointer;
transition: all 0.3s ease;
display: flex;
align-items: center;
justify-content: center;
min-width: 40px;
height: 32px;
padding: 0;
}
.pagination-img-btn:hover:not(:disabled) {
background: #1a2951;
border-color: #1a2951;
}
.pagination-img-btn:disabled {
background: #f8fafc;
border-color: #e2e8f0;
cursor: not-allowed;
opacity: 0.5;
}
.pagination-img-btn svg {
width: 16px;
height: 16px;
stroke: #1a2951;
transition: stroke 0.3s ease;
}
.pagination-img-btn:hover:not(:disabled) svg {
stroke: white;
}
/* ===== TABLE WRAPPER ===== */
.table-wrapper {
width: 100%;
overflow-x: auto;
-webkit-overflow-scrolling: touch;
scroll-behavior: smooth;
border-radius: 12px;
background: #fff;
box-shadow: 0 2px 10px rgba(0,0,0,0.08);
padding: 12px;
box-sizing: border-box;
}
.table-wrapper::-webkit-scrollbar {
height: 8px;
}
.table-wrapper::-webkit-scrollbar-thumb {
background: linear-gradient(90deg, #a7b8ff, #6c8eff);
border-radius: 10px;
}
.table-wrapper::-webkit-scrollbar-thumb:hover {
background: linear-gradient(90deg, #5a78ff, #3f63e0);
}
.table-wrapper::-webkit-scrollbar-track {
background: #f1f1f1;
}
/* ===== RESPONSIVE DESIGN ===== */
@media (max-width: 576px) {
.container-fluid {
padding-left: 10px;
padding-right: 10px;
}
.stats-card {
padding: 10px;
min-height: 70px;
}
.stats-value {
font-size: 1.1rem;
}
.table-wrapper {
padding: 8px;
}
.pagination-page-btn {
min-width: 30px;
padding: 4px 8px;
font-size: 12px;
}
.pagination-img-btn {
min-width: 35px;
height: 30px;
}
.btn-outline-primary {
min-width: 60px;
padding: 4px 8px;
font-size: 11px;
height: 28px;
}
.badge {
width: 120px !important;
font-size: 11px !important;
padding: 5px 10px !important;
height: 26px !important;
}
.create-order-modal .modal-body {
padding: 15px;
}
.create-order-modal .table-wrapper {
padding: 8px;
}
.create-order-modal .table th,
.create-order-modal .table td {
padding: 8px 4px !important;
font-size: 11px;
}
/* Adjust create order modal table for mobile */
.create-order-modal .table th,
.create-order-modal .table td {
min-width: 50px !important;
font-size: 10px;
}
.create-order-modal .table th:nth-child(2),
.create-order-modal .table td:nth-child(2) {
min-width: 80px !important;
}
}
@media (min-width: 1400px) {
.container-fluid {
max-width: 1400px;
margin: 0 auto;
}
.stats-row {
gap: 20px;
}
}
/* =====================================================
GLOBAL EDGE-TO-EDGE + ZOOM SAFE PATCH (CSS ONLY)
===================================================== */
/* 1⃣ Kill boxed layouts on desktop & zoom */
html, body {
width: 100%;
max-width: 100%;
overflow-x: clip;
}
/* 2⃣ Force container-fluid to truly span full width */
.container-fluid {
width: 100% !important;
max-width: 100% !important;
margin: 0 !important;
padding-left: clamp(12px, 1.8vw, 28px) !important;
padding-right: clamp(12px, 1.8vw, 28px) !important;
margin-top: -30px !important; /* Fix top margin if any */
}
/* 3⃣ Zoom-safe scaling (VERY IMPORTANT) */
body {
font-size: clamp(14px, 0.95vw, 16px);
}
/* =====================================================
DASHBOARD CARD & GRID FIXES (NO HTML CHANGE)
===================================================== */
/* 4⃣ Make stat grids auto-adjust on zoom */
.stats-row,
.shipment-totals-row {
display: grid !important;
grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)) !important;
gap: clamp(12px, 1.5vw, 20px) !important;
}
/* 5⃣ Prevent hover zoom breaking layout */
.stats-card:hover,
.card:hover,
.table tbody tr:hover {
transform: translateY(-4px) !important;
}
/* =====================================================
TABLE ZOOM FIX (NO MORE CRUSHING / OVERFLOW)
===================================================== */
/* 6⃣ Tables behave like shipment page */
.table-responsive {
width: 100%;
overflow-x: auto;
}
/* 7⃣ Remove hard min-widths that break zoom */
.table,
.custom-table-modal,
.shipment-details-table {
width: 100% !important;
min-width: max-content !important;
}
/* 8⃣ Let text wrap naturally when zoomed */
.table td,
.table th {
white-space: nowrap;
}
/* =====================================================
MODALS EDGE TO EDGE WITHOUT TOUCHING MARKUP
===================================================== */
.modal-xl {
max-width: 96vw !important;
width: 96vw !important;
margin: 1vh auto !important;
}
@media (max-width: 768px) {
.modal-xl {
max-width: 100vw !important;
width: 100vw !important;
margin: 0 !important;
height: 100vh !important;
}
}
/* =====================================================
FINAL SAFETY PREVENT LAYOUT SHRINK ON ZOOM
===================================================== */
* {
box-sizing: border-box;
}
</style>
<div class="container-fluid py-3">
<!-- DASHBOARD TITLE -->
<div class="dash-top-titlebox">
<div class="dash-title-main">Admin Dashboard</div>
<div class="dash-title-desc">Monitor operations and manage system</div>
</div>
<!-- STATS CARDS -->
<div class="stats-row-wrap">
{{-- Row 1: Total Containers, Active Customers, Total Invoices, Paid Invoices --}}
<div class="stats-row">
<div class="stats-card stats-card-blue">
<span class="stats-icon">&#x1F6A2;</span>
<div>
<div class="stats-label">Total Containers</div>
<div class="stats-value">{{ $totalContainers }}</div>
</div>
</div>
<div class="stats-card stats-card-blue">
<span class="stats-icon">&#x1F465;</span>
<div>
<div class="stats-label">Active Customers</div>
<div class="stats-value">{{ $activeCustomers }}</div>
</div>
</div>
<div class="stats-card stats-card-blue">
<span class="stats-icon">&#x1F9FE;</span>
<div>
<div class="stats-label">Total Orders</div>
<div class="stats-value">{{ $totalInvoices }}</div>
</div>
</div>
<div class="stats-card stats-card-green">
<span class="stats-icon">&#x2705;</span>
<div>
<div class="stats-label">Paid Invoices</div>
<div class="stats-value">{{ $paidInvoices }}</div>
</div>
</div>
</div>
{{-- Row 2: Pending Invoices, Total Staff, Inactive Customers, Total Revenue --}}
<div class="stats-row">
<div class="stats-card stats-card-orng">
<span class="stats-icon">&#x1F550;</span>
<div>
<div class="stats-label">Pending Orders</div>
<div class="stats-value">{{ $pendingInvoices }}</div>
</div>
</div>
<div class="stats-card stats-card-blue">
<span class="stats-icon">&#x1F9D1;&#x200D;&#x1F4BC;</span>
<div>
<div class="stats-label">Total Staff</div>
<div class="stats-value">{{ $totalStaff }}</div>
</div>
</div>
<div class="stats-card stats-card-orng">
<span class="stats-icon">&#x26D4;</span>
<div>
<div class="stats-label">Inactive Customers</div>
<div class="stats-value">{{ $inactiveCustomers }}</div>
</div>
</div>
<div class="stats-card stats-card-green">
<span class="stats-icon">&#x1F4B0;</span>
<div>
<div class="stats-label">Total Revenue</div>
<div class="stats-value">&#8377;{{ number_format($totalRevenue, 2) }}</div>
</div>
</div>
</div>
{{-- COMMENTED OUT --}}
{{--
<div class="stats-card stats-card-red">
<div class="stats-label">Pending Orders</div>
<div class="stats-value">{{ $pendingOrders }}</div>
</div>
<div class="stats-card stats-card-red">
<div class="stats-label">Overdue Invoices</div>
<div class="stats-value">{{ $overdueInvoices }}</div>
</div>
<div class="stats-card stats-card-blue">
<div class="stats-label">Total Orders</div>
<div class="stats-value">{{ $totalOrders }}</div>
</div>
<div class="stats-card stats-card-blue">
<div class="stats-label">Delivered Orders</div>
<div class="stats-value">{{ $totalOrders - $pendingOrders }}</div>
</div>
--}}
</div>
<!-- ORDER MANAGEMENT -->
<!-- <div class="order-mgmt-box">
<div class="order-mgmt-bar">
<span class="order-mgmt-title"><i class="bi bi-table"></i> Order Management</span>
@can('order.create')
<button class="create-order-btn" id="openCreateOrderModal">
<i class="bi bi-plus-circle"></i> Create Order
</button>
@endcan
</div>
<div class="order-mgmt-main"> -->
<!-- RECENT ORDERS TABLE -->
<!-- <div class="card shadow-sm">
<div class="card-header">
<strong>Recent Orders</strong>
<span style="font-size:13px;color:rgba(255,255,255,0.8);margin-left:10px;">
Total orders: <span id="ordersCount">{{ $orders->count() }}</span>
</span>
</div>
<div class="card-body">
<div class="table-responsive">
<div class="table-wrapper">
<table class="table table-striped align-middle text-center">
<thead class="table-light">
<tr>
<th>#</th>
<th>Order ID</th>
<th>Mark No</th>
<th>Origin</th>
<th>Destination</th>
<th>Total CTN</th>
<th>Total QTY</th>
<th>Total TTL/QTY</th>
<th>Total Amount ()</th>
<th>Total CBM</th>
<th>Total TTL CBM</th>
<th>Total KG</th>
<th>Total TTL KG</th>
<th>Status</th>
<th>Date</th>
<th>Actions</th>
</tr>
</thead>
<tbody id="ordersTableBody">
@forelse($orders as $order)
<tr>
<td>{{ $order->id }}</td>
<td>
<a href="javascript:void(0)"
class="fw-semibold text-primary open-order-modal"
data-id="{{ $order->id }}">
{{ $order->order_id }}
</a>
</td>
<td>{{ $order->mark_no }}</td>
<td>{{ $order->origin }}</td>
<td>{{ $order->destination }}</td>
<td>{{ $order->ctn }}</td>
<td>{{ $order->qty }}</td>
<td>{{ $order->ttl_qty }}</td>
<td>{{ number_format($order->ttl_amount, 2) }}</td>
<td>{{ $order->cbm }}</td>
<td>{{ $order->ttl_cbm }}</td>
<td>{{ $order->kg }}</td>
<td>{{ $order->ttl_kg }}</td>
<td>
@php
// Badge color mapping
$badgeMap = [
'order_placed' => 'secondary',
'order_confirmed' => 'info',
'supplier_warehouse' => 'warning',
'consolidate_warehouse' => 'warning',
'export_custom' => 'primary',
'international_transit' => 'primary',
'arrived_india' => 'info',
'import_custom' => 'info',
'warehouse' => 'dark',
'domestic_distribution' => 'primary',
'out_for_delivery' => 'success',
'delivered' => 'success',
'pending' => 'warning',
];
// Icon mapping
$iconMap = [
'order_placed' => 'bi-clock-fill',
'order_confirmed' => 'bi-check-circle',
'supplier_warehouse' => 'bi-box-seam',
'consolidate_warehouse' => 'bi-boxes',
'export_custom' => 'bi-upload',
'international_transit' => 'bi-truck',
'arrived_india' => 'bi-geo-alt',
'import_custom' => 'bi-download',
'warehouse' => 'bi-building',
'domestic_distribution' => 'bi-diagram-3',
'out_for_delivery' => 'bi-truck-flatbed',
'delivered' => 'bi-check-circle-fill',
'pending' => 'bi-clock-fill',
];
$badgeClass = $badgeMap[$order->status] ?? 'secondary';
$iconClass = $iconMap[$order->status] ?? 'bi-info-circle';
@endphp
<span class="badge bg-{{ $badgeClass }}">
<i class="bi {{ $iconClass }} status-icon"></i>
{{ $order->status_label }}
</span>
</td>
<td>{{ $order->created_at->format('d-m-Y') }}</td>
<td>
<a href="{{ route('admin.orders.show', $order->id) }}" class="btn btn-sm btn-outline-primary">
<i class="bi bi-eye"></i> View
</a>
</td>
</tr>
@empty
<tr>
<td colspan="16" class="text-muted">No orders found</td>
</tr>
@endforelse
</tbody>
</table>
</div> -->
<!-- Pagination Controls -->
<!-- <div class="pagination-container">
<div class="pagination-info" id="pageInfo">Showing 1 to 10 of {{ $orders->count() }} entries</div>
<div class="pagination-controls">
<button class="pagination-img-btn" id="prevPageBtn" title="Previous page">
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<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"> -->
<!-- Page numbers will be inserted here -->
<!-- </div>
<button class="pagination-img-btn" id="nextPageBtn" title="Next page">
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M6 4L10 8L6 12" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
</button>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div> -->
<!-- CREATE ORDER MODAL -->
<div class="create-order-modal" id="createOrderModal">
<div class="modal-card">
<div class="modal-header">
<h5 class="modal-title">Create New Order</h5>
<button class="close-btn" id="closeCreateOrderModal">&times;</button>
</div>
<div class="modal-body">
@if(session('success'))
<div class="alert alert-success alert-dismissible fade show" role="alert">
{{ session('success') }}
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
</div>
@endif
<!-- CREATE ORDER FORM -->
<form action="{{ route('admin.orders.temp.add') }}" method="POST" id="createOrderForm">
@csrf
<div class="row g-3">
{{-- MARK NO --}}
<div class="col-md-4">
<label class="form-label">Mark No</label>
@if(session('temp_order_items'))
<input type="text" class="form-control" value="{{ session('mark_no') }}" disabled>
<input type="hidden" name="mark_no" value="{{ session('mark_no') }}">
@else
<select class="form-select" id="markNoSelect" name="mark_no" required>
<option value="">Select Mark No</option>
@foreach($markList as $mark)
<option value="{{ $mark->mark_no }}"
data-origin="{{ $mark->origin }}"
data-destination="{{ $mark->destination }}"
@if(session('mark_no') == $mark->mark_no) selected @endif>
{{ $mark->mark_no }} - {{ $mark->customer_name }}
</option>
@endforeach
</select>
@endif
</div>
{{-- ORIGIN --}}
<div class="col-md-4">
<label class="form-label">Origin</label>
<input type="text" class="form-control"
id="originField"
name="origin"
readonly required
value="{{ session('origin') }}">
</div>
{{-- DESTINATION --}}
<div class="col-md-4">
<label class="form-label">Destination</label>
<input type="text" class="form-control"
id="destinationField"
name="destination"
readonly required
value="{{ session('destination') }}">
</div>
</div>
<hr class="my-3">
{{-- ITEM INPUTS --}}
<h6 class="text-primary">Add Item</h6>
{{-- NEW ITEMS TABLE (INSTEAD OF SINGLE-ROW INPUTS) --}}
<div class="table-wrapper mb-3">
<table class="table align-middle text-center" id="itemsTable">
<thead class="table-light">
<tr>
<th>#</th>
<th>Description</th>
<th>CTN</th>
<th>QTY</th>
<th>TTL/QTY</th>
<th>Unit</th>
<th>Price</th>
<th>TTL Amount</th>
<th>CBM</th>
<th>TTL CBM</th>
<th>KG</th>
<th>TTL KG</th>
<th>Shop No</th>
<th>Remove</th>
</tr>
</thead>
<tbody id="itemsTableBody">
{{-- JS will create default 2 blank rows --}}
</tbody>
</table>
</div>
<div class="row g-3">
<div class="col-md-12 text-end mt-3">
<button type="button" class="btn btn-secondary clear-form-btn" id="clearForm">
<i class="bi bi-arrow-clockwise"></i> Clear Form
</button>
<button type="submit" class="btn btn-info" id="addItemBtn">
<i class="bi bi-plus-circle"></i> Add Item
</button>
<input type="file" id="excelInput" accept=".xlsx,.xls" hidden>
<button type="button" class="btn btn-outline-success" id="uploadExcelBtn">
<i class="bi bi-file-earmark-excel"></i> Upload Excel
</button>
</div>
</div>
</form>
{{-- RESET ORDER BUTTON --}}
@if(session('temp_order_items'))
<div class="text-start mt-2">
<form action="{{ route('admin.orders.temp.reset') }}" method="POST">
@csrf
<button type="submit" class="btn btn-warning btn-sm">
<i class="bi bi-arrow-repeat"></i> Reset Order
</button>
</form>
</div>
@endif
{{-- TEMPORARY ITEMS TABLE --}}
@if(session('temp_order_items') && count(session('temp_order_items')) > 0)
<hr class="my-4">
<h5 class="text-success">Temporary Items ({{ count(session('temp_order_items')) }} items)</h5>
<div class="table-wrapper">
<table class="table text-center align-middle">
<thead class="table-light">
<tr>
<th>#</th>
<th>Description</th>
<th>CTN</th>
<th>QTY</th>
<th>TTL/QTY</th>
<th>Unit</th>
<th>Price</th>
<th>TTL Amount</th>
<th>CBM</th>
<th>TTL CBM</th>
<th>KG</th>
<th>TTL KG</th>
<th>Shop No</th>
<th>Remove</th>
</tr>
</thead>
<tbody>
@foreach(session('temp_order_items') as $index => $item)
<tr>
<td>{{ $index + 1 }}</td>
<td>{{ $item['description'] }}</td>
<td>{{ $item['ctn'] }}</td>
<td>{{ $item['qty'] }}</td>
<td>{{ $item['ttl_qty'] }}</td>
<td>{{ $item['unit'] }}</td>
<td>{{ $item['price'] }}</td>
<td>{{ $item['ttl_amount'] }}</td>
<td>{{ $item['cbm'] }}</td>
<td>{{ $item['ttl_cbm'] }}</td>
<td>{{ $item['kg'] }}</td>
<td>{{ $item['ttl_kg'] }}</td>
<td>{{ $item['shop_no'] }}</td>
<td>
<form action="{{ route('admin.orders.temp.delete') }}" method="POST">
@csrf
<input type="hidden" name="index" value="{{ $index }}">
<button type="submit" class="btn btn-danger btn-sm">
<i class="bi bi-trash"></i>
</button>
</form>
</td>
</tr>
@endforeach
</tbody>
</table>
</div>
<div class="text-end mt-3">
<form action="{{ route('admin.orders.finish') }}" method="POST">
@csrf
<input type="hidden" name="mark_no" value="{{ session('mark_no') }}">
<input type="hidden" name="origin" value="{{ session('origin') }}">
<input type="hidden" name="destination" value="{{ session('destination') }}">
<button type="submit" class="btn btn-success btn-lg">
<i class="bi bi-check-circle"></i> Finish & Save Order
</button>
</form>
</div>
@endif
</div>
</div>
</div>
<!-- MODERN ORDER DETAILS MODAL -->
<div class="modal fade" id="orderDetailsModal" tabindex="-1">
<div class="modal-dialog modal-xl modal-dialog-scrollable">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Order Details</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body" id="orderDetailsBody">
<p class="text-center text-muted">Loading...</p>
</div>
</div>
</div>
</div>
<script>
document.addEventListener('DOMContentLoaded', function() {
const modal = document.getElementById('createOrderModal');
const openBtn = document.getElementById('openCreateOrderModal');
const closeBtn = document.getElementById('closeCreateOrderModal');
const clearFormBtn = document.getElementById('clearForm');
// Pagination state
let currentPage = 1;
const ordersPerPage = 10;
let allOrders = @json($orders->values());
// ------- ITEMS TABLE LOGIC -------
const itemsTableBody = document.getElementById('itemsTableBody');
function addRow(index) {
const tr = document.createElement('tr');
tr.innerHTML = `
<td class="align-middle fw-bold">${index + 1}</td>
<td>
<input type="text" class="form-control form-control-sm items-input" name="items[${index}][description]" data-field="description">
</td>
<td>
<input type="number" class="form-control form-control-sm items-input" name="items[${index}][ctn]" data-field="ctn">
</td>
<td>
<input type="number" class="form-control form-control-sm items-input" name="items[${index}][qty]" data-field="qty">
</td>
<td>
<input type="number" class="form-control form-control-sm bg-light" name="items[${index}][ttl_qty]" data-field="ttl_qty" readonly>
</td>
<td>
<input type="text" class="form-control form-control-sm items-input" name="items[${index}][unit]" data-field="unit">
</td>
<td>
<input type="number" class="form-control form-control-sm items-input" name="items[${index}][price]" data-field="price" step="0.01">
</td>
<td>
<input type="number" class="form-control form-control-sm bg-light" name="items[${index}][ttl_amount]" data-field="ttl_amount" step="0.001" readonly>
</td>
<td>
<input type="number" class="form-control form-control-sm items-input" name="items[${index}][cbm]" data-field="cbm" step="0.0001">
</td>
<td>
<input type="number" class="form-control form-control-sm bg-light" name="items[${index}][ttl_cbm]" data-field="ttl_cbm" step="0.0001" readonly>
</td>
<td>
<input type="number" class="form-control form-control-sm items-input" name="items[${index}][kg]" data-field="kg" step="0.0001">
</td>
<td>
<input type="number" class="form-control form-control-sm bg-light" name="items[${index}][ttl_kg]" data-field="ttl_kg" step="0.0001" readonly>
</td>
<td>
<input type="text" class="form-control form-control-sm items-input" name="items[${index}][shop_no]" data-field="shop_no">
</td>
<td>
<button type="button" class="btn btn-sm btn-danger remove-row-btn">&times;</button>
</td>
`;
itemsTableBody.appendChild(tr);
}
function calculateRow(row) {
const ctn = parseFloat(row.querySelector('[data-field="ctn"]')?.value) || 0;
const qty = parseFloat(row.querySelector('[data-field="qty"]')?.value) || 0;
const price = parseFloat(row.querySelector('[data-field="price"]')?.value) || 0;
const cbm = parseFloat(row.querySelector('[data-field="cbm"]')?.value) || 0;
const kg = parseFloat(row.querySelector('[data-field="kg"]')?.value) || 0;
const ttlQty = ctn * qty;
const ttlAmount = ttlQty * price;
const ttlCbm = cbm * ctn;
const ttlKg = ctn * kg;
row.querySelector('[data-field="ttl_qty"]').value = ttlQty.toFixed(2);
row.querySelector('[data-field="ttl_amount"]').value = ttlAmount.toFixed(2);
row.querySelector('[data-field="ttl_cbm"]').value = ttlCbm.toFixed(3);
row.querySelector('[data-field="ttl_kg"]').value = ttlKg.toFixed(3);
}
itemsTableBody.addEventListener('input', function (e) {
const row = e.target.closest('tr');
if (!row) return;
const calcFields = ['ctn', 'qty', 'price', 'cbm', 'kg'];
if (calcFields.includes(e.target.dataset.field)) {
calculateRow(row);
}
});
function generateDefaultRows() {
itemsTableBody.innerHTML = '';
addRow(0);
addRow(1);
focusFirstInput();
}
function reindexRows() {
const rows = itemsTableBody.querySelectorAll('tr');
rows.forEach((tr, idx) => {
tr.querySelector('td:first-child').textContent = idx + 1;
tr.querySelectorAll('input').forEach(input => {
const field = input.getAttribute('data-field');
input.name = `items[${idx}][${field}]`;
});
});
}
function rowHasData(row) {
const inputs = row.querySelectorAll('input');
return Array.from(inputs).some(inp => inp.value.trim() !== '');
}
function focusFirstInput() {
const first = itemsTableBody.querySelector('tr:first-child input');
if (first) first.focus();
}
// ------- PAGINATION INITIALIZE -------
initializePagination();
// Reset temp data function
const resetTempData = () => {
fetch('{{ route("admin.orders.temp.reset") }}', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRF-TOKEN': '{{ csrf_token() }}'
}
});
};
// Modal functions
const openModal = () => {
modal.classList.add('show');
document.body.style.overflow = 'hidden';
document.querySelector('.alert-success')?.remove();
generateDefaultRows();
};
const closeModal = () => {
modal.classList.remove('show');
document.body.style.overflow = '';
@if(session('temp_order_items') && count(session('temp_order_items')) > 0)
setTimeout(() => {
resetTempData();
window.location.reload();
}, 100);
@endif
};
// Clear form -> clear items table
const clearForm = () => {
generateDefaultRows();
};
// Event listeners
openBtn.addEventListener('click', openModal);
closeBtn.addEventListener('click', closeModal);
clearFormBtn.addEventListener('click', clearForm);
modal.addEventListener('click', (e) => e.target === modal && closeModal());
document.addEventListener('keydown', (e) => e.key === 'Escape' && modal.classList.contains('show') && closeModal());
// Mark No functionality
const markNoSelect = document.getElementById('markNoSelect');
if (markNoSelect) {
markNoSelect.addEventListener('change', function() {
const locked = {{ session('temp_order_items') ? 'true' : 'false' }};
if (locked) {
alert("You must finish the current order before changing Mark No.");
this.value = "{{ session('mark_no') }}";
return;
}
const option = this.options[this.selectedIndex];
document.getElementById('originField').value = option.dataset.origin || '';
document.getElementById('destinationField').value = option.dataset.destination || '';
});
}
// Auto open modal if temp items exist
@if(session('temp_order_items') && count(session('temp_order_items')) > 0)
modal.classList.add('show');
document.body.style.overflow = 'hidden';
generateDefaultRows();
@endif
// Reset confirmation
document.querySelectorAll('form[action="{{ route("admin.orders.temp.reset") }}"]')
.forEach(form => form.addEventListener('submit', e => {
if (!confirm('Are you sure you want to reset the current order? All temporary items will be lost.')) {
e.preventDefault();
}
}));
// Order details modal functionality
document.querySelectorAll('.open-order-modal').forEach(button => {
button.addEventListener('click', function() {
let id = this.dataset.id;
let modalInstance = new bootstrap.Modal(document.getElementById('orderDetailsModal'));
document.getElementById('orderDetailsBody').innerHTML =
"<p class='text-center text-muted'>Loading...</p>";
modalInstance.show();
fetch(`/admin/orders/view/${id}`)
.then(response => response.text())
.then(html => {
document.getElementById('orderDetailsBody').innerHTML = html;
})
.catch(() => {
document.getElementById('orderDetailsBody').innerHTML =
"<p class='text-danger text-center'>Failed to load order details.</p>";
});
});
});
/* ---------- Pagination Functions ---------- */
function initializePagination() {
renderOrdersTable(allOrders);
updatePaginationControls();
document.getElementById('prevPageBtn').addEventListener('click', goToPreviousPage);
document.getElementById('nextPageBtn').addEventListener('click', goToNextPage);
}
function goToPreviousPage() {
if (currentPage > 1) {
currentPage--;
renderOrdersTable(allOrders);
updatePaginationControls();
}
}
function goToNextPage() {
const totalPages = Math.ceil(allOrders.length / ordersPerPage);
if (currentPage < totalPages) {
currentPage++;
renderOrdersTable(allOrders);
updatePaginationControls();
}
}
function updatePaginationControls() {
const totalPages = Math.ceil(allOrders.length / ordersPerPage);
const prevBtn = document.getElementById('prevPageBtn');
const nextBtn = document.getElementById('nextPageBtn');
const pageInfo = document.getElementById('pageInfo');
const paginationPages = document.getElementById('paginationPages');
prevBtn.disabled = currentPage === 1;
nextBtn.disabled = currentPage === totalPages || totalPages === 0;
const startIndex = (currentPage - 1) * ordersPerPage + 1;
const endIndex = Math.min(currentPage * ordersPerPage, allOrders.length);
pageInfo.textContent = `Showing ${startIndex} to ${endIndex} of ${allOrders.length} entries`;
paginationPages.innerHTML = '';
if (totalPages <= 7) {
for (let i = 1; i <= totalPages; i++) {
addPageButton(i, paginationPages);
}
} else {
addPageButton(1, paginationPages);
if (currentPage > 3) {
paginationPages.innerHTML += '<span class="pagination-ellipsis">...</span>';
}
const start = Math.max(2, currentPage - 1);
const end = Math.min(totalPages - 1, currentPage + 1);
for (let i = start; i <= end; i++) {
addPageButton(i, paginationPages);
}
if (currentPage < totalPages - 2) {
paginationPages.innerHTML += '<span class="pagination-ellipsis">...</span>';
}
addPageButton(totalPages, paginationPages);
}
}
function addPageButton(pageNumber, container) {
const button = document.createElement('button');
button.className = 'pagination-page-btn';
if (pageNumber === currentPage) {
button.classList.add('active');
}
button.textContent = pageNumber;
button.addEventListener('click', () => {
currentPage = pageNumber;
renderOrdersTable(allOrders);
updatePaginationControls();
});
container.appendChild(button);
}
function renderOrdersTable(orders) {
const tbody = document.getElementById('ordersTableBody');
tbody.innerHTML = '';
if (!orders || orders.length === 0) {
tbody.innerHTML = '<tr><td colspan="16" class="text-muted">No orders found</td></tr>';
return;
}
const startIndex = (currentPage - 1) * ordersPerPage;
const endIndex = startIndex + ordersPerPage;
const paginatedOrders = orders.slice(startIndex, endIndex);
paginatedOrders.forEach(order => {
// Use original logic for badge classes
const badgeMap = {
'order_placed': 'secondary',
'order_confirmed': 'info',
'supplier_warehouse': 'warning',
'consolidate_warehouse': 'warning',
'export_custom': 'primary',
'international_transit': 'primary',
'arrived_india': 'info',
'import_custom': 'info',
'warehouse': 'dark',
'domestic_distribution': 'primary',
'out_for_delivery': 'success',
'delivered': 'success',
'pending': 'warning'
};
const iconMap = {
'order_placed': 'bi-clock-fill',
'order_confirmed': 'bi-check-circle',
'supplier_warehouse': 'bi-box-seam',
'consolidate_warehouse': 'bi-boxes',
'export_custom': 'bi-upload',
'international_transit': 'bi-truck',
'arrived_india': 'bi-geo-alt',
'import_custom': 'bi-download',
'warehouse': 'bi-building',
'domestic_distribution': 'bi-diagram-3',
'out_for_delivery': 'bi-truck-flatbed',
'delivered': 'bi-check-circle-fill',
'pending': 'bi-clock-fill'
};
const badgeClass = badgeMap[order.status] || 'secondary';
const iconClass = iconMap[order.status] || 'bi-info-circle';
const tr = document.createElement('tr');
tr.innerHTML = `
<td>${order.id}</td>
<td>
<a href="javascript:void(0)"
class="fw-semibold text-primary open-order-modal"
data-id="${order.id}">
${order.order_id}
</a>
</td>
<td>${order.mark_no || ''}</td>
<td>${order.origin || ''}</td>
<td>${order.destination || ''}</td>
<td>${order.ctn || ''}</td>
<td>${order.qty || ''}</td>
<td>${order.ttl_qty || ''}</td>
<td>₹${order.ttl_amount ? Number(order.ttl_amount).toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 }) : '0.00'}</td>
<td>${order.cbm || ''}</td>
<td>${order.ttl_cbm || ''}</td>
<td>${order.kg || ''}</td>
<td>${order.ttl_kg || ''}</td>
<td>
<span class="badge bg-${badgeClass}">
<i class="bi ${iconClass}"></i>
${order.status_label || order.status || 'N/A'}
</span>
</td>
<td>${new Date(order.created_at).toLocaleDateString('en-GB')}</td>
<td>
<a href="/admin/orders/${order.id}" class="btn btn-sm btn-outline-primary">
<i class="bi bi-eye"></i> View
</a>
</td>
`;
tbody.appendChild(tr);
const orderLink = tr.querySelector('.open-order-modal');
if (orderLink) {
orderLink.addEventListener('click', function() {
let id = this.dataset.id;
let modalInstance = new bootstrap.Modal(document.getElementById('orderDetailsModal'));
document.getElementById('orderDetailsBody').innerHTML =
"<p class='text-center text-muted'>Loading...</p>";
modalInstance.show();
fetch(`/admin/orders/view/${id}`)
.then(response => response.text())
.then(html => {
document.getElementById('orderDetailsBody').innerHTML = html;
})
.catch(() => {
document.getElementById('orderDetailsBody').innerHTML =
"<p class='text-danger text-center'>Failed to load order details.</p>";
});
});
}
});
}
// Enter key behavior for items table
itemsTableBody.addEventListener('keydown', function(e) {
if (e.key !== 'Enter' || e.target.tagName !== 'INPUT') return;
e.preventDefault();
const currentInput = e.target;
const currentRow = currentInput.closest('tr');
const rows = Array.from(itemsTableBody.querySelectorAll('tr'));
const currentRowIndex = rows.indexOf(currentRow);
const inputs = Array.from(currentRow.querySelectorAll('input'));
const currentInputIndex = inputs.indexOf(currentInput);
const isLastRow = currentRowIndex === rows.length - 1;
const hasData = rowHasData(currentRow);
if (currentInputIndex < inputs.length - 1) {
inputs[currentInputIndex + 1].focus();
return;
}
if (!isLastRow) {
const nextRow = rows[currentRowIndex + 1];
const firstInputNextRow = nextRow.querySelector('input');
if (firstInputNextRow) firstInputNextRow.focus();
return;
}
if (isLastRow && hasData) {
const newIndex = rows.length;
addRow(newIndex);
reindexRows();
const newRow = itemsTableBody.querySelector('tr:last-child');
const firstInput = newRow.querySelector('input');
if (firstInput) firstInput.focus();
}
});
// Remove row
itemsTableBody.addEventListener('click', function(e) {
if (!e.target.classList.contains('remove-row-btn')) return;
const rows = itemsTableBody.querySelectorAll('tr');
if (rows.length <= 1) {
alert('At least one row must exist.');
return;
}
e.target.closest('tr').remove();
reindexRows();
});
// ===== EXCEL UPLOAD LOGIC =====
const uploadExcelBtn = document.getElementById('uploadExcelBtn');
const excelInput = document.getElementById('excelInput');
if (uploadExcelBtn && excelInput) {
uploadExcelBtn.addEventListener('click', () => excelInput.click());
excelInput.addEventListener('change', function () {
const file = this.files[0];
if (!file) return;
const formData = new FormData();
formData.append('excel', file);
formData.append('_token', '{{ csrf_token() }}');
fetch('{{ route("admin.orders.upload.excel.preview") }}', {
method: 'POST',
body: formData,
headers: {
'Accept': 'application/json'
}
})
.then(async res => {
if (!res.ok) {
const text = await res.text();
throw new Error(text);
}
return res.json();
})
.then(res => {
if (!res.success) {
alert('Invalid Excel file');
return;
}
populateItemsTable(res.items);
})
.catch(err => {
console.error(err);
alert('Excel upload failed');
});
});
}
function populateItemsTable(items) {
itemsTableBody.innerHTML = '';
items.forEach((item, index) => {
addRow(index);
const row = itemsTableBody.children[index];
row.querySelector('[data-field="description"]').value = item.description ?? '';
row.querySelector('[data-field="ctn"]').value = item.ctn ?? 0;
row.querySelector('[data-field="qty"]').value = item.qty ?? 0;
row.querySelector('[data-field="unit"]').value = item.unit ?? '';
row.querySelector('[data-field="price"]').value= item.price ?? 0;
row.querySelector('[data-field="cbm"]').value = item.cbm ?? 0;
row.querySelector('[data-field="kg"]').value = item.kg ?? 0;
row.querySelector('[data-field="shop_no"]').value = item.shop_no ?? '';
calculateRow(row);
});
reindexRows();
}
});
document.addEventListener("hidden.bs.modal", function () {
document.querySelectorAll(".modal-backdrop").forEach(el => el.remove());
document.body.classList.remove("modal-open");
document.body.style.overflow = "";
});
</script>
@endsection