Staaarter

Booking Workspace

Split hotel booking dashboard: a tabbed left panel (Overview, Bookings, Rooms) with revenue, occupancy, and stay metrics, toggleable active-booking cards showing a room-availability timeline, and a right calendar rail with a real month grid and a per-day agenda list.

By Staaarter Team
Dashboard
Docs
Live preview

Docs

Installation

A real shadcn registry command, not a copy-paste stand-in: it fetches this block plus its button, badge dependencies and any missing npm packages, and installs them straight into your project.

npx shadcn add https://staaarter.com/r/booking-workspace.json

Prefer not to use the CLI? Copy the source from the Code toggle above into src/components/blocks/dashboard/dashboard5.tsx instead.

Usage

The file also exports dashboard5Demo, the exact props behind the preview above. Spread it to get a working section in one line, then replace it with your own data.

import { Dashboard5, dashboard5Demo } from "@/components/blocks/dashboard/dashboard5";

export default function Page() {
  return <Dashboard5 {...dashboard5Demo} />;
}

Props

PropTypeDefaultDescription
propertyNamestring"Harbor View Inn"Name shown in the top header.
manageMenuItemsstring[]["New booking", "Export bookings", "Workspace settings"]Labels listed in the Manage dropdown.
revenueRevenueMetricnoneRevenue tile in the Overview bento grid.
occupancyRatenumbernone0-100 value rendered by the occupancy RadialGauge.
avgStaySimpleMetricnoneAverage length-of-stay tile.
imageTileImageTilenonePhoto tile in the bento grid.
activeBookingsActiveBooking[]noneToggleable booking cards shown in the Overview tab.
roomTimelinesRoomTimeline[]nonePer-room booked/available segment strips, matched to cards and rooms by room name.
bookingsBookingRow[]noneFull booking list rendered as a table in the Bookings tab.
roomsRoomStatusItem[]noneRoom list with status and rate rendered in the Rooms tab.
calendarCalendarConfignoneFixed month/year and weekday-offset used to lay out the calendar grid.
agendaByDayRecord<number, AgendaItem[]>noneTime-slotted agenda rows keyed by day-of-month; days with no entry show an empty state.
classNamestringnoneExtra classes for the outer section element.

Types

type RevenueMetric = { label: string; value: string; delta: string; trend: "up" | "down" };
type SimpleMetric = { label: string; value: string; helper?: string };
type ImageTile = { src: string; alt: string; caption?: string };

type ActiveBooking = {
  id: string;
  guest: string;
  room: string;
  checkIn: string;
  checkOut: string;
  guests: number;
  status: "Confirmed" | "Checked in" | "Pending";
  notes: string;
};

type RoomTimeline = { room: string; segments: { status: "booked" | "available" }[] };

type BookingRow = {
  id: string;
  guest: string;
  room: string;
  checkIn: string;
  checkOut: string;
  status: "Confirmed" | "Checked in" | "Pending" | "Checked out";
};

type RoomStatusItem = { name: string; type: string; status: "Occupied" | "Vacant" | "Cleaning"; rate: string };

type CalendarConfig = {
  monthLabel: string;
  year: number;
  startWeekday: number; // 0 = Sunday, column offset for day 1
  daysInMonth: number;
  bookedDays: number[]; // days that render a small dot marker
  defaultSelectedDay: number;
};

type AgendaItem = { time: string; title: string; room: string };

Behavior notes

  • The Overview/Bookings/Rooms tab bar is real: it's a hand-written button group (not a UI-kit Tabs primitive) that swaps which panel renders below via local state.
  • The Manage button is a genuine open/close toggle for a small inline dropdown, but its menu items are decorative and only close the menu when clicked.
  • Active booking cards genuinely expand/collapse on click, revealing notes, guest count, and that room's availability timeline; only one card's notes are shown expanded by default.
  • The room-availability timeline is a static, evenly divided six-segment strip per room (booked vs. available) that is not tied to a real clock; it does not recompute as time passes.
  • The month calendar grid is laid out from the fixed calendar.startWeekday/daysInMonth props rather than a live Date object, so it renders identically on the server and in card thumbnails.
  • Clicking a calendar day is real: it updates selectedDay and swaps the agenda list below to that day's entries from agendaByDay, falling back to a 'No bookings scheduled' empty state when a day has no entries.
  • The dot marker on a calendar day only reflects membership in calendar.bookedDays; it is independent of whether that day has agenda entries.