View file File name : items.php Content :<?php session_start(); if (!isset($_SESSION['user_id'])) { header('Location: index.php'); exit(); } require_once '_helpers.php'; load_data(); try { require 'db_config.php'; $conn = new mysqli($servername, $username, $password, $dbname); if ($conn->connect_error) { throw new Exception("Connection failed: " . $conn->connect_error); } $items_result = $conn->query("SELECT * FROM items ORDER BY name ASC"); $items_list = []; if($items_result) { while($row = $items_result->fetch_assoc()) { $items_list[] = $row; } } $conn->close(); } catch (Exception $e) { $items_list = []; } ?> <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Products & Services - <?php echo htmlspecialchars($business['name']); ?></title> <script src="https://cdn.tailwindcss.com"></script> <style>:root { --primary: <?php echo htmlspecialchars($business['primary_color'] ?? '217 91% 60%'); ?>; } .bg-primary { background-color: hsl(var(--primary)); } .text-primary { color: hsl(var(--primary)); } .border-primary { border-color: hsl(var(--primary)); }</style> </head> <body class="bg-slate-50"> <div class="flex h-screen"> <?php include '_sidebar.php'; ?> <div class="flex-1 flex flex-col overflow-hidden lg:ml-64"> <?php include '_header.php'; ?> <main class="flex-1 overflow-x-hidden overflow-y-auto bg-slate-50 p-6"> <div class="flex flex-col gap-8"> <div class="flex flex-col sm:flex-row items-start sm:items-center justify-between gap-4"> <div> <h1 class="text-3xl font-bold tracking-tight">Products & Services</h1> <p class="text-slate-500">Manage your products and services.</p> </div> <a href="item-form.php" class="px-4 py-2 bg-primary text-white rounded-full text-sm font-semibold hover:bg-opacity-90 flex items-center gap-2"> <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><line x1="12" x2="12" y1="8" y2="16"/><line x1="8" x2="16" y1="12" y2="12"/></svg> Add a product or service </a> </div> <div class="relative w-full max-w-sm"> <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="absolute left-3 top-1/2 -translate-y-1/2 text-slate-400"><circle cx="11" cy="11" r="8"/><path d="m21 21-4.3-4.3"/></svg> <input id="item-search" type="text" placeholder="Search by name or description" class="pl-10 w-full h-10 px-3 py-2 border border-slate-300 rounded-full bg-white text-sm"> </div> <div class="bg-white rounded-lg shadow-sm border"> <table class="w-full text-sm" id="items-table"> <thead class="bg-slate-50"> <tr> <th class="p-4 text-left font-semibold text-slate-600">Name</th> <th class="p-4 text-left font-semibold text-slate-600 hidden md:table-cell">Description</th> <th class="p-4 text-right font-semibold text-slate-600">Price</th> <th class="p-4"></th> </tr> </thead> <tbody> <?php foreach ($items_list as $item): ?> <tr class="border-b hover:bg-slate-50 item-row" data-search-text="<?php echo strtolower(htmlspecialchars($item['name'] . ' ' . $item['description'])); ?>"> <td class="p-4 font-medium text-slate-800"><?php echo htmlspecialchars($item['name']); ?></td> <td class="p-4 text-slate-500 max-w-sm truncate hidden md:table-cell"><?php echo htmlspecialchars($item['description']); ?></td> <td class="p-4 text-right"><?php echo format_currency($item['price']); ?></td> <td class="p-4 relative"> <button class="dropdown-toggle p-2 rounded-full hover:bg-slate-100"> <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="1"/><circle cx="19" cy="12" r="1"/><circle cx="5" cy="12" r="1"/></svg> </button> <div class="dropdown-menu hidden absolute right-8 top-1/2 -translate-y-1/2 w-48 bg-white rounded-md shadow-lg border z-10 p-1"> <a href="item-form.php?id=<?php echo htmlspecialchars($item['id']); ?>" class="flex items-center gap-2 w-full text-left px-3 py-1.5 text-sm text-slate-700 hover:bg-slate-50 rounded-md"><svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M17 3a2.85 2.83 0 1 1 4 4L7.5 20.5 2 22l1.5-5.5Z"/><path d="m15 5 4 4"/></svg>Edit</a> <hr class="my-1"> <button class="item-action flex items-center gap-2 w-full text-left px-3 py-1.5 text-sm text-red-600 hover:bg-red-50 rounded-md" data-action="delete" data-id="<?php echo htmlspecialchars($item['id']); ?>" data-name="<?php echo htmlspecialchars($item['name']); ?>"><svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 6h18"/><path d="M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6"/><path d="M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2"/></svg>Delete</button> </div> </td> </tr> <?php endforeach; ?> </tbody> </table> </div> </div> </main> </div> </div> <script> document.addEventListener('DOMContentLoaded', () => { const searchInput = document.getElementById('item-search'); const rows = document.querySelectorAll('.item-row'); searchInput.addEventListener('input', (e) => { const searchTerm = e.target.value.toLowerCase(); rows.forEach(row => { row.style.display = row.dataset.searchText.includes(searchTerm) ? '' : 'none'; }); }); document.body.addEventListener('click', (e) => { document.querySelectorAll('.dropdown-menu').forEach(menu => { if (!menu.parentElement.contains(e.target)) { menu.classList.add('hidden'); } }); const dropdownToggle = e.target.closest('.dropdown-toggle'); if (dropdownToggle) { e.stopPropagation(); const menu = dropdownToggle.nextElementSibling; document.querySelectorAll('.dropdown-menu').forEach(m => { if (m !== menu) m.classList.add('hidden'); }); menu.classList.toggle('hidden'); } const itemAction = e.target.closest('.item-action'); if(itemAction && itemAction.dataset.action === 'delete') { e.preventDefault(); e.stopPropagation(); const itemId = itemAction.dataset.id; const itemName = itemAction.dataset.name; if(confirm(`Are you sure you want to delete "${itemName}"?`)) { const formData = new FormData(); formData.append('action', 'delete_item'); formData.append('item_id', itemId); fetch('api.php', { method: 'POST', body: formData }) .then(res => res.json()) .then(data => { if(data.success) { alert(data.data.message); location.reload(); } else { alert('Error: ' + data.message); } }); } } }); }); </script> </body> </html>