Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor questionnaire response and migrated to TanStack's query #9995

Conversation

abhimanyurajeesh
Copy link
Contributor

@abhimanyurajeesh abhimanyurajeesh commented Jan 15, 2025

Proposed Changes

Part of #9837

@ohcnetwork/care-fe-code-reviewers

Merge Checklist

  • Add specs that demonstrate bug / test a new feature.
  • Update product documentation.
  • Ensure that UI text is kept in I18n files.
  • Prep screenshot or demo video for changelog entry, and attach it to issue.
  • Request for Peer Reviews
  • Completion of QA

Summary by CodeRabbit

  • New Features

    • Added a new error message for loading questionnaire responses in the English locale.
  • Refactor

    • Updated data fetching logic across multiple components to use @tanstack/react-query.
    • Replaced custom query hooks with native useQuery and useMutation hooks.
    • Improved query key management and caching strategies.
  • Bug Fixes

    • Enhanced error handling for questionnaire-related data retrieval.

@abhimanyurajeesh abhimanyurajeesh requested a review from a team as a code owner January 15, 2025 14:45
Copy link
Contributor

coderabbitai bot commented Jan 15, 2025

Walkthrough

This pull request introduces updates to the application's error handling and data fetching mechanisms. The changes primarily focus on modernizing the query management by migrating from a custom useQuery hook to the @tanstack/react-query library. A new localization entry for questionnaire response loading errors has been added to the English JSON file. Multiple components, including QuestionnaireResponseView, QuestionnaireEditor, QuestionnaireForm, and QuestionnaireList, have been updated to use the new query configuration with improved key management and loading state handling.

Changes

File Change Summary
public/locale/en.json Added new error message for questionnaire response loading
src/components/Facility/ConsultationDetails/QuestionnaireResponseView.tsx Migrated to @tanstack/react-query, updated import and query configuration
src/components/Questionnaire/QuestionnaireEditor.tsx Updated query imports, added queryKey, replaced loading with isLoading
src/components/Questionnaire/QuestionnaireForm.tsx Migrated to @tanstack/react-query, updated query configuration
src/components/Questionnaire/index.tsx Updated to use @tanstack/react-query, modified query structure and loading state
src/hooks/useQuestionnaireOptions.ts Updated queryKey from ["questionnaire", slug] to ["questionnaires", slug]

Possibly related PRs

  • Clean Refactor Scribe as MFE | Support for Questionnaires #9636: The changes in this PR involve modifications to the public/locale/en.json file, which include the addition of new localization keys related to questionnaires, enhancing the application's internationalization support.
  • Appointment as structured question + other enhancements #9661: This PR also modifies the public/locale/en.json file by adding new keys for appointment scheduling, which aligns with the changes made in the main PR regarding error handling for questionnaire responses.
  • Patient files #9787: This PR introduces several new keys to the public/locale/en.json file, enhancing localization for patient management functionalities, which is relevant to the error handling improvements in the main PR.

Suggested labels

needs review, tested

Suggested reviewers

  • rithviknishad
  • bodhish
  • Jacobjeevan

Poem

🐰 Queries dance with grace and might,
Error messages now shine so bright!
React Query leads the way today,
Smooth data fetching, hip hooray!
Code evolves, no need to fright! 🌟

Finishing Touches

  • 📝 Generate Docstrings (Beta)

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 generate docstrings to generate docstrings for this PR. (Beta)
  • @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.

Copy link

netlify bot commented Jan 15, 2025

Deploy Preview for care-ohc ready!

Name Link
🔨 Latest commit 9a7b44b
🔍 Latest deploy log https://app.netlify.com/sites/care-ohc/deploys/67891063067e350008294297
😎 Deploy Preview https://deploy-preview-9995--care-ohc.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify site configuration.

@abhimanyurajeesh
Copy link
Contributor Author

@rithviknishad requesting for review, Thank you!

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 comments (1)
src/components/Questionnaire/QuestionnaireForm.tsx (1)

Line range hint 171-238: Refactor submission logic for better maintainability and validation.

The handleSubmit function is handling too many responsibilities and could benefit from being split into smaller, focused functions. Additionally, consider adding pre-submission validation.

