TypeScript library for BookingLab and JRNI APIs with React hooks support
npm install @bookinglab/booking-journey-apiA lightweight, developer-friendly TypeScript library for BookingLab and JRNI APIs. Supports both vanilla JavaScript/TypeScript and React applications.
- 🎯 Type-safe - Full TypeScript support with comprehensive type definitions
- ⚛️ React-ready - Context providers and hooks for seamless React integration
- 🌳 Tree-shakable - Only bundle what you use
- 🔧 Flexible - Works with vanilla JS/TS or React
- 📦 Lightweight - Minimal dependencies
``bash`
npm install @bookinglab/booking-journey-api
For React applications, you'll also need:
`bash`
npm install @tanstack/react-query
#### JRNI API
`typescript
import { createJrniClient } from '@bookinglab/booking-journey-api';
const client = createJrniClient('https://api.jrni.com', {
appId: 'your-app-id',
appKey: 'your-app-key',
});
// Login
const response = await client.login({
email: 'user@example.com',
password: 'password',
});
console.log(response.data.auth_token);
`
#### BookingLab API
`typescript
import { createBookingLabClient } from '@bookinglab/booking-journey-api';
const client = createBookingLabClient({ baseUrl: 'https://api.bookinglab.com' });
client.setAuthToken('your-auth-token');
// Get bookings
const bookings = await client.getBookings();
// Get services
const services = await client.getServices();
// Create a booking
const newBooking = await client.createBooking({
userId: 'user-123',
serviceId: 'service-456',
date: '2024-01-15T10:00:00Z',
});
`
#### Single Provider (JRNI Only)
`tsx
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { JrniProvider, useLogin } from '@bookinglab/booking-journey-api';
const queryClient = new QueryClient();
function App() {
return (
config={{ appId: 'your-app-id', appKey: 'your-app-key' }}
>
);
}
function LoginForm() {
const loginMutation = useLogin();
const handleLogin = () => {
loginMutation.mutate({
email: 'user@example.com',
password: 'password',
});
};
return (
);
}
`
#### Single Provider (BookingLab Only)
`tsx
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { BookingLabProvider, useBookings, useServices } from '@bookinglab/booking-journey-api';
const queryClient = new QueryClient();
function App() {
return (
authToken="your-auth-token"
>
);
}
function Dashboard() {
const { data: bookings, isLoading } = useBookings();
const { data: services } = useServices();
if (isLoading) return
return (
#### Combined Provider (Both APIs)
`tsx
import { ApiClientProvider, useJrniClient, useBookingLabClient } from '@bookinglab/booking-journey-api';function App() {
return (
bookingLabBaseUrl="https://api.bookinglab.com"
jrniBaseUrl="https://api.jrni.com"
jrniConfig={{ appId: 'your-app-id', appKey: 'your-app-key' }}
authToken="your-auth-token"
>
);
}
function YourApp() {
const jrniClient = useJrniClient();
const bookingLabClient = useBookingLabClient();
// Use both clients as needed
}
`API Reference
$3
####
createJrniClient(baseUrl, config)Creates a new JRNI client instance.
`typescript
const client = createJrniClient('https://api.jrni.com', {
appId: 'your-app-id',
appKey: 'your-app-key',
});
`Methods:
-
client.login(credentials) - Authenticate a user
- client.forgottenPassword(companyId, request) - Request password reset email
- client.getChildCompanies(companyId, params?) - Get child companies for a parent company
- client.getResources(companyId) - Get bookable resources for a company
- client.getServices(companyId) - Get services for a company
- client.createBasket(request) - Create a new basket
- client.clearBaskets() - Clear all baskets
- client.addServiceItem(basketId, serviceItem) - Add a service item to a basket
- client.getTimes(companyId, params) - Get available booking times for a service
- client.getQuestions(companyId, params) - Get questions for a detail group
- client.checkoutBasket(basketId, request) - Checkout a basket with client details
- client.listBookings(companyId, memberId, params, authToken) - Get member bookings
- client.setAuthToken(token) - Set auth token for subsequent requests####
createBookingLabClient(options)Creates a new BookingLab client instance.
`typescript
const client = createBookingLabClient({ baseUrl: 'https://api.bookinglab.com' });
client.setAuthToken('your-auth-token');
`Methods:
-
client.getBookings() - Get all bookings
- client.getBooking(id) - Get a specific booking
- client.createBooking(data) - Create a new booking
- client.updateBooking(id, data) - Update a booking
- client.cancelBooking(id) - Cancel a booking
- client.deleteBooking(id) - Delete a booking
- client.getServices() - Get all services
- client.getService(id) - Get a specific service
- client.setAuthToken(token) - Set auth token for subsequent requests$3
####
JrniProviderProvides JRNI client context to React components.
`tsx
baseUrl="https://api.jrni.com"
config={{ appId: 'your-app-id', appKey: 'your-app-key' }}
>
{children}
`####
BookingLabProviderProvides BookingLab client context to React components.
`tsx
baseUrl="https://api.bookinglab.com"
authToken="your-auth-token"
>
{children}
`####
ApiClientProviderCombined provider for applications using multiple API clients.
`tsx
bookingLabBaseUrl="https://api.bookinglab.com"
jrniBaseUrl="https://api.jrni.com"
jrniConfig={{ appId: 'your-app-id', appKey: 'your-app-key' }}
authToken="your-auth-token"
>
{children}
`$3
#### JRNI Hooks
-
useLogin() - Hook for user authentication
- useForgottenPassword(companyId) - Request password reset email
- useChildCompanies(companyId, params?, enabled?) - Get child companies
- useResources(companyId, enabled?) - Get bookable resources
- useServices(companyId, enabled?) - Get services for a company
- useCreateBasket() - Create a new basket
- useClearBaskets() - Clear all baskets
- useAddServiceItem(basketId) - Add a service item to a basket
- useTimes(companyId, params, enabled?) - Get available booking times for a service
- useQuestions(companyId, params, enabled?) - Get questions for a detail group
- useCheckoutBasket(basketId, authToken) - Checkout a basket with client details
- useListBookings(companyId, memberId, params, authToken, enabled?) - Get member bookings
- useJrniClient() - Access the JRNI client directly`typescript
const loginMutation = useLogin();
loginMutation.mutate({ email: 'user@example.com', password: 'password' });// Request password reset
const forgotPasswordMutation = useForgottenPassword(37004);
forgotPasswordMutation.mutate({ email: 'user@example.com' });
// Response: { result: 'Success', message: 'An e-mail has been sent if the login information is valid.' }
const { data: childCompanies } = useChildCompanies(37000);
const { data: resources } = useResources(37000);
const { data: services } = useServices(37000);
const createBasketMutation = useCreateBasket();
createBasketMutation.mutate({ company_id: 37000 });
// With auth token for authenticated users:
// createBasketMutation.mutate({ company_id: 37000, authToken: 'user-auth-token' });
const clearBasketsMutation = useClearBaskets();
clearBasketsMutation.mutate();
// With auth token: clearBasketsMutation.mutate({ authToken: 'user-auth-token' });
const addServiceItemMutation = useAddServiceItem('basket-123');
addServiceItemMutation.mutate({
service_id: 1,
start: '2024-01-15T10:00:00Z',
questions: [{ id: '123', answer: 'John Doe' }, { id: '456', answer: 'john@example.com' }]
});
// With auth token, pass as second argument to mutate
const { data: times } = useTimes(37000, { service_id: 48320, start_date: '2025-01-15' });
// times.times = [{ start: "2025-01-15T09:00:00+00:00", available: true, durations: [30, 60, 90] }, ...]
const { data: questions } = useQuestions(37000, { detail_group_id: 18529 });
// questions.questions = [{ id: 3, name: "Do you require equipment?", detail_type: "text_area", ... }]
const checkoutMutation = useCheckoutBasket('basket-123', 'user-auth-token');
checkoutMutation.mutate({
client: { id: 'client-456' },
take_from_wallet: false,
no_notifications: false,
reference: 'REF-001'
});
const { data: bookings } = useListBookings(
37001, // companyId
19, // memberId
{
start_date: '2026-01-15',
end_date: '2026-07-15',
include_cancelled: 'false'
},
'user-auth-token' // authToken (required)
);
// bookings._embedded.bookings = [{ id: 523, service_name: "...", datetime: "...", ... }]
const client = useJrniClient();
`#### BookingLab Hooks
-
useBookings() - Get all bookings
- useBooking(id) - Get a specific booking
- useCreateBooking() - Create a new booking
- useUpdateBooking() - Update a booking
- useCancelBooking() - Cancel a booking
- useServices() - Get all services
- useService(id) - Get a specific service
- useBookingLabClient() - Access the BookingLab client directly`typescript
const { data: bookings, isLoading } = useBookings();
const { data: services } = useServices();
const createBookingMutation = useCreateBooking();createBookingMutation.mutate({
userId: 'user-123',
serviceId: 'service-456',
date: '2024-01-15T10:00:00Z',
});
const client = useBookingLabClient();
`Types
The library exports comprehensive TypeScript types:
`typescript
import type {
// JRNI Types
LoginRequest,
LoginResponse,
ChildCompany,
ChildCompanyAddress,
ChildCompanySettings,
ChildCompaniesResponse,
GetChildCompaniesParams,
Resource,
ResourceLinks,
ResourcesResponse,
JrniService,
ServicesResponse,
Question,
QuestionsResponse,
Location,
LocationsResponse,
Vehicle,
VehiclesResponse,
JrniBooking,
MemberBookingsResponse,
AvailabilityTime,
AvailabilityTimesResponse,
ClearBasketsResponse,
AddServiceItemRequest,
AddServiceItemAssets,
ServiceItemResponse,
GetTimesParams,
TimeSlot,
TimesResponse,
GetQuestionsParams,
Question,
QuestionsResponse,
CreateBasketRequest,
CreateBasketResponse,
CheckoutBasketRequest,
CheckoutBasketResponse,
CheckoutBasketClient,
ListBookingsParams,
MemberBooking,
ListBookingsResponse,
ForgottenPasswordRequest,
ForgottenPasswordResponse,
// BookingLab Types
Booking,
CreateBookingRequest,
Service,
} from '@bookinglab/booking-journey-api';
`$3
When calling
useServices(companyId) or client.getServices(companyId), you'll receive a ServicesResponse:`typescript
{
total_entries: 2,
_embedded: {
services: [
{
id: 48320,
category_id: 1,
name: "Football 3G Astroturf Pitch Hire",
description: "Book a 3G Astroturf pitch",
durations: [60, 90, 120, 150, 180],
prices: [0, 0, 0, 0, 0],
detail_group_id: 18528,
listed_durations: [],
extra: {},
booking_time_step: 30,
can_refund_automatically: false,
is_event_group: false,
type: "service",
group_id: 1,
deleted: false,
queuing_disabled: true,
company_id: 37001,
min_advance_period: 172800, // seconds (2 days)
max_advance_period: 7776000, // seconds (90 days)
min_cancel_period: 172800, // seconds (2 days)
booking_type_public: "booking",
booking_type: 3,
mbooking_type: 5,
min_bookings: 1,
max_bookings: 1,
method_of_appointment: "In-person",
groups: [],
order: 48320,
child_level_service: false,
global_id: 48320,
availability: 0,
prices_in_major_units: [0.0, 0.0, 0.0, 0.0, 0.0],
combine_resource_and_staff: false,
disabled: false,
_links: {
self: { href: "https://api.jrni.com/api/v5/37001/services/48320" },
items: { href: "https://api.jrni.com/api/v5/37001/services/48320/items" }
}
}
]
},
_links: {
self: { href: "https://api.jrni.com/api/v5/37001/services" }
}
}
`$3
`typescript
interface JrniService {
id: number; // Unique service identifier
name: string; // Display name
description: string; // Service description
durations: number[]; // Available durations in minutes
prices: number[]; // Prices corresponding to durations (in minor units)
detail_group_id: number; // Associated detail group ID
listed_durations: any[]; // Publicly listed durations
extra: Record; // Custom extra fields
booking_time_step: number; // Booking time interval in minutes
can_refund_automatically: boolean; // Auto-refund capability
is_event_group: boolean; // Whether this is an event group
type: string; // Service type (e.g., "service")
group_id: number | null; // Parent group ID
deleted: boolean; // Soft delete flag
queuing_disabled: boolean; // Queue functionality flag
company_id: number; // Owning company ID
min_advance_period: number; // Minimum advance booking time (seconds)
max_advance_period: number; // Maximum advance booking time (seconds)
min_cancel_period: number; // Minimum cancellation notice (seconds)
booking_type_public: string; // Public booking type label
booking_type: number; // Internal booking type code
mbooking_type: number; // Mobile booking type code
min_bookings: number; // Minimum bookings required
max_bookings: number; // Maximum bookings allowed
method_of_appointment: string; // Appointment method (e.g., "In-person")
groups: any[]; // Associated groups
order: number; // Display order
child_level_service: boolean; // Child company service flag
global_id: number; // Global service identifier
availability: number; // Availability status
prices_in_major_units: number[]; // Prices in major currency units
combine_resource_and_staff: boolean; // Resource/staff combination flag
disabled: boolean; // Service disabled flag
_links: Record; // HAL links
}
``MIT