Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import { useSelector } from 'react-redux';
import styles from './Participation.module.css';

function AnalyticsNavigation() {
const darkMode = useSelector(state => state.theme.darkMode);

const navigationItems = [
{
title: 'Virtual vs. In-Person Attendance',
description: 'Compare attendance patterns between virtual and in-person events',
icon: '💻',
link: '/communityportal/reports/participation/virtual-vs-inperson',
stats: '65% Virtual, 35% In-Person',
},
{
title: 'Estimated Event Value',
description: 'Calculate and analyze the estimated value of different event types',
icon: '💰',
link: '/communityportal/reports/participation/event-value',
stats: 'Avg Value: $2,400',
},
{
title: 'Participation Trends',
description: 'Track participation trends over time and identify patterns',
icon: '📈',
link: '/communityportal/reports/participation/trends',
stats: '+15% Growth',
},
{
title: 'Event Performance Metrics',
description: 'Detailed performance metrics for individual events',
icon: '📊',
link: '/communityportal/reports/participation/performance',
stats: '24 Active Events',
},
];

return (
<div
className={`${styles.analyticsNavigation} ${darkMode ? styles.analyticsNavigationDark : ''}`}
>
<h2 className={`${styles.sectionTitle} ${darkMode ? styles.sectionTitleDark : ''}`}>
Detailed Analytics
</h2>
<p className={`${styles.sectionSubtitle} ${darkMode ? styles.sectionSubtitleDark : ''}`}>
Explore detailed analytics and insights for event participation
</p>

<div className={styles.navigationGrid}>
{navigationItems.map(item => (
<a
key={item.link}
href={item.link}
className={`${styles.navigationCard} ${darkMode ? styles.navigationCardDark : ''}`}
>
<div className={styles.cardIcon}>{item.icon}</div>
<div className={styles.cardContent}>
<h3 className={styles.cardTitle}>{item.title}</h3>
<p className={styles.cardDescription}>{item.description}</p>
<div className={styles.cardStats}>{item.stats}</div>
</div>
<div className={styles.cardArrow}>→</div>
</a>
))}
</div>
</div>
);
}

export default AnalyticsNavigation;
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
import { useSelector } from 'react-redux';
import styles from './Participation.module.css';

function EngagementBarChart() {
const darkMode = useSelector(state => state.theme.darkMode);

const engagementData = [
{ month: 'Jan', attendance: 35, engagement: 78, events: 6 },
{ month: 'Feb', attendance: 42, engagement: 82, events: 8 },
{ month: 'Mar', attendance: 38, engagement: 75, events: 7 },
{ month: 'Apr', attendance: 45, engagement: 85, events: 9 },
{ month: 'May', attendance: 40, engagement: 80, events: 8 },
{ month: 'Jun', attendance: 48, engagement: 88, events: 10 },
];

const maxAttendance = Math.max(...engagementData.map(item => item.attendance));
const maxEngagement = Math.max(...engagementData.map(item => item.engagement));

return (
<div className={`${styles.barChartSection} ${darkMode ? styles.barChartSectionDark : ''}`}>
<h3 className={`${styles.chartTitle} ${darkMode ? styles.chartTitleDark : ''}`}>
Monthly Engagement Trends
</h3>

<div className={styles.barChartContainer}>
<div className={styles.chartArea}>
<div className={styles.yAxis}>
<div className={styles.yAxisValues}>
{[0, 20, 40, 60].map(value => (
<div key={value} className={styles.yAxisValue}>
{value}
</div>
))}
</div>
<div className={styles.yAxisLabel}>Attendance</div>
</div>

<div className={styles.barsContainer}>
{engagementData.map((item, index) => (
<div key={item.month} className={styles.barGroup}>
<div className={styles.barWrapper}>
<div
className={`${styles.bar} ${styles.attendanceBar}`}
style={{
height: `${(item.attendance / maxAttendance) * 100}%`,
backgroundColor: darkMode ? '#4CAF50' : '#2196F3',
}}
/>
<div
className={`${styles.bar} ${styles.engagementBar}`}
style={{
height: `${(item.engagement / maxEngagement) * 100}%`,
backgroundColor: darkMode ? '#FF9800' : '#4CAF50',
}}
/>
</div>
<div className={styles.barLabel}>{item.month}</div>
<div className={styles.barValues}>
<div className={styles.barValue}>{item.attendance}</div>
<div className={styles.barValue}>{item.engagement}%</div>
</div>
</div>
))}
</div>
</div>

<div className={styles.chartLegend}>
<div className={styles.legendItem}>
<div
className={styles.legendColor}
style={{ backgroundColor: darkMode ? '#4CAF50' : '#2196F3' }}
/>
<span className={styles.legendLabel}>Average Attendance</span>
</div>
<div className={styles.legendItem}>
<div
className={styles.legendColor}
style={{ backgroundColor: darkMode ? '#FF9800' : '#4CAF50' }}
/>
<span className={styles.legendLabel}>Engagement Rate (%)</span>
</div>
</div>
</div>

<div className={styles.chartInsights}>
<div className={styles.insightItem}>
<span className={styles.insightLabel}>Peak Month:</span>
<span className={styles.insightValue}>June (48 avg attendance)</span>
</div>
<div className={styles.insightItem}>
<span className={styles.insightLabel}>Growth Trend:</span>
<span className={styles.insightValue}>+37% from Jan to Jun</span>
</div>
</div>
</div>
);
}

