frontend Order Section Update

This commit is contained in:
Utkarsh Khedkar
2025-11-26 23:07:12 +05:30
parent bebe0711f4
commit 04b00c9db8
18 changed files with 3604 additions and 1334 deletions

View File

@@ -10,9 +10,6 @@ use Mpdf\Mpdf;
use App\Models\InvoiceInstallment; use App\Models\InvoiceInstallment;
use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log;
class AdminInvoiceController extends Controller class AdminInvoiceController extends Controller
{ {
// ------------------------------------------------------------- // -------------------------------------------------------------
@@ -40,14 +37,12 @@ class AdminInvoiceController extends Controller
return view('admin.popup_invoice', compact('invoice', 'shipment')); return view('admin.popup_invoice', compact('invoice', 'shipment'));
} }
// ------------------------------------------------------------- // -------------------------------------------------------------
// EDIT INVOICE PAGE // EDIT INVOICE PAGE
// ------------------------------------------------------------- // -------------------------------------------------------------
public function edit($id) public function edit($id)
{ {
$invoice = Invoice::with(['order.shipments'])->findOrFail($id); $invoice = Invoice::with(['order.shipments'])->findOrFail($id);
$shipment = $invoice->order?->shipments?->first(); $shipment = $invoice->order?->shipments?->first();
return view('admin.invoice_edit', compact('invoice', 'shipment')); return view('admin.invoice_edit', compact('invoice', 'shipment'));
@@ -56,7 +51,6 @@ class AdminInvoiceController extends Controller
// ------------------------------------------------------------- // -------------------------------------------------------------
// UPDATE INVOICE // UPDATE INVOICE
// ------------------------------------------------------------- // -------------------------------------------------------------
public function update(Request $request, $id) public function update(Request $request, $id)
{ {
Log::info("🟡 Invoice Update Request Received", [ Log::info("🟡 Invoice Update Request Received", [
@@ -84,13 +78,11 @@ public function update(Request $request, $id)
if ($data['tax_type'] === 'gst') { if ($data['tax_type'] === 'gst') {
Log::info("🟢 GST Selected", compact('taxPercent')); Log::info("🟢 GST Selected", compact('taxPercent'));
$data['cgst_percent'] = $taxPercent / 2; $data['cgst_percent'] = $taxPercent / 2;
$data['sgst_percent'] = $taxPercent / 2; $data['sgst_percent'] = $taxPercent / 2;
$data['igst_percent'] = 0; $data['igst_percent'] = 0;
} else { } else {
Log::info("🔵 IGST Selected", compact('taxPercent')); Log::info("🔵 IGST Selected", compact('taxPercent'));
$data['cgst_percent'] = 0; $data['cgst_percent'] = 0;
$data['sgst_percent'] = 0; $data['sgst_percent'] = 0;
$data['igst_percent'] = $taxPercent; $data['igst_percent'] = $taxPercent;
@@ -100,8 +92,6 @@ public function update(Request $request, $id)
$data['gst_amount'] = $taxAmount; $data['gst_amount'] = $taxAmount;
$data['final_amount_with_gst'] = $finalAmount + $taxAmount; $data['final_amount_with_gst'] = $finalAmount + $taxAmount;
// ✅ store original % for UI reference
$data['gst_percent'] = $taxPercent; $data['gst_percent'] = $taxPercent;
Log::info("📌 Final Calculated Invoice Values", [ Log::info("📌 Final Calculated Invoice Values", [
@@ -129,22 +119,14 @@ public function update(Request $request, $id)
->with('success', 'Invoice updated & PDF generated successfully.'); ->with('success', 'Invoice updated & PDF generated successfully.');
} }
// ------------------------------------------------------------- // -------------------------------------------------------------
// PDF GENERATION USING mPDF // PDF GENERATION USING mPDF
// ------------------------------------------------------------- // -------------------------------------------------------------
public function generateInvoicePDF($invoice) public function generateInvoicePDF($invoice)
{ {
// Load relationship including shipment
$invoice->load(['items', 'order.shipments']); $invoice->load(['items', 'order.shipments']);
// Fetch shipment
$shipment = $invoice->order?->shipments?->first(); $shipment = $invoice->order?->shipments?->first();
// PDF filename
$fileName = 'invoice-' . $invoice->invoice_number . '.pdf'; $fileName = 'invoice-' . $invoice->invoice_number . '.pdf';
// Directory path
$folder = public_path('invoices/'); $folder = public_path('invoices/');
if (!file_exists($folder)) { if (!file_exists($folder)) {
@@ -152,39 +134,20 @@ public function update(Request $request, $id)
} }
$filePath = $folder . $fileName; $filePath = $folder . $fileName;
// Delete old file if exists
if (file_exists($filePath)) { if (file_exists($filePath)) {
unlink($filePath); unlink($filePath);
} }
// Create mPDF instance $mpdf = new Mpdf(['mode' => 'utf-8', 'format' => 'A4', 'default_font' => 'sans-serif']);
$mpdf = new Mpdf([ $html = view('admin.pdf.invoice', ['invoice' => $invoice, 'shipment' => $shipment])->render();
'mode' => 'utf-8',
'format' => 'A4',
'default_font' => 'sans-serif',
]);
// Load HTML view
$html = view('admin.pdf.invoice', [
'invoice' => $invoice,
'shipment' => $shipment
])->render();
// Write HTML to PDF
$mpdf->WriteHTML($html); $mpdf->WriteHTML($html);
// Save PDF
$mpdf->Output($filePath, 'F'); $mpdf->Output($filePath, 'F');
$invoice->update(['pdf_path' => 'invoices/' . $fileName]);
// Update DB path
$invoice->update([
'pdf_path' => 'invoices/' . $fileName
]);
} }
// -------------------------------------------------------------
// INSTALLMENTS (ADD/DELETE)
// -------------------------------------------------------------
public function storeInstallment(Request $request, $invoice_id) public function storeInstallment(Request $request, $invoice_id)
{ {
$request->validate([ $request->validate([
@@ -197,7 +160,8 @@ public function storeInstallment(Request $request, $invoice_id)
$invoice = Invoice::findOrFail($invoice_id); $invoice = Invoice::findOrFail($invoice_id);
$paidTotal = $invoice->installments()->sum('amount'); $paidTotal = $invoice->installments()->sum('amount');
$remaining = $invoice->final_amount - $paidTotal; // Use GST-inclusive total for all calculations/checks
$remaining = $invoice->final_amount_with_gst - $paidTotal;
if ($request->amount > $remaining) { if ($request->amount > $remaining) {
return response()->json([ return response()->json([
@@ -214,10 +178,10 @@ public function storeInstallment(Request $request, $invoice_id)
'amount' => $request->amount, 'amount' => $request->amount,
]); ]);
// Update invoice status to paid if fully cleared
$newPaid = $paidTotal + $request->amount; $newPaid = $paidTotal + $request->amount;
if ($newPaid >= $invoice->final_amount) { // Mark as 'paid' if GST-inclusive total is cleared
if ($newPaid >= $invoice->final_amount_with_gst) {
$invoice->update(['status' => 'paid']); $invoice->update(['status' => 'paid']);
} }
@@ -226,24 +190,24 @@ public function storeInstallment(Request $request, $invoice_id)
'message' => 'Installment added successfully.', 'message' => 'Installment added successfully.',
'installment' => $installment, 'installment' => $installment,
'totalPaid' => $newPaid, 'totalPaid' => $newPaid,
'remaining' => max(0, $invoice->final_amount - $newPaid), 'gstAmount' => $invoice->gst_amount,
'isCompleted' => $newPaid >= $invoice->final_amount 'finalAmountWithGst' => $invoice->final_amount_with_gst,
'baseAmount' => $invoice->final_amount,
'remaining' => max(0, $invoice->final_amount_with_gst - $newPaid),
'isCompleted' => $newPaid >= $invoice->final_amount_with_gst
]); ]);
} }
public function deleteInstallment($id) public function deleteInstallment($id)
{ {
$installment = InvoiceInstallment::findOrFail($id); $installment = InvoiceInstallment::findOrFail($id);
$invoice = $installment->invoice; $invoice = $installment->invoice;
// delete installment
$installment->delete(); $installment->delete();
// recalc totals
$paidTotal = $invoice->installments()->sum('amount'); $paidTotal = $invoice->installments()->sum('amount');
$remaining = $invoice->final_amount - $paidTotal; $remaining = $invoice->final_amount_with_gst - $paidTotal;
// auto update invoice status // Update status if not fully paid anymore
if ($remaining > 0 && $invoice->status === "paid") { if ($remaining > 0 && $invoice->status === "paid") {
$invoice->update(['status' => 'pending']); $invoice->update(['status' => 'pending']);
} }
@@ -252,10 +216,12 @@ public function deleteInstallment($id)
'status' => 'success', 'status' => 'success',
'message' => 'Installment deleted.', 'message' => 'Installment deleted.',
'totalPaid' => $paidTotal, 'totalPaid' => $paidTotal,
'gstAmount' => $invoice->gst_amount,
'finalAmountWithGst' => $invoice->final_amount_with_gst,
'baseAmount' => $invoice->final_amount,
'remaining' => $remaining, 'remaining' => $remaining,
'isZero' => $paidTotal == 0 'isZero' => $paidTotal == 0
]); ]);
} }
} }

View File

@@ -297,4 +297,17 @@ class AdminOrderController extends Controller
->with('success', 'Order reset successfully.'); ->with('success', 'Order reset successfully.');
} }
public function orderShow()
{
$orders = Order::with([
'markList', // company, customer, origin, destination, date
'shipments', // shipment_id, shipment_date, status
'invoice' // invoice number, dates, amounts, status
])
->latest('id') // show latest orders first
->get();
return view('admin.orders', compact('orders'));
}
} }

View File

@@ -53,4 +53,6 @@ class RequestController extends Controller
'data' => $newRequest 'data' => $newRequest
]); ]);
} }
} }

View File

