Skip to content

Commit

Permalink
Merge pull request #189 from Divyesh000/paginationUI
Browse files Browse the repository at this point in the history
Improve pagination UI on shop page
  • Loading branch information
creme332 authored May 18, 2024
2 parents 651f2e7 + 1fdf810 commit fa3a401
Show file tree
Hide file tree
Showing 3 changed files with 193 additions and 43 deletions.
50 changes: 49 additions & 1 deletion public/styles/views/Shop.css
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
box-shadow: rgba(0, 0, 0, 0.05) 0px 6px 24px 0px, rgba(0, 0, 0, 0.08) 0px 0px 0px 1px;
}

#item-grid > a:focus{
#item-grid > a:focus {
background-color: transparent;
}

Expand Down Expand Up @@ -61,4 +61,52 @@ article header {
#item-grid {
grid-template-columns: repeat(1, 1fr);
}
}

.pagination {
display: flex;
list-style: none;
border-radius: 0.25rem;
gap: 0.45rem;
margin-top: 2cm;
}


.page-item {
--bs-padding-x: 0.5rem;
--bs-padding-y: 0.25rem;
}

.page-link {
position: relative;
display: block;
padding: var(--bs-padding-y) var(--bs-padding-x);
text-decoration: none;
transition: color .25s ease-in-out, background-color .25s ease-in-out;
outline: 1px solid #dee2e6;
}

.page-link:hover {
z-index: 2;
background-color: var(--contrast-hover);
color: var(--contrast-inverse);
}

.page-link:focus {
z-index: 3;
outline: 0;
box-shadow: 0 0 0.25rem rgba(0, 0, 0, 0.25);
}

.page-item.active .page-link {
z-index: 3;
background-color: var(--contrast);
color: var(--contrast-inverse);
}

.page-item.disabled .page-link {
color: var(--form-element-disabled-opacity);
outline-color: var(--form-element-disabled-border-color);
pointer-events: none;
background-color: var(--form-element-disabled-background-color);
}
63 changes: 47 additions & 16 deletions src/controllers/Shop.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ class Shop
use Controller;

private array $data;
private static int $MAX_PRODUCTS_PER_PAGE = 4;

/**
* Check if a product matches the category filter (if any)
Expand Down Expand Up @@ -71,7 +72,7 @@ private function sort_product(Product $a, Product $b): int
return 0;
}

// sort by date
// sort by descending date
if ($_GET['sort'] === 'newest') {
return ($a->getCreatedDate() > $b->getCreatedDate()) ? -1 : 1;
}
Expand Down Expand Up @@ -99,6 +100,46 @@ private function sort_product(Product $a, Product $b): int
return 0; // no sorting if invalid sorting option
}

/**
* @return Product[] Array of products which match filters (excluding pagination) and sorting applied by user
*/
public function getMatchingProducts(): array
{
// Fetch all products from the database
$all_products = Product::getAll();

// Apply filtering based on search keyword and category (existing functionality)
$filtered_products = array_filter($all_products, array($this, "match_keyword"));
$filtered_products = array_filter($filtered_products, array($this, "match_category"));

// Sort the filtered products (existing functionality)
usort($filtered_products, array($this, "sort_product"));

return $filtered_products;
}

/**
* @return int Page number on shop page. Defaults to 1.
*/
public function getPageNumber(): int
{
return (int)($_GET['page'] ?? 1);
}

/**
* @param $products
* @return array Products which should be displayed on current page
*/
public function applyPagination($products): array
{
// Slice the products based on pagination
return array_slice(
$products,
($this->getPageNumber() - 1) * Shop::$MAX_PRODUCTS_PER_PAGE,
Shop::$MAX_PRODUCTS_PER_PAGE
);
}

public function index(): void
{
// check if URL follows format /shop/products/<number>
Expand All @@ -115,30 +156,20 @@ public function index(): void
return;
}

// Retrieve the page number from the URL query parameters
$page = $_GET['page'] ?? 1;
$perPage = (int) $page * 4; // Number of products per page

// Fetch all products from the database
$all_products = Product::getAll();

// Apply filtering based on search keyword and category (existing functionality)
$filtered_products = array_filter($all_products, array($this, "match_keyword"));
$filtered_products = array_filter($filtered_products, array($this, "match_category"));

// Sort the filtered products (existing functionality)
usort($filtered_products, array($this, "sort_product"));
// get all products that match user criteria
$filtered_products = $this->getMatchingProducts();

// Slice the products based on pagination
$paginated_products = array_slice($filtered_products, 0, $perPage);
$paginated_products = $this->applyPagination($filtered_products);

