Spa Day Package Builder
A spa package builder: five service categories (Massage, Facial, Body, Nails, Add-ons) each list a few addable items with duration and price. Clicking Add pushes an item into a running package shown in a summary panel, where each line can be removed individually. The panel shows live total duration and price, an animated progress bar toward a bundle-discount threshold, and two quick-start preset buttons that replace the whole package with a fixed set of items.
Docs
Installation
A real shadcn registry command, not a copy-paste stand-in: it fetches this block plus its button dependencies and any missing npm packages, and installs them straight into your project.
npx shadcn add https://staaarter.com/r/spa-day-package-builder.jsonPrefer not to use the CLI? Copy the source from the Code toggle above into src/components/blocks/booking/booking22.tsx instead.
Usage
The file also exports booking22Demo, 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 { Booking22, booking22Demo } from "@/components/blocks/booking/booking22"; export default function Page() { return <Booking22 {...booking22Demo} />; }
Props
| Prop | Type | Default | Description |
|---|---|---|---|
| heading | string | "Build your spa day" | Section heading. |
| subheading | string | "Mix and match services into your own package, or start from a preset." | Supporting copy under the heading. |
| className | string | none | Extra classes for the outer section element. |
Types
interface CatalogItem { id: string; name: string; duration: number; price: number; } interface PackageLine extends CatalogItem { uid: number; }
Behavior notes
- Clicking 'Add' next to any service pushes a real copy of that item into the package array (a useState array of PackageLine, each tagged with a unique incrementing uid so duplicates and removal both work correctly).
- Each line in the 'Your package' summary has a real X remove button that filters that line out of the array by its uid.
- Total duration and total price are computed live from the current package array on every render.
- The bundle-discount progress bar's fill width is computed live as `Math.min(100, (totalPrice / threshold) * 100)`, a deterministic function of state, not `Math.random()`; once the total crosses the fixed $150 threshold a real 10% discount is applied to the displayed total due.
- The 'Relax & Restore' and 'Full Glow-Up' quick-start buttons replace the entire package array with a fixed, hardcoded preset list of items, no randomness involved.
- The 'Book package' button is decorative only, no submission handler is wired since that would require a real backend.
More Booking Blocks
View all →date-time-picker
Date & Time Picker
Split-panel scheduler: a real monthly calendar on the left, morning/afternoon time slots on the right, and a live booking summary footer.
reservation-summary
Reservation Summary
A static booking confirmation card with service, date/time, provider avatar, price breakdown, promo code field, and cancellation policy.
appointment-list
Appointment List
Upcoming and past appointments grouped by date, with provider avatar, status badge, and reschedule/cancel actions.
service-selector
Service Selector
Category-tabbed grid of bookable services with icon, description, duration, and price.
provider-picker
Provider Picker
A selectable grid of staff/provider cards with rating, reviews, availability, and an Any Provider fallback.
restaurant-reservation
Restaurant Reservation
Table reservation form with a guest stepper, date/time inputs, seating pills, and a live summary panel.