diff --git a/public/components/Navbar.php b/public/components/Navbar.php index 4406ea08d504ed73f4c15f2cb9da93d8e8ecebfc..62d17756b1168e61da1b2ac3e86d6a58f6db4a5b 100644 --- a/public/components/Navbar.php +++ b/public/components/Navbar.php @@ -1,18 +1,21 @@ <nav> - <ul> - <li><a href="/">Home</a></li> - <li><a href="cat">Cats</a></li> - <li><a href="sighting">Sightings</a></li> - <?php - // Check if the user is logged in (You will need to implement this logic) - $loggedIn = isset($_SESSION['user_id']); - - if ($loggedIn) { - echo '<li><a href="logout">Logout</a></li>'; - } else { - echo '<li><a href="register">Register</a></li>'; - echo '<li><a href="login">Login</a></li>'; - } - ?> - </ul> - </nav> + <ul> + <li><a href="/">Home</a></li> + <li><a href="cat">Cats</a></li> + <li><a href="sighting">Sightings</a></li> + <?php + // Check if the user is logged in (You will need to implement this logic) + $loggedIn = isset($_SESSION['user_id']); + $isAdmin = isset($_SESSION['isAdmin']); + if ($isAdmin) { + echo '<li><a href="admin">Manage Users</a></li>'; + } + if ($loggedIn) { + echo '<li><a href="logout">Logout</a></li>'; + } else { + echo '<li><a href="register">Register</a></li>'; + echo '<li><a href="login">Login</a></li>'; + } + ?> + </ul> +</nav> \ No newline at end of file diff --git a/public/components/Pagination.php b/public/components/Pagination.php index 87965a8a75e027293beefd66f006d399ef4eb008..cdbe6c40a969b7c03ac47b174737bbac07be3437 100644 --- a/public/components/Pagination.php +++ b/public/components/Pagination.php @@ -31,7 +31,7 @@ function generatePaginationLinks($currentPage, $totalPages) } $totalCount = $_count; // Total number of cats -$pageSize = 10; // Number of cats per page +$pageSize = isset($_GET['pageSize']) ? intval($_GET['pageSize']) : 10; // Number of cats per page $totalPages = ceil($totalCount / $pageSize); $currentPage = isset($_GET['pageNo']) ? intval($_GET['pageNo']) : 1; diff --git a/public/css/styles.css b/public/css/styles.css index 51ac1b4fedfc3f40cdcba55758e4e576869f6891..fc8644ec68401efa1fcb227e2de63e99a14a4d4c 100644 --- a/public/css/styles.css +++ b/public/css/styles.css @@ -395,4 +395,85 @@ button[type="submit"] { justify-content: center; align-items: center; margin-top: 20px; -} \ No newline at end of file +} + +.search-form { + background-color: #f7f7f7; + border: 1px solid #ddd; + border-radius: 5px; + padding: 10px; + display: flex; + flex-wrap: wrap; + justify-content: space-between; + align-items: center; +} + +.search-bar { + width: 100%; + display: flex; + align-items: center; +} + +.search-input { + flex: 1; + padding: 8px; + border: 1px solid #ccc; + border-radius: 3px; + font-size: 14px; + margin-right: 10px; +} + +.search-button { + background-color: #007bff; + color: #fff; + border: none; + padding: 8px 16px; + border-radius: 3px; + cursor: pointer; + font-size: 14px; +} + +.search-options { + display: flex; + flex-wrap: wrap; + width: 100%; + justify-content: space-between; + margin-top: 10px; +} + +.filter-bar, +.sort-bar { + flex: 1; + display: flex; + flex-wrap: wrap; + align-items: center; +} + +.filter-select, +.sort-select { + padding: 8px; + border: 1px solid #ccc; + border-radius: 3px; + font-size: 14px; + margin-right: 10px; +} + +.sort-label { + font-weight: bold; +} + +.sort-options { + display: flex; + flex-wrap: wrap; +} + +.sort-option { + display: flex; + align-items: center; + margin-right: 20px; +} + +.sort-checkbox { + margin-right: 5px; +} + diff --git a/public/js/cats.js b/public/js/cats.js index 5af36b3c4fd8fa7e8e5ca71d467c65d90ebeb15f..ddc859fe431e10eb95d2fac3b5da5163b11e29e0 100644 --- a/public/js/cats.js +++ b/public/js/cats.js @@ -1,4 +1,3 @@ -// app.js const addCatModal = document.getElementById("add-cat-modal"); const addCatButton = document.getElementById("add-cat-button"); @@ -11,35 +10,32 @@ function closeAddCatModal() { addCatModal.style.display = "none"; } -// Close the modal if the user clicks outside of it window.onclick = function (event) { if (event.target === addCatModal) { closeAddCatModal(); } } -// Submit form + + const addCatForm = document.getElementById("add-cat-form"); addCatForm.addEventListener("submit", function (event) { event.preventDefault(); - // Create a FormData object to send the form data as a multipart/form-data request + const formData = new FormData(addCatForm); - // Use the Fetch API to send a POST request to the server + fetch("/cat", { method: "POST", body: formData, }) .then((response) => { if (response.ok) { - // Cat added successfully, you can handle the response here if needed + console.log("Cat added successfully"); - // Close the modal after successful submission closeAddCatModal(); - // Reload the page to show the updated cat list window.location.reload(); } else { - // Handle error cases here console.error("Failed to add cat"); } }) @@ -48,32 +44,56 @@ addCatForm.addEventListener("submit", function (event) { }); }); +function getQueryParam(name) { + const urlParams = new URLSearchParams(window.location.search); + return urlParams.get(name); +} + +function setFormFieldValue(searchForm, fieldName, value) { + + const field = searchForm.querySelector(`[name='${fieldName}']`); + if (field) { + if (field.type === 'checkbox') { + // If it's a checkbox, set the 'checked' property + field.checked = value === 'true'; + } else { + field.value = value; + } + } +} + + + // JavaScript to handle delete button click document.addEventListener("DOMContentLoaded", function () { const deleteButtons = document.querySelectorAll(".delete-button"); deleteButtons.forEach(function (button) { button.addEventListener("click", function (event) { - event.preventDefault(); + let conf = confirm('Are you sure you want to delete this cat?'); + if (!conf) { + event.preventDefault(); + return; + } + - // Get the URL from the button's href attribute const deleteUrl = button.getAttribute("href"); - // Send a DELETE request to the specified URL + fetch(deleteUrl, { method: "DELETE", }) .then(function (response) { if (response.ok) { - // If the DELETE request was successful, reload the page + location.reload(); } else { - // Handle errors here if needed + console.error("DELETE request failed."); } }) .catch(function (error) { - // Handle network errors here if needed + console.error("Network error:", error); }); }); @@ -102,12 +122,11 @@ document.addEventListener("DOMContentLoaded", function () { }) .then((response) => { if (response.ok) { - // Handle success, e.g., close the modal, refresh the page, etc. + closeEditCatModal(); location.reload(); - // You may want to add code here to refresh the cat card with updated data + } else { - // Handle errors console.error("Error editing cat:", response.statusText); } }) @@ -115,15 +134,57 @@ document.addEventListener("DOMContentLoaded", function () { console.error("Error editing cat:", error); }); }); + const searchForm = document.getElementById("search-form"); + let debounceTimeout; + + searchForm.addEventListener("input", function (event) { + clearTimeout(debounceTimeout); + + debounceTimeout = setTimeout(() => { + const search = searchForm.querySelector("[name='search']").value; + const gender = searchForm.querySelector("[name='gender']").value; + const spayed = searchForm.querySelector("[name='spayed']").value; + const isDesc = searchForm.querySelector("[name='isDesc']").checked; + const pageNo = searchForm.querySelector("[name='pageNo']").value; + const pageSize = searchForm.querySelector("[name='pageSize']").value; + + const checkboxes = searchForm.querySelectorAll("[name='order[]']"); + const selectedOptions = Array.from(checkboxes) + .filter(checkbox => checkbox.checked) + .map(checkbox => checkbox.value); + + const order = selectedOptions.join(","); + + const queryString = `/cat?search=${search}&gender=${gender}&spayed=${spayed}&isDesc=${isDesc}&order=${order}&pageNo=${pageNo}&pageSize=${pageSize}`; + + window.location.href = queryString; + }, 1000); // Set the debounce delay in milliseconds + }); + + + setFormFieldValue(searchForm, 'search', getQueryParam('search')); + setFormFieldValue(searchForm, 'gender', getQueryParam('gender')); + setFormFieldValue(searchForm, 'spayed', getQueryParam('spayed')); + setFormFieldValue(searchForm, 'isDesc', getQueryParam('isDesc')); + setFormFieldValue(searchForm, 'pageNo', getQueryParam('pageNo')); + setFormFieldValue(searchForm, 'pageSize', getQueryParam('pageSize')); + + const orderValues = getQueryParam('order'); + if (orderValues) { + const orderCheckboxes = searchForm.querySelectorAll("[name='order[]']"); + orderCheckboxes.forEach((checkbox) => { + if (orderValues.split(',').includes(checkbox.value)) { + checkbox.checked = true; + } + }); + } }); function editCat(catId) { - // Find the cat card element using the catId const catCard = document.getElementById(`cat-card-${catId}`); if (catCard) { populateEditForm(catCard, catId); - // Open the edit modal openEditCatModal(); } else { console.error("Cat card not found for catId:", catId); @@ -142,7 +203,6 @@ function findTextContent(element, searchText) { return ""; } function populateEditForm(catCard, catId) { - // Get all the data from the cat card const catName = catCard.querySelector(".cat-title").textContent.trim(); const catGender = catCard.querySelector(".cat-gender").textContent.trim(); const catSpayed = catCard.querySelector(".cat-spayed").textContent.trim(); @@ -153,7 +213,6 @@ function populateEditForm(catCard, catId) { // const catImage = catCard.querySelector(".cat-image").src; // const catSound = catCard.querySelector(".cat-audio source").src; - // Populate the edit form with cat data document.getElementById("edit-name").value = catName; document.getElementById("edit-gender").value = catGender; document.getElementById("edit-color").value = catColor; @@ -175,9 +234,10 @@ function closeEditCatModal() { editCatModal.style.display = "none"; } -// Close the modal if the user clicks outside of it + window.onclick = function (event) { if (event.target === editCatModal) { closeEditCatModal(); } } + diff --git a/public/view/cats.php b/public/view/cats.php index af45f9985078056293b7a4ae487c5e2668d7b45d..677e749f5ac774262f623b31b41a93dc7075ae29 100644 --- a/public/view/cats.php +++ b/public/view/cats.php @@ -9,12 +9,64 @@ <body> <?php require_once(PROJECT_ROOT_PATH . '/public/components/Navbar.php'); ?> - <h1>List of Cats</h1> + <div class="search-container"> + <form method="get" id="search-form" class="search-form"> + <div class="search-bar"> + <input type="text" name="search" class="search-input" placeholder="Search..."> + </div> + + <div class="search-options"> + <div class="filter-bar"> + <select name="gender" class="filter-select"> + <option value="">Filter by Gender</option> + <option value="Male">Male</option> + <option value="Female">Female</option> + </select> + + <select name="spayed" class="filter-select"> + <option value="">Filter by Spayed</option> + <option value="Yes">Yes</option> + <option value="No">No</option> + </select> + </div> + + <div class="sort-bar"> + <label for="order" class="sort-label">Sort by:</label> + <div class="sort-options"> + <div class="sort-option"> + <input type="checkbox" name="order[]" value="name" id="name-checkbox" class="sort-checkbox"> + <label for="name-checkbox" class="sort-option-label">Name</label> + </div> + <div class="sort-option"> + <input type="checkbox" name="order[]" value="location" id="location-checkbox" + class="sort-checkbox"> + <label for="location-checkbox" class="sort-option-label">Location</label> + </div> + <div class="sort-option"> + <input type="checkbox" name="order[]" value="color" id="color-checkbox" + class="sort-checkbox"> + <label for="color-checkbox" class="sort-option-label">Color</label> + </div> + <div class="sort-option"> + <input type="checkbox" name="order[]" value="cat_added" id="cat-added-checkbox" + class="sort-checkbox"> + <label for="cat-added-checkbox" class="sort-option-label">Cat Added</label> + </div> + </div> + <label for="isDesc" class="sort-label">Descending:</label> + <input type="checkbox" name="isDesc" value="true" class="sort-checkbox"> + </div> + </div> + <input type="hidden" name="pageNo" value="<?= isset($_GET['pageNo']) ? intval($_GET['pageNo']) : 1 ?>"> + <input type="hidden" name="pageSize" + value="<?= isset($_GET['pageSize']) ? intval($_GET['pageSize']) : 10 ?>"> + </form> + </div> + <div class="cat-cards-container"> <?php foreach ($responseCats as $cat): ?> <div class="cat-card" id="cat-card-<?= $cat['cat_id'] ?>"> - <a class="delete-button" href="/cat/<?= htmlspecialchars($cat['cat_id']) ?>" - onclick="return confirm('Are you sure you want to delete this cat?')">X</a> + <a class="delete-button" href="/cat/<?= htmlspecialchars($cat['cat_id']) ?>">X</a> <h2 class="cat-title"> <?= htmlspecialchars($cat['name']) ?> </h2> diff --git a/src/bases/BaseRepository.php b/src/bases/BaseRepository.php index 40279397922823fe2a6736aa0658290ea237243a..d5b44aac93cb44e2da4ac19f05c57944ff96f956 100644 --- a/src/bases/BaseRepository.php +++ b/src/bases/BaseRepository.php @@ -73,11 +73,13 @@ abstract class BaseRepository $query .= " WHERE " . implode(" AND ", $where); } + + if (!empty($orderBy)) { - $query .= " ORDER BY " . implode(", ", $orderBy); - if (!empty($isDesc)) { - $query .= " DESC"; - } + $orderByWithDesc = array_map(function ($column) use ($isDesc) { + return $column . ($isDesc && $isDesc != "false" ? " DESC" : ""); + }, $orderBy); + $query .= " ORDER BY " . implode(", ", $orderByWithDesc); } if (!empty($perPage)) { @@ -85,7 +87,7 @@ abstract class BaseRepository $query .= " LIMIT $perPage OFFSET $offset"; } - + echo $query; $stmt = $this->pdo->prepare($query); $stmt->execute(); @@ -119,7 +121,6 @@ abstract class BaseRepository $stmt = $this->pdo->prepare($sql); foreach ($filteredData as $key => $value) { - echo $value; $stmt->bindValue(':' . $key, $value, $paramTypes[$key]); } diff --git a/src/controllers/cat/CatController.php b/src/controllers/cat/CatController.php index e30fc734c066532300bcc899806a9ca2141436f1..bac61a7efc862dfcbd4ec003b7940a3c7644cc5a 100644 --- a/src/controllers/cat/CatController.php +++ b/src/controllers/cat/CatController.php @@ -32,7 +32,7 @@ class CatController extends BaseController $cats = $this->srv->getAll([ "search" => $_GET['search'] ?? null, "gender" => $_GET['gender'] ?? null, - "color" => $_GET['color'] ?? null, + "spayed" => $_GET['spayed'] ?? null, "order" => $_GET['order'] ?? null, "pageNo" => $_GET['pageNo'] ?? null, "pageSize" => $_GET['pageSize'] ?? null, diff --git a/src/services/CatSrv.php b/src/services/CatSrv.php index e29c6d344f44a35ebe816664ad6aded47704503c..d4583ce6cb50b23b34598b1d0a445404a63cb581 100644 --- a/src/services/CatSrv.php +++ b/src/services/CatSrv.php @@ -34,13 +34,13 @@ class CatSrv extends BaseSrv $search = $config['search']; $where = []; if ($search) { - $where[] = "name LIKE '%$search%' OR location LIKE '%$search%'"; + $where[] = "(name LIKE '%$search%' OR location LIKE '%$search%')"; } if ($config['gender']) { $where[] = "gender = '{$config['gender']}'"; } - if ($config['color']) { - $where[] = "color = '{$config['color']}'"; + if ($config['spayed']) { + $where[] = "spayed = '{$config['spayed']}'"; } $order = []; if ($config["order"]) {