123 lines
3.1 KiB
Markdown
123 lines
3.1 KiB
Markdown
# OpenSpec Change: enterprise-r3f-booking
|
|
|
|
- **Change ID**: enterprise-r3f-booking
|
|
- **Package**: `@suaveplan/r3f-booking`
|
|
- **Category**: r3f/commerce
|
|
- **Target path**: `r3f/commerce/r3f-booking`
|
|
- **Status**: PROPOSED
|
|
- **Date**: 2026-04-24
|
|
- **Reference spec**: `/mnt/s/web/suaveplan/enterprise/r3f-booking.md`
|
|
|
|
---
|
|
|
|
## Summary
|
|
|
|
Deliver `@suaveplan/r3f-booking` on the genesis branch from scratch at enterprise quality. The package provides interactive 3D venue maps for seat/space booking — concert halls, stadiums, offices, conference rooms. It ships `<VenueMap />`, `<VenueSeat />`, `<VenueSection />`, `<VenueFloorPlan />`, and a `useVenueSelection` hook. Seats have availability states (available/reserved/selected/disabled), animated selection feedback, accessible keyboard navigation, and a JSON venue schema for data-driven layout. Storybook stories for every component; Vitest + `@testing-library/react` tests.
|
|
|
|
---
|
|
|
|
## Current-state audit (genesis)
|
|
|
|
Does not exist on genesis — fresh build.
|
|
|
|
---
|
|
|
|
## Available workspace deps on genesis
|
|
|
|
Same R3F + React stack as `enterprise-r3f-earth`, plus no additional deps.
|
|
|
|
---
|
|
|
|
## Public API surface
|
|
|
|
```tsx
|
|
function VenueMap(props: VenueMapProps): JSX.Element
|
|
function VenueFloorPlan(props: VenueFloorPlanProps): JSX.Element
|
|
function VenueSection(props: VenueSectionProps): JSX.Element
|
|
function VenueSeat(props: VenueSeatProps): JSX.Element
|
|
function useVenueSelection(options: UseVenueSelectionOptions): VenueSelectionState
|
|
|
|
interface VenueMapProps {
|
|
venue: VenueDefinition
|
|
selectedSeats?: string[]
|
|
onSeatSelect?: (seatId: string) => void
|
|
onSeatDeselect?: (seatId: string) => void
|
|
maxSelectable?: number
|
|
colorScheme?: VenueColorScheme
|
|
cameraControls?: boolean
|
|
}
|
|
|
|
interface VenueDefinition {
|
|
id: string
|
|
name: string
|
|
sections: SectionDefinition[]
|
|
}
|
|
|
|
interface SectionDefinition {
|
|
id: string
|
|
label: string
|
|
rows: RowDefinition[]
|
|
color?: string
|
|
position: { x: number; y: number; z: number }
|
|
rotation?: number
|
|
}
|
|
|
|
interface RowDefinition {
|
|
id: string
|
|
label: string
|
|
seats: SeatDefinition[]
|
|
}
|
|
|
|
interface SeatDefinition {
|
|
id: string
|
|
label: string
|
|
status: 'available' | 'reserved' | 'disabled'
|
|
category?: string
|
|
price?: number
|
|
}
|
|
|
|
type VenueSelectionState = {
|
|
selected: string[]
|
|
select: (seatId: string) => void
|
|
deselect: (seatId: string) => void
|
|
clear: () => void
|
|
isSelected: (seatId: string) => boolean
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## File layout
|
|
|
|
```text
|
|
r3f/commerce/r3f-booking/
|
|
package.json
|
|
tsconfig.json
|
|
vitest.config.ts
|
|
src/
|
|
index.ts
|
|
error-codes.ts
|
|
types/
|
|
r3f-booking.types.ts
|
|
r3f-booking.types.md
|
|
components/
|
|
venue-map/ (tsx + md + types + test + stories + index)
|
|
venue-floor-plan/ ...
|
|
venue-section/ ...
|
|
venue-seat/ ...
|
|
hooks/
|
|
use-venue-selection/
|
|
use-venue-selection.ts / .md / .test.ts / index.ts
|
|
schemas/
|
|
venue-schema/
|
|
venue-schema.ts / venue-schema.md / venue-schema.test.ts / index.ts
|
|
```
|
|
|
|
---
|
|
|
|
## Impact
|
|
|
|
Downstream: booking UI, event ticketing, office space booking.
|
|
|
|
**Prerequisites on Verdaccio**: `@suaveplan/error`, `@suaveplan/types`, `@suaveplan/logger`.
|