Availability editor
Weekly working hours and date overrides that set which slots can be booked. It loads its data on the server through the block's client.
pnpm dev:example) to see it.Add the components
terminal npx shadcn add badge card empty skeletonInstall the glue
Install the block with
npx better-supabase add bookings. The glue items are copied into your app, so edit them as you need.None: the page calls the block's client on the server.
Write the component
React and shadcn
View in the exampleavailability-editor.tsx export async function AvailabilityEditor() { const session = await getSession(); if (!can(session, "bookings.manage")) { forbidden(); } const [t, setup] = await Promise.all([ getExtracted("bookings"), settle(loadBookingSetup), ]); const page = setup.kind === "ok" ? setup.data.page : null; return ( <Card data-recipe="availability-editor"> <CardHeader> <CardTitle>{t("Weekly hours")}</CardTitle> <CardDescription> {page ? t( "Visitors can book 30 minute slots inside these hours, in {tz}.", { tz: page.tz, }, ) : t("The hours visitors can book you in.")} </CardDescription> {page ? ( <CardAction className="flex items-center gap-2"> <Badge variant={page.liveLinks > 0 ? "success-light" : "secondary"}> {t( "{count, plural, =0 {No live links} one {# live link} other {# live links}}", { count: page.liveLinks, }, )} </Badge> {can(session, "share_links.create") ? <BookingLinkButton /> : null} </CardAction> ) : null} </CardHeader> <CardContent> {setup.kind === "error" ? ( <BookingsLoadError title={t("Your booking page didn't load.")} /> ) : page && setup.kind === "ok" ? ( <WeeklyHoursForm hours={setup.data.hours} /> ) : ( <Empty className="border"> <EmptyHeader> <EmptyMedia variant="icon"> <CalendarClockIcon /> </EmptyMedia> <EmptyTitle>{t("No booking page yet")}</EmptyTitle> <EmptyDescription> {setup.kind === "missing" ? t("Pick an organization to set up a booking page.") : t( "Set it up with weekday hours from 09:00 to 17:00, then change them here.", )} </EmptyDescription> </EmptyHeader> {setup.kind === "ok" ? ( <EmptyContent> <SetUpBookingButton /> </EmptyContent> ) : null} </Empty> )} </CardContent> </Card> ); }