Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Conversation

jobenjada
Copy link
Member

@jobenjada jobenjada commented Sep 30, 2025

As requested by GetUp, you can now hit ENTER when typing options in Single & Multi Select Questions. If there are empty options, it jumps to the next empty option. If there are no empty options, it creates a new one and readjusts focus.

This makes survey creation faster & smoother.

This applies to:

  • Single select
  • Multi select
  • Ranking and
  • Matrix (Cols & Rows)

Additionally, the PR removes the unused "lastQuestion" prop and fixes a few SonarQube issues in the related files.

@jobenjada jobenjada requested a review from Dhruwang September 30, 2025 13:11
@jobenjada jobenjada marked this pull request as ready for review September 30, 2025 13:11
Copy link
Contributor

coderabbitai bot commented Sep 30, 2025

Walkthrough

Removed the public ref prop from QuestionFormInputProps; the component now uses an internal input ref. MatrixQuestionForm gained index-aware onKeyDown, a focusItem helper, Enter to add-or-focus, and ArrowUp/ArrowDown navigation. lastQuestion was removed from MultipleChoiceQuestionForm and RankingQuestionForm props and call sites. QuestionOptionChoice added Enter/Arrow navigation and add-and-focus behavior. Several import blocks were reordered/merged. Tests were simplified and refocused, adding keyboard-focused tests and lightweight input/dnd-kit mocks.

Pre-merge checks

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Description Check ⚠️ Warning The pull request description provides a concise summary of the feature but does not follow the required repository template: it lacks the “What does this PR do?” and “How should this be tested?” headings, the issue reference line, and checklist entries. Please update the description to use the repository’s template by adding the mandated “What does this PR do?”, “Fixes #…”, and “How should this be tested?” sections with reproduction steps and test instructions, and complete the checklist.
✅ Passed checks (2 passed)
Check name Status Explanation
Title Check ✅ Passed The title follows the Conventional Commits format and succinctly describes the main feature—allowing users to hit ENTER to create or move to a new option—which matches the core change in the pull request.
Docstring Coverage ✅ Passed No functions found in the changes. Docstring coverage check skipped.

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3e80b0d and 45d308a.

📒 Files selected for processing (1)
  • apps/web/modules/survey/editor/components/matrix-question-form.tsx (5 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • apps/web/modules/survey/editor/components/matrix-question-form.tsx
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (7)
  • GitHub Check: Build Formbricks-web / Build Formbricks-web
  • GitHub Check: Run Unit Tests / Unit Tests
  • GitHub Check: Run E2E Tests / Run E2E Tests
  • GitHub Check: Run Linters / Linters
  • GitHub Check: Validate Docker Build
  • GitHub Check: SonarQube
  • GitHub Check: Analyze (javascript)

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (2)
apps/web/modules/survey/editor/components/matrix-sortable-item.tsx (1)

66-72: Include onFocused in the dependency array.

The useEffect hook calls onFocused?.() but omits it from the dependency array. While the eslint rule is disabled, this can lead to stale closures if onFocused changes between renders.

Apply this diff:

   useEffect(() => {
     if (shouldFocus && inputRef.current) {
       inputRef.current.focus();
       onFocused?.();
     }
-    // eslint-disable-next-line react-hooks/exhaustive-deps
-  }, [shouldFocus]);
+  }, [shouldFocus, onFocused]);

As per coding guidelines

apps/web/modules/survey/editor/components/ranking-question-form.tsx (1)

43-43: Remove unused lastChoiceRef and its dead useEffect

  • In ranking-question-form.tsx: delete the const lastChoiceRef = useRef<HTMLInputElement>(null); declaration (line 43) and its accompanying useEffect block (lines 115–119).
  • In multiple-choice-question-form.tsx: delete the const lastChoiceRef = useRef<HTMLInputElement>(null); declaration (line 51) and its accompanying useEffect block (lines 157–159).
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3733c22 and 051d648.

📒 Files selected for processing (9)
  • apps/web/modules/survey/components/question-form-input/index.tsx (4 hunks)
  • apps/web/modules/survey/editor/components/matrix-question-form.tsx (5 hunks)
  • apps/web/modules/survey/editor/components/matrix-sortable-item.tsx (4 hunks)
  • apps/web/modules/survey/editor/components/multiple-choice-question-form.test.tsx (0 hunks)
  • apps/web/modules/survey/editor/components/multiple-choice-question-form.tsx (4 hunks)
  • apps/web/modules/survey/editor/components/question-card.tsx (1 hunks)
  • apps/web/modules/survey/editor/components/question-option-choice.tsx (8 hunks)
  • apps/web/modules/survey/editor/components/ranking-question-form.test.tsx (0 hunks)
  • apps/web/modules/survey/editor/components/ranking-question-form.tsx (5 hunks)
