Bookings
The bookings view of plinth lives on book.timetospare.com. It is a public facing website that allows people to browse and book activities. The code is in the timetospare-book repo.
Creating an account

To book an activity on plinth, you need to have account and be logged in. This is because the booking system is designed to be integrated with the rest of the plinth platform, and so it attempts to connect the 2 profiles together.
On creating an account, it sends an account verification email (unless the user used the Google log in button):
if (user.email && !user?.emailVerified) {
const site =
process.env.NODE_ENV === 'production'
? 'https://book.timetospare.com'
: 'https://localhost:3001'
let link = `${site}/verify-email`
if (redirect) {
link = `${link}?redirect=${redirect}`
}
const actionCodeSettings = {
// URL you want to redirect back to. The domain (www.example.com) for this
// URL must be in the authorized domains list in the authentication system console.
url: link,
// This must be true.
handleCodeInApp: true,
}
sendEmailVerification(auth.currentUser, actionCodeSettings)
.then(() => {
window.localStorage.setItem('emailForSignIn', email)
setStage('email-verification')
})
.catch((error) => {
const errorCode = error.code
const errorMessage = error.message
// ...
})
}
This sign up flow is quite nice, because it starts by just asking for the email address, and then on the next stage will prompt the right sign up method (e.g. remembering the user's choice if they used Google last time). This uses the fetchSignInMethodsForEmail function.
Booking an activity
Once a user has an account, and has found their way to an activity they like, they can book it. This is typically done by clicking the "Book" or "Choose" button on the activity page.

The activity page itself fetches data in getStaticProps and revalidates every 60 seconds. The specific details of the event (e.g. the dates it is running and the remaining capacity) is fetched client-side.
Free and uncomplicated
To book a free and uncomplicated activity, clicking the "Book" or "Choose" button opens up a modal. This modal has a few different steps:
- Choose date(s)/time(s)
- Fill in the booking registration form
- Confirmation of the booking
This all happens in the Booking component.
The choose date and time is fairly straightforward, it's just a series of checkboxes for the relevant dates and time slots.
The booking registration form is a bit more complicated. This is handled by the ChooseAndUpdateProfile component. This fetches all the "profiles" for the user (e.g. their own details, those of their kids), across all the different organisations they have registered with. It shows a dropdown to select which profile to use, and then renders the relevant form for that profile with the relevant data pre-filled.
Saving the details happens in the saveBooking() function. This is a bit of a mess (because we used to handle multiple profiles differently), but the basic idea is to take all the dates selected, add the profile details to each one, and then write them to a batch object. This is then written to the database.
Complicated
Some activities we class as "complicated". This might mean e.g.:
- People have to book the whole activity (e.g. a holiday camp)
- There are eligibilty criteria (e.g. you have to be a certain age)
- There are multiple prices (e.g. for different age groups)
In these cases, the "Book" button takes you to a separate page, where it will calculate the right price and your eligibility before you can book it.

This page is at /programme/[orgId]/[eventId].
Payments
Managing your bookings/profile
Organisation pages
Other half-baked features
