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

Added skeleton loader during advanced filters #9020

Open
wants to merge 2 commits into
base: develop
Choose a base branch
from

Conversation

Rishith25
Copy link
Contributor

@Rishith25 Rishith25 commented Nov 6, 2024

Proposed Changes

@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

Release Notes

  • New Features

    • Enhanced loading state management for various components, ensuring accurate display of counts only when valid data is available.
    • Improved error handling for phone number inputs and user management functions.
  • Bug Fixes

    • Resolved issues with conditional rendering of counts in multiple components to prevent incorrect displays during loading states.
  • Documentation

    • Updated internal documentation to reflect changes in component behavior and error handling processes.

@Rishith25 Rishith25 requested a review from a team as a code owner November 6, 2024 11:36
Copy link

coderabbitai bot commented Nov 6, 2024

Walkthrough

The changes in this pull request primarily involve modifications to the CountBlock component across various files, allowing the count property to accept null values in addition to number. This adjustment necessitated updates to conditional rendering logic, ensuring that loading states are accurately reflected in the UI. Various components now conditionally render null for the count prop when loading or when the count is undefined, enhancing error handling and user experience in asset management, facility lists, and patient management.

Changes

File Path Change Summary
src/CAREUI/display/Count.tsx Updated Props interface to allow count as `number
src/components/Assets/AssetsList.tsx Modified count prop to conditionally render null based on loading state. Improved error handling in accessAssetIdFromQR.
src/components/Facility/DischargedPatientsList.tsx Updated count prop to render null when loading or if count is undefined. Enhanced phone number input validation.
src/components/Facility/FacilityList.tsx Adjusted count prop to conditionally set to null if loading or permittedData.count is undefined.
src/components/Facility/FacilityUsers.tsx Updated count prop to render null if loading or facilityUserData.count is undefined.
src/components/Patient/ManagePatients.tsx Modified count prop to conditionally display null when loading or if count is undefined. Enhanced phone number validation.
src/components/Users/ManageUsers.tsx Updated count prop to conditionally return null if loading or userListData.count is undefined. Improved error handling in submission functions.
src/components/Patient/SampleViewAdmin.tsx Updated count prop to conditionally set to null if loading or if sampeleData.count is undefined.

Assessment against linked issues

Objective Addressed Explanation
Add a skeleton loader during advance filters are loaded (#8030)

🐇 In the meadow where bunnies play,
The count now hides when loading's at bay.
With props that shift like clouds in the sky,
We show the right numbers, oh my, oh my!
A hop and a skip, our UI's so bright,
With each little change, it feels just right! 🌼


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.

Copy link

netlify bot commented Nov 6, 2024

Deploy Preview for care-ohc ready!

Name Link
🔨 Latest commit bc81b10
🔍 Latest deploy log https://app.netlify.com/sites/care-ohc/deploys/672b593fcf07690008dc4537
😎 Deploy Preview https://deploy-preview-9020--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.

@Rishith25 Rishith25 changed the title Added skeleton loadier during advanced filters Added skeleton loader during advanced filters Nov 6, 2024
Copy link

@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 (10)
src/CAREUI/display/Count.tsx (1)

Line range hint 1-33: Consider adding prop-types validation and documentation.

Since this is a shared UI component (CAREUI), consider the following improvements:

  1. Add JSDoc comments documenting the null behavior
  2. Add runtime validation for the count prop
  3. Update component tests to cover null scenarios

Would you like me to help generate the documentation and test cases?

src/components/Facility/FacilityUsers.tsx (2)

275-279: LGTM! The changes effectively prevent showing 0 during loading.

The implementation correctly handles the loading state by passing null to trigger the skeleton loader, which aligns with the PR objectives to fix the count display during data fetching.

Consider simplifying the condition and adding proper TypeScript types:

- count={
-   isLoading || facilityUserData?.count === undefined
-     ? null
-     : facilityUserData.count
- }
+ type FacilityUserData = {
+   count: number;
+   results: Array<any>; // Define proper user type
+ };
+ 
+ count={isLoading ? null : facilityUserData?.count}

This refactor:

  1. Adds type safety with proper TypeScript interfaces
  2. Simplifies the condition since undefined check is handled by optional chaining

275-279: Consider consolidating loading state handling.

The component has multiple loading indicators:

  1. CountBlock's loading prop
  2. CountBlock's count being null
  3. <Loading /> component when facilityUserData is null

This might lead to inconsistent loading states. Consider using a single source of truth for loading state.

Suggestions:

  1. Use only the isLoading state from useQuery
  2. Remove the separate loading prop from CountBlock since the null count already triggers the skeleton
  3. Use Suspense boundaries for consistent loading behavior across the app
src/components/Facility/DischargedPatientsList.tsx (1)

284-286: LGTM! The loading state implementation looks good.

The conditional rendering of null for the count prop effectively prevents the display of zero counts during loading states. This implementation aligns well with the PR objective of improving the user experience during data fetching.

Consider extracting the condition into a more descriptive variable for improved readability:

-count={
-  facilityQuery.loading || count === undefined ? null : count
-}
+const isLoadingCount = facilityQuery.loading || count === undefined;
+count={isLoadingCount ? null : count}
src/components/Assets/AssetsList.tsx (2)

Line range hint 31-32: Consider consolidating loading state management.

The component currently manages multiple loading states (loading from useQuery and isLoading for QR scanning). Consider unifying these into a single loading state manager for better maintainability and consistency.

Example approach:

// Create a custom hook for managing loading states
const useLoadingState = () => {
  const [loadingStates, setLoadingStates] = useState({
    dataFetching: false,
    qrScanning: false
  });

  const setLoading = (key: keyof typeof loadingStates, value: boolean) => 
    setLoadingStates(prev => ({ ...prev, [key]: value }));

  const isLoading = Object.values(loadingStates).some(Boolean);

  return { loadingStates, setLoading, isLoading };
};

Also applies to: 362-362, 427-429


Line range hint 108-157: Enhance error handling in QR code scanning.

The current error handling uses generic messages for different error scenarios. Consider providing more specific error messages for different failure cases to improve user experience.

Example improvement:

 const accessAssetIdFromQR = async (assetURL: string) => {
   try {
     setIsLoading(true);
     setIsScannerActive(false);
     if (!isValidURL(assetURL)) {
       setIsLoading(false);
       Notification.Error({
-        msg: t("invalid_asset_id_msg"),
+        msg: t("invalid_qr_url_format"),
       });
       return;
     }
     const params = parseQueryParams(assetURL);
     const assetId = params.asset || params.assetQR;

     if (assetId) {
       const { data } = await request(routes.listAssetQR, {
         pathParams: { qr_code_id: assetId },
       });
       if (!data) {
         setIsLoading(false);
         Notification.Error({
-          msg: t("invalid_asset_id_msg"),
+          msg: t("qr_code_not_registered"),
         });
         return;
       }
       const { data: assetData } = await request(routes.listAssets, {
         query: { qr_code_id: assetId, limit: 1 },
       });
       if (assetData?.results.length === 1) {
         navigate(
           `/facility/${assetData.results[0].location_object.facility?.id}/assets/${assetData.results[0].id}`,
         );
       } else {
         setIsLoading(false);
         Notification.Error({
-          msg: t("asset_not_found_msg"),
+          msg: t("asset_deleted_or_unavailable"),
         });
       }
     } else {
       setIsLoading(false);
       Notification.Error({
-        msg: t("invalid_asset_id_msg"),
+        msg: t("missing_asset_id_in_qr"),
       });
     }
   } catch (err) {
     Notification.Error({
-      msg: t("invalid_asset_id_msg"),
+      msg: t("qr_scan_failed"),
     });
   } finally {
     setIsLoading(false);
   }
 };
src/components/Users/ManageUsers.tsx (3)

Line range hint 279-309: Improve type safety in weekly hours validation.

The current type conversion using the + operator could lead to NaN in edge cases. Consider using a more robust parsing approach.

-  if (!username || !weeklyHours || +weeklyHours < 0 || +weeklyHours > 168) {
+  const hours = Number(weeklyHours);
+  if (!username || !weeklyHours || Number.isNaN(hours) || hours < 0 || hours > 168) {
     setWeeklyHoursError("Value should be between 0 and 168");
     return;
   }

Line range hint 654-662: Standardize loading indicators across the component.

The component uses different loading indicators (Loading and CircularProgress) in different places. Consider standardizing the loading UI pattern for consistency.

Also applies to: 787-793


Line range hint 1-1000: Consider restructuring the component for better maintainability.

The current file structure has several areas for improvement:

  1. The file contains two large components that could be split into separate files
  2. Helper functions could be extracted to a separate utilities file
  3. Consider using a reducer or custom hook to manage related state
src/components/Patient/ManagePatients.tsx (1)

977-979: LGTM! The count handling aligns with the PR objectives.

The implementation correctly prevents showing a misleading zero count during loading by passing null to the CountBlock component. This change effectively addresses issue #8030.

Consider adding type safety by explicitly typing the count prop:

-  count={
-    isLoading || data?.count === undefined ? null : data?.count
-  }
+  count={
+    isLoading || data?.count === undefined ? null : (data.count as number)
+  }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 3008cc2 and 417c610.

📒 Files selected for processing (7)
  • src/CAREUI/display/Count.tsx (2 hunks)
  • src/components/Assets/AssetsList.tsx (1 hunks)
  • src/components/Facility/DischargedPatientsList.tsx (1 hunks)
  • src/components/Facility/FacilityList.tsx (1 hunks)
  • src/components/Facility/FacilityUsers.tsx (1 hunks)
  • src/components/Patient/ManagePatients.tsx (1 hunks)
  • src/components/Users/ManageUsers.tsx (1 hunks)
🔇 Additional comments (5)
src/CAREUI/display/Count.tsx (2)

5-5: LGTM! Type change aligns with loading state requirements.

The change from number to number | null is a good approach for handling loading states, allowing explicit distinction between "no data yet" (null) and "zero items" (0).


Line range hint 23-29: Verify loading state behavior across components.

The loading state implementation looks good and addresses the original issue of showing 0 counts during loading. However, we should verify that all parent components are correctly passing null during loading states.

✅ Verification successful

Based on the search results, I can generate the final response as I have sufficient information about how the CountBlock component is being used across the codebase.

Loading states are properly handled across all parent components

All instances of CountBlock usage in the codebase correctly handle loading states by passing null during loading or when count is undefined:

  • ManageUsers.tsx: count={userListLoading || districtDataLoading || userListData?.count === undefined ? null : ...}
  • ManagePatients.tsx: count={isLoading || data?.count === undefined ? null : data?.count}
  • FacilityUsers.tsx: count={isLoading || facilityUserData?.count === undefined ? null : facilityUserData.count}
  • FacilityList.tsx: count={isLoading || permittedData?.count === undefined ? null : permittedData.count}
  • DischargedPatientsList.tsx: count={facilityQuery.loading || count === undefined ? null : count}
  • AssetsList.tsx: count={loading || totalCount === undefined ? null : totalCount}

The only minor exception is in SampleViewAdmin.tsx which uses count={sampeleData?.count || 0}, but it properly passes the loading state separately via the loading prop.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify CountBlock usage patterns across the codebase
# Expected: All CountBlock usages should handle loading states by passing null

# Search for CountBlock usage patterns
rg -A 5 "CountBlock" | grep -v "src/CAREUI/display/Count.tsx"

# Search specifically for count prop patterns to verify null handling
ast-grep --pattern 'count={$_}'

Length of output: 7453

src/components/Facility/FacilityList.tsx (1)

181-185: LGTM! Verify CountBlock's null handling.

The conditional rendering of count aligns well with the PR objectives by preventing the display of zero counts during loading states. The implementation correctly handles both loading and undefined states.

Let's verify that the CountBlock component properly handles null values:

✅ Verification successful

CountBlock properly handles null values

The CountBlock component is correctly implemented to handle null values by showing a loading skeleton when either loading is true or count is null. The changes in FacilityList.tsx to pass null during loading states align with the component's design.

Reasoning:

  1. The CountBlock Props interface explicitly types count as number | null
  2. The component implementation shows proper null handling:
{props.loading || props.count == null ? (
  <dd className="h-10 w-full max-w-[100px] animate-pulse rounded-lg bg-secondary-300" />
) : (
  <dd id="count" className="text-5xl font-black leading-9">
    {props.count}
  </dd>
)}
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify CountBlock component's handling of null values
# Test: Look for CountBlock's implementation and its handling of null counts
ast-grep --pattern 'interface Props {
  $$$
  count: $count_type
  $$$
}'

# Test: Look for conditional rendering based on count being null
ast-grep --pattern 'const CountBlock = $$$({count}$$$) => {
  $$$
}'

Length of output: 146


Script:

#!/bin/bash
# Let's try a broader search for CountBlock component and its props
rg -A 10 "CountBlock" --type typescript

# Also search for any type definitions related to count prop
rg "count.*:" --type typescript

# Search for any imports of CountBlock to understand its location
rg "import.*CountBlock" --type typescript

Length of output: 222


Script:

#!/bin/bash
# Let's try searching without type filters since typescript type isn't recognized
# Search for CountBlock component definition and usage
rg -A 10 "CountBlock"

# Search for files that might contain CountBlock
fd CountBlock

# Look for type definitions or interfaces containing count
rg -A 5 "interface.*Props"

Length of output: 98943


Script:

#!/bin/bash
# Let's look at the CountBlock component implementation in CAREUI
rg -A 10 "interface Props" src/CAREUI/display/Count.tsx

# Also check for any usages of CountBlock with null values
rg "count={.*null.*}" --type ts --type tsx

Length of output: 455


Script:

#!/bin/bash
# Search for CountBlock usages with null values using a simpler pattern
rg "count=\{.*\?.*null" --type ts --type tsx

# Look at the implementation of CountBlock to see how it handles null
rg -A 15 "export default function CountBlock" src/CAREUI/display/Count.tsx

Length of output: 934

src/components/Assets/AssetsList.tsx (1)

362-362: LGTM! The count prop update improves loading state handling.

The change correctly implements the loading state for the count display, preventing the misleading "0" count during data fetching. This aligns well with the PR objectives.

src/components/Users/ManageUsers.tsx (1)

547-553: LGTM! Implementation successfully addresses the loading state issue.

The conditional logic effectively prevents displaying a zero count during loading by passing null when the data is being fetched or is undefined. This directly addresses the PR objective of implementing a loading state for patient counts.

Copy link

@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)
src/components/Patient/SampleViewAdmin.tsx (1)

Line range hint 1-424: Consider these improvements for better consistency and error handling.

While the loading state implementation for CountBlock is good, there are a few areas where the component could be enhanced:

  1. Loading state handling could be unified across the component
  2. Error states for data fetching should be handled explicitly
  3. Complex computations in the render method could benefit from memoization

Consider these improvements:

 export default function SampleViewAdmin() {
+  // Memoize the filtered and mapped sample list
+  const memoizedSampleList = useMemo(() => {
+    if (!sampeleData?.results) return [];
+    return sampeleData.results.map((item) => {
+      // ... existing mapping logic
+    });
+  }, [sampeleData?.results]);

   // ... existing code

   if (isLoading || !sampeleData) {
     manageSamples = (
       <div className="flex w-full justify-center">
         <Loading />
       </div>
     );
+  } else if (error) {
+    manageSamples = (
+      <div className="w-full rounded-lg bg-white p-3">
+        <div className="mt-4 flex w-full justify-center text-2xl font-bold text-red-600">
+          Error loading sample tests
+        </div>
+      </div>
+    );
   } else if (sampeleData?.count) {
     manageSamples = (
       <>
-        {sampleList}
+        {memoizedSampleList}
         <Pagination totalCount={sampeleData?.count} />
       </>
     );
   }
src/components/Assets/AssetsList.tsx (3)

74-74: Consider explicit null handling for undefined data

While optional chaining is good, consider explicitly setting totalCount to null when data is undefined for more predictable behavior.

-        setTotalCount(data?.count);
+        setTotalCount(data?.count ?? null);

362-364: Simplify loading state handling

The current condition is a bit complex and has some redundancy with the separate loading prop. Consider simplifying:

-          count={loading || totalCount === undefined ? null : totalCount}
-          loading={loading}
+          count={totalCount}
+          loading={loading}

The CountBlock component can handle the null state internally along with the loading prop for a cleaner implementation.


446-446: Consider showing skeleton loader for Pagination

While checking for totalCount !== null prevents invalid rendering, consider showing a skeleton loader for the Pagination component during loading to prevent layout shifts.

-              {totalCount !== null && <Pagination totalCount={totalCount} />}
+              {loading ? (
+                <div className="h-10 w-full animate-pulse rounded bg-gray-100" />
+              ) : (
+                totalCount !== null && <Pagination totalCount={totalCount} />
+              )}
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 417c610 and bc81b10.

📒 Files selected for processing (2)
  • src/components/Assets/AssetsList.tsx (4 hunks)
  • src/components/Patient/SampleViewAdmin.tsx (1 hunks)
🔇 Additional comments (2)
src/components/Patient/SampleViewAdmin.tsx (1)

338-342: LGTM! The count prop implementation effectively prevents premature zero counts.

The conditional logic properly handles loading states and undefined data, ensuring users don't see misleading zero counts while data is being fetched. This implementation aligns well with the PR objective of adding a skeleton loader during advanced filters.

src/components/Assets/AssetsList.tsx (1)

44-44: LGTM: Improved type safety for loading state

The change to allow null values for totalCount is a good approach to represent the loading state.

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.

Add a skeleton loader during advance filters are loaded
1 participant