Skip to content

feat: logic fallback option added#4306

Merged
gupta-piyush19 merged 5 commits intomainfrom
406-logic-allow-all-other-questions-to-be-changed
Nov 15, 2024
Merged

feat: logic fallback option added#4306
gupta-piyush19 merged 5 commits intomainfrom
406-logic-allow-all-other-questions-to-be-changed

Conversation

@gupta-piyush19
Copy link
Contributor

@gupta-piyush19 gupta-piyush19 commented Nov 14, 2024

What does this PR do?

logic fallback option added

Fixes https://github.com/formbricks/internal/issues/406

How should this be tested?

  • Test A
  • Test B

Checklist

Required

  • Filled out the "How to test" section in this PR
  • Read How we Code at Formbricks
  • Self-reviewed my own code
  • Commented on my code in hard-to-understand bits
  • Ran pnpm build
  • Checked for warnings, there are none
  • Removed all console.logs
  • Merged the latest changes from main onto my branch with git pull origin main
  • My changes don't cause any responsiveness issues
  • First PR at Formbricks? Please sign the CLA! Without it we wont be able to merge it 🙏

Appreciated

  • If a UI change was made: Added a screen recording or screenshots to this PR
  • Updated the Formbricks Docs if changes were necessary

Summary by CodeRabbit

Release Notes

  • New Features

    • Introduced fallback logic options for survey questions, enhancing navigation and response handling.
    • Added a user-friendly selection component for choosing fallback options in the survey editor.
    • Enhanced the ability to check if ending cards are referenced in survey logic before deletion.
    • Improved survey management with robust validation checks for saving and publishing surveys.
  • Bug Fixes

    • Improved error handling for database-related issues in survey summary generation.
    • Enhanced logic evaluation to prevent cyclic dependencies in question navigation.
  • Localization Updates

    • Updated German, English, and Brazilian Portuguese localization files for clarity and consistency in user interface text.

@vercel
Copy link

vercel bot commented Nov 14, 2024

The latest updates on your projects. Learn more about Vercel for Git ↗︎

2 Skipped Deployments
Name Status Preview Comments Updated (UTC)
formbricks-cloud ⬜️ Ignored (Inspect) Visit Preview Nov 15, 2024 11:30am
formbricks-docs ⬜️ Ignored (Inspect) Visit Preview Nov 15, 2024 11:30am

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 14, 2024

Walkthrough

The changes in this pull request primarily enhance the survey logic handling within the application. Key modifications include the introduction of fallback logic for survey questions, updates to the handling of conditional logic, and improvements in localization files for various languages. New functions and properties are added to support these features, while existing functions are refined for better error handling and logic evaluation. The overall structure of the affected components remains intact, ensuring functionality is preserved alongside the enhancements.

Changes

File Change Summary
apps/web/app/(app)/(survey-editor)/environments/[environmentId]/surveys/[surveyId]/edit/components/ConditionalLogic.tsx Modified handleRemoveLogic to include a check for the last logic item being removed, affecting the logicFallback property in updateQuestion.
apps/web/app/(app)/(survey-editor)/environments/[environmentId]/surveys/[surveyId]/edit/components/LogicEditor.tsx Introduced a useMemo hook for fallbackOptions, added a Select component for fallback selection, and updated rendering logic. New imports added for localization and icons.
apps/web/app/(app)/(survey-editor)/environments/[environmentId]/surveys/[surveyId]/edit/lib/utils.tsx Added findEndingCardUsedInLogic function and modified findQuestionUsedInLogic to include logicFallback checks.
apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/lib/surveySummary.ts Modified evaluateLogicAndGetNextQuestionId to incorporate fallback logic and refined error handling in getSurveySummary.
packages/lib/messages/de-DE.json Updated German localization strings for grammatical accuracy and clarity.
packages/lib/messages/en-US.json Modified English localization strings for clarity and consistency, including the addition of a new string.
packages/lib/messages/pt-BR.json Updated Brazilian Portuguese localization strings for improved clarity and consistency, with new strings added for user engagement.
packages/surveys/src/components/general/Survey.tsx Enhanced evaluateLogicAndGetNextQuestionId to utilize logicFallback when no jump target is set.
packages/types/surveys/types.ts Added optional logicFallback property to ZSurveyQuestionBase schema and introduced a new validation function.
packages/types/surveys/validation.ts Enhanced findQuestionsWithCyclicLogic to check for fallback logic in addition to existing jump actions.
apps/web/app/(app)/(survey-editor)/environments/[environmentId]/surveys/[surveyId]/edit/components/EditEndingCard.tsx Updated deleteEndingCard to check if an ending card is in use before deletion, incorporating findEndingCardUsedInLogic and displaying error notifications.
apps/web/app/(app)/(survey-editor)/environments/[environmentId]/surveys/[surveyId]/edit/components/SurveyMenuBar.tsx Adjusted tooltip content and enhanced validation checks in handleSurveySave and handleSurveyPublish functions for better user feedback and error handling.

