WorkingHours

A WorkingHours component lets users define daily start and end times for availability. It also supports adding multiple break intervals within the availabilty and validates to prevent overlaps or out-of-range times.

Quick Start

Installation
npm install @adaptavant/working-hours
Import
import { WorkingHours } from '@adaptavant/working-hours';

Key Features

A comprehensive time management widget for configuring business availability and break schedules:

  • Dual-mode operation - Configure working hours or break times with multi-slot scheduling per day. Supports complex schedules like split shifts and multiple availability windows.
  • Intelligent validation - Real-time overlap detection, error highlighting, and change tracking. Prevents conflicting time slots with immediate feedback and unsaved change notifications.
  • Flexible time input - Supports multiple formats (9:30 AM, 21:30, 930) with automatic parsing.
  • Permission & bulk controls - Role-based access with apply-to-all functionality for quick setup. Control add/delete capabilities, time intervals, and bulk day configuration copying.
  • Full internationalization - Customizable labels for UI text, day names, and error messages for multi-language support.

Working Hours Mode

The example displays "Monday to Friday 8 AM to 5 PM" time schedule with weekends off. Demonstrates full permission settings, custom labels, and event tracking setup.

Use componentBaseType prop to define the type of the component (Working hours or Break) and initialWeekDayConfig prop can be used to set the initial time slots for each day.

The prop workingHoursPermisions controls the visibility of the delete and add slot buttons, the apply to all button, the 24 hour slot option and the time picker interval.

Use customLables prop to set the custom labels for the multi-language support and gtmEventsSetUp prop to set the Google Tag Manager event tracking.

Closed
Closed
Closed
Closed
Closed
Closed
Closed
<WorkingHours
	componentBaseType="workingHours"
	initialWeekDayConfig={{
		MO: { hours: [{ start: 480, end: 1020 }], breaks: [] },
		TU: { hours: [{ start: 480, end: 1020 }], breaks: [] },
		WE: { hours: [{ start: 480, end: 1020 }], breaks: [] },
		TH: { hours: [{ start: 480, end: 1020 }], breaks: [] },
		FR: { hours: [{ start: 480, end: 1020 }], breaks: [] },
		SA: {},
		SU: {},
	}}
	workingHoursPermisions={{
		isValidUserToRenderDeleteAndAddSlot: true,
		isValidUserToRenderApplyToAll: true,
		allow24HourSlot: false,
		timePickerInterval: 15,
	}}
	customLables={{
		toggleOffTitle: 'Closed',
		toggleDisabledTitle: 'Not Available',
		errorMessage: 'Invalid time range',
		applyToAllButtonTitle: 'Apply to all days',
		addSlotButtonTitle: 'Add Slot',
		deleteButtonTitle: 'Delete Slot',
		dayLabels: {
			Monday: 'Monday',
			Tuesday: 'Tuesday',
			Wednesday: 'Wednesday',
			Thursday: 'Thursday',
			Friday: 'Friday',
			Saturday: 'Saturday',
			Sunday: 'Sunday',
		},
	}}
	gtmEventsSetUp={{
		sendGtmAnalytics: (eventName, eventData) => {},
		gtmEventsObject:{
			toggleOn: 'working_hours_toggle_on',
			toggleOff: 'working_hours_toggle_off',
			deleteSlot: 'working_hours_delete_slot',
			addSlot: 'working_hours_add_slot',
			applyToAll: 'working_hours_apply_to_all',
		}
	}}
	onWeekDayConfigChange={(config) => console.log('Config changed:', config)}
	onValidationChange={(hasErrors, errors) => console.log('Validation:', hasErrors, errors)}
	onUpdateStatusChange={(hasUpdates) => console.log('Updates:', hasUpdates)}
/>

Breaks Mode

Set componentBaseType="breaks" to configure break times. This mode allows you to set single or multiple break times for each day.

