Room Booking Integration
Introduction
MapsIndoors offers powerful capabilities for integrating real-time data with indoor mapping, making it an ideal platform for implementing room booking systems. This guide explores how to connect external booking data sources with MapsIndoors to create a dynamic map that reflects real-time room availability and enables users to book spaces directly from the map interface.
Use Case: Benefits of Room Booking Integrations with your MapsIndoors Map
Room booking integration with MapsIndoors addresses several key challenges in modern workplace and facility management:
Improved Space Utilization: Users can quickly identify available rooms based on visual cues
Reduced Booking Conflicts: Real-time status updates prevent double-bookings and confusion
Streamlined User Experience: Booking directly from the map simplifies the workflow
Enhanced Wayfinding: Users can navigate to their booked spaces using the same interface
Data-Driven Decision Making: Facility managers gain insights into space usage patterns
This integration is particularly valuable in large facilities like corporate campuses, universities, hospitals, and conference centers where managing meeting spaces efficiently is crucial for operations.
Disclaimer
This guide presents one recommended approach to integrating room booking functionality with MapsIndoors. Your implementation may vary based on your existing technology stack, booking systems, and architectural preferences. Whether you choose to integrate with established calendar systems (Microsoft 365, Google Workspace), specialized booking platforms, or build a custom solution, the core concepts of mapping booking states to visual display rules remain applicable. The examples provided are intended to inspire your own implementation rather than prescribe a definitive solution. Furthermore, the code examples use the MapsIndoors Web SDK, but the approach can be used with the Android and iOS SDKs as well.
Please also view the code samples provided in this guide primarily as inspiration for your own application. It might need to be further improved or expanded to achieve your goals.
Prerequisites
To follow this guide, we assume that you already have a MapsIndoors map setup, have access to the MapsIndoors CMS and have familiarized yourself with our getting started guides for MapsIndoors Web SDK. Please visit our docsite or reach out to your MapsIndoors representative to get started.
Implementation Summary
Implementing room booking integration with MapsIndoors requires connecting your booking system data with map visualization through a series of coordinated steps. This approach ensures real-time availability information is accurately reflected on your indoor maps.
Configure location mapping in MapsIndoors: Set up external IDs in your MapsIndoors CMS for all bookable spaces (meeting rooms, desks, etc.) that match identifiers in your booking system, creating the foundation for data synchronization between platforms.
Establish booking system connectivity: Develop an API integration with your booking platform (Microsoft Exchange, Google Calendar, Condeco, Robin, or custom systems) using REST API calls, proper authentication, and data parsing to retrieve current booking status.
Map booking statuses to Display Rules: Create a mapping system that translates booking statuses (available, booked, pending) into MapsIndoors Display Rules, including polygon colors, opacity levels, and custom icons for clear visual representation.
Implement real-time updates: Set up mechanisms to maintain current booking data through either WebSocket connections for instant updates or polling strategies (periodic API calls) to ensure map accuracy.
Create the booking workflow: Develop click event handlers and booking interfaces that allow users to reserve spaces directly from the map, including form submission and confirmation processes.
Architecture Overview
The system architecture consists of interconnected components that manage data flow between your booking system and the MapsIndoors visualization layer. Data moves through these components in a coordinated sequence to maintain real-time accuracy and enable user interactions.
MapsIndoors SDK: The core JavaScript SDK that renders your indoor maps using either Google Maps or Mapbox as the base map provider. It loads and retrieves all bookable locations using LocationsService with filtering by location types (meetingroom, desk), establishing the foundation for map rendering and interaction.
Booking API status retrieval: The Booking API Client executes HTTP requests to your booking system's endpoints (Microsoft Graph API, Google Calendar API) to fetch current status information for all mapped locations.
Status Manager processing: The Status Manager receives booking data, maintains location state tracking, and calls MapsIndoors setDisplayRule methods to update visual appearance based on availability (green for available, red for booked).
User interaction handling: Click event listeners capture user interactions with available locations, trigger booking form displays, and send POST requests through the API Client to create new reservations in the external system.
Real-time update propagation: Status updates arrive via WebSocket connections or polling mechanisms, triggering the Status Manager to immediately update affected locations' Display Rules and maintain visual synchronization with booking changes.
This architecture follows a modular approach that separates concerns, making it easier to maintain and adapt to different booking systems. It can be implemented with any modern JavaScript framework or as vanilla JavaScript, depending on your application's existing technology stack.
Code Examples
Let's examine the implementation details through the provided code examples. Please remember that below examples aim to inspire. They are not production ready code.
1. Initializing MapsIndoors
const mapViewOptions = {
accessToken: 'YOUR_MAPBOX_TOKEN',
element: document.getElementById('map'),
center: { lat: YOUR_LAT, lng: YOUR_LNG },
zoom: 20,
maxZoom: 22,
};
const mapViewInstance = new mapsindoors.mapView.MapboxView(mapViewOptions);
const mapsIndoorsInstance = new mapsindoors.MapsIndoors({
mapView: mapViewInstance,
});
const mapboxInstance = mapViewInstance.getMap();
This code initializes the MapsIndoors instance with Mapbox as the base map provider, setting the initial view parameters.
2. Booking Status Management
class BookingStatusManager {
constructor(mapsIndoorsInstance) {
this.mapsIndoors = mapsIndoorsInstance;
this.locationStatuses = new Map();
this.displayRules = {
available: {
polygonVisible: true,
polygonFillColor: '#4CAF50', // Green
polygonFillOpacity: 0.3,
iconUrl: 'path/to/available-icon.png'
},
occupied: {
polygonVisible: true,
polygonFillColor: '#F44336', // Red
polygonFillOpacity: 0.3,
iconUrl: 'path/to/occupied-icon.png'
},
pending: {
polygonVisible: true,
polygonFillColor: '#FFC107', // Amber
polygonFillOpacity: 0.3,
iconUrl: 'path/to/pending-icon.png'
}
};
}
async initialize() {
// Get all bookable locations
const bookableLocations = await mapsindoors.services.LocationsService
.getLocations({
types: ['meetingroom', 'workspace']
});
// Initialize status tracking
bookableLocations.forEach(location => {
this.locationStatuses.set(location.id, {
id: location.id,
status: 'available',
lastUpdated: new Date(),
bookingData: null
});
});
// Apply initial display rules
this.updateAllDisplayRules();
}
updateAllDisplayRules() {
// Group locations by status to enable batch operations
const locationsByStatus = new Map();
// Initialize status groups
Object.keys(this.displayRules).forEach(status => {
locationsByStatus.set(status, []);
});
// Group location IDs by their current status
this.locationStatuses.forEach((statusData, locationId) => {
const statusGroup = locationsByStatus.get(statusData.status);
if (statusGroup) {
statusGroup.push(locationId);
}
});
// Apply display rules in batches for each status
locationsByStatus.forEach((locationIds, status) => {
if (locationIds.length > 0) {
this.mapsIndoors.setDisplayRule(
locationIds, // Pass array of location IDs for batch operation
this.displayRules[status]
);
}
});
}
// Method to update status of specific locations and batch update display rules
updateLocationStatuses(statusUpdates) {
// statusUpdates is an array of objects: [{id, status, bookingData}, ...]
statusUpdates.forEach(update => {
if (this.locationStatuses.has(update.id)) {
this.locationStatuses.set(update.id, {
...this.locationStatuses.get(update.id),
status: update.status,
lastUpdated: new Date(),
bookingData: update.bookingData || null
});
}
});
// Batch update display rules for all affected locations
this.updateAllDisplayRules();
}
// Method to update a single location status
updateLocationStatus(locationId, status, bookingData = null) {
this.updateLocationStatuses([{
id: locationId,
status: status,
bookingData: bookingData
}]);
}
}
The BookingStatusManager class handles:
Defining Display Rules for different room statuses (available, occupied, pending).
Retrieving all bookable locations from MapsIndoors using the LocationsService.
Tracking the current status of each location.
Applying Display Rules based on status using batch processing for optimized performance.
3. Booking API Integration
//Implement authentication for your Booking API or Booking provider first
class BookingAPIClient {
constructor(baseUrl) {
this.baseUrl = baseUrl;
}
async getLocationStatus(locationId) {
try {
const response = await fetch(
`${this.baseUrl}/location-status/${locationId}`
);
if (!response.ok) throw new Error('Status fetch failed');
return await response.json();
} catch (error) {
console.error('Error fetching status:', error);
return null;
}
}
async bookLocation(locationId, bookingDetails) {
try {
const response = await fetch(
`${this.baseUrl}/book/${locationId}`,
{
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(bookingDetails)
}
);
if (!response.ok) throw new Error('Booking failed');
return await response.json();
} catch (error) {
console.error('Error booking location:', error);
return null;
}
}
}
This API client provides methods to:
Fetch the current status of a location from the booking system.
Send booking requests to the external API.
4. Real-time Updates and Workflow
Note: Below we provide an example for a Websocket based approach. Alternative solutions exist (e.g. pub-sub, cloud-based services, http-polling, etc.). Choose the approach that suits your needs and overall architecture the best.
class BookingWorkflow {
constructor(mapsIndoorsInstance, apiBaseUrl) {
this.statusManager = new BookingStatusManager(mapsIndoorsInstance);
this.apiClient = new BookingAPIClient(apiBaseUrl);
this.setupWebSocket();
}
setupWebSocket() {
this.ws = new WebSocket('YOUR_WEBSOCKET_ENDPOINT');
this.ws.onmessage = async (event) => {
const update = JSON.parse(event.data);
await this.handleStatusUpdate(update);
};
this.ws.onerror = (error) => {
console.error('WebSocket error:', error);
// Implement retry logic
setTimeout(() => this.setupWebSocket(), 5000);
};
}
async handleStatusUpdate(update) {
const { locationId, status, bookingData } = update;
if (!this.statusManager.locationStatuses.has(locationId)) {
return;
}
// Update status tracking
this.statusManager.locationStatuses.set(locationId, {
id: locationId,
status,
lastUpdated: new Date(),
bookingData
});
// Apply new display rule
this.statusManager.mapsIndoors.setDisplayRule(
locationId,
this.statusManager.displayRules[status]
);
// Emit event for UI updates
this.emit('statusChanged', {
locationId,
status,
bookingData
});
}
async bookLocation(locationId, bookingDetails) {
// Set pending state
await this.handleStatusUpdate({
locationId,
status: 'pending',
bookingData: null
});
// Attempt booking
const result = await this.apiClient.bookLocation(
locationId,
bookingDetails
);
if (result && result.success) {
await this.handleStatusUpdate({
locationId,
status: 'occupied',
bookingData: result.bookingData
});
return true;
} else {
// Revert to previous state
const currentStatus = await this.apiClient
.getLocationStatus(locationId);
await this.handleStatusUpdate({
locationId,
status: currentStatus.status,
bookingData: currentStatus.bookingData
});
return false;
}
}
}
The BookingWorkflow class handles:
Setting up WebSocket connections for real-time updates.
Processing status updates from the server.
Managing the booking process with intermediate states.
Updating Display Rules in response to status changes.
5. Putting It All Together
// Initialize the workflow
async function initializeBookingWorkflow() {
const workflow = new BookingWorkflow(
mapsIndoorsInstance,
'https://your-api-endpoint.com'
);
// Initialize status tracking
await workflow.statusManager.initialize();
// Set up click handling
mapsIndoorsInstance.addListener('click', async (location) => {
if (!location) return;
const status = workflow.statusManager.locationStatuses
.get(location.id);
if (!status) return;
if (status.status === 'available') {
const shouldBook = confirm(
`Would you like to book ${location.properties.name}?`
);
if (shouldBook) {
const bookingDetails = {
startTime: new Date(),
duration: 60, // minutes
userId: 'current-user-id'
};
const success = await workflow.bookLocation(
location.id,
bookingDetails
);
if (success) {
alert('Booking successful!');
} else {
alert('Booking failed. Please try again.');
}
}
} else if (status.status === 'occupied') {
alert(
`This location is booked until ${
new Date(status.bookingData.endTime).toLocaleTimeString()
}`
);
}
});
return workflow;
}
// Start everything when MapsIndoors is ready
mapsIndoorsInstance.addListener('ready', async () => {
const workflow = await initializeBookingWorkflow();
console.log('Booking workflow initialized');
});
This initialization code:
Creates the booking workflow when MapsIndoors is ready.
Sets up click event handling on map locations.
Implements the user interaction flow for booking available rooms.
Provides feedback about occupied rooms.
Summary
Room booking integration with MapsIndoors transforms how users discover and reserve spaces by combining real-time availability data with intuitive map-based interactions. This solution addresses common workplace challenges like booking conflicts and inefficient space utilization while providing a seamless user experience.
With the architecture and implementation steps outlined in this guide, you're ready to begin development. Start by configuring your location mappings and establishing API connectivity with your booking system, then progressively add real-time updates and user interaction features. Consider extending the basic implementation with advanced capabilities like booking analytics, occupancy insights, or integration with additional workplace systems to maximize the value of your indoor mapping investment.
Last updated
Was this helpful?