Skip to content

Commit 1dc5db3

Browse files
Merge branch 'development' into darkmodestylings
2 parents 51295a6 + cd9daaa commit 1dc5db3

34 files changed

Lines changed: 2736 additions & 2150 deletions

package-lock.json

Lines changed: 47 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,7 @@
127127
"tinymce": "^7.2.0",
128128
"util": "^0.12.5",
129129
"uuid": "^9.0.1",
130+
"validator": "^13.15.26",
130131
"webpack": "^5.104.1"
131132
},
132133
"resolutions": {

src/actions/eventActions.js

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,9 @@ import { ENDPOINTS } from '~/utils/URL';
1313
*/
1414
export async function getEvents(params = {}) {
1515
try {
16-
const { type = '', location = '', page = 1, limit = 9, sortBy = 'date' } = params;
16+
const { type = '', location = '', page = 1, limit = 9, sortBy = 'date', userId = '' } = params;
1717
const queryParams = new URLSearchParams();
18+
if (userId) queryParams.append('userId', userId);
1819
if (type) queryParams.append('type', type);
1920
if (location) queryParams.append('location', location);
2021
queryParams.append('page', page);
@@ -68,3 +69,28 @@ export async function getEventLocations() {
6869
};
6970
}
7071
}
72+
73+
export async function joinWaitlist(eventId, userId, token) {
74+
const url = `${ENDPOINTS.EVENTS}/${eventId}/waitlist`;
75+
76+
return axios.post(
77+
url,
78+
{ userId },
79+
{
80+
headers: {
81+
Authorization: token,
82+
},
83+
}
84+
);
85+
}
86+
87+
export async function leaveWaitlist(eventId, userId, token) {
88+
const url = `${ENDPOINTS.EVENTS}/${eventId}/waitlist`;
89+
90+
return axios.delete(url, {
91+
data: { userId },
92+
headers: {
93+
Authorization: token,
94+
},
95+
});
96+
}

src/components/AttendanceSystem/AttendanceNoShowCharts.jsx

Lines changed: 26 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,14 @@
22

33
'use client';
44

5-
import { useState, useEffect } from 'react';
6-
import { useSelector } from 'react-redux';
7-
import axios from 'axios';
5+
import { useState, useMemo } from 'react';
86
import { PieChart, Pie, Cell, Tooltip, Legend, ResponsiveContainer } from 'recharts';
97
import { ENDPOINTS } from '~/utils/URL';
10-
import { events as mockEvents } from './mockData';
8+
import { events } from './mockData';
119
import styles from './AttendanceNoShowCharts.module.css';
10+
import { useSelector } from 'react-redux';
1211

13-
const attendanceColors = ['#0088FE', '#FF8042'];
12+
const attendanceColors = ['#0088FE', '#FF8042', '#FFBB28'];
1413
const noShowColors = ['#00C49F', '#FF0000'];
1514

1615
// Status color mapping
@@ -133,18 +132,21 @@ const renderCustomizedLabel = ({ cx, cy, midAngle, innerRadius, outerRadius, per
133132
<text
134133
x={x}
135134
y={y}
136-
fill="black"
137-
textAnchor={x > cx ? 'start' : 'end'}
135+
fill="white"
136+
textAnchor="middle"
138137
dominantBaseline="central"
139138
fontSize="12"
139+
fontWeight="bold"
140140
>
141-
{`${(percent * 100).toFixed(1)}%`}
141+
{percent > 0 ? `${(percent * 100).toFixed(0)}%` : ''}
142142
</text>
143143
);
144144
};
145145

146146
const CustomTooltip = ({ active, payload }) => {
147+
console.log(active, payload);
147148
if (active && payload && payload.length) {
149+
console.log('Tooltip payload:', payload);
148150
return (
149151
<div className={styles.chartTooltip}>
150152
<p className={styles.chartTooltipItem}>{`${payload[0].name} : ${payload[0].value}`}</p>
@@ -155,76 +157,14 @@ const CustomTooltip = ({ active, payload }) => {
155157
};
156158

157159
function AttendanceNoShowCharts() {
158-
const [events, setEvents] = useState(mockEvents);
159-
const [selectedEvent, setSelectedEvent] = useState(null);
160-
const [loading, setLoading] = useState(true);
160+
const [selectedId, setSelectedId] = useState(events[0].id);
161+
const [loading, setLoading] = useState(false);
161162
const [error, setError] = useState(null);
162163
const darkMode = useSelector(state => state.theme.darkMode);
163-
164-
// Fetch events data from backend
165-
useEffect(() => {
166-
const fetchEvents = async () => {
167-
setLoading(true);
168-
setError(null);
169-
try {
170-
const response = await axios.get(ENDPOINTS.EVENT_ATTENDANCE_STATS);
171-
172-
// Check if response has data in expected format
173-
if (response.data && Array.isArray(response.data)) {
174-
// Transform API data to match mock data format if needed
175-
const transformedEvents = response.data.map(transformEvent);
176-
177-
setEvents(transformedEvents);
178-
if (transformedEvents.length > 0) {
179-
setSelectedEvent(transformedEvents[0]);
180-
}
181-
} else if (response.data && response.data.events && Array.isArray(response.data.events)) {
182-
// Handle nested response structure
183-
const transformedEvents = response.data.events.map(transformEvent);
184-
185-
setEvents(transformedEvents);
186-
if (transformedEvents.length > 0) {
187-
setSelectedEvent(transformedEvents[0]);
188-
}
189-
} else {
190-
// If data format doesn't match, fall back to mock data
191-
throw new Error('Unexpected data format from API');
192-
}
193-
} catch (err) {
194-
// Fall back to mock data if API is unavailable or returns error
195-
// eslint-disable-next-line no-console
196-
console.warn('Failed to fetch events from API, using mock data:', err.message);
197-
// Calculate status for mock events
198-
const mockEventsWithStatus = mockEvents.map(event => ({
199-
...event,
200-
status: calculateEventStatus(event) || event.status,
201-
}));
202-
setEvents(mockEventsWithStatus);
203-
if (mockEventsWithStatus.length > 0) {
204-
setSelectedEvent(mockEventsWithStatus[0]);
205-
}
206-
setError('Using mock data - API endpoint not available');
207-
} finally {
208-
setLoading(false);
209-
}
210-
};
211-
212-
fetchEvents();
213-
}, []);
214-
215-
// Update selectedEvent when events change
216-
useEffect(() => {
217-
if (events.length > 0 && !selectedEvent) {
218-
setSelectedEvent(events[0]);
219-
}
220-
}, [events, selectedEvent]);
164+
const selectedEvent = useMemo(() => events.find(e => e.id === selectedId), [selectedId]);
221165

222166
const handleEventChange = e => {
223-
const selectedEventId = e.target.value;
224-
const newSelectedEvent = events.find(event => event.id === selectedEventId);
225-
if (newSelectedEvent) {
226-
setSelectedEvent(newSelectedEvent);
227-
}
167+
setSelectedId(e.target.value);
228168
};
229169

230170
const calculatePercentage = (value, total) => {
@@ -478,14 +418,19 @@ function AttendanceNoShowCharts() {
478418
)}
479419

480420
{/* No-Show Chart */}
481-
<div className={styles.chartWrapper}>
482-
<h3 className={styles.chartSectionTitle}>
483-
Registration vs Attendance
484-
{currentStatus === 'In Progress' && (
485-
<span className={styles.chartLiveBadge}>(Live)</span>
486-
)}
421+
<div style={{ width: '100%' }}>
422+
<h3
423+
style={{
424+
fontSize: '18px',
425+
fontWeight: '500',
426+
color: '#111827',
427+
marginBottom: '12px',
428+
textAlign: 'center',
429+
}}
430+
>
431+
No-Show Breakdown
487432
</h3>
488-
<div className={styles.chartContainer}>
433+
<div style={{ height: '300px', width: '100%' }}>
489434
<ResponsiveContainer width="100%" height="100%">
490435
<PieChart>
491436
<Pie

src/components/AttendanceSystem/AttendanceNoShowCharts.module.css

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,6 @@
166166
height: 12px;
167167
border-radius: 50%;
168168
}
169-
170169
.statusValue {
171170
font-size: 18px;
172171
font-weight: 600;

src/components/BMDashboard/Issues/IssueHeader.jsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ export function IssueHeader(props) {
9595
</DropdownItem>
9696
</DropdownMenu>
9797
</UncontrolledDropdown>
98-
<Link to="/bmdashboard/projects" style={{ textDecoration: 'none' }}>
98+
<Link to="/bmdashboard" style={{ textDecoration: 'none' }}>
9999
<button className={darkMode ? styles.backButtonDark : styles.backButton} type="button">
100100
Back to Projects
101101
</button>

0 commit comments

Comments
 (0)