Files
Kent-logistics-Laravel/resources/views/admin/account.blade.php

3481 lines
107 KiB
PHP
Raw Normal View History

2025-11-06 17:09:52 +05:30
@extends('admin.layouts.app')
2025-11-11 14:51:35 +05:30
@section('page-title', 'Account Dashboard')
2025-11-06 17:09:52 +05:30
@section('content')
2025-11-21 16:07:43 +05:30
<meta name="csrf-token" content="{{ csrf_token() }}">
2025-11-11 14:51:35 +05:30
<style>
2025-11-21 16:07:43 +05:30
/* ---------- Base ---------- */
2026-02-27 10:51:26 +05:30
2025-11-21 16:07:43 +05:30
:root{
--primary-1:#1a2951;
--primary-2:#243a72;
--muted:#9ba5bb;
--card-bg: linear-gradient(180deg,#ffffff,#f5f7fb);
--glass: rgba(255,255,255,0.6);
--success:#34c86c;
--danger:#ef4f4f;
--accent:#276dea;
--rounded:12px;
}
body {
2025-11-12 19:56:06 +05:30
font-family: 'Segoe UI', Arial, sans-serif;
2025-11-21 16:07:43 +05:30
background: linear-gradient(135deg, #eef2f7, #f9fbff);
margin:0; padding:0;
color:#253047;
-webkit-font-smoothing:antialiased;
}
/* container */
.account-container {
padding: 28px 34px;
2025-11-26 23:07:12 +05:30
max-width:1400px;
2025-11-21 16:07:43 +05:30
margin: 18px auto;
box-sizing:border-box;
}
/* header */
.account-header {
margin-bottom: 18px;
2026-02-27 10:51:26 +05:30
background:linear-gradient(135deg, #667eea 0%, #764ba2 100%);
2025-11-21 16:07:43 +05:30
padding: 22px 26px;
border-radius: var(--rounded);
box-shadow: 0 6px 18px rgba(34,50,90,0.12);
2025-11-12 19:56:06 +05:30
color: #fff;
2025-11-21 16:07:43 +05:30
}
.account-header h2 { font-size: 26px; font-weight:700; margin:0 0 6px 0; }
.account-header p { font-size:14px; margin:2px 0; opacity:0.95 }
/* top actions row */
.top-actions {
2025-12-23 21:11:53 +05:30
align-items:center; justify-content:space-between;
2025-11-21 16:07:43 +05:30
gap:12px; margin:16px 0 20px 0; flex-wrap:wrap;
}
.top-actions .left {
display:flex; gap:12px; align-items:center; flex-wrap:wrap;
}
.search-row input {
width:360px; padding:10px 14px; border-radius:8px; border:1px solid #d6dde9;
background: #fff; font-size:14px; box-shadow:0 1px 3px rgba(0,0,0,0.03);
}
.search-row input:focus{ outline:none; border-color:var(--primary-1); box-shadow:0 6px 18px rgba(26,41,81,0.06);}
.btn {
display:inline-flex; align-items:center; justify-content:center; gap:8px;
2026-02-27 10:51:26 +05:30
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
2025-11-21 16:07:43 +05:30
color:#fff; border:none; padding:10px 16px; border-radius:10px; font-weight:600;
cursor:pointer; transition: transform .15s ease, box-shadow .15s;
}
2025-12-01 10:34:27 +05:30
.btn.ghost { background: transparent; color:var(--primary-1); border:1.5px solid #dbe4f5; box-shadow:none; }
2025-12-23 21:11:53 +05:30
.btn:hover{ transform: translateY(-3px); box-shadow: 0 8px 26px rgba(227, 229, 234, 0.12); }
2025-11-21 16:07:43 +05:30
/* account panels */
2025-11-26 23:07:12 +05:30
.account-panels {
display:flex;
gap:22px;
2025-12-01 10:34:27 +05:30
align-items:stretch;
2025-11-26 23:07:12 +05:30
flex-wrap:wrap;
}
2025-12-01 10:34:27 +05:30
/* Payment block with pagination */
.payment-block {
flex:1;
min-width:48%;
display: flex;
flex-direction: column;
}
2025-11-21 16:07:43 +05:30
.panel-card {
2025-11-26 23:07:12 +05:30
background: var(--card-bg);
border-radius:12px;
box-shadow:0 8px 20px rgba(25,40,80,0.06);
2025-12-23 21:11:53 +05:30
padding:20px; /* 005 */
2025-11-26 23:07:12 +05:30
box-sizing:border-box;
overflow-x:auto;
transition: transform .12s, box-shadow .12s;
2025-12-01 10:34:27 +05:30
min-height: 520px;
2025-12-23 21:11:53 +05:30
/* display: flex; */ /* 005 */
2025-11-26 23:07:12 +05:30
flex-direction: column;
2025-12-01 10:34:27 +05:30
flex: 1;
height: 100%;
2025-11-21 16:07:43 +05:30
}
.panel-card:hover{ transform: translateY(-4px); box-shadow:0 12px 28px rgba(25,40,80,0.08); }
2025-11-26 23:07:12 +05:30
.panel-title {
font-weight:700;
font-size:16px;
color:var(--primary-1);
margin-bottom:16px;
display:flex;
align-items:center;
justify-content:space-between;
}
2025-11-21 16:07:43 +05:30
/* table */
2025-11-26 23:07:12 +05:30
table {
width:100%;
border-collapse:collapse;
min-width:720px;
font-size:14px;
flex:1;
}
th, td {
padding:12px 14px;
text-align:left;
border-bottom:1px solid #eef3fb;
white-space:nowrap;
color:#2d3b53;
}
th {
background: linear-gradient(90deg,#f6f9ff,#fbfdff);
color:#4a5570;
font-weight:700;
font-size:13px;
}
2025-11-21 16:07:43 +05:30
tr:hover td{ background:#fbfdff; }
.entry-link{ color:var(--accent); text-decoration:underline; cursor:pointer; font-weight:700; }
/* badges */
2025-11-26 23:07:12 +05:30
/* === Modern Status Badges === */
.status-badge {
display: inline-block;
padding: 6px 16px;
border-radius: 999px;
font-size: 13px;
font-weight: 700;
color: #fff;
min-width: 76px;
text-align: center;
box-shadow: 0 2px 8px rgba(33, 43, 90, 0.07);
letter-spacing: 0.1px;
2025-12-01 10:34:27 +05:30
background: #6b7280;
2025-11-26 23:07:12 +05:30
transition: box-shadow 0.22s, transform 0.17s, background 0.22s;
vertical-align: middle;
margin: 3px 2px;
cursor: default;
backdrop-filter: blur(2px);
width: 99px;
}
.status-badge:hover {
transform: translateY(-3px) scale(1.045);
box-shadow: 0 4px 16px rgba(33, 43, 90, 0.16);
opacity: 0.96;
}
/* High-impact, soft gradients for each status */
.status-unpaid {
background: linear-gradient(90deg, #ff5959, #dc3545);
border: 1.5px solid #d42c3f21;
width: 95px;
}
.status-paid {
background: linear-gradient(90deg, #36d399 0%, #4ade80 100%);
border: 1.5px solid #31b47a1a;
width: 95px;
}
.status-loading {
background: linear-gradient(90deg, #509cf8 0%, #3f79d3 100%);
border: 1.5px solid #1665c320;
width: 95px;
}
.status-dispatched {
background: linear-gradient(90deg, #9775fa 0%, #845ef7 100%);
border: 1.5px solid #9775fa40;
width: 95px;
}
.pending-badge-red {
background: linear-gradient(90deg, #f43f5e, #ef4444);
border: 1.5px solid #f43f5e41;
width: 95px;
}
.pending-badge-green {
background: linear-gradient(90deg, #10b981 0%, #22d3ee 100%);
border: 1.5px solid #10b98141;
width: 95px;
}
.status-delivered {
background: linear-gradient(90deg, #22c55e 0%, #16a34a 100%);
border: 1.5px solid #22c55e44;
width: 95px;
}
2025-11-21 16:07:43 +05:30
/* 3-state toggle */
.toggle-switch-btn {
appearance:none;
-webkit-appearance:none;
2025-12-23 21:11:53 +05:30
width:64px;
height:26.5px; /* 005 */
2025-12-01 10:34:27 +05:30
background:#f25b5b;
2025-11-21 16:07:43 +05:30
border:2px solid #f25b5b;
border-radius:999px;
position:relative;
outline:none;
cursor:pointer;
transition: background .22s, border .22s;
}
.toggle-switch-btn::before{
content:"";
width:20px;
height:20px;
background:#fff;
border-radius:50%;
position:absolute;
top:1.7px;
left:2px;
transition: transform .22s;
box-shadow:0 2px 8px rgba(0,0,0,0.15);
}
/* YELLOW */
.toggle-switch-btn.mid {
background:#f2c94c;
border-color:#f2c94c;
}
.toggle-switch-btn.mid::before {
transform: translateX(20px);
}
/* GREEN */
.toggle-switch-btn.checked {
background:#43d05c;
border-color:#43d05c;
}
.toggle-switch-btn.checked::before {
transform: translateX(38px);
}
/* plus button */
2025-11-26 23:07:12 +05:30
.plus-btn {
display:inline-block;
width:36px;
height:36px;
border-radius:10px;
background:#fff;
color:var(--primary-1);
border:1.5px solid #e6edf8;
font-size:1.15rem;
font-weight:700;
text-align:center;
line-height:34px;
cursor:pointer;
transition: transform .12s;
}
2025-11-21 16:07:43 +05:30
.plus-btn:hover{ transform: translateY(-3px); box-shadow:0 8px 16px rgba(33,47,90,0.04); }
2025-11-26 23:07:12 +05:30
/* ---------- Create Order Popup Modal ---------- */
.create-order-modal {
position:fixed;
inset:0;
background:rgba(16,24,50,0.44);
display:none;
align-items:center;
justify-content:center;
z-index:1200;
padding:18px;
}
.create-order-modal.modal-open { display:flex; }
.create-order-modal .modal-box {
background:#fff;
border-radius:12px;
padding:20px 24px;
box-shadow:0 14px 40px rgba(18,30,60,0.12);
max-width:1200px;
width:100%;
max-height:92vh;
overflow:auto;
}
2025-11-21 16:07:43 +05:30
/* consolidated orders area */
.consolidate-area {
background: linear-gradient(90deg,#fbfbff,#f9fcff);
2025-11-26 23:07:12 +05:30
border:1px solid #eef5ff;
padding:14px;
border-radius:10px;
box-shadow: inset 0 1px 0 rgba(255,255,255,0.6);
margin-top:12px;
overflow:auto;
min-height: 400px;
display: flex;
flex-direction: column;
2025-11-21 16:07:43 +05:30
}
/* compact table in consolidate */
2025-11-26 23:07:12 +05:30
#consolidateOrdersTable th, #consolidateOrdersTable td { padding:10px 12px; font-size:13px; border-bottom:1px solid #f1f6ff; }
/* ---------- Pagination Styles ---------- */
.pagination-container {
display: flex;
justify-content: space-between;
align-items: center;
margin-top: 15px;
padding: 12px 0;
border-top: 1px solid #eef3fb;
2025-12-23 21:11:53 +05:30
/* margin-right:550px; */
2025-11-26 23:07:12 +05:30
}
.pagination-info {
font-size: 13px;
color: var(--muted);
font-weight: 600;
}
.pagination-controls {
display: flex;
align-items: center;
gap: 8px;
2025-12-23 21:11:53 +05:30
position: absolute;
right: 16px; /* 005 */
2025-12-01 10:34:27 +05:30
2025-12-03 16:17:14 +05:30
}
.pagination-controls1 {
display: flex;
align-items: center;
gap: 8px;
2026-02-27 10:51:26 +05:30
margin-right:-550px;
2025-12-03 16:17:14 +05:30
2025-11-26 23:07:12 +05:30
}
2025-12-03 16:17:14 +05:30
.pagination-controls2 {
display: flex;
align-items: center;
gap: 8px;
2026-02-27 10:51:26 +05:30
margin-right:8=500px;
2025-12-03 16:17:14 +05:30
}
2025-11-26 23:07:12 +05:30
.pagination-btn {
background: #fff;
border: 1px solid #e3eaf6;
color: var(--primary-1);
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;
}
.pagination-btn:hover:not(:disabled) {
background: var(--primary-1);
color: white;
border-color: var(--primary-1);
}
.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: var(--primary-1);
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;
}
.pagination-page-btn:hover {
background: var(--primary-1);
color: white;
border-color: var(--primary-1);
}
.pagination-page-btn.active {
background: var(--primary-1);
color: white;
border-color: var(--primary-1);
}
.pagination-pages {
display: flex;
gap: 4px;
align-items: center;
}
.pagination-ellipsis {
color: var(--muted);
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: var(--primary-1);
border-color: var(--primary-1);
}
.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%);
}
2025-11-21 16:07:43 +05:30
2026-02-27 10:51:26 +05:30
/* ---------- Entry Details Modal (Enhanced) ---------- */
2025-11-26 23:07:12 +05:30
.modal-fade1 {
position:fixed;
inset:0;
background:rgba(16,24,50,0.44);
display:none;
align-items:center;
justify-content:center;
z-index:1200;
padding:18px;
}
2025-11-21 16:07:43 +05:30
.modal-fade1.modal-open { display:flex; }
2025-11-26 23:07:12 +05:30
.modal-box1 {
2026-02-27 10:51:26 +05:30
background:#fff;
border-radius:12px;
padding:20px 24px;
box-shadow:0 14px 40px rgba(18,30,60,0.12);
max-width:1200px;
width:100%;
max-height:92vh;
overflow:auto;
min-height: 500px;
}
#entryOrdersModal {
z-index: 1300;
2025-11-26 23:07:12 +05:30
}
2025-12-02 18:11:58 +05:30
#entryOrdersModal {
z-index: 1300;
}
2025-11-21 16:07:43 +05:30
/* entry summary cards */
2025-11-26 23:07:12 +05:30
.entry-summary-cards {
display:flex;
gap:16px;
2026-02-27 10:51:26 +05:30
margin-top:25px;
2025-11-26 23:07:12 +05:30
flex-wrap:wrap;
}
.entry-summary-card {
background:#fbfdff;
border:1px solid #eef6ff;
padding:16px;
border-radius:10px;
min-width:180px;
box-shadow:0 6px 18px rgba(22,36,72,0.03);
flex:1;
}
2025-11-21 16:07:43 +05:30
.entry-summary-label{ font-size:12px; color:var(--muted); }
.entry-summary-value{ font-size:18px; font-weight:700; color:#253047; margin-top:6px; }
2026-02-27 10:51:26 +05:30
/* Enhanced dropdown */
.installment-status-dropdown {
cursor: pointer;
appearance: none;
width: 100%;
padding: 10px 40px 10px 12px;
border-radius: 8px;
border: 1.5px solid #e3eaf6;
background: white;
font-size: 13px;
font-weight: 500;
transition: all 0.2s ease;
background-image: url('data:image/svg+xml;charset=US-ASCII,<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="%236b7280" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="6 9 12 15 18 9"></polyline></svg>');
background-repeat: no-repeat;
background-position: right 12px center;
min-width: 140px;
}
.installment-status-dropdown:hover {
border-color: #c2d1f0;
background-color: #f8fafc;
}
.installment-status-dropdown:focus {
outline: none;
border-color: var(--accent);
box-shadow: 0 0 0 3px rgba(39, 109, 234, 0.1);
}
/* Status-specific dropdown options */
.installment-status-dropdown option {
padding: 12px !important;
font-size: 13px;
font-weight: 500;
}
.installment-status-dropdown option[value="Pending"] {
color: #f59e0b;
}
.installment-status-dropdown option[value="Loading"] {
color: #3b82f6;
}
.installment-status-dropdown option[value="Packed"] {
color: #8b5cf6;
}
.installment-status-dropdown option[value="Dispatched"] {
color: #10b981;
}
.installment-status-dropdown option[value="Delivered"] {
color: #0c6b2e;
}
/* ---------- Entry Orders Modal (Enhanced) ---------- */
.entry-orders-modal .modal-box1 {
padding: 0 !important;
overflow: hidden;
border-radius: 16px;
box-shadow: 0 20px 60px rgba(18, 30, 60, 0.25);
}
.entry-orders-header {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
padding: 24px 30px;
color: white;
border-radius: 16px 16px 0 0;
}
.entry-orders-header h2 {
margin: 0 0 8px 0;
font-size: 24px;
font-weight: 700;
color: white;
}
.entry-orders-header .subtitle {
font-size: 14px;
opacity: 0.9;
display: flex;
align-items: center;
gap: 8px;
}
.entry-orders-content {
padding: 30px;
max-height: 70vh;
overflow-y: auto;
}
/* Orders table in modal */
.orders-table-container {
max-height: 400px;
overflow-y: auto;
border: 1px solid #eef3fb;
border-radius: 12px;
margin: 20px 0;
}
.orders-table {
width: 100%;
border-collapse: collapse;
font-size: 14px;
}
.orders-table th {
background: linear-gradient(90deg, #f8fbff, #f5f9ff);
padding: 14px 16px;
text-align: left;
font-weight: 700;
color: var(--primary-1);
border-bottom: 2px solid #eef3fb;
position: sticky;
top: 0;
}
.orders-table td {
padding: 14px 16px;
border-bottom: 1px solid #f1f6ff;
}
.orders-table tr:hover {
background: #fbfdff;
}
.orders-table tr:last-child td {
border-bottom: none;
}
/* Order ID with badge style */
.order-id-badge {
display: inline-block;
background: linear-gradient(90deg, #f0f7ff, #e6f0ff);
color: var(--primary-1);
padding: 4px 10px;
border-radius: 6px;
font-weight: 600;
font-size: 12px;
border: 1px solid #dbe4f5;
}
/* Summary row */
.orders-summary-row {
display: flex;
justify-content: space-between;
align-items: center;
padding: 16px 20px;
background: linear-gradient(90deg, #e6ebf5 0%, #f9fbff 100%);
border-radius: 10px;
margin-top: 20px;
border: 1px solid #eef3fb;
}
.orders-summary-item {
display: flex;
flex-direction: column;
align-items: center;
flex: 1;
}
.orders-summary-value {
font-size: 20px;
font-weight: 800;
color: var(--primary-1);
}
.orders-summary-label {
font-size: 12px;
color: var(--muted);
margin-top: 4px;
text-transform: uppercase;
letter-spacing: 0.5px;
}
2025-11-21 16:07:43 +05:30
/* installment modal */
#installmentModal .modal-box1 { max-width:720px; min-width:380px; }
/* small helpers */
.helper-note{ font-size:12px; color:#7687a3; margin-top:6px; display:block; }
.empty-state{ padding:18px; text-align:center; color:#6f7b8f; }
.kv { font-weight:700; color:#26364f; }
2025-11-26 23:07:12 +05:30
/* form styles */
2025-12-02 18:11:58 +05:30
.input, select {
width:100%;
padding:12px 14px;
border-radius:8px;
border:1.3px solid #e3eaf6;
background:#fff;
font-size:14px;
box-sizing:border-box;
}
/* Additional styling for the installment dropdown - doesn't affect original class */
.installment-status-dropdown {
cursor: pointer;
appearance: none;
background-image: url('data:image/svg+xml;charset=US-ASCII,<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="%236b7280" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="6 9 12 15 18 9"></polyline></svg>');
background-repeat: no-repeat;
background-position: right 12px center;
padding-right: 40px;
transition: all 0.2s ease;
}
.installment-status-dropdown:hover {
border-color: #c2d1f0;
}
.installment-status-dropdown:focus {
outline: none;
border-color: #4d7cfe;
box-shadow: 0 0 0 3px rgba(77, 124, 254, 0.1);
}
/* Status-specific styling for selected option */
.installment-status-dropdown option:checked {
font-weight: 600;
}
2025-11-26 23:07:12 +05:30
.create-grid {
display:grid;
grid-template-columns: 1fr 1fr;
gap:16px;
align-items:start;
margin-bottom:16px;
}
.create-actions {
display:flex;
gap:12px;
justify-content:flex-end;
margin-top:16px;
}
2025-12-02 18:11:58 +05:30
/* Combined filters row styling */
.combined-filters-row {
2025-12-23 21:11:53 +05:30
display: ruby; /* 005 */
2025-12-01 10:34:27 +05:30
gap: 12px;
align-items: center;
margin-bottom: 16px;
flex-wrap: wrap;
padding: 14px 16px;
background: linear-gradient(90deg, #f8fbff, #f5f9ff);
border-radius: 10px;
border: 1px solid #eef3fb;
2025-12-02 18:11:58 +05:30
width: 365px;
}
.right{
2025-12-23 21:11:53 +05:30
/* margin-left:auto;
margin-top:-16px; */ /* 005 */
2025-12-02 18:11:58 +05:30
}
.filter-group1 {
display: flex;
flex-direction: column;
gap: 6px;
width: 159px;
}
.filter-group2 {
display: flex;
flex-direction: column;
gap: 6px;
width: 160px;
2025-12-01 10:34:27 +05:30
}
2025-12-02 18:11:58 +05:30
.filter-group3 {
flex: 1;
width: 159px;
}
.filter-label {
display: block;
font-size: 13px;
font-weight: 600;
color: #44546a;
margin-bottom: 6px;
}
.payment-filters-section {
display: flex;
align-items: flex-end;
gap: 16px;
}
.filter-group4 {
2025-12-01 10:34:27 +05:30
display: flex;
flex-direction: column;
gap: 6px;
2025-12-02 18:11:58 +05:30
width: 160px;
2025-12-01 10:34:27 +05:30
}
2025-12-02 18:11:58 +05:30
.filter-label {
display: block;
font-size: 13px;
font-weight: 600;
color: #44546a;
margin-bottom: 2px;
}
/* Status option colors */
.filter-control option {
padding: 10px 12px;
font-size: 14px;
}
.filter-control option[value=""] {
color: #6b778c;
}
.filter-control option[value="pending"] {
color: #f59e0b;
font-weight: 500;
}
.filter-control option[value="loading"] {
color: #3b82f6;
font-weight: 500;
}
.filter-control option[value="packed"] {
color: #8b5cf6;
font-weight: 500;
}
.filter-control option[value="dispatched"] {
color: #10b981;
font-weight: 500;
}
.filter-control option[value="delivered"] {
color: #0c6b2e;
font-weight: 500;
}
.status-color {
width: 12px;
height: 12px;
border-radius: 50%;
}
.status-color.pending { background-color: #f59e0b; }
.status-color.loading { background-color: #3b82f6; }
.status-color.packed { background-color: #8b5cf6; }
.status-color.dispatched { background-color: #10b981; }
.status-color.delivered { background-color: #0c6b2e; }
/* Style for options with icons */
.filter-control option {
padding: 8px 12px;
}
.filter-control option[value=""] {
color: #6b778c;
}
.filter-control option[value="paid"] {
color: #0c6b2e;
font-weight: 500;
}
.filter-control option[value="unpaid"] {
color: #c9372c;
font-weight: 500;
}
.filter-control option[value="pending"] {
color: #f59e0b;
font-weight: 500;
}
.filter-group4 {
display: flex;
flex-direction: column;
gap: 6px;
width: 510px;
}
/* Modern filter alternative with icons */
.filter-status-buttons {
display: flex;
gap: 8px;
margin-top: 8px;
}
.status-btn {
display: flex;
align-items: center;
gap: 6px;
padding: 6px 12px;
border-radius: 6px;
border: 1px solid #e3eaf6;
background: #fff;
font-size: 13px;
font-weight: 500;
cursor: pointer;
transition: all 0.2s ease;
}
.status-btn:hover {
background-color: #f8fafc;
transform: translateY(-1px);
}
.status-btn.active {
border-color: transparent;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.08);
}
.status-btn[data-status="paid"] {
color: #0c6b2e;
background-color: #f0f9f0;
}
.status-btn[data-status="paid"].active {
background-color: #e1f7e1;
}
.status-btn[data-status="paid"] i {
color: #0c6b2e;
}
.status-btn[data-status="unpaid"] {
color: #c9372c;
background-color: #fef0f0;
}
.status-btn[data-status="unpaid"].active {
background-color: #fde8e8;
}
.status-btn[data-status="unpaid"] i {
color: #c9372c;
}
.status-btn[data-status="pending"] {
color: #f59e0b;
background-color: #fff7e6;
}
.status-btn[data-status="pending"].active {
background-color: #fff0cc;
}
.status-btn[data-status="pending"] i {
color: #f59e0b;
}
.status-btn[data-status="all"] {
color: #44546a;
background-color: #f8fafc;
}
.status-btn[data-status="all"].active {
background-color: #f1f5f9;
}
.status-btn[data-status="all"] i {
color: #44546a;
}
2025-12-01 10:34:27 +05:30
.filter-label {
font-size: 13px;
font-weight: 600;
color: var(--primary-1);
}
.filter-control {
padding: 8px 12px;
border-radius: 8px;
border: 1px solid #e3eaf6;
background: #fff;
font-size: 14px;
min-width: 140px;
}
.filter-control:focus {
outline: none;
border-color: var(--primary-1);
box-shadow: 0 0 0 2px rgba(26, 41, 81, 0.1);
}
2025-12-02 18:11:58 +05:30
/* Table-specific filter sections */
.payment-filters-section, .order-filters-section {
2025-12-01 10:34:27 +05:30
display: flex;
2025-12-02 18:11:58 +05:30
gap: 12px;
align-items: center;
flex-wrap: wrap;
margin-bottom: 16px;
padding: 12px 14px;
2026-02-27 10:51:26 +05:30
background:linear-gradient(90deg, #e6ebf5 0%, #f9fbff 100%);
2025-12-02 18:11:58 +05:30
border-radius: 8px;
border: 1px solid #eef3fb;
2025-12-01 10:34:27 +05:30
}
/* Action buttons in table */
.action-btn {
background: transparent;
border: none;
cursor: pointer;
padding: 6px 8px;
border-radius: 6px;
transition: all 0.2s ease;
display: inline-flex;
align-items: center;
justify-content: center;
}
.edit-btn {
color: var(--primary-1);
}
.edit-btn:hover {
background: rgba(26, 41, 81, 0.08);
}
.delete-btn {
color: var(--danger);
}
.delete-btn:hover {
background: rgba(239, 79, 79, 0.08);
}
.action-btns {
display: flex;
gap: 4px;
justify-content: center;
}
/* Edit modal styles */
.edit-modal .modal-box1 {
max-width: 800px;
2025-12-02 18:11:58 +05:30
z-index: 1250;
2025-12-01 10:34:27 +05:30
}
.edit-form-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 16px;
margin-bottom: 16px;
}
.edit-form-actions {
display: flex;
gap: 12px;
justify-content: flex-end;
margin-top: 20px;
}
/* Order management in edit modal */
.order-management-section {
margin-top: 20px;
border-top: 1px solid #eef3fb;
padding-top: 16px;
}
.order-management-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 12px;
}
.order-management-title {
font-weight: 700;
color: var(--primary-1);
font-size: 16px;
}
.orders-table-container {
max-height: 300px;
overflow-y: auto;
border: 1px solid #eef3fb;
border-radius: 8px;
margin-bottom: 12px;
}
.orders-table {
width: 100%;
border-collapse: collapse;
font-size: 13px;
}
.orders-table th {
background: #f8fbff;
padding: 10px 12px;
text-align: left;
font-weight: 600;
color: var(--primary-1);
border-bottom: 1px solid #eef3fb;
position: sticky;
top: 0;
}
.orders-table td {
padding: 10px 12px;
border-bottom: 1px solid #f1f6ff;
}
.order-actions {
display: flex;
gap: 6px;
}
.remove-order-btn {
background: var(--danger);
color: white;
border: none;
border-radius: 4px;
padding: 4px 8px;
font-size: 12px;
cursor: pointer;
transition: background 0.2s;
}
2025-12-23 21:11:53 +05:30
.combined-top-row .btn:hover {
color: #ffffff !important;
background-color: inherit !important;
border-color: inherit !important;
transform: none !important;
box-shadow: none !important;
}
2025-12-01 10:34:27 +05:30
.remove-order-btn:hover {
background: #d42c3f;
}
/* Add Order Modal */
.add-order-modal .modal-box1 {
max-width: 1000px;
}
.add-order-actions {
display: flex;
justify-content: flex-end;
gap: 12px;
margin-top: 16px;
}
2025-11-21 16:07:43 +05:30
/* responsive */
@media (max-width:980px){
2025-11-26 23:07:12 +05:30
.create-grid { grid-template-columns: 1fr; }
2025-11-21 16:07:43 +05:30
.panel-card { min-width:100%; }
.search-row input{ width:220px; }
2025-11-26 23:07:12 +05:30
.pagination-container { flex-direction: column; gap: 10px; align-items: stretch; }
.pagination-controls { justify-content: center; }
.account-container { padding: 20px; }
.panel-card { padding: 18px; }
2025-12-02 18:11:58 +05:30
.combined-filters-row { flex-direction: column; align-items: stretch; }
2025-12-01 10:34:27 +05:30
.filter-group { width: 100%; }
.filter-control { min-width: auto; }
.edit-form-grid { grid-template-columns: 1fr; }
2025-12-02 18:11:58 +05:30
.payment-filters-section, .order-filters-section { flex-direction: column; align-items: stretch; }
2025-11-26 23:07:12 +05:30
}
@media (max-width:768px){
.account-header { padding: 18px; }
.top-actions { flex-direction: column; align-items: stretch; }
.top-actions .left { justify-content: center; }
.entry-summary-cards { gap: 12px; }
.entry-summary-card { min-width: 140px; }
2025-12-01 10:34:27 +05:30
.edit-form-grid { grid-template-columns: 1fr; }
.order-management-header { flex-direction: column; align-items: flex-start; gap: 10px; }
2025-11-21 16:07:43 +05:30
}
2025-11-27 19:39:36 +05:30
/* Table pagination wrapper */
.table-pagination-wrapper {
margin-top: 20px;
border-top: 1px solid #eef3fb;
padding-top: 15px;
}
/* Modal pagination wrapper */
.modal-pagination-wrapper {
margin-top: 15px;
border-top: 1px solid #eef3fb;
padding-top: 12px;
}
2025-12-01 10:34:27 +05:30
/* Right-aligned pagination */
.pagination-right {
justify-content: flex-end;
}
2025-12-02 18:11:58 +05:30
/* Combined top row styling */
.combined-top-row {
display: flex;
gap: 12px;
align-items: center;
flex-wrap: wrap;
}
2025-12-22 16:49:27 +05:30
/* नवीन responsive styles */
@media (max-width:980px){
.account-container {
padding: 20px !important;
margin: 0 auto;
}
.panel-card {
min-width:100% !important;
padding: 18px !important;
}
.search-row input{
width:220px !important;
}
.pagination-container {
flex-direction: column;
gap: 10px;
align-items: stretch;
margin-right: 0 !important;
}
.combined-filters-row {
flex-direction: column;
align-items: stretch;
}
.filter-group1,
.filter-group2,
.filter-group3,
.filter-group4 {
width: 100% !important;
}
}
@media (max-width:768px){
body {
overflow-x: hidden;
}
.account-container {
padding: 15px !important;
}
.account-header {
padding: 18px !important;
}
.top-actions {
flex-direction: column;
align-items: stretch;
gap: 10px;
}
.top-actions .left {
justify-content: center;
}
.account-panels {
gap: 15px;
}
.search-row input {
width: 100% !important;
max-width: 300px;
}
/* pagination adjustments for mobile */
.pagination-controls,
.pagination-controls1,
.pagination-controls2 {
margin-right: 0 !important;
justify-content: center;
}
.pagination-container {
margin-right: 0 !important;
}
2026-02-27 10:51:26 +05:30
/* Responsive modals */
.entry-details-modal .modal-box1,
.entry-orders-modal .modal-box1 {
margin: 10px;
border-radius: 12px;
}
.entry-details-header,
.entry-orders-header {
padding: 18px 20px;
}
.entry-details-content,
.entry-orders-content {
padding: 20px;
}
.entry-summary-cards {
grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
gap: 12px;
}
.entry-summary-value {
font-size: 20px;
}
.orders-summary-row {
flex-direction: column;
gap: 15px;
text-align: center;
}
2025-12-22 16:49:27 +05:30
}
/* Zoom out specific fix */
@media screen and (max-width: 1200px) {
.account-container {
padding: 20px;
max-width: 95%;
}
.payment-block {
min-width: 100%;
}
}
/* Extra small screens */
@media screen and (max-width: 576px) {
.account-container {
padding: 10px;
}
.account-header h2 {
font-size: 22px;
}
.panel-card {
padding: 15px;
min-height: auto;
}
.pagination-container {
padding: 10px 0;
}
.pagination-info {
font-size: 12px;
}
2026-02-27 10:51:26 +05:30
.entry-summary-cards {
grid-template-columns: 1fr;
}
2025-12-22 16:49:27 +05:30
}
/* Prevent horizontal scroll on very small screens */
@media screen and (max-width: 400px) {
body {
min-width: 320px;
}
.account-container {
padding: 10px 5px;
}
.table-responsive {
overflow-x: auto;
-webkit-overflow-scrolling: touch;
}
}
/* Fix for sidebar gap on zoom out */
html, body {
max-width: 100vw;
overflow-x: hidden;
}
/* Ensure all containers are properly constrained */
.container, .container-fluid, .account-container {
max-width: 100%;
overflow-x: hidden;
}
2026-02-27 10:51:26 +05:30
2025-11-11 14:51:35 +05:30
</style>
<div class="account-container">
<!-- Header -->
<div class="account-header">
<h2>Account Dashboard</h2>
2025-11-21 16:07:43 +05:30
<p>Viewing: All Regions Workflow: Manage payments and dispatch.</p>
2025-11-11 14:51:35 +05:30
</div>
2025-11-21 16:07:43 +05:30
2025-12-02 18:11:58 +05:30
<!-- Combined Top Row - Search, Create Installment, Date Filters, Refresh -->
2025-11-21 16:07:43 +05:30
<div class="top-actions">
2025-12-02 18:11:58 +05:30
<div class="combined-top-row">
<!-- Search Section -->
2025-11-21 16:07:43 +05:30
<div class="search-row">
<input type="text" id="main-search" placeholder="Search by Entry No or Description" aria-label="Search entries">
<button class="btn ghost" id="searchBtn">Search</button>
</div>
2025-12-02 18:11:58 +05:30
<!-- Create Installment Button -->
2025-12-05 17:16:02 +05:30
@can('account.create_order')
<button class="btn" id="openCreateModalBtn">+ Create New Order</button>
@endcan
2025-12-02 18:11:58 +05:30
<!-- Date Filters -->
<div class="combined-filters-row">
<div class="filter-group1">
<label class="filter-label">From Date</label>
<input type="date" id="fromDateFilter" class="filter-control">
</div>
<div class="filter-group2">
<label class="filter-label">To Date</label>
<input type="date" id="toDateFilter" class="filter-control">
</div>
</div>
<div class="right">
<!-- Refresh Button -->
2025-11-21 16:07:43 +05:30
<button class="btn" id="refreshBtn"> Refresh</button>
2025-12-02 18:11:58 +05:30
</div>
2025-11-11 14:51:35 +05:30
</div>
2025-11-21 16:07:43 +05:30
<!-- Panels -->
2025-11-11 14:51:35 +05:30
<div class="account-panels" id="account-panels">
2025-12-01 10:34:27 +05:30
<!-- Payment Sent block + pagination एकत्र -->
<div class="payment-block">
<div class="panel-card">
<div class="panel-title">
<span>Payment Sent to China</span>
<span style="font-size:13px;color:var(--muted)">Total entries: <span id="entriesCount">0</span></span>
</div>
2025-12-02 18:11:58 +05:30
<!-- PAYMENT TABLE FILTERS (inside table) -->
<div class="payment-filters-section">
<div class="filter-group3">
<label class="filter-label">Payment Status</label>
<select id="paymentStatusFilter" class="filter-control">
<option value="">📋 All Statuses</option>
<option value="paid"> Paid</option>
<option value="unpaid"> Unpaid</option>
<option value="pending"> Pending</option>
</select>
</div>
</div>
2025-12-01 10:34:27 +05:30
<table id="main-payment-table">
<thead>
<tr>
<th>Entry No</th><th>Date</th><th>Description</th>
<th>Order Quantity</th><th>Region</th><th>Payment</th><th>Amount</th><th>Status</th>
<th>Actions</th>
</tr>
</thead>
<tbody id="paymentTableBody">
<!-- Entries will be loaded here -->
</tbody>
</table>
2025-11-21 16:07:43 +05:30
</div>
2025-12-02 18:11:58 +05:30
2025-12-01 10:34:27 +05:30
<!-- Pagination for Payment Table OUTSIDE table but SAME column -->
<div class="table-pagination-wrapper pagination-right">
2025-11-27 19:39:36 +05:30
<div class="pagination-container">
<div class="pagination-info" id="paymentPageInfo">Showing 0 entries</div>
<div class="pagination-controls">
<button class="pagination-img-btn" id="paymentPrevBtn" 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="paymentPaginationPages">
<!-- Page numbers will be inserted here -->
</div>
<button class="pagination-img-btn" id="paymentNextBtn" 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>
2025-11-11 14:51:35 +05:30
</div>
2025-11-21 16:07:43 +05:30
2025-11-27 19:39:36 +05:30
<!-- Order Dispatch Table -->
2025-11-11 14:51:35 +05:30
<div class="panel-card">
2025-11-21 16:07:43 +05:30
<div class="panel-title">
<span>Order Dispatch Status</span>
<span style="font-size:13px;color:var(--muted)">Actions: <strong>+ Add Installment</strong></span>
</div>
2025-12-01 10:34:27 +05:30
2025-12-02 18:11:58 +05:30
<!-- ORDER TABLE FILTERS (inside table) -->
<div class="order-filters-section">
<div class="filter-group4">
<label class="filter-label">Dispatch Status</label>
<select id="orderStatusFilter" class="filter-control">
<option value="">📋 All Statuses</option>
<option value="pending"> Pending</option>
<option value="loading">📦 Loading</option>
<option value="packed">📦 Packed</option>
<option value="dispatched">🚚 Dispatched</option>
<option value="delivered"> Delivered</option>
</select>
</div>
</div>
2025-12-01 10:34:27 +05:30
2025-11-11 14:51:35 +05:30
<table id="main-order-table">
<thead>
<tr>
<th>Entry No</th><th>Date</th><th>Description</th>
<th>Region</th><th>Amount</th><th>Status</th>
<th>Pending</th><th></th>
</tr>
</thead>
2025-11-21 16:07:43 +05:30
<tbody id="orderTableBody">
2025-11-27 19:39:36 +05:30
<!-- Entries will be loaded here -->
2025-11-11 14:51:35 +05:30
</tbody>
</table>
2025-12-01 10:34:27 +05:30
<!-- No pagination for second table -->
2025-11-11 14:51:35 +05:30
</div>
</div>
</div>
2025-11-26 23:07:12 +05:30
<!-- CREATE ORDER POPUP MODAL -->
<div class="create-order-modal" id="createOrderModal">
<div class="modal-box">
2026-02-27 10:51:26 +05:30
<div style="display:flex; align-items:center; justify-content:space-between; margin-bottom:16px; background:linear-gradient(135deg, #667eea 0%, #764ba2 100%); padding:20px; border-radius:12px; color:white; margin-top:-20px; margin-left:-20px; margin-right:-15px; margin-top:-15px;">
2025-12-23 21:11:53 +05:30
<div style="font-size:20px; font-weight:800;">Create New Installment</div>
2025-11-26 23:07:12 +05:30
<button class="btn ghost" id="closeCreateModal" title="Close create form"></button>
</div>
<form id="createOrderInlineForm" autocomplete="off">
<div class="create-grid">
<div>
<label for="inline_description">Description *</label>
<input class="input" type="text" id="inline_description" name="description" required placeholder="Short description for consolidated entry">
</div>
<div>
<label for="inline_region">Region *</label>
<select id="inline_region" name="region" class="input" required>
<option value="China">China</option>
<option value="Europe">Europe</option>
<option value="US">US</option>
</select>
</div>
<div>
<label for="inline_amount">Total Amount () *</label>
<input class="input" type="number" id="inline_amount" name="amount" min="0" required>
</div>
<div>
<label for="inline_entry_date">Entry Date *</label>
<input class="input" type="date" id="inline_entry_date" name="entry_date" value="{{ date('Y-m-d') }}" required>
</div>
</div>
<div style="margin-top:16px;">
<div style="display:flex; align-items:center; margin-bottom:8px;">
<div style="font-weight:700; color:#233063; margin-right:6px;">Consolidated Orders</div>
<div style="margin-left:auto; font-size:13px; color:var(--muted);">Select orders to include in the consolidated entry</div>
</div>
<div class="consolidate-area" id="consolidateArea">
<table id="consolidateOrdersTable">
<thead>
<tr>
<th></th>
<th>Order ID</th>
<th>Mark No</th>
<th>Origin</th>
<th>Destination</th>
<th>CTN</th>
<th>QTY</th>
<th>TTL/QTY</th>
<th>Total Amount ()</th>
<th>CBM</th>
<th>TTL CBM</th>
<th>KG</th>
<th>TTL KG</th>
</tr>
</thead>
<tbody id="consolidateOrdersBody">
2025-11-27 19:39:36 +05:30
<!-- Orders will be loaded here -->
2025-11-26 23:07:12 +05:30
</tbody>
</table>
2025-11-27 19:39:36 +05:30
<!-- Pagination for Create Order Modal -->
2025-12-01 10:34:27 +05:30
<div class="modal-pagination-wrapper pagination-right">
2025-11-27 19:39:36 +05:30
<div class="pagination-container">
<div class="pagination-info" id="modalPageInfo">Showing 0 entries</div>
2025-12-03 16:17:14 +05:30
<div class="pagination-controls2">
2025-11-27 19:39:36 +05:30
<button class="pagination-img-btn" id="modalPrevBtn" 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="modalPaginationPages">
<!-- Page numbers will be inserted here -->
</div>
<button class="pagination-img-btn" id="modalNextBtn" 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>
2025-11-26 23:07:12 +05:30
</div>
</div>
</div>
</div>
</div>
<div class="create-actions">
<button type="button" class="btn ghost" id="cancelCreateModal">Cancel</button>
2025-12-05 17:16:02 +05:30
<button type="submit" class="btn">Create Order</button>
2025-11-26 23:07:12 +05:30
</div>
</form>
</div>
</div>
2026-02-27 10:51:26 +05:30
<!-- ENTRY DETAILS MODAL (Enhanced) -->
<div class="modal-fade1 entry-details-modal" id="entryDetailsModal">
<div class="modal-box1">
<div class="entry-details-header" >
<h2 >Entry Details</h2>
<div class="subtitle">
<span id="entryDetailsId">Loading...</span>
<span> Complete view of all installments for this entry</span>
2025-11-21 16:07:43 +05:30
</div>
2025-11-12 19:56:06 +05:30
</div>
2026-02-27 10:51:26 +05:30
<div class="entry-details-content">
<div class="entry-summary-cards">
<div class="entry-summary-card">
<div class="entry-summary-label">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M12 2v20M17 5H9.5a3.5 3.5 0 0 0 0 7h5a3.5 3.5 0 0 1 0 7H6"/>
</svg>
Original Amount
</div>
<div class="entry-summary-value" id="originalAmount">-</div>
</div>
<div class="entry-summary-card">
<div class="entry-summary-label">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M22 12h-4l-3 9L9 3l-3 9H2"/>
</svg>
Total Processed
</div>
<div class="entry-summary-value" id="totalProcessed">-</div>
</div>
<div class="entry-summary-card">
<div class="entry-summary-label">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<circle cx="12" cy="12" r="10"/><path d="M12 6v6l4 2"/>
</svg>
Pending Balance
</div>
<div class="entry-summary-value" id="pendingBalance">-</div>
</div>
<div class="entry-summary-card">
<div class="entry-summary-label">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/>
</svg>
Total Installments
</div>
<div class="entry-summary-value" id="totalInstallments">-</div>
</div>
2025-11-12 19:56:06 +05:30
</div>
2026-02-27 10:51:26 +05:30
<div style="margin-top: 30px;">
<h3 style="font-size: 18px; font-weight: 700; color: var(--primary-1); margin-bottom: 16px;">
Installment History
</h3>
<div class="orders-table-container">
<table class="entry-installments-table">
<thead>
<tr>
<th>Installment</th>
<th>Date</th>
<th>Description</th>
<th>Region</th>
<th>Amount</th>
<th>Status</th>
</tr>
</thead>
<tbody id="installmentsTableBody">
<tr><td colspan="6" class="empty-state">No installments yet</td></tr>
</tbody>
</table>
</div>
2025-11-12 19:56:06 +05:30
</div>
</div>
2025-11-21 16:07:43 +05:30
2026-02-27 10:51:26 +05:30
<div style="padding: 20px 30px; border-top: 1px solid #eef3fb; display: flex; justify-content: space-between; align-items: center;">
<button type="button" class="btn ghost" onclick="closeEntryDetailsModal()">
Close
</button>
2025-12-05 17:16:02 +05:30
@can('account.add_installment')
2026-02-27 10:51:26 +05:30
<button type="button" class="btn" id="addInstallmentFromDetails">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" style="margin-right: 6px;">
<line x1="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/>
</svg>
Add New Installment
</button>
2025-12-05 17:16:02 +05:30
@endcan
2025-11-12 19:56:06 +05:30
</div>
</div>
</div>
2026-02-27 10:51:26 +05:30
<!-- ENTRY ORDERS MODAL (Enhanced) -->
<div class="modal-fade1 entry-orders-modal" id="entryOrdersModal">
<div class="modal-box1">
<div class="entry-orders-header">
<h2>Entry Orders</h2>
<div class="subtitle">
<span id="entryOrdersEntryNo-span">Loading...</span>
<span> All orders associated with this entry</span>
</div>
</div>
<div class="entry-orders-content">
<div class="orders-table-container">
<table class="orders-table">
<thead>
<tr>
<th>Order ID</th>
<th>Mark No</th>
<th>Origin</th>
<th>Destination</th>
<th>CTN</th>
<th>QTY</th>
<th>Amount</th>
</tr>
</thead>
<tbody id="entryOrdersTableBody">
<tr>
<td colspan="7" class="empty-state">Loading orders...</td>
</tr>
</tbody>
</table>
</div>
<div class="orders-summary-row">
<div class="orders-summary-item">
<div class="orders-summary-value" id="ordersTotalCount">0</div>
<div class="orders-summary-label">Total Orders</div>
</div>
<div class="orders-summary-item">
<div class="orders-summary-value" id="ordersTotalQuantity">0</div>
<div class="orders-summary-label">Total Quantity</div>
</div>
<div class="orders-summary-item">
<div class="orders-summary-value" id="ordersTotalAmount">₹0</div>
<div class="orders-summary-label">Total Amount</div>
</div>
</div>
2025-12-02 18:11:58 +05:30
</div>
2026-02-27 10:51:26 +05:30
<div style="padding: 20px 30px; border-top: 1px solid #eef3fb; display: flex; justify-content: flex-end;">
<button class="btn ghost" type="button" onclick="closeEntryOrdersModal()">
Close
</button>
</div>
2025-12-02 18:11:58 +05:30
</div>
</div>
2025-11-21 16:07:43 +05:30
<!-- Installment Modal -->
2025-11-11 14:51:35 +05:30
<div class="modal-fade1" id="installmentModal">
2025-11-21 16:07:43 +05:30
<div class="modal-box1" style="max-width:720px;">
2026-02-27 10:51:26 +05:30
<div style="display:flex;align-items:center; justify-content:space-between; margin-bottom:12px; background:linear-gradient(135deg, #667eea 0%, #764ba2 100%); padding:16px; border-radius:8px; color:white; margin-top:-15px; margin-left:-20px; margin-right:-15px;">
2025-11-21 16:07:43 +05:30
<div style="font-size:18px;font-weight:800;color:#243a72;">+ Add New Installment</div>
2025-11-26 23:07:12 +05:30
<button class="btn ghost" onclick="closeInstallmentModal()"></button>
2025-11-11 14:51:35 +05:30
</div>
2025-11-21 16:07:43 +05:30
<div style="font-size:14px;color:#6f7b8f;margin-bottom:14px;">Create a new processing entry for the remaining pending amount</div>
<div id="instDetailsRow" style="display:flex; gap:18px; margin-bottom:12px; flex-wrap:wrap;"></div>
2025-11-11 14:51:35 +05:30
<form id="installmentForm" autocomplete="off">
2025-11-21 16:07:43 +05:30
<div style="display:grid; grid-template-columns:1fr 1fr; gap:12px;">
<div>
<label>Processing Date *</label>
<input type="date" name="proc_date" required style="width:100%; padding:10px; border-radius:8px; border:1.4px solid #e7eefb;" value="{{ date('Y-m-d') }}">
2025-11-11 14:51:35 +05:30
</div>
2025-11-21 16:07:43 +05:30
<div>
<label>Processing Amount *</label>
<input type="number" min="1" name="proc_amount" required placeholder="Enter amount" style="width:100%; padding:10px; border-radius:8px; border:1.4px solid #e7eefb;">
<span class="helper-note">Maximum allowed: <strong id="maxPending">-</strong></span>
2025-11-11 14:51:35 +05:30
</div>
2025-11-21 16:07:43 +05:30
<div>
<label>Status</label>
<select name="status" required style="width:100%; padding:10px; border-radius:8px; border:1.4px solid #e7eefb;">
<option>Pending</option><option>Loading</option><option>Packed</option><option>Dispatched</option><option>Delivered</option>
2025-11-11 14:51:35 +05:30
</select>
</div>
</div>
2025-11-21 16:07:43 +05:30
<div style="display:flex; justify-content:flex-end; gap:12px; margin-top:14px;">
<button type="button" class="btn ghost" onclick="closeInstallmentModal()">Cancel</button>
2025-12-05 17:16:02 +05:30
@can('account.add_installment')
<button type="submit" class="btn">Create Installment2</button>
@endcan
2025-11-11 14:51:35 +05:30
</div>
</form>
</div>
</div>
2025-12-01 10:34:27 +05:30
<!-- Edit Entry Modal -->
<div class="modal-fade1 edit-modal" id="editEntryModal">
<div class="modal-box1">
<div style="display:flex;align-items:center; justify-content:space-between; margin-bottom:12px;">
<div style="font-size:18px;font-weight:800;color:#243a72;">Edit Entry</div>
<button class="btn ghost" onclick="closeEditModal()"></button>
</div>
<div style="font-size:14px;color:#6f7b8f;margin-bottom:14px;">Update the description and order quantity for this entry</div>
<form id="editEntryForm" autocomplete="off">
<input type="hidden" id="edit_entry_no" name="entry_no">
<div class="edit-form-grid">
<div>
<label>Description *</label>
<input type="text" id="edit_description" name="description" required class="input" placeholder="Entry description">
</div>
<div>
2025-12-04 11:21:46 +05:30
<label>
Order Quantity
<span style="font-size:12px; color:#6b7280; margin-left:4px;">
(Auto Update)
</span>
</label>
<input
type="number"
id="edit_order_quantity"
name="order_quantity"
min="0"
class="input"
placeholder="Order quantity"
readonly
style="cursor:pointer;"
onclick="openEntryOrdersModal(document.getElementById('edit_entry_no').value)"
>
<small class="helper-note">
Click on quantity to view associated orders.
</small>
2025-12-02 18:11:58 +05:30
</div>
2025-12-04 11:21:46 +05:30
<!-- <div>
2025-12-01 10:34:27 +05:30
<label>Payment Status</label>
<select id="edit_payment_status" name="payment_status" class="input">
<option value="unpaid">Unpaid</option>
<option value="paid">Paid</option>
<option value="pending">Pending</option>
</select>
2025-12-04 11:21:46 +05:30
</div>-->
2025-12-01 10:34:27 +05:30
<div>
<label>Region</label>
<select id="edit_region" name="region" class="input" required>
<option value="China">China</option>
<option value="Europe">Europe</option>
<option value="US">US</option>
</select>
</div>
<div>
<label>Amount () *</label>
<input type="number" id="edit_amount" name="amount" min="0" required class="input" placeholder="Entry amount">
</div>
</div>
<!-- Order Management Section -->
<div class="order-management-section">
<div class="order-management-header">
<div class="order-management-title">Associated Orders</div>
<button type="button" class="btn ghost" id="addOrderBtn">+ Add Orders</button>
</div>
<div class="orders-table-container">
<table class="orders-table">
<thead>
<tr>
<th>Order ID</th>
<th>Mark No</th>
<th>Origin</th>
<th>Destination</th>
<th>CTN</th>
<th>QTY</th>
<th>Amount ()</th>
<th>Actions</th>
</tr>
</thead>
<tbody id="editOrdersTableBody">
<!-- Orders will be loaded here -->
</tbody>
</table>
</div>
<div id="editOrdersEmptyState" class="empty-state" style="display:none;">
No orders associated with this entry
</div>
</div>
<div class="edit-form-actions">
<button type="button" class="btn ghost" onclick="closeEditModal()">Cancel</button>
<button type="submit" class="btn">Update Entry</button>
</div>
</form>
</div>
</div>
<!-- Add Order Modal -->
<div class="modal-fade1 add-order-modal" id="addOrderModal">
<div class="modal-box1">
<div style="display:flex;align-items:center; justify-content:space-between; margin-bottom:12px;">
<div style="font-size:18px;font-weight:800;color:#243a72;">Add Orders to Entry</div>
<button class="btn ghost" onclick="closeAddOrderModal()"></button>
</div>
<div style="font-size:14px;color:#6f7b8f;margin-bottom:14px;">Select orders to associate with this entry</div>
<div class="consolidate-area" style="min-height: 400px;">
<table id="addOrderTable">
<thead>
<tr>
<th></th>
<th>Order ID</th>
<th>Mark No</th>
<th>Origin</th>
<th>Destination</th>
<th>CTN</th>
<th>QTY</th>
<th>Amount ()</th>
</tr>
</thead>
<tbody id="addOrderTableBody">
<!-- Orders will be loaded here -->
</tbody>
</table>
<!-- Pagination for Add Order Modal -->
<div class="modal-pagination-wrapper pagination-right">
<div class="pagination-container">
<div class="pagination-info" id="addOrderPageInfo">Showing 0 entries</div>
2025-12-03 16:17:14 +05:30
<div class="pagination-controls1">
2025-12-01 10:34:27 +05:30
<button class="pagination-img-btn" id="addOrderPrevBtn" 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="addOrderPaginationPages">
<!-- Page numbers will be inserted here -->
</div>
<button class="pagination-img-btn" id="addOrderNextBtn" 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 class="add-order-actions">
<button type="button" class="btn ghost" onclick="closeAddOrderModal()">Cancel</button>
<button type="button" class="btn" id="confirmAddOrdersBtn">Add Selected Orders</button>
</div>
</div>
</div>
2025-12-05 17:16:02 +05:30
<script>
window.CAN_EDIT_ORDER = @json(auth()->user()->can('account.edit_order'));
window.CAN_DELETE_ORDER = @json(auth()->user()->can('account.delete_order'));
window.CAN_TOGGLE_PAYMENT = @json(auth()->user()->can('account.toggle_payment_status'));
</script>
2025-11-21 16:07:43 +05:30
<script>
/* ---------- Helpers & state ---------- */
2025-12-02 18:11:58 +05:30
function setToggleVisual(btn, pos) {
// pos: 0 = unpaid (red), 1 = pending (yellow), 2 = paid (green)
btn.classList.remove('mid', 'checked');
if (pos === 1) {
btn.classList.add('mid'); // yellow
} else if (pos === 2) {
btn.classList.add('checked'); // green
}
}
2025-11-21 16:07:43 +05:30
const csrfToken = document.querySelector('meta[name="csrf-token"]').getAttribute('content');
function jsonFetch(url, opts = {}) {
2025-12-01 10:34:27 +05:30
opts.headers = Object.assign(
{ 'Content-Type': 'application/json', 'X-CSRF-TOKEN': csrfToken },
opts.headers || {}
);
if (opts.body && typeof opts.body !== 'string') {
opts.body = JSON.stringify(opts.body);
}
return fetch(url, opts).then(r =>
r.json().catch(() => {
throw new Error('Invalid server response');
})
);
2025-11-21 16:07:43 +05:30
}
2025-12-01 10:34:27 +05:30
2025-11-21 16:07:43 +05:30
let entries = [];
let availableOrders = [];
let currentEntry = null;
2025-12-01 10:34:27 +05:30
let currentEditEntry = null;
2025-11-21 16:07:43 +05:30
2025-11-27 19:39:36 +05:30
/* Single pagination state for both tables */
2025-11-26 23:07:12 +05:30
let currentPage = 1;
2025-11-27 19:39:36 +05:30
const entriesPerPage = 10;
2025-12-01 10:34:27 +05:30
/* Separate pagination state for modals */
2025-11-27 19:39:36 +05:30
let modalCurrentPage = 1;
const modalOrdersPerPage = 10;
2025-12-01 10:34:27 +05:30
let addOrderCurrentPage = 1;
2025-12-02 18:11:58 +05:30
/* Date filter state */
let fromDateFilter = '';
let toDateFilter = '';
/* Status filter state */
2025-12-01 10:34:27 +05:30
let paymentStatusFilter = '';
let orderStatusFilter = '';
2025-11-26 23:07:12 +05:30
2025-11-21 16:07:43 +05:30
/* small util */
function escapeHtml(s){ if(s === null || s === undefined) return ''; return String(s).replace(/[&<>"']/g, m => ({'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":"&#39;"}[m])); }
function formatCurrency(v){ return '₹' + Number(v || 0).toLocaleString(undefined, { minimumFractionDigits:0, maximumFractionDigits:2 }); }
function capitalize(s){ if(!s) return ''; s = String(s); return s.charAt(0).toUpperCase() + s.slice(1); }
function statusClass(status){
switch(String(status || '').toLowerCase()){
case 'unpaid': return 'status-unpaid';
case 'paid': return 'status-paid';
case 'loading': return 'status-loading';
case 'dispatched': return 'status-dispatched';
2025-12-01 10:34:27 +05:30
case 'packed': return 'status-loading';
case 'delivered': return 'status-delivered';
case 'pending': return 'pending-badge-red';
2025-11-21 16:07:43 +05:30
default: return 'status-loading';
}
}
/* ---------- Init ---------- */
window.addEventListener('DOMContentLoaded', () => {
bindUI();
loadDashboard();
});
2025-11-12 19:56:06 +05:30
2025-11-21 16:07:43 +05:30
/* ---------- UI binding ---------- */
function bindUI(){
2025-11-26 23:07:12 +05:30
// Create Order Modal
2025-12-05 17:16:02 +05:30
//document.getElementById('openCreateModalBtn').addEventListener('click', openCreateOrderModal);
const createBtn = document.getElementById('openCreateModalBtn');
if (createBtn) {
createBtn.addEventListener('click', openCreateOrderModal);
}
2025-11-26 23:07:12 +05:30
document.getElementById('closeCreateModal').addEventListener('click', closeCreateOrderModal);
document.getElementById('cancelCreateModal').addEventListener('click', closeCreateOrderModal);
2025-11-21 16:07:43 +05:30
document.getElementById('createOrderInlineForm').addEventListener('submit', submitCreateOrderInline);
2025-11-26 23:07:12 +05:30
2025-12-01 10:34:27 +05:30
// Payment Table Pagination (only pagination controls)
2025-11-27 19:39:36 +05:30
document.getElementById('paymentPrevBtn').addEventListener('click', () => goToPreviousPage());
document.getElementById('paymentNextBtn').addEventListener('click', () => goToNextPage());
2025-12-01 10:34:27 +05:30
// No pagination controls for order table
2025-11-27 19:39:36 +05:30
// Modal Pagination
document.getElementById('modalPrevBtn').addEventListener('click', () => goToModalPreviousPage());
document.getElementById('modalNextBtn').addEventListener('click', () => goToModalNextPage());
2025-11-26 23:07:12 +05:30
2025-12-01 10:34:27 +05:30
// Add Order Modal Pagination
document.getElementById('addOrderPrevBtn').addEventListener('click', () => goToAddOrderPreviousPage());
document.getElementById('addOrderNextBtn').addEventListener('click', () => goToAddOrderNextPage());
2025-12-02 18:11:58 +05:30
document.getElementById('refreshBtn').addEventListener('click', () => {
loadDashboard();
clearDateFilters();
clearStatusFilters();
});
2025-11-21 16:07:43 +05:30
document.getElementById('searchBtn').addEventListener('click', handleSearch);
2025-12-05 17:16:02 +05:30
const addInstallBtn = document.getElementById('addInstallmentFromDetails');
if (addInstallBtn) {
addInstallBtn.addEventListener('click', () => {
if (!currentEntry) return;
openInstallmentModal(
currentEntry.entry_no,
currentEntry.description,
currentEntry.region,
currentEntry.pending_amount
);
closeEntryDetailsModal();
});
}
2025-11-21 16:07:43 +05:30
// Installment form submit
document.getElementById('installmentForm').addEventListener('submit', submitInstallment);
2025-12-01 10:34:27 +05:30
// Edit form submit
document.getElementById('editEntryForm').addEventListener('submit', submitEditEntry);
// Add Order button in Edit Modal
document.getElementById('addOrderBtn').addEventListener('click', openAddOrderModal);
// Confirm Add Orders button
document.getElementById('confirmAddOrdersBtn').addEventListener('click', confirmAddOrders);
2025-12-02 18:11:58 +05:30
// Date Filter bindings
document.getElementById('fromDateFilter').addEventListener('change', (e) => {
fromDateFilter = e.target.value;
applyAllFilters();
2025-12-01 10:34:27 +05:30
});
2025-12-02 18:11:58 +05:30
document.getElementById('toDateFilter').addEventListener('change', (e) => {
toDateFilter = e.target.value;
applyAllFilters();
2025-12-01 10:34:27 +05:30
});
2025-12-02 18:11:58 +05:30
// Status Filter bindings
document.getElementById('paymentStatusFilter').addEventListener('change', (e) => {
paymentStatusFilter = e.target.value;
applyAllFilters();
2025-12-01 10:34:27 +05:30
});
document.getElementById('orderStatusFilter').addEventListener('change', (e) => {
orderStatusFilter = e.target.value;
2025-12-02 18:11:58 +05:30
applyAllFilters();
2025-12-01 10:34:27 +05:30
});
}
2025-12-02 18:11:58 +05:30
/* ---------- Filter Functions ---------- */
function applyAllFilters() {
2025-12-01 10:34:27 +05:30
let filteredEntries = [...entries];
2025-12-02 18:11:58 +05:30
// Apply date filters (both tables)
if (fromDateFilter) {
filteredEntries = filteredEntries.filter(entry => entry.entry_date >= fromDateFilter);
}
if (toDateFilter) {
filteredEntries = filteredEntries.filter(entry => entry.entry_date <= toDateFilter);
2025-12-01 10:34:27 +05:30
}
2025-12-02 18:11:58 +05:30
// Apply payment status filter (ONLY for payment table)
let paymentFilteredEntries = [...filteredEntries];
2025-12-01 10:34:27 +05:30
if (paymentStatusFilter) {
2025-12-02 18:11:58 +05:30
paymentFilteredEntries = paymentFilteredEntries.filter(entry =>
2025-12-01 10:34:27 +05:30
entry.payment_status.toLowerCase() === paymentStatusFilter.toLowerCase()
);
}
2025-12-02 18:11:58 +05:30
// Apply order status filter (ONLY for order table)
let orderFilteredEntries = [...filteredEntries];
if (orderStatusFilter) {
orderFilteredEntries = orderFilteredEntries.filter(entry =>
entry.dispatch_status.toLowerCase() === orderStatusFilter.toLowerCase()
);
}
2025-12-01 10:34:27 +05:30
// Reset to first page when filtering
currentPage = 1;
2025-12-02 18:11:58 +05:30
// Render each table with its own filtered data
renderPaymentTable(paymentFilteredEntries);
renderOrderTable(orderFilteredEntries);
2025-12-01 10:34:27 +05:30
updatePaginationControls();
}
2025-12-02 18:11:58 +05:30
function applyOrderTableFilters(entriesList) {
let filtered = [...entriesList];
2025-12-01 10:34:27 +05:30
2025-12-02 18:11:58 +05:30
// Apply order status filter (for order table only)
2025-12-01 10:34:27 +05:30
if (orderStatusFilter) {
2025-12-02 18:11:58 +05:30
filtered = filtered.filter(entry =>
2025-12-01 10:34:27 +05:30
entry.dispatch_status.toLowerCase() === orderStatusFilter.toLowerCase()
);
}
2025-12-02 18:11:58 +05:30
return filtered;
2025-12-01 10:34:27 +05:30
}
2025-12-02 18:11:58 +05:30
function clearDateFilters() {
document.getElementById('fromDateFilter').value = '';
document.getElementById('toDateFilter').value = '';
fromDateFilter = '';
toDateFilter = '';
2025-12-01 10:34:27 +05:30
}
2025-12-02 18:11:58 +05:30
function clearStatusFilters() {
document.getElementById('paymentStatusFilter').value = '';
2025-12-01 10:34:27 +05:30
document.getElementById('orderStatusFilter').value = '';
2025-12-02 18:11:58 +05:30
paymentStatusFilter = '';
2025-12-01 10:34:27 +05:30
orderStatusFilter = '';
2025-11-21 16:07:43 +05:30
}
2025-11-26 23:07:12 +05:30
/* ---------- Pagination Functions ---------- */
function goToPreviousPage() {
if (currentPage > 1) {
currentPage--;
2025-11-27 19:39:36 +05:30
renderBothTables();
2025-12-01 10:34:27 +05:30
updatePaginationControls();
2025-11-26 23:07:12 +05:30
}
}
function goToNextPage() {
2025-11-27 19:39:36 +05:30
const totalPages = Math.ceil(entries.length / entriesPerPage);
2025-11-26 23:07:12 +05:30
if (currentPage < totalPages) {
currentPage++;
2025-11-27 19:39:36 +05:30
renderBothTables();
2025-12-01 10:34:27 +05:30
updatePaginationControls();
2025-11-27 19:39:36 +05:30
}
}
function goToModalPreviousPage() {
if (modalCurrentPage > 1) {
modalCurrentPage--;
renderConsolidateOrders(availableOrders);
updateModalPaginationControls();
}
}
function goToModalNextPage() {
const totalPages = Math.ceil(availableOrders.length / modalOrdersPerPage);
if (modalCurrentPage < totalPages) {
modalCurrentPage++;
2025-11-26 23:07:12 +05:30
renderConsolidateOrders(availableOrders);
2025-11-27 19:39:36 +05:30
updateModalPaginationControls();
2025-11-26 23:07:12 +05:30
}
}
2025-12-01 10:34:27 +05:30
function goToAddOrderPreviousPage() {
if (addOrderCurrentPage > 1) {
addOrderCurrentPage--;
renderAddOrderModal(availableOrders);
updateAddOrderPaginationControls();
}
}
function goToAddOrderNextPage() {
const totalPages = Math.ceil(availableOrders.length / modalOrdersPerPage);
if (addOrderCurrentPage < totalPages) {
addOrderCurrentPage++;
renderAddOrderModal(availableOrders);
updateAddOrderPaginationControls();
}
2025-11-27 19:39:36 +05:30
}
2025-12-01 10:34:27 +05:30
function updatePaginationControls() {
const totalPages = Math.ceil(entries.length / entriesPerPage);
const prevBtn = document.getElementById('paymentPrevBtn');
const nextBtn = document.getElementById('paymentNextBtn');
const pageInfo = document.getElementById('paymentPageInfo');
const paginationPages = document.getElementById('paymentPaginationPages');
2025-11-26 23:07:12 +05:30
prevBtn.disabled = currentPage === 1;
nextBtn.disabled = currentPage === totalPages || totalPages === 0;
// Update page info text
2025-11-27 19:39:36 +05:30
const startIndex = (currentPage - 1) * entriesPerPage + 1;
const endIndex = Math.min(currentPage * entriesPerPage, entries.length);
pageInfo.textContent = `Showing ${startIndex} to ${endIndex} of ${entries.length} entries`;
2025-11-26 23:07:12 +05:30
// 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);
}
}
2025-11-27 19:39:36 +05:30
function updateModalPaginationControls() {
const totalPages = Math.ceil(availableOrders.length / modalOrdersPerPage);
const prevBtn = document.getElementById('modalPrevBtn');
const nextBtn = document.getElementById('modalNextBtn');
const pageInfo = document.getElementById('modalPageInfo');
const paginationPages = document.getElementById('modalPaginationPages');
prevBtn.disabled = modalCurrentPage === 1;
nextBtn.disabled = modalCurrentPage === totalPages || totalPages === 0;
// Update page info text
const startIndex = (modalCurrentPage - 1) * modalOrdersPerPage + 1;
const endIndex = Math.min(modalCurrentPage * modalOrdersPerPage, availableOrders.length);
pageInfo.textContent = `Showing ${startIndex} to ${endIndex} of ${availableOrders.length} orders`;
// 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="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="pagination-ellipsis">...</span>';
}
addModalPageButton(totalPages, paginationPages);
}
}
2025-12-01 10:34:27 +05:30
function updateAddOrderPaginationControls() {
const totalPages = Math.ceil(availableOrders.length / modalOrdersPerPage);
const prevBtn = document.getElementById('addOrderPrevBtn');
const nextBtn = document.getElementById('addOrderNextBtn');
const pageInfo = document.getElementById('addOrderPageInfo');
const paginationPages = document.getElementById('addOrderPaginationPages');
prevBtn.disabled = addOrderCurrentPage === 1;
nextBtn.disabled = addOrderCurrentPage === totalPages || totalPages === 0;
// Update page info text
const startIndex = (addOrderCurrentPage - 1) * modalOrdersPerPage + 1;
const endIndex = Math.min(addOrderCurrentPage * modalOrdersPerPage, availableOrders.length);
pageInfo.textContent = `Showing ${startIndex} to ${endIndex} of ${availableOrders.length} orders`;
// Generate page numbers
paginationPages.innerHTML = '';
if (totalPages <= 7) {
// Show all pages
for (let i = 1; i <= totalPages; i++) {
addAddOrderPageButton(i, paginationPages);
}
} else {
// Show first page, current page range, and last page
addAddOrderPageButton(1, paginationPages);
if (addOrderCurrentPage > 3) {
paginationPages.innerHTML += '<span class="pagination-ellipsis">...</span>';
}
const start = Math.max(2, addOrderCurrentPage - 1);
const end = Math.min(totalPages - 1, addOrderCurrentPage + 1);
for (let i = start; i <= end; i++) {
addAddOrderPageButton(i, paginationPages);
}
if (addOrderCurrentPage < totalPages - 2) {
paginationPages.innerHTML += '<span class="pagination-ellipsis">...</span>';
}
addAddOrderPageButton(totalPages, paginationPages);
}
}
2025-11-26 23:07:12 +05:30
function addPageButton(pageNumber, container) {
const button = document.createElement('button');
button.className = 'pagination-page-btn';
2025-11-27 19:39:36 +05:30
2025-11-26 23:07:12 +05:30
if (pageNumber === currentPage) {
button.classList.add('active');
}
2025-11-27 19:39:36 +05:30
2025-11-26 23:07:12 +05:30
button.textContent = pageNumber;
button.addEventListener('click', () => {
currentPage = pageNumber;
2025-11-27 19:39:36 +05:30
renderBothTables();
2025-12-01 10:34:27 +05:30
updatePaginationControls();
2025-11-27 19:39:36 +05:30
});
container.appendChild(button);
}
function addModalPageButton(pageNumber, container) {
const button = document.createElement('button');
button.className = 'pagination-page-btn';
if (pageNumber === modalCurrentPage) {
button.classList.add('active');
}
button.textContent = pageNumber;
button.addEventListener('click', () => {
modalCurrentPage = pageNumber;
2025-11-26 23:07:12 +05:30
renderConsolidateOrders(availableOrders);
2025-11-27 19:39:36 +05:30
updateModalPaginationControls();
2025-11-26 23:07:12 +05:30
});
container.appendChild(button);
2025-11-21 16:07:43 +05:30
}
2025-11-26 23:07:12 +05:30
2025-12-01 10:34:27 +05:30
function addAddOrderPageButton(pageNumber, container) {
const button = document.createElement('button');
button.className = 'pagination-page-btn';
if (pageNumber === addOrderCurrentPage) {
button.classList.add('active');
}
button.textContent = pageNumber;
button.addEventListener('click', () => {
addOrderCurrentPage = pageNumber;
renderAddOrderModal(availableOrders);
updateAddOrderPaginationControls();
});
container.appendChild(button);
}
2025-11-27 19:39:36 +05:30
function renderBothTables() {
renderPaymentTable(entries);
renderOrderTable(entries);
}
2025-11-26 23:07:12 +05:30
/* ---------- Create Order Modal Functions ---------- */
function openCreateOrderModal(){
const modal = document.getElementById('createOrderModal');
modal.classList.add('modal-open');
2025-11-21 16:07:43 +05:30
loadAvailableOrders();
setTimeout(()=> document.getElementById('inline_description').focus(), 220);
}
2025-11-26 23:07:12 +05:30
function closeCreateOrderModal(){
const modal = document.getElementById('createOrderModal');
modal.classList.remove('modal-open');
document.getElementById('createOrderInlineForm').reset();
2025-11-27 19:39:36 +05:30
modalCurrentPage = 1; // Reset modal pagination when closing
2025-11-21 16:07:43 +05:30
}
/* ---------- Loaders ---------- */
function loadDashboard(){
2025-12-01 10:34:27 +05:30
jsonFetch('/admin/account/dashboard')
.then(res => {
if(!res.success) throw new Error(res.message || 'Failed to load dashboard');
entries = res.entries || [];
renderBothTables();
updatePaginationControls(); // Initialize pagination after loading
document.getElementById('entriesCount').textContent = entries.length;
})
.catch(err => {
console.error(err);
document.getElementById('paymentTableBody').innerHTML = '<tr><td colspan="9" class="empty-state">Unable to load entries</td></tr>';
document.getElementById('orderTableBody').innerHTML = '<tr><td colspan="8" class="empty-state">Unable to load entries</td></tr>';
});
}
function loadAvailableOrders() {
const tbody = document.getElementById('consolidateOrdersBody');
tbody.innerHTML = '<tr><td colspan="14" class="empty-state">Loading available orders...</td></tr>';
jsonFetch('/admin/account/available-orders', { method: 'GET' })
.then(res => {
if (!res.success) throw new Error(res.message || 'Failed to load orders');
availableOrders = res.orders || [];
modalCurrentPage = 1; // Reset to first page when loading new orders
renderConsolidateOrders(availableOrders);
updateModalPaginationControls();
})
.catch(err => {
console.error(err);
tbody.innerHTML = '<tr><td colspan="14" class="empty-state">Unable to load orders</td></tr>';
updateModalPaginationControls();
});
}
2025-12-03 16:17:14 +05:30
function loadAvailableOrdersForAddModal() {
const tbody = document.getElementById('addOrderTableBody');
if (tbody) {
tbody.innerHTML = `
<tr>
<td colspan="8" class="empty-state">Loading available orders...</td>
</tr>
`;
}
jsonFetch('/admin/account/available-orders', {
method: 'GET'
})
.then(res => {
if (!res.success) {
throw new Error(res.message || 'Failed to load available orders');
}
availableOrders = res.orders || [];
addOrderCurrentPage = 1;
renderAddOrderModal(availableOrders);
updateAddOrderPaginationControls();
})
.catch(err => {
console.error(err);
if (tbody) {
tbody.innerHTML = `
<tr>
<td colspan="8" class="empty-state">Unable to load available orders</td>
</tr>
`;
}
updateAddOrderPaginationControls();
});
}
2025-12-01 10:34:27 +05:30
2025-11-21 16:07:43 +05:30
/* ---------- Renderers ---------- */
function renderPaymentTable(list){
2025-12-02 18:11:58 +05:30
const body = document.getElementById('paymentTableBody');
body.innerHTML = '';
if (!list || list.length === 0) {
2025-12-05 17:16:02 +05:30
body.innerHTML = '<tr><td colspan="9" class="empty-state">No entries found</td></tr>';
return;
2025-12-02 18:11:58 +05:30
}
2025-12-05 17:16:02 +05:30
2025-12-02 18:11:58 +05:30
const startIndex = (currentPage - 1) * entriesPerPage;
const endIndex = startIndex + entriesPerPage;
const paginatedEntries = list.slice(startIndex, endIndex);
2025-12-05 17:16:02 +05:30
2025-12-02 18:11:58 +05:30
paginatedEntries.forEach(entry => {
2025-12-05 17:16:02 +05:30
const tr = document.createElement('tr');
2025-12-02 18:11:58 +05:30
2025-12-05 17:16:02 +05:30
const canActions = ['unpaid','pending'].includes(entry.payment_status.toLowerCase());
2025-12-04 11:21:46 +05:30
2025-12-05 17:16:02 +05:30
// permissions passed from Blade
const canEdit = window.CAN_EDIT_ORDER;
const canDelete = window.CAN_DELETE_ORDER;
const canToggle = window.CAN_TOGGLE_PAYMENT;
2025-12-04 11:21:46 +05:30
2025-12-05 17:16:02 +05:30
tr.innerHTML = `
<td>${escapeHtml(entry.entry_no)}</td>
<td>${escapeHtml(entry.entry_date)}</td>
<td>${escapeHtml(entry.description)}</td>
2026-03-09 10:24:44 +05:30
<!-- Order Quantity - Clickable number without box -->
2025-12-05 17:16:02 +05:30
<td>
2026-03-09 10:24:44 +05:30
<span onclick="openEntryOrdersModal('${escapeHtml(entry.entry_no)}')"
style="cursor: pointer; color: #276dea; font-weight: 600; text-decoration: underline; text-decoration-color: #ccc;">
2025-12-05 17:16:02 +05:30
${entry.order_quantity ?? '-'}
2026-03-09 10:24:44 +05:30
</span>
2025-12-05 17:16:02 +05:30
</td>
<td>${escapeHtml(entry.region)}</td>
<td>
<button class="toggle-switch-btn"
data-entry="${entry.entry_no}"
data-pos="${entry.toggle_pos ?? 0}"
${!canToggle ? 'disabled class="toggle-switch-btn disabled-toggle"' : ''}
></button>
</td>
<td>${formatCurrency(entry.amount)}</td>
<td>
<span class="status-badge ${statusClass(entry.payment_status)}">
${capitalize(entry.payment_status)}
</span>
</td>
<td>
<div class="action-btns">
${(canActions && canEdit) ? `
<button class="action-btn edit-btn"
data-entry="${entry.entry_no}"
title="Edit entry">
</button>
` : ''}
2025-12-04 11:21:46 +05:30
2025-12-05 17:16:02 +05:30
${(canActions && canDelete) ? `
<button class="action-btn delete-btn"
data-entry="${entry.entry_no}"
title="Delete entry">
🗑
</button>
` : ''}
2025-12-04 11:21:46 +05:30
2025-12-05 17:16:02 +05:30
</div>
</td>
`;
/* Toggle Button Logic */
const toggleBtn = tr.querySelector('.toggle-switch-btn');
setToggleVisual(toggleBtn, Number(toggleBtn.dataset.pos));
if (canToggle) {
toggleBtn.addEventListener("click", () => cycleToggle(toggleBtn));
} else {
toggleBtn.style.opacity = "0.5";
toggleBtn.style.cursor = "not-allowed";
}
/* EDIT binding */
if (canActions && canEdit) {
const editBtn = tr.querySelector(".edit-btn");
editBtn?.addEventListener("click", () => openEditModal(entry));
}
/* DELETE binding */
if (canActions && canDelete) {
const delBtn = tr.querySelector(".delete-btn");
delBtn?.addEventListener("click", () => deleteEntry(entry.entry_no));
}
body.appendChild(tr);
2025-12-02 18:11:58 +05:30
});
2025-12-05 17:16:02 +05:30
}
2025-12-04 11:21:46 +05:30
function cycleToggle(btn) {
// वर्तमान position घेऊन पुढचा स्टेट कॅल्क्युलेट करा
let pos = parseInt(btn.dataset.pos || '0', 10); // 0 = unpaid, 1 = pending, 2 = paid
pos = (pos + 1) % 3;
btn.dataset.pos = pos;
setToggleVisual(btn, pos); // रंग वगैरे अपडेट
const entryNo = btn.dataset.entry;
jsonFetch('/admin/account/toggle-payment', {
method: 'POST',
body: {
entry_no: entryNo, // controller मध्ये जी नावे आहेत तीच
toggle_pos: pos
}
}).then(res => {
if (!res.success) {
alert(res.message || 'Failed to update payment status');
// error असेल तर UI परत जुन्या स्टेटला ने
pos = (pos + 2) % 3;
btn.dataset.pos = pos;
setToggleVisual(btn, pos);
return;
}
// 1) global entries array update करा (dashboard data)
if (Array.isArray(entries)) {
const idx = entries.findIndex(e => e.entry_no === entryNo);
if (idx !== -1) {
entries[idx].toggle_pos = res.entry.toggle_pos;
entries[idx].payment_status = res.entry.payment_status;
}
}
// 2) current row मधला status badge आणि actions अपडेट करा
const row = btn.closest('tr');
if (row) {
// status badge
const statusCell = row.querySelector('.status-badge');
if (statusCell) {
statusCell.textContent = res.entry.payment_status;
statusCell.className = 'status-badge ' + statusClass(res.entry.payment_status);
}
// paid झाल्यावर edit/delete लपवा
const actions = row.querySelector('.action-btns');
if (actions) {
if (res.entry.payment_status.toLowerCase() === 'paid') {
actions.style.display = 'none';
} else {
actions.style.display = 'flex'; // किंवा तुझा default layout
}
}
}
}).catch(() => {
alert('Network error while updating payment status');
// network error UI मागे घे
pos = (pos + 2) % 3;
btn.dataset.pos = pos;
setToggleVisual(btn, pos);
});
}
2025-11-21 16:07:43 +05:30
function renderOrderTable(list){
const body = document.getElementById('orderTableBody');
body.innerHTML = '';
2025-11-27 19:39:36 +05:30
2025-11-21 16:07:43 +05:30
if(!list || list.length === 0){
body.innerHTML = '<tr><td colspan="8" class="empty-state">No entries found</td></tr>';
return;
}
2025-11-27 19:39:36 +05:30
2025-12-01 10:34:27 +05:30
// Calculate pagination (using same currentPage as first table)
2025-11-27 19:39:36 +05:30
const startIndex = (currentPage - 1) * entriesPerPage;
const endIndex = startIndex + entriesPerPage;
const paginatedEntries = list.slice(startIndex, endIndex);
paginatedEntries.forEach(entry => {
2025-11-21 16:07:43 +05:30
const tr = document.createElement('tr');
const pending = Number(entry.pending_amount || 0);
const pendingHtml = pending <= 0 ? '<span class="status-badge pending-badge-green">Completed</span>' : `<span class="status-badge pending-badge-red">${formatCurrency(pending)}</span>`;
tr.innerHTML = `
<td><a class="entry-link" data-entry="${escapeHtml(entry.entry_no)}">${escapeHtml(entry.entry_no)}</a></td>
<td>${escapeHtml(entry.entry_date)}</td>
<td>${escapeHtml(entry.description)}</td>
<td>${escapeHtml(entry.region)}</td>
<td>${formatCurrency(entry.amount)}</td>
<td><span class="status-badge ${statusClass(entry.dispatch_status)}">${capitalize(entry.dispatch_status)}</span></td>
<td>${pendingHtml}</td>
<td>${pending > 0 ? `<button class="plus-btn" data-entry="${escapeHtml(entry.entry_no)}" title="Add installment">+</button>` : ''}</td>
`;
body.appendChild(tr);
// bind entry link
const link = tr.querySelector('.entry-link');
link.addEventListener('click', (e) => openEntryDetailsModal(e.target.dataset.entry));
// bind plus
const plus = tr.querySelector('.plus-btn');
if(plus) plus.addEventListener('click', (e) => openInstallmentModal(e.target.dataset.entry, entry.description, entry.region, entry.pending_amount));
});
}
function renderConsolidateOrders(list){
const body = document.getElementById('consolidateOrdersBody');
body.innerHTML = '';
2025-11-26 23:07:12 +05:30
2025-11-21 16:07:43 +05:30
if(!list || list.length === 0){
2025-11-26 23:07:12 +05:30
body.innerHTML = '<tr><td colspan="14" class="empty-state">No available orders</td></tr>';
2025-11-27 19:39:36 +05:30
updateModalPaginationControls();
2025-11-21 16:07:43 +05:30
return;
}
2025-11-26 23:07:12 +05:30
2025-11-27 19:39:36 +05:30
// Calculate pagination for modal
const startIndex = (modalCurrentPage - 1) * modalOrdersPerPage;
const endIndex = startIndex + modalOrdersPerPage;
2025-11-26 23:07:12 +05:30
const paginatedOrders = list.slice(startIndex, endIndex);
paginatedOrders.forEach(order => {
2025-11-21 16:07:43 +05:30
const tr = document.createElement('tr');
tr.innerHTML = `
<td><input type="checkbox" value="${order.id}"></td>
<td><a href="#" class="order-link" data-id="${order.id}">${escapeHtml(order.order_id || ('#'+order.id))}</a></td>
<td>${escapeHtml(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 ?? ''}</td>
<td>${order.cbm ?? ''}</td>
<td>${order.ttl_cbm ?? ''}</td>
<td>${order.kg ?? ''}</td>
<td>${order.ttl_kg ?? ''}</td>
`;
body.appendChild(tr);
});
}
2025-11-12 19:56:06 +05:30
2025-12-02 18:11:58 +05:30
function renderAddOrderModal(orders) {
const tbody = document.getElementById('addOrderTableBody');
tbody.innerHTML = '';
2025-12-01 10:34:27 +05:30
2025-12-02 18:11:58 +05:30
if (!orders || !orders.length) {
tbody.innerHTML = `
<tr>
<td colspan="8" class="empty-state">No orders found</td>
</tr>
`;
return;
2025-11-21 16:07:43 +05:30
}
2025-11-12 19:56:06 +05:30
2025-12-02 18:11:58 +05:30
const start = (addOrderCurrentPage - 1) * modalOrdersPerPage;
const end = Math.min(start + modalOrdersPerPage, orders.length);
const pageOrders = orders.slice(start, end);
2025-11-21 16:07:43 +05:30
2025-12-02 18:11:58 +05:30
// Hya entry sathi already associated order IDs collect kara
const attachedIds = new Set(
(currentEditEntry?.orders || []).map(o => o.id)
);
2025-11-21 16:07:43 +05:30
2025-12-02 18:11:58 +05:30
pageOrders.forEach(order => {
const tr = document.createElement('tr');
const idString = (order.orderid ?? order.id ?? '').toString().trim();
const numericId = parseInt(idString, 10);
const formattedId = isNaN(numericId)
? escapeHtml(idString)
: 'KNT-25-' + String(numericId).padStart(8, '0');
const isAttached = attachedIds.has(order.id);
tr.innerHTML = `
<td>
<input type="checkbox"
class="add-order-checkbox"
value="${order.id}"
${isAttached ? 'checked disabled' : ''}>
</td>
<td>${formattedId}</td>
<td>${escapeHtml(order.markno ?? order.mark_no ?? '')}</td>
<td>${escapeHtml(order.origin ?? '')}</td>
<td>${escapeHtml(order.destination ?? '')}</td>
<td>${escapeHtml(order.ctn ?? '')}</td>
<td>${escapeHtml(order.qty ?? '')}</td>
<td>${formatCurrency(order.ttl_amount ?? order.ttlamount ?? order.total_amount ?? order.amount ?? 0)}</td>
`;
tbody.appendChild(tr);
2025-11-21 16:07:43 +05:30
});
}
2025-12-02 18:11:58 +05:30
2025-12-01 10:34:27 +05:30
/* ---------- Edit Entry Functions ---------- */
function openEditModal(entry) {
currentEditEntry = entry;
document.getElementById('edit_entry_no').value = entry.entry_no;
document.getElementById('edit_description').value = entry.description || '';
document.getElementById('edit_order_quantity').value = entry.order_quantity || '';
2025-12-04 11:21:46 +05:30
// document.getElementById('edit_payment_status').value = entry.payment_status || 'unpaid';
2025-12-01 10:34:27 +05:30
document.getElementById('edit_region').value = entry.region || 'China';
document.getElementById('edit_amount').value = entry.amount || '';
// Load associated orders
loadEntryOrders(entry.entry_no);
document.getElementById('editEntryModal').classList.add('modal-open');
}
function closeEditModal() {
document.getElementById('editEntryModal').classList.remove('modal-open');
currentEditEntry = null;
}
function loadEntryOrders(entryNo) {
const tbody = document.getElementById('editOrdersTableBody');
const emptyState = document.getElementById('editOrdersEmptyState');
tbody.innerHTML = '<tr><td colspan="8" class="empty-state">Loading orders...</td></tr>';
jsonFetch(`/admin/account/entry-orders/${encodeURIComponent(entryNo)}`)
.then(res => {
if (!res.success) throw new Error(res.message || 'Failed to load orders');
tbody.innerHTML = '';
if (!res.orders || res.orders.length === 0) {
emptyState.style.display = 'block';
return;
}
emptyState.style.display = 'none';
res.orders.forEach(order => {
const tr = document.createElement('tr');
tr.innerHTML = `
<td>${escapeHtml(order.order_id || ('#'+order.id))}</td>
<td>${escapeHtml(order.mark_no || '')}</td>
<td>${order.origin ?? ''}</td>
<td>${order.destination ?? ''}</td>
<td>${order.ctn ?? ''}</td>
<td>${order.qty ?? ''}</td>
<td>${order.ttl_amount ?? ''}</td>
<td>
<div class="order-actions">
2025-12-02 18:11:58 +05:30
<button type="button" class="remove-order-btn" data-order-id="${order.id}">Remove</button>
2025-12-01 10:34:27 +05:30
</div>
</td>
`;
tbody.appendChild(tr);
// Bind remove button
const removeBtn = tr.querySelector('.remove-order-btn');
removeBtn.addEventListener('click', () => removeOrderFromEntry(order.id, entryNo));
});
})
.catch(err => {
console.error(err);
tbody.innerHTML = '<tr><td colspan="8" class="empty-state">Unable to load orders</td></tr>';
});
}
async function refreshEntryHeader(entryNo) {
try {
const res = await jsonFetch('/admin/account/entry/' + encodeURIComponent(entryNo));
if (!res.success) return;
const entry = res.entry;
const qtyInput = document.getElementById('editorderquantity');
if (qtyInput) qtyInput.value = entry.order_quantity ?? 0;
const idx = entries.findIndex(e => e.entry_no === entry.entry_no);
if (idx !== -1) {
entries[idx].order_quantity = entry.order_quantity;
renderBothTables();
updatePaginationControls();
}
} catch (e) {
console.error(e);
}
}
async function removeOrderFromEntry(orderId, entryNo) {
if (!confirm('Are you sure you want to remove this order from the entry?')) {
return;
}
try {
const res = await jsonFetch('/admin/account/remove-order-from-entry', {
method: 'POST',
body: {
entry_no: entryNo,
order_id: orderId
}
});
if (!res.success) throw new Error(res.message || 'Failed to remove order');
2025-12-02 18:11:58 +05:30
// नवीन quantity backend कडून घ्या
const newQty = res.entry.order_quantity ?? res.entry.orderquantity ?? 0;
// 1) currentEditEntry update
if (currentEditEntry) {
currentEditEntry.order_quantity = newQty;
}
// 2) Edit popup मधला field लगेच update
const oqInput = document.getElementById('edit_order_quantity');
if (oqInput) {
oqInput.value = newQty;
}
// 3) इतर UI refresh
2025-12-01 10:34:27 +05:30
loadEntryOrders(entryNo);
loadAvailableOrders();
2025-12-02 18:11:58 +05:30
await refreshEntryHeader(entryNo);
2025-12-01 10:34:27 +05:30
} catch (err) {
alert(err.message || 'Failed to remove order');
console.error(err);
}
}
async function submitEditEntry(e) {
e.preventDefault();
const form = e.target;
const payload = {
entry_no: form.entry_no.value,
description: form.description.value.trim(),
order_quantity: Number(form.order_quantity.value) || 0,
2025-12-04 11:21:46 +05:30
// payment_status: form.payment_status.value,
2025-12-01 10:34:27 +05:30
region: form.region.value,
amount: Number(form.amount.value) || 0
};
if (!payload.description) {
alert('Please enter a valid description.');
return;
}
try {
const btn = form.querySelector('button[type="submit"]');
btn.disabled = true;
btn.textContent = 'Updating...';
const res = await jsonFetch('/admin/account/update-entry', {
method: 'POST',
body: payload
});
if (!res.success) throw new Error(res.message || 'Update failed');
// Success
closeEditModal();
loadDashboard();
} catch (err) {
alert(err.message || 'Failed to update entry');
console.error(err);
} finally {
const btn = form.querySelector('button[type="submit"]');
if (btn) {
btn.disabled = false;
btn.textContent = 'Update Entry';
}
}
}
2025-12-02 18:11:58 +05:30
2026-02-27 10:51:26 +05:30
function openEntryOrdersModal(entryNo) {
// Set entry number in header
document.getElementById('entryOrdersEntryNo-span').textContent = `(${entryNo})`;
2025-12-02 18:11:58 +05:30
2026-02-27 10:51:26 +05:30
// Reset summary values
document.getElementById('ordersTotalCount').textContent = '0';
document.getElementById('ordersTotalQuantity').textContent = '0';
document.getElementById('ordersTotalAmount').textContent = '₹0';
// table loading state
const tbody = document.getElementById('entryOrdersTableBody');
tbody.innerHTML = `
<tr>
<td colspan="7" class="empty-state">Loading orders...</td>
</tr>
`;
// API call: /admin/account/entry-orders/{entryno}
jsonFetch(`/admin/account/entry-orders/${encodeURIComponent(entryNo)}`, {
method: 'GET'
})
.then(res => {
if (!res.success) {
2025-12-02 18:11:58 +05:30
tbody.innerHTML = `
2026-02-27 10:51:26 +05:30
<tr>
<td colspan="7" class="empty-state">Failed to load orders</td>
</tr>
2025-12-02 18:11:58 +05:30
`;
2026-02-27 10:51:26 +05:30
return;
}
2025-12-02 18:11:58 +05:30
2026-02-27 10:51:26 +05:30
const orders = res.orders || [];
if (!orders.length) {
tbody.innerHTML = `
<tr>
<td colspan="7" class="empty-state">No orders associated with this entry</td>
</tr>
`;
return;
}
2025-12-02 18:11:58 +05:30
2026-02-27 10:51:26 +05:30
tbody.innerHTML = '';
let totalQuantity = 0;
let totalAmount = 0;
2025-12-23 22:15:45 +05:30
2026-02-27 10:51:26 +05:30
orders.forEach(order => {
const tr = document.createElement('tr');
2025-12-23 22:15:45 +05:30
2026-02-27 10:51:26 +05:30
const idString = (order.orderid ?? order.id ?? '').toString().trim();
const numericId = parseInt(idString, 10);
const formattedId = isNaN(numericId)
? escapeHtml(idString)
: 'KNT-25-' + String(numericId).padStart(8, '0');
2025-12-23 22:15:45 +05:30
2026-02-27 10:51:26 +05:30
// Calculate values for summary
const quantity = Number(order.qty || order.order_qty || 0);
const amountValue = Number(order.ttl_amount ?? order.ttlamount ?? order.total_amount ?? order.order_amount ?? order.amount ?? 0);
totalQuantity += quantity;
totalAmount += amountValue;
2025-12-23 22:15:45 +05:30
2026-02-27 10:51:26 +05:30
tr.innerHTML = `
<td>
<span class="order-id-badge">${formattedId}</span>
</td>
<td>${escapeHtml(order.markno ?? order.mark_no ?? '')}</td>
<td>${escapeHtml(order.origin ?? '')}</td>
<td>${escapeHtml(order.destination ?? '')}</td>
<td>${escapeHtml(order.ctn ?? '')}</td>
<td><strong>${quantity}</strong></td>
<td><strong>${formatCurrency(amountValue)}</strong></td>
`;
tbody.appendChild(tr);
});
2025-12-23 22:15:45 +05:30
2026-02-27 10:51:26 +05:30
// Update summary
document.getElementById('ordersTotalCount').textContent = orders.length;
document.getElementById('ordersTotalQuantity').textContent = totalQuantity.toLocaleString();
document.getElementById('ordersTotalAmount').textContent = formatCurrency(totalAmount);
2025-12-23 22:15:45 +05:30
2026-02-27 10:51:26 +05:30
})
.catch(() => {
tbody.innerHTML = `
<tr>
<td colspan="7" class="empty-state">Error loading orders</td>
</tr>
`;
});
2025-12-02 18:11:58 +05:30
2026-02-27 10:51:26 +05:30
document.getElementById('entryOrdersModal').classList.add('modal-open');
}
2025-12-02 18:11:58 +05:30
function closeEntryOrdersModal() {
document.getElementById('entryOrdersModal').classList.remove('modal-open');
}
2025-12-01 10:34:27 +05:30
/* ---------- Add Order Modal Functions ---------- */
function openAddOrderModal() {
if (!currentEditEntry) return;
2025-12-03 16:17:14 +05:30
2025-12-01 10:34:27 +05:30
document.getElementById('addOrderModal').classList.add('modal-open');
2025-12-03 16:17:14 +05:30
// नेहमी इथेच ताजे orders load कर
2025-12-01 10:34:27 +05:30
addOrderCurrentPage = 1;
2025-12-03 16:17:14 +05:30
loadAvailableOrdersForAddModal();
2025-12-01 10:34:27 +05:30
}
2025-12-03 16:17:14 +05:30
2025-12-01 10:34:27 +05:30
function closeAddOrderModal() {
document.getElementById('addOrderModal').classList.remove('modal-open');
}
async function confirmAddOrders() {
if (!currentEditEntry) return;
const selected = Array.from(
document.querySelectorAll('#addOrderTableBody input[type="checkbox"]:checked')
).map(i => Number(i.value));
if (selected.length === 0) {
alert('Please select at least one order to add.');
return;
}
try {
const res = await jsonFetch('/admin/account/add-orders-to-entry', {
method: 'POST',
body: {
entry_no: currentEditEntry.entry_no,
order_ids: selected
}
});
if (!res.success) throw new Error(res.message || 'Failed to add orders');
loadEntryOrders(currentEditEntry.entry_no);
loadAvailableOrders();
await refreshEntryHeader(currentEditEntry.entry_no); // ⬅ इथे नवं
closeAddOrderModal();
} catch (err) {
alert(err.message || 'Failed to add orders');
console.error(err);
}
}
/* ---------- Delete Entry Function ---------- */
async function deleteEntry(entryNo) {
if (!confirm(`Are you sure you want to delete entry ${entryNo}? This action cannot be undone.`)) {
return;
}
try {
const res = await jsonFetch('/admin/account/delete-entry', {
method: 'POST',
body: { entry_no: entryNo }
});
if (!res.success) throw new Error(res.message || 'Delete failed');
// Success
loadDashboard();
} catch (err) {
alert(err.message || 'Failed to delete entry');
console.error(err);
}
}
2025-11-26 23:07:12 +05:30
/* ---------- Create Order Inline (Now in Popup) ---------- */
2025-11-21 16:07:43 +05:30
async function submitCreateOrderInline(e){
e.preventDefault();
const form = e.target;
const selected = Array.from(document.querySelectorAll('#consolidateOrdersBody input[type=checkbox]:checked')).map(i=>Number(i.value));
const payload = {
description: form.description.value.trim(),
region: form.region.value,
amount: Number(form.amount.value) || 0,
entry_date: form.entry_date.value,
selected_orders: selected
};
if(!payload.description || payload.amount <= 0){
alert('Please enter a valid description and amount.');
return;
}
try {
const btn = form.querySelector('button[type="submit"]');
btn.disabled = true;
btn.textContent = 'Creating...';
const res = await jsonFetch('/admin/account/create-order', { method:'POST', body: payload });
if(!res.success) throw new Error(res.message || 'Create failed');
// success
form.reset();
2025-11-26 23:07:12 +05:30
closeCreateOrderModal();
2025-11-21 16:07:43 +05:30
loadDashboard();
} catch(err){
alert(err.message || 'Failed to create order');
console.error(err);
} finally {
const btn = form.querySelector('button[type="submit"]');
2025-12-01 10:34:27 +05:30
if(btn){ btn.disabled = false; btn.textContent = 'Create Installment'; }
2025-11-21 16:07:43 +05:30
}
}
/* ---------- Search ---------- */
function handleSearch(){
const q = document.getElementById('main-search').value.trim().toLowerCase();
2025-11-27 19:39:36 +05:30
if(!q){
renderBothTables();
2025-12-01 10:34:27 +05:30
updatePaginationControls();
2025-11-27 19:39:36 +05:30
return;
}
2025-11-21 16:07:43 +05:30
const filtered = entries.filter(e => {
return String(e.entry_no || '').toLowerCase().includes(q) ||
String(e.description || '').toLowerCase().includes(q) ||
String(e.region || '').toLowerCase().includes(q);
});
2025-11-27 19:39:36 +05:30
entries = filtered;
currentPage = 1; // Reset to first page when searching
renderBothTables();
2025-12-01 10:34:27 +05:30
updatePaginationControls();
2025-11-21 16:07:43 +05:30
}
2026-02-27 10:51:26 +05:30
/* ---------- Entry details & installments (Enhanced) ---------- */
2025-11-21 16:07:43 +05:30
async function openEntryDetailsModal(entryNo) {
try {
const res = await jsonFetch('/admin/account/entry/' + encodeURIComponent(entryNo));
if (!res.success) throw new Error(res.message || 'Failed to load entry');
const entry = res.entry;
currentEntry = entry;
2026-02-27 10:51:26 +05:30
// Set header info
2025-11-21 16:07:43 +05:30
document.getElementById('entryDetailsId').textContent = entry.entry_no;
2026-02-27 10:51:26 +05:30
// Calculate values
const originalAmount = Number(entry.amount || 0);
const pendingAmount = Number(entry.pending_amount || 0);
const totalProcessed = originalAmount - pendingAmount;
// Update summary cards
document.getElementById('originalAmount').textContent = formatCurrency(originalAmount);
2025-11-21 16:07:43 +05:30
document.getElementById('totalProcessed').textContent = formatCurrency(totalProcessed);
2026-02-27 10:51:26 +05:30
document.getElementById('pendingBalance').textContent = formatCurrency(pendingAmount);
document.getElementById('totalInstallments').textContent = entry.installments?.length || 0;
2025-11-21 16:07:43 +05:30
2026-02-27 10:51:26 +05:30
// Render installments table
2025-11-21 16:07:43 +05:30
const tbody = document.getElementById('installmentsTableBody');
tbody.innerHTML = '';
2026-02-27 10:51:26 +05:30
if (!entry.installments || entry.installments.length === 0) {
tbody.innerHTML = `
<tr>
<td colspan="6" class="empty-state">
<div style="padding: 30px; text-align: center;">
<div style="font-size: 48px; color: #eef3fb; margin-bottom: 16px;">📋</div>
<div style="font-size: 16px; color: #6f7b8f; font-weight: 500;">
No installments found for this entry
</div>
<div style="font-size: 14px; color: #9ba5bb; margin-top: 8px;">
Add your first installment to get started
</div>
</div>
</td>
</tr>
2025-11-21 16:07:43 +05:30
`;
2026-02-27 10:51:26 +05:30
} else {
entry.installments.forEach((ins, idx) => {
const tr = document.createElement('tr');
// Determine installment label
let installmentLabel = 'Original Entry';
if (idx > 0) {
installmentLabel = `Installment ${idx}`;
}
// Status dropdown options with colors
const statusOptions = [
{ value: 'Pending', label: '⏳ Pending', color: '#f59e0b' },
{ value: 'Loading', label: '📦 Loading', color: '#3b82f6' },
{ value: 'Packed', label: '📦 Packed', color: '#8b5cf6' },
{ value: 'Dispatched', label: '🚚 Dispatched', color: '#10b981' },
{ value: 'Delivered', label: '✅ Delivered', color: '#0c6b2e' }
];
let statusOptionsHtml = '';
statusOptions.forEach(opt => {
const selected = ins.status === opt.value ? 'selected' : '';
statusOptionsHtml += `<option value="${opt.value}" ${selected} style="color: ${opt.color}; font-weight: 500;">${opt.label}</option>`;
});
tr.innerHTML = `
<td>
<div style="display: flex; align-items: center; gap: 8px;">
<div style="width: 32px; height: 32px; border-radius: 8px; background: linear-gradient(135deg, #f0f7ff, #e6f0ff); display: flex; align-items: center; justify-content: center; font-weight: 700; color: var(--primary-1);">
${idx + 1}
</div>
<span style="font-weight: 600;">${installmentLabel}</span>
</div>
</td>
<td>
<div style="display: flex; align-items: center; gap: 6px;">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<rect x="3" y="4" width="18" height="18" rx="2" ry="2"/>
<line x1="16" y1="2" x2="16" y2="6"/><line x1="8" y1="2" x2="8" y2="6"/>
<line x1="3" y1="10" x2="21" y2="10"/>
</svg>
${escapeHtml(ins.proc_date || ins.date || '')}
</div>
</td>
<td>${escapeHtml(ins.description || '')}</td>
<td>
<span style="padding: 4px 8px; background: #f0f7ff; border-radius: 6px; font-size: 12px; font-weight: 600; color: var(--primary-1);">
${escapeHtml(ins.region || '')}
</span>
</td>
<td>
<span style="font-weight: 700; color: var(--primary-1);">
${formatCurrency(ins.amount || 0)}
</span>
</td>
<td>
<select class="installment-status-dropdown"
data-id="${ins.id}"
onchange="updateInstallmentStatus(${ins.id}, this.value)"
title="Update installment status">
${statusOptionsHtml}
</select>
</td>
`;
tbody.appendChild(tr);
});
}
2025-11-21 16:07:43 +05:30
2026-02-27 10:51:26 +05:30
// Show modal
2025-11-21 16:07:43 +05:30
document.getElementById('entryDetailsModal').classList.add('modal-open');
} catch (err) {
console.error(err);
alert('Unable to load entry details');
2025-11-12 19:56:06 +05:30
}
}
function closeEntryDetailsModal() {
document.getElementById('entryDetailsModal').classList.remove('modal-open');
}
2025-11-21 16:07:43 +05:30
async function updateInstallmentStatus(id, status) {
try {
const res = await jsonFetch('/admin/account/installment/update-status', {
method: 'POST',
body: { installment_id: id, status: status }
});
if (!res.success) {
alert('Failed to update status');
return;
}
// Refresh details modal instantly
openEntryDetailsModal(res.entry.entry_no);
} catch (err) {
console.error(err);
alert('Unable to update installment status');
}
}
/* ---------- Installment modal ---------- */
function openInstallmentModal(entryNo, desc, region, pending){
currentEntry = { entry_no: entryNo, description: desc, region: region, pending_amount: pending };
document.getElementById('instDetailsRow').innerHTML = `
<div style="min-width:120px"><div class="kv">Entry No</div><div>${escapeHtml(entryNo)}</div></div>
<div style="min-width:160px"><div class="kv">Description</div><div>${escapeHtml(desc)}</div></div>
<div style="min-width:120px"><div class="kv">Region</div><div>${escapeHtml(region)}</div></div>
<div style="min-width:120px"><div class="kv">Pending</div><div>${formatCurrency(pending)}</div></div>
2025-11-12 19:56:06 +05:30
`;
2025-11-21 16:07:43 +05:30
document.getElementById('maxPending').textContent = formatCurrency(pending);
document.getElementById('installmentModal').classList.add('modal-open');
// set example default value to pending (but not exceed)
const amountInput = document.querySelector('#installmentForm input[name="proc_amount"]');
if(amountInput) amountInput.value = pending ? Number(pending) : '';
}
function closeInstallmentModal(){ document.getElementById('installmentModal').classList.remove('modal-open'); }
async function submitInstallment(e){
e.preventDefault();
if(!currentEntry){ alert('No entry selected'); return; }
const form = e.target;
const payload = { entry_no: currentEntry.entry_no, proc_date: form.proc_date.value, amount: Number(form.proc_amount.value) || 0, status: form.status.value };
if(payload.amount > Number(currentEntry.pending_amount || 0)){
alert('Amount cannot exceed pending amount'); return;
}
try {
const btn = form.querySelector('button[type="submit"]');
btn.disabled = true; btn.textContent = 'Submitting...';
const res = await jsonFetch('/admin/account/installment/create', { method:'POST', body: payload });
if(!res.success) throw new Error(res.message || 'Failed to create installment');
closeInstallmentModal();
await loadDashboard();
openEntryDetailsModal(currentEntry.entry_no); // open updated details
} catch(err){
console.error(err);
alert(err.message || 'Failed to create installment');
} finally {
const btn = form.querySelector('button[type="submit"]');
if(btn){ btn.disabled = false; btn.textContent = 'Create Installment'; }
}
}
2025-12-01 10:34:27 +05:30
2025-11-11 14:51:35 +05:30
</script>
2025-11-21 16:07:43 +05:30
2025-11-26 23:07:12 +05:30
@endsection