💤 Files with no reviewable changes (2)
  • apps/web/modules/survey/editor/components/multiple-choice-question-form.test.tsx
  • apps/web/modules/survey/editor/components/ranking-question-form.test.tsx
🧰 Additional context used
📓 Path-based instructions (5)
**/*.tsx

📄 CodeRabbit inference engine (.cursor/rules/build-and-deployment.mdc)

**/*.tsx: Capture ref values in variables within useEffect cleanup
Avoid accessing .current directly in cleanup functions

Implement proper cleanup in useEffect to avoid React hooks warnings

Files:

  • apps/web/modules/survey/components/question-form-input/index.tsx
  • apps/web/modules/survey/editor/components/matrix-question-form.tsx
  • apps/web/modules/survey/editor/components/multiple-choice-question-form.tsx
  • apps/web/modules/survey/editor/components/ranking-question-form.tsx
  • apps/web/modules/survey/editor/components/question-option-choice.tsx
  • apps/web/modules/survey/editor/components/question-card.tsx
  • apps/web/modules/survey/editor/components/matrix-sortable-item.tsx
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/storybook-component-migration.mdc)

**/*.{ts,tsx}: Search for import.*[DeprecatedComponent] patterns to identify deprecated component usage in the codebase
Exclude specified components (e.g., 'ModalWithTabs') from migration if the user requests
Update import statements to use the new component(s) as specified by the user
Transform component props according to user-specified mapping rules and remove deprecated props
Update the component structure to match the new component system as specified by the user, preserving all logic, state management, and event handlers

**/*.{ts,tsx}: Types should be imported from @formbricks/types for shared definitions, and local types can be defined in component or hook files
Use type guards for runtime validation

**/*.{ts,tsx}: Always generate cache keys using createCacheKey utilities
Never use flat cache keys (e.g., "user_data_456"); use namespaced, structured keys via createCacheKey

Files:

  • apps/web/modules/survey/components/question-form-input/index.tsx
  • apps/web/modules/survey/editor/components/matrix-question-form.tsx
  • apps/web/modules/survey/editor/components/multiple-choice-question-form.tsx
  • apps/web/modules/survey/editor/components/ranking-question-form.tsx
  • apps/web/modules/survey/editor/components/question-option-choice.tsx
  • apps/web/modules/survey/editor/components/question-card.tsx
  • apps/web/modules/survey/editor/components/matrix-sortable-item.tsx
**/*.{tsx,jsx}

📄 CodeRabbit inference engine (.cursor/rules/formbricks-architecture.mdc)

**/*.{tsx,jsx}: Use useState for component-specific state, useReducer for complex state logic, and refs for mutable values that don't trigger re-renders
Use React Context for feature-specific shared state
Optimize dependency arrays in useEffect to prevent unnecessary re-renders
Implement proper loading states in components
Use client-side error boundaries and server-side error logging for error tracking

Files:

  • apps/web/modules/survey/components/question-form-input/index.tsx
  • apps/web/modules/survey/editor/components/matrix-question-form.tsx
  • apps/web/modules/survey/editor/components/multiple-choice-question-form.tsx
  • apps/web/modules/survey/editor/components/ranking-question-form.tsx
  • apps/web/modules/survey/editor/components/question-option-choice.tsx
  • apps/web/modules/survey/editor/components/question-card.tsx
  • apps/web/modules/survey/editor/components/matrix-sortable-item.tsx
apps/web/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/cache-optimization.mdc)

apps/web/**/*.{ts,tsx}: Never use Next.js unstable_cache(); use Redis-based caching (withCache, cache service) instead
Remove revalidateEnvironment and tag-based invalidation when migrating from unstable_cache; use TTL-based expiration
Use React cache() for request-level deduplication within Next.js/React server components or handlers

Files:

  • apps/web/modules/survey/components/question-form-input/index.tsx
  • apps/web/modules/survey/editor/components/matrix-question-form.tsx
  • apps/web/modules/survey/editor/components/multiple-choice-question-form.tsx
  • apps/web/modules/survey/editor/components/ranking-question-form.tsx
  • apps/web/modules/survey/editor/components/question-option-choice.tsx
  • apps/web/modules/survey/editor/components/question-card.tsx
  • apps/web/modules/survey/editor/components/matrix-sortable-item.tsx
{apps,packages}/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/cache-optimization.mdc)

