-
-
-
- Events
-
-
Upcoming career days, workshops, and networking events
+ let allEvents = [];
+ let filteredEvents = [];
+ let currentFilters = {
+ type: 'all',
+ dateRange: 'all'
+ };
+
+ function renderEventsGrid() {
+ const eventsGrid = document.getElementById('eventsGrid');
+ if (!eventsGrid) return;
+
+ if (filteredEvents.length === 0) {
+ eventsGrid.innerHTML = `
+
+
+
No events found
+
Try adjusting your filters or check back later for new events.
+
+ `;
+ return;
+ }
+
+ eventsGrid.innerHTML = filteredEvents.map(event => `
+
+
+
+
+ ${getEventTypeLabel(event.type)}
+
+
+
${event.title}
+
${event.description}
+
+
+
+ ${formatDate(event.date)} at ${event.time}
+
+
+
+ ${event.isOnline ? 'Online Event' : event.location}
+
+
+
+ ${event.registeredCount || 0} / ${event.maxParticipants || '∞'} registered
+
+
+
+
+ `).join('');
+
+ document.querySelectorAll('.view-event-btn').forEach(btn => {
+ if (!btn.disabled) {
+ btn.addEventListener('click', () => {
+ const event = allEvents.find(e => e.id === btn.dataset.eventId);
+ if (event) showEventDetails(event);
+ });
+ }
+ });
+ }
+
+ function showEventDetails(event) {
+ const modalHtml = `
+
+
+
+
${event.title}
+
+
+
+
+
+ ${formatDate(event.date)} at ${event.time}
+
+
+
+ ${event.isOnline ? 'Online Event' : event.location}
+
+
+
+ ${event.registeredCount || 0} / ${event.maxParticipants || 'Unlimited'} participants
+
+
+
About this event
+
${event.description}
+
+
+
+
+
+
+
+
+ `;
+
+ document.body.insertAdjacentHTML('beforeend', modalHtml);
+
+ const modal = document.getElementById('eventModal');
+ const closeModal = () => modal.remove();
+
+ document.getElementById('closeModalBtn')?.addEventListener('click', closeModal);
+ document.getElementById('closeModalBtn2')?.addEventListener('click', closeModal);
+ document.getElementById('registerFromModalBtn')?.addEventListener('click', async () => {
+ await handleRegistration(event.id);
+ closeModal();
+ });
+ modal.addEventListener('click', (e) => { if (e.target === modal) closeModal(); });
+ }
+
+ async function handleRegistration(eventId) {
+ try {
+ const result = await mockDataService.registerForEvent(eventId, user.id);
+
+ if (result.success) {
+ const event = allEvents.find(e => e.id === eventId);
+ if (event) event.registeredCount = (event.registeredCount || 0) + 1;
+ showToast('Successfully registered for the event!', 'success');
+ applyFiltersAndRender();
+ } else if (result.reason === 'event_full') {
+ showToast('Sorry, this event is full!', 'error');
+ }
+ } catch (error) {
+ console.error('Registration failed:', error);
+ showToast('Failed to register for event. Please try again.', 'error');
+ }
+ }
+
+ function applyFiltersAndRender() {
+ let filtered = [...allEvents];
+ if (currentFilters.type !== 'all') {
+ filtered = filtered.filter(event => event.type === currentFilters.type);
+ }
+ filtered = filterEventsByDate(filtered, currentFilters.dateRange);
+ filteredEvents = filtered;
+ renderEventsGrid();
+ }
+
+ function handleFilterChange(filterType, filterValue) {
+ currentFilters[filterType] = filterValue;
+ updateFilterButtonStyles(filterType, filterValue);
+ applyFiltersAndRender();
+ }
+
+ try {
+ app.innerHTML = `
+ ${renderAppHeader(user, window.location.pathname)}
+
+ `;
+
+ allEvents = await mockDataService.getEvents();
+ filteredEvents = [...allEvents];
+
+ const headerContainer = document.getElementById('eventsHeader');
+ const filtersContainer = document.getElementById('filtersContainer');
+
+ if (headerContainer) headerContainer.innerHTML = renderEventsHeader(allEvents);
+ if (filtersContainer) filtersContainer.innerHTML = renderEventsFilters(currentFilters, handleFilterChange);
+
+ renderEventsGrid();
+ attachFilterListeners(handleFilterChange);
+
+ } catch (error) {
+ console.error('Failed to load events:', error);
+ app.innerHTML = `
+ ${renderAppHeader(user, window.location.pathname)}
+
+
-
-
TODO: Events listing
-
Implement events grid, filters, and registration flow.
+
+
Failed to load events
+
Please try again later.
-
- `;
+ `;
+ }
const logoutBtn = document.getElementById('logoutBtn');
if (logoutBtn) logoutBtn.addEventListener('click', () => authService.logout());
diff --git a/assets/js/utils/eventHelpers.js b/assets/js/utils/eventHelpers.js
new file mode 100644
index 0000000..b78616a
--- /dev/null
+++ b/assets/js/utils/eventHelpers.js
@@ -0,0 +1,77 @@
+/**
+ * Event Helper Functions
+ */
+
+export function formatDate(dateString) {
+ const options = { year: 'numeric', month: 'long', day: 'numeric' };
+ return new Date(dateString).toLocaleDateString('en-US', options);
+}
+
+export function getEventTypeStyles(type) {
+ const styles = {
+ 'career-day': 'bg-purple-100 text-purple-700',
+ 'workshop': 'bg-blue-100 text-blue-700',
+ 'webinar': 'bg-green-100 text-green-700',
+ 'networking': 'bg-yellow-100 text-yellow-700'
+ };
+ return styles[type] || 'bg-gray-100 text-gray-700';
+}
+
+export function getEventTypeIcon(type) {
+ const icons = {
+ 'career-day': 'fa-briefcase',
+ 'workshop': 'fa-laptop-code',
+ 'webinar': 'fa-chalkboard-teacher',
+ 'networking': 'fa-handshake'
+ };
+ return icons[type] || 'fa-calendar';
+}
+
+export function getEventTypeLabel(type) {
+ const labels = {
+ 'career-day': 'Career Day',
+ 'workshop': 'Workshop',
+ 'webinar': 'Webinar',
+ 'networking': 'Networking'
+ };
+ return labels[type] || 'Event';
+}
+
+export function filterEventsByDate(events, dateRange) {
+ const today = new Date();
+ today.setHours(0, 0, 0, 0);
+
+ switch (dateRange) {
+ case 'upcoming':
+ return events.filter(event => new Date(event.date) >= today);
+ case 'this-week':
+ const nextWeek = new Date(today);
+ nextWeek.setDate(today.getDate() + 7);
+ return events.filter(event => {
+ const eventDate = new Date(event.date);
+ return eventDate >= today && eventDate <= nextWeek;
+ });
+ case 'this-month':
+ const nextMonth = new Date(today);
+ nextMonth.setMonth(today.getMonth() + 1);
+ return events.filter(event => {
+ const eventDate = new Date(event.date);
+ return eventDate >= today && eventDate <= nextMonth;
+ });
+ default:
+ return events;
+ }
+}
+
+export function showToast(message, type = 'info') {
+ const toast = document.createElement('div');
+ const colors = {
+ success: 'bg-green-500',
+ error: 'bg-red-500',
+ info: 'bg-blue-500'
+ };
+ toast.className = `fixed bottom-4 right-4 px-6 py-3 rounded-lg shadow-lg text-white z-50 fade-in ${colors[type] || colors.info}`;
+ toast.innerHTML = `
${message}`;
+ document.body.appendChild(toast);
+ setTimeout(() => toast.remove(), 3000);
+}
diff --git a/assets/js/views/events/eventsFilters.js b/assets/js/views/events/eventsFilters.js
new file mode 100644
index 0000000..17733ac
--- /dev/null
+++ b/assets/js/views/events/eventsFilters.js
@@ -0,0 +1,54 @@
+/**
+ * Events Filters View
+ */
+
+export function renderEventsFilters(currentFilters, onFilterChange) {
+ return `
+
+
Filters
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ `;
+}
+
+export function attachFilterListeners(onFilterChange) {
+ document.querySelectorAll('.filter-btn').forEach(btn => {
+ btn.addEventListener('click', () => {
+ const filterType = btn.dataset.filterType;
+ const filterValue = btn.dataset.filterValue;
+ onFilterChange(filterType, filterValue);
+ });
+ });
+}
+
+export function updateFilterButtonStyles(filterType, filterValue) {
+ document.querySelectorAll(`.filter-btn[data-filter-type="${filterType}"]`).forEach(btn => {
+ if (btn.dataset.filterValue === filterValue) {
+ btn.classList.add('bg-purple-600', 'text-white');
+ btn.classList.remove('bg-white', 'text-gray-700', 'border-gray-300');
+ } else {
+ btn.classList.remove('bg-purple-600', 'text-white');
+ btn.classList.add('bg-white', 'text-gray-700', 'border-gray-300');
+ }
+ });
+}
diff --git a/assets/js/views/events/eventsHeader.js b/assets/js/views/events/eventsHeader.js
new file mode 100644
index 0000000..65c4b39
--- /dev/null
+++ b/assets/js/views/events/eventsHeader.js
@@ -0,0 +1,37 @@
+/**
+ * Events Header View
+ */
+
+export function renderEventsHeader(events) {
+ const totalEvents = events.length;
+ const totalRegistrations = events.reduce((sum, e) => sum + (e.registeredCount || 0), 0);
+ const totalWorkshops = events.filter(e => e.type === 'workshop').length;
+
+ return `
+
+
+
+ Events
+
+
Upcoming career days, workshops, and networking events
+
+
+
+
+
+
${totalEvents}
+
Upcoming Events
+
+
+
+
${totalRegistrations}
+
Total Registrations
+
+
+
+
${totalWorkshops}
+
Workshops Available
+
+
+ `;
+}