diff --git a/app/Http/Controllers/Admin/AdminAccountController.php b/app/Http/Controllers/Admin/AdminAccountController.php index d760951..8b5d98d 100644 --- a/app/Http/Controllers/Admin/AdminAccountController.php +++ b/app/Http/Controllers/Admin/AdminAccountController.php @@ -11,6 +11,71 @@ use Illuminate\Support\Facades\DB; 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 */ @@ -245,4 +310,82 @@ class AdminAccountController extends Controller '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, + ]); + }); +} + +} \ No newline at end of file diff --git a/app/Http/Controllers/Admin/AdminCustomerController.php b/app/Http/Controllers/Admin/AdminCustomerController.php index 393db9a..aab2cd1 100644 --- a/app/Http/Controllers/Admin/AdminCustomerController.php +++ b/app/Http/Controllers/Admin/AdminCustomerController.php @@ -9,36 +9,42 @@ use Illuminate\Support\Facades\Hash; class AdminCustomerController extends Controller { + + // --------------------------------------------------------- // LIST CUSTOMERS (with search + status filter) // --------------------------------------------------------- public function index(Request $request) - { - $search = $request->search; - $status = $request->status; +{ + $search = $request->search; + $status = $request->status; - $query = User::with(['marks', 'orders'])->orderBy('id', 'desc'); + $query = User::with(['marks', 'orders'])->orderBy('id', 'desc'); - // SEARCH FILTER - if (!empty($search)) { - $query->where(function ($q) use ($search) { - $q->where('customer_name', 'like', "%$search%") - ->orWhere('email', 'like', "%$search%") - ->orWhere('mobile_no', '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')); + // SEARCH FILTER + if (!empty($search)) { + $query->where(function ($q) use ($search) { + $q->where('customer_name', 'like', "%$search%") + ->orWhere('email', 'like', "%$search%") + ->orWhere('mobile_no', 'like', "%$search%") + ->orWhere('customer_id', 'like', "%$search%"); + }); } + // 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 // --------------------------------------------------------- @@ -130,5 +136,6 @@ class AdminCustomerController extends Controller return back()->with('success', 'Customer status updated.'); } + } diff --git a/app/Http/Controllers/Admin/AdminOrderController.php b/app/Http/Controllers/Admin/AdminOrderController.php index 47a1da3..ce86dfc 100644 --- a/app/Http/Controllers/Admin/AdminOrderController.php +++ b/app/Http/Controllers/Admin/AdminOrderController.php @@ -7,28 +7,123 @@ use Illuminate\Http\Request; use App\Models\Order; use App\Models\OrderItem; use App\Models\MarkList; +use App\Models\Invoice; +use App\Models\InvoiceItem; +use App\Models\User; class AdminOrderController extends Controller { + // --------------------------- + // LIST / DASHBOARD + // --------------------------- public function index() { + // raw list for admin dashboard (simple) $orders = Order::latest()->get(); $markList = MarkList::where('status', 'active')->get(); 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 - $item = $request->validate([ - 'mark_no' => 'required', - 'origin' => 'required', - 'destination' => 'required', + // return a dedicated create view - create it at resources/views/admin/orders_create.blade.php + // If you prefer create UI on dashboard, change this to redirect route('admin.orders.index') etc. + $markList = MarkList::where('status', 'active')->get(); + return view('admin.orders_create', compact('markList')); + } + + /** + * Store a new order and optionally create initial invoice + */ + public function store(Request $request) + { + $data = $request->validate([ + 'mark_no' => 'required|string', + 'origin' => 'nullable|string', + 'destination' => 'nullable|string', + // totals optional when creating without items + 'ctn' => 'nullable|numeric', + 'qty' => 'nullable|numeric', + 'ttl_qty' => 'nullable|numeric', + 'ttl_amount' => 'nullable|numeric', + 'cbm' => 'nullable|numeric', + 'ttl_cbm' => 'nullable|numeric', + 'kg' => 'nullable|numeric', + 'ttl_kg' => 'nullable|numeric', + ]); + + $order = Order::create([ + 'order_id' => $this->generateOrderId(), + 'mark_no' => $data['mark_no'], + 'origin' => $data['origin'] ?? null, + 'destination' => $data['destination'] ?? null, + 'ctn' => $data['ctn'] ?? 0, + 'qty' => $data['qty'] ?? 0, + 'ttl_qty' => $data['ttl_qty'] ?? 0, + 'ttl_amount' => $data['ttl_amount'] ?? 0, + 'cbm' => $data['cbm'] ?? 0, + 'ttl_cbm' => $data['ttl_cbm'] ?? 0, + 'kg' => $data['kg'] ?? 0, + 'ttl_kg' => $data['ttl_kg'] ?? 0, + 'status' => 'pending', + ]); + + // If you want to auto-create an invoice at order creation, uncomment: + // $this->createInvoice($order); + + return redirect()->route('admin.orders.show', $order->id) + ->with('success', 'Order created successfully.'); + } + + // --------------------------- + // SHOW / POPUP + // --------------------------- + public function show($id) + { + $order = Order::with('items', 'markList')->findOrFail($id); + $user = $this->getCustomerFromOrder($order); + + return view('admin.orders_show', compact('order', 'user')); + } + + // public function popup($id) + // { + // $order = Order::with(['items', 'markList'])->findOrFail($id); + // $user = $this->getCustomerFromOrder($order); + + // return view('admin.popup', compact('order', 'user')); + // } + + // --------------------------- + // ORDER ITEM MANAGEMENT (DB) + // --------------------------- + /** + * Add an item to an existing order + */ + public function addItem(Request $request, $orderId) + { + $order = Order::findOrFail($orderId); + + $data = $request->validate([ 'description' => 'required|string', 'ctn' => 'nullable|numeric', 'qty' => 'nullable|numeric', @@ -43,233 +138,207 @@ class AdminOrderController extends Controller 'shop_no' => 'nullable|string', ]); - // ❌ Prevent changing mark_no once first item added - 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.'); - } + $data['order_id'] = $order->id; - // Save mark, origin, destination ONLY ONCE - if (!session()->has('mark_no')) { - session([ - 'mark_no' => $request->mark_no, - 'origin' => $request->origin, - 'destination' => $request->destination + OrderItem::create($data); + + // recalc totals and save to order + $this->recalcTotals($order); + + 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.'); } - // ------------------------------------------------------------------------- - // STEP 2 : DELETE TEMPORARY ITEM - // ------------------------------------------------------------------------- - - public function deleteTempItem(Request $request) + private function generateInvoiceNumber() { - $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])) { - unset($items[$index]); - session(['temp_order_items' => array_values($items)]); + private function getCustomerFromMarkList($markNo) + { + $markList = MarkList::where('mark_no', $markNo)->first(); + + if ($markList && $markList->customer_id) { + return User::where('customer_id', $markList->customer_id)->first(); } - // If no items left → reset mark_no lock - if (empty($items)) { - session()->forget(['mark_no', 'origin', 'destination']); - } - - return redirect()->to(route('admin.orders.index') . '#createOrderForm') - ->with('success', 'Item removed successfully.'); + return null; } - // ------------------------------------------------------------------------- - // 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) + private function getCustomerFromOrder($order) { - $order = Order::with('items', 'markList')->findOrFail($id); - - $user = null; 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) @@ -309,5 +378,46 @@ class AdminOrderController extends Controller 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'); +} } diff --git a/app/Http/Controllers/Admin/ShipmentController.php b/app/Http/Controllers/Admin/ShipmentController.php index c0883fd..d281059 100644 --- a/app/Http/Controllers/Admin/ShipmentController.php +++ b/app/Http/Controllers/Admin/ShipmentController.php @@ -14,7 +14,7 @@ class ShipmentController extends Controller /** * Show shipment page (Create Shipment + Shipment List) */ - public function index() + public function index() { // 1) Get all used order IDs $usedOrderIds = ShipmentItem::pluck('order_id')->toArray(); @@ -29,8 +29,6 @@ class ShipmentController extends Controller return view('admin.shipments', compact('availableOrders', 'shipments')); } - - /** * Store new shipment */ @@ -115,8 +113,6 @@ class ShipmentController extends Controller return redirect()->back()->with('success', "Shipment $newShipmentId created successfully!"); } - - /** * Show shipment details (for modal popup) */ @@ -135,8 +131,6 @@ class ShipmentController extends Controller ]); } - - /** * 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.'); + } +} \ No newline at end of file diff --git a/app/Http/Controllers/RequestController.php b/app/Http/Controllers/RequestController.php index 685271c..e2078c1 100644 --- a/app/Http/Controllers/RequestController.php +++ b/app/Http/Controllers/RequestController.php @@ -44,6 +44,8 @@ class RequestController extends Controller 'pincode' => $request->pincode, 'date' => Carbon::now()->toDateString(), // Auto current date 'status' => 'pending', // Default status + + ]); // ✅ Response diff --git a/app/Models/Order.php b/app/Models/Order.php index d3691c8..029cf35 100644 --- a/app/Models/Order.php +++ b/app/Models/Order.php @@ -4,11 +4,13 @@ namespace App\Models; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; +use Illuminate\Database\Eloquent\SoftDeletes; + class Order extends Model { - use HasFactory; - + use HasFactory,SoftDeletes; + protected $fillable = [ 'order_id', 'mark_no', diff --git a/app/Models/OrderItem.php b/app/Models/OrderItem.php index 75cd416..6d37939 100644 --- a/app/Models/OrderItem.php +++ b/app/Models/OrderItem.php @@ -4,10 +4,11 @@ namespace App\Models; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; +use Illuminate\Database\Eloquent\SoftDeletes; class OrderItem extends Model { - use HasFactory; + use HasFactory, SoftDeletes; protected $fillable = [ 'order_id', diff --git a/database/migrations/2025_11_24_131305_create_invoice_installments_table.php b/database/migrations/2025_11_24_131305_create_invoice_installments_table.php index f9e33cc..d1c540f 100644 --- a/database/migrations/2025_11_24_131305_create_invoice_installments_table.php +++ b/database/migrations/2025_11_24_131305_create_invoice_installments_table.php @@ -8,23 +8,16 @@ return new class extends Migration { public function up(): void { - Schema::create('invoice_installments', function (Blueprint $table) { - $table->id(); - - $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(); + // Table already exists. Add updates here if needed. + Schema::table('invoice_installments', function (Blueprint $table) { + // nothing to update }); } public function down(): void { - Schema::dropIfExists('invoice_installments'); + Schema::table('invoice_installments', function (Blueprint $table) { + // nothing to rollback + }); } }; diff --git a/database/migrations/2025_11_28_182057_add_soft_deletes_to_orders_table.php b/database/migrations/2025_11_28_182057_add_soft_deletes_to_orders_table.php new file mode 100644 index 0000000..4d837c8 --- /dev/null +++ b/database/migrations/2025_11_28_182057_add_soft_deletes_to_orders_table.php @@ -0,0 +1,22 @@ +softDeletes(); + }); + } + + public function down(): void + { + Schema::table('order_items', function (Blueprint $table) { + $table->dropSoftDeletes(); + }); + } +}; diff --git a/database/migrations/2025_11_29_045236_add_deleted_at_to_order_items_table.php b/database/migrations/2025_11_29_045236_add_deleted_at_to_order_items_table.php new file mode 100644 index 0000000..660229b --- /dev/null +++ b/database/migrations/2025_11_29_045236_add_deleted_at_to_order_items_table.php @@ -0,0 +1,26 @@ +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 + } + }); + } +}; diff --git a/public/invoices/invoice-INV-2025-000026.pdf b/public/invoices/invoice-INV-2025-000026.pdf new file mode 100644 index 0000000..619708c Binary files /dev/null and b/public/invoices/invoice-INV-2025-000026.pdf differ diff --git a/resources/views/admin/account.blade.php b/resources/views/admin/account.blade.php index 454de4c..cf3d3a3 100644 --- a/resources/views/admin/account.blade.php +++ b/resources/views/admin/account.blade.php @@ -66,29 +66,38 @@ body { color:#fff; border:none; padding:10px 16px; border-radius:10px; font-weight:600; cursor:pointer; transition: transform .15s ease, box-shadow .15s; } -.btn.ghost { background: transparent; color:var(--primary-1); border:1px solid #dbe4f5; box-shadow:none; } +.btn.ghost { background: transparent; color:var(--primary-1); border:1.5px solid #dbe4f5; box-shadow:none; } .btn:hover{ transform: translateY(-3px); box-shadow: 0 8px 26px rgba(36,58,114,0.12); } /* account panels */ .account-panels { display:flex; gap:22px; - align-items:flex-start; + align-items:stretch; flex-wrap:wrap; } + +/* Payment block with pagination */ +.payment-block { + flex:1; + min-width:48%; + display: flex; + flex-direction: column; +} + .panel-card { background: var(--card-bg); border-radius:12px; box-shadow:0 8px 20px rgba(25,40,80,0.06); - flex:1; - min-width:48%; padding:22px; box-sizing:border-box; overflow-x:auto; transition: transform .12s, box-shadow .12s; - min-height: 480px; + min-height: 520px; display: flex; flex-direction: column; + flex: 1; + height: 100%; } .panel-card:hover{ transform: translateY(-4px); box-shadow:0 12px 28px rgba(25,40,80,0.08); } .panel-title { @@ -139,12 +148,11 @@ tr:hover td{ background:#fbfdff; } text-align: center; box-shadow: 0 2px 8px rgba(33, 43, 90, 0.07); letter-spacing: 0.1px; - background: #6b7280; /* fallback */ + background: #6b7280; transition: box-shadow 0.22s, transform 0.17s, background 0.22s; vertical-align: middle; margin: 3px 2px; cursor: default; - /* subtle glass effect */ backdrop-filter: blur(2px); width: 99px; } @@ -199,7 +207,7 @@ tr:hover td{ background:#fbfdff; } -webkit-appearance:none; width:60px; height:24px; - background:#f25b5b; /* RED */ + background:#f25b5b; border:2px solid #f25b5b; border-radius:999px; position:relative; @@ -305,6 +313,7 @@ tr:hover td{ background:#fbfdff; } margin-top: 15px; padding: 12px 0; border-top: 1px solid #eef3fb; + margin-right:550px; } .pagination-info { @@ -317,6 +326,8 @@ tr:hover td{ background:#fbfdff; } display: flex; align-items: center; gap: 8px; + margin-right:-1050px; + } .pagination-btn { @@ -505,6 +516,190 @@ tr:hover td{ background:#fbfdff; } margin-top:16px; } +/* Filter section styles - FOR BOTH TABLES */ +.payment-filters, .order-filters { + display: flex; + gap: 12px; + align-items: center; + margin-bottom: 16px; + flex-wrap: wrap; + padding: 14px 16px; + background: linear-gradient(90deg, #f8fbff, #f5f9ff); + border-radius: 10px; + border: 1px solid #eef3fb; + width: 480px; + max-width: 480px; +} + +.filter-group { + display: flex; + flex-direction: column; + gap: 6px; +} + +.filter-label { + font-size: 13px; + font-weight: 600; + color: var(--primary-1); +} + +.filter-control { + padding: 8px 12px; + border-radius: 8px; + border: 1px solid #e3eaf6; + background: #fff; + font-size: 14px; + min-width: 140px; +} + +.filter-control:focus { + outline: none; + border-color: var(--primary-1); + box-shadow: 0 0 0 2px rgba(26, 41, 81, 0.1); +} + +.filter-actions { + display: flex; + gap: 8px; + align-items: flex-end; +} + +/* Action buttons in table */ +.action-btn { + background: transparent; + border: none; + cursor: pointer; + padding: 6px 8px; + border-radius: 6px; + transition: all 0.2s ease; + display: inline-flex; + align-items: center; + justify-content: center; +} + +.edit-btn { + color: var(--primary-1); +} + +.edit-btn:hover { + background: rgba(26, 41, 81, 0.08); +} + +.delete-btn { + color: var(--danger); +} + +.delete-btn:hover { + background: rgba(239, 79, 79, 0.08); +} + +.action-btns { + display: flex; + gap: 4px; + justify-content: center; +} + +/* Edit modal styles */ +.edit-modal .modal-box1 { + max-width: 800px; +} + +.edit-form-grid { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 16px; + margin-bottom: 16px; +} + +.edit-form-actions { + display: flex; + gap: 12px; + justify-content: flex-end; + margin-top: 20px; +} + +/* Order management in edit modal */ +.order-management-section { + margin-top: 20px; + border-top: 1px solid #eef3fb; + padding-top: 16px; +} + +.order-management-header { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 12px; +} + +.order-management-title { + font-weight: 700; + color: var(--primary-1); + font-size: 16px; +} + +.orders-table-container { + max-height: 300px; + overflow-y: auto; + border: 1px solid #eef3fb; + border-radius: 8px; + margin-bottom: 12px; +} + +.orders-table { + width: 100%; + border-collapse: collapse; + font-size: 13px; +} + +.orders-table th { + background: #f8fbff; + padding: 10px 12px; + text-align: left; + font-weight: 600; + color: var(--primary-1); + border-bottom: 1px solid #eef3fb; + position: sticky; + top: 0; +} + +.orders-table td { + padding: 10px 12px; + border-bottom: 1px solid #f1f6ff; +} + +.order-actions { + display: flex; + gap: 6px; +} + +.remove-order-btn { + background: var(--danger); + color: white; + border: none; + border-radius: 4px; + padding: 4px 8px; + font-size: 12px; + cursor: pointer; + transition: background 0.2s; +} + +.remove-order-btn:hover { + background: #d42c3f; +} + +/* Add Order Modal */ +.add-order-modal .modal-box1 { + max-width: 1000px; +} + +.add-order-actions { + display: flex; + justify-content: flex-end; + gap: 12px; + margin-top: 16px; +} + /* responsive */ @media (max-width:980px){ .create-grid { grid-template-columns: 1fr; } @@ -514,6 +709,10 @@ tr:hover td{ background:#fbfdff; } .pagination-controls { justify-content: center; } .account-container { padding: 20px; } .panel-card { padding: 18px; } + .payment-filters, .order-filters { flex-direction: column; align-items: stretch; } + .filter-group { width: 100%; } + .filter-control { min-width: auto; } + .edit-form-grid { grid-template-columns: 1fr; } } @media (max-width:768px){ @@ -522,6 +721,27 @@ tr:hover td{ background:#fbfdff; } .top-actions .left { justify-content: center; } .entry-summary-cards { gap: 12px; } .entry-summary-card { min-width: 140px; } + .edit-form-grid { grid-template-columns: 1fr; } + .order-management-header { flex-direction: column; align-items: flex-start; gap: 10px; } +} + +/* Table pagination wrapper */ +.table-pagination-wrapper { + margin-top: 20px; + border-top: 1px solid #eef3fb; + padding-top: 15px; +} + +/* Modal pagination wrapper */ +.modal-pagination-wrapper { + margin-top: 15px; + border-top: 1px solid #eef3fb; + padding-top: 12px; +} + +/* Right-aligned pagination */ +.pagination-right { + justify-content: flex-end; } @@ -540,7 +760,7 @@ tr:hover td{ background:#fbfdff; }
- +
@@ -551,29 +771,104 @@ tr:hover td{ background:#fbfdff; }
-
-
- Payment Sent to China - Total entries: 0 + +
+
+
+ Payment Sent to China + Total entries: 0 +
+ + +
+
+ + +
+ +
+ + +
+ +
+ +
+
+ + + + + + + + + + + + +
Entry NoDateDescriptionOrder QuantityRegionPaymentAmountStatusActions
+
+ nt + +
+
+
Showing 0 entries
+
+ +
+ +
+ +
+
- - - - - - - - - - -
Entry NoDateDescriptionOrder QuantityRegionPaymentAmountStatus
Loading entries...
+
Order Dispatch Status Actions: + Add Installment
+ + +
+
+ + +
+ +
+ + +
+ +
+ +
+
+ @@ -583,9 +878,10 @@ tr:hover td{ background:#fbfdff; } - +
Loading entries...
+
@@ -594,7 +890,7 @@ tr:hover td{ background:#fbfdff; }
+ + + + + + @endsection \ No newline at end of file diff --git a/resources/views/admin/customers.blade.php b/resources/views/admin/customers.blade.php index dd20aef..3321dc2 100644 --- a/resources/views/admin/customers.blade.php +++ b/resources/views/admin/customers.blade.php @@ -5,6 +5,14 @@ @section('content')
- +
-

Customer List

+

Customer List

- -
-
-
{{ $customers->count() }}
-
Total Customers
- + +
+ +
+
+ +
+
+
{{ $allCustomers->count() }}
+
Total Customers
+
-
-
- @php - $newThisMonth = $customers->filter(function($customer) { - return $customer->created_at->format('Y-m') === now()->format('Y-m'); - })->count(); - @endphp - {{ $newThisMonth }} + +
+
+ +
+
+
+ @php + $newThisMonth = $allCustomers->filter(function($customer) { + return $customer->created_at->format('Y-m') === now()->format('Y-m'); + })->count(); + @endphp + {{ $newThisMonth }} +
+
New This Month
-
New This Month
-
-
-
- @php - $activeCustomers = $customers->where('status', 'active')->count(); - @endphp - {{ $activeCustomers }} + +
+
+ +
+
+
+ @php + $activeCustomers = $allCustomers->where('status', 'active')->count(); + @endphp + {{ $activeCustomers }} +
+
Active Customers
-
Active Customers
-
-
-
- @php - $premiumCount = $customers->where('customer_type', 'premium')->count(); - @endphp - {{ $premiumCount }} + +
+
+ +
+
+
+ @php + $premiumCount = $allCustomers->where('customer_type', 'premium')->count(); + @endphp + {{ $premiumCount }} +
+
Premium Customers
-
Premium Customers
-
- +
- +
@@ -368,7 +784,7 @@ name="search" value="{{ $search ?? '' }}" class="search-input" - placeholder="Search Customer Name, Email, or Phone..."> + placeholder="Search customers by name, email, or phone..."> @if(!empty($status)) @endif @@ -404,16 +820,18 @@
- + + + - + - + @forelse($customers as $c) @@ -433,20 +851,27 @@ {{ $c->email }}
{{ $c->mobile_no }} -
- {{ $c->orders->count() }} orders • ₹{{ number_format($c->orders->sum('ttl_amount'), 2) }} total -
- + + + + + + - @@ -461,7 +886,7 @@ @empty - @@ -489,6 +914,64 @@
Customer Info Customer IDOrdersTotal Create Date StatusActionsActions
+ {{ $c->customer_id }} + {{ $c->orders->count() }} + + ₹{{ number_format($c->orders->sum('ttl_amount'), 2) }} + + {{ $c->created_at ? $c->created_at->format('d-m-Y') : '-' }} -
+ No customers found.
+ + +
+
+ Showing {{ $customers->firstItem() ?? 0 }} to {{ $customers->lastItem() ?? 0 }} of {{ $customers->total() }} entries +
+
+ +
+ @for ($i = 1; $i <= $customers->lastPage(); $i++) + + {{ $i }} + + @endfor +
+ +
+
+ + @endsection \ No newline at end of file diff --git a/resources/views/admin/dashboard.blade.php b/resources/views/admin/dashboard.blade.php index 1dc430a..c08ec6c 100644 --- a/resources/views/admin/dashboard.blade.php +++ b/resources/views/admin/dashboard.blade.php @@ -12,6 +12,7 @@ html, body { body, .container-fluid { background: #f4f7fc; + font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; } .container-fluid { @@ -34,6 +35,7 @@ body, .container-fluid { letter-spacing: .018em; color: #18213e; margin-bottom: 2px; + font-family: 'Inter', sans-serif; } .dash-title-desc { @@ -42,6 +44,7 @@ body, .container-fluid { margin-bottom: 5px; font-weight: 500; letter-spacing: .01em; + font-family: 'Inter', sans-serif; } /* ===== STATS CARDS - RESPONSIVE GRID ===== */ @@ -127,12 +130,14 @@ body, .container-fluid { color:#63709b; font-weight:600; letter-spacing:.28px; + font-family: 'Inter', sans-serif; } .stats-value { font-size:1.25rem; font-weight:700; color:#194073; + font-family: 'Inter', sans-serif; } .stats-card:hover .stats-icon { @@ -170,6 +175,7 @@ body, .container-fluid { display: flex; align-items: center; gap: 11px; + font-family: 'Inter', sans-serif; } .order-mgmt-title i { @@ -191,6 +197,7 @@ body, .container-fluid { align-items: center; gap: 8px; font-family: inherit; + font-family: 'Inter', sans-serif; } .create-order-btn:hover { @@ -201,7 +208,7 @@ body, .container-fluid { .card-body, .order-mgmt-main { background: #fff; border-radius: 0 0 17px 17px; - padding:25px; + padding:20px; margin-top: 15px; } @@ -213,7 +220,7 @@ body, .container-fluid { margin-top: 15px; } -/* ===== TABLE STYLES ===== */ +/* ===== IMPROVED TABLE STYLES ===== */ .table thead tr { background: #feebbe !important; border-radius: 12px 12px 0 0; @@ -226,9 +233,10 @@ body, .container-fluid { font-weight: 700; color: #343535; letter-spacing: 0.02em; - font-size:15px; - padding-top: 12px; - padding-bottom: 10px; + font-size: 15px; + padding: 16px 12px; + font-family: 'Inter', sans-serif; + border-bottom: 2px solid #e9ecef; } .table thead th:first-child { border-radius: 9px 0 0 0;} @@ -239,20 +247,24 @@ body, .container-fluid { border-radius:9px; box-shadow:0 2px 12px #e2ebf941; border-collapse: separate; - border-spacing: 0 2px; + border-spacing: 0 8px; + font-family: 'Inter', sans-serif; + font-size: 14px; } .table-striped tbody tr { background: #fff; - border-radius: 6px; - box-shadow: 0 1px 3px rgba(0,0,0,0.04); - margin-bottom: 2px; + border-radius: 8px; + box-shadow: 0 2px 6px rgba(0,0,0,0.04); + margin-bottom: 8px; transition: all 0.3s ease; + height: 60px; } .table-striped tbody tr:hover { - box-shadow: 0 2px 6px rgba(0,0,0,0.08); - transform: translateY(-1px); + box-shadow: 0 4px 12px rgba(0,0,0,0.08); + transform: translateY(-2px); + background: #f8fafd; } .table-striped tbody tr:nth-of-type(odd) { @@ -264,39 +276,110 @@ body, .container-fluid { } .table td { - padding: 12px 6px; + padding: 14px 12px; border: none; 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 { - border-radius: 6px 0 0 6px; + border-radius: 8px 0 0 8px; + border-left: 3px solid transparent; } .table td:last-child { - border-radius: 0 6px 6px 0; + border-radius: 0 8px 8px 0; } .table-responsive { border-radius:10px; } -.badge { - font-size:13px; - font-weight:600; - padding:7px 17px; - border-radius:12px; +/* ===== UPDATED STATUS BADGE STYLES ===== */ +.badge { + padding: 7px 17px !important; + border-radius: 20px !important; + font-weight: 600 !important; + font-size: 13px !important; + border: 2px solid transparent !important; + min-width: 40px !important; + text-align: center !important; + display: inline-flex !important; + align-items: center; + justify-content: center; + line-height: 1.2 !important; + font-family: 'Inter', sans-serif; + gap: 6px; + width: 110px; } -.bg-info { - background-color:#22cbfa!important; - color:#fff!important; +.status-icon { + font-size: 13px; + 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 { font-weight:600; color:#1d3159; font-size:15px; + font-family: 'Inter', sans-serif; } .form-control, .form-select { @@ -305,6 +388,7 @@ body, .container-fluid { background: #f7f9fe; border:1.2px solid #c7dbfa; font-weight:500; + font-family: 'Inter', sans-serif; } .form-control:focus, .form-select:focus { @@ -316,6 +400,7 @@ body, .container-fluid { color:#2469d6; font-weight:600; text-decoration:underline; + font-family: 'Inter', sans-serif; } /* ===== HORIZONTAL SCROLL CONTAINER ===== */ @@ -327,7 +412,7 @@ body, .container-fluid { border-radius: 12px; background: #fff; box-shadow: 0 2px 10px rgba(0,0,0,0.08); - padding: 8px; + padding: 12px; } .table-wrapper::-webkit-scrollbar { @@ -348,7 +433,7 @@ body, .container-fluid { } .table { - min-width: 1200px; + min-width: 2000px; border-radius: 10px; } @@ -394,6 +479,7 @@ body, .container-fluid { font-size: 1.4rem; font-weight: 700; margin: 0; + font-family: 'Inter', sans-serif; } .create-order-modal .close-btn { @@ -425,6 +511,7 @@ body, .container-fluid { color: #1d3159; font-size: 15px; margin-bottom: 5px; + font-family: 'Inter', sans-serif; } .create-order-modal .form-control, @@ -435,6 +522,7 @@ body, .container-fluid { font-size: 15px; font-weight: 500; padding: 8px 12px; + font-family: 'Inter', sans-serif; } .create-order-modal .form-control:focus, @@ -449,6 +537,7 @@ body, .container-fluid { padding: 10px 20px; font-weight: 600; border-radius: 8px; + font-family: 'Inter', sans-serif; } .create-order-modal .btn-info:hover { @@ -461,6 +550,7 @@ body, .container-fluid { padding: 12px 30px; font-weight: 600; border-radius: 8px; + font-family: 'Inter', sans-serif; } .create-order-modal .btn-success:hover { @@ -472,6 +562,7 @@ body, .container-fluid { border: none; color: #000; font-weight: 600; + font-family: 'Inter', sans-serif; } .create-order-modal .btn-warning:hover { @@ -481,6 +572,7 @@ body, .container-fluid { .create-order-modal .btn-danger { background: #dc3545; border: none; + font-family: 'Inter', sans-serif; } .create-order-modal .btn-danger:hover { @@ -505,6 +597,7 @@ body, .container-fluid { position: sticky; top: 0; z-index: 10; + font-family: 'Inter', sans-serif; } /* ===== ORDER DETAILS MODAL STYLES ===== */ @@ -536,6 +629,7 @@ body, .container-fluid { font-weight: 700; color: white; margin: 0; + font-family: 'Inter', sans-serif; } .modal-header .btn-close { @@ -554,6 +648,143 @@ body, .container-fluid { background: #f8fafc; max-height: 70vh; 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 ===== */ @@ -596,7 +827,17 @@ body, .container-fluid { .table th, .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 td { - padding: 8px 4px; + padding: 10px 6px; } .badge { @@ -771,7 +1012,7 @@ body, .container-fluid { .table th, .table td { - padding: 6px 3px; + padding: 8px 4px; } .form-control, .form-select { @@ -900,69 +1141,107 @@ body, .container-fluid {
Recent Orders + + Total orders: {{ $orders->count() }} +
- - - - - - - - - - - - - - - - - - - - - - - @forelse($orders as $order) - - - - - - - - - - - - - - - +
+
#Order IDMark NoOriginDestinationTotal CTNTotal QTYTotal TTL/QTYTotal Amount (₹)Total CBMTotal TTL CBMTotal KGTotal TTL KGStatusDateActions
{{ $order->id }} - - {{ $order->order_id }} - - {{ $order->mark_no }}{{ $order->origin }}{{ $order->destination }}{{ $order->ctn }}{{ $order->qty }}{{ $order->ttl_qty }}₹{{ number_format($order->ttl_amount, 2) }}{{ $order->cbm }}{{ $order->ttl_cbm }}{{ $order->kg }}{{ $order->ttl_kg }}
+ + + + + + + + + + + + + + + + + + + + + + @forelse($orders as $order) + + - - - - @empty - - - - @endforelse - -
#Order IDMark NoOriginDestinationTotal CTNTotal QTYTotal TTL/QTYTotal Amount (₹)Total CBMTotal TTL CBMTotal KGTotal TTL KGStatusDateActions
{{ $order->id }} - {{ ucfirst($order->status) }} - {{ $order->created_at->format('d-m-Y') }} - - View + + {{ $order->order_id }}
No orders found
+ + {{ $order->mark_no }} + {{ $order->origin }} + {{ $order->destination }} + {{ $order->ctn }} + {{ $order->qty }} + {{ $order->ttl_qty }} + ₹{{ number_format($order->ttl_amount, 2) }} + {{ $order->cbm }} + {{ $order->ttl_cbm }} + {{ $order->kg }} + {{ $order->ttl_kg }} + + + @if($order->status == 'pending') + + @elseif($order->status == 'in_transit') + + @elseif($order->status == 'dispatched') + + @elseif($order->status == 'delivered') + + @endif + {{ ucfirst(str_replace('_', ' ', $order->status)) }} + + + {{ $order->created_at->format('d-m-Y') }} + + + View + + + + @empty + + No orders found + + @endforelse + + +
+ + +
+
Showing 1 to 10 of {{ $orders->count() }} entries
+
+ +
+ +
+ +
+
@@ -1167,6 +1446,14 @@ document.addEventListener('DOMContentLoaded', function() { const closeBtn = document.getElementById('closeCreateOrderModal'); 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 const resetTempData = () => { 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 += '...'; + } + + 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 += '...'; + } + + 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 = 'No orders found'; + 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 = ` + ${order.id} + + + ${order.order_id} + + + ${order.mark_no || ''} + ${order.origin || ''} + ${order.destination || ''} + ${order.ctn || ''} + ${order.qty || ''} + ${order.ttl_qty || ''} + ₹${order.ttl_amount ? Number(order.ttl_amount).toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 }) : '0.00'} + ${order.cbm || ''} + ${order.ttl_cbm || ''} + ${order.kg || ''} + ${order.ttl_kg || ''} + + + ${order.status === 'pending' ? '' : ''} + ${order.status === 'in_transit' ? '' : ''} + ${order.status === 'dispatched' ? '' : ''} + ${order.status === 'delivered' ? '' : ''} + ${order.status ? order.status.charAt(0).toUpperCase() + order.status.slice(1).replace('_', ' ') : ''} + + + ${new Date(order.created_at).toLocaleDateString('en-GB')} + + + View + + + `; + 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 = + "

Loading...

"; + + modal.show(); + + fetch(`/admin/orders/view/${id}`) + .then(response => response.text()) + .then(html => { + document.getElementById('orderDetailsBody').innerHTML = html; + }) + .catch(() => { + document.getElementById('orderDetailsBody').innerHTML = + "

Failed to load order details.

"; + }); + }); + } + }); + } }); diff --git a/resources/views/admin/invoice.blade.php b/resources/views/admin/invoice.blade.php index 2c4e0b4..84aa37a 100644 --- a/resources/views/admin/invoice.blade.php +++ b/resources/views/admin/invoice.blade.php @@ -4,1210 +4,1659 @@ @section('content')
- -
-
- - Invoice Management - -
- - -
- - - - -
- - - -
- - to - + +
+
+ + Invoice Management +
-
- -
+ +
+ +
+ + + +
-
- -
-
-
{{ $invoices->count() }}
-
Total Invoices
-
-
-
₹{{ number_format($invoices->sum('final_amount_with_gst'), 2) }}
-
Total Revenue
-
-
-
{{ $invoices->where('status', 'paid')->count() }}
-
Paid Invoices
-
-
-
{{ $invoices->where('status', 'pending')->count() }}
-
Pending Invoices
-
-
+ +
+ - -
-
-

All Invoices

- - {{ $invoices->count() }} invoices - -
- -
-
- - - - - - - - - - - - - - - + +
+ + to + +
+ - + + + + +
+ +
+
+
{{ $invoices->count() }}
+
Total Invoices
+
+
+
₹{{ number_format($invoices->sum('final_amount_with_gst'), 2) }}
+
Total Revenue
+
+
+
{{ $invoices->where('status', 'paid')->count() }}
+
Paid Invoices
+
+
+
{{ $invoices->where('status', 'pending')->count() }}
+
Pending Invoices
+
+
+ + +
+
+

All Invoices

+ + {{ $invoices->count() }} invoices + +
+ +
+
+
#Invoice NumberCustomerFinal AmountGST %Total w/GSTStatusInvoice DateDue DateAction
+ + + + + + + + + + + + + + + + + @php + $totalInvoices = $invoices->count(); + $sortedInvoices = $invoices->sortByDesc('created_at'); // Latest first + @endphp + + @forelse($sortedInvoices as $i => $invoice) + + + + + + + + + + + + + + + + + + + @empty + + + + @endforelse + +
#Invoice NumberCustomerFinal AmountGST %Total w/GSTStatusInvoice DateDue DateAction
{{ $totalInvoices - $i }} + + {{ $invoice->customer_name }}₹{{ number_format($invoice->final_amount, 2) }}{{ $invoice->gst_percent }}%₹{{ number_format($invoice->final_amount_with_gst, 2) }} + + @if($invoice->status == 'paid') + + @elseif($invoice->status == 'pending') + + @elseif($invoice->status == 'overdue') + + @endif + {{ ucfirst($invoice->status) }} + + {{ $invoice->invoice_date }}{{ $invoice->due_date }} + + Entry + +
No invoices found
+
+
+
+ + +
@php $totalInvoices = $invoices->count(); $sortedInvoices = $invoices->sortByDesc('created_at'); // Latest first @endphp @forelse($sortedInvoices as $i => $invoice) - - {{ $totalInvoices - $i }} - - -
-
- -
- - {{ $invoice->invoice_number }} - +
+
+
+
+ +
+ {{ $invoice->invoice_number }} +
+ + @if($invoice->status == 'paid') + + @elseif($invoice->status == 'pending') + + @elseif($invoice->status == 'overdue') + + @endif + {{ ucfirst($invoice->status) }} +
- - - {{ $invoice->customer_name }} - - ₹{{ number_format($invoice->final_amount, 2) }} - {{ $invoice->gst_percent }}% - ₹{{ number_format($invoice->final_amount_with_gst, 2) }} - - - - @if($invoice->status == 'paid') - - @elseif($invoice->status == 'pending') - - @elseif($invoice->status == 'overdue') - - @endif - {{ ucfirst($invoice->status) }} - - - - {{ $invoice->invoice_date }} - {{ $invoice->due_date }} - - - - Entry - - - + +
+
+ Customer + {{ $invoice->customer_name }} +
+
+ Amount + ₹{{ number_format($invoice->final_amount, 2) }} +
+
+ GST + {{ $invoice->gst_percent }}% +
+
+ Total + ₹{{ number_format($invoice->final_amount_with_gst, 2) }} +
+
+ Invoice Date + {{ $invoice->invoice_date }} +
+
+ Due Date + {{ $invoice->due_date }} +
+
+ + +
@empty - - No invoices found - +
No invoices found
@endforelse - - -
-
-
+
- -
- @php - $totalInvoices = $invoices->count(); - $sortedInvoices = $invoices->sortByDesc('created_at'); // Latest first - @endphp - - @forelse($sortedInvoices as $i => $invoice) -
-
-
-
- -
- {{ $invoice->invoice_number }} + +
+
Showing 1 to {{ $invoices->count() }} of {{ $invoices->count() }} entries
+
+ +
+ +
+ +
- - @if($invoice->status == 'paid') - - @elseif($invoice->status == 'pending') - - @elseif($invoice->status == 'overdue') - - @endif - {{ ucfirst($invoice->status) }} - -
- -
-
- Customer - {{ $invoice->customer_name }} -
-
- Amount - ₹{{ number_format($invoice->final_amount, 2) }} -
-
- GST - {{ $invoice->gst_percent }}% -
-
- Total - ₹{{ number_format($invoice->final_amount_with_gst, 2) }} -
-
- Invoice Date - {{ $invoice->invoice_date }} -
-
- Due Date - {{ $invoice->due_date }} -
-
- -
- @empty -
No invoices found
- @endforelse -
-
{{-- POPUP MODAL --}}
diff --git a/resources/views/admin/orders.blade.php b/resources/views/admin/orders.blade.php index 9d421ba..865844d 100644 --- a/resources/views/admin/orders.blade.php +++ b/resources/views/admin/orders.blade.php @@ -5,250 +5,1090 @@ @section('content') -{{-- Make sure you include Font Awesome CDN in your main layout file, e.g., in : - ---}} -
-
- Orders List +
+ Orders Management +
+ + +
+
+
{{ $orders->count() }}
+
Total Orders
+ +
+
{{ $orders->where('invoice.status', 'pending')->count() }}
+
Pending Invoices
+
+
+
{{ $orders->where('invoice.status', 'overdue')->count() }}
+
Overdue Invoices
+
+
- @if(isset($orders) && $orders->count() > 0) -
- - - - - - - - - - - - - - - - - - - + +
+ + +
- - @foreach($orders as $order) + +
+ + + +
- @php - $mark = $order->markList ?? null; - $invoice = $order->invoice ?? null; - $shipment = $order->shipments->first() ?? null; - $invoiceStatus = strtolower($invoice->status ?? ''); - $shipmentStatus = strtolower(str_replace('_', ' ', $shipment->status ?? '')); - @endphp + @if(isset($orders) && $orders->count() > 0) +
+
Order IDShipment IDCustomer IDCompanyOriginDestinationOrder DateInvoice NoInvoice DateAmountAmount + GSTInvoice StatusShipment StatusAction
+ + + + + + + + + + + + + + + + + + - - - - - - - - + + @foreach($orders as $order) + @php + $mark = $order->markList ?? null; + $invoice = $order->invoice ?? null; + $shipment = $order->shipments->first() ?? null; + $invoiceStatus = strtolower($invoice->status ?? ''); + $shipmentStatus = strtolower(str_replace('_', ' ', $shipment->status ?? '')); + @endphp - + + + + + + + + - + - + - + - + - + - - + - @endforeach - -
Order IDShipment IDCustomer IDCompanyOriginDestinationOrder DateInvoice NoInvoice DateAmountAmount + GSTInvoice StatusShipment StatusAction
{{ $order->order_id ?? '-' }}{{ $shipment->shipment_id ?? '-' }}{{ $mark->customer_id ?? '-' }}{{ $mark->company_name ?? '-' }}{{ $mark->origin ?? $order->origin ?? '-' }}{{ $mark->destination ?? $order->destination ?? '-' }}{{ $order->created_at ? $order->created_at->format('d-m-Y') : '-' }}
{{ $invoice->invoice_number ?? '-' }}
{{ $order->order_id ?? '-' }}{{ $shipment->shipment_id ?? '-' }}{{ $mark->customer_id ?? '-' }}{{ $mark->company_name ?? '-' }}{{ $mark->origin ?? $order->origin ?? '-' }}{{ $mark->destination ?? $order->destination ?? '-' }}{{ $order->created_at ? $order->created_at->format('d-m-Y') : '-' }} - {{ $invoice?->invoice_date ? date('d-m-Y', strtotime($invoice->invoice_date)) : '-' }} - {{ $invoice->invoice_number ?? '-' }} - {{ $invoice?->final_amount ? '₹'.number_format($invoice->final_amount, 2) : '-' }} - + {{ $invoice?->invoice_date ? date('d-m-Y', strtotime($invoice->invoice_date)) : '-' }} + - {{ $invoice?->final_amount_with_gst ? '₹'.number_format($invoice->final_amount_with_gst, 2) : '-' }} - + {{ $invoice?->final_amount ? '₹'.number_format($invoice->final_amount, 2) : '-' }} + - @if($invoice?->status) - - {{ ucfirst($invoice->status) }} - - @else - Pending - @endif - + {{ $invoice?->final_amount_with_gst ? '₹'.number_format($invoice->final_amount_with_gst, 2) : '-' }} + - @if($shipment?->status) - - {{ ucfirst($shipmentStatus) }} - - @else - - - @endif - + @if($invoice?->status) + + {{ ucfirst($invoice->status) }} + + @else + Pending + @endif + - - - -
+ @if($shipment?->status) + + {{ ucfirst($shipmentStatus) }} + + @else + Pending + @endif +
-
{{-- End table-wrapper --}} - @else -

- No orders found. -

- @endif + + + + + + + @endforeach + + +
{{-- End table-wrapper --}} + + +
+
Showing 1 to {{ min(10, count($orders)) }} of {{ count($orders) }} entries
+
+ +
+ +
+ +
+
+ @else +
+ +
No orders found
+

There are currently no orders in the system.

+
+ @endif
+ + @endsection \ No newline at end of file diff --git a/resources/views/admin/orders_show.blade.php b/resources/views/admin/orders_show.blade.php index e9c1d8e..2810649 100644 --- a/resources/views/admin/orders_show.blade.php +++ b/resources/views/admin/orders_show.blade.php @@ -5,28 +5,96 @@ @section('content')
- {{-- Header --}} + {{-- HEADER --}}
+ + {{-- TOP BAR --}}
-

Order Details

+

Order Details

Detailed view of this shipment order
+ {{-- ACTION BUTTONS --}} +
+ + {{-- ADD ITEM --}} + + + {{-- EDIT ORDER --}} + @if($order->status === 'pending') + + @else + + @endif + + {{-- DELETE ORDER --}} + @if($order->status === 'pending') + + @csrf + @method('DELETE') + + + @endif + +
+
- {{-- Customer Info --}} + {{-- EDIT ORDER FORM --}} + + + {{-- CUSTOMER INFO --}}
-
{{ strtoupper(substr($user->customer_name ?? 'U', 0, 1)) }}
+
{{ $user->customer_name ?? 'Unknown Customer' }}

{{ $user->company_name ?? 'N/A' }}

@@ -34,13 +102,14 @@

{{ $user->mobile_no ?? '' }}

+

{{ $user->address ?? '' }}

{{ $user->pincode ?? '' }}
- {{-- Order Summary --}} + {{-- ORDER SUMMARY --}}
@@ -65,7 +134,7 @@
- {{-- Origin - Destination --}} + {{-- ORIGIN / DESTINATION --}}

Origin

@@ -77,7 +146,7 @@
- {{-- Order Items Table --}} + {{-- ITEMS TABLE --}}
@@ -88,15 +157,17 @@ - - + + + + @foreach($order->items as $index => $item) @@ -113,38 +184,531 @@ + + @endforeach
QTY TTL/QTY UnitPrice (₹)TTL Amount (₹)PriceTotal Amount CBM TTL CBM KG TTL KG Shop NoActions
{{ $item->kg }} {{ $item->ttl_kg }} {{ $item->shop_no }} +
+ @csrf + @method('DELETE') + +
+
- {{-- Totals --}} + {{-- TOTALS --}}
{{ $order->ctn }}
- Total CTN + Total CTN
{{ $order->qty }}
- Total QTY + Total QTY
{{ $order->ttl_kg }}
- Total TTL KG + Total KG
₹{{ number_format($order->ttl_amount, 2) }}
- Total Amount + Total Amount
-
-@endsection +{{-- ADD ITEM MODAL --}} + + +{{-- AUTO-FILL SCRIPT --}} + + + + +@endsection \ No newline at end of file diff --git a/resources/views/admin/pdf/order_pdf.blade.php b/resources/views/admin/pdf/order_pdf.blade.php new file mode 100644 index 0000000..906dea3 --- /dev/null +++ b/resources/views/admin/pdf/order_pdf.blade.php @@ -0,0 +1,43 @@ + + + + + Orders Report + + + +

Orders Report

+ + + + + + + + + + + + @foreach($orders as $order) + @php + $mark = $order->markList ?? null; + $invoice = $order->invoice ?? null; + $shipment = $order->shipments->first() ?? null; + @endphp + + + + + + + + @endforeach + +
Order IDCompanyInvoice NoInvoice StatusShipment Status
{{ $order->order_id ?? '-' }}{{ $mark->company_name ?? '-' }}{{ $invoice->invoice_number ?? '-' }}{{ $invoice->status ?? '-' }}{{ $shipment->status ?? '-' }}
+ + diff --git a/resources/views/admin/reports.blade.php b/resources/views/admin/reports.blade.php index 8049351..d0d088a 100644 --- a/resources/views/admin/reports.blade.php +++ b/resources/views/admin/reports.blade.php @@ -6,20 +6,28 @@ - +
-

User Requests

-
- - {{ $requests->where('status', 'pending')->count() }} Pending - - - {{ $requests->where('status', 'approved')->count() }} Approved - - - {{ $requests->where('status', 'rejected')->count() }} Rejected - -
+

User Requests (Total: {{ $total }})

+
+
-
-
- - + +
+ +
+ + +
+ + +
+ {{ $requests->where('status', 'pending')->count() }} Pending + {{ $requests->where('status', 'approved')->count() }} Approved + {{ $requests->where('status', 'rejected')->count() }} Rejected
- +
- - - - - - - - - - - - - - - + + + - @foreach($requests as $index => $req) + @forelse($currentItems as $index => $req) - + - + - @endforeach + @empty + + @endforelse
#Request IDNameCompanyEmailMobileAddressPriorityDateStatusActions
#Request IDNameCompanyEmailMobileAddressPriorityDateStatusActions
{{ $requests->count() - $index }}{{ ($currentPage - 1) * $perPage + $index + 1 }} {{ $req->request_id }} {{ $req->customer_name }} {{ $req->company_name }} {{ $req->email }} {{ $req->mobile_no }}{{ $req->address }}{{ Str::limit($req->address, 30) }} - @if(strtolower($req->priority) == 'high') - High - @elseif(strtolower($req->priority) == 'medium') - Medium - @elseif(strtolower($req->priority) == 'low') - Low - @else - {{ $req->priority }} - @endif + @if(strtolower($req->priority) == 'high')High + @elseif(strtolower($req->priority) == 'medium')Medium + @elseif(strtolower($req->priority) == 'low')Low + @else{{ $req->priority ?? 'N/A' }}@endif {{ $req->date }} - @if($req->status == 'approved') - - - Approved - - @elseif($req->status == 'rejected') - - - Rejected - - @else - - - Pending - - @endif + @if($req->status == 'approved')Approved + @elseif($req->status == 'rejected')Rejected + @elsePending@endif @if($req->status == 'pending') @@ -306,12 +382,79 @@
No records found.
- @if($requests->isEmpty()) -
No records found.
- @endif +
+ + {{-- ✅ PAGINATION - WITH ARROW BUTTONS --}} +
+
+ Showing {{ ($currentPage - 1) * $perPage + 1 }} to {{ min($currentPage * $perPage, $total) }} of {{ $total }} entries +
+
+ {{-- Previous Page --}} + @if($currentPage > 1) + + + + + + @else + + @endif + + {{-- Page Numbers --}} +
+ @php + $start = max(1, $currentPage - 1); + $end = min($totalPages, $currentPage + 1); + @endphp + + @if($start > 1) + 1 + @if($start > 2) + ... + @endif + @endif + + @for($i = $start; $i <= $end; $i++) + @if($i == $currentPage) + {{ $i }} + @else + {{ $i }} + @endif + @endfor + + @if($end < $totalPages) + @if($end < $totalPages - 1) + ... + @endif + {{ $totalPages }} + @endif +
+ + {{-- Next Page --}} + @if($currentPage < $totalPages) + + + + + + @else + + @endif +
diff --git a/resources/views/admin/shipments.blade.php b/resources/views/admin/shipments.blade.php index 81b7d96..4092ae7 100644 --- a/resources/views/admin/shipments.blade.php +++ b/resources/views/admin/shipments.blade.php @@ -7,15 +7,18 @@ /*Remove horizontal scroll bar*/ html, body { overflow-x: hidden !important; + font-family: 'Inter', sans-serif; } .table thead th, .table tbody td { white-space: nowrap !important; - padding: 8px 4px !important; + padding: 14px 8px !important; + font-size: 14px; + font-family: 'Inter', sans-serif; } - .table th:nth-child(10), /* if Date is column 10 */ + .table th:nth-child(10), .table td:nth-child(10) { max-width: 110px !important; width: 110px !important; @@ -25,6 +28,7 @@ .table { table-layout: fixed !important; + font-family: 'Inter', sans-serif; } @@ -32,6 +36,7 @@ min-width: unset !important; width: 100% !important; table-layout: auto !important; + font-family: 'Inter', sans-serif; } .table thead th, @@ -42,6 +47,8 @@ .shipment-details-table td { white-space: normal !important; word-break: break-word; + font-family: 'Inter', sans-serif; + font-size: 14px; } .table-responsive, .modal .table-responsive { @@ -63,62 +70,125 @@ --hover-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04); } + /* Search Bar Styles */ .search-shipment-bar { display: flex; align-items: center; gap: 15px; padding: 20px; - background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); + background: white; border-radius: 16px; box-shadow: var(--card-shadow); flex-wrap: wrap; margin-bottom: 30px; - color: white; + color: #333; position: relative; overflow: hidden; + font-family: 'Inter', sans-serif; + border: 1px solid #e2e8f0; } - .search-shipment-bar::before { - content: ''; - position: absolute; - top: 0; - left: 0; - right: 0; - bottom: 0; - background: rgba(255,255,255,0.1); - z-index: 0; - } - - .search-shipment-bar > * { - position: relative; - z-index: 1; - } - - .search-shipment-bar input, - .search-shipment-bar select { - padding: 12px 16px; - border: 1px solid rgba(255,255,255,0.2); - border-radius: 10px; + .search-input-container { + display: flex; flex: 1; - min-width: 150px; - background: rgba(255,255,255,0.9); - font-weight: 500; + min-width: 300px; + background: white; + border-radius: 10px; + overflow: hidden; + border: 1px solid #d1d5db; transition: all 0.3s ease; } - .search-shipment-bar input:focus, + .search-input-container:focus-within { + border-color: #4361ee; + box-shadow: 0 0 0 3px rgba(67, 97, 238, 0.1); + } + + .search-shipment-bar input { + padding: 12px 16px; + border: none; + flex: 1; + background: transparent; + font-weight: 500; + transition: all 0.3s ease; + font-family: 'Inter', sans-serif; + font-size: 14px; + outline: none; + color: #333; + } + + .search-shipment-bar input::placeholder { + color: #6b7280; + } + + .search-button { + background: white; + color: #4361ee; + border: none; + padding: 12px 20px; + cursor: pointer; + transition: all 0.3s ease; + font-weight: 600; + font-family: 'Inter', sans-serif; + font-size: 14px; + display: flex; + align-items: center; + gap: 8px; + border-radius: 0 10px 10px 0; + min-width: 100px; + justify-content: center; + border-left: 1px solid #d1d5db; + } + + .search-input-group { + border: 1px solid #d1d5db !important; + border-radius: 8px !important; + padding: 4px !important; + background: #ffffff !important; + } + + .search-button:hover { + background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); + color: white; + transform: translateY(-1px); + box-shadow: 0 4px 12px rgba(102, 126, 234, 0.3); + } + + .search-icon { + font-size: 16px; + color: #4361ee; + transition: all 0.3s ease; + } + + .search-button:hover .search-icon { + color: white; + } + + .search-shipment-bar select { + padding: 20px 16px; + border: 1px solid #d1d5db; + border-radius: 10px; + min-width: 150px; + background: white; + font-weight: 500; + transition: all 0.3s ease; + font-family: 'Inter', sans-serif; + font-size: 14px; + color: #333; + } + .search-shipment-bar select:focus { background: white; - box-shadow: 0 0 0 3px rgba(255,255,255,0.3); + box-shadow: 0 0 0 3px rgba(67, 97, 238, 0.1); outline: none; + border-color: #4361ee; } .btn-add-shipment { - background: rgba(255,255,255,0.2); - backdrop-filter: blur(10px); + background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; - border: 1px solid rgba(255,255,255,0.3); - padding: 12px 24px; + border: none; + padding: 17px 24px; border-radius: 10px; cursor: pointer; display: flex; @@ -127,17 +197,13 @@ transition: all 0.3s ease; white-space: nowrap; font-weight: 600; + font-family: 'Inter', sans-serif; + font-size: 14px; } .btn-add-shipment:hover { - background: rgba(255,255,255,0.3); transform: translateY(-2px); - box-shadow: 0 10px 20px rgba(0,0,0,0.1); - } - - .search-icon { - font-size: 20px; - filter: drop-shadow(0 2px 4px rgba(0,0,0,0.1)); + box-shadow: 0 10px 20px rgba(102, 126, 234, 0.3); } .truck-icon { @@ -149,7 +215,7 @@ flex-direction: column; align-items: stretch; } - .search-shipment-bar input, + .search-input-container, .search-shipment-bar select { width: 100%; } @@ -162,6 +228,7 @@ box-shadow: var(--card-shadow); transition: all 0.3s ease; overflow: hidden; + font-family: 'Inter', sans-serif; } .card:hover { @@ -175,6 +242,7 @@ border: none; padding: 20px 25px; border-radius: 16px 16px 0 0 !important; + font-family: 'Inter', sans-serif; } .card-header h5 { @@ -183,6 +251,8 @@ display: flex; align-items: center; gap: 10px; + font-family: 'Inter', sans-serif; + font-size: 18px; } /* Table Styles */ @@ -198,6 +268,7 @@ width: 100%; min-width: 1200px; padding: 0; + font-family: 'Inter', sans-serif; } .table thead th { @@ -211,6 +282,8 @@ border-bottom: 2px solid var(--border); position: relative; white-space: nowrap; + font-family: 'Inter', sans-serif; + font-size: 14px; } .table thead th:first-child { @@ -239,13 +312,15 @@ border-bottom: 1px solid var(--border); font-weight: 500; white-space: nowrap; + font-family: 'Inter', sans-serif; + font-size: 14px; } .table tbody tr:last-child td { border-bottom: none; } - /* UPDATED: Status Badge Styles - ALL SAME SIZE */ + /* Status Badge Styles */ .badge { padding: 7px 17px !important; border-radius: 20px !important; @@ -254,63 +329,51 @@ border: 2px solid transparent !important; min-width: 40px !important; text-align: center !important; - display: inline-block !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; } - /* Pending Status - SAME SIZE */ + /* Status icons */ + .status-icon { + font-size: 13px; + display: flex; + align-items: center; + justify-content: center; + } + + /* Pending Status */ .badge-pending { background: linear-gradient(135deg, #fef3c7, #fde68a) !important; color: #d97706 !important; border-color: #f59e0b !important; - width: 110px; } - /* In Transit Status - SAME SIZE */ + /* In Transit Status */ .badge-in_transit { background: linear-gradient(135deg, #dbeafe, #93c5fd) !important; color: #1e40af !important; border-color: #3b82f6 !important; - width: 110px; } - /* Dispatched Status - SAME SIZE */ + /* Dispatched Status */ .badge-dispatched { background: linear-gradient(135deg, #e9d5ff, #c4b5fd) !important; color: #6b21a8 !important; border-color: #8b5cf6 !important; - width: 110px; } - /* Delivered Status - SAME SIZE */ + /* Delivered Status */ .badge-delivered { background: linear-gradient(135deg, #d1fae5, #a7f3d0) !important; color: #065f46 !important; border-color: #10b981 !important; - width: 110px; } - /* Default badge styles - SAME SIZE */ - .badge.bg-info { - background: linear-gradient(135deg, #4cc9f0, #4361ee) !important; - color: white !important; - } - - .badge.bg-success { - background: linear-gradient(135deg, #4ade80, #22c55e) !important; - color: white !important; - } - - .badge.bg-warning { - background: linear-gradient(135deg, #fbbf24, #f59e0b) !important; - color: white !important; - } - - .badge.bg-danger { - background: linear-gradient(135deg, #f87171, #ef4444) !important; - color: white !important; - } - /* Light badges for quantity, kg, cbm */ .badge.bg-light { background: #f8f9fa !important; @@ -318,9 +381,12 @@ border: 1px solid #dee2e6 !important; min-width: 80px !important; padding: 6px 12px !important; + font-family: 'Inter', sans-serif; + font-size: 13px; + width: auto; } - /* NEW: Action Button Styles */ + /* Action Button Styles */ .action-container { position: relative; display: inline-block; @@ -339,6 +405,7 @@ justify-content: center; width: 36px; height: 36px; + font-family: 'Inter', sans-serif; } .btn-edit-status:hover { @@ -362,6 +429,7 @@ margin-top: -50px; border: 1px solid var(--border); z-index: 1050; + font-family: 'Inter', sans-serif; } .status-dropdown.show { @@ -382,6 +450,7 @@ gap: 8px; background: transparent; width: 100%; + font-family: 'Inter', sans-serif; } .status-option:hover { @@ -447,12 +516,73 @@ background: #10b981; } + /* View Button Styles */ + .btn-view { + background: #4361ee; + color: white; + border: none; + border-radius: 8px; + padding: 8px; + cursor: pointer; + transition: all 0.3s ease; + display: flex; + align-items: center; + justify-content: center; + width: 36px; + height: 36px; + font-weight: 600; + font-size: 16px; + font-family: 'Inter', sans-serif; + position: relative; + overflow: hidden; + } + + .btn-view::before { + content: ''; + position: absolute; + top: 0; + left: -100%; + width: 100%; + height: 100%; + background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); + transition: all 0.3s ease; + z-index: 1; + } + + .btn-view:hover::before { + left: 0; + } + + .btn-view i { + position: relative; + z-index: 2; + transition: all 0.3s ease; + } + + .btn-view:hover { + transform: translateY(-2px); + box-shadow: 0 4px 12px rgba(102, 126, 234, 0.4); + } + + .btn-view:hover i { + transform: scale(1.1); + } + + /* Action buttons container */ + .action-buttons { + display: flex; + gap: 8px; + align-items: center; + justify-content: center; + } + /* Modal Styles */ .modal-content { border-radius: 20px; border: none; box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25); overflow: hidden; + font-family: 'Inter', sans-serif; } .modal-header { @@ -462,6 +592,7 @@ padding: 25px 30px 15px; border-radius: 20px 20px 0 0; position: relative; + font-family: 'Inter', sans-serif; } .modal-header::after { @@ -477,6 +608,7 @@ .modal-title { font-weight: 700; font-size: 1.5rem; + font-family: 'Inter', sans-serif; } .btn-close { @@ -490,6 +622,7 @@ .modal-body { padding: 25px 30px; + font-family: 'Inter', sans-serif; } /* Form Styles */ @@ -498,16 +631,18 @@ color: #5a6c7d; margin-bottom: 8px; font-size: 0.9rem; + font-family: 'Inter', sans-serif; } .form-control { border-radius: 10px; border: 1px solid #e2e8f0; padding: 12px 16px; - font-size: 15px; + font-size: 14px; transition: all 0.3s ease; background: #fafbfc; color: #4a5568; + font-family: 'Inter', sans-serif; } .form-control:focus { @@ -520,39 +655,6 @@ color: #a0aec0; } - /* Date Input Styling */ - input[type="date"] { - position: relative; - } - - input[type="date"]::-webkit-calendar-picker-indicator { - background: transparent; - bottom: 0; - color: transparent; - cursor: pointer; - height: auto; - left: 0; - position: absolute; - right: 0; - top: 0; - width: auto; - } - - input[type="date"] { - position: relative; - padding-right: 40px; - } - - input[type="date"]:after { - content: "📅"; - position: absolute; - right: 12px; - top: 50%; - transform: translateY(-50%); - pointer-events: none; - font-size: 16px; - } - /* Button Styles */ .btn-cancel { background: #f7fafc; @@ -562,6 +664,8 @@ font-weight: 600; padding: 12px 30px; transition: all 0.3s ease; + font-family: 'Inter', sans-serif; + font-size: 14px; } .btn-cancel:hover { @@ -575,11 +679,12 @@ background: linear-gradient(135deg, #48bb78, #38a169); color: white; font-weight: 600; - font-size: 16px; + font-size: 14px; border-radius: 10px; padding: 12px 35px; border: none; transition: all 0.3s ease; + font-family: 'Inter', sans-serif; } .btn-create:hover { @@ -595,6 +700,7 @@ border-spacing: 0 8px; margin: 0; min-width: 1300px; + font-family: 'Inter', sans-serif; } .custom-table-modal thead th { @@ -605,9 +711,10 @@ border: 1px solid #e2e8f0; text-align: center; position: relative; - font-size: 0.9rem; + font-size: 14px; letter-spacing: 0.3px; white-space: nowrap; + font-family: 'Inter', sans-serif; } .custom-table-modal thead th:first-child { @@ -644,6 +751,8 @@ position: relative; color: #4a5568; white-space: nowrap; + font-family: 'Inter', sans-serif; + font-size: 14px; } .custom-table-modal tbody tr td:first-child { @@ -656,38 +765,6 @@ border-bottom-right-radius: 10px; } - /* Checkbox Styling */ - input[type="checkbox"] { - width: 20px; - height: 20px; - border-radius: 6px; - border: 2px solid #cbd5e0; - cursor: pointer; - position: relative; - transition: all 0.2s ease; - background: #f7fafc; - } - - input[type="checkbox"]:checked { - background: var(--primary); - border-color: var(--primary); - } - - /* Link Styling */ - a.text-primary { - color: var(--primary) !important; - text-decoration: none; - font-weight: 600; - transition: all 0.3s ease; - position: relative; - color: #4361ee !important; - } - - a.text-primary:hover { - color: var(--primary-dark) !important; - text-decoration: underline; - } - /* Shipment Details Modal */ .shipment-details-header { background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); @@ -695,10 +772,12 @@ border: none; padding: 25px 30px 15px; border-radius: 20px 20px 0 0; + font-family: 'Inter', sans-serif; } .shipment-details-body { padding: 40px 45px; + font-family: 'Inter', sans-serif; } .shipment-info-row { @@ -709,6 +788,7 @@ background: #f8fafc; border-radius: 12px; box-shadow: 0 2px 10px rgba(0,0,0,0.05); + font-family: 'Inter', sans-serif; } .shipment-info-item { @@ -722,12 +802,14 @@ color: #64748b; font-size: 14px; margin-bottom: 5px; + font-family: 'Inter', sans-serif; } .shipment-info-value { font-weight: 700; font-size: 18px; color: var(--dark); + font-family: 'Inter', sans-serif; } .shipment-details-table { @@ -736,6 +818,7 @@ border-spacing: 0 8px; margin-top: 20px; min-width: 1400px; + font-family: 'Inter', sans-serif; } .shipment-details-table th { @@ -747,6 +830,8 @@ border: none; position: relative; white-space: nowrap; + font-family: 'Inter', sans-serif; + font-size: 14px; } .shipment-details-table th:first-child { @@ -766,6 +851,8 @@ background: white; box-shadow: 0 2px 5px rgba(0,0,0,0.05); white-space: nowrap; + font-family: 'Inter', sans-serif; + font-size: 14px; } .shipment-details-table tr td:first-child { @@ -778,6 +865,31 @@ border-bottom-right-radius: 10px; } + /* Delete Button for Orders */ + .btn-delete-order { + background: linear-gradient(135deg, #f87171, #ef4444); + color: white; + border: none; + border-radius: 6px; + padding: 6px 12px; + cursor: pointer; + transition: all 0.3s ease; + font-size: 12px; + font-weight: 600; + font-family: 'Inter', sans-serif; + display: flex; + align-items: center; + gap: 4px; + min-width: 80px; + justify-content: center; + } + + .btn-delete-order:hover { + background: linear-gradient(135deg, #ef4444, #dc2626); + transform: translateY(-2px); + box-shadow: 0 4px 12px rgba(239, 68, 68, 0.3); + } + /* Shipment Totals Section */ .shipment-totals { margin-top: 25px; @@ -786,6 +898,7 @@ border-radius: 12px; box-shadow: 0 4px 6px rgba(0,0,0,0.05); border-left: 4px solid #4361ee; + font-family: 'Inter', sans-serif; } .shipment-totals-row { @@ -812,6 +925,7 @@ margin-bottom: 8px; text-transform: uppercase; letter-spacing: 0.5px; + font-family: 'Inter', sans-serif; } .shipment-total-value { @@ -819,6 +933,7 @@ font-size: 20px; color: #1e293b; line-height: 1.2; + font-family: 'Inter', sans-serif; } .total-amount { @@ -891,6 +1006,7 @@ /* Status Filter Styles */ .status-filter-container { position: relative; + margin-left:350px; } .status-filter-select { @@ -905,17 +1021,189 @@ padding-right: 40px !important; } - /* Shipment row styling for filtering */ - .shipment-row { + /* Pagination Styles */ + .pagination-container { + display: flex; + justify-content: space-between; + align-items: center; + margin-top: 15px; + padding: 12px 25px; + border-top: 1px solid #eef3fb; + font-family: 'Inter', sans-serif; + } + + .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%); + } + + @media (max-width: 768px) { + .pagination-container { + flex-direction: column; + gap: 10px; + align-items: stretch; + } + + .pagination-controls { + justify-content: center; + } + } + + /* Delete Confirmation Modal */ + .delete-confirmation-modal .modal-header { + background: linear-gradient(135deg, #ef4444, #dc2626); + } + + .delete-confirmation-modal .btn-confirm-delete { + background: linear-gradient(135deg, #ef4444, #dc2626); + color: white; + border: none; + border-radius: 8px; + padding: 10px 20px; + font-weight: 600; transition: all 0.3s ease; } - .shipment-row.hidden { - display: none !important; + .delete-confirmation-modal .btn-confirm-delete:hover { + background: linear-gradient(135deg, #dc2626, #b91c1c); + transform: translateY(-2px); + box-shadow: 0 4px 12px rgba(220, 38, 38, 0.3); } - .shipment-row.visible { - display: table-row; + .delete-confirmation-modal .btn-cancel-delete { + background: #f7fafc; + color: #718096; + border: 1px solid #cbd5e0; + border-radius: 8px; + padding: 10px 20px; + font-weight: 600; + transition: all 0.3s ease; + } + + .delete-confirmation-modal .btn-cancel-delete:hover { + background: #edf2f7; + color: #4a5568; } @@ -938,12 +1226,27 @@
@endif - - - +
- 🔍 - +
+
+ + +
+
+
-
- - - +