diff --git a/src/components/CommunityPortal/Activities/ActivityList.jsx b/src/components/CommunityPortal/Activities/ActivityList.jsx index 4e7f3137b5..41fdf72c57 100644 --- a/src/components/CommunityPortal/Activities/ActivityList.jsx +++ b/src/components/CommunityPortal/Activities/ActivityList.jsx @@ -1,6 +1,6 @@ // Activity List Component import { useState, useEffect, useMemo } from 'react'; -import { useSelector, useStore } from 'react-redux'; +import { useSelector } from 'react-redux'; import { Modal, ModalHeader, ModalBody, ModalFooter, Button } from 'reactstrap'; import styles from './ActivityList.module.css'; // import { useHistory } from 'react-router-dom'; @@ -13,16 +13,22 @@ function ActivityList() { const [error, setError] = useState(null); const [selectedActivity, setSelectedActivity] = useState(null); const [modalOpen, setModalOpen] = useState(false); + const darkMode = useSelector(state => state.theme.darkMode); + const [filter, setFilter] = useState({ type: '', date: '', location: '', - pastEvents: false, }); + const [sortOrder, setSortOrder] = useState('earliest'); const [showPastEvents, setShowPastEvents] = useState(false); + const [currentPage, setCurrentPage] = useState(1); + const itemsPerPage = 10; + + // Dark mode body class useEffect(() => { if (darkMode) { document.body.classList.add('activity-list-dark-body'); @@ -35,18 +41,22 @@ function ActivityList() { }; }, [darkMode]); + // Fetch activities (mock fallback) useEffect(() => { const fetchActivities = async () => { try { setLoading(true); setError(null); + throw new Error('API not implemented yet'); } catch (err) { setError(err.message); + const parsed = mockActivities.map(a => ({ ...a, _dateObj: new Date(`${a.date}T00:00:00`), })); + setActivities(parsed); } finally { setLoading(false); @@ -56,9 +66,14 @@ function ActivityList() { fetchActivities(); }, []); + // Reset pagination on filter/sort change + useEffect(() => { + setCurrentPage(1); + }, [filter, sortOrder, showPastEvents]); + const handleFilterChange = e => { const { name, value } = e.target; - setFilter({ ...filter, [name]: value }); + setFilter(prev => ({ ...prev, [name]: value })); }; const handleSortChange = e => { @@ -70,9 +85,9 @@ function ActivityList() { type: '', date: '', location: '', - showPastEvents: false, }); setShowPastEvents(false); + setCurrentPage(1); }; const handleActivityClick = activity => { @@ -99,9 +114,7 @@ function ActivityList() { } }); - return [...typeOrder.keys()].sort( - (typeA, typeB) => typeOrder.get(typeA) - typeOrder.get(typeB), - ); + return [...typeOrder.keys()].sort((a, b) => typeOrder.get(a) - typeOrder.get(b)); }, [activities]); const filteredActivities = activities @@ -120,6 +133,13 @@ function ActivityList() { return sortOrder === 'earliest' ? dateA - dateB : dateB - dateA; }); + // Pagination + const totalPages = Math.ceil(filteredActivities.length / itemsPerPage); + const safePage = Math.min(currentPage, totalPages || 1); + const startIndex = (safePage - 1) * itemsPerPage; + + const paginatedActivities = filteredActivities.slice(startIndex, startIndex + itemsPerPage); + const hasActivities = paginatedActivities.length > 0; return (

Activity List