@@ -56,5 +56,11 @@ class Order extends Model
return $this->belongsToMany(\App\Models\Shipment::class, 'shipment_items', 'order_id', 'shipment_id'); return $this->belongsToMany(\App\Models\Shipment::class, 'shipment_items', 'order_id', 'shipment_id');
} }
public function invoice()
{
return $this->hasOne(\App\Models\Invoice::class, 'order_id', 'id');
}
} }

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -29,7 +29,7 @@ body {
/* container */ /* container */
.account-container { .account-container {
padding: 28px 34px; padding: 28px 34px;
max-width:1300px; max-width:1400px;
margin: 18px auto; margin: 18px auto;
box-sizing:border-box; box-sizing:border-box;
} }
@@ -70,29 +70,128 @@ body {
.btn:hover{ transform: translateY(-3px); box-shadow: 0 8px 26px rgba(36,58,114,0.12); } .btn:hover{ transform: translateY(-3px); box-shadow: 0 8px 26px rgba(36,58,114,0.12); }
/* account panels */ /* account panels */
.account-panels { display:flex; gap:22px; align-items:flex-start; flex-wrap:wrap; } .account-panels {
display:flex;
gap:22px;
align-items:flex-start;
flex-wrap:wrap;
}
.panel-card { .panel-card {
background: var(--card-bg); border-radius:12px; box-shadow:0 8px 20px rgba(25,40,80,0.06); background: var(--card-bg);
flex:1; min-width:48%; padding:18px; box-sizing:border-box; overflow-x:auto; transition: transform .12s, box-shadow .12s; border-radius:12px;
box-shadow:0 8px 20px rgba(25,40,80,0.06);
flex:1;
min-width:48%;
padding:22px;
box-sizing:border-box;
overflow-x:auto;
transition: transform .12s, box-shadow .12s;
min-height: 480px;
display: flex;
flex-direction: column;
} }
.panel-card:hover{ transform: translateY(-4px); box-shadow:0 12px 28px rgba(25,40,80,0.08); } .panel-card:hover{ transform: translateY(-4px); box-shadow:0 12px 28px rgba(25,40,80,0.08); }
.panel-title { font-weight:700; font-size:16px; color:var(--primary-1); margin-bottom:12px; display:flex; align-items:center; justify-content:space-between; } .panel-title {
font-weight:700;
font-size:16px;
color:var(--primary-1);
margin-bottom:16px;
display:flex;
align-items:center;
justify-content:space-between;
}
/* table */ /* table */
table { width:100%; border-collapse:collapse; min-width:720px; font-size:14px; } table {
th, td { padding:10px 12px; text-align:left; border-bottom:1px solid #eef3fb; white-space:nowrap; color:#2d3b53; } width:100%;
th { background: linear-gradient(90deg,#f6f9ff,#fbfdff); color:#4a5570; font-weight:700; font-size:13px; } 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;
}
tr:hover td{ background:#fbfdff; } tr:hover td{ background:#fbfdff; }
.entry-link{ color:var(--accent); text-decoration:underline; cursor:pointer; font-weight:700; } .entry-link{ color:var(--accent); text-decoration:underline; cursor:pointer; font-weight:700; }
/* badges */ /* badges */
.status-badge { display:inline-block; padding:6px 12px; border-radius:20px; color:#fff; font-size:13px; font-weight:600; }
.status-unpaid{ background:var(--danger); } /* === Modern Status Badges === */
.status-paid{ background:var(--success); } .status-badge {
.status-loading{ background:#509cf8; } display: inline-block;
.status-dispatched{ background:#20c5c7; } padding: 6px 16px;
.pending-badge-red{ background:var(--danger); } border-radius: 999px;
.pending-badge-green{ background:var(--success); } 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;
background: #6b7280; /* fallback */
transition: box-shadow 0.22s, transform 0.17s, background 0.22s;
vertical-align: middle;
margin: 3px 2px;
cursor: default;
/* subtle glass effect */
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;
}
/* 3-state toggle */ /* 3-state toggle */
.toggle-switch-btn { .toggle-switch-btn {
@@ -140,48 +239,237 @@ tr:hover td{ background:#fbfdff; }
transform: translateX(38px); transform: translateX(38px);
} }
/* plus button */ /* plus button */
.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; } .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;
}
.plus-btn:hover{ transform: translateY(-3px); box-shadow:0 8px 16px rgba(33,47,90,0.04); } .plus-btn:hover{ transform: translateY(-3px); box-shadow:0 8px 16px rgba(33,47,90,0.04); }
/* ---------- Expandable Create Order Card (Option D) ---------- */ /* ---------- Create Order Popup Modal ---------- */
.create-card { .create-order-modal {
margin: 10px 0 18px 0; position:fixed;
border-radius: 12px; inset:0;
background: linear-gradient(180deg,#ffffff,#fbfdff); background:rgba(16,24,50,0.44);
box-shadow:0 10px 30px rgba(20,40,80,0.04); display:none;
overflow: hidden; transition: max-height .28s ease, padding .22s ease; align-items:center;
max-height: 0; padding: 0 18px; opacity:0; pointer-events:none; 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;
} }
.create-card.open { max-height: 1500px; padding: 18px; opacity:1; pointer-events:auto; }
.create-card .create-inner { display:flex; gap:14px; flex-direction:column; }
.create-card .create-grid { display:grid; grid-template-columns: 1fr 1fr; gap:12px; align-items:start; }
.create-card label{ font-weight:700; color:#28384f; margin-bottom:6px; font-size:13px; }
.input, select { width:100%; padding:10px 12px; border-radius:8px; border:1.3px solid #e3eaf6; background:#fff; font-size:14px; box-sizing:border-box; }
.create-actions { display:flex; gap:10px; justify-content:flex-end; margin-top:12px; }
/* consolidated orders area */ /* consolidated orders area */
.consolidate-area { .consolidate-area {
background: linear-gradient(90deg,#fbfbff,#f9fcff); background: linear-gradient(90deg,#fbfbff,#f9fcff);
border:1px solid #eef5ff; padding:10px; border-radius:10px; box-shadow: inset 0 1px 0 rgba(255,255,255,0.6); border:1px solid #eef5ff;
margin-top:8px; overflow:auto; 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;
} }
.consolidate-toggle { display:flex; gap:10px; align-items:center; margin-bottom:8px; }
.consolidate-tab-btn { background:#fff; border:1px solid #e6edf9; padding:8px 10px; border-radius:8px; font-weight:700; cursor:pointer; }
.consolidate-tab-btn.active { background:linear-gradient(90deg,var(--primary-1),var(--primary-2)); color:#fff; border-color:transparent; box-shadow:0 6px 18px rgba(36,58,114,0.08); }
/* compact table in consolidate */ /* compact table in consolidate */
#consolidateOrdersTable th, #consolidateOrdersTable td { padding:8px 9px; font-size:13px; border-bottom:1px solid #f1f6ff; } #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;
}
.pagination-info {
font-size: 13px;
color: var(--muted);
font-weight: 600;
}
.pagination-controls {
display: flex;
align-items: center;
gap: 8px;
}
.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%);
}
/* ---------- Entry Details Modal (existing) ---------- */ /* ---------- Entry Details Modal (existing) ---------- */
.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; } .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;
}
.modal-fade1.modal-open { display:flex; } .modal-fade1.modal-open { display:flex; }
.modal-box1 { background:#fff; border-radius:12px; padding:16px 18px; box-shadow:0 14px 40px rgba(18,30,60,0.12); max-width:1100px; width:100%; max-height:92vh; overflow:auto; } .modal-box1 {
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;
}
/* entry summary cards */ /* entry summary cards */
.entry-summary-cards { display:flex; gap:12px; margin-bottom:14px; flex-wrap:wrap; } .entry-summary-cards {
.entry-summary-card { background:#fbfdff; border:1px solid #eef6ff; padding:12px; border-radius:10px; min-width:160px; box-shadow:0 6px 18px rgba(22,36,72,0.03); } display:flex;
gap:16px;
margin-bottom:20px;
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;
}
.entry-summary-label{ font-size:12px; color:var(--muted); } .entry-summary-label{ font-size:12px; color:var(--muted); }
.entry-summary-value{ font-size:18px; font-weight:700; color:#253047; margin-top:6px; } .entry-summary-value{ font-size:18px; font-weight:700; color:#253047; margin-top:6px; }
@@ -193,11 +481,47 @@ tr:hover td{ background:#fbfdff; }
.empty-state{ padding:18px; text-align:center; color:#6f7b8f; } .empty-state{ padding:18px; text-align:center; color:#6f7b8f; }
.kv { font-weight:700; color:#26364f; } .kv { font-weight:700; color:#26364f; }
/* form styles */
.input, select {
width:100%;
padding:12px 14px;
border-radius:8px;
border:1.3px solid #e3eaf6;
background:#fff;
font-size:14px;
box-sizing:border-box;
}
.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;
}
/* responsive */ /* responsive */
@media (max-width:980px){ @media (max-width:980px){
.create-card .create-grid { grid-template-columns: 1fr; } .create-grid { grid-template-columns: 1fr; }
.panel-card { min-width:100%; } .panel-card { min-width:100%; }
.search-row input{ width:220px; } .search-row input{ width:220px; }
.pagination-container { flex-direction: column; gap: 10px; align-items: stretch; }
.pagination-controls { justify-content: center; }
.account-container { padding: 20px; }
.panel-card { padding: 18px; }
}
@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; }
} }
</style> </style>
@@ -216,7 +540,7 @@ tr:hover td{ background:#fbfdff; }
<button class="btn ghost" id="searchBtn">Search</button> <button class="btn ghost" id="searchBtn">Search</button>
</div> </div>
<div style="display:flex; align-items:center; gap:8px; margin-left:6px;"> <div style="display:flex; align-items:center; gap:8px; margin-left:6px;">
<button class="btn" id="toggleCreateBtn" aria-expanded="false">+ Create New Order</button> <button class="btn" id="openCreateModalBtn">+ Create New Order</button>
</div> </div>
</div> </div>
@@ -225,83 +549,6 @@ tr:hover td{ background:#fbfdff; }
</div> </div>
</div> </div>
<!-- Expandable Create Order Card (Option D) -->
<div class="create-card" id="createCard">
<div class="create-inner">
<div style="display:flex; align-items:center; justify-content:space-between;">
<div style="font-size:18px; font-weight:800; color:var(--primary-1)">Create New Order</div>
<button class="consolidate-tab-btn" id="closeCreateInline" title="Close create form"></button>
</div>
<form id="createOrderInlineForm" autocomplete="off">
<div class="create-grid" style="margin-top:6px;">
<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:10px;">
<div class="consolidate-toggle">
<button type="button" id="toggleConsolidatedBtn" class="consolidate-tab-btn active">Hide Orders</button>
<div style="font-weight:700; color:#233063; margin-left: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">
<tr><td colspan="14" class="empty-state">Loading available orders...</td></tr>
</tbody>
</table>
</div>
</div>
<div class="create-actions">
<button type="button" class="btn ghost" id="cancelCreateInline">Cancel</button>
<button type="submit" class="btn">Create Order</button>
</div>
</form>
<div class="helper-note">Tip: Select orders from the list to include them in this consolidated entry. You can also search orders above.</div>
</div>
</div>
<!-- Panels --> <!-- Panels -->
<div class="account-panels" id="account-panels"> <div class="account-panels" id="account-panels">
<div class="panel-card"> <div class="panel-card">
@@ -343,6 +590,103 @@ tr:hover td{ background:#fbfdff; }
</div> </div>
</div> </div>
<!-- CREATE ORDER POPUP MODAL -->
<div class="create-order-modal" id="createOrderModal">
<div class="modal-box">
<div style="display:flex; align-items:center; justify-content:space-between; margin-bottom:16px;">
<div style="font-size:20px; font-weight:800; color:var(--primary-1)">Create New Order</div>
<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">
<tr><td colspan="14" class="empty-state">Loading available orders...</td></tr>
</tbody>
</table>
<!-- Pagination Controls -->
<div class="pagination-container">
<div class="pagination-info" id="pageInfo">Showing 1 to 10 of 0 entries</div>
<div class="pagination-controls">
<button class="pagination-img-btn" id="prevPageBtn" title="Previous page">
<!-- Left arrow SVG -->
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M10 12L6 8L10 4" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
</button>
<div class="pagination-pages" id="paginationPages">
<!-- Page numbers will be inserted here -->
</div>
<button class="pagination-img-btn" id="nextPageBtn" title="Next page">
<!-- Right arrow SVG -->
<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="create-actions">
<button type="button" class="btn ghost" id="cancelCreateModal">Cancel</button>
<button type="submit" class="btn">Create Order</button>
</div>
</form>
<div class="helper-note">Tip: Select orders from the list to include them in this consolidated entry. You can also search orders above.</div>
</div>
</div>
<!-- ENTRY DETAILS MODAL --> <!-- ENTRY DETAILS MODAL -->
<div class="modal-fade1" id="entryDetailsModal"> <div class="modal-fade1" id="entryDetailsModal">
<div class="modal-box1 entry-details-modal"> <div class="modal-box1 entry-details-modal">
@@ -389,7 +733,6 @@ tr:hover td{ background:#fbfdff; }
</tbody> </tbody>
</table> </table>
<div style="display:flex; justify-content: flex-end; gap:12px; margin-top:16px;"> <div style="display:flex; justify-content: flex-end; gap:12px; margin-top:16px;">
<button type="button" class="btn ghost" onclick="closeEntryDetailsModal()">Close</button> <button type="button" class="btn ghost" onclick="closeEntryDetailsModal()">Close</button>
<button type="button" class="btn" id="addInstallmentFromDetails">+ Add New Installment</button> <button type="button" class="btn" id="addInstallmentFromDetails">+ Add New Installment</button>
@@ -402,7 +745,7 @@ tr:hover td{ background:#fbfdff; }
<div class="modal-box1" style="max-width:720px;"> <div class="modal-box1" style="max-width:720px;">
<div style="display:flex;align-items:center; justify-content:space-between; margin-bottom:12px;"> <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 New Installment</div> <div style="font-size:18px;font-weight:800;color:#243a72;">+ Add New Installment</div>
<button class="consolidate-tab-btn" onclick="closeInstallmentModal()"></button> <button class="btn ghost" onclick="closeInstallmentModal()"></button>
</div> </div>
<div style="font-size:14px;color:#6f7b8f;margin-bottom:14px;">Create a new processing entry for the remaining pending amount</div> <div style="font-size:14px;color:#6f7b8f;margin-bottom:14px;">Create a new processing entry for the remaining pending amount</div>
@@ -453,6 +796,10 @@ let entries = [];
let availableOrders = []; let availableOrders = [];
let currentEntry = null; let currentEntry = null;
/* Pagination state */
let currentPage = 1;
const ordersPerPage = 10;
/* small util */ /* small util */
function escapeHtml(s){ if(s === null || s === undefined) return ''; return String(s).replace(/[&<>"']/g, m => ({'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":"&#39;"}[m])); } 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 formatCurrency(v){ return '₹' + Number(v || 0).toLocaleString(undefined, { minimumFractionDigits:0, maximumFractionDigits:2 }); }
@@ -471,17 +818,21 @@ function statusClass(status){
window.addEventListener('DOMContentLoaded', () => { window.addEventListener('DOMContentLoaded', () => {
bindUI(); bindUI();
loadDashboard(); loadDashboard();
loadAvailableOrders();
}); });
/* ---------- UI binding ---------- */ /* ---------- UI binding ---------- */
function bindUI(){ function bindUI(){
document.getElementById('toggleCreateBtn').addEventListener('click', toggleCreateCard); // Create Order Modal
document.getElementById('closeCreateInline').addEventListener('click', () => closeCreateCard()); document.getElementById('openCreateModalBtn').addEventListener('click', openCreateOrderModal);
document.getElementById('cancelCreateInline').addEventListener('click', () => closeCreateCard()); document.getElementById('closeCreateModal').addEventListener('click', closeCreateOrderModal);
document.getElementById('cancelCreateModal').addEventListener('click', closeCreateOrderModal);
document.getElementById('createOrderInlineForm').addEventListener('submit', submitCreateOrderInline); document.getElementById('createOrderInlineForm').addEventListener('submit', submitCreateOrderInline);
document.getElementById('refreshBtn').addEventListener('click', () => { loadDashboard(); loadAvailableOrders(); });
document.getElementById('toggleConsolidatedBtn').addEventListener('click', toggleConsolidateVisibility); // Pagination buttons
document.getElementById('prevPageBtn').addEventListener('click', goToPreviousPage);
document.getElementById('nextPageBtn').addEventListener('click', goToNextPage);
document.getElementById('refreshBtn').addEventListener('click', () => { loadDashboard(); });
document.getElementById('searchBtn').addEventListener('click', handleSearch); document.getElementById('searchBtn').addEventListener('click', handleSearch);
document.getElementById('addInstallmentFromDetails').addEventListener('click', () => { document.getElementById('addInstallmentFromDetails').addEventListener('click', () => {
if(!currentEntry) return; if(!currentEntry) return;
@@ -493,29 +844,100 @@ function bindUI(){
document.getElementById('installmentForm').addEventListener('submit', submitInstallment); document.getElementById('installmentForm').addEventListener('submit', submitInstallment);
} }
/* ---------- Toggle create inline ---------------- */ /* ---------- Pagination Functions ---------- */
function toggleCreateCard(){ function goToPreviousPage() {
const card = document.getElementById('createCard'); if (currentPage > 1) {
const btn = document.getElementById('toggleCreateBtn'); currentPage--;
if(card.classList.contains('open')){ renderConsolidateOrders(availableOrders);
closeCreateCard(); updatePaginationControls();
}
}
function goToNextPage() {
const totalPages = Math.ceil(availableOrders.length / ordersPerPage);
if (currentPage < totalPages) {
currentPage++;
renderConsolidateOrders(availableOrders);
updatePaginationControls();
}
}
function updatePaginationControls() {
const totalPages = Math.ceil(availableOrders.length / ordersPerPage);
const prevBtn = document.getElementById('prevPageBtn');
const nextBtn = document.getElementById('nextPageBtn');
const pageInfo = document.getElementById('pageInfo');
const paginationPages = document.getElementById('paginationPages');
prevBtn.disabled = currentPage === 1;
nextBtn.disabled = currentPage === totalPages || totalPages === 0;
// Update page info text
const startIndex = (currentPage - 1) * ordersPerPage + 1;
const endIndex = Math.min(currentPage * ordersPerPage, availableOrders.length);
pageInfo.textContent = `Showing ${startIndex} to ${endIndex} of ${availableOrders.length} entries`;
// Generate page numbers
paginationPages.innerHTML = '';
if (totalPages <= 7) {
// Show all pages
for (let i = 1; i <= totalPages; i++) {
addPageButton(i, paginationPages);
}
} else { } else {
openCreateCard(); // Show first page, current page range, and last page
addPageButton(1, paginationPages);
if (currentPage > 3) {
paginationPages.innerHTML += '<span class="pagination-ellipsis">...</span>';
}
const start = Math.max(2, currentPage - 1);
const end = Math.min(totalPages - 1, currentPage + 1);
for (let i = start; i <= end; i++) {
addPageButton(i, paginationPages);
}
if (currentPage < totalPages - 2) {
paginationPages.innerHTML += '<span class="pagination-ellipsis">...</span>';
}
addPageButton(totalPages, paginationPages);
} }
} }
function openCreateCard(){
const card = document.getElementById('createCard'); function addPageButton(pageNumber, container) {
card.classList.add('open'); const button = document.createElement('button');
document.getElementById('toggleCreateBtn').setAttribute('aria-expanded','true'); button.className = 'pagination-page-btn';
// refresh orders if (pageNumber === currentPage) {
button.classList.add('active');
}
button.textContent = pageNumber;
button.addEventListener('click', () => {
currentPage = pageNumber;
renderConsolidateOrders(availableOrders);
updatePaginationControls();
});
container.appendChild(button);
}
/* ---------- Create Order Modal Functions ---------- */
function openCreateOrderModal(){
const modal = document.getElementById('createOrderModal');
modal.classList.add('modal-open');
loadAvailableOrders(); loadAvailableOrders();
// focus first input // focus first input
setTimeout(()=> document.getElementById('inline_description').focus(), 220); setTimeout(()=> document.getElementById('inline_description').focus(), 220);
} }
function closeCreateCard(){
const card = document.getElementById('createCard'); function closeCreateOrderModal(){
card.classList.remove('open'); const modal = document.getElementById('createOrderModal');
document.getElementById('toggleCreateBtn').setAttribute('aria-expanded','false'); modal.classList.remove('modal-open');
// reset form and pagination
document.getElementById('createOrderInlineForm').reset();
currentPage = 1;
} }
/* ---------- Loaders ---------- */ /* ---------- Loaders ---------- */
@@ -540,16 +962,19 @@ function loadDashboard(){
function loadAvailableOrders(){ function loadAvailableOrders(){
const tbody = document.getElementById('consolidateOrdersBody'); const tbody = document.getElementById('consolidateOrdersBody');
tbody.innerHTML = '<tr><td colspan="10" class="empty-state">Loading available orders...</td></tr>'; tbody.innerHTML = '<tr><td colspan="14" class="empty-state">Loading available orders...</td></tr>';
jsonFetch('/admin/account/available-orders') jsonFetch('/admin/account/available-orders')
.then(res => { .then(res => {
if(!res.success) throw new Error(res.message || 'Failed to load orders'); if(!res.success) throw new Error(res.message || 'Failed to load orders');
availableOrders = res.orders || []; availableOrders = res.orders || [];
currentPage = 1; // Reset to first page when loading new orders
renderConsolidateOrders(availableOrders); renderConsolidateOrders(availableOrders);
updatePaginationControls();
}) })
.catch(err => { .catch(err => {
console.error(err); console.error(err);
tbody.innerHTML = '<tr><td colspan="10" class="empty-state">Unable to load orders</td></tr>'; tbody.innerHTML = '<tr><td colspan="14" class="empty-state">Unable to load orders</td></tr>';
updatePaginationControls();
}); });
} }
@@ -619,11 +1044,18 @@ function renderOrderTable(list){
function renderConsolidateOrders(list){ function renderConsolidateOrders(list){
const body = document.getElementById('consolidateOrdersBody'); const body = document.getElementById('consolidateOrdersBody');
body.innerHTML = ''; body.innerHTML = '';
if(!list || list.length === 0){ if(!list || list.length === 0){
body.innerHTML = '<tr><td colspan="10" class="empty-state">No available orders</td></tr>'; body.innerHTML = '<tr><td colspan="14" class="empty-state">No available orders</td></tr>';
return; return;
} }
list.forEach(order => {
// Calculate pagination
const startIndex = (currentPage - 1) * ordersPerPage;
const endIndex = startIndex + ordersPerPage;
const paginatedOrders = list.slice(startIndex, endIndex);
paginatedOrders.forEach(order => {
const tr = document.createElement('tr'); const tr = document.createElement('tr');
tr.innerHTML = ` tr.innerHTML = `
<td><input type="checkbox" value="${order.id}"></td> <td><input type="checkbox" value="${order.id}"></td>
@@ -639,13 +1071,11 @@ function renderConsolidateOrders(list){
<td>${order.ttl_cbm ?? ''}</td> <td>${order.ttl_cbm ?? ''}</td>
<td>${order.kg ?? ''}</td> <td>${order.kg ?? ''}</td>
<td>${order.ttl_kg ?? ''}</td> <td>${order.ttl_kg ?? ''}</td>
`; `;
body.appendChild(tr); body.appendChild(tr);
}); });
} }
function setToggleVisual(btn, pos) { function setToggleVisual(btn, pos) {
btn.classList.remove('mid', 'checked'); btn.classList.remove('mid', 'checked');
@@ -686,9 +1116,7 @@ function cycleToggle(btn) {
}); });
} }
/* ---------- Create Order Inline (Now in Popup) ---------- */
/* ---------- Create Order Inline (Option D) ---------- */
async function submitCreateOrderInline(e){ async function submitCreateOrderInline(e){
e.preventDefault(); e.preventDefault();
const form = e.target; const form = e.target;
@@ -714,9 +1142,8 @@ async function submitCreateOrderInline(e){
if(!res.success) throw new Error(res.message || 'Create failed'); if(!res.success) throw new Error(res.message || 'Create failed');
// success // success
form.reset(); form.reset();
closeCreateCard(); closeCreateOrderModal();
loadDashboard(); loadDashboard();
loadAvailableOrders();
} catch(err){ } catch(err){
alert(err.message || 'Failed to create order'); alert(err.message || 'Failed to create order');
console.error(err); console.error(err);
@@ -726,19 +1153,6 @@ async function submitCreateOrderInline(e){
} }
} }
/* ---------- Consolidate toggle ---------- */
function toggleConsolidateVisibility(){
const btn = document.getElementById('toggleConsolidatedBtn');
const area = document.getElementById('consolidateArea');
if(btn.classList.contains('active')){
btn.classList.remove('active'); btn.textContent = 'Show Orders';
area.style.display = 'none';
} else {
btn.classList.add('active'); btn.textContent = 'Hide Orders';
area.style.display = 'block';
}
}
/* ---------- Search ---------- */ /* ---------- Search ---------- */
function handleSearch(){ function handleSearch(){
const q = document.getElementById('main-search').value.trim().toLowerCase(); const q = document.getElementById('main-search').value.trim().toLowerCase();
@@ -810,8 +1224,6 @@ function closeEntryDetailsModal() {
document.getElementById('entryDetailsModal').classList.remove('modal-open'); document.getElementById('entryDetailsModal').classList.remove('modal-open');
} }
async function updateInstallmentStatus(id, status) { async function updateInstallmentStatus(id, status) {
try { try {
const res = await jsonFetch('/admin/account/installment/update-status', { const res = await jsonFetch('/admin/account/installment/update-status', {
@@ -833,7 +1245,6 @@ async function updateInstallmentStatus(id, status) {
} }
} }
/* ---------- Installment modal ---------- */ /* ---------- Installment modal ---------- */
function openInstallmentModal(entryNo, desc, region, pending){ function openInstallmentModal(entryNo, desc, region, pending){
currentEntry = { entry_no: entryNo, description: desc, region: region, pending_amount: pending }; currentEntry = { entry_no: entryNo, description: desc, region: region, pending_amount: pending };

View File

@@ -55,6 +55,7 @@
padding: 8px 15px; padding: 8px 15px;
border: 1px solid rgba(0, 0, 0, 0.1); border: 1px solid rgba(0, 0, 0, 0.1);
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05); box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
width: 100%;
} }
.search-input { .search-input {
@@ -105,7 +106,6 @@
border-radius: 10px; border-radius: 10px;
overflow: hidden; overflow: hidden;
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.05); box-shadow: 0 4px 15px rgba(0, 0, 0, 0.05);
} }
.table-header { .table-header {
@@ -244,6 +244,66 @@
border-radius: 10px 10px 0 0; border-radius: 10px 10px 0 0;
overflow: hidden; overflow: hidden;
} }
/* Remove horizontal scroll */
.table-responsive {
overflow-x: visible !important;
}
.container-fluid {
overflow-x: hidden;
}
/* Adjust table layout to fit without scroll */
.table {
width: 100%;
min-width: auto;
}
/* Ensure proper column sizing */
.table th,
.table td {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
/* Fix for search and filter section */
.search-filter-container {
display: flex;
align-items: center;
justify-content: space-between;
flex-wrap: nowrap;
gap: 15px;
}
.search-section {
flex: 1;
min-width: 300px;
}
.filter-section {
display: flex;
align-items: center;
flex-wrap: nowrap;
gap: 8px;
}
@media (max-width: 768px) {
.search-filter-container {
flex-direction: column;
align-items: stretch;
}
.search-section {
min-width: auto;
}
.filter-section {
justify-content: center;
flex-wrap: wrap;
}
}
</style> </style>
<div class="container-fluid"> <div class="container-fluid">
@@ -252,37 +312,55 @@
<h4 style="color: #2c3e50; font-weight: 700;">Customer List</h4> <h4 style="color: #2c3e50; font-weight: 700;">Customer List</h4>
</div> </div>
<!-- Stats Cards --> <!-- Stats Cards with REAL DATA -->
<div class="stats-row"> <div class="stats-row">
<div class="stats-card"> <div class="stats-card">
<div class="stats-count">{{ $totalCustomers ?? '1,247' }}</div> <div class="stats-count">{{ $customers->count() }}</div>
<div class="stats-label">Total Customers</div> <div class="stats-label">Total Customers</div>
<i class="bi bi-people-fill stats-icon"></i> <i class="bi bi-people-fill stats-icon"></i>
</div> </div>
<div class="stats-card" style="background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);"> <div class="stats-card" style="background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);">
<div class="stats-count">{{ $newThisMonth ?? '342' }}</div> <div class="stats-count">
@php
$newThisMonth = $customers->filter(function($customer) {
return $customer->created_at->format('Y-m') === now()->format('Y-m');
})->count();
@endphp
{{ $newThisMonth }}
</div>
<div class="stats-label">New This Month</div> <div class="stats-label">New This Month</div>
<i class="bi bi-person-plus stats-icon"></i> <i class="bi bi-person-plus stats-icon"></i>
</div> </div>
<div class="stats-card" style="background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);"> <div class="stats-card" style="background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);">
<div class="stats-count">{{ $activeThisMonth ?? '123' }}</div> <div class="stats-count">
<div class="stats-label">Active This Month</div> @php
$activeCustomers = $customers->where('status', 'active')->count();
@endphp
{{ $activeCustomers }}
</div>
<div class="stats-label">Active Customers</div>
<i class="bi bi-activity stats-icon"></i> <i class="bi bi-activity stats-icon"></i>
</div> </div>
<div class="stats-card" style="background: linear-gradient(135deg, #43e97b 0%, #38f9d7 100%);"> <div class="stats-card" style="background: linear-gradient(135deg, #43e97b 0%, #38f9d7 100%);">
<div class="stats-count">{{ $premiumCount ?? '23' }}</div> <div class="stats-count">
@php
$premiumCount = $customers->where('customer_type', 'premium')->count();
@endphp
{{ $premiumCount }}
</div>
<div class="stats-label">Premium Customers</div> <div class="stats-label">Premium Customers</div>
<i class="bi bi-award-fill stats-icon"></i> <i class="bi bi-award-fill stats-icon"></i>
</div> </div>
</div> </div>
<!-- Search and Filter Section --> <!-- Search and Filter Section - FIXED LAYOUT -->
<div class="glass-card p-3 mb-3"> <div class="glass-card p-3 mb-3">
<div class="row align-items-center"> <div class="search-filter-container">
<div class="col-md-6"> <!-- Search Section -->
<div class="search-section">
<form method="GET" action="{{ route('admin.customers.index') }}" class="d-flex align-items-center"> <form method="GET" action="{{ route('admin.customers.index') }}" class="d-flex align-items-center">
<div class="search-container"> <div class="search-container">
<i class="bi bi-search text-muted me-2"></i> <i class="bi bi-search text-muted me-2"></i>
@@ -290,14 +368,16 @@
name="search" name="search"
value="{{ $search ?? '' }}" value="{{ $search ?? '' }}"
class="search-input" class="search-input"
placeholder="Search Customer Name"> placeholder="Search Customer Name, Email, or Phone...">
@if(!empty($status)) @if(!empty($status))
<input type="hidden" name="status" value="{{ $status }}"> <input type="hidden" name="status" value="{{ $status }}">
@endif @endif
</div> </div>
</form> </form>
</div> </div>
<div class="col-md-6 text-end">
<!-- Filter Section -->
<div class="filter-section">
<a href="{{ route('admin.customers.index', ['status'=>'active', 'search'=>$search ?? '']) }}" <a href="{{ route('admin.customers.index', ['status'=>'active', 'search'=>$search ?? '']) }}"
class="filter-btn {{ ($status ?? '') == 'active' ? 'active' : '' }}"> class="filter-btn {{ ($status ?? '') == 'active' ? 'active' : '' }}">
Active Active
@@ -313,7 +393,7 @@
All All
</a> </a>
<a href="{{ route('admin.customers.add') }}" class="add-customer-btn ms-2"> <a href="{{ route('admin.customers.add') }}" class="add-customer-btn">
<i class="bi bi-plus-circle me-1"></i>Add Customer <i class="bi bi-plus-circle me-1"></i>Add Customer
</a> </a>
</div> </div>
@@ -321,11 +401,6 @@
</div> </div>
<!-- Customer List Table --> <!-- Customer List Table -->
<div class="glass-card">
<div class="p-3 border-bottom">
<h5 class="mb-0" style="color: #2c3e50; font-weight: 600;">Customer List</h5>
</div>
<div class="table-container"> <div class="table-container">
<div class="table-responsive"> <div class="table-responsive">
<table class="table table-hover align-middle mb-0"> <table class="table table-hover align-middle mb-0">
@@ -415,6 +490,5 @@
</div> </div>
</div> </div>
</div> </div>
</div>
@endsection @endsection

View File

@@ -394,8 +394,8 @@
border-color: #8b5cf6 !important; border-color: #8b5cf6 !important;
} }
/* Action Button - Centered */ /* Entry Button - Centered */
.btn-primary { .btn-entry {
background: linear-gradient(135deg, #3492f8 55%, #1256cc 110%); background: linear-gradient(135deg, #3492f8 55%, #1256cc 110%);
border: none; border: none;
border-radius: 6px; border-radius: 6px;
@@ -410,13 +410,15 @@
align-items: center; align-items: center;
justify-content: center; justify-content: center;
gap: 4px; gap: 4px;
text-decoration: none;
} }
.btn-primary:hover { .btn-entry:hover {
background: linear-gradient(135deg, #46b4fd 55%, #226ad6 110%); background: linear-gradient(135deg, #46b4fd 55%, #226ad6 110%);
transform: translateY(-1px); transform: translateY(-1px);
box-shadow: 0 2px 8px rgba(52, 146, 248, 0.4); box-shadow: 0 2px 8px rgba(52, 146, 248, 0.4);
color: white; color: white;
text-decoration: none;
} }
/* Amount Styling - Centered */ /* Amount Styling - Centered */
@@ -593,7 +595,7 @@
justify-content: center; justify-content: center;
} }
.table tbody tr td .btn-primary { .table tbody tr td .btn-entry {
margin: 0 auto; margin: 0 auto;
} }
@@ -729,7 +731,7 @@
border: 1px solid #2469d6; border: 1px solid #2469d6;
} }
.mobile-action-btn.edit { .mobile-action-btn.entry {
background: linear-gradient(135deg, #3492f8 55%, #1256cc 110%); background: linear-gradient(135deg, #3492f8 55%, #1256cc 110%);
color: white; color: white;
border: none; border: none;
@@ -785,7 +787,7 @@
font-size: 10px; font-size: 10px;
} }
.btn-primary { .btn-entry {
padding: 4px 8px; padding: 4px 8px;
font-size: 11px; font-size: 11px;
} }
@@ -987,8 +989,8 @@
<td> <td>
<a href="{{ route('admin.invoices.edit', $invoice->id) }}" <a href="{{ route('admin.invoices.edit', $invoice->id) }}"
class="btn btn-sm btn-primary"> class="btn-entry">
<i class="bi bi-pencil"></i> Edit <i class="bi bi-pencil"></i> Entry
</a> </a>
</td> </td>
</tr> </tr>
@@ -1062,8 +1064,8 @@
<a href="#" class="mobile-action-btn view open-invoice-popup" data-id="{{ $invoice->id }}"> <a href="#" class="mobile-action-btn view open-invoice-popup" data-id="{{ $invoice->id }}">
<i class="bi bi-eye"></i> View <i class="bi bi-eye"></i> View
</a> </a>
<a href="{{ route('admin.invoices.edit', $invoice->id) }}" class="mobile-action-btn edit"> <a href="{{ route('admin.invoices.edit', $invoice->id) }}" class="mobile-action-btn entry">
<i class="bi bi-pencil"></i> Edit <i class="bi bi-pencil"></i> Entry
</a> </a>
</div> </div>
</div> </div>

File diff suppressed because it is too large Load Diff

View File

@@ -6,6 +6,8 @@
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet" /> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet" />
<link href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.css" rel="stylesheet" /> <link href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.css" rel="stylesheet" />
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.5/font/bootstrap-icons.css"> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.5/font/bootstrap-icons.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css" integrity="sha512-DTOQO9RWCH3ppGqcWaEA1BIZOC6xxalwEsw9c2QQeAIftl+Vegovlnee1c9QX4TctnWMn13TZye+giMm8e2LwA==" crossorigin="anonymous" referrerpolicy="no-referrer" />
<style> <style>
body { body {
@@ -205,7 +207,10 @@
class="{{ request()->routeIs('admin.orders.*') ? 'active' : '' }}"> class="{{ request()->routeIs('admin.orders.*') ? 'active' : '' }}">
<i class="bi bi-bag"></i> Orders <i class="bi bi-bag"></i> Orders
</a> --> </a> -->
<a href="{{ route('admin.orders') }}" class="{{ request()->routeIs('admin.orders') ? 'active' : '' }}"><i class="bi bi-bag"></i> Orders</a> <a href="{{ route('admin.orders') }}"
class="{{ request()->routeIs('admin.orders') ? 'active' : '' }}">
<i class="bi bi-bag"></i> Orders
</a>
<a href="{{ route('admin.requests') }}" class="{{ request()->routeIs('admin.requests') ? 'active' : '' }}"><i class="bi bi-envelope"></i> Requests</a> <a href="{{ route('admin.requests') }}" class="{{ request()->routeIs('admin.requests') ? 'active' : '' }}"><i class="bi bi-envelope"></i> Requests</a>
<a href="{{ route('admin.staff') }}" class="{{ request()->routeIs('admin.staff') ? 'active' : '' }}"><i class="bi bi-person-badge"></i> Staff</a> <a href="{{ route('admin.staff') }}" class="{{ request()->routeIs('admin.staff') ? 'active' : '' }}"><i class="bi bi-person-badge"></i> Staff</a>
<a href="{{ route('admin.account') }}" class="{{ request()->routeIs('admin.account') ? 'active' : '' }}"><i class="bi bi-gear"></i> Account</a> <a href="{{ route('admin.account') }}" class="{{ request()->routeIs('admin.account') ? 'active' : '' }}"><i class="bi bi-gear"></i> Account</a>

View File

@@ -80,60 +80,158 @@
transition: all 0.2s ease; transition: all 0.2s ease;
} }
/* ✨ NEW BADGE STYLES - Same as Invoice System */
.badge { .badge {
padding: 7px 16px; font-size: 11px !important;
border-radius: 20px; font-weight: 600 !important;
font-size: 0.85rem; padding: 6px 12px 6px 8px !important;
font-weight: 600; border-radius: 20px !important;
user-select: none; text-transform: uppercase;
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.08); letter-spacing: 0.3px;
display: inline-flex !important;
align-items: center;
justify-content: center;
background-size: cover !important;
background-position: center !important;
color: #fff !important;
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.3);
border: 2px solid transparent !important;
min-width: 40px;
box-sizing: border-box;
line-height: 1.2;
gap: 6px;
} }
.bg-success { /* Status icons */
background-color: #28a745 !important; .status-icon {
color: #fff !important; font-size: 12px;
box-shadow: 0 0 10px #6ee86e77; display: flex;
align-items: center;
justify-content: center;
}
/* Custom status badge backgrounds with icons */
.badge-active {
background: url('/images/status-bg-paid.png') !important;
}
.badge-inactive {
background: url('/images/status-bg-overdue.png') !important;
}
/* Fallback colors if images don't load - ALL WITH SAME SIZE */
.badge.badge-active {
background: linear-gradient(135deg, #d1fae5, #a7f3d0) !important;
color: #065f46 !important;
border-color: #10b981 !important;
width: 98px;
}
.badge.badge-inactive {
background: linear-gradient(135deg, #e9d5ff, #c4b5fd) !important;
color: #6b21a8 !important;
border-color: #8b5cf6 !important;
}
/* Animation effects for badges */
.badge.badge-active {
animation: pulseGreen 2s infinite; animation: pulseGreen 2s infinite;
} }
.badge.badge-inactive {
animation: pulseRed 2s infinite;
}
@keyframes pulseGreen { @keyframes pulseGreen {
0% { box-shadow: 0 0 8px #6ee86e77; } 0% { box-shadow: 0 0 8px #6ee86e77; }
50% { box-shadow: 0 0 14px #5dd75d88; } 50% { box-shadow: 0 0 14px #5dd75d88; }
100% { box-shadow: 0 0 8px #6ee86e77; } 100% { box-shadow: 0 0 8px #6ee86e77; }
} }
.bg-danger {
background-color: #dc3545 !important;
color: #fff !important;
box-shadow: 0 0 10px #f97f7f77;
animation: pulseRed 2s infinite;
}
@keyframes pulseRed { @keyframes pulseRed {
0% { box-shadow: 0 0 8px #f97f7f77; } 0% { box-shadow: 0 0 8px #f97f7f77; }
50% { box-shadow: 0 0 14px #ff868677; } 50% { box-shadow: 0 0 14px #ff868677; }
100% { box-shadow: 0 0 8px #f97f7f77; } 100% { box-shadow: 0 0 8px #f97f7f77; }
} }
/* ✨ ENHANCED ACTION BUTTONS - Professional & Attractive */
.btn-action { .btn-action {
background-color: #ffd283; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
border: none; border: none;
color: #1b1c21; color: white;
padding: 7px 20px; padding: 10px 22px;
font-size: 0.95rem; font-size: 0.85rem;
border-radius: 8px; border-radius: 12px;
font-weight: 700; font-weight: 600;
transition: all 0.25s ease; transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
margin: 3px; margin: 3px;
cursor: pointer; cursor: pointer;
box-shadow: 0 2px 6px rgba(141, 106, 0, 0.1); box-shadow: 0 4px 15px rgba(102, 126, 234, 0.3);
display: inline-block; display: inline-flex;
align-items: center;
justify-content: center;
gap: 8px;
text-decoration: none;
min-width: 120px;
text-transform: uppercase;
letter-spacing: 0.5px;
position: relative;
overflow: hidden;
}
.btn-action::before {
content: '';
position: absolute;
top: 0;
left: -100%;
width: 100%;
height: 100%;
background: linear-gradient(90deg, transparent, rgba(255,255,255,0.2), transparent);
transition: left 0.5s;
}
.btn-action:hover::before {
left: 100%;
} }
.btn-action:hover { .btn-action:hover {
background-color: #ffc85a; transform: translateY(-3px);
transform: translateY(-2px); box-shadow: 0 8px 25px rgba(102, 126, 234, 0.4);
box-shadow: 0 4px 10px rgba(141, 106, 0, 0.25); color: white;
text-decoration: none;
}
.btn-action:active {
transform: translateY(-1px);
box-shadow: 0 4px 12px rgba(102, 126, 234, 0.4);
}
/* Specific styles for Activate button */
.btn-action-activate {
background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);
box-shadow: 0 4px 15px rgba(79, 172, 254, 0.3);
}
.btn-action-activate:hover {
box-shadow: 0 8px 25px rgba(79, 172, 254, 0.5);
}
/* Specific styles for Deactivate button */
.btn-action-deactivate {
background: linear-gradient(135deg, #fa709a 0%, #fee140 100%);
box-shadow: 0 4px 15px rgba(250, 112, 154, 0.3);
}
.btn-action-deactivate:hover {
box-shadow: 0 8px 25px rgba(250, 112, 154, 0.5);
}
/* Button icons */
.btn-icon {
font-size: 14px;
display: flex;
align-items: center;
justify-content: center;
} }
.text-muted { .text-muted {
@@ -219,16 +317,28 @@
<td>{{ \Carbon\Carbon::parse($mark->date)->format('d-m-Y') }}</td> <td>{{ \Carbon\Carbon::parse($mark->date)->format('d-m-Y') }}</td>
<td> <td>
@if($mark->status == 'active') @if($mark->status == 'active')
<span class="badge bg-success">Active</span> <span class="badge badge-active">
<i class="bi bi-check-circle-fill status-icon"></i>
Active
</span>
@else @else
<span class="badge bg-danger">In-Active</span> <span class="badge badge-inactive">
<i class="bi bi-exclamation-triangle-fill status-icon"></i>
In-Active
</span>
@endif @endif
</td> </td>
<td> <td>
@if($mark->status == 'active') @if($mark->status == 'active')
<a href="{{ route('admin.marklist.toggle', $mark->id) }}" class="btn-action">Deactivate</a> <a href="{{ route('admin.marklist.toggle', $mark->id) }}" class="btn-action btn-action-deactivate">
<i class="bi bi-power btn-icon"></i>
Deactivate
</a>
@else @else
<a href="{{ route('admin.marklist.toggle', $mark->id) }}" class="btn-action">Activate</a> <a href="{{ route('admin.marklist.toggle', $mark->id) }}" class="btn-action btn-action-activate">
<i class="bi bi-play-circle btn-icon"></i>
Activate
</a>
@endif @endif
</td> </td>
</tr> </tr>

View File

@@ -1,12 +1,254 @@
@extends('admin.layouts.app') @extends('admin.layouts.app')
@section('page-title', 'Dashboard') @section('page-title', 'Orders')
@section('content') @section('content')
<div class="card shadow-sm"> <style>
<div class="card-body"> /* ===== GLOBAL RESPONSIVE STYLES ===== */
<h4>Welcome to the Admin orders</h4> html, body {
<p>Here you can manage all system modules.</p> overflow-x: hidden !important;
max-width: 100%;
}
/* VARIABLES AND BASE STYLES */
:root {
--primary-color: #3b82f6; /* Blue 500 */
--primary-hover: #2563eb; /* Blue 600 */
--border-light: #e5e7eb; /* Gray 200 */
--bg-container: #ffffff;
--bg-light: #f9fafb; /* Gray 50 */
--bg-hover: #f3f4f6; /* Gray 100 */
--text-dark: #1f2937; /* Gray 800 */
--text-muted: #6b7280; /* Gray 500 */
--shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
}
.orders-container {
background: var(--bg-container);
padding: 24px;
border-radius: 12px;
box-shadow: var(--shadow-lg);
margin-top: 28px;
font-family: 'Inter', sans-serif; /* A modern, clean font */
}
.orders-title {
font-size: 28px;
font-weight: 700;
margin-bottom: 24px;
color: var(--text-dark);
border-bottom: 1px solid var(--border-light);
padding-bottom: 16px;
}
/* TABLE STRUCTURE & WRAPPER FOR RESPONSIVENESS */
.table-wrapper {
overflow-x: auto; /* Enables horizontal scrollbar */
max-width: 100%;
border-radius: 8px;
border: 1px solid var(--border-light);
}
.orders-table {
width: 100%;
min-width: 1300px; /* Minimum width to prevent excessive squeezing of columns */
border-collapse: separate; /* Required for border-radius on cells in the future */
border-spacing: 0;
font-size: 14px;
color: var(--text-dark);
}
.orders-table thead {
background: var(--bg-light);
}
.orders-table th {
padding: 16px 20px;
font-weight: 600;
color: var(--text-muted);
text-align: left;
white-space: nowrap;
border-bottom: 2px solid var(--border-light);
text-transform: uppercase;
letter-spacing: 0.05em;
}
.orders-table td {
padding: 14px 20px;
border-bottom: 1px solid var(--border-light);
white-space: nowrap;
}
.orders-table tbody tr:last-child td {
border-bottom: none;
}
.orders-table tbody tr:hover {
background: var(--bg-hover);
transition: background 0.2s ease;
}
/* STATUS BADGES */
.status-badge {
padding: 6px 10px;
border-radius: 9999px; /* Pill shape */
font-size: 12px;
font-weight: 600;
display: inline-flex;
align-items: center;
text-transform: capitalize;
white-space: nowrap;
}
.shipstatus{
}
/* INVOICE STATUS STYLES */
.status-paid { background: #d1fae5; color: #059669; } /* Green */
.status-pending { background: #fffbeb; color: #d97706; } /* Yellow */
/* SHIPMENT STATUS STYLES */
.status-delivered { background: #e0f2fe; color: #0284c7; } /* Sky Blue */
.status-in_transit { background: #fef3c7; color: #b45309; } /* Amber */
/* ACTION BUTTON */
.action-btn {
color: var(--text-muted);
cursor: pointer;
transition: color 0.2s ease, transform 0.2s ease;
font-size: 18px;
}
.action-btn:hover {
color: var(--primary-color);
transform: scale(1.15);
}
/* EMPTY STATE */
.no-data {
padding: 40px;
text-align: center;
font-size: 16px;
color: var(--text-muted);
background: var(--bg-light);
border-radius: 8px;
margin-top: 10px;
border: 1px solid var(--border-light);
}
/* RESPONSIVE ADJUSTMENTS */
@media(max-width: 768px) {
.orders-title {
font-size: 24px;
}
.orders-container {
padding: 16px;
}
}
</style>
{{-- Make sure you include Font Awesome CDN in your main layout file, e.g., in <head>:
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css">
--}}
<div class="orders-container">
<div class="orders-title">
<i class="fas fa-box-open mr-2"></i> Orders List
</div> </div>
@if(isset($orders) && $orders->count() > 0)
<div class="table-wrapper">
<table class="orders-table">
<thead>
<tr>
<th>Order ID</th>
<th>Shipment ID</th>
<th>Customer ID</th>
<th>Company</th>
<th>Origin</th>
<th>Destination</th>
<th>Order Date</th>
<th>Invoice No</th>
<th>Invoice Date</th>
<th>Amount</th>
<th>Amount + GST</th>
<th>Invoice Status</th>
<th>Shipment Status</th>
<th>Action</th>
</tr>
</thead>
<tbody>
@foreach($orders as $order)
@php
$mark = $order->markList ?? null;
$invoice = $order->invoice ?? null;
$shipment = $order->shipments->first() ?? null;
$invoiceStatus = strtolower($invoice->status ?? '');
$shipmentStatus = strtolower(str_replace('_', ' ', $shipment->status ?? ''));
@endphp
<tr>
<td>{{ $order->order_id ?? '-' }}</td>
<td>{{ $shipment->shipment_id ?? '-' }}</td>
<td>{{ $mark->customer_id ?? '-' }}</td>
<td>{{ $mark->company_name ?? '-' }}</td>
<td>{{ $mark->origin ?? $order->origin ?? '-' }}</td>
<td>{{ $mark->destination ?? $order->destination ?? '-' }}</td>
<td>{{ $order->created_at ? $order->created_at->format('d-m-Y') : '-' }}</td>
<td>{{ $invoice->invoice_number ?? '-' }}</td>
<td>
{{ $invoice?->invoice_date ? date('d-m-Y', strtotime($invoice->invoice_date)) : '-' }}
</td>
<td>
{{ $invoice?->final_amount ? '₹'.number_format($invoice->final_amount, 2) : '-' }}
</td>
<td>
{{ $invoice?->final_amount_with_gst ? '₹'.number_format($invoice->final_amount_with_gst, 2) : '-' }}
</td>
<td>
@if($invoice?->status)
<span class="status-badge status-{{ $invoiceStatus }}">
{{ ucfirst($invoice->status) }}
</span>
@else
<span class="status-badge status-pending">Pending</span>
@endif
</td>
<td>
@if($shipment?->status)
<span class="status-badge status-{{ str_replace(' ', '_', $shipmentStatus) }}">
{{ ucfirst($shipmentStatus) }}
</span>
@else
<span class="shipstatus">-</span>
@endif
</td>
<td class="text-center">
<a href="{{ route('admin.orders.show', $order->id) }}" title="View Details">
<i class="fas fa-eye action-btn"></i>
</a>
</td>
</tr>
@endforeach
</tbody>
</table>
</div> {{-- End table-wrapper --}}
@else
<p class="no-data">
<i class="fas fa-info-circle mr-2"></i> No orders found.
</p>
@endif
</div> </div>
@endsection @endsection

View File

@@ -1,263 +1,601 @@
{{-- INVOICE CONTENT (NO POPUP WRAPPERS HERE) --}} <!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Professional Invoice</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/css/bootstrap.min.css" rel="stylesheet">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
<style>
:root {
--primary: #2c3e50;
--secondary: #3498db;
--accent: #e74c3c;
--light: #f8f9fa;
--dark: #2c3e50;
--success: #27ae60;
--warning: #f39c12;
--danger: #e74c3c;
--border-radius: 8px;
--box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
}
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
background-color: #f5f7fa;
color: #333;
line-height: 1.5;
}
.invoice-container {
max-width: 1200px;
margin: 2rem auto;
background: white;
border-radius: var(--border-radius);
box-shadow: var(--box-shadow);
overflow: hidden;
}
.invoice-header {
background: white;
padding: 1.5rem 2rem;
border-bottom: 1px solid #e9ecef;
}
.invoice-title {
font-weight: 700;
font-size: 1.8rem;
color: var(--primary);
}
.status-badge {
font-size: 0.85rem;
padding: 0.5rem 1rem;
border-radius: 50px;
font-weight: 600;
}
.id-container {
margin-bottom: 1rem; /* Reduced from 1.5rem */
}
.id-box {
background: white;
border-radius: var(--border-radius);
padding: 1rem;
border: 1px solid #e9ecef;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
transition: all 0.3s ease;
height: 100%;
}
.id-box:hover {
transform: translateY(-1px);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
}
.id-box-primary {
border-left: 4px solid var(--secondary);
}
.id-box-secondary {
border-left: 4px solid var(--success);
}
.id-box-accent {
border-left: 4px solid var(--warning);
}
.id-icon {
width: 36px;
height: 36px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
margin-bottom: 0.5rem; /* Reduced from 0.75rem */
font-size: 1rem;
}
.id-icon-primary {
background: rgba(52, 152, 219, 0.1);
color: var(--secondary);
}
.id-icon-secondary {
background: rgba(39, 174, 96, 0.1);
color: var(--success);
}
.id-icon-accent {
background: rgba(243, 156, 18, 0.1);
color: var(--warning);
}
.id-label {
font-size: 0.75rem;
color: #6c757d;
font-weight: 600;
margin-bottom: 0.25rem;
text-transform: uppercase;
letter-spacing: 0.5px;
}
.id-value {
font-size: 0.95rem;
font-weight: 700;
color: var(--primary);
margin-bottom: 0;
}
.date-container {
background: white;
border-radius: var(--border-radius);
padding: 1rem; /* Reduced from 1.25rem */
margin-bottom: 1rem; /* Reduced from 1.5rem */
border: 1px solid #e9ecef;
box-shadow: var(--box-shadow);
}
.date-card {
text-align: center;
padding: 0.75rem;
background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%);
border-radius: var(--border-radius);
border: 1px solid rgba(0,0,0,0.05);
}
.date-icon {
width: 40px;
height: 40px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
margin: 0 auto 0.5rem; /* Reduced from 0.75rem */
background: var(--secondary);
color: white;
font-size: 1rem;
}
.date-label {
font-size: 0.8rem;
color: #6c757d;
font-weight: 600;
margin-bottom: 0.5rem;
text-transform: uppercase;
letter-spacing: 0.5px;
}
.date-value {
font-size: 1rem;
font-weight: 700;
color: var(--primary);
padding: 0.5rem;
background: white;
border-radius: 4px;
border: 1px solid #e9ecef;
}
.date-connector {
display: flex;
align-items: center;
justify-content: center;
height: 100%;
}
.date-connector i {
background: var(--light);
padding: 10px;
border-radius: 50%;
color: var(--secondary);
border: 2px solid #e9ecef;
}
.card {
border: 1px solid #e9ecef;
border-radius: var(--border-radius);
margin-bottom: 1rem; /* Reduced from 1.5rem */
box-shadow: var(--box-shadow);
}
.card-header {
background: var(--light);
border-bottom: 1px solid #e9ecef;
padding: 0.75rem 1.25rem;
font-weight: 600;
color: var(--primary);
}
.table {
margin-bottom: 0;
font-size: 0.9rem;
}
.table > :not(caption) > * > * {
padding: 10px 8px;
}
.table thead th {
background-color: var(--light);
color: var(--primary);
font-weight: 600;
border-bottom: 1px solid #dee2e6;
font-size: 0.85rem;
}
.table tbody tr:hover {
background-color: rgba(52, 152, 219, 0.03);
}
.summary-card {
background: var(--light);
border-left: 4px solid var(--secondary);
}
.summary-header {
background: var(--primary);
color: white;
}
.amount-row {
border-bottom: 1px solid #e9ecef;
padding: 0.75rem 0;
}
.total-row {
border-top: 2px solid #dee2e6;
font-size: 1.1rem;
font-weight: 700;
}
.text-primary {
color: var(--primary) !important;
}
.text-success {
color: var(--success) !important;
}
.text-danger {
color: var(--danger) !important;
}
.badge {
font-size: 0.75rem;
padding: 0.35rem 0.65rem;
}
/* COMPACT HEADER STYLES */
.compact-header {
margin-bottom: 0.75rem; /* Reduced from default */
}
.compact-header .invoice-title {
margin-bottom: 0.25rem; /* Reduced gap */
}
.compact-header .status-badge {
margin-top: 0.25rem; /* Reduced gap */
}
@media (max-width: 768px) {
.invoice-container {
margin: 1rem;
}
.date-connector {
margin: 1rem 0;
}
.table-responsive {
font-size: 0.8rem;
}
.id-box {
margin-bottom: 1rem;
}
}
</style>
</head>
<body>
<div class="invoice-container">
<div class="p-4">
<!-- ============================ <!-- ============================
INVOICE HEADER INVOICE HEADER - COMPACT
============================ --> ============================ -->
<div class="mb-4"> @php
$showActions = $showActions ?? true;
@endphp
<div class="row"> <div class="compact-header">
<div class="row align-items-center">
<div class="col-md-6"> <div class="col-md-6">
<h2 class="invoice-title mb-1">
<h2 class="fw-bold text-primary mb-1">
<i class="fas fa-file-invoice me-2"></i> INVOICE <i class="fas fa-file-invoice me-2"></i> INVOICE
</h2> </h2>
<h4 class="fw-bold text-dark mb-0">{{ $invoice->invoice_number }}</h4> <h4 class="fw-bold text-dark mb-0">{{ $invoice->invoice_number }}</h4>
{{-- ORDER + SHIPMENT INFO --}}
<div class="mt-2 small">
{{-- ORDER ID --}}
@if($invoice->order_id)
<div>
<strong>Order ID:</strong>
{{ $invoice->order->order_id ?? $invoice->order_id }}
</div>
@endif
{{-- SHIPMENT ID --}}
@if(isset($shipment) && $shipment)
<div>
<strong>Shipment ID:</strong> {{ $shipment->shipment_id }}
</div>
@endif
</div>
</div> </div>
<div class="col-md-6 text-end"> <div class="col-md-6 text-end">
<span class="status-badge
<span class="badge fs-6 px-3 py-2
@if($invoice->status=='paid') bg-success @if($invoice->status=='paid') bg-success
@elseif($invoice->status=='overdue') bg-danger @elseif($invoice->status=='overdue') bg-danger
@elseif($invoice->status=='pending') bg-warning text-dark @elseif($invoice->status=='pending') bg-warning text-dark
@else bg-secondary @endif"> @else bg-secondary @endif">
<i class="fas <i class="fas
@if($invoice->status=='paid') fa-check-circle @if($invoice->status=='paid') fa-check-circle
@elseif($invoice->status=='overdue') fa-exclamation-circle @elseif($invoice->status=='overdue') fa-exclamation-circle
@elseif($invoice->status=='pending') fa-clock @elseif($invoice->status=='pending') fa-clock
@else fa-question-circle @endif me-1"></i> @else fa-question-circle @endif me-1"></i>
{{ ucfirst($invoice->status) }} {{ ucfirst($invoice->status) }}
</span> </span>
</div>
</div> </div>
</div> </div>
<!-- Three ID Boxes in One Row -->
<div class="id-container">
<div class="row">
<!-- Invoice ID Box -->
<div class="col-md-4 mb-3">
<div class="id-box id-box-primary">
<div class="id-icon id-icon-primary">
<i class="fas fa-receipt"></i>
</div>
<div class="id-label">Invoice ID</div>
<div class="id-value">{{ $invoice->invoice_number }}</div>
</div>
</div> </div>
<!-- Order ID Box -->
<div class="col-md-4 mb-3">
<div class="id-box id-box-secondary">
<div class="id-icon id-icon-secondary">
<i class="fas fa-shopping-cart"></i>
</div>
<div class="id-label">Order ID</div>
<div class="id-value">
@if($invoice->order && $invoice->order->order_id)
{{ $invoice->order->order_id }}
@elseif($invoice->order_id)
{{ $invoice->order_id }}
@else
N/A
@endif
</div>
</div>
</div>
<!-- Shipment ID Box -->
<div class="col-md-4 mb-3">
<div class="id-box id-box-accent">
<div class="id-icon id-icon-accent">
<i class="fas fa-shipping-fast"></i>
</div>
<div class="id-label">Shipment ID</div>
<div class="id-value">
@php
$shipmentId = 'N/A';
// Try multiple ways to get shipment ID
if($invoice->shipment && $invoice->shipment->shipment_id) {
$shipmentId = $invoice->shipment->shipment_id;
} elseif($invoice->shipment_id) {
$shipmentId = $invoice->shipment_id;
} elseif(isset($shipment) && $shipment && $shipment->shipment_id) {
$shipmentId = $shipment->shipment_id;
}
@endphp
{{ $shipmentId }}
</div>
</div>
</div>
</div>
</div>
<!-- ============================ <!-- ============================
DATES SECTION DATES SECTION
============================ --> ============================ -->
<div class="card border-0 shadow-sm mb-4"> <div class="date-container">
<div class="card-body py-3"> <div class="row align-items-center">
<div class="row text-center align-items-center">
<div class="col-md-5"> <div class="col-md-5">
<small class="text-muted fw-semibold">INVOICE DATE</small> <div class="date-card">
<div class="fw-bold text-dark"> <div class="date-icon">
{{ \Carbon\Carbon::parse($invoice->invoice_date)->format('M d, Y') }} <i class="fas fa-calendar-alt"></i>
</div>
<div class="date-label">INVOICE DATE</div>
<div class="date-value">{{ \Carbon\Carbon::parse($invoice->invoice_date)->format('M d, Y') }}</div>
</div> </div>
</div> </div>
<div class="col-md-2"> <div class="col-md-2">
<i class="fas fa-arrow-right text-muted"></i> <div class="date-connector">
<i class="fas fa-arrow-right"></i>
</div>
</div> </div>
<div class="col-md-5"> <div class="col-md-5">
<small class="text-muted fw-semibold">DUE DATE</small> <div class="date-card">
<div class="fw-bold {{ $invoice->status=='overdue' ? 'text-danger' : 'text-dark' }}"> <div class="date-icon">
<i class="fas fa-clock"></i>
</div>
<div class="date-label">DUE DATE</div>
<div class="date-value @if($invoice->status == 'overdue') text-danger @endif">
{{ \Carbon\Carbon::parse($invoice->due_date)->format('M d, Y') }} {{ \Carbon\Carbon::parse($invoice->due_date)->format('M d, Y') }}
</div> </div>
</div> </div>
</div>
</div> </div>
</div> </div>
</div>
<!-- ============================ <!-- ============================
CUSTOMER DETAILS CUSTOMER DETAILS
============================ --> ============================ -->
<div class="card border-0 shadow-sm mb-4"> <div class="card">
<div class="card-header">
<div class="card-header bg-light py-2"> <h6 class="mb-0 fw-bold">
<h6 class="fw-bold mb-0"><i class="fas fa-user me-2"></i> Customer Details</h6> <i class="fas fa-user me-2"></i> Customer Details
</h6>
</div> </div>
<div class="card-body"> <div class="card-body">
<div class="row"> <div class="row">
<div class="col-md-6"> <div class="col-md-6">
<h6 class="fw-bold text-primary">{{ $invoice->customer_name }}</h6> <h6 class="fw-bold text-primary mb-1">{{ $invoice->customer_name }}</h6>
@if($invoice->company_name) @if($invoice->company_name)
<p class="mb-1"><strong>Company:</strong> {{ $invoice->company_name }}</p> <p class="mb-1">
<strong>Company:</strong> {{ $invoice->company_name }}
</p>
@endif @endif
<p class="mb-1">
<p class="mb-1"><strong>Mobile:</strong> {{ $invoice->customer_mobile }}</p> <strong>Mobile:</strong> {{ $invoice->customer_mobile }}
<p class="mb-1"><strong>Email:</strong> {{ $invoice->customer_email }}</p> </p>
<p class="mb-1">
<strong>Email:</strong> {{ $invoice->customer_email }}
</p>
</div> </div>
<div class="col-md-6"> <div class="col-md-6">
<p class="mb-1"><strong>Address:</strong><br>{{ $invoice->customer_address }}</p> <p class="mb-1">
<p class="mb-1"><strong>Pincode:</strong> {{ $invoice->pincode }}</p> <strong>Address:</strong><br>
{{ $invoice->customer_address }}
</p>
<p class="mb-1">
<strong>Pincode:</strong> {{ $invoice->pincode }}
</p>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<!-- ============================ <!-- ============================
INVOICE ITEMS INVOICE ITEMS
============================ --> ============================ -->
<div class="card border-0 shadow-sm mb-4"> <div class="card">
<div class="card-header">
<div class="card-header bg-light py-2"> <h6 class="mb-0 fw-bold">
<h6 class="fw-bold mb-0"><i class="fas fa-list me-2"></i> Invoice Items</h6> <i class="fas fa-list me-2"></i> Invoice Items
</h6>
</div> </div>
<div class="card-body p-0">
<div class="table-responsive"> <div class="table-responsive">
<table class="table table-bordered table-hover align-middle mb-0"> <table class="table table-bordered table-hover align-middle mb-0">
<thead class="table-light"> <thead class="table-light">
<tr> <tr>
<th>#</th> <th class="text-center">#</th>
<th>Description</th> <th>Description</th>
<th>CTN</th> <th class="text-center">CTN</th>
<th>QTY</th> <th class="text-center">QTY</th>
<th>TTL/QTY</th> <th class="text-center">TTL/QTY</th>
<th>Unit</th> <th class="text-center">Unit</th>
<th>Price</th> <th class="text-center">Price</th>
<th>TTL Amount</th> <th class="text-center">TTL Amount</th>
<th>CBM</th> <th class="text-center">CBM</th>
<th>TTL CBM</th> <th class="text-center">TTL CBM</th>
<th>KG</th> <th class="text-center">KG</th>
<th>TTL KG</th> <th class="text-center">TTL KG</th>
<th>Shop No</th> <th class="text-center">Shop No</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
@foreach($invoice->items as $i => $item) @foreach($invoice->items as $i => $item)
<tr> <tr>
<td class="text-center fw-bold">{{ $i + 1 }}</td> <td class="text-center fw-bold text-muted">{{ $i+1 }}</td>
<td>{{ $item->description }}</td> <td class="fw-semibold">{{ $item->description }}</td>
<td class="text-center">{{ $item->ctn }}</td> <td class="text-center">{{ $item->ctn }}</td>
<td class="text-center">{{ $item->qty }}</td> <td class="text-center">{{ $item->qty }}</td>
<td class="text-center">{{ $item->ttl_qty }}</td> <td class="text-center fw-bold">{{ $item->ttl_qty }}</td>
<td class="text-center">{{ $item->unit }}</td> <td class="text-center">{{ $item->unit }}</td>
<td class="text-center">{{ number_format($item->price,2) }}</td> <td class="text-center text-success fw-bold">{{ number_format($item->price,2) }}</td>
<td class="text-center fw-bold text-primary">{{ number_format($item->ttl_amount,2) }}</td> <td class="text-center text-primary fw-bold">{{ number_format($item->ttl_amount,2) }}</td>
<td class="text-center">{{ $item->cbm }}</td> <td class="text-center">{{ $item->cbm }}</td>
<td class="text-center">{{ $item->ttl_cbm }}</td> <td class="text-center">{{ $item->ttl_cbm }}</td>
<td class="text-center">{{ $item->kg }}</td> <td class="text-center">{{ $item->kg }}</td>
<td class="text-center">{{ $item->ttl_kg }}</td> <td class="text-center">{{ $item->ttl_kg }}</td>
<td class="text-center">{{ $item->shop_no }}</td> <td class="text-center">
<span class="badge bg-light text-dark border">{{ $item->shop_no }}</span>
</td>
</tr> </tr>
@endforeach @endforeach
</tbody> </tbody>
</table> </table>
</div> </div>
</div> </div>
</div>
<!-- ============================ <!-- ============================
FINAL SUMMARY FINAL SUMMARY
============================ --> ============================ -->
<div class="row"> <div class="row">
<div class="col-md-6 offset-md-6"> <div class="col-md-6 offset-md-6">
<div class="card summary-card">
<div class="card border-0 bg-light"> <div class="card-header summary-header">
<h6 class="mb-0 fw-bold">
<div class="card-header bg-dark text-white py-2"> <i class="fas fa-calculator me-2"></i> Final Summary
<h6 class="fw-bold mb-0"><i class="fas fa-calculator me-2"></i> Final Summary</h6> </h6>
</div> </div>
<div class="card-body"> <div class="card-body">
<div class="d-flex justify-content-between align-items-center mb-2 pb-1 border-bottom">
<div class="d-flex justify-content-between mb-2 border-bottom pb-1">
<span class="fw-semibold">Amount:</span> <span class="fw-semibold">Amount:</span>
<span class="fw-bold">{{ number_format($invoice->final_amount, 2) }}</span> <span class="fw-bold text-dark">{{ number_format($invoice->final_amount,2) }}</span>
</div> </div>
@if($invoice->tax_type === 'gst') @if($invoice->tax_type === 'gst')
{{-- CGST --}} {{-- CGST --}}
<div class="d-flex justify-content-between mb-2 border-bottom pb-1"> <div class="d-flex justify-content-between align-items-center mb-2 pb-1 border-bottom">
<span class="fw-semibold">CGST ({{ $invoice->cgst_percent }}%):</span> <span class="fw-semibold">CGST ({{ $invoice->cgst_percent ?? ($invoice->gst_percent/2) }}%):</span>
<span class="fw-bold text-danger">{{ number_format($invoice->gst_amount/2, 2) }}</span> <span class="fw-bold text-danger">{{ number_format($invoice->gst_amount/2, 2) }}</span>
</div> </div>
{{-- SGST --}} {{-- SGST --}}
<div class="d-flex justify-content-between mb-2 border-bottom pb-1"> <div class="d-flex justify-content-between align-items-center mb-2 pb-1 border-bottom">
<span class="fw-semibold">SGST ({{ $invoice->sgst_percent }}%):</span> <span class="fw-semibold">SGST ({{ $invoice->sgst_percent ?? ($invoice->gst_percent/2) }}%):</span>
<span class="fw-bold text-danger">{{ number_format($invoice->gst_amount/2, 2) }}</span> <span class="fw-bold text-danger">{{ number_format($invoice->gst_amount/2, 2) }}</span>
</div> </div>
@elseif($invoice->tax_type === 'igst') @elseif($invoice->tax_type === 'igst')
{{-- IGST --}} {{-- IGST --}}
<div class="d-flex justify-content-between mb-2 border-bottom pb-1"> <div class="d-flex justify-content-between align-items-center mb-2 pb-1 border-bottom">
<span class="fw-semibold">IGST ({{ $invoice->igst_percent }}%):</span> <span class="fw-semibold">IGST ({{ $invoice->igst_percent ?? $invoice->gst_percent }}%):</span>
<span class="fw-bold text-danger">{{ number_format($invoice->gst_amount, 2) }}</span>
</div>
@else
{{-- Default GST --}}
<div class="d-flex justify-content-between align-items-center mb-2 pb-1 border-bottom">
<span class="fw-semibold">GST ({{ $invoice->gst_percent }}%):</span>
<span class="fw-bold text-danger">{{ number_format($invoice->gst_amount, 2) }}</span> <span class="fw-bold text-danger">{{ number_format($invoice->gst_amount, 2) }}</span>
</div> </div>
@endif @endif
<div class="d-flex justify-content-between pt-1"> <div class="d-flex justify-content-between align-items-center pt-1">
<span class="fw-bold text-dark">Total Payable:</span> <span class="fw-bold text-dark">Total Payable:</span>
<span class="fw-bold text-success">{{ number_format($invoice->final_amount_with_gst,2) }}</span> <span class="fw-bold text-success">{{ number_format($invoice->final_amount_with_gst,2) }}</span>
</div> </div>
</div>
</div>
</div> </div>
</div> </div>
</div>
</div>
<!-- ============================ <!-- ============================
FOOTER DOWNLOAD & SHARE FOOTER DOWNLOAD & SHARE
============================ --> ============================ -->
<div class="modal-footer"> <div class="mt-4 pt-3 border-top text-center">
@if($invoice->pdf_path) @if($invoice->pdf_path)
<a href="{{ asset($invoice->pdf_path) }}" class="btn btn-primary" download> <a href="{{ asset($invoice->pdf_path) }}" class="btn btn-primary me-2" download>
<i class="bi bi-download me-1"></i> Download PDF <i class="fas fa-download me-1"></i> Download PDF
</a> </a>
<button class="btn btn-success" onclick="shareInvoice()"> <button class="btn btn-success" onclick="shareInvoice()">
<i class="bi bi-share me-1"></i> Share <i class="fas fa-share me-1"></i> Share
</button> </button>
@endif @endif
<!-- <button class="btn btn-secondary" data-bs-dismiss="modal">Close</button> -->
</div> </div>
<!-- Footer Message -->
<div class="mt-4 pt-3 border-top text-center text-muted">
<p class="mb-1">Thank you for your business!</p>
<p class="mb-0">For any inquiries, contact us at support@Kent Logistic</p>
</div>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/js/bootstrap.bundle.min.js"></script>
<!-- ============================ <!-- ============================
SHARE SCRIPT SHARE SCRIPT
@@ -278,3 +616,5 @@ function shareInvoice() {
} }
} }
</script> </script>
</body>
</html>

File diff suppressed because it is too large Load Diff

View File

@@ -38,12 +38,11 @@
display: inline-flex; display: inline-flex;
align-items: center; align-items: center;
font-size: 13.5px; font-size: 13.5px;
padding: 4px 16px 4px 11px; padding: 6px 16px;
border-radius: 12px; border-radius: 12px;
font-weight: 500; font-weight: 600;
gap: 6px;
box-shadow: 0 1px 2px 0 rgba(130,130,130,0.15); box-shadow: 0 1px 2px 0 rgba(130,130,130,0.15);
min-width: 76px; width: 90px;
min-height: 28px; min-height: 28px;
justify-content: center; justify-content: center;
color: #fff; color: #fff;
@@ -53,18 +52,9 @@
.priority-badge:hover { .priority-badge:hover {
transform: scale(1.08); transform: scale(1.08);
} }
.priority-high { background: linear-gradient(135deg, #ff8a8a, #d12929); color: #fff; } .priority-high { background: linear-gradient(135deg, #ff8a8a, #d12929); }
.priority-medium { background: linear-gradient(135deg, #ffe390, #f5b041); color: #fff; } .priority-medium { background: linear-gradient(135deg, #ffe390, #f5b041); }
.priority-low { background: linear-gradient(135deg, #b8f0c2, #1d8660); color: #fff; } .priority-low { background: linear-gradient(135deg, #b8f0c2, #1d8660); }
.priority-badge .icon {
margin-right: 5px;
font-size: 1.1em;
line-height: 1;
display:inline-block;
width: 17px;
text-align: center;
}
/* 🎨 Table Header (keep original bg-light color) */ /* 🎨 Table Header (keep original bg-light color) */
.custom-table thead th { .custom-table thead th {
@@ -75,7 +65,7 @@
font-size: 17px; font-size: 17px;
letter-spacing: 0.5px; letter-spacing: 0.5px;
border-bottom: 2px solid #bfbfbf; border-bottom: 2px solid #bfbfbf;
background-color: #fde4b3 /* Bootstrap bg-light */ background-color: #fde4b3; /* Bootstrap bg-light */
} }
/* 🟢 Rounded Corners for Header */ /* 🟢 Rounded Corners for Header */
@@ -118,11 +108,87 @@
background: #fff; background: #fff;
} }
/* ⚡ Status Badges */ /* ⚡ Status Badges - NEW ATTRACTIVE STYLES */
.badge { .badge {
font-size: 13px; font-size: 11px !important;
padding: 7px 12px; font-weight: 600 !important;
border-radius: 10px; padding: 7px 13px !important;
border-radius: 20px !important;
text-transform: uppercase;
letter-spacing: 0.3px;
display: inline-flex !important;
align-items: center;
justify-content: center;
background-size: cover !important;
background-position: center !important;
color: #fff !important;
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.3);
border: 2px solid transparent !important;
box-sizing: border-box;
line-height: 1.2;
gap: 6px;
animation: pulse 2s infinite;
width: 99px;
}
/* Status icons */
.status-icon {
font-size: 0px;
display: flex;
align-items: center;
justify-content: center;
}
/* Custom status badge backgrounds */
.badge-pending {
background: url('/images/status-bg-pending.png') !important;
}
.badge-approved {
background: url('/images/status-bg-approved.png') !important;
}
.badge-rejected {
background: url('/images/status-bg-rejected.png') !important;
}
/* Fallback colors if images don't load */
.badge.badge-pending {
background: linear-gradient(135deg, #fef3c7, #fde68a) !important;
color: #d97706 !important;
border-color: #f59e0b !important;
width: 85px;
}
.badge.badge-approved {
background: linear-gradient(135deg, #d1fae5, #a7f3d0) !important;
color: #065f46 !important;
border-color: #10b981 !important;
width: 85px;
}
.badge.badge-rejected {
background: linear-gradient(135deg, #fecaca, #fca5a5) !important;
color: #991b1b !important;
border-color: #ef4444 !important;
width: 85px;
}
/* Animation effects for badges */
@keyframes pulse {
0% { box-shadow: 0 0 8px rgba(0,0,0,0.1); }
50% { box-shadow: 0 0 14px rgba(0,0,0,0.15); }
100% { box-shadow: 0 0 8px rgba(0,0,0,0.1); }
}
/* Count badges at top */
.count-badge {
--bs-badge-padding-x: 0.65em;
--bs-badge-padding-y: 0.35em;
--bs-badge-font-size: 0.75em;
--bs-badge-font-weight: 700;
--bs-badge-color: #fff;
--bs-badge-border-radius: var(--bs-border-radius);
} }
/* ✨ Heading style */ /* ✨ Heading style */
@@ -145,13 +211,13 @@
<div class="d-flex justify-content-between align-items-center mb-2 mt-3"> <div class="d-flex justify-content-between align-items-center mb-2 mt-3">
<h4 class="fw-bold mb-0">User Requests</h4> <h4 class="fw-bold mb-0">User Requests</h4>
<div> <div>
<span class="badge rounded-pill bg-primary me-1"> <span class="count-badge badge rounded-pill bg-warning text-dark me-1">
{{ $requests->where('status', 'pending')->count() }} Pending {{ $requests->where('status', 'pending')->count() }} Pending
</span> </span>
<span class="badge rounded-pill bg-success me-1"> <span class="count-badge badge rounded-pill bg-success me-1">
{{ $requests->where('status', 'approved')->count() }} Approved {{ $requests->where('status', 'approved')->count() }} Approved
</span> </span>
<span class="badge rounded-pill bg-danger"> <span class="count-badge badge rounded-pill bg-danger">
{{ $requests->where('status', 'rejected')->count() }} Rejected {{ $requests->where('status', 'rejected')->count() }} Rejected
</span> </span>
</div> </div>
@@ -195,11 +261,11 @@
<td>{{ $req->address }}</td> <td>{{ $req->address }}</td>
<td> <td>
@if(strtolower($req->priority) == 'high') @if(strtolower($req->priority) == 'high')
<span class="priority-badge priority-high"><span class="icon">🔥</span>High</span> <span class="priority-badge priority-high">High</span>
@elseif(strtolower($req->priority) == 'medium') @elseif(strtolower($req->priority) == 'medium')
<span class="priority-badge priority-medium"><span class="icon"></span>Medium</span> <span class="priority-badge priority-medium">Medium</span>
@elseif(strtolower($req->priority) == 'low') @elseif(strtolower($req->priority) == 'low')
<span class="priority-badge priority-low"><span class="icon">🟢</span>Low</span> <span class="priority-badge priority-low">Low</span>
@else @else
{{ $req->priority }} {{ $req->priority }}
@endif @endif
@@ -207,11 +273,20 @@
<td>{{ $req->date }}</td> <td>{{ $req->date }}</td>
<td> <td>
@if($req->status == 'approved') @if($req->status == 'approved')
<span class="badge bg-success">Approved</span> <span class="badge badge-approved">
<i class="bi bi-check-circle-fill status-icon"></i>
Approved
</span>
@elseif($req->status == 'rejected') @elseif($req->status == 'rejected')
<span class="badge bg-danger">Rejected</span> <span class="badge badge-rejected">
<i class="bi bi-x-circle-fill status-icon"></i>
Rejected
</span>
@else @else
<span class="badge bg-warning text-dark">Pending</span> <span class="badge badge-pending">
<i class="bi bi-clock-fill status-icon"></i>
Pending
</span>
@endif @endif
</td> </td>
<td>N/A</td> <td>N/A</td>

View File

@@ -87,9 +87,10 @@ Route::prefix('admin')
// --------------------------- // ---------------------------
// ORDERS // ORDERS
// --------------------------- // ---------------------------
Route::get('/orders', fn() => view('admin.orders')) Route::get('/orders', [AdminOrderController::class, 'orderShow'])
->name('admin.orders'); ->name('admin.orders');
Route::get('/orders/list', [AdminOrderController::class, 'index']) Route::get('/orders/list', [AdminOrderController::class, 'index'])
->name('admin.orders.index'); ->name('admin.orders.index');