From 746e3c0c7ed0963d431f6016f5d5143e8acca324 Mon Sep 17 00:00:00 2001 From: Pamudu Sarasith Date: Thu, 28 Nov 2024 15:19:16 +0530 Subject: [PATCH] Refactor product details retrieval and enhance sidebar styling; add API endpoint for product details --- app/Routes.php | 1 + app/controllers/Products.php | 12 + app/models/Product.php | 81 ++- app/views/Categories.view.php | 2 +- app/views/Products.view.php | 45 +- app/views/components/CategoryForm.view.php | 544 +++++++++++++++------ app/views/components/Navbar.view.php | 316 ++++++++++-- app/views/components/ProductForm.view.php | 28 +- app/views/components/Sidebar.view.php | 124 ++--- public/css/styles.css | 2 +- 10 files changed, 859 insertions(+), 296 deletions(-) diff --git a/app/Routes.php b/app/Routes.php index 841a03e..1ac3c65 100644 --- a/app/Routes.php +++ b/app/Routes.php @@ -7,6 +7,7 @@ '/products' => ['controller' => App\Controllers\Products::class], '/products/search' => ['controller' => App\Controllers\Products::class, 'action' => 'search'], '/product' => ['controller' => App\Controllers\Products::class, 'action' => 'details'], + '/api/product' => ['controller' => App\Controllers\Products::class, 'action' => 'apiDetails'], '/categories/search' => ['controller' => App\Controllers\Categories::class, 'action' => 'search'], '/users' => ['controller' => App\Controllers\UserController::class], '/roles' => ['controller' => App\Controllers\RolesController::class], diff --git a/app/controllers/Products.php b/app/controllers/Products.php index cd274f0..dc30460 100644 --- a/app/controllers/Products.php +++ b/app/controllers/Products.php @@ -79,4 +79,16 @@ public function details() 'data' => ['product' => $product] ]); } + + public function apiDetails() + { + App\Utils::requireAuth(); + + $id = $_GET['id']; + $model = new App\Models\Product(); + $product = $model->getProductDetails($id); + + header(Consts::HEADER_JSON); + echo json_encode($product); + } } diff --git a/app/models/Product.php b/app/models/Product.php index b7dac85..0d9357d 100644 --- a/app/models/Product.php +++ b/app/models/Product.php @@ -38,24 +38,44 @@ public function getProductsByCategory(string $category_id): array SELECT p.id, p.name, + p.description, + p.measure_unit, + p.weight, + p.dimensions, + p.barcode, + p.is_active, + SUM(i.quantity) as quantity, IF( - COUNT(pb.selling_price) > 1, - \"Multiple\", - pb.selling_price - ) AS price, - SUM(pb.quantity) AS quantity + COUNT(DISTINCT i.selling_price) > 1, + 'Multiple', + i.selling_price + ) as selling_price, + GROUP_CONCAT(DISTINCT c.name) as categories, + -- Add threshold details + t.min_threshold, + t.max_threshold, + t.reorder_point, + t.reorder_quantity FROM - `product_category` pc - INNER JOIN product p ON - p.id = pc.product_id - INNER JOIN inventory pb ON - p.id = pb.product_id + product p + LEFT JOIN inventory i ON p.id = i.product_id + LEFT JOIN product_category pc ON p.id = pc.product_id + LEFT JOIN category c ON pc.category_id = c.id + LEFT JOIN threshold t ON p.id = t.product_id WHERE - p.branch_id = :branch_id AND pc.category_id = :category_id + p.is_active = 1 + AND p.branch_id = :branch_id + AND pc.category_id = :category_id GROUP BY - p.id;"); + p.id + ORDER BY + p.name;"); $stmt->execute(['branch_id' => $_SESSION["branch_id"], 'category_id' => $category_id]); - return $stmt->fetchAll(); + $result = $stmt->fetchAll(); + foreach ($result as &$product) { + $product['quantity'] = is_numeric($product['quantity']) ? (int) $product['quantity'] : 0; + } + return $result; } public function addProduct(array $product): void @@ -129,14 +149,41 @@ public function getProductBatches(int $id): array public function getProductDetails(int $id): array { - $stmt = $this->dbh->prepare("SELECT id, name, description, measure_unit, image FROM product WHERE id = :id"); - $stmt->execute(['id' => $id]); + $stmt = $this->dbh->prepare(" + SELECT + p.id, + p.name, + p.description, + p.measure_unit, + p.weight, + p.dimensions, + p.shelf_life_days, + p.storage_requirements, + p.barcode, + p.image, + p.is_active, + GROUP_CONCAT(DISTINCT c.name) as categories, + -- Add threshold details + t.min_threshold, + t.max_threshold, + t.reorder_point, + t.reorder_quantity, + t.alert_email + FROM + product p + LEFT JOIN product_category pc ON p.id = pc.product_id + LEFT JOIN category c ON pc.category_id = c.id + LEFT JOIN threshold t ON p.id = t.product_id + WHERE + p.is_active = 1 + AND p.branch_id = :branch_id + AND p.id = :id;"); + $stmt->execute(['id' => $id, 'branch_id' => $_SESSION["branch_id"]]); $result = $stmt->fetch(); $finfo = new \finfo(FILEINFO_MIME_TYPE); $mime = $finfo->buffer($result["image"]); $result["image"] = "data:$mime;base64," . base64_encode($result["image"]); - $result['categories'] = $this->getProductCategories($id); - $result['batches'] = $this->getProductBatches($id); + // $result['batches'] = $this->getProductBatches($id); return $result; } diff --git a/app/views/Categories.view.php b/app/views/Categories.view.php index ad6751f..a6d617c 100644 --- a/app/views/Categories.view.php +++ b/app/views/Categories.view.php @@ -5,7 +5,7 @@