+ {/* Filters */}
+ {/* Activity List */}
- {loading ? ( -

Loading activities...

- ) : filteredActivities.length > 0 ? ( + {loading &&

Loading activities...

} + + {!loading && hasActivities && ( - ) : ( + )} + + {!loading && !hasActivities && (

No activities found

)}
- {/* Modal for activity details */} + {/* Pagination */} + {totalPages > 1 && ( +
+ + + {Array.from({ length: totalPages }, (_, i) => i + 1).map(page => ( + + ))} + + +
+ )} + + {/* Modal */} - - {selectedActivity ? selectedActivity.name : ''} - + {selectedActivity?.name} {selectedActivity && (
@@ -264,7 +306,6 @@ function ActivityList() {

Description: {selectedActivity.description}

- {/* Add more details as needed */}
)}
diff --git a/src/components/CommunityPortal/Activities/ActivityList.module.css b/src/components/CommunityPortal/Activities/ActivityList.module.css index e0003a31aa..e9f44282b5 100644 --- a/src/components/CommunityPortal/Activities/ActivityList.module.css +++ b/src/components/CommunityPortal/Activities/ActivityList.module.css @@ -1,4 +1,6 @@ /* stylelint-disable no-descending-specificity */ + +/* Container */ .activityListContainer { padding: 20px; min-height: calc(100vh - 140px); @@ -9,6 +11,7 @@ padding-bottom: 40px; } +/* Heading */ .heading { text-align: center; margin: 20px 0; @@ -17,6 +20,7 @@ font-weight: 600; } +/* Filters */ .filters { display: flex; justify-content: center; @@ -50,6 +54,7 @@ color: #1f2937; } +/* Inputs */ .filters input, .filters select, .darkModeFilters input, @@ -64,6 +69,11 @@ color: #333; } +.filters select { + height: 48px; +} + +/* Dark mode input */ .darkModeInput { background-color: #1e2a3a !important; color: #fff !important; @@ -71,23 +81,14 @@ color-scheme: dark; } -.filters select { - padding: 10px; - height: 48px; - border: 1px solid #d1d5db; - border-radius: 6px; - margin-top: 5px; - font-size: 1rem; - background: #fff; -} - -/* Dark mode date input - style the calendar icon */ .darkModeInput[type="date"]::-webkit-calendar-picker-indicator { filter: invert(1); cursor: pointer; } -.filters input:focus { +/* Focus */ +.filters input:focus, +.filters select:focus { outline: none; border-color: #3b82f6; box-shadow: 0 0 8px rgb(59 130 246 / 30%); @@ -102,10 +103,7 @@ color: #a0a0a0; } -.darkFilters input[type="date"]::-webkit-calendar-picker-indicator { - filter: invert(1); -} - +/* Activity List */ .activityList { max-width: 900px; margin: 0 auto; @@ -120,7 +118,6 @@ box-shadow: none; border: 1px solid #3a4a5c; border-radius: 0; - margin: 0 auto; } .activityList ul { @@ -128,6 +125,7 @@ padding: 0; } +/* Activity Item */ .activityItem { display: flex; flex-direction: column; @@ -137,8 +135,15 @@ border: 1px solid #e5e7eb; border-radius: 8px; background-color: #f9fafb; + transition: transform 0.2s ease, box-shadow 0.2s ease; } +.activityItem:hover { + transform: translateY(-3px); + box-shadow: 0 4px 8px rgb(0 0 0 / 10%); +} + +/* Dark item */ .darkModeItem { background-color: #1e2a3a !important; border: 1px solid #3a4a5c !important; @@ -146,16 +151,12 @@ border-radius: 0; } -.activityList li:hover { - transform: translateY(-3px); - box-shadow: 0 4px 8px rgb(0 0 0 / 10%); -} - .darkModeItem:hover { background-color: #3d4f62 !important; box-shadow: none !important; } +/* Text */ .activityItem strong { color: #1e3a8a; font-size: 1.2rem; @@ -178,6 +179,7 @@ color: #d1d5db !important; } +/* Empty state */ .activityList p { text-align: center; color: #6b7280; @@ -185,7 +187,8 @@ margin: 20px 0; } -.clearButtonWrapper{ +/* Clear Button */ +.clearButtonWrapper { display: flex; justify-content: center; gap: 30px; @@ -214,10 +217,8 @@ .clearFiltersButton:hover:not(:disabled) { transform: scale(1.05); - background-color: #f9fafb; } - .clearFiltersButtonDark { border: 1px solid #fff; background: #0f172a; @@ -228,7 +229,6 @@ background: #111c33; } - /* Suggestions */ .suggestions { position: absolute; @@ -269,6 +269,7 @@ background-color: #334155; } +/* Show Past Toggle */ .showPastToggle { display: inline-flex; align-items: center; @@ -297,24 +298,51 @@ accent-color: #60a5fa; } +/* Focus-visible accessibility */ .showPastToggle input[type="checkbox"]:focus-visible { - outline: none; - border-radius: 4px; + outline: 2px solid #3b82f6; + outline-offset: 2px; +} + +/* Pagination */ +.pagination { + display: flex; + gap: 8px; + justify-content: center; + margin-top: 16px; +} + +.pagination button { + border-radius: 6px; + padding: 6px 12px; +} + +.activePage { + font-weight: bold; + background-color: #2563eb; + color: white; } /* Responsive */ @media (width <= 768px) { - .filters { + .filters, + .darkModeFilters { flex-direction: column; align-items: center; gap: 20px; } - .filters label { + .filters label, + .darkModeFilters label { width: 100%; } .activityList { padding: 20px; } + + .activityItem { + flex-direction: column; + padding: 10px; + } } \ No newline at end of file