From ff212db72fdd6ec384e699e745fa674e78cacd9d Mon Sep 17 00:00:00 2001
From: Julian PEREZ-RAMIREZ <julian.perez-ramirez@imt-atlantique.net>
Date: Wed, 26 Mar 2025 09:52:12 +0100
Subject: [PATCH] adjusted errors and pagination

---
 server/web_app/config/services.yaml           |  4 ++
 server/web_app/public/css/error.css           | 32 ++++++++++
 server/web_app/public/css/home.css            | 58 +++++++++++++++++++
 server/web_app/public/css/users.css           | 26 +++++++++
 server/web_app/public/css/wishlist.css        | 26 +++++++++
 server/web_app/public/js/users.js             | 29 +++++++++-
 server/web_app/public/js/wishlist.js          | 27 +++++++--
 .../src/EventListener/ExceptionListener.php   | 30 ++++++++++
 server/web_app/templates/error.html.twig      | 14 ++++-
 server/web_app/templates/home.html.twig       | 30 +++++++++-
 .../templates/usersManagement.html.twig       |  2 +
 server/web_app/templates/wishList.html.twig   |  2 +
 12 files changed, 271 insertions(+), 9 deletions(-)
 create mode 100644 server/web_app/public/css/error.css
 create mode 100644 server/web_app/public/css/home.css
 create mode 100644 server/web_app/src/EventListener/ExceptionListener.php

diff --git a/server/web_app/config/services.yaml b/server/web_app/config/services.yaml
index 2d6a76f..ab18fc6 100644
--- a/server/web_app/config/services.yaml
+++ b/server/web_app/config/services.yaml
@@ -11,6 +11,10 @@ services:
         autowire: true      # Automatically injects dependencies in your services.
         autoconfigure: true # Automatically registers your services as commands, event subscribers, etc.
 
+    App\EventListener\ExceptionListener:
+        tags:
+            - { name: kernel.event_listener, event: kernel.exception }
+
     # makes classes in src/ available to be used as services
     # this creates a service per class whose id is the fully-qualified class name
     App\:
