Booking Section Enhancement Implementation Plan
For agentic workers: REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (
- [ ]) syntax for tracking.
Goal: Enhance BookingSection on /booking page to match the spec's conversion requirements — proper pricing display, scarcity signals, and integrated 4-step booking flow.
Architecture: Booking section serves as the entry point. Clicking "Book Now" opens the modal with the full 4-step flow (tickets → addons → checkout → confirmation). Scarcity signals and countdown timer maintain urgency throughout.
Tech Stack: Next.js 16, Tailwind CSS v4, Radix UI, Convex, paraglide-js i18n
File Structure
apps/frontend/
├── app/[locale]/(landing)/booking/
│ └── page.tsx # Booking page (receives BookingSection)
├── components/home/
│ └── booking-section.tsx # Grid of ExperienceCards with availability
├── components/booking/
│ ├── experience-card.tsx # Already exists - card with price + scarcity
│ ├── booking-modal.tsx # Already exists - 4-step modal flow
│ ├── countdown-timer.tsx # Already exists - 10-minute timer
│ ├── sticky-cart.tsx # Already exists - persistent cart sidebar
│ └── sticky-cart-footer.tsx # Mobile sticky footer
├── contexts/booking-modal-context.tsx # Already exists - modal state
└── lib/utils/availability.ts # Already exists - computeAvailabilityTask 1: Enhance ExperienceCard with Price Display
Files:
- Modify:
apps/frontend/components/booking/experience-card.tsx - Modify:
apps/frontend/components/home/booking-section.tsx
The spec requires: Price displayed as "From [amount] VND", availability badge, and two buttons ("Discover" / "Book Now").
- Step 1: Update ExperienceCardData type to include price
// In experience-card.tsx, add price field
export type ExperienceCardShow = {
// ... existing fields
defaultDinnerPrice?: number;
defaultShowOnlyPrice?: number; // NEW
};- Step 2: Update useBookingData to map price from event
// In booking-section.tsx
const shows: ExperienceCardData[] = useMemo(() => {
if (!rawEvents) return [];
return rawEvents.map((event) => ({
event: {
/* existing */
},
show: {
_id: event.experienceCode,
title: event.experienceTitle,
slug: event.experienceSlug,
gallery: [] as string[],
defaultDinnerPrice: event.dinnerPrice, // NEW - already there
defaultShowOnlyPrice: event.showOnlyPrice, // NEW
},
}));
}, [rawEvents]);- Step 3: Add price display to default variant card
In the default variant's render, add price line:
<div className="flex items-center gap-2">
<span className="font-sans text-sm text-[var(--color-muted-foreground)]">
{formatShowDateWithDay(event.date)} at {formatShowTime(event.time)}
</span>
{showData.defaultDinnerPrice && (
<span className="font-sans text-sm text-[var(--color-gold)] font-semibold ml-auto">
From {formatPrice(showData.defaultDinnerPrice)} VND
</span>
)}
</div>- Step 4: Add formatPrice utility
// In lib/utils/format.ts
export function formatPrice(amount: number): string {
return new Intl.NumberFormat("vi-VN").format(amount);
}- Step 5: Update badge colors per spec
Add gold/green/orange/grey badges matching spec:
- Green: Available (>10 seats)
- Orange: Few left (1-10 seats)
- Grey: Sold out (0 seats)
Task 2: Add Scarcity Signals
Files:
- Modify:
apps/frontend/components/booking/experience-card.tsx
Per spec: "Only X seats left for this date" if <10 seats, "This date is filling up fast"
- Step 1: Add scarcity messaging to card
// In the card, after availability badge
{
remaining <= 10 && remaining > 0 && (
<p className="text-sm text-orange-500 font-semibold animate-pulse">
Only {remaining} seats left!
</p>
);
}
{
remaining > 10 && remaining <= 20 && (
<p className="text-sm text-[var(--color-gold)]">Selling fast</p>
);
}- Step 2: Add orange-500 to tailwind config if not exists
Check tailwind.config.ts for custom colors.
Task 3: Integrate Countdown Timer
Files:
- Modify:
apps/frontend/components/booking/booking-modal.tsx - Check:
apps/frontend/components/booking/countdown-timer.tsx
Per spec: "From step 1 onwards, start a 10-minute timer: 'Your seats are reserved for 09:54'"
- Step 1: Verify countdown-timer exists and works
Read components/booking/countdown-timer.tsx to understand implementation.
- Step 2: Import and render countdown in modal header
// In booking-modal.tsx
import { CountdownTimer } from "~/components/booking/countdown-timer";
// In BookingFlow component, add after StepIndicator
<div className="px-6 py-3 bg-surface/50">
<CountdownTimer />
</div>;- Step 3: Verify timer resets on modal open
The timer should start when step 1 (tickets) renders. Verify in ReservationDraftProvider or step-tickets.
Task 4: Verify Sticky Cart Integration
Files:
- Check:
apps/frontend/components/booking/sticky-cart.tsx - Check:
apps/frontend/components/booking/sticky-cart-footer.tsx
Per spec: "Visible at all steps 1-2-3. On mobile: fixed bar at bottom. On desktop: right-hand sidebar."
- Step 1: Verify sticky-cart renders in modal
Read booking-modal.tsx to see if sticky-cart is included.
- Step 2: Verify mobile footer variant exists
Check sticky-cart-footer.tsx for mobile-specific implementation.
Task 5: Add Trust Signals to Checkout
Files:
- Modify:
apps/frontend/components/booking/checkout-form.tsx
Per spec: Payment logos (VNPay, OnePay, Visa, Mastercard), "Secure encrypted payment" badge.
- Step 1: Read checkout-form.tsx
Check current implementation.
- Step 2: Add trust signals above payment button
// Add before the pay button
<div className="flex items-center justify-center gap-4 py-4">
<Image src="/images/payment/vnpay.svg" alt="VNPay" width={40} height={24} />
<Image src="/images/payment/visacard.svg" alt="Visa" width={40} height={24} />
<Image
src="/images/payment/mastercard.svg"
alt="Mastercard"
width={40}
height={24}
/>
<span className="text-xs text-muted-foreground flex items-center gap-1">
<Lock className="w-3 h-3" />
Secure payment
</span>
</div>- Step 3: Create payment logo assets if missing
Check if /public/images/payment/ exists with vnpay.svg, visacard.svg, mastercard.svg.
Task 6: Add Paraglide Messages
Files:
- Modify:
apps/src/paraglide/messages.ts - Add translations to
apps/src/paraglide/messages.en.tsandapps/src/paraglide/messages.vi.ts
Messages needed:
-
booking_title()— "Book Your Experience" -
booking_subtitle()— "Select an upcoming show to book" -
booking_from_price()— "From {price} VND" -
booking_only_seats_left()— "Only {count} seats left!" -
booking_selling_fast()— "Selling fast" -
booking_secure_payment()— "Secure encrypted payment" -
Step 1: Add messages to paraglide
// In messages.ts
booking_title: () => string;
booking_subtitle: () => string;
booking_from_price: (params: { price: string }) => string;
booking_only_seats_left: (params: { count: number }) => string;
booking_selling_fast: () => string;
booking_secure_payment: () => string;- Step 2: Add English translations
// In messages.en.ts
booking_title: () => "Book Your Experience",
booking_subtitle: () => "Select an upcoming show to book",
booking_from_price: ({ price }) => `From ${price} VND`,
booking_only_seats_left: ({ count }) => `Only ${count} seats left!`,
booking_selling_fast: () => "Selling fast",
booking_secure_payment: () => "Secure encrypted payment",- Step 3: Add Vietnamese translations
// In messages.vi.ts
booking_title: () => "Đặt Vé Trải Nghiệm",
booking_subtitle: () => "Chọn một suất diễn sắp tới để đặt",
booking_from_price: ({ price }) => `Từ ${price} VND`,
booking_only_seats_left: ({ count }) => `Chỉ còn ${count} chỗ!`,
booking_selling_fast: () => "Đang bán nhanh",
booking_secure_payment: () => "Thanh toán bảo mật",Task 7: Test the Flow
Files:
-
Run: Development server
-
Step 1: Start dev server
cd apps/frontend && npm run dev- Step 2: Navigate to /booking page
Verify:
-
Cards display with "From X VND" price
-
Availability badges show correctly (green/orange/grey)
-
"Only X seats left" appears when <10 seats
-
"Book Now" button opens modal
-
Step 3: Complete booking flow in modal
- Select ticket type and quantity
- Click Continue to Add-ons
- Skip or select add-ons
- Fill checkout form
- Verify trust signals visible
- Check countdown timer running
Verification Checklist
Per spec requirements:
- Cards show "From [price] VND"
- Availability badge: Available (>10 seats) / Few left (1-10) / Sold out
- Scarcity signal: "Only X seats left" when <10
- "Selling fast" when 10-20 seats
- Countdown timer starts on step 1
- Sticky cart visible on mobile (bottom) and desktop (sidebar)
- Trust signals in checkout (logos + "Secure payment")
- No page reload between steps (SPA)
- Mobile-first: touch targets ≥44px
Execution Options
Plan complete and saved to docs/superpowers/plans/2026-05-12-booking-section-enhancement.md. Two execution options:
1. Subagent-Driven (recommended) - I dispatch a fresh subagent per task, review between tasks, fast iteration
2. Inline Execution - Execute tasks in this session using executing-plans, batch execution with checkpoints
Which approach?