From bbf8f6ba3667b58cd3f4f12898db600964469c7b Mon Sep 17 00:00:00 2001
From: Anamaria Miranda <anny13miranda@gmail.com>
Date: Wed, 26 Mar 2025 01:08:54 +0100
Subject: [PATCH] Added full management insights and wishlits

---
 server/web_app/public/css/global.css          |  23 ++-
 server/web_app/public/css/insights.css        |  55 ++++++++
 server/web_app/public/css/users.css           |  17 ---
 server/web_app/public/js/insights.js          | 132 ++++++++++++++++++
 server/web_app/public/js/users.js             |   2 +-
 .../src/Controller/DashboardController.php    |  13 +-
 server/web_app/templates/dashboard.html.twig  |   2 +-
 server/web_app/templates/insights.html.twig   |  68 ++++++++-
 .../templates/usersManagement.html.twig       |   2 +-
 9 files changed, 285 insertions(+), 29 deletions(-)

diff --git a/server/web_app/public/css/global.css b/server/web_app/public/css/global.css
index a868886..00e58ea 100644
--- a/server/web_app/public/css/global.css
+++ b/server/web_app/public/css/global.css
@@ -37,7 +37,6 @@
 * {
   box-sizing: border-box;
   font-family: var(--font-family-style);
-  line-height: var(--line-heigth-normal);
   font-weight: var(--font-weight-regular);
   margin: 0;
   padding: 0;
@@ -50,3 +49,25 @@ body {
 .container {
   margin: var(--padding-space-large);
 }
+
+.table-container {
+  margin: var(--padding-space-large);
+  overflow-x: auto;
+}
+
+table {
+  width: 100%;
+  border-collapse: collapse;
+  background-color: var(--color-complementary);
+}
+
+table th, table td {
+  border: var(--border-thin) solid var(--color-hover);
+  padding: var(--padding-space-small);
+  text-align: left;
+}
+
+table th {
+  background-color: var(--color-hover);
+  color: var(--color-complementary);
+}
diff --git a/server/web_app/public/css/insights.css b/server/web_app/public/css/insights.css
index 20d32d7..83179fb 100644
--- a/server/web_app/public/css/insights.css
+++ b/server/web_app/public/css/insights.css
@@ -1 +1,56 @@
 @import url('global.css');
+
+.controls {
+  display: flex;
+  gap: 20px;
+  margin-bottom: 20px;
+}
+
+.selector {
+  display: inline-block;
+}
+
+button {
+  padding: 8px 16px;
+  background-color: #4CAF50;
+  color: white;
+  border: none;
+  border-radius: 5px;
+  cursor: pointer;
+}
+
+button:disabled {
+  background-color: grey;
+
+}
+
+.active {
+  background-color: green;
+  padding: var(--padding-space-small);
+  border-radius: 5%;
+}
+
+.inactive {
+  background-color: var(--color-light);
+  padding: var(--padding-space-small);
+  border-radius: 5%;
+}
+
+#filterControl {
+  display: flex;
+  justify-items: center;
+  margin: var(--margin-space-large);
+  flex-wrap: wrap;
+}
+
+#pageTitle {
+  margin-top: 2%;
+}
+
+select {
+  padding: 10px;
+  border: 2px solid #ccc;
+  border-radius: 5px;
+  background-color: #f9f9f9;
+  width: 200px;
+}
\ No newline at end of file
diff --git a/server/web_app/public/css/users.css b/server/web_app/public/css/users.css
index ace1e04..8caf7e0 100644
--- a/server/web_app/public/css/users.css
+++ b/server/web_app/public/css/users.css
@@ -1,22 +1,5 @@
 @import url('global.css');
 