Possibly related PRs

  • feat: Advanced logic editor #3020: The changes in the main PR regarding the ConditionalLogic.tsx file, specifically the handleRemoveLogic function, relate to the enhancements made in the LogicEditorActions.tsx file, which also deals with logic actions within the survey editor.
  • feat: add auto animate to web app components #3825 #3887: The integration of auto-animate in various components, including ConditionalLogic.tsx, aligns with the changes made in the main PR, enhancing user experience through animations.
  • fix: summary calculation in multi choice questions #4022: The modifications in the surveySummary.ts file to improve summary calculations for multiple-choice questions are relevant to the changes in the main PR, which also focuses on logic handling and user interactions in survey components.
  • fix: inconsistencies in survey summary  #4032: The changes in the SurveyMenuBar.tsx file to update caution messages and validation logic are related to the overall improvements in user feedback and survey summary handling in the main PR.
  • fix: styling fixes #4279: The updates to the CardStylingSettings.tsx file regarding default values for card arrangements are relevant to the main PR's focus on enhancing the survey editor's functionality and user interface.

Suggested labels

enhancement, bug, customer request

Suggested reviewers

  • Dhruwang
  • jobenjada

Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@github-actions
Copy link
Contributor

github-actions bot commented Nov 14, 2024

Thank you for following the naming conventions for pull request titles! 🙏

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: 3

🧹 Outside diff range and nitpick comments (16)
apps/web/app/(app)/(survey-editor)/environments/[environmentId]/surveys/[surveyId]/edit/components/LogicEditor.tsx (2)

38-65: Enhance type safety and simplify the implementation.

The useMemo implementation is correct, but could benefit from some improvements:

Consider applying these enhancements:

