Skip to content

added max attendee configuration option - #2

Open
jjmah-eng wants to merge 2 commits into
mainfrom
test
Open

added max attendee configuration option#2
jjmah-eng wants to merge 2 commits into
mainfrom
test

Conversation

@jjmah-eng

@jjmah-eng jjmah-eng commented Jan 20, 2026

Copy link
Copy Markdown

Configurable max attendees for multiemail guest field

Adds a new optional maxEntries field-level setting (primarily for the guests multiemail booking question) that caps how many additional attendee emails can be entered. The limit is surfaced in the form-builder UI, enforced in the booking UI for multiemail fields, and validated server-side during booking response processing, with new i18n strings for helper text and error messages.

Key Changes:
• Extend baseFieldSchema in packages/prisma/zod-utils.ts with optional maxEntries: z.number().int().min(1).optional() for list-type fields like multiemail.
• Update TextLikeComponentProps in packages/app-store/routing-forms/components/react-awesome-query-builder/widgets.tsx to accept an optional maxEntries?: number, enabling typed propagation of this config to text-list components.
• Wire field.maxEntries through ComponentForField in packages/features/form-builder/FormBuilderField.tsx into textList components, so multiemail receives the limit.
• Enhance the multiemail component in packages/features/form-builder/Components.tsx to compute hasReachedLimit based on maxEntries, disable add buttons, guard onClick handlers, and show helper text using t("max_attendees_allowed", { count: maxEntries }).
• Add a maxEntries numeric input in the booking question editor for multiemail guests fields in apps/web/modules/event-types/components/tabs/advanced/FormBuilder.tsx, with setValueAs coercion that rejects non-integer or < 1 values and UI min={1}.
• Introduce server-side enforcement in packages/features/bookings/lib/getBookingResponsesSchema.ts so that for multiemail fields, if bookingField.maxEntries is set and emails.length > maxEntries, a custom Zod issue is added using m("max_attendees_allowed", { count: bookingField.maxEntries }) before duplicate detection.
• Add i18n keys max_attendees and max_attendees_allowed to apps/web/public/static/locales/en/common.json for the configuration label and limit message.

Possible Issues:
• The UI limit for multiemail uses listValue.length, which counts even empty rows; the server-side limit uses the parsed emails.length (non-empty, valid emails). This means users may hit the UI cap based on total rows rather than number of non-empty addresses, which may or may not match the desired semantics.
• The maxEntries configuration input is currently displayed only when formFieldType === "multiemail" && fieldName === "guests"; if additional multiemail fields are introduced later, they will not have a UI for setting maxEntries unless this condition is broadened.
• If non-English locales are missing translations for max_attendees or max_attendees_allowed, users in those locales may see fallback keys or inconsistent messaging between frontend and backend errors.
• Existing data or API clients that bypass the UI and attempt to set maxEntries to 0, negative, or non-integer values will be rejected by the Zod schema, which could surface as unexpected validation errors if not accounted for.

Review Focus

• Confirm maxEntries is added only at the schema level where appropriate (baseFieldSchema) and currently consumed only by multiemail/guests, with no unintended effect on other field types.
• Validate the multiemail UI logic in packages/features/form-builder/Components.tsx, particularly that hasReachedLimit semantics (listValue.length including empty rows) match product expectations vs counting only non-empty emails.
• Check the server-side multiemail branch in packages/features/bookings/lib/getBookingResponsesSchema.ts for correct ordering: required check, parse, special-case empty guests, then maxEntries enforcement, then duplicate detection, ensuring no behavior regressions.
• Review maxEntries coercion in apps/web/modules/event-types/components/tabs/advanced/FormBuilder.tsx (setValueAs logic) to ensure it properly rejects "", non-numeric, non-integer, and < 1 inputs to stay consistent with the Zod schema.
• Ensure that extending TextLikeComponentProps and passing maxEntries={field.maxEntries} in packages/features/form-builder/FormBuilderField.tsx is type-safe and does not break existing widget consumers.
• Verify that new i18n keys are named consistently and reused correctly across frontend helper text and backend validation messages.

Potential Impact

Functionality: Enables event creators to cap the number of additional guests on multiemail fields (currently exposed in the UI only for the guests field). The booking UI prevents adding more inputs once maxEntries is reached, and submissions exceeding the limit are rejected server-side with a translated error. Existing configurations without maxEntries keep prior behavior.

Performance: Impact is minimal: the client does an extra array length check when rendering buttons, and the server adds an O(1) emails.length check before existing validation steps.

Security: Adds an extra guard against excessively large guest lists on multiemail fields, slightly reducing risk of abuse via oversized payloads, but does not change auth or authorization behavior.

Scalability: No significant scalability changes; maxEntries is a scalar field on the booking field schema and the additional checks are constant-time relative to existing per-field validation.

Affected Areas

• Booking question form-builder configuration (apps/web/modules/event-types/components/tabs/advanced/FormBuilder.tsx)
• Form-builder runtime components and wiring for multiemail (packages/features/form-builder/Components.tsx, packages/features/form-builder/FormBuilderField.tsx)
• Booking responses validation pipeline, specifically multiemail handling (packages/features/bookings/lib/getBookingResponsesSchema.ts)
• Shared booking field schema / Zod utilities (packages/prisma/zod-utils.ts)
• Routing-forms widget prop typing (packages/app-store/routing-forms/components/react-awesome-query-builder/widgets.tsx)
• English locale strings for helper and error text (apps/web/public/static/locales/en/common.json)