{apps,packages}/**/*.{ts,tsx}: Use cache.withCache() for simple database queries with an explicit TTL (milliseconds)
Always treat cache-manager + Keyv TTLs as milliseconds; set correct units when using withCache or direct set operations
Avoid creating wrapper functions solely for caching; add caching directly to the expensive, original function
Do not cache low-overhead operations (property access, basic transformations, simple lookups); reserve caching for I/O-bound or expensive work

Files:

  • apps/web/modules/survey/components/question-form-input/index.tsx
  • apps/web/modules/survey/editor/components/matrix-question-form.tsx
  • apps/web/modules/survey/editor/components/multiple-choice-question-form.tsx
  • apps/web/modules/survey/editor/components/ranking-question-form.tsx
  • apps/web/modules/survey/editor/components/question-option-choice.tsx
  • apps/web/modules/survey/editor/components/question-card.tsx
  • apps/web/modules/survey/editor/components/matrix-sortable-item.tsx
🧠 Learnings (2)
📚 Learning: 2025-08-19T12:08:11.413Z
Learnt from: pandeymangg
PR: formbricks/formbricks#6379
File: packages/surveys/src/index.ts:0-0
Timestamp: 2025-08-19T12:08:11.413Z
Learning: In the formbricks surveys package, RTL detection and direction handling is implemented in the RenderSurvey component (packages/surveys/src/components/general/render-survey.tsx), not in the renderSurvey function (packages/surveys/src/index.ts). The RenderSurvey component properly handles consumer-provided dir props and updates direction dynamically when languageCode or survey changes.

Applied to files:

  • apps/web/modules/survey/components/question-form-input/index.tsx
📚 Learning: 2025-08-14T14:03:56.338Z
Learnt from: mattinannt
PR: formbricks/formbricks#6418
File: apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/components/shareEmbedModal/link-settings-tab.tsx:160-160
Timestamp: 2025-08-14T14:03:56.338Z
Learning: In the formbricks/formbricks repository, the description placeholder "Complete this survey" in link-settings-tab.tsx is intentionally hardcoded rather than using i18n translation keys. This is because it serves as the default metadata description and the system cannot support translations for all possible survey languages that users might create surveys in.

Applied to files:

  • apps/web/modules/survey/components/question-form-input/index.tsx
🧬 Code graph analysis (4)
apps/web/modules/survey/editor/components/matrix-question-form.tsx (1)
apps/web/lib/i18n/utils.ts (1)
  • createI18nString (13-51)
apps/web/modules/survey/editor/components/multiple-choice-question-form.tsx (1)
apps/web/modules/survey/editor/components/question-option-choice.tsx (1)
  • QuestionOptionChoice (49-195)
apps/web/modules/survey/editor/components/ranking-question-form.tsx (1)
apps/web/modules/survey/editor/components/question-option-choice.tsx (1)
  • QuestionOptionChoice (49-195)
apps/web/modules/survey/editor/components/question-option-choice.tsx (1)
apps/web/lib/i18n/utils.ts (1)
  • createI18nString (13-51)
🔇 Additional comments (16)
apps/web/modules/survey/components/question-form-input/index.tsx (1)

53-53: LGTM! Clean external ref support added.

The addition of externalInputRef prop with fallback to internal inputRef follows React best practices for optional external ref control. This enables parent components to manage focus programmatically while maintaining backward compatibility.

Also applies to: 81-81, 389-389

apps/web/modules/survey/editor/components/question-card.tsx (2)

3-18: LGTM! Import consolidation improves readability.

The imports have been properly consolidated at the top of the file, following standard TypeScript/React conventions.


299-321: LGTM! Unused lastQuestion prop correctly removed.

The lastQuestion prop has been removed from MultipleChoiceQuestionForm and RankingQuestionForm components as indicated in the PR objectives, while appropriately retained for components that still require it (e.g., NPSQuestionForm, RatingQuestionForm, CTAQuestionForm).

Also applies to: 449-459

apps/web/modules/survey/editor/components/matrix-question-form.tsx (3)

47-48: LGTM! Clean focus state management.

The introduction of focusRowId and focusColumnId state variables with proper initialization in handleAddLabel provides a clean mechanism for tracking which newly added row or column should receive focus.