export default EngagementBarChart;
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import { useSelector } from 'react-redux';
import styles from './Participation.module.css';

function EngagementSummaryCards() {
const darkMode = useSelector(state => state.theme.darkMode);

const engagementData = {
averageAttendance: 35,
highestRatedEvent: {
name: 'Yoga Class',
rating: 4.8,
participants: 45,
},
mostPopularEvent: {
name: 'Fitness Bootcamp',
attendance: 55,
growth: '+12%',
},
engagementRate: 78,
};

return (
<div className={`${styles.engagementSection} ${darkMode ? styles.engagementSectionDark : ''}`}>
<h2 className={`${styles.sectionTitle} ${darkMode ? styles.sectionTitleDark : ''}`}>
Engagement Summary
</h2>

<div className={styles.engagementCards}>
<div className={`${styles.engagementCard} ${darkMode ? styles.engagementCardDark : ''}`}>
<div className={styles.cardIcon}>📊</div>
<div className={styles.cardContent}>
<div className={styles.cardValue}>{engagementData.averageAttendance}</div>
<div className={styles.cardLabel}>Average Attendance</div>
<div className={styles.cardSubtext}>Across all events</div>
</div>
</div>

<div className={`${styles.engagementCard} ${darkMode ? styles.engagementCardDark : ''}`}>
<div className={styles.cardIcon}>⭐</div>
<div className={styles.cardContent}>
<div className={styles.cardValue}>{engagementData.highestRatedEvent.rating}</div>
<div className={styles.cardLabel}>Highest Rated Event</div>
<div className={styles.cardSubtext}>{engagementData.highestRatedEvent.name}</div>
</div>
</div>

<div className={`${styles.engagementCard} ${darkMode ? styles.engagementCardDark : ''}`}>
<div className={styles.cardIcon}>🔥</div>
<div className={styles.cardContent}>
<div className={styles.cardValue}>{engagementData.mostPopularEvent.attendance}</div>
<div className={styles.cardLabel}>Most Popular Event</div>
<div className={styles.cardSubtext}>
{engagementData.mostPopularEvent.name} {engagementData.mostPopularEvent.growth}
</div>
</div>
</div>

<div className={`${styles.engagementCard} ${darkMode ? styles.engagementCardDark : ''}`}>
<div className={styles.cardIcon}>📈</div>
<div className={styles.cardContent}>
<div className={styles.cardValue}>{engagementData.engagementRate}%</div>
<div className={styles.cardLabel}>Overall Engagement</div>
<div className={styles.cardSubtext}>Event participation rate</div>
</div>
</div>
</div>
</div>
);
}