No breaks
No breaks
No breaks
No breaks
No breaks
No breaks
No breaks
<WorkingHours
	componentBaseType="breaks"
	initialWeekDayConfig={{
		MO: { 
			hours: [{ start: 480, end: 1020 }], 
			breaks: [{ start: 720, end: 780 }] 
		},
		TU: { 
			hours: [{ start: 480, end: 1020 }], 
			breaks: [{ start: 720, end: 780 }] 
		},
		WE: { hours: [{ start: 480, end: 1020 }], breaks: [] },
		TH: { hours: [{ start: 480, end: 1020 }], breaks: [] },
		FR: { hours: [{ start: 480, end: 1020 }], breaks: [] },
		SA: {},
		SU: {},
	}}
	workingHoursPermisions={{
		isValidUserToRenderDeleteAndAddSlot: true,
		isValidUserToRenderApplyToAll: true,
		allow24HourSlot: false,
		timePickerInterval: 15,
	}}
	customLables={{
		toggleOffTitle: 'No breaks',
		toggleDisabledTitle: 'Day off',
		errorMessage: 'Invalid time range',
		deleteButtonTitle: 'Delete Break',
		addSlotButtonTitle: 'Add Break',
		applyToAllButtonTitle: 'Apply to All',
		dayLabels: {
			Monday: 'Monday',
			Tuesday: 'Tuesday',
			Wednesday: 'Wednesday',
			Thursday: 'Thursday',
			Friday: 'Friday',
			Saturday: 'Saturday',
			Sunday: 'Sunday',
		},
	}}
	gtmEventsSetUp={{
		sendGtmAnalytics: (eventName) => {},
		gtmEventsObject: {
			toggleOn: 'breaks_toggle_on',
			toggleOff: 'breaks_toggle_off',
			deleteSlot: 'breaks_delete_slot',
			addSlot: 'breaks_add_slot',
			applyToAll: 'breaks_apply_to_all',
		}
	}}
/>

Style API

Our design system components include style props that allow you to easily customize different parts of each component to match your design needs.

Please refer to the Style API documentation for more insights.

WorkingHours parts

Closed
Closed
Closed
Closed
Closed
Closed
Closed
<WorkingHours
	className="border-primary border-2"
	componentBaseType="workingHours"
	initialWeekDayConfig={{
		MO: { hours: [{ start: 480, end: 1020 }], breaks: [] },
		TU: { hours: [{ start: 480, end: 1020 }], breaks: [] },
		WE: { hours: [{ start: 480, end: 1020 }], breaks: [] },
		TH: { hours: [{ start: 480, end: 1020 }], breaks: [] },
		FR: { hours: [{ start: 480, end: 1020 }], breaks: [] },
		SA: {},
		SU: {},
	}}
	workingHoursPermisions={{
		isValidUserToRenderDeleteAndAddSlot: true,
		isValidUserToRenderApplyToAll: true,
		allow24HourSlot: false,
		timePickerInterval: 15,
	}}
	customLables={{
		toggleOffTitle: 'Closed',
		toggleDisabledTitle: 'Not Available',
		errorMessage: 'Invalid time range',
		applyToAllButtonTitle: 'Apply to all days',
		addSlotButtonTitle: 'Add Slot',
		deleteButtonTitle: 'Delete Slot',
		dayLabels: {
			Monday: 'Monday',
			Tuesday: 'Tuesday',
			Wednesday: 'Wednesday',
			Thursday: 'Thursday',
			Friday: 'Friday',
			Saturday: 'Saturday',
			Sunday: 'Sunday',
		},
	}}
	gtmEventsSetUp={{
		sendGtmAnalytics: (eventName, eventData) => {},
		gtmEventsObject:{
			toggleOn: 'working_hours_toggle_on',
			toggleOff: 'working_hours_toggle_off',
			deleteSlot: 'working_hours_delete_slot',
			addSlot: 'working_hours_add_slot',
			applyToAll: 'working_hours_apply_to_all',
		}
	}}
	onWeekDayConfigChange={(config) => console.log('Config changed:', config)}
	onValidationChange={(hasErrors, errors) => console.log('Validation:', hasErrors, errors)}
	onUpdateStatusChange={(hasUpdates) => console.log('Updates:', hasUpdates)}
/>
Stylable PartsDescription
rootThe container that wraps the WorkingHours component