+ type FallbackOption = {
+   icon?: ReactElement;
+   label: string;
+   value: string;
+ };

  const fallbackOptions = useMemo(() => {
-   let options: {
-     icon?: ReactElement;
-     label: string;
-     value: string;
-   }[] = [];
+   const options: FallbackOption[] = [];

    localSurvey.questions.forEach((ques) => {
-     if (ques.id === question.id) return null;
+     if (ques.id === question.id) return;
      options.push({
        icon: QUESTIONS_ICON_MAP[ques.type],
        label: getLocalizedValue(ques.headline, "default"),
        value: ques.id,
      });
    });

Line range hint 37-115: Consider adding validation and error handling.

The implementation could benefit from additional safeguards:

  1. Add null checks for localSurvey.questions and localSurvey.endings arrays
  2. Validate that the logicFallback value exists in the available options before applying it
  3. Consider adding error boundaries to handle potential rendering failures

Would you like me to provide a code example implementing these safeguards?

apps/web/app/(app)/(survey-editor)/environments/[environmentId]/surveys/[surveyId]/edit/components/ConditionalLogic.tsx (1)

Line range hint 1-190: Consider extracting logic operations to a custom hook.

The component currently handles multiple logic operations (add, remove, move, duplicate). To improve maintainability and reusability, consider:

  1. Extracting these operations into a custom hook (e.g., useSurveyLogic)
  2. Moving the logic transformation utilities to a separate service
  3. Creating a dedicated LogicOperations context if these operations are used across multiple components

Example structure:

// hooks/useSurveyLogic.ts
export function useSurveyLogic(question, questionIdx, updateQuestion) {
  const addLogic = useCallback(() => {
    // Current addLogic implementation
  }, [question, questionIdx, updateQuestion]);

  const removeLogic = useCallback((logicItemIdx) => {
    // Current handleRemoveLogic implementation
  }, [question, questionIdx, updateQuestion]);

  // ... other operations

  return { addLogic, removeLogic, moveLogic, duplicateLogic };
}
packages/types/surveys/validation.ts (2)

229-229: Consider documenting the fallback behavior.

The comment "Handle default behavior" could be more explicit about the precedence rules between jump actions, fallback logic, and default next question behavior.

-      // Handle default behavior: move to the next question if no jump actions or fallback logic is defined
+      // Precedence: 1. Jump actions (if conditions met)
+      //            2. Fallback logic (if specified)
+      //            3. Default: move to next question

217-229: Consider performance optimization for deep fallback chains.

While the implementation is correct, deep fallback chains could impact performance during validation. Consider:

  1. Adding a maximum depth limit for fallback chains
  2. Caching visited paths to optimize repeated validations
  3. Adding telemetry to monitor chain depths in production

Example implementation:

const MAX_FALLBACK_DEPTH = 10;
const visitedPaths = new Map<string, Set<string>>();

const checkForCyclicLogic = (questionId: TSurveyQuestionId, depth = 0): boolean => {
  if (depth > MAX_FALLBACK_DEPTH) {
    console.warn(`Maximum fallback depth exceeded for question ${questionId}`);
    return false;
  }
  
  // Cache hit: return early if we've seen this path before
  const pathKey = Array.from(recStack).filter(([_, v]) => v).map(([k]) => k).join(',');
  if (visitedPaths.has(pathKey)) {
    return visitedPaths.get(pathKey)!.has(questionId);
  }
  
  // Rest of the existing logic...
}
packages/surveys/src/components/general/Survey.tsx (2)

Line range hint 258-275: Add validation for logicFallback value

The current implementation should validate the logicFallback value to ensure it references a valid question or ending ID.

Add validation to prevent navigation to invalid questions:

    // Use logicFallback if no jump target was set
    if (!firstJumpTarget && currQuesTemp.logicFallback) {
+     // Validate that logicFallback points to a valid question or ending
+     const isValidQuestion = questions.some(q => q.id === currQuesTemp.logicFallback);
+     const isValidEnding = survey.endings.some(e => e.id === currQuesTemp.logicFallback);
+     if (!isValidQuestion && !isValidEnding) {
+       console.warn(`Invalid logicFallback target: ${currQuesTemp.logicFallback}`);
+       firstJumpTarget = questions[currentQuestionIndex + 1]?.id || firstEndingId;
+     } else {
        firstJumpTarget = currQuesTemp.logicFallback;
+     }
    }

Line range hint 245-260: Enhance error handling in logic evaluation

The current error handling is minimal and could be improved to provide better debugging information and handle edge cases more gracefully.

Consider enhancing the error handling:

    if (questionId === "start")
      return { nextQuestionId: questions[0]?.id || firstEndingId, calculatedVariables: {} };

-   if (!currQuesTemp) throw new Error("Question not found");
+   if (!currQuesTemp) {
+     console.error(`Failed to find question with ID: ${questionId}`);
+     throw new Error(`Question not found: ${questionId}`);
+   }

    let firstJumpTarget: string | undefined;
    const allRequiredQuestionIds: string[] = [];

    let calculationResults = { ...currentVariables };
    const localResponseData = { ...responseData, ...data };

+   try {
      if (currQuesTemp.logic && currQuesTemp.logic.length > 0) {
        for (const logic of currQuesTemp.logic) {
          if (
            evaluateLogic(
              localSurvey,
              localResponseData,
              calculationResults,
              logic.conditions,
              selectedLanguage
            )
          ) {
            // ... existing logic ...
          }
        }
      }
+   } catch (error) {
+     console.error(`Logic evaluation failed for question ${questionId}:`, error);
+     // Fallback to next question in sequence
+     return {
+       nextQuestionId: questions[currentQuestionIndex + 1]?.id || firstEndingId,
+       calculatedVariables: calculationResults
+     };
+   }
apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/lib/surveySummary.ts (3)

122-125: Add documentation for the fallback logic behavior.

While the implementation is correct, adding a comment explaining when and why the fallback logic is triggered would improve code maintainability.

-  // If no jump target was set, check for a fallback logic
+  // If no conditions in the logic array evaluate to true or no jump target is set,
+  // use the fallback logic to determine the next question. This ensures a default
+  // path when no specific logic conditions are met.
   if (!firstJumpTarget && currQuesTemp.logicFallback) {

Line range hint 1-1000: Consider adding more specific error handling.

The error handling is good but could be enhanced by adding specific error types for different scenarios. This would help in better error reporting and debugging.

Consider creating and handling specific error types for:

  1. Invalid filter criteria
  2. Cache-related errors
  3. Data transformation errors

Example implementation:

class InvalidFilterError extends Error {
  constructor(message: string) {
    super(message);
    this.name = 'InvalidFilterError';
  }
}

class CacheError extends Error {
  constructor(message: string) {
    super(message);
    this.name = 'CacheError';
  }
}

Line range hint 1-1000: Consider splitting the file into smaller modules.

The file has grown quite large and handles multiple responsibilities. Consider breaking it down into smaller, more focused modules for better maintainability.

Suggested structure:

  1. Create a separate module for each question type handler
  2. Move utility functions to a separate file
  3. Create a dedicated types file
  4. Consider using the Strategy pattern for question type handling

Example reorganization:

// questionHandlers/
//   - multipleChoice.ts
//   - rating.ts
//   - openText.ts
//   etc.

// utils/
//   - validation.ts
//   - transformation.ts
//   - cache.ts

// types/
//   - questions.ts
//   - responses.ts
//   - summary.ts
apps/web/app/(app)/(survey-editor)/environments/[environmentId]/surveys/[surveyId]/edit/lib/utils.tsx (3)

1063-1065: Consider improving readability with destructuring

The condition check could be more readable by destructuring the question properties.

-    (question) =>
-      question.logicFallback === questionId ||
-      (question.id !== questionId && question.logic?.some(isUsedInLogicRule))
+    ({ id, logicFallback, logic }) =>
+      logicFallback === questionId ||
+      (id !== questionId && logic?.some(isUsedInLogicRule))

1151-1163: Add JSDoc documentation for consistency

The new function follows the pattern of other utility functions but lacks documentation. Consider adding JSDoc for consistency with other utility functions.

+/**
+ * Finds the index of the first question that uses the specified ending card in its logic
+ * @param survey - The survey to search in
+ * @param endingCardId - The ID of the ending card to search for
+ * @returns The index of the first question using the ending card, or -1 if not found
+ */
 export const findEndingCardUsedInLogic = (survey: TSurvey, endingCardId: string): number => {

1160-1162: Consider improving readability with destructuring (similar to previous comment)

For consistency with the suggested improvement above, consider destructuring here as well.

-    (question) => question.logicFallback === endingCardId || question.logic?.some(isUsedInLogicRule)
+    ({ logicFallback, logic }) => logicFallback === endingCardId || logic?.some(isUsedInLogicRule)
packages/lib/messages/de-DE.json (1)

Line range hint 1-2000: Inconsistent use of formal/informal address throughout the file

There are inconsistencies in the use of formal ("Sie") and informal ("Du") address forms throughout the translations. For example, some sections use the informal "Du" while others use the formal "Sie", which could create an inconsistent tone of voice.

Consider standardizing the address form throughout the translations to maintain consistency. The informal "Du" form seems to be more prevalent and aligns better with modern software UI conventions.

packages/types/surveys/types.ts (2)

2032-2076: Consider returning an empty array from validateLogicFallback for consistency.

To simplify the handling of validation issues, modify validateLogicFallback to always return a z.ZodIssue[], returning an empty array when there are no issues. This avoids the need to check for undefined when combining validation results.

Apply this diff to implement the change:

-const validateLogicFallback = (survey: TSurvey, questionIdx: number): z.ZodIssue[] | undefined => {
+const validateLogicFallback = (survey: TSurvey, questionIdx: number): z.ZodIssue[] => {
  const question = survey.questions[questionIdx];

-  if (!question.logicFallback) return;
+  if (!question.logicFallback) return [];

  // ... rest of the code ...
}

Update the validateLogic function accordingly:

 const validateLogic = (survey: TSurvey, questionIndex: number, logic: TSurveyLogic[]): z.ZodIssue[] => {
   const logicFallbackIssue = validateLogicFallback(survey, questionIndex);

-  return [...logicIssues.flat(), ...(logicFallbackIssue ? logicFallbackIssue : [])];
+  return [...logicIssues.flat(), ...logicFallbackIssue];
 };

2055-2066: Simplify collection of possibleFallbackIds.

You can improve readability by using array methods like filter and map to collect possibleFallbackIds.

Apply this diff to refactor the code:

-  const possibleFallbackIds: string[] = [];
-
-  survey.questions.forEach((q, idx) => {
-    if (idx !== questionIdx) {
-      possibleFallbackIds.push(q.id);
-    }
-  });
-
-  survey.endings.forEach((e) => {
-    possibleFallbackIds.push(e.id);
-  });
+  const possibleFallbackIds = survey.questions
+    .filter((_, idx) => idx !== questionIdx)
+    .map((q) => q.id)
+    .concat(survey.endings.map((e) => e.id));
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between a8ab4aa and b9854fc.

📒 Files selected for processing (10)
  • apps/web/app/(app)/(survey-editor)/environments/[environmentId]/surveys/[surveyId]/edit/components/ConditionalLogic.tsx (1 hunks)
  • apps/web/app/(app)/(survey-editor)/environments/[environmentId]/surveys/[surveyId]/edit/components/LogicEditor.tsx (3 hunks)
  • apps/web/app/(app)/(survey-editor)/environments/[environmentId]/surveys/[surveyId]/edit/lib/utils.tsx (2 hunks)
  • apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/lib/surveySummary.ts (1 hunks)
  • packages/lib/messages/de-DE.json (2 hunks)
  • packages/lib/messages/en-US.json (2 hunks)
  • packages/lib/messages/pt-BR.json (2 hunks)
  • packages/surveys/src/components/general/Survey.tsx (1 hunks)
  • packages/types/surveys/types.ts (2 hunks)
  • packages/types/surveys/validation.ts (1 hunks)
🔇 Additional comments (9)
apps/web/app/(app)/(survey-editor)/environments/[environmentId]/surveys/[surveyId]/edit/components/LogicEditor.tsx (1)

5-15: LGTM: Imports are well-organized and necessary.

The new imports support the fallback logic functionality and maintain consistency with the existing codebase.

apps/web/app/(app)/(survey-editor)/environments/[environmentId]/surveys/[surveyId]/edit/components/ConditionalLogic.tsx (1)

90-95: LGTM with minor suggestions for type safety.

The logic for clearing the fallback when removing the last logic item is sound. However, consider these improvements:

- const isLast = logicCopy.length === 1;
+ const isLast = Array.isArray(logicCopy) && logicCopy.length === 1;

Let's verify the logicFallback property is properly typed in the TSurveyQuestion interface:

packages/types/surveys/validation.ts (1)

217-228: Verify edge cases in fallback logic cycle detection.

The implementation correctly checks for cyclic dependencies in fallback logic, following the same pattern as jump actions. However, there are a few edge cases to consider:

  1. A question could have both logic jumps and fallback logic
  2. The fallback chain could be very long, potentially affecting performance

Let's verify these edge cases:

✅ Verification successful

After analyzing the complete implementation, I can now provide a final response:

The cyclic logic detection implementation is robust and handles edge cases correctly

The implementation in findQuestionsWithCyclicLogic properly handles all edge cases:

  1. Questions with both logic jumps and fallback logic are handled sequentially - first checking jump actions, then fallback logic
  2. The recursive implementation with visited and recStack maps prevents infinite loops in long fallback chains
  3. The function maintains the existing behavior of checking next questions while adding fallback logic support

The code follows the same proven depth-first search pattern used for jump actions, making it a reliable solution for detecting cycles in the question flow graph.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for questions with both logic jumps and fallback logic
# This helps us understand the complexity of logic chains

# Search for questions with both logic and logicFallback
ast-grep --pattern 'const question = {
  $$$
  logic: $_,
  $$$
  logicFallback: $_,
  $$$
}'

Length of output: 95


Script:

#!/bin/bash
# Let's try a different approach to analyze the cyclic logic detection implementation

# First, let's see the full implementation of the cyclic detection function
rg -A 30 "function.*findQuestionsWithCyclicLogic" 

# Then, let's look for any test cases that verify this behavior
rg -l "logicFallback.*test|test.*logicFallback"

# Also search for any interfaces or types defining the question structure
ast-grep --pattern 'interface $_ {
  $$$
  logicFallback?: $_
  $$$
}'

Length of output: 174


Script:

#!/bin/bash
# Let's try a simpler approach focusing on the validation.ts file

# View the complete validation.ts file to understand the full context
cat packages/types/surveys/validation.ts

# Also check for any test files in the same directory
fd "validation.test" packages/types/surveys/

Length of output: 9884

packages/surveys/src/components/general/Survey.tsx (1)

261-264: Verify handling of logicFallback in all survey flows

The implementation of the logic fallback looks correct, providing a clean fallback mechanism when no jump target is determined from the logic conditions. However, we should ensure this change is properly integrated with all survey scenarios.

Let's verify the integration of logicFallback:

Consider adding a comment explaining the fallback behavior for better maintainability:

    // Use logicFallback if no jump target was set
+   // This provides a default navigation path when no logic conditions are met
    if (!firstJumpTarget && currQuesTemp.logicFallback) {
      firstJumpTarget = currQuesTemp.logicFallback;
    }
✅ Verification successful

Based on the shell script results, I can now provide a final response:

Logic fallback implementation is properly integrated

The verification shows that:

  • The logicFallback property is properly integrated into the survey system's type definitions and editor components
  • The feature is used in multiple places:
    • Survey editor's logic editor component for configuration
    • Survey validation in types package
    • Survey flow evaluation in the main Survey component
  • The implementation is consistent with the existing logic evaluation system and properly handles edge cases
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify logicFallback implementation and usage

# Check for logicFallback property definition in survey types
ast-grep --pattern 'interface TSurveyQuestion {
  $$$
  logicFallback?: $_
  $$$
}'

# Check for logicFallback assignments in survey configuration
rg -A 3 'logicFallback.*=' 

# Check for potential edge cases in logic evaluation
rg -A 5 'evaluateLogic.*\(' 

Length of output: 11279

packages/lib/messages/en-US.json (1)

1261-1261: LGTM! Good refactoring of translation strings.

Breaking down "all_other_answers_will_continue_to_the_next_question" into two separate strings:

  • "all_other_answers_will_continue_to"
  • "next_question"

This improves modularity and allows for more flexible translations and string reuse.

Also applies to: 1438-1438

packages/lib/messages/pt-BR.json (1)

Line range hint 1-2000: LGTM! Overall translations look good

The Brazilian Portuguese translations are well-structured, culturally appropriate, and maintain consistent formatting throughout the file. The translations effectively convey the meaning while using natural language that would resonate with Brazilian users.

packages/lib/messages/de-DE.json (1)

Line range hint 1-2000: Verify completeness of translations for new features

Some newer features might be missing translations or using English fallbacks.

Let's verify the completeness of translations:

✅ Verification successful

Based on the search results, I can provide a final assessment of the translation completeness:

German translations are well-maintained with minimal English remnants

The scan reveals that English words appear primarily in expected contexts:

  • Technical terms that are commonly left in English (e.g. "Button", "Settings", "Admin")
  • Variable placeholders and code-related content (e.g. "in your settings", "click event")
  • Brand names and product terms (e.g. "Formbricks")

The translations maintain high quality German with proper grammar and natural phrasing. The few English terms found are either:

  1. Industry standard technical terms
  2. Part of code examples/variables
  3. Intentionally preserved brand names

No concerning patterns of missing or incomplete translations were identified.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Find potential missing translations by looking for English text in the German translation file
# Look for common English words that shouldn't appear in German translations
rg -i '\b(the|and|or|with|in|on|at|to|for|is|are|was|were)\b' packages/lib/messages/de-DE.json

# Look for potential untranslated UI elements (words that are typically translated)
rg -i '\b(button|click|select|choose|settings|options|menu|file|edit|view|help)\b' packages/lib/messages/de-DE.json

Length of output: 20575

packages/types/surveys/types.ts (2)

468-468: Addition of logicFallback property is appropriate.

The optional logicFallback property correctly extends ZSurveyQuestionBase to support fallback logic in surveys.


2079-2088: Integration of validateLogicFallback into validateLogic is correct.

The validateLogic function correctly incorporates validateLogicFallback to include fallback logic validation alongside existing logic validations.

Comment on lines +91 to +115
<Select
autoComplete="true"
defaultValue={question.logicFallback || "default_selection"}
onValueChange={(val) => {
updateQuestion(questionIdx, {
logicFallback: val === "default_selection" ? undefined : val,
});
}}>
<SelectTrigger className="w-auto bg-white">
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectItem key="default_selection" value={"default_selection"}>
{t("environments.surveys.edit.next_question")}
</SelectItem>
{fallbackOptions.map((option) => (
<SelectItem key={option.value} value={option.value}>
<div className="flex items-center gap-2">
{option.icon}
{option.label}
</div>
</SelectItem>
))}
</SelectContent>
</Select>
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Fix Select component props and enhance theme compatibility.

The Select implementation has a few minor issues that should be addressed:

Apply these fixes:

  <Select
-   autoComplete="true"
+   autoComplete={true}
    defaultValue={question.logicFallback || "default_selection"}
    onValueChange={(val) => {
      updateQuestion(questionIdx, {
        logicFallback: val === "default_selection" ? undefined : val,
      });
    }}>
-   <SelectTrigger className="w-auto bg-white">
+   <SelectTrigger className="w-auto">
      <SelectValue />
    </SelectTrigger>
    <SelectContent>
-     <SelectItem key="default_selection" value={"default_selection"}>
+     <SelectItem key="fallback_default_selection" value={"default_selection"}>
        {t("environments.surveys.edit.next_question")}
      </SelectItem>
      {fallbackOptions.map((option) => (
-       <SelectItem key={option.value} value={option.value}>
+       <SelectItem key={`fallback_${option.value}`} value={option.value}>
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<Select
autoComplete="true"
defaultValue={question.logicFallback || "default_selection"}
onValueChange={(val) => {
updateQuestion(questionIdx, {
logicFallback: val === "default_selection" ? undefined : val,
});
}}>
<SelectTrigger className="w-auto bg-white">
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectItem key="default_selection" value={"default_selection"}>
{t("environments.surveys.edit.next_question")}
</SelectItem>
{fallbackOptions.map((option) => (
<SelectItem key={option.value} value={option.value}>
<div className="flex items-center gap-2">
{option.icon}
{option.label}
</div>
</SelectItem>
))}
</SelectContent>
</Select>
<Select
autoComplete={true}
defaultValue={question.logicFallback || "default_selection"}
onValueChange={(val) => {
updateQuestion(questionIdx, {
logicFallback: val === "default_selection" ? undefined : val,
});
}}>
<SelectTrigger className="w-auto">
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectItem key="fallback_default_selection" value={"default_selection"}>
{t("environments.surveys.edit.next_question")}
</SelectItem>
{fallbackOptions.map((option) => (
<SelectItem key={`fallback_${option.value}`} value={option.value}>
<div className="flex items-center gap-2">
{option.icon}
{option.label}
</div>
</SelectItem>
))}
</SelectContent>
</Select>

"adjust_survey_closed_message_description": "Mude a mensagem que os visitantes veem quando a pesquisa está fechada.",
"adjust_the_theme_in_the": "Ajuste o tema no",
"all_other_answers_will_continue_to_the_next_question": "Todas as outras respostas continuarão para a próxima pergunta",
"all_other_answers_will_continue_to": "Todas as outras respostas continuarão a",
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Fix incomplete translation string

The translation "Todas as outras respostas continuarão a" appears to be incomplete as it ends with a preposition "a" without completing the sentence. This could cause confusion for users.

Please complete the translation by adding what the answers will continue to do, for example:

  • "Todas as outras respostas continuarão a próxima pergunta" or
  • "Todas as outras respostas continuarão ao próximo passo"

"adjust_survey_closed_message_description": "Ändere die Nachricht, die Besucher sehen, wenn die Umfrage geschlossen ist.",
"adjust_the_theme_in_the": "Passe das Thema an in den",
"all_other_answers_will_continue_to_the_next_question": "Alle anderen Antworten führen zur nächsten Frage",
"all_other_answers_will_continue_to": "Alle anderen Antworten werden weiterhin",
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Incomplete translation needs attention

The translation "Alle anderen Antworten werden weiterhin" appears to be incomplete as it lacks the completion of the sentence. The phrase ends abruptly without specifying what happens with other answers.

Consider completing the sentence to properly convey the intended meaning.

Copy link
Contributor

@pandeymangg pandeymangg left a comment

Choose a reason for hiding this comment

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

looks great and works great 🚀
just mentioned some very small changes (mostly nits), please go through them

also, pls capitalize the casing for the next question option here:

Screenshot 2024-11-15 at 3 43 38 PM

return survey.questions.findIndex((question) => question.logic?.some(isUsedInLogicRule));
};

export const findEndingCardUsedInLogic = (survey: TSurvey, endingCardId: string): number => {
Copy link
Contributor

Choose a reason for hiding this comment

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

I couldn't find any implmentations of this function, pls use this or remove if its not required

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

🧹 Outside diff range and nitpick comments (4)
apps/web/app/(app)/(survey-editor)/environments/[environmentId]/surveys/[surveyId]/edit/components/LogicEditor.tsx (2)

38-65: Enhance the fallback options implementation.

A few suggestions to improve the code:

+ interface FallbackOption {
+   icon?: ReactElement;
+   label: string;
+   value: string;
+ }

  const fallbackOptions = useMemo(() => {
-   let options: {
-     icon?: ReactElement;
-     label: string;
-     value: string;
-   }[] = [];
+   const availableOptions: FallbackOption[] = [];

    localSurvey.questions.forEach((ques) => {
-     if (ques.id === question.id) return null;
+     if (ques.id === question.id) return;
      options.push({
        icon: QUESTIONS_ICON_MAP[ques.type],
        label: getLocalizedValue(ques.headline, "default"),
        value: ques.id,
      });
    });

91-115: Extract string literals into constants.

Consider extracting the repeated string literal into a constant for better maintainability:

+ const DEFAULT_SELECTION_VALUE = "defaultSelection";

  <Select
    autoComplete={true}
-   defaultValue={question.logicFallback || "defaultSelection"}
+   defaultValue={question.logicFallback || DEFAULT_SELECTION_VALUE}
    onValueChange={(val) => {
      updateQuestion(questionIdx, {
-       logicFallback: val === "defaultSelection" ? undefined : val,
+       logicFallback: val === DEFAULT_SELECTION_VALUE ? undefined : val,
      });
    }}>
    ...
    <SelectContent>
      <SelectItem 
        key="fallback_default_selection" 
-       value={"defaultSelection"}
+       value={DEFAULT_SELECTION_VALUE}
      >
apps/web/app/(app)/(survey-editor)/environments/[environmentId]/surveys/[surveyId]/edit/components/EditEndingCard.tsx (1)

104-104: Consider enhancing the error message for better clarity

The current error message uses array index + 1 to show the question number. This might be confusing if questions can be reordered or if some questions are hidden/inactive.

Consider modifying the error message to include more context:

-toast.error(t("environments.surveys.edit.ending_card_used_in_logic", { questionIndex: quesIdx + 1 }));
+toast.error(t("environments.surveys.edit.ending_card_used_in_logic", {
+  questionIndex: quesIdx + 1,
+  questionTitle: localSurvey.questions[quesIdx].headline[selectedLanguageCode] || `Question ${quesIdx + 1}`
+}));

You'll also need to update the translation key to include the question title in the message.

packages/types/surveys/types.ts (1)

2037-2045: Optimize the condition check

The condition can be simplified using short-circuit evaluation.

-  if (!question.logic?.length && question.logicFallback) {
+  if (!question.logic?.length) {

This works because we already check for logicFallback existence at line 2035.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between b9854fc and 6f386e7.

📒 Files selected for processing (8)
  • apps/web/app/(app)/(survey-editor)/environments/[environmentId]/surveys/[surveyId]/edit/components/EditEndingCard.tsx (2 hunks)
  • apps/web/app/(app)/(survey-editor)/environments/[environmentId]/surveys/[surveyId]/edit/components/LogicEditor.tsx (3 hunks)
  • apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/lib/surveySummary.ts (1 hunks)
  • packages/lib/messages/de-DE.json (3 hunks)
  • packages/lib/messages/en-US.json (3 hunks)
  • packages/lib/messages/pt-BR.json (3 hunks)
  • packages/surveys/src/components/general/Survey.tsx (1 hunks)
  • packages/types/surveys/types.ts (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (5)
  • apps/web/app/(app)/environments/[environmentId]/surveys/[surveyId]/(analysis)/summary/lib/surveySummary.ts
  • packages/lib/messages/de-DE.json
  • packages/lib/messages/en-US.json
  • packages/lib/messages/pt-BR.json
  • packages/surveys/src/components/general/Survey.tsx
🔇 Additional comments (6)
apps/web/app/(app)/(survey-editor)/environments/[environmentId]/surveys/[surveyId]/edit/components/LogicEditor.tsx (1)

91-115: Verify integration with survey logic evaluation.

The fallback logic implementation looks good, but let's ensure it's properly integrated with the survey logic evaluation system.

✅ Verification successful

Based on the gathered information, I can now provide the final response as the implementation details are clear. The logicFallback is properly integrated across the codebase with:

  1. Type definitions and validation in types.ts
  2. Cyclic dependency checks in validation.ts
  3. Logic evaluation in Survey.tsx
  4. Usage tracking in utils.tsx
  5. Proper state management in ConditionalLogic.tsx

The logicFallback implementation is correctly integrated with the survey logic evaluation system

The implementation:

  • Has proper type safety and validation
  • Prevents cyclic logic paths
  • Correctly evaluates fallback logic during survey execution
  • Maintains consistency when questions are modified
  • Properly handles the relationship with other logic rules
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the integration of logicFallback with survey logic evaluation

# Check for logicFallback usage in survey logic evaluation
echo "Checking for logicFallback usage in survey logic evaluation..."
rg -l "logicFallback" --type ts

# Check for potential validation implementations
echo "Checking for validation implementations..."
ast-grep --pattern 'function $_(logicFallback: $_) {
  $$$
}'

Length of output: 889


Script:

#!/bin/bash
# Let's examine the implementation details in key files

# Check the types definition
echo "=== Checking types definition ==="
cat packages/types/surveys/types.ts | grep -A 10 "logicFallback"

# Check validation implementation
echo -e "\n=== Checking validation implementation ==="
cat packages/types/surveys/validation.ts | grep -A 10 "logicFallback"

# Check survey logic evaluation
echo -e "\n=== Checking survey logic evaluation ==="
cat packages/surveys/src/components/general/Survey.tsx | grep -A 10 "logicFallback"

# Check utils implementation
echo -e "\n=== Checking utils implementation ==="
cat "apps/web/app/(app)/(survey-editor)/environments/[environmentId]/surveys/[surveyId]/edit/lib/utils.tsx" | grep -A 10 "logicFallback"

# Check conditional logic implementation
echo -e "\n=== Checking conditional logic implementation ==="
cat "apps/web/app/(app)/(survey-editor)/environments/[environmentId]/surveys/[surveyId]/edit/components/ConditionalLogic.tsx" | grep -A 10 "logicFallback"

Length of output: 5163

apps/web/app/(app)/(survey-editor)/environments/[environmentId]/surveys/[surveyId]/edit/components/EditEndingCard.tsx (2)

6-9: LGTM: Import statements are properly structured

The new imports support the enhanced functionality for checking logic dependencies and error notifications.

Also applies to: 16-16


100-106: LGTM: Added safety check before deleting ending cards

The implementation correctly prevents deletion of ending cards that are referenced in survey logic, maintaining data integrity.

packages/types/surveys/types.ts (3)

468-468: LGTM: logicFallback property addition

The new logicFallback property is correctly typed as an optional ZSurveyQuestionId, ensuring consistent ID validation across the survey system.


2079-2088: LGTM: Clean integration of logicFallback validation

The integration preserves the existing validation structure while properly incorporating the new logicFallback validation. The spread operator usage ensures all validation results are properly combined.


2032-2076: Verify validation coverage for edge cases

The validation logic looks solid but let's verify coverage for all edge cases.

✅ Verification successful

Based on the comprehensive analysis of the codebase, I can now provide the final response:

The validation logic is robust and covers all critical edge cases

The implementation handles all important scenarios:

  • Validates fallback logic without any conditional logic
  • Prevents self-referential fallback logic
  • Validates existence of fallback question ID
  • Detects and prevents cyclic logic paths through both conditional logic and fallback logic
  • Integrates with the broader survey validation system

The cyclic logic detection is particularly thorough, covering:

  • Direct cycles through fallback logic
  • Indirect cycles through question chains
  • Combinations of conditional jumps and fallback logic
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for potential edge cases in the codebase
# Test: Search for existing logicFallback usage patterns

# Look for any existing logicFallback implementations
rg -l "logicFallback"

# Look for any logic-related test files
fd -e test.ts -e spec.ts | rg -i "logic"

Length of output: 626


Script:

#!/bin/bash
# Let's analyze the implementation and test coverage

# Check the validation implementation
rg -A 10 "logicFallback" packages/types/surveys/validation.ts

# Look for test cases in the codebase
rg -A 10 "validateLogicFallback" --type ts

# Check the actual usage in components to understand edge cases
rg -A 5 "logicFallback" packages/surveys/src/components/general/Survey.tsx

# Check logic editor implementation for potential edge cases
rg -A 5 "logicFallback" 'apps/web/app/(app)/(survey-editor)/environments/[environmentId]/surveys/[surveyId]/edit/components/LogicEditor.tsx'

Length of output: 3101


Script:

#!/bin/bash
# Let's check for cyclic logic validation and other edge cases

# Check cyclic logic validation implementation
ast-grep --pattern 'function checkForCyclicLogic($_) {
  $$$
}'

# Look for any test cases involving cyclic logic
rg -B 5 -A 10 "cyclic.*logic" --type ts -i

# Check the schema definition to understand the complete logic structure
rg -A 10 "logicFallback.*z\." --type ts

Length of output: 12987

Copy link
Contributor

@pandeymangg pandeymangg left a comment

Choose a reason for hiding this comment

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

LGTM 🚀

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

🧹 Outside diff range and nitpick comments (1)
apps/web/app/(app)/(survey-editor)/environments/[environmentId]/surveys/[surveyId]/edit/components/SurveyMenuBar.tsx (1)

347-347: Consider accessibility improvements for the tooltip text

The tooltip text is correctly using the pre-translated cautionText variable. However, to improve accessibility and user experience:

  1. Consider adding an aria-label to the tooltip trigger for screen readers
  2. The text size (text-xs) might be too small for comfortable reading
-                  <p className="py-2 text-center text-xs text-slate-500 dark:text-slate-400">{cautionText}</p>
+                  <p className="py-2 text-center text-sm text-slate-500 dark:text-slate-400" role="tooltip">{cautionText}</p>

Additionally, consider adding an aria-label to the trigger:

-                  <AlertTriangleIcon className="h-5 w-5 text-amber-400" />
+                  <AlertTriangleIcon className="h-5 w-5 text-amber-400" aria-label="Warning about survey changes" />
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 6f386e7 and fff5785.

📒 Files selected for processing (1)
  • apps/web/app/(app)/(survey-editor)/environments/[environmentId]/surveys/[surveyId]/edit/components/SurveyMenuBar.tsx (1 hunks)
🔇 Additional comments (1)
apps/web/app/(app)/(survey-editor)/environments/[environmentId]/surveys/[surveyId]/edit/components/SurveyMenuBar.tsx (1)

Line range hint 183-235: Verify validation handling for new logic fallback feature

The validateSurveyWithZod function uses the ZSurvey schema for validation. Since this PR introduces logic fallback options, we should verify that this validation properly handles the new feature.

@pandeymangg pandeymangg added this pull request to the merge queue Nov 15, 2024
@github-merge-queue github-merge-queue bot removed this pull request from the merge queue due to failed status checks Nov 15, 2024
@gupta-piyush19 gupta-piyush19 added this pull request to the merge queue Nov 15, 2024
Merged via the queue into main with commit 43b1cb9 Nov 15, 2024
@gupta-piyush19 gupta-piyush19 deleted the 406-logic-allow-all-other-questions-to-be-changed branch November 15, 2024 13:25
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