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

User Management Redesign and User Details Page #9080

Conversation

Jacobjeevan
Copy link
Contributor

@Jacobjeevan Jacobjeevan commented Nov 11, 2024

Proposed Changes

To Do:

  • Open an issue for moving Profile: I've already moved most of the elements from existing profile page to to user details page (when it's details of logged in user), but there's a few issues in the works modifying certain elements in the profile page, so may need to tweak user details page.
  • Done: While testing, I noticed that user deletion doesn't work for facility users page (delete route sets is_active flag to false, which works fine for userList (/api/v1/users/), but not for getFacilityUsers (facility/facilityId/get_users/) as latter is checking for deleted=False flag. BE PR here

Potential things to check:

  • Conditional rendering of elements
    • Qualifications (under Professional Information) only for Doctors/Nurses
    • YOE and Medical registration number (under Professional Information) only for Doctors
    • Logged in user can edit their own profile as well as change password
    • Edit (other users) only available for District/StateAdmin and superusers only
    • Deletion only (other users) for District/StateAdmins and superusers only
      • Only can delete users below in hierarchy
    • Avatar edit option (for all users) only for super user
    • Logged in user can edit their own avatar
  • Users without edit permissions can view profiles of other users
image image image image image image image image image image

If user doesn't have edit permissions:

image image

@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 user management functionalities with new localization entries for account actions.
    • Introduced components for managing linked facilities and skills, including confirmation dialogs.
    • Added user avatar management capabilities, allowing users to upload and delete profile pictures.
    • Implemented a comprehensive user editing interface with toggling between view and edit modes.
    • Added a new component for displaying linked skills associated with a user.
    • Introduced a new component for managing user summaries and interactions.
    • Added a new LinkedSkillsTab component for displaying linked skills associated with a user.
    • Introduced a UserHome component for user management with dynamic tab rendering.
    • Added a UserBanner component for displaying user information in a banner format.
    • Introduced a UserResetPassword component for managing password resets.
    • Enhanced error handling and validation logic across various user management components.
  • Bug Fixes

    • Improved validation logic for user forms, ensuring accurate error messages and handling.
    • Streamlined state management in user-related components for better performance.
  • Documentation

    • Updated internal documentation to reflect new props and components introduced in this release.
  • Tests

    • Added new end-to-end tests for user homepage functionalities and user management scenarios.
    • Updated existing tests to reflect changes in error messages and selectors for user verification.

- Creating a separate user detail page (for user management) Pt 1
- Remove role editing from role management component
- Use passable formData for formValidation
- Minor customizations for role management issues
- Only show role management options for pages of users with Roles: Doctor and Nurse
- Import the form into UserInformationTab (removing the current form)
- Moved out the form components into its own file
	- Import the form into UserAdd
- Refactor FacilityUsers to use similar format as ManageUsers
- Extracted out the list/card logic to UserListAndCard
- Changed FacilityUsers to use userList route (with facilityId as home_facility parameter)
- Modified to use a new route instead
	- Added a new route to Backend rather than changing permissions for UserModel
- Display view details button based on permissions
- Moving out additional common functionality inyo UserListAndCard
	- Removed memoization since it was causing hook errors
- Switched back to using getFacilityUsers route in FacilityUsers as that should be faster
- password reset form fix
	- use passed in username than authUser's username
- UserAddEditForm
	- pass in facility Ids than full facilities in handleSubmit
- Added error message notifications for the form submits
@Jacobjeevan Jacobjeevan requested a review from a team as a code owner November 11, 2024 10:54
Copy link
Contributor

coderabbitai bot commented Nov 11, 2024

Walkthrough

The pull request implements extensive modifications across various components primarily focused on user management and localization. Key changes include the enhancement of the en.json localization file with new entries for user management functionalities, updates to routing in UserRoutes.tsx, and the introduction of new components for managing user details and skills. Additionally, existing components have been refactored for improved functionality, including user forms and dialogs, while several components related to user skills and facilities have been added or removed to streamline user interactions.

Changes

File Path Change Summary
public/locale/en.json Added new localization entries for user management, account prompts, and error messages.
src/Routers/routes/UserRoutes.tsx Updated import for UserAdd, added routes for UserHome, and modified routing structure.
src/components/Auth/ResetPassword.tsx Changed import for validateRule, updated validation messages to use translation keys.
src/components/Common/Page.tsx Added optional property hideTitleOnPage to PageProps interface.
src/components/Common/PageTitle.tsx Introduced hideTitleOnPage prop to conditionally render title.
src/components/Common/SkillSelect.tsx Updated selected and setSelected property types in SkillSelectProps.
src/components/Common/UserColumns.tsx Added new UserColumns component for displaying user-related data.
src/components/Common/UserDetails.tsx Modified class names for styling in the title display.
src/components/Facility/FacilityUsers.tsx Refactored to use a new useFilters hook for managing query parameters and user data.
src/components/Form/Form.tsx Added new props for form reset functionality and modified handleCancel logic.
src/components/Users/ConfirmFacilityModal.tsx Introduced a new modal component for confirming facility management actions.
src/components/Users/ConfirmHomeFacilityUpdateDialog.tsx Removed the component as part of refactoring.
src/components/Users/LinkFacilityDialog.tsx Deleted the component for linking facilities.
src/components/Users/LinkedFacilities.tsx Added a component for managing linked facilities with various functionalities.
src/components/Users/LinkedSkills.tsx Introduced a component for managing linked skills with asynchronous operations.
src/components/Users/ManageUsers.tsx Significant restructuring for user management, including removal of unused components.
src/components/Users/UserAdd.tsx Streamlined to directly render UserAddEditForm, removing internal state management.
src/components/Users/UserAddEditForm.tsx Added comprehensive form handling for user profiles with validation and state management.
src/components/Users/UserHome.tsx Introduced a component for user management with tabbed navigation.
src/components/Users/UserProfile.tsx Updated import for validateRule, enhanced validation logic for user input.
src/Utils/utils.ts Modified isUserOnline function to handle undefined last_login gracefully.
src/common/validation.tsx Added validateNumber function for numeric validation.
src/components/Users/UserFormValidations.tsx Enhanced user form validation logic with new validation functions for various fields.
cypress/e2e/users_spec/UsersHomepage.cy.ts Added a new test case for searching by username in the user homepage.
cypress/e2e/users_spec/UsersManage.cy.ts Enhanced tests for user management, focusing on nurse and doctor functionalities.
cypress/pageobject/Users/ManageUserPage.ts Extensive modifications to methods for improved user management interactions.
cypress/pageobject/Users/UserSearch.ts Updated methods for dynamic verification of usernames and list view functionality.
src/Utils/permissions.ts Introduced new functions for checking user permissions based on location and roles.
src/components/Common/ConfirmDialog.tsx Added optional name property to ConfirmDialogProps for button customization.
src/components/Common/FacilitySelect.tsx Added optional id property to FacilitySelectProps.
src/components/Common/Tabs.tsx Updated tabs array type to include an optional id property.
src/components/Common/LanguageSelector.tsx Simplified layout by removing unused elements and adjusting class names.
src/components/Users/UserAvatar.tsx Introduced a component for managing user avatars with upload and delete functionalities.
src/components/Users/UserEditDetails.tsx Added components for editing user information with toggle functionality for view/edit modes.
src/components/Users/UserViewDetails.tsx Introduced components for displaying user details with localization support.
cypress/pageobject/Login/LoginPage.ts Updated loginManuallyAsNurse method to accept an optional password parameter.
src/components/Users/LinkedSkillsTab.tsx Added a new component for displaying linked skills associated with a user.

Assessment against linked issues