Categories

-
diff --git a/app/views/Products.view.php b/app/views/Products.view.php index cf6f18c..0931b07 100644 --- a/app/views/Products.view.php +++ b/app/views/Products.view.php @@ -11,14 +11,10 @@

Manage your products, stock levels and categories

- -
@@ -59,7 +55,7 @@ foreach ($categories as $category): $categoryProducts = $products[$category] ?? []; $totalProducts = count($categoryProducts); - $lowStock = count(array_filter($categoryProducts, fn($p) => $p['quantity'] <= 100 && $p['quantity'] > 0)); + $lowStock = count(array_filter($categoryProducts, fn($p) => $p['quantity'] <= $p['min_threshold'] && $p['quantity'] > 0)); $outOfStock = count(array_filter($categoryProducts, fn($p) => $p['quantity'] === 0)); ?>
@@ -90,7 +86,7 @@ Product Details - Price + Selling Price Stock Level Status Actions @@ -107,13 +103,13 @@

- ID: + BARCODE:
- + @@ -126,22 +122,19 @@
- - -
@@ -370,6 +363,7 @@ font-size: 0.75rem; font-weight: 600; text-transform: uppercase; + text-align: left; letter-spacing: 0.05em; color: var(--text-secondary); border-bottom: 1px solid var(--border-light); @@ -808,4 +802,23 @@ function openHistoryModal(productId) { console.log('View history:', productId); } }); + + async function fetchProductDetails(productId) { + try { + const response = await fetch(`/api/product?id=${productId}`); + if (!response.ok) throw new Error('Failed to fetch product details'); + return await response.json(); + } catch (error) { + console.error('Error fetching product details:', error); + return null; + } + } + + // Update the openProductEditModal function + async function openProductEditModal(productId) { + const productData = await fetchProductDetails(productId); + if (productData) { + openProductModal(true, productData); + } + } \ No newline at end of file diff --git a/app/views/components/CategoryForm.view.php b/app/views/components/CategoryForm.view.php index 27009e9..c075e39 100644 --- a/app/views/components/CategoryForm.view.php +++ b/app/views/components/CategoryForm.view.php @@ -1,167 +1,405 @@ - -
- close -
-

Add New Category

-
- - - - - - - - - - - -