Also applies to: 53-62


118-143: LGTM! Smart Enter key handling improves UX.

The enhanced Enter key logic intelligently prioritizes focusing existing empty labels before creating new ones. This prevents unnecessary option proliferation and guides users to fill in incomplete fields first.


266-267: LGTM! Proper focus lifecycle management.

The shouldFocus and onFocused props correctly propagate focus control to child MatrixSortableItem components, with onFocused callbacks resetting the focus state after the focus operation completes.

Also applies to: 314-315

apps/web/modules/survey/editor/components/matrix-sortable-item.tsx (1)

36-37: LGTM! Clean focus prop threading.

The addition of shouldFocus and onFocused props with proper ref management enables external focus control. The inputRef is correctly passed to QuestionFormInput via externalInputRef.

Also applies to: 55-56, 64-64, 100-100

apps/web/modules/survey/editor/components/multiple-choice-question-form.tsx (2)

54-54: LGTM! Focus state management for choices.

The focusChoiceId state and its initialization when adding a new choice provides the foundation for auto-focusing newly created options.

Also applies to: 111-111


252-275: LGTM! Comprehensive focus control for choices.

The rendering of QuestionOptionChoice components with shouldFocus, onFocused, and onRequestFocus props enables:

  • Auto-focus on newly created choices
  • Focus lifecycle management via callbacks
  • Programmatic focus requests between choices

This pattern is consistent with the focus management approach used across other question forms in this PR.

apps/web/modules/survey/editor/components/question-option-choice.tsx (3)

122-138: LGTM! Enter key handler implements smart focus navigation.

The logic correctly:

  • Prevents default form submission
  • Excludes the "other" option from empty-label search
  • Uses proper language fallback with nullish coalescing
  • Requests focus on existing empty options before creating new ones

This aligns well with the PR objective to speed up survey creation.


148-149: LGTM! Proper use of nullish coalescing for placeholder.

The nullish coalescing operator correctly provides a default value when question.otherOptionPlaceholder is null or undefined, ensuring the placeholder is always defined.


164-164: LGTM! Optional chaining prevents potential runtime errors.

The optional chaining on question.choices?.length safely handles cases where choices might be undefined, improving robustness.

apps/web/modules/survey/editor/components/ranking-question-form.tsx (4)

45-45: LGTM! Focus state enables programmatic input focus.

The focusChoiceId state correctly tracks which choice should receive focus, integrating cleanly with the new focus management system.


72-72: LGTM! New choices automatically receive focus.

Setting focusChoiceId when adding choices ensures the newly created input is focused immediately, improving UX during survey creation.

Also applies to: 88-88


219-221: LGTM! Focus props properly wired to QuestionOptionChoice.

The focus management props are correctly passed:

  • shouldFocus compares choice.id with focusChoiceId
  • onFocused clears the focus state after focusing
  • onRequestFocus allows choices to request focus on other choices

This enables the Enter key navigation feature described in the PR objectives.


200-223: LGTM! Optional chaining prevents runtime errors.

The optional chaining on question.choices?.map safely handles undefined choices arrays, making the component more robust.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (1)
apps/web/modules/survey/editor/components/matrix-question-form.test.tsx (1)

98-125: Add explicit focus assertion for the first empty row
In the Enter focuses first empty row if present test, after pressing Enter on qfi-row-0, also assert that the first empty row input (e.g. screen.getByTestId("qfi-row-1")) has focus. Currently the test only verifies that updateQuestion isn’t called—adding the .toHaveFocus() check ensures the focus-management behavior is actually tested.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 051d648 and 9291ef0.

📒 Files selected for processing (1)
  • apps/web/modules/survey/editor/components/matrix-question-form.test.tsx (1 hunks)
🧰 Additional context used
📓 Path-based instructions (7)
**/*.tsx

📄 CodeRabbit inference engine (.cursor/rules/build-and-deployment.mdc)

**/*.tsx: Capture ref values in variables within useEffect cleanup
Avoid accessing .current directly in cleanup functions

Implement proper cleanup in useEffect to avoid React hooks warnings

Files:

  • apps/web/modules/survey/editor/components/matrix-question-form.test.tsx
**/*.test.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/build-and-deployment.mdc)

**/*.test.{ts,tsx}: Ensure all test mocks include required constants like SESSION_MAX_AGE
Remove unused imports and constants from test files
Use literal values instead of imported constants when the constant isn't actually needed

