@tour-kit/scheduling
Time-based scheduling for controlling when tours, announcements, and content appear — business hours, dates, and timezones
LLM Context File
Working with an AI assistant? Download the context file for @tour-kit/scheduling and paste it into your conversation for accurate code generation.
Time-based scheduling for tours, announcements, and onboarding content.
Why Scheduling Matters
Not all users should see tours at the same time. Scheduling helps you:
- Launch at the right time - Show tours when features go live, not before
- Respect user hours - Only display content during business hours or specific time zones
- Avoid peak times - Block tours during critical periods like end-of-quarter
- Target by region - Use timezone-aware scheduling for global audiences
- Create recurring patterns - Show weekly tips or monthly feature highlights
Installation
pnpm add @tour-kit/schedulingQuick Start
import { useSchedule } from '@tour-kit/scheduling'
function OnboardingTour() {
const schedule = {
startAt: '2024-01-15',
endAt: '2024-03-31',
daysOfWeek: [1, 2, 3, 4, 5], // Weekdays only
timeOfDay: { start: '09:00', end: '17:00' },
useUserTimezone: true,
}
const { isActive, reason } = useSchedule(schedule)
if (!isActive) {
return null
}
return <Tour tourId="onboarding">...</Tour>
}Core Concepts
Schedule
A Schedule defines when content should be shown:
interface Schedule {
enabled?: boolean
startAt?: DateString | Date
endAt?: DateString | Date
daysOfWeek?: DayOfWeek[]
timeOfDay?: TimeRange
useUserTimezone?: boolean
timezone?: string
blackouts?: BlackoutPeriod[]
recurring?: RecurringPattern
businessHours?: BusinessHours
metadata?: Record<string, unknown>
}Evaluation Order
Schedules are evaluated in this order:
- Enabled check - Is
enabledtrue? - Date range - Is now between
startAtandendAt? - Blackout periods - Are we in a blackout?
- Day of week - Is today in
daysOfWeek? - Time of day - Is now in
timeOfDayrange? - Business hours - Are we in business hours (if configured)?
- Recurring pattern - Does now match the pattern?
The first failed check determines the inactive reason.
Timezone Handling
All scheduling is timezone-aware:
// Use the user's browser timezone
const schedule = {
useUserTimezone: true,
timeOfDay: { start: '09:00', end: '17:00' },
}
// Or specify a fixed timezone
const schedule = {
timezone: 'America/New_York',
timeOfDay: { start: '09:00', end: '17:00' },
}Dates are evaluated in the schedule's timezone, not UTC. This ensures users in different timezones see content at the correct local time.
Blackout Periods
Block specific date ranges regardless of other rules:
const schedule = {
startAt: '2024-01-01',
endAt: '2024-12-31',
blackouts: [
{
id: 'holiday-freeze',
start: '2024-12-20',
end: '2024-12-31',
reason: 'Holiday freeze',
},
{
id: 'major-release',
start: '2024-06-15T00:00:00Z',
end: '2024-06-15T23:59:59Z',
reason: 'Major product release',
},
],
}Blackouts override all other schedule rules.
Recurring Patterns
Show content on a repeating schedule:
// Every Monday and Wednesday
const schedule = {
recurring: {
type: 'weekly',
daysOfWeek: [1, 3],
},
}
// First day of each month
const schedule = {
recurring: {
type: 'monthly',
dayOfMonth: 1,
},
}
// Every 2 weeks, up to 5 occurrences
const schedule = {
recurring: {
type: 'weekly',
interval: 2,
maxOccurrences: 5,
},
}Package Structure
Hooks
React hooks for reactive scheduling:
useSchedule- Simple active/inactive checkuseScheduleStatus- Detailed status with next active/inactive timesuseUserTimezone- Get user's browser timezone
Utilities
Pure functions for schedule evaluation:
- Evaluation -
checkSchedule,isScheduleActive,getScheduleStatus - Timezone -
getUserTimezone,isValidTimezone,formatDateString - Date Range -
isWithinDateRange - Time Range -
isWithinTimeRange,isWithinAnyTimeRange - Day of Week -
getDayOfWeek,isAllowedDay - Blackouts -
isInBlackoutPeriod,getCurrentBlackout - Business Hours -
isWithinBusinessHours,isHoliday - Recurring -
matchesRecurringPattern
Types
Full TypeScript definitions:
Presets
Built-in configurations:
Common Patterns
Weekdays Only
import { DAY_GROUPS } from '@tour-kit/scheduling'
const schedule = {
daysOfWeek: DAY_GROUPS.weekdays, // [1, 2, 3, 4, 5]
}Business Hours
Attach a businessHours window and the schedule is active only inside that
window, evaluated in the schedule's timezone. The standard preset opens
Monday–Friday 9:00–17:00 and is closed on weekends.
import { BUSINESS_HOURS_PRESETS } from '@tour-kit/scheduling'
const schedule = {
businessHours: BUSINESS_HOURS_PRESETS.standard, // Mon–Fri 9:00–17:00
timezone: 'America/New_York',
}
// Active at 10:30 in New York; inactive at the same instant in Tokyo (23:30),
// outside the window → reason: 'outside_business_hours'.businessHours is independent of timeOfDay — set both and a schedule must
satisfy both to be active. To pin a store's hours regardless of the schedule's
timezone, set businessHours.timezone; it takes precedence.
Limited-Time Campaign
const schedule = {
startAt: '2024-02-01',
endAt: '2024-02-14',
timeOfDay: { start: '08:00', end: '20:00' },
useUserTimezone: true,
}Recurring Weekly Tips
const schedule = {
recurring: {
type: 'weekly',
daysOfWeek: [2], // Every Tuesday
interval: 1,
endDate: '2024-12-31',
},
}Next Steps
- useSchedule Hook - Start using reactive scheduling
- Schedule Evaluation - Understand how schedules are evaluated
- Components - Schedule-aware display components
- Types Reference - Explore all available types
@tour-kit/schedulingAPI reference - Full export surface in one page
Ship onboarding, not config.
npm i @tour-kit/core is MIT and free. The Pro packages work unlicensed too — a one-time $99 license removes the production watermark when you ship.
MIT-licensed — no signup, no credit card. Pay once, only when you ship.