export default EngagementSummaryCards;
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
/* eslint-disable testing-library/no-node-access */
import { useSelector } from 'react-redux';
import { useRef, useState, useCallback } from 'react';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faFilePdf } from '@fortawesome/free-solid-svg-icons';
import { useRef } from 'react';
import EventParticipationHeader from './EventParticipationHeader';
import EngagementSummaryCards from './EngagementSummaryCards';
import EventTypePieChart from './EventTypePieChart';
import EngagementBarChart from './EngagementBarChart';
import AnalyticsNavigation from './AnalyticsNavigation';
import MyCases from './MyCases';
import DropOffTracking from './DropOffTracking';
import NoShowInsights from './NoShowInsights';
Expand All @@ -11,36 +14,6 @@ import styles from './Participation.module.css';
function EventParticipation() {
const darkMode = useSelector(state => state.theme.darkMode);
const exportRef = useRef(null);
const [exporting, setExporting] = useState(false);
const [selectedOrganizer, setSelectedOrganizer] = useState('All Organizers');

const handleSaveAsPDF = useCallback(() => {
if (globalThis.window === undefined || globalThis.document === undefined) return;
if (exporting) return;
setExporting(true);

document.documentElement.dataset.exporting = 'true';

// Expand "More" so all visible items are included
const moreBtn = document.querySelector('.more-btn-global');
const toggled = moreBtn?.textContent?.toLowerCase().includes('more') ?? false;
if (toggled) moreBtn.click();

const prevTitle = document.title;
document.title = 'event_participation';

setTimeout(() => {
globalThis.print();

setTimeout(() => {
if (toggled) moreBtn.click();

delete document.documentElement.dataset.exporting;
document.title = prevTitle;
setExporting(false);
}, 100);
}, 500);
}, [exporting]);

return (
<div
Expand All @@ -49,54 +22,21 @@ function EventParticipation() {
darkMode ? styles.participationLandingPageDark : ''
}`}
>
{/* Print-only page title header */}
<header
className={`${styles.landingPageHeaderContainer} ${styles.avoidBreak} ${styles.noPrintGap}`}
>
<h1
className={`${styles.landingPageHeader} ${darkMode ? styles.landingPageHeaderDark : ''}`}
>
Social And Recreational Management
</h1>
<div className={styles.headerActions}>
<button
className={`${styles.savePdfBtn} ${
darkMode ? styles.savePdfBtnDark : styles.savePdfBtnLight
} ${styles.noPrint}`}
onClick={handleSaveAsPDF}
disabled={exporting}
aria-busy={exporting}
>
{exporting ? (
'Preparing…'
) : (
<>
<FontAwesomeIcon icon={faFilePdf} style={{ marginRight: '6px' }} />
Save as PDF
</>
)}
</button>

<select
className={`${styles.organizerDropdown} ${
darkMode ? styles.organizerDropdownDark : ''
}`}
value={selectedOrganizer}
onChange={e => setSelectedOrganizer(e.target.value)}
>
<option value="All Organizers">All Organizers</option>
<option value="Organizer 1">Organizer 1</option>
<option value="Organizer 2">Organizer 2</option>
<option value="Organizer 3">Organizer 3</option>
</select>
<EventParticipationHeader />
<EngagementSummaryCards />
<div className={styles.chartsSection}>
<div className={styles.chartsRow}>
<EventTypePieChart />
<EngagementBarChart />
</div>
</header>
</div>

<MyCases />
<div className={`${styles.analyticsSection}`}>
<DropOffTracking />
<NoShowInsights />
</div>
<AnalyticsNavigation />

{/* Print-only footer note */}
</div>
Expand Down
Loading
Loading