// Initialize view variables (existing functionality)
$this->data['products'] = $paginated_products;
$this->data['search_keyword'] = $_GET['keyword'] ?? "";
$this->data['categories'] = Product::getCategories();
$this->data['sort_option'] = $_GET['sort'] ?? "";
$this->data['selected_categories'] = $_GET['categories'] ?? [];
$this->data['page'] = $page;
$this->data['current_page_number'] = $this->getPageNumber();
$this->data['total_pages'] = (int)ceil(count($filtered_products) / Shop::$MAX_PRODUCTS_PER_PAGE);

// Render the view with pagination information
$this->view(
Expand Down
123 changes: 97 additions & 26 deletions src/views/Shop.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@
* @var string[] $selected_categories Array of selected categories
* @var string $search_keyword keyword used to filter products
* @var string $sort_option Sort By option selected by user
* @var int $page Current page number
* @var int $current_page_number Current page number.
* @var int $total_pages Total number of pages
*/

use Steamy\Model\Product;
Expand All @@ -32,14 +33,76 @@ function displayProduct(Product $product): void
echo <<<EOL
<a data-aos="zoom-in" href="$product_href">
<img src="$product_img_src" alt="$img_alt_text">
<hgroup>
<h5>$name</h5>
<h5>Rs $price</h5>
</hgroup>
<hgroup>
<h5>$name</h5>
<h5>Rs $price</h5>
</hgroup>
</a>
EOL;
}

/**
* Returns a query string that maintains all current query string parameters and page number.
* @param int $page_number
* @return string Query string link for page item
*/
function getPageItemLink(int $page_number): string
{
// create a string with all past query parameters except page and url
unset($_GET['page']);
unset($_GET['url']);

$link = '?' . http_build_query($_GET);

// add page number as query parameter
$link .= '&page=' . $page_number;

return $link;
}

/**
* Prints page item in HTML format.
*
* @param int $current_page_number
* @param int $page_number Page number of page item
* @return void
*/
function displayPageItem(int $current_page_number, int $page_number): void
{
$page_link = getPageItemLink($page_number);
$className = "page-item" . ($page_number === $current_page_number ? " active" : "");

echo <<< EOL
<li class="$className">
<a class="page-link" href="$page_link">$page_number</a>
</li>
EOL;
}

/**
* Prints navigation button in HTML format
* @param int $current_page_number
* @param int $total_pages Total number of pages
* @param bool $is_left True indicates left navigation button.
* @return void
*/
function displayNavigationButton(int $current_page_number, int $total_pages, bool $is_left): void
{
$page_link = getPageItemLink($current_page_number + ($is_left ? -1 : 1));
$link_content = htmlspecialchars($is_left ? "<" : ">");
$className = "page-item";

if (($current_page_number === 1 && $is_left) || ($current_page_number === $total_pages && !$is_left)) {
$className .= " disabled";
}

echo <<< EOL
<li class="$className">
<a class="page-link" href="$page_link">$link_content</a>
</li>
EOL;
}

?>

<form method="get" class="container">
Expand Down Expand Up @@ -71,12 +134,12 @@ function displayProduct(Product $product): void
$sanitized_category = htmlspecialchars($category);

echo <<< EOL
<li>
<label>
<input $checked value="$category" name="categories[]" type="checkbox">
$sanitized_category
</label>
</li>
<li>
<label>
<input $checked value="$category" name="categories[]" type="checkbox">
$sanitized_category
</label>
</li>
EOL;
}
?>
Expand All @@ -96,27 +159,35 @@ function displayProduct(Product $product): void
}
?>
</div>
</main>

<form style="margin-top: 10rem;">
<nav class="container" style="display: flex; justify-content: center">
<ul class="pagination">
<?php
// any previously selected categories should be preserved
foreach ($selected_categories as $category) {
echo <<< EOL
<input value="$category" name="categories[]" type="hidden">
EOL;
// Display previous page button
displayNavigationButton(
$current_page_number,
$total_pages,
true
);

// Display each page item
for ($page_num = 1; $page_num <= $total_pages; $page_num++) {
displayPageItem($current_page_number, $page_num);
}
?>
<!--any previously selected filter should be preserved-->
<input value="<?= htmlspecialchars($sort_option) ?>" name="sort" type="hidden"/>
<input value="<?= htmlspecialchars($search_keyword) ?>" name="keyword" type="hidden"/>

<button type="submit" name="page" value="<?= $page + 1 ?>">Load More</button>
</form>

</main>
// Display next page button
displayNavigationButton(
$current_page_number,
$total_pages,
false
);
?>
</ul>
</nav>

<script>
document.addEventListener("DOMContentLoaded", function() {
AOS.init();
});
</script>
</script>

0 comments on commit fa3a401

Please sign in to comment.