-
- Least Popular Event
-
-
- {leastPopularEvent.type || 'N/A'}
-
+
+
+
Least Popular Event
+
{leastPopularEvent?.type || 'N/A'}
>
)}
diff --git a/src/components/CommunityPortal/EventPersonalization/EventStats.module.css b/src/components/CommunityPortal/EventPersonalization/EventStats.module.css
index 2f589f6b12..bd6da94400 100644
--- a/src/components/CommunityPortal/EventPersonalization/EventStats.module.css
+++ b/src/components/CommunityPortal/EventPersonalization/EventStats.module.css
@@ -1,107 +1,64 @@
-.popularEventsContainer {
+/* Container */
+.popular-events-container {
max-height: 100%;
margin: 0 auto;
padding: 20px;
font-family: Arial, sans-serif;
- background: white;
}
-.popularEventsContainerDark {
- margin: 0 auto;
- padding: 20px;
- font-family: Arial, sans-serif;
- background: #1B2A41;
- min-height: 100%;
-}
-
-.headerContainer {
- display: flex;
- justify-content: space-between;
- align-items: center;
-}
-
-.headerContainerDark {
+/* Header */
+.header-container {
display: flex;
justify-content: space-between;
align-items: center;
- color: #1C2541;
}
-.popularEventsHeader {
+.popular-events-header {
font-size: 1.5rem;
- color: #000000;
margin: 0;
}
-.popularEventsHeaderDark {
- font-size: 1.5rem;
- color: #ffffff;
- margin: 0;
- background-color: #1C2541;
-}
-
+/* Filters */
.filters {
display: flex;
gap: 10px;
}
-.filtersDark {
- display: flex;
- gap: 10px;
- background-color: #1C2541;
-}
-
-.filters select {
+.selectBase {
padding: 6px;
font-size: 14px;
- border: 1px solid #ccc;
border-radius: 5px;
cursor: pointer;
+ border: 1px solid #ccc;
}
+/* Stats */
.stats {
display: flex;
flex-direction: column;
gap: 20px;
border-radius: 8px;
- box-shadow: 0px 2px 4px rgba(0, 0, 0, 0.1);
padding: 30px;
}
-.statsDark {
+.stat-item {
display: flex;
- flex-direction: column;
- gap: 20px;
- border-radius: 8px;
- box-shadow: 0px 2px 4px rgba(0, 0, 0, 0.1);
- padding: 30px;
- background-color: #1C2541;
-}
-
-.statItem {
- display: grid;
- grid-template-columns: 140px 1fr auto;
align-items: center;
gap: 15px;
}
-.statLabel {
+.stat-label {
+ flex: 1;
font-size: 14px;
font-weight: bold;
- color: #333;
}
-.statLabelDark {
- font-size: 14px;
- font-weight: bold;
- color: #ffffff;
-}
-
-.statBar {
- width: 100%;
- background: #f0f0f0;
+.stat-bar {
+ flex: 3;
height: 8px;
border-radius: 5px;
+ margin: 0 10px;
+ background: #f0f0f0;
position: relative;
overflow: hidden;
}
@@ -112,37 +69,17 @@
transition: width 0.5s ease-in-out;
}
-.bar.green {
- background-color: #4caf50;
-}
-
-.bar.orange {
- background-color: #ff9800;
-}
-
-.bar.red {
- background-color: #f44336;
-}
+.green { background-color: #4caf50; }
+.orange { background-color: #ff9800; }
+.red { background-color: #f44336; }
-.statValue {
+.stat-value {
font-size: 14px;
font-weight: bold;
- color: #333;
- white-space: nowrap;
- text-align: right;
- min-width: 110px;
}
-.statValueDark {
- font-size: 14px;
- font-weight: bold;
- color: #ffffff;
- white-space: nowrap;
- text-align: right;
- min-width: 110px;
-}
-
-.eventSummary {
+/* Summary */
+.event-summary {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 10px;
@@ -152,169 +89,19 @@
padding-bottom: 20px;
}
-.summaryItem {
- background: white;
+.summary-item {
padding: 12px;
border-radius: 8px;
box-shadow: 0px 2px 4px rgba(0, 0, 0, 0.1);
- display: flex;
- flex-direction: column;
- justify-content: center;
- align-items: center;
- max-height: 90px;
- min-height: 80px;
- overflow: hidden;
- text-align: center;
-}
-
-.summaryItemDark {
- background: #3A506B;
- padding: 12px;
- border-radius: 8px;
- box-shadow: 0px 2px 4px rgba(0, 0, 0, 0.1);
- display: flex;
- flex-direction: column;
- justify-content: center;
- align-items: center;
- max-height: 90px;
- min-height: 80px;
- overflow: hidden;
- text-align: center;
-}
-
-.summaryTitle {
- font-size: 14px;
- font-weight: bold;
- text-align: center;
- white-space: normal;
- word-wrap: break-word;
- max-width: 90%;
- color: #777;
-}
-
-.summaryTitleDark {
- font-size: 14px;
- font-weight: bold;
- text-align: center;
- white-space: normal;
- word-wrap: break-word;
- max-width: 90%;
- color: #ffffff;
}
-.summaryValue {
+.summary-title {
font-size: 14px;
font-weight: bold;
- color: #000;
- margin-top: 4px;
}
-.summaryValueDark {
+.summary-value {
font-size: 14px;
font-weight: bold;
- color: #ffffff;
margin-top: 4px;
-}
-
-/* ── Responsive: tablets and below ── */
-@media (max-width: 768px) {
- .popularEventsContainer,
- .popularEventsContainerDark {
- padding: 14px;
- }
-
- .headerContainer,
- .headerContainerDark {
- flex-direction: column;
- align-items: flex-start;
- gap: 10px;
- }
-
- .popularEventsHeader,
- .popularEventsHeaderDark {
- font-size: 1.2rem;
- }
-
- .filters,
- .filtersDark {
- width: 100%;
- flex-wrap: wrap;
- }
-
- .filters select,
- .filtersDark select {
- flex: 1;
- min-width: 100px;
- }
-
- .stats,
- .statsDark {
- padding: 16px;
- gap: 14px;
- }
-
- .statItem {
- grid-template-columns: 1fr auto;
- grid-template-rows: auto auto;
- gap: 6px 10px;
- }
-
- .statLabel,
- .statLabelDark {
- grid-column: 1 / -1;
- font-size: 13px;
- }
-
- .statBar {
- grid-column: 1;
- grid-row: 2;
- }
-
- .statValue,
- .statValueDark {
- grid-column: 2;
- grid-row: 2;
- font-size: 13px;
- min-width: unset;
- }
-
- .eventSummary {
- grid-template-columns: repeat(2, 1fr);
- gap: 10px;
- padding-bottom: 14px;
- }
-
- .summaryItem,
- .summaryItemDark {
- min-height: 70px;
- padding: 10px;
- }
-
- .summaryTitle,
- .summaryTitleDark {
- font-size: 12px;
- }
-
- .summaryValue,
- .summaryValueDark {
- font-size: 13px;
- }
-}
-
-/* ── Responsive: small phones ── */
-@media (max-width: 480px) {
- .popularEventsHeader,
- .popularEventsHeaderDark {
- font-size: 1.1rem;
- }
-
- .statLabel,
- .statLabelDark {
- font-size: 12px;
- }
-
- .statValue,
- .statValueDark {
- font-size: 12px;
- }
}
\ No newline at end of file
diff --git a/src/components/CommunityPortal/EventPersonalization/__tests__/EventStats.test.jsx b/src/components/CommunityPortal/EventPersonalization/__tests__/EventStats.test.jsx
new file mode 100644
index 0000000000..697c7e70fd
--- /dev/null
+++ b/src/components/CommunityPortal/EventPersonalization/__tests__/EventStats.test.jsx
@@ -0,0 +1,134 @@
+import { render, screen, fireEvent } from '@testing-library/react';
+import { Provider } from 'react-redux';
+import { configureStore } from '@reduxjs/toolkit';
+import PopularEvents from '../EventStats';
+
+// Minimal mock reducer
+const mockThemeReducer = (darkMode = false) => () => ({ darkMode });
+
+const renderWithStore = (darkMode = false) => {
+ const store = configureStore({
+ reducer: {
+ theme: mockThemeReducer(darkMode),
+ },
+ });
+
+ return render(
+
+
+ ,
+ );
+};
+
+describe('PopularEvents Component', () => {
+ // ---------------------------
+ // BASIC RENDER
+ // ---------------------------
+ test('renders header', () => {
+ renderWithStore();
+ expect(screen.getByRole('heading', { name: /Most Popular Event/i })).toBeInTheDocument();
+ });
+
+ test('renders exactly 7 event labels initially', () => {
+ renderWithStore();
+ const labels = screen.getAllByTestId('stat-label');
+ expect(labels.length).toBe(7);
+ });
+
+ // ---------------------------
+ // FILTERS
+ // ---------------------------
+ test('filters events by type (Offline)', () => {
+ renderWithStore();
+ const typeSelect = screen.getAllByRole('combobox')[1];
+
+ fireEvent.change(typeSelect, { target: { value: 'Offline' } });
+
+ const labels = screen.getAllByTestId('stat-label');
+ expect(labels.length).toBe(4);
+ });
+
+ test('filters events by time (Morning)', () => {
+ renderWithStore();
+ const timeSelect = screen.getAllByRole('combobox')[0];
+
+ fireEvent.change(timeSelect, { target: { value: 'Morning' } });
+
+ const labels = screen.getAllByTestId('stat-label');
+ expect(labels.length).toBe(3);
+ });
+
+ test('changing filters multiple times restores all 7 events', () => {
+ renderWithStore();
+ const select = screen.getAllByRole('combobox')[1];
+
+ fireEvent.change(select, { target: { value: 'Offline' } });
+ fireEvent.change(select, { target: { value: 'Online' } });
+ fireEvent.change(select, { target: { value: 'All' } });
+
+ const labels = screen.getAllByTestId('stat-label');
+ expect(labels.length).toBe(7);
+ });
+
+ // ---------------------------
+ // SUMMARY CARDS
+ // ---------------------------
+ test('summary shows correct values', () => {
+ renderWithStore();
+
+ expect(screen.getByText('Total Number of Events')).toBeInTheDocument();
+ expect(screen.getByTestId('summary-total-events')).toHaveTextContent('7');
+
+ expect(screen.getByTestId('summary-total-enrollments')).toHaveTextContent('145');
+
+ expect(screen.getAllByText('Most Popular Event').length).toBe(2);
+ expect(screen.getByTestId('summary-most')).toHaveTextContent('Type of Event 2');
+
+ expect(screen.getAllByText('Least Popular Event').length).toBe(1);
+ expect(screen.getByTestId('summary-least')).toHaveTextContent('Type of Event 7');
+ });
+
+ // ---------------------------
+ // DARK MODE
+ // ---------------------------
+ test('dark mode applies proper class', () => {
+ renderWithStore(true);
+
+ // specifically select ONLY the main header, not the summary box
+ const heading = screen.getByRole('heading', {
+ name: 'Most Popular Event',
+ });
+
+ expect(heading.className.includes('text-light')).toBe(true);
+ });
+
+ // ---------------------------
+ // EMPTY FILTER RESULTS
+ // ---------------------------
+ test('no summary cards when filteredData is empty', () => {
+ renderWithStore();
+
+ const timeSelect = screen.getAllByRole('combobox')[0];
+ fireEvent.change(timeSelect, { target: { value: 'NonExistent' } });
+
+ // Header stays
+ expect(screen.getByRole('heading', { name: 'Most Popular Event' })).toBeInTheDocument();
+
+ // These disappear because filteredData is empty
+ expect(screen.queryByTestId('summary-most')).not.toBeInTheDocument();
+ expect(screen.queryByTestId('summary-least')).not.toBeInTheDocument();
+ });
+
+ // ---------------------------
+ // BAR WIDTH
+ // ---------------------------
+ test('bars have inline width style', () => {
+ renderWithStore();
+
+ const bars = screen.getAllByTestId('stat-bar-inner');
+
+ bars.forEach(inner => {
+ expect(inner.style.width).toMatch(/%/);
+ });
+ });
+});