diff --git a/public/components/Navbar.php b/public/components/Navbar.php index 3e3f0aad05f8e1f501b8fee32d156e3bee76796f..53d7b0a20a6863c1db4da2a7f21639ef10ffca73 100644 --- a/public/components/Navbar.php +++ b/public/components/Navbar.php @@ -1,19 +1,20 @@ <nav> <ul> <li><a href="/">Home</a></li> - <li><a href="cat">Cats</a></li> - <li><a href="sighting">Sightings</a></li> + <li><a href="/cat">Cats</a></li> + <li><a href="/sighting">Sightings</a></li> <?php $loggedIn = isset($_SESSION['user_id']); $isAdmin = isset($_SESSION['isAdmin']) && $_SESSION['isAdmin']; if ($isAdmin) { - echo '<li><a href="user">Manage Users</a></li>'; + echo '<li><a href="/user">Manage Users</a></li>'; } if ($loggedIn) { - echo '<li><a href="logout">Logout</a></li>'; + echo '<li><a href="/logout">Logout</a></li>'; + echo '<li class="user-info">Welcome, ' . $_SESSION['username'] . '<br> Role: ' . ($isAdmin ? 'Admin' : 'User') . '</li>'; } else { - echo '<li><a href="register">Register</a></li>'; - echo '<li><a href="login">Login</a></li>'; + echo '<li><a href="/register">Register</a></li>'; + echo '<li><a href="/login">Login</a></li>'; } ?> </ul> diff --git a/public/css/styles.css b/public/css/styles.css index ef1c8b26740ec47c4f8000c6c2a1213e44902a6a..7c76807e47b4a7cdda68de599dc7f829048163e1 100644 --- a/public/css/styles.css +++ b/public/css/styles.css @@ -5,16 +5,6 @@ nav { padding: 10px; } -nav ul { - list-style-type: none; - padding: 0; -} - -nav ul li { - display: inline; - margin-right: 10px; -} - nav ul li a { text-decoration: none; color: #fff; @@ -42,60 +32,13 @@ nav ul li a:hover { } - -.cat-audio { - width: 100%; -} - -.cat-title, .user-card { - font-size: 24px; - margin: 8px 0; -} - - -.cat-details, .user-card { - font-size: 16px; - margin: 8px 0; -} - -.cat-title { - font-size: 24px; - margin: 8px 0; - color: #333; -} - - -.cat-description { - font-size: 14px; - margin: 8px 0; - color: #555; -} - -.cat-location { - font-size: 14px; - margin: 8px 0; - color: #555; -} - -.cat-spayed { - font-size: 14px; - margin: 8px 0; - color: #555; -} - -.cat-added { - font-size: 14px; - margin: 8px 0; - color: #555; -} - - .cat-card, .sighting-card, .user-card { position: relative; border: 1px solid #ccc; padding: 5px; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); border-radius: 5px; + cursor: pointer; } .delete-button { @@ -484,6 +427,7 @@ button[type="submit"] { color: #fff; text-align: center; padding: 20px 0; + } @@ -560,9 +504,14 @@ button[type="submit"] { .cat-image-container { - margin-bottom: 10px; + margin-bottom: 10px; + display: flex; + flex-direction: column; /* Stack elements vertically */ + align-items: center; /* Center content horizontally */ + text-align: center; /* Center text within the container */ } + .cat-image { width: 350px; height: 350px; @@ -571,24 +520,36 @@ button[type="submit"] { } .cat-details { + overflow: hidden; + white-space: normal; + word-wrap: break-word; text-align: left; flex-grow: 1; width: 80%; } .cat-title { + overflow: hidden; + white-space: normal; + word-wrap: break-word; font-size: 24px; margin: 10px 0; color: #333; } .cat-description { + overflow: hidden; + white-space: normal; + word-wrap: break-word; font-size: 16px; color: #555; margin-bottom: 20px; } .cat-metadata { + overflow: hidden; + white-space: normal; + word-wrap: break-word; display: flex; flex-direction: column; align-items: flex-start; @@ -596,10 +557,16 @@ button[type="submit"] { } .cat-metadata-item { + overflow: hidden; + white-space: normal; + word-wrap: break-word; margin-bottom: 5px; } .cat-metadata-item strong { + overflow: hidden; + white-space: normal; + word-wrap: break-word; font-weight: bold; margin-right: 5px; } @@ -636,3 +603,27 @@ button[type="submit"] { .edit-button:hover { background-color: #0056b3; } + +.cat-banner { + display: flex; + align-items: center; + justify-content: center; + flex-direction: column; + background-color: #f0f0f0; + padding: 20px; +} + +nav ul { + list-style: none; + padding: 0; + display: flex; + justify-content: flex-end; /* Align items to the right */ +} + +nav li { + margin-left: 10px; /* Add some spacing between list items */ +} + +.user-info { + margin-left: auto; /* Push user info to the right */ +} diff --git a/public/js/cats.js b/public/js/cats.js index cfdec714555816f5342f296e998f9a87bfa388da..cfe580b51cb0fff7342d1d33fb7bdd20e2df6088 100644 --- a/public/js/cats.js +++ b/public/js/cats.js @@ -15,35 +15,74 @@ window.onclick = function (event) { closeAddCatModal(); } } +function redirectToCatPage(catId) { + // Construct the URL with the cat_id + const catUrl = `/cat/${catId}`; + // Redirect to the cat page + window.location.href = catUrl; +} + + +function editCatForm(event) { + event.preventDefault(); + const catId = document.getElementById("edit-cat-id").value; -const addCatForm = document.getElementById("add-cat-form"); -if (addCatForm) { - addCatForm.addEventListener("submit", function (event) { - event.preventDefault(); + const formData = new FormData(); + formData.append("name", document.getElementById("edit-name").value); + formData.append("description", document.getElementById("edit-description").value); + formData.append("location", document.getElementById("edit-location").value); + formData.append("gender", document.getElementById("edit-gender").value); + formData.append("color", document.getElementById("edit-color").value); + formData.append("spayed", document.getElementById("edit-spayed").value); + formData.append("image_file", document.getElementById("edit-image_file").files[0]); + formData.append("sound_file", document.getElementById("edit-sound_file").files[0]); - const formData = new FormData(addCatForm); + // Send a POST request to /cats/{cat_id} + fetch(`/cat/${catId}`, { + method: "POST", + body: formData, + }) + .then((response) => { + if (response.ok) { + closeEditCatModal(); + location.reload(); - fetch("/cat", { - method: "POST", - body: formData, + } else { + console.error("Error editing cat:", response.statusText); + } }) - .then((response) => { - if (response.ok) { - - console.log("Cat added successfully"); - closeAddCatModal(); - window.location.reload(); - } else { - console.error("Failed to add cat"); - } - }) - .catch((error) => { - console.error("Error:", error); - }); - }); + .catch((error) => { + console.error("Error editing cat:", error); + }); +} + + +function addCatSubmit(event) { + event.preventDefault(); + const addCatForm = document.getElementById("add-cat-form"); + + const formData = new FormData(addCatForm); + + fetch("/cat", { + method: "POST", + body: formData, + }) + .then((response) => { + if (response.ok) { + + console.log("Cat added successfully"); + closeAddCatModal(); + window.location.reload(); + } else { + console.error("Failed to add cat"); + } + }) + .catch((error) => { + console.error("Error:", error); + }); } function getQueryParam(name) { @@ -69,9 +108,17 @@ function setFormFieldValue(searchForm, fieldName, value) { // JavaScript to handle delete button click document.addEventListener("DOMContentLoaded", function () { const deleteButtons = document.querySelectorAll(".delete-button"); + const editButton = document.querySelectorAll(".edit-button"); + + editButton.forEach(function (button) { + button.addEventListener("click", function (event) { + event.stopPropagation(); + }) + }); deleteButtons.forEach(function (button) { button.addEventListener("click", function (event) { + event.stopPropagation(); event.preventDefault(); let conf = confirm('Are you sure you want to delete this cat?'); if (!conf) { @@ -102,43 +149,6 @@ document.addEventListener("DOMContentLoaded", function () { }); }); - const editCatForm = document.getElementById("edit-cat-form"); - if (editCatForm) { - editCatForm.addEventListener("submit", function (event) { - event.preventDefault(); - - const catId = document.getElementById("edit-cat-id").value; - - const formData = new FormData(); - formData.append("name", document.getElementById("edit-name").value); - formData.append("description", document.getElementById("edit-description").value); - formData.append("location", document.getElementById("edit-location").value); - formData.append("gender", document.getElementById("edit-gender").value); - formData.append("color", document.getElementById("edit-color").value); - formData.append("spayed", document.getElementById("edit-spayed").value); - formData.append("image_file", document.getElementById("edit-image_file").files[0]); - formData.append("sound_file", document.getElementById("edit-sound_file").files[0]); - - // Send a POST request to /cats/{cat_id} - fetch(`/cat/${catId}`, { - method: "POST", - body: formData, - }) - .then((response) => { - if (response.ok) { - - closeEditCatModal(); - location.reload(); - - } else { - console.error("Error editing cat:", response.statusText); - } - }) - .catch((error) => { - console.error("Error editing cat:", error); - }); - }); - } const searchForm = document.getElementById("search-form"); let debounceTimeout; diff --git a/public/js/login.js b/public/js/login.js index b672c619d7f2e36dce15852e69f16b3d59aa53db..a494fd01f8826ee3400c521b550ffd2bb537ba99 100644 --- a/public/js/login.js +++ b/public/js/login.js @@ -1,8 +1,4 @@ -function isValidEmail(email) { - // Basic email validation using a regular expression - const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; - return emailRegex.test(email); -} + function login(e) { e.preventDefault(); @@ -11,31 +7,6 @@ function login(e) { data.append("email", document.getElementById("email").value); data.append("password", document.getElementById("password").value); - const emailError = document.getElementById("emailError"); - const passwordError = document.getElementById("passwordError"); - - let isError = false; - - if (!isValidEmail(document.getElementById("email").value)) { - - emailError.textContent = "Invalid email address"; - emailInput.focus(); - isError = true; - } else { - emailError.textContent = ""; - } - - if (document.getElementById("password").value === "") { - passwordError.textContent = "Password cannot be empty" - passwordError.focus(); - isError = true; - } else { - passwordError.textContent = ""; - } - - if (isError) { - return; - } xhr.onreadystatechange = function () { if (xhr.readyState === 4) { diff --git a/public/js/sighting.js b/public/js/sighting.js index 35cbd682c590d95daaf02f5e10b8262815b6caf0..c6a877e0783d60f6c48b518f618920f36795bd65 100644 --- a/public/js/sighting.js +++ b/public/js/sighting.js @@ -17,40 +17,36 @@ function closeEditSightingModal() { editSightingModal.style.display = "none"; } - - -document.addEventListener("DOMContentLoaded", function () { - +function addForm(e) { + e.preventDefault(); const addSightingForm = document.getElementById("add-sighting-form"); - if (addSightingForm) { - addSightingForm.addEventListener("submit", function (e) { - e.preventDefault(); - const formData = new FormData(addSightingForm); - let conf = confirm("Are you sure you want to add this sighting?"); - if (!conf) { - return; + const formData = new FormData(addSightingForm); + let conf = confirm("Are you sure you want to add this sighting?"); + if (!conf) { + return; + } + fetch("/sighting", { + method: "POST", + body: formData, + }) + .then((response) => { + if (response.ok) { + console.log(addSightingForm); + console.log("Sighting added"); + closeAddSightingModal(); + window.location.reload(); + } else { + console.log("failed"); } - fetch("/sighting", { - method: "POST", - body: formData, - }) - .then((response) => { - if (response.ok) { - console.log(addSightingForm); - console.log("Sighting added"); - closeAddSightingModal(); - window.location.reload(); - } else { - console.log("failed"); - } - }) - .catch((error) => { - console.error(error); - }) }) + .catch((error) => { + console.error(error); + }) +} + - } +document.addEventListener("DOMContentLoaded", function () { const deleteButton = document.querySelectorAll(".delete-button"); deleteButton.forEach(function (button) { button.addEventListener("click", function (event) { @@ -79,44 +75,8 @@ document.addEventListener("DOMContentLoaded", function () { }) }) }) - const editSightingForm = document.getElementById("edit-sighting-form"); - if (editSightingForm) { - editSightingForm.addEventListener("submit", function (event) { - event.preventDefault(); - const sightingId = document.getElementById("edit-sighting-id").value; - const formData = new FormData(); - formData.append("cat_id", document.getElementById("edit-cat-name-select").value); - formData.append("sighting_location", document.getElementById("edit-sighting-location").value); - formData.append("date", document.getElementById("edit-date").value); - formData.append("time", document.getElementById("edit-time").value); - formData.append("sighting_description", document.getElementById("edit-sighting-description").value); - formData.append("image_url", document.getElementById("edit-image_url").files[0]); - - let conf = confirm("Are you sure you want to edit this sighting?"); - if (!conf) { - return; - } - fetch(`/sighting/${sightingId}`, { - method: "POST", - body: formData, - }) - .then((response) => { - if (response.ok) { - closeEditSightingModal(); - location.reload(); - } else { - console.error("error editing sighting: ", response) - } - }) - .catch((error) => { - console.error("error editing sighting: ", error); - }); - }); - - - } const searchForm = document.getElementById("search-form"); let debounceTimeOut; @@ -158,6 +118,38 @@ document.addEventListener("DOMContentLoaded", function () { } }) +function editForm(event) { + event.preventDefault(); + const sightingId = document.getElementById("edit-sighting-id").value; + const formData = new FormData(); + formData.append("cat_id", document.getElementById("edit-cat-name-select").value); + formData.append("sighting_location", document.getElementById("edit-sighting-location").value); + formData.append("date", document.getElementById("edit-date").value); + formData.append("time", document.getElementById("edit-time").value); + formData.append("sighting_description", document.getElementById("edit-sighting-description").value); + formData.append("image_url", document.getElementById("edit-image_url").files[0]); + + let conf = confirm("Are you sure you want to edit this sighting?"); + if (!conf) { + return; + } + fetch(`/sighting/${sightingId}`, { + method: "POST", + body: formData, + }) + .then((response) => { + if (response.ok) { + closeEditSightingModal(); + location.reload(); + } else { + console.error("error editing sighting: ", response) + } + }) + .catch((error) => { + console.error("error editing sighting: ", error); + }); +}; + function editSighting(sightingId) { const sightingCard = document.getElementById(`sighting-card-${sightingId}`); diff --git a/public/js/users.js b/public/js/users.js index c0933b002695e10b95fe67a568ab74e8f144f2ec..cf179e5da1aad4b8976e6431c0a9b1462922cc6e 100644 --- a/public/js/users.js +++ b/public/js/users.js @@ -14,10 +14,9 @@ window.onclick = function (event) { } } -const editUserForm = document.getElementById("edit-user-form"); -editUserForm.addEventListener("submit", function (event) { +function editForm(event) { event.preventDefault(); - + const editUserForm = document.getElementById("edit-user-form"); const userId = document.getElementById("edit-user-id").value; const formData = new FormData(); @@ -42,7 +41,7 @@ editUserForm.addEventListener("submit", function (event) { .catch((error) => { console.error("Error editing user:", error); }); -}); +}; // JavaScript to handle delete button click document.addEventListener("DOMContentLoaded", function () { diff --git a/public/view/cat_specific.php b/public/view/cat_specific.php new file mode 100644 index 0000000000000000000000000000000000000000..4a0135e342ce6b000efd58ce045de2a7d109779e --- /dev/null +++ b/public/view/cat_specific.php @@ -0,0 +1,176 @@ +<!DOCTYPE html> +<html> + +<head> + <meta charset="UTF-8"> + <title>Cat Sightings</title> + <meta http-equiv="X-UA-Compatible" content="IE=edge"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <link rel="stylesheet" type="text/css" href="../public/css/styles.css"> +</head> + +<body> + <?php require_once(PROJECT_ROOT_PATH . '/public/components/Navbar.php'); ?> + <div class="cat-banner"> + <div class="cat-image-container"> + <h2 class="cat-title"> + Sightings for + <?= htmlspecialchars($cat['name']) ?> + </h2> + <img class="cat-image" onerror="this.src='../public/images/placeholder.png'" + src="../public/<?= htmlspecialchars($cat['image_path']) ?>" alt="cat image"> + </div> + </div> + <div class="cat-cards-container"> + <?php foreach ($responseSightings as $sighting): ?> + <div class="cat-card" id="sighting-card-<?= $sighting['sighting_id'] ?>"> + <?php if ((isset($_SESSION['user_id']) && $_SESSION['user_id'] == $sighting['user_id']) || ((isset($_SESSION['isAdmin']) && $_SESSION['isAdmin'] == 1))) { + echo ("<a class=\"delete-button\" href='/sighting/" . $sighting['sighting_id'] . "'>X</a>"); + } ?> + <div class="cat-image-container"> + <img class="cat-image" onerror="this.src='../public/images/placeholder.png'" + src="../public/<?= htmlspecialchars($sighting['image_url']) ?>" alt="sighting image"> + </div> + <div class="cat-details"> + <div class="cat-info"> + <h2 class="cat-title"> + <?= htmlspecialchars($cat['name']) ?> + </h2> + <p class="sighting-description"> + <?= htmlspecialchars($sighting['sighting_description']) ?> + </p> + </div> + <div class="cat-metadata"> + <div class="cat-metadata-item"> + <strong>Sighted by:</strong> + <span class="sighting-username"> + <?= htmlspecialchars($sighting['username']) ?> + </span> + </div> + <div class="cat-metadata-item"> + <strong>Location:</strong> + <span class="sighting-location"> + <?= htmlspecialchars($sighting['sighting_location']) ?> + </span> + </div> + <div class="cat-metadata-item"> + <strong>Date:</strong> + <span class="sighting-date"> + <?= htmlspecialchars($sighting['date']) ?> + </span> + </div> + <div class="cat-metadata-item"> + <strong>Time:</strong> + <span class="sighting-time"> + <?= htmlspecialchars($sighting['time']) ?> + </span> + </div> + <div class="sighting-cat-id" style="display: none;"> + <?= htmlspecialchars($sighting['cat_id']) ?> + </div> + + </div> + </div> + <?php if ((isset($_SESSION['user_id']) && $_SESSION['user_id'] === $sighting['user_id']) || ((isset($_SESSION['isAdmin']) && $_SESSION['isAdmin'] == 1))): ?> + <button class="edit-button" onclick="editSighting(<?= $sighting['sighting_id'] ?>)">Edit</button> + <?php endif; ?> + </div> + <?php endforeach; ?> + </div> + + <?php require_once(PROJECT_ROOT_PATH . '/public/components/Pagination.php'); ?> + <?php if (isset($_SESSION['user_id'])): ?> + <div> + <div id="edit-sighting-modal" class="modal"> + <div class="modal-content"> + <span class="close" onclick="closeEditSightingModal()">×</span> + <h2>Edit Sighting</h2> + <form id="edit-sighting-form" enctype="multipart/form-data" onsubmit="editForm(event)"> + <input type="hidden" id="edit-sighting-id" name="sighting_id"> + <div class="form-group"> + <label for="edit-cat-name-select">Cat name:</label> + <select id="edit-cat-name-select" name="cat_id" class="form-control"> + <?php { + echo ('<option value="' . $cat['cat_id'] . '">' . $cat['name'] . '</option>'); + } ?> + </select> + </div> + <div class="form-group"> + <label for="edit-sighting-location">Location:</label> + <textarea id="edit-sighting-location" name="sighting_location" class="form-control" required + maxlength="150"></textarea> + </div> + <div class="form-group"> + <label for="edit-date">Date:</label> + <input type="date" id="edit-date" name="date" class="form-control" aria-label="date" required> + </div> + <div class="form-group"> + <label for="edit-time">Time:</label> + <input type="time" value="00:00:00" id="edit-time" name="time" class="form-control" + aria-label="time" required> + </div> + <div class="form-group"> + <label for="edit-sighting-description">Description:</label> + <textarea id="edit-sighting-description" name="sighting_description" class="form-control" + aria-label="description" required maxlength="150"></textarea> + </div> + <div class="form-group"> + <label for="edit-image_url">Image File (JPG, JPEG, PNG):</label> + <input type="file" id="edit-image_url" name="image_url" class="file-input" + accept=".jpg, .jpeg, .png" aria-label="image_url"> + </div> + <button type="submit" class="submit-button">Edit Sighting</button> + </form> + </div> + </div> + </div> + <div> + <div id="add-sighting-modal" class="modal"> + <div class="modal-content"> + <span class="close" onclick="closeAddSightingModal()">×</span> + <h2>Add New Sighting</h2> + <form id="add-sighting-form" enctype="multipart/form-data" onsubmit="addForm(event)"> + <input type="hidden" id="edit-sighting-id" name="sighting_id" class="form-control"> + <div class="form-group"> + <label for="cat-name">Cat name:</label> + <select id="cat-name-select" name="cat_id" class="form-control"> + <?php { + echo ('<option value="' . $cat['cat_id'] . '">' . $cat['name'] . '</option>'); + } ?> + </select> + </div> + <div class="form-group"> + <label for="sighting_location">Location:</label> + <textarea id="sighting_location" name="sighting_location" class="form-control" required + maxlength="50"></textarea> + </div> + <div class="form-group"> + <label for="date">Date:</label> + <input type="date" id="date" name="date" class="form-control" required> + </div> + <div class="form-group"> + <label for="time">Time:</label> + <input type="time" value="00:00:00" id="time" name="time" class="form-control" required> + </div> + <div class="form-group"> + <label for="sighting_description">Description:</label> + <textarea id="sighting_description" name="sighting_description" class="form-control" required + maxlength="150"></textarea> + </div> + <div class="form-group"> + <label for="image_url">Image File (JPG, JPEG, PNG):</label> + <input type="file" id="image_url" name="image_url" class="file-input" accept=".jpg, .jpeg, .png" + required> + </div> + <button type="submit" class="submit-button">Add Cat Sighting</button> + </form> + </div> + </div> + <button id="add-sighting-button" class="add-button" onclick="openAddSightingModal()">+</button> + </div> + <?php endif; ?> + <?php require_once(PROJECT_ROOT_PATH . '/public/components/Footer.php'); ?> + <script src="../public/js/sighting.js"></script> +</body> + +</html> \ No newline at end of file diff --git a/public/view/cats.php b/public/view/cats.php index 1f4623ce0fb96f8f7b3b8bfae60c4ebea20ac948..d7a814ac4f50b5006be791eecd5917d122abcbb8 100644 --- a/public/view/cats.php +++ b/public/view/cats.php @@ -75,7 +75,7 @@ </div> <div class="cat-cards-container"> <?php foreach ($responseCats as $cat): ?> - <div class="cat-card" id="cat-card-<?= $cat['cat_id'] ?>"> + <div class="cat-card" id="cat-card-<?= $cat['cat_id'] ?>" onclick="redirectToCatPage(<?= $cat['cat_id'] ?>)"> <?php if (isset($_SESSION['isAdmin']) && $_SESSION['isAdmin']): ?> <a class="delete-button" href="/cat/<?= htmlspecialchars($cat['cat_id']) ?>">X</a> <?php endif; ?> @@ -148,26 +148,28 @@ <div class="modal-content"> <span class="close" onclick="closeEditCatModal()">×</span> <h2>Edit Cat</h2> - <form id="edit-cat-form" enctype="multipart/form-data"> + <form id="edit-cat-form" enctype="multipart/form-data" onsubmit="editCatForm(event)"> <input type="hidden" id="edit-cat-id" name="cat_id" class="form-control"> <div class="form-group"> <label for="name">Name:</label> - <input type="text" id="edit-name" name="name" class="form-control"> + <input type="text" id="edit-name" name="name" class="form-control" required maxlength="50"> </div> <div class="form-group"> <label for="description">Description:</label> - <textarea id="edit-description" name="description" class="form-control"></textarea> + <textarea id="edit-description" name="description" class="form-control" required + maxlength="150"></textarea> </div> <div class="form-group"> <label for="location">Location:</label> - <input type="text" id="edit-location" name="location" class="form-control"> + <input type="text" id="edit-location" name="location" class="form-control" required + maxlength="150"> </div> <div class="form-group"> <label for="gender">Gender:</label> - <select id="edit-gender" name="gender" class="form-control"> + <select id="edit-gender" name="gender" class="form-control" required> <option value="Male">Male</option> <option value="Female">Female</option> </select> @@ -175,12 +177,12 @@ <div class="form-group"> <label for="color">Color:</label> - <input type="text" id="edit-color" name="color" class="form-control"> + <input type="text" id="edit-color" name="color" class="form-control" required> </div> <div class="form-group"> <label for="spayed">Spayed:</label> - <select id="edit-spayed" name="spayed" class="form-control"> + <select id="edit-spayed" name="spayed" class="form-control" required> <option value="Yes">Yes</option> <option value="No">No</option> </select> @@ -212,25 +214,26 @@ <div class="modal-content"> <span class="close" onclick="closeAddCatModal()">×</span> <h2>Add New Cat</h2> - <form id="add-cat-form" enctype="multipart/form-data"> + <form id="add-cat-form" enctype="multipart/form-data" onsubmit="addCatSubmit(event)"> <div class="form-group"> <label for="name">Name:</label> - <input type="text" id="name" name="name" class="form-control"> + <input type="text" id="name" name="name" class="form-control" required maxlength="50"> </div> <div class="form-group"> <label for="description">Description:</label> - <textarea id="description" name="description" class="form-control"></textarea> + <textarea id="description" name="description" class="form-control" required + maxlength="150"></textarea> </div> <div class="form-group"> <label for="location">Location:</label> - <input type="text" id="location" name="location" class="form-control"> + <input type="text" id="location" name="location" class="form-control" required maxlength="150"> </div> <div class="form-group"> <label for="gender">Gender:</label> - <select id="gender" name="gender" class="form-control"> + <select id="gender" name="gender" class="form-control" required> <option value="Male">Male</option> <option value="Female">Female</option> </select> @@ -238,11 +241,11 @@ <div class="form-group"> <label for="color">Color:</label> - <input type="text" id="color" name="color" class="form-control"> + <input type="text" id="color" name="color" class="form-control" required> </div> <div class="form-group"> <label for="spayed">Spayed:</label> - <select id="spayed" name="spayed" class="form-control"> + <select id="spayed" name="spayed" class="form-control" required> <option value="Yes">Yes</option> <option value="No">No</option> </select> @@ -251,14 +254,14 @@ <!-- File Upload for Sound --> <div class="form-group"> <label for="sound_file">Sound File (MP3):</label> - <input type="file" id="sound_file" name="sound_file" class="file-input" accept=".mp3"> + <input type="file" id="sound_file" name="sound_file" class="file-input" accept=".mp3" required> </div> <!-- File Upload for Image --> <div class="form-group"> <label for="image_file">Image File (JPG, JPEG, PNG):</label> <input type="file" id="image_file" name="image_file" class="file-input" - accept=".jpg, .jpeg, .png"> + accept=".jpg, .jpeg, .png" required> </div> <button type="submit" class="submit-button">Add Cat</button> diff --git a/public/view/login.php b/public/view/login.php index 3386ee54e29681c7bf114cf7204fbafa1e46eb2a..734fa5d570296b33d8892f77ee45a65af296eb87 100644 --- a/public/view/login.php +++ b/public/view/login.php @@ -15,14 +15,12 @@ <img src="public/images/logo.jpeg" alt="Your Logo"> </div> <h1 class="login-title">Welcome Back</h1> - <form class="login-form" id="inputForm"> + <form class="login-form" id="inputForm" onsubmit="login(event)"> <label for="email" class="login-label">Email:</label> - <input type="text" id="email" class="login-input" required> - <span id="emailError" class="error-message"></span><br><br> + <input type="email" id="email" class="login-input" required><br><br> <label for="password" class="login-label">Password:</label> <input type="password" id="password" class="login-input" required><br><br> - <span id="passwordError" class="error-message"></span><br><br> - <button type="submit" class="login-button" onclick="login(event)">Login</button> + <button type="submit" class="login-button">Login</button> </form> </div> </body> diff --git a/public/view/sighting.php b/public/view/sighting.php index aefed55542d1a535aa9b7fd1f7019b6fe58429ed..6940b74941eafdcfd760f065771b1e9ebd5a0d5c 100644 --- a/public/view/sighting.php +++ b/public/view/sighting.php @@ -14,7 +14,8 @@ <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..." aria-label="search"> + <input type="text" name="search" class="search-input" placeholder="Search..." aria-label="search" + maxlength="50"> </div> <div class="search-options"> <div class="sort-bar"> @@ -42,7 +43,7 @@ <div class="cat-cards-container"> <?php foreach ($responseSightings as $sighting): ?> <div class="cat-card" id="sighting-card-<?= $sighting['sighting_id'] ?>"> - <?php if (isset($_SESSION['user_id']) && $_SESSION['user_id'] == $sighting['user_id']) { + <?php if ((isset($_SESSION['user_id']) && $_SESSION['user_id'] == $sighting['user_id']) || ((isset($_SESSION['isAdmin']) && $_SESSION['isAdmin'] == 1))) { echo ("<a class=\"delete-button\" href='sighting/" . $sighting['sighting_id'] . "'>X</a>"); } ?> <div class="cat-image-container"> @@ -89,7 +90,7 @@ </div> </div> - <?php if (isset($_SESSION['user_id']) && $_SESSION['user_id'] === $sighting['user_id']): ?> + <?php if ((isset($_SESSION['user_id']) && $_SESSION['user_id'] === $sighting['user_id']) || ((isset($_SESSION['isAdmin']) && $_SESSION['isAdmin'] == 1))): ?> <button class="edit-button" onclick="editSighting(<?= $sighting['sighting_id'] ?>)">Edit</button> <?php endif; ?> </div> @@ -103,7 +104,7 @@ <div class="modal-content"> <span class="close" onclick="closeEditSightingModal()">×</span> <h2>Edit Sighting</h2> - <form id="edit-sighting-form" enctype="multipart/form-data"> + <form id="edit-sighting-form" enctype="multipart/form-data" onsubmit="editForm(event)"> <input type="hidden" id="edit-sighting-id" name="sighting_id"> <div class="form-group"> <label for="edit-cat-name-select">Cat name:</label> @@ -115,21 +116,22 @@ </div> <div class="form-group"> <label for="edit-sighting-location">Location:</label> - <textarea id="edit-sighting-location" name="sighting_location" class="form-control"></textarea> + <textarea id="edit-sighting-location" name="sighting_location" class="form-control" required + maxlength="150"></textarea> </div> <div class="form-group"> <label for="edit-date">Date:</label> - <input type="date" id="edit-date" name="date" class="form-control" aria-label="date"> + <input type="date" id="edit-date" name="date" class="form-control" aria-label="date" required> </div> <div class="form-group"> <label for="edit-time">Time:</label> <input type="time" value="00:00:00" id="edit-time" name="time" class="form-control" - aria-label="time"> + aria-label="time" required> </div> <div class="form-group"> <label for="edit-sighting-description">Description:</label> <textarea id="edit-sighting-description" name="sighting_description" class="form-control" - aria-label="description"></textarea> + aria-label="description" required maxlength="150"></textarea> </div> <div class="form-group"> <label for="edit-image_url">Image File (JPG, JPEG, PNG):</label> @@ -148,7 +150,7 @@ <div class="modal-content"> <span class="close" onclick="closeAddSightingModal()">×</span> <h2>Add New Sighting</h2> - <form id="add-sighting-form" enctype="multipart/form-data"> + <form id="add-sighting-form" enctype="multipart/form-data" onsubmit="addForm(event)"> <input type="hidden" id="edit-sighting-id" name="sighting_id" class="form-control"> <div class="form-group"> <label for="cat-name">Cat name:</label> @@ -160,24 +162,26 @@ </div> <div class="form-group"> <label for="sighting_location">Location:</label> - <textarea id="sighting_location" name="sighting_location" class="form-control"></textarea> + <textarea id="sighting_location" name="sighting_location" class="form-control" required + maxlength="150"></textarea> </div> <div class="form-group"> <label for="date">Date:</label> - <input type="date" id="date" name="date" class="form-control"> + <input type="date" id="date" name="date" class="form-control" required> </div> <div class="form-group"> <label for="time">Time:</label> - <input type="time" value="00:00:00" id="time" name="time" class="form-control"> + <input type="time" value="00:00:00" id="time" name="time" class="form-control" required> </div> <div class="form-group"> <label for="sighting_description">Description:</label> - <textarea id="sighting_description" name="sighting_description" class="form-control"></textarea> + <textarea id="sighting_description" name="sighting_description" class="form-control" required + maxlength="150"></textarea> </div> <div class="form-group"> <label for="image_url">Image File (JPG, JPEG, PNG):</label> - <input type="file" id="image_url" name="image_url" class="file-input" - accept=".jpg, .jpeg, .png"> + <input type="file" id="image_url" name="image_url" class="file-input" accept=".jpg, .jpeg, .png" + required> </div> <button type="submit" class="submit-button">Add Cat</button> </form> diff --git a/public/view/users.php b/public/view/users.php index 19c14f93093fdcab8c53dbb678e448bb88880edb..691e456e00873c5e6864eb7139654b8b5dadd4c7 100644 --- a/public/view/users.php +++ b/public/view/users.php @@ -40,11 +40,11 @@ <div class="modal-content"> <span class="close" onclick="closeEditUserModal()">×</span> <h2>Edit User</h2> - <form id="edit-user-form" enctype="multipart/form-data"> + <form id="edit-user-form" enctype="multipart/form-data" onsubmit="editForm(event)"> <input type="hidden" id="edit-user-id" name="user_id" class="form-control"> <div class="form-group"> <label for="nama">Nama:</label> - <input type="text" id="edit-nama" name="nama" class="form-control"> + <input type="text" id="edit-nama" name="nama" class="form-control" required maxlength="50"> </div> <div class="form-group"> @@ -54,7 +54,8 @@ <div class="form-group"> <label for="username">Username:</label> - <input type="text" id="edit-username" name="username" class="form-control"> + <input type="text" id="edit-username" name="username" class="form-control" required + maxlength="50"> </div> <div class="form-group"> diff --git a/src/bases/BaseRepository.php b/src/bases/BaseRepository.php index 18ce80ee0fc41a400fc1c53c4bc7d22276552c64..186e6d8ce8cee181b4e4c486a730caad24781c6b 100644 --- a/src/bases/BaseRepository.php +++ b/src/bases/BaseRepository.php @@ -73,8 +73,6 @@ abstract class BaseRepository $query .= " WHERE " . implode(" AND ", $where); } - - if (!empty($orderBy)) { $orderByWithDesc = array_map(function ($column) use ($isDesc) { return $column . ($isDesc && $isDesc != "false" ? " DESC" : ""); diff --git a/src/controllers/cat/CatController.php b/src/controllers/cat/CatController.php index 0e5db81d62ca7a187f7ed8fcda194bbf394c7a9c..4d3207ad4874838e835e6e1bf567aef34e91a1ed 100644 --- a/src/controllers/cat/CatController.php +++ b/src/controllers/cat/CatController.php @@ -54,7 +54,7 @@ class CatController extends BaseController } $cat_id = $urlParams[0]; - $cat = $this->srv->getCatById($cat_id); + $cat = $this->srv->getCatById($cat_id)->toResponse(); $sightings = SightingSrv::getInstance()->getByCatId( [ @@ -64,10 +64,14 @@ class CatController extends BaseController ] ); + $responseSightings = array_map(function ($sighting) { + return $sighting->toResponse(); + }, $sightings["result"]); + $_count = $sightings["count"]; - // TODO GET CATS WITH ALL SIGHTINGS DO JOIN. - return (new BaseResponse(false, null, "NOT IMPLEMENTED", 404))->toJSON(); + + require_once PROJECT_ROOT_PATH . "/public/view/cat_specific.php"; } } public function post($urlParams) diff --git a/src/services/SightingSrv.php b/src/services/SightingSrv.php index 18ba96429dd2748d69265b92662612f0cb18a9d6..e385ba32edd55337f1d916f2c58eee366d039195 100644 --- a/src/services/SightingSrv.php +++ b/src/services/SightingSrv.php @@ -27,12 +27,12 @@ class SightingSrv extends BaseSrv $where = []; $catId = $config["catId"]; if ($catId) { - $where[] = "(cat_id = '$catId')"; + $where[] = "(s.cat_id = '$catId')"; } $order = ["date", "time"]; - $res = $this->repository->select("*", $where, $order, $config["pageNo"], $config['pageSize'], true); + $res = $this->repository->join("*", $where, $order, $config["pageNo"], $config['pageSize'], true); $sightings = [];