diff --git a/src/home/index.php b/src/home/index.php index 3eabce4f15da4e17c1506c07b617f5e6808f6397..b8b0d2681cd933950b2726dbd588be54c81496a3 100644 --- a/src/home/index.php +++ b/src/home/index.php @@ -24,18 +24,18 @@ $selectedCity = $_GET["city"] ?? null; $selectedPriceRange = $_GET["price-range"] ?? null; $selectedSorting = $_GET["sorting"] ?? null; -$gymsFiltered = GymService::getInstance()->getFiltered( - [ - 'page' => $currentPage, - 'cityId' => $selectedCity, - 'sorting' => $selectedSorting, - 'priceRange' => $selectedPriceRange, - 'sortingOption' => $sortingOption, - 'priceRangeOption' => $priceRangeOption, - 'gymCountInPage' => $itemInPage, - 'searching' => $searching - ] -); +// $gymsFiltered = GymService::getInstance()->getFiltered( +// [ +// 'page' => $currentPage, +// 'cityId' => $selectedCity, +// 'sorting' => $selectedSorting, +// 'priceRange' => $selectedPriceRange, +// 'sortingOption' => $sortingOption, +// 'priceRangeOption' => $priceRangeOption, +// 'gymCountInPage' => $itemInPage, +// 'searching' => $searching +// ] +// ); ?> @@ -51,8 +51,20 @@ $gymsFiltered = GymService::getInstance()->getFiltered( <body> <div class="app"> + <script> + const gym_name = <?php echo json_encode($_GET["gym_name"] ?? null) ?>; + const page = <?php echo json_encode($currentPage) ?>; + const selectedCity = <?php echo json_encode($selectedCity) ?>; + const selectedSorting = <?php echo json_encode($selectedSorting) ?>; + const selectedPriceRange = <?php echo json_encode($selectedPriceRange) ?>; + const sortingOption = <?php echo json_encode($sortingOption) ?>; + const priceRangeOption = <?php echo json_encode($priceRangeOption) ?>; + const itemInPage = <?php echo json_encode($itemInPage) ?>; + const searching = <?php echo json_encode($searching) ?>; + console.log(gym_name); + </script> <?php - echo Navbar(); + echo Navbar(); ?> <div class="space"></div> <div class="first-line-button"> @@ -63,32 +75,24 @@ $gymsFiltered = GymService::getInstance()->getFiltered( <?php echo FilterForm($selectedCity, $selectedPriceRange, $selectedSorting); ?> - <div class="form-search"> - <input id="input-search" class="input-search" type="text" name="name" onChange={handleChange} - placeholder="Search a gym" /> - <button class="button-search" id="button-search" onclick="callSearchGym()"> + <form class="form-search"> + <input id="input-search" class="input-search" type="text" name="gym_name" placeholder="Search Gym"> + <button class="button-search" id="button-search"> <img src="/public/icon/vector_search.svg" alt="Search Icon"> </button> - </div> + </form> </div> - <div class="gym-card-container"> - <?php - if (sizeof($gymsFiltered['gyms']) == 0) { - ?> - <?= "No Gym Found" ?> - <?php - } - foreach ($gymsFiltered['gyms'] as $gym) { - echo GymCard($gym); - } - ?> + <div class="gym-card-container" id="gym-card-container"> + <div class="space"></div> + Loading... </div> + <div class="pagination-container" id="pagination-container"> - <div class="pagination-container"> - <?php echo generatePagination($gymsFiltered['itemCount'], $itemInPage, $currentPage, $maxPages); ?> </div> </div> + <script src="/public/javascript/gym/gym_card.js"></script> + <script src="/public/javascript/pagination.js"></script> <script src="/public/javascript/gym/filter.js"></script> <script src="/public/javascript/gym/search.js"></script> </body> diff --git a/src/public/javascript/gym/filter.js b/src/public/javascript/gym/filter.js index ad99c8989226b5cd941df2f2dacd0756ac1618d0..5486e4cf5f4678a8b09624eddf08ae6c3378d149 100644 --- a/src/public/javascript/gym/filter.js +++ b/src/public/javascript/gym/filter.js @@ -2,14 +2,64 @@ const filter = document.getElementById("filter-gym"); const filterButton = document.getElementById("button-filter"); const searchFilter = document.getElementById("button-search-filter"); const cancelFilter = document.getElementById("button-cancel-filter"); -const searchButton = document.getElementById("button-search"); -const inputSearch = document.getElementById("input-search"); -const inputPriceMin = document.getElementById("filter-min-price"); -const inputPriceMax = document.getElementById("filter-max-price"); -const toggleAlphAsc = document.getElementById("filter-alph-asc"); -const toggleAlphDesc = document.getElementById("filter-alph-desc"); -const togglePriceAsc = document.getElementById("filter-price-asc"); -const togglePriceDesc = document.getElementById("filter-price-desc"); +const queryParams = new URLSearchParams(window.location.search); + +function getFilteredGyms(){ + const params = { + page: page, + cityId: selectedCity, + sorting: selectedSorting, + priceRange: selectedPriceRange, + sortingOption: sortingOption, + priceRangeOption: priceRangeOption, + gymCountInPage: itemInPage, + searching: searching + }; + const jsonParams = JSON.stringify(params); + + const xhr = new XMLHttpRequest(); + xhr.onreadystatechange = function() { + if(this.readyState === 4) { + if(this.status === 200) { + FilteredGyms(JSON.parse(this.responseText), page, itemInPage); + } else { + const json = JSON.parse(this.responseText); + alert(json["error"]); + } + } + }; + + xhr.open("PUT", `/api/gym/filter`, true); + xhr.send(jsonParams); +} +// check if the params has a gym_name +if ((queryParams.has("gym_name")==false) || queryParams.get("gym_name") == "") { + // if (queryParams.get("gym_name") == "") { + // queryParams.delete("gym_name"); + // window.location.search = queryParams.toString(); + // } + getFilteredGyms(); +} + +function FilteredGyms(data, page, itemInPage) { + let gyms = data["gyms"]; + let data_length = data["itemCount"]; + let gym_card_container = document.getElementById("gym-card-container"); + let paginationContainer = document.getElementById("pagination-container"); + gym_card_container.innerHTML = ""; + if (gyms.length == 0) { + gym_card_container.innerHTML = "No gyms found"; + } + for (let i = 0; i < gyms.length; i++) { + gym_card_container.innerHTML += GymCard(gyms[i]); + } + // alert(page) + let pg = generatePagination(data_length, itemInPage, page); + paginationContainer.innerHTML = pg; +} + + + filter.style.display = "none"; filter.addEventListener("click", function (event) { // stop propagation but if clicks outside of the filter, it will close the filter @@ -30,10 +80,3 @@ searchFilter.addEventListener("click", function () { cancelFilter.addEventListener("click", function () { filter.style.display = "none"; }); -// change price min and max input from document -// inputPriceMin.addEventListener("change", function () { -// filteredGymData.price_min = inputPriceMin.value; -// }); -// inputPriceMax.addEventListener("change", function () { -// filteredGymData.price_max = inputPriceMax.value; -// }); diff --git a/src/public/javascript/gym/gym_card.js b/src/public/javascript/gym/gym_card.js new file mode 100644 index 0000000000000000000000000000000000000000..bb43578b575a959b4bf01d16715fa97ca00df991 --- /dev/null +++ b/src/public/javascript/gym/gym_card.js @@ -0,0 +1,44 @@ +function truncateText(text, length) +{ + if (text.length <= length) { + return text; + } else { + text = text.substring(0, length-3); + text = text + "..."; + return text; + } +} + +function formatPrice(price) +{ + if (price == 0) { + return "Free"; + } + price = price.toLocaleString('id-ID'); + return 'Rp' + price; +} + +function GymCard(gym){ + let truncated_name = truncateText(gym.name, 16); + let formatted_price = formatPrice(gym.monthly_price); + let gym_card = ` + <a class="gym-card" id="gym-card-${gym.gym_id}" href="./gym?gym_id=${gym.gym_id}"> + <div class="content-gym-card"> + <img class="gym-card-picture" src="../public/image/gym/${gym.picture_id}.png" alt="Gym Image-${gym.picture_id}"> + <div class="gym-card-text"> + <div class="gym-card-name">${truncated_name}</div> + <div class="gym-card-text-bottom"> + <div class="gym-card-text-bottom-left"> + ${gym.average_rating} + <img src="../public/icon/star.svg" alt="Star Icon"> + </div> + <div class="gym-card-text-bottom-right"> + ${formatted_price} + </div> + </div> + </div> + </div> + </a> + `; + return gym_card; +} \ No newline at end of file diff --git a/src/public/javascript/gym/search.js b/src/public/javascript/gym/search.js index 14b32f38c3be74e57a19516658c266c46a1f6036..c0047ceb62bc48d1fb8cd79fbdd324281f1676af 100644 --- a/src/public/javascript/gym/search.js +++ b/src/public/javascript/gym/search.js @@ -1,9 +1,16 @@ -function callSearchGym() { +if (gym_name != null && gym_name != "") { + callSearchGym(gym_name); +} + +function callSearchGym(gym_name) { + // alert(JSON.stringify(gyms)); + // searchGym(gyms, document.getElementById("input-search").value); const xhr = new XMLHttpRequest(); xhr.onreadystatechange = function() { if(this.readyState === 4) { if(this.status === 200) { - searchGym(JSON.parse(this.responseText), document.getElementById("input-search").value); + // searchGym(JSON.parse(this.responseText), document.getElementById("input-search").value); + searchGym(JSON.parse(this.responseText), gym_name); } else { const json = JSON.parse(this.responseText); alert(json["error"]); @@ -15,31 +22,25 @@ function callSearchGym() { xhr.send(); } - function searchGym(allGyms, searchString) { - const searchedGyms = []; - for(let i = 0; i < allGyms.length; i++) { - if(allGyms[i]["name"].toUpperCase().includes(searchString.toUpperCase())) { - searchedGyms.push(allGyms[i]); - } - } + const paginationContainer = document.getElementById("pagination-container"); + const searchedGyms = allGyms.filter((gym) => { + return gym["name"].toUpperCase().includes(searchString.toUpperCase()); + }); + data_length = searchedGyms.length; + let gymCardContainer = document.getElementById("gym-card-container"); + gymCardContainer.innerHTML = ""; + if(searchedGyms.length == 0) { + gymCardContainer.innerHTML = "No gyms found"; + } else { + // Slice the array to display + let startIndex = (page - 1) * itemInPage; + let slicedGyms = searchedGyms.slice(startIndex, startIndex + itemInPage); - const xhr = new XMLHttpRequest(); - - xhr.onreadystatechange = function() { - if(this.readyState === 4) { - if(this.status === 200) { - - window.location.reload(true); - } else { - const json = JSON.parse(this.responseText); - alert(json["error"]); - } + for(let i = 0; i < slicedGyms.length; i++) { + gymCardContainer.innerHTML += GymCard(slicedGyms[i]); } - }; - - xhr.open("POST", `/home/`, true); - xhr.setRequestHeader('Content-Type', 'application/json'); - - xhr.send(JSON.stringify(searchedGyms)); -} \ No newline at end of file + let pg = generatePagination(data_length, itemInPage, page); + paginationContainer.innerHTML = pg; + } +} diff --git a/src/public/javascript/pagination.js b/src/public/javascript/pagination.js new file mode 100644 index 0000000000000000000000000000000000000000..5364ec565f5d8d4ea118d0cd17240b35cd032bb8 --- /dev/null +++ b/src/public/javascript/pagination.js @@ -0,0 +1,45 @@ +function generatePagination(totalItems, itemsPerPage, currentPage, maxPages = 6) { + const totalPages = Math.ceil(totalItems / itemsPerPage); + let pagination = '<div class="pagination">'; + const queryParams = new URLSearchParams(window.location.search); + queryParams.delete('page'); + + const queryString = queryParams.toString() ? `&${queryParams.toString()}` : ''; + + // Previous page + if (currentPage > 1) { + pagination += `<a href="?page=${currentPage - 1}${queryString}">«</a>`; + } + + // Individual pages + if (totalPages > maxPages) { + let start = Math.max(1, currentPage - Math.floor(maxPages / 2)); + let end = Math.min(totalPages, start + maxPages - 1); + start = Math.max(1, end - maxPages + 1); + + if (start > 1) { + pagination += '<span>...</span>'; + } + + for (let i = start; i <= end; i++) { + pagination += `<a href="?page=${i}${queryString}" ${i == currentPage ? 'class="active"' : ''}>${i}</a>`; + } + + if (end < totalPages) { + pagination += '<span>...</span>'; + } + } else { + for (let i = 1; i <= totalPages; i++) { + pagination += `<a href="?page=${i}${queryString}" ${i === currentPage ? 'class="active"' : ''}>${i}</a>`; + } + } + + // Next page + if (currentPage < totalPages) { + pagination += `<a href="?page=${currentPage + 1}${queryString}">»</a>`; + } + + pagination += '</div>'; + + return pagination; +}