Skip to content

Commit

Permalink
Refactor product details retrieval and enhance sidebar styling; add A…
Browse files Browse the repository at this point in the history
…PI endpoint for product details
  • Loading branch information
pamudusarasith committed Nov 28, 2024
1 parent e1815bc commit 746e3c0
Show file tree
Hide file tree
Showing 10 changed files with 859 additions and 296 deletions.
1 change: 1 addition & 0 deletions app/Routes.php
Original file line number Diff line number Diff line change
Expand Up @@ -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],
Expand Down
12 changes: 12 additions & 0 deletions app/controllers/Products.php
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}
81 changes: 64 additions & 17 deletions app/models/Product.php
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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;
}
Expand Down
2 changes: 1 addition & 1 deletion app/views/Categories.view.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<div class="category-container">
<div class="top-bar">
<h1>Categories</h1>
<button id="new-category-btn" class="btn btn-primary">
<button id="new-category-btn" class="btn btn-primary" onclick="openCategoryModal()">
<span class="material-symbols-rounded">add</span>New Category
</button>
</div>
Expand Down
45 changes: 29 additions & 16 deletions app/views/Products.view.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,10 @@
<p class="header-description">Manage your products, stock levels and categories</p>
</div>
<div class="header-actions">
<button id="new-prod-btn" class="btn btn-light" onclick="openProductModal()">
<button id="new-prod-btn" class="btn btn-primary" onclick="openProductModal()">
<span class="material-symbols-rounded">add_box</span>
New Product
</button>
<button id="new-batch-btn" class="btn btn-primary" onclick="openBatchModal()">
<span class="material-symbols-rounded">inventory_2</span>
Add Batch
</button>
</div>
</div>

Expand Down Expand Up @@ -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));
?>
<div class="category-card glass">
Expand Down Expand Up @@ -90,7 +86,7 @@
<thead>
<tr>
<th>Product Details</th>
<th>Price</th>
<th>Selling Price</th>
<th>Stock Level</th>
<th>Status</th>
<th>Actions</th>
Expand All @@ -107,13 +103,13 @@
</div>
<div class="product-details">
<p class="product-name"><?= htmlspecialchars($product['name']) ?></p>
<span class="product-id">ID: <?= htmlspecialchars($product['id']) ?></span>
<span class="product-barcode">BARCODE: <?= htmlspecialchars($product['barcode']) ?></span>
</div>
</div>
</td>
<td class="price-cell">
<span class="price">
<?= is_numeric($product['price']) ? "Rs. " . number_format($product['price'], 2) : $product['price'] ?>
<?= is_numeric($product['selling_price']) ? "Rs. " . number_format($product['selling_price'], 2) : $product['selling_price'] ?>
</span>
</td>
<td class="stock-cell">
Expand All @@ -126,22 +122,19 @@
</td>
<td class="status-cell">
<?php
$status = $product['quantity'] === 0 ? 'out' : ($product['quantity'] <= 100 ? 'low' : 'in');
$statusText = $product['quantity'] === 0 ? 'Out of Stock' : ($product['quantity'] <= 100 ? 'Low Stock' : 'In Stock');
$status = $product['quantity'] === 0 ? 'out' : ($product['quantity'] <= $product['min_threshold'] ? 'low' : 'in');
$statusText = $product['quantity'] === 0 ? 'Out of Stock' : ($product['quantity'] <= $product['min_threshold'] ? 'Low Stock' : 'In Stock');
?>
<span class="status-badge <?= $status ?>"><?= $statusText ?></span>
</td>
<td class="actions-cell">
<div class="action-buttons">
<button class="action-btn" title="Edit Product" data-action="edit">
<button class="action-btn" title="Edit Product" data-action="edit" onclick="openProductEditModal(<?= $product['id'] ?>)">
<span class="material-symbols-rounded">edit</span>
</button>
<button class="action-btn" title="Add Stock" data-action="stock">
<button class="action-btn" title="Add Stock" data-action="stock" onclick="openBatchModal()">
<span class="material-symbols-rounded">add_circle</span>
</button>
<button class="action-btn" title="View History" data-action="history">
<span class="material-symbols-rounded">history</span>
</button>
</div>
</td>
</tr>
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
}
}
</script>
Loading

0 comments on commit 746e3c0

Please sign in to comment.