From 05d55b559f3d099f2c7fb1bc24bb0d2149594d3d Mon Sep 17 00:00:00 2001 From: Akshith <33996844+akshith312@users.noreply.github.com> Date: Wed, 4 Mar 2026 12:17:59 -0800 Subject: [PATCH 1/2] feat: added pagination controls to no-show and drop-off table --- .../Reports/Participation/DropOffTracking.jsx | 149 ++++++++++++++++- .../Participation/Participation.module.css | 151 ++++++++++++++++++ 2 files changed, 296 insertions(+), 4 deletions(-) diff --git a/src/components/CommunityPortal/Reports/Participation/DropOffTracking.jsx b/src/components/CommunityPortal/Reports/Participation/DropOffTracking.jsx index 63ffd35c82..71ecf9fe9d 100644 --- a/src/components/CommunityPortal/Reports/Participation/DropOffTracking.jsx +++ b/src/components/CommunityPortal/Reports/Participation/DropOffTracking.jsx @@ -1,4 +1,4 @@ -import { useState } from 'react'; +import { useState, useMemo, useEffect } from 'react'; import { useSelector } from 'react-redux'; import styles from './Participation.module.css'; import mockEvents from './mockData'; @@ -6,6 +6,11 @@ import mockEvents from './mockData'; function DropOffTracking() { const [selectedEvent, setSelectedEvent] = useState('All Events'); const [selectedTime, setSelectedTime] = useState('All Time'); + const [currentPage, setCurrentPage] = useState(1); + const [pageSize, setPageSize] = useState(20); + + const PAGINATION_THRESHOLD = 20; + const PAGE_SIZE_OPTIONS = [10, 20, 50]; const getDateRange = () => { const today = new Date(); @@ -44,6 +49,69 @@ function DropOffTracking() { return true; }); + useEffect(() => { + setCurrentPage(1); + }, [selectedEvent, selectedTime]); + + const paginatedEvents = useMemo(() => { + const startIndex = (currentPage - 1) * pageSize; + const endIndex = startIndex + pageSize; + + return filteredEvents.slice(startIndex, endIndex); + }, [filteredEvents, currentPage, pageSize]); + + const totalPages = Math.ceil(filteredEvents.length / pageSize); + const showPagination = totalPages > 1; + + const handlePageSizeChange = e => { + setPageSize(Number(e.target.value)); + setCurrentPage(1); + }; + + const handlePreviousPage = () => { + setCurrentPage(prev => Math.max(prev - 1, 1)); + }; + + const handleNextPage = () => { + setCurrentPage(prev => Math.min(prev + 1, totalPages)); + }; + + const getVisiblePages = () => { + const pages = []; + const maxVisible = 5; // numbers in the middle section + + if (totalPages <= 7) { + // Small page count → show everything + return Array.from({ length: totalPages }, (_, i) => i + 1); + } + + const leftBound = Math.max(2, currentPage - 1); + const rightBound = Math.min(totalPages - 1, currentPage + 1); + + // Always show first page + pages.push(1); + + // Show left ellipsis + if (currentPage > 3) { + pages.push('left-ellipsis'); + } + + // Middle pages + for (let i = leftBound; i <= rightBound; i++) { + pages.push(i); + } + + // Show right ellipsis + if (currentPage < totalPages - 2) { + pages.push('right-ellipsis'); + } + + // Always show last page + pages.push(totalPages); + + return pages; + }; + const darkMode = useSelector(state => state.theme.darkMode); return ( @@ -109,17 +177,90 @@ function DropOffTracking() { - {filteredEvents.map(event => ( + {paginatedEvents.map(event => ( {event.eventName} - {event.noShowRate} - {event.dropOffRate} + {event.noShowRate} + {event.dropOffRate} {event.attendees} ))} + + {/*Pagination*/} + {showPagination && ( +
+
+ Showing {(currentPage - 1) * pageSize + 1} to{' '} + {Math.min(currentPage * pageSize, filteredEvents.length)} of {filteredEvents.length}{' '} + records +
+ +
+ + +
+ {getVisiblePages().map(page => + page === 'left-ellipsis' || page === 'right-ellipsis' ? ( + + ... + + ) : ( + + ), + )} +
+ + + Page {currentPage} of {totalPages} + + + +
+ +
+ + +
+
+ )} ); } diff --git a/src/components/CommunityPortal/Reports/Participation/Participation.module.css b/src/components/CommunityPortal/Reports/Participation/Participation.module.css index d250be26a1..3e2ba86a26 100644 --- a/src/components/CommunityPortal/Reports/Participation/Participation.module.css +++ b/src/components/CommunityPortal/Reports/Participation/Participation.module.css @@ -932,3 +932,154 @@ .insightsTabDarkMode:hover { background-color: #374151; } + +/* Pagination Styles */ +.paginationContainer { + display: flex; + justify-content: space-between; + align-items: center; + padding: 16px; + border-top: 1px solid #e0e0e0; + margin-top: 16px; + gap: 16px; + flex-wrap: nowrap; + background-color: #f9f9f9; + border-radius: 4px; + width: 100%; +} + +.paginationContainerDark { + background-color: #1C2541; + border-top: 1px solid #3A506B; +} + +.paginationInfo { + font-size: 14px; + color: #666; + min-width: 200px; +} + +.paginationContainerDark .paginationInfo { + color: #aaa; +} + +.paginationControls { + display: flex; + gap: 12px; + align-items: center; +} + +.paginationControls button { + padding: 8px 16px; + border: 1px solid #ccc; + background-color: white; + border-radius: 4px; + cursor: pointer; + font-size: 14px; + transition: all 0.2s ease; +} + +.paginationControls button:hover:not(:disabled) { + background-color: #f0f0f0; + border-color: #999; +} + +.paginationControls button:disabled { + opacity: 0.5; + cursor: not-allowed; +} + +.paginationContainerDark .paginationControls button { + background-color: #3A506B; + border-color: #4A607B; + color: #ffffff; +} + +.paginationContainerDark .paginationControls button:hover:not(:disabled) { + background-color: #4A607B; + border-color: #5B708C; +} +.paginationButtonDark:hover:not(:disabled) { + background-color: #4a4a4a; + border-color: #777; +} +.paginationContainerDark .paginationControls button:disabled { + background-color: #2a2a2a; + border-color: #444; + color: #777; +} + +.pageIndicator { + font-size: 14px; + color: #666; + font-weight: 500; + min-width: 120px; + text-align: center; +} + +.paginationContainerDark .pageIndicator { + color: #aaa; +} + +.pageSizeSelector { + display: flex; + gap: 8px; + align-items: center; + min-width: 200px; + justify-content: flex-end; + white-space: nowrap; + flex-shrink: 0; +} + +.pageSizeSelector label { + font-size: 14px; + color: #666; +} + +.paginationContainerDark .pageSizeSelector label { + color: #aaa; +} + +.pageSizeSelector select { + padding: 6px 12px; + border: 1px solid #ccc; + border-radius: 4px; + background-color: white; + font-size: 14px; + cursor: pointer; +} + +.pageSizeSelectorDark select { + background-color: #3a3a3a; + border-color: #555; + color: #fff; +} + +.pageNumbers { + display: flex; + align-items: center; + gap: 6px; +} + +.pageNumberButton { + padding: 4px 10px; + border-radius: 4px; + border: 1px solid #ccc; + background: white; + cursor: pointer; +} + +.pageNumberButton:hover { + background: #f2f2f2; +} + +.activePage { + background: #007bff; + color: white; + border-color: #007bff; +} + +.ellipsis { + padding: 0 6px; + font-weight: bold; +} \ No newline at end of file From 3c11ff868bfb0985eccaf1f1d27f6d3d72a1b5fd Mon Sep 17 00:00:00 2001 From: Akshith <33996844+akshith312@users.noreply.github.com> Date: Wed, 4 Mar 2026 17:55:57 -0800 Subject: [PATCH 2/2] fix: sonarqube issues --- .../Reports/Participation/DropOffTracking.jsx | 8 -------- .../Participation/Participation.module.css | 20 +++++++++++++------ 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/components/CommunityPortal/Reports/Participation/DropOffTracking.jsx b/src/components/CommunityPortal/Reports/Participation/DropOffTracking.jsx index 71ecf9fe9d..73c9370959 100644 --- a/src/components/CommunityPortal/Reports/Participation/DropOffTracking.jsx +++ b/src/components/CommunityPortal/Reports/Participation/DropOffTracking.jsx @@ -9,7 +9,6 @@ function DropOffTracking() { const [currentPage, setCurrentPage] = useState(1); const [pageSize, setPageSize] = useState(20); - const PAGINATION_THRESHOLD = 20; const PAGE_SIZE_OPTIONS = [10, 20, 50]; const getDateRange = () => { @@ -78,35 +77,28 @@ function DropOffTracking() { const getVisiblePages = () => { const pages = []; - const maxVisible = 5; // numbers in the middle section if (totalPages <= 7) { - // Small page count → show everything return Array.from({ length: totalPages }, (_, i) => i + 1); } const leftBound = Math.max(2, currentPage - 1); const rightBound = Math.min(totalPages - 1, currentPage + 1); - // Always show first page pages.push(1); - // Show left ellipsis if (currentPage > 3) { pages.push('left-ellipsis'); } - // Middle pages for (let i = leftBound; i <= rightBound; i++) { pages.push(i); } - // Show right ellipsis if (currentPage < totalPages - 2) { pages.push('right-ellipsis'); } - // Always show last page pages.push(totalPages); return pages; diff --git a/src/components/CommunityPortal/Reports/Participation/Participation.module.css b/src/components/CommunityPortal/Reports/Participation/Participation.module.css index 3e2ba86a26..94220890ab 100644 --- a/src/components/CommunityPortal/Reports/Participation/Participation.module.css +++ b/src/components/CommunityPortal/Reports/Participation/Participation.module.css @@ -294,6 +294,7 @@ border-radius: 10px; padding: 10px; background: #fff; + margin-bottom: 20px; } .trackingListContainerDark { max-height: 600px; @@ -1004,9 +1005,10 @@ border-color: #777; } .paginationContainerDark .paginationControls button:disabled { - background-color: #2a2a2a; - border-color: #444; - color: #777; + background-color: #2E3B4E; + border-color: #3A506B; + color: #C5D1E0; + opacity: 0.7; } .pageIndicator { @@ -1040,6 +1042,12 @@ color: #aaa; } +.paginationContainerDark .pageSizeSelector select { + background-color: #3A506B; + border-color: #4A607B; + color: #ffffff; +} + .pageSizeSelector select { padding: 6px 12px; border: 1px solid #ccc; @@ -1074,9 +1082,9 @@ } .activePage { - background: #007bff; - color: white; - border-color: #007bff; + background: #1E40AF; + color: #ffffff; + border-color: #1E40AF; } .ellipsis {