Advanced configuration
Booking.js is made for various use-cases, so it's really extensible and customizable. We augment all the intrinsic options so you can overwrite them as needed, e.g. Timekit availability
options or fullcalendar
settings.
Timekit works best with projects. A project in Timekit is a configuration of a specific booking experience. Usually, a project will correspond to an existing process already present in your organization.
You can create projects from your admin interface and reference them through your Booking Widget configuration. You can even modify them further if that is what you need. If you choose not use a project as your starting point, be sure to configure the necessary keys or your Booking Widget will be hard to use. Read more about projects here.
Before you continue!
Again, as stated above, please consider using projects to persist configuration with us. They are easy to create and manage both in our admin and through our API.
Example
{
// Required
app_key: '', // Your Timekit client-side key (App Widget Key)
// Optional
project_id: '', // Reference a project where you want to pull settings from and connect bookings to
el: '#bookingjs', // Which element should we the library load into
autoload: true, // Auto initialization if a windo.timekitBookingConfig variable is found
debug: false, // Enable debugging mode to output useful state/step data in the console
disable_confirm_page: false, // Disable the confirmation page and use the "clickTimeslot" callback to receive selected timeslot
// Manual configuration (not needed when supplying project_id; however, please make sure your project has a resource assigned to it)
resources: [], // ID's of the resources that are available as par of this project
availability: { ... }, // Configure how availability should be queried. (see below)
availability_constraints: [ ... ], // Configure any cross-resource constraints. (see below)
booking: { ... }, // Configure how bookings should be made. (see below)
reminders: [ ... ], // Reminder settings specific to this project. (see below)
customer_fields: { ... }, // Configure which inputs the customer can add to the booking. (see below)
ui: { ... }, // UI specific configuration used by our booking.js widget (v2) reference coming.
fullcalendar: { ... }, // Configure FullCalendar options. (see below)
callbacks: { ... } // Register callbacks on events. (see below)
}
Structure follows projects
Whether you choose to override project settings or supply all configuration manually, do know that the naming and content of the configuration parameters (e.g.
resources
,availability_constraints
,customer_fields
etc) follow the exact same naming conventions as used in projects. See the Create Project endpoint for reference.
Availability
A central feature of Timekit is searching for availability
of your resources. Availability are timeslots that your resources are open for booking i.e. spots where they are not already booked or blocked.
We support different modes/types of availability: mutual
, roundrobin_random
and roundrobin_prioritized
. You can retrieve availability for a single resource or multiple at the same time.
Constraints are used to further limit the search space, with the most common use case being opening hours. Here is a typical setup used for half an hour timeslots with random resource selection:
availability: {
mode: 'roundrobin_random',
length: '30 minutes',
from: '-1 hour',
to: '4 weeks',
buffer: '15 minutes',
ignore_all_day_events: false
}
Find details on each key by looking at our availability endpoint.
Availability Constraints
The most typical use-case for availability_constraints
is setting opening hours and/or working hours. You can do this with two different kinds of constraints; blocking and allowing. "Allowing" constraints implicitly blocks everything else, so for instance the constraint AllowDay
, with the day set to monday
, will block all the other days in the week. This means that you do not need to explicitly block periods that are implicitly being blocked with an "allowing" constraint. So if you are using the allow_weekdays
constraint, you don't need to also supply the block_weekends
constraint.
You can combine constraints to fit your use-case. As mentioned the most common use case is setting opening hours. With opening hours Monday to Friday 9am to 5pm this would look like this:
availability_constraints: [
{ allow_day_and_time: { day: 'monday', start: 9, end: 17 } },
{ allow_day_and_time: { day: 'tuesday', start: 9, end: 17 } }
],
Find details on each key by looking at our availability_constraints endpoint.
Booking
Setting a booking
configuration helps you define the way a booking is handled and presented. A typical scenario will use the graph type instant
, so no confirmation is needed by the recipient. You can see how all of Timekit's graphs work right here.
booking: {
graph: 'instant', // what type of flow? instant confirms the booking immediately
what: 'TBD',
where: 'West End'
}
Find details on each key by looking at our booking endpoint.
Reminders
The easiest way to send reminders
emails before or after a booking is to use the built-in reminder emails.
Setting up an email-reminder to be send to the owner 15 minutes before a booking takes place looks like this:
reminders: [
{
type: 'email',
settings: {
recipient: 'owner',
subject: 'Sales call in 15 mins!'
},
when: {
type: 'before',
unit: 'mins',
time: 15
}
}
]
Find details on each key by looking at our booking endpoint here.
Customer Fields
You can customize the booking form fields and their settings in customer_fields
. Only the name
, and email
are required by default (for the event creation to work properly).
Customer fields are flexible and highly customizable. You can create your own fields with different input types to collect all sorts of customer info. To add a new field, simply define a new object in customer_fields
object with the slug being an unique key.
Here's an example of changing the name of the email
field and adding a new department
dropdown field:
customer_fields: {
email: {
title: 'Your e-mail'
},
department: {
title: 'Your department',
required: true,
format: 'select',
enum: ['Design', 'Development', 'Sales']
}
}
Here's a complete list of all the settings you can set per field:
Field key | Description |
---|---|
title | The name of the field as shown in the form |
required | Boolean, defines whether the field is required or optional |
prefilled | Allows you to prefill the value in form. Set to false to disable. |
readonly | Allows you lock the field from customer input in the form. Set to false to disable. |
format | Defines the field type and how it should be rendered in the form. See table below. |
enum | Only used by fields that have "format" set to "select" (dropdown). Supply an array of possible values. |
Here's the possible values for the format
key:
Format value | Description |
---|---|
text | Standard text field. This is the default value if the "format" key is omitted entirely. |
textarea | Multi-line text field |
Text field with email validation | |
tel | Text field with phone number validation |
number | Text field with number/integer validation |
checkbox | A checkbox that allows the customer to tick on/off (saves result as true/false) |
select | Dropdown as a select field with multiple options to choose from. Declare possible options in the "enum" key (see above) |
If you're collecting user information before loading the widget, it can be useful to inject it into the form by setting the "prefilled" keys - just pass in the values and they will be set upon load. Combine it with "readonly" to lock the fields for user input.
Pre-filling input fields article
Learn how to prefill the fields through URL parameters or with dynamic values in our Help Center article
Here's a full example:
customer_fields: {
name: {
title: 'Full name',
prefilled: false,
readonly: false
},
email: {
title: 'E-mail',
prefilled: '[email protected]',
readonly: true
},
comment: {
title: 'Comment',
prefilled: false,
required: true,
readonly: false,
format: 'textarea'
},
phone: {
title: 'Phone number',
prefilled: false,
required: false,
readonly: false,
format: 'tel'
},
voip: {
title: 'Skype username',
prefilled: false,
required: false,
readonly: false
},
location: {
title: 'Location',
prefilled: false,
required: false,
readonly: false
}
}
See our customer fields example on GitHub.
UI
Changing the appearance of the widget can be achieved by configuring the widget ui
(User Interface).
ui: {
display_name: 'Martys Timetravel Service',
avatar: 'http://via.placeholder.com/100x100',
availability_view: 'agendaWeek',
timezone: null,
show_credits: true,
show_timezone_helper: true,
time_date_format: '12h-mdy-sun',
localization: {
allocated_resource_prefix: 'for',
submit_button: 'Book it now!',
success_message: 'Thanks for booking!'
}
}
Here's a few articles on how to achieve specific tasks:
Full Calendar
The Booking Widget is built on top of Full Calendar. Setting a fullcalendar
configuration will allow you to override all the internal FullCalendar settings.
Below is an example of us changing a few things:
fullcalendar: {
header: {
left: '',
center: '',
right: 'today, prev, next'
},
views: {
agenda: {
displayEventEnd: false
}
},
allDaySlot: false,
scrollTime: '08:00:00',
defaultView: sizing.view, // Inserted dynamically based on the current width of the widget
height: sizing.height, // Inserted dynamically based on the current width of the widget
eventClick: function(event), // Handled internally in Booking.js (overwrite if you want to replace the booking page)
windowResize: function(view) // Handled internally in Booking.js (overwrite if you want to disable or change automatic resizing)
}
Callbacks
With callbacks
, you can hook into events happening throughout the user flow and perform asynchronous events. This is especially powerful for saving user data to your CRM system or redirect users to a payment gateway after booking is finished.
Inspect the source code to learn more about in which order callbacks are fired. Below is a complete list of all callbacks available:
callbacks: {
fetchAvailabilityStarted: function(args) {},
fetchAvailabilitySuccessful: function(response) {},
fetchAvailabilityFailed: function(response) {},
createBookingStarted: function(args) {},
createBookingSuccessful: function(response) {},
createBookingFailed: function(response) {},
getUserTimezoneStarted: function(args) {},
getUserTimezoneSuccessful: function(response) {},
getUserTimezoneFailed: function(response) {},
fullCalendarInitialized: function() {},
renderCompleted: function() {},
showBookingPage: function(event) {},
closeBookingPage: function() {},
submitBookingForm: function(values) {},
errorTriggered: function(message) {}
}
Disable confirmation page
In some cases, you might want to only use the widget for selecting timeslots and implement a customer form outside of the widget in your own UI (or programmatically). To achieve this, you can use the "disable_confirm_page" setting.
Here's how:
- Add
disable_confirm_page: true
to the widget config object. - Register the
clickTimeslot
callback where the timeslot event data will be passed as a parameter - Do your magic here. Have the customer fill a form or fetch customer data from an API. That's up to you.
- Call the
timekitCreateBooking
instance method with two argument: the customer info and the timeslot event data. This will trigger the same booking creation request that the widget usually does, but with you in control. It returns a promise.
Here's a code example:
// Example customer info
var customer = {
name: 'Marty',
email: '[email protected]'
}
// Create a new widget instance and init it
var widget = new TimekitBooking();
widget.init({
// Usual settings here
// ...
disable_confirm_page: true,
callbacks: {
clickTimeslot: function (timeslot) {
// In this example, we just trigger the booking creation immediately
// with static customer info, but you could add any logic or steps
// in here instead.
widget.timekitCreateBooking(customer, timeslot)
.then(function () {
console.log('Success, booking created!');
})
}
}
});
You can also use this test case as reference/inspiration for how the setting is used.
Methods
After you instantiated the widget, you can control it with the following methods:
var widget = new TimekitBooking();
widget.init(config); // Initializes the widget with the given config
widget.render(); // Re-renders the widget with it's instance config
widget.setConfig(config); // Push a new config into it (call render() afterwards)
widget.getConfig(); // Returns the current config
widget.destroy(); // Cleans the DOM element and empty config
widget.fullCalendar(action); // Direct access to FullCalendar's own method (for advanced use)
Instantiation Methods
Only available when you're using the instantiation approach and not autoload
Updated 11 months ago