Code Quality Assessment

packages/features/bookings/lib/getBookingResponsesSchema.ts: The new maxEntries check is added in the multiemail branch directly after successful parsing and before duplicate detection, with an early continue on violation and consistent use of m("max_attendees_allowed", ...) for translation-aware messages.

packages/features/form-builder/Components.tsx: The multiemail factory now normalizes value via listValue, derives a clear hasReachedLimit flag, disables buttons, and guards onClick handlers, reducing the risk of accidental over-additions; helper copy is centralized via i18n.

packages/features/form-builder/FormBuilderField.tsx: Prop plumbing for maxEntries into textList components is minimal and contained; checks against componentConfig.propsType remain readable and the new prop is only passed where relevant.

packages/app-store/routing-forms/components/react-awesome-query-builder/widgets.tsx: Adding optional maxEntries?: number to TextLikeComponentProps is backwards-compatible and does not affect existing widgets, as it is purely an additional optional prop.

apps/web/modules/event-types/components/tabs/advanced/FormBuilder.tsx: The maxEntries editor control is gated to formFieldType === "multiemail" && fieldName === "guests" and uses setValueAs to align with the schema (reject non-integers and < 1), though the name-based condition should be kept in sync if the guests field name ever changes.

apps/web/public/static/locales/en/common.json: New keys max_attendees and max_attendees_allowed follow existing naming and interpolation patterns (e.g., {{count}}), aiding reuse across UI and validation.

packages/prisma/zod-utils.ts: The baseFieldSchema extension for maxEntries is well-documented with clear JSDoc and uses z.number().int().min(1).optional() to match UI constraints, keeping schema-level validation tight.

Best Practices

Validation:
• Enforce critical constraints like maxEntries in both the client (disabling add actions) and server (getBookingResponsesSchema) to prevent circumvention.
• Keep UI coercion (setValueAs for maxEntries) consistent with schema-level validation (int().min(1)) to avoid mismatched expectations and opaque save failures.

Schema Design:
• Add new configuration such as maxEntries at the shared baseFieldSchema layer so it can be reused across multiple UIs and consumers.
• Document new schema fields with clear comments describing scope (list fields only, e.g. multiemail) and semantics.

Ux:
• Use i18n keys (max_attendees, max_attendees_allowed) for helper and error text so users see consistent messaging across editor, booking UI, and validation.
• Disable and guard interactive controls (e.g., add buttons in multiemail) instead of relying solely on validation errors after the fact.

Testing Needed

• In the event-type editor, set the guests booking question to type multiemail, configure maxEntries to values like 1 and 3, and verify the booking page disables the add-guests / add-another-guest buttons exactly when the number of guest inputs reaches the configured limit.
• Attempt to submit a booking with more non-empty guest emails than maxEntries (e.g., via devtools or direct API call) and confirm server-side validation fails with the max_attendees_allowed message, correctly scoped to the guests field.
• Verify that when maxEntries is unset, multiemail behaves as before: no UI limit on the number of rows and no max-attendees error from the backend.
• Test multiemail edge cases: required vs optional guests, all inputs empty for guests (should still normalize to an empty array without error), mixed valid/empty entries, and duplicate emails, ensuring the new limit check does not prevent existing duplicate_email validation from firing.
• Check that invalid maxEntries input in the editor (empty, 0, negative, non-integer, non-numeric) is coerced to undefined and does not break saving, while valid integers >= 1 are persisted.
• Confirm the new max_attendees label and max_attendees_allowed messages render correctly in English on both the editor and booking UI, and that other locales have acceptable fallback behavior.


This summary was automatically generated by @propel-code-bot

@propel-code-bot propel-code-bot Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 Propel found 1 suggestion(s) in this PR

Comment thread apps/web/modules/event-types/components/tabs/advanced/FormBuilder.tsx Outdated

@propel-code-bot propel-code-bot Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 Propel found 1 suggestion(s) in this PR

Comment on lines +720 to +729
setValueAs: (value) => {
if (value === "") {
return undefined;
}
const parsed = Number(value);
if (Number.isNaN(parsed) || !Number.isInteger(parsed) || parsed < 1) {
return undefined;
}
return parsed;
},

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Important

[Logic] The setValueAs function currently swallows validation errors (like non-integers or values less than 1) by returning undefined, which zod treats as a valid optional value. This means invalid inputs (e.g. "1.5" or "-1") will simply unset the limit rather than showing a validation error.

Simiplifying this to just type coercion allows the Zod schema (z.number().int().min(1)) to handle the validation and provide proper error feedback to the user.

Context for Agents
The `setValueAs` function currently swallows validation errors (like non-integers or values less than 1) by returning `undefined`, which `zod` treats as a valid optional value. This means invalid inputs (e.g. "1.5" or "-1") will simply unset the limit rather than showing a validation error.

Simiplifying this to just type coercion allows the Zod schema (`z.number().int().min(1)`) to handle the validation and provide proper error feedback to the user.

File: apps/web/modules/event-types/components/tabs/advanced/FormBuilder.tsx
Line: 729

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant