Files
Kent-logistics-Laravel/resources/views/admin/shipments.blade.php
Utkarsh Khedkar 8b6d3d5fad Account Changes
2025-12-27 11:15:00 +05:30

2767 lines
88 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', 'Shipment Management')
@section('content')
<style>
/* Remove horizontal scroll bar from body */
html, body {
overflow-x: hidden !important;
max-width: 100vw !important;
}
.container-fluid {
padding-left: 15px !important;
padding-right: 15px !important;
max-width: 100vw !important;
overflow-x: hidden !important;
}
/* Card and table container fixes */
.card {
width: 100% !important;
max-width: 100vw !important;
overflow: hidden !important;
}
.card-body {
padding: 0 !important;
overflow: hidden !important;
max-width: 100% !important;
}
.table-responsive {
width: 100% !important;
max-width: 100vw !important
overflow-x: auto !important;
overflow-x: hidden !important;
margin: 0 !important;
padding: 0 !important;
-webkit-overflow-scrolling: touch;
}
.table-responsive {
overflow-x: hidden !important; /* auto ऐवजी hidden जर full remove करायचं असेल तर */
}
/* Table specific fixes */
.table {
width: 100% !important;
/* min-width: 1200px !important; */
margin: 0 !important;
border-collapse: separate;
border-spacing: 0;
table-layout: auto !important;
}
.table thead th,
.table tbody td {
padding: 12px 8px !important;
vertical-align: middle !important;
white-space: nowrap !important;
}
/* Make sure modals don't cause horizontal scroll */
.modal {
overflow-x: hidden !important;
}
.modal-content {
/* max-width: 100vw !important; */
overflow-x: hidden !important;
width: 1250px;
margin-left:-45px;
}
.modal-body {
max-width: 100% !important;
overflow-x: hidden !important;
}
/* Specific fixes for different table types */
.custom-table-modal,
.shipment-details-table {
width: 100% !important;
min-width: 1300px !important;
table-layout: auto !important;
}
: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);
}
.search-shipment-bar {
display: flex;
align-items: center;
gap: 15px;
padding: 20px;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
border-radius: 16px;
box-shadow: var(--card-shadow);
flex-wrap: wrap;
margin-bottom: 30px;
color: white;
position: relative;
overflow: hidden;
width: 100% !important;
max-width: 100% !important;
}
.search-shipment-bar::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(255,255,255,0.1);
z-index: 0;
}
.search-shipment-bar > * {
position: relative;
z-index: 1;
}
.search-shipment-bar input,
.search-shipment-bar select {
padding: 12px 16px;
border: 1px solid rgba(255,255,255,0.2);
border-radius: 10px;
flex: 1;
min-width: 150px;
background: rgba(255,255,255,0.9);
font-weight: 500;
transition: all 0.3s ease;
}
.search-shipment-bar input:focus,
.search-shipment-bar select:focus {
background: white;
box-shadow: 0 0 0 3px rgba(255,255,255,0.3);
outline: none;
}
.btn-add-shipment {
background: rgba(255,255,255,0.2);
backdrop-filter: blur(10px);
color: white;
border: 1px solid rgba(255,255,255,0.3);
padding: 12px 24px;
border-radius: 10px;
cursor: pointer;
display: flex;
align-items: center;
gap: 8px;
transition: all 0.3s ease;
white-space: nowrap;
font-weight: 600;
}
.btn-add-shipment:hover {
background: rgba(255,255,255,0.3);
transform: translateY(-2px);
box-shadow: 0 10px 20px rgba(0,0,0,0.1);
}
.search-icon {
font-size: 20px;
filter: drop-shadow(0 2px 4px rgba(0,0,0,0.1));
}
.truck-icon {
font-size: 18px;
}
@media (max-width: 768px) {
.search-shipment-bar {
flex-direction: column;
align-items: stretch;
}
.search-shipment-bar input,
.search-shipment-bar select {
width: 100%;
}
}
/* Card Styles */
.card {
border: none;
border-radius: 16px;
box-shadow: var(--card-shadow);
transition: all 0.3s ease;
overflow: hidden;
width: 100% !important;
max-width: 100% !important;
}
.card:hover {
transform: translateY(-5px);
box-shadow: var(--hover-shadow);
}
.card-header {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
border: none;
padding: 20px 25px;
border-radius: 16px 16px 0 0 !important;
width: 100% !important;
}
.card-header h5 {
margin: 0;
font-weight: 700;
display: flex;
align-items: center;
gap: 10px;
}
/* Table Styles */
.table-responsive {
border-radius: 0 0 16px 16px;
overflow-x: auto !important;
width: 100% !important;
}
.table thead th {
background: #f8f9fa;
border: none;
padding: 16px 12px;
font-weight: 700;
color: var(--dark);
text-align: center;
vertical-align: middle;
border-bottom: 2px solid var(--border);
position: relative;
white-space: nowrap;
}
.table thead th:first-child {
border-radius: 0;
}
.table thead th:last-child {
border-radius: 0;
}
.table tbody tr {
transition: all 0.3s ease;
border-radius: 10px;
}
.table tbody tr:hover {
background-color: #f8f9ff;
transform: scale(1.01);
box-shadow: 0 4px 12px rgba(0,0,0,0.1);
}
.table tbody td {
padding: 14px 12px;
text-align: center;
vertical-align: middle;
border-bottom: 1px solid var(--border);
font-weight: 500;
white-space: nowrap;
}
.table tbody tr:last-child td {
border-bottom: none;
}
/* UPDATED: Status Badge Styles - ALL SAME SIZE */
.badge {
padding: 7px 17px !important;
border-radius: 20px !important;
font-weight: 600 !important;
font-size: 13px !important;
border: 2px solid transparent !important;
min-width: 40px !important;
text-align: center !important;
display: inline-block !important;
line-height: 1.2 !important;
}
/* Status-specific badges */
/* 1⃣ Shipment Ready ORANGE (Process Start) */
.badge-shipment_ready {
background: linear-gradient(135deg, #ffedd5, #fdba74) !important;
color: #9a3412 !important;
border-color: #f97316 !important;
width: 160px;
}
/* 2⃣ Export Custom PURPLE (Official / Docs) */
.badge-export_custom {
background: linear-gradient(135deg, #ede9fe, #c4b5fd) !important;
color: #5b21b6 !important;
border-color: #8b5cf6 !important;
width: 160px;
}
/* 3⃣ International Transit YELLOW (In-Transit / Alert) */
.badge-international_transit {
background: linear-gradient(135deg, #fef9c3, #fde047) !important;
color: #a16207 !important;
border-color: #facc15 !important;
width: 160px;
}
/* 4⃣ Arrived India GREEN (Safe Arrival) */
.badge-arrived_india {
background: linear-gradient(135deg, #dcfce7, #86efac) !important;
color: #166534 !important;
border-color: #22c55e !important;
width: 160px;
}
/* 5⃣ Import Custom AMBER (Verification / Hold) */
.badge-import_custom {
background: linear-gradient(135deg, #fef3c7, #fbbf24) !important;
color: #92400e !important;
border-color: #f59e0b !important;
width: 160px;
}
/* 6⃣ Warehouse INDIGO (Storage / Control) */
.badge-warehouse {
background: linear-gradient(135deg, #e0e7ff, #a5b4fc) !important;
color: #312e81 !important;
border-color: #6366f1 !important;
width: 160px;
}
/* 7⃣ Domestic Distribution BLUE (Movement) */
.badge-domestic_distribution {
background: linear-gradient(135deg, #dbeafe, #60a5fa) !important;
color: #1e3a8a !important;
border-color: #3b82f6 !important;
width: 160px;
}
/* 8⃣ Out For Delivery PINK (Final Action) */
.badge-out_for_delivery {
background: linear-gradient(135deg, #fce7f3, #f9a8d4) !important;
color: #9d174d !important;
border-color: #ec4899 !important;
width: 160px;
}
/* 9⃣ Delivered DARK GREEN (Success) */
.badge-delivered {
background: linear-gradient(135deg, #d1fae5, #6ee7b7) !important;
color: #065f46 !important;
border-color: #10b981 !important;
width: 150px;
}
/* Default badge styles - SAME SIZE */
.badge.bg-info {
background: linear-gradient(135deg, #4cc9f0, #4361ee) !important;
color: white !important;
}
.badge.bg-success {
background: linear-gradient(135deg, #4ade80, #22c55e) !important;
color: white !important;
}
.badge.bg-warning {
background: linear-gradient(135deg, #fbbf24, #f59e0b) !important;
color: white !important;
}
.badge.bg-danger {
background: linear-gradient(135deg, #f87171, #ef4444) !important;
color: white !important;
}
/* Light badges for quantity, kg, cbm */
.badge.bg-light {
background: #f8f9fa !important;
color: #212529 !important;
border: 1px solid #dee2e6 !important;
min-width: 80px !important;
padding: 6px 12px !important;
}
/* Eye Button Style - PROPER */
.btn-eye {
background: linear-gradient(135deg, #4cc9f0, #4361ee);
color: white;
border: none;
border-radius: 8px;
padding: 8px 10px;
cursor: pointer;
transition: all 0.3s ease;
display: flex;
align-items: center;
justify-content: center;
width: 36px;
height: 36px;
margin: 0 auto;
}
.btn-eye:hover {
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(76, 201, 240, 0.3);
background: linear-gradient(135deg, #38bdf8, #3a56d4);
}
/* Action Button Styles */
.action-container {
position: relative;
display: inline-block;
}
.btn-edit-status {
background: linear-gradient(135deg, #667eea, #764ba2);
color: white;
border: none;
border-radius: 8px;
padding: 8px 10px;
cursor: pointer;
transition: all 0.3s ease;
display: flex;
align-items: center;
justify-content: center;
width: 36px;
height: 36px;
}
.btn-edit-status:hover {
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(102, 126, 234, 0.3);
background: linear-gradient(135deg, #5a6fd8, #6a42a0);
}
/* ==================== PROFESSIONAL STATUS DROPDOWN STYLES ==================== */
.status-dropdown {
position: absolute;
top: calc(100% + 5px);
right: 50px;
background: white;
border-radius: 12px;
box-shadow: 0 10px 40px rgba(0, 0, 0, 0.15);
padding: 8px 0;
min-width: 200px;
display: none;
flex-direction: column;
border: 1px solid rgba(0, 0, 0, 0.08);
z-index: 1050;
overflow: hidden;
}
.status-dropdown.show {
display: flex;
animation: dropdownFadeIn 0.2s ease-out;
}
@keyframes dropdownFadeIn {
from {
opacity: 0;
transform: translateY(-10px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.status-dropdown .status-form {
display: flex;
flex-direction: column;
gap: 2px;
padding: 0;
}
/* Status Option Styles - PROFESSIONAL DESIGN */
.status-option {
padding: 12px 16px;
border: none;
border-radius: 0;
cursor: pointer;
font-size: 14px;
font-weight: 500;
transition: all 0.2s ease;
text-align: left;
display: flex;
align-items: center;
gap: 12px;
background: transparent;
width: 100%;
color: #4a5568;
border-left: 3px solid transparent;
position: relative;
overflow: hidden;
}
.status-option:hover {
background: linear-gradient(90deg, rgba(248, 250, 252, 0.8), rgba(241, 245, 249, 0.8));
color: #2d3748;
transform: none;
border-left-color: currentColor;
}
.status-option:active {
background: linear-gradient(90deg, rgba(226, 232, 240, 0.8), rgba(203, 213, 224, 0.8));
}
/* Status option specific colors */
.status-option.shipment_ready {
color: #3b82f6;
}
.status-option.export_custom {
color: #8b5cf6;
}
.status-option.international_transit {
color: #f59e0b;
}
.status-option.arrived_india {
color: #10b981;
}
.status-option.import_custom {
color: #f59e0b;
}
.status-option.warehouse {
color: #7c3aed;
}
.status-option.domestic_distribution {
color: #3b82f6;
}
.status-option.out_for_delivery {
color: #ec4899;
}
.status-option.delivered {
color: #10b981;
}
/* Status indicator - UPDATED DESIGN */
.status-indicator {
width: 10px;
height: 10px;
border-radius: 50%;
display: inline-block;
border: 2px solid currentColor;
background-color: currentColor;
box-shadow: 0 0 8px currentColor;
transition: all 0.3s ease;
}
.status-option:hover .status-indicator {
transform: scale(1.2);
box-shadow: 0 0 12px currentColor;
}
.status-indicator.shipment_ready {
background-color: #3b82f6;
border-color: #3b82f6;
}
.status-indicator.export_custom {
background-color: #8b5cf6;
border-color: #8b5cf6;
}
.status-indicator.international_transit {
background-color: #f59e0b;
border-color: #f59e0b;
}
.status-indicator.arrived_india {
background-color: #10b981;
border-color: #10b981;
}
.status-indicator.import_custom {
background-color: #f59e0b;
border-color: #f59e0b;
}
.status-indicator.warehouse {
background-color: #7c3aed;
border-color: #7c3aed;
}
.status-indicator.domestic_distribution {
background-color: #3b82f6;
border-color: #3b82f6;
}
.status-indicator.out_for_delivery {
background-color: #ec4899;
border-color: #ec4899;
}
.status-indicator.delivered {
background-color: #10b981;
border-color: #10b981;
}
/* Status option text with gradient effect on hover */
.status-option::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.1), transparent);
transform: translateX(-100%);
transition: transform 0.3s ease;
}
.status-option:hover::before {
transform: translateX(100%);
}
/* ==================== END STATUS DROPDOWN STYLES ==================== */
/* ==================== PROFESSIONAL STATUS FILTER STYLES ==================== */
.status-filter-container {
position: relative;
flex: 1;
min-width: 200px;
}
.status-filter-select {
cursor: pointer;
appearance: none;
-webkit-appearance: none;
-moz-appearance: none;
width: 100%;
padding: 12px 45px 12px 16px;
border: 1px solid rgba(255, 255, 255, 0.2);
border-radius: 10px;
background: rgba(255, 255, 255, 0.9);
font-weight: 500;
font-size: 14px;
color: #2d3748;
transition: all 0.3s ease;
position: relative;
background-image: url("data:image/svg+xml;charset=UTF-8,%3csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%236c757d' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3e%3cpolyline points='6 9 12 15 18 9'%3e%3c/polyline%3e%3c/svg%3e");
background-repeat: no-repeat;
background-position: right 12px center;
background-size: 18px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
}
.status-filter-select:hover {
background-color: white;
border-color: rgba(255, 255, 255, 0.3);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
}
.status-filter-select:focus {
outline: none;
border-color: rgba(255, 255, 255, 0.4);
background-color: white;
box-shadow: 0 0 0 3px rgba(255, 255, 255, 0.2);
}
/* Status filter option colors */
.status-filter-select option {
padding: 12px;
font-weight: 500;
}
.status-filter-select option[value="shipment_ready"] {
color: #3b82f6;
background: linear-gradient(135deg, rgba(219, 234, 254, 0.1), rgba(147, 197, 253, 0.1));
}
.status-filter-select option[value="export_custom"] {
color: #8b5cf6;
background: linear-gradient(135deg, rgba(233, 213, 255, 0.1), rgba(196, 181, 253, 0.1));
}
.status-filter-select option[value="international_transit"] {
color: #f59e0b;
background: linear-gradient(135deg, rgba(254, 243, 199, 0.1), rgba(253, 230, 138, 0.1));
}
.status-filter-select option[value="arrived_india"] {
color: #10b981;
background: linear-gradient(135deg, rgba(209, 250, 229, 0.1), rgba(167, 243, 208, 0.1));
}
.status-filter-select option[value="import_custom"] {
color: #f59e0b;
background: linear-gradient(135deg, rgba(253, 230, 138, 0.1), rgba(251, 191, 36, 0.1));
}
.status-filter-select option[value="warehouse"] {
color: #7c3aed;
background: linear-gradient(135deg, rgba(196, 181, 253, 0.1), rgba(167, 139, 250, 0.1));
}
.status-filter-select option[value="domestic_distribution"] {
color: #3b82f6;
background: linear-gradient(135deg, rgba(147, 197, 253, 0.1), rgba(96, 165, 250, 0.1));
}
.status-filter-select option[value="out_for_delivery"] {
color: #ec4899;
background: linear-gradient(135deg, rgba(251, 207, 232, 0.1), rgba(249, 168, 212, 0.1));
}
.status-filter-select option[value="delivered"] {
color: #10b981;
background: linear-gradient(135deg, rgba(209, 250, 229, 0.1), rgba(167, 243, 208, 0.1));
}
.status-filter-select option[value="all"] {
color: #64748b;
background: linear-gradient(135deg, rgba(248, 250, 252, 0.1), rgba(241, 245, 249, 0.1));
}
/* Status filter indicator in dropdown */
.status-filter-select::after {
content: '';
position: absolute;
right: 40px;
top: 50%;
transform: translateY(-50%);
width: 8px;
height: 8px;
border-radius: 50%;
display: none;
}
.status-filter-select[data-status="shipment_ready"]::after {
background-color: #3b82f6;
display: block;
}
.status-filter-select[data-status="export_custom"]::after {
background-color: #8b5cf6;
display: block;
}
.status-filter-select[data-status="international_transit"]::after {
background-color: #f59e0b;
display: block;
}
.status-filter-select[data-status="arrived_india"]::after {
background-color: #10b981;
display: block;
}
.status-filter-select[data-status="import_custom"]::after {
background-color: #f59e0b;
display: block;
}
.status-filter-select[data-status="warehouse"]::after {
background-color: #7c3aed;
display: block;
}
.status-filter-select[data-status="domestic_distribution"]::after {
background-color: #3b82f6;
display: block;
}
.status-filter-select[data-status="out_for_delivery"]::after {
background-color: #ec4899;
display: block;
}
.status-filter-select[data-status="delivered"]::after {
background-color: #10b981;
display: block;
}
/* ==================== END STATUS FILTER STYLES ==================== */
/* Modal Styles */
.modal-content {
border-radius: 20px;
border: none;
box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);
overflow: hidden;
}
.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;
}
/* Form Styles */
.form-label {
font-weight: 600;
color: #5a6c7d;
margin-bottom: 8px;
font-size: 0.9rem;
}
.form-control {
border-radius: 10px;
border: 1px solid #e2e8f0;
padding: 12px 16px;
font-size: 15px;
transition: all 0.3s ease;
background: #fafbfc;
color: #4a5568;
}
.form-control:focus {
border-color: #a3bffa;
box-shadow: 0 0 0 3px rgba(163, 191, 250, 0.2);
background: white;
}
.form-control::placeholder {
color: #a0aec0;
}
/* Date Input Styling */
input[type="date"] {
position: relative;
}
input[type="date"]::-webkit-calendar-picker-indicator {
background: transparent;
bottom: 0;
color: transparent;
cursor: pointer;
height: auto;
left: 0;
position: absolute;
right: 0;
top: 0;
width: auto;
}
input[type="date"] {
position: relative;
padding-right: 40px;
}
input[type="date"]:after {
content: "📅";
position: absolute;
right: 12px;
top: 50%;
transform: translateY(-50%);
pointer-events: none;
font-size: 16px;
}
/* Button Styles */
.btn-cancel {
background: #f7fafc;
color: #718096;
border: 1px solid #cbd5e0;
border-radius: 10px;
font-weight: 600;
padding: 12px 30px;
transition: all 0.3s ease;
}
.btn-cancel:hover {
background: #edf2f7;
color: #4a5568;
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(0,0,0,0.1);
}
.btn-create {
background: linear-gradient(135deg, #48bb78, #38a169);
color: white;
font-weight: 600;
font-size: 16px;
border-radius: 10px;
padding: 12px 35px;
border: none;
transition: all 0.3s ease;
}
.btn-create:hover {
transform: translateY(-2px);
box-shadow: 0 10px 20px rgba(72, 187, 120, 0.3);
background: linear-gradient(135deg, #38a169, #2f855a);
}
/* Custom Table in Modal */
.custom-table-modal {
width: 100%;
border-collapse: separate;
border-spacing: 0 8px;
margin: 0;
min-width: 1300px;
}
.custom-table-modal thead th {
background: linear-gradient(135deg, #ebf8ff, #f0fff4);
color: #2b6cb0;
font-weight: 600;
padding: 16px 10px;
border: 1px solid #e2e8f0;
text-align: center;
position: relative;
font-size: 0.9rem;
letter-spacing: 0.3px;
white-space: nowrap;
}
.custom-table-modal thead th:first-child {
border-top-left-radius: 12px;
border-bottom-left-radius: 12px;
}
.custom-table-modal thead th:last-child {
border-top-right-radius: 12px;
border-bottom-right-radius: 12px;
}
.custom-table-modal tbody tr {
background: #fdfdfe;
border-radius: 10px;
box-shadow: 0 1px 3px rgba(0,0,0,0.04);
transition: all 0.3s ease;
border: 1px solid #f1f5f9;
}
.custom-table-modal tbody tr:hover {
transform: translateY(-1px);
box-shadow: 0 4px 12px rgba(0,0,0,0.08);
border-color: #e2e8f0;
background: white;
}
.custom-table-modal tbody td {
padding: 14px 10px;
text-align: center;
vertical-align: middle;
border: none;
font-weight: 500;
position: relative;
color: #4a5568;
white-space: nowrap;
}
.custom-table-modal tbody tr td:first-child {
border-top-left-radius: 10px;
border-bottom-left-radius: 10px;
}
.custom-table-modal tbody tr td:last-child {
border-top-right-radius: 10px;
border-bottom-right-radius: 10px;
}
/* Checkbox Styling */
input[type="checkbox"] {
width: 20px;
height: 20px;
border-radius: 6px;
border: 2px solid #cbd5e0;
cursor: pointer;
position: relative;
transition: all 0.2s ease;
background: #f7fafc;
}
input[type="checkbox"]:checked {
background: var(--primary);
border-color: var(--primary);
}
/* Link Styling */
a.text-primary {
color: var(--primary) !important;
text-decoration: none;
font-weight: 600;
transition: all 0.3s ease;
position: relative;
color: #4361ee !important;
}
a.text-primary:hover {
color: var(--primary-dark) !important;
text-decoration: underline;
}
/* Shipment Details Modal - EDGE-TO-EDGE STYLING */
.modal-xl.edge-to-edge {
max-width: 95vw !important;
width: 95vw !important;
margin: 1vh auto !important;
}
/* UPDATED: Shipment Order Details Modal - ALSO EDGE-TO-EDGE */
.modal-xl.edge-to-edge.order-details-modal {
max-width: 95vw !important;
width: 95vw !important;
margin: 1vh auto !important;
}
.shipment-details-header {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
border: none;
padding: 25px 35px 15px;
border-radius: 20px 20px 0 0;
}
.shipment-details-body {
padding: 30px 35px;
width: 100%;
}
.shipment-info-row {
display: flex;
justify-content: space-between;
margin-bottom: 25px;
padding: 20px;
background: #f8fafc;
border-radius: 12px;
box-shadow: 0 2px 10px rgba(0,0,0,0.05);
}
.shipment-info-item {
flex: 1;
text-align: center;
padding: 0 15px;
}
.shipment-info-label {
font-weight: 600;
color: #64748b;
font-size: 14px;
margin-bottom: 5px;
}
.shipment-info-value {
font-weight: 700;
font-size: 18px;
color: var(--dark);
}
.shipment-details-table {
width: 100%;
border-collapse: separate;
border-spacing: 0 8px;
margin-top: 20px;
min-width: 1400px;
}
.shipment-details-table th {
background: #f1f5f9;
padding: 16px 12px;
text-align: center;
font-weight: 700;
color: var(--dark);
border: none;
position: relative;
white-space: nowrap;
}
.shipment-details-table th:first-child {
border-top-left-radius: 10px;
border-bottom-left-radius: 10px;
}
.shipment-details-table th:last-child {
border-top-right-radius: 10px;
border-bottom-right-radius: 10px;
}
.shipment-details-table td {
padding: 14px 12px;
text-align: center;
border: none;
background: white;
box-shadow: 0 2px 5px rgba(0,0,0,0.05);
white-space: nowrap;
}
.shipment-details-table tr td:first-child {
border-top-left-radius: 10px;
border-bottom-left-radius: 10px;
}
.shipment-details-table tr td:last-child {
border-top-right-radius: 10px;
border-bottom-right-radius: 10px;
}
/* Shipment Totals Section - SINGLE ROW ON DESKTOP */
.shipment-totals {
margin-top: 25px;
padding: 25px 20px;
background: linear-gradient(135deg, #f8fafc, #e2e8f0);
border-radius: 12px;
box-shadow: 0 4px 6px rgba(0,0,0,0.05);
border-left: 4px solid #4361ee;
width: 100%;
}
.shipment-totals-row {
display: grid;
grid-template-columns: repeat(8, 1fr);
gap: 12px;
justify-content: center;
align-items: stretch;
width: 100%;
}
.shipment-total-item {
text-align: center;
padding: 15px 10px;
background: white;
border-radius: 10px;
box-shadow: 0 2px 8px rgba(0,0,0,0.08);
min-width: 0;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
flex-shrink: 1;
}
.shipment-total-label {
font-weight: 600;
color: #64748b;
font-size: 11px;
margin-bottom: 8px;
text-transform: uppercase;
letter-spacing: 0.5px;
line-height: 1.2;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
width: 100%;
}
.shipment-total-value {
font-weight: 800;
font-size: 18px;
color: #1e293b;
line-height: 1.2;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
width: 100%;
}
.total-amount {
color: #059669 !important;
background: linear-gradient(135deg, #d1fae5, #a7f3d0);
padding: 10px;
border-radius: 8px;
border: 2px solid #10b981;
width: 100%;
}
.total-quantity {
color: #0369a1 !important;
background: linear-gradient(135deg, #e0f2fe, #bae6fd);
padding: 10px;
border-radius: 8px;
border: 2px solid #0ea5e9;
width: 100%;
}
.total-weight {
color: #7c3aed !important;
background: linear-gradient(135deg, #f3e8ff, #e9d5ff);
padding: 10px;
border-radius: 8px;
border: 2px solid #8b5cf6;
width: 100%;
}
.total-cbm {
color: #dc2626 !important;
background: linear-gradient(135deg, #fecaca, #fca5a5);
padding: 10px;
border-radius: 8px;
border: 2px solid #ef4444;
width: 100%;
}
.total-ctn {
color: #d97706 !important;
background: linear-gradient(135deg, #fef3c7, #fde68a);
padding: 10px;
border-radius: 8px;
border: 2px solid #f59e0b;
width: 100%;
}
.total-ttl-cbm {
color: #7c3aed !important;
background: linear-gradient(135deg, #e9d5ff, #c4b5fd);
padding: 10px;
border-radius: 8px;
border: 2px solid #8b5cf6;
width: 100%;
}
.total-ttl-kg {
color: #0d9488 !important;
background: linear-gradient(135deg, #ccfbf1, #99f6e4);
padding: 10px;
border-radius: 8px;
border: 2px solid #14b8a6;
width: 100%;
}
/* Animation for loading */
@keyframes pulse {
0% { opacity: 1; }
50% { opacity: 0.5; }
100% { opacity: 1; }
}
.loading {
animation: pulse 1.5s infinite;
}
/* Shipment row styling for filtering */
.shipment-row {
transition: all 0.3s ease;
}
.shipment-row.hidden {
display: none !important;
}
.shipment-row.visible {
display: table-row;
}
/* ---------- Pagination Styles ---------- */
.pagination-container {
display: flex;
justify-content: space-between;
align-items: center;
margin-top: 15px;
padding: 12px 25px;
border-top: 1px solid #eef3fb;
width: 100%;
overflow: hidden;
}
.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;
}
/* Image-based pagination buttons */
.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 img {
width: 16px;
height: 16px;
filter: brightness(0) saturate(100%) invert(26%) sepia(89%) saturate(748%) hue-rotate(201deg) brightness(93%) contrast(89%);
transition: filter 0.3s ease;
}
.pagination-img-btn:hover:not(:disabled) img {
filter: brightness(0) saturate(100%) invert(100%) sepia(100%) saturate(0%) hue-rotate(288deg) brightness(106%) contrast(101%);
}
.pagination-img-btn:disabled img {
filter: brightness(0) saturate(100%) invert(84%) sepia(8%) saturate(165%) hue-rotate(179deg) brightness(89%) contrast(86%);
}
/* Modal table pagination styles */
.modal-pagination-container {
display: flex;
justify-content: space-between;
align-items: center;
margin-top: 15px;
padding: 10px 15px;
border-top: 1px solid #e2e8f0;
background: #f8fafc;
border-radius: 0 0 12px 12px;
width: 100%;
overflow: hidden;
}
.modal-pagination-info {
font-size: 12px;
color: #64748b;
font-weight: 600;
white-space: nowrap;
}
.modal-pagination-controls {
display: flex;
align-items: center;
gap: 6px;
flex-wrap: wrap;
}
.modal-pagination-btn {
background: #fff;
border: 1px solid #cbd5e0;
color: #475569;
padding: 5px 8px;
border-radius: 5px;
font-size: 12px;
font-weight: 600;
cursor: pointer;
transition: all 0.3s ease;
display: flex;
align-items: center;
justify-content: center;
min-width: 32px;
height: 28px;
white-space: nowrap;
}
.modal-pagination-btn:hover:not(:disabled) {
background: #4361ee;
color: white;
border-color: #4361ee;
}
.modal-pagination-btn:disabled {
background: #f1f5f9;
color: #94a3b8;
border-color: #e2e8f0;
cursor: not-allowed;
opacity: 0.6;
}
.modal-pagination-page-btn {
background: #fff;
border: 1px solid #cbd5e0;
color: #475569;
padding: 4px 8px;
border-radius: 5px;
font-size: 12px;
font-weight: 600;
cursor: pointer;
transition: all 0.3s ease;
min-width: 30px;
text-align: center;
white-space: nowrap;
}
.modal-pagination-page-btn:hover {
background: #4361ee;
color: white;
border-color: #4361ee;
}
.modal-pagination-page-btn.active {
background: #4361ee;
color: white;
border-color: #4361ee;
}
.modal-pagination-pages {
display: flex;
gap: 3px;
align-items: center;
flex-wrap: wrap;
}
.modal-pagination-ellipsis {
color: #94a3b8;
font-size: 12px;
padding: 0 4px;
}
/* RESPONSIVE DESIGN FOR TABLET/MOBILE */
@media (max-width: 1200px) {
.modal-xl.edge-to-edge {
max-width: 96vw !important;
width: 96vw !important;
margin: 2vh auto !important;
}
.modal-xl.edge-to-edge.order-details-modal {
max-width: 96vw !important;
width: 96vw !important;
margin: 2vh auto !important;
}
.shipment-totals-row {
grid-template-columns: repeat(4, 1fr);
gap: 15px;
}
.table {
min-width: 1100px !important;
}
}
@media (max-width: 992px) {
.modal-xl.edge-to-edge {
max-width: 95vw !important;
width: 95vw !important;
margin: 2.5vh auto !important;
}
.modal-xl.edge-to-edge.order-details-modal {
max-width: 95vw !important;
width: 95vw !important;
margin: 2.5vh auto !important;
}
.shipment-details-body {
padding: 20px 25px;
}
.shipment-totals-row {
grid-template-columns: repeat(3, 1fr);
}
.table {
min-width: 1000px !important;
}
}
@media (max-width: 768px) {
.pagination-container {
flex-direction: column;
gap: 10px;
align-items: stretch;
}
.pagination-controls {
justify-content: center;
}
.modal-xl.edge-to-edge {
max-width: 100vw !important;
width: 100vw !important;
margin: 0 !important;
height: 100vh !important;
max-height: 100vh !important;
}
.modal-xl.edge-to-edge.order-details-modal {
max-width: 100vw !important;
width: 100vw !important;
margin: 0 !important;
height: 100vh !important;
max-height: 100vh !important;
}
.shipment-details-body {
padding: 15px 20px;
}
.shipment-info-row {
flex-direction: column;
gap: 15px;
padding: 15px;
}
.shipment-info-item {
padding: 10px 0;
}
.shipment-totals {
padding: 20px 15px;
}
.shipment-totals-row {
grid-template-columns: repeat(2, 1fr);
gap: 12px;
}
.shipment-total-item {
padding: 12px 8px;
}
.shipment-total-label {
font-size: 10px;
}
.shipment-total-value {
font-size: 16px;
}
/* Order details modal specific responsive styles */
.order-details-content {
padding: 15px;
}
.order-details-table {
min-width: 1000px;
}
/* Modal pagination responsive */
.modal-pagination-container {
flex-direction: column;
gap: 8px;
padding: 10px;
}
.modal-pagination-controls {
justify-content: center;
}
.table {
min-width: 900px !important;
}
}
@media (max-width: 576px) {
.shipment-totals-row {
grid-template-columns: 1fr;
gap: 10px;
}
.modal-xl.edge-to-edge .modal-content {
border-radius: 0;
height: 100vh;
overflow-y: auto;
}
.modal-xl.edge-to-edge.order-details-modal .modal-content {
border-radius: 0;
height: 100vh;
overflow-y: auto;
}
.shipment-details-header {
padding: 20px 25px 15px;
border-radius: 0;
}
.order-details-header {
padding: 20px 15px 10px;
border-radius: 0;
}
.order-details-body {
padding: 15px;
}
.search-shipment-bar {
padding: 15px;
}
.table {
min-width: 800px !important;
}
}
@media (max-width: 480px) {
.modal-xl.edge-to-edge,
.modal-xl.edge-to-edge.order-details-modal {
margin: 0 !important;
padding: 0 !important;
}
.modal-content {
border-radius: 0 !important;
}
.shipment-details-body,
.order-details-body {
padding: 10px 15px;
}
.table {
min-width: 700px !important;
}
}
/* For very small screens */
@media (max-width: 360px) {
.table {
min-width: 600px !important;
}
.shipment-info-row {
padding: 10px;
}
.shipment-info-value {
font-size: 16px;
}
}
</style>
<div class="container-fluid py-4">
{{-- SUCCESS / ERROR MESSAGES --}}
@if(session('success'))
<div class="alert alert-success alert-dismissible fade show" role="alert">
<i class="bi bi-check-circle-fill me-2"></i>
{{ session('success') }}
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
</div>
@endif
@if(session('error'))
<div class="alert alert-danger alert-dismissible fade show" role="alert">
<i class="bi bi-exclamation-triangle-fill me-2"></i>
{{ session('error') }}
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
</div>
@endif
<div class="search-shipment-bar">
<span class="search-icon">🔍</span>
<input type="text" id="searchInput" placeholder="Search Shipments...">
<div class="status-filter-container">
<select id="statusFilter" class="status-filter-select">
<option value="all">All Status</option>
<option value="shipment_ready">Shipment Ready</option>
<option value="export_custom">Export Custom</option>
<option value="international_transit">International Transit</option>
<option value="arrived_india">Arrived at India</option>
<option value="import_custom">Import Custom</option>
<option value="warehouse">Warehouse</option>
<option value="domestic_distribution">Domestic Distribution</option>
<option value="out_for_delivery">Out for Delivery</option>
<option value="delivered">Delivered</option>
</select>
</div>
<!-- <select id="carrierFilter">
<option value="all">All Carriers</option>
<option value="fedex">FedEx</option>
<option value="ups">UPS</option>
<option value="dhl">DHL</option>
</select> -->
<button type="button" class="btn-add-shipment" data-bs-toggle="modal" data-bs-target="#createShipmentModal">
<span class="truck-icon">🚚</span>
Add Shipments
</button>
</div>
<!-- CREATE SHIPMENT MODAL (POPUP FORMAT) -->
<div class="modal fade" id="createShipmentModal" tabindex="-1" aria-labelledby="createShipmentModalLabel" aria-hidden="true">
<div class="modal-dialog modal-xl">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="createShipmentModalLabel">
<i class="bi bi-plus-circle me-2"></i>Create New Shipment
</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<form action="{{ route('admin.shipments.store') }}" method="POST">
@csrf
<div class="row g-3 pb-2">
<div class="col-md-4">
<label class="form-label">Origin *</label>
<input type="text" class="form-control" name="origin" placeholder="Enter origin city" required>
</div>
<div class="col-md-4">
<label class="form-label">Destination *</label>
<input type="text" class="form-control" name="destination" placeholder="Enter destination city" required>
</div>
<div class="col-md-4">
<label class="form-label">Shipment Date *</label>
<input type="date"
name="shipment_date"
class="form-control"
value="{{ date('Y-m-d') }}"
min="{{ date('Y-m-d') }}"
required>
</div>
</div>
<div class="table-responsive mt-4" style="max-height:400px; border-radius:12px;">
<table class="custom-table-modal" id="modalOrdersTable">
<thead>
<tr>
<th></th>
<th>Order ID</th>
<th>Origin</th>
<th>Destination</th>
<th>CTN</th>
<th>QTY</th>
<th>TTL/QTY</th>
<th>CBM</th>
<th>TTL CBM</th>
<th>KG</th>
<th>TTL KG</th>
<th>Amount ()</th>
</tr>
</thead>
<tbody id="modalOrdersTableBody">
<!-- Orders will be loaded here via JavaScript -->
</tbody>
</table>
</div>
<!-- Modal Pagination -->
<div class="modal-pagination-container">
<div class="modal-pagination-info" id="modalPageInfo">
Showing 0 to 0 of {{ count($availableOrders) }} entries
</div>
<div class="modal-pagination-controls">
<button class="modal-pagination-btn" id="modalPrevPageBtn" title="Previous page" disabled>
<svg width="14" height="14" 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="modal-pagination-pages" id="modalPaginationPages">
<!-- Page numbers will be inserted here -->
</div>
<button class="modal-pagination-btn" id="modalNextPageBtn" title="Next page" disabled>
<svg width="14" height="14" 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 class="d-flex justify-content-end mt-4 mb-2">
<button type="button" class="btn-cancel me-3" data-bs-dismiss="modal">Cancel</button>
<button type="submit" class="btn-create">
<i class="bi bi-check-lg me-2"></i>Create Shipment
</button>
</div>
</form>
</div>
</div>
</div>
</div>
<div class="card">
<div class="card-header">
<h5 class="mb-0"><i class="bi bi-truck me-2"></i> Shipments List</h5>
</div>
<div class="card-body p-0">
<div class="table-responsive">
<table class="table table-hover mb-0">
<thead>
<tr>
<th>#</th>
<th>Shipment ID</th>
<th>Origin</th>
<th>Destination</th>
<th>Total QTY</th>
<th>Total KG</th>
<th>Total CBM</th>
<th>Total Amount</th>
<th>Status</th>
<th>Date</th>
<th>View</th>
<th>Action</th>
</tr>
</thead>
<tbody id="shipmentsTableBody">
@php
$totalShipments = count($shipments);
@endphp
@forelse($shipments as $ship)
<tr class="shipment-row" data-status="{{ $ship->status }}" data-shipment-id="{{ $ship->shipment_id }}">
{{-- REVERSE INDEX: सर्वात वरच्या shipment ला सर्वात मोठा क्रमांक --}}
<td class="fw-bold">{{ $totalShipments - $loop->index }}</td>
<td>
<a href="#" class="text-primary fw-bold"
onclick="openShipmentDetails({{ $ship->id }})">
{{ $ship->shipment_id }}
</a>
</td>
<td>{{ $ship->origin }}</td>
<td>{{ $ship->destination }}</td>
<td><span class="badge bg-light text-dark">{{ $ship->total_qty }}</span></td>
<td><span class="badge bg-light text-dark">{{ $ship->total_kg }} kg</span></td>
<td><span class="badge bg-light text-dark">{{ $ship->total_cbm }} CBM</span></td>
<td class="fw-bold text-success">{{ number_format($ship->total_amount, 2) }}</td>
<td>
<span class="badge badge-{{ $ship->status }}">
{{ ucfirst(str_replace('_', ' ', $ship->status)) }}
</span>
</td>
<td>{{ \Carbon\Carbon::parse($ship->shipment_date)->format('d M Y') }}</td>
<td>
<a href="{{ route('admin.shipments.dummy', $ship->id) }}"
class="btn-view-details">
<i class="bi bi-eye"></i>
</a>
</td>
<td>
<div class="action-container">
<button type="button" class="btn-edit-status" onclick="toggleStatusDropdown(this, {{ $ship->id }})" title="Edit Status">
<i class="bi bi-pencil"></i>
</button>
<div class="status-dropdown" id="statusDropdown-{{ $ship->id }}">
<form action="{{ route('admin.shipments.updateStatus') }}" method="POST" class="status-form">
@csrf
<input type="hidden" name="shipment_id" value="{{ $ship->id }}">
<button type="submit" name="status" value="shipment_ready" class="status-option shipment_ready">
<span class="status-indicator shipment_ready"></span>
Shipment Ready
</button>
<button type="submit" name="status" value="export_custom" class="status-option export_custom">
<span class="status-indicator export_custom"></span>
Export Custom
</button>
<button type="submit" name="status" value="international_transit" class="status-option international_transit">
<span class="status-indicator international_transit"></span>
International Transit
</button>
<button type="submit" name="status" value="arrived_india" class="status-option arrived_india">
<span class="status-indicator arrived_india"></span>
Arrived at India
</button>
<button type="submit" name="status" value="import_custom" class="status-option import_custom">
<span class="status-indicator import_custom"></span>
Import Custom
</button>
<button type="submit" name="status" value="warehouse" class="status-option warehouse">
<span class="status-indicator warehouse"></span>
Warehouse
</button>
<button type="submit" name="status" value="domestic_distribution" class="status-option domestic_distribution">
<span class="status-indicator domestic_distribution"></span>
Domestic Distribution
</button>
<button type="submit" name="status" value="out_for_delivery" class="status-option out_for_delivery">
<span class="status-indicator out_for_delivery"></span>
Out for Delivery
</button>
<button type="submit" name="status" value="delivered" class="status-option delivered">
<span class="status-indicator delivered"></span>
Delivered
</button>
</form>
</div>
</div>
</td>
</tr>
@empty
<tr>
<td colspan="12" class="text-center py-5 text-muted">
<i class="bi bi-inbox display-4 d-block mb-3"></i>
No shipments found
</td>
</tr>
@endforelse
</tbody>
</table>
</div>
<div class="pagination-container">
<div class="pagination-info" id="pageInfo">Showing 1 to {{ $shipments->count() }} of {{ $shipments->count() }} entries</div>
<div class="pagination-controls">
<button class="pagination-img-btn" id="prevPageBtn" title="Previous page" disabled>
<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">
</div>
<button class="pagination-img-btn" id="nextPageBtn" title="Next page" disabled>
<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>
{{-- SHIPMENT DETAILS MODAL --}}
<div class="modal fade" id="shipmentDetailsModal" tabindex="-1">
<div class="modal-dialog modal-xl edge-to-edge modal-dialog-scrollable">
<div class="modal-content">
<div class="modal-header shipment-details-header">
<h5 class="modal-title fw-bold"><i class="bi bi-box-seam me-2"></i>Consolidated Shipment Details</h5>
<button class="btn-close" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body shipment-details-body" id="shipmentDetailsContent">
<div class="text-center py-4 loading">
<div class="spinner-border text-primary" role="status">
<span class="visually-hidden">Loading...</span>
</div>
<p class="mt-2 text-muted">Loading shipment details...</p>
</div>
</div>
</div>
</div>
</div>
</div>
<script>
// Pagination state for main table
let currentPage = 1;
const itemsPerPage = 10;
let allShipments = @json($shipments);
let filteredShipments = [...allShipments];
// ==================== CREATE SHIPMENT MODAL PAGINATION ====================
// Modal pagination state
let modalCurrentPage = 1;
const modalItemsPerPage = 10;
// IMPORTANT: सर्व orders एकाच decending order मध्ये
// Order ID च्या क्रमाने sort करा (KNT-25-00000041, KNT-25-00000040, etc.)
let allAvailableOrders = @json($availableOrders);
// Sort all orders in descending order by order_id (newest/highest number first)
// This function extracts the numeric part from order_id for proper sorting
function sortOrdersInDescending(orders) {
return orders.sort((a, b) => {
// Extract the number from order_id (e.g., "KNT-25-00000041" -> 41)
const extractNumber = (orderId) => {
if (!orderId) return 0;
const match = orderId.match(/\d+$/);
return match ? parseInt(match[0]) : 0;
};
const numA = extractNumber(a.order_id);
const numB = extractNumber(b.order_id);
// Descending order (highest number first)
return numB - numA;
});
}
// Initialize modal pagination when DOM is loaded
document.addEventListener('DOMContentLoaded', function() {
// Initialize main table pagination
renderTable();
updatePaginationControls();
// Bind main pagination events
document.getElementById('prevPageBtn').addEventListener('click', goToPreviousPage);
document.getElementById('nextPageBtn').addEventListener('click', goToNextPage);
// Status Filter Functionality for main table
const statusFilter = document.getElementById('statusFilter');
const searchInput = document.getElementById('searchInput');
const carrierFilter = document.getElementById('carrierFilter');
// Function to filter shipments
function filterShipments() {
const selectedStatus = statusFilter.value;
const searchTerm = searchInput.value.toLowerCase();
const selectedCarrier = carrierFilter.value;
filteredShipments = allShipments.filter(shipment => {
let include = true;
// Status filter
if (selectedStatus !== 'all' && shipment.status !== selectedStatus) {
include = false;
}
// Search filter
if (searchTerm) {
const matchesSearch =
shipment.shipment_id.toLowerCase().includes(searchTerm) ||
shipment.origin.toLowerCase().includes(searchTerm) ||
shipment.destination.toLowerCase().includes(searchTerm);
if (!matchesSearch) include = false;
}
// Carrier filter
if (selectedCarrier !== 'all') {
// Add carrier filtering logic here if you have carrier data
}
return include;
});
currentPage = 1;
renderTable();
updatePaginationControls();
}
// Event listeners for filters
statusFilter.addEventListener('change', filterShipments);
searchInput.addEventListener('input', filterShipments);
carrierFilter.addEventListener('change', filterShipments);
// Update status filter appearance
statusFilter.addEventListener('change', function() {
if (this.value === 'all') {
this.removeAttribute('data-status');
} else {
this.setAttribute('data-status', this.value);
}
});
// Initialize filter on page load
filterShipments();
// Initialize modal when create shipment modal is shown
const createShipmentModal = document.getElementById('createShipmentModal');
if (createShipmentModal) {
createShipmentModal.addEventListener('show.bs.modal', function() {
// Sort orders in descending order
allAvailableOrders = sortOrdersInDescending(@json($availableOrders));
// Reset to first page
modalCurrentPage = 1;
renderModalTable();
updateModalPaginationControls();
});
}
});
// ==================== MODAL PAGINATION FUNCTIONS ====================
function renderModalTable() {
const tbody = document.getElementById('modalOrdersTableBody');
if (allAvailableOrders.length === 0) {
tbody.innerHTML = `
<tr>
<td colspan="12" class="text-muted text-center py-4">
<i class="bi bi-search display-6 d-block mb-3"></i>
No available orders to add to shipment
</td>
</tr>
`;
return;
}
// Calculate pagination
const startIndex = (modalCurrentPage - 1) * modalItemsPerPage;
const endIndex = startIndex + modalItemsPerPage;
// Get orders for current page
const paginatedItems = allAvailableOrders.slice(startIndex, endIndex);
// Render table rows
tbody.innerHTML = '';
paginatedItems.forEach((order, index) => {
const row = document.createElement('tr');
row.innerHTML = `
<td>
<input type="checkbox" name="order_ids[]" value="${order.id}">
</td>
<td>
<a href="#" class="text-primary fw-bold">${order.order_id}</a>
</td>
<td>${order.origin}</td>
<td>${order.destination}</td>
<td>${order.ctn}</td>
<td>${order.qty}</td>
<td>${order.ttl_qty}</td>
<td>${order.cbm}</td>
<td>${order.ttl_cbm}</td>
<td>${order.kg}</td>
<td>${order.ttl_kg}</td>
<td class="fw-bold text-success">₹${parseFloat(order.ttl_amount).toLocaleString('en-IN', {minimumFractionDigits: 2, maximumFractionDigits: 2})}</td>
`;
tbody.appendChild(row);
});
}
function updateModalPaginationControls() {
const totalPages = Math.ceil(allAvailableOrders.length / modalItemsPerPage);
const prevBtn = document.getElementById('modalPrevPageBtn');
const nextBtn = document.getElementById('modalNextPageBtn');
const pageInfo = document.getElementById('modalPageInfo');
const paginationPages = document.getElementById('modalPaginationPages');
prevBtn.disabled = modalCurrentPage === 1;
nextBtn.disabled = modalCurrentPage === totalPages || totalPages === 0;
// Update page info text - Showing 1 to 10 of 14 entries
const startIndex = (modalCurrentPage - 1) * modalItemsPerPage + 1;
const endIndex = Math.min(modalCurrentPage * modalItemsPerPage, allAvailableOrders.length);
pageInfo.textContent = `Showing ${startIndex} to ${endIndex} of ${allAvailableOrders.length} entries`;
// Generate page numbers
paginationPages.innerHTML = '';
if (totalPages <= 7) {
// Show all pages
for (let i = 1; i <= totalPages; i++) {
addModalPageButton(i, paginationPages);
}
} else {
// Show first page, current page range, and last page
addModalPageButton(1, paginationPages);
if (modalCurrentPage > 3) {
paginationPages.innerHTML += '<span class="modal-pagination-ellipsis">...</span>';
}
const start = Math.max(2, modalCurrentPage - 1);
const end = Math.min(totalPages - 1, modalCurrentPage + 1);
for (let i = start; i <= end; i++) {
addModalPageButton(i, paginationPages);
}
if (modalCurrentPage < totalPages - 2) {
paginationPages.innerHTML += '<span class="modal-pagination-ellipsis">...</span>';
}
addModalPageButton(totalPages, paginationPages);
}
}
function addModalPageButton(pageNumber, container) {
const button = document.createElement('button');
button.className = 'modal-pagination-page-btn';
if (pageNumber === modalCurrentPage) {
button.classList.add('active');
}
button.textContent = pageNumber;
button.addEventListener('click', () => {
modalCurrentPage = pageNumber;
renderModalTable();
updateModalPaginationControls();
});
container.appendChild(button);
}
function goToModalPreviousPage() {
if (modalCurrentPage > 1) {
modalCurrentPage--;
renderModalTable();
updateModalPaginationControls();
}
}
function goToModalNextPage() {
const totalPages = Math.ceil(allAvailableOrders.length / modalItemsPerPage);
if (modalCurrentPage < totalPages) {
modalCurrentPage++;
renderModalTable();
updateModalPaginationControls();
}
}
// ==================== MAIN TABLE PAGINATION FUNCTIONS ====================
function goToPreviousPage() {
if (currentPage > 1) {
currentPage--;
renderTable();
updatePaginationControls();
}
}
function goToNextPage() {
const totalPages = Math.ceil(filteredShipments.length / itemsPerPage);
if (currentPage < totalPages) {
currentPage++;
renderTable();
updatePaginationControls();
}
}
function updatePaginationControls() {
const totalPages = Math.ceil(filteredShipments.length / itemsPerPage);
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;
// Update page info text
const startIndex = (currentPage - 1) * itemsPerPage + 1;
const endIndex = Math.min(currentPage * itemsPerPage, filteredShipments.length);
pageInfo.textContent = `Showing ${startIndex} to ${endIndex} of ${filteredShipments.length} entries`;
// Generate page numbers
paginationPages.innerHTML = '';
if (totalPages <= 7) {
// Show all pages
for (let i = 1; i <= totalPages; i++) {
addPageButton(i, paginationPages);
}
} else {
// Show first page, current page range, and last page
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;
renderTable();
updatePaginationControls();
});
container.appendChild(button);
}
// Render Table Function
function renderTable() {
const tbody = document.getElementById('shipmentsTableBody');
if (filteredShipments.length === 0) {
tbody.innerHTML = `
<tr>
<td colspan="12" class="text-center py-5 text-muted">
<i class="bi bi-search display-4 d-block mb-3"></i>
No shipments found matching your criteria
</td>
</tr>
`;
return;
}
// Calculate pagination
const startIndex = (currentPage - 1) * itemsPerPage;
const endIndex = startIndex + itemsPerPage;
const paginatedItems = filteredShipments.slice(startIndex, endIndex);
// Sort by creation date (newest first) - descending order
const sortedItems = [...paginatedItems].sort((a, b) => new Date(b.created_at) - new Date(a.created_at));
// Render table rows
tbody.innerHTML = '';
sortedItems.forEach((shipment, index) => {
const displayIndex = filteredShipments.length - (startIndex + index);
const row = document.createElement('tr');
row.className = 'shipment-row';
row.setAttribute('data-status', shipment.status);
row.setAttribute('data-shipment-id', shipment.shipment_id);
// Function to format status string
const formatStatus = (status) => {
if (!status) return '';
return status.charAt(0).toUpperCase() + status.slice(1).replace(/_/g, ' ');
};
row.innerHTML = `
<td class="fw-bold">${displayIndex}</td>
<td>
<a href="#" class="text-primary fw-bold" onclick="openShipmentDetails(${shipment.id})">
${shipment.shipment_id}
</a>
</td>
<td>${shipment.origin}</td>
<td>${shipment.destination}</td>
<td><span class="badge bg-light text-dark">${shipment.total_qty}</span></td>
<td><span class="badge bg-light text-dark">${shipment.total_kg} kg</span></td>
<td><span class="badge bg-light text-dark">${shipment.total_cbm} CBM</span></td>
<td class="fw-bold text-success">₹${parseFloat(shipment.total_amount).toLocaleString('en-IN', {minimumFractionDigits: 2, maximumFractionDigits: 2})}</td>
<td>
<span class="badge badge-${shipment.status}">
${formatStatus(shipment.status)}
</span>
</td>
<td>${new Date(shipment.shipment_date).toLocaleDateString('en-GB', { day: '2-digit', month: 'short', year: 'numeric' })}</td>
<td>
<a href="/admin/shipment/dummy/${shipment.id}"
class="btn-view-details">
<i class="bi bi-eye"></i>
</a>
</td>
<td>
<div class="action-container">
<button type="button"
class="btn-edit-status"
onclick="toggleStatusDropdown(this, ${shipment.id})"
title="Edit Status">
<i class="bi bi-pencil"></i>
</button>
<div class="status-dropdown" id="statusDropdown-${shipment.id}">
<form action="/admin/shipments/update-status" method="POST" class="status-form">
<input type="hidden" name="_token" value="{{ csrf_token() }}">
<input type="hidden" name="shipment_id" value="${shipment.id}">
<button type="submit" name="status" value="shipment_ready" class="status-option shipment_ready">
<span class="status-indicator shipment_ready"></span>
Shipment Ready
</button>
<button type="submit" name="status" value="export_custom" class="status-option export_custom">
<span class="status-indicator export_custom"></span>
Export Custom
</button>
<button type="submit" name="status" value="international_transit" class="status-option international_transit">
<span class="status-indicator international_transit"></span>
International Transit
</button>
<button type="submit" name="status" value="arrived_india" class="status-option arrived_india">
<span class="status-indicator arrived_india"></span>
Arrived at India
</button>
<button type="submit" name="status" value="import_custom" class="status-option import_custom">
<span class="status-indicator import_custom"></span>
Import Custom
</button>
<button type="submit" name="status" value="warehouse" class="status-option warehouse">
<span class="status-indicator warehouse"></span>
Warehouse
</button>
<button type="submit" name="status" value="domestic_distribution" class="status-option domestic_distribution">
<span class="status-indicator domestic_distribution"></span>
Domestic Distribution
</button>
<button type="submit" name="status" value="out_for_delivery" class="status-option out_for_delivery">
<span class="status-indicator out_for_delivery"></span>
Out for Delivery
</button>
<button type="submit" name="status" value="delivered" class="status-option delivered">
<span class="status-indicator delivered"></span>
Delivered
</button>
</form>
</div>
</div>
</td>
`;
tbody.appendChild(row);
});
}
// --------------------------------------------------------------------
// Function: Open Consolidated Shipment Details Modal
// --------------------------------------------------------------------
function openShipmentDetails(id) {
let modal = new bootstrap.Modal(document.getElementById('shipmentDetailsModal'));
let content = document.getElementById('shipmentDetailsContent');
content.innerHTML = `
<div class="text-center py-4 loading">
<div class="spinner-border text-primary" role="status">
<span class="visually-hidden">Loading...</span>
</div>
<p class="mt-2 text-muted">Loading shipment details...</p>
</div>
`;
fetch(`/admin/shipments/${id}`)
.then(res => {
if (!res.ok) throw new Error('Network response was not ok');
return res.json();
})
.then(data => {
// Format date properly
const shipmentDate = new Date(data.shipment.shipment_date);
const formattedDate = shipmentDate.toLocaleDateString('en-GB', {
day: '2-digit',
month: 'short',
year: 'numeric'
});
// Function to format status string
const formatStatus = (status) => {
if (!status) return 'N/A';
return status.charAt(0).toUpperCase() + status.slice(1).replace(/_/g, ' ');
};
let html = `
<div class="shipment-info-row">
<div class="shipment-info-item">
<div class="shipment-info-label">Shipment ID</div>
<div class="shipment-info-value">${data.shipment.shipment_id}</div>
</div>
<div class="shipment-info-item">
<div class="shipment-info-label">Total Orders</div>
<div class="shipment-info-value">${data.orders.length}</div>
</div>
<div class="shipment-info-item">
<div class="shipment-info-label">Status</div>
<div class="shipment-info-value">${formatStatus(data.shipment.status)}</div>
</div>
<div class="shipment-info-item">
<div class="shipment-info-label">Date</div>
<div class="shipment-info-value">${formattedDate}</div>
</div>
</div>
<h6 class="fw-bold mt-4 mb-3">Detailed view of all orders in this shipment consolidation</h6>
<div class="table-responsive">
<table class="shipment-details-table">
<thead>
<tr>
<th>Order ID</th>
<th>Origin</th>
<th>Destination</th>
<th>Item No</th>
<th>Description</th>
<th>CTN</th>
<th>QTY</th>
<th>TTL/QTY</th>
<th>CBM</th>
<th>TTL CBM</th>
<th>KG</th>
<th>TTL KG</th>
<th>Amount (₹)</th>
</tr>
</thead>
<tbody>
`;
data.orders.forEach(order => {
html += `
<tr>
<td class="fw-bold">
<a href="javascript:void(0)"
class="text-primary fw-bold"
onclick="openShipmentOrderDetails(${order.id})">
${order.order_id}
</a>
</td>
<td>${order.origin || 'N/A'}</td>
<td>${order.destination || 'N/A'}</td>
<td>${order.mark_no || 'ITEM001'}</td>
<td>${order.description || 'Manufacturing Equipment'}</td>
<td>${order.ctn}</td>
<td>${order.qty}</td>
<td>${order.ttl_qty}</td>
<td>${order.cbm || '0.00'}</td>
<td>${order.ttl_cbm || '0.00'}</td>
<td>${order.kg || '0.00'}</td>
<td>${order.ttl_kg || '0.00'}</td>
<td class="fw-bold text-success">₹${parseFloat(order.ttl_amount).toLocaleString('en-IN', {minimumFractionDigits: 2, maximumFractionDigits: 2})}</td>
</tr>
`;
});
html += `
</tbody>
</table>
</div>
<div class="shipment-totals">
<div class="shipment-totals-row">
<div class="shipment-total-item">
<div class="shipment-total-label">Total CTN</div>
<div class="shipment-total-value total-ctn">${data.shipment.total_ctn}</div>
</div>
<div class="shipment-total-item">
<div class="shipment-total-label">Total QTY</div>
<div class="shipment-total-value total-quantity">${data.shipment.total_qty}</div>
</div>
<div class="shipment-total-item">
<div class="shipment-total-label">Total CBM</div>
<div class="shipment-total-value total-cbm">${data.shipment.total_cbm}</div>
</div>
<div class="shipment-total-item">
<div class="shipment-total-label">Total KG</div>
<div class="shipment-total-value total-weight">${data.shipment.total_kg}</div>
</div>
<div class="shipment-total-item">
<div class="shipment-total-label">Total TTL/QTY</div>
<div class="shipment-total-value total-quantity">${data.shipment.total_ttl_qty}</div>
</div>
<div class="shipment-total-item">
<div class="shipment-total-label">Total TTL/CBM</div>
<div class="shipment-total-value total-ttl-cbm">${data.shipment.total_ttl_cbm}</div>
</div>
<div class="shipment-total-item">
<div class="shipment-total-label">Total TTL/KG</div>
<div class="shipment-total-value total-ttl-kg">${data.shipment.total_ttl_kg}</div>
</div>
<div class="shipment-total-item">
<div class="shipment-total-label">Total Amount</div>
<div class="shipment-total-value total-amount">₹${parseFloat(data.shipment.total_amount).toLocaleString('en-IN', {minimumFractionDigits: 2, maximumFractionDigits: 2})}</div>
</div>
</div>
</div>
`;
content.innerHTML = html;
})
.catch(error => {
console.error('Error loading shipment details:', error);
content.innerHTML = `
<div class="text-center py-5">
<i class="bi bi-exclamation-triangle display-1 text-danger"></i>
<h4 class="mt-3 text-danger">Error Loading Shipment Details</h4>
<p class="text-muted">Please try again later</p>
<button class="btn btn-primary mt-2" onclick="openShipmentDetails(${id})">Retry</button>
</div>
`;
});
modal.show();
}
// Toggle status dropdown
function toggleStatusDropdown(button, shipmentId) {
const dropdown = document.getElementById(`statusDropdown-${shipmentId}`);
const isShowing = dropdown.classList.contains('show');
// Close all other dropdowns
document.querySelectorAll('.status-dropdown.show').forEach(dropdown => {
dropdown.classList.remove('show');
});
// Toggle current dropdown
if (!isShowing) {
dropdown.classList.add('show');
}
// Close dropdown when clicking outside
document.addEventListener('click', function closeDropdown(e) {
if (!button.contains(e.target) && !dropdown.contains(e.target)) {
dropdown.classList.remove('show');
document.removeEventListener('click', closeDropdown);
}
});
}
// Auto-close dropdown after form submission
document.addEventListener('DOMContentLoaded', function() {
document.querySelectorAll('.status-form').forEach(form => {
form.addEventListener('submit', function() {
const dropdown = this.closest('.status-dropdown');
if (dropdown) {
dropdown.classList.remove('show');
}
});
});
});
function openShipmentOrderDetails(orderId) {
const modal = new bootstrap.Modal(
document.getElementById('shipmentOrderDetailsModal')
);
const body = document.getElementById('shipmentOrderDetailsBody');
body.innerHTML = "<p class='text-center text-muted'>Loading...</p>";
modal.show();
fetch(`/admin/orders/view/${orderId}`)
.then(res => res.text())
.then(html => {
body.innerHTML = html;
})
.catch(() => {
body.innerHTML =
"<p class='text-danger text-center'>Failed to load order details.</p>";
});
}
</script>
<!-- SHIPMENT ORDER DETAILS MODAL - UPDATED TO EDGE-TO-EDGE -->
<div class="modal fade" id="shipmentOrderDetailsModal" tabindex="-1">
<div class="modal-dialog modal-xl edge-to-edge order-details-modal modal-dialog-scrollable">
<div class="modal-content">
<div class="modal-header shipment-details-header order-details-header">
<h5 class="modal-title fw-bold"><i class="bi bi-file-text me-2"></i>Order Details</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body shipment-details-body order-details-body" id="shipmentOrderDetailsBody">
<p class="text-center text-muted">Loading order details...</p>
</div>
</div>
</div>
</div>
@endsection