Use the rules in .github/copilot-instructions.md when writing tests

**/*.test.{ts,tsx}: Find and update corresponding test files (same name with .test.tsx or .test.ts) to mock the new component(s) and update test expectations
Replace old component mocks in test files with new component mocks as specified by the user
Update test IDs and component-specific assertions in test files to match the new component system
Ensure all new component parts used in the migrated component are mocked in the corresponding test files

**/*.test.{ts,tsx}: Unit tests for utilities and services should be placed alongside the implementation files and named *.test.ts or *.test.tsx
Mock external dependencies properly in tests

**/*.test.{ts,tsx}: Always use waitFor for async operations in tests
Test both loading and completed states for async hooks
Verify API calls with correct parameters in tests
Test AbortController implementation to ensure race condition prevention in async hooks
Test API error handling by mocking rejected promises and verifying error handling logic
Test that state is not updated for cancelled requests
Use type assertions for edge cases in mocks (e.g., null as any, undefined as any)
Ensure mocks match the actual interface, using type assertions when partial mocking is needed
Test state changes by triggering updates and verifying the new state
Test multiple scenarios (e.g., different modes) by mocking dependencies and rerendering
Use descriptive test names that explain the scenario (e.g., 'fetches response count on mount for regular survey')

Files:

  • apps/web/modules/survey/editor/components/matrix-question-form.test.tsx
**/*.test.tsx

📄 CodeRabbit inference engine (.cursor/rules/build-and-deployment.mdc)

Mock Next.js navigation hooks properly: useParams, useRouter, useSearchParams

**/*.test.tsx: Always wrap components using context in the provider during tests
Use initialCount prop for predictable test scenarios
Mock context dependencies like useParams, useResponseFilter in tests
Mock next/navigation with useParams returning environment and survey IDs in context provider tests
Mock response filter context and actions in context provider tests
Mock API actions that the provider depends on in context provider tests

**/*.test.tsx: Use .test.tsx for React component/hook tests (jsdom environment)
When testing hooks that use React Context, mock the context values
To test useEffect dependencies, ensure mocks return different values and trigger re-renders
Test cleanup on unmount by verifying cleanup functions (e.g., AbortController.abort) are called
For hooks, ensure you test: initialization, data fetching (success/error), state updates, dependency changes, manual actions, race condition prevention, cleanup, mode switching, and edge cases

Files:

  • apps/web/modules/survey/editor/components/matrix-question-form.test.tsx
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/storybook-component-migration.mdc)

**/*.{ts,tsx}: Search for import.*[DeprecatedComponent] patterns to identify deprecated component usage in the codebase
Exclude specified components (e.g., 'ModalWithTabs') from migration if the user requests
Update import statements to use the new component(s) as specified by the user
Transform component props according to user-specified mapping rules and remove deprecated props
Update the component structure to match the new component system as specified by the user, preserving all logic, state management, and event handlers

**/*.{ts,tsx}: Types should be imported from @formbricks/types for shared definitions, and local types can be defined in component or hook files
Use type guards for runtime validation

**/*.{ts,tsx}: Always generate cache keys using createCacheKey utilities
Never use flat cache keys (e.g., "user_data_456"); use namespaced, structured keys via createCacheKey

Files:

  • apps/web/modules/survey/editor/components/matrix-question-form.test.tsx
**/*.{tsx,jsx}

📄 CodeRabbit inference engine (.cursor/rules/formbricks-architecture.mdc)

**/*.{tsx,jsx}: Use useState for component-specific state, useReducer for complex state logic, and refs for mutable values that don't trigger re-renders
Use React Context for feature-specific shared state
Optimize dependency arrays in useEffect to prevent unnecessary re-renders
Implement proper loading states in components
Use client-side error boundaries and server-side error logging for error tracking

Files:

  • apps/web/modules/survey/editor/components/matrix-question-form.test.tsx
apps/web/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/cache-optimization.mdc)

apps/web/**/*.{ts,tsx}: Never use Next.js unstable_cache(); use Redis-based caching (withCache, cache service) instead
Remove revalidateEnvironment and tag-based invalidation when migrating from unstable_cache; use TTL-based expiration
Use React cache() for request-level deduplication within Next.js/React server components or handlers

