Skip to Content
TutorialNested List Seat Booking

Nested List Seat Booking

https://editor.momen.app/tool/dK5wjNzNOPr/WEB?code=J7UZZat2LVnrK&ref=0562398

Introduction

  • Goal: Implement a conflict-resistant seat booking feature using nested lists and unique constraints.
  • Applicable Scenario: Cinema seat selection, stadium ticketing, restaurant reservations, or any grid-based resource scheduling scenario.
  • Core Logic: Render a 2D seat layout using a “List in List” structure (Rows -> Seats). Leverage Database Composite Unique Constraints to guarantee absolute data consistency and prevent duplicate bookings at the database level.

Steps

Data Storage

To build this architecture, we need five distinct tables to manage users, sessions, physical layout, and transaction records.

Data Model

1. Table: account System-generated table used to track order ownership.

Field NameTypeNote
idBigintAuto-generated, unique user identifier

2. Table: session Used to enable resource reuse across different times or events.

Field NameTypeNote
idBigintAuto-generated, distinguishes different events/screenings

3. Table: row The data source for the outer list, defining vertical tiers.

Field NameTypeNote
nameTexte.g., “Row B”, “Row 1”
sort_orderBigintDetermines the vertical display order on the screen

4. Table: seat The data source for the inner list, defining physical locations.

Field NameTypeNote
seat_orderBigintDetermines the horizontal order within a row
typeTextseat (Valid seat) or none (Aisle/Gap)
row_idBigintRelation: Many-to-One to row

5. Table: order The core transaction table. Uses unique constraints to prevent booking conflicts.

Field NameTypeNote
account_idBigintRelation: Many-to-One to account. Records the buyer.
session_idBigintRelation: Many-to-One to session.
seat_idBigintRelation: Many-to-One to seat.

Configuring Unique Constraints

To prevent data duplication and physical overlap, we configure two constraints:

  1. Seat Physics Constraint: In the seat table, add a Composite Unique Constraint named uk_row_seat using the fields row_id and seat_order. This ensures two seats cannot occupy the same physical coordinates.
  2. Order Logic Constraint: In the order table, add a Composite Unique Constraint named uk_session_seat using session_id and seat_id. This guarantees a specific seat can only be booked once per session.

Data for rows and seats can be rapidly populated using Momen’s “Import” function with an Excel/CSV file.


UI Construction & Interaction

Outer List: Rows

  1. Add a List component to the canvas.
  2. In the right Data panel:
    • Data source: Remote
    • Data model: row
    • Sort: Add a sort by sort_order Ascending.
  3. Inside this List, place a Text component to display the row name. Bind its content to {Data source/rowList.../item/name}.

Inner List: Seats

  1. Add another List component inside the List Row.
  2. Configure the Layout to be horizontal so seats line up side-by-side.
  3. In the right Data panel:
    • Data source: Remote
    • Data model: seat
    • Filter: Add a condition where row_id is Equal to {Data source/rowList.../item/id}. This is the crucial step that nests the seats within their respective rows.
    • Sort: By seat_order Ascending.


Logic & State Configuration

Inside the inner List Seat, drop a Conditional view component. We will define multiple states for each seat based on the database context.

1. Hidden State (Aisles/Gaps)

Create a case named Hidden.

  • Condition: Check if the seat’s type is equal to none.
  • UI: Leave the container empty or invisible to act as a walkway gap in your grid.

2. Purchased State (Logged-in User’s Booking)

Create a case named Purchased.

  • Condition: Filter the order table where seat_id equals the current seat’s ID, session_id equals the current session (e.g., 1), AND account_id equals the {Logged in user/id}. If the Count is Equal to 1, the current user owns this seat.
  • UI: Display an icon or image indicating the user’s reserved seat.

3. Occupied State (Booked by Others)

Create a case named Occupied.

  • Condition: Filter the order table where seat_id equals the current seat’s ID, session_id equals the current session, AND account_id is Not equal to {Logged in user/id}. If the Count is Not equal to 0, someone else owns it.
  • UI: Display a grayed-out or locked icon.

4. Available State (Default)

Create a case named Available.

  • Condition: Set this as the default fallback branch.
  • UI: Display an empty checkbox or selectable seat icon.

Actionflow Construction

Now we attach logic to the On click events of the corresponding states in the Conditional view.

Canceling an Order (Purchased State)

When a user clicks their own purchased seat, allow them to cancel.

  1. Add a Show modal node asking “Confirm Booking Cancelation?”.
  2. Add a Delete order node. Filter where account_id equals {Logged in user/id} and seat_id equals the current seat ID.
  3. Add a Switch view case node pointing back to Available.

Handling Unavailable Seats (Occupied State)

When a user clicks a seat someone else booked.

  1. Add a simple Show toast node displaying: “Sorry, this seat is already taken”.

Booking a Seat (Available State)

This is where we handle the high-concurrency conflict checks.

  1. Add a Show modal node: “Confirm Booking?”.
  2. Add an Insert order node. Map account_id to {Logged in user/id}, session_id to 1 (or your active session variable), and seat_id to the current seat’s ID.
    • Crucial Step: In the On Conflict settings, select the uk_session_seat constraint and set the Action Type to None.
  3. Add a Condition node to evaluate the result of the Insert action.
    • Success Branch: Check if {Action result/Insert order/id} is Not null. If true, show a success Toast and use Switch view case to Purchased.
    • Failed Branch: Check if {Action result/Insert order/id} is Is null (meaning the unique constraint blocked the insertion because someone else just booked it). Show a failure Toast (“Seat already booked”) and use Switch view case to Occupied.


Verification

To test the conflict-resolution architecture:

Step 1: Initial Booking (User 1)

  1. Open the preview and log in as ​User 1​.
  2. Select ​Row B, Seat 2​. A confirmation modal appears: ​*“Book Row B, Seat 2?”*​.
  3. Click ​Yes​. The seat icon immediately turns blue (the Purchased state).

Step 2: Concurrent Session (User 2)

  1. Open a new Incognito window and log in as ​User 2​.
  2. Notice that Row B, Seat 2 is already grayed out (Occupied), proving the conditional container is working.
  3. User 2 then successfully books ​Row C, Seat 3​.

Step 3: The “Ghost” Selection & Conflict Interception (User 1)

  1. Switch back to User 1’s window. Since the page hasn’t refreshed, Row C, Seat 3 still appears black (Available).
  2. User 1 attempts to book ​Row C, Seat 3​.
  3. Upon clicking ​Yes​, the database interceptor kicks in:
    • The uk_session_seat constraint blocks the insertion.
    • The Actionflow detects the null ID result and triggers the ​Failed Branch​.
    • A Toast notification appears: “Sorry, this seat is no longer available.”
    • State Rollback: The seat icon instantly switches from black to gray (Occupied) without a page reload.

Step 4: Cancellation & Release

  1. User 1 clicks their blue seat (​Row B, Seat 2​).
  2. Confirm the cancellation. The Delete action removes the record from the Order table.
  3. The unique constraint is released, and the seat returns to the Available state for all users.

Check your Database order table to ensure only one record was successfully created for that specific seat and session.

Last updated on