Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 | 1x 4x 4x 2x 1x 1x 1x 5x 1x 8x 7x 7x 7x 6x 3x 3x 3x 2x 2x 1x 1x 3x 2x 1x 6x 2x 5x 2x 2x 2x 2x 4x | /**
* WalkMe Triggers Module
*
* Tour trigger evaluation system.
* Determines when a tour should be automatically activated.
*/
import type { Tour, TourTrigger } from '../types/walkme.types'
// ---------------------------------------------------------------------------
// Types
// ---------------------------------------------------------------------------
export interface TriggerEvaluationContext {
/** Current page route/pathname */
currentRoute: string
/** Total number of page visits */
visitCount: number
/** ISO date string of first visit */
firstVisitDate: string | null
/** IDs of completed tours */
completedTourIds: string[]
/** Set of custom events that have been emitted */
customEvents: Set<string>
}
// ---------------------------------------------------------------------------
// Main Evaluation
// ---------------------------------------------------------------------------
/**
* Evaluate whether a tour should be triggered based on its trigger config
* and the current context. Does NOT check conditions (that's a separate step).
*/
export function shouldTriggerTour(
tour: Tour,
context: TriggerEvaluationContext,
): boolean {
const { trigger } = tour
switch (trigger.type) {
case 'onFirstVisit':
return evaluateOnFirstVisit(trigger, context)
case 'onRouteEnter':
return evaluateOnRouteEnter(trigger, context)
case 'onEvent':
return evaluateOnEvent(trigger, context)
case 'manual':
return false // Manual tours are started programmatically only
case 'scheduled':
return evaluateScheduled(trigger, context)
default:
return false
}
}
// ---------------------------------------------------------------------------
// Individual Trigger Evaluators
// ---------------------------------------------------------------------------
/** First visit: triggers only when visitCount === 1 */
export function evaluateOnFirstVisit(
_trigger: TourTrigger,
context: TriggerEvaluationContext,
): boolean {
return context.visitCount === 1
}
/** Route enter: triggers when current route matches the trigger's route pattern */
export function evaluateOnRouteEnter(
trigger: TourTrigger,
context: TriggerEvaluationContext,
): boolean {
if (!trigger.route) return false
const pattern = trigger.route
const route = context.currentRoute
// Exact match
if (pattern === route) return true
// Wildcard match: /dashboard/* matches /dashboard/anything
if (pattern.endsWith('/*')) {
const prefix = pattern.slice(0, -2)
return route.startsWith(prefix)
}
// Glob match: /dashboard/** matches /dashboard/a/b/c
if (pattern.endsWith('/**')) {
const prefix = pattern.slice(0, -3)
return route.startsWith(prefix)
}
return false
}
/** Event trigger: activates when a specific custom event has been emitted */
export function evaluateOnEvent(
trigger: TourTrigger,
context: TriggerEvaluationContext,
): boolean {
if (!trigger.event) return false
return context.customEvents.has(trigger.event)
}
/** Scheduled trigger: activates after N visits or N days since first visit */
export function evaluateScheduled(
trigger: TourTrigger,
context: TriggerEvaluationContext,
): boolean {
// Check visit-based threshold
if (trigger.afterVisits !== undefined) {
if (context.visitCount >= trigger.afterVisits) return true
}
// Check day-based threshold
if (trigger.afterDays !== undefined && context.firstVisitDate) {
const firstVisit = new Date(context.firstVisitDate)
const now = new Date()
const daysSinceFirstVisit = Math.floor(
(now.getTime() - firstVisit.getTime()) / (1000 * 60 * 60 * 24),
)
if (daysSinceFirstVisit >= trigger.afterDays) return true
}
return false
}
|