+ const validateSubmission = () => {
+   if (!encounterId || !patientId) {
+     toast.error(t("missing_required_fields"));
+     return false;
+   }
+   return true;
+ };
+
+ const prepareStructuredRequests = (
+   forms: QuestionnaireFormState[],
+   context: { patientId: string; encounterId: string }
+ ): BatchRequest[] => {
+   const requests: BatchRequest[] = [];
+   forms.forEach((form) => {
+     // ... structured request logic ...
+   });
+   return requests;
+ };
+
+ const prepareQuestionnaireRequests = (
+   forms: QuestionnaireFormState[]
+ ): BatchRequest[] => {
+   const requests: BatchRequest[] = [];
+   forms.forEach((form) => {
+     // ... questionnaire submission logic ...
+   });
+   return requests;
+ };

  const handleSubmit = async () => {
    setIsDirty(false);
-   if (hasErrors) return;
+   if (hasErrors || !validateSubmission()) return;

    const requests: BatchRequest[] = [];
+   const context = { patientId, encounterId: encounterId! };
+
    if (encounterId && patientId) {
-     const context = { patientId, encounterId };
-     // First, collect all structured data requests...
+     requests.push(...prepareStructuredRequests(questionnaireForms, context));
    }

-   // Then, add questionnaire submission requests...
+   requests.push(...prepareQuestionnaireRequests(questionnaireForms));

    submitBatch({ requests });
  };
🧹 Nitpick comments (5)
src/components/Questionnaire/QuestionnaireEditor.tsx (2)

63-69: LGTM! Well-structured query configuration.

The query configuration follows TanStack Query best practices. Consider enhancing type safety for query keys.

Consider creating a type-safe query key factory:

const queryKeys = {
  questionnaireDetail: (id: string) => 
    ['questionnaireDetail', id] as const
} as const;

// Usage
useQuery({
  queryKey: queryKeys.questionnaireDetail(id),
  queryFn: query(questionnaireApi.detail, {
    pathParams: { id },
  }),
});

Line range hint 1-1000: LGTM! Well-implemented questionnaire editor with robust features.

The component demonstrates excellent organization, proper state management, and good accessibility practices.

Consider memoizing the question editor components to optimize performance with large questionnaires:

const MemoizedQuestionEditor = React.memo(QuestionEditor);

// Usage in the mapping function
{questionnaire.questions.map((question, index) => (
  <Draggable key={question.id} draggableId={question.id} index={index}>
    {(provided) => (
      <MemoizedQuestionEditor
        // ... props
      />
    )}
  </Draggable>
))}
src/components/Questionnaire/QuestionnaireForm.tsx (3)

77-84: Add type safety to error handling in useQuery.

While the query configuration follows TanStack's best practices, consider adding explicit error typing for better type safety.

  const {
    data: questionnaireData,
    isLoading: isQuestionnaireLoading,
-   error: questionnaireError,
+   error: questionnaireError,
+   } = useQuery<QuestionnaireDetail, Error>({
-   }) = useQuery({
    queryKey: ["questionnaireDetail", questionnaireSlug],
    queryFn: query(questionnaireApi.detail, {
      pathParams: { id: questionnaireSlug ?? "" },
    }),
    enabled: !!questionnaireSlug && !FIXED_QUESTIONNAIRES[questionnaireSlug],
  });

Line range hint 115-124: Enhance error handling with retry mechanism and detailed error states.

Consider implementing a more robust error handling strategy:

  1. Add retry mechanism for transient failures
  2. Handle network errors explicitly
  3. Display more detailed error information when available
  if (questionnaireError) {
+   const isNetworkError = questionnaireError instanceof Error && 
+     questionnaireError.message === 'Network Error';
    return (
      <Alert variant="destructive" className="m-4">
        <AlertTitle>{t("questionnaire_error_loading")}</AlertTitle>
-       <AlertDescription>{t("questionnaire_not_exist")}</AlertDescription>
+       <AlertDescription>
+         {isNetworkError 
+           ? t("network_error_try_again")
+           : t("questionnaire_not_exist")}
+       </AlertDescription>
+       <Button 
+         onClick={() => window.location.reload()} 
+         variant="outline" 
+         className="mt-2"
+       >
+         {t("retry")}
+       </Button>
      </Alert>
    );
  }

Line range hint 1-424: Consider implementing optimistic updates and caching strategy.

While the migration to TanStack's react-query is well implemented, the component could benefit from additional react-query features:

  1. Implement optimistic updates for better UX
  2. Add proper cache invalidation strategy
  3. Consider implementing infinite query for large questionnaire lists

Example implementation for optimistic updates:

const { mutate: submitBatch } = useMutation({
  mutationFn: mutate(routes.batchRequest, { silent: true }),
  onMutate: async (variables) => {
    // Cancel outgoing refetches
    await queryClient.cancelQueries({ queryKey: ['questionnaire'] });
    
    // Snapshot the previous value
    const previousData = queryClient.getQueryData(['questionnaire']);
    
    // Optimistically update to the new value
    queryClient.setQueryData(['questionnaire'], (old) => ({
      ...old,
      // Apply optimistic update
    }));
    
    // Return context with the snapshotted value
    return { previousData };
  },
  onError: (err, variables, context) => {
    // If the mutation fails, use the context we returned above
    queryClient.setQueryData(['questionnaire'], context.previousData);
  },
  onSettled: () => {
    // Always refetch after error or success
    queryClient.invalidateQueries({ queryKey: ['questionnaire'] });
  },
});
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 71890dc and 2b33e64.

📒 Files selected for processing (2)
  • src/components/Questionnaire/QuestionnaireEditor.tsx (4 hunks)
  • src/components/Questionnaire/QuestionnaireForm.tsx (3 hunks)
🧰 Additional context used
📓 Learnings (1)
src/components/Questionnaire/QuestionnaireForm.tsx (1)
Learnt from: Jacobjeevan
PR: ohcnetwork/care_fe#9838
File: src/components/Questionnaire/QuestionnaireForm.tsx:100-105
Timestamp: 2025-01-14T05:04:43.093Z
Learning: The QuestionnaireForm component in care_fe uses raviger's useNavigationPrompt hook for handling navigation prompts, replacing a previous custom hook implementation.
⏰ Context from checks skipped due to timeout of 90000ms (2)
  • GitHub Check: cypress-run (1)
  • GitHub Check: OSSAR-Scan
🔇 Additional comments (3)
src/components/Questionnaire/QuestionnaireEditor.tsx (2)

2-2: LGTM! Clean migration to TanStack Query.

The imports are well-structured and follow best practices for React Query integration.

Also applies to: 32-32


Line range hint 93-113: LGTM! Comprehensive state handling.

The component properly handles all query states (loading, error, empty) with appropriate UI feedback.

src/components/Questionnaire/QuestionnaireForm.tsx (1)

1-1: LGTM! Import changes align with TanStack migration.

The migration from local useQuery to TanStack's react-query is implemented correctly.

Note: There's a TODO comment about switching to tanstack router's useBlocker hook in the future, which would be a good follow-up improvement.

Also applies to: 19-19

@abhimanyurajeesh
Copy link
Contributor Author

@rithviknishad I have made changes to one more file (index), which is a part of questionnaires. Sorry that I missed it out early.

@github-actions github-actions bot added needs-triage question Further information is requested labels Jan 16, 2025
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 comments (1)
src/components/Questionnaire/index.tsx (1)

Pagination implementation is needed - API already supports it

The API endpoint returns PaginatedResponse<QuestionnaireDetail>, but the component isn't utilizing this pagination capability. Implementing pagination in the frontend component is necessary to:

  • Handle large datasets efficiently
  • Improve initial load performance
  • Match the backend's paginated response structure
🔗 Analysis chain

Line range hint 25-91: Consider implementing pagination for large questionnaire lists.

The table implementation is clean and well-structured, but it might need pagination for better performance with large datasets. Consider:

  1. Implementing pagination using TanStack Query's built-in features
  2. Adding infinite scroll or load more functionality

Let's verify if pagination is needed by checking the API response structure:

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for pagination-related fields in the API response type
ast-grep --pattern 'interface QuestionnaireDetail {
  $$$
}'

Length of output: 849


Script:

#!/bin/bash
# Search for questionnaire list fetching logic
rg -A 5 "questionnaireList" --type typescript

# Also search for any API endpoints related to questionnaires
ast-grep --pattern 'get($$$"/questionnaire"$$$)'

Length of output: 131


Script:

#!/bin/bash
# Search for questionnaire list fetching logic in TypeScript files
rg -t ts -t tsx -A 5 "questionnaireList"

# Search for API calls using fetch or axios
rg -t ts -t tsx "(/api/questionnaire|/questionnaire)" -A 3

# Look for pagination-related terms
rg -t ts -t tsx "(pageSize|currentPage|pagination|infinite.*scroll)"

Length of output: 256


Script:

#!/bin/bash
# Find all TypeScript/React files first
fd "\.(ts|tsx)$" src/

# Search for API/fetch patterns in all files
grep -r "fetch.*questionnaire\|axios.*questionnaire" src/

# Use ast-grep to find React component with questionnaireList
ast-grep --pattern 'const $$ = $$$questionnaireList$$$'

