-
Notifications
You must be signed in to change notification settings - Fork 518
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
Move all the Skeletons to seperate file #9982
base: develop
Are you sure you want to change the base?
Conversation
WalkthroughThis pull request focuses on refactoring skeleton loading components across multiple files and enhancing localization. The changes involve extracting skeleton loading states from various components into dedicated files, creating centralized skeleton components for different sections like encounters, organizations, and facility organizations. Additionally, new localization entries have been added to the Changes
Assessment against linked issues
Possibly related PRs
Suggested labels
Suggested reviewers
📜 Recent review detailsConfiguration used: CodeRabbit UI 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
⏰ Context from checks skipped due to timeout of 90000ms (3)
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? 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
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)
Other keywords and placeholders
CodeRabbit Configuration File (
|
✅ Deploy Preview for care-ohc ready!
To edit notification comments on pull requests, go to your Netlify site configuration. |
Hey Team, could you add work-in-progess label as skeletons is pending for |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 4
🔭 Outside diff range comments (2)
src/components/Patient/symptoms/list.tsx (1)
Line range hint
48-48
: Missing translation for CardTitleThe title "Symptoms" is hardcoded while other instances use the translation key. This creates inconsistency in internationalization.
- <CardTitle>Symptoms</CardTitle> + <CardTitle>{t("symptoms")}</CardTitle>src/pages/Organization/OrganizationIndex.tsx (1)
Line range hint
41-42
: Add translations for static textSeveral strings in the component are hardcoded and should be translated for internationalization support:
- No Organizations Found + {t("organizations.not_found")} - You don't have access to any organizations yet. + {t("organizations.no_access")} - Organizations help you manage facilities, users, and resources - efficiently. Contact your administrator to get access. + {t("organizations.help_text")} - View Details + {t("common.view_details")}Don't forget to add the translation hook:
+ const { t } = useTranslation();
Also applies to: 44-45, 48-51, 85-85
🧹 Nitpick comments (4)
src/components/Patient/allergy/list.tsx (1)
Line range hint
56-71
: Consider extracting badge style utilitiesThe
getStatusBadgeStyle
andgetCategoryBadgeStyle
functions could be moved to a shared utility file since they might be reused across components.Create a new file
src/utils/badgeStyles.ts
:export const getStatusBadgeStyle = (status: string | undefined) => { switch (status?.toLowerCase()) { case "active": return "bg-green-100 text-green-800 border-green-200"; case "inactive": return "bg-gray-100 text-gray-800 border-gray-200"; default: return "bg-gray-100 text-gray-800 border-gray-200"; } }; export const getCategoryBadgeStyle = (category: string) => { switch (category?.toLowerCase()) { case "food": return "bg-orange-100 text-orange-800 border-orange-200"; case "medication": return "bg-blue-100 text-blue-800 border-blue-200"; case "environment": return "bg-green-100 text-green-800 border-green-200"; default: return "bg-gray-100 text-gray-800 border-gray-200"; } };Also applies to: 73-84
src/components/Common/UseSkeletons.tsx (2)
15-47
: Add props for customizing skeleton counts and dimensions.The skeleton components have hardcoded values for:
- Number of items (length: 3, length: 6)
- Dimensions (w-32, h-6, etc.)
Consider making these configurable through props for better reusability.
Example implementation:
- export const EncounterListSkeleton = () => { + interface SkeletonProps { + count?: number; + className?: string; + } + + export const EncounterListSkeleton = ({ count = 6, className }: SkeletonProps) => { return ( <> - {Array.from({ length: 6 }).map((_, i) => ( + {Array.from({ length: count }).map((_, i) => ( <Card key={i} className="hover:shadow-lg transition-shadow">Also applies to: 49-69, 71-85, 87-110, 112-146
148-159
: Consider adding loading animation to PatientListSkeleton.The
PatientListSkeleton
lacks the pulse animation present in other skeleton components. Consider addinganimate-pulse
for consistency.<CardContent> - <Skeleton className="h-[100px] w-full" /> + <Skeleton className="h-[100px] w-full animate-pulse" /> </CardContent>src/components/Facility/ConsultationDetails/QuestionnaireResponsesList.tsx (1)
Line range hint
151-165
: Consider moving skeleton to UseSkeletons.tsx.This skeleton implementation could be moved to the centralized location for consistency with the PR's objective.
+ // In UseSkeletons.tsx + export const QuestionnaireResponseSkeleton = ({ count = 3 }: SkeletonProps) => ( + <div className="grid gap-4"> + {Array.from({ length: count }).map((_, i) => ( + <Card key={i} className="flex items-center justify-between p-4"> + <div className="flex items-start gap-4"> + <div className="h-5 w-5 animate-pulse rounded-full bg-muted" /> + <div className="space-y-2"> + <div className="h-4 w-48 animate-pulse rounded bg-muted" /> + <div className="h-3 w-32 animate-pulse rounded bg-muted" /> + <div className="h-3 w-40 animate-pulse rounded bg-muted" /> + </div> + </div> + </Card> + ))} + </div> + ); - // In QuestionnaireResponsesList.tsx - {Array.from({ length: 3 }).map((_, i) => ( - <Card key={i} className="flex items-center justify-between p-4"> - ... - </Card> - ))} + <QuestionnaireResponseSkeleton />
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (12)
public/locale/en.json
(3 hunks)src/components/Common/UseSkeletons.tsx
(1 hunks)src/components/Facility/ConsultationDetails/QuestionnaireResponsesList.tsx
(1 hunks)src/components/Patient/PatientDetailsTab/patientUpdates.tsx
(1 hunks)src/components/Patient/allergy/list.tsx
(4 hunks)src/components/Patient/diagnosis/list.tsx
(4 hunks)src/components/Patient/symptoms/list.tsx
(3 hunks)src/pages/Encounters/EncounterList.tsx
(2 hunks)src/pages/Encounters/tabs/EncounterNotesTab.tsx
(1 hunks)src/pages/FacilityOrganization/FacilityOrganizationIndex.tsx
(2 hunks)src/pages/Organization/OrganizationIndex.tsx
(2 hunks)src/pages/Organization/components/OrganizationLayout.tsx
(2 hunks)
👮 Files not reviewed due to content moderation or server errors (4)
- src/pages/Encounters/tabs/EncounterNotesTab.tsx
- src/pages/Encounters/EncounterList.tsx
- src/pages/FacilityOrganization/FacilityOrganizationIndex.tsx
- public/locale/en.json
🔇 Additional comments (2)
src/pages/Organization/components/OrganizationLayout.tsx (1)
18-18
: LGTM! Clean replacement of inline skeleton.The change successfully moves the skeleton implementation to the centralized location.
Also applies to: 72-72
src/components/Patient/PatientDetailsTab/patientUpdates.tsx (1)
51-51
: LGTM! Consistent array generation pattern.The change aligns with the pattern used in other skeleton components.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (8)
src/pages/Encounters/EncounterList.tsx (1)
37-37
: LGTM! Consider maintaining grid layout consistency during loading.The skeleton implementation is clean, but the grid layout might shift between loading and loaded states. Consider wrapping the
EncounterListSkeleton
with the same grid container div to maintain consistent layout:{isLoading ? ( - <EncounterListSkeleton /> + <div className="col-span-full"> + <EncounterListSkeleton /> + </div> ) : encounters.length === 0 ? (Also applies to: 669-669
src/components/Common/SkeletonComponents.tsx.tsx (7)
15-47
: Add accessibility attributes and consider using consistent width variables.While the skeleton structure is well-organized, consider these improvements:
- Add
aria-busy="true"
androle="status"
to the skeleton container for better accessibility- Consider defining width constants or CSS variables for consistent skeleton widths across components
export const EncounterListSkeleton = () => { return ( - <> + <div aria-busy="true" role="status"> {Array.from({ length: 6 }).map((_, i) => ( <Card key={i} className="hover:shadow-lg transition-shadow">
49-69
: Standardize spacing units and enhance accessibility.Consider these improvements:
- Use consistent spacing units (either all rem-based or all pixel-based)
- Add accessibility attributes as suggested for the previous component
export const FacilityOrganizationSkeleton = () => { return ( - <div className="px-6 py-6 space-y-6"> + <div className="p-6 space-y-6" aria-busy="true" role="status">
71-85
: Add TypeScript return type for consistency.The component implementation is clean, but let's maintain type safety:
-export const MessageSkeleton = () => ( +export const MessageSkeleton = (): JSX.Element => (
87-110
: Consider component composition to reduce duplication.This component shares similar card structure with
FacilityOrganizationSkeleton
. Consider extracting a commonSkeletonCard
component to reduce code duplication and maintain consistency.Example:
const SkeletonCard = () => ( <Card className="relative"> <CardHeader> <Skeleton className="h-6 w-2/3" /> <Skeleton className="h-4 w-1/2" /> </CardHeader> <CardContent> <Skeleton className="h-4 w-full mb-2" /> <Skeleton className="h-4 w-3/4" /> </CardContent> <CardFooter> <Skeleton className="h-8 w-24" /> </CardFooter> </Card> );
112-146
: Consider adding configuration props for flexibility.The component could benefit from configuration props to control:
- Number of items in each section (
itemCount
)- Grid layout configuration (columns per breakpoint)
- Spacing customization
This would make the component more reusable across different contexts.
-export const OrganizationLayoutSkeleton = () => { +interface OrganizationLayoutSkeletonProps { + itemCount?: number; + gridCols?: { + sm?: number; + md?: number; + lg?: number; + }; +} + +export const OrganizationLayoutSkeleton = ({ + itemCount = 6, + gridCols = { sm: 1, md: 2, lg: 3 } +}: OrganizationLayoutSkeletonProps): JSX.Element => {
148-159
: Add prop type validation and consider flexible height.The component could be improved by:
- Adding proper TypeScript interface for props
- Making the height configurable
- Adding prop validation
+interface PatientListSkeletonProps { + title: string; + height?: string; +} + -export const PatientListSkeleton = ({ title }: { title: string }) => { +export const PatientListSkeleton = ({ + title, + height = "100px" +}: PatientListSkeletonProps): JSX.Element => { return ( <Card> <CardHeader> <CardTitle>{title}</CardTitle> </CardHeader> <CardContent> - <Skeleton className="h-[100px] w-full" /> + <Skeleton className={`h-[${height}] w-full`} /> </CardContent> </Card> ); };
1-159
: Well-structured implementation of skeleton components!The centralization of skeleton components is well-executed, with consistent patterns and good organization. The components provide a solid foundation for loading states across the application.
Some general suggestions for the entire file:
- Consider adding a README.md to document usage patterns and available customization options
- Add storybook stories to showcase different states and configurations
- Consider adding unit tests to verify proper rendering and prop handling
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (9)
src/components/Common/SkeletonComponents.tsx.tsx
(1 hunks)src/components/Patient/allergy/list.tsx
(4 hunks)src/components/Patient/diagnosis/list.tsx
(4 hunks)src/components/Patient/symptoms/list.tsx
(3 hunks)src/pages/Encounters/EncounterList.tsx
(2 hunks)src/pages/Encounters/tabs/EncounterNotesTab.tsx
(1 hunks)src/pages/FacilityOrganization/FacilityOrganizationIndex.tsx
(2 hunks)src/pages/Organization/OrganizationIndex.tsx
(2 hunks)src/pages/Organization/components/OrganizationLayout.tsx
(2 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
- src/pages/FacilityOrganization/FacilityOrganizationIndex.tsx
- src/pages/Encounters/tabs/EncounterNotesTab.tsx
- src/components/Patient/symptoms/list.tsx
🔇 Additional comments (5)
src/pages/Organization/components/OrganizationLayout.tsx (1)
18-18
: LGTM! Clean implementation of centralized loading state.The changes successfully move the skeleton component to a separate file, improving code organization and maintainability.
Also applies to: 72-72
src/components/Patient/diagnosis/list.tsx (1)
19-19
: Verify all required translation keys exist.The component uses several translation keys that need to be present in all locale files:
- "diagnosis"
- "diagnosis_empty_message"
#!/bin/bash # Check if translation keys exist in all locale files for key in "diagnosis" "diagnosis_empty_message"; do echo "=== Checking key: $key ===" rg "\"$key\":" public/locale/*.json doneAlso applies to: 30-30, 37-37, 40-42, 51-51
src/pages/Organization/OrganizationIndex.tsx (1)
17-17
: LGTM! Clean implementation of loading state.The replacement of multiple Skeleton components with a single OrganizationIndexSkeleton improves code maintainability.
Also applies to: 33-33
src/components/Patient/allergy/list.tsx (1)
28-28
: Verify all required translation keys exist.The component uses several translation keys that need to be present in all locale files:
- "allergies"
- "allergies_empty_message"
- "allergen"
- "category"
- "status"
- "criticality"
- "created_by"
#!/bin/bash # Check if translation keys exist in all locale files for key in "allergies" "allergies_empty_message" "allergen" "category" "status" "criticality" "created_by"; do echo "=== Checking key: $key ===" rg "\"$key\":" public/locale/*.json doneAlso applies to: 38-38, 45-45, 48-50, 89-93
src/components/Common/SkeletonComponents.tsx.tsx (1)
1-14
: Well-organized imports!The imports are properly organized and grouped, with clear separation between external dependencies and internal components.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (1)
src/pages/Organization/components/OrganizationLayout.tsx (1)
18-18
: Remove the.tsx
extension from the import path.The file extension in import statements is unnecessary and should be removed for consistency with TypeScript best practices.
-import { OrganizationIndexSkeleton } from "@/components/Common/SkeletonComponents.tsx"; +import { OrganizationIndexSkeleton } from "@/components/Common/SkeletonComponents";
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
public/locale/en.json
(3 hunks)src/pages/Organization/components/OrganizationLayout.tsx
(2 hunks)
🔇 Additional comments (2)
public/locale/en.json (1)
381-381
: LGTM! The new empty state messages are well-structured.The added translations for empty states follow consistent naming conventions and message formatting patterns.
Also applies to: 761-761, 1974-1974
src/pages/Organization/components/OrganizationLayout.tsx (1)
72-72
: LGTM! Good job centralizing the loading state.The change successfully moves the skeleton component to a separate file while maintaining proper loading state handling.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (4)
src/components/Common/SkeletonComponents.tsx (4)
15-47
: Consider extracting the card skeleton to a reusable component.The
EncounterListSkeleton
maps over an array to create multiple identical card structures. This pattern could be reused across other components.Consider creating a reusable
CardSkeleton
component:interface CardSkeletonProps { headerItems?: number[]; // widths for header items contentItems?: number[]; // widths for content items showSeparator?: boolean; } const CardSkeleton = ({ headerItems = [32, 16], contentItems = [12, 20, 12, 24], showSeparator = true }: CardSkeletonProps) => ( <Card className="hover:shadow-lg transition-shadow"> <CardHeader className="space-y-1"> <div className="flex items-center justify-between"> {headerItems.map((width, i) => ( <Skeleton key={i} className={`h-6 w-${width}`} /> ))} </div> </CardHeader> <CardContent> <div className="flex flex-col space-y-2"> {contentItems.map((width, i) => ( <div key={i} className="flex items-center justify-between"> <Skeleton className={`h-4 w-${width}`} /> </div> ))} {showSeparator && <Separator className="my-2" />} </div> </CardContent> </Card> );
49-69
: Consider making the skeleton count configurable.The component has a hardcoded length of 6 items. Making this configurable would improve reusability.
interface FacilityOrganizationSkeletonProps { count?: number; } export const FacilityOrganizationSkeleton = ({ count = 6 }: FacilityOrganizationSkeletonProps) => { return ( <div className="px-6 py-6 space-y-6"> <Skeleton className="h-8 w-48" /> <Skeleton className="h-8 w-48 self-end" /> <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4"> {Array.from({ length: count }).map((_, i) => ( // ... rest of the component ))} </div> </div> ); };
71-85
: Add aria-label for accessibility.The message skeleton should indicate its loading state to screen readers.
-export const MessageSkeleton = () => ( +export const MessageSkeleton = () => ( - <div className="space-y-4"> + <div className="space-y-4" role="status" aria-label="Loading messages"> {Array.from({ length: 3 }).map((_, i) => (
148-159
: Consider adding a loading indicator for screen readers.The
PatientListSkeleton
should communicate its loading state to screen readers.export const PatientListSkeleton = ({ title }: { title: string }) => { return ( - <Card> + <Card role="status" aria-label={`Loading ${title}`}> <CardHeader> <CardTitle>{title}</CardTitle> </CardHeader>
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (9)
src/components/Common/SkeletonComponents.tsx
(1 hunks)src/components/Patient/allergy/list.tsx
(4 hunks)src/components/Patient/diagnosis/list.tsx
(4 hunks)src/components/Patient/symptoms/list.tsx
(3 hunks)src/pages/Encounters/EncounterList.tsx
(2 hunks)src/pages/Encounters/tabs/EncounterNotesTab.tsx
(1 hunks)src/pages/FacilityOrganization/FacilityOrganizationIndex.tsx
(2 hunks)src/pages/Organization/OrganizationIndex.tsx
(2 hunks)src/pages/Organization/components/OrganizationLayout.tsx
(2 hunks)
🚧 Files skipped from review as they are similar to previous changes (7)
- src/pages/FacilityOrganization/FacilityOrganizationIndex.tsx
- src/components/Patient/diagnosis/list.tsx
- src/pages/Encounters/tabs/EncounterNotesTab.tsx
- src/pages/Organization/OrganizationIndex.tsx
- src/components/Patient/allergy/list.tsx
- src/components/Patient/symptoms/list.tsx
- src/pages/Encounters/EncounterList.tsx
🔇 Additional comments (4)
src/components/Common/SkeletonComponents.tsx (2)
1-14
: LGTM! Well-organized imports.The imports are properly structured and all are being utilized in the implementation.
87-110
: LGTM! Well-implemented i18n support.The component properly uses the translation hook for the title, making it internationalization-ready.
src/pages/Organization/components/OrganizationLayout.tsx (2)
18-18
: LGTM! Clean import of the skeleton component.The import follows the project's import organization pattern.
72-72
: LGTM! Proper implementation of the skeleton component.The loading state is handled correctly using the imported skeleton component.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (5)
src/components/Common/SkeletonComponents.tsx (5)
14-46
: Consider making the number of skeleton items configurable.The component hardcodes 6 skeleton cards. Consider accepting a prop to configure the number of items for better reusability across different use cases.
-export const EncounterListSkeleton = () => { +export const EncounterListSkeleton = ({ count = 6 }: { count?: number }) => { return ( <> - {Array.from({ length: 6 }).map((_, i) => ( + {Array.from({ length: count }).map((_, i) => (
48-68
: Consider creating a shared utility for repeated skeleton patterns.Multiple skeleton components share similar patterns (array generation, card structures). Consider creating a utility function or component to reduce duplication:
type SkeletonCardProps = { count?: number; children: React.ReactNode; gridCols?: { default: number; md?: number; lg?: number; }; }; const SkeletonCardGrid = ({ count = 6, children, gridCols = { default: 1, md: 2, lg: 3 } }: SkeletonCardProps) => ( <div className={`grid grid-cols-${gridCols.default} ${ gridCols.md ? `md:grid-cols-${gridCols.md}` : '' } ${gridCols.lg ? `lg:grid-cols-${gridCols.lg}` : ''} gap-4`}> {Array.from({ length: count }).map((_, i) => ( <React.Fragment key={i}>{children}</React.Fragment> ))} </div> );
70-84
: Maintain consistency in animation approaches.While other components rely on the Skeleton component's built-in animation, this component uses the
animate-pulse
utility class. Consider standardizing the animation approach across all skeleton components.- <div key={i} className="p-4 rounded-lg bg-gray-100 animate-pulse"> + <div key={i} className="p-4 rounded-lg"> <div className="flex items-start gap-3"> - <div className="w-8 h-8 rounded-full bg-gray-200" /> + <Skeleton className="w-8 h-8 rounded-full" />
111-145
: Consider breaking down the complex layout into smaller components.The component has multiple distinct sections that could be extracted into separate components for better maintainability and reusability.
Example refactor:
const HeaderSection = () => ( <> <Skeleton className="h-8 w-48 mb-4" /> <Skeleton className="h-4 w-24 mb-4" /> </> ); const TabsSection = () => ( <div className="flex space-x-4 mb-4"> {Array.from({ length: 3 }).map((_, index) => ( <Skeleton key={index} className="h-8 w-24" /> ))} </div> ); export const OrganizationLayoutSkeleton = () => ( <div className="p-4"> <HeaderSection /> <TabsSection /> {/* ... rest of the component */} </div> );
1-145
: Consider implementing a skeleton component system.The file shows several repeated patterns across components. Consider implementing a more systematic approach:
- Create base skeleton components (SkeletonCard, SkeletonGrid, etc.)
- Define a consistent animation strategy
- Implement a configuration system for common properties (count, dimensions, etc.)
This would improve maintainability and ensure consistency across the application's loading states.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
src/components/Common/SkeletonComponents.tsx
(1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (3)
- GitHub Check: CodeQL-Build
- GitHub Check: OSSAR-Scan
- GitHub Check: cypress-run (1)
🔇 Additional comments (2)
src/components/Common/SkeletonComponents.tsx (2)
1-13
: LGTM! Well-organized imports.The imports are logically grouped and all dependencies are necessary for the components.
86-109
: LGTM! Well-structured component with i18n support.The component follows best practices with proper internationalization and consistent use of design system components.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's NOT create a giant file that contains all of the skeletons.
Idea is to move all new pieces to src/pages
directory.
And src/pages/<module>/components/
directory would contain components associated to that module.
Let's do that
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (6)
src/pages/Encounters/components/EncounterNoteSkeleton.tsx (1)
3-19
: Add accessibility attributes and configuration options.Consider the following improvements:
- Add aria-label to indicate loading state
- Make the number of skeleton items configurable via props
- Respect user's reduced motion preferences
+ import { cn } from "@/lib/utils"; + + interface EncounterNoteSkeletonProps { + count?: number; + } + - export default function EncounterNoteSkeleton() { + export default function EncounterNoteSkeleton({ count = 3 }: EncounterNoteSkeletonProps) { return ( - <div className="space-y-4"> + <div + className="space-y-4" + role="status" + aria-label="Loading encounter notes" + > - {Array.from({ length: 3 }).map((_, i) => ( + {Array.from({ length: count }).map((_, i) => ( <div key={i} - className="p-4 rounded-lg bg-gray-100 animate-pulse" + className={cn( + "p-4 rounded-lg bg-gray-100", + "@motion-reduce:animate-none animate-pulse" + )} >src/pages/FacilityOrganization/components/FacilityOrganizationSkeleton.tsx (1)
4-24
: Enhance component flexibility and accessibility.The component could benefit from:
- Proper accessibility attributes
- Configurable number of skeleton cards
- Extracted card skeleton to a separate component for reuse
+ interface FacilityOrganizationSkeletonProps { + count?: number; + } + + function FacilityOrganizationCardSkeleton() { + return ( + <Card className="relative space-y-4"> + <CardHeader> + <Skeleton className="h-6 w-1/3" /> + <Skeleton className="h-4 w-1/4" /> + </CardHeader> + <CardFooter> + <Skeleton className="h-10 w-full" /> + </CardFooter> + </Card> + ); + } + - export default function FacilityOrganizationSkeleton() { + export default function FacilityOrganizationSkeleton({ count = 6 }: FacilityOrganizationSkeletonProps) { return ( - <div className="px-6 py-6 space-y-6"> + <div + className="px-6 py-6 space-y-6" + role="status" + aria-label="Loading facility organizations" + > <Skeleton className="h-8 w-48" /> <Skeleton className="h-8 w-48 self-end" /> <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4"> - {Array.from({ length: 6 }).map((_, i) => ( - <Card key={i} className="relative space-y-4"> - <CardHeader> - <Skeleton className="h-6 w-1/3" /> - <Skeleton className="h-4 w-1/4" /> - </CardHeader> - <CardFooter> - <Skeleton className="h-10 w-full" /> - </CardFooter> - </Card> + {Array.from({ length: count }).map((_, i) => ( + <FacilityOrganizationCardSkeleton key={i} /> ))} </div> </div> ); }src/pages/Organization/components/OrganizationIndexSkeleton.tsx (1)
13-36
: Add accessibility and prevent potential memory leaks.Consider these improvements:
- Add proper accessibility attributes
- Make the number of skeleton items configurable
- Ensure proper cleanup of translation resources
+ interface OrganizationIndexSkeletonProps { + count?: number; + } + - export default function OrganizationIndexSkeleton() { + export default function OrganizationIndexSkeleton({ count = 3 }: OrganizationIndexSkeletonProps) { - const { t } = useTranslation(); + const [t] = useTranslation(); return ( <Page title={t("organizations")}> - <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4"> + <div + className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4" + role="status" + aria-label={t("loading_organizations")} + > - {Array.from({ length: 3 }).map((_, i) => ( + {Array.from({ length: count }).map((_, i) => (src/pages/Encounters/components/EncounterListSkeleton.tsx (2)
5-37
: Improve component structure and accessibility.The component needs several improvements:
- Add accessibility attributes
- Make the number of skeleton items configurable
- Consider a container element instead of fragment
- Extract card skeleton to a separate component
+ interface EncounterListSkeletonProps { + count?: number; + } + + function EncounterCardSkeleton() { + return ( + <Card className="hover:shadow-lg transition-shadow"> + <CardHeader className="space-y-1"> + <div className="flex items-center justify-between"> + <Skeleton className="h-6 w-32" /> + <Skeleton className="h-5 w-16" /> + </div> + <Skeleton className="h-4 w-24" /> + </CardHeader> + <CardContent> + <div className="flex flex-col space-y-2"> + <div className="flex items-center justify-between"> + <Skeleton className="h-4 w-12" /> + <Skeleton className="h-5 w-20" /> + </div> + <div className="flex items-center justify-between"> + <Skeleton className="h-4 w-12" /> + <Skeleton className="h-4 w-24" /> + </div> + <Separator className="my-2" /> + <div className="flex justify-end"> + <Skeleton className="h-4 w-24" /> + </div> + </div> + </CardContent> + </Card> + ); + } + - export default function EncounterListSkeleton() { + export default function EncounterListSkeleton({ count = 6 }: EncounterListSkeletonProps) { return ( - <> + <div + className="space-y-4" + role="status" + aria-label="Loading encounters" + > - {Array.from({ length: 6 }).map((_, i) => ( - <Card key={i} className="hover:shadow-lg transition-shadow"> - // ... card content ... - </Card> + {Array.from({ length: count }).map((_, i) => ( + <EncounterCardSkeleton key={i} /> ))} - </> + </div> ); }
1-1
: Consider creating a shared skeleton component library.All skeleton components share similar patterns and could benefit from standardization. Consider:
- Creating base skeleton components (e.g., CardSkeleton, ListSkeleton)
- Establishing consistent props interface (count, aria-labels)
- Implementing shared utilities for animation and accessibility
This would improve maintainability and ensure consistent loading states across the application.
src/pages/Organization/components/OrganizationLayoutSkeleton.tsx (1)
4-38
: Consider adding prop types for better customization.The component could benefit from the following improvements:
- Add prop types to customize the number of skeleton items
- Use constants for magic numbers (3, 6) to improve maintainability
- Consider adding aria-label for better accessibility
Here's a suggested implementation:
+interface OrganizationLayoutSkeletonProps { + headerCount?: number; + cardCount?: number; +} + +const DEFAULT_HEADER_COUNT = 3; +const DEFAULT_CARD_COUNT = 6; + -export default function OrganizationLayoutSkeleton() { +export default function OrganizationLayoutSkeleton({ + headerCount = DEFAULT_HEADER_COUNT, + cardCount = DEFAULT_CARD_COUNT, +}: OrganizationLayoutSkeletonProps) { return ( - <div className="p-4"> + <div className="p-4" aria-label="Loading organization layout"> <Skeleton className="h-8 w-48 mb-4" /> <Skeleton className="h-4 w-24 mb-4" /> <div className="flex space-x-4 mb-4"> - {Array.from({ length: 3 }).map((_, index) => ( + {Array.from({ length: headerCount }).map((_, index) => ( <Skeleton key={index} className="h-8 w-24" /> ))} </div> <Skeleton className="h-6 w-40 mb-4" /> <Skeleton className="h-8 w-1/4 mb-4" /> <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4"> - {Array.from({ length: 6 }).map((_, i) => ( + {Array.from({ length: cardCount }).map((_, i) => ( <Card key={i}>
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (10)
src/pages/Encounters/EncounterList.tsx
(2 hunks)src/pages/Encounters/components/EncounterListSkeleton.tsx
(1 hunks)src/pages/Encounters/components/EncounterNoteSkeleton.tsx
(1 hunks)src/pages/Encounters/tabs/EncounterNotesTab.tsx
(3 hunks)src/pages/FacilityOrganization/FacilityOrganizationIndex.tsx
(2 hunks)src/pages/FacilityOrganization/components/FacilityOrganizationSkeleton.tsx
(1 hunks)src/pages/Organization/OrganizationIndex.tsx
(2 hunks)src/pages/Organization/components/OrganizationIndexSkeleton.tsx
(1 hunks)src/pages/Organization/components/OrganizationLayout.tsx
(2 hunks)src/pages/Organization/components/OrganizationLayoutSkeleton.tsx
(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (4)
- src/pages/FacilityOrganization/FacilityOrganizationIndex.tsx
- src/pages/Organization/OrganizationIndex.tsx
- src/pages/Encounters/tabs/EncounterNotesTab.tsx
- src/pages/Encounters/EncounterList.tsx
⏰ Context from checks skipped due to timeout of 90000ms (1)
- GitHub Check: cypress-run (1)
🔇 Additional comments (4)
src/pages/Organization/components/OrganizationLayoutSkeleton.tsx (1)
16-35
: LGTM! Well-structured responsive grid layout.The grid implementation with responsive breakpoints and consistent spacing looks good. The use of flex layouts for card content alignment is appropriate.
src/pages/Organization/components/OrganizationLayout.tsx (3)
21-21
: LGTM! Clean import of the new skeleton component.The import statement is properly placed with other page-specific imports.
72-72
: LGTM! Clean replacement of inline skeleton.The loading state implementation is now cleaner and more maintainable by using the dedicated skeleton component.
72-72
: Verify completion of FacilityUsers skeletons.Note that this PR is marked as WIP pending the completion of FacilityUsers skeletons after PR #9954 is merged. Please update the PR once all skeletons are moved to separate files.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (4)
src/components/Facility/FacilityUsersSkeletons.tsx (4)
4-57
: Add accessibility attributes to improve screen reader experience.The table structure should include appropriate ARIA attributes for better accessibility.
Apply this diff:
- <table className="relative min-w-full divide-y divide-gray-200"> + <table + className="relative min-w-full divide-y divide-gray-200" + role="progressbar" + aria-label="Loading users" + aria-busy="true" + >
29-53
: Consider extracting magic numbers into constants.The number of skeleton rows (7) is hardcoded. Consider making it configurable through props for better reusability.
Apply this diff:
+const DEFAULT_LIST_ROWS = 7; + +export const UserListSkeleton = ({ rows = DEFAULT_LIST_ROWS }: { rows?: number }) => ( // ... - {Array.from({ length: 7 }).map((_, i) => ( + {Array.from({ length: rows }).map((_, i) => (
59-99
: Consider adding loading state animation.The skeleton components could benefit from a subtle animation to indicate the loading state.
Add a pulsing animation to the skeleton components by applying this diff:
import { Card, CardContent } from "@/components/ui/card"; -import { Skeleton } from "@/components/ui/skeleton"; +import { Skeleton } from "@/components/ui/skeleton"; +import { cn } from "@/lib/utils"; + +const pulseAnimation = "animate-pulse"; export const UserCardSkeleton = () => ( // ... - <Skeleton className="h-12 w-12 sm:h-16 sm:w-16 rounded-full flex-shrink-0" /> + <Skeleton className={cn("h-12 w-12 sm:h-16 sm:w-16 rounded-full flex-shrink-0", pulseAnimation)} />
61-62
: Consider making the grid layout more configurable.The grid configuration and number of skeleton cards (6) are hardcoded. Consider making them configurable through props.
Apply this diff:
+interface UserCardSkeletonProps { + cards?: number; + gridCols?: { + sm?: number; + md?: number; + lg?: number; + }; +} + +const DEFAULT_CARDS = 6; +const DEFAULT_GRID = { + sm: 1, + md: 2, + lg: 3, +}; + -export const UserCardSkeleton = () => ( +export const UserCardSkeleton = ({ + cards = DEFAULT_CARDS, + gridCols = DEFAULT_GRID, +}: UserCardSkeletonProps = {}) => ( <div> - <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4"> + <div className={cn( + "grid gap-4", + `grid-cols-${gridCols.sm}`, + `md:grid-cols-${gridCols.md}`, + `lg:grid-cols-${gridCols.lg}`, + )}> - {Array.from({ length: 6 }).map((_, i) => ( + {Array.from({ length: cards }).map((_, i) => (
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
public/locale/en.json
(3 hunks)src/components/Facility/FacilityUsers.tsx
(1 hunks)src/components/Facility/FacilityUsersSkeletons.tsx
(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- public/locale/en.json
⏰ Context from checks skipped due to timeout of 90000ms (1)
- GitHub Check: cypress-run (1)
🔇 Additional comments (1)
src/components/Facility/FacilityUsers.tsx (1)
12-15
: LGTM! Clean separation of skeleton components.The skeleton components have been properly extracted and imported from a dedicated file, maintaining the same functionality while improving code organization.
Let's verify that all skeleton usages have been updated:
✅ Verification successful
Verified: Skeleton components properly migrated and used
The skeleton components are correctly defined in FacilityUsersSkeletons.tsx and properly used in FacilityUsers.tsx, with no remaining inline definitions or unhandled usages across the codebase.
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash # Search for any remaining inline skeleton definitions in FacilityUsers rg -l "UserCardSkeleton.*=.*\(\)" src/components/Facility/ rg -l "UserListSkeleton.*=.*\(\)" src/components/Facility/Length of output: 223
Script:
#!/bin/bash # Check usage of skeleton components in FacilityUsers.tsx echo "=== Checking skeleton component usage ===" rg "UserCardSkeleton|UserListSkeleton" src/components/Facility/FacilityUsers.tsx -A 1 # Check if these components are imported elsewhere echo -e "\n=== Checking skeleton component imports across codebase ===" rg "import.*UserCardSkeleton|import.*UserListSkeleton" -g "!FacilityUsersSkeletons.tsx"Length of output: 588
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (1)
src/pages/Organization/components/OrganizationLayout.tsx (1)
72-74
: Clean up loading state implementation.The skeleton implementation looks good, but there are two minor improvements to consider:
- Consider adding type checking for OrganizationLayoutSkeleton props if any are required
- Remove the redundant comment "add loading state" as it's no longer needed
if (isLoading) { return <OrganizationLayoutSkeleton />; } - // add loading state if (!org) {
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
public/locale/en.json
(3 hunks)src/pages/Organization/components/OrganizationLayout.tsx
(2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- public/locale/en.json
⏰ Context from checks skipped due to timeout of 90000ms (1)
- GitHub Check: OSSAR-Scan
🔇 Additional comments (2)
src/pages/Organization/components/OrganizationLayout.tsx (2)
21-21
: LGTM! Clean import of the skeleton component.The import follows React best practices with clear naming and proper organization.
Line range hint
21-72
: Verify skeleton component consistency across the codebase.Since this is part of a larger refactoring effort to centralize skeleton components, let's verify the consistency of the implementation across other files.
✅ Verification successful
Skeleton component implementation is consistent with the refactoring pattern
The implementation in OrganizationLayout follows the established pattern where complex layouts have dedicated skeleton components, while simpler components continue to use the base Skeleton component directly.
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash # Description: Check for any remaining inline Skeleton imports and usages that should be moved to separate files # Check for any remaining direct Skeleton imports echo "Checking for remaining direct Skeleton imports..." rg "import.*Skeleton.*from.*@/components/ui/skeleton" # Check for any remaining inline Skeleton usage echo "Checking for remaining inline Skeleton usage..." ast-grep --pattern 'return <Skeleton $$$>' # List all the new skeleton component files for reference echo "Listing all skeleton component files..." fd -e tsx -e ts ".*Skeleton.*"Length of output: 2411
Proposed Changes
@ohcnetwork/care-fe-code-reviewers
Merge Checklist
Summary by CodeRabbit
Release Notes
Localization
User Interface
Performance
These updates enhance the application's user experience by providing clearer feedback during data loading and improving empty state messaging.