Skip to content

Commit 8619d6c

Browse files
Merge pull request #4692 from OneCommunityGlobal/akshith-event-pop-improve
Akshith - Improve Data Clarity & Interpretation in the Event Popularity Page
2 parents c2b64b7 + fc15608 commit 8619d6c

2 files changed

Lines changed: 553 additions & 130 deletions

File tree

src/components/EventPopularity/EventPopularity.jsx

Lines changed: 230 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -1,155 +1,304 @@
11
'use client';
22

3+
import { useState } from 'react';
4+
import { useSelector } from 'react-redux';
35
import {
46
Bar,
57
BarChart,
68
CartesianGrid,
9+
Legend,
710
ResponsiveContainer,
11+
Tooltip,
812
XAxis,
913
YAxis,
10-
Tooltip,
11-
Legend,
1214
} from 'recharts';
15+
import PropTypes from 'prop-types';
1316
import styles from './EventPopularity.module.css';
14-
import { useSelector } from 'react-redux';
1517

16-
// Sample data
1718
const eventTypeData = [
18-
{ name: 'Event Type 1', registered: 75 },
19-
{ name: 'Event Type 2', registered: 60 },
20-
{ name: 'Event Type 3', registered: 55 },
21-
{ name: 'Event Type 4', registered: 50 },
22-
{ name: 'Event Type 5', registered: 45 },
23-
{ name: 'Event Type 6', registered: 40 },
19+
{ name: 'Community Volunteer Day', registered: 75 },
20+
{ name: 'Skill Development Workshop', registered: 60 },
21+
{ name: 'Networking Mixer', registered: 55 },
22+
{ name: 'Environmental Cleanup', registered: 50 },
23+
{ name: 'Youth Membership Program', registered: 45 },
24+
{ name: 'Cultural Exchange Event', registered: 40 },
2425
];
2526

2627
const timeData = [
27-
{ time: '9:00', registered: 8, attended: 12 },
28-
{ time: '11:00', registered: 15, attended: 18 },
29-
{ time: '13:00', registered: 20, attended: 25 },
30-
{ time: '15:00', registered: 25, attended: 30 },
31-
{ time: '17:00', registered: 18, attended: 20 },
32-
{ time: '19:00', registered: 10, attended: 15 },
33-
{ time: '21:00', registered: 5, attended: 8 },
28+
{ time: '9:00 AM', registered: 8, attended: 12 },
29+
{ time: '11:00 AM', registered: 15, attended: 18 },
30+
{ time: '1:00 PM', registered: 20, attended: 25 },
31+
{ time: '3:00 PM', registered: 25, attended: 30 },
32+
{ time: '5:00 PM', registered: 18, attended: 20 },
33+
{ time: '7:00 PM', registered: 10, attended: 15 },
34+
{ time: '9:00 PM', registered: 5, attended: 8 },
3435
];
3536

3637
const participationCards = [
3738
{
38-
title: '5+',
39-
subtitle: 'Repeated participation',
39+
title: '5+ Events',
40+
subtitle: 'Highly Engaged Members',
41+
description: 'Users who attended 5 or more events',
4042
trend: '-10%',
4143
trendType: 'negative',
4244
participants: 3,
4345
},
4446
{
45-
title: '2+',
46-
subtitle: 'Repeated participation',
47+
title: '2-4 Events',
48+
subtitle: 'Regular Participants',
49+
description: 'Users who attended 2 to 4 events',
4750
trend: '+25%',
4851
trendType: 'positive',
4952
participants: 3,
5053
},
5154
{
52-
title: '<1',
53-
subtitle: 'Repeated participation',
55+
title: '1 Event',
56+
subtitle: 'New/One-Time Attendees',
57+
description: 'First-time or one-time participants',
5458
trend: '-5%',
5559
trendType: 'negative',
5660
participants: 3,
5761
},
5862
{
59-
title: '420',
60-
subtitle: 'Total Members',
63+
title: '420 Users',
64+
subtitle: 'Total Active Members',
65+
description: 'Total users with at least one event attendance',
6166
trend: '+20%',
6267
trendType: 'positive',
6368
},
6469
];
6570