diff --git a/server/web_app/public/css/error.css b/server/web_app/public/css/error.css
new file mode 100644
index 0000000..3312cd5
--- /dev/null
+++ b/server/web_app/public/css/error.css
@@ -0,0 +1,32 @@
+@import url('global.css');
+
+.error-container {
+    text-align: center;
+    padding: 50px;
+    max-width: 600px;
+    margin-top: 10%;
+}
+
+h1 {
+    font-size: 36px;
+    color: #dc3545;
+}
+
+p {
+    font-size: 18px;
+    color: #666;
+}
+
+.btn {
+    display: inline-block;
+    padding: 12px 18px;
+    margin: 10px;
+    border-radius: 5px;
+    text-decoration: none;
+    background-color: var(--color-hover);
+    color: white;
+}
+
+.btn:hover {
+    background-color: #0056b3;
+}
diff --git a/server/web_app/public/css/home.css b/server/web_app/public/css/home.css
new file mode 100644
index 0000000..8d4f955
--- /dev/null
+++ b/server/web_app/public/css/home.css
@@ -0,0 +1,58 @@
+@import url('global.css');
+
+.home-container {
+    text-align: center;
+    padding: 50px;
+    max-width: 600px;
+    margin: auto;
+}
+
+.guest-content {
+    background: #f9f9f9;
+    padding: 30px;
+    border-radius: 10px;
+    box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1);
+}
+
+.gift-image {
+    width: 180px;
+    height: auto;
+    margin-bottom: 20px;
+}
+
+h2, h3 {
+    color: #333;
+}
+
+p {
+    font-size: 16px;
+    color: #666;
+}
+
+.btn {
+    display: inline-block;
+    padding: 12px 18px;
+    margin: 10px;
+    border-radius: 5px;
+    text-decoration: none;
+    font-weight: bold;
+    transition: background 0.3s ease;
+}
+
+.btn-primary {
+    background-color: #28a745;
+    color: white;
+}
+
+.btn-primary:hover {
+    background-color: #218838;
+}
+
+.btn {
+    background-color: var(--color-hover);
+    color: white;
+}
+
+.btn:hover {
+    background-color: #0056b3;
+}
diff --git a/server/web_app/public/css/users.css b/server/web_app/public/css/users.css
index 8caf7e0..de53fd5 100644
--- a/server/web_app/public/css/users.css
+++ b/server/web_app/public/css/users.css
@@ -48,3 +48,29 @@ button:disabled {
 .popup button {
   margin: 10px;
 }
+
+.pagination {
+  text-align: center;
+  margin-top: 20px;
+}
+
+.pagination button {
+  display: inline-block;
+  padding: 8px 12px;
+  margin: 0 5px;
+  border-radius: 4px;
+  background-color: var(--color-hover);
+  color: white;
+  border: none;
+  cursor: pointer;
+}
+
+.pagination button:hover {
+  background-color: #0056b3;
+}
+
+.pagination .active {
+  font-weight: bold;
+  background-color: #004085;
+}
+
diff --git a/server/web_app/public/css/wishlist.css b/server/web_app/public/css/wishlist.css
index a5084e6..415a358 100644
--- a/server/web_app/public/css/wishlist.css
+++ b/server/web_app/public/css/wishlist.css
@@ -19,3 +19,29 @@ button:disabled {
   background-color: var(--color-light);
   color: black;
 }
+
+.pagination {
+  text-align: center;
+  margin-top: 20px;
+}
+
+.pagination button {
+  display: inline-block;
+  padding: 8px 12px;
+  margin: 0 5px;
+  border-radius: 4px;
+  background-color: var(--color-hover);
+  color: white;
+  border: none;
+  cursor: pointer;
+}
+
+.pagination button:hover {
+  background-color: #0056b3;
+}
+
+.pagination .active {
+  font-weight: bold;
+  background-color: #004085;
+}
+
diff --git a/server/web_app/public/js/users.js b/server/web_app/public/js/users.js
index 9f06931..280acaa 100644
--- a/server/web_app/public/js/users.js
+++ b/server/web_app/public/js/users.js
@@ -4,8 +4,11 @@ let currentAction = null;
 let currentUserId = null;
 let actionType = null; // New variable to track whether it's block or unblock
 
-async function fetchUsers() {
-  const response = await fetch(`${ROUTE}:${PORT}/users?userRole=user`);
+let currentPageUsers = 1;
+const usersPerPage = 5;
+
+async function fetchUsers(page=1) {
+  const response = await fetch(`${ROUTE}:${PORT}/users?userRole=user&page=${page}&max=${usersPerPage}`);
   const data = await response.json();
   const tableBody = document.querySelector('#usersTable tbody');
   tableBody.innerHTML = ''; // Clear current table rows
@@ -26,6 +29,26 @@ async function fetchUsers() {
       `;
       tableBody.appendChild(row);
   });
+
+  setupUserPagination(2, page);
+}
+
+// Función para crear la paginación visualmente
+function setupUserPagination(totalPages, currentPage) {
+  const paginationContainer = document.getElementById('userPagination');
+  paginationContainer.innerHTML = '';
+
+  if (currentPage > 1) {
+      paginationContainer.innerHTML += `<button onclick="fetchUsers(${currentPage - 1})">« Prev</button>`;
+  }
+
+  for (let i = 1; i <= totalPages; i++) {
+      paginationContainer.innerHTML += `<button class="${i === currentPage ? 'active' : ''}" onclick="fetchUsers(${i})">${i}</button>`;
+  }
+
+  if (currentPage < totalPages) {
+      paginationContainer.innerHTML += `<button onclick="fetchUsers(${currentPage + 1})">Next »</button>`;
+  }
 }
 
 // Toggle block/unblock
@@ -109,4 +132,4 @@ async function deleteUser(userId) {
   }
 }
 // Fetch users when the page loads
-window.onload = fetchUsers;
+window.onload = fetchUsers(currentPageUsers);
diff --git a/server/web_app/public/js/wishlist.js b/server/web_app/public/js/wishlist.js
index cd3965d..ca34fa7 100644
--- a/server/web_app/public/js/wishlist.js
+++ b/server/web_app/public/js/wishlist.js
@@ -1,23 +1,42 @@
 const ROUTE = 'http://34.70.36.158';
 const PORT = '8080';
+let currentPage = 1;
+const itemsPerPage = 5;
 
 // Obtener el parámetro `userId` de la URL
 const urlParams = new URLSearchParams(window.location.search);
 
 // Function to fetch wishlists and populate the table
-async function fetchData() {
-    const url = `${ROUTE}:${PORT}/wishLists?userId=${userId}`;
+async function fetchData(page = 1) {
+    const url = `${ROUTE}:${PORT}/wishLists?userId=${userId}&page=${page}&limit=${itemsPerPage}`;
 
     try {
         const response = await fetch(url);
         const data = await response.json();
-        console.log(data)
         populateTable(data.wishLists); // Populate the table with the fetched data
+        setupPagination(2, page);
     } catch (error) {
         console.error('Error fetching data:', error);
     }
 }
 
+function setupPagination(totalPages, currentPage) {
+    const paginationContainer = document.getElementById('pagination');
+    paginationContainer.innerHTML = '';
+
+    if (currentPage > 1) {
+        paginationContainer.innerHTML += `<button onclick="fetchData(${currentPage - 1})">« Prev</button>`;
+    }
+
+    for (let i = 1; i <= totalPages; i++) {
+        paginationContainer.innerHTML += `<button class="${i === currentPage ? 'active' : ''}" onclick="fetchData(${i})">${i}</button>`;
+    }
+
+    if (currentPage < totalPages) {
+        paginationContainer.innerHTML += `<button onclick="fetchData(${currentPage + 1})">Next »</button>`;
+    }
+}
+
 // Function to populate the table with the wishlists
 function populateTable(data) {
     const tableBody = document.getElementById('dataBody');
@@ -69,4 +88,4 @@ function detailsItem(id) {
 }
 
 // Fetch the wishlists when the page loads
-window.onload = fetchData;
+window.onload = fetchData(currentPage);
diff --git a/server/web_app/src/EventListener/ExceptionListener.php b/server/web_app/src/EventListener/ExceptionListener.php
new file mode 100644
index 0000000..0ce6d55
--- /dev/null
+++ b/server/web_app/src/EventListener/ExceptionListener.php
@@ -0,0 +1,30 @@
+<?php
+
+namespace App\EventListener;
+
+use Psr\Log\LoggerInterface;
+use Symfony\Component\HttpFoundation\RedirectResponse;
+use Symfony\Component\HttpKernel\Event\ExceptionEvent;
+use Symfony\Component\Routing\RouterInterface;
+use Symfony\Component\EventDispatcher\Attribute\AsEventListener;
+
+#[AsEventListener(event: 'kernel.exception')]
+class ExceptionListener
+{
+    private RouterInterface $router;
+    private LoggerInterface $logger;
+
+    public function __construct(RouterInterface $router, LoggerInterface $logger)
+    {
+        $this->router = $router;
+        $this->logger = $logger;
+    }
+
+    public function onKernelException(ExceptionEvent $event)
+    {
+        $this->logger->error('🛑 ExceptionListener se ejecutó y redirige a /error');
+
+        $response = new RedirectResponse($this->router->generate('error'));
+        $event->setResponse($response);
+    }
+}
diff --git a/server/web_app/templates/error.html.twig b/server/web_app/templates/error.html.twig
index f17a6b7..16312bb 100644
--- a/server/web_app/templates/error.html.twig
+++ b/server/web_app/templates/error.html.twig
@@ -1 +1,13 @@
-{% block body %} This page does not exist or you do not have rigths to see {% endblock %}
\ No newline at end of file
+{% extends 'base.html.twig' %}
+
+{% block styles %}
+  <link rel="stylesheet" href="{{ asset('css/error.css') }}">
+{% endblock %}
+
+{% block body %}
+    <div class="error-container">
+        <h1>Error</h1>
+        <p>This page does not exist or you do not have rigths to see.</p>
+        <a href="{{ path('home') }}" class="btn">Return to Homepage</a>
+    </div>
+{% endblock %}
\ No newline at end of file
diff --git a/server/web_app/templates/home.html.twig b/server/web_app/templates/home.html.twig
index 06d07ac..76ba4bd 100644
--- a/server/web_app/templates/home.html.twig
+++ b/server/web_app/templates/home.html.twig
@@ -1,3 +1,31 @@
 {% extends 'base.html.twig' %}
 
-{% block body %} Welcome {% endblock %}
+{% block styles %}
+    <link rel="stylesheet" href="{{ asset('css/home.css') }}">
+{% endblock %}
+
+{% block body %}
+    <section class="home-container container">
+        {% if app.user %}
+            <h2>Welcome, {{ app.user.username }}!</h2>
+            <p>You are now logged in and ready to explore our platform.</p>
+            <p>Feel free to navigate through your dashboard, manage your wishlists, and connect with others.</p>
+        {% else %}
+            <div class="guest-content">
+                <img src="{{ asset('img/gifts.png') }}" alt="Gift" class="gift-image">
+                
+                <h2>Discover a World of Possibilities</h2>
+                <p>Are you curious about what we do and how we can help you? Learn more about our platform and how it can enhance your experience.</p>
+                <a href="{{ path('about') }}" class="btn">Learn More About Us</a>
+
+                <h3>Already have an account?</h3>
+                <p>If you're already part of our community, log in now to access your account and continue where you left off.</p>
+                <a href="{{ path('app_login') }}" class="btn">Sign In</a>
+
+                <h3>Join Us Today!</h3>
+                <p>Creating an account is quick and easy. Start managing your wishlists, sharing experiences, and making the most out of our platform.</p>
+                <a href="#" class="btn btn-primary">Create an Account</a>
+            </div>
+        {% endif %}
+    </section>
+{% endblock %}
diff --git a/server/web_app/templates/usersManagement.html.twig b/server/web_app/templates/usersManagement.html.twig
index 93a4a7f..86a57b6 100644
--- a/server/web_app/templates/usersManagement.html.twig
+++ b/server/web_app/templates/usersManagement.html.twig
@@ -33,4 +33,6 @@
     </div>
 
     <script src="{{ asset('js/users.js') }}"></script>
+
+    <div id="userPagination" class="pagination"></div>
 {% endblock %}
diff --git a/server/web_app/templates/wishList.html.twig b/server/web_app/templates/wishList.html.twig
index 443db77..9be12c8 100644
--- a/server/web_app/templates/wishList.html.twig
+++ b/server/web_app/templates/wishList.html.twig
@@ -32,4 +32,6 @@
     </script>
 
     <script src="{{ asset('js/wishlist.js') }}"></script>
+
+    <div id="pagination" class="pagination"></div>
 {% endblock %}
-- 
GitLab