diff --git a/search.asp b/search.asp index a214376..c4d2077 100644 --- a/search.asp +++ b/search.asp @@ -262,7 +262,7 @@ Set rs = Nothing
-
+
-

West Jefferson Events

+

West Jefferson Dashboard

@@ -967,6 +1088,19 @@ let recognitionCarouselInterval = null; let isRecognitionTransitioning = false; + // Current events carousel state - NOW FOR NON-INCIDENTS ONLY + // Incidents stay pinned, other events rotate + let nonIncidentEvents = []; + let currentNonIncidentIndex = 0; + let nonIncidentCarouselInterval = null; + let isNonIncidentTransitioning = false; + + // Keep old variables for compatibility but they won't be used + let currentEventPairs = []; + let currentPairIndex = 0; + let currentCarouselInterval = null; + let isCurrentTransitioning = false; + // Get business unit from URL parameter function getBusinessUnitFromURL() { const urlParams = new URLSearchParams(window.location.search); @@ -1054,8 +1188,8 @@ // Render events on the page (with smart delay during transitions) function renderEvents(data) { - // If carousel is mid-transition, delay the render - if (isTransitioning) { + // If any carousel is mid-transition, delay the render + if (isTransitioning || isNonIncidentTransitioning || isRecognitionTransitioning) { console.log('Carousel: Transition in progress, delaying render by 800ms'); pendingDataRender = data; return; @@ -1068,92 +1202,7 @@ const recognitions = data.current ? data.current.filter(e => e.typecolor === 'recognition') : []; const otherCurrentEvents = data.current ? data.current.filter(e => e.typecolor !== 'recognition') : []; - // Current Events - show all in grid layout (excluding Recognition) - FIRST priority - if (otherCurrentEvents.length > 0) { - // Split into active and resolved events - const activeEvents = otherCurrentEvents.filter(e => !e.resolved); - const resolvedEvents = otherCurrentEvents.filter(e => e.resolved); - - // Sort function: by type priority (Incident > Change > Awareness > TBD), then by date (earliest first) - const typePriority = { - 'Incident': 1, - 'Change': 2, - 'Awareness': 3, - 'Recognition': 4, - 'TBD': 5 - }; - - const sortByTypeAndDate = (a, b) => { - // First, sort by type priority - const priorityA = typePriority[a.typename] || 999; - const priorityB = typePriority[b.typename] || 999; - - if (priorityA !== priorityB) { - return priorityA - priorityB; - } - - // If same type, sort by start time (earliest first) - const dateA = new Date(a.starttime); - const dateB = new Date(b.starttime); - return dateA - dateB; - }; - - // Sort both active and resolved events - activeEvents.sort(sortByTypeAndDate); - resolvedEvents.sort(sortByTypeAndDate); - - // Combine with active first, resolved last - const sortedEvents = [...activeEvents, ...resolvedEvents]; - - // Determine badge color based on highest severity - const severity = getHighestSeverity(data.current); - - html += '
'; - html += `
CURRENT EVENTS
`; - - // Determine grid class based on number of events - const gridClass = sortedEvents.length === 1 ? 'single' : 'multi'; - html += `
`; - - sortedEvents.forEach(event => { - const borderColor = getColorFromType(event.typecolor); - const ticketBadge = event.ticketnumber - ? `${escapeHtml(event.ticketnumber)}` - : ''; - const resolvedIndicator = event.resolved ? '
RESOLVED
' : ''; - - const endTimeText = event.resolved - ? `
Resolved: ${formatDateTime(event.endtime)}` - : event.endtime ? `
Ends: ${formatDateTime(event.endtime)}` : '
Status: Ongoing (no end time)'; - - // Calculate progressive fade for resolved incidents (fade over 30 minutes) - let opacity = 1.0; - let resolvedClass = ''; - if (event.resolved && event.minutes_since_end !== null && event.minutes_since_end !== undefined) { - // Fade from 1.0 to 0.5 over 30 minutes, then drop off - opacity = Math.max(0.5, 1.0 - (event.minutes_since_end / 30) * 0.5); - resolvedClass = ' resolved'; - } - - html += ` -
- ${resolvedIndicator} -
${ticketBadge}
-
-
${escapeHtml(event.notification)}
-
-
- Started: ${formatDateTime(event.starttime)}${endTimeText} -
-
- `; - }); - - html += '
'; // Close grid - html += '
'; // Close section - } - - // Recognition Carousel Section - AFTER current events, BEFORE upcoming + // Recognition Carousel Section - FIRST (top of dashboard) if (recognitions.length > 0) { recognitionEvents = recognitions; @@ -1197,22 +1246,148 @@ }); html += '
'; // Close carousel wrapper - - // Add dots if multiple recognitions - if (recognitions.length > 1) { - html += '
'; - recognitions.forEach((_, index) => { - html += ``; - }); - html += '
'; - } - html += '
'; // Close carousel container html += '
'; // Close section } else { recognitionEvents = []; } + // Current Events - NEW LOGIC: Incidents pinned, others rotate + // Separate incidents from other event types + const incidents = otherCurrentEvents.filter(e => e.typename === 'Incident'); + const nonIncidents = otherCurrentEvents.filter(e => e.typename !== 'Incident'); + + // Sort function: by date (earliest first), then resolved status + const sortByDateAndResolved = (a, b) => { + // Active events before resolved + if (a.resolved !== b.resolved) { + return a.resolved ? 1 : -1; + } + // Then by start time (earliest first) + const dateA = new Date(a.starttime); + const dateB = new Date(b.starttime); + return dateA - dateB; + }; + + // Sort incidents and non-incidents + incidents.sort(sortByDateAndResolved); + nonIncidents.sort(sortByDateAndResolved); + + // Helper function to render a single event card + const renderEventCard = (event, index, total, showCounter = true) => { + const borderColor = getColorFromType(event.typecolor); + const ticketBadge = event.ticketnumber + ? `${escapeHtml(event.ticketnumber)}` + : ''; + const resolvedIndicator = event.resolved ? '
RESOLVED
' : ''; + const eventCounter = (showCounter && total > 1) ? `
${index + 1} of ${total}
` : ''; + + const endTimeText = event.resolved + ? `
Resolved: ${formatDateTime(event.endtime)}` + : event.endtime ? `
Ends: ${formatDateTime(event.endtime)}` : '
Status: Ongoing (no end time)'; + + // Calculate progressive fade for resolved incidents (fade over 30 minutes) + let opacity = 1.0; + let resolvedClass = ''; + if (event.resolved && event.minutes_since_end !== null && event.minutes_since_end !== undefined) { + opacity = Math.max(0.5, 1.0 - (event.minutes_since_end / 30) * 0.5); + resolvedClass = ' resolved'; + } + + return ` +
+ ${resolvedIndicator} + ${eventCounter} +
${ticketBadge}
+
+
${escapeHtml(event.notification)}
+
+
+ Started: ${formatDateTime(event.starttime)}${endTimeText} +
+
+ `; + }; + + // Determine badge color based on highest severity + const severity = getHighestSeverity(data.current); + + // Only show current events section if there are incidents OR non-incidents + if (incidents.length > 0 || nonIncidents.length > 0) { + html += '
'; + html += `
CURRENT EVENTS
`; + + // ======================================== + // INCIDENTS SECTION - Always visible (pinned) + // ======================================== + if (incidents.length > 0) { + html += '
'; + + const gridClass = incidents.length === 1 ? 'single' : 'multi'; + html += `
`; + incidents.forEach((event, index) => { + html += renderEventCard(event, index, incidents.length, false); // No counter for pinned + }); + html += '
'; // Close incidents grid + html += '
'; // Close incidents section + } + + // ======================================== + // NON-INCIDENTS SECTION - Rotating carousel + // ======================================== + if (nonIncidents.length > 0) { + nonIncidentEvents = nonIncidents; + + // Preserve current index if valid + if (currentNonIncidentIndex >= nonIncidents.length) { + currentNonIncidentIndex = 0; + } + + html += ''; // Close non-incidents section + } else { + nonIncidentEvents = []; + } + + html += '
'; // Close events-section + } else { + nonIncidentEvents = []; + } + + // Clear old carousel state (not used anymore) + currentEventPairs = []; + // Upcoming Events - carousel with slide-up transition if (data.upcoming && data.upcoming.length > 0) { // Sort upcoming events by type priority, then by date @@ -1262,8 +1437,10 @@ ? `${escapeHtml(event.ticketnumber)}` : ''; const activeClass = index === currentUpcomingIndex ? 'active' : 'enter-down'; + const upcomingCounter = sortedUpcoming.length > 1 ? `
${index + 1} of ${sortedUpcoming.length}
` : ''; html += `