Book a meeting
Pick a day, then a free time slot.
Sara Malik Payroll specialist, People Ops
Benefits consultation
Questions about pension, health cover or your 2027 benefits choices.
- 30 minutes
- Video call, link sent by email
1. Pick a day
October 2026
| Sun | Mon | Tue | Wed | Thu | Fri | Sat |
|---|---|---|---|---|---|---|
27 | 28 | 29 | 30 | 1 | 2 | 3 |
4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 |
1 | 2 | 3 | 4 | 5 | 6 | 7 |
2. Pick a time on Thursday 15 October
Times are Pakistan Standard Time (UTC+5).
book-a-meeting.tsx
"use client";
import { useState } from "react";
import { isWeekend, parseDate, toCalendarDate, type CalendarDate } from "@internationalized/date";
import { LuClock, LuVideo } from "react-icons/lu";
import {
Alert,
AvatarLabel,
Avatar,
Button,
CalendarMonth,
CalendarTimeSlot,
} from "@nexera-ui/react";
const ZONE = "Asia/Karachi";
const FIRST_DAY = parseDate("2026-10-14");
const LAST_DAY = parseDate("2026-11-30");
const TIMES = [
"09:00",
"09:30",
"10:00",
"10:30",
"11:00",
"11:30",
"14:00",
"14:30",
"15:00",
"15:30",
"16:00",
"16:30",
];
/** Sara's calendar: which slots are taken on a given day (a fixed pattern, so the demo is the same on every render). */
const isBusy = (day: CalendarDate, index: number) =>
(day.day + index * 3) % 5 === 0 || (day.day % 2 === 0 && index === 6);
/** Book a meeting: pick a day in the month, then a free 30-minute slot, and confirm. */
export default function BookAMeeting() {
const [day, setDay] = useState<CalendarDate>(parseDate("2026-10-15"));
const [time, setTime] = useState<string | null>(null);
const [booked, setBooked] = useState(false);
const label = new Intl.DateTimeFormat("en-GB", {
weekday: "long",
day: "numeric",
month: "long",
timeZone: "UTC",
}).format(day.toDate("UTC"));
return (
<div className="@container bg-page px-4 py-8 @3xl:px-8">
<section
aria-labelledby="book-title"
className="mx-auto grid w-full max-w-4xl gap-6 rounded-xl border border-default bg-surface p-4 shadow-sm @3xl:p-6 @5xl:grid-cols-[16rem_1fr_1fr]"
>
<header className="grid content-start gap-3">
<AvatarLabel
name="Sara Malik"
subtitle="Payroll specialist, People Ops"
size="md"
avatar={<Avatar size="md" initials="SM" isDecorative />}
/>
<h2 id="book-title" className="text-heading-h3 text-primary">
Benefits consultation
</h2>
<p className="text-body-default text-secondary">
Questions about pension, health cover or your 2027 benefits choices.
</p>
<ul className="m-0 grid list-none gap-1.5 p-0 text-body-small text-secondary">
<li className="flex items-center gap-2">
<LuClock aria-hidden="true" /> 30 minutes
</li>
<li className="flex items-center gap-2">
<LuVideo aria-hidden="true" /> Video call, link sent by email
</li>
</ul>
</header>
<div className="grid content-start gap-2">
<h3 className="text-body-strong text-primary">1. Pick a day</h3>
<CalendarMonth
aria-label="Meeting day"
value={day}
minValue={FIRST_DAY}
maxValue={LAST_DAY}
isDateUnavailable={(date) => isWeekend(date, "en-GB")}
onChange={(value) => {
setDay(toCalendarDate(value));
setTime(null);
setBooked(false);
}}
/>
</div>
<div className="grid content-start gap-3">
<h3 id="slots-title" className="text-body-strong text-primary">
2. Pick a time on {label}
</h3>
<ul
aria-labelledby="slots-title"
className="m-0 grid list-none grid-cols-2 gap-2 p-0 @3xl:grid-cols-3 @5xl:grid-cols-2"
>
{TIMES.map((t, i) => (
<li key={t}>
<CalendarTimeSlot
cellRole="presentation"
time={t}
start={new Date(`${day.toString()}T${t}:00+05:00`)}
timeZone={ZONE}
status={isBusy(day, i) ? "busy" : "available"}
isSelected={time === t}
onChange={(on) => {
setTime(on ? t : null);
setBooked(false);
}}
className="w-full"
/>
</li>
))}
</ul>
<p className="text-body-small text-secondary">
Times are Pakistan Standard Time (UTC+5).
</p>
<Button
size="md"
isDisabled={time === null || booked}
onPress={() => {
setBooked(true);
}}
>
{time ? `Book ${label}, ${time}` : "Choose a time"}
</Button>
{booked ? (
<Alert
tone="success"
title="Meeting booked"
description={`You and Sara Malik on ${label} at ${time}. An invite is on its way.`}
politeness="polite"
/>
) : null}
</div>
</section>
</div>
);
}
More scheduling and calendar blocks
- Month calendarEvents across a month, with a 'more' overflow.
- Week calendarHour-by-hour week view with events.
- Team availabilityWho is free when, side by side.
- Event detailsA popover with time, place and people.
- Leave requestRequest time off and see the balance.
- Leave approvalReview a request and approve or decline.
- Shift pickerChoose a morning, evening or night shift.