Files:

  • apps/web/modules/survey/editor/components/matrix-question-form.test.tsx
{apps,packages}/**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/cache-optimization.mdc)

{apps,packages}/**/*.{ts,tsx}: Use cache.withCache() for simple database queries with an explicit TTL (milliseconds)
Always treat cache-manager + Keyv TTLs as milliseconds; set correct units when using withCache or direct set operations
Avoid creating wrapper functions solely for caching; add caching directly to the expensive, original function
Do not cache low-overhead operations (property access, basic transformations, simple lookups); reserve caching for I/O-bound or expensive work

Files:

  • apps/web/modules/survey/editor/components/matrix-question-form.test.tsx
🧬 Code graph analysis (1)
apps/web/modules/survey/editor/components/matrix-question-form.test.tsx (2)
packages/types/surveys/types.ts (3)
  • TSurveyLanguage (754-754)
  • TSurvey (2480-2480)
  • TSurveyMatrixQuestion (660-660)
apps/web/modules/survey/editor/components/matrix-question-form.tsx (1)
  • MatrixQuestionForm (34-345)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (6)
  • GitHub Check: Build Formbricks-web / Build Formbricks-web
  • GitHub Check: Run E2E Tests / Run E2E Tests
  • GitHub Check: Run Unit Tests / Unit Tests
  • GitHub Check: Validate Docker Build
  • GitHub Check: SonarQube
  • GitHub Check: Analyze (javascript)
🔇 Additional comments (8)
apps/web/modules/survey/editor/components/matrix-question-form.test.tsx (8)

1-12: LGTM!

Imports are correctly structured with types from @formbricks/types and all imports are used in the test file.


13-31: LGTM!

The dnd-kit mocks are appropriately minimal for keyboard-focused tests, providing passthrough behavior for DndContext and SortableContext while stubbing out drag-related properties.


33-43: LGTM!

The QuestionFormInput mock correctly forwards onKeyDown and provides a testable input element, which is appropriate for validating keyboard event handling.


45-60: LGTM!

The beforeEach hook properly mocks window.matchMedia with all required properties, ensuring browser API compatibility for the tests.


62-96: LGTM!

Test setup helpers create predictable test data with appropriate structure. The baseQuestion helper includes one empty row and column, which enables testing both "focus empty" and "add new" scenarios.


127-162: LGTM!

The test correctly validates that pressing Enter when no empty rows exist adds a new row with the expected structure (id and empty label). Payload validation is thorough.


164-190: LGTM!

The test correctly validates that no new column is added when an empty column exists. Similar to the row test, focus movement isn't explicitly verified, but the core behavior (not adding a new column) is properly tested.


192-226: LGTM!

The test correctly validates that pressing Enter when no empty columns exist adds a new column with the expected structure. Payload validation matches the row test pattern and is thorough.

Copy link
Member

@Dhruwang Dhruwang left a comment

Choose a reason for hiding this comment

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

Thanks for the PR 😊, Functionality works pretty well but I think we can still improve the focus logic and make it more natural.

The current implementation uses complex prop drilling (externalInputRef, shouldFocus, onFocused) across multiple components just to focus newly added choices. This adds unnecessary complexity and coupling.

A simpler approach would be to let each QuestionFormInput handle its own focus behavior:

// In QuestionFormInput
useEffect(() => {
  if (id.includes("choice") && inputRef.current) {
    inputRef.current.focus();
  }
}, []);

Ideally we can also remove check for choice in above code, so all the newly added input fields are focused automatically

Benefits:

  • ✅ Eliminates 3 props and complex state management
  • ✅ Self-contained, more predictable behavior
  • ✅ Follows React's composition over configuration principle
  • ✅ Easier to test and maintain

This way, newly added choice inputs automatically get focused on mount without requiring parent components to manage focus state or pass refs down through multiple layers.

Can you give this a try ?

@jobenjada
Copy link
Member Author

i'd love to, thanks for the review and explanation 😊

@jobenjada jobenjada requested a review from Dhruwang October 3, 2025 11:08
@jobenjada jobenjada enabled auto-merge October 3, 2025 13:41
@jobenjada jobenjada requested a review from Dhruwang October 3, 2025 13:42
Copy link

sonarqubecloud bot commented Oct 6, 2025

Copy link
Member

@Dhruwang Dhruwang left a comment

Choose a reason for hiding this comment

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

Looks good ✅🚀

@jobenjada jobenjada added this pull request to the merge queue Oct 6, 2025
Merged via the queue into main with commit 3a09af6 Oct 6, 2025
16 checks passed
@jobenjada jobenjada deleted the add-option-on-enter branch October 6, 2025 07:41
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.

2 participants