Objective Addressed Explanation
Refactor user list and user management pages (#8878)
Improve Age Validation in User Creation Form (#9001)
Enhance Grid Layout in "View Users Associated with Facilities" Section (#8983) No changes made to grid layout as proposed.

Possibly related PRs

Suggested reviewers

  • nihal467
  • rithviknishad

🐰 In the garden where users play,
New features bloom, brightening the day.
With skills and facilities linked with care,
User management's now beyond compare!
So hop along, let’s celebrate,
These changes make our app first-rate! 🌼


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. (Experiment)
  • @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 11, 2024

Deploy Preview for care-ohc ready!

Name Link
🔨 Latest commit 7359cc1
🔍 Latest deploy log https://app.netlify.com/sites/care-ohc/deploys/675822c33307db00085f1f79
😎 Deploy Preview https://deploy-preview-9080--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.

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

🧹 Outside diff range and nitpick comments (67)
src/Routers/routes/UserRoutes.tsx (1)

11-17: Consider deprecating the "/user/profile" route.

The PR summary mentions plans to remove/redirect the existing profile page. Since you've introduced a new user details page at /users/:username, consider:

  1. Adding a deprecation notice for /user/profile
  2. Implementing a redirect from /user/profile to the new user details page

Example implementation:

"/user/profile": () => {
  console.warn('Deprecated: Use /users/:username instead');
  const username = getCurrentUser()?.username;
  return username ? <Navigate to={`/users/${username}`} replace /> : <UserProfile />;
},
src/components/Common/UserColumns.tsx (3)

3-6: Follow TypeScript naming conventions for type definitions.

The type name userChildProps should be in PascalCase as per TypeScript conventions.

-export type userChildProps = {
+export type UserChildProps = {
   userData: UserModel;
   username: string;
 };

8-13: Improve component type safety and structure.

Consider these improvements:

  1. Use PascalCase for component name
  2. Use React.FC for better type safety
  3. Group props into a single interface
+interface UserColumnsProps {
+  heading: string;
+  note: string;
+  Child: (childProps: UserChildProps) => JSX.Element | undefined;
+  childProps: UserChildProps;
+}

-export default function userColumns(
-  heading: string,
-  note: string,
-  Child: (childProps: userChildProps) => JSX.Element | undefined,
-  childProps: userChildProps,
-) {
+const UserColumns: React.FC<UserColumnsProps> = ({
+  heading,
+  note,
+  Child,
+  childProps,
+}) => {

1-29: Well-structured component that aligns with PR objectives.

The component provides a consistent and reusable layout pattern for user management sections, which aligns well with the PR's goal of improving user management UI. The split-column design effectively organizes content, with clear separation between section headers and content.

Consider documenting usage examples in comments or creating a Storybook story to showcase different use cases of this reusable component.

src/components/Users/LinkedFacilitiesTab.tsx (2)

7-10: Consider using interface for better documentation.

Consider using an interface instead of type for Props to allow for better documentation and extensibility.

-type Props = {
+interface Props {
   userData: UserModel;
   username: string;
-};
+}

12-32: Consider adding error boundary and loading state.

The component could benefit from error handling and loading states to improve user experience.

Consider wrapping the component with an error boundary and adding a loading state:

export default function LinkedFacilitiesTab(props: Props) {
  const { userData } = props;
  const { t } = useTranslation();

  if (!userData) {
    return null;
  }

  return (
    <ErrorBoundary fallback={<div>{t("error_message")}</div>}>
      <Suspense fallback={<LoadingSpinner />}>
        <div className="mt-10 flex flex-col gap-y-12">
          {userColumns(
            t("linked_facilities"),
            t("linked_facilities_note"),
            LinkedFacilities,
            props,
          )}
        </div>
      </Suspense>
    </ErrorBoundary>
  );
}
src/components/Users/UnlinkSkillDialog.tsx (2)

32-38: Enhance accessibility and error handling.

While the translation implementation is good, consider these improvements:

  1. Add aria-label for better screen reader support
  2. Add error handling for undefined skillName
-        <div className="flex leading-relaxed text-secondary-800">
+        <div 
+          className="flex leading-relaxed text-secondary-800"
+          role="alert"
+          aria-label={t("unlink_skill_confirmation_message")}
+        >
           <span>
-            {t("unlink_skill_confirm")} <strong>{props.skillName}</strong>{" "}
+            {t("unlink_skill_confirm")} <strong>{props.skillName || t("unknown_skill")}</strong>{" "}
             {t("from_user")} <strong>{props.userName}</strong>?{" "}
             {t("unlink_skill_access")}
           </span>
         </div>

24-25: Consider using template literals for translation keys.

The action prop is hardcoded while the title uses translation. Consider using translation for both for consistency.

-      action="Unlink"
+      action={t("unlink_action")}
       title={t("unlink_skill")}
src/components/Users/RoleAndSkillsTab.tsx (2)

13-16: Add component documentation.

Consider adding JSDoc documentation to describe the component's purpose, props, and usage example.

+/**
+ * RoleAndSkillsTab displays user qualifications and linked skills based on user type.
+ * Qualifications are only shown for Doctors and Nurses.
+ * @param {Props} props - Component props
+ * @param {UserModel} props.userData - User data containing user type and other details
+ * @param {string} props.username - Username of the user
+ */
 export default function RoleAndSkillsTab(props: Props) {

17-19: Improve guard clause implementation.

The current implementation silently returns undefined. Consider returning null explicitly or implementing an error boundary for better debugging and maintainability.

 if (!userData || !username) {
-  return;
+  return null; // Explicit return for better readability
 }
src/components/Common/SkillSelect.tsx (3)

4-4: Consider moving SkillModel to a shared location.

Since SkillSelect is in the Common components directory but imports SkillModel from the Users module, this could create tight coupling or potential circular dependencies. Consider moving the model to a shared location (e.g., @/models or @/types).


Line range hint 54-59: Add type safety to optionLabel callback.

The optionLabel callback uses any type which bypasses TypeScript's type checking. This could lead to runtime errors if the option object structure changes.

Apply this fix:

-  optionLabel={(option: any) =>
+  optionLabel={(option: SkillModel) =>
     option.name +
     (option.district_object ? `, ${option.district_object.name}` : "")
   }

Line range hint 35-47: Add error handling for API response.

The skillSearch callback assumes the API response will always have a results property. Consider adding error handling to gracefully handle API failures or unexpected response formats.

Consider this improvement:

   const skillSearch = useCallback(
     async (text: string) => {
       const query = {
         limit: 50,
         offset: 0,
         search_text: text,
         all: searchAll,
       };
-      const { data } = await request(routes.getAllSkills, { query });
-      return data?.results.filter(
-        (skill) =>
-          !userSkills?.some(
-            (userSkill) => userSkill.skill_object.id === skill.id,
-          ),
-      );
+      try {
+        const { data } = await request(routes.getAllSkills, { query });
+        return data?.results?.filter(
+          (skill) =>
+            !userSkills?.some(
+              (userSkill) => userSkill.skill_object.id === skill.id,
+            ),
+        ) ?? [];
+      } catch (error) {
+        console.error('Failed to fetch skills:', error);
+        return [];
+      }
     },
     [searchAll, userSkills],
   );
src/components/Common/Page.tsx (1)

20-20: Add JSDoc documentation for the new prop.

Please add documentation for the hideTitleOnPage prop to maintain consistency with other props (like collapseSidebar) and improve maintainability.

+  /**
+   * If true, hides the title on the page while preserving other PageTitle functionality.
+   * @default false
+   */
   hideTitleOnPage?: boolean;
src/components/Users/ConfirmFacilityModal.tsx (3)

6-20: Consider improving type safety and maintainability.

  1. Extract the props interface for better reusability and documentation.
  2. Use a union type for the type prop instead of string to restrict valid values.
+type FacilityActionType = "unlink_facility" | "clear_home_facility" | "replace_home_facility";
+
+interface ConfirmFacilityModalProps {
+  username: string;
+  currentFacility?: FacilityModel;
+  homeFacility?: FacilityModel;
+  handleCancel: () => void;
+  handleOk: () => void;
+  type: FacilityActionType;
+}
+
-const ConfirmFacilityModal = ({
-  username,
-  currentFacility,
-  homeFacility,
-  handleCancel,
-  handleOk,
-  type,
-}: {
-  username: string;
-  currentFacility?: FacilityModel;
-  homeFacility?: FacilityModel;
-  handleCancel: () => void;
-  handleOk: () => void;
-  type: string;
-}) => {
+const ConfirmFacilityModal = ({
+  username,
+  currentFacility,
+  homeFacility,
+  handleCancel,
+  handleOk,
+  type,
+}: ConfirmFacilityModalProps) => {

21-64: Improve code organization and consistency.

  1. The switch statement could be simplified by extracting the modal configurations.
  2. The body content structure is inconsistent (some cases have extra div wrappers).
+interface ModalConfig {
+  action: string;
+  body: JSX.Element;
+}
+
+const getModalConfig = (
+  type: FacilityActionType,
+  t: (key: string) => string,
+  username: string,
+  currentFacility?: FacilityModel,
+  homeFacility?: FacilityModel
+): ModalConfig => {
+  const configs: Record<FacilityActionType, ModalConfig> = {
+    unlink_facility: {
+      action: "Unlink",
+      body: (
+        <div>
+          {t("unlink_facility_confirm")}{" "}
+          <strong>{currentFacility?.name}</strong> {t("from_user")}{" "}
+          <strong>{username}</strong>
+          <br />
+          {t("unlink_facility_access")}
+        </div>
+      )
+    },
+    clear_home_facility: {
+      action: "Clear",
+      body: (
+        <div>
+          {t("clear_home_facility_confirm")}{" "}
+          <strong>{currentFacility?.name}</strong> {t("from_user")}{" "}
+          <strong>{username}</strong>
+        </div>
+      )
+    },
+    replace_home_facility: {
+      action: "Replace",
+      body: (
+        <div>
+          {t("replace_home_facility_confirm")}{" "}
+          <strong>{homeFacility?.name}</strong> {t("with")}{" "}
+          <strong>{currentFacility?.name}</strong>{" "}
+          {t("replace_home_facility_confirm_as")} <strong>{username}</strong>?
+        </div>
+      )
+    }
+  };
+  return configs[type];
+};

65-76: Consider improving modal control and presentation.

  1. The show prop could be controlled externally for better flexibility.
  2. The danger variant might not be appropriate for all actions (e.g., replace_home_facility).
  3. The extra div wrapper around the body content is redundant.
-      show={true}
+      show={show}
-      variant="danger"
+      variant={type === "unlink_facility" ? "danger" : "warning"}
-      <div className="flex leading-relaxed text-secondary-800">{body}</div>
+      {body}
src/components/Users/UserSummary.tsx (2)

21-28: Enhance error handling for undefined userData

The early return for undefined userData could be improved to provide better user feedback.

Consider this enhancement:

 if (!userData) {
-  return;
+  return (
+    <div className="flex justify-center p-4">
+      {t("user_data_not_found")}
+    </div>
+  );
 }

84-93: Improve button implementation

The button implementation can be enhanced for better performance and accessibility.

Consider these improvements:

 <ButtonV2
-  authorizeFor={() => deletePermitted}
+  authorizeFor={deletePermitted}
   onClick={() => setshowDeleteDialog(true)}
   variant="danger"
   data-testid="user-delete-button"
-  className="my-1 inline-flex"
+  className="my-1 inline-flex items-center gap-2"
+  aria-label={t("delete_account_aria_label")}
 >
   <CareIcon icon="l-trash" className="h-4" />
-  <span className="">{t("delete_account_btn")}</span>
+  <span>{t("delete_account_btn")}</span>
 </ButtonV2>
src/components/Users/UserInformation.tsx (2)

66-77: Add confirmation dialog and loading state for avatar deletion.

The avatar deletion could benefit from a confirmation dialog and loading state to prevent accidental deletions and provide better user feedback.

 const handleAvatarDelete = async (onError: () => void) => {
+  const confirmed = window.confirm(t("confirm_delete_avatar"));
+  if (!confirmed) return;
+
+  setIsDeleting(true);
   try {
     const { res } = await request(routes.deleteProfilePicture, {
       pathParams: { username },
     });
     if (res?.ok) {
       Notification.Success({ msg: "Profile picture deleted" });
       await refetchUserData();
       setEditAvatar(false);
     } else {
       onError();
     }
   } catch (error) {
     onError();
   } finally {
+    setIsDeleting(false);
   }
 };

79-116: Enhance accessibility with ARIA labels and roles.

While the component structure is good, it could benefit from improved accessibility.

 <div className="overflow-visible rounded-lg bg-white px-4 py-5 shadow sm:rounded-lg sm:px-6">
-  <div className="my-4 flex justify-between">
+  <div className="my-4 flex justify-between" role="region" aria-label={t("profile_section")}>
     <div className="flex items-center">
       <Avatar
         imageUrl={userData?.read_profile_picture_url}
         name={formatDisplayName(userData)}
         className="h-20 w-20"
+        aria-label={t("profile_picture")}
       />
       <div className="my-4 ml-4 flex flex-col gap-2">
         <ButtonV2
           onClick={(_) => setEditAvatar(!editAvatar)}
           type="button"
           id="edit-cancel-profile-button"
           className="border border-gray-200 bg-gray-50 text-black hover:bg-gray-100"
           shadow={false}
+          aria-label={t("change_avatar_button")}
         >
src/components/Form/Form.tsx (3)

36-36: LGTM! Consider adding JSDoc documentation.

The new optional resetFormVals prop is well-typed and appropriately positioned. Consider adding JSDoc documentation to explain its purpose and behavior.

+/** Whether to reset form values to initial state on cancel. */
 resetFormVals?: boolean;

83-88: LGTM! Consider adding error handling.

The cancel handler implementation is clean and correctly implements the reset functionality. However, consider wrapping the state reset in a try-catch block to handle potential dispatch errors.

 const handleCancel = () => {
   if (props.resetFormVals) {
+    try {
       dispatch({ type: "set_form", form: formVals.current });
+    } catch (error) {
+      console.error('Failed to reset form:', error);
+      Notification.Error({ msg: "Failed to reset form" });
+    }
   }
   props.onCancel?.();
 };

Line range hint 36-88: Consider form reset feature documentation and testing.

The form reset feature is a good addition that aligns with the user management redesign objectives. To ensure proper usage across the application:

  1. Document the reset behavior in the component's README or documentation
  2. Add unit tests covering the reset functionality
  3. Consider adding a FormProvider context property to expose the reset capability programmatically

Would you like me to help with generating the documentation or test cases?

src/components/Users/UserHome.tsx (5)

23-26: Consider improving the tabChildProp interface naming and documentation.

The interface could be more descriptive and include documentation:

-export interface tabChildProp {
+export interface TabContentProps {
+  /** Component to render the tab content */
   body: (childProps: userChildProps) => JSX.Element | undefined;
+  /** Optional custom name for the tab. If not provided, the tab key is used */
   name?: string;
 }

46-49: Simplify role visibility check and improve naming.

The function can be simplified and renamed to better reflect its purpose.

-const roleInfoBeVisible = () => {
-  if (["Doctor", "Nurse"].includes(userData?.user_type ?? "")) return true;
-  return false;
-};
+const hasQualifications = () => ["Doctor", "Nurse"].includes(userData?.user_type ?? "");

51-62: Improve tab configuration maintainability and type safety.

Consider extracting the tab configuration to a separate constant and improving type safety:

+export const enum TabKeys {
+  PROFILE = 'PROFILE',
+  SKILLS = 'SKILLS',
+  FACILITIES = 'FACILITIES'
+}

+type TabConfig = Record<TabKeys, TabContentProps>;

-const TABS: {
-  PROFILE: tabChildProp;
-  SKILLS: tabChildProp;
-  FACILITIES: tabChildProp;
-} = {
+const TABS: TabConfig = {
   [TabKeys.PROFILE]: { body: UserSummaryTab },
   [TabKeys.SKILLS]: {
     body: RoleAndSkillsTab,
-    name: roleInfoBeVisible() ? "QUALIFICATIONS_SKILLS" : "SKILLS",
+    name: hasQualifications() ? "QUALIFICATIONS_SKILLS" : "SKILLS",
   },
   [TabKeys.FACILITIES]: { body: LinkedFacilitiesTab },
 };

94-117: Enhance navigation accessibility and loading state.

Consider improving the tab navigation accessibility and loading experience:

  1. Add ARIA roles and states to the tab navigation
  2. Consider using a skeleton loader instead of a simple loading spinner
 <nav
   className="flex space-x-6 overflow-x-auto"
   id="usermanagement_tab_nav"
+  role="tablist"
+  aria-label={t("user_management_navigation")}
 >
   {keysOf(TABS).map((p) => {
     const tabName = TABS[p]?.name ?? p;
     return (
       <Link
         key={p}
         className={classNames(/*...*/)}
         href={`/users/${username}/${p.toLocaleLowerCase()}`}
+        role="tab"
+        aria-selected={currentTab === p}
+        aria-controls={`${p.toLowerCase()}-panel`}
       >

28-127: Add unit tests for the UserHome component.

To ensure reliability and meet PR objectives, consider adding tests for:

  1. Tab navigation and rendering
  2. User data loading and error states
  3. Role-based visibility logic
  4. Accessibility features

Would you like me to help create a test suite for this component?

src/components/Users/UserBanner.tsx (2)

19-25: Consider memoizing the online status calculation.

The isUserOnline check runs on every render due to the useEffect. Consider memoizing this value using useMemo to optimize performance, especially if isUserOnline is computationally expensive.

-const [userOnline, setUserOnline] = useState(false);
+const userOnline = useMemo(() => userData ? isUserOnline(userData) : false, [userData]);

-useEffect(() => {
-  if (!userData) return;
-  setUserOnline(isUserOnline(userData));
-}, [userData]);

116-124: Enhance experience calculation robustness.

The current experience calculation doesn't handle edge cases like future dates. Consider extracting this logic into a utility function with proper validation.

+// Add to utils.ts
+export const calculateExperienceYears = (startDate: string): number => {
+  const start = dayjs(startDate);
+  if (!start.isValid() || start.isAfter(dayjs())) {
+    return 0;
+  }
+  return dayjs().diff(start, "years", false);
+};

// In component
-{dayjs().diff(
-  userData.doctor_experience_commenced_on,
-  "years",
-  false,
-)}{" "}
+{calculateExperienceYears(userData.doctor_experience_commenced_on)}{" "}
src/components/Users/UserResetPassword.tsx (2)

40-50: Enhance password validation security.

While the current validation covers basic requirements, consider strengthening it by:

  1. Adding special character requirement
  2. Making the validation function more configurable
  3. Adding maximum length validation

Example implementation:

-const validateNewPassword = (password: string) => {
+const validateNewPassword = (password: string, options = {
+  minLength: 8,
+  maxLength: 128,
+  requireSpecialChar: true
+}) => {
   if (
-    password.length < 8 ||
+    password.length < options.minLength ||
+    password.length > options.maxLength ||
     !/\d/.test(password) ||
     password === password.toUpperCase() ||
-    password === password.toLowerCase()
+    password === password.toLowerCase() ||
+    (options.requireSpecialChar && !/[!@#$%^&*(),.?":{}|<>]/.test(password))
   ) {
     return false;
   }
   return true;
 };

98-192: Enhance form accessibility and validation UX.

  1. Add proper ARIA attributes for better screen reader support
  2. Show validation messages consistently, not just on focus
  3. Consider extracting validation rules to a configuration object

Example improvements:

-<form action="#" method="POST">
+<form 
+  action="#" 
+  method="POST"
+  aria-label="Password reset form"
+  noValidate
+>
   <div className="grid grid-cols-6 gap-4">
     <TextFormField
       name="old_password"
       label={t("current_password")}
       className="col-span-6 sm:col-span-3"
       type="password"
       value={changePasswordForm.old_password}
       onChange={(e) => setChangePasswordForm({
         ...changePasswordForm,
         old_password: e.value,
       })}
       error={changePasswordErrors.old_password}
+      aria-required="true"
+      aria-invalid={!!changePasswordErrors.old_password}
+      aria-describedby="old-password-error"
       required
     />
+    {changePasswordErrors.old_password && (
+      <div id="old-password-error" className="text-error-600">
+        {changePasswordErrors.old_password}
+      </div>
+    )}
   </div>
   
-  <div className="text-small mb-2 hidden pl-2 text-secondary-500 peer-focus-within:block">
+  <div className="text-small mb-2 pl-2 text-secondary-500" 
+       role="alert"
+       aria-live="polite">
     {/* ... validation messages ... */}
   </div>
 </form>
src/components/ABDM/LinkAbhaNumber/CreateWithAadhaar.tsx (2)

Line range hint 466-484: Refactor validation logic to improve maintainability.

The ABHA address validation regex pattern is duplicated. Consider:

  1. Extracting the regex pattern to a constant
  2. Creating a reusable validation function

Apply this refactor:

+const ABHA_ADDRESS_REGEX = /^(?![\d.])[a-zA-Z0-9._]{4,}(?<!\.)$/;
+
+const validateAbhaAddress = (healthId: string) => ABHA_ADDRESS_REGEX.test(healthId);
+
 function ChooseAbhaAddress({
   // ...
   <ButtonV2
     className="w-full"
-    disabled={
-      memory?.isLoading ||
-      !/^(?![\d.])[a-zA-Z0-9._]{4,}(?<!\.)$/.test(healthId)
-    }
+    disabled={memory?.isLoading || !validateAbhaAddress(healthId)}
     onClick={handleSubmit}
   >

Also applies to: 516-519


Line range hint 252-269: Enhance error handling for better user experience.

The error handling for API calls could be more robust. Consider:

  1. Adding specific error messages for different failure scenarios
  2. Handling session expiry gracefully
  3. Managing error states more effectively in the form state

Apply this enhancement:

 const handleResendOtp = async () => {
   setMemory((prev) => ({ ...prev, isLoading: true }));
+  try {
     const { res, data } = await request(
       routes.abdm.healthId.abhaCreateLinkMobileNumber,
       {
         body: {
           mobile: memory?.mobileNumber.replace("+91", "").replace(/ /g, ""),
           transaction_id: memory?.transactionId,
         },
       },
     );

     if (res?.status === 200 && data) {
       setMemory((prev) => ({
         ...prev,
         transactionId: data.transaction_id,
         resendOtpCount: prev.resendOtpCount + 1,
       }));
       Notify.Success({
         msg: data.detail ?? t("mobile_otp_send_success"),
       });
-    } else {
+    } else if (res?.status === 401) {
+      Notify.Error({
+        msg: t("session_expired_please_retry"),
+      });
+      // Handle session expiry
+    } else if (res?.status === 429) {
+      Notify.Error({
+        msg: t("too_many_attempts_please_wait"),
+      });
+      // Handle rate limiting
+    } else {
       setMemory((prev) => ({
         ...prev,
         resendOtpCount: Infinity,
       }));
-      Notify.Success({
+      Notify.Error({
         msg: t("mobile_otp_send_error"),
       });
     }
+  } catch (error) {
+    Notify.Error({
+      msg: t("network_error_please_retry"),
+    });
+  } finally {
     setMemory((prev) => ({ ...prev, isLoading: false }));
+  }
 };

Also applies to: 359-376

src/components/Users/UserProfile.tsx (4)

Line range hint 279-291: Internationalize password validation messages

The password validation messages should use the translation function (t) to support multiple languages, as mentioned in the PR objectives for internationalization of UI text.

 const rules = [
   {
     test: (p: string) => p.length >= 8,
-    message: "Password should be at least 8 characters long",
+    message: t("password_min_length_message"),
   },
   {
     test: (p: string) => p !== p.toUpperCase(),
-    message: "Password should contain at least 1 lowercase letter",
+    message: t("password_lowercase_message"),
   },
   {
     test: (p: string) => p !== p.toLowerCase(),
-    message: "Password should contain at least 1 uppercase letter",
+    message: t("password_uppercase_message"),
   },
   {
     test: (p: string) => /\d/.test(p),
-    message: "Password should contain at least 1 number",
+    message: t("password_number_message"),
   },
 ];

Line range hint 293-397: Enhance form validation implementation

Several improvements can be made to the validation logic:

  1. Extract magic numbers into named constants
  2. Internationalize error messages
  3. Consider extracting field-specific validation logic into separate functions for better maintainability
+ const MIN_AGE = 17;
+ const MAX_EXPERIENCE_YEARS = 100;
+ const MAX_WEEKLY_HOURS = 168;

 const validateForm = () => {
   const errors = { ...initError };
   let invalidForm = false;
   Object.keys(states.form).forEach((field) => {
     switch (field) {
       case "date_of_birth":
         if (!states.form[field]) {
-          errors[field] = "Enter a valid date of birth";
+          errors[field] = t("enter_valid_dob");
           invalidForm = true;
         } else if (
           !dayjs(states.form[field]).isValid() ||
-          dayjs(states.form[field]).isAfter(dayjs().subtract(17, "year"))
+          dayjs(states.form[field]).isAfter(dayjs().subtract(MIN_AGE, "year"))
         ) {
-          errors[field] = "Enter a valid date of birth";
+          errors[field] = t("enter_valid_dob");
           invalidForm = true;
         }
         return;
       // Similar changes for other validation messages

Line range hint 467-503: Enhance form submission error handling and internationalization

The form submission handler needs improvements:

  1. Add error handling for date parsing
  2. Internationalize success message
  3. Consider adding loading state during submission
 const handleSubmit = async (e: FormEvent) => {
   e.preventDefault();
   const validForm = validateForm();
   if (validForm) {
+    try {
+      setIsSubmitting(true);
       const data = {
         // ... other fields ...
         doctor_experience_commenced_on:
           states.form.user_type === "Doctor"
             ? dayjs()
                 .subtract(
                   parseInt(
                     (states.form.doctor_experience_commenced_on as string) ??
                       "0",
                   ),
                   "years",
                 )
                 .format("YYYY-MM-DD")
             : undefined,
       };
       const { res } = await request(routes.partialUpdateUser, {
         pathParams: { username: authUser.username },
         body: data,
       });
       if (res?.ok) {
         Notification.Success({
-          msg: "Details updated successfully",
+          msg: t("details_updated_successfully"),
         });
         await refetchUserData();
         setShowEdit(false);
       }
+    } catch (error) {
+      Notification.Error({
+        msg: t("error_updating_details"),
+      });
+    } finally {
+      setIsSubmitting(false);
+    }
   }
 };

Line range hint 544-586: Improve password change handler implementation

The password change handler needs several improvements:

  1. Add proper TypeScript typing for the event parameter
  2. Internationalize error messages
  3. Add loading state during submission
  4. Consider using a more structured form validation approach
- const changePassword = async (e: any) => {
+ const changePassword = async (e: FormEvent) => {
   e.preventDefault();
+  try {
+    setIsChangingPassword(true);
     if (
       changePasswordForm.new_password_1 !== changePasswordForm.new_password_2
     ) {
       Notification.Error({
-        msg: "Passwords are different in new password and confirmation password column.",
+        msg: t("password_mismatch_error"),
       });
     } else if (!validateNewPassword(changePasswordForm.new_password_1)) {
       Notification.Error({
-        msg: "Entered New Password is not valid, please check!",
+        msg: t("invalid_password_error"),
       });
     } else if (
       changePasswordForm.new_password_1 === changePasswordForm.old_password
     ) {
       Notification.Error({
-        msg: "New password is same as old password, Please enter a different new password.",
+        msg: t("same_password_error"),
       });
     } else {
       const form: UpdatePasswordForm = {
         old_password: changePasswordForm.old_password,
         username: authUser.username,
         new_password: changePasswordForm.new_password_1,
       };
       const { res, data, error } = await request(routes.updatePassword, {
         body: form,
       });
       if (res?.ok) {
         Notification.Success({ msg: data?.message });
       } else if (!error) {
         Notification.Error({
-          msg: "There was some error. Please try again in some time.",
+          msg: t("generic_error_message"),
         });
       }
       setChangePasswordForm({
         ...changePasswordForm,
         new_password_1: "",
         new_password_2: "",
         old_password: "",
       });
     }
+  } catch (error) {
+    Notification.Error({
+      msg: t("password_change_error"),
+    });
+  } finally {
+    setIsChangingPassword(false);
+  }
 };
public/locale/en.json (1)

658-660: Consider enhancing the username validation message.

While most validation messages are clear, the username validation message could be more specific about allowed special characters.

Consider updating the message to be more explicit:

-  "invalid_username": "Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.",
+  "invalid_username": "Required. 150 characters or fewer. Only lowercase letters, numbers, and the special characters @ . + - _ are allowed.",

Also applies to: 709-709, 818-818, 1322-1322

src/components/Users/UserAdd.tsx (4)

Line range hint 16-19: Include rel="noopener noreferrer" when using target="_blank to prevent security risks.

When using target="_blank``, adding rel="noopener noreferrer"prevents the new page from accessing thewindow.opener` property, which can pose a security risk. This ensures that the external page cannot manipulate the original page.

Apply this diff to fix the issue:

          href="https://school.ohc.network/targets/12953"
          className="inline-block rounded border border-secondary-600 bg-secondary-50 px-4 py-2 text-secondary-600 transition hover:bg-secondary-100"
-         target="_blank"
+         target="_blank" rel="noopener noreferrer"
        >

Line range hint 20-21: Internationalize the 'Need Help?' text.

The text 'Need Help?' is currently hardcoded and not wrapped in the translation function t(). To ensure consistent internationalization across the application, please use the translation function so that the text can be translated into other languages.

Apply this diff to fix the issue:

-          <CareIcon icon="l-question-circle" className="text-lg" /> &nbsp;Need
-          Help?
+          <CareIcon icon="l-question-circle" className="text-lg" /> &nbsp;{t("Need Help?")}

Line range hint 15-23: Use an <a> element instead of Link for external URLs.

The Link component from raviger is intended for internal routing within the application. When linking to external URLs, it's appropriate to use an <a> element to ensure proper behavior and accessibility.

Apply this diff to fix the issue:

-        <Link
+        <a
          href="https://school.ohc.network/targets/12953"
          className="inline-block rounded border border-secondary-600 bg-secondary-50 px-4 py-2 text-secondary-600 transition hover:bg-secondary-100"
          target="_blank" rel="noopener noreferrer"
-        >
+        >
          <CareIcon icon="l-question-circle" className="text-lg" /> &nbsp;{t("Need Help?")}
-        </Link>
+        </a>

1-1: Remove unused import of Link from raviger.

After replacing the Link component with an <a> element, the import statement is no longer needed and can be removed to keep the code clean.

Apply this diff to fix the issue:

-import { Link } from "raviger";
src/components/Facility/FacilityUsers.tsx (2)

28-41: Ensure robust handling of pagination parameters

The calculation of offset depends on qParams.page. If qParams.page is undefined or invalid, it could lead to incorrect offsets. Consider providing a default value to enhance robustness.

Apply this diff to provide a default value for qParams.page:

-             (qParams.page ? qParams.page - 1 : 0) * resultsPerPage
+             ((qParams.page ?? 1) - 1) * resultsPerPage

49-55: Consider updating the icon in CountBlock for clarity

The icon "l-user-injured" may not best represent the total number of users. Using an icon like "l-users" might provide better clarity to users.

Apply this diff to change the icon:

-        icon="l-user-injured"
+        icon="l-users"
src/components/Users/LinkedSkills.tsx (1)

130-141: Avoid passing empty strings to errors prop

The errors prop is passed as an empty string to SkillSelect. If there are no errors, it's better to pass undefined or omit the prop entirely to prevent unnecessary rendering or checks within the child component.

Apply this diff:

 <SkillSelect
   id="select-skill"
   multiple={false}
   name="skill"
   disabled={!authorizeForAddSkill}
   showNOptions={Infinity}
   selected={selectedSkill}
   setSelected={setSelectedSkill}
-  errors=""
+  errors={undefined}
   className="z-10 w-full"
   userSkills={skills?.results || []}
 />
src/components/Users/UserQualifications.tsx (3)

179-180: Localize notification messages

The success message is hardcoded and not localized. To support internationalization, wrap the message with the t() function.

-            msg: "Details updated successfully",
+            msg: t("details_updated_successfully"),

220-223: Add maximum value constraint to the years of experience field

To prevent users from entering an invalid number of years of experience, consider adding a max attribute to the input field.

                            type="number"
                            min={0}
+                           max={99}
                            label={t("years_of_experience")}

88-91: Consider storing and handling experience dates directly

Calculating dates by subtracting years from the current date might lead to inaccuracies over time. It's more reliable to store and handle doctor_experience_commenced_on as a date rather than calculating it from years of experience.

Also applies to: 157-167

src/components/Users/LinkedFacilities.tsx (2)

164-164: Remove commented-out code to improve code cleanliness

The lines //setIsLoading(true); and //setIsLoading(false); are commented out. If these lines are no longer needed, consider removing them to keep the codebase clean. If they are placeholders for future functionality, add a TODO comment explaining their purpose.

Also applies to: 180-180


184-218: Refactor render functions to eliminate code duplication

The functions renderFacilityButtons and renderHomeFacilityButton have similar structures. Refactoring them into a single function with conditional logic can reduce code duplication and enhance maintainability.

Consider combining them as follows:

const renderFacilityButton = (facility: FacilityModel, isHomeFacility: boolean) => {
  if (!facility) return null;
  return (
    <div id={`facility_${facility.id}`} key={`facility_${facility.id}`}>
      <div className="flex flex-row items-center rounded-sm border bg-secondary-100">
        <div className="rounded p-1 text-sm">{facility.name}</div>
        <div className="border-l-3 rounded-r bg-secondary-300 px-2 py-1">
          {isHomeFacility ? (
            <button
              onClick={() => handleOnClick("clear_home_facility", facility)}
              title={t("clear_home_facility")}
              aria-label={t("clear_home_facility")}
            >
              <CareIcon icon="l-multiply" className="text-sm" />
            </button>
          ) : (
            <DropdownMenu>
              <DropdownMenuTrigger>
                <CareIcon icon="l-setting" className="text-sm" />
              </DropdownMenuTrigger>
              <DropdownMenuContent>
                <DropdownMenuItem
                  onClick={() =>
                    handleOnClick(
                      homeFacility ? "replace_home_facility" : "set_home_facility",
                      facility,
                    )
                  }
                >
                  {t("set_home_facility")}
                </DropdownMenuItem>
                <DropdownMenuItem
                  onClick={() => handleOnClick("unlink_facility", facility)}
                >
                  {t("unlink_this_facility")}
                </DropdownMenuItem>
              </DropdownMenuContent>
            </DropdownMenu>
          )}
        </div>
      </div>
    </div>
  );
};

Also applies to: 220-240

src/components/Users/UserListAndCard.tsx (6)

268-272: Simplify conditional rendering for district information.

The conditional logic for displaying district information in UserListRow can be simplified to improve readability.

You can simplify it as follows:

-            {"district_object" in user && user.district_object
-              ? user.district_object?.name
-              : "district" in user && user.district
-                ? user.district
-                : ""}
+            {user.district_object?.name || user.district || ""}

180-193: Simplify conditional rendering for district information.

The conditional logic for displaying district information in UserCard can be simplified for better readability.

You can simplify it as follows:

-        {"district_object" in user && user.district_object && (
-          <div className="text-sm">
-            <div className="text-gray-500">{t("district")}</div>
-            <div className="font-medium">
-              {user.district_object.name}
-            </div>
-          </div>
-        )}
-        {"district" in user && user.district && (
-          <div className="text-sm">
-            <div className="text-gray-500">{t("district")}</div>
-            <div className="font-medium">{user.district}</div>
-          </div>
-        )}
+        {(user.district_object?.name || user.district) && (
+          <div className="text-sm">
+            <div className="text-gray-500">{t("district")}</div>
+            <div className="font-medium">
+              {user.district_object?.name || user.district}
+            </div>
+          </div>
+        )}

162-162: Use full user name in Avatar component for better display.

Currently, the name prop for the Avatar component is set to user.username on line 162. Consider using the user's full name for a better user experience.

Apply this diff:

-                    name={user.username ?? ""}
+                    name={formatName(user)}

249-249: Use full user name in Avatar component for better display.

Currently, the name prop for the Avatar component is set to user.username on line 249. Consider using the user's full name for a better user experience.

Apply this diff:

-                name={user.username ?? ""}
+                name={formatName(user)}

326-326: Localize static text 'Card' for internationalization.

The text 'Card' on line 326 is not wrapped with the translation function t. This may lead to missing translations in other languages.

Apply this diff:

-                      <span>Card</span>
+                      <span>{t("card")}</span>

336-336: Localize static text 'List' for internationalization.

The text 'List' on line 336 is not wrapped with the translation function t. This may lead to missing translations in other languages.

Apply this diff:

-                      <span>List</span>
+                      <span>{t("list")}</span>
src/components/Users/ManageUsers.tsx (2)

Line range hint 109-127: Simplify component rendering by eliminating unnecessary variable

The use of the manageUsers variable adds unnecessary complexity. Consider rendering the user list components directly within the return statement to improve readability and maintainability.

You can refactor the code as follows:

- let manageUsers: JSX.Element = <></>;

- if (userListLoading || districtDataLoading || !userListData?.results) {
-   return <Loading />;
- }

- if (userListData?.results.length) {
-   manageUsers = (
-     <div>
-       <UserListView
-         users={userListData?.results ?? []}
-         onSearch={(username) => updateQuery({ username })}
-         searchValue={qParams.username}
-       />
-       <Pagination totalCount={userListData.count} />
-     </div>
-   );
- } else if (userListData?.results && userListData?.results.length === 0) {
-   manageUsers = (
-     <div>
-       <div className="h-full space-y-2 rounded-lg bg-white p-7 shadow">
-         <div className="flex w-full items-center justify-center text-xl font-bold text-secondary-500">
-           No Users Found
-         </div>
-       </div>
-     </div>
-   );
- }

- return (
-   <Page title={t("user_management")} hideBack={true} breadcrumbs={false}>
-     {/* ...other components... */}
-     <div>{manageUsers}</div>
-   </Page>
- );

+ if (userListLoading || districtDataLoading || !userListData?.results) {
+   return <Loading />;
+ }

+ return (
+   <Page title={t("user_management")} hideBack={true} breadcrumbs={false}>
+     {/* ...other components... */}
+     {userListData?.results.length ? (
+       <div>
+         <UserListView
+           users={userListData?.results ?? []}
+           onSearch={(username) => updateQuery({ username })}
+           searchValue={qParams.username}
+         />
+         <Pagination totalCount={userListData.count} />
+       </div>
+     ) : (
+       <div>
+         <div className="h-full space-y-2 rounded-lg bg-white p-7 shadow">
+           <div className="flex w-full items-center justify-center text-xl font-bold text-secondary-500">
+             {t("no_users_found")}
+           </div>
+         </div>
+       </div>
+     )}
+   </Page>
+ );

Line range hint 124-127: Internationalize the 'No Users Found' message

The text 'No Users Found' is hardcoded and not internationalized. Use the translation function to support multiple languages and improve accessibility.

Apply this diff to internationalize the text:

- No Users Found
+ {t("no_users_found")}

Also, ensure the translation key 'no_users_found' is added to the localization files.

src/components/Users/UserAddEditForm.tsx (7)

182-182: Simplify boolean assignment of 'editUser'.

Instead of using a ternary operator, you can directly convert username to a boolean.

Apply this diff to simplify the assignment:

-      const editUser = username ? true : false;
+      const editUser = !!username;
🧰 Tools
🪛 Biome

[error] 182-182: Unnecessary use of boolean literals in conditional expression.

Simplify your code by directly assigning the result without using a ternary operator.
If your goal is negation, you may use the logical NOT (!) or double NOT (!!) operator for clearer and concise code.
Check for more details about NOT operator.
Unsafe fix: Remove the conditional expression with

(lint/complexity/noUselessTernary)


305-305: Correct the typo in the error message.

The word "availabality" should be corrected to "availability".

Apply this diff to fix the typo:

             Notification.Error({
-              msg: "Some error checking username availabality. Please try again later.",
+              msg: "Some error checking username availability. Please try again later.",
             });

480-480: Fix the typo in the validation message.

"Atleast" should be "at least" in the error message.

Apply this diff to correct the message:

-          return "Please select atleast one of the facilities you are linked to";
+          return "Please select at least one of the facilities you are linked to";

883-952: Remove unnecessary fragment around a single child element.

The fragment wrapping the <div> is redundant since it contains only a single child. Removing it simplifies the JSX.

Apply this diff to remove the unnecessary fragment:

-                <>
                   <div className="text-small pl-2 text-secondary-500">
                     {/* ... */}
                   </div>
-                </>
🧰 Tools
🪛 Biome

[error] 886-920: Avoid using unnecessary Fragment.

A fragment is redundant if it contains only one child, or if it is the child of a html element, and is not a keyed fragment.
Unsafe fix: Remove the Fragment

(lint/complexity/noUselessFragments)


956-1023: Eliminate redundant fragment wrapping a single element.

The fragment here is unnecessary and can be removed to improve code clarity.

Apply this diff:

-                  <>
                     <div className="flex flex-col justify-between gap-x-3 sm:flex-row">
                       {/* ... */}
                     </div>
-                  </>
🧰 Tools
🪛 Biome

[error] 956-1023: Avoid using unnecessary Fragment.

A fragment is redundant if it contains only one child, or if it is the child of a html element, and is not a keyed fragment.
Unsafe fix: Remove the Fragment

(lint/complexity/noUselessFragments)


1082-1105: Remove unnecessary fragment to simplify JSX structure.

Since the fragment contains only one child, it can be omitted for cleaner code.

Apply this diff:

-                <>
                   <div className="flex flex-col justify-between gap-x-3 sm:flex-row">
                     {/* ... */}
                   </div>
-                </>
🧰 Tools
🪛 Biome

[error] 1082-1105: Avoid using unnecessary Fragment.

A fragment is redundant if it contains only one child, or if it is the child of a html element, and is not a keyed fragment.
Unsafe fix: Remove the Fragment

(lint/complexity/noUselessFragments)


883-952: Refactor validation rule displays into a reusable component.

The code for displaying username and password validation rules is similar. Extracting this into a separate component reduces duplication and enhances maintainability.

Also applies to: 972-997

🧰 Tools
🪛 Biome

[error] 886-920: Avoid using unnecessary Fragment.

A fragment is redundant if it contains only one child, or if it is the child of a html element, and is not a keyed fragment.
Unsafe fix: Remove the Fragment

(lint/complexity/noUselessFragments)

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 6931845 and 0565d84.

📒 Files selected for processing (33)
  • public/locale/en.json (25 hunks)
  • src/Routers/routes/UserRoutes.tsx (1 hunks)
  • src/Utils/request/api.tsx (1 hunks)
  • src/components/ABDM/LinkAbhaNumber/CreateWithAadhaar.tsx (1 hunks)
  • src/components/Auth/ResetPassword.tsx (1 hunks)
  • src/components/Common/Page.tsx (2 hunks)
  • src/components/Common/PageTitle.tsx (3 hunks)
  • src/components/Common/SkillSelect.tsx (2 hunks)
  • src/components/Common/UserColumns.tsx (1 hunks)
  • src/components/Common/UserDetails.tsx (1 hunks)
  • src/components/Facility/FacilityUsers.tsx (2 hunks)
  • src/components/Form/Form.tsx (5 hunks)
  • src/components/Users/ConfirmFacilityModal.tsx (1 hunks)
  • src/components/Users/ConfirmHomeFacilityUpdateDialog.tsx (0 hunks)
  • src/components/Users/LinkFacilityDialog.tsx (0 hunks)
  • src/components/Users/LinkedFacilities.tsx (1 hunks)
  • src/components/Users/LinkedFacilitiesTab.tsx (1 hunks)
  • src/components/Users/LinkedSkills.tsx (1 hunks)
  • src/components/Users/ManageUsers.tsx (4 hunks)
  • src/components/Users/RoleAndSkillsTab.tsx (1 hunks)
  • src/components/Users/SkillsSlideOver.tsx (0 hunks)
  • src/components/Users/SkillsSlideOverComponents.tsx (0 hunks)
  • src/components/Users/UnlinkSkillDialog.tsx (2 hunks)
  • src/components/Users/UserAdd.tsx (2 hunks)
  • src/components/Users/UserAddEditForm.tsx (1 hunks)
  • src/components/Users/UserBanner.tsx (1 hunks)
  • src/components/Users/UserHome.tsx (1 hunks)
  • src/components/Users/UserInformation.tsx (1 hunks)
  • src/components/Users/UserListAndCard.tsx (1 hunks)
  • src/components/Users/UserProfile.tsx (1 hunks)
  • src/components/Users/UserQualifications.tsx (1 hunks)
  • src/components/Users/UserResetPassword.tsx (1 hunks)
  • src/components/Users/UserSummary.tsx (1 hunks)
💤 Files with no reviewable changes (4)
  • src/components/Users/ConfirmHomeFacilityUpdateDialog.tsx
  • src/components/Users/LinkFacilityDialog.tsx
  • src/components/Users/SkillsSlideOver.tsx
  • src/components/Users/SkillsSlideOverComponents.tsx
✅ Files skipped from review due to trivial changes (2)
  • src/components/Auth/ResetPassword.tsx
  • src/components/Common/UserDetails.tsx
🧰 Additional context used
🪛 Biome
src/components/Users/UserAddEditForm.tsx

[error] 182-182: Unnecessary use of boolean literals in conditional expression.

Simplify your code by directly assigning the result without using a ternary operator.
If your goal is negation, you may use the logical NOT (!) or double NOT (!!) operator for clearer and concise code.
Check for more details about NOT operator.
Unsafe fix: Remove the conditional expression with

(lint/complexity/noUselessTernary)


[error] 619-619: isNaN is unsafe. It attempts a type coercion. Use Number.isNaN instead.

See the MDN documentation for more details.
Unsafe fix: Use Number.isNaN instead.

(lint/suspicious/noGlobalIsNan)


[error] 886-920: Avoid using unnecessary Fragment.

A fragment is redundant if it contains only one child, or if it is the child of a html element, and is not a keyed fragment.
Unsafe fix: Remove the Fragment

(lint/complexity/noUselessFragments)


[error] 956-1023: Avoid using unnecessary Fragment.

A fragment is redundant if it contains only one child, or if it is the child of a html element, and is not a keyed fragment.
Unsafe fix: Remove the Fragment

(lint/complexity/noUselessFragments)


[error] 1082-1105: Avoid using unnecessary Fragment.

A fragment is redundant if it contains only one child, or if it is the child of a html element, and is not a keyed fragment.
Unsafe fix: Remove the Fragment

(lint/complexity/noUselessFragments)

src/components/Users/UserBanner.tsx

[error] 34-133: Avoid using unnecessary Fragment.

A fragment is redundant if it contains only one child, or if it is the child of a html element, and is not a keyed fragment.
Unsafe fix: Remove the Fragment

(lint/complexity/noUselessFragments)

🔇 Additional comments (36)
src/Routers/routes/UserRoutes.tsx (1)

2-3: LGTM! Import changes are well-structured.

The import statements follow React conventions and align with the user management redesign objectives.

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

1-32: Verify integration with user details page.

The component implementation aligns with PR objectives for user management redesign. However, let's verify its integration with the user details page.

✅ Verification successful

Integration with user details page verified successfully

The LinkedFacilitiesTab component is properly integrated in UserHome.tsx as one of the main tabs (FACILITIES) alongside PROFILE and SKILLS tabs, which aligns with the user management redesign objectives. The implementation and integration are correct.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check how LinkedFacilitiesTab is integrated into the user details page
rg -l "LinkedFacilitiesTab" --type tsx

Length of output: 66


Script:

#!/bin/bash
# Check how LinkedFacilitiesTab is integrated using ripgrep without file type filter
rg -l "LinkedFacilitiesTab"

Length of output: 106


Script:

#!/bin/bash
# Check the integration in UserHome.tsx
rg "LinkedFacilitiesTab" src/components/Users/UserHome.tsx -A 5 -B 5

Length of output: 956

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

15-15: Verify translation key definitions.

Let's ensure all translation keys used in the component are properly defined in the localization files.

Also applies to: 24-38

✅ Verification successful

All translation keys are properly defined in the localization file

All translation keys used in the UnlinkSkillDialog component (unlink_skill, unlink_skill_confirm, from_user, unlink_skill_access) are correctly defined in the English locale file.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check if all translation keys are defined in the English locale file

# Keys to check
KEYS=("unlink_skill" "unlink_skill_confirm" "from_user" "unlink_skill_access")

# Check each key in the locale file
for key in "${KEYS[@]}"; do
  echo "Checking key: $key"
  if ! rg "\"$key\":" public/locale/en.json; then
    echo "Warning: Translation key '$key' not found!"
  fi
done

Length of output: 866

src/components/Users/RoleAndSkillsTab.tsx (2)

1-11: LGTM! Well-structured imports and type definitions.

The imports are well-organized and the Props type is properly defined with required fields, which aligns well with the component's guard clause.


21-41: 🛠️ Refactor suggestion

Enhance type safety for user type checks.

The current string literal comparison for user types could be improved using TypeScript enums or constants for better type safety and maintainability.

+// Add to UserModel.ts or a constants file
+export enum UserType {
+  Doctor = "Doctor",
+  Nurse = "Nurse",
+}

 return (
   <>
     <div className="mt-10 flex flex-col gap-y-12">
       {userData.user_type &&
-        ["Doctor", "Nurse"].includes(userData.user_type) &&
+        Object.values(UserType).includes(userData.user_type as UserType) &&
         userColumns(
           t("user_qualifications"),
           t("user_qualifications_note"),
           UserQualifications,
           props,
         )}

Additionally, verify that these user types are consistently used across the application.

src/components/Common/Page.tsx (1)

55-55: Verify the relationship between hideTitleOnPage and hideBack props.

The component already has a hideBack prop that affects padding when the back button is hidden. Please clarify how these props interact and whether they serve distinct purposes.

Let's check the PageTitle component implementation to understand the difference:

✅ Verification successful

The hideBack and hideTitleOnPage props serve distinct purposes

Based on the implementation in PageTitle.tsx:

  • hideBack is passed to the Breadcrumbs component to control the visibility of the back button/navigation
  • hideTitleOnPage controls the visibility of the page title (h2 element) in the main content area
  • These props are independent and do not interact with each other
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Analyze the relationship between hideTitleOnPage and hideBack props
# Expected: Find the implementation showing distinct purposes for these props

# Search for the PageTitle component implementation
ast-grep --pattern 'export default function PageTitle($$$) {
  $$$
}'

# Search for usage patterns of both props
rg -A 5 'hideTitleOnPage|hideBack' src/components/Common/PageTitle.tsx

Length of output: 5285

src/components/Common/PageTitle.tsx (3)

22-22: LGTM! Well-structured prop addition.

The new prop follows TypeScript and React naming conventions, and its optional nature is appropriate for backward compatibility.


39-39: LGTM! Clean props destructuring.

The prop destructuring is consistent with the interface definition and maintains the logical grouping of display-related props.


75-77: Consider accessibility implications when hiding the title.

While the conditional rendering works correctly, hiding the h2 element might affect the page's heading hierarchy and accessibility. Consider:

  1. Providing an alternative heading for screen readers when the visible title is hidden
  2. Ensuring the page maintains a logical heading structure

Consider this alternative implementation that maintains accessibility:

- {!hideTitleOnPage && (
-   <h2 className="ml-0 text-2xl leading-tight">{title}</h2>
- )}
+ <h2 
+   className={classNames(
+     "ml-0 text-2xl leading-tight",
+     hideTitleOnPage && "sr-only"
+   )}
+ >
+   {title}
+ </h2>

This approach keeps the heading in the document structure while visually hiding it when needed.

✅ Verification successful

Based on the search results, I can now generate the final response as I have enough context about the heading structure in the codebase.

Hiding the title is safe from an accessibility perspective

The conditional rendering of the title in PageTitle.tsx is acceptable because:

  1. The component is used consistently as a secondary heading (h2)
  2. Other components maintain their own heading hierarchy independently
  3. The title hiding is likely used in specific UI scenarios where the same information is presented through other means

While the suggested sr-only approach is a good practice, the current implementation doesn't pose significant accessibility concerns as it's a controlled hide/show of a secondary heading that doesn't break document outline.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check if there are other headings that might be affected by hiding this h2
rg -g '*.tsx' -g '*.jsx' '<h[1-6]' --type-add 'tsx:*.tsx' --type-add 'jsx:*.jsx'

Length of output: 22902

src/components/Users/ConfirmFacilityModal.tsx (2)

79-79: LGTM!

The export statement follows React component conventions.


1-79: Overall implementation aligns well with PR objectives.

The component successfully implements the facility management confirmation dialogs needed for the user management redesign. It provides clear user feedback and handles different facility-related actions appropriately.

Some suggestions for improvement have been provided above, but the core functionality is solid and meets the requirements.

Let's verify the translation keys are properly defined:

✅ Verification successful

Translation keys are properly defined and accessible

The verification confirms that all required translation keys used in the ConfirmFacilityModal component are present in the locale file (public/locale/en.json), ensuring proper internationalization support for all facility management actions.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify that all translation keys used in the component exist in the locale file

# Test: Check if all required translation keys exist
rg -q "unlink_facility|unlink_facility_confirm|unlink_facility_access|clear_home_facility_confirm|replace_home_facility_confirm|replace_home_facility_confirm_as|from_user|with" "public/locale/en.json" && echo "All translation keys found" || echo "Missing translation keys"

Length of output: 263

src/components/Users/UserSummary.tsx (2)

1-20: LGTM! Well-organized imports

The imports are properly organized with clear separation between external dependencies and internal modules.


47-48: Verify user permission handling

Let's verify that the permission checks align with the PR objectives.

src/components/Users/UserInformation.tsx (2)

1-19: LGTM! Well-organized imports with clear separation of concerns.

The imports are properly organized and all dependencies are relevant to the component's functionality.


1-117: Well-implemented component that aligns with PR objectives.

The UserInformation component successfully contributes to the user management redesign by providing a clean and functional interface for managing user profiles and avatars. It aligns well with the objectives outlined in Issue #8878.

src/components/Form/Form.tsx (2)

134-134: LGTM! Handler update is correct.

The Cancel button's onClick handler is properly updated to use the new handleCancel function.


47-47: Verify handling of props.defaults changes.

The useRef initialization looks good, but consider how changes to props.defaults after initial render might affect the reset behavior.

Consider using useEffect to update formVals.current when props.defaults changes:

 const formVals = useRef(props.defaults);
+useEffect(() => {
+  formVals.current = props.defaults;
+}, [props.defaults]);
src/components/Users/UserBanner.tsx (1)

103-113: LGTM: Role-specific information display.

The conditional rendering of qualifications for Doctors and Nurses, along with Doctor-specific experience information, aligns well with the PR objectives for role-specific displays.

Also applies to: 114-129

src/components/Users/UserResetPassword.tsx (2)

1-19: LGTM! Well-structured component setup.

The imports are properly organized and the component interface is well-defined with appropriate TypeScript types.


13-17: Verify user permissions for password changes.

According to the PR objectives, password changes should be restricted to logged-in users and District Admins or higher. However, the current implementation doesn't include these permission checks.

Let's verify the permission implementation:

src/components/ABDM/LinkAbhaNumber/CreateWithAadhaar.tsx (2)

13-13: LGTM! Good refactoring of validation rules.

Moving validateRule to UserAddEditForm promotes code reuse and maintains consistency across user-related forms.


Line range hint 32-38: Consider enhancing security measures for sensitive data handling.

While basic security measures are in place, consider implementing:

  1. UI masking for verified mobile numbers
  2. Rate limiting for OTP attempts beyond the current count-based limit
  3. Session-based validation for transaction IDs

Let's verify the current security measures:

Also applies to: 89-91

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

20-20: LGTM: Import path update is correct

The import path change from UserAdd to UserAddEditForm aligns with the refactoring objectives.

src/Utils/request/api.tsx (1)

1046-1049: LGTM! The endpoint change is consistent with the codebase.

The change to a static endpoint for getUserDetails is appropriate while maintaining other user-specific endpoints that correctly use the username parameter. This change aligns with the PR objectives for user management redesign.

public/locale/en.json (6)

211-214: LGTM! Well-structured tab labels.

The new user management tab labels follow a consistent naming pattern and provide clear, hierarchical navigation.


393-394: LGTM! Clear and context-aware profile management labels.

The labels appropriately distinguish between self-update and admin-update scenarios, and provide helpful guidance for avatar uploads.

Also applies to: 1019-1020


460-460: LGTM! Comprehensive password-related messages.

The messages provide clear validation requirements, user-friendly error messages, and helpful instructions for password management.

Also applies to: 980-981, 1027-1028, 1129-1129


829-829: LGTM! Clear and cautionary facility management messages.

The messages effectively communicate the implications of facility management actions and maintain consistent terminology.

Also applies to: 1110-1112, 1279-1281


831-831: LGTM! Consistent skill management messages.

The messages follow the same clear pattern as facility management, effectively communicating actions and their consequences.

Also applies to: 1282-1284


1356-1356: LGTM! Clear weekly hours validation message.

The message clearly defines the valid range using the logical maximum of 168 hours (24*7).

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

Line range hint 8-29: Code implementation looks good.

The UserAdd component is well-structured and correctly renders the UserAddEditForm within the Page component. The use of useTranslation for the title is appropriate, and the component follows good React practices.

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

13-13: Good use of explicit prop typing

Explicitly typing props as { facilityId: number } enhances type safety and improves code readability.


15-18: Confirm the cacheBlacklist configuration in useFilters

Using cacheBlacklist: ["username"] prevents the username parameter from being cached between navigations. Please verify if this aligns with the intended behavior.


57-61: Verify that onSearch correctly updates the user list

Ensure that the onSearch handler updates the query parameters and triggers a re-fetch of the user list when the search input changes.


63-63: Confirm the functionality of the Pagination component

Check that the Pagination component interacts properly with qParams.page and updateQuery to handle page changes and that it correctly updates the user list.

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

56-58: Verify the usage of AuthorizeFor within useIsAuthorized

Ensure that AuthorizeFor is correctly used as an argument for useIsAuthorized. Depending on its implementation, AuthorizeFor might not be necessary here, or you might need to pass the roles array directly to useIsAuthorized.

Run the following script to inspect the implementations of useIsAuthorized and AuthorizeFor:

This script will help determine if AuthorizeFor is appropriately used within useIsAuthorized and whether any adjustments are necessary.

✅ Verification successful

Let me gather more information about the implementation details.


Let me check one more thing to see how AuthorizeFor is implemented since we didn't get its implementation in the previous search.


Let me try one final search pattern to find the AuthorizeFor implementation.


AuthorizeFor is correctly used with useIsAuthorized

The implementation shows that:

  • AuthorizeFor is a function that takes an array of UserRoles and returns a callback function matching the AuthorizedForCB type
  • useIsAuthorized expects a parameter of type AuthorizedForCB, which is exactly what AuthorizeFor(["DistrictAdmin", "StateAdmin"]) returns
  • This pattern is consistently used across the codebase in multiple components (e.g., LocationManagement.tsx, BedManagement.tsx)
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the correct usage of `useIsAuthorized` and `AuthorizeFor`.

# Test: Find definitions of `useIsAuthorized` and `AuthorizeFor`.
# Expect: Confirm whether `AuthorizeFor` should be used as an argument to `useIsAuthorized`.

# Search for the definition of `useIsAuthorized`
fd --extension ts --type f | xargs rg 'export function useIsAuthorized'

# Search for the definition of `AuthorizeFor`
fd --extension ts --type f | xargs rg 'export default function AuthorizeFor'

# Search for examples where `useIsAuthorized` is used
rg --type ts 'useIsAuthorized'

# Search for examples where `AuthorizeFor` is used
rg --type ts 'AuthorizeFor'

Length of output: 4086


Script:

#!/bin/bash
# Get the implementation of useIsAuthorized hook
rg -A 10 "export const useIsAuthorized" src/hooks/useIsAuthorized.ts

# Get the implementation of AuthorizeFor
rg -A 10 "export default function AuthorizeFor" src/Utils/AuthorizeFor.tsx

# Get the type definition of AuthorizedForCB
rg "type AuthorizedForCB" src/Utils/AuthorizeFor.tsx

Length of output: 413


Script:

#!/bin/bash
# Search for AuthorizeFor function implementation with a broader pattern
rg -A 10 "AuthorizeFor.*=.*\[" src/Utils/AuthorizeFor.tsx

# Alternative search pattern
rg -A 10 "function AuthorizeFor" src/Utils/AuthorizeFor.tsx

Length of output: 121


Script:

#!/bin/bash
# Try to find any content in AuthorizeFor.tsx
cat src/Utils/AuthorizeFor.tsx

# Alternative search for exports from this file
rg "export" src/Utils/AuthorizeFor.tsx

Length of output: 1620

src/Routers/routes/UserRoutes.tsx Show resolved Hide resolved
src/components/Common/UserColumns.tsx Outdated Show resolved Hide resolved
src/components/Users/LinkedFacilitiesTab.tsx Outdated Show resolved Hide resolved
src/components/Users/LinkedFacilitiesTab.tsx Outdated Show resolved Hide resolved
src/components/Users/LinkedFacilitiesTab.tsx Outdated Show resolved Hide resolved
src/components/Users/UserListAndCard.tsx Outdated Show resolved Hide resolved
src/components/Users/UserListAndCard.tsx Show resolved Hide resolved
src/components/Users/ManageUsers.tsx Show resolved Hide resolved
src/components/Users/UserAddEditForm.tsx Outdated Show resolved Hide resolved
src/components/Users/UserAddEditForm.tsx Outdated Show resolved Hide resolved
@Jacobjeevan Jacobjeevan marked this pull request as draft November 11, 2024 16:38
@github-actions github-actions bot added the merge conflict pull requests with merge conflict label Nov 12, 2024
@Jacobjeevan Jacobjeevan removed the merge conflict pull requests with merge conflict label Dec 2, 2024
@github-actions github-actions bot added the merge conflict pull requests with merge conflict label Dec 4, 2024
Copy link

github-actions bot commented Dec 4, 2024

👋 Hi, @Jacobjeevan,
Conflicts have been detected against the base branch. Please rebase your branch against the base branch.


This message is automatically generated by prince-chrismc/label-merge-conflicts-action so don't hesitate to report issues/improvements there.

@nihal467
Copy link
Member

nihal467 commented Dec 4, 2024

@Jacobjeevan what is the status on this PR

@Jacobjeevan
Copy link
Contributor Author

Jacobjeevan commented Dec 4, 2024

@Jacobjeevan what is the status on this PR

@nihal467 Still waiting on the backend 👍 I'll get the conflicts addressed though.

@github-actions github-actions bot removed the merge conflict pull requests with merge conflict label Dec 5, 2024
Copy link

github-actions bot commented Dec 5, 2024

👋 Hi, @Jacobjeevan,
Conflicts have been detected against the base branch. Please rebase your branch against the base branch.


This message is automatically generated by prince-chrismc/label-merge-conflicts-action so don't hesitate to report issues/improvements there.

@github-actions github-actions bot added the merge conflict pull requests with merge conflict label Dec 5, 2024
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)
src/components/Facility/FacilityUsers.tsx (1)

7-7: Well-structured separation of concerns!

Good architectural decision to:

  • Extract filtering logic into a reusable useFilters hook
  • Use a dedicated UserListView component for displaying users

Also applies to: 9-9, 16-19

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

110-121: Consider memoizing the user list view

To prevent unnecessary re-renders, consider wrapping the UserListView with useMemo:

- manageUsers = (
+ manageUsers = useMemo(() => (
    <div>
      <UserListView
        users={userListData?.results ?? []}
        onSearch={(username) => updateQuery({ username })}
        searchValue={qParams.username}
        activeTab={activeTab}
        onTabChange={setActiveTab}
      />
      <Pagination totalCount={userListData.count} />
    </div>
+ ), [userListData, qParams.username, activeTab]);

Line range hint 280-285: Add error boundary for facility management operations

Consider implementing an error boundary to gracefully handle failures in facility management operations.

class FacilityErrorBoundary extends React.Component {
  componentDidCatch(error, errorInfo) {
    // Log error to monitoring service
    Notification.Error({
      msg: "An error occurred while managing facilities",
    });
  }
  // ... rest of implementation
}

Wrap the facility management section with this error boundary:

+ <FacilityErrorBoundary>
    <div className="h-full">
      {/* ... existing code ... */}
    </div>
+ </FacilityErrorBoundary>
src/components/Users/UserAdd.tsx (1)

Line range hint 49-55: Consider moving the help URL to configuration

The help documentation URL is hardcoded. Consider moving it to a configuration file or environment variable for better maintainability.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between c0744c5 and 3a02614.

📒 Files selected for processing (3)
  • src/components/Facility/FacilityUsers.tsx (2 hunks)
  • src/components/Users/ManageUsers.tsx (3 hunks)
  • src/components/Users/UserAdd.tsx (3 hunks)
🔇 Additional comments (7)
src/components/Facility/FacilityUsers.tsx (2)

34-38: Remove unnecessary toString() conversion

The request utility will handle string conversion automatically.

- limit: resultsPerPage.toString(),
+ limit: resultsPerPage,

51-67: Clean and efficient implementation!

The component effectively:

  • Displays user count with loading states
  • Integrates search functionality
  • Handles pagination properly
src/components/Users/ManageUsers.tsx (2)

71-71: Fix the district query parameter key

The parameter key should be 'district' instead of 'district_id' to match the API's expected parameter.

- district_id: qParams.district,
+ district: qParams.district,

106-108: Good loading state handling!

Appropriate use of loading component while waiting for data.

src/components/Users/UserAdd.tsx (3)

Line range hint 42-63: Clean and well-structured implementation

The component follows good practices:

  • Uses internationalization for text
  • Provides clear navigation with back button
  • Delegates form handling to a specialized component
  • Includes help documentation link

60-60: Verify age validation implementation

Since Issue #9001 mentions implementing age validation (minimum 15 years), verify that this validation is properly implemented in the UserAddEditForm component.

✅ Verification successful

Age validation is properly implemented

The code shows proper age validation in the UserAddEditForm component with a minimum age requirement of 16 years. This is implemented in the validation logic:

else if (dayjs(formData[field]).isAfter(dayjs().subtract(16, "year"))) {
  errors[field] = t("enter_valid_dob_age");
}
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check for age validation implementation in UserAddEditForm
rg -A 10 "age|birth|dob" src/components/Users/UserAddEditForm.tsx

Length of output: 4048


Line range hint 12-41: Move validateRule to UserAddEditForm component

The comment indicates this is a temporary placement. Since this function is related to form validation, it should be moved to UserAddEditForm to maintain code organization and follow the component's responsibility separation.

Let's verify if this function is already defined in UserAddEditForm:

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Outside diff range and nitpick comments (3)
public/locale/en.json (3)

377-377: Improve avatar-related messages for better clarity and consistency.

The avatar-related messages could be improved for better user experience.

Apply these changes:

- "avatar_updated_success": "Avatar updated successfully",
+ "avatar_updated_success": "Profile picture updated successfully",
- "change_avatar": "Change Avatar",
+ "change_avatar": "Change Profile Picture",
- "change_avatar_note": "JPG, GIF or PNG. 1MB max.",
+ "change_avatar_note": "Accepted formats: JPG, GIF, or PNG. Maximum size: 1MB",
- "edit_avatar": "Edit Avatar",
+ "edit_avatar": "Edit Profile Picture",
- "edit_avatar_note": "Change the avatar of the user",
+ "edit_avatar_note": "Change the user's profile picture",
- "edit_avatar_note_self": "Change your avatar",
+ "edit_avatar_note_self": "Change your profile picture",
- "edit_avatar_permission_error": "You do not have permissions to edit the avatar of this user",
+ "edit_avatar_permission_error": "You do not have permission to change this user's profile picture"

Also applies to: 420-421, 661-663


291-291: Improve facility management messages for better clarity and consistency.

The facility management messages could be enhanced for better user experience.

Apply these changes:

- "facility_linked_success": "Facility linked successfully",
+ "facility_linked_success": "Facility has been linked successfully",
- "home_facility_cleared_success": "Home Facility cleared successfully",
+ "home_facility_cleared_success": "Home facility has been removed successfully",
- "home_facility_updated_error": "Error while updating Home Facility",
+ "home_facility_updated_error": "Failed to update home facility. Please try again.",
- "home_facility_updated_success": "Home Facility updated successfully",
+ "home_facility_updated_success": "Home facility has been updated successfully",
- "replace_home_facility": "Replace Home Facility",
+ "replace_home_facility": "Replace home facility",
- "replace_home_facility_confirm": "Are you sure you want to replace",
+ "replace_home_facility_confirm": "Are you sure you want to replace the current home facility",
- "unlink_facility": "Unlink Facility",
+ "unlink_facility": "Remove facility access",
- "unlink_facility_access": "The user will lose access to the facility",
+ "unlink_facility_access": "Warning: The user will no longer have access to this facility",
- "unlink_facility_error": "Error while unlinking facility. Try again later.",
+ "unlink_facility_error": "Failed to remove facility access. Please try again.",
- "unlink_facility_success": "Facility unlinked successfully",
+ "unlink_facility_success": "Facility access has been removed successfully",
- "unlink_home_facility_error": "Error while unlinking home facility. Try again later.",
+ "unlink_home_facility_error": "Failed to remove home facility. Please try again.",
- "unlink_home_facility_success": "Home Facility cleared successfully"
+ "unlink_home_facility_success": "Home facility has been removed successfully"

Also applies to: 734-734, 823-825, 1240-1242, 1443-1449


303-303: Improve skill management messages for better clarity and consistency.

The skill management messages could be enhanced for better user experience.

Apply these changes:

- "skill_add_error": "Error while adding skill",
+ "skill_add_error": "Failed to add skill. Please try again.",
- "skill_added_successfully": "Skill added successfully",
+ "skill_added_successfully": "Skill has been added successfully",
- "unlink_skill": "Unlink Skill",
+ "unlink_skill": "Remove skill",
- "unlink_skill_access": "The user will not have the skill associated anymore.",
+ "unlink_skill_access": "Warning: This skill will be removed from the user's profile",
- "unlink_skill_error": "Error while unlinking skill. Try again later.",
+ "unlink_skill_error": "Failed to remove skill. Please try again.",
- "unlink_skill_success": "Skill unlinked successfully"
+ "unlink_skill_success": "Skill has been removed successfully"

Also applies to: 1362-1363, 1450-1454

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 3a02614 and 8b462dc.

📒 Files selected for processing (2)
  • public/locale/en.json (39 hunks)
  • src/components/Common/Page.tsx (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/components/Common/Page.tsx
🔇 Additional comments (7)
public/locale/en.json (7)

218-220: LGTM: User management tab labels are clear and consistent.

The tab labels for user management are descriptive and follow a consistent pattern:

  • "Linked Facilities"
  • "User Information"
  • "Linked Skills"

385-385: LGTM: User information sections have clear and consistent messaging.

The messages for basic, contact, and professional information sections are well-structured and maintain consistency in their note patterns:

  • View/update variations for self vs. other users
  • Clear section headings
  • Consistent terminology

Also applies to: 534-537, 1136-1138, 1204-1207


881-881: LGTM: WhatsApp validation message is clear.

The message for WhatsApp number validation is clear and concise.


1160-1160: LGTM: User type selection messages are consistent.

The messages for user type selection maintain consistency.

Also applies to: 1500-1500


1498-1499: LGTM: User qualification messages are clear.

The messages for user qualifications are descriptive and helpful.


942-942: LGTM: User management action messages are consistent.

The messages for user management actions maintain consistency in terminology.

Also applies to: 1494-1494, 1539-1540


1079-1083: 🛠️ Refactor suggestion

Enhance password-related messages for better security and user experience.

Applying the previously suggested password validation message improvements and adding new suggestions for the password reset flow.

Apply these changes:

- "password_length_validation": "Password must be at least 8 characters long",
- "password_lowercase_validation": "Password must contain at least one lowercase letter (a-z)",
- "password_number_validation": "Password must contain at least one number (0-9)",
- "password_uppercase_validation": "Password must contain at least one uppercase letter (A-Z)",
- "password_validation": "Password must contain at least: 8 characters, 1 uppercase letter (A-Z), 1 lowercase letter (a-z), and 1 number (0-9)",
+ "password_length_validation": "Password must be at least 8 characters long",
+ "password_lowercase_validation": "Password must contain at least one lowercase letter (a-z)",
+ "password_number_validation": "Password must contain at least one number (0-9)",
+ "password_uppercase_validation": "Password must contain at least one uppercase letter (A-Z)",
+ "password_validation": "Password must contain at least: 8 characters, 1 uppercase letter (A-Z), 1 lowercase letter (a-z), and 1 number (0-9)",
- "please_confirm_password": "Please confirm your new password.",
+ "please_confirm_password": "Please re-enter your new password to confirm",
- "please_enter_current_password": "Please enter your current password.",
+ "please_enter_current_password": "Please enter your current password for verification",
- "please_enter_new_password": "Please enter your new password.",
+ "please_enter_new_password": "Please enter a new password that meets the requirements",
- "reset_password_note": "Enter user's current password, then create and confirm the new password",
+ "reset_password_note": "To reset the password: 1) Enter current password, 2) Create new password, 3) Confirm new password",
- "reset_password_note_self": "Enter your current password, then create and confirm your new password",
+ "reset_password_note_self": "To reset your password: 1) Enter current password, 2) Create new password, 3) Confirm new password"

Also applies to: 1087-1089, 1145-1145, 1147-1149, 1261-1262

public/locale/en.json Show resolved Hide resolved
@github-actions github-actions bot added merge conflict pull requests with merge conflict and removed merge conflict pull requests with merge conflict labels Dec 9, 2024
Copy link

👋 Hi, @Jacobjeevan,
Conflicts have been detected against the base branch. Please rebase your branch against the base branch.


This message is automatically generated by prince-chrismc/label-merge-conflicts-action so don't hesitate to report issues/improvements there.

@rithviknishad rithviknishad removed needs review merge conflict pull requests with merge conflict labels Dec 10, 2024
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Outside diff range and nitpick comments (7)
src/components/Form/Form.tsx (3)

35-37: LGTM! Consider adding JSDoc comments.

The new props are well-typed and follow naming conventions. Consider adding JSDoc comments to document their purpose and usage.

+/** Reset form to initial values when cancel is clicked */
 resetFormValsOnCancel?: boolean;
+/** Reset form to initial values after successful submission */
 resetFormValsOnSubmit?: boolean;
+/** Hide the cancel button in the form footer */
 hideCancelButton?: boolean;

88-93: LGTM! Consider adding error boundary.

The cancel handler implementation is clean and maintains backward compatibility. Consider wrapping the onCancel callback in a try-catch for better error handling.

 const handleCancel = () => {
   if (props.resetFormValsOnCancel) {
     dispatch({ type: "set_form", form: formVals.current });
   }
-  props.onCancel?.();
+  try {
+    props.onCancel?.();
+  } catch (error) {
+    console.error('Error in form cancel handler:', error);
+    Notification.Error({ msg: "Failed to cancel form" });
+  }
 };

Line range hint 1-156: Consider extracting form reset logic to a custom hook.

The form reset functionality could be abstracted into a custom hook to promote reusability across other form components in the user management system.

Example implementation:

function useFormReset<T extends FormDetails>(
  defaults: T,
  dispatch: (action: any) => void
) {
  const formVals = useRef(defaults);

  useEffect(() => {
    formVals.current = defaults;
  }, [defaults]);

  const resetForm = () => {
    dispatch({ type: "set_form", form: formVals.current });
  };

  return { resetForm };
}
src/components/Users/UserSummary.tsx (1)

49-51: Add explicit return value

The early return statement should explicitly return null for better clarity and type safety.

   if (!userData) {
-    return <></>;
+    return null;
   }
public/locale/en.json (3)

1087-1097: Improve password validation message consistency

The password validation messages should be more consistent in their wording and provide clearer guidance.

-"password_validation": "Password must contain at least: 8 characters, 1 uppercase letter (A-Z), 1 lowercase letter (a-z), and 1 number (0-9)",
+"password_validation": "Password must contain at least: 8 characters, one uppercase letter (A-Z), one lowercase letter (a-z), and one number (0-9)",
-"password_length_validation": "Password must be at least 8 characters long",
+"password_length_validation": "Password must contain at least 8 characters",
-"password_lowercase_validation": "Password must contain at least one lowercase letter (a-z)",
+"password_lowercase_validation": "Password must contain at least one lowercase letter (a-z)",
-"password_uppercase_validation": "Password must contain at least one uppercase letter (A-Z)",
+"password_uppercase_validation": "Password must contain at least one uppercase letter (A-Z)",
-"password_number_validation": "Password must contain at least one number (0-9)",
+"password_number_validation": "Password must contain at least one number (0-9)"

1497-1503: Enhance error messages with specific guidance

Error messages should provide more specific information about what went wrong and how to resolve it.

-"user_add_error": "Error while adding User",
+"user_add_error": "Failed to add user. Please verify the information and try again",
-"user_delete_error": "Error while deleting User",
+"user_delete_error": "Failed to delete user. Please ensure you have the necessary permissions",
-"user_details_update_error": "Error while updating user details",
+"user_details_update_error": "Failed to update user details. Please verify the changes and try again"

601-603: Enhance account deletion confirmation message

The account deletion message should provide more specific information about the consequences.

-"delete_account_note": "Deleting this account will remove all associated data and cannot be undone.",
+"delete_account_note": "Deleting this account will permanently remove all associated data including linked facilities, skills, and user information. This action cannot be undone."
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 8b462dc and 3fa1e76.

📒 Files selected for processing (6)
  • public/locale/en.json (39 hunks)
  • src/Utils/permissions.ts (1 hunks)
  • src/Utils/utils.ts (1 hunks)
  • src/components/Common/Page.tsx (2 hunks)
  • src/components/Form/Form.tsx (4 hunks)
  • src/components/Users/UserSummary.tsx (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/components/Common/Page.tsx
  • src/Utils/utils.ts
🧰 Additional context used
📓 Learnings (2)
src/components/Users/UserSummary.tsx (1)
Learnt from: Jacobjeevan
PR: ohcnetwork/care_fe#9080
File: src/components/Users/UserSummary.tsx:53-71
Timestamp: 2024-11-22T12:04:39.044Z
Learning: In the `UserSummaryTab` component (`src/components/Users/UserSummary.tsx`), when there is an error during user deletion, the delete dialog is intentionally closed to prevent the user from immediately trying to delete the user again.
src/Utils/permissions.ts (1)
Learnt from: Jacobjeevan
PR: ohcnetwork/care_fe#9080
File: src/Utils/permissions.ts:37-50
Timestamp: 2024-11-14T08:07:32.427Z
Learning: In the `showUserPasswordReset` function within `src/Utils/permissions.ts`, both `authUser` and `targetUser` are guaranteed to be provided. Therefore, null or undefined checks for these parameters are unnecessary.
🔇 Additional comments (10)
src/components/Form/Form.tsx (3)

83-84: LGTM! Form reset on successful submission.

The implementation correctly resets the form to initial values only after a successful submission when resetFormValsOnSubmit is true.


138-143: LGTM! Clean implementation of conditional Cancel button.

The conditional rendering and event handling for the Cancel button is well-implemented, maintaining existing styling and accessibility features.


43-43: Consider deps array for formVals ref

The formVals ref stores the initial form values, but it won't update if props.defaults changes. Consider if this is the intended behavior.

If updates to props.defaults should be reflected, consider using useEffect:

+useEffect(() => {
+  formVals.current = props.defaults;
+}, [props.defaults]);

Also applies to: 49-49

src/Utils/permissions.ts (4)

25-37: LGTM! Good security improvements

The changes to prevent self-deletion and maintain proper hierarchy checks are well implemented.


46-56: LGTM! Well-structured permission checks

Both functions implement appropriate permission checks:

  • Avatar editing is properly restricted to self or superuser
  • Permission editing correctly combines superuser access with administrative jurisdiction

39-43: 🛠️ Refactor suggestion

Consider adding hierarchical access control

The current implementation only allows self-reset. Consider adding hierarchical access control similar to the delete functionality to allow administrators to reset passwords of users under their jurisdiction.

 export const showUserPasswordReset = (
   authUser: UserModel,
   targetUser: UserModel,
 ) => {
-  return authUser.username === targetUser.username;
+  // Allow self-reset
+  if (authUser.username === targetUser.username) {
+    return true;
+  }
+
+  // Check if auth user has higher privileges
+  if (USER_TYPES.indexOf(authUser.user_type) <= USER_TYPES.indexOf(targetUser.user_type)) {
+    return false;
+  }
+
+  // Allow admins to reset passwords for users in their jurisdiction
+  return checkIfStateOrDistrictAdminInSameLocation(authUser, targetUser);
 };

Likely invalid or redundant comment.


5-24: 🛠️ Refactor suggestion

Improve type safety and function naming

The helper function could be improved in several ways:

  1. The hasLocation check is redundant as the subsequent checks implicitly handle this
  2. Optional chaining makes the code less type-safe
  3. The function name could be more precise to reflect its purpose
-const checkIfStateOrDistrictAdminInSameLocation = (
+const hasAdministrativeJurisdiction = (
   authUser: UserModel,
   targetUser: UserModel,
 ) => {
-  const hasLocation = Boolean(
-    targetUser.state_object || targetUser.district_object,
-  );

+  if (!targetUser.state_object && !targetUser.district_object) {
+    return false;
+  }

   const isStateAdminOfSameState =
     authUser.user_type === "StateAdmin" &&
-    targetUser.state_object?.id === authUser.state;
+    targetUser.state_object &&
+    targetUser.state_object.id === authUser.state;

   const isDistrictAdminOfSameDistrict =
     authUser.user_type === "DistrictAdmin" &&
-    targetUser.district_object?.id === authUser.district;
+    targetUser.district_object &&
+    targetUser.district_object.id === authUser.district;

-  return (
-    hasLocation && (isStateAdminOfSameState || isDistrictAdminOfSameDistrict)
-  );
+  return isStateAdminOfSameState || isDistrictAdminOfSameDistrict;
 };

Likely invalid or redundant comment.

src/components/Users/UserSummary.tsx (3)

53-71: LGTM! Well-implemented delete handler

The delete handler implementation includes:

  • Proper loading state management
  • Error handling with user feedback
  • Navigation after successful deletion
  • Intentional dialog closure on error to prevent immediate retry

73-82: LGTM! Clean permission management

Well-organized permission checks with descriptive variable names and proper use of utility functions.


134-235: LGTM! Well-structured component layout

The component layout is well-organized with:

  • Clean conditional rendering
  • Consistent use of UserColumns for layout
  • Proper permission-based feature gates

src/components/Users/UserSummary.tsx Show resolved Hide resolved
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Outside diff range and nitpick comments (2)
cypress/e2e/users_spec/UsersCreation.cy.ts (1)

Line range hint 1-199: Add test coverage for new user management requirements.

Based on the PR objectives, the following test scenarios are missing:

  1. Conditional rendering of qualifications for Doctors and Nurses
  2. Password change restrictions for non-admin users
  3. User deletion permissions
  4. Facility user deletion edge cases (is_active flag)

Consider adding these test cases:

it("should only show qualifications for Doctors and Nurses", () => {
  // Test for Doctor role
  userCreationPage.selectUserType("Doctor");
  cy.get("[data-testid=qualification-field]").should("be.visible");
  
  // Test for Nurse role
  userCreationPage.selectUserType("Nurse");
  cy.get("[data-testid=qualification-field]").should("be.visible");
  
  // Test for other roles
  userCreationPage.selectUserType("Staff");
  cy.get("[data-testid=qualification-field]").should("not.exist");
});

it("should restrict password changes to authorized users", () => {
  // Test as non-admin user
  loginPage.loginByRole("staff");
  userProfilePage.visitUserProfile(someOtherUser);
  cy.get("[data-testid=change-password-button]").should("not.exist");
  
  // Test as admin
  loginPage.loginByRole("districtAdmin");
  userProfilePage.visitUserProfile(someOtherUser);
  cy.get("[data-testid=change-password-button]").should("be.visible");
});

it("should handle facility user deletion correctly", () => {
  // Test deletion and verify is_active flag
  loginPage.loginByRole("districtAdmin");
  userPage.deleteUser(facilityUser);
  cy.intercept("DELETE", "/api/v1/users/*").as("deleteUser");
  cy.wait("@deleteUser").then((interception) => {
    expect(interception.request.body).to.have.property("is_active", false);
  });
});
public/locale/en.json (1)

542-545: Consider consolidating similar information notes

The information notes for contact, personal, and professional info sections follow the same pattern but are duplicated. Consider using a template string with placeholders.

Example approach:

+"info_note_template": "View{{edit}} {{user}}'s {{type}} information",
-"contact_info_note": "View or update user's contact information",
-"contact_info_note_self": "View or update your contact information",
+"contact_info_note": "{{info_note_template, edit: ' or update', user: 'user', type: 'contact'}}",
+"contact_info_note_self": "{{info_note_template, edit: ' or update', user: 'your', type: 'contact'}}"

Also applies to: 1144-1146, 1212-1215

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 3fa1e76 and 7359cc1.

📒 Files selected for processing (3)
  • cypress/e2e/users_spec/UsersCreation.cy.ts (2 hunks)
  • cypress/pageobject/Users/UserCreation.ts (1 hunks)
  • public/locale/en.json (39 hunks)
🔇 Additional comments (9)
cypress/e2e/users_spec/UsersCreation.cy.ts (1)

167-167: Selector updates align with new component structure.

The selectors have been updated to:

  1. Include dynamic username (#name-${username}) for better specificity
  2. Use hyphen instead of underscore (#home-facility)

These changes improve selector specificity and maintain consistent naming conventions.

Also applies to: 170-170

cypress/pageobject/Users/UserCreation.ts (1)

49-49: Verify UI button label consistency

The button text change from "Save User" to "Submit" should be consistent with other form submission buttons in the application.

✅ Verification successful

Button text change is consistent with application's form submission patterns

The change from "Save User" to "Submit" aligns with the application's consistent use of "Submit" as the primary action button text across various forms and operations. The codebase shows:

  1. The application uses "Submit" as the default button text in the core implementation:
Cypress.Commands.add("clickSubmitButton", (buttonText = "Submit") => {
  1. "Submit" is used consistently across different form submissions:
  • User management: "Submit" for user creation
  • Patient management: "Submit" for prescriptions, consultations
  • Asset management: "Submit" for updates
  • Login forms: "Submit" for authentication
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for consistency in button labels across the codebase
# Look for other instances of "Save User" or "Submit" buttons

# Search for Save User button text
echo "Searching for 'Save User' button text..."
rg -i "save.?user" --type ts --type tsx

# Search for Submit button text
echo "Searching for 'Submit' button text..."
rg -i "submit.?button" --type ts --type tsx

Length of output: 331


Script:

#!/bin/bash
# Let's try a different approach to search for button patterns in TypeScript files

# Search for button text patterns in TypeScript files
echo "Searching for button text patterns..."
rg -t ts "cy\.(click|get).*Button.*['\"]" -A 1

# Search specifically for clickSubmitButton usage
echo "Searching for clickSubmitButton usage..."
rg -t ts "clickSubmitButton" -A 1

# Search for any button-related text in TypeScript files
echo "Searching for button text patterns..."
rg -t ts "(Save|Submit).*Button" -A 1

Length of output: 58245

public/locale/en.json (7)

226-228: LGTM: User interface tab labels are clear and consistent

The new tab labels for user management are descriptive and follow a consistent pattern.


428-429: LGTM: Avatar management strings are clear and include helpful notes

The avatar-related strings provide clear instructions and size limitations.

Also applies to: 669-671


1087-1097: Enhance password validation messages

The password validation messages could be improved for better clarity and consistency.

Also applies to: 1153-1156


831-833: LGTM: Facility management messages are comprehensive

The strings cover all facility management scenarios including success/error states and confirmation messages.

Also applies to: 1248-1250, 1450-1456


1457-1461: LGTM: Skill management messages follow facility management pattern

The skill management messages maintain consistency with facility management messages.


1497-1503: Enhance error messages with more specific information

The error messages should provide more specific information about what went wrong.


1509-1512: Improve username validation messages for better security

The username validation messages should be more secure by not revealing specific validation rules.

cypress/e2e/users_spec/UsersCreation.cy.ts Show resolved Hide resolved
@khavinshankar khavinshankar merged commit 1f173e8 into ohcnetwork:develop Dec 11, 2024
24 checks passed
Copy link

@Jacobjeevan 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
None yet
7 participants