71+
const CustomTooltip = ({ active, payload, label }) => {
72+
if (!active || !payload?.length) {
73+
return null;
74+
}
75+
76+
return (
77+
<div className={styles.tooltipBox}>
78+
<div className={styles.tooltipTitle}>{label}</div>
79+
80+
{payload.map(item => (
81+
<div key={item.dataKey} className={styles.tooltipRow}>
82+
<span>{item.name}: </span>
83+
<strong>{item.value} users</strong>
84+
</div>
85+
))}
86+
</div>
87+
);
88+
};
89+
90+
CustomTooltip.propTypes = {
91+
active: PropTypes.bool,
92+
payload: PropTypes.arrayOf(
93+
PropTypes.shape({
94+
dataKey: PropTypes.string,
95+
name: PropTypes.string,
96+
value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
97+
}),
98+
),
99+
label: PropTypes.string,
100+
};
101+
102+
const InfoTooltip = ({ text, children }) => {
103+
const [showTooltip, setShowTooltip] = useState(false);
104+
105+
return (
106+
<button
107+
type="button"
108+
className={styles.infotooltipHover}
109+
onMouseEnter={() => setShowTooltip(true)}
110+
onMouseLeave={() => setShowTooltip(false)}
111+
onFocus={() => setShowTooltip(true)}
112+
onBlur={() => setShowTooltip(false)}
113+
>
114+
{children}
115+
116+
{showTooltip && <div className={styles.infotooltipheading}>{text}</div>}
117+
</button>
118+
);
119+
};
120+
121+
InfoTooltip.propTypes = {
122+
text: PropTypes.string.isRequired,
123+
children: PropTypes.node.isRequired,
124+
};
125+
66126
export default function EventDashboard() {
67127
const darkMode = useSelector(state => state.theme?.darkMode);
68128

129+
const currentDate = new Date();
130+
131+
const thirtyDaysAgo = new Date(currentDate.getTime() - 30 * 24 * 60 * 60 * 1000);
132+
133+
const dateRangeLabel = `${thirtyDaysAgo.toLocaleDateString()} - ${currentDate.toLocaleDateString()}`;
134+
69135
return (
70-
<div className={`${styles.eventpopularity} ${darkMode ? styles.dark : ''}`}>
71-
<h1 className={styles.epheader}>Event Attendance Trend</h1>
136+
<div className={`${styles.dashboardContainer} ${darkMode ? styles.dark : ''}`}>
137+
<div className={styles.headerSection}>
138+
<h1 className={styles.pageTitle}>Event Attendance Dashboard</h1>
139+
140+
<div className={styles.timePeriod}>
141+
<strong>Time Period:</strong> Last 30 days ({dateRangeLabel})
142+
</div>
72143

73-
<div className={styles.epgrid}>
74-
{/* Event Registration Trend (Type) */}
75-
<div className={styles.epCard}>
76-
<h2>Event Registration Trend (Type)</h2>
144+
<div className={styles.subHeader}>
145+
All metrics below reflect data from the selected time period
146+
</div>
147+
</div>
77148

78-
<div>
79-
<div className={styles.epRowLabel}>
149+
<div className={styles.dashboardGrid}>
150+
{/* Registration by Type */}
151+
<div className={styles.chartCard}>
152+
<div className={styles.cardHeader}>
153+
<h2 className={styles.cardTitle}>Event Registration by Type</h2>
154+
155+
<InfoTooltip text="Total users who registered for each event type">
156+
<span className={styles.infoIcon}>?</span>
157+
</InfoTooltip>
158+
</div>
159+
160+
<div className={styles.eventList}>
161+
<div className={styles.tableHeader}>
80162
<span>Event Name</span>
81-
<span>Registered Members</span>
163+
<span>Registered Users</span>
82164
</div>
83165

84166
{eventTypeData.map(event => (
85-
<div key={event.name} className={styles.epRowLabel}>
86-
<span className={styles.epEventName}>{event.name}</span>
167+
<div key={event.name} className={styles.eventRow}>
168+
<span className={styles.eventName}>{event.name}</span>
87169

88-
<div className={styles.epProgressBar}>
170+
<div className={styles.progressBarBackground}>
89171
<div
90-
className={styles.epProgressFill}
91-
style={{ width: `${(event.registered / 75) * 100}%` }}
172+
className={styles.progressBarFill}
173+
style={{
174+
width: `${(event.registered / 75) * 100}%`,
175+
}}
92176
/>
93177
</div>
94178

95-
<span>{event.registered}</span>
179+
<span className={styles.eventCount}>{event.registered} users</span>
96180
</div>
97181
))}
98182
</div>
99183

100-
<div className={styles.epStatsGrid}>
101-
<div className={styles.epStatCard}>
102-
<h3 style={{ color: 'var(--ep-primary)' }}>325</h3>
103-
<p className={styles.epStatSubtitle}>Total Registered Members</p>
104-
</div>
184+
<div className={styles.statsGrid}>
185+
{[
186+
{
187+
title: '325 Users',
188+
subtitle: 'Total Registrations',
189+
isPrimary: true,
190+
},
191+
{
192+
title: 'Community Volunteer Day',
193+
subtitle: 'Most Popular',
194+
},
195+
{
196+
title: 'Cultural Exchange Event',
197+
subtitle: 'Least Popular',
198+
},
199+
].map(card => (
200+
<div key={card.title} className={styles.statCard}>
201+
<h3 className={card.isPrimary ? styles.primaryStatTitle : styles.statTitle}>
202+
{card.title}
203+
</h3>
105204

106-
<div className={styles.epStatCard}>
107-
<h3>Event Type 1</h3>
108-
<p className={styles.epStatSubtitle}>Most Popular Event Type</p>
109-
</div>
110-
111-
<div className={styles.epStatCard}>
112-
<h3>Event Type 6</h3>
113-
<p className={styles.epStatSubtitle}>Least Popular Event Type</p>
114-
</div>
205+
<p className={styles.statSubtitle}>{card.subtitle}</p>
206+
</div>
207+
))}
115208
</div>
116209
</div>
117210

118-
{/* Event Registration Trend (Time) */}
119-
<div className={styles.epChartCard}>
120-
<h2>Event Registration Trend (Time)</h2>
121-
122-
<ResponsiveContainer width="100%" height={200}>
123-
<BarChart data={timeData}>
124-
<CartesianGrid stroke="var(--ep-grid-stroke)" strokeDasharray="3 3" />
125-
<XAxis dataKey="time" stroke="var(--ep-chart-tick)" />
126-
<YAxis stroke="var(--ep-chart-tick)" />
127-
<Tooltip
128-
contentStyle={{
129-
background: 'var(--ep-card-bg)',
130-
color: 'var(--ep-text-color)',
211+
{/* Attendance by Time */}
212+
<div className={styles.chartCard}>
213+
<div className={styles.cardHeader}>
214+
<h2 className={styles.cardTitle}>Event Attendance by Time Slot</h2>
215+
216+
<InfoTooltip text="Registered = sign-ups | Attended = actual participants">
217+
<span className={styles.infoIcon}>?</span>
218+
</InfoTooltip>
219+
</div>
220+
221+
<div className={styles.chartWrapper}>
222+
<ResponsiveContainer width="100%" height={250}>
223+
<BarChart
224+
data={timeData}
225+
margin={{
226+
top: 20,
227+
right: 20,
228+
left: 80,
229+
bottom: 40,
131230
}}
132-
/>
133-
<Legend />
134-
<Bar dataKey="registered" fill="var(--ep-primary)" />
135-
<Bar dataKey="attended" fill="var(--ep-primary-2)" />
136-
</BarChart>
137-
</ResponsiveContainer>
138-
139-
<div className={styles.epParticipationGrid}>
231+
>
232+
<CartesianGrid strokeDasharray="3 3" stroke="var(--ep-grid-stroke, #d1d5db)" />
233+
234+
<XAxis
235+
dataKey="time"
236+
interval={0}
237+
angle={-35}
238+
textAnchor="end"
239+
height={60}
240+
stroke="var(--ep-chart-tick, #64748b)"
241+
/>
242+
243+
<YAxis
244+
width={80}
245+
tick={{ fontSize: 12 }}
246+
stroke="var(--ep-chart-tick, #64748b)"
247+
label={{
248+
value: 'Number of Users',
249+
angle: -90,
250+
position: 'insideLeft',
251+
dx: -25,
252+
style: {
253+
textAnchor: 'middle',
254+
fill: 'var(--ep-chart-tick, #64748b)',
255+
fontSize: 12,
256+
},
257+
}}
258+
/>
259+
260+
<Tooltip content={<CustomTooltip />} />
261+
262+
<Legend
263+
wrapperStyle={{
264+
paddingTop: '20px',
265+
}}
266+
/>
267+
268+
<Bar
269+
dataKey="registered"
270+
name="Registered Users"
271+
fill="var(--ep-primary, #4A90E2)"
272+
/>
273+
274+
<Bar dataKey="attended" name="Attended Users" fill="var(--ep-primary-2, #82B7FF)" />
275+
</BarChart>
276+
</ResponsiveContainer>
277+
</div>
278+
279+
<div className={styles.participationGrid}>
140280
{participationCards.map(card => (
141-
<div key={card.title} className={styles.epParticipationCard}>
142-
<h3>{card.title}</h3>
143-
<p className={styles.epStatSubtitle}>{card.subtitle}</p>
281+
<div key={card.title} className={styles.participationCard}>
282+
<div className={styles.participationHeader}>
283+
<h3 className={styles.participationTitle}>{card.title}</h3>
284+
285+
<InfoTooltip text={card.description}>
286+
<span className={styles.smallInfoIcon}>?</span>
287+
</InfoTooltip>
288+
</div>
289+
290+
<p className={styles.participationSubtitle}>{card.subtitle}</p>
144291

145-
{!!card.participants && <div> +{card.participants}</div>}
292+
{Boolean(card.participants) && (
293+
<div className={styles.participantCount}>👥 {card.participants} users</div>
294+
)}
146295

147296
<p
148297
className={
149-
card.trendType === 'positive' ? styles.trendPositive : styles.trendNegative
298+
card.trendType === 'positive' ? styles.positiveTrend : styles.negativeTrend
150299
}
151300
>
152-
{card.trend} Monthly
301+
{card.trend} vs last month
153302
</p>
154303
</div>
155304
))}

0 commit comments

Comments
 (0)