merge Conflict
This commit is contained in:
@@ -11,6 +11,71 @@ use Illuminate\Support\Facades\DB;
|
|||||||
|
|
||||||
class AdminAccountController extends Controller
|
class AdminAccountController extends Controller
|
||||||
{
|
{
|
||||||
|
public function updateEntry(Request $request)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$data = $request->validate([
|
||||||
|
'entry_no' => 'required|exists:entries,entry_no',
|
||||||
|
'description' => 'required|string|max:255',
|
||||||
|
'order_quantity' => 'required|numeric|min:0',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$entry = Entry::where('entry_no', $data['entry_no'])->first();
|
||||||
|
|
||||||
|
if (!$entry) {
|
||||||
|
return response()->json([
|
||||||
|
'success' => false,
|
||||||
|
'message' => 'Entry not found.',
|
||||||
|
], 404);
|
||||||
|
}
|
||||||
|
|
||||||
|
$entry->description = $data['description'];
|
||||||
|
$entry->order_quantity = $data['order_quantity'];
|
||||||
|
$entry->save();
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'success' => true,
|
||||||
|
'message' => 'Entry updated successfully.',
|
||||||
|
'entry' => $entry,
|
||||||
|
]);
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
return response()->json([
|
||||||
|
'success' => false,
|
||||||
|
'message' => 'Server error: '.$e->getMessage(),
|
||||||
|
], 500);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function deleteEntry(Request $request)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$data = $request->validate([
|
||||||
|
'entry_no' => 'required|exists:entries,entry_no',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$entry = Entry::where('entry_no', $data['entry_no'])->first();
|
||||||
|
|
||||||
|
if (!$entry) {
|
||||||
|
return response()->json([
|
||||||
|
'success' => false,
|
||||||
|
'message' => 'Entry not found.',
|
||||||
|
], 404);
|
||||||
|
}
|
||||||
|
|
||||||
|
$entry->delete();
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'success' => true,
|
||||||
|
'message' => 'Entry deleted successfully.',
|
||||||
|
]);
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
return response()->json([
|
||||||
|
'success' => false,
|
||||||
|
'message' => 'Server error: '.$e->getMessage(),
|
||||||
|
], 500);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 🚀 1. Get dashboard entries
|
* 🚀 1. Get dashboard entries
|
||||||
*/
|
*/
|
||||||
@@ -245,4 +310,82 @@ class AdminAccountController extends Controller
|
|||||||
'pending' => $entry->pending_amount,
|
'pending' => $entry->pending_amount,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//--------------------------
|
||||||
|
//add order Entry
|
||||||
|
//--------------------------
|
||||||
|
public function addOrdersToEntry(Request $request)
|
||||||
|
{
|
||||||
|
$data = $request->validate([
|
||||||
|
'entry_no' => 'required|exists:entries,entry_no',
|
||||||
|
'order_ids' => 'required|array',
|
||||||
|
'order_ids.*' => 'integer|exists:orders,id',
|
||||||
|
]);
|
||||||
|
|
||||||
|
return DB::transaction(function () use ($data) {
|
||||||
|
$entry = Entry::where('entry_no', $data['entry_no'])->firstOrFail();
|
||||||
|
|
||||||
|
// आधीचे orders काढू नका, फक्त नवीन add करा
|
||||||
|
$entry->orders()->syncWithoutDetaching($data['order_ids']);
|
||||||
|
|
||||||
|
// इथे quantity auto update
|
||||||
|
$entry->order_quantity = $entry->orders()->count();
|
||||||
|
$entry->save();
|
||||||
|
|
||||||
|
$entry->load('orders');
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'success' => true,
|
||||||
|
'message' => 'Orders added successfully.',
|
||||||
|
'entry' => $entry,
|
||||||
|
]);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public function getEntryOrders($entry_no)
|
||||||
|
{
|
||||||
|
$entry = Entry::where('entry_no', $entry_no)
|
||||||
|
->with('orders')
|
||||||
|
->first();
|
||||||
|
|
||||||
|
if (!$entry) {
|
||||||
|
return response()->json([
|
||||||
|
'success' => false,
|
||||||
|
'message' => 'Entry not found.',
|
||||||
|
], 404);
|
||||||
|
}
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'success' => true,
|
||||||
|
'orders' => $entry->orders,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function removeOrderFromEntry(Request $request)
|
||||||
|
{
|
||||||
|
$data = $request->validate([
|
||||||
|
'entry_no' => 'required|exists:entries,entry_no',
|
||||||
|
'order_id' => 'required|integer|exists:orders,id',
|
||||||
|
]);
|
||||||
|
|
||||||
|
return DB::transaction(function () use ($data) {
|
||||||
|
$entry = Entry::where('entry_no', $data['entry_no'])->firstOrFail();
|
||||||
|
|
||||||
|
// order detach करा
|
||||||
|
$entry->orders()->detach($data['order_id']);
|
||||||
|
|
||||||
|
// इथे quantity auto update
|
||||||
|
$entry->order_quantity = $entry->orders()->count();
|
||||||
|
$entry->save();
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'success' => true,
|
||||||
|
'message' => 'Order removed successfully.',
|
||||||
|
'entry' => $entry,
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -9,36 +9,42 @@ use Illuminate\Support\Facades\Hash;
|
|||||||
|
|
||||||
class AdminCustomerController extends Controller
|
class AdminCustomerController extends Controller
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
||||||
// ---------------------------------------------------------
|
// ---------------------------------------------------------
|
||||||
// LIST CUSTOMERS (with search + status filter)
|
// LIST CUSTOMERS (with search + status filter)
|
||||||
// ---------------------------------------------------------
|
// ---------------------------------------------------------
|
||||||
public function index(Request $request)
|
public function index(Request $request)
|
||||||
{
|
{
|
||||||
$search = $request->search;
|
$search = $request->search;
|
||||||
$status = $request->status;
|
$status = $request->status;
|
||||||
|
|
||||||
$query = User::with(['marks', 'orders'])->orderBy('id', 'desc');
|
$query = User::with(['marks', 'orders'])->orderBy('id', 'desc');
|
||||||
|
|
||||||
// SEARCH FILTER
|
// SEARCH FILTER
|
||||||
if (!empty($search)) {
|
if (!empty($search)) {
|
||||||
$query->where(function ($q) use ($search) {
|
$query->where(function ($q) use ($search) {
|
||||||
$q->where('customer_name', 'like', "%$search%")
|
$q->where('customer_name', 'like', "%$search%")
|
||||||
->orWhere('email', 'like', "%$search%")
|
->orWhere('email', 'like', "%$search%")
|
||||||
->orWhere('mobile_no', 'like', "%$search%")
|
->orWhere('mobile_no', 'like', "%$search%")
|
||||||
->orWhere('customer_id', 'like', "%$search%");
|
->orWhere('customer_id', 'like', "%$search%");
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
// STATUS FILTER
|
|
||||||
if (!empty($status) && in_array($status, ['active', 'inactive'])) {
|
|
||||||
$query->where('status', $status);
|
|
||||||
}
|
|
||||||
|
|
||||||
$customers = $query->get();
|
|
||||||
|
|
||||||
return view('admin.customers', compact('customers', 'search', 'status'));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// STATUS FILTER
|
||||||
|
if (!empty($status) && in_array($status, ['active', 'inactive'])) {
|
||||||
|
$query->where('status', $status);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get all customers for statistics (without pagination)
|
||||||
|
$allCustomers = $query->get();
|
||||||
|
|
||||||
|
// Get paginated customers for the table (10 per page)
|
||||||
|
$customers = $query->paginate(10);
|
||||||
|
|
||||||
|
return view('admin.customers', compact('customers', 'allCustomers', 'search', 'status'));
|
||||||
|
}
|
||||||
|
|
||||||
// ---------------------------------------------------------
|
// ---------------------------------------------------------
|
||||||
// SHOW ADD CUSTOMER FORM
|
// SHOW ADD CUSTOMER FORM
|
||||||
// ---------------------------------------------------------
|
// ---------------------------------------------------------
|
||||||
@@ -130,5 +136,6 @@ class AdminCustomerController extends Controller
|
|||||||
|
|
||||||
return back()->with('success', 'Customer status updated.');
|
return back()->with('success', 'Customer status updated.');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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()
|
||||||
|
// {
|
||||||
|
// $orders = Order::with(['markList', 'shipments', 'invoice'])
|
||||||
|
// ->latest('id')
|
||||||
|
// ->get();
|
||||||
|
|
||||||
public function addTempItem(Request $request)
|
// 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()
|
||||||
{
|
{
|
||||||
// Validate item fields
|
// return a dedicated create view - create it at resources/views/admin/orders_create.blade.php
|
||||||
$item = $request->validate([
|
// If you prefer create UI on dashboard, change this to redirect route('admin.orders.index') etc.
|
||||||
'mark_no' => 'required',
|
$markList = MarkList::where('status', 'active')->get();
|
||||||
'origin' => 'required',
|
return view('admin.orders_create', compact('markList'));
|
||||||
'destination' => 'required',
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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,233 +138,207 @@ 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')
|
|
||||||
->with('error', 'You must finish or clear the current order before changing Mark No.');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Save mark, origin, destination ONLY ONCE
|
OrderItem::create($data);
|
||||||
if (!session()->has('mark_no')) {
|
|
||||||
session([
|
// recalc totals and save to order
|
||||||
'mark_no' => $request->mark_no,
|
$this->recalcTotals($order);
|
||||||
'origin' => $request->origin,
|
|
||||||
'destination' => $request->destination
|
return redirect()->back()->with('success', 'Item added and totals updated.');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Soft-delete an order item and recalc totals
|
||||||
|
*/
|
||||||
|
public function deleteItem($id)
|
||||||
|
{
|
||||||
|
$item = OrderItem::findOrFail($id);
|
||||||
|
$order = $item->order;
|
||||||
|
|
||||||
|
$item->delete(); // soft delete
|
||||||
|
|
||||||
|
// recalc totals
|
||||||
|
$this->recalcTotals($order);
|
||||||
|
|
||||||
|
return redirect()->back()->with('success', 'Item deleted and totals updated.');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Restore soft-deleted item and recalc totals
|
||||||
|
*/
|
||||||
|
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.');
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------------
|
||||||
|
// ORDER CRUD: update / destroy
|
||||||
|
// ---------------------------
|
||||||
|
public function update(Request $request, $id)
|
||||||
|
{
|
||||||
|
$order = Order::findOrFail($id);
|
||||||
|
|
||||||
|
$data = $request->validate([
|
||||||
|
'mark_no' => 'required|string',
|
||||||
|
'origin' => 'nullable|string',
|
||||||
|
'destination' => 'nullable|string',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$order->update([
|
||||||
|
'mark_no' => $data['mark_no'],
|
||||||
|
'origin' => $data['origin'] ?? null,
|
||||||
|
'destination' => $data['destination'] ?? null,
|
||||||
|
]);
|
||||||
|
|
||||||
|
// optionally recalc totals (not necessary unless you change item-level fields here)
|
||||||
|
$this->recalcTotals($order);
|
||||||
|
|
||||||
|
return redirect()->route('admin.orders.show', $order->id)
|
||||||
|
->with('success', 'Order updated successfully.');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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');
|
||||||
|
$prefix = "KNT-$year-";
|
||||||
|
|
||||||
|
$lastOrder = Order::latest('id')->first();
|
||||||
|
$nextNumber = $lastOrder ? intval(substr($lastOrder->order_id, -8)) + 1 : 1;
|
||||||
|
|
||||||
|
return $prefix . str_pad($nextNumber, 8, '0', STR_PAD_LEFT);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------------
|
||||||
|
// 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;
|
||||||
|
|
||||||
|
$invoice = Invoice::create([
|
||||||
|
'order_id' => $order->id,
|
||||||
|
'customer_id' => $customer->id ?? null,
|
||||||
|
'mark_no' => $order->mark_no,
|
||||||
|
'invoice_number' => $invoiceNumber,
|
||||||
|
'invoice_date' => now(),
|
||||||
|
'due_date' => now()->addDays(10),
|
||||||
|
'payment_method' => null,
|
||||||
|
'reference_no' => null,
|
||||||
|
'status' => 'pending',
|
||||||
|
'final_amount' => $totalAmount,
|
||||||
|
'gst_percent' => 0,
|
||||||
|
'gst_amount' => 0,
|
||||||
|
'final_amount_with_gst' => $totalAmount,
|
||||||
|
'customer_name' => $customer->customer_name ?? null,
|
||||||
|
'company_name' => $customer->company_name ?? null,
|
||||||
|
'customer_email' => $customer->email ?? null,
|
||||||
|
'customer_mobile' => $customer->mobile_no ?? null,
|
||||||
|
'customer_address' => $customer->address ?? null,
|
||||||
|
'pincode' => $customer->pincode ?? null,
|
||||||
|
'notes' => null,
|
||||||
|
'pdf_path' => null,
|
||||||
|
]);
|
||||||
|
|
||||||
|
// clone order items into invoice items
|
||||||
|
foreach ($order->items as $item) {
|
||||||
|
InvoiceItem::create([
|
||||||
|
'invoice_id' => $invoice->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,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ❌ 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.');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// -------------------------------------------------------------------------
|
private function generateInvoiceNumber()
|
||||||
// STEP 2 : DELETE TEMPORARY ITEM
|
|
||||||
// -------------------------------------------------------------------------
|
|
||||||
|
|
||||||
public function deleteTempItem(Request $request)
|
|
||||||
{
|
{
|
||||||
$index = $request->index;
|
$lastInvoice = Invoice::latest()->first();
|
||||||
|
$nextInvoice = $lastInvoice ? $lastInvoice->id + 1 : 1;
|
||||||
|
|
||||||
$items = session('temp_order_items', []);
|
return 'INV-' . date('Y') . '-' . str_pad($nextInvoice, 6, '0', STR_PAD_LEFT);
|
||||||
|
}
|
||||||
|
|
||||||
if (isset($items[$index])) {
|
private function getCustomerFromMarkList($markNo)
|
||||||
unset($items[$index]);
|
{
|
||||||
session(['temp_order_items' => array_values($items)]);
|
$markList = MarkList::where('mark_no', $markNo)->first();
|
||||||
|
|
||||||
|
if ($markList && $markList->customer_id) {
|
||||||
|
return User::where('customer_id', $markList->customer_id)->first();
|
||||||
}
|
}
|
||||||
|
|
||||||
// If no items left → reset mark_no lock
|
return null;
|
||||||
if (empty($items)) {
|
|
||||||
session()->forget(['mark_no', 'origin', 'destination']);
|
|
||||||
}
|
|
||||||
|
|
||||||
return redirect()->to(route('admin.orders.index') . '#createOrderForm')
|
|
||||||
->with('success', 'Item removed successfully.');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// -------------------------------------------------------------------------
|
private function getCustomerFromOrder($order)
|
||||||
// STEP 3 : FINISH ORDER
|
|
||||||
// -------------------------------------------------------------------------
|
|
||||||
|
|
||||||
public function finishOrder(Request $request)
|
|
||||||
{
|
|
||||||
$request->validate([
|
|
||||||
'mark_no' => 'required',
|
|
||||||
'origin' => 'required',
|
|
||||||
'destination' => 'required',
|
|
||||||
]);
|
|
||||||
|
|
||||||
$items = session('temp_order_items', []);
|
|
||||||
|
|
||||||
if (empty($items)) {
|
|
||||||
return redirect()->to(route('admin.orders.index') . '#createOrderForm')
|
|
||||||
->with('error', 'Add at least one item before finishing.');
|
|
||||||
}
|
|
||||||
|
|
||||||
// =======================
|
|
||||||
// GENERATE ORDER ID
|
|
||||||
// =======================
|
|
||||||
$year = date('y');
|
|
||||||
$prefix = "KNT-$year-";
|
|
||||||
|
|
||||||
$lastOrder = Order::latest('id')->first();
|
|
||||||
$nextNumber = $lastOrder ? intval(substr($lastOrder->order_id, -8)) + 1 : 1;
|
|
||||||
|
|
||||||
$orderId = $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
|
|
||||||
// =======================
|
|
||||||
|
|
||||||
// 1. Auto-generate invoice number
|
|
||||||
$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,
|
|
||||||
'customer_id' => $customer->id ?? null,
|
|
||||||
'mark_no' => $order->mark_no,
|
|
||||||
|
|
||||||
'invoice_number' => $invoiceNumber,
|
|
||||||
'invoice_date' => now(),
|
|
||||||
'due_date' => now()->addDays(10),
|
|
||||||
|
|
||||||
'payment_method' => null,
|
|
||||||
'reference_no' => null,
|
|
||||||
'status' => 'pending',
|
|
||||||
|
|
||||||
'final_amount' => $total_amount,
|
|
||||||
'gst_percent' => 0,
|
|
||||||
'gst_amount' => 0,
|
|
||||||
'final_amount_with_gst' => $total_amount,
|
|
||||||
|
|
||||||
// snapshot customer fields
|
|
||||||
'customer_name' => $customer->customer_name ?? null,
|
|
||||||
'company_name' => $customer->company_name ?? null,
|
|
||||||
'customer_email' => $customer->email ?? null,
|
|
||||||
'customer_mobile' => $customer->mobile_no ?? null,
|
|
||||||
'customer_address' => $customer->address ?? null,
|
|
||||||
'pincode' => $customer->pincode ?? null,
|
|
||||||
|
|
||||||
'notes' => null,
|
|
||||||
]);
|
|
||||||
|
|
||||||
// 4. Clone order items into invoice_items
|
|
||||||
foreach ($order->items as $item) {
|
|
||||||
\App\Models\InvoiceItem::create([
|
|
||||||
'invoice_id' => $invoice->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,
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 5. TODO: PDF generation (I will add this later)
|
|
||||||
$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);
|
|
||||||
|
|
||||||
$user = null;
|
|
||||||
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)
|
public function popup($id)
|
||||||
@@ -309,5 +378,46 @@ class AdminOrderController extends Controller
|
|||||||
|
|
||||||
return view('admin.orders', compact('orders'));
|
return view('admin.orders', compact('orders'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function downloadPdf(Request $request)
|
||||||
|
{
|
||||||
|
$query = Order::with(['markList', 'invoice', 'shipments']);
|
||||||
|
|
||||||
|
// Apply filters
|
||||||
|
if ($request->has('search') && $request->search) {
|
||||||
|
$search = $request->search;
|
||||||
|
$query->where(function($q) use ($search) {
|
||||||
|
$q->where('order_id', 'like', "%{$search}%")
|
||||||
|
->orWhereHas('markList', function($q) use ($search) {
|
||||||
|
$q->where('company_name', 'like', "%{$search}%");
|
||||||
|
})
|
||||||
|
->orWhereHas('invoice', function($q) use ($search) {
|
||||||
|
$q->where('invoice_number', 'like', "%{$search}%");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($request->has('status') && $request->status) {
|
||||||
|
$query->whereHas('invoice', function($q) use ($request) {
|
||||||
|
$q->where('status', $request->status);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($request->has('shipment') && $request->shipment) {
|
||||||
|
$query->whereHas('shipments', function($q) use ($request) {
|
||||||
|
$q->where('status', $request->shipment);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
$orders = $query->get();
|
||||||
|
|
||||||
|
$pdf = PDF::loadView('admin.orders.pdf', compact('orders'));
|
||||||
|
return $pdf->download('orders-report-' . date('Y-m-d') . '.pdf');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function downloadExcel(Request $request)
|
||||||
|
{
|
||||||
|
return Excel::download(new OrdersExport($request), 'orders-report-' . date('Y-m-d') . '.xlsx');
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ class ShipmentController extends Controller
|
|||||||
/**
|
/**
|
||||||
* Show shipment page (Create Shipment + Shipment List)
|
* Show shipment page (Create Shipment + Shipment List)
|
||||||
*/
|
*/
|
||||||
public function index()
|
public function index()
|
||||||
{
|
{
|
||||||
// 1) Get all used order IDs
|
// 1) Get all used order IDs
|
||||||
$usedOrderIds = ShipmentItem::pluck('order_id')->toArray();
|
$usedOrderIds = ShipmentItem::pluck('order_id')->toArray();
|
||||||
@@ -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.');
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -44,6 +44,8 @@ class RequestController extends Controller
|
|||||||
'pincode' => $request->pincode,
|
'pincode' => $request->pincode,
|
||||||
'date' => Carbon::now()->toDateString(), // Auto current date
|
'date' => Carbon::now()->toDateString(), // Auto current date
|
||||||
'status' => 'pending', // Default status
|
'status' => 'pending', // Default status
|
||||||
|
|
||||||
|
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// ✅ Response
|
// ✅ Response
|
||||||
|
|||||||
@@ -4,11 +4,13 @@ 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',
|
||||||
'mark_no',
|
'mark_no',
|
||||||
|
|||||||
@@ -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',
|
||||||
|
|||||||
@@ -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
|
||||||
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -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();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -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
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
BIN
public/invoices/invoice-INV-2025-000026.pdf
Normal file
BIN
public/invoices/invoice-INV-2025-000026.pdf
Normal file
Binary file not shown.
File diff suppressed because it is too large
Load Diff
@@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
.table-header {
|
/* Single gradient for entire header - Blue to Purple */
|
||||||
|
.table thead {
|
||||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%) !important;
|
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-header {
|
||||||
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,91 +422,360 @@
|
|||||||
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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 {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
margin-top: 15px;
|
||||||
|
padding: 12px 0;
|
||||||
|
border-top: 1px solid #eef3fb;
|
||||||
|
font-family: 'Inter', sans-serif;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pagination-info {
|
||||||
|
font-size: 13px;
|
||||||
|
color: #9ba5bb;
|
||||||
|
font-weight: 600;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pagination-controls {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
justify-content: flex-end;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pagination-btn {
|
||||||
|
background: #fff;
|
||||||
|
border: 1px solid #e3eaf6;
|
||||||
|
color: #1a2951;
|
||||||
|
padding: 8px 12px;
|
||||||
|
border-radius: 6px;
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 600;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
min-width: 40px;
|
||||||
|
height: 32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pagination-btn:hover:not(:disabled) {
|
||||||
|
background: #1a2951;
|
||||||
|
color: white;
|
||||||
|
border-color: #1a2951;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pagination-btn:disabled {
|
||||||
|
background: #f8fafc;
|
||||||
|
color: #cbd5e0;
|
||||||
|
border-color: #e2e8f0;
|
||||||
|
cursor: not-allowed;
|
||||||
|
opacity: 0.6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pagination-page-btn {
|
||||||
|
background: #fff;
|
||||||
|
border: 1px solid #e3eaf6;
|
||||||
|
color: #1a2951;
|
||||||
|
padding: 6px 12px;
|
||||||
|
border-radius: 6px;
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 600;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
min-width: 36px;
|
||||||
|
text-align: center;
|
||||||
|
text-decoration: none;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pagination-page-btn:hover {
|
||||||
|
background: #1a2951;
|
||||||
|
color: white;
|
||||||
|
border-color: #1a2951;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pagination-page-btn.active {
|
||||||
|
background: #1a2951;
|
||||||
|
color: white;
|
||||||
|
border-color: #1a2951;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pagination-pages {
|
||||||
|
display: flex;
|
||||||
|
gap: 4px;
|
||||||
|
align-items: center;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pagination-ellipsis {
|
||||||
|
color: #9ba5bb;
|
||||||
|
font-size: 13px;
|
||||||
|
padding: 0 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Image-based pagination buttons */
|
||||||
|
.pagination-img-btn {
|
||||||
|
background: #fff;
|
||||||
|
border: 1px solid #e3eaf6;
|
||||||
|
border-radius: 6px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
min-width: 40px;
|
||||||
|
height: 32px;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pagination-img-btn:hover:not(:disabled) {
|
||||||
|
background: #1a2951;
|
||||||
|
border-color: #1a2951;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pagination-img-btn:disabled {
|
||||||
|
background: #f8fafc;
|
||||||
|
border-color: #e2e8f0;
|
||||||
|
cursor: not-allowed;
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pagination-img-btn img {
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
filter: brightness(0) saturate(100%) invert(26%) sepia(89%) saturate(748%) hue-rotate(201deg) brightness(93%) contrast(89%);
|
||||||
|
transition: filter 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pagination-img-btn:hover:not(:disabled) img {
|
||||||
|
filter: brightness(0) saturate(100%) invert(100%) sepia(100%) saturate(0%) hue-rotate(288deg) brightness(106%) contrast(101%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.pagination-img-btn:disabled img {
|
||||||
|
filter: brightness(0) saturate(100%) invert(84%) sepia(8%) saturate(165%) hue-rotate(179deg) brightness(89%) contrast(86%);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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 {
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.pagination-container {
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 10px;
|
||||||
|
align-items: stretch;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pagination-controls {
|
||||||
|
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">{{ $customers->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">
|
||||||
@php
|
<div class="stat-icon">
|
||||||
$newThisMonth = $customers->filter(function($customer) {
|
<i class="bi bi-person-plus"></i>
|
||||||
return $customer->created_at->format('Y-m') === now()->format('Y-m');
|
</div>
|
||||||
})->count();
|
<div class="stat-content">
|
||||||
@endphp
|
<div class="stat-value">
|
||||||
{{ $newThisMonth }}
|
@php
|
||||||
|
$newThisMonth = $allCustomers->filter(function($customer) {
|
||||||
|
return $customer->created_at->format('Y-m') === now()->format('Y-m');
|
||||||
|
})->count();
|
||||||
|
@endphp
|
||||||
|
{{ $newThisMonth }}
|
||||||
|
</div>
|
||||||
|
<div class="stat-label">New This Month</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="stats-label">New This Month</div>
|
|
||||||
<i class="bi bi-person-plus stats-icon"></i>
|
|
||||||
</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">
|
||||||
@php
|
<div class="stat-icon">
|
||||||
$activeCustomers = $customers->where('status', 'active')->count();
|
<i class="bi bi-activity"></i>
|
||||||
@endphp
|
</div>
|
||||||
{{ $activeCustomers }}
|
<div class="stat-content">
|
||||||
|
<div class="stat-value">
|
||||||
|
@php
|
||||||
|
$activeCustomers = $allCustomers->where('status', 'active')->count();
|
||||||
|
@endphp
|
||||||
|
{{ $activeCustomers }}
|
||||||
|
</div>
|
||||||
|
<div class="stat-label">Active Customers</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="stats-label">Active Customers</div>
|
|
||||||
<i class="bi bi-activity stats-icon"></i>
|
|
||||||
</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">
|
||||||
@php
|
<div class="stat-icon">
|
||||||
$premiumCount = $customers->where('customer_type', 'premium')->count();
|
<i class="bi bi-award-fill"></i>
|
||||||
@endphp
|
</div>
|
||||||
{{ $premiumCount }}
|
<div class="stat-content">
|
||||||
|
<div class="stat-value">
|
||||||
|
@php
|
||||||
|
$premiumCount = $allCustomers->where('customer_type', 'premium')->count();
|
||||||
|
@endphp
|
||||||
|
{{ $premiumCount }}
|
||||||
|
</div>
|
||||||
|
<div class="stat-label">Premium Customers</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="stats-label">Premium Customers</div>
|
|
||||||
<i class="bi bi-award-fill stats-icon"></i>
|
|
||||||
</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">
|
||||||
@@ -368,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
|
||||||
@@ -404,16 +820,18 @@
|
|||||||
<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>
|
<tbody id="customersTableBody">
|
||||||
@forelse($customers as $c)
|
@forelse($customers as $c)
|
||||||
<tr>
|
<tr>
|
||||||
<!-- Customer Info Column -->
|
<!-- Customer Info Column -->
|
||||||
@@ -433,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>
|
||||||
|
|
||||||
@@ -461,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>
|
||||||
@@ -479,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>
|
||||||
@@ -489,6 +914,64 @@
|
|||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Pagination Controls -->
|
||||||
|
<div class="pagination-container">
|
||||||
|
<div class="pagination-info" id="pageInfo">
|
||||||
|
Showing {{ $customers->firstItem() ?? 0 }} to {{ $customers->lastItem() ?? 0 }} of {{ $customers->total() }} entries
|
||||||
|
</div>
|
||||||
|
<div class="pagination-controls">
|
||||||
|
<button class="pagination-img-btn" id="prevPageBtn" title="Previous page" {{ $customers->onFirstPage() ? 'disabled' : '' }}>
|
||||||
|
<!-- Left arrow SVG -->
|
||||||
|
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M10 12L6 8L10 4" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
<div class="pagination-pages" id="paginationPages">
|
||||||
|
@for ($i = 1; $i <= $customers->lastPage(); $i++)
|
||||||
|
<a href="{{ $customers->url($i) }}"
|
||||||
|
class="pagination-page-btn {{ $customers->currentPage() == $i ? 'active' : '' }}">
|
||||||
|
{{ $i }}
|
||||||
|
</a>
|
||||||
|
@endfor
|
||||||
|
</div>
|
||||||
|
<button class="pagination-img-btn" id="nextPageBtn" title="Next page" {{ $customers->hasMorePages() ? '' : 'disabled' }}>
|
||||||
|
<!-- Right arrow SVG -->
|
||||||
|
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M6 4L10 8L6 12" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
// Add hover effects to table rows
|
||||||
|
const tableRows = document.querySelectorAll('.table tbody tr');
|
||||||
|
tableRows.forEach(row => {
|
||||||
|
row.addEventListener('mouseenter', function() {
|
||||||
|
this.style.transform = 'translateX(5px)';
|
||||||
|
});
|
||||||
|
|
||||||
|
row.addEventListener('mouseleave', function() {
|
||||||
|
this.style.transform = 'translateX(0)';
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Pagination button handlers
|
||||||
|
document.getElementById('prevPageBtn').addEventListener('click', function() {
|
||||||
|
@if(!$customers->onFirstPage())
|
||||||
|
window.location.href = '{{ $customers->previousPageUrl() }}';
|
||||||
|
@endif
|
||||||
|
});
|
||||||
|
|
||||||
|
document.getElementById('nextPageBtn').addEventListener('click', function() {
|
||||||
|
@if($customers->hasMorePages())
|
||||||
|
window.location.href = '{{ $customers->nextPageUrl() }}';
|
||||||
|
@endif
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
@endsection
|
@endsection
|
||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
.badge {
|
/* ===== UPDATED STATUS BADGE STYLES ===== */
|
||||||
font-size:13px;
|
.badge {
|
||||||
font-weight:600;
|
padding: 7px 17px !important;
|
||||||
padding:7px 17px;
|
border-radius: 20px !important;
|
||||||
border-radius:12px;
|
font-weight: 600 !important;
|
||||||
|
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,143 @@ 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-container {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
margin-top: 15px;
|
||||||
|
padding: 12px 0;
|
||||||
|
border-top: 1px solid #eef3fb;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pagination-info {
|
||||||
|
font-size: 13px;
|
||||||
|
color: #9ba5bb;
|
||||||
|
font-weight: 600;
|
||||||
|
font-family: 'Inter', sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pagination-controls {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pagination-btn {
|
||||||
|
background: #fff;
|
||||||
|
border: 1px solid #e3eaf6;
|
||||||
|
color: #1a2951;
|
||||||
|
padding: 8px 12px;
|
||||||
|
border-radius: 6px;
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 600;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
min-width: 40px;
|
||||||
|
height: 32px;
|
||||||
|
font-family: 'Inter', sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pagination-btn:hover:not(:disabled) {
|
||||||
|
background: #1a2951;
|
||||||
|
color: white;
|
||||||
|
border-color: #1a2951;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pagination-btn:disabled {
|
||||||
|
background: #f8fafc;
|
||||||
|
color: #cbd5e0;
|
||||||
|
border-color: #e2e8f0;
|
||||||
|
cursor: not-allowed;
|
||||||
|
opacity: 0.6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pagination-page-btn {
|
||||||
|
background: #fff;
|
||||||
|
border: 1px solid #e3eaf6;
|
||||||
|
color: #1a2951;
|
||||||
|
padding: 6px 12px;
|
||||||
|
border-radius: 6px;
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 600;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
min-width: 36px;
|
||||||
|
text-align: center;
|
||||||
|
font-family: 'Inter', sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pagination-page-btn:hover {
|
||||||
|
background: #1a2951;
|
||||||
|
color: white;
|
||||||
|
border-color: #1a2951;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pagination-page-btn.active {
|
||||||
|
background: #1a2951;
|
||||||
|
color: white;
|
||||||
|
border-color: #1a2951;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pagination-pages {
|
||||||
|
display: flex;
|
||||||
|
gap: 4px;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pagination-ellipsis {
|
||||||
|
color: #9ba5bb;
|
||||||
|
font-size: 13px;
|
||||||
|
padding: 0 4px;
|
||||||
|
font-family: 'Inter', sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pagination-img-btn {
|
||||||
|
background: #fff;
|
||||||
|
border: 1px solid #e3eaf6;
|
||||||
|
border-radius: 6px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
min-width: 40px;
|
||||||
|
height: 32px;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pagination-img-btn:hover:not(:disabled) {
|
||||||
|
background: #1a2951;
|
||||||
|
border-color: #1a2951;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pagination-img-btn:disabled {
|
||||||
|
background: #f8fafc;
|
||||||
|
border-color: #e2e8f0;
|
||||||
|
cursor: not-allowed;
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pagination-img-btn img {
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
filter: brightness(0) saturate(100%) invert(26%) sepia(89%) saturate(748%) hue-rotate(201deg) brightness(93%) contrast(89%);
|
||||||
|
transition: filter 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pagination-img-btn:hover:not(:disabled) img {
|
||||||
|
filter: brightness(0) saturate(100%) invert(100%) sepia(100%) saturate(0%) hue-rotate(288deg) brightness(106%) contrast(101%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.pagination-img-btn:disabled img {
|
||||||
|
filter: brightness(0) saturate(100%) invert(84%) sepia(8%) saturate(165%) hue-rotate(179deg) brightness(89%) contrast(86%);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ===== RESPONSIVE BREAKPOINTS ===== */
|
/* ===== RESPONSIVE BREAKPOINTS ===== */
|
||||||
@@ -596,7 +827,17 @@ body, .container-fluid {
|
|||||||
|
|
||||||
.table th,
|
.table th,
|
||||||
.table td {
|
.table td {
|
||||||
padding: 10px 5px;
|
padding: 12px 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pagination-container {
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 10px;
|
||||||
|
align-items: stretch;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pagination-controls {
|
||||||
|
justify-content: center;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -669,7 +910,7 @@ body, .container-fluid {
|
|||||||
|
|
||||||
.table th,
|
.table th,
|
||||||
.table td {
|
.table td {
|
||||||
padding: 8px 4px;
|
padding: 10px 6px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.badge {
|
.badge {
|
||||||
@@ -771,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 {
|
||||||
@@ -900,69 +1141,107 @@ body, .container-fluid {
|
|||||||
<div class="card shadow-sm">
|
<div class="card shadow-sm">
|
||||||
<div class="card-header bg-light">
|
<div class="card-header bg-light">
|
||||||
<strong>Recent Orders</strong>
|
<strong>Recent Orders</strong>
|
||||||
|
<span style="font-size:13px;color:#6577a3;margin-left:10px;">
|
||||||
|
Total orders: <span id="ordersCount">{{ $orders->count() }}</span>
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="card-body table-responsive">
|
<div class="card-body table-responsive">
|
||||||
<table class="table table-striped table-bordered align-middle text-center">
|
<div class="table-wrapper">
|
||||||
<thead class="table-light">
|
<table class="table table-striped table-bordered align-middle text-center">
|
||||||
<tr>
|
<thead class="table-light">
|
||||||
<th>#</th>
|
<tr>
|
||||||
<th>Order ID</th>
|
<th>#</th>
|
||||||
<th>Mark No</th>
|
<th>Order ID</th>
|
||||||
<th>Origin</th>
|
<th>Mark No</th>
|
||||||
<th>Destination</th>
|
<th>Origin</th>
|
||||||
<th>Total CTN</th>
|
<th>Destination</th>
|
||||||
<th>Total QTY</th>
|
<th>Total CTN</th>
|
||||||
<th>Total TTL/QTY</th>
|
<th>Total QTY</th>
|
||||||
<th>Total Amount (₹)</th>
|
<th>Total TTL/QTY</th>
|
||||||
<th>Total CBM</th>
|
<th>Total Amount (₹)</th>
|
||||||
<th>Total TTL CBM</th>
|
<th>Total CBM</th>
|
||||||
<th>Total KG</th>
|
<th>Total TTL CBM</th>
|
||||||
<th>Total TTL KG</th>
|
<th>Total KG</th>
|
||||||
<th>Status</th>
|
<th>Total TTL KG</th>
|
||||||
<th>Date</th>
|
<th>Status</th>
|
||||||
<th>Actions</th>
|
<th>Date</th>
|
||||||
</tr>
|
<th>Actions</th>
|
||||||
</thead>
|
</tr>
|
||||||
<tbody>
|
</thead>
|
||||||
@forelse($orders as $order)
|
<tbody id="ordersTableBody">
|
||||||
<tr>
|
@forelse($orders as $order)
|
||||||
<td>{{ $order->id }}</td>
|
<tr>
|
||||||
<td>
|
<td>{{ $order->id }}</td>
|
||||||
<a href="javascript:void(0)"
|
|
||||||
class="fw-semibold text-primary open-order-modal"
|
|
||||||
data-id="{{ $order->id }}">
|
|
||||||
{{ $order->order_id }}
|
|
||||||
</a>
|
|
||||||
</td>
|
|
||||||
|
|
||||||
<td>{{ $order->mark_no }}</td>
|
|
||||||
<td>{{ $order->origin }}</td>
|
|
||||||
<td>{{ $order->destination }}</td>
|
|
||||||
<td>{{ $order->ctn }}</td>
|
|
||||||
<td>{{ $order->qty }}</td>
|
|
||||||
<td>{{ $order->ttl_qty }}</td>
|
|
||||||
<td>₹{{ number_format($order->ttl_amount, 2) }}</td>
|
|
||||||
<td>{{ $order->cbm }}</td>
|
|
||||||
<td>{{ $order->ttl_cbm }}</td>
|
|
||||||
<td>{{ $order->kg }}</td>
|
|
||||||
<td>{{ $order->ttl_kg }}</td>
|
|
||||||
<td>
|
<td>
|
||||||
<span class="badge bg-info text-dark">{{ ucfirst($order->status) }}</span>
|
<a href="javascript:void(0)"
|
||||||
</td>
|
class="fw-semibold text-primary open-order-modal"
|
||||||
<td>{{ $order->created_at->format('d-m-Y') }}</td>
|
data-id="{{ $order->id }}">
|
||||||
<td>
|
{{ $order->order_id }}
|
||||||
<a href="{{ route('admin.orders.show', $order->id) }}" class="btn btn-sm btn-outline-primary">
|
|
||||||
<i class="bi bi-eye"></i> View
|
|
||||||
</a>
|
</a>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
|
||||||
@empty
|
<td>{{ $order->mark_no }}</td>
|
||||||
<tr>
|
<td>{{ $order->origin }}</td>
|
||||||
<td colspan="16" class="text-muted">No orders found</td>
|
<td>{{ $order->destination }}</td>
|
||||||
</tr>
|
<td>{{ $order->ctn }}</td>
|
||||||
@endforelse
|
<td>{{ $order->qty }}</td>
|
||||||
</tbody>
|
<td>{{ $order->ttl_qty }}</td>
|
||||||
</table>
|
<td>₹{{ number_format($order->ttl_amount, 2) }}</td>
|
||||||
|
<td>{{ $order->cbm }}</td>
|
||||||
|
<td>{{ $order->ttl_cbm }}</td>
|
||||||
|
<td>{{ $order->kg }}</td>
|
||||||
|
<td>{{ $order->ttl_kg }}</td>
|
||||||
|
<td>
|
||||||
|
<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>{{ $order->created_at->format('d-m-Y') }}</td>
|
||||||
|
<td>
|
||||||
|
<a href="{{ route('admin.orders.show', $order->id) }}" class="btn btn-sm btn-outline-primary">
|
||||||
|
<i class="bi bi-eye"></i> View
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
@empty
|
||||||
|
<tr>
|
||||||
|
<td colspan="16" class="text-muted">No orders found</td>
|
||||||
|
</tr>
|
||||||
|
@endforelse
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Pagination Controls -->
|
||||||
|
<div class="pagination-container">
|
||||||
|
<div class="pagination-info" id="pageInfo">Showing 1 to 10 of {{ $orders->count() }} entries</div>
|
||||||
|
<div class="pagination-controls">
|
||||||
|
<button class="pagination-img-btn" id="prevPageBtn" title="Previous page">
|
||||||
|
<!-- Left arrow SVG -->
|
||||||
|
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M10 12L6 8L10 4" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
<div class="pagination-pages" id="paginationPages">
|
||||||
|
<!-- Page numbers will be inserted here -->
|
||||||
|
</div>
|
||||||
|
<button class="pagination-img-btn" id="nextPageBtn" title="Next page">
|
||||||
|
<!-- Right arrow SVG -->
|
||||||
|
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M6 4L10 8L6 12" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -1167,6 +1446,14 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||||||
const closeBtn = document.getElementById('closeCreateOrderModal');
|
const closeBtn = document.getElementById('closeCreateOrderModal');
|
||||||
const clearFormBtn = document.getElementById('clearForm');
|
const clearFormBtn = document.getElementById('clearForm');
|
||||||
|
|
||||||
|
// Pagination state
|
||||||
|
let currentPage = 1;
|
||||||
|
const ordersPerPage = 10;
|
||||||
|
let allOrders = @json($orders->values());
|
||||||
|
|
||||||
|
// Initialize pagination
|
||||||
|
initializePagination();
|
||||||
|
|
||||||
// Reset temp data function
|
// Reset temp data function
|
||||||
const resetTempData = () => {
|
const resetTempData = () => {
|
||||||
fetch('{{ route("admin.orders.temp.reset") }}', {
|
fetch('{{ route("admin.orders.temp.reset") }}', {
|
||||||
@@ -1265,6 +1552,174 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/* ---------- Pagination Functions ---------- */
|
||||||
|
function initializePagination() {
|
||||||
|
renderOrdersTable(allOrders);
|
||||||
|
updatePaginationControls();
|
||||||
|
|
||||||
|
// Bind pagination buttons
|
||||||
|
document.getElementById('prevPageBtn').addEventListener('click', goToPreviousPage);
|
||||||
|
document.getElementById('nextPageBtn').addEventListener('click', goToNextPage);
|
||||||
|
}
|
||||||
|
|
||||||
|
function goToPreviousPage() {
|
||||||
|
if (currentPage > 1) {
|
||||||
|
currentPage--;
|
||||||
|
renderOrdersTable(allOrders);
|
||||||
|
updatePaginationControls();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function goToNextPage() {
|
||||||
|
const totalPages = Math.ceil(allOrders.length / ordersPerPage);
|
||||||
|
if (currentPage < totalPages) {
|
||||||
|
currentPage++;
|
||||||
|
renderOrdersTable(allOrders);
|
||||||
|
updatePaginationControls();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function updatePaginationControls() {
|
||||||
|
const totalPages = Math.ceil(allOrders.length / ordersPerPage);
|
||||||
|
const prevBtn = document.getElementById('prevPageBtn');
|
||||||
|
const nextBtn = document.getElementById('nextPageBtn');
|
||||||
|
const pageInfo = document.getElementById('pageInfo');
|
||||||
|
const paginationPages = document.getElementById('paginationPages');
|
||||||
|
|
||||||
|
prevBtn.disabled = currentPage === 1;
|
||||||
|
nextBtn.disabled = currentPage === totalPages || totalPages === 0;
|
||||||
|
|
||||||
|
// Update page info text
|
||||||
|
const startIndex = (currentPage - 1) * ordersPerPage + 1;
|
||||||
|
const endIndex = Math.min(currentPage * ordersPerPage, allOrders.length);
|
||||||
|
pageInfo.textContent = `Showing ${startIndex} to ${endIndex} of ${allOrders.length} entries`;
|
||||||
|
|
||||||
|
// Generate page numbers
|
||||||
|
paginationPages.innerHTML = '';
|
||||||
|
|
||||||
|
if (totalPages <= 7) {
|
||||||
|
// Show all pages
|
||||||
|
for (let i = 1; i <= totalPages; i++) {
|
||||||
|
addPageButton(i, paginationPages);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Show first page, current page range, and last page
|
||||||
|
addPageButton(1, paginationPages);
|
||||||
|
|
||||||
|
if (currentPage > 3) {
|
||||||
|
paginationPages.innerHTML += '<span class="pagination-ellipsis">...</span>';
|
||||||
|
}
|
||||||
|
|
||||||
|
const start = Math.max(2, currentPage - 1);
|
||||||
|
const end = Math.min(totalPages - 1, currentPage + 1);
|
||||||
|
|
||||||
|
for (let i = start; i <= end; i++) {
|
||||||
|
addPageButton(i, paginationPages);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentPage < totalPages - 2) {
|
||||||
|
paginationPages.innerHTML += '<span class="pagination-ellipsis">...</span>';
|
||||||
|
}
|
||||||
|
|
||||||
|
addPageButton(totalPages, paginationPages);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function addPageButton(pageNumber, container) {
|
||||||
|
const button = document.createElement('button');
|
||||||
|
button.className = 'pagination-page-btn';
|
||||||
|
if (pageNumber === currentPage) {
|
||||||
|
button.classList.add('active');
|
||||||
|
}
|
||||||
|
button.textContent = pageNumber;
|
||||||
|
button.addEventListener('click', () => {
|
||||||
|
currentPage = pageNumber;
|
||||||
|
renderOrdersTable(allOrders);
|
||||||
|
updatePaginationControls();
|
||||||
|
});
|
||||||
|
container.appendChild(button);
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderOrdersTable(orders) {
|
||||||
|
const tbody = document.getElementById('ordersTableBody');
|
||||||
|
tbody.innerHTML = '';
|
||||||
|
|
||||||
|
if (!orders || orders.length === 0) {
|
||||||
|
tbody.innerHTML = '<tr><td colspan="16" class="text-muted">No orders found</td></tr>';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate pagination
|
||||||
|
const startIndex = (currentPage - 1) * ordersPerPage;
|
||||||
|
const endIndex = startIndex + ordersPerPage;
|
||||||
|
const paginatedOrders = orders.slice(startIndex, endIndex);
|
||||||
|
|
||||||
|
paginatedOrders.forEach(order => {
|
||||||
|
const tr = document.createElement('tr');
|
||||||
|
tr.innerHTML = `
|
||||||
|
<td>${order.id}</td>
|
||||||
|
<td>
|
||||||
|
<a href="javascript:void(0)"
|
||||||
|
class="fw-semibold text-primary open-order-modal"
|
||||||
|
data-id="${order.id}">
|
||||||
|
${order.order_id}
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
<td>${order.mark_no || ''}</td>
|
||||||
|
<td>${order.origin || ''}</td>
|
||||||
|
<td>${order.destination || ''}</td>
|
||||||
|
<td>${order.ctn || ''}</td>
|
||||||
|
<td>${order.qty || ''}</td>
|
||||||
|
<td>${order.ttl_qty || ''}</td>
|
||||||
|
<td>₹${order.ttl_amount ? Number(order.ttl_amount).toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 }) : '0.00'}</td>
|
||||||
|
<td>${order.cbm || ''}</td>
|
||||||
|
<td>${order.ttl_cbm || ''}</td>
|
||||||
|
<td>${order.kg || ''}</td>
|
||||||
|
<td>${order.ttl_kg || ''}</td>
|
||||||
|
<td>
|
||||||
|
<span class="badge 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>${new Date(order.created_at).toLocaleDateString('en-GB')}</td>
|
||||||
|
<td>
|
||||||
|
<a href="/admin/orders/${order.id}" class="btn btn-sm btn-outline-primary">
|
||||||
|
<i class="bi bi-eye"></i> View
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
`;
|
||||||
|
tbody.appendChild(tr);
|
||||||
|
|
||||||
|
// Re-bind order details modal for newly rendered rows
|
||||||
|
const orderLink = tr.querySelector('.open-order-modal');
|
||||||
|
if (orderLink) {
|
||||||
|
orderLink.addEventListener('click', function() {
|
||||||
|
let id = this.dataset.id;
|
||||||
|
let modal = new bootstrap.Modal(document.getElementById('orderDetailsModal'));
|
||||||
|
|
||||||
|
document.getElementById('orderDetailsBody').innerHTML =
|
||||||
|
"<p class='text-center text-muted'>Loading...</p>";
|
||||||
|
|
||||||
|
modal.show();
|
||||||
|
|
||||||
|
fetch(`/admin/orders/view/${id}`)
|
||||||
|
.then(response => response.text())
|
||||||
|
.then(html => {
|
||||||
|
document.getElementById('orderDetailsBody').innerHTML = html;
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
document.getElementById('orderDetailsBody').innerHTML =
|
||||||
|
"<p class='text-danger text-center'>Failed to load order details.</p>";
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -277,6 +277,139 @@
|
|||||||
from { box-shadow: 0 0 0px #b4a02455 inset; }
|
from { box-shadow: 0 0 0px #b4a02455 inset; }
|
||||||
to { box-shadow: 0 0 10px #b4a024aa inset; }
|
to { box-shadow: 0 0 10px #b4a024aa inset; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ---------- Pagination Styles ---------- */
|
||||||
|
.pagination-container {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
margin-top: 15px;
|
||||||
|
padding: 12px 0;
|
||||||
|
border-top: 1px solid #eef3fb;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pagination-info {
|
||||||
|
font-size: 13px;
|
||||||
|
color: #9ba5bb;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pagination-controls {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pagination-btn {
|
||||||
|
background: #fff;
|
||||||
|
border: 1px solid #e3eaf6;
|
||||||
|
color: #1a2951;
|
||||||
|
padding: 8px 12px;
|
||||||
|
border-radius: 6px;
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 600;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
min-width: 40px;
|
||||||
|
height: 32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pagination-btn:hover:not(:disabled) {
|
||||||
|
background: #1a2951;
|
||||||
|
color: white;
|
||||||
|
border-color: #1a2951;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pagination-btn:disabled {
|
||||||
|
background: #f8fafc;
|
||||||
|
color: #cbd5e0;
|
||||||
|
border-color: #e2e8f0;
|
||||||
|
cursor: not-allowed;
|
||||||
|
opacity: 0.6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pagination-page-btn {
|
||||||
|
background: #fff;
|
||||||
|
border: 1px solid #e3eaf6;
|
||||||
|
color: #1a2951;
|
||||||
|
padding: 6px 12px;
|
||||||
|
border-radius: 6px;
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 600;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
min-width: 36px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pagination-page-btn:hover {
|
||||||
|
background: #1a2951;
|
||||||
|
color: white;
|
||||||
|
border-color: #1a2951;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pagination-page-btn.active {
|
||||||
|
background: #1a2951;
|
||||||
|
color: white;
|
||||||
|
border-color: #1a2951;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pagination-pages {
|
||||||
|
display: flex;
|
||||||
|
gap: 4px;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pagination-ellipsis {
|
||||||
|
color: #9ba5bb;
|
||||||
|
font-size: 13px;
|
||||||
|
padding: 0 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Image-based pagination buttons */
|
||||||
|
.pagination-img-btn {
|
||||||
|
background: #fff;
|
||||||
|
border: 1px solid #e3eaf6;
|
||||||
|
border-radius: 6px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
min-width: 40px;
|
||||||
|
height: 32px;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pagination-img-btn:hover:not(:disabled) {
|
||||||
|
background: #1a2951;
|
||||||
|
border-color: #1a2951;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pagination-img-btn:disabled {
|
||||||
|
background: #f8fafc;
|
||||||
|
border-color: #e2e8f0;
|
||||||
|
cursor: not-allowed;
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pagination-img-btn img {
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
filter: brightness(0) saturate(100%) invert(26%) sepia(89%) saturate(748%) hue-rotate(201deg) brightness(93%) contrast(89%);
|
||||||
|
transition: filter 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pagination-img-btn:hover:not(:disabled) img {
|
||||||
|
filter: brightness(0) saturate(100%) invert(100%) sepia(100%) saturate(0%) hue-rotate(288deg) brightness(106%) contrast(101%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.pagination-img-btn:disabled img {
|
||||||
|
filter: brightness(0) saturate(100%) invert(84%) sepia(8%) saturate(165%) hue-rotate(179deg) brightness(89%) contrast(86%);
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
@if(session('success'))
|
@if(session('success'))
|
||||||
@@ -304,63 +437,207 @@
|
|||||||
<th>Action</th>
|
<th>Action</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody id="markListTableBody">
|
||||||
@foreach($markList as $mark)
|
<!-- Data will be loaded dynamically -->
|
||||||
<tr>
|
|
||||||
<td>{{ $mark->id }}</td>
|
|
||||||
<td>{{ $mark->mark_no }}</td>
|
|
||||||
<td>{{ $mark->origin }}</td>
|
|
||||||
<td>{{ $mark->destination }}</td>
|
|
||||||
<td>{{ $mark->customer_name }}</td>
|
|
||||||
<td>{{ $mark->customer_id }}</td>
|
|
||||||
<td>{{ $mark->mobile_no }}</td>
|
|
||||||
<td>{{ \Carbon\Carbon::parse($mark->date)->format('d-m-Y') }}</td>
|
|
||||||
<td>
|
|
||||||
@if($mark->status == 'active')
|
|
||||||
<span class="badge badge-active">
|
|
||||||
<i class="bi bi-check-circle-fill status-icon"></i>
|
|
||||||
Active
|
|
||||||
</span>
|
|
||||||
@else
|
|
||||||
<span class="badge badge-inactive">
|
|
||||||
<i class="bi bi-exclamation-triangle-fill status-icon"></i>
|
|
||||||
In-Active
|
|
||||||
</span>
|
|
||||||
@endif
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
@if($mark->status == 'active')
|
|
||||||
<a href="{{ route('admin.marklist.toggle', $mark->id) }}" class="btn-action btn-action-deactivate">
|
|
||||||
<i class="bi bi-power btn-icon"></i>
|
|
||||||
Deactivate
|
|
||||||
</a>
|
|
||||||
@else
|
|
||||||
<a href="{{ route('admin.marklist.toggle', $mark->id) }}" class="btn-action btn-action-activate">
|
|
||||||
<i class="bi bi-play-circle btn-icon"></i>
|
|
||||||
Activate
|
|
||||||
</a>
|
|
||||||
@endif
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
@endforeach
|
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
@if($markList->isEmpty())
|
<!-- Pagination Controls -->
|
||||||
<div class="py-4 text-center text-muted fst-italic">No mark numbers found.</div>
|
<div class="pagination-container">
|
||||||
@endif
|
<div class="pagination-info" id="pageInfo">Showing 0 entries</div>
|
||||||
|
<div class="pagination-controls">
|
||||||
|
<button class="pagination-img-btn" id="prevPageBtn" title="Previous page" disabled>
|
||||||
|
<!-- Left arrow SVG -->
|
||||||
|
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M10 12L6 8L10 4" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
<div class="pagination-pages" id="paginationPages">
|
||||||
|
<!-- Page numbers will be inserted here -->
|
||||||
|
</div>
|
||||||
|
<button class="pagination-img-btn" id="nextPageBtn" title="Next page" disabled>
|
||||||
|
<!-- Right arrow SVG -->
|
||||||
|
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M6 4L10 8L6 12" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="noResults" class="py-4 text-center text-muted fst-italic" style="display: none;">No mark numbers found.</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
document.getElementById('globalSearch').addEventListener('input', function () {
|
// Pagination state
|
||||||
const filter = this.value.toLowerCase();
|
let currentPage = 1;
|
||||||
const rows = document.querySelectorAll('#markListTable tbody tr');
|
const itemsPerPage = 10;
|
||||||
|
let allMarkList = @json($markList);
|
||||||
|
let filteredMarkList = [...allMarkList];
|
||||||
|
|
||||||
rows.forEach(row => {
|
// Initialize pagination
|
||||||
const text = row.textContent.toLowerCase();
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
row.style.display = text.includes(filter) ? '' : 'none';
|
renderTable();
|
||||||
});
|
updatePaginationControls();
|
||||||
|
|
||||||
|
// Bind pagination events
|
||||||
|
document.getElementById('prevPageBtn').addEventListener('click', goToPreviousPage);
|
||||||
|
document.getElementById('nextPageBtn').addEventListener('click', goToNextPage);
|
||||||
|
|
||||||
|
// Bind search event
|
||||||
|
document.getElementById('globalSearch').addEventListener('input', handleSearch);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Pagination Functions
|
||||||
|
function goToPreviousPage() {
|
||||||
|
if (currentPage > 1) {
|
||||||
|
currentPage--;
|
||||||
|
renderTable();
|
||||||
|
updatePaginationControls();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function goToNextPage() {
|
||||||
|
const totalPages = Math.ceil(filteredMarkList.length / itemsPerPage);
|
||||||
|
if (currentPage < totalPages) {
|
||||||
|
currentPage++;
|
||||||
|
renderTable();
|
||||||
|
updatePaginationControls();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function updatePaginationControls() {
|
||||||
|
const totalPages = Math.ceil(filteredMarkList.length / itemsPerPage);
|
||||||
|
const prevBtn = document.getElementById('prevPageBtn');
|
||||||
|
const nextBtn = document.getElementById('nextPageBtn');
|
||||||
|
const pageInfo = document.getElementById('pageInfo');
|
||||||
|
const paginationPages = document.getElementById('paginationPages');
|
||||||
|
|
||||||
|
prevBtn.disabled = currentPage === 1;
|
||||||
|
nextBtn.disabled = currentPage === totalPages || totalPages === 0;
|
||||||
|
|
||||||
|
// Update page info text
|
||||||
|
const startIndex = (currentPage - 1) * itemsPerPage + 1;
|
||||||
|
const endIndex = Math.min(currentPage * itemsPerPage, filteredMarkList.length);
|
||||||
|
pageInfo.textContent = `Showing ${startIndex} to ${endIndex} of ${filteredMarkList.length} entries`;
|
||||||
|
|
||||||
|
// Generate page numbers
|
||||||
|
paginationPages.innerHTML = '';
|
||||||
|
|
||||||
|
if (totalPages <= 7) {
|
||||||
|
// Show all pages
|
||||||
|
for (let i = 1; i <= totalPages; i++) {
|
||||||
|
addPageButton(i, paginationPages);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Show first page, current page range, and last page
|
||||||
|
addPageButton(1, paginationPages);
|
||||||
|
|
||||||
|
if (currentPage > 3) {
|
||||||
|
paginationPages.innerHTML += '<span class="pagination-ellipsis">...</span>';
|
||||||
|
}
|
||||||
|
|
||||||
|
const start = Math.max(2, currentPage - 1);
|
||||||
|
const end = Math.min(totalPages - 1, currentPage + 1);
|
||||||
|
|
||||||
|
for (let i = start; i <= end; i++) {
|
||||||
|
addPageButton(i, paginationPages);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentPage < totalPages - 2) {
|
||||||
|
paginationPages.innerHTML += '<span class="pagination-ellipsis">...</span>';
|
||||||
|
}
|
||||||
|
|
||||||
|
addPageButton(totalPages, paginationPages);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function addPageButton(pageNumber, container) {
|
||||||
|
const button = document.createElement('button');
|
||||||
|
button.className = 'pagination-page-btn';
|
||||||
|
if (pageNumber === currentPage) {
|
||||||
|
button.classList.add('active');
|
||||||
|
}
|
||||||
|
button.textContent = pageNumber;
|
||||||
|
button.addEventListener('click', () => {
|
||||||
|
currentPage = pageNumber;
|
||||||
|
renderTable();
|
||||||
|
updatePaginationControls();
|
||||||
|
});
|
||||||
|
container.appendChild(button);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Search Function
|
||||||
|
function handleSearch() {
|
||||||
|
const filter = this.value.toLowerCase();
|
||||||
|
filteredMarkList = allMarkList.filter(mark => {
|
||||||
|
return Object.values(mark).some(value =>
|
||||||
|
String(value).toLowerCase().includes(filter)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
currentPage = 1;
|
||||||
|
renderTable();
|
||||||
|
updatePaginationControls();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Render Table Function - FIXED: Using direct URL construction
|
||||||
|
function renderTable() {
|
||||||
|
const tbody = document.getElementById('markListTableBody');
|
||||||
|
const noResults = document.getElementById('noResults');
|
||||||
|
tbody.innerHTML = '';
|
||||||
|
|
||||||
|
if (filteredMarkList.length === 0) {
|
||||||
|
tbody.innerHTML = '';
|
||||||
|
noResults.style.display = 'block';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
noResults.style.display = 'none';
|
||||||
|
|
||||||
|
// Calculate pagination
|
||||||
|
const startIndex = (currentPage - 1) * itemsPerPage;
|
||||||
|
const endIndex = startIndex + itemsPerPage;
|
||||||
|
const paginatedItems = filteredMarkList.slice(startIndex, endIndex);
|
||||||
|
|
||||||
|
paginatedItems.forEach(mark => {
|
||||||
|
const row = document.createElement('tr');
|
||||||
|
row.innerHTML = `
|
||||||
|
<td>${mark.id}</td>
|
||||||
|
<td>${mark.mark_no}</td>
|
||||||
|
<td>${mark.origin}</td>
|
||||||
|
<td>${mark.destination}</td>
|
||||||
|
<td>${mark.customer_name}</td>
|
||||||
|
<td>${mark.customer_id}</td>
|
||||||
|
<td>${mark.mobile_no}</td>
|
||||||
|
<td>${new Date(mark.date).toLocaleDateString('en-GB')}</td>
|
||||||
|
<td>
|
||||||
|
${mark.status == 'active'
|
||||||
|
? `<span class="badge badge-active">
|
||||||
|
<i class="bi bi-check-circle-fill status-icon"></i>
|
||||||
|
Active
|
||||||
|
</span>`
|
||||||
|
: `<span class="badge badge-inactive">
|
||||||
|
<i class="bi bi-exclamation-triangle-fill status-icon"></i>
|
||||||
|
In-Active
|
||||||
|
</span>`
|
||||||
|
}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
${mark.status == 'active'
|
||||||
|
? `<a href="/admin/mark-list/status/${mark.id}" class="btn-action btn-action-deactivate">
|
||||||
|
<i class="bi bi-power btn-icon"></i>
|
||||||
|
Deactivate
|
||||||
|
</a>`
|
||||||
|
: `<a href="/admin/mark-list/status/${mark.id}" class="btn-action btn-action-activate">
|
||||||
|
<i class="bi bi-play-circle btn-icon"></i>
|
||||||
|
Activate
|
||||||
|
</a>`
|
||||||
|
}
|
||||||
|
</td>
|
||||||
|
`;
|
||||||
|
tbody.appendChild(row);
|
||||||
|
});
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -5,28 +5,96 @@
|
|||||||
@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">
|
||||||
<div class="rounded-circle bg-secondary text-white d-flex align-items-center justify-content-center"
|
<div class="rounded-circle bg-secondary text-white d-flex align-items-center justify-content-center"
|
||||||
style="width:60px; height:60px; font-size:20px;">
|
style="width:60px; height:60px; font-size:20px;">
|
||||||
{{ 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
|
||||||
43
resources/views/admin/pdf/order_pdf.blade.php
Normal file
43
resources/views/admin/pdf/order_pdf.blade.php
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>Orders Report</title>
|
||||||
|
<style>
|
||||||
|
body { font-family: DejaVu Sans, sans-serif; font-size: 12px; }
|
||||||
|
table { width: 100%; border-collapse: collapse; margin-top: 10px; }
|
||||||
|
th, td { border: 1px solid #ccc; padding: 6px 8px; text-align: left; }
|
||||||
|
th { background: #f3f4f6; }
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h3>Orders Report</h3>
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Order ID</th>
|
||||||
|
<th>Company</th>
|
||||||
|
<th>Invoice No</th>
|
||||||
|
<th>Invoice Status</th>
|
||||||
|
<th>Shipment Status</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
@foreach($orders as $order)
|
||||||
|
@php
|
||||||
|
$mark = $order->markList ?? null;
|
||||||
|
$invoice = $order->invoice ?? null;
|
||||||
|
$shipment = $order->shipments->first() ?? null;
|
||||||
|
@endphp
|
||||||
|
<tr>
|
||||||
|
<td>{{ $order->order_id ?? '-' }}</td>
|
||||||
|
<td>{{ $mark->company_name ?? '-' }}</td>
|
||||||
|
<td>{{ $invoice->invoice_number ?? '-' }}</td>
|
||||||
|
<td>{{ $invoice->status ?? '-' }}</td>
|
||||||
|
<td>{{ $shipment->status ?? '-' }}</td>
|
||||||
|
</tr>
|
||||||
|
@endforeach
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -5,289 +5,365 @@
|
|||||||
@section('content')
|
@section('content')
|
||||||
<div class="container-fluid px-0">
|
<div class="container-fluid px-0">
|
||||||
|
|
||||||
|
@php
|
||||||
|
$perPage = 5; // ✅ FORCED to show pagination even with few records
|
||||||
|
$currentPage = request()->get('page', 1);
|
||||||
|
$currentPage = max(1, (int)$currentPage);
|
||||||
|
$total = $requests->count();
|
||||||
|
$totalPages = ceil($total / $perPage);
|
||||||
|
$currentItems = $requests->slice(($currentPage - 1) * $perPage, $perPage);
|
||||||
|
@endphp
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
/* 🌟 Smooth fade-in animation */
|
/* [ALL YOUR ORIGINAL CSS HERE - SAME AS BEFORE] */
|
||||||
@keyframes fadeInUp {
|
@keyframes fadeInUp {0% { transform: translateY(20px); opacity: 0; }100% { transform: translateY(0); opacity: 1; }}
|
||||||
0% {
|
.card, .custom-table-wrapper { animation: fadeInUp 0.8s ease both; }
|
||||||
transform: translateY(20px);
|
.custom-table tbody tr { transition: all 0.25s ease-in-out; }
|
||||||
opacity: 0;
|
.custom-table tbody tr:hover { background-color: #fffbea; transform: scale(1.01); box-shadow: 0 2px 6px rgba(0,0,0,0.05); }
|
||||||
}
|
.priority-badge {
|
||||||
100% {
|
display: inline-flex; align-items: center; font-size: 13.5px; padding: 6px 16px; border-radius: 12px; font-weight: 600;
|
||||||
transform: translateY(0);
|
box-shadow: 0 1px 2px 0 rgba(130,130,130,0.15); width: 90px; min-height: 28px; justify-content: center;
|
||||||
opacity: 1;
|
color: #fff; margin: 2px 0; transition: transform 0.2s ease-in-out;
|
||||||
}
|
}
|
||||||
}
|
.priority-badge:hover { transform: scale(1.08); }
|
||||||
|
.priority-high { background: linear-gradient(135deg, #ff8a8a, #d12929); }
|
||||||
|
.priority-medium { background: linear-gradient(135deg, #ffe390, #f5b041); }
|
||||||
|
.priority-low { background: linear-gradient(135deg, #b8f0c2, #1d8660); }
|
||||||
|
.custom-table thead th {
|
||||||
|
text-align: center; font-weight: 700; color: #000; padding: 14px; font-size: 17px; letter-spacing: 0.5px;
|
||||||
|
border-bottom: 2px solid #bfbfbf; background-color: #fde4b3;
|
||||||
|
}
|
||||||
|
.custom-table thead tr:first-child th:first-child { border-top-left-radius: 12px; }
|
||||||
|
.custom-table thead tr:first-child th:last-child { border-top-right-radius: 12px; }
|
||||||
|
.custom-table tbody tr:last-child td:first-child { border-bottom-left-radius: 12px; }
|
||||||
|
.custom-table tbody tr:last-child td:last-child { border-bottom-right-radius: 12px; }
|
||||||
|
.input-group input { border-radius: 10px 0 0 10px; border: 1px solid #ccc; box-shadow: inset 0 1px 3px rgba(0,0,0,0.05); }
|
||||||
|
.input-group .btn { border-radius: 0 10px 10px 0; transition: all 0.2s ease-in-out; }
|
||||||
|
.input-group .btn:hover { background: #ffd65a; border-color: #ffd65a; color: #000; }
|
||||||
|
.card { border-radius: 16px; border: none; box-shadow: 0 4px 10px rgba(0,0,0,0.08); background: #fff; }
|
||||||
|
.badge {
|
||||||
|
font-size: 11px !important; font-weight: 600 !important; padding: 7px 13px !important; border-radius: 20px !important;
|
||||||
|
text-transform: uppercase; letter-spacing: 0.3px; display: inline-flex !important; align-items: center; justify-content: center;
|
||||||
|
color: #fff !important; text-shadow: 0 1px 2px rgba(0,0,0,0.3); border: 2px solid transparent !important;
|
||||||
|
line-height: 1.2; gap: 6px; animation: pulse 2s infinite; width: 99px;
|
||||||
|
}
|
||||||
|
.status-icon { font-size: 0px; display: flex; align-items: center; justify-content: center; }
|
||||||
|
.badge.badge-pending { background: linear-gradient(135deg, #fef3c7, #fde68a) !important; color: #d97706 !important; border-color: #f59e0b !important; width: 85px; }
|
||||||
|
.badge.badge-approved { background: linear-gradient(135deg, #d1fae5, #a7f3d0) !important; color: #065f46 !important; border-color: #10b981 !important; width: 85px; }
|
||||||
|
.badge.badge-rejected { background: linear-gradient(135deg, #fecaca, #fca5a5) !important; color: #991b1b !important; border-color: #ef4444 !important; width: 85px; }
|
||||||
|
@keyframes pulse {0% { box-shadow: 0 0 8px rgba(0,0,0,0.1); }50% { box-shadow: 0 0 14px rgba(0,0,0,0.15); }100% { box-shadow: 0 0 8px rgba(0,0,0,0.1); }}
|
||||||
|
.count-badge { --bs-badge-padding-x: 0.65em; --bs-badge-padding-y: 0.35em; --bs-badge-font-size: 0.75em; --bs-badge-font-weight: 700; --bs-badge-color: #fff; --bs-badge-border-radius: var(--bs-border-radius); }
|
||||||
|
h4.fw-bold { background: linear-gradient(90deg, #000000ff 0%, #030302ff 100%); -webkit-background-clip: text; -webkit-text-fill-color: transparent; font-weight: 800; letter-spacing: 1px; }
|
||||||
|
.custom-table tbody td:last-child { text-align: center !important; vertical-align: middle !important; }
|
||||||
|
|
||||||
|
/* ===== PAGINATION STYLES ===== */
|
||||||
|
.pagination-container {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
margin-top: 15px;
|
||||||
|
padding: 12px 0;
|
||||||
|
border-top: 1px solid #eef3fb;
|
||||||
|
}
|
||||||
|
|
||||||
/* ✨ Container animation */
|
.pagination-info {
|
||||||
.card, .custom-table-wrapper {
|
font-size: 13px;
|
||||||
animation: fadeInUp 0.8s ease both;
|
color: #9ba5bb;
|
||||||
}
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
/* 🪄 Table hover effect */
|
.pagination-controls {
|
||||||
.custom-table tbody tr {
|
display: flex;
|
||||||
transition: all 0.25s ease-in-out;
|
align-items: center;
|
||||||
}
|
gap: 8px;
|
||||||
.custom-table tbody tr:hover {
|
}
|
||||||
background-color: #fffbea;
|
|
||||||
transform: scale(1.01);
|
|
||||||
box-shadow: 0 2px 6px rgba(0,0,0,0.05);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 🎯 Priority Badges */
|
.pagination-btn {
|
||||||
.priority-badge {
|
background: #fff;
|
||||||
display: inline-flex;
|
border: 1px solid #e3eaf6;
|
||||||
align-items: center;
|
color: #1a2951;
|
||||||
font-size: 13.5px;
|
padding: 8px 12px;
|
||||||
padding: 6px 16px;
|
border-radius: 6px;
|
||||||
border-radius: 12px;
|
font-size: 13px;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
box-shadow: 0 1px 2px 0 rgba(130,130,130,0.15);
|
cursor: pointer;
|
||||||
width: 90px;
|
transition: all 0.3s ease;
|
||||||
min-height: 28px;
|
display: flex;
|
||||||
justify-content: center;
|
align-items: center;
|
||||||
color: #fff;
|
justify-content: center;
|
||||||
margin: 2px 0;
|
min-width: 40px;
|
||||||
transition: transform 0.2s ease-in-out;
|
height: 32px;
|
||||||
}
|
}
|
||||||
.priority-badge:hover {
|
|
||||||
transform: scale(1.08);
|
|
||||||
}
|
|
||||||
.priority-high { background: linear-gradient(135deg, #ff8a8a, #d12929); }
|
|
||||||
.priority-medium { background: linear-gradient(135deg, #ffe390, #f5b041); }
|
|
||||||
.priority-low { background: linear-gradient(135deg, #b8f0c2, #1d8660); }
|
|
||||||
|
|
||||||
/* 🎨 Table Header (keep original bg-light color) */
|
.pagination-btn:hover:not(:disabled) {
|
||||||
.custom-table thead th {
|
background: #1a2951;
|
||||||
text-align: center;
|
color: white;
|
||||||
font-weight: 700;
|
border-color: #1a2951;
|
||||||
color: #000;
|
}
|
||||||
padding: 14px;
|
|
||||||
font-size: 17px;
|
|
||||||
letter-spacing: 0.5px;
|
|
||||||
border-bottom: 2px solid #bfbfbf;
|
|
||||||
background-color: #fde4b3; /* Bootstrap bg-light */
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 🟢 Rounded Corners for Header */
|
.pagination-btn:disabled {
|
||||||
.custom-table thead tr:first-child th:first-child {
|
background: #f8fafc;
|
||||||
border-top-left-radius: 12px;
|
color: #cbd5e0;
|
||||||
}
|
border-color: #e2e8f0;
|
||||||
.custom-table thead tr:first-child th:last-child {
|
cursor: not-allowed;
|
||||||
border-top-right-radius: 12px;
|
opacity: 0.6;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 🧾 Table bottom corners */
|
.pagination-page-btn {
|
||||||
.custom-table tbody tr:last-child td:first-child {
|
background: #fff;
|
||||||
border-bottom-left-radius: 12px;
|
border: 1px solid #e3eaf6;
|
||||||
}
|
color: #1a2951;
|
||||||
.custom-table tbody tr:last-child td:last-child {
|
padding: 6px 12px;
|
||||||
border-bottom-right-radius: 12px;
|
border-radius: 6px;
|
||||||
}
|
font-size: 13px;
|
||||||
|
font-weight: 600;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
min-width: 36px;
|
||||||
|
text-align: center;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
/* 💫 Search box styling */
|
.pagination-page-btn:hover {
|
||||||
.input-group input {
|
background: #1a2951;
|
||||||
border-radius: 10px 0 0 10px;
|
color: white;
|
||||||
border: 1px solid #ccc;
|
border-color: #1a2951;
|
||||||
box-shadow: inset 0 1px 3px rgba(0,0,0,0.05);
|
}
|
||||||
}
|
|
||||||
.input-group .btn {
|
|
||||||
border-radius: 0 10px 10px 0;
|
|
||||||
transition: all 0.2s ease-in-out;
|
|
||||||
}
|
|
||||||
.input-group .btn:hover {
|
|
||||||
background: #ffd65a;
|
|
||||||
border-color: #ffd65a;
|
|
||||||
color: #000;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 🎨 Card Style */
|
.pagination-page-btn.active {
|
||||||
.card {
|
background: #1a2951;
|
||||||
border-radius: 16px;
|
color: white;
|
||||||
border: none;
|
border-color: #1a2951;
|
||||||
box-shadow: 0 4px 10px rgba(0,0,0,0.08);
|
}
|
||||||
background: #fff;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ⚡ Status Badges - NEW ATTRACTIVE STYLES */
|
.pagination-pages {
|
||||||
.badge {
|
display: flex;
|
||||||
font-size: 11px !important;
|
gap: 4px;
|
||||||
font-weight: 600 !important;
|
align-items: center;
|
||||||
padding: 7px 13px !important;
|
}
|
||||||
border-radius: 20px !important;
|
|
||||||
text-transform: uppercase;
|
|
||||||
letter-spacing: 0.3px;
|
|
||||||
display: inline-flex !important;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
background-size: cover !important;
|
|
||||||
background-position: center !important;
|
|
||||||
color: #fff !important;
|
|
||||||
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.3);
|
|
||||||
border: 2px solid transparent !important;
|
|
||||||
box-sizing: border-box;
|
|
||||||
line-height: 1.2;
|
|
||||||
gap: 6px;
|
|
||||||
animation: pulse 2s infinite;
|
|
||||||
width: 99px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Status icons */
|
.pagination-ellipsis {
|
||||||
.status-icon {
|
color: #9ba5bb;
|
||||||
font-size: 0px;
|
font-size: 13px;
|
||||||
display: flex;
|
padding: 0 4px;
|
||||||
align-items: center;
|
}
|
||||||
justify-content: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Custom status badge backgrounds */
|
.pagination-img-btn {
|
||||||
.badge-pending {
|
background: #fff;
|
||||||
background: url('/images/status-bg-pending.png') !important;
|
border: 1px solid #e3eaf6;
|
||||||
}
|
border-radius: 6px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
min-width: 40px;
|
||||||
|
height: 32px;
|
||||||
|
padding: 0;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
.badge-approved {
|
.pagination-img-btn:hover:not(:disabled) {
|
||||||
background: url('/images/status-bg-approved.png') !important;
|
background: #1a2951;
|
||||||
}
|
border-color: #1a2951;
|
||||||
|
}
|
||||||
|
|
||||||
.badge-rejected {
|
.pagination-img-btn:disabled {
|
||||||
background: url('/images/status-bg-rejected.png') !important;
|
background: #f8fafc;
|
||||||
}
|
border-color: #e2e8f0;
|
||||||
|
cursor: not-allowed;
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
/* Fallback colors if images don't load */
|
.pagination-img-btn svg {
|
||||||
.badge.badge-pending {
|
width: 16px;
|
||||||
background: linear-gradient(135deg, #fef3c7, #fde68a) !important;
|
height: 16px;
|
||||||
color: #d97706 !important;
|
transition: filter 0.3s ease;
|
||||||
border-color: #f59e0b !important;
|
}
|
||||||
width: 85px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.badge.badge-approved {
|
.pagination-img-btn:hover:not(:disabled) svg {
|
||||||
background: linear-gradient(135deg, #d1fae5, #a7f3d0) !important;
|
filter: brightness(0) saturate(100%) invert(100%) sepia(100%) saturate(0%) hue-rotate(288deg) brightness(106%) contrast(101%);
|
||||||
color: #065f46 !important;
|
}
|
||||||
border-color: #10b981 !important;
|
|
||||||
width: 85px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.badge.badge-rejected {
|
.pagination-img-btn:disabled svg {
|
||||||
background: linear-gradient(135deg, #fecaca, #fca5a5) !important;
|
filter: brightness(0) saturate(100%) invert(84%) sepia(8%) saturate(165%) hue-rotate(179deg) brightness(89%) contrast(86%);
|
||||||
color: #991b1b !important;
|
}
|
||||||
border-color: #ef4444 !important;
|
|
||||||
width: 85px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Animation effects for badges */
|
/* ===== UPDATED SEARCH BAR STYLES ===== */
|
||||||
@keyframes pulse {
|
.search-container {
|
||||||
0% { box-shadow: 0 0 8px rgba(0,0,0,0.1); }
|
display: flex;
|
||||||
50% { box-shadow: 0 0 14px rgba(0,0,0,0.15); }
|
justify-content: space-between;
|
||||||
100% { box-shadow: 0 0 8px rgba(0,0,0,0.1); }
|
align-items: center;
|
||||||
}
|
margin-bottom: 20px;
|
||||||
|
gap: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-form {
|
||||||
|
flex: 1;
|
||||||
|
max-width: 400px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-input-group {
|
||||||
|
display: flex;
|
||||||
|
box-shadow: 0 2px 6px rgba(0,0,0,0.08);
|
||||||
|
border-radius: 10px;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-input {
|
||||||
|
flex: 1;
|
||||||
|
border: 1px solid #e2e8f0;
|
||||||
|
border-right: none;
|
||||||
|
padding: 10px 16px;
|
||||||
|
font-size: 14px;
|
||||||
|
background-color: #fff;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-input:focus {
|
||||||
|
outline: none;
|
||||||
|
border-color: #3b82f6;
|
||||||
|
box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-button {
|
||||||
|
background: #3b82f6;
|
||||||
|
border: 1px solid #3b82f6;
|
||||||
|
color: white;
|
||||||
|
padding: 10px 16px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-button:hover {
|
||||||
|
background: #2563eb;
|
||||||
|
border-color: #2563eb;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-icon {
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-badges {
|
||||||
|
display: flex;
|
||||||
|
gap: 8px;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-badge {
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 600;
|
||||||
|
padding: 6px 12px;
|
||||||
|
border-radius: 20px;
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 4px;
|
||||||
|
box-shadow: 0 1px 3px rgba(0,0,0,0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-badge-pending {
|
||||||
|
background: linear-gradient(135deg, #fef3c7, #fde68a);
|
||||||
|
color: #d97706;
|
||||||
|
border: 1px solid #f59e0b;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-badge-approved {
|
||||||
|
background: linear-gradient(135deg, #d1fae5, #a7f3d0);
|
||||||
|
color: #065f46;
|
||||||
|
border: 1px solid #10b981;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-badge-rejected {
|
||||||
|
background: linear-gradient(135deg, #fecaca, #fca5a5);
|
||||||
|
color: #991b1b;
|
||||||
|
border: 1px solid #ef4444;
|
||||||
|
}
|
||||||
|
|
||||||
/* Count badges at top */
|
/* Responsive styles */
|
||||||
.count-badge {
|
@media (max-width: 768px) {
|
||||||
--bs-badge-padding-x: 0.65em;
|
.pagination-container {
|
||||||
--bs-badge-padding-y: 0.35em;
|
flex-direction: column;
|
||||||
--bs-badge-font-size: 0.75em;
|
gap: 10px;
|
||||||
--bs-badge-font-weight: 700;
|
align-items: stretch;
|
||||||
--bs-badge-color: #fff;
|
}
|
||||||
--bs-badge-border-radius: var(--bs-border-radius);
|
.pagination-controls {
|
||||||
}
|
justify-content: center;
|
||||||
|
}
|
||||||
/* ✨ Heading style */
|
|
||||||
h4.fw-bold {
|
.search-container {
|
||||||
background: linear-gradient(90deg, #000000ff 0%, #030302ff 100%);
|
flex-direction: column;
|
||||||
-webkit-background-clip: text;
|
align-items: stretch;
|
||||||
-webkit-text-fill-color: transparent;
|
}
|
||||||
font-weight: 800;
|
|
||||||
letter-spacing: 1px;
|
.search-form {
|
||||||
}
|
max-width: 100%;
|
||||||
|
}
|
||||||
/* ✅ Center align for last column */
|
|
||||||
.custom-table tbody td:last-child {
|
.status-badges {
|
||||||
text-align: center !important;
|
justify-content: center;
|
||||||
vertical-align: middle !important;
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<!-- Heading and status badges row -->
|
<!-- Counts -->
|
||||||
<div class="d-flex justify-content-between align-items-center mb-2 mt-3">
|
<div class="d-flex justify-content-between align-items-center mb-2 mt-3">
|
||||||
<h4 class="fw-bold mb-0">User Requests</h4>
|
<h4 class="fw-bold mb-0">User Requests (Total: {{ $total }})</h4>
|
||||||
<div>
|
|
||||||
<span class="count-badge badge rounded-pill bg-warning text-dark me-1">
|
|
||||||
{{ $requests->where('status', 'pending')->count() }} Pending
|
|
||||||
</span>
|
|
||||||
<span class="count-badge badge rounded-pill bg-success me-1">
|
|
||||||
{{ $requests->where('status', 'approved')->count() }} Approved
|
|
||||||
</span>
|
|
||||||
<span class="count-badge badge rounded-pill bg-danger">
|
|
||||||
{{ $requests->where('status', 'rejected')->count() }} Rejected
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Search + Table -->
|
||||||
<div class="card mb-4 shadow-sm">
|
<div class="card mb-4 shadow-sm">
|
||||||
<div class="card-body pb-1">
|
<div class="card-body pb-1">
|
||||||
<form method="GET" action="">
|
<!-- Updated Search Bar with Status Badges in the same line -->
|
||||||
<div class="input-group mb-2">
|
<div class="search-container">
|
||||||
<input type="text" name="search" value="{{ old('search', request('search')) }}" class="form-control" placeholder="Search Request by name, email, Company or Request ID">
|
<form method="GET" action="" class="search-form">
|
||||||
<button class="btn btn-outline-primary" type="submit"><i class="bi bi-search"></i></button>
|
<div class="search-input-group">
|
||||||
|
<input type="text" name="search" value="{{ request('search') }}" class="search-input" placeholder="Search by name, email, company...">
|
||||||
|
<button class="search-button" type="submit">
|
||||||
|
<svg class="search-icon" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M21 21L16.514 16.506L21 21ZM19 10.5C19 15.194 15.194 19 10.5 19C5.806 19 2 15.194 2 10.5C2 5.806 5.806 2 10.5 2C15.194 2 19 5.806 19 10.5Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<div class="status-badges">
|
||||||
|
<span class="status-badge status-badge-pending">{{ $requests->where('status', 'pending')->count() }} Pending</span>
|
||||||
|
<span class="status-badge status-badge-approved">{{ $requests->where('status', 'approved')->count() }} Approved</span>
|
||||||
|
<span class="status-badge status-badge-rejected">{{ $requests->where('status', 'rejected')->count() }} Rejected</span>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</div>
|
||||||
|
|
||||||
<div class="table-responsive custom-table-wrapper">
|
<div class="table-responsive custom-table-wrapper">
|
||||||
<table class="table align-middle mb-0 custom-table">
|
<table class="table align-middle mb-0 custom-table">
|
||||||
<thead class="bg-light">
|
<thead><tr>
|
||||||
<tr>
|
<th>#</th><th>Request ID</th><th>Name</th><th>Company</th><th>Email</th><th>Mobile</th><th>Address</th><th>Priority</th><th>Date</th><th>Status</th><th>Actions</th>
|
||||||
<th>#</th>
|
</tr></thead>
|
||||||
<th>Request ID</th>
|
|
||||||
<th>Name</th>
|
|
||||||
<th>Company</th>
|
|
||||||
<th>Email</th>
|
|
||||||
<th>Mobile</th>
|
|
||||||
<th>Address</th>
|
|
||||||
<th>Priority</th>
|
|
||||||
<th>Date</th>
|
|
||||||
<th>Status</th>
|
|
||||||
<th>Actions</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
<tbody>
|
||||||
@foreach($requests as $index => $req)
|
@forelse($currentItems as $index => $req)
|
||||||
<tr>
|
<tr>
|
||||||
<td>{{ $requests->count() - $index }}</td>
|
<td><strong>{{ ($currentPage - 1) * $perPage + $index + 1 }}</strong></td>
|
||||||
<td>{{ $req->request_id }}</td>
|
<td>{{ $req->request_id }}</td>
|
||||||
<td>{{ $req->customer_name }}</td>
|
<td>{{ $req->customer_name }}</td>
|
||||||
<td>{{ $req->company_name }}</td>
|
<td>{{ $req->company_name }}</td>
|
||||||
<td>{{ $req->email }}</td>
|
<td>{{ $req->email }}</td>
|
||||||
<td>{{ $req->mobile_no }}</td>
|
<td>{{ $req->mobile_no }}</td>
|
||||||
<td>{{ $req->address }}</td>
|
<td>{{ Str::limit($req->address, 30) }}</td>
|
||||||
<td>
|
<td>
|
||||||
@if(strtolower($req->priority) == 'high')
|
@if(strtolower($req->priority) == 'high')<span class="priority-badge priority-high">High</span>
|
||||||
<span class="priority-badge priority-high">High</span>
|
@elseif(strtolower($req->priority) == 'medium')<span class="priority-badge priority-medium">Medium</span>
|
||||||
@elseif(strtolower($req->priority) == 'medium')
|
@elseif(strtolower($req->priority) == 'low')<span class="priority-badge priority-low">Low</span>
|
||||||
<span class="priority-badge priority-medium">Medium</span>
|
@else{{ $req->priority ?? 'N/A' }}@endif
|
||||||
@elseif(strtolower($req->priority) == 'low')
|
|
||||||
<span class="priority-badge priority-low">Low</span>
|
|
||||||
@else
|
|
||||||
{{ $req->priority }}
|
|
||||||
@endif
|
|
||||||
</td>
|
</td>
|
||||||
<td>{{ $req->date }}</td>
|
<td>{{ $req->date }}</td>
|
||||||
<td>
|
<td>
|
||||||
@if($req->status == 'approved')
|
@if($req->status == 'approved')<span class="badge badge-approved"><i class="bi bi-check-circle-fill status-icon"></i>Approved</span>
|
||||||
<span class="badge badge-approved">
|
@elseif($req->status == 'rejected')<span class="badge badge-rejected"><i class="bi bi-x-circle-fill status-icon"></i>Rejected</span>
|
||||||
<i class="bi bi-check-circle-fill status-icon"></i>
|
@else<span class="badge badge-pending"><i class="bi bi-clock-fill status-icon"></i>Pending</span>@endif
|
||||||
Approved
|
|
||||||
</span>
|
|
||||||
@elseif($req->status == 'rejected')
|
|
||||||
<span class="badge badge-rejected">
|
|
||||||
<i class="bi bi-x-circle-fill status-icon"></i>
|
|
||||||
Rejected
|
|
||||||
</span>
|
|
||||||
@else
|
|
||||||
<span class="badge badge-pending">
|
|
||||||
<i class="bi bi-clock-fill status-icon"></i>
|
|
||||||
Pending
|
|
||||||
</span>
|
|
||||||
@endif
|
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
@if($req->status == 'pending')
|
@if($req->status == 'pending')
|
||||||
@@ -306,12 +382,79 @@
|
|||||||
</td>
|
</td>
|
||||||
|
|
||||||
</tr>
|
</tr>
|
||||||
@endforeach
|
@empty
|
||||||
|
<tr><td colspan="11" class="text-center text-muted py-4">No records found.</td></tr>
|
||||||
|
@endforelse
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
@if($requests->isEmpty())
|
</div>
|
||||||
<div class="py-4 text-center text-muted">No records found.</div>
|
|
||||||
@endif
|
{{-- ✅ PAGINATION - WITH ARROW BUTTONS --}}
|
||||||
|
<div class="pagination-container">
|
||||||
|
<div class="pagination-info">
|
||||||
|
Showing {{ ($currentPage - 1) * $perPage + 1 }} to {{ min($currentPage * $perPage, $total) }} of {{ $total }} entries
|
||||||
|
</div>
|
||||||
|
<div class="pagination-controls">
|
||||||
|
{{-- Previous Page --}}
|
||||||
|
@if($currentPage > 1)
|
||||||
|
<a href="{{ request()->fullUrlWithQuery(['page' => $currentPage - 1]) }}" class="pagination-img-btn" title="Previous page">
|
||||||
|
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M10 12L6 8L10 4" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
</svg>
|
||||||
|
</a>
|
||||||
|
@else
|
||||||
|
<button class="pagination-img-btn" disabled title="Previous page">
|
||||||
|
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M10 12L6 8L10 4" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
@endif
|
||||||
|
|
||||||
|
{{-- Page Numbers --}}
|
||||||
|
<div class="pagination-pages">
|
||||||
|
@php
|
||||||
|
$start = max(1, $currentPage - 1);
|
||||||
|
$end = min($totalPages, $currentPage + 1);
|
||||||
|
@endphp
|
||||||
|
|
||||||
|
@if($start > 1)
|
||||||
|
<a href="{{ request()->fullUrlWithQuery(['page' => 1]) }}" class="pagination-page-btn">1</a>
|
||||||
|
@if($start > 2)
|
||||||
|
<span class="pagination-ellipsis">...</span>
|
||||||
|
@endif
|
||||||
|
@endif
|
||||||
|
|
||||||
|
@for($i = $start; $i <= $end; $i++)
|
||||||
|
@if($i == $currentPage)
|
||||||
|
<span class="pagination-page-btn active">{{ $i }}</span>
|
||||||
|
@else
|
||||||
|
<a href="{{ request()->fullUrlWithQuery(['page' => $i]) }}" class="pagination-page-btn">{{ $i }}</a>
|
||||||
|
@endif
|
||||||
|
@endfor
|
||||||
|
|
||||||
|
@if($end < $totalPages)
|
||||||
|
@if($end < $totalPages - 1)
|
||||||
|
<span class="pagination-ellipsis">...</span>
|
||||||
|
@endif
|
||||||
|
<a href="{{ request()->fullUrlWithQuery(['page' => $totalPages]) }}" class="pagination-page-btn">{{ $totalPages }}</a>
|
||||||
|
@endif
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{-- Next Page --}}
|
||||||
|
@if($currentPage < $totalPages)
|
||||||
|
<a href="{{ request()->fullUrlWithQuery(['page' => $currentPage + 1]) }}" class="pagination-img-btn" title="Next page">
|
||||||
|
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M6 4L10 8L6 12" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
</svg>
|
||||||
|
</a>
|
||||||
|
@else
|
||||||
|
<button class="pagination-img-btn" disabled title="Next page">
|
||||||
|
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M6 4L10 8L6 12" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
@endif
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
137
routes/web.php
137
routes/web.php
@@ -32,6 +32,8 @@ Route::prefix('admin')->group(function () {
|
|||||||
|
|
||||||
Route::post('/logout', [AdminAuthController::class, 'logout'])
|
Route::post('/logout', [AdminAuthController::class, 'logout'])
|
||||||
->name('admin.logout');
|
->name('admin.logout');
|
||||||
|
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
@@ -111,23 +113,59 @@ 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');
|
||||||
|
|
||||||
|
|
||||||
// ---------------------------
|
// ---------------------------
|
||||||
// SHIPMENTS
|
// 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 (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
|
||||||
@@ -180,36 +218,67 @@ Route::prefix('admin')
|
|||||||
->name('admin.customers.status');
|
->name('admin.customers.status');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// ==========================================
|
||||||
// ==========================================
|
// ADMIN ACCOUNT (AJAX) ROUTES
|
||||||
// ADMIN ACCOUNT (AJAX) ROUTES
|
// ==========================================
|
||||||
// ==========================================
|
Route::prefix('admin/account')
|
||||||
Route::prefix('admin/account')
|
->middleware('auth:admin')
|
||||||
->middleware('auth:admin')
|
->name('admin.account.')
|
||||||
->name('admin.account.')
|
->group(function () {
|
||||||
->group(function () {
|
|
||||||
|
Route::get('/dashboard', [AdminAccountController::class, 'getDashboardData'])
|
||||||
Route::get('/dashboard', [AdminAccountController::class, 'getDashboardData'])
|
->name('dashboard');
|
||||||
->name('dashboard');
|
|
||||||
|
Route::get('/available-orders', [AdminAccountController::class, 'getAvailableOrders'])
|
||||||
Route::get('/available-orders', [AdminAccountController::class, 'getAvailableOrders'])
|
->name('orders.available');
|
||||||
->name('orders.available');
|
|
||||||
|
Route::post('/create-order', [AdminAccountController::class, 'accountCreateOrder'])
|
||||||
Route::post('/create-order', [AdminAccountController::class, 'accountCreateOrder'])
|
->name('create');
|
||||||
->name('create');
|
|
||||||
|
Route::post('/toggle-payment', [AdminAccountController::class, 'togglePayment'])
|
||||||
Route::post('/toggle-payment', [AdminAccountController::class, 'togglePayment'])
|
->name('toggle');
|
||||||
->name('toggle');
|
|
||||||
|
Route::post('/installment/create', [AdminAccountController::class, 'addInstallment'])
|
||||||
Route::post('/installment/create', [AdminAccountController::class, 'addInstallment'])
|
->name('installment.create');
|
||||||
->name('installment.create');
|
|
||||||
|
Route::post('/installment/update-status', [AdminAccountController::class, 'updateInstallmentStatus'])
|
||||||
Route::post('/installment/update-status', [AdminAccountController::class, 'updateInstallmentStatus'])
|
->name('installment.update');
|
||||||
->name('installment.update');
|
|
||||||
|
Route::get('/entry/{entry_no}', [AdminAccountController::class, 'getEntryDetails'])
|
||||||
Route::get('/entry/{entry_no}', [AdminAccountController::class, 'getEntryDetails'])
|
->name('entry.details');
|
||||||
->name('entry.details');
|
|
||||||
});
|
// ⬇⬇ NEW ROUTES FOR EDIT + DELETE ⬇⬇
|
||||||
|
Route::post('/update-entry', [AdminAccountController::class, 'updateEntry'])
|
||||||
|
->name('update.entry');
|
||||||
|
|
||||||
|
Route::post('/delete-entry', [AdminAccountController::class, 'deleteEntry'])
|
||||||
|
->name('delete.entry');
|
||||||
|
|
||||||
|
|
||||||
|
// ===== Associated Orders Routes (EDIT MODAL साठी) =====
|
||||||
|
Route::post('/add-orders-to-entry', [AdminAccountController::class, 'addOrdersToEntry'])
|
||||||
|
->name('add.orders.to.entry');
|
||||||
|
|
||||||
|
Route::get('/entry-orders/{entry_no}', [AdminAccountController::class, 'getEntryOrders'])
|
||||||
|
->name('entry.orders');
|
||||||
|
|
||||||
|
Route::post('/remove-order-from-entry', [AdminAccountController::class, 'removeOrderFromEntry'])
|
||||||
|
->name('remove.order.from.entry');
|
||||||
|
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// ---------------------------
|
||||||
|
// REPORTS DOWNLOAD ROUTES
|
||||||
|
// ---------------------------
|
||||||
|
Route::get('/admin/orders/download/pdf', [OrderController::class, 'downloadPdf'])->name('admin.orders.download.pdf');
|
||||||
|
Route::get('/admin/orders/download/excel', [OrderController::class, 'downloadExcel'])->name('admin.orders.download.excel');
|
||||||
|
|
||||||
|
//---------------------------
|
||||||
|
//Edit Button Route
|
||||||
|
//---------------------------
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user