Length of output: 16466


Script:

#!/bin/bash
# Check the questionnaire API implementation
cat src/types/questionnaire/questionnaireApi.ts

# Look for pagination usage in questionnaire components
grep -r "PaginatedList\|Pagination" src/components/Questionnaire/

Length of output: 2882

🧹 Nitpick comments (2)
src/components/Questionnaire/index.tsx (2)

15-18: Enhance query configuration for better cache management.

Consider the following improvements:

  1. Use a more specific query key to prevent cache collisions
  2. Add error handling
  3. Configure retry and cache settings
   const { data: response, isLoading } = useQuery({
-    queryKey: ["questionnaire"],
+    queryKey: ["questionnaires", "list"], // More specific key
     queryFn: query(questionnaireApi.list),
+    retry: 2,
+    staleTime: 5 * 60 * 1000, // 5 minutes
+    onError: (error) => {
+      console.error("Failed to fetch questionnaires:", error);
+      // Add error notification/handling here
+    },
   });

20-23: Consider enhancing loading and error states for better UX.

While the current loading state handling works, consider implementing:

  1. A skeleton UI instead of a generic loading spinner
  2. Error state UI for failed queries
  3. Empty state UI when no questionnaires exist
-  if (isLoading) {
-    return <Loading />;
+  if (isLoading) {
+    return <QuestionnaireListSkeleton />; // Add skeleton UI component
+  }
+
+  if (error) {
+    return (
+      <ErrorState
+        message="Failed to load questionnaires"
+        retry={() => refetch()}
+      />
+    );
   }
+
+  if (!questionnaireList.length) {
+    return <EmptyState message="No questionnaires found" />;
+  }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2b33e64 and 0b7c635.

📒 Files selected for processing (1)
  • src/components/Questionnaire/index.tsx (1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (2)
  • GitHub Check: cypress-run (1)
  • GitHub Check: OSSAR-Scan
🔇 Additional comments (1)
src/components/Questionnaire/index.tsx (1)

1-1: LGTM! Clean migration to TanStack Query.

The migration from a custom useQuery hook to @tanstack/react-query is a good modernization step. The imports are well-organized, and the addition of the query utility suggests proper separation of concerns.

Also applies to: 7-7

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

🧹 Nitpick comments (2)
src/hooks/useQuestionnaireOptions.ts (1)

20-20: LGTM! Consider adding a query key factory.

The query key change to "questionnaires" (plural) aligns well with REST resource naming conventions. To improve maintainability, consider extracting query keys to a centralized factory.

Example implementation:

// src/utils/queryKeys.ts
export const queryKeys = {
  questionnaires: {
    list: (slug: string) => ["questionnaires", slug] as const,
  },
} as const;

Then use it as:

queryKey: queryKeys.questionnaires.list(slug),
src/components/Questionnaire/index.tsx (1)

20-23: LGTM! Consider adding a loading skeleton.

The loading state handling looks good. Consider using a skeleton loader instead of the generic loading component for a better user experience.

Example implementation:

if (isLoading) {
  return (
    <div className="animate-pulse">
      {[...Array(5)].map((_, i) => (
        <div key={i} className="h-16 bg-gray-200 mb-2 rounded" />
      ))}
    </div>
  );
}
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0b7c635 and 9a7b44b.

📒 Files selected for processing (2)
  • src/components/Questionnaire/index.tsx (1 hunks)
  • src/hooks/useQuestionnaireOptions.ts (1 hunks)

src/components/Questionnaire/index.tsx Show resolved Hide resolved
@nihal467
Copy link
Member

LGTM

@nihal467 nihal467 added tested and removed question Further information is requested needs testing needs-triage labels Jan 17, 2025
@@ -17,7 +17,7 @@ const DEFAULT_OPTIONS: EditQuestionnaireOption[] = [

export default function useQuestionnaireOptions(slug: string) {
const { data } = useQuery({
queryKey: ["questionnaire", slug] as const,
queryKey: ["questionnaires", slug] as const,
Copy link
Member

Choose a reason for hiding this comment

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

nice find

@rithviknishad rithviknishad merged commit a0183bb into ohcnetwork:develop Jan 17, 2025
17 checks passed
Copy link

@abhimanyurajeesh Your efforts have helped advance digital healthcare and TeleICU systems. 🚀 Thank you for taking the time out to make CARE better. We hope you continue to innovate and contribute; your impact is immense! 🙌

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
Status: Done
Development

Successfully merging this pull request may close these issues.

4 participants