RegistryUI recipes
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; the bookings block must be installed (npx better-supabase add bookings). Its page on bettersupabase.com is /recipes/availability-editor.
Web, with shadcn components:
npx shadcn add badge card empty skeletonexport 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>
);
}Last updated on