Spaces:
Running
Running
| // Course data for 2025-2026 | |
| const coursesData = [ | |
| // Q1 2025 | |
| { | |
| "_id": { | |
| "$oid": "6913bb88e6a18803422e7b82" | |
| }, | |
| "Course": "MDB100: MongoDB Database and Security", | |
| "Confirmed?": "Pending", | |
| "Start Date": "8-Dec-25", | |
| "End Date": "8-Dec-25", | |
| "Time Zone": "US CST", | |
| "Time Slot": "All Day (9:00 AM - 5:00 PM)", | |
| "Region": "AMER", | |
| "Language": "English", | |
| "Instructor": "Ann Duong", | |
| "Session": "US CST | 2025 Dec 08 | English (MDB100)", | |
| "Registration Code": "ca5d29d0-1924-44b2-bf0d-ee6eb2ed631f", | |
| "raw_start_date": "8-Dec-2025", | |
| "raw_end_date": "8-Dec-2025", | |
| "start_timestamp": { | |
| "$date": "2025-12-08T00:00:00.000Z" | |
| }, | |
| "end_timestamp": { | |
| "$date": "2025-12-08T00:00:00.000Z" | |
| } | |
| }, | |
| { | |
| "_id": { | |
| "$oid": "6913bb88e6a18803422e7b83" | |
| }, | |
| "Fiscal Q": "FY26 Q4", | |
| "Course": "MDB100: MongoDB Database and Security", | |
| "Confirmed?": "Pending", | |
| "Start Date": "8-Dec-25", | |
| "End Date": "8-Dec-25", | |
| "Time Zone": "SG SGT", | |
| "Time Slot": "All Day (9:00 AM - 5:00 PM)", | |
| "Region": "APAC", | |
| "Language": "English", | |
| "Instructor": "Jirachai Chansivanon", | |
| "RR Link (Held)": "https://mongodb.my.salesforce.com/aDQUe0000002tGXOAY", | |
| "Assignment Link": "", | |
| "Session": "SG SGT | 2025 Dec 08 | English (MDB100)", | |
| "Registration Code": "56f03773-aa3f-4246-bc38-e0e50d9b67ec", | |
| "raw_start_date": "8-Dec-2025", | |
| "raw_end_date": "8-Dec-2025", | |
| "start_timestamp": { | |
| "$date": "2025-12-08T00:00:00.000Z" | |
| }, | |
| "end_timestamp": { | |
| "$date": "2025-12-08T00:00:00.000Z" | |
| } | |
| }, | |
| { | |
| "_id": { | |
| "$oid": "6913bb88e6a18803422e7b84" | |
| }, | |
| "Fiscal Q": "FY26 Q4", | |
| "Course": "MDB100: MongoDB Database and Security", | |
| "Confirmed?": "Pending", | |
| "Start Date": "8-Dec-25", | |
| "End Date": "8-Dec-25", | |
| "Time Zone": "UK GMT", | |
| "Time Slot": "All Day (9:00 AM - 5:00 PM)", | |
| "Region": "EMEA", | |
| "Language": "English", | |
| "Instructor": "Joe Nyirenda", | |
| "RR Link (Held)": "https://mongodb.my.salesforce.com/aDQUe0000002tI9OAI", | |
| "Assignment Link": "", | |
| "Session": "UK GMT | 2025 Dec 08 | English (MDB100)", | |
| "Registration Code": "915b651a-fd73-4b6c-8b20-f8a815c85006", | |
| "raw_start_date": "8-Dec-2025", | |
| "raw_end_date": "8-Dec-2025", | |
| "start_timestamp": { | |
| "$date": "2025-12-08T00:00:00.000Z" | |
| }, | |
| "end_timestamp": { | |
| "$date": "2025-12-08T00:00:00.000Z" | |
| } | |
| }, | |
| { | |
| "_id": { | |
| "$oid": "6913bb88e6a18803422e7b85" | |
| }, | |
| "Fiscal Q": "FY26 Q4", | |
| "Course": "MDB200: MongoDB Optimization and Performance", | |
| "Confirmed?": "Pending", | |
| "Start Date": "9-Dec-25", | |
| "End Date": "9-Dec-25", | |
| "Time Zone": "US CST", | |
| "Time Slot": "All Day (9:00 AM - 5:00 PM)", | |
| "Region": "AMER", | |
| "Language": "English", | |
| "Instructor": "Ann Duong", | |
| "RR Link (Held)": "https://mongodb.my.salesforce.com/aDQUe0000002tLNOAY", | |
| "Assignment Link": "", | |
| "Session": "US CST | 2025 Dec 09 | English (MDB200)", | |
| "Registration Code": "1d098b3b-229c-47c3-a22c-68dfd5f1ad2b", | |
| "raw_start_date": "9-Dec-2025", | |
| "raw_end_date": "9-Dec-2025", | |
| "start_timestamp": { | |
| "$date": "2025-12-09T00:00:00.000Z" | |
| }, | |
| "end_timestamp": { | |
| "$date": "2025-12-09T00:00:00.000Z" | |
| } | |
| }, | |
| { | |
| "_id": { | |
| "$oid": "6913bb88e6a18803422e7b86" | |
| }, | |
| "Fiscal Q": "FY26 Q4", | |
| "Course": "MDB200: MongoDB Optimization and Performance", | |
| "Confirmed?": "Pending", | |
| "Start Date": "9-Dec-25", | |
| "End Date": "9-Dec-25", | |
| "Time Zone": "SG SGT", | |
| "Time Slot": "All Day (9:00 AM - 5:00 PM)", | |
| "Region": "APAC", | |
| "Language": "English", | |
| "Instructor": "Jirachai Chansivanon", | |
| "RR Link (Held)": "https://mongodb.my.salesforce.com/aDQUe0000002tMzOAI", | |
| "Assignment Link": "", | |
| "Session": "SG SGT | 2025 Dec 09 | English (MDB200)", | |
| "Registration Code": "1df5cf37-e329-434f-a955-cd7866d40fbe", | |
| "raw_start_date": "9-Dec-2025", | |
| "raw_end_date": "9-Dec-2025", | |
| "start_timestamp": { | |
| "$date": "2025-12-09T00:00:00.000Z" | |
| }, | |
| "end_timestamp": { | |
| "$date": "2025-12-09T00:00:00.000Z" | |
| } | |
| }, | |
| { | |
| "_id": { | |
| "$oid": "6913bb88e6a18803422e7b87" | |
| }, | |
| "Fiscal Q": "FY26 Q4", | |
| "Course": "MDB200: MongoDB Optimization and Performance", | |
| "Confirmed?": "Pending", | |
| "Start Date": "9-Dec-25", | |
| "End Date": "9-Dec-25", | |
| "Time Zone": "UK GMT", | |
| "Time Slot": "All Day (9:00 AM - 5:00 PM)", | |
| "Region": "EMEA", | |
| "Language": "English", | |
| "Instructor": "Joe Nyirenda", | |
| "RR Link (Held)": "https://mongodb.my.salesforce.com/aDQUe0000002tObOAI", | |
| "Assignment Link": "", | |
| "Session": "UK GMT | 2025 Dec 09 | English (MDB200)", | |
| "Registration Code": "87d323f0-d3cc-4e20-966d-f27deea2e0c6", | |
| "raw_start_date": "9-Dec-2025", | |
| "raw_end_date": "9-Dec-2025", | |
| "start_timestamp": { | |
| "$date": "2025-12-09T00:00:00.000Z" | |
| }, | |
| "end_timestamp": { | |
| "$date": "2025-12-09T00:00:00.000Z" | |
| } | |
| }, | |
| // Q2 2025 | |
| { | |
| "Course": "MDB200: MongoDB Optimization", | |
| "Start Date": "02-Apr-25", | |
| "Time": "09:00 AM - 05:00 PM", | |
| "Instructor": "John Smith", | |
| "Location": "Online" | |
| }, | |
| { | |
| "Course": "DEV500: Data Modeling", | |
| "Start Date": "16-Apr-25", | |
| "Time": "09:00 AM - 05:00 PM", | |
| "Instructor": "Sarah Johnson", | |
| "Location": "Online" | |
| }, | |
| { | |
| "Course": "OFS400: Ops Manager Admin", | |
| "Start Date": "07-May-25", | |
| "Time": "09:00 AM - 05:00 PM", | |
| "Instructor": "Michael Brown", | |
| "Location": "Online" | |
| }, | |
| { | |
| "Course": "DA620: Languages Drivers", | |
| "Start Date": "21-May-25", | |
| "Time": "09:00 AM - 05:00 PM", | |
| "Instructor": "Emily Davis", | |
| "Location": "Online" | |
| }, | |
| { | |
| "Course": "OA630: Self-Hosted Security", | |
| "Start Date": "04-Jun-25", | |
| "Time": "09:00 AM - 05:00 PM", | |
| "Instructor": "Robert Wilson", | |
| "Location": "Online" | |
| }, | |
| // Q3 2025 | |
| { | |
| "Course": "MDB300: Production Readiness", | |
| "Start Date": "09-Jul-25", | |
| "Time": "09:00 AM - 05:00 PM", | |
| "Instructor": "John Smith", | |
| "Location": "Online" | |
| }, | |
| { | |
| "Course": "DS110: Atlas Search", | |
| "Start Date": "23-Jul-25", | |
| "Time": "09:00 AM - 05:00 PM", | |
| "Instructor": "Sarah Johnson", | |
| "Location": "Online" | |
| }, | |
| { | |
| "Course": "OFA500: Atlas API", | |
| "Start Date": "06-Aug-25", | |
| "Time": "09:00 AM - 05:00 PM", | |
| "Instructor": "Michael Brown", | |
| "Location": "Online" | |
| }, | |
| { | |
| "Course": "DA630: Distributed Systems", | |
| "Start Date": "20-Aug-25", | |
| "Time": "09:00 AM - 05:00 PM", | |
| "Instructor": "Emily Davis", | |
| "Location": "Online" | |
| }, | |
| { | |
| "Course": "OA640: Atlas Security", | |
| "Start Date": "03-Sep-25", | |
| "Time": "09:00 AM - 05:00 PM", | |
| "Instructor": "Robert Wilson", | |
| "Location": "Online" | |
| }, | |
| // Q4 2025 | |
| { | |
| "Course": "DS120: Atlas Data Lake", | |
| "Start Date": "08-Oct-25", | |
| "Time": "09:00 AM - 05:00 PM", | |
| "Instructor": "John Smith", | |
| "Location": "Online" | |
| }, | |
| { | |
| "Course": "DA640: App Optimization", | |
| "Start Date": "22-Oct-25", | |
| "Time": "09:00 AM - 05:00 PM", | |
| "Instructor": "Sarah Johnson", | |
| "Location": "Online" | |
| }, | |
| { | |
| "Course": "OFS500: Ops Manager API", | |
| "Start Date": "05-Nov-25", | |
| "Time": "09:00 AM - 05:00 PM", | |
| "Instructor": "Michael Brown", | |
| "Location": "Online" | |
| }, | |
| { | |
| "Course": "DA650: Advanced Aggregation", | |
| "Start Date": "19-Nov-25", | |
| "Time": "09:00 AM - 05:00 PM", | |
| "Instructor": "Emily Davis", | |
| "Location": "Online" | |
| }, | |
| { | |
| "Course": "DS130: CSFLE", | |
| "Start Date": "03-Dec-25", | |
| "Time": "09:00 AM - 05:00 PM", | |
| "Instructor": "Robert Wilson", | |
| "Location": "Online" | |
| }, | |
| // Q1 2026 | |
| { | |
| "Course": "MDB100: MongoDB Database and Security", | |
| "Start Date": "14-Jan-26", | |
| "Time": "09:00 AM - 05:00 PM", | |
| "Instructor": "John Smith", | |
| "Location": "Online" | |
| }, | |
| { | |
| "Course": "DEV400: MongoDB Developer Extension", | |
| "Start Date": "28-Jan-26", | |
| "Time": "09:00 AM - 05:00 PM", | |
| "Instructor": "Sarah Johnson", | |
| "Location": "Online" | |
| }, | |
| { | |
| "Course": "DA660: AI Integration", | |
| "Start Date": "11-Feb-26", | |
| "Time": "09:00 AM - 05:00 PM", | |
| "Instructor": "Michael Brown", | |
| "Location": "Online" | |
| }, | |
| { | |
| "Course": "DA670: Vector Search", | |
| "Start Date": "25-Feb-26", | |
| "Time": "09:00 AM - 05:00 PM", | |
| "Instructor": "Emily Davis", | |
| "Location": "Online" | |
| }, | |
| { | |
| "Course": "OA620: Ops Manager Sizing", | |
| "Start Date": "11-Mar-26", | |
| "Time": "09:00 AM - 05:00 PM", | |
| "Instructor": "Robert Wilson", | |
| "Location": "Online" | |
| } | |
| ]; | |
| // Calendar functionality | |
| let currentMonth = new Date().getMonth(); | |
| let currentYear = new Date().getFullYear(); | |
| const calendar = new Calendar('#calendar', { | |
| defaultView: 'week', | |
| template: { | |
| time(event) { | |
| const { start, end, title } = event; | |
| return `<span style="color: white;">${formatTime(start)}~${formatTime(end)} ${title}</span>`; | |
| }, | |
| allday(event) { | |
| return `<span style="color: gray;">${event.title}</span>`; | |
| }, | |
| }, | |
| calendars: [ | |
| { | |
| id: 'cal1', | |
| name: 'Personal', | |
| backgroundColor: '#03bd9e', | |
| }, | |
| { | |
| id: 'cal2', | |
| name: 'Work', | |
| backgroundColor: '#00a9ff', | |
| }, | |
| ], | |
| }); | |
| function renderCalendar() { | |
| const firstDay = new Date(currentYear, currentMonth, 1); | |
| const lastDay = new Date(currentYear, currentMonth + 1, 0); | |
| const daysInMonth = lastDay.getDate(); | |
| let startingDay = firstDay.getDay(); | |
| // Adjust to make Monday (1) the first day of week instead of Sunday (0) | |
| startingDay = startingDay === 0 ? 6 : startingDay - 1; | |
| // Update month display | |
| const monthNames = ['January', 'February', 'March', 'April', 'May', 'June', | |
| 'July', 'August', 'September', 'October', 'November', 'December']; | |
| document.getElementById('current-month-display').textContent = | |
| `${monthNames[currentMonth]} ${currentYear}`; | |
| // Clear previous calendar | |
| const calendarDays = document.getElementById('calendar-days'); | |
| calendarDays.innerHTML = ''; | |
| // Add empty cells for days before the first day of month | |
| for (let i = 0; i < startingDay; i++) { | |
| const cell = document.createElement('div'); | |
| cell.className = 'bg-white h-24 p-1'; | |
| calendarDays.appendChild(cell); | |
| } | |
| // Add days of month | |
| for (let day = 1; day <= daysInMonth; day++) { | |
| const cell = document.createElement('div'); | |
| cell.className = 'bg-white h-24 p-1 overflow-auto'; | |
| const date = new Date(currentYear, currentMonth, day); | |
| const dateStr = date.toLocaleDateString('en-US', { day: '2-digit', month: 'short', year: 'numeric' }); | |
| // Add day number | |
| const dayNumber = document.createElement('div'); | |
| dayNumber.className = 'font-semibold text-sm mb-1'; | |
| dayNumber.textContent = day; | |
| cell.appendChild(dayNumber); | |
| // Add courses for this day | |
| const coursesToday = coursesData.filter(course => { | |
| const courseDate = new Date(course['Start Date']); | |
| return courseDate.getDate() === day && | |
| courseDate.getMonth() === currentMonth && | |
| courseDate.getFullYear() === currentYear; | |
| }); | |
| coursesToday.forEach(course => { | |
| const courseEl = document.createElement('div'); | |
| courseEl.className = 'text-xs p-1 mb-1 rounded bg-blue-50 border-l-4 border-blue-500 truncate'; | |
| courseEl.title = `${course.Course}\n${course.Time}\n${course.Instructor}`; | |
| courseEl.textContent = course.Course; | |
| cell.appendChild(courseEl); | |
| }); | |
| calendarDays.appendChild(cell); | |
| } | |
| } | |
| // Close dropdowns when clicking outside | |
| document.addEventListener('click', function(event) { | |
| if (!event.target.matches('.dropdown-btn')) { | |
| const dropdowns = document.querySelectorAll('.dropdown-content'); | |
| dropdowns.forEach(dropdown => { | |
| if (dropdown.classList.contains('show')) { | |
| dropdown.classList.remove('show'); | |
| } | |
| }); | |
| } | |
| }); | |
| // Initialize the page | |
| document.addEventListener('DOMContentLoaded', () => { | |
| // Set initial view to current month | |
| const now = new Date(); | |
| currentMonth = now.getMonth(); | |
| currentYear = now.getFullYear(); | |
| renderCalendar(); | |
| renderUpcomingDates(); | |
| // Month navigation | |
| document.getElementById('prev-month').addEventListener('click', () => { | |
| currentMonth--; | |
| if (currentMonth < 0) { | |
| currentMonth = 11; | |
| currentYear--; | |
| } | |
| renderCalendar(); | |
| feather.replace(); | |
| }); | |
| document.getElementById('next-month').addEventListener('click', () => { | |
| currentMonth++; | |
| if (currentMonth > 11) { | |
| currentMonth = 0; | |
| currentYear++; | |
| } | |
| renderCalendar(); | |
| feather.replace(); | |
| }); | |
| }); | |
| // Helper function to parse date strings | |
| function parseDate(dateStr) { | |
| const parts = dateStr.split('-'); | |
| const day = parseInt(parts[0]); | |
| const monthNames = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']; | |
| const month = monthNames.indexOf(parts[1]); | |
| const year = parseInt(parts[2]) + 2000; | |
| return new Date(year, month, day); | |
| } | |
| // Group courses by month | |
| function groupCoursesByMonth(courses) { | |
| const now = new Date(); | |
| const currentMonth = now.getMonth(); | |
| const currentYear = now.getFullYear(); | |
| const grouped = { | |
| current: [], | |
| next: [], | |
| following: [] | |
| }; | |
| courses.forEach(course => { | |
| const courseDate = parseDate(course['Start Date']); | |
| const courseMonth = courseDate.getMonth(); | |
| const courseYear = courseDate.getFullYear(); | |
| if (courseYear === currentYear || courseYear === currentYear + 1) { | |
| if (courseMonth === currentMonth && courseYear === currentYear) { | |
| grouped.current.push(course); | |
| } else if ( | |
| (courseMonth === currentMonth + 1 && courseYear === currentYear) || | |
| (currentMonth === 11 && courseMonth === 0 && courseYear === currentYear + 1) | |
| ) { | |
| grouped.next.push(course); | |
| } else if ( | |
| (courseMonth === currentMonth + 2 && courseYear === currentYear) || | |
| (currentMonth === 10 && courseMonth === 0 && courseYear === currentYear + 1) || | |
| (currentMonth === 11 && courseMonth === 1 && courseYear === currentYear + 1) | |
| ) { | |
| grouped.following.push(course); | |
| } | |
| } | |
| }); | |
| return grouped; | |
| } | |
| // Render courses to the DOM | |
| function renderCourses(courses, containerId) { | |
| const container = document.getElementById(containerId); | |
| container.innerHTML = ''; | |
| if (courses.length === 0) { | |
| container.innerHTML = '<p class="text-gray-600">No courses scheduled for this period.</p>'; | |
| return; | |
| } | |
| courses.forEach(course => { | |
| const card = document.createElement('custom-course-card'); | |
| card.setAttribute('title', course.Course); | |
| card.setAttribute('date', parseDate(course['Start Date']).toLocaleDateString('en-US', { | |
| month: 'short', | |
| day: 'numeric', | |
| year: 'numeric' | |
| })); | |
| card.setAttribute('time', course.Time); | |
| card.setAttribute('location', course.Location); | |
| card.setAttribute('link', '#'); | |
| container.appendChild(card); | |
| }); | |
| } | |
| // Render upcoming dates list | |
| function renderUpcomingDates() { | |
| const upcomingDatesList = document.getElementById('upcoming-dates-list'); | |
| upcomingDatesList.innerHTML = ''; | |
| // Sort courses by date | |
| const sortedCourses = [...coursesData].sort((a, b) => { | |
| return new Date(a['Start Date']) - new Date(b['Start Date']); | |
| }); | |
| // Get next 10 upcoming courses | |
| const now = new Date(); | |
| const upcomingCourses = sortedCourses.filter(course => { | |
| return new Date(course['Start Date']) >= now; | |
| }).slice(0, 10); | |
| if (upcomingCourses.length === 0) { | |
| upcomingDatesList.innerHTML = '<p class="text-gray-600">No upcoming courses scheduled.</p>'; | |
| return; | |
| } | |
| upcomingCourses.forEach(course => { | |
| const date = new Date(course['Start Date']); | |
| const dateItem = document.createElement('div'); | |
| dateItem.className = 'flex items-start border-b border-gray-100 pb-4 last:border-0 last:pb-0'; | |
| dateItem.innerHTML = ` | |
| <div class="bg-green-100 rounded-lg p-2 mr-4 flex-shrink-0"> | |
| <div class="text-green-800 font-bold text-center text-sm">${date.toLocaleDateString('en-US', { month: 'short' })}</div> | |
| <div class="text-green-800 font-bold text-center text-xl">${date.getDate()}</div> | |
| </div> | |
| <div> | |
| <h4 class="font-medium text-gray-800">${course.Course}</h4> | |
| <p class="text-sm text-gray-600">${course.Time} β’ ${course.Location}</p> | |
| <p class="text-sm text-gray-500 mt-1">Instructor: ${course.Instructor}</p> | |
| </div> | |
| `; | |
| upcomingDatesList.appendChild(dateItem); | |
| }); | |
| } | |
| // Filter courses based on selected filters | |
| function filterCourses() { | |
| const language = document.querySelector('select:nth-of-type(1)').value; | |
| const region = document.querySelector('select:nth-of-type(2)').value; | |
| const timezone = document.querySelector('select:nth-of-type(3)').value; | |
| const course = document.querySelector('select:nth-of-type(4)').value; | |
| // Filter logic would go here | |
| console.log('Filtering by:', {language, region, timezone, course}); | |
| // In a real implementation, you would filter the coursesData array | |
| // and update the displayed courses | |
| } | |
| // Initialize the page | |
| function init() { | |
| // Add event listeners to filter selects | |
| document.querySelectorAll('.filter-select').forEach(select => { | |
| select.addEventListener('change', filterCourses); | |
| }); | |
| const groupedCourses = groupCoursesByMonth(coursesData); | |
| renderCourses(groupedCourses.current, 'current-month-courses'); | |
| renderCourses(groupedCourses.next, 'next-month-courses'); | |
| renderCourses(groupedCourses.following, 'following-month-courses'); | |
| // Update month selector labels with actual month names | |
| const now = new Date(); | |
| const monthNames = ['January', 'February', 'March', 'April', 'May', 'June', | |
| 'July', 'August', 'September', 'October', 'November', 'December']; | |
| const buttons = document.querySelectorAll('.month-btn'); | |
| buttons[0].textContent = monthNames[now.getMonth()]; | |
| buttons[1].textContent = monthNames[(now.getMonth() + 1) % 12]; | |
| buttons[2].textContent = monthNames[(now.getMonth() + 2) % 12]; | |
| // Add enrol button functionality | |
| document.getElementById('enrol-mdb100').addEventListener('click', () => { | |
| const courseId = document.getElementById('mdb100-select').value; | |
| window.open(`https://learn.mongodb.com/courses/mdb100-mongodb-database-and-security?courseId=${courseId}`, '_blank'); | |
| }); | |
| } | |
| init(); | |