Frontend dashboard, shipment, invoice , customer

This commit is contained in:
divya abdar
2025-12-01 10:38:52 +05:30
parent 97db70c40e
commit aa616fcf61
15 changed files with 4280 additions and 2509 deletions

View File

@@ -7,28 +7,123 @@ use Illuminate\Http\Request;
use App\Models\Order; use App\Models\Order;
use App\Models\OrderItem; use App\Models\OrderItem;
use App\Models\MarkList; use App\Models\MarkList;
use App\Models\Invoice;
use App\Models\InvoiceItem;
use App\Models\User;
class AdminOrderController extends Controller class AdminOrderController extends Controller
{ {
// ---------------------------
// LIST / DASHBOARD
// ---------------------------
public function index() public function index()
{ {
// raw list for admin dashboard (simple)
$orders = Order::latest()->get(); $orders = Order::latest()->get();
$markList = MarkList::where('status', 'active')->get(); $markList = MarkList::where('status', 'active')->get();
return view('admin.dashboard', compact('orders', 'markList')); return view('admin.dashboard', compact('orders', 'markList'));
} }
// ------------------------------------------------------------------------- /**
// STEP 1 : ADD TEMPORARY ITEM * Orders list (detailed)
// ------------------------------------------------------------------------- */
public function orderShow()
public function addTempItem(Request $request)
{ {
// Validate item fields $orders = Order::with(['markList', 'shipments', 'invoice'])
$item = $request->validate([ ->latest('id')
'mark_no' => 'required', ->get();
'origin' => 'required',
'destination' => 'required', return view('admin.orders', compact('orders'));
}
// ---------------------------
// CREATE NEW ORDER (simple DB flow)
// ---------------------------
/**
* Show create form (you can place create UI on separate view or dashboard)
*/
public function create()
{
// return a dedicated create view - create it at resources/views/admin/orders_create.blade.php
// If you prefer create UI on dashboard, change this to redirect route('admin.orders.index') etc.
$markList = MarkList::where('status', 'active')->get();
return view('admin.orders_create', compact('markList'));
}
/**
* Store a new order and optionally create initial invoice
*/
public function store(Request $request)
{
$data = $request->validate([
'mark_no' => 'required|string',
'origin' => 'nullable|string',
'destination' => 'nullable|string',
// totals optional when creating without items
'ctn' => 'nullable|numeric',
'qty' => 'nullable|numeric',
'ttl_qty' => 'nullable|numeric',
'ttl_amount' => 'nullable|numeric',
'cbm' => 'nullable|numeric',
'ttl_cbm' => 'nullable|numeric',
'kg' => 'nullable|numeric',
'ttl_kg' => 'nullable|numeric',
]);
$order = Order::create([
'order_id' => $this->generateOrderId(),
'mark_no' => $data['mark_no'],
'origin' => $data['origin'] ?? null,
'destination' => $data['destination'] ?? null,
'ctn' => $data['ctn'] ?? 0,
'qty' => $data['qty'] ?? 0,
'ttl_qty' => $data['ttl_qty'] ?? 0,
'ttl_amount' => $data['ttl_amount'] ?? 0,
'cbm' => $data['cbm'] ?? 0,
'ttl_cbm' => $data['ttl_cbm'] ?? 0,
'kg' => $data['kg'] ?? 0,
'ttl_kg' => $data['ttl_kg'] ?? 0,
'status' => 'pending',
]);
// If you want to auto-create an invoice at order creation, uncomment:
// $this->createInvoice($order);
return redirect()->route('admin.orders.show', $order->id)
->with('success', 'Order created successfully.');
}
// ---------------------------
// SHOW / POPUP
// ---------------------------
public function show($id)
{
$order = Order::with('items', 'markList')->findOrFail($id);
$user = $this->getCustomerFromOrder($order);
return view('admin.orders_show', compact('order', 'user'));
}
public function popup($id)
{
$order = Order::with(['items', 'markList'])->findOrFail($id);
$user = $this->getCustomerFromOrder($order);
return view('admin.popup', compact('order', 'user'));
}
// ---------------------------
// ORDER ITEM MANAGEMENT (DB)
// ---------------------------
/**
* Add an item to an existing order
*/
public function addItem(Request $request, $orderId)
{
$order = Order::findOrFail($orderId);
$data = $request->validate([
'description' => 'required|string', 'description' => 'required|string',
'ctn' => 'nullable|numeric', 'ctn' => 'nullable|numeric',
'qty' => 'nullable|numeric', 'qty' => 'nullable|numeric',
@@ -43,187 +138,164 @@ class AdminOrderController extends Controller
'shop_no' => 'nullable|string', 'shop_no' => 'nullable|string',
]); ]);
// ❌ Prevent changing mark_no once first item added $data['order_id'] = $order->id;
if (session()->has('mark_no') && session('mark_no') != $request->mark_no) {
return redirect()->to(route('admin.orders.index') . '#createOrderForm') OrderItem::create($data);
->with('error', 'You must finish or clear the current order before changing Mark No.');
// recalc totals and save to order
$this->recalcTotals($order);
return redirect()->back()->with('success', 'Item added and totals updated.');
} }
// Save mark, origin, destination ONLY ONCE /**
if (!session()->has('mark_no')) { * Soft-delete an order item and recalc totals
session([ */
'mark_no' => $request->mark_no, public function deleteItem($id)
'origin' => $request->origin,
'destination' => $request->destination
]);
}
// ❌ DO NOT overwrite these values again
// session(['mark_no' => $request->mark_no]);
// session(['origin' => $request->origin]);
// session(['destination' => $request->destination]);
// Add new sub-item into session
session()->push('temp_order_items', $item);
return redirect()->to(route('admin.orders.index') . '#createOrderForm')
->with('success', 'Item added.');
}
// -------------------------------------------------------------------------
// STEP 2 : DELETE TEMPORARY ITEM
// -------------------------------------------------------------------------
public function deleteTempItem(Request $request)
{ {
$index = $request->index; $item = OrderItem::findOrFail($id);
$order = $item->order;
$items = session('temp_order_items', []); $item->delete(); // soft delete
if (isset($items[$index])) { // recalc totals
unset($items[$index]); $this->recalcTotals($order);
session(['temp_order_items' => array_values($items)]);
return redirect()->back()->with('success', 'Item deleted and totals updated.');
} }
// If no items left → reset mark_no lock /**
if (empty($items)) { * Restore soft-deleted item and recalc totals
session()->forget(['mark_no', 'origin', 'destination']); */
public function restoreItem($id)
{
$item = OrderItem::withTrashed()->findOrFail($id);
$order = Order::findOrFail($item->order_id);
$item->restore();
// recalc totals
$this->recalcTotals($order);
return redirect()->back()->with('success', 'Item restored and totals updated.');
} }
return redirect()->to(route('admin.orders.index') . '#createOrderForm') // ---------------------------
->with('success', 'Item removed successfully.'); // ORDER CRUD: update / destroy
} // ---------------------------
public function update(Request $request, $id)
{
$order = Order::findOrFail($id);
// ------------------------------------------------------------------------- $data = $request->validate([
// STEP 3 : FINISH ORDER 'mark_no' => 'required|string',
// ------------------------------------------------------------------------- 'origin' => 'nullable|string',
'destination' => 'nullable|string',
public function finishOrder(Request $request)
{
$request->validate([
'mark_no' => 'required',
'origin' => 'required',
'destination' => 'required',
]); ]);
$items = session('temp_order_items', []); $order->update([
'mark_no' => $data['mark_no'],
'origin' => $data['origin'] ?? null,
'destination' => $data['destination'] ?? null,
]);
if (empty($items)) { // optionally recalc totals (not necessary unless you change item-level fields here)
return redirect()->to(route('admin.orders.index') . '#createOrderForm') $this->recalcTotals($order);
->with('error', 'Add at least one item before finishing.');
return redirect()->route('admin.orders.show', $order->id)
->with('success', 'Order updated successfully.');
} }
// ======================= /**
// GENERATE ORDER ID * Soft-delete whole order and its items (soft-delete items first then order)
// ======================= */
public function destroy($id)
{
$order = Order::findOrFail($id);
// soft-delete items first (so they show up in onlyTrashed for restore)
OrderItem::where('order_id', $order->id)->delete();
// then soft-delete order
$order->delete();
return redirect()->route('admin.orders.index')
->with('success', 'Order deleted successfully.');
}
// ---------------------------
// HELPERS
// ---------------------------
/**
* Recalculate totals for the order from current (non-deleted) items
*/
private function recalcTotals(Order $order)
{
// make sure we re-query live items (non-deleted)
$items = $order->items()->get();
$order->update([
'ctn' => (int) $items->sum(fn($i) => (int) ($i->ctn ?? 0)),
'qty' => (int) $items->sum(fn($i) => (int) ($i->qty ?? 0)),
'ttl_qty' => (int) $items->sum(fn($i) => (int) ($i->ttl_qty ?? 0)),
'ttl_amount'=> (float) $items->sum(fn($i) => (float) ($i->ttl_amount ?? 0)),
'cbm' => (float) $items->sum(fn($i) => (float) ($i->cbm ?? 0)),
'ttl_cbm' => (float) $items->sum(fn($i) => (float) ($i->ttl_cbm ?? 0)),
'kg' => (float) $items->sum(fn($i) => (float) ($i->kg ?? 0)),
'ttl_kg' => (float) $items->sum(fn($i) => (float) ($i->ttl_kg ?? 0)),
]);
}
/**
* Generate order id (keeps old format)
*/
private function generateOrderId()
{
$year = date('y'); $year = date('y');
$prefix = "KNT-$year-"; $prefix = "KNT-$year-";
$lastOrder = Order::latest('id')->first(); $lastOrder = Order::latest('id')->first();
$nextNumber = $lastOrder ? intval(substr($lastOrder->order_id, -8)) + 1 : 1; $nextNumber = $lastOrder ? intval(substr($lastOrder->order_id, -8)) + 1 : 1;
$orderId = $prefix . str_pad($nextNumber, 8, '0', STR_PAD_LEFT); return $prefix . str_pad($nextNumber, 8, '0', STR_PAD_LEFT);
// =======================
// TOTAL SUMS
// =======================
$total_ctn = array_sum(array_column($items, 'ctn'));
$total_qty = array_sum(array_column($items, 'qty'));
$total_ttl_qty = array_sum(array_column($items, 'ttl_qty'));
$total_amount = array_sum(array_column($items, 'ttl_amount'));
$total_cbm = array_sum(array_column($items, 'cbm'));
$total_ttl_cbm = array_sum(array_column($items, 'ttl_cbm'));
$total_kg = array_sum(array_column($items, 'kg'));
$total_ttl_kg = array_sum(array_column($items, 'ttl_kg'));
// =======================
// CREATE ORDER
// =======================
$order = Order::create([
'order_id' => $orderId,
'mark_no' => $request->mark_no,
'origin' => $request->origin,
'destination' => $request->destination,
'ctn' => $total_ctn,
'qty' => $total_qty,
'ttl_qty' => $total_ttl_qty,
'ttl_amount' => $total_amount,
'cbm' => $total_cbm,
'ttl_cbm' => $total_ttl_cbm,
'kg' => $total_kg,
'ttl_kg' => $total_ttl_kg,
'status' => 'pending',
]);
// SAVE ORDER ITEMS
foreach ($items as $item) {
OrderItem::create([
'order_id' => $order->id,
'description' => $item['description'],
'ctn' => $item['ctn'],
'qty' => $item['qty'],
'ttl_qty' => $item['ttl_qty'],
'unit' => $item['unit'],
'price' => $item['price'],
'ttl_amount' => $item['ttl_amount'],
'cbm' => $item['cbm'],
'ttl_cbm' => $item['ttl_cbm'],
'kg' => $item['kg'],
'ttl_kg' => $item['ttl_kg'],
'shop_no' => $item['shop_no'],
]);
} }
// ======================= // ---------------------------
// INVOICE CREATION START // INVOICE CREATION (optional helper used by store/finish)
// ======================= // ---------------------------
private function createInvoice(Order $order)
{
$invoiceNumber = $this->generateInvoiceNumber();
$customer = $this->getCustomerFromMarkList($order->mark_no);
$totalAmount = $order->ttl_amount;
// 1. Auto-generate invoice number $invoice = Invoice::create([
$lastInvoice = \App\Models\Invoice::latest()->first();
$nextInvoice = $lastInvoice ? $lastInvoice->id + 1 : 1;
$invoiceNumber = 'INV-' . date('Y') . '-' . str_pad($nextInvoice, 6, '0', STR_PAD_LEFT);
// 2. Fetch customer (using mark list → customer_id)
$markList = MarkList::where('mark_no', $order->mark_no)->first();
$customer = null;
if ($markList && $markList->customer_id) {
$customer = \App\Models\User::where('customer_id', $markList->customer_id)->first();
}
// 3. Create Invoice Record
$invoice = \App\Models\Invoice::create([
'order_id' => $order->id, 'order_id' => $order->id,
'customer_id' => $customer->id ?? null, 'customer_id' => $customer->id ?? null,
'mark_no' => $order->mark_no, 'mark_no' => $order->mark_no,
'invoice_number' => $invoiceNumber, 'invoice_number' => $invoiceNumber,
'invoice_date' => now(), 'invoice_date' => now(),
'due_date' => now()->addDays(10), 'due_date' => now()->addDays(10),
'payment_method' => null, 'payment_method' => null,
'reference_no' => null, 'reference_no' => null,
'status' => 'pending', 'status' => 'pending',
'final_amount' => $totalAmount,
'final_amount' => $total_amount,
'gst_percent' => 0, 'gst_percent' => 0,
'gst_amount' => 0, 'gst_amount' => 0,
'final_amount_with_gst' => $total_amount, 'final_amount_with_gst' => $totalAmount,
// snapshot customer fields
'customer_name' => $customer->customer_name ?? null, 'customer_name' => $customer->customer_name ?? null,
'company_name' => $customer->company_name ?? null, 'company_name' => $customer->company_name ?? null,
'customer_email' => $customer->email ?? null, 'customer_email' => $customer->email ?? null,
'customer_mobile' => $customer->mobile_no ?? null, 'customer_mobile' => $customer->mobile_no ?? null,
'customer_address' => $customer->address ?? null, 'customer_address' => $customer->address ?? null,
'pincode' => $customer->pincode ?? null, 'pincode' => $customer->pincode ?? null,
'notes' => null, 'notes' => null,
'pdf_path' => null,
]); ]);
// 4. Clone order items into invoice_items // clone order items into invoice items
foreach ($order->items as $item) { foreach ($order->items as $item) {
\App\Models\InvoiceItem::create([ InvoiceItem::create([
'invoice_id' => $invoice->id, 'invoice_id' => $invoice->id,
'description' => $item->description, 'description' => $item->description,
'ctn' => $item->ctn, 'ctn' => $item->ctn,
@@ -239,75 +311,33 @@ class AdminOrderController extends Controller
'shop_no' => $item->shop_no, 'shop_no' => $item->shop_no,
]); ]);
} }
}
// 5. TODO: PDF generation (I will add this later) private function generateInvoiceNumber()
$invoice->pdf_path = null; // placeholder for now
$invoice->save();
// =======================
// END INVOICE CREATION
// =======================
// CLEAR TEMP DATA
session()->forget(['temp_order_items', 'mark_no', 'origin', 'destination']);
return redirect()->route('admin.orders.index')
->with('success', 'Order + Invoice created successfully.');
}
// -------------------------------------------------------------------------
// ORDER SHOW PAGE
// -------------------------------------------------------------------------
public function show($id)
{ {
$order = Order::with('items', 'markList')->findOrFail($id); $lastInvoice = Invoice::latest()->first();
$nextInvoice = $lastInvoice ? $lastInvoice->id + 1 : 1;
$user = null; return 'INV-' . date('Y') . '-' . str_pad($nextInvoice, 6, '0', STR_PAD_LEFT);
}
private function getCustomerFromMarkList($markNo)
{
$markList = MarkList::where('mark_no', $markNo)->first();
if ($markList && $markList->customer_id) {
return User::where('customer_id', $markList->customer_id)->first();
}
return null;
}
private function getCustomerFromOrder($order)
{
if ($order->markList && $order->markList->customer_id) { if ($order->markList && $order->markList->customer_id) {
$user = \App\Models\User::where('customer_id', $order->markList->customer_id)->first(); return User::where('customer_id', $order->markList->customer_id)->first();
} }
return view('admin.orders_show', compact('order', 'user')); return null;
} }
public function popup($id)
{
// Load order with items + markList
$order = Order::with(['items', 'markList'])->findOrFail($id);
// Fetch user based on markList customer_id (same as show method)
$user = null;
if ($order->markList && $order->markList->customer_id) {
$user = \App\Models\User::where('customer_id', $order->markList->customer_id)->first();
}
return view('admin.popup', compact('order', 'user'));
}
public function resetTemp()
{
session()->forget(['temp_order_items', 'mark_no', 'origin', 'destination']);
return redirect()->to(route('admin.orders.index') . '#createOrderForm')
->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

@@ -29,8 +29,6 @@ class ShipmentController extends Controller
return view('admin.shipments', compact('availableOrders', 'shipments')); return view('admin.shipments', compact('availableOrders', 'shipments'));
} }
/** /**
* Store new shipment * Store new shipment
*/ */
@@ -115,8 +113,6 @@ class ShipmentController extends Controller
return redirect()->back()->with('success', "Shipment $newShipmentId created successfully!"); return redirect()->back()->with('success', "Shipment $newShipmentId created successfully!");
} }
/** /**
* Show shipment details (for modal popup) * Show shipment details (for modal popup)
*/ */
@@ -135,8 +131,6 @@ class ShipmentController extends Controller
]); ]);
} }
/** /**
* Update Shipment status from action button * Update Shipment status from action button
*/ */
@@ -164,5 +158,55 @@ class ShipmentController extends Controller
); );
} }
/**
* Update shipment details
*/
public function update(Request $request, $id)
{
$shipment = Shipment::findOrFail($id);
$data = $request->validate([
'origin' => 'required|string',
'destination' => 'required|string',
'shipment_date' => 'required|date',
'status' => 'required|string',
]);
$shipment->update($data);
// If it's an AJAX request, return JSON response
if ($request->ajax() || $request->wantsJson()) {
return response()->json([
'success' => true,
'message' => 'Shipment updated successfully.'
]);
}
return redirect()->back()->with('success', 'Shipment updated successfully.');
}
/**
* Delete shipment permanently
*/
public function destroy($id, Request $request)
{
$shipment = Shipment::findOrFail($id);
// Delete shipment items
ShipmentItem::where('shipment_id', $shipment->id)->delete();
// Delete shipment itself
$shipment->delete();
// If it's an AJAX request, return JSON response
if ($request->ajax() || $request->wantsJson()) {
return response()->json([
'success' => true,
'message' => 'Shipment deleted successfully.'
]);
}
return redirect()->route('admin.shipments')
->with('success', 'Shipment deleted successfully.');
}
} }