-table {
-  width: 100%;
-  border-collapse: collapse;
-  background-color: var(--color-complementary);
-}
-
-table th, table td {
-  border: var(--border-thin) solid var(--color-hover);
-  padding: var(--padding-space-small);
-  text-align: left;
-}
-
-table th {
-  background-color: var(--color-hover);
-  color: var(--color-complementary);
-}
-
 button {
   padding: 6px 12px;
   margin: var(--margin-space-xsmall);
diff --git a/server/web_app/public/js/insights.js b/server/web_app/public/js/insights.js
index e69de29..2c3cfab 100644
--- a/server/web_app/public/js/insights.js
+++ b/server/web_app/public/js/insights.js
@@ -0,0 +1,132 @@
+const ROUTE = 'http://localhost';
+const PORT = '8080';
+
+// State management
+let currentSort, currentTarget;
+let isFetching = false;
+const button = document.getElementById("refreshBtn");
+const form = document.getElementById("filterControl");
+const title = document.getElementById("pageTitle");
+const wishTitle = "Top 3 wishlists with the highest total purchase amount";
+const itemTitle = "Top 3 most expensive purchased items";
+const trItem = document.getElementById("itemsTable");
+const trWish = document.getElementById("wishlistsTable");
+
+// Initialize from URL
+function initFromUrl() {
+    const path = window.location.pathname;
+    const segments = path.split("/").filter(segment => segment !== "");
+    currentSort = segments[segments.length - 1];
+    currentTarget = segments[segments.length - 2];
+}
+
+// Main data loading function
+async function fetchData() {
+    let url = '';
+    if (currentTarget === 'items') {
+        url = `${ROUTE}:${PORT}/items?sortBy=price&sort=${currentSort}&onlyBought=true`;
+    } else {
+        url = `${ROUTE}:${PORT}/wishLists/sortedByTotalBought?sort=${currentSort}`;
+    }
+
+    try {
+        const response = await fetch(url);
+        const data = await response.json();
+        
+        // Populate table based on target
+        const tableBody = document.getElementById('dataBody');
+        tableBody.innerHTML = '';
+        
+        const itemsToDisplay = currentTarget === 'wishlists' ? data.wishLists : data.items;
+        populateTable(itemsToDisplay);
+
+        title.innerText = currentTarget === "wishlists" ? wishTitle : itemTitle;
+
+        if (currentTarget === "wishlists") {
+            trItem.hidden = true;
+            trWish.hidden = false;
+        } else {
+            trWish.hidden = true;
+            trItem.hidden = false;
+        }
+        
+    } catch (error) {
+        console.error('Error fetching data:', error);
+    } finally {
+        isFetching = false;
+        button.disabled = false;
+    }
+}
+
+// Table population
+function populateTable(data) {
+    const tableBody = document.getElementById('dataBody');
+
+    data.forEach(key => {
+        const row = document.createElement('tr');
+        
+        if (currentTarget === 'items') {
+            row.innerHTML = `
+                <td>${key.id}</td>
+                <td>${key.title}</td>
+                <td>${key.description}</td>
+                <td>${key.price}</td>
+                <td>${key.wishList.name}</td>
+                <td class="active">${key.wishList.isActive ? 'Active' : 'Unactive'}</td>
+                <td>${key.wishList.createdAt}</td>
+                <td>${key.wishList.expirationDate}</td>
+                <td>${key.wishList.user.username}</td>
+            `;
+        } else {
+            row.innerHTML = `
+                <td>${key.wishList.id}</td>
+                <td>${key.wishList.name}</td>
+                <td>${key.wishList.description}</td>
+                <td>${key.totalPrice}</td>
+                <td>
+                    <span class="${key.isActive ? 'active' : 'inactive'}">
+                        ${key.isActive ? 'Active' : 'Inactive'}
+                    </span>
+                </td>
+                <td>${key.wishList.user.username}</td>
+                <td>${key.wishList.createdAt}</td>
+                <td>${key.wishList.expirationDate}</td>
+            `;
+        }
+
+        tableBody.appendChild(row);
+    });
+}
+
+// Controlled data loading
+function loadData() {
+    if (isFetching) return;
+    
+    isFetching = true;
+    button.disabled = true;
+    fetchData();
+}
+
+// Form submission handler
+form.addEventListener("submit", function(event) {
+    event.preventDefault();
+    
+    currentSort = document.getElementById('sort').value;
+    currentTarget = document.getElementById('target').value;
+    
+    // Update URL without reload
+    const newUrl = `/dashboard/insights/${currentTarget}/${currentSort}`;
+    window.history.pushState({ path: newUrl }, '', newUrl);
+    
+    loadData();
+});
+
+// Handle browser navigation
+window.addEventListener('popstate', () => {
+    initFromUrl();
+    loadData();
+});
+
+// Initial setup
+initFromUrl();
+loadData();
\ No newline at end of file
diff --git a/server/web_app/public/js/users.js b/server/web_app/public/js/users.js
index c5ee461..6d4fdae 100644
--- a/server/web_app/public/js/users.js
+++ b/server/web_app/public/js/users.js
@@ -5,7 +5,7 @@ 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`);
+  const response = await fetch(`${ROUTE}:${PORT}/users?userRole=user`);
   const data = await response.json();
   const tableBody = document.querySelector('#usersTable tbody');
   tableBody.innerHTML = ''; // Clear current table rows
diff --git a/server/web_app/src/Controller/DashboardController.php b/server/web_app/src/Controller/DashboardController.php
index 0c9a0ec..a353f1e 100644
--- a/server/web_app/src/Controller/DashboardController.php
+++ b/server/web_app/src/Controller/DashboardController.php
@@ -29,13 +29,12 @@ class DashboardController extends AbstractController
         return $this->render('usersManagement.html.twig');
     }
 
-    #[Route('/insights', name: 'manageInsights')]
-    public function items(): Response
+    #[Route('/insights/{type}/{order}', name: 'manageInsights', defaults: ['type' => 'wishlists', 'order' => 'asc'])]
+    public function insights(string $type, string $order): Response
     {
-        if (!$this->isGranted('ROLE_ADMIN')) {
-            return $this->redirectToRoute('error');
-        }
-
-        return $this->render('insights.html.twig');
+        return $this->render('insights.html.twig', [
+            'target' => $type,
+            'sort' => $order,
+        ]);
     }
 }
diff --git a/server/web_app/templates/dashboard.html.twig b/server/web_app/templates/dashboard.html.twig
index 75ab75c..ccec0af 100644
--- a/server/web_app/templates/dashboard.html.twig
+++ b/server/web_app/templates/dashboard.html.twig
@@ -6,7 +6,7 @@
 
 {% block body %}
   <section class="container">
-    <a class="card" href="{{ path('manageInsights') }}">
+    <a class="card" href="{{ path('manageInsights', {'type': 'items', 'order': 'desc'}, false ) }}">
       <article>
         <img src="{{ asset('img/gifts.png') }}" alt="">
         <h4>Insights</h4>
diff --git a/server/web_app/templates/insights.html.twig b/server/web_app/templates/insights.html.twig
index f682d0e..b783655 100644
--- a/server/web_app/templates/insights.html.twig
+++ b/server/web_app/templates/insights.html.twig
@@ -1,9 +1,75 @@
 {% extends 'base.html.twig' %}
 
 {% block styles %}
-  <link rel="stylesheet" href="{{ asset('css/insights.css') }}">
+    <link rel="stylesheet" href="{{ asset('css/insights.css') }}">
 {% endblock %}
 
 {% block body %}
+    {% if target == 'items' %}
+        <h3 id="pageTitle">Top 3 most expensive purchased items</h3>
+    {% else %}
+        <h3 id="pageTitle">Top 3 wishlists with the highest total purchase amount</h3>
+    {% endif %}
+    
+    <!-- Controls -->
+    <form id="filterControl" class="controls">
+        <div class="selector">
+            <label for="sort">Sort By:</label>
+            <select id="sort">
+                <option value="asc" {% if sort == 'asc' %}selected{% endif %}>Ascending</option>
+                <option value="desc" {% if sort == 'desc' %}selected{% endif %}>Descending</option>
+            </select>
+        </div>
+        <div class="selector">
+            <label for="target">Select Target:</label>
+            <select id="target">
+                <option value="wishlists" {% if target == 'wishlists' %}selected{% endif %}>Wishlists</option>
+                <option value="items" {% if target == 'items' %}selected{% endif %}>Items</option>
+            </select>
+        </div>
+        <button id="refreshBtn" disabled type="submit">Update</button>
+    </form>
 
+    <!-- Table to show data -->
+    <section class="table-container">
+        <table id="dataTable">
+            <thead>
+                <tr id="itemsTable"
+                    {% if target == 'wishlists' %}
+                        hidden
+                    {% endif %}
+                >
+                    <th>ID</th>
+                    <th>Title</th>
+                    <th>Description</th>
+                    <th>Price</th>
+                    <th>WishList name</th>
+                    <th>Status</th>
+                    <th>Create at</th>
+                    <th>Expiration date</th>
+                    <th>WishList owner</th>
+                </tr>
+
+                <tr id="wishlistsTable"
+                    {% if target == 'items' %}
+                        hidden
+                    {% endif %}
+                >  
+                    <th>ID</th>
+                    <th>Name</th>
+                    <th>Description</th>
+                    <th>Total Amount</th>
+                    <th>Status</th>
+                    <th>WishList owner</th>
+                    <th>Creation Date</th>
+                    <th>Expiration date</th>
+                </tr>
+            </thead>
+            <tbody id="dataBody">
+                <!-- Data will be populated here dynamically -->
+            </tbody>
+        </table>
+    </section>
+
+    <script src="{{ asset('js/insights.js') }}"></script>
 {% endblock %}
diff --git a/server/web_app/templates/usersManagement.html.twig b/server/web_app/templates/usersManagement.html.twig
index 1c16889..93a4a7f 100644
--- a/server/web_app/templates/usersManagement.html.twig
+++ b/server/web_app/templates/usersManagement.html.twig
@@ -7,7 +7,7 @@
 {% block body %}
     <h3>User control panel</h3>
 
-    <article class="container">
+    <article class="table-container">
         <table id="usersTable">
             <thead>
                 <tr>
-- 
GitLab