Inbox & Messaging
Architecture, schema design, and business logic for guest-to-host messaging and quoting.
Overview
The Inbox & Messaging module is a critical feature in the marketplace. It facilitates communication between guests and hosts and acts as a precursor to bookings. The system supports:
- Standard messaging
- Custom quote generation
- Real-time price breakdowns based on listing configurations
Use Cases
- Guests can inquire about availability and details before booking
- Hosts can offer tailored pricing or packages
- Messaging interface can evolve into a full inbox or conversation thread
UI & Component Architecture
MessageHostContainer.tsx
This container handles:
- Rendering dynamic forms based on the listing’s
pricingStrategy - State management via
react-hook-form+zod - Live price calculations using
useDeepCompareEffect - Conditional rendering of time pickers, alcohol checkbox, and custom activity fields
Key Concepts:
- Controlled inputs for all fields (dates, guests, activity, etc.)
- Dynamically calculates price as the user adjusts the form
- Triggers a dialog (
PriceBreakdownDialog) to confirm pricing before submission - Displays error feedback on submission failure
Schema Design
Zod Schema (MessageHost.schema.ts)
z.discriminatedUnion("type", [
z.object({ type: z.literal("LUMPSUM"), listingId, activity, numberOfPeople, consumeAlcohol, message }),
z.object({ type: z.literal("PER_HOUR"), listingId, date, from, to, ... }),
z.object({ type: z.literal("CUSTOM"), listingId, activity, message }),
])Why Discriminated Unions?
- Enables dynamic validation and conditional form rendering
- Prevents invalid field combinations depending on strategy
- Simplifies inference and autocomplete for consumers of the schema
Utilities
calculateLumpsumPrice, calculatePerHourPrice
These functions receive listing metadata and guest input, then compute pricing:
- Lumpsum: flat rate per person + alcohol surcharge
- Per Hour: hourly rate × duration
- Custom: optional pricing
Internally they use:
differenceInHoursfromdate-fns- Alcohol multiplier logic
- Configurable pricing per listing record
Messaging Logic
Currently the "Send Message" flow:
- Validates input with Zod
- Shows a price breakdown dialog for confirmation
- Submits data to a
messageHostmutation or route (tRPC or REST depending on backend) - Creates an initial message or pending booking intent in DB
Potential Improvements
Full Inbox View
- Build an inbox by grouping messages per listing/user
- Use Supabase
realtimeto sync new messages - Add read/unread tracking, timestamps, and indicators
Real-Time Chat
- Use Supabase channel subscriptions or WebSockets
- Allow hosts and guests to chat before or after a booking
Quotes as Bookings
- Quote messages could trigger draft bookings
- Improve conversion by enabling "Accept Quote" → "Book Now"
Attachments
- Support file/image uploads for proposals or verification
- Use Supabase storage with signed URLs
Security & Abuse Protection
- Validate message payloads against session identity
- Rate-limit submissions per user/listing
- Optionally scan messages for harmful content (e.g. profanity, links)
File Index
| File | Responsibility |
|---|---|
containers/message-host/MessageHostContainer.tsx | Messaging UI, form state, rendering |
containers/message-host/MessageHost.schema.ts | Zod schema validation per strategy |
utils/calculateBookingPrice.ts | Pricing computation logic |
components/ui/loading-button.tsx | UI button with pending state |
components/ui/dialog/PriceBreakdownDialog.tsx | Dialog to confirm price before submission |