View File

@@ -4,10 +4,12 @@ namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
class Order extends Model class Order extends Model
{ {
use HasFactory; use HasFactory,SoftDeletes;
protected $fillable = [ protected $fillable = [
'order_id', 'order_id',

View File

@@ -4,10 +4,11 @@ namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
class OrderItem extends Model class OrderItem extends Model
{ {
use HasFactory; use HasFactory, SoftDeletes;
protected $fillable = [ protected $fillable = [
'order_id', 'order_id',

View File

@@ -8,23 +8,16 @@ return new class extends Migration
{ {
public function up(): void public function up(): void
{ {
Schema::create('invoice_installments', function (Blueprint $table) { // Table already exists. Add updates here if needed.
$table->id(); Schema::table('invoice_installments', function (Blueprint $table) {
// nothing to update
$table->unsignedBigInteger('invoice_id');
$table->foreign('invoice_id')->references('id')->on('invoices')->onDelete('cascade');
$table->date('installment_date');
$table->string('payment_method')->nullable(); // cash, bank, UPI, cheque, etc
$table->string('reference_no')->nullable();
$table->decimal('amount', 10, 2);
$table->timestamps();
}); });
} }
public function down(): void public function down(): void
{ {
Schema::dropIfExists('invoice_installments'); Schema::table('invoice_installments', function (Blueprint $table) {
// nothing to rollback
});
} }
}; };

View File

@@ -0,0 +1,22 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
Schema::table('order_items', function (Blueprint $table) {
$table->softDeletes();
});
}
public function down(): void
{
Schema::table('order_items', function (Blueprint $table) {
$table->dropSoftDeletes();
});
}
};

View File

@@ -0,0 +1,26 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
Schema::table('order_items', function (Blueprint $table) {
if (! Schema::hasColumn('order_items', 'deleted_at')) {
$table->softDeletes(); // adds deleted_at (nullable timestamp)
}
});
}
public function down(): void
{
Schema::table('order_items', function (Blueprint $table) {
if (Schema::hasColumn('order_items', 'deleted_at')) {
$table->dropSoftDeletes(); // drops deleted_at
}
});
}
};

View File

@@ -5,6 +5,14 @@
@section('content') @section('content')
<style> <style>
/* Import Inter font */
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap');
body {
font-family: 'Inter', sans-serif;
overflow-x: hidden; /* Prevent horizontal scroll on body */
}
.glass-card { .glass-card {
background: rgba(255, 255, 255, 0.95); background: rgba(255, 255, 255, 0.95);
backdrop-filter: blur(20px); backdrop-filter: blur(20px);
@@ -14,71 +22,171 @@
overflow: hidden; overflow: hidden;
} }
.stats-card { /* New Stats Container */
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); .stats-container {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
gap: 12px;
margin: 20px 0;
}
.stat-card {
background: linear-gradient(135deg, #f8f9ff 0%, #f0f4ff 100%);
padding: 16px;
border-radius: 12px; border-radius: 12px;
padding: 15px; border-left: 4px solid #4f46e5;
color: white; box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
position: relative;
overflow: hidden;
transition: transform 0.3s ease; transition: transform 0.3s ease;
min-height: 80px; display: flex;
align-items: center;
gap: 12px;
min-height: 70px;
} }
.stats-card:hover { .stat-card:hover {
transform: translateY(-3px); transform: translateY(-2px);
} }
.stats-count { .stat-card.warning {
font-size: 1.4rem; border-left-color: #f59e0b;
background: linear-gradient(135deg, #fffbeb 0%, #fef3c7 100%);
}
.stat-card.success {
border-left-color: #10b981;
background: linear-gradient(135deg, #ecfdf5 0%, #d1fae5 100%);
}
.stat-card.danger {
border-left-color: #ef4444;
background: linear-gradient(135deg, #fef2f2 0%, #fee2e2 100%);
}
.stat-card.info {
border-left-color: #3b82f6;
background: linear-gradient(135deg, #eff6ff 0%, #dbeafe 100%);
}
.stat-card.secondary {
border-left-color: #8b5cf6;
background: linear-gradient(135deg, #faf5ff 0%, #f3e8ff 100%);
}
.stat-icon {
width: 45px;
height: 45px;
border-radius: 10px;
display: flex;
align-items: center;
justify-content: center;
background: rgba(79, 70, 229, 0.1);
flex-shrink: 0;
}
.stat-icon i {
font-size: 18px;
color: #4f46e5;
}
.stat-card.warning .stat-icon {
background: rgba(245, 158, 11, 0.1);
}
.stat-card.warning .stat-icon i {
color: #f59e0b;
}
.stat-card.success .stat-icon {
background: rgba(16, 185, 129, 0.1);
}
.stat-card.success .stat-icon i {
color: #10b981;
}
.stat-card.danger .stat-icon {
background: rgba(239, 68, 68, 0.1);
}
.stat-card.danger .stat-icon i {
color: #ef4444;
}
.stat-card.info .stat-icon {
background: rgba(59, 130, 246, 0.1);
}
.stat-card.info .stat-icon i {
color: #3b82f6;
}
.stat-card.secondary .stat-icon {
background: rgba(139, 92, 246, 0.1);
}
.stat-card.secondary .stat-icon i {
color: #8b5cf6;
}
.stat-content {
flex: 1;
}
.stat-value {
font-size: 22px;
font-weight: 700; font-weight: 700;
color: #1a202c;
line-height: 1.2;
margin-bottom: 2px; margin-bottom: 2px;
} }
.stats-label { .stat-label {
font-size: 0.75rem; font-size: 12px;
opacity: 0.9; color: #718096;
font-weight: 500; font-weight: 500;
line-height: 1.3;
} }
.stats-icon { /* Updated Search Container - Wider with icon on left */
position: absolute;
top: 12px;
right: 12px;
font-size: 1.2rem;
opacity: 0.7;
}
.search-container { .search-container {
background: rgba(255, 255, 255, 0.9); background: rgba(255, 255, 255, 0.9);
border-radius: 10px; border-radius: 10px;
padding: 8px 15px; padding: 6px 12px;
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%; width: 350px; /* Increased width */
display: flex;
align-items: center;
} }
.search-input { .search-input {
border: none; border: none;
background: transparent; background: transparent;
padding: 5px 10px; padding: 4px 8px;
width: 100%; width: 100%;
font-size: 14px; font-size: 13px;
outline: none; outline: none;
font-family: 'Inter', sans-serif;
}
.search-input::placeholder {
color: #9ca3af;
font-size: 13px;
} }
.filter-btn { .filter-btn {
background: rgba(102, 126, 234, 0.1); background: rgba(102, 126, 234, 0.1);
border: 2px solid transparent; border: 2px solid transparent;
color: #667eea; color: #667eea;
padding: 6px 15px; padding: 5px 12px;
border-radius: 8px; border-radius: 8px;
font-weight: 600; font-weight: 600;
transition: all 0.3s ease; transition: all 0.3s ease;
margin: 0 5px; margin: 0 3px;
text-decoration: none; text-decoration: none;
display: inline-block; display: inline-block;
font-size: 0.8rem; font-size: 0.75rem;
font-family: 'Inter', sans-serif;
} }
.filter-btn.active { .filter-btn.active {
@@ -91,45 +199,106 @@
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
border: none; border: none;
border-radius: 8px; border-radius: 8px;
padding: 8px 20px; padding: 6px 16px;
color: white; color: white;
font-weight: 600; font-weight: 600;
box-shadow: 0 4px 15px rgba(102, 126, 234, 0.4); box-shadow: 0 4px 15px rgba(102, 126, 234, 0.4);
transition: all 0.3s ease; transition: all 0.3s ease;
text-decoration: none; text-decoration: none;
display: inline-block; display: inline-block;
font-size: 0.8rem; font-size: 0.75rem;
font-family: 'Inter', sans-serif;
} }
/* Updated Table Styles - Fixed horizontal scroll */
.table-glass { .table-glass {
background: rgba(255, 255, 255, 0.9); background: rgba(255, 255, 255, 0.9);
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);
font-family: 'Inter', sans-serif;
}
/* Single gradient for entire header - Blue to Purple */
.table thead {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%) !important;
} }
.table-header { .table-header {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%) !important;
color: white !important; color: white !important;
font-weight: 600; font-weight: 600;
font-size: 0.9rem; font-size: 0.85rem;
padding: 12px 15px !important; padding: 14px 12px !important;
position: relative;
border: none; border: none;
font-family: 'Inter', sans-serif;
position: relative;
background: linear-gradient(135deg, #667eea 0%);;
} }
/* Curved borders for table headers */ /* Remove individual curved borders */
.table-header:first-child { .table-header:first-child {
border-top-left-radius: 10px; border-top-left-radius: 0;
} }
.table-header:last-child { .table-header:last-child {
border-top-right-radius: 0;
}
/* Apply rounded corners to the entire header container */
.table-container thead tr:first-child th:first-child {
border-top-left-radius: 10px;
}
.table-container thead tr:first-child th:last-child {
border-top-right-radius: 10px; border-top-right-radius: 10px;
} }
/* Updated Table Column Alignment */
.table > :not(caption) > * > * { .table > :not(caption) > * > * {
padding: 12px 15px; padding: 14px 12px;
border-bottom: 1px solid rgba(0, 0, 0, 0.05); border-bottom: 1px solid rgba(0, 0, 0, 0.05);
font-size: 14px;
font-family: 'Inter', sans-serif;
vertical-align: middle;
}
/* Center align specific columns */
.table > :not(caption) > * > *:nth-child(2), /* Customer ID */
.table > :not(caption) > * > *:nth-child(3), /* Orders */
.table > :not(caption) > * > *:nth-child(4), /* Total */
.table > :not(caption) > * > *:nth-child(5) { /* Create Date */
text-align: center;
}
/* Customer Info column should remain left-aligned */
.table > :not(caption) > * > *:first-child {
text-align: left;
}
/* Status and Actions columns should remain as is */
.table > :not(caption) > * > *:nth-child(6), /* Status */
.table > :not(caption) > * > *:nth-child(7) { /* Actions */
text-align: center;
}
/* Updated header alignment to match */
.table-header:nth-child(2),
.table-header:nth-child(3),
.table-header:nth-child(4),
.table-header:nth-child(5) {
text-align: center;
}
/* Customer Info header stays left */
.table-header:first-child {
text-align: Center;
}
/* Status and Actions headers stay centered */
.table-header:nth-child(6),
.table-header:nth-child(7) {
text-align: center;
} }
.customer-avatar { .customer-avatar {
@@ -165,7 +334,7 @@
} }
.status-badge { .status-badge {
padding: 4px 10px; padding: 5px 10px;
border-radius: 8px; border-radius: 8px;
font-size: 0.75rem; font-size: 0.75rem;
font-weight: 600; font-weight: 600;
@@ -203,15 +372,9 @@
transform: scale(1.05); transform: scale(1.05);
} }
.stats-row {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
gap: 12px;
margin-bottom: 20px;
}
.customer-info-column { .customer-info-column {
min-width: 300px; min-width: 220px;
max-width: 220px; /* Added max-width to prevent overflow */
} }
.table tbody tr { .table tbody tr {
@@ -228,44 +391,28 @@
color: #6c757d; color: #6c757d;
} }
.customer-stats { /* Remove customer-stats since we're adding columns */
font-size: 0.75rem;
color: #6c757d;
}
/* Enhanced table styling */ /* Enhanced table styling - Fixed horizontal scroll */
.table-container { .table-container {
border-radius: 10px; border-radius: 10px;
overflow: hidden; overflow: hidden;
width: 100%; /* Ensure container takes full width */
} }
.table-header-container { /* Fix table responsiveness */
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
border-radius: 10px 10px 0 0;
overflow: hidden;
}
/* Remove horizontal scroll */
.table-responsive { .table-responsive {
overflow-x: visible !important; overflow-x: auto;
-webkit-overflow-scrolling: touch;
width: 100%;
} }
.container-fluid { /* Ensure table doesn't exceed container */
overflow-x: hidden;
}
/* Adjust table layout to fit without scroll */
.table { .table {
width: 100%; width: 100%;
min-width: auto; max-width: 100%;
} margin-bottom: 0;
table-layout: auto; /* Changed to auto for better column distribution */
/* Ensure proper column sizing */
.table th,
.table td {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
} }
/* Fix for search and filter section */ /* Fix for search and filter section */
@@ -275,21 +422,43 @@
justify-content: space-between; justify-content: space-between;
flex-wrap: nowrap; flex-wrap: nowrap;
gap: 15px; gap: 15px;
width: 100%;
} }
.search-section { .search-section {
flex: 1; display: flex;
min-width: 300px; align-items: center;
flex-shrink: 0;
} }
.filter-section { .filter-section {
display: flex; display: flex;
align-items: center; align-items: center;
flex-wrap: nowrap; flex-wrap: nowrap;
gap: 8px; gap: 6px;
flex-shrink: 0;
} }
/* ---------- Pagination Styles (Same as Account Dashboard) ---------- */ /* New columns styling */
.orders-column, .total-column, .customer-id-column, .create-date-column {
text-align: center;
font-weight: 500;
min-width: 80px; /* Added minimum widths for consistency */
}
.orders-count {
font-size: 14px;
color: #1a202c;
font-weight: 600;
}
.total-amount {
font-size: 14px;
color: #10b981;
font-weight: 600;
}
/* ---------- Pagination Styles ---------- */
.pagination-container { .pagination-container {
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
@@ -297,18 +466,23 @@
margin-top: 15px; margin-top: 15px;
padding: 12px 0; padding: 12px 0;
border-top: 1px solid #eef3fb; border-top: 1px solid #eef3fb;
font-family: 'Inter', sans-serif;
width: 100%;
} }
.pagination-info { .pagination-info {
font-size: 13px; font-size: 13px;
color: #9ba5bb; color: #9ba5bb;
font-weight: 600; font-weight: 600;
flex-shrink: 0;
} }
.pagination-controls { .pagination-controls {
display: flex; display: flex;
align-items: center; align-items: center;
gap: 8px; gap: 8px;
flex-wrap: wrap;
justify-content: flex-end;
} }
.pagination-btn { .pagination-btn {
@@ -354,6 +528,8 @@
transition: all 0.3s ease; transition: all 0.3s ease;
min-width: 36px; min-width: 36px;
text-align: center; text-align: center;
text-decoration: none;
display: inline-block;
} }
.pagination-page-btn:hover { .pagination-page-btn:hover {
@@ -372,6 +548,7 @@
display: flex; display: flex;
gap: 4px; gap: 4px;
align-items: center; align-items: center;
flex-wrap: wrap;
} }
.pagination-ellipsis { .pagination-ellipsis {
@@ -422,14 +599,46 @@
filter: brightness(0) saturate(100%) invert(84%) sepia(8%) saturate(165%) hue-rotate(179deg) brightness(89%) contrast(86%); filter: brightness(0) saturate(100%) invert(84%) sepia(8%) saturate(165%) hue-rotate(179deg) brightness(89%) contrast(86%);
} }
/* Mobile responsive fixes */
@media (max-width: 1200px) {
.table > :not(caption) > * > * {
padding: 12px 8px;
font-size: 13px;
}
.customer-info-column {
min-width: 180px;
max-width: 180px;
}
}
@media (max-width: 992px) {
.search-container {
width: 280px;
}
.stats-container {
grid-template-columns: repeat(2, 1fr);
}
}
@media (max-width: 768px) { @media (max-width: 768px) {
.stats-container {
grid-template-columns: repeat(2, 1fr);
}
.search-filter-container { .search-filter-container {
flex-direction: column; flex-direction: column;
align-items: stretch; align-items: stretch;
gap: 10px;
} }
.search-section { .search-section {
min-width: auto; justify-content: center;
}
.search-container {
width: 100%;
} }
.filter-section { .filter-section {
@@ -446,25 +655,79 @@
.pagination-controls { .pagination-controls {
justify-content: center; justify-content: center;
} }
.table > :not(caption) > * > * {
padding: 10px 6px;
font-size: 12px;
}
.customer-info-column {
min-width: 150px;
max-width: 150px;
}
.customer-avatar {
width: 32px;
height: 32px;
font-size: 0.8rem;
}
.action-btn {
width: 26px;
height: 26px;
font-size: 0.7rem;
}
}
@media (max-width: 576px) {
.stats-container {
grid-template-columns: 1fr;
}
.table-responsive {
font-size: 12px;
}
.customer-info-column {
min-width: 120px;
max-width: 120px;
}
.premium-badge,
.regular-badge,
.status-badge {
font-size: 0.6rem;
padding: 2px 6px;
}
} }
</style> </style>
<div class="container-fluid"> <div class="container-fluid">
<!-- Header --> <!-- Header - Removed gradient -->
<div class="d-flex justify-content-between align-items-center mb-3"> <div class="d-flex justify-content-between align-items-center mb-3">
<h4 style="color: #2c3e50; font-weight: 700;">Customer List</h4> <h4 style="color: #2c3e50; font-weight: 700; font-family: 'Inter', sans-serif;">Customer List</h4>
</div> </div>
<!-- Stats Cards with REAL DATA --> <!-- Stats Cards with NEW DESIGN -->
<div class="stats-row"> <div class="stats-container">
<div class="stats-card"> <!-- Total Customers -->
<div class="stats-count">{{ $allCustomers->count() }}</div> <div class="stat-card">
<div class="stats-label">Total Customers</div> <div class="stat-icon">
<i class="bi bi-people-fill stats-icon"></i> <i class="bi bi-people-fill"></i>
</div>
<div class="stat-content">
<div class="stat-value">{{ $allCustomers->count() }}</div>
<div class="stat-label">Total Customers</div>
</div>
</div> </div>
<div class="stats-card" style="background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);"> <!-- New This Month -->
<div class="stats-count"> <div class="stat-card warning">
<div class="stat-icon">
<i class="bi bi-person-plus"></i>
</div>
<div class="stat-content">
<div class="stat-value">
@php @php
$newThisMonth = $allCustomers->filter(function($customer) { $newThisMonth = $allCustomers->filter(function($customer) {
return $customer->created_at->format('Y-m') === now()->format('Y-m'); return $customer->created_at->format('Y-m') === now()->format('Y-m');
@@ -472,37 +735,47 @@
@endphp @endphp
{{ $newThisMonth }} {{ $newThisMonth }}
</div> </div>
<div class="stats-label">New This Month</div> <div class="stat-label">New This Month</div>
<i class="bi bi-person-plus stats-icon"></i> </div>
</div> </div>
<div class="stats-card" style="background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);"> <!-- Active Customers -->
<div class="stats-count"> <div class="stat-card success">
<div class="stat-icon">
<i class="bi bi-activity"></i>
</div>
<div class="stat-content">
<div class="stat-value">
@php @php
$activeCustomers = $allCustomers->where('status', 'active')->count(); $activeCustomers = $allCustomers->where('status', 'active')->count();
@endphp @endphp
{{ $activeCustomers }} {{ $activeCustomers }}
</div> </div>
<div class="stats-label">Active Customers</div> <div class="stat-label">Active Customers</div>
<i class="bi bi-activity stats-icon"></i> </div>
</div> </div>
<div class="stats-card" style="background: linear-gradient(135deg, #43e97b 0%, #38f9d7 100%);"> <!-- Premium Customers -->
<div class="stats-count"> <div class="stat-card secondary">
<div class="stat-icon">
<i class="bi bi-award-fill"></i>
</div>
<div class="stat-content">
<div class="stat-value">
@php @php
$premiumCount = $allCustomers->where('customer_type', 'premium')->count(); $premiumCount = $allCustomers->where('customer_type', 'premium')->count();
@endphp @endphp
{{ $premiumCount }} {{ $premiumCount }}
</div> </div>
<div class="stats-label">Premium Customers</div> <div class="stat-label">Premium Customers</div>
<i class="bi bi-award-fill stats-icon"></i> </div>
</div> </div>
</div> </div>
<!-- Search and Filter Section - FIXED LAYOUT --> <!-- Search and Filter Section -->
<div class="glass-card p-3 mb-3"> <div class="glass-card p-3 mb-3">
<div class="search-filter-container"> <div class="search-filter-container">
<!-- Search Section --> <!-- Search Section - Wider with icon on left -->
<div class="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">
@@ -511,7 +784,7 @@
name="search" name="search"
value="{{ $search ?? '' }}" value="{{ $search ?? '' }}"
class="search-input" class="search-input"
placeholder="Search Customer Name, Email, or Phone..."> placeholder="Search customers by 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
@@ -547,13 +820,15 @@
<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">
<thead> <thead class="gradient-table-header">
<tr> <tr>
<th class="table-header">Customer Info</th> <th class="table-header">Customer Info</th>
<th class="table-header">Customer ID</th> <th class="table-header">Customer ID</th>
<th class="table-header">Orders</th>
<th class="table-header">Total</th>
<th class="table-header">Create Date</th> <th class="table-header">Create Date</th>
<th class="table-header">Status</th> <th class="table-header">Status</th>
<th class="table-header" width="120">Actions</th> <th class="table-header" width="100">Actions</th>
</tr> </tr>
</thead> </thead>
<tbody id="customersTableBody"> <tbody id="customersTableBody">
@@ -576,20 +851,27 @@
{{ $c->email }}<br> {{ $c->email }}<br>
{{ $c->mobile_no }} {{ $c->mobile_no }}
</div> </div>
<div class="customer-stats mt-1">
{{ $c->orders->count() }} orders {{ number_format($c->orders->sum('ttl_amount'), 2) }} total
</div>
</div> </div>
</div> </div>
</td> </td>
<!-- Customer ID --> <!-- Customer ID -->
<td> <td class="customer-id-column">
<span class="fw-bold text-primary">{{ $c->customer_id }}</span> <span class="fw-bold text-primary">{{ $c->customer_id }}</span>
</td> </td>
<!-- Orders Column -->
<td class="orders-column">
<span class="orders-count">{{ $c->orders->count() }}</span>
</td>
<!-- Total Column -->
<td class="total-column">
<span class="total-amount">{{ number_format($c->orders->sum('ttl_amount'), 2) }}</span>
</td>
<!-- Create Date --> <!-- Create Date -->
<td> <td class="create-date-column">
<span class="text-muted">{{ $c->created_at ? $c->created_at->format('d-m-Y') : '-' }}</span> <span class="text-muted">{{ $c->created_at ? $c->created_at->format('d-m-Y') : '-' }}</span>
</td> </td>
@@ -604,7 +886,7 @@
<!-- Actions --> <!-- Actions -->
<td> <td>
<div class="d-flex"> <div class="d-flex justify-content-center">
<a href="{{ route('admin.customers.view', $c->id) }}" <a href="{{ route('admin.customers.view', $c->id) }}"
class="action-btn" title="View"> class="action-btn" title="View">
<i class="bi bi-eye"></i> <i class="bi bi-eye"></i>
@@ -622,7 +904,7 @@
</tr> </tr>
@empty @empty
<tr> <tr>
<td colspan="5" class="text-center py-4"> <td colspan="7" class="text-center py-4">
<i class="bi bi-people display-4 text-muted d-block mb-2"></i> <i class="bi bi-people display-4 text-muted d-block mb-2"></i>
<span class="text-muted">No customers found.</span> <span class="text-muted">No customers found.</span>
</td> </td>

View File

@@ -12,6 +12,7 @@ html, body {
body, .container-fluid { body, .container-fluid {
background: #f4f7fc; background: #f4f7fc;
font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
} }
.container-fluid { .container-fluid {
@@ -34,6 +35,7 @@ body, .container-fluid {
letter-spacing: .018em; letter-spacing: .018em;
color: #18213e; color: #18213e;
margin-bottom: 2px; margin-bottom: 2px;
font-family: 'Inter', sans-serif;
} }
.dash-title-desc { .dash-title-desc {
@@ -42,6 +44,7 @@ body, .container-fluid {
margin-bottom: 5px; margin-bottom: 5px;
font-weight: 500; font-weight: 500;
letter-spacing: .01em; letter-spacing: .01em;
font-family: 'Inter', sans-serif;
} }
/* ===== STATS CARDS - RESPONSIVE GRID ===== */ /* ===== STATS CARDS - RESPONSIVE GRID ===== */
@@ -127,12 +130,14 @@ body, .container-fluid {
color:#63709b; color:#63709b;
font-weight:600; font-weight:600;
letter-spacing:.28px; letter-spacing:.28px;
font-family: 'Inter', sans-serif;
} }
.stats-value { .stats-value {
font-size:1.25rem; font-size:1.25rem;
font-weight:700; font-weight:700;
color:#194073; color:#194073;
font-family: 'Inter', sans-serif;
} }
.stats-card:hover .stats-icon { .stats-card:hover .stats-icon {
@@ -170,6 +175,7 @@ body, .container-fluid {
display: flex; display: flex;
align-items: center; align-items: center;
gap: 11px; gap: 11px;
font-family: 'Inter', sans-serif;
} }
.order-mgmt-title i { .order-mgmt-title i {
@@ -191,6 +197,7 @@ body, .container-fluid {
align-items: center; align-items: center;
gap: 8px; gap: 8px;
font-family: inherit; font-family: inherit;
font-family: 'Inter', sans-serif;
} }
.create-order-btn:hover { .create-order-btn:hover {
@@ -201,7 +208,7 @@ body, .container-fluid {
.card-body, .order-mgmt-main { .card-body, .order-mgmt-main {
background: #fff; background: #fff;
border-radius: 0 0 17px 17px; border-radius: 0 0 17px 17px;
padding:25px; padding:20px;
margin-top: 15px; margin-top: 15px;
} }
@@ -213,7 +220,7 @@ body, .container-fluid {
margin-top: 15px; margin-top: 15px;
} }
/* ===== TABLE STYLES ===== */ /* ===== IMPROVED TABLE STYLES ===== */
.table thead tr { .table thead tr {
background: #feebbe !important; background: #feebbe !important;
border-radius: 12px 12px 0 0; border-radius: 12px 12px 0 0;
@@ -226,9 +233,10 @@ body, .container-fluid {
font-weight: 700; font-weight: 700;
color: #343535; color: #343535;
letter-spacing: 0.02em; letter-spacing: 0.02em;
font-size:15px; font-size: 15px;
padding-top: 12px; padding: 16px 12px;
padding-bottom: 10px; font-family: 'Inter', sans-serif;
border-bottom: 2px solid #e9ecef;
} }
.table thead th:first-child { border-radius: 9px 0 0 0;} .table thead th:first-child { border-radius: 9px 0 0 0;}
@@ -239,20 +247,24 @@ body, .container-fluid {
border-radius:9px; border-radius:9px;
box-shadow:0 2px 12px #e2ebf941; box-shadow:0 2px 12px #e2ebf941;
border-collapse: separate; border-collapse: separate;
border-spacing: 0 2px; border-spacing: 0 8px;
font-family: 'Inter', sans-serif;
font-size: 14px;
} }
.table-striped tbody tr { .table-striped tbody tr {
background: #fff; background: #fff;
border-radius: 6px; border-radius: 8px;
box-shadow: 0 1px 3px rgba(0,0,0,0.04); box-shadow: 0 2px 6px rgba(0,0,0,0.04);
margin-bottom: 2px; margin-bottom: 8px;
transition: all 0.3s ease; transition: all 0.3s ease;
height: 60px;
} }
.table-striped tbody tr:hover { .table-striped tbody tr:hover {
box-shadow: 0 2px 6px rgba(0,0,0,0.08); box-shadow: 0 4px 12px rgba(0,0,0,0.08);
transform: translateY(-1px); transform: translateY(-2px);
background: #f8fafd;
} }
.table-striped tbody tr:nth-of-type(odd) { .table-striped tbody tr:nth-of-type(odd) {
@@ -264,39 +276,110 @@ body, .container-fluid {
} }
.table td { .table td {
padding: 12px 6px; padding: 14px 12px;
border: none; border: none;
position: relative; position: relative;
vertical-align: middle;
font-family: 'Inter', sans-serif;
font-size: 14px;
font-weight: 500;
color: #495057;
line-height: 1.5;
border-bottom: 1px solid #f1f3f4;
} }
.table td:first-child { .table td:first-child {
border-radius: 6px 0 0 6px; border-radius: 8px 0 0 8px;
border-left: 3px solid transparent;
} }
.table td:last-child { .table td:last-child {
border-radius: 0 6px 6px 0; border-radius: 0 8px 8px 0;
} }
.table-responsive { .table-responsive {
border-radius:10px; border-radius:10px;
} }
/* ===== UPDATED STATUS BADGE STYLES ===== */
.badge { .badge {
font-size:13px; padding: 7px 17px !important;
font-weight:600; border-radius: 20px !important;
padding:7px 17px; font-weight: 600 !important;
border-radius:12px; font-size: 13px !important;
border: 2px solid transparent !important;
min-width: 40px !important;
text-align: center !important;
display: inline-flex !important;
align-items: center;
justify-content: center;
line-height: 1.2 !important;
font-family: 'Inter', sans-serif;
gap: 6px;
width: 110px;
} }
.bg-info { .status-icon {
background-color:#22cbfa!important; font-size: 13px;
color:#fff!important; display: flex;
align-items: center;
justify-content: center;
}
/* Pending Status - SAME SIZE WITH CLOCK ICON */
.badge-pending {
background: linear-gradient(135deg, #fef3c7, #fde68a) !important;
color: #d97706 !important;
border-color: #f59e0b !important;
}
/* In Transit Status - SAME SIZE WITH TRUCK ICON */
.badge-in_transit {
background: linear-gradient(135deg, #dbeafe, #93c5fd) !important;
color: #1e40af !important;
border-color: #3b82f6 !important;
}
/* Dispatched Status - SAME SIZE WITH BOX ICON */
.badge-dispatched {
background: linear-gradient(135deg, #e9d5ff, #c4b5fd) !important;
color: #6b21a8 !important;
border-color: #8b5cf6 !important;
}
/* Delivered Status - SAME SIZE WITH CHECK ICON */
.badge-delivered {
background: linear-gradient(135deg, #d1fae5, #a7f3d0) !important;
color: #065f46 !important;
border-color: #10b981 !important;
}
/* Default badge styles - SAME SIZE */
.badge.bg-info {
background: linear-gradient(135deg, #4cc9f0, #4361ee) !important;
color: white !important;
}
.badge.bg-success {
background: linear-gradient(135deg, #4ade80, #22c55e) !important;
color: white !important;
}
.badge.bg-warning {
background: linear-gradient(135deg, #fbbf24, #f59e0b) !important;
color: white !important;
}
.badge.bg-danger {
background: linear-gradient(135deg, #f87171, #ef4444) !important;
color: white !important;
} }
.form-label { .form-label {
font-weight:600; font-weight:600;
color:#1d3159; color:#1d3159;
font-size:15px; font-size:15px;
font-family: 'Inter', sans-serif;
} }
.form-control, .form-select { .form-control, .form-select {
@@ -305,6 +388,7 @@ body, .container-fluid {
background: #f7f9fe; background: #f7f9fe;
border:1.2px solid #c7dbfa; border:1.2px solid #c7dbfa;
font-weight:500; font-weight:500;
font-family: 'Inter', sans-serif;
} }
.form-control:focus, .form-select:focus { .form-control:focus, .form-select:focus {
@@ -316,6 +400,7 @@ body, .container-fluid {
color:#2469d6; color:#2469d6;
font-weight:600; font-weight:600;
text-decoration:underline; text-decoration:underline;
font-family: 'Inter', sans-serif;
} }
/* ===== HORIZONTAL SCROLL CONTAINER ===== */ /* ===== HORIZONTAL SCROLL CONTAINER ===== */
@@ -327,7 +412,7 @@ body, .container-fluid {
border-radius: 12px; border-radius: 12px;
background: #fff; background: #fff;
box-shadow: 0 2px 10px rgba(0,0,0,0.08); box-shadow: 0 2px 10px rgba(0,0,0,0.08);
padding: 8px; padding: 12px;
} }
.table-wrapper::-webkit-scrollbar { .table-wrapper::-webkit-scrollbar {
@@ -348,7 +433,7 @@ body, .container-fluid {
} }
.table { .table {
min-width: 1200px; min-width: 2000px;
border-radius: 10px; border-radius: 10px;
} }
@@ -394,6 +479,7 @@ body, .container-fluid {
font-size: 1.4rem; font-size: 1.4rem;
font-weight: 700; font-weight: 700;
margin: 0; margin: 0;
font-family: 'Inter', sans-serif;
} }
.create-order-modal .close-btn { .create-order-modal .close-btn {
@@ -425,6 +511,7 @@ body, .container-fluid {
color: #1d3159; color: #1d3159;
font-size: 15px; font-size: 15px;
margin-bottom: 5px; margin-bottom: 5px;
font-family: 'Inter', sans-serif;
} }
.create-order-modal .form-control, .create-order-modal .form-control,
@@ -435,6 +522,7 @@ body, .container-fluid {
font-size: 15px; font-size: 15px;
font-weight: 500; font-weight: 500;
padding: 8px 12px; padding: 8px 12px;
font-family: 'Inter', sans-serif;
} }
.create-order-modal .form-control:focus, .create-order-modal .form-control:focus,
@@ -449,6 +537,7 @@ body, .container-fluid {
padding: 10px 20px; padding: 10px 20px;
font-weight: 600; font-weight: 600;
border-radius: 8px; border-radius: 8px;
font-family: 'Inter', sans-serif;
} }
.create-order-modal .btn-info:hover { .create-order-modal .btn-info:hover {
@@ -461,6 +550,7 @@ body, .container-fluid {
padding: 12px 30px; padding: 12px 30px;
font-weight: 600; font-weight: 600;
border-radius: 8px; border-radius: 8px;
font-family: 'Inter', sans-serif;
} }
.create-order-modal .btn-success:hover { .create-order-modal .btn-success:hover {
@@ -472,6 +562,7 @@ body, .container-fluid {
border: none; border: none;
color: #000; color: #000;
font-weight: 600; font-weight: 600;
font-family: 'Inter', sans-serif;
} }
.create-order-modal .btn-warning:hover { .create-order-modal .btn-warning:hover {
@@ -481,6 +572,7 @@ body, .container-fluid {
.create-order-modal .btn-danger { .create-order-modal .btn-danger {
background: #dc3545; background: #dc3545;
border: none; border: none;
font-family: 'Inter', sans-serif;
} }
.create-order-modal .btn-danger:hover { .create-order-modal .btn-danger:hover {
@@ -505,6 +597,7 @@ body, .container-fluid {
position: sticky; position: sticky;
top: 0; top: 0;
z-index: 10; z-index: 10;
font-family: 'Inter', sans-serif;
} }
/* ===== ORDER DETAILS MODAL STYLES ===== */ /* ===== ORDER DETAILS MODAL STYLES ===== */
@@ -536,6 +629,7 @@ body, .container-fluid {
font-weight: 700; font-weight: 700;
color: white; color: white;
margin: 0; margin: 0;
font-family: 'Inter', sans-serif;
} }
.modal-header .btn-close { .modal-header .btn-close {
@@ -554,6 +648,7 @@ body, .container-fluid {
background: #f8fafc; background: #f8fafc;
max-height: 70vh; max-height: 70vh;
overflow-y: auto; overflow-y: auto;
font-family: 'Inter', sans-serif;
} }
/* ===== PAGINATION STYLES ===== */ /* ===== PAGINATION STYLES ===== */
@@ -570,6 +665,7 @@ body, .container-fluid {
font-size: 13px; font-size: 13px;
color: #9ba5bb; color: #9ba5bb;
font-weight: 600; font-weight: 600;
font-family: 'Inter', sans-serif;
} }
.pagination-controls { .pagination-controls {
@@ -593,6 +689,7 @@ body, .container-fluid {
justify-content: center; justify-content: center;
min-width: 40px; min-width: 40px;
height: 32px; height: 32px;
font-family: 'Inter', sans-serif;
} }
.pagination-btn:hover:not(:disabled) { .pagination-btn:hover:not(:disabled) {
@@ -621,6 +718,7 @@ body, .container-fluid {
transition: all 0.3s ease; transition: all 0.3s ease;
min-width: 36px; min-width: 36px;
text-align: center; text-align: center;
font-family: 'Inter', sans-serif;
} }
.pagination-page-btn:hover { .pagination-page-btn:hover {
@@ -645,6 +743,7 @@ body, .container-fluid {
color: #9ba5bb; color: #9ba5bb;
font-size: 13px; font-size: 13px;
padding: 0 4px; padding: 0 4px;
font-family: 'Inter', sans-serif;
} }
.pagination-img-btn { .pagination-img-btn {
@@ -728,7 +827,7 @@ body, .container-fluid {
.table th, .table th,
.table td { .table td {
padding: 10px 5px; padding: 12px 8px;
} }
.pagination-container { .pagination-container {
@@ -811,7 +910,7 @@ body, .container-fluid {
.table th, .table th,
.table td { .table td {
padding: 8px 4px; padding: 10px 6px;
} }
.badge { .badge {
@@ -913,7 +1012,7 @@ body, .container-fluid {
.table th, .table th,
.table td { .table td {
padding: 6px 3px; padding: 8px 4px;
} }
.form-control, .form-select { .form-control, .form-select {
@@ -1047,6 +1146,7 @@ body, .container-fluid {
</span> </span>
</div> </div>
<div class="card-body table-responsive"> <div class="card-body table-responsive">
<div class="table-wrapper">
<table class="table table-striped table-bordered align-middle text-center"> <table class="table table-striped table-bordered align-middle text-center">
<thead class="table-light"> <thead class="table-light">
<tr> <tr>
@@ -1092,7 +1192,18 @@ body, .container-fluid {
<td>{{ $order->kg }}</td> <td>{{ $order->kg }}</td>
<td>{{ $order->ttl_kg }}</td> <td>{{ $order->ttl_kg }}</td>
<td> <td>
<span class="badge bg-info text-dark">{{ ucfirst($order->status) }}</span> <span class="badge badge-{{ $order->status }}">
@if($order->status == 'pending')
<i class="bi bi-clock-fill status-icon"></i>
@elseif($order->status == 'in_transit')
<i class="bi bi-truck status-icon"></i>
@elseif($order->status == 'dispatched')
<i class="bi bi-box-seam status-icon"></i>
@elseif($order->status == 'delivered')
<i class="bi bi-check-circle-fill status-icon"></i>
@endif
{{ ucfirst(str_replace('_', ' ', $order->status)) }}
</span>
</td> </td>
<td>{{ $order->created_at->format('d-m-Y') }}</td> <td>{{ $order->created_at->format('d-m-Y') }}</td>
<td> <td>
@@ -1108,6 +1219,7 @@ body, .container-fluid {
@endforelse @endforelse
</tbody> </tbody>
</table> </table>
</div>
<!-- Pagination Controls --> <!-- Pagination Controls -->
<div class="pagination-container"> <div class="pagination-container">
@@ -1566,7 +1678,13 @@ document.addEventListener('DOMContentLoaded', function() {
<td>${order.kg || ''}</td> <td>${order.kg || ''}</td>
<td>${order.ttl_kg || ''}</td> <td>${order.ttl_kg || ''}</td>
<td> <td>
<span class="badge bg-info text-dark">${order.status ? order.status.charAt(0).toUpperCase() + order.status.slice(1) : ''}</span> <span class="badge badge-${order.status}">
${order.status === 'pending' ? '<i class="bi bi-clock-fill status-icon"></i>' : ''}
${order.status === 'in_transit' ? '<i class="bi bi-truck status-icon"></i>' : ''}
${order.status === 'dispatched' ? '<i class="bi bi-box-seam status-icon"></i>' : ''}
${order.status === 'delivered' ? '<i class="bi bi-check-circle-fill status-icon"></i>' : ''}
${order.status ? order.status.charAt(0).toUpperCase() + order.status.slice(1).replace('_', ' ') : ''}
</span>
</td> </td>
<td>${new Date(order.created_at).toLocaleDateString('en-GB')}</td> <td>${new Date(order.created_at).toLocaleDateString('en-GB')}</td>
<td> <td>

File diff suppressed because it is too large Load Diff

View File

@@ -5,10 +5,18 @@
@section('content') @section('content')
<style> <style>
/* ===== GLOBAL RESPONSIVE STYLES ===== */ /* ===== GLOBAL RESPONSIVE STYLES ===== */
html, body { html, body {
overflow-x: hidden !important; overflow-x: hidden !important;
max-width: 100%; max-width: 100%;
} }
/* Use Inter globally */
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap');
:root { --admin-font: 'Inter', sans-serif; }
body, input, select, textarea, button, table, th, td, .orders-container {
font-family: var(--admin-font);
}
/* VARIABLES AND BASE STYLES */ /* VARIABLES AND BASE STYLES */
:root { :root {
--primary-color: #3b82f6; /* Blue 500 */ --primary-color: #3b82f6; /* Blue 500 */
@@ -28,8 +36,6 @@ html, body {
border-radius: 12px; border-radius: 12px;
box-shadow: var(--shadow-lg); box-shadow: var(--shadow-lg);
margin-top: 28px; margin-top: 28px;
font-family: 'Inter', sans-serif; /* A modern, clean font */
} }
.orders-title { .orders-title {
@@ -58,25 +64,41 @@ html, body {
color: var(--text-dark); color: var(--text-dark);
} }
/* GRADIENT HEADER STYLES FROM SHIPPING REPORT */
.orders-table thead { .orders-table thead {
background: var(--bg-light); background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
position: sticky;
top: 0;
z-index: 10;
} }
.orders-table th { .orders-table th {
padding: 16px 20px; padding: 16px 20px;
text-align: center; /* Center align header text */
font-size: 14px;
font-weight: 600; font-weight: 600;
color: var(--text-muted); color: white;
text-align: left; border-bottom: none;
white-space: nowrap; white-space: nowrap;
border-bottom: 2px solid var(--border-light); position: relative;
text-transform: uppercase; }
letter-spacing: 0.05em;
.orders-table th:not(:last-child)::after {
content: '';
position: absolute;
right: 0;
top: 50%;
transform: translateY(-50%);
width: 1px;
height: 16px;
background: rgba(255, 255, 255, 0.3);
} }
.orders-table td { .orders-table td {
padding: 14px 20px; padding: 14px 20px;
border-bottom: 1px solid var(--border-light); border-bottom: 1px solid var(--border-light);
white-space: nowrap; white-space: nowrap;
text-align: center; /* Center align all table data */
} }
.orders-table tbody tr:last-child td { .orders-table tbody tr:last-child td {
@@ -88,30 +110,109 @@ html, body {
transition: background 0.2s ease; transition: background 0.2s ease;
} }
/* STATUS BADGES */ /* ===== IMPROVED STATUS BADGES (FROM SHIPPING REPORT) ===== */
.status-badge { .status-badge {
padding: 6px 10px; font-size: 11px !important;
border-radius: 9999px; /* Pill shape */ font-weight: 600 !important;
font-size: 12px; padding: 6px 12px 6px 8px !important;
font-weight: 600; border-radius: 20px !important;
display: inline-flex; text-transform: uppercase;
letter-spacing: 0.3px;
display: inline-flex !important;
align-items: center; align-items: center;
text-transform: capitalize; 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;
position: relative;
overflow: hidden;
white-space: nowrap; white-space: nowrap;
margin: 0 auto; /* Center badges */
}
.status-badge::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: inherit;
opacity: 0.9;
z-index: -1;
}
/* Status icons */
.status-icon {
font-size: 11px;
display: flex;
align-items: center;
justify-content: center;
position: relative;
z-index: 1;
}
/* Invoice Status Badges */
.status-paid {
background: linear-gradient(135deg, #10b981, #34d399) !important;
color: white !important;
border-color: #059669 !important;
width: 99px;
}
.status-pending {
background: linear-gradient(135deg, #fef3c7, #fde68a) !important;
color: #d97706 !important;
border-color: #f59e0b !important;
width: 99px;
}
.status-overdue {
background: linear-gradient(135deg, #fef2f2, #fecaca) !important;
color: #dc2626 !important;
border-color: #ef4444 !important;
width: 99px;
}
/* Shipment Status Badges */
.ship-pending {
background: linear-gradient(135deg, #fef3c7, #fde68a) !important;
color: #d97706 !important;
border-color: #f59e0b !important;
width: 99px;
}
.ship-in_transit {
background: linear-gradient(135deg, #dbeafe, #bfdbfe) !important;
color: #1e40af !important;
border-color: #3b82f6 !important;
width: 99px;
}
.ship-dispatched {
background: linear-gradient(135deg, #e9d5ff, #d8b4fe) !important;
color: #7e22ce !important;
border-color: #8b5cf6 !important;
width: 99px;
}
.ship-delivered {
background: linear-gradient(135deg, #d1fae5, #a7f3d0) !important;
color: #065f46 !important;
border-color: #10b981 !important;
width: 99px;
} }
.shipstatus{ .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 BUTTON */
.action-btn { .action-btn {
color: var(--text-muted); color: var(--text-muted);
@@ -357,11 +458,11 @@ html, body {
<td> <td>
@if($shipment?->status) @if($shipment?->status)
<span class="status-badge status-{{ str_replace(' ', '_', $shipmentStatus) }}"> <span class="status-badge ship-{{ str_replace(' ', '_', $shipmentStatus) }}">
{{ ucfirst($shipmentStatus) }} {{ ucfirst($shipmentStatus) }}
</span> </span>
@else @else
<span class="shipstatus">-</span> <span class="status-badge ship-pending">Pending</span>
@endif @endif
</td> </td>
@@ -411,6 +512,35 @@ html, body {
let allOrders = @json($orders); let allOrders = @json($orders);
let filteredOrders = [...allOrders]; let filteredOrders = [...allOrders];
// Status icon helper functions
function getInvoiceStatusIcon(status) {
switch(status) {
case 'paid':
return '<i class="bi bi-check-circle-fill status-icon"></i>';
case 'pending':
return '<i class="bi bi-clock-fill status-icon"></i>';
case 'overdue':
return '<i class="bi bi-exclamation-triangle-fill status-icon"></i>';
default:
return '';
}
}
function getShipmentStatusIcon(status) {
switch(status) {
case 'pending':
return '<i class="bi bi-clock-fill status-icon"></i>';
case 'in_transit':
return '<i class="bi bi-truck status-icon"></i>';
case 'dispatched':
return '<i class="bi bi-send-fill status-icon"></i>';
case 'delivered':
return '<i class="bi bi-check-circle-fill status-icon"></i>';
default:
return '';
}
}
// Initialize pagination // Initialize pagination
document.addEventListener('DOMContentLoaded', function() { document.addEventListener('DOMContentLoaded', function() {
renderTable(); renderTable();
@@ -537,14 +667,14 @@ html, body {
<td>${invoice?.final_amount_with_gst ? '₹' + Number(invoice.final_amount_with_gst).toLocaleString('en-IN', {minimumFractionDigits: 2, maximumFractionDigits: 2}) : '-'}</td> <td>${invoice?.final_amount_with_gst ? '₹' + Number(invoice.final_amount_with_gst).toLocaleString('en-IN', {minimumFractionDigits: 2, maximumFractionDigits: 2}) : '-'}</td>
<td> <td>
${invoice?.status ${invoice?.status
? `<span class="status-badge status-${invoiceStatus}">${invoice.status.charAt(0).toUpperCase() + invoice.status.slice(1)}</span>` ? `<span class="status-badge status-${invoiceStatus}">${getInvoiceStatusIcon(invoiceStatus)}${invoice.status.charAt(0).toUpperCase() + invoice.status.slice(1)}</span>`
: '<span class="status-badge status-pending">Pending</span>' : '<span class="status-badge status-pending"><i class="bi bi-clock-fill status-icon"></i>Pending</span>'
} }
</td> </td>
<td> <td>
${shipment?.status ${shipment?.status
? `<span class="status-badge status-${shipmentStatus.replace(' ', '_')}">${shipment.status.charAt(0).toUpperCase() + shipment.status.slice(1)}</span>` ? `<span class="status-badge ship-${shipmentStatus.replace(' ', '_')}">${getShipmentStatusIcon(shipmentStatus.replace(' ', '_'))}${shipment.status.charAt(0).toUpperCase() + shipment.status.slice(1)}</span>`
: '<span class="shipstatus">-</span>' : '<span class="status-badge ship-pending"><i class="bi bi-clock-fill status-icon"></i>Pending</span>'
} }
</td> </td>
<td class="text-center"> <td class="text-center">

View File

@@ -5,20 +5,87 @@
@section('content') @section('content')
<div class="container py-4"> <div class="container py-4">
{{-- Header --}} {{-- HEADER --}}
<div class="card shadow-sm rounded-3 border-0"> <div class="card shadow-sm rounded-3 border-0">
<div class="card-body"> <div class="card-body">
{{-- TOP BAR --}}
<div class="d-flex justify-content-between align-items-start"> <div class="d-flex justify-content-between align-items-start">
<div> <div>
<h4 class="fw-bold mb-0">Order Details</Details></h4> <h4 class="fw-bold mb-0">Order Details</h4>
<small class="text-muted">Detailed view of this shipment order</small> <small class="text-muted">Detailed view of this shipment order</small>
</div> </div>
<a href="{{ route('admin.dashboard') }}" class="btn-close"></a> <a href="{{ route('admin.dashboard') }}" class="btn-close"></a>
</div> </div>
{{-- ACTION BUTTONS --}}
<div class="mt-3 d-flex gap-2">
{{-- ADD ITEM --}}
<button class="btn btn-add-item" data-bs-toggle="modal" data-bs-target="#addItemModal">
<i class="fas fa-plus-circle me-2"></i>Add New Item
</button>
{{-- EDIT ORDER --}}
@if($order->status === 'pending')
<button class="btn btn-edit-order" onclick="document.getElementById('editOrderForm').style.display='block'">
<i class="fas fa-edit me-2"></i>Edit Order
</button>
@else
<button class="btn btn-edit-order" disabled><i class="fas fa-edit me-2"></i>Edit Order</button>
@endif
{{-- DELETE ORDER --}}
@if($order->status === 'pending')
<form action="{{ route('admin.orders.destroy', $order->id) }}"
method="POST"
onsubmit="return confirm('Delete this entire order?')">
@csrf
@method('DELETE')
<button class="btn btn-delete-order">
<i class="fas fa-trash-alt me-2"></i>Delete Order
</button>
</form>
@endif
</div>
<hr> <hr>
{{-- Customer Info --}} {{-- EDIT ORDER FORM --}}
<div id="editOrderForm" class="p-3 bg-light rounded mb-4 shadow-sm" style="display:none;">
<h5 class="fw-bold mb-3">Edit Order</h5>
<form action="{{ route('admin.orders.update', $order->id) }}" method="POST">
@csrf
<div class="row">
<div class="col-md-4 mb-3">
<label>Mark No</label>
<input type="text" name="mark_no" value="{{ $order->mark_no }}" class="form-control custom-input">
</div>
<div class="col-md-4 mb-3">
<label>Origin</label>
<input type="text" name="origin" value="{{ $order->origin }}" class="form-control custom-input">
</div>
<div class="col-md-4 mb-3">
<label>Destination</label>
<input type="text" name="destination" value="{{ $order->destination }}" class="form-control custom-input">
</div>
</div>
<button class="btn btn-save-changes">Save Changes</button>
<button type="button"
class="btn btn-cancel"
onclick="document.getElementById('editOrderForm').style.display='none'">
Cancel
</button>
</form>
</div>
{{-- CUSTOMER INFO --}}
<div class="row mb-4"> <div class="row mb-4">
<div class="col-md-8 d-flex"> <div class="col-md-8 d-flex">
<div class="me-3"> <div class="me-3">
@@ -27,6 +94,7 @@
{{ strtoupper(substr($user->customer_name ?? 'U', 0, 1)) }} {{ strtoupper(substr($user->customer_name ?? 'U', 0, 1)) }}
</div> </div>
</div> </div>
<div> <div>
<h5 class="mb-0">{{ $user->customer_name ?? 'Unknown Customer' }}</h5> <h5 class="mb-0">{{ $user->customer_name ?? 'Unknown Customer' }}</h5>
<p class="mb-0">{{ $user->company_name ?? 'N/A' }}</p> <p class="mb-0">{{ $user->company_name ?? 'N/A' }}</p>
@@ -34,13 +102,14 @@
<p class="mb-0 text-muted">{{ $user->mobile_no ?? '' }}</p> <p class="mb-0 text-muted">{{ $user->mobile_no ?? '' }}</p>
</div> </div>
</div> </div>
<div class="col-md-4 text-end"> <div class="col-md-4 text-end">
<p class="mb-0">{{ $user->address ?? '' }}</p> <p class="mb-0">{{ $user->address ?? '' }}</p>
<small class="text-muted">{{ $user->pincode ?? '' }}</small> <small class="text-muted">{{ $user->pincode ?? '' }}</small>
</div> </div>
</div> </div>
{{-- Order Summary --}} {{-- ORDER SUMMARY --}}
<div class="bg-light rounded p-3 mb-3"> <div class="bg-light rounded p-3 mb-3">
<div class="row text-center"> <div class="row text-center">
<div class="col-md-3 border-end"> <div class="col-md-3 border-end">
@@ -65,7 +134,7 @@
</div> </div>
</div> </div>
{{-- Origin - Destination --}} {{-- ORIGIN / DESTINATION --}}
<div class="row text-center mb-4"> <div class="row text-center mb-4">
<div class="col-md-6"> <div class="col-md-6">
<p class="mb-1 fw-semibold text-muted">Origin</p> <p class="mb-1 fw-semibold text-muted">Origin</p>
@@ -77,7 +146,7 @@
</div> </div>
</div> </div>
{{-- Order Items Table --}} {{-- ITEMS TABLE --}}
<div class="table-responsive"> <div class="table-responsive">
<table class="table table-bordered align-middle text-center"> <table class="table table-bordered align-middle text-center">
<thead class="table-light"> <thead class="table-light">
@@ -88,15 +157,17 @@
<th>QTY</th> <th>QTY</th>
<th>TTL/QTY</th> <th>TTL/QTY</th>
<th>Unit</th> <th>Unit</th>
<th>Price ()</th> <th>Price</th>
<th>TTL Amount ()</th> <th>Total Amount</th>
<th>CBM</th> <th>CBM</th>
<th>TTL CBM</th> <th>TTL CBM</th>
<th>KG</th> <th>KG</th>
<th>TTL KG</th> <th>TTL KG</th>
<th>Shop No</th> <th>Shop No</th>
<th>Actions</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
@foreach($order->items as $index => $item) @foreach($order->items as $index => $item)
<tr> <tr>
@@ -113,38 +184,531 @@
<td>{{ $item->kg }}</td> <td>{{ $item->kg }}</td>
<td>{{ $item->ttl_kg }}</td> <td>{{ $item->ttl_kg }}</td>
<td>{{ $item->shop_no }}</td> <td>{{ $item->shop_no }}</td>
<td>
<form action="{{ route('admin.orders.deleteItem', $item->id) }}"
method="POST"
onsubmit="return confirm('Delete this item?')">
@csrf
@method('DELETE')
<button class="btn btn-sm btn-delete-item">
<i class="fas fa-trash"></i>
</button>
</form>
</td>
</tr> </tr>
@endforeach @endforeach
</tbody> </tbody>
</table> </table>
</div> </div>
{{-- Totals --}} {{-- TOTALS --}}
<div class="row text-center mt-4"> <div class="row text-center mt-4">
<div class="col-md-3"> <div class="col-md-3">
<h6 class="fw-bold text-primary">{{ $order->ctn }}</h6> <h6 class="fw-bold text-primary">{{ $order->ctn }}</h6>
<small class="text-muted">Total CTN</small> <small>Total CTN</small>
</div> </div>
<div class="col-md-3"> <div class="col-md-3">
<h6 class="fw-bold text-primary">{{ $order->qty }}</h6> <h6 class="fw-bold text-primary">{{ $order->qty }}</h6>
<small class="text-muted">Total QTY</small> <small>Total QTY</small>
</div> </div>
<div class="col-md-3"> <div class="col-md-3">
<h6 class="fw-bold text-success">{{ $order->ttl_kg }}</h6> <h6 class="fw-bold text-success">{{ $order->ttl_kg }}</h6>
<small class="text-muted">Total TTL KG</small> <small>Total KG</small>
</div> </div>
<div class="col-md-3"> <div class="col-md-3">
<h6 class="fw-bold text-danger">{{ number_format($order->ttl_amount, 2) }}</h6> <h6 class="fw-bold text-danger">{{ number_format($order->ttl_amount, 2) }}</h6>
<small class="text-muted">Total Amount</small> <small>Total Amount</small>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
@endsection
{{-- ADD ITEM MODAL --}}
<div class="modal fade" id="addItemModal" tabindex="-1">
<div class="modal-dialog modal-lg">
<div class="modal-content custom-modal">
<div class="modal-header modal-gradient-header">
<h5 class="modal-title text-white"><i class="fas fa-cube me-2"></i>Add Item To Order</h5>
<button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal"></button>
</div>
<form action="{{ route('admin.orders.addItem', $order->id) }}" method="POST">
@csrf
<div class="modal-body">
{{-- DELETED ITEMS --}}
@php
$deletedItems = \App\Models\OrderItem::onlyTrashed()
->where('order_id', $order->id)
->get();
@endphp
<h5 class="section-title">Deleted Items (Use / Restore)</h5>
<ul class="list-group mb-3">
@forelse($deletedItems as $deleted)
<li class="list-group-item">
<div class="d-flex justify-content-between">
<div>
<strong>{{ $deleted->description }}</strong><br>
<small>
CTN: {{ $deleted->ctn }},
QTY: {{ $deleted->qty }},
TTL/QTY: {{ $deleted->ttl_qty }},
Unit: {{ $deleted->unit }},
Price: {{ $deleted->price }},
TTL Amt: {{ $deleted->ttl_amount }},
CBM: {{ $deleted->cbm }},
TTL CBM: {{ $deleted->ttl_cbm }},
KG: {{ $deleted->kg }},
TTL KG: {{ $deleted->ttl_kg }},
Shop: {{ $deleted->shop_no }}
</small>
</div>
<div class="d-flex gap-2">
{{-- Auto-fill button --}}
<button type="button" class="btn btn-sm btn-use-item"
onclick="fillFormFromDeleted({{ json_encode($deleted) }})">
Use This
</button>
{{-- Restore --}}
<form action="{{ route('admin.orders.restoreItem', $deleted->id) }}" method="POST">
@csrf
<button class="btn btn-sm btn-restore">Restore</button>
</form>
</div>
</div>
</li>
@empty
<li class="list-group-item text-muted">No deleted items.</li>
@endforelse
</ul>
{{-- ADD FORM --}}
<div class="row g-3">
<div class="col-md-6">
<label class="form-label">Description</label>
<input type="text" name="description" class="form-control custom-input" required>
</div>
<div class="col-md-3">
<label class="form-label">CTN</label>
<input type="number" name="ctn" class="form-control custom-input">
</div>
<div class="col-md-3">
<label class="form-label">QTY</label>
<input type="number" name="qty" class="form-control custom-input">
</div>
<div class="col-md-3">
<label class="form-label">TTL QTY</label>
<input type="number" name="ttl_qty" class="form-control custom-input">
</div>
<div class="col-md-3">
<label class="form-label">Unit</label>
<input type="text" name="unit" class="form-control custom-input">
</div>
<div class="col-md-3">
<label class="form-label">Price</label>
<input type="number" name="price" class="form-control custom-input">
</div>
<div class="col-md-3">
<label class="form-label">Total Amount</label>
<input type="number" name="ttl_amount" class="form-control custom-input">
</div>
<div class="col-md-3">
<label class="form-label">CBM</label>
<input type="number" name="cbm" class="form-control custom-input">
</div>
<div class="col-md-3">
<label class="form-label">TTL CBM</label>
<input type="number" name="ttl_cbm" class="form-control custom-input">
</div>
<div class="col-md-3">
<label class="form-label">KG</label>
<input type="number" name="kg" class="form-control custom-input">
</div>
<div class="col-md-3">
<label class="form-label">TTL KG</label>
<input type="number" name="ttl_kg" class="form-control custom-input">
</div>
<div class="col-md-3">
<label class="form-label">Shop No</label>
<input type="text" name="shop_no" class="form-control custom-input">
</div>
</div>
</div>
<div class="modal-footer">
<button class="btn btn-modal-close" data-bs-dismiss="modal">Close</button>
<button class="btn btn-modal-add">Add Item</button>
</div>
</form>
</div>
</div>
</div>
{{-- AUTO-FILL SCRIPT --}}
<script>
function fillFormFromDeleted(item) {
document.querySelector('input[name="description"]').value = item.description;
document.querySelector('input[name="ctn"]').value = item.ctn;
document.querySelector('input[name="qty"]').value = item.qty;
document.querySelector('input[name="ttl_qty"]').value = item.ttl_qty;
document.querySelector('input[name="unit"]').value = item.unit;
document.querySelector('input[name="price"]').value = item.price;
document.querySelector('input[name="ttl_amount"]').value = item.ttl_amount;
document.querySelector('input[name="cbm"]').value = item.cbm;
document.querySelector('input[name="ttl_cbm"]').value = item.ttl_cbm;
document.querySelector('input[name="kg"]').value = item.kg;
document.querySelector('input[name="ttl_kg"]').value = item.ttl_kg;
document.querySelector('input[name="shop_no"]').value = item.shop_no;
}
</script>
<style>
/* Custom Button Styles */
.btn-add-item {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
border: none;
color: white;
padding: 12px 24px;
border-radius: 10px;
font-weight: 600;
transition: all 0.3s ease;
box-shadow: 0 4px 15px 0 rgba(102, 126, 234, 0.3);
position: relative;
overflow: hidden;
}
.btn-add-item:hover {
transform: translateY(-2px);
box-shadow: 0 8px 25px 0 rgba(102, 126, 234, 0.4);
color: white;
}
.btn-add-item::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: 0.5s;
}
.btn-add-item:hover::before {
left: 100%;
}
.btn-edit-order {
background: linear-gradient(135deg, #4776E6 0%, #8E54E9 100%);
border: none;
color: white;
padding: 12px 24px;
border-radius: 10px;
font-weight: 600;
transition: all 0.3s ease;
box-shadow: 0 4px 15px 0 rgba(71, 118, 230, 0.3);
}
.btn-edit-order:hover:not(:disabled) {
transform: translateY(-2px);
box-shadow: 0 8px 25px 0 rgba(71, 118, 230, 0.4);
color: white;
}
.btn-edit-order:disabled {
opacity: 0.6;
cursor: not-allowed;
}
.btn-delete-order {
background: linear-gradient(135deg, #ff416c 0%, #ff4b2b 100%);
border: none;
color: white;
padding: 12px 24px;
border-radius: 10px;
font-weight: 600;
transition: all 0.3s ease;
box-shadow: 0 4px 15px 0 rgba(255, 65, 108, 0.3);
}
.btn-delete-order:hover {
transform: translateY(-2px);
box-shadow: 0 8px 25px 0 rgba(255, 65, 108, 0.4);
color: white;
}
.btn-delete-item {
background: linear-gradient(135deg, #ff416c 0%, #ff4b2b 100%);
border: none;
color: white;
border-radius: 6px;
padding: 6px 12px;
transition: all 0.3s ease;
width: 40px;
height: 40px;
display: flex;
align-items: center;
justify-content: center;
}
.btn-delete-item:hover {
transform: scale(1.05);
color: white;
}
/* Form Buttons */
.btn-save-changes {
background: linear-gradient(135deg, #00b09b 0%, #96c93d 100%);
border: none;
color: white;
padding: 10px 20px;
border-radius: 8px;
font-weight: 600;
transition: all 0.3s ease;
box-shadow: 0 4px 12px rgba(0, 176, 155, 0.2);
}
.btn-save-changes:hover {
transform: translateY(-1px);
box-shadow: 0 6px 20px rgba(0, 176, 155, 0.4);
color: white;
}
.btn-cancel {
background: linear-gradient(135deg, #8e9eab 0%, #eef2f3 100%);
border: none;
color: #2c3e50;
padding: 10px 20px;
border-radius: 8px;
font-weight: 600;
transition: all 0.3s ease;
}
.btn-cancel:hover {
transform: translateY(-1px);
box-shadow: 0 4px 12px rgba(142, 158, 171, 0.3);
}
/* Modal Styles */
.custom-modal {
border-radius: 15px;
border: none;
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
overflow: hidden;
}
.modal-gradient-header {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
border-bottom: none;
padding: 20px 25px;
}
.section-title {
color: #2c3e50;
font-weight: 600;
margin-bottom: 15px;
padding-bottom: 10px;
border-bottom: 2px solid #667eea;
}
.custom-input {
border: 2px solid #e9ecef;
border-radius: 8px;
padding: 10px 15px;
transition: all 0.3s ease;
font-size: 14px;
}
.custom-input:focus {
border-color: #667eea;
box-shadow: 0 0 0 0.2rem rgba(102, 126, 234, 0.25);
transform: translateY(-1px);
}
.btn-use-item {
background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);
border: none;
color: white;
border-radius: 6px;
padding: 5px 15px;
font-size: 0.875rem;
transition: all 0.3s ease;
font-weight: 500;
}
.btn-use-item:hover {
transform: translateY(-1px);
box-shadow: 0 4px 12px rgba(79, 172, 254, 0.4);
color: white;
}
.btn-restore {
background: linear-gradient(135deg, #00b09b 0%, #96c93d 100%);
border: none;
color: white;
border-radius: 6px;
padding: 5px 15px;
font-size: 0.875rem;
transition: all 0.3s ease;
font-weight: 500;
}
.btn-restore:hover {
transform: translateY(-1px);
box-shadow: 0 4px 12px rgba(0, 176, 155, 0.4);
color: white;
}
.btn-modal-close {
background: linear-gradient(135deg, #8e9eab 0%, #eef2f3 100%);
border: none;
color: #2c3e50;
padding: 10px 25px;
border-radius: 8px;
font-weight: 600;
transition: all 0.3s ease;
}
.btn-modal-close:hover {
transform: translateY(-1px);
box-shadow: 0 4px 12px rgba(142, 158, 171, 0.3);
}
.btn-modal-add {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
border: none;
color: white;
padding: 10px 25px;
border-radius: 8px;
font-weight: 600;
transition: all 0.3s ease;
box-shadow: 0 4px 15px 0 rgba(102, 126, 234, 0.3);
}
.btn-modal-add:hover {
transform: translateY(-2px);
box-shadow: 0 8px 25px 0 rgba(102, 126, 234, 0.4);
color: white;
}
/* Animation for the Add Item Button */
@keyframes pulse-glow {
0% {
box-shadow: 0 0 0 0 rgba(102, 126, 234, 0.7);
}
70% {
box-shadow: 0 0 0 10px rgba(102, 126, 234, 0);
}
100% {
box-shadow: 0 0 0 0 rgba(102, 126, 234, 0);
}
}
.btn-add-item {
animation: pulse-glow 2s infinite;
}
/* List group items */
.list-group-item {
border: 1px solid #e9ecef;
margin-bottom: 8px;
border-radius: 8px !important;
transition: all 0.3s ease;
padding: 15px;
}
.list-group-item:hover {
border-color: #667eea;
transform: translateX(5px);
box-shadow: 0 4px 12px rgba(102, 126, 234, 0.1);
}
/* Enhanced table styling */
.table {
border-radius: 10px;
overflow: hidden;
}
.table thead th {
background: #667eea ;
color: white;
border: none;
padding: 15px 10px;
font-weight: 600;
}
.table tbody tr {
transition: all 0.3s ease;
}
.table tbody tr:hover {
background-color: rgba(102, 126, 234, 0.05);
transform: translateY(-1px);
}
/* Badge styling */
.badge {
font-size: 0.85em;
padding: 8px 12px;
border-radius: 8px;
}
/* Card enhancements */
.card {
border: none;
box-shadow: 0 5px 25px rgba(0, 0, 0, 0.1);
}
/* Responsive adjustments */
@media (max-width: 768px) {
.btn-add-item,
.btn-edit-order,
.btn-delete-order {
padding: 10px 15px;
font-size: 0.9rem;
}
.modal-gradient-header {
padding: 15px 20px;
}
}
</style>
@endsection

View File

@@ -10,16 +10,24 @@
max-width: 100%; max-width: 100%;
} }
/* Use Inter globally (keeps your existing @import too) */
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap'); @import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap');
/* Apply Inter globally but keep specificity low so your component styles still work */
:root { --admin-font: 'Inter', sans-serif; }
body, input, select, textarea, button, table, th, td, .report-container {
font-family: var(--admin-font);
}
.report-container { .report-container {
background: #ffffff; background: #ffffff;
padding: 25px; padding: 25px;
border-radius: 16px; border-radius: 16px;
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.08); box-shadow: 0 8px 32px rgba(0, 0, 0, 0.08);
margin: 20px auto; margin: 20px auto;
max-width: 100%; max-width: 100%;
font-family: 'Inter', sans-serif; /* font-family now coming from :root */
border: 1px solid #f0f0f0; border: 1px solid #f0f0f0;
} }
@@ -69,18 +77,21 @@
.stats-container { .stats-container {
display: grid; display: grid;
grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
gap: 15px; gap: 12px;
margin: 20px 0; margin: 20px 0;
} }
.stat-card { .stat-card {
background: linear-gradient(135deg, #f8f9ff 0%, #f0f4ff 100%); background: linear-gradient(135deg, #f8f9ff 0%, #f0f4ff 100%);
padding: 18px 15px; padding: 16px;
border-radius: 12px; border-radius: 12px;
border-left: 4px solid #4f46e5; border-left: 4px solid #4f46e5;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05); box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
transition: transform 0.3s ease; transition: transform 0.3s ease;
text-align: center; display: flex;
align-items: center;
gap: 12px;
min-height: 70px;
} }
.stat-card:hover { .stat-card:hover {
@@ -112,7 +123,16 @@
background: linear-gradient(135deg, #faf5ff 0%, #f3e8ff 100%); background: linear-gradient(135deg, #faf5ff 0%, #f3e8ff 100%);
} }
.stat-icon {
width: 45px;
height: 45px;
border-radius: 10px;
display: flex;
align-items: center;
justify-content: center;
background: rgba(79, 70, 229, 0.1);
flex-shrink: 0;
}
.stat-icon i { .stat-icon i {
font-size: 18px; font-size: 18px;
@@ -143,9 +163,9 @@
color: #ef4444; color: #ef4444;
} }
/* .stat-card.info .stat-icon { .stat-card.info .stat-icon {
background: rgba(59, 130, 246, 0.1); background: rgba(59, 130, 246, 0.1);
} */ }
.stat-card.info .stat-icon i { .stat-card.info .stat-icon i {
color: #3b82f6; color: #3b82f6;
@@ -159,16 +179,20 @@
color: #8b5cf6; color: #8b5cf6;
} }
.stat-content {
flex: 1;
}
.stat-value { .stat-value {
font-size: 22px; font-size: 22px;
font-weight: 700; font-weight: 700;
color: #1a202c; color: #1a202c;
margin-bottom: 4px;
line-height: 1.2; line-height: 1.2;
margin-bottom: 2px;
} }
.stat-label { .stat-label {
font-size: 13px; font-size: 12px;
color: #718096; color: #718096;
font-weight: 500; font-weight: 500;
line-height: 1.3; line-height: 1.3;
@@ -216,10 +240,10 @@
border-radius: 8px; border-radius: 8px;
border: 1.5px solid #e5e7eb; border: 1.5px solid #e5e7eb;
background: #ffffff; background: #ffffff;
font-size: 13px; font-size: 14px; /* increased to match global font sizing */
color: #1f2937; color: #1f2937;
transition: all 0.3s ease; transition: all 0.3s ease;
font-family: 'Inter', sans-serif; font-family: var(--admin-font);
} }
.filter-control:focus { .filter-control:focus {
@@ -242,12 +266,15 @@
/* Ensure table takes full width and doesn't wrap */ /* Ensure table takes full width and doesn't wrap */
.report-table { .report-table {
width: 100%; width: 100%;
border-collapse: collapse; /* keep your collapse behavior but update spacing to match Orders page */
border-collapse: separate;
border-spacing: 0;
min-width: 1200px; /* Minimum width to prevent squeezing */ min-width: 1200px; /* Minimum width to prevent squeezing */
table-layout: auto; /* Allow columns to adjust based on content */ table-layout: auto; /* Allow columns to adjust based on content */
font-size: 14px; /* unified table font size */
} }
/* Table header styling - CENTER ALIGNED */ /* Table header styling - CENTER ALIGNED (keep your gradient & sticky) */
.report-table thead { .report-table thead {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
position: sticky; position: sticky;
@@ -255,10 +282,11 @@
z-index: 10; z-index: 10;
} }
/* Adjusted header padding to match Orders spacing */
.report-table th { .report-table th {
padding: 15px 12px; padding: 16px 20px; /* changed from 15px 12px to match Orders' spacing */
text-align: center; /* Center align header text */ text-align: center; /* Center align header text */
font-size: 13px; font-size: 14px;
font-weight: 600; font-weight: 600;
color: white; color: white;
border-bottom: none; border-bottom: none;
@@ -280,8 +308,8 @@
/* Table cell styling with proper text handling - CENTER ALIGNED */ /* Table cell styling with proper text handling - CENTER ALIGNED */
.report-table td { .report-table td {
padding: 12px; padding: 14px 20px; /* changed from 12px to match Orders' td padding */
font-size: 13px; font-size: 14px; /* unified */
color: #374151; color: #374151;
border-bottom: 1px solid #f3f4f6; border-bottom: 1px solid #f3f4f6;
vertical-align: middle; vertical-align: middle;
@@ -292,12 +320,13 @@
min-width: 120px; /* Minimum column width */ min-width: 120px; /* Minimum column width */
text-align: center; /* Center align all table data */ text-align: center; /* Center align all table data */
} }
/* Specific column width adjustments */ /* Specific column width adjustments */
.report-table th:nth-child(1), /* Order ID */ .report-table th:nth-child(1), /* Order ID */
.report-table td:nth-child(1) { .report-table td:nth-child(1) {
min-width: 100px; min-width: 200px !important;
max-width: 150px; max-width: 200px !important;
padding-left: 20px !important;
} }
.report-table th:nth-child(2), /* Shipment ID */ .report-table th:nth-child(2), /* Shipment ID */
@@ -411,8 +440,12 @@
z-index: -1; z-index: -1;
} }
.status-badge i { /* Status icons */
font-size: 8px; .status-icon {
font-size: 11px;
display: flex;
align-items: center;
justify-content: center;
position: relative; position: relative;
z-index: 1; z-index: 1;
} }
@@ -469,19 +502,18 @@
} }
.data-highlight { .data-highlight {
font-weight: 600; font-weight: 400;
color: #1a202c; color: #1a202c;
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; /* Center content */ justify-content: center; /* Center content */
gap: 4px; gap: 4px;
font-size: 13px; font-size: 14px;
white-space: nowrap; white-space: nowrap;
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
margin: 0 auto; /* Center the highlight container */ margin: 0 auto; /* Center the highlight container */
} }
.data-highlight i { .data-highlight i {
color: #4f46e5; color: #4f46e5;
font-size: 11px; font-size: 11px;
@@ -706,11 +738,21 @@
.stats-container { .stats-container {
grid-template-columns: repeat(2, 1fr); grid-template-columns: repeat(2, 1fr);
gap: 12px; gap: 10px;
} }
.stat-card { .stat-card {
padding: 15px 12px; padding: 14px;
gap: 10px;
}
.stat-icon {
width: 40px;
height: 40px;
}
.stat-icon i {
font-size: 16px;
} }
.stat-value { .stat-value {
@@ -755,7 +797,7 @@
} }
.stat-card { .stat-card {
padding: 15px; padding: 12px;
} }
.report-table { .report-table {
@@ -794,45 +836,57 @@
<div class="stat-icon"> <div class="stat-icon">
<i class="fas fa-box-open"></i> <i class="fas fa-box-open"></i>
</div> </div>
<div class="stat-content">
<div class="stat-value" id="totalShipments">{{ count($reports) }}</div> <div class="stat-value" id="totalShipments">{{ count($reports) }}</div>
<div class="stat-label">Total Shipments</div> <div class="stat-label">Total Shipments</div>
</div> </div>
</div>
<div class="stat-card warning"> <div class="stat-card warning">
<div class="stat-icon"> <div class="stat-icon">
<i class="fas fa-clock"></i> <i class="fas fa-clock"></i>
</div> </div>
<div class="stat-content">
<div class="stat-value" id="pendingShipments">0</div> <div class="stat-value" id="pendingShipments">0</div>
<div class="stat-label">Pending Shipments</div> <div class="stat-label">Pending Shipments</div>
</div> </div>
</div>
<div class="stat-card info"> <div class="stat-card info">
<div class="stat-icon"> <div class="stat-icon">
<i class="fas fa-truck-moving"></i> <i class="fas fa-truck-moving"></i>
</div> </div>
<div class="stat-content">
<div class="stat-value" id="inTransitShipments">0</div> <div class="stat-value" id="inTransitShipments">0</div>
<div class="stat-label">In Transit</div> <div class="stat-label">In Transit</div>
</div> </div>
</div>
<div class="stat-card secondary"> <div class="stat-card secondary">
<div class="stat-icon"> <div class="stat-icon">
<i class="fas fa-shipping-fast"></i> <i class="fas fa-shipping-fast"></i>
</div> </div>
<div class="stat-content">
<div class="stat-value" id="dispatchedShipments">0</div> <div class="stat-value" id="dispatchedShipments">0</div>
<div class="stat-label">Dispatched</div> <div class="stat-label">Dispatched</div>
</div> </div>
</div>
<div class="stat-card success"> <div class="stat-card success">
<div class="stat-icon"> <div class="stat-icon">
<i class="fas fa-check-circle"></i> <i class="fas fa-check-circle"></i>
</div> </div>
<div class="stat-content">
<div class="stat-value" id="deliveredShipments">0</div> <div class="stat-value" id="deliveredShipments">0</div>
<div class="stat-label">Delivered</div> <div class="stat-label">Delivered</div>
</div> </div>
</div>
<div class="stat-card danger"> <div class="stat-card danger">
<div class="stat-icon"> <div class="stat-icon">
<i class="fas fa-exclamation-triangle"></i> <i class="fas fa-exclamation-triangle"></i>
</div> </div>
<div class="stat-content">
<div class="stat-value" id="overdueInvoices">0</div> <div class="stat-value" id="overdueInvoices">0</div>
<div class="stat-label">Overdue Invoices</div> <div class="stat-label">Overdue Invoices</div>
</div> </div>
</div> </div>
</div>
<!-- FILTER SECTION --> <!-- FILTER SECTION -->
<div class="filter-section"> <div class="filter-section">
@@ -879,24 +933,23 @@
</div> </div>
</div> </div>
</div> </div>
<!-- TABLE SECTION --> <!-- TABLE SECTION -->
<div class="table-container"> <div class="table-container">
<table class="report-table"> <table class="report-table">
<thead> <thead>
<tr> <tr>
<th><i class="fas fa-hashtag"></i> Order ID</th> <th>Order ID</th>
<th><i class="fas fa-barcode"></i> Shipment ID</th> <th>Shipment ID</th>
<th><i class="fas fa-building"></i> Company Name</th> <th>Company Name</th>
<th><i class="fas fa-user"></i> User Name</th> <th>User Name</th>
<th><i class="fas fa-map-marker-alt"></i> Origin</th> <th><i class="fas fa-map-marker-alt"></i> Origin</th>
<th><i class="fas fa-location-arrow"></i> Destination</th> <th><i class="fas fa-location-arrow"></i> Destination</th>
<th><i class="fas fa-calendar"></i> Date</th> <th>Date</th>
<th><i class="fas fa-file-invoice"></i> Invoice ID</th> <th>Invoice ID</th>
<th><i class="fas fa-calendar-day"></i> Invoice Date</th> <th>Invoice Date</th>
<th><i class="fas fa-money-bill-wave"></i> Invoice Amount</th> <th>Invoice Amount</th>
<th><i class="fas fa-receipt"></i> Invoice Status</th> <th>Invoice Status</th>
<th><i class="fas fa-shipping-fast"></i> Shipment Status</th> <th>Shipment Status</th>
</tr> </tr>
</thead> </thead>
<tbody id="reportTableBody"> <tbody id="reportTableBody">
@@ -904,13 +957,11 @@
<tr data-status="{{ $r->shipment_status }}" data-invoice-status="{{ strtolower($r->invoice_status) }}" data-company="{{ $r->company_name ?? '' }}" data-date="{{ $r->shipment_date }}"> <tr data-status="{{ $r->shipment_status }}" data-invoice-status="{{ strtolower($r->invoice_status) }}" data-company="{{ $r->company_name ?? '' }}" data-date="{{ $r->shipment_date }}">
<td> <td>
<span class="data-highlight" title="{{ $r->order_id }}"> <span class="data-highlight" title="{{ $r->order_id }}">
<i class="fas fa-hashtag"></i>
{{ $r->order_id }} {{ $r->order_id }}
</span> </span>
</td> </td>
<td> <td>
<span class="data-highlight" title="{{ $r->shipment_id }}"> <span class="data-highlight" title="{{ $r->shipment_id }}">
<i class="fas fa-barcode"></i>
{{ $r->shipment_id }} {{ $r->shipment_id }}
</span> </span>
</td> </td>
@@ -919,9 +970,10 @@
<td> <td>
<span class="data-highlight" title="{{ $r->origin }}"> <span class="data-highlight" title="{{ $r->origin }}">
<i class="fas fa-map-marker-alt"></i> <i class="fas fa-map-marker-alt"></i>
{{ $r->origin }} {{ $r->origin ?? '-' }}
</span> </span>
</td> </td>
<td> <td>
<span class="data-highlight" title="{{ $r->destination }}"> <span class="data-highlight" title="{{ $r->destination }}">
<i class="fas fa-location-arrow"></i> <i class="fas fa-location-arrow"></i>
@@ -931,31 +983,43 @@
<td>{{ \Carbon\Carbon::parse($r->shipment_date)->format('d/m/Y') }}</td> <td>{{ \Carbon\Carbon::parse($r->shipment_date)->format('d/m/Y') }}</td>
<td> <td>
<span class="data-highlight" title="{{ $r->invoice_number }}"> <span class="data-highlight" title="{{ $r->invoice_number }}">
<i class="fas fa-file-invoice"></i>
{{ $r->invoice_number }} {{ $r->invoice_number }}
</span> </span>
</td> </td>
<td>{{ \Carbon\Carbon::parse($r->invoice_date)->format('d/m/Y') }}</td> <td>{{ \Carbon\Carbon::parse($r->invoice_date)->format('d/m/Y') }}</td>
<td> <td>
<span class="data-highlight" title="{{ number_format($r->final_amount) }}"> <span class="data-highlight" title="{{ number_format($r->final_amount) }}">
<i class="fas fa-rupee-sign"></i> {{ number_format($r->final_amount) }}
{{ number_format($r->final_amount) }}
</span> </span>
</td> </td>
<td> <td>
@php $ist = strtolower($r->invoice_status); @endphp @php $ist = strtolower($r->invoice_status ?? ''); @endphp
<span class="status-badge <span class="status-badge
@if($ist === 'paid') status-paid @if($ist === 'paid') status-paid
@elseif($ist === 'pending') status-pending @elseif($ist === 'pending') status-pending
@elseif($ist === 'overdue') status-overdue @elseif($ist === 'overdue') status-overdue
@endif"> @endif">
<i class="fas fa-circle"></i> @if($ist === 'paid')
<i class="bi bi-check-circle-fill status-icon"></i>
@elseif($ist === 'pending')
<i class="bi bi-clock-fill status-icon"></i>
@elseif($ist === 'overdue')
<i class="bi bi-exclamation-triangle-fill status-icon"></i>
@endif
{{ ucfirst($ist) }} {{ ucfirst($ist) }}
</span> </span>
</td> </td>
<td> <td>
<span class="status-badge ship-{{ $r->shipment_status }}"> <span class="status-badge ship-{{ $r->shipment_status }}">
<i class="fas fa-circle"></i> @if($r->shipment_status === 'pending')
<i class="bi bi-clock-fill status-icon"></i>
@elseif($r->shipment_status === 'in_transit')
<i class="bi bi-truck status-icon"></i>
@elseif($r->shipment_status === 'dispatched')
<i class="bi bi-send-fill status-icon"></i>
@elseif($r->shipment_status === 'delivered')
<i class="bi bi-check-circle-fill status-icon"></i>
@endif
{{ ucfirst(str_replace('_',' ', $r->shipment_status)) }} {{ ucfirst(str_replace('_',' ', $r->shipment_status)) }}
</span> </span>
</td> </td>
@@ -999,7 +1063,6 @@
</div> </div>
</div> </div>
</div> </div>
<script> <script>
// Pagination state // Pagination state
let currentPage = 1; let currentPage = 1;
@@ -1007,6 +1070,35 @@
let allReports = @json($reports); let allReports = @json($reports);
let filteredReports = [...allReports]; let filteredReports = [...allReports];
// Status icon helper functions
function getInvoiceStatusIcon(status) {
switch(status) {
case 'paid':
return '<i class="bi bi-check-circle-fill status-icon"></i>';
case 'pending':
return '<i class="bi bi-clock-fill status-icon"></i>';
case 'overdue':
return '<i class="bi bi-exclamation-triangle-fill status-icon"></i>';
default:
return '';
}
}
function getShipmentStatusIcon(status) {
switch(status) {
case 'pending':
return '<i class="bi bi-clock-fill status-icon"></i>';
case 'in_transit':
return '<i class="bi bi-truck status-icon"></i>';
case 'dispatched':
return '<i class="bi bi-send-fill status-icon"></i>';
case 'delivered':
return '<i class="bi bi-check-circle-fill status-icon"></i>';
default:
return '';
}
}
document.addEventListener('DOMContentLoaded', function() { document.addEventListener('DOMContentLoaded', function() {
// Initialize statistics and pagination // Initialize statistics and pagination
updateStatistics(); updateStatistics();
@@ -1021,18 +1113,25 @@
return date.toISOString().split('T')[0]; return date.toISOString().split('T')[0];
}; };
document.getElementById('fromDate').value = formatDate(lastMonth); if (document.getElementById('fromDate')) document.getElementById('fromDate').value = formatDate(lastMonth);
document.getElementById('toDate').value = formatDate(today); if (document.getElementById('toDate')) document.getElementById('toDate').value = formatDate(today);
// Add event listeners for filters // Add event listeners for filters
document.getElementById('fromDate').addEventListener('change', filterTable); const fd = document.getElementById('fromDate');
document.getElementById('toDate').addEventListener('change', filterTable); const td = document.getElementById('toDate');
document.getElementById('companyFilter').addEventListener('change', filterTable); const cf = document.getElementById('companyFilter');
document.getElementById('statusFilter').addEventListener('change', filterTable); const sf = document.getElementById('statusFilter');
if(fd) fd.addEventListener('change', filterTable);
if(td) td.addEventListener('change', filterTable);
if(cf) cf.addEventListener('change', filterTable);
if(sf) sf.addEventListener('change', filterTable);
// Bind pagination events // Bind pagination events
document.getElementById('prevPageBtn').addEventListener('click', goToPreviousPage); const prevBtn = document.getElementById('prevPageBtn');
document.getElementById('nextPageBtn').addEventListener('click', goToNextPage); const nextBtn = document.getElementById('nextPageBtn');
if(prevBtn) prevBtn.addEventListener('click', goToPreviousPage);
if(nextBtn) nextBtn.addEventListener('click', goToNextPage);
function updateStatistics() { function updateStatistics() {
const rows = document.querySelectorAll('#reportTableBody tr'); const rows = document.querySelectorAll('#reportTableBody tr');
@@ -1062,12 +1161,18 @@
}); });
// Update statistics cards // Update statistics cards
document.getElementById('totalShipments').textContent = totalShipments; const elTotal = document.getElementById('totalShipments');
document.getElementById('pendingShipments').textContent = pendingShipments; if(elTotal) elTotal.textContent = totalShipments;
document.getElementById('inTransitShipments').textContent = inTransitShipments; const elPending = document.getElementById('pendingShipments');
document.getElementById('dispatchedShipments').textContent = dispatchedShipments; if(elPending) elPending.textContent = pendingShipments;
document.getElementById('deliveredShipments').textContent = deliveredShipments; const elInTransit = document.getElementById('inTransitShipments');
document.getElementById('overdueInvoices').textContent = overdueInvoices; if(elInTransit) elInTransit.textContent = inTransitShipments;
const elDispatched = document.getElementById('dispatchedShipments');
if(elDispatched) elDispatched.textContent = dispatchedShipments;
const elDelivered = document.getElementById('deliveredShipments');
if(elDelivered) elDelivered.textContent = deliveredShipments;
const elOverdue = document.getElementById('overdueInvoices');
if(elOverdue) elOverdue.textContent = overdueInvoices;
} }
// Pagination Functions // Pagination Functions
@@ -1095,16 +1200,16 @@
const pageInfo = document.getElementById('pageInfo'); const pageInfo = document.getElementById('pageInfo');
const paginationPages = document.getElementById('paginationPages'); const paginationPages = document.getElementById('paginationPages');
prevBtn.disabled = currentPage === 1; if(prevBtn) prevBtn.disabled = currentPage === 1;
nextBtn.disabled = currentPage === totalPages || totalPages === 0; if(nextBtn) nextBtn.disabled = currentPage === totalPages || totalPages === 0;
// Update page info text // Update page info text
const startIndex = (currentPage - 1) * itemsPerPage + 1; const startIndex = (currentPage - 1) * itemsPerPage + 1;
const endIndex = Math.min(currentPage * itemsPerPage, filteredReports.length); const endIndex = Math.min(currentPage * itemsPerPage, filteredReports.length);
pageInfo.textContent = `Showing ${startIndex} to ${endIndex} of ${filteredReports.length} entries`; if(pageInfo) pageInfo.textContent = `Showing ${startIndex} to ${endIndex} of ${filteredReports.length} entries`;
// Generate page numbers // Generate page numbers
paginationPages.innerHTML = ''; if(paginationPages) paginationPages.innerHTML = '';
if (totalPages <= 7) { if (totalPages <= 7) {
// Show all pages // Show all pages
@@ -1116,7 +1221,7 @@
addPageButton(1, paginationPages); addPageButton(1, paginationPages);
if (currentPage > 3) { if (currentPage > 3) {
paginationPages.innerHTML += '<span class="pagination-ellipsis">...</span>'; if(paginationPages) paginationPages.innerHTML += '<span class="pagination-ellipsis">...</span>';
} }
const start = Math.max(2, currentPage - 1); const start = Math.max(2, currentPage - 1);
@@ -1127,7 +1232,7 @@
} }
if (currentPage < totalPages - 2) { if (currentPage < totalPages - 2) {
paginationPages.innerHTML += '<span class="pagination-ellipsis">...</span>'; if(paginationPages) paginationPages.innerHTML += '<span class="pagination-ellipsis">...</span>';
} }
addPageButton(totalPages, paginationPages); addPageButton(totalPages, paginationPages);
@@ -1135,6 +1240,7 @@
} }
function addPageButton(pageNumber, container) { function addPageButton(pageNumber, container) {
if(!container) return;
const button = document.createElement('button'); const button = document.createElement('button');
button.className = 'pagination-page-btn'; button.className = 'pagination-page-btn';
if (pageNumber === currentPage) { if (pageNumber === currentPage) {
@@ -1152,6 +1258,7 @@
// Render Table Function // Render Table Function
function renderTable() { function renderTable() {
const tbody = document.getElementById('reportTableBody'); const tbody = document.getElementById('reportTableBody');
if(!tbody) return;
tbody.innerHTML = ''; tbody.innerHTML = '';
if (filteredReports.length === 0) { if (filteredReports.length === 0) {
@@ -1187,42 +1294,38 @@
row.innerHTML = ` row.innerHTML = `
<td> <td>
<span class="data-highlight" title="${report.order_id}"> <span class="data-highlight" title="${report.order_id}">
<i class="fas fa-hashtag"></i> ${report.order_id || '-'}
${report.order_id}
</span> </span>
</td> </td>
<td> <td>
<span class="data-highlight" title="${report.shipment_id}"> <span class="data-highlight" title="${report.shipment_id}">
<i class="fas fa-barcode"></i> ${report.shipment_id || '-'}
${report.shipment_id}
</span> </span>
</td> </td>
<td title="${report.company_name || '-'}">${report.company_name || '-'}</td> <td title="${report.company_name || '-'}">${report.company_name || '-'}</td>
<td title="${report.customer_name || '-'}">${report.customer_name || '-'}</td> <td title="${report.customer_name || '-'}">${report.customer_name || '-'}</td>
<td> <td>
<span class="data-highlight" title="${report.origin}"> <span class="data-highlight" title="${report.origin || '-'}">
<i class="fas fa-map-marker-alt"></i> <i class="fas fa-map-marker-alt"></i>
${report.origin} ${report.origin || '-'}
</span> </span>
</td> </td>
<td> <td>
<span class="data-highlight" title="${report.destination}"> <span class="data-highlight" title="${report.destination || '-'}">
<i class="fas fa-location-arrow"></i> <i class="fas fa-location-arrow"></i>
${report.destination} ${report.destination || '-'}
</span> </span>
</td> </td>
<td>${new Date(report.shipment_date).toLocaleDateString('en-GB')}</td> <td>${report.shipment_date ? new Date(report.shipment_date).toLocaleDateString('en-GB') : '-'}</td>
<td> <td>
<span class="data-highlight" title="${report.invoice_number}"> <span class="data-highlight" title="${report.invoice_number || '-'}">
<i class="fas fa-file-invoice"></i> ${report.invoice_number || '-'}
${report.invoice_number}
</span> </span>
</td> </td>
<td>${new Date(report.invoice_date).toLocaleDateString('en-GB')}</td> <td>${report.invoice_date ? new Date(report.invoice_date).toLocaleDateString('en-GB') : '-'}</td>
<td> <td>
<span class="data-highlight" title="${Number(report.final_amount).toLocaleString('en-IN')}"> <span class="data-highlight" title="${Number(report.final_amount || 0).toLocaleString('en-IN')}">
<i class="fas fa-rupee-sign"></i> ${Number(report.final_amount || 0).toLocaleString('en-IN')}
${Number(report.final_amount).toLocaleString('en-IN')}
</span> </span>
</td> </td>
<td> <td>
@@ -1230,14 +1333,14 @@
${ist === 'paid' ? 'status-paid' : ''} ${ist === 'paid' ? 'status-paid' : ''}
${ist === 'pending' ? 'status-pending' : ''} ${ist === 'pending' ? 'status-pending' : ''}
${ist === 'overdue' ? 'status-overdue' : ''}"> ${ist === 'overdue' ? 'status-overdue' : ''}">
<i class="fas fa-circle"></i> ${getInvoiceStatusIcon(ist)}
${ist.charAt(0).toUpperCase() + ist.slice(1)} ${ist ? ist.charAt(0).toUpperCase() + ist.slice(1) : '-'}
</span> </span>
</td> </td>
<td> <td>
<span class="status-badge ship-${report.shipment_status}"> <span class="status-badge ship-${report.shipment_status || ''}">
<i class="fas fa-circle"></i> ${getShipmentStatusIcon(report.shipment_status)}
${report.shipment_status.charAt(0).toUpperCase() + report.shipment_status.slice(1).replace('_', ' ')} ${report.shipment_status ? (report.shipment_status.charAt(0).toUpperCase() + report.shipment_status.slice(1)).replace('_',' ') : '-'}
</span> </span>
</td> </td>
`; `;
@@ -1246,10 +1349,10 @@
} }
function filterTable() { function filterTable() {
const fromDate = document.getElementById('fromDate').value; const fromDate = document.getElementById('fromDate')?.value;
const toDate = document.getElementById('toDate').value; const toDate = document.getElementById('toDate')?.value;
const companyFilter = document.getElementById('companyFilter').value; const companyFilter = document.getElementById('companyFilter')?.value;
const statusFilter = document.getElementById('statusFilter').value; const statusFilter = document.getElementById('statusFilter')?.value;
filteredReports = allReports.filter(report => { filteredReports = allReports.filter(report => {
let include = true; let include = true;
@@ -1285,7 +1388,7 @@
updateStatistics(); updateStatistics();
} }
// Add hover effects to table rows // Add hover effects to table rows (for rows present initially in DOM — dynamic rows handled in renderTable)
const tableRows = document.querySelectorAll('.report-table tbody tr'); const tableRows = document.querySelectorAll('.report-table tbody tr');
tableRows.forEach(row => { tableRows.forEach(row => {
row.addEventListener('mouseenter', function() { row.addEventListener('mouseenter', function() {

File diff suppressed because it is too large Load Diff

View File

@@ -114,22 +114,58 @@ Route::prefix('admin')
Route::get('/orders/view/{id}', [AdminOrderController::class, 'popup']) Route::get('/orders/view/{id}', [AdminOrderController::class, 'popup'])
->name('admin.orders.popup'); ->name('admin.orders.popup');
// ---------------------------
// ORDERS (FIXED ROUTES)
// ---------------------------
// Add item to order
Route::post('/orders/{order}/item', [AdminOrderController::class, 'addItem'])
->name('admin.orders.addItem');
// Delete item from order
Route::delete('/orders/item/{id}', [AdminOrderController::class, 'deleteItem'])
->name('admin.orders.deleteItem');
// Restore deleted item
Route::post('/orders/item/{id}/restore', [AdminOrderController::class, 'restoreItem'])
->name('admin.orders.restoreItem');
// Update main order fields
Route::post('/orders/{id}/update', [AdminOrderController::class, 'update'])
->name('admin.orders.update');
// Delete full order
Route::delete('/orders/{id}/delete', [AdminOrderController::class, 'destroy'])
->name('admin.orders.destroy');
// --------------------------- // ---------------------------
// SHIPMENTS // SHIPMENTS (FIXED ROUTES)
// --------------------------- // ---------------------------
Route::get('/shipments', [ShipmentController::class, 'index']) Route::get('/shipments', [ShipmentController::class, 'index'])
->name('admin.shipments'); ->name('admin.shipments');
Route::post('/shipments/store', [ShipmentController::class, 'store']) Route::post('/shipments', [ShipmentController::class, 'store'])
->name('admin.shipments.store'); ->name('admin.shipments.store');
Route::post('/shipments/update-status', [ShipmentController::class, 'updateStatus']) Route::post('/shipments/update-status', [ShipmentController::class, 'updateStatus'])
->name('admin.shipments.updateStatus'); ->name('admin.shipments.updateStatus');
// Get shipment orders for modal (AJAX)
Route::get('/shipments/{id}/orders', [ShipmentController::class, 'getShipmentOrders'])
->name('admin.shipments.orders');
// Get shipment details for edit (AJAX)
Route::get('/shipments/{id}', [ShipmentController::class, 'show']) Route::get('/shipments/{id}', [ShipmentController::class, 'show'])
->name('admin.shipments.show'); ->name('admin.shipments.show');
// Shipment Update
Route::put('/shipments/{id}', [ShipmentController::class, 'update'])
->name('admin.shipments.update');
// Shipment Delete
Route::delete('/shipments/{id}', [ShipmentController::class, 'destroy'])
->name('admin.shipments.destroy');
// --------------------------- // ---------------------------
// INVOICES // INVOICES
@@ -212,6 +248,3 @@ Route::prefix('admin/account')
Route::get('/entry/{entry_no}', [AdminAccountController::class, 'getEntryDetails']) Route::get('/entry/{entry_no}', [AdminAccountController::class, 'getEntryDetails'])
->name('entry.details'); ->name('entry.details');
}); });