Skip to content

Commit b2299ca

Browse files
committed
Improve error handling and fix edge cases for Activity Agenda
- Enhanced error handling with specific messages for different error types (404, network, server, permission errors) - Added validation for activity ID (empty string check) - Improved date/time formatting with NaN validation to prevent invalid date displays - Enhanced schedule building with null/undefined resource filtering - Added type checking for numeric values (maxAttendees, currentAttendees) - Improved fallback API call error handling with network error detection - Better event data validation (object type check) - Enhanced error messages for better user experience - Fixed date display logic to handle null dates properly - Added array validation for schedule and resources data
1 parent b6e7af3 commit b2299ca

1 file changed

Lines changed: 89 additions & 28 deletions

File tree

src/components/CommunityPortal/Activities/ActivityAgenda.jsx

Lines changed: 89 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -16,37 +16,72 @@ function ActivityAgenda() {
1616

1717
// Fetch event data by ID
1818
useEffect(() => {
19-
if (!activityid) {
19+
if (!activityid || activityid.trim() === '') {
2020
setError('Activity ID is missing');
2121
setLoading(false);
2222
return;
2323
}
24+
2425
const fetchEventData = async () => {
2526
setLoading(true);
2627
setError(null);
2728
setImageError(false);
2829
try {
2930
// Try to fetch event by ID first
3031
let event = null;
32+
3133
try {
3234
const response = await axios.get(ENDPOINTS.EVENT_BY_ID(activityid));
33-
event = response.data;
35+
if (response.data) {
36+
event = response.data;
37+
}
3438
} catch (idError) {
35-
// If endpoint doesn't exist, fetch all events and filter by ID
36-
const response = await axios.get(ENDPOINTS.EVENTS);
37-
const events = response.data.events || [];
38-
event = events.find(e => e._id === activityid || e.id === activityid);
39+
// Check if it's a 404 or network error
40+
if (idError.response && idError.response.status === 404) {
41+
// Event not found at this endpoint, try fallback
42+
} else if (idError.code === 'ECONNREFUSED' || idError.message.includes('Network Error')) {
43+
throw new Error('Unable to connect to server. Please check your internet connection.');
44+
}
3945
}
4046

47+
// If endpoint doesn't exist or returned 404, fetch all events and filter by ID
4148
if (!event) {
42-
throw new Error('Event not found');
49+
try {
50+
const response = await axios.get(ENDPOINTS.EVENTS);
51+
const events = response.data?.events || [];
52+
event = events.find(
53+
e =>
54+
e._id === activityid || e.id === activityid || String(e._id) === String(activityid),
55+
);
56+
} catch (fallbackError) {
57+
if (
58+
fallbackError.code === 'ECONNREFUSED' ||
59+
fallbackError.message.includes('Network Error')
60+
) {
61+
throw new Error(
62+
'Unable to connect to server. Please check your internet connection.',
63+
);
64+
}
65+
throw new Error('Failed to fetch events. Please try again later.');
66+
}
67+
}
68+
69+
if (!event || typeof event !== 'object') {
70+
throw new Error(
71+
`Event with ID "${activityid}" not found. Please verify the activity ID.`,
72+
);
4373
}
4474

45-
// Format date and time helper functions
75+
// Format date and time helper functions with validation
4676
const formatTime = timeString => {
4777
if (!timeString) return 'TBD';
4878
try {
49-
return new Date(timeString).toLocaleTimeString('en-US', {
79+
const date = new Date(timeString);
80+
// Check if date is valid
81+
if (isNaN(date.getTime())) {
82+
return timeString;
83+
}
84+
return date.toLocaleTimeString('en-US', {
5085
hour: '2-digit',
5186
minute: '2-digit',
5287
});
@@ -56,57 +91,83 @@ function ActivityAgenda() {
5691
};
5792

5893
const formatDate = dateString => {
59-
if (!dateString) return 'TBD';
94+
if (!dateString) return null;
6095
try {
61-
return new Date(dateString).toLocaleDateString('en-US', {
96+
const date = new Date(dateString);
97+
// Check if date is valid
98+
if (isNaN(date.getTime())) {
99+
return null;
100+
}
101+
return date.toLocaleDateString('en-US', {
62102
weekday: 'long',
63103
year: 'numeric',
64104
month: 'long',
65105
day: 'numeric',
66106
});
67107
} catch {
68-
return dateString;
108+
return null;
69109
}
70110
};
71111

72112
// Build schedule from resources or use event time
73113
let schedule = [];
74-
if (event.resources && event.resources.length > 0) {
75-
schedule = event.resources.map((resource, index) => ({
76-
time:
77-
event.startTime && event.endTime
78-
? `${formatTime(event.startTime)} to ${formatTime(event.endTime)}`
79-
: `Session ${index + 1}`,
80-
activity: resource.name || 'Activity',
81-
resourceLocation: resource.location || event.location,
82-
}));
114+
if (event.resources && Array.isArray(event.resources) && event.resources.length > 0) {
115+
schedule = event.resources
116+
.filter(resource => resource != null) // Filter out null/undefined resources
117+
.map((resource, index) => ({
118+
time:
119+
event.startTime && event.endTime
120+
? `${formatTime(event.startTime)} to ${formatTime(event.endTime)}`
121+
: `Session ${index + 1}`,
122+
activity: resource?.name || 'Activity',
123+
resourceLocation: resource?.location || event.location || 'Not specified',
124+
}));
83125
} else if (event.startTime && event.endTime) {
84126
schedule = [
85127
{
86128
time: `${formatTime(event.startTime)} to ${formatTime(event.endTime)}`,
87129
activity: event.type || 'Event',
88-
resourceLocation: event.location,
130+
resourceLocation: event.location || 'Not specified',
89131
},
90132
];
91133
}
92134

93-
// Transform event data to match component structure
135+
// Transform event data to match component structure with validation
94136
const transformedData = {
95137
activityName: event.title || 'Untitled Event',
96138
description: event.description || 'No description available.',
97-
schedule,
139+
schedule: Array.isArray(schedule) ? schedule : [],
98140
image: event.coverImage || ActivityImg,
99141
date: formatDate(event.date),
100142
location: event.location || 'Not specified',
101143
type: event.type || 'Event',
102144
status: event.status || 'New',
103-
maxAttendees: event.maxAttendees || 0,
104-
currentAttendees: event.currentAttendees || 0,
145+
maxAttendees: typeof event.maxAttendees === 'number' ? event.maxAttendees : 0,
146+
currentAttendees: typeof event.currentAttendees === 'number' ? event.currentAttendees : 0,
105147
};
106148

107149
setEventData(transformedData);
108150
} catch (err) {
109-
setError(err.message || 'Failed to fetch event data');
151+
// Provide more specific error messages
152+
let errorMessage = 'Failed to fetch event data';
153+
if (err.message) {
154+
errorMessage = err.message;
155+
} else if (err.response) {
156+
// Handle HTTP errors
157+
if (err.response.status === 404) {
158+
errorMessage = `Event with ID "${activityid}" not found.`;
159+
} else if (err.response.status >= 500) {
160+
errorMessage = 'Server error. Please try again later.';
161+
} else if (err.response.status === 401 || err.response.status === 403) {
162+
errorMessage = 'You do not have permission to view this event.';
163+
} else {
164+
errorMessage = `Error ${err.response.status}: ${err.response.statusText ||
165+
'Request failed'}`;
166+
}
167+
} else if (err.request) {
168+
errorMessage = 'No response from server. Please check your connection.';
169+
}
170+
setError(errorMessage);
110171
} finally {
111172
setLoading(false);
112173
}
@@ -194,7 +255,7 @@ function ActivityAgenda() {
194255
borderBottom: darkMode ? '1px solid rgba(255, 255, 255, 0.2)' : '1px solid #e0e0e0',
195256
}}
196257
>
197-
{eventData.date && (
258+
{eventData.date && eventData.date !== 'TBD' && (
198259
<p style={{ marginBottom: '8px' }}>
199260
<strong>Date:</strong> {eventData.date}
200261
</p>

0 commit comments

Comments
 (0)