Skip to content

Conversation

pitabash-eGov
Copy link
Contributor

@pitabash-eGov pitabash-eGov commented Sep 8, 2025

Choose the appropriate template for your PR:

Feature/Bugfix Request

JIRA ID

Module

Description

Summary by CodeRabbit

  • New Features

    • Attendee inbox: boundary selector, search/enroll/assign PopUps, edit-attendee modal, attendee-inbox and edit-register pages, user-assignment widget, HRMS module card.
  • Enhancements

    • Microplan list: per-row multi-actions (download, draft, edit, freeze, view) with validations, toasts, gated actions, wrapped long names and consistent "N/A" fallbacks; improved attendance edit table with de-enroll flow.
  • Integration

    • Payments and HRMS wired into startup; new attendee search/enroll/de-enroll flows/hooks exposed.
  • Style

    • Loader, table, pagination and layout refinements; minor UI formatting tweaks.

@pitabash-eGov pitabash-eGov self-assigned this Sep 8, 2025
@pitabash-eGov pitabash-eGov requested a review from a team as a code owner September 8, 2025 04:34
Copy link
Contributor

coderabbitai bot commented Sep 8, 2025

Important

Review skipped

Review was skipped due to path filters

⛔ Files ignored due to path filters (1)
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/package.json is excluded by !**/*.json

CodeRabbit blocks several paths by default. You can override this behavior by explicitly including those paths in the path filters. For example, including **/dist/** will override the default block on the dist directory, by removing the pattern from both the lists.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

📝 Walkthrough

Walkthrough

Adds attendance enroll/de‑enroll/search clients and hooks, payment + HRMS UI components/pages (inbox, edit register, popups, boundary selection), new proxy routes and URLs, example UI customizations, and extensive campaign‑manager conditional navigation/display editor enhancements.

Changes

Cohort / File(s) Summary
Example customizations
health/micro-ui/web/micro-ui-internals/example/src/UICustomizations.js
Exported AttendeeSearchInboxConfig; built data.body.Individual in preProcess; extended MicroplanSearchConfig with tightened preProcess, per-row gating, ACTIONS handlers (download/edit/draft/freeze/view) and render tweaks.
Bootstrap & proxy
health/micro-ui/web/micro-ui-internals/example/src/index.js, health/micro-ui/web/micro-ui-internals/example/src/setupProxy.js
Replaced DSS init with initPaymentComponents() (DSS left commented); added proxy routes for /health-attendance/attendee/v1/_delete, /health-attendance/attendee/v1/_create, and /health-hrms/employees/_search.
HRMS module & components
.../modules/health-hrms/src/Module.js, .../components/HRMSCard.js, .../pageComponents/UserAssigment.js, .../pageComponents/SearchUserToReport.js, .../pageComponents/SelectableList.js, .../components/config/createEmployeeConfig.js, .../pages/employee/*
Registered HRMS components (HRMSCard, UserAssignment, SearchUserToReport, SelectableList); injected UserAssignment into create-employee form (URL-gated); added reportingTo to payload; adjusted MDMS flags and standardized loader presentation.
Attendee clients & HRMS wrappers
.../services/hrms/AttendeeService.js, .../services/hrms/SearchUser.js, .../services/urls.js (hrms)
Added AttendeeService client (search, delete) and HRMS AttendanceService wrappers (boundary/register search, de‑enroll, searchIndividual); added Urls.attendee entries.
Payments module registration
.../modules/health-payments/src/Module.js, .../services/PaymentsInitialization.js
Registered AttendeeBoundaryComponent in payments module; adjusted loading wrapper/presentation and added commented hierarchy scaffolding.
Payments UI components
health-payments/src/components/EditAttendanceManagementTable.js, .../SearchUserPopUp.js, .../SelectableList.js, .../editAttendeesPopUp.js, .../SearchAttendeeBoundary.js, .../HierachySelection.js, .../table_inbox_custom_style.js, .../PaymentsCard.js
Added components: EditAttendanceManagementTable (de‑enroll action), SearchUserPopUp (search & enroll), SelectableList, EditAttendeePopUp, AttendeeBoundaryComponent, HierarchySelection, and editAttendeetableCustomStyle; minor PaymentsCard formatting.
Pages, routing & inbox behavior
health-payments/src/pages/employee/index.js, .../ViewAttendance.js, .../EditRegister.js, .../AttendeeSearchAssign.js, .../attendance_inbox/table_inbox.js, .../project_selection.js
Added routes/pages /attendee-inbox and /edit-register; new EditRegister and InboxAttendeesSearch pages; conditional navigation (edit vs view) using register endDate; de‑enroll/edit popup scaffolds; updated ActionBar usage.
Payments hooks
health-payments/src/hooks/index.js, .../hooks/attendance/create_attendee_register.js, .../delete_attendee_register.js, .../search_individual.js
Added React Query mutation hooks: useCreateAttendeeFromRegister, useDeleteAttendeeFromRegister, useSearchIndividualForRegister; exported via payments hooks index.
Payments services & URLs
.../services/attendance/attendanceService.js, .../attendee_service/attendeeService.js, .../services/urls.js (payments)
Extended AttendanceService with deEnrollment_attendee and searchIndividual; added AttendeeService client (search/create/delete); introduced central payments Urls module.
Utilities & constants
health-payments/src/utils/constants.js, .../utils/update_attendance_summary.js
Added edit‑attendee pagination defaults and useAttendanceSummary hook to merge attendance registers with individual profiles; returns summary, loading and raw data.
HRMS presentation & pages
.../health-hrms/src/pages/*, .../pageComponents/*
Standardized loader presentation to a centered full-viewport wrapper across multiple HRMS pages; minor UI spacing and breadcrumb tweaks.
Campaign‑manager conditional editors & helpers
.../campaign-manager/src/pages/..., .../utils/...
Large additions/refactors: NavigationLogicWrapper, DependentFieldsWrapper, display/navigation editors, useCustomT behavior changes, flattening helpers, template helper updates, and several wrapper signature updates for app-configuration flows.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor User
  participant Table as EditAttendanceManagementTable
  participant Confirm as AlertPopUp
  participant HookDel as useDeleteAttendeeFromRegister
  participant APIdel as AttendeeService.delete
  participant Toast as UI_Toast

  User->>Table: Click "Disable User"
  Table->>Confirm: Open confirmation
  User->>Confirm: Confirm
  Confirm->>Table: onConfirm
  Table->>HookDel: mutate(deEnrollPayload)
  HookDel->>APIdel: POST /health-attendance/attendee/v1/_delete
  APIdel-->>HookDel: Success / Error
  alt Success
    HookDel-->>Table: onSuccess
    Table->>Toast: show success
    Table->>Table: refresh list callback
  else Error
    HookDel-->>Table: onError
    Table->>Toast: show error
  end
Loading
sequenceDiagram
  autonumber
  actor User
  participant PopUp as SearchUserPopUp
  participant HookSearch as useSearchIndividualForRegister
  participant APIsearch as AttendeeService.search
  participant HookCreate as useCreateAttendeeFromRegister
  participant APIcreate as AttendeeService.create
  participant Toast as UI_Toast

  User->>PopUp: Enter name + Submit
  PopUp->>HookSearch: mutate(searchParams)
  HookSearch->>APIsearch: POST /health-individual/v1/_search
  APIsearch-->>HookSearch: Individuals
  HookSearch-->>PopUp: results
  User->>PopUp: Select individual & Enroll
  PopUp->>HookCreate: mutate(enrollPayload)
  HookCreate->>APIcreate: POST /health-attendance/attendee/v1/_create
  APIcreate-->>HookCreate: Success / Error
  alt Success
    HookCreate-->>PopUp: onSuccess
    PopUp->>Toast: show success
    PopUp->>PopUp: clear/close
  else Error
    HookCreate-->>PopUp: onError
    PopUp->>Toast: show error
  end
Loading
sequenceDiagram
  autonumber
  actor User
  participant Inbox as AttendanceInboxTable
  participant Session as Digit.SessionStorage
  participant Router as History.push

  User->>Inbox: Click Register ID
  Inbox->>Session: Read paymentInbox.selectedProject.endDate
  alt endDate exists
    Inbox->>Inbox: compare Date.now() to endDate
    alt expired
      Inbox->>Router: navigate to /view-attendance?registerNumber&boundaryCode
    else active
      Inbox->>Router: navigate to /edit-register?registerNumber&boundaryCode&registerId
    end
  else missing endDate
    Inbox->>Router: navigate to /view-attendance (fallback)
  end
Loading

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~120 minutes

Poem

I hop through dropdowns, toast, and queue,
I fetch a user, enroll one or two 🥕
Pop‑ups bustle, boundaries bind,
Tables shuffle, routes decide,
A carrot‑coded patch — rabbit's small pride.

Pre-merge checks and finishing touches

❌ Failed checks (2 warnings, 1 inconclusive)
Check name Status Explanation Resolution
Description Check ⚠️ Warning The pull request description includes only the placeholder template headings for JIRA ID, module, and description without any actual content, so it fails to communicate the context, scope, and purpose of the changes. Reviewers have no information about what is being added, modified, or fixed, making it impossible to understand the pull request’s intent. Please complete the PR description by providing the actual JIRA ID, specifying the affected module, and writing a clear, detailed description of the feature or bugfix being implemented, in accordance with the repository’s template.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
Title Check ❓ Inconclusive “Hcmpre 3049” merely references a ticket number and does not describe any of the functionality or fixes introduced in the pull request, making the title too generic and uninformative. Reviewers scanning the repository history cannot infer the scope or intent of the changes from this title. A concise, descriptive title would improve clarity and context. Please revise the title to succinctly summarize the primary change or feature being implemented so that team members can quickly grasp the pull request’s intent without inspecting the diff.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (15)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/attendance_inbox/table_inbox.js (2)

71-74: Centralize navigation and harden date handling (ms/sec, ISO) + URL-encode params

Prevents ms/sec bugs, unifies logic for both link and row-click, and avoids duplicated route strings.

@@
   const onCommentLogClose = () => {
     setCommentLogs(false);
   };
 
+  // Centralized navigation based on register end date
+  const navigateForRow = (row, e) => {
+    e?.stopPropagation?.();
+    e?.preventDefault?.();
+    const existingPaymentInbox = Digit.SessionStorage.get("paymentInbox");
+    const rawEnd =
+      selectedProject?.endDate ?? existingPaymentInbox?.selectedProject?.endDate;
+    let endMs;
+    if (typeof rawEnd === "number") {
+      endMs = rawEnd < 1e12 ? rawEnd * 1000 : rawEnd; // support epoch seconds
+    } else if (rawEnd instanceof Date) {
+      endMs = rawEnd.getTime();
+    } else if (rawEnd) {
+      const parsed = Date.parse(rawEnd); // support ISO strings
+      endMs = Number.isNaN(parsed) ? undefined : parsed;
+    }
+
+    const base = `/${window?.contextPath}/employee/payments`;
+    const registerNumber = encodeURIComponent(row?.id ?? "");
+    const boundaryCode = encodeURIComponent(row?.boundary ?? "");
+
+    // Allow edit until and including end date; otherwise view-only
+    if (endMs && Date.now() <= endMs && row?.registerId) {
+      history.push(
+        `${base}/edit-register?registerNumber=${registerNumber}&boundaryCode=${boundaryCode}&registerId=${encodeURIComponent(
+          row.registerId
+        )}`
+      );
+    } else {
+      history.push(
+        `${base}/view-attendance?registerNumber=${registerNumber}&boundaryCode=${boundaryCode}`
+      );
+    }
+  };

194-198: Align row-click behavior with link behavior to avoid inconsistent UX

Use the same gating function for row clicks.

   const handleRowClick = (row) => {
-    history.push(
-      `/${window?.contextPath}/employee/payments/view-attendance?registerNumber=${row?.id}&boundaryCode=${row?.boundary}`
-    )
+    navigateForRow(row);
   };
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/pages/employee/project_selection.js (7)

34-41: Potential crash when boundaryHierarchyOrder is undefined; ensure AGGREGATION_LEVEL_OPTIONS is always an array

AGGREGATION_LEVEL_OPTIONS can become undefined, but later code calls .find/.filter on it. Provide a safe fallback and robust max-order handling.

-const AGGREGATION_LEVEL_OPTIONS = boundaryHierarchyOrder
-    ?.filter(item => item.order <= boundaryHierarchyOrder?.find(d => d.code === lowestLevelBoundaryType)?.order)
-    ?.map(b => ({
-        name: `HCM_AM_${b?.code}_LEVEL`,
-        code: b?.code,
-        order: b?.order,
-    }));
+const maxOrder =
+  boundaryHierarchyOrder?.find((d) => d.code === lowestLevelBoundaryType)?.order;
+const source = Array.isArray(boundaryHierarchyOrder) ? boundaryHierarchyOrder : [];
+const AGGREGATION_LEVEL_OPTIONS = source
+  .filter((item) => (maxOrder == null ? true : item.order <= maxOrder))
+  .map((b) => ({
+    name: `HCM_AM_${b?.code}_LEVEL`,
+    code: b?.code,
+    order: b?.order,
+  }));

43-55: Falsy check on boundaryTypeOrder breaks when order is 0; use nullish check

If order can be 0, current truthy check falls back incorrectly to all options.

-const boundaryTypeOrder = AGGREGATION_LEVEL_OPTIONS.find(option => option.code === selectedProject?.address?.boundaryType)?.order;
-
-if (boundaryTypeOrder) {
+const boundaryTypeOrder = AGGREGATION_LEVEL_OPTIONS.find(
+  (option) => option.code === selectedProject?.address?.boundaryType
+)?.order;
+
+if (boundaryTypeOrder != null) {
   setFilteredAggregationOptions(AGGREGATION_LEVEL_OPTIONS.filter(option => option.order >= boundaryTypeOrder));
 } else {
   setFilteredAggregationOptions(AGGREGATION_LEVEL_OPTIONS);
 }

58-64: Don’t overwrite a previously selected project on mount

Only default to the first project if there’s no prior selection.

-const projectData = Digit?.SessionStorage.get("staffProjects") || [];
-setProject(projectData);
-handleProjectSelect(projectData?.[0]); // Default to the first project
+const projectData = Digit?.SessionStorage.get("staffProjects") || [];
+setProject(projectData);
+if (!selectedProject && projectData?.length) {
+  handleProjectSelect(projectData[0]); // Default to the first project
+}

73-81: Compare aggregation level by identity key, not object reference

Object reference inequality will always clear boundary even when the same level is re-selected. Compare by code.

- if (value !== Digit.SessionStorage.get("selectedLevel")) {
+ if (value?.code !== Digit.SessionStorage.get("selectedLevel")?.code) {
    Digit.SessionStorage.del("selectedBoundaryCode");
    Digit.SessionStorage.del("boundary");
    Digit.SessionStorage.del("selectedValues");
  }

24-31: Harden SessionStorage access; use optional chaining consistently

Mixing Digit? and Digit can cause runtime errors in non-standard boot paths. Be consistent and safe.

-const [selectedProject, setSelectedProject] = useState(() => Digit.SessionStorage.get("selectedProject") || null);
-const [selectedLevel, setSelectedLevel] = useState(() => Digit.SessionStorage.get("selectedLevel") || null);
-const boundaryHierarchyOrder = Digit.SessionStorage.get("boundaryHierarchyOrder");
-const lowestLevelBoundaryType = Digit.SessionStorage.get("paymentsConfig")?.lowestLevelBoundary || "DISTRICT";
+const [selectedProject, setSelectedProject] = useState(() => Digit?.SessionStorage.get("selectedProject") || null);
+const [selectedLevel, setSelectedLevel] = useState(() => Digit?.SessionStorage.get("selectedLevel") || null);
+const boundaryHierarchyOrder = Digit?.SessionStorage.get("boundaryHierarchyOrder");
+const lowestLevelBoundaryType = Digit?.SessionStorage.get("paymentsConfig")?.lowestLevelBoundary || "DISTRICT";

136-146: Drop redundant braces around wrapper div

Reduces noise; no functional change.

-                            {<div className="label-text">
+                            <div className="label-text">
                                 <Dropdown
                                   t={t}
                                   option={filteredAggregationOptions}
                                   name={"code"}
                                   optionKey={"name"}
                                   selected={selectedLevel}
                                   select={handleAggregationLevelChange}
                                 />
-                            </div>}
+                            </div>

150-171: Fix stray comma rendering and unnecessary braces around ActionBar

A literal comma after the first Button will render in the UI. Also, wrapping in braces is unnecessary.

-            {<ActionBar className="mc_back">
+            <ActionBar className="mc_back">
                
                     <Button
                         icon="ArrowBack"
                         label={t("HCM_AM_BACK_LABEL")}
                         onClick={() => history.push(`/${window.contextPath}/employee`)}
                         style={{ marginLeft: "2.5rem", minWidth: "14rem" }}
                         type="button"
                         variation="secondary"
-                    />,
+                    />
                     <Button
                         icon="ArrowForward"
                         isSuffix
                         label={t("HCM_AM_NEXT_LABEL")}
                         onClick={handleNextClick}
                         style={{ minWidth: "14rem" }}
                         type="button"
                         variation="primary"
                     />
-                
-            </ActionBar>}
+            </ActionBar>
health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/services/service.js (1)

69-76: Avoid persisting literal "undefined" for reportingTo
In service.js:

  • In the createdAssignments payload (around line 73), replace
    - reportingTo: data?.UserAssignment?.code || "undefined"
    + ...(data?.UserAssignment?.code && { reportingTo: data.UserAssignment.code })
  • In formPayloadToUpdateUser (export at ~line 124), add
    assignment.reportingTo = data?.UserAssignment?.code ?? assignment.reportingTo;
  • In editDefaultUserValue (export at ~line 198), prefill:
    UserAssignment: data?.[0]?.assignments?.[0]?.reportingTo
      ? { code: data[0].assignments[0].reportingTo }
      : null,
health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/pages/employee/createEmployee.js (1)

360-387: Ensure UserAssignment is part of submit gating

With reportingTo added to the payload, include formData?.UserAssignment?.code in the readiness check to prevent sending incomplete data.

Add outside this hunk (in the same function):

// In the big if-condition that computes canSubmit:
&& formData?.UserAssignment?.code
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/pages/employee/index.js (1)

17-58: Fix undefined variable ‘location’ passed to ProjectBreadCrumb.

App passes location but it’s not defined in this scope; this will throw. Let ProjectBreadCrumb derive location via useLocation() and remove the prop.

-const ProjectBreadCrumb = ({ location }) => {
+const ProjectBreadCrumb = () => {
   const { t } = useTranslation();
 
-  const local = useLocation();
+  const local = useLocation();
   const { fromCampaignSupervisor } = local?.state || false;
 
   const crumbs = [
@@
-      show:
-        Digit.Utils.locale.getTransformedLocale(location.pathname.split("/").pop()) === "REGISTERS_INBOX" || ((Digit.Utils.locale.getTransformedLocale(location.pathname.split("/").pop()) === "VIEW_ATTENDANCE" ||
-          Digit.Utils.locale.getTransformedLocale(location.pathname.split("/").pop()) === "EDIT_ATTENDANCE") && !fromCampaignSupervisor)
+      show:
+        Digit.Utils.locale.getTransformedLocale(local.pathname.split("/").pop()) === "REGISTERS_INBOX" || ((Digit.Utils.locale.getTransformedLocale(local.pathname.split("/").pop()) === "VIEW_ATTENDANCE" ||
+          Digit.Utils.locale.getTransformedLocale(local.pathname.split("/").pop()) === "EDIT_ATTENDANCE") && !fromCampaignSupervisor)
@@
-      show:
-        Digit.Utils.locale.getTransformedLocale(location.pathname.split("/").pop()) === "GENERATE_BILL" || ((Digit.Utils.locale.getTransformedLocale(location.pathname.split("/").pop()) === "VIEW_ATTENDANCE" ||
-          Digit.Utils.locale.getTransformedLocale(location.pathname.split("/").pop()) === "EDIT_ATTENDANCE") && fromCampaignSupervisor)
+      show:
+        Digit.Utils.locale.getTransformedLocale(local.pathname.split("/").pop()) === "GENERATE_BILL" || ((Digit.Utils.locale.getTransformedLocale(local.pathname.split("/").pop()) === "VIEW_ATTENDANCE" ||
+          Digit.Utils.locale.getTransformedLocale(local.pathname.split("/").pop()) === "EDIT_ATTENDANCE") && fromCampaignSupervisor)
@@
-      show:
-        Digit.Utils.locale.getTransformedLocale(location.pathname.split("/").pop()) === "VIEW_ATTENDANCE" ||
-        Digit.Utils.locale.getTransformedLocale(location.pathname.split("/").pop()) === "EDIT_ATTENDANCE" ||
-        Digit.Utils.locale.getTransformedLocale(location.pathname.split("/").pop()) === "EDIT_REGISTER"
+      show:
+        Digit.Utils.locale.getTransformedLocale(local.pathname.split("/").pop()) === "VIEW_ATTENDANCE" ||
+        Digit.Utils.locale.getTransformedLocale(local.pathname.split("/").pop()) === "EDIT_ATTENDANCE" ||
+        Digit.Utils.locale.getTransformedLocale(local.pathname.split("/").pop()) === "EDIT_REGISTER"
@@
-      content: t(`HCM_AM_BREADCRUMBS_${Digit.Utils.locale.getTransformedLocale(location.pathname.split("/").pop())}`),
+      content: t(`HCM_AM_BREADCRUMBS_${Digit.Utils.locale.getTransformedLocale(local.pathname.split("/").pop())}`),
@@
-          <ProjectBreadCrumb location={location} />
+          <ProjectBreadCrumb />

Also applies to: 66-70

health/micro-ui/web/micro-ui-internals/example/src/UICustomizations.js (3)

54-60: Comment contradicts implementation: returns milliseconds, not seconds

The function returns getTime() (ms). Update the comment to avoid misuse.

-  // Convert the date to epoch time (seconds)
+  // Convert the date to epoch time (milliseconds)
   return Math.floor(date.getTime());

2223-2236: Duplicate getCustomActionLabel keys

getCustomActionLabel is defined twice in several configs; later definitions shadow earlier ones. Clean up duplicates.

Remove the first occurrence and keep a single getCustomActionLabel per config.

Also applies to: 2298-2311, 2374-2387, 2449-2462, 2524-2537, 2598-2611


1587-1641: PGR preProcess: ensure consistent clearing of filters

Good cleanup overall. Minor nits:

  • Coalesce localityArray with a default empty array;
  • Avoid leaving complaintType as undefined.

No diff required; optional tighten-ups.

Also applies to: 1624-1630

📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f6e943b and 4884c43.

⛔ Files ignored due to path filters (2)
  • health/micro-ui/web/micro-ui-internals/example/package.json is excluded by !**/*.json
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/package.json is excluded by !**/*.json
📒 Files selected for processing (37)
  • health/micro-ui/web/micro-ui-internals/example/src/UICustomizations.js (24 hunks)
  • health/micro-ui/web/micro-ui-internals/example/src/index.js (2 hunks)
  • health/micro-ui/web/micro-ui-internals/example/src/setupProxy.js (1 hunks)
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/Module.js (2 hunks)
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/components/config/createEmployeeConfig.js (1 hunks)
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/components/pageComponents/UserAssigment.js (1 hunks)
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/pages/employee/HierarchySelection.js (2 hunks)
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/pages/employee/createEmployee.js (2 hunks)
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/services/service.js (5 hunks)
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/services/urls.js (1 hunks)
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/Module.js (5 hunks)
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/BoundaryComponent.js (1 hunks)
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/EditAttendanceManagementTable.js (1 hunks)
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/HierachySelection.js (1 hunks)
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/PaymentsCard.js (1 hunks)
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/SearchAttendeeBoundary.js (1 hunks)
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/SearchUserPopUp.js (1 hunks)
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/SelectableList.js (1 hunks)
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/attendance_inbox/table_inbox.js (1 hunks)
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/editAttendeesPopUp.js (1 hunks)
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/table_inbox_custom_style.js (1 hunks)
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/config/AttendeeInboxConfig.js (1 hunks)
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/hooks/attendance/create_attendee_register.js (1 hunks)
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/hooks/attendance/delete_attendee_register.js (1 hunks)
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/hooks/attendance/search_individual.js (1 hunks)
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/hooks/index.js (1 hunks)
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/pages/employee/AttendeeSearchAssign.js (1 hunks)
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/pages/employee/EditRegister.js (1 hunks)
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/pages/employee/ViewAttendance.js (5 hunks)
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/pages/employee/index.js (3 hunks)
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/pages/employee/project_selection.js (6 hunks)
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/services/PaymentsInitialization.js (1 hunks)
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/services/attendance/attendanceService.js (1 hunks)
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/services/attendance/attendee_service/attendeeService.js (1 hunks)
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/services/urls.js (1 hunks)
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/utils/constants.js (1 hunks)
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/utils/update_attendance_summary.js (1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.js

⚙️ CodeRabbit configuration file

check

Files:

  • health/micro-ui/web/micro-ui-internals/example/src/setupProxy.js
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/PaymentsCard.js
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/SelectableList.js
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/BoundaryComponent.js
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/hooks/attendance/search_individual.js
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/hooks/attendance/create_attendee_register.js
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/services/attendance/attendee_service/attendeeService.js
  • health/micro-ui/web/micro-ui-internals/example/src/index.js
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/SearchAttendeeBoundary.js
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/services/PaymentsInitialization.js
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/utils/constants.js
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/EditAttendanceManagementTable.js
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/config/AttendeeInboxConfig.js
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/table_inbox_custom_style.js
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/hooks/attendance/delete_attendee_register.js
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/pages/employee/index.js
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/pages/employee/createEmployee.js
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/pages/employee/AttendeeSearchAssign.js
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/services/urls.js
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/attendance_inbox/table_inbox.js
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/components/config/createEmployeeConfig.js
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/pages/employee/ViewAttendance.js
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/hooks/index.js
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/HierachySelection.js
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/services/urls.js
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/services/attendance/attendanceService.js
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/SearchUserPopUp.js
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/pages/employee/EditRegister.js
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/editAttendeesPopUp.js
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/Module.js
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/pages/employee/HierarchySelection.js
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/Module.js
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/services/service.js
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/utils/update_attendance_summary.js
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/components/pageComponents/UserAssigment.js
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/pages/employee/project_selection.js
  • health/micro-ui/web/micro-ui-internals/example/src/UICustomizations.js
🧠 Learnings (10)
📚 Learning: 2024-11-28T11:34:27.480Z
Learnt from: rachana-egov
PR: egovernments/DIGIT-Frontend#1925
File: health/micro-ui/web/micro-ui-internals/packages/modules/microplan/src/components/UserUpload.js:267-269
Timestamp: 2024-11-28T11:34:27.480Z
Learning: In the `downloadTemplate` function of `health/micro-ui/web/micro-ui-internals/packages/modules/microplan/src/components/UserUpload.js`, the scenario where `state?.hierarchyType` is undefined will not occur.

Applied to files:

  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/BoundaryComponent.js
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/services/PaymentsInitialization.js
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/HierachySelection.js
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/pages/employee/HierarchySelection.js
📚 Learning: 2025-07-15T04:58:30.634Z
Learnt from: Hari-egov
PR: egovernments/DIGIT-Frontend#2788
File: micro-ui/web/micro-ui-internals/packages/modules/hrms/src/components/pageComponents/jurisdiction.js:26-26
Timestamp: 2025-07-15T04:58:30.634Z
Learning: In the HRMS module (micro-ui/web/micro-ui-internals/packages/modules/hrms/src/components/pageComponents/jurisdiction.js), the team has moved away from using MDMS hooks for boundary data fetching and now uses direct API calls to the boundary service endpoint `/boundary-service/boundary-relationships/_search` instead of the `useHrmsMDMS` hook with "FetchBoundaries" parameter.

Applied to files:

  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/BoundaryComponent.js
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/config/AttendeeInboxConfig.js
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/Module.js
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/Module.js
📚 Learning: 2024-06-10T19:25:42.992Z
Learnt from: siddhant-nawale-egov
PR: egovernments/DIGIT-Frontend#698
File: micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanPreview.js:1-1
Timestamp: 2024-06-10T19:25:42.992Z
Learning: The imports in `MicroplanPreview.js` are from different libraries: `egovernments/digit-ui-components` and `egovernments/digit-ui-react-components`.

Applied to files:

  • health/micro-ui/web/micro-ui-internals/example/src/index.js
  • health/micro-ui/web/micro-ui-internals/example/src/UICustomizations.js
📚 Learning: 2025-03-25T10:47:10.916Z
Learnt from: Tulika-eGov
PR: egovernments/DIGIT-Frontend#2288
File: micro-ui/web/micro-ui-internals/packages/modules/core/src/pages/employee/Landing/LandingComponent.js:33-33
Timestamp: 2025-03-25T10:47:10.916Z
Learning: In DIGIT-Frontend, window.contextPath is dynamically determined and cannot be given a static fallback value like 'digit-ui'. The application relies on this dynamic context path for proper routing.

Applied to files:

  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/services/PaymentsInitialization.js
📚 Learning: 2024-11-07T11:02:33.520Z
Learnt from: rachana-egov
PR: egovernments/DIGIT-Frontend#1770
File: health/micro-ui/web/micro-ui-internals/packages/modules/microplan/src/pages/employee/viewVillage.js:320-322
Timestamp: 2024-11-07T11:02:33.520Z
Learning: In `health/micro-ui/web/micro-ui-internals/packages/modules/microplan/src/pages/employee/viewVillage.js`, the `data?.additionalFields` object is guaranteed to be defined, so checking for its existence before accessing its keys is unnecessary.

Applied to files:

  • health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/pages/employee/createEmployee.js
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/components/config/createEmployeeConfig.js
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/pages/employee/HierarchySelection.js
📚 Learning: 2025-02-05T10:01:29.668Z
Learnt from: Tulika-eGov
PR: egovernments/DIGIT-Frontend#2188
File: micro-ui/web/micro-ui-internals/packages/modules/core/src/pages/employee/Login/login.js:72-78
Timestamp: 2025-02-05T10:01:29.668Z
Learning: In the employee login form, defaultValues are dynamically generated from config[0].body based on populators.defaultValue, so spreading the entire defaultValues object is required rather than cherry-picking specific fields.

Applied to files:

  • health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/pages/employee/createEmployee.js
📚 Learning: 2025-06-27T05:52:33.156Z
Learnt from: Hari-egov
PR: egovernments/DIGIT-Frontend#2644
File: micro-ui/web/micro-ui-internals/packages/modules/core/src/components/PrivacyComponent.js:0-0
Timestamp: 2025-06-27T05:52:33.156Z
Learning: The PrivacyComponent in `micro-ui/web/micro-ui-internals/packages/modules/core/src/components/PrivacyComponent.js` is mostly used in login and signup pages, especially in formcomposer where the UI is stable, making layout changes less likely to cause regressions.

Applied to files:

  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/SearchUserPopUp.js
📚 Learning: 2024-06-10T19:25:42.992Z
Learnt from: siddhant-nawale-egov
PR: egovernments/DIGIT-Frontend#0
File: :0-0
Timestamp: 2024-06-10T19:25:42.992Z
Learning: The Button component from `egovernments/digit-ui-components` has compatibility issues with the ActionBar, leading to the preference for using the Button from `egovernments/digit-ui-react-components` in certain scenarios.

Applied to files:

  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/pages/employee/project_selection.js
📚 Learning: 2024-06-10T19:25:42.992Z
Learnt from: siddhant-nawale-egov
PR: egovernments/DIGIT-Frontend#0
File: :0-0
Timestamp: 2024-06-10T19:25:42.992Z
Learning: The `Toast` component's styling is managed internally within the component, ensuring consistency and adaptability across different contexts without the need for additional external styling.

Applied to files:

  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/pages/employee/project_selection.js
📚 Learning: 2024-11-07T07:17:27.636Z
Learnt from: jagankumar-egov
PR: egovernments/DIGIT-Frontend#1763
File: health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/MyCampaign.js:65-75
Timestamp: 2024-11-07T07:17:27.636Z
Learning: In `MyCampaign.js`, when suggesting code improvements for the `onClickRow` function, keep suggestions simple and avoid unnecessary complexity.

Applied to files:

  • health/micro-ui/web/micro-ui-internals/example/src/UICustomizations.js
🧬 Code graph analysis (25)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/SelectableList.js (1)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/SearchUserPopUp.js (1)
  • onSelect (71-75)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/BoundaryComponent.js (3)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/Module.js (1)
  • hierarchyType (21-21)
health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/services/urls.js (1)
  • hierarchyType (6-6)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/services/PaymentsInitialization.js (1)
  • hierarchyType (26-26)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/hooks/attendance/search_individual.js (2)
health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/hooks/useUpdateAppConfigForFeatures.js (1)
  • useMutation (151-155)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/services/attendance/attendanceService.js (2)
  • AttendanceService (4-108)
  • AttendanceService (4-108)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/hooks/attendance/create_attendee_register.js (1)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/services/attendance/attendanceService.js (2)
  • AttendanceService (4-108)
  • AttendanceService (4-108)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/services/attendance/attendee_service/attendeeService.js (1)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/services/urls.js (1)
  • Urls (9-55)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/SearchAttendeeBoundary.js (4)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/pages/employee/AttendeeSearchAssign.js (2)
  • Digit (9-9)
  • config (31-31)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/pages/employee/project_selection.js (2)
  • selectedProject (24-24)
  • lowestLevelBoundaryType (31-31)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/Module.js (1)
  • hierarchyType (21-21)
micro-ui/web/micro-ui-internals/packages/react-components/src/atoms/Dropdown.js (1)
  • Dropdown (94-281)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/services/PaymentsInitialization.js (3)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/Module.js (1)
  • hierarchyType (21-21)
health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/services/urls.js (1)
  • hierarchyType (6-6)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/BoundaryComponent.js (1)
  • hierarchyType (16-16)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/EditAttendanceManagementTable.js (3)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/utils/constants.js (4)
  • defaultRowsPerPageForEditAttendee (19-19)
  • defaultRowsPerPageForEditAttendee (19-19)
  • defaultPaginationValuesForEditAttendee (22-22)
  • defaultPaginationValuesForEditAttendee (22-22)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/table_inbox_custom_style.js (2)
  • editAttendeetableCustomStyle (227-334)
  • editAttendeetableCustomStyle (227-334)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/alertPopUp.js (1)
  • AlertPopUp (19-57)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/hooks/attendance/delete_attendee_register.js (2)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/pages/employee/ViewAttendance.js (2)
  • data (47-47)
  • tenantId (34-34)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/services/attendance/attendanceService.js (2)
  • AttendanceService (4-108)
  • AttendanceService (4-108)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/pages/employee/index.js (2)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/pages/employee/AttendeeSearchAssign.js (2)
  • Digit (9-9)
  • InboxAttendeesSearch (7-64)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/pages/employee/EditRegister.js (4)
  • Digit (32-32)
  • location (23-23)
  • location (33-33)
  • EditRegister (22-420)
health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/pages/employee/createEmployee.js (1)
health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/components/config/createEmployeeConfig.js (2)
  • CreateEmployeeConfig (6-321)
  • CreateEmployeeConfig (6-321)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/pages/employee/AttendeeSearchAssign.js (3)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/pages/employee/EditRegister.js (2)
  • useTranslation (24-24)
  • Digit (32-32)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/config/AttendeeInboxConfig.js (1)
  • inboxAttendeeSearchConfig (13-219)
micro-ui/web/micro-ui-internals/packages/react-components/src/hoc/InboxSearchComposer.js (1)
  • InboxSearchComposer (19-322)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/attendance_inbox/table_inbox.js (2)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/pages/employee/EditRegister.js (1)
  • Digit (32-32)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/pages/employee/ViewAttendance.js (1)
  • Digit (32-32)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/pages/employee/ViewAttendance.js (2)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/pages/employee/EditRegister.js (3)
  • showDeEnrollPopup (54-54)
  • handleDeEnrollClick (225-227)
  • onDeEnrollClose (229-231)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/editAttendeesPopUp.js (1)
  • EditAttendeePopUp (14-235)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/HierachySelection.js (1)
micro-ui/web/micro-ui-internals/packages/react-components/src/atoms/Dropdown.js (1)
  • Dropdown (94-281)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/services/urls.js (1)
health/micro-ui/web/micro-ui-internals/example/src/UICustomizations.js (1)
  • projectContextPath (1898-1898)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/services/attendance/attendanceService.js (1)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/services/attendance/attendee_service/attendeeService.js (1)
  • AttendeeService (3-46)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/SearchUserPopUp.js (3)
health/micro-ui/web/micro-ui-internals/example/src/UICustomizations.js (19)
  • tenantId (391-391)
  • tenantId (757-757)
  • tenantId (840-840)
  • tenantId (1387-1387)
  • tenantId (1442-1442)
  • tenantId (1689-1689)
  • tenantId (1897-1897)
  • tenantId (2162-2162)
  • tenantId (2194-2194)
  • tenantId (2239-2239)
  • tenantId (2269-2269)
  • tenantId (2314-2314)
  • tenantId (2345-2345)
  • tenantId (2390-2390)
  • Digit (1443-1443)
  • Digit (2722-2722)
  • createMapping (2721-2721)
  • result (64-64)
  • boundaryCode (2660-2661)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/services/attendance/attendanceService.js (3)
  • result (79-100)
  • AttendanceService (4-108)
  • AttendanceService (4-108)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/SelectableList.js (1)
  • SelectableList (3-37)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/pages/employee/EditRegister.js (3)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/pages/employee/ViewAttendance.js (26)
  • location (22-22)
  • location (33-33)
  • useTranslation (23-23)
  • history (24-24)
  • attendanceContextPath (27-27)
  • individualContextPath (29-29)
  • Digit (32-32)
  • attendanceDuration (35-35)
  • attendanceSummary (36-36)
  • initialAttendanceSummary (37-37)
  • isSubmitEnabled (38-38)
  • disabledAction (40-40)
  • openEditAlertPopUp (41-41)
  • openApproveCommentPopUp (42-42)
  • openApproveAlertPopUp (43-43)
  • individualIds (48-48)
  • showToast (51-51)
  • AttendancereqCri (62-74)
  • isAttendanceLoading (76-76)
  • allIndividualReqCriteria (312-331)
  • isAllIndividualsLoading (333-333)
  • individualReqCriteria (335-357)
  • closeActionBarPopUp (428-430)
  • handleDeEnrollClick (441-443)
  • onDeEnrollClose (445-447)
  • renderLabelPair (450-455)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/editAttendeesPopUp.js (13)
  • useTranslation (24-24)
  • history (15-15)
  • attendanceContextPath (17-19)
  • individualContextPath (20-22)
  • tenantId (25-25)
  • attendanceSummary (32-32)
  • individualIds (33-33)
  • AttendancereqCri (42-53)
  • isAttendanceLoading (55-56)
  • allIndividualReqCriteria (69-86)
  • isAllIndividualsLoading (88-89)
  • closeActionBarPopUp (171-173)
  • EditAttendeePopUp (14-235)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/EditAttendanceManagementTable.js (5)
  • useTranslation (33-33)
  • history (34-34)
  • tenantId (40-40)
  • showToast (36-36)
  • EditAttendanceManagementTable (31-274)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/editAttendeesPopUp.js (3)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/SearchUserPopUp.js (6)
  • attendanceContextPath (18-20)
  • individualContextPath (21-23)
  • useTranslation (25-25)
  • tenantId (14-14)
  • searchQuery (32-32)
  • SearchUserPopUp (12-176)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/EditAttendanceManagementTable.js (3)
  • useTranslation (33-33)
  • tenantId (40-40)
  • EditAttendanceManagementTable (31-274)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/utils/update_attendance_summary.js (7)
  • attendanceContextPath (4-6)
  • individualContextPath (7-9)
  • attendanceSummary (12-12)
  • individualIds (11-11)
  • isAttendanceLoading (27-28)
  • allIndividualReqCriteria (41-58)
  • isAllIndividualsLoading (60-61)
health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/pages/employee/HierarchySelection.js (2)
health/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/components/HierarchySelection.js (2)
  • HierarchySelection (15-167)
  • selectedHierarchy (24-26)
health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/components/pageComponents/Jurisdictions.js (1)
  • selectedHierarchy (8-8)
health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/services/service.js (2)
health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/constants/constants.js (2)
  • HRMS_CONSTANTS (1-7)
  • HRMS_CONSTANTS (1-7)
health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/utils/utlis.js (2)
  • convertEpochToDate (2-15)
  • convertEpochToDate (2-15)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/utils/update_attendance_summary.js (6)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/editAttendeesPopUp.js (8)
  • attendanceContextPath (17-19)
  • individualContextPath (20-22)
  • individualIds (33-33)
  • attendanceSummary (32-32)
  • tenantId (25-25)
  • isAttendanceLoading (55-56)
  • allIndividualReqCriteria (69-86)
  • isAllIndividualsLoading (88-89)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/services/PaymentsInitialization.js (2)
  • individualContextPath (25-25)
  • individual (155-155)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/Module.js (1)
  • tenantId (19-19)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/EditAttendanceManagementTable.js (1)
  • tenantId (40-40)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/BoundaryComponent.js (1)
  • tenantId (15-15)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/HierachySelection.js (1)
  • tenantId (17-17)
health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/components/pageComponents/UserAssigment.js (3)
health/micro-ui/web/micro-ui-internals/example/src/UICustomizations.js (38)
  • options (890-890)
  • options (1721-1724)
  • boundaryCode (2660-2661)
  • Digit (1443-1443)
  • Digit (2722-2722)
  • tenantId (391-391)
  • tenantId (757-757)
  • tenantId (840-840)
  • tenantId (1387-1387)
  • tenantId (1442-1442)
  • tenantId (1689-1689)
  • tenantId (1897-1897)
  • tenantId (2162-2162)
  • tenantId (2194-2194)
  • tenantId (2239-2239)
  • tenantId (2269-2269)
  • tenantId (2314-2314)
  • tenantId (2345-2345)
  • tenantId (2390-2390)
  • tenantId (2420-2420)
  • tenantId (2465-2465)
  • data (415-415)
  • data (517-517)
  • data (734-734)
  • data (794-794)
  • data (811-811)
  • data (1071-1071)
  • data (1333-1333)
  • data (1350-1350)
  • data (1351-1351)
  • data (1352-1352)
  • data (2164-2164)
  • data (2165-2165)
  • data (2241-2241)
  • data (2242-2242)
  • data (2316-2316)
  • data (2317-2317)
  • result (64-64)
health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/services/service.js (3)
  • result (18-18)
  • result (43-43)
  • result (303-303)
micro-ui/web/micro-ui-internals/packages/react-components/src/atoms/Dropdown.js (1)
  • Dropdown (94-281)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/pages/employee/project_selection.js (3)
micro-ui/web/micro-ui-internals/packages/react-components/src/atoms/Dropdown.js (1)
  • Dropdown (94-281)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/pages/employee/EditRegister.js (1)
  • project (56-56)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/SearchAttendeeBoundary.js (1)
  • selectedProject (22-22)
🪛 Biome (2.1.2)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/SelectableList.js

[error] 20-31: Static Elements should not be interactive.

To add interactivity such as a mouse or key event listener to a static element, give the element an appropriate role value.

(lint/a11y/noStaticElementInteractions)


[error] 20-31: Enforce to have the onClick mouse event with the onKeyUp, the onKeyDown, or the onKeyPress keyboard event.

Actions triggered using mouse events should have corresponding keyboard events to account for keyboard-only navigation.

(lint/a11y/useKeyWithClickEvents)

health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/SearchAttendeeBoundary.js

[error] 228-233: Static Elements should not be interactive.

To add interactivity such as a mouse or key event listener to a static element, give the element an appropriate role value.

(lint/a11y/noStaticElementInteractions)


[error] 228-233: Enforce to have the onClick mouse event with the onKeyUp, the onKeyDown, or the onKeyPress keyboard event.

Actions triggered using mouse events should have corresponding keyboard events to account for keyboard-only navigation.

(lint/a11y/useKeyWithClickEvents)

health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/services/urls.js

[error] 10-15: This property is later overwritten by an object member with the same name.

Overwritten with this property.

If an object property with the same name is defined multiple times (except when combining a getter with a setter), only the last definition makes it into the object and previous definitions are ignored.
Unsafe fix: Remove this property.

(lint/suspicious/noDuplicateObjectKeys)

health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/SearchUserPopUp.js

[error] 136-136: Avoid passing children using a prop

The canonical way to pass children in React is to use JSX elements

(lint/correctness/noChildrenProp)

health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/pages/employee/EditRegister.js

[error] 270-271: Provide screen reader accessible content when using heading elements.

All headings on a page should have content that is accessible to screen readers.

(lint/a11y/useHeadingContent)

health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/editAttendeesPopUp.js

[error] 183-183: Avoid passing children using a prop

The canonical way to pass children in React is to use JSX elements

(lint/correctness/noChildrenProp)

health/micro-ui/web/micro-ui-internals/example/src/UICustomizations.js

[error] 887-887: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.

The declaration is defined in this switch clause:

Safe fix: Wrap the declaration in a block.

(lint/correctness/noSwitchDeclarations)


[error] 888-888: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.

The declaration is defined in this switch clause:

Safe fix: Wrap the declaration in a block.

(lint/correctness/noSwitchDeclarations)


[error] 889-889: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.

The declaration is defined in this switch clause:

Safe fix: Wrap the declaration in a block.

(lint/correctness/noSwitchDeclarations)


[error] 890-890: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.

The declaration is defined in this switch clause:

Safe fix: Wrap the declaration in a block.

(lint/correctness/noSwitchDeclarations)


[error] 902-916: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.

The declaration is defined in this switch clause:

Safe fix: Wrap the declaration in a block.

(lint/correctness/noSwitchDeclarations)


[error] 918-962: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.

The declaration is defined in this switch clause:

Safe fix: Wrap the declaration in a block.

(lint/correctness/noSwitchDeclarations)


[error] 964-966: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.

The declaration is defined in this switch clause:

Safe fix: Wrap the declaration in a block.

(lint/correctness/noSwitchDeclarations)

⏰ Context from checks skipped due to timeout of 10000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (16)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/attendance_inbox/table_inbox.js (1)

87-117: Ensure endDate is normalized to milliseconds
Convert or parse selectedProject.endDate into a millisecond timestamp (e.g. via Date.parse(endDate) or multiplying seconds by 1000) before comparing it to Date.now().

health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/PaymentsCard.js (1)

12-12: No-op whitespace change. LGTM.
No functional impact.

health/micro-ui/web/micro-ui-internals/example/src/index.js (1)

17-17: Module wiring addition looks correct.
Importing initPaymentComponents is fine and consistent with other modules.

health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/utils/constants.js (1)

19-22: New pagination constants look good.
Naming/values are clear and scoped to the edit-attendee table.

health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/services/service.js (1)

89-94: LGTM: Phone number normalization covers +91 and +258

The substring logic correctly strips known country codes and falls back safely.

Also applies to: 147-152

health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/pages/employee/HierarchySelection.js (1)

15-15: LGTM: Cleaned prop signature

Whitespace cleanup improves readability without behavioral change.

health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/pages/employee/createEmployee.js (2)

75-77: No-op whitespace

No functional impact.


322-323: Restore MDMS-driven form config with local fallback
In createEmployee.js, update the fConfig assignment:

- const fConfig = CreateEmployeeConfig?.CreateEmployeeConfig?.[0];
+ const fConfig = mdmsData || CreateEmployeeConfig?.CreateEmployeeConfig?.[0];

Verify any Digit.Hooks.useCommonMDMS(…) calls use enabled: true (not enable) when toggling MDMS fetching.

health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/HierachySelection.js (1)

33-39: Confirm hook name and spelling
All usages of Digit.Hooks.hrms.useBoundriesFetch are internally consistent but no local definition exists. Verify in the external Digit.Hooks.hrms API that the hook is indeed named useBoundriesFetch; if it’s actually useFetchBoundaries, update the references (e.g. in both HierarchySelection.js files and SelectEmployeeBoundary.js).

health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/Module.js (1)

20-20: Verify import/export name alignment for UserAssignment.

Import path is UserAssigment (missing “n”). Ensure the file name and default export match (UserAssignment). Mismatches will break registry at runtime.

health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/pages/employee/ViewAttendance.js (1)

440-447: Dead code: popup toggles have no trigger.

The only opener button is commented out. Either restore a trigger or remove the popup state/effects.

health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/hooks/index.js (1)

10-18: LGTM: hooks are properly exposed under payments.

Exports look consistent; no further action.

health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/pages/employee/EditRegister.js (4)

245-247: Loader condition is fine.

Good guard to avoid rendering before all data is ready.


285-286: Table rendered read-only here; actionable edits handled via popup.

Consistent with UX—no action column when editAction is false.


292-300: De-enroll popup wiring looks correct.

Props passed match component expectations (registerNumber, registerId, boundaryCode).


33-33: Fix unsafe destructuring of location.state.

Destructuring from false throws. Use optional chaining/nullish coalescing.

Apply:

-    const { fromCampaignSupervisor } = location.state || false;
+    const fromCampaignSupervisor = location.state?.fromCampaignSupervisor ?? false;

Likely an incorrect or invalid review comment.

initMicroplanComponents();
initHRMSComponents();
initPGRComponents();
initPaymentComponents();
Copy link
Contributor

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Call order OK; verify module key consistency.
Ensure the Payments module registers itself with the key expected by enabledModules ("Payments").

Use this to confirm:


🏁 Script executed:

#!/bin/bash
rg -nP --type=js -C2 '(initPaymentComponents)|(moduleName\s*:\s*"Payments")|ComponentRegistryService'

Length of output: 45698


🏁 Script executed:

#!/bin/bash
grep -R "const componentsToRegister" -n health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/Module.js

Length of output: 33


🏁 Script executed:

#!/bin/bash
sed -n '80,120p' health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/Module.js

Length of output: 458


🏁 Script executed:

#!/bin/bash
grep -R "setupRegistry" -n health/micro-ui/web/micro-ui-internals

Length of output: 119


Mismatch in Payments module registry key
The health-payments module registers under PaymentsModule (componentsToRegister in health-payments/src/Module.js:83) but enabledModules is looking for "Payments". Rename the registration key to "Payments" or update enabledModules to use "PaymentsModule".

🤖 Prompt for AI Agents
In health/micro-ui/web/micro-ui-internals/example/src/index.js around line 85,
there is a mismatch between the payments module registry key and the
enabledModules lookup: the payments package registers as "PaymentsModule"
(health-payments/src/Module.js line ~83) while enabledModules expects
"Payments". Fix by making the keys consistent—either rename the registration key
in health-payments/src/Module.js from "PaymentsModule" to "Payments", or update
enabledModules in this file to include "PaymentsModule" instead; apply the
change in the single place where componentsToRegister is defined or where
enabledModules is declared so both sides use the exact same string.

Comment on lines +114 to 118
// attendee delete
"/health-attendance/attendee/v1/_delete",
"/health-attendance/attendee/v1/_create",
"/health-hrms/employees/_search",
].forEach((location) => app.use(location, createProxy));
Copy link
Contributor

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Redundant proxy entry; keep only the broader prefix.
/health-hrms/employees already proxies /health-hrms/employees/_search. The explicit _search entry is redundant.

-    "/health-attendance/attendee/v1/_delete",
-    "/health-attendance/attendee/v1/_create",
-    "/health-hrms/employees/_search",
+    "/health-attendance/attendee/v1/_delete",
+    "/health-attendance/attendee/v1/_create",

Confirm the prefix covers subpaths:


🏁 Script executed:

#!/bin/bash
# http-proxy-middleware mounts middleware at the given path prefix.
rg -n 'app\.use\(.+createProxyMiddleware' example/src/setupProxy.js -n -C2

Length of output: 65


🏁 Script executed:

#!/bin/bash
# Locate setupProxy.js and inspect proxy entries
setup_file=$(find . -type f -name setupProxy.js)
echo "Found: $setup_file"
rg -n -C2 '\.forEach' "$setup_file"

Length of output: 446


🏁 Script executed:

#!/bin/bash
file="./health/micro-ui/web/micro-ui-internals/example/src/setupProxy.js"
sed -n '100,140p' "$file"

Length of output: 820


🏁 Script executed:

#!/bin/bash
file="./health/micro-ui/web/micro-ui-internals/example/src/setupProxy.js"
sed -n '1,80p' "$file"

Length of output: 2313


Remove redundant /health-hrms/employees/_search entry.
app.use("/health-hrms/employees", createProxy) already matches all subpaths.

-    "/health-hrms/employees/_search",
📝 Committable suggestion

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

Suggested change
// attendee delete
"/health-attendance/attendee/v1/_delete",
"/health-attendance/attendee/v1/_create",
"/health-hrms/employees/_search",
].forEach((location) => app.use(location, createProxy));
// attendee delete
"/health-attendance/attendee/v1/_delete",
"/health-attendance/attendee/v1/_create",
].forEach((location) => app.use(location, createProxy));
🤖 Prompt for AI Agents
In health/micro-ui/web/micro-ui-internals/example/src/setupProxy.js around lines
114 to 118, the array passed to forEach includes a redundant
"/health-hrms/employees/_search" entry because app.use("/health-hrms/employees",
createProxy) already covers that subpath; remove the
"/health-hrms/employees/_search" string from the list so the proxy locations
array only contains unique, necessary paths and leave the existing
app.use("/health-hrms/employees", createProxy) intact.

Comment on lines 304 to 315
// INFO:: testing

{
type: "component",
isMandatory: true,
component: "UserAssignment",
key: "UserAssignment",
withoutLabel: true,
populators: {
name: "UserAssignment",
},
},
Copy link
Contributor

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Remove leftover “testing” comment and confirm component registration.
The inline // INFO:: testing should not ship. Ensure UserAssignment is registered and its file name/spelling matches the import path.

Apply:

-            // INFO:: testing

Verify registration:


🏁 Script executed:

#!/bin/bash
rg -nP --type=js '(componentsToRegister|ComponentRegistryService).*UserAssignment|component:\s*"UserAssignment"'
fd -t f -a 'UserAssigment.js' 2>/dev/null || true

Length of output: 294


Remove leftover “testing” comment and correct UserAssignment filename

  • Remove the // INFO:: testing line from createEmployeeConfig.js.
  • Rename pageComponents/UserAssigment.jspageComponents/UserAssignment.js to match the component: "UserAssignment" reference.
  • Update all imports and registry entries to use the corrected filename and path.
🤖 Prompt for AI Agents
In
health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/components/config/createEmployeeConfig.js
around lines 304 to 315, remove the leftover comment line "// INFO:: testing"
and ensure the referenced component filename matches the component key: rename
the physical file pageComponents/UserAssigment.js to
pageComponents/UserAssignment.js, then update every import, export and
registry/registration entry across the module to use "UserAssignment" and the
corrected path/filename so imports, dynamic loads and any component map keys
align with component: "UserAssignment".

Comment on lines 24 to 31
const reqCri = {
url: `/health-individual/v1/_search`,
params: {
tenantId: tenantId,
limit: 4,
offset: 0,
},
body: {
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Avoid hard-coded service name; honor INDIVIDUAL_CONTEXT_PATH

Keep endpoints configurable like the rest of the codebase.

+    const individualContextPath = window?.globalConfigs?.getConfig("INDIVIDUAL_CONTEXT_PATH") || "health-individual";
@@
-        url: `/health-individual/v1/_search`,
+        url: `/${individualContextPath}/v1/_search`,
@@
-            select: (data) => {
-
-                console.log("data", data);
-                return data.Individual;
-            },
+            select: (data) => data.Individual,

Also applies to: 45-55

🤖 Prompt for AI Agents
In
health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/components/pageComponents/UserAssigment.js
around lines 24-31 (and similarly at lines 45-55), the request URL is hard-coded
to "/health-individual/v1/_search"; replace that hard-coded service path with
the shared INDIVIDUAL_CONTEXT_PATH constant (e.g. construct the URL as
`${INDIVIDUAL_CONTEXT_PATH}/v1/_search`) so the endpoint stays configurable; if
INDIVIDUAL_CONTEXT_PATH is not imported in this file, import it from the project
constants/config where other modules read it, and add a sensible fallback (or
throw) to avoid undefined values.

const projectContextPath = window?.globalConfigs?.getConfig("PROJECT_CONTEXT_PATH") || "health-project";
const individualContextPath = window?.globalConfigs?.getConfig("INDIVIDUAL_CONTEXT_PATH") || "health-individual";
const hierarchyType = window?.globalConfigs?.getConfig("HIERARCHY_TYPE") || "MICROPLAN";
const hierarchyType = "NEWTEST00222";
Copy link
Contributor

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Remove hard-coded hierarchyType.
Hard-coding "NEWTEST00222" risks deploying with the wrong hierarchy. Use the configured value and keep it consistent with other modules.

-  const hierarchyType = "NEWTEST00222";
+  const hierarchyType = window?.globalConfigs?.getConfig("HIERARCHY_TYPE");
+  if (!hierarchyType) {
+    throw new Error("HIERARCHY_TYPE not configured");
+  }

Find any remaining occurrences:


🏁 Script executed:

#!/bin/bash
rg -n --hidden -S 'NEWTEST00222' -g '!**/node_modules/**'

Length of output: 148


🏁 Script executed:

#!/bin/bash
rg -n --no-ignore 'NEWTEST00222' -g '!node_modules/**'

Length of output: 148


🏁 Script executed:

#!/bin/bash
# Search all files, including hidden, ignoring no patterns
rg -n --no-ignore --hidden 'NEWTEST00222'

Length of output: 570


Remove all hard-coded and fallback “NEWTEST00222” hierarchyType defaults
Replace every occurrence of the literal or fallback default with the configured value and fail fast if it’s missing:

  • In src/services/PaymentsInitialization.js:26, remove
      const hierarchyType = "NEWTEST00222";
    and use:
      const hierarchyType = window?.globalConfigs?.getConfig("HIERARCHY_TYPE");
      if (!hierarchyType) throw new Error("HIERARCHY_TYPE not configured");
  • In src/components/BoundaryComponent.js:16 and src/components/SearchAttendeeBoundary.js:27, remove the || "NEWTEST00222" fallback so they read:
      const hierarchyType = window?.globalConfigs?.getConfig("HIERARCHY_TYPE");
      if (!hierarchyType) throw new Error("HIERARCHY_TYPE not configured");

Ensures no deployments slip through with the wrong hierarchy.

🤖 Prompt for AI Agents
In
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/services/PaymentsInitialization.js
around line 26, remove the hard-coded const hierarchyType = "NEWTEST00222" and
instead read the configured value via
window?.globalConfigs?.getConfig("HIERARCHY_TYPE") and throw an Error if it is
missing; likewise update src/components/BoundaryComponent.js (line ~16) and
src/components/SearchAttendeeBoundary.js (line ~27) to remove any ||
"NEWTEST00222" fallback and replace with the same getConfig call followed by a
fail-fast throw when the value is not present so the app fails fast on missing
configuration.

Comment on lines +3 to +8
const healthHrms = window?.globalConfigs?.getConfig("HRMS_CONTEXT_PATH") || "health-hrms";
const mdmsPath = window?.globalConfigs?.getConfig("MDMS_CONTEXT_PATH") || "mdms-v2";
const boundarySearchPath = window?.globalConfigs?.getConfig("BOUNDARY_CONTEXT") || "boundary-service/boundary-relationships/_search?";
const hierarchyType = window?.globalConfigs?.getConfig("HIERARCHY_TYPE") || "HIERARCHYTEST";
const projectContextPath = window?.globalConfigs?.getConfig("PROJECT_SERVICE_PATH") || "health-project";

Copy link
Contributor

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Parameterize attendee/individual endpoints via global configs (no hard-coded service names)

Hard-coded paths block environment overrides. Also, attendee.search actually hits individual search; make intent clear while preserving key names to avoid breakage.

 const healthHrms = window?.globalConfigs?.getConfig("HRMS_CONTEXT_PATH") || "health-hrms";
 const mdmsPath = window?.globalConfigs?.getConfig("MDMS_CONTEXT_PATH") || "mdms-v2";
+const attendanceContextPath = window?.globalConfigs?.getConfig("ATTENDANCE_CONTEXT_PATH") || "health-attendance";
+const individualContextPath = window?.globalConfigs?.getConfig("INDIVIDUAL_CONTEXT_PATH") || "health-individual";
 const projectContextPath = window?.globalConfigs?.getConfig("PROJECT_SERVICE_PATH") || "health-project";
@@
   attendee:{
-    deenrollAttendee:`/health-attendance/attendee/v1/_delete`,
-    search: `/health-individual/v1/_search`,
-    enrollAttendee:`/health-attendance/attendee/v1/_create`,
+    deenrollAttendee:`/${attendanceContextPath}/attendee/v1/_delete`,
+    enrollAttendee:`/${attendanceContextPath}/attendee/v1/_create`,
+    // search is for Individuals; keep key for backward-compat
+    search: `/${individualContextPath}/v1/_search`,

Run to find and validate all references to these keys:

Also applies to: 49-54


🏁 Script executed:

#!/bin/bash
rg -nP 'Urls\.attendee\.(search|enrollAttendee|deenrollAttendee)' -C2

Length of output: 2407


🏁 Script executed:

#!/bin/bash
# Inspect the Urls.attendee block in urls.js to confirm existing paths
rg -nP -C5 'Urls\.attendee' health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/services/urls.js

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Display the contents of urls.js to locate the Urls.attendee configuration
cat health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/services/urls.js

Length of output: 2058


Parameterize attendee and individual service paths

In health/micro-ui/.../urls.js, replace hard-coded “health-attendance” and “health-individual” segments with globalConfigs:

 const projectContextPath = window?.globalConfigs?.getConfig("PROJECT_SERVICE_PATH") || "health-project";
+const attendanceContextPath = window?.globalConfigs?.getConfig("ATTENDANCE_CONTEXT_PATH") || "health-attendance";
+const individualContextPath = window?.globalConfigs?.getConfig("INDIVIDUAL_CONTEXT_PATH") || "health-individual";

 const Urls = {
   … 
   attendee:{
-    deenrollAttendee:`/health-attendance/attendee/v1/_delete`,
-    search: `/health-individual/v1/_search`,
-    enrollAttendee:`/health-attendance/attendee/v1/_create`,
+    deenrollAttendee: `/${attendanceContextPath}/attendee/v1/_delete`,
+    enrollAttendee: `/${attendanceContextPath}/attendee/v1/_create`,
+    // search targets Individuals; retain key for backward compatibility
+    search: `/${individualContextPath}/v1/_search`,
   }
 };
📝 Committable suggestion

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

Suggested change
const healthHrms = window?.globalConfigs?.getConfig("HRMS_CONTEXT_PATH") || "health-hrms";
const mdmsPath = window?.globalConfigs?.getConfig("MDMS_CONTEXT_PATH") || "mdms-v2";
const boundarySearchPath = window?.globalConfigs?.getConfig("BOUNDARY_CONTEXT") || "boundary-service/boundary-relationships/_search?";
const hierarchyType = window?.globalConfigs?.getConfig("HIERARCHY_TYPE") || "HIERARCHYTEST";
const projectContextPath = window?.globalConfigs?.getConfig("PROJECT_SERVICE_PATH") || "health-project";
const healthHrms = window?.globalConfigs?.getConfig("HRMS_CONTEXT_PATH") || "health-hrms";
const mdmsPath = window?.globalConfigs?.getConfig("MDMS_CONTEXT_PATH") || "mdms-v2";
const boundarySearchPath = window?.globalConfigs?.getConfig("BOUNDARY_CONTEXT") || "boundary-service/boundary-relationships/_search?";
const hierarchyType = window?.globalConfigs?.getConfig("HIERARCHY_TYPE") || "HIERARCHYTEST";
const projectContextPath = window?.globalConfigs?.getConfig("PROJECT_SERVICE_PATH") || "health-project";
const attendanceContextPath = window?.globalConfigs?.getConfig("ATTENDANCE_CONTEXT_PATH") || "health-attendance";
const individualContextPath = window?.globalConfigs?.getConfig("INDIVIDUAL_CONTEXT_PATH") || "health-individual";
const Urls = {
attendee: {
- deenrollAttendee: `/health-attendance/attendee/v1/_delete`,
- search: `/health-individual/v1/_search`,
deenrollAttendee: `/${attendanceContextPath}/attendee/v1/_delete`,
enrollAttendee: `/${attendanceContextPath}/attendee/v1/_create`,
// search targets Individuals; retain key for backward compatibility
search: `/${individualContextPath}/v1/_search`,
}
};
🤖 Prompt for AI Agents
In
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/services/urls.js
around lines 3 to 8, the code currently uses hard-coded service path segments
for attendance and individual; add two new constants that read from
window?.globalConfigs?.getConfig("ATTENDANCE_SERVICE_PATH") and
window?.globalConfigs?.getConfig("INDIVIDUAL_SERVICE_PATH") with sensible
defaults "health-attendance" and "health-individual" respectively, and replace
any hard-coded "health-attendance" and "health-individual" usages in this file
with these new constants so the service paths are parameterized via
globalConfigs.

Comment on lines +5 to +7
const boundarySearchPath = window?.globalConfigs?.getConfig("BOUNDARY_CONTEXT") || "boundary-service/boundary-relationships/_search?";
const hierarchyType = window?.globalConfigs?.getConfig("HIERARCHY_TYPE") || "HIERARCHYTEST";
const projectContextPath = window?.globalConfigs?.getConfig("PROJECT_SERVICE_PATH") || "health-project";
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Remove unused constants and mock endpoint

boundarySearchPath and hierarchyType aren’t used. filter_data points to an external mock endpoint; keep it out of production bundles.

-const boundarySearchPath = window?.globalConfigs?.getConfig("BOUNDARY_CONTEXT") || "boundary-service/boundary-relationships/_search?";
-const hierarchyType = window?.globalConfigs?.getConfig("HIERARCHY_TYPE") || "HIERARCHYTEST";
+// (removed unused BOUNDARY_CONTEXT and HIERARCHY_TYPE; re-add when wired)
@@
-  filter_data: `https://run.mocky.io/v3/597a50a0-90e5-4a45-b82e-8a2186b760bd`,
+  // filter_data: '...mock-url...', // keep mocks in dev-only code paths if required

Also applies to: 20-21

🤖 Prompt for AI Agents
In
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/services/urls.js
around lines 5-7 (and also address lines 20-21), remove the unused constants
boundarySearchPath and hierarchyType, and replace the external mock filter_data
endpoint with a production-safe source: either read the URL from globalConfigs
(or an environment/config value) or point to an internal stub file; update
imports/usages accordingly and ensure no hard-coded external mock URLs remain in
the bundle.

Comment on lines +10 to +15
hrms: {
search: `/${healthHrms}/employees/_search`,
count: `/${healthHrms}/employees/_count`,
create: `/${healthHrms}/employees/_create`,
update: `/${healthHrms}/employees/_update`,
},
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Duplicate "hrms" key — first definition is shadowed and dead code

Object key duplication makes the first hrms block inert and triggers lints. Keep a single hrms block.

Apply:

   const Urls = {
-  hrms: {
-    search: `/${healthHrms}/employees/_search`,
-    count: `/${healthHrms}/employees/_count`,
-    create: `/${healthHrms}/employees/_create`,
-    update: `/${healthHrms}/employees/_update`,
-  },
+  // hrms block defined once below

Also applies to: 34-39

🧰 Tools
🪛 Biome (2.1.2)

[error] 10-15: This property is later overwritten by an object member with the same name.

Overwritten with this property.

If an object property with the same name is defined multiple times (except when combining a getter with a setter), only the last definition makes it into the object and previous definitions are ignored.
Unsafe fix: Remove this property.

(lint/suspicious/noDuplicateObjectKeys)

🤖 Prompt for AI Agents
In
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/services/urls.js
around lines 10-15 (and similarly at 34-39) there are duplicate object keys
named "hrms" so the first block is shadowed and triggers lints; remove or merge
the duplicate entries so only one "hrms" property remains containing all
required routes (search, count, create, update), ensure no key collisions remain
and update any references if needed.

Comment on lines +25 to +27
EmployeeSearch: `/${healthHrms}/employees/_search`,

InboxSearch: "/works-inbox-service/v2/_search",
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Avoid redundant top-level "EmployeeSearch" — use Urls.hrms.search

This duplicates hrms.search and increases surface area for drift.

-  EmployeeSearch: `/${healthHrms}/employees/_search`,
+  // Use Urls.hrms.search instead of duplicating
📝 Committable suggestion

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

Suggested change
EmployeeSearch: `/${healthHrms}/employees/_search`,
InboxSearch: "/works-inbox-service/v2/_search",
// Use Urls.hrms.search instead of duplicating
InboxSearch: "/works-inbox-service/v2/_search",
🤖 Prompt for AI Agents
In
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/services/urls.js
around lines 25 to 27, the top-level EmployeeSearch URL duplicates hrms.search;
remove the redundant EmployeeSearch property from this file and update any code
that references Urls.EmployeeSearch to use Urls.hrms.search instead (search and
replace references, run tests/linters to ensure no remaining usages).

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.

Review continued from previous batch...

Comment on lines 1 to 12
import React, { useEffect, useState } from "react";
import { useTranslation } from "react-i18next";
import {
Dropdown,
Loader,
HeaderComponent,
Card,
LabelFieldPair,
Button,
Toast,
CardLabel
} from "@egovernments/digit-ui-components";
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Prune unused imports

useTranslation, HeaderComponent, Card, Button, Toast are not used.

-import React, { useEffect, useState } from "react";
-import { useTranslation } from "react-i18next";
-import {
-    Dropdown,
-    Loader,
-    HeaderComponent,
-    Card,
-    LabelFieldPair,
-    Button,
-    Toast,
-    CardLabel
-} from "@egovernments/digit-ui-components";
+import React, { useEffect, useState } from "react";
+import { Dropdown, Loader, LabelFieldPair, CardLabel } from "@egovernments/digit-ui-components";
📝 Committable suggestion

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

Suggested change
import React, { useEffect, useState } from "react";
import { useTranslation } from "react-i18next";
import {
Dropdown,
Loader,
HeaderComponent,
Card,
LabelFieldPair,
Button,
Toast,
CardLabel
} from "@egovernments/digit-ui-components";
import React, { useEffect, useState } from "react";
import { Dropdown, Loader, LabelFieldPair, CardLabel } from "@egovernments/digit-ui-components";
🤖 Prompt for AI Agents
In
health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/components/pageComponents/UserAssigment.js
around lines 1 to 12, there are unused imports (useTranslation, HeaderComponent,
Card, Button, Toast) that should be removed to clean up the file; update the
import statement from "@egovernments/digit-ui-components" to only include the
components actually used (Dropdown, Loader, LabelFieldPair, CardLabel) and run a
quick lint/format to ensure the import line is properly formatted after removal.

@@ -0,0 +1,104 @@
import React, { useEffect, useState } from "react";
Copy link
Contributor

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Filename typo: UserAssigment.js

Consider renaming file to UserAssignment.js for consistency with the component name.

If you opt to rename, update imports:


🏁 Script executed:

#!/bin/bash
rg -nP 'UserAssigment' -g '!**/node_modules/**'

Length of output: 148


🏁 Script executed:

#!/bin/bash
# Locate file with potential typo
find . -type f -iname '*UserAssigment*'
# Search codebase for any references to the misspelled component
rg -n 'UserAssigment' --ignore-dir node_modules

Length of output: 559


🏁 Script executed:

#!/bin/bash
# Find all references to the typo across the codebase
rg -n 'UserAssigment' --glob '!node_modules/**'
# Inspect the component’s name and export in the file
head -n 100 health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/components/pageComponents/UserAssigment.js

Length of output: 2857


🏁 Script executed:

# Search for any occurrences of the misspelled filename in code or imports
grep -R "UserAssigment" -n . --exclude-dir=node_modules
grep -R "from .*UserAssigment" -n . --exclude-dir=node_modules

Length of output: 357


Rename UserAssigment.js to UserAssignment.js and update imports
File health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/components/pageComponents/UserAssigment.js has a typo in its name—rename it to UserAssignment.js and update the import in health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/Module.js (line 20).

🤖 Prompt for AI Agents
In
health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/components/pageComponents/UserAssigment.js
(line 1) the filename contains a typo; rename the file to UserAssignment.js and
update any references to it—specifically change the import in
health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/Module.js
at line 20 to import from './components/pageComponents/UserAssignment' (and
adjust any other imports/exports that reference the old name).

Comment on lines 20 to 23
const boundaryCode = Digit?.SessionStorage.get("selectedBoundary")?.code;
//const { t } = useTranslation();
const tenantId = Digit.ULBService.getStateId();

Copy link
Contributor

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Use environment-consistent tenant getter

Elsewhere the app predominantly uses getCurrentTenantId() for API calls. Align unless this screen explicitly needs state-level tenant.

-    const tenantId = Digit.ULBService.getStateId();
+    const tenantId = Digit.ULBService.getCurrentTenantId();

Verify usage across HRMS:


🏁 Script executed:

#!/bin/bash
rg -nP 'ULBService\.get(StateId|getCurrentTenantId)\(' -C2 health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms

Length of output: 4796


🏁 Script executed:

#!/bin/bash
rg -nP "getStateId\(" -C3 micro-ui/web/micro-ui-internals/packages/modules/core/src
rg -nP "getCurrentTenantId\(" -C3 micro-ui/web/micro-ui-internals/packages/modules/core/src

Length of output: 17928


Use getCurrentTenantId() for tenantId in UserAssigment.js

Align with other HRMS API calls (e.g., Inbox.js) by replacing the state-level getter:

- const tenantId = Digit.ULBService.getStateId();
+ const tenantId = Digit.ULBService.getCurrentTenantId();
📝 Committable suggestion

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

Suggested change
const boundaryCode = Digit?.SessionStorage.get("selectedBoundary")?.code;
//const { t } = useTranslation();
const tenantId = Digit.ULBService.getStateId();
const boundaryCode = Digit?.SessionStorage.get("selectedBoundary")?.code;
//const { t } = useTranslation();
const tenantId = Digit.ULBService.getCurrentTenantId();
🤖 Prompt for AI Agents
In
health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/components/pageComponents/UserAssigment.js
around lines 20 to 23, the code uses Digit.ULBService.getStateId() for tenantId
which is inconsistent with other HRMS API calls; replace that call with
Digit.ULBService.getCurrentTenantId() so tenantId is derived at the tenant scope
like Inbox.js, and keep boundaryCode retrieval as-is.

Comment on lines 62 to 67
const result = individualData.map(item => ({
code: item.id,
name: item.name?.givenName || null
}));
setOptions(result);
}, [individualData]);
Copy link
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick (assertive)

Harden option mapping against missing names

Prevent blank labels by falling back to username or a translated NA.

-        const result = individualData.map(item => ({
-            code: item.id,
-            name: item.name?.givenName || null
-        }));
+        const result = individualData.map((item) => ({
+            code: item.id,
+            name: item?.name?.givenName || item?.userDetails?.username || t("NA"),
+        }));
📝 Committable suggestion

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

Suggested change
const result = individualData.map(item => ({
code: item.id,
name: item.name?.givenName || null
}));
setOptions(result);
}, [individualData]);
const result = individualData.map((item) => ({
code: item.id,
name: item?.name?.givenName || item?.userDetails?.username || t("NA"),
}));
setOptions(result);
}, [individualData]);
🤖 Prompt for AI Agents
In
health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/components/pageComponents/UserAssigment.js
around lines 62 to 67, the option mapping can produce blank labels when
givenName is missing; update the mapping so name is resolved to
item.name?.givenName || item.username || a translated "N/A" (or a sensible
fallback string). If your codebase uses i18n, call the appropriate translation
helper (e.g. t('common.na')) for the final fallback; otherwise use a constant
like 'N/A'. Keep the rest of the structure (code -> id, name -> resolved label)
and ensure setOptions(result) still receives the updated array.

Comment on lines +4 to +10
const attendanceContextPath =
window?.globalConfigs?.getConfig("ATTENDANCE_CONTEXT_PATH") ||
"health-attendance";
const individualContextPath =
window?.globalConfigs?.getConfig("INDIVIDUAL_CONTEXT_PATH") ||
"health-individual";

Copy link
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick (assertive)

Centralize context paths via Urls to avoid duplication

This file re-reads globals; consider importing from the centralized Urls module to keep one source of truth.

I can provide a small helper to export resolved base paths (attendance/individual) from urls.js if you want.

🤖 Prompt for AI Agents
In
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/utils/update_attendance_summary.js
around lines 4 to 10, the file re-reads globals for ATTENDANCE_CONTEXT_PATH and
INDIVIDUAL_CONTEXT_PATH; replace those window.globalConfigs calls by importing
the centralized Urls helper and using its exported resolved base paths (e.g.
Urls.attendanceBasePath and Urls.individualBasePath or the helper names your
team provides). Remove the duplicated fallback logic and rely on Urls to provide
the canonical values (or add a small export in urls.js that resolves those
globals and import that instead).

Comment on lines +31 to +38
useEffect(() => {
if (attendanceData?.attendanceRegister?.length > 0) {
const ids = attendanceData.attendanceRegister[0].attendees.map(
(a) => a.individualId
);
setIndividualIds(ids);
}
}, [attendanceData]);
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Reset and de-duplicate individual IDs

Prevents stale IDs when register changes and avoids duplicate lookups.

-  useEffect(() => {
-    if (attendanceData?.attendanceRegister?.length > 0) {
-      const ids = attendanceData.attendanceRegister[0].attendees.map(
-        (a) => a.individualId
-      );
-      setIndividualIds(ids);
-    }
-  }, [attendanceData]);
+  useEffect(() => {
+    if (attendanceData?.attendanceRegister?.length > 0) {
+      const ids = Array.from(
+        new Set(attendanceData.attendanceRegister[0]?.attendees?.map((a) => a.individualId).filter(Boolean))
+      );
+      setIndividualIds(ids);
+    } else {
+      setIndividualIds([]);
+    }
+  }, [attendanceData]);
📝 Committable suggestion

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

Suggested change
useEffect(() => {
if (attendanceData?.attendanceRegister?.length > 0) {
const ids = attendanceData.attendanceRegister[0].attendees.map(
(a) => a.individualId
);
setIndividualIds(ids);
}
}, [attendanceData]);
useEffect(() => {
if (attendanceData?.attendanceRegister?.length > 0) {
const ids = Array.from(
new Set(
attendanceData.attendanceRegister[0]
?.attendees
?.map((a) => a.individualId)
.filter(Boolean)
)
);
setIndividualIds(ids);
} else {
setIndividualIds([]);
}
}, [attendanceData]);
🤖 Prompt for AI Agents
In
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/utils/update_attendance_summary.js
around lines 31 to 38, the effect only reads the first register and can leave
stale or duplicate individualIds when registers change; update the effect to (1)
bail to setIndividualIds([]) when attendanceRegister is empty, (2) flatten all
attendanceRegister entries to collect every attendee.individualId, (3) remove
duplicates (use a Set) before calling setIndividualIds, and (4) ensure the
effect tracks the actual register (attendanceData.attendanceRegister) in its
dependency array so it runs when the register content changes.

Comment on lines +45 to +47
limit: individualIds.length,
offset: 0,
},
Copy link
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick (assertive)

Guard against very large ID lists (server max limit/pagination)

Using limit: individualIds.length can exceed server caps. Consider chunked fetch or a sane upper bound.

Would you like me to propose a chunking helper that batches IDs (e.g., 50 per request) and merges results?

Comment on lines +65 to +81
const attendanceLogData =
attendanceData.attendanceRegister[0].attendees.map((individualEntry) => {
const individualId = individualEntry.individualId;
const matchingIndividual = individualsData?.Individual?.find(
(individual) => individual.id === individualId
);

if (matchingIndividual) {
const userName = matchingIndividual.name?.givenName || t("NA");
const userId = matchingIndividual?.userDetails?.username || t("NA");
const userRole = t(matchingIndividual.skills?.[0]?.type) || t("NA");
const noOfDaysWorked =
individualEntry?.denrollmentDate == null ? true : false;

const id = individualEntry.individualId || 0;

return [id, userName, userId, userRole, noOfDaysWorked];
Copy link
Contributor

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Fix typo in field name and avoid misnamed "noOfDaysWorked" boolean

denrollmentDate looks like a typo. Also the variable is a boolean flagged as a count.

-          const userRole = t(matchingIndividual.skills?.[0]?.type) || t("NA");
-          const noOfDaysWorked =
-            individualEntry?.denrollmentDate == null ? true : false;
+          const userRole = t(matchingIndividual.skills?.[0]?.type) || t("NA");
+          const isActive = individualEntry?.deEnrollmentDate == null;
@@
-          return [id, userName, userId, userRole, noOfDaysWorked];
+          return [id, userName, userId, userRole, isActive];
@@
-          return [
-            "N/A",
-            "Unknown",
-            "N/A",
-            "Unassigned",
-            individualEntry?.denrollmentDate == null ? true : false,
-          ];
+          return [
+            "N/A",
+            t("UNKNOWN"),
+            "N/A",
+            t("UNASSIGNED"),
+            individualEntry?.deEnrollmentDate == null,
+          ];

Confirm the correct field name from the attendance API schema. If it’s disEnrollmentDate or similar, update accordingly.

Also applies to: 83-90


🌐 Web query:

What is the correct field name for an attendee's end-of-enrollment date in the DIGIT Health Attendance Register API? (e.g., deEnrollmentDate vs denrollmentDate)

💡 Result:

The correct field name is deEnrollmentDate. [1][2]

Sources:
[1] DIGIT Attendance API (spec & API contract). (health.digit.org)
[2] DIGIT Attendance documentation. (docs.digit.org)

Citations:


Use deEnrollmentDate and rename noOfDaysWorked to isActive

  • Replace all individualEntry?.denrollmentDate with individualEntry.deEnrollmentDate (the API schema’s correct field is deEnrollmentDate).
  • Rename the boolean noOfDaysWorked to isActive and simplify its assignment to const isActive = individualEntry.deEnrollmentDate == null.
  • Update both the main and fallback return arrays (lines 65–81 and 83–90) to use deEnrollmentDate and isActive.
🤖 Prompt for AI Agents
In
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/utils/update_attendance_summary.js
around lines 65 to 81 and also covering the fallback return at 83 to 90, replace
any use of individualEntry?.denrollmentDate with
individualEntry.deEnrollmentDate, rename the boolean variable noOfDaysWorked to
isActive and simplify its assignment to const isActive =
individualEntry.deEnrollmentDate == null, and update both the main returned
array and the fallback returned array to return isActive in place of the old
noOfDaysWorked variable.

Comment on lines +99 to +111
useEffect(() => {
if (
attendanceData?.attendanceRegister?.length > 0 &&
allIndividualsData?.Individual?.length > 0
) {
const summary = getUserAttendanceSummary(
attendanceData,
allIndividualsData,
t
);
setAttendanceSummary(summary);
}
}, [allIndividualsData, attendanceData, t]);
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Ensure summary resets when data becomes unavailable

Avoid showing stale rows if either dataset empties out.

   useEffect(() => {
     if (
       attendanceData?.attendanceRegister?.length > 0 &&
       allIndividualsData?.Individual?.length > 0
     ) {
       const summary = getUserAttendanceSummary(
         attendanceData,
         allIndividualsData,
         t
       );
       setAttendanceSummary(summary);
-    }
+    } else {
+      setAttendanceSummary([]);
+    }
   }, [allIndividualsData, attendanceData, t]);
📝 Committable suggestion

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

Suggested change
useEffect(() => {
if (
attendanceData?.attendanceRegister?.length > 0 &&
allIndividualsData?.Individual?.length > 0
) {
const summary = getUserAttendanceSummary(
attendanceData,
allIndividualsData,
t
);
setAttendanceSummary(summary);
}
}, [allIndividualsData, attendanceData, t]);
useEffect(() => {
if (
attendanceData?.attendanceRegister?.length > 0 &&
allIndividualsData?.Individual?.length > 0
) {
const summary = getUserAttendanceSummary(
attendanceData,
allIndividualsData,
t
);
setAttendanceSummary(summary);
} else {
setAttendanceSummary([]);
}
}, [allIndividualsData, attendanceData, t]);
🤖 Prompt for AI Agents
In
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/utils/update_attendance_summary.js
around lines 99 to 111, the effect only sets attendanceSummary when both
datasets have length > 0, so stale rows remain if one dataset becomes empty;
update the useEffect to explicitly reset attendanceSummary (e.g.,
setAttendanceSummary([]) or null) in the else branch when attendanceData or
allIndividualsData are missing or have zero length, keeping the existing
dependency array.

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.

Review continued from previous batch...

Comment on lines +810 to 823
preProcess: (data, additionalDetails) => {
const { name, status } = data?.state?.searchForm || {};
data.body.PlanConfigurationSearchCriteria = {};
data.body.PlanConfigurationSearchCriteria.limit = data?.state?.tableForm?.limit;
// data.body.PlanConfigurationSearchCriteria.limit = 10
data.body.PlanConfigurationSearchCriteria.offset = data?.state?.tableForm?.offset;
data.body.PlanConfigurationSearchCriteria.name = name;
data.body.PlanConfigurationSearchCriteria.tenantId = Digit.ULBService.getCurrentTenantId();
data.body.PlanConfigurationSearchCriteria.userUuid = Digit.UserService.getUser().info.uuid;
// delete data.body.PlanConfigurationSearchCriteria.pagination
data.body.PlanConfigurationSearchCriteria.status = status?.status;
data.body.PlanConfigurationSearchCriteria.name = data?.state?.searchForm?.microplanName;
cleanObject(data.body.PlanConfigurationSearchCriteria);

Copy link
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick (assertive)

Duplicate/overwritten fields in MicroplanSearchConfig.preProcess

name is assigned twice; status is first read from form and later overridden by tab filter. Simplify to avoid confusion.

-      const { name, status } = data?.state?.searchForm || {};
+      const { name } = data?.state?.searchForm || {};
...
-      data.body.PlanConfigurationSearchCriteria.name = name;
+      data.body.PlanConfigurationSearchCriteria.name = name;
...
-      data.body.PlanConfigurationSearchCriteria.status = status?.status;
-      data.body.PlanConfigurationSearchCriteria.name = data?.state?.searchForm?.microplanName;
+      // status set below using tab filter
+      if (data?.state?.searchForm?.microplanName) {
+        data.body.PlanConfigurationSearchCriteria.name = data.state.searchForm.microplanName;
+      }

Confirm expected precedence between name and microplanName.

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In health/micro-ui/web/micro-ui-internals/example/src/UICustomizations.js around
lines 810 to 823, the preProcess block assigns the same fields twice which
causes ambiguity (name is set from searchForm then from microplanName, and
status may be coming from two sources); remove the duplicate assignment and make
explicit which source has precedence: set
data.body.PlanConfigurationSearchCriteria.name once (use microplanName if the UI
expects that to override the generic name, otherwise use name), and ensure
status is sourced from the intended place (either keep status from the form or
from the tab filter) — update the code to assign each field only once, remove
the commented/duplicate lines, and add a short inline comment noting the chosen
precedence so future reviewers know which source wins.

Comment on lines +839 to +967
const [showToast, setShowToast] = useState(false);
const tenantId = Digit.ULBService.getCurrentTenantId();
const microplanId = row?.id;

const { data: rootEstimationApprover } = Digit.Hooks.microplanv1.usePlanSearchEmployeeWithTagging({
tenantId: tenantId,
body: {
PlanEmployeeAssignmentSearchCriteria: {
tenantId: tenantId,
planConfigurationId: microplanId,
role: ["ROOT_PLAN_ESTIMATION_APPROVER"],
active: true,
},
});
},
config: {
enabled: true,
},
});

const { data: rootPopulationApprover } = Digit.Hooks.microplanv1.usePlanSearchEmployeeWithTagging({
tenantId,
body: {
PlanEmployeeAssignmentSearchCriteria: {
tenantId,
planConfigurationId: microplanId,
role: ["ROOT_POPULATION_DATA_APPROVER"],
active: true,
},
const { data: rootPopulationApprover } = Digit.Hooks.microplanv1.usePlanSearchEmployeeWithTagging({
tenantId,
body: {
PlanEmployeeAssignmentSearchCriteria: {
tenantId,
planConfigurationId: microplanId,
role: ["ROOT_POPULATION_DATA_APPROVER"],
active: true,
},
config: { enabled: true },
});
},
config: { enabled: true },
});

const { data: rootFacilityMapper } = Digit.Hooks.microplanv1.usePlanSearchEmployeeWithTagging({
tenantId,
body: {
PlanEmployeeAssignmentSearchCriteria: {
tenantId,
planConfigurationId: microplanId,
role: ["ROOT_FACILITY_CATCHMENT_MAPPER"],
active: true,
},
const { data: rootFacilityMapper } = Digit.Hooks.microplanv1.usePlanSearchEmployeeWithTagging({
tenantId,
body: {
PlanEmployeeAssignmentSearchCriteria: {
tenantId,
planConfigurationId: microplanId,
role: ["ROOT_FACILITY_CATCHMENT_MAPPER"],
active: true,
},
config: { enabled: true },
});

switch (key) {
case "ACTIONS":
// TODO : Replace dummy file id with real file id when API is ready
const dummyFile = "c22a7676-d5d7-49b6-bcdb-83e9519f58df"
const microplanFileId = row?.campaignDetails?.additionalDetails?.microplanFileId || dummyFile;
const EstimationsfileId = row?.files.find((item) => item.templateIdentifier === "Estimations")?.filestoreId;
let options = [];

if (row?.status == "DRAFT") {
options = [
{ code: "1", name: "MP_ACTIONS_EDIT_SETUP" },
{ code: "2", name: "MP_ACTIONS_DOWNLOAD_DRAFT" },
{ code: "3", name: "MP_ACTIONS_FREEZE_MICROPLAN" },
];
} else {
options = [{ code: "1", name: "MP_ACTIONS_VIEW_SUMMARY" }];
},
config: { enabled: true },
});

switch (key) {
case "ACTIONS":
// TODO : Replace dummy file id with real file id when API is ready
const dummyFile = "c22a7676-d5d7-49b6-bcdb-83e9519f58df"
const microplanFileId = row?.campaignDetails?.additionalDetails?.microplanFileId || dummyFile;
const EstimationsfileId = row?.files.find((item) => item.templateIdentifier === "Estimations")?.filestoreId;
let options = [];

if (row?.status == "DRAFT") {
options = [
{ code: "1", name: "MP_ACTIONS_EDIT_SETUP" },
{ code: "2", name: "MP_ACTIONS_DOWNLOAD_DRAFT" },
{ code: "3", name: "MP_ACTIONS_FREEZE_MICROPLAN" },
];
} else {
options = [{ code: "1", name: "MP_ACTIONS_VIEW_SUMMARY" }];
}

const handleDownload = ({ type }) => {

const template = type === "Estimations" ? "Estimations" : "DraftComplete";
const fileId = row?.files.find((item) => item.templateIdentifier === template)?.filestoreId;
if (!fileId) {
setShowToast({ label: t("NO_DRAFT_FILE_FOUND") });
return;
}

const handleDownload = ({type}) => {

const template = type === "Estimations" ? "Estimations" : "DraftComplete";
const fileId = row?.files.find((item) => item.templateIdentifier === template)?.filestoreId;
if (!fileId) {
setShowToast({ label: t("NO_DRAFT_FILE_FOUND") });
return;
}
const campaignName = row?.name || "";
const customName = type === "Estimations" ? campaignName : `${campaignName}_DRAFT`;
Digit.Utils.campaign.downloadExcelWithCustomName({
fileStoreId: fileId,
customName: customName,
});
};

const onActionSelect = async (e,row) => {
if (e.name === "MP_ACTIONS_EDIT_SETUP") {
const key = parseInt(row?.additionalDetails?.key);
const resolvedKey = key === 8 ? 7 : key === 10 ? 11 : key || 2;
const url = `/${window.contextPath}/employee/microplan/setup-microplan?key=${resolvedKey}&microplanId=${row.id}&campaignId=${row.campaignDetails.id}`;
window.location.href = url;
const campaignName = row?.name || "";
const customName = type === "Estimations" ? campaignName : `${campaignName}_DRAFT`;
Digit.Utils.campaign.downloadExcelWithCustomName({
fileStoreId: fileId,
customName: customName,
});
};

const onActionSelect = async (e, row) => {
if (e.name === "MP_ACTIONS_EDIT_SETUP") {
const key = parseInt(row?.additionalDetails?.key);
const resolvedKey = key === 8 ? 7 : key === 10 ? 11 : key || 2;
const url = `/${window.contextPath}/employee/microplan/setup-microplan?key=${resolvedKey}&microplanId=${row.id}&campaignId=${row.campaignDetails.id}`;
window.location.href = url;
}
if (e.name === "MP_ACTIONS_DOWNLOAD_DRAFT") {
if (row?.status == "DRAFT" && row?.assumptions.length > 0 && row?.operations.length > 0) {
handleDownload({ type: "Draft" });
} else {
setShowToast({ label: t("PLEASE_UPDATE_THE_SETUP_INFORMATION_BEFORE_DOWNLOADING_DRAFT") });
}
if (e.name === "MP_ACTIONS_DOWNLOAD_DRAFT") {
if (row?.status == "DRAFT" && row?.assumptions.length > 0 && row?.operations.length > 0) {
handleDownload({ type: "Draft" });
} else {
setShowToast({ label: t("PLEASE_UPDATE_THE_SETUP_INFORMATION_BEFORE_DOWNLOADING_DRAFT") });
}
if (e.name === "MP_ACTIONS_FREEZE_MICROPLAN") {
if (
row?.status == "DRAFT" &&
row?.assumptions.length > 0 &&
row?.operations.length > 0 &&
rootEstimationApprover?.data?.length > 0 &&
rootPopulationApprover?.data?.length > 0 &&
rootFacilityMapper?.data?.length > 0
) {
const triggeredFromMain = "OPEN_MICROPLANS";
const response = await Digit.Hooks.microplanv1.useCompleteSetUpFlow({
tenantId,
microplanId,
triggeredFrom: triggeredFromMain,
});
if (response && !response?.isError) {
window.history.pushState(response?.state, "", response?.redirectTo);
window.dispatchEvent(new PopStateEvent("popstate", { state: response?.state }));
}
}
if (e.name === "MP_ACTIONS_FREEZE_MICROPLAN") {
if (
row?.status == "DRAFT" &&
row?.assumptions.length > 0 &&
row?.operations.length > 0 &&
rootEstimationApprover?.data?.length > 0 &&
rootPopulationApprover?.data?.length > 0 &&
rootFacilityMapper?.data?.length > 0
) {
const triggeredFromMain = "OPEN_MICROPLANS";
const response = await Digit.Hooks.microplanv1.useCompleteSetUpFlow({
tenantId,
microplanId,
triggeredFrom: triggeredFromMain,
});
if (response && !response?.isError) {
window.history.pushState(response?.state, "", response?.redirectTo);
window.dispatchEvent(new PopStateEvent("popstate", { state: response?.state }));
}
if (response && response?.isError) {
console.error(`ERR_FAILED_TO_COMPLETE_SETUP`);
}
} else {
setShowToast({ label:t("PLEASE_FINISH_THE_DRAFT_BEFORE_FREEZING") });
if (response && response?.isError) {
console.error(`ERR_FAILED_TO_COMPLETE_SETUP`);
}
} else {
setShowToast({ label: t("PLEASE_FINISH_THE_DRAFT_BEFORE_FREEZING") });
}
if (e.name == "MP_ACTIONS_VIEW_SUMMARY") {
window.location.href = `/${window.contextPath}/employee/microplan/setup-microplan?key=${11}&microplanId=${row.id}&campaignId=${
row.campaignDetails.id
}
if (e.name == "MP_ACTIONS_VIEW_SUMMARY") {
window.location.href = `/${window.contextPath}/employee/microplan/setup-microplan?key=${11}&microplanId=${row.id}&campaignId=${row.campaignDetails.id
}&setup-completed=true`;
}
};

const handleToast = () => {
setShowToast(false);
};
}
};

return (
<>
const handleToast = () => {
setShowToast(false);
};

Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

⚠️ Potential issue

Invalid Hook usage inside cell renderer; and switch-case declarations leak scope

useState and data hooks are called directly inside additionalCustomizations and within a switch case. This violates React Hook rules and triggers Biome noSwitchDeclarations.

Refactor the ACTIONS cell into a small component and reference it from the switch; also wraps case scope.

-    additionalCustomizations: (row, key, column, value, t, searchResult) => {
-      const [showToast, setShowToast] = useState(false);
-      const tenantId = Digit.ULBService.getCurrentTenantId();
-      const microplanId = row?.id;
-      const { data: rootEstimationApprover } = Digit.Hooks.microplanv1.usePlanSearchEmployeeWithTagging({ ... });
-      const { data: rootPopulationApprover } = Digit.Hooks.microplanv1.usePlanSearchEmployeeWithTagging({ ... });
-      const { data: rootFacilityMapper } = Digit.Hooks.microplanv1.usePlanSearchEmployeeWithTagging({ ... });
-      switch (key) {
-        case "ACTIONS":
-          // ... lots of declarations and hooks ...
-          return (<> ... </>);
+    additionalCustomizations: (row, key, column, value, t, searchResult) => {
+      switch (key) {
+        case "ACTIONS": {
+          return <MicroplanActionsCell row={row} t={t} />;
+        }
         case "NAME_OF_MICROPLAN":
           ...
       }
     },

Add this component (outside the object, anywhere in module scope):

function MicroplanActionsCell({ row, t }) {
  const [showToast, setShowToast] = useState(false);
  const tenantId = Digit.ULBService.getCurrentTenantId();
  const microplanId = row?.id;

  const { data: rootEstimationApprover } = Digit.Hooks.microplanv1.usePlanSearchEmployeeWithTagging({ /* as-is */ });
  const { data: rootPopulationApprover } = Digit.Hooks.microplanv1.usePlanSearchEmployeeWithTagging({ /* as-is */ });
  const { data: rootFacilityMapper } = Digit.Hooks.microplanv1.usePlanSearchEmployeeWithTagging({ /* as-is */ });

  // existing handleDownload / onActionSelect / handleToast logic unchanged
  // but remove dummy file id and rely on real availability
  const EstimationsfileId = row?.files?.find((it) => it.templateIdentifier === "Estimations")?.filestoreId;

  // return the same JSX previously returned for the case
  return (/* same JSX */);
}

Also remove the hard-coded dummyFile and rely on real file presence; disable download button if fileId is absent.

This resolves both hook rules and noSwitchDeclarations warnings.

🧰 Tools
🪛 Biome (2.1.2)

[error] 887-887: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.

The declaration is defined in this switch clause:

Safe fix: Wrap the declaration in a block.

(lint/correctness/noSwitchDeclarations)


[error] 888-888: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.

The declaration is defined in this switch clause:

Safe fix: Wrap the declaration in a block.

(lint/correctness/noSwitchDeclarations)


[error] 889-889: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.

The declaration is defined in this switch clause:

Safe fix: Wrap the declaration in a block.

(lint/correctness/noSwitchDeclarations)


[error] 890-890: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.

The declaration is defined in this switch clause:

Safe fix: Wrap the declaration in a block.

(lint/correctness/noSwitchDeclarations)


[error] 902-916: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.

The declaration is defined in this switch clause:

Safe fix: Wrap the declaration in a block.

(lint/correctness/noSwitchDeclarations)


[error] 918-962: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.

The declaration is defined in this switch clause:

Safe fix: Wrap the declaration in a block.

(lint/correctness/noSwitchDeclarations)


[error] 964-966: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.

The declaration is defined in this switch clause:

Safe fix: Wrap the declaration in a block.

(lint/correctness/noSwitchDeclarations)

Comment on lines +887 to +916
const dummyFile = "c22a7676-d5d7-49b6-bcdb-83e9519f58df"
const microplanFileId = row?.campaignDetails?.additionalDetails?.microplanFileId || dummyFile;
const EstimationsfileId = row?.files.find((item) => item.templateIdentifier === "Estimations")?.filestoreId;
let options = [];

if (row?.status == "DRAFT") {
options = [
{ code: "1", name: "MP_ACTIONS_EDIT_SETUP" },
{ code: "2", name: "MP_ACTIONS_DOWNLOAD_DRAFT" },
{ code: "3", name: "MP_ACTIONS_FREEZE_MICROPLAN" },
];
} else {
options = [{ code: "1", name: "MP_ACTIONS_VIEW_SUMMARY" }];
}

const handleDownload = ({ type }) => {

const template = type === "Estimations" ? "Estimations" : "DraftComplete";
const fileId = row?.files.find((item) => item.templateIdentifier === template)?.filestoreId;
if (!fileId) {
setShowToast({ label: t("NO_DRAFT_FILE_FOUND") });
return;
}

const handleDownload = ({type}) => {

const template = type === "Estimations" ? "Estimations" : "DraftComplete";
const fileId = row?.files.find((item) => item.templateIdentifier === template)?.filestoreId;
if (!fileId) {
setShowToast({ label: t("NO_DRAFT_FILE_FOUND") });
return;
}
const campaignName = row?.name || "";
const customName = type === "Estimations" ? campaignName : `${campaignName}_DRAFT`;
Digit.Utils.campaign.downloadExcelWithCustomName({
fileStoreId: fileId,
customName: customName,
});
};

const onActionSelect = async (e,row) => {
if (e.name === "MP_ACTIONS_EDIT_SETUP") {
const key = parseInt(row?.additionalDetails?.key);
const resolvedKey = key === 8 ? 7 : key === 10 ? 11 : key || 2;
const url = `/${window.contextPath}/employee/microplan/setup-microplan?key=${resolvedKey}&microplanId=${row.id}&campaignId=${row.campaignDetails.id}`;
window.location.href = url;
const campaignName = row?.name || "";
const customName = type === "Estimations" ? campaignName : `${campaignName}_DRAFT`;
Digit.Utils.campaign.downloadExcelWithCustomName({
fileStoreId: fileId,
customName: customName,
});
};
Copy link
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick (assertive)

noSwitchDeclarations: wrap declarations in block scopes

Even if you don’t adopt the component refactor immediately, wrap each case with {} to scope const declarations and satisfy Biome.

-        case "ACTIONS":
+        case "ACTIONS": {
           const dummyFile = ...
           const microplanFileId = ...
           let options = [];
           ...
-          return ( ... );
+          return ( ... );
+        }

Repeat for other cases with inline declarations.

Also applies to: 918-962, 964-966

🧰 Tools
🪛 Biome (2.1.2)

[error] 887-887: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.

The declaration is defined in this switch clause:

Safe fix: Wrap the declaration in a block.

(lint/correctness/noSwitchDeclarations)


[error] 888-888: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.

The declaration is defined in this switch clause:

Safe fix: Wrap the declaration in a block.

(lint/correctness/noSwitchDeclarations)


[error] 889-889: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.

The declaration is defined in this switch clause:

Safe fix: Wrap the declaration in a block.

(lint/correctness/noSwitchDeclarations)


[error] 890-890: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.

The declaration is defined in this switch clause:

Safe fix: Wrap the declaration in a block.

(lint/correctness/noSwitchDeclarations)


[error] 902-916: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.

The declaration is defined in this switch clause:

Safe fix: Wrap the declaration in a block.

(lint/correctness/noSwitchDeclarations)

🤖 Prompt for AI Agents
In health/micro-ui/web/micro-ui-internals/example/src/UICustomizations.js around
lines 887-916 (and also apply same change to 918-962 and 964-966), the
switch/case-like inline branches declare consts in the outer scope; wrap each
case branch in its own block scope by adding { } around the code for that branch
so each const/let is scoped to that block and Biome noSwitchDeclarations is
satisfied; apply the same wrapping to the other listed ranges where inline
declarations occur.

Comment on lines +1108 to +1113
const handleFileDownload = () => {
const fileId = row?.files.find((item) => item.templateIdentifier === "Estimations")?.filestoreId;
if (!fileId) {
console.error("Estimation template file not found");
return;
}
return;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick (assertive)

Action button config misuse

For the action button in MyMicroplanSearchConfig:

  • You pass isSearchable, options, and onOptionSelect but also an onClick no-op. Prefer removing redundant onClick.
  • Guard download button using EstimationsfileId.
-              isSearchable={false}
-              title={t("MP_ACTIONS_FOR_MICROPLANS")}
-              label={t("MP_ACTIONS_FOR_MICROPLANS")}
-              isDisabled={!EstimationsfileId}
-              onClick={() => { }}
+              isSearchable={false}
+              title={t("MP_ACTIONS_FOR_MICROPLANS")}
+              label={t("MP_ACTIONS_FOR_MICROPLANS")}
+              isDisabled={!EstimationsfileId}

Also applies to: 1194-1218

🤖 Prompt for AI Agents
In health/micro-ui/web/micro-ui-internals/example/src/UICustomizations.js around
lines 1108-1113 (and similarly at 1194-1218), the MyMicroplanSearchConfig action
button is being passed redundant props including a no-op onClick and the
download action is not properly guarded by the Estimations file id; remove the
unnecessary onClick prop so only isSearchable, options, and onOptionSelect are
passed, and add a guard that checks the Estimations file id (e.g.,
EstimationsfileId or the lookup for templateIdentifier "Estimations") before
rendering/enabling the download button so the button is hidden/disabled when
that id is missing.

Comment on lines +1 to +12
import React, { useState } from "react";
import { useTranslation } from "react-i18next";
import { PopUp, Timeline, Loader, TextInput, Button } from '@egovernments/digit-ui-components';
import { useEffect } from "react";
import EditAttendanceManagementTable from "./EditAttendanceManagementTable";
import { useHistory } from "react-router-dom";
import AttendeeService from "../services/attendance/attendee_service/attendeeService";

import { useAttendanceSummary } from "../utils/update_attendance_summary";

import SearchUserPopUp from "./SearchUserPopUp";

Copy link
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick (assertive)

Remove unused imports and dead code

Timeline, AttendeeService, and useAttendanceSummary are not used.

-import { PopUp, Timeline, Loader, TextInput, Button } from '@egovernments/digit-ui-components';
+import { PopUp, Loader, TextInput, Button } from '@egovernments/digit-ui-components';
...
-import AttendeeService from "../services/attendance/attendee_service/attendeeService";
-
-import { useAttendanceSummary } from "../utils/update_attendance_summary";
+// removed unused imports

Also applies to: 7-7, 9-10

🤖 Prompt for AI Agents
In
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/editAttendeesPopUp.js
around lines 1-12 (and specifically lines 7 and 9-10), remove the unused imports
Timeline, AttendeeService, and useAttendanceSummary from the import list and
delete any dead code or references related to them; ensure you only keep imports
that are actually used (e.g., PopUp, Loader, TextInput, Button,
EditAttendanceManagementTable, SearchUserPopUp, useTranslation, useState,
useEffect, useHistory), run the linter/TypeScript check to confirm no remaining
unused symbols, and adjust imports formatting if necessary.

Comment on lines +55 to +66
const { isLoading: isAttendanceLoading, data: AttendanceData } =
Digit.Hooks.useCustomAPIHook(AttendancereqCri);

// Extract individualIds once AttendanceData is fetched
useEffect(() => {
if (AttendanceData?.attendanceRegister?.length > 0) {
const ids = AttendanceData.attendanceRegister[0].attendees.map(
(a) => a.individualId
);
setIndividualIds(ids);
}
}, [AttendanceData]);
Copy link
Contributor

Choose a reason for hiding this comment

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

💡 Verification agent

❓ Verification inconclusive

Harden extraction when attendanceRegister or attendees are missing

Avoid runtime errors if API returns empty/malformed data.

-    useEffect(() => {
-        if (AttendanceData?.attendanceRegister?.length > 0) {
-            const ids = AttendanceData.attendanceRegister[0].attendees.map(
-                (a) => a.individualId
-            );
-            setIndividualIds(ids);
-        }
-    }, [AttendanceData]);
+    useEffect(() => {
+        const attendees = AttendanceData?.attendanceRegister?.[0]?.attendees || [];
+        if (Array.isArray(attendees) && attendees.length) {
+            setIndividualIds(attendees.map((a) => a.individualId).filter(Boolean));
+        } else {
+            setIndividualIds([]);
+        }
+    }, [AttendanceData]);

Consider adding an empty state in UI when no attendees exist.


Harden extraction of individualIds in useEffect
Use optional chaining and a safe default to avoid runtime errors when attendanceRegister or attendees is missing:

-    useEffect(() => {
-        if (AttendanceData?.attendanceRegister?.length > 0) {
-            const ids = AttendanceData.attendanceRegister[0].attendees.map(
-                (a) => a.individualId
-            );
-            setIndividualIds(ids);
-        }
-    }, [AttendanceData]);
+    useEffect(() => {
+        const attendees = AttendanceData?.attendanceRegister?.[0]?.attendees ?? [];
+        setIndividualIds(
+            Array.isArray(attendees)
+                ? attendees.map(a => a.individualId).filter(Boolean)
+                : []
+        );
+    }, [AttendanceData]);

Also render an empty-state UI when individualIds is empty.

📝 Committable suggestion

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

Suggested change
const { isLoading: isAttendanceLoading, data: AttendanceData } =
Digit.Hooks.useCustomAPIHook(AttendancereqCri);
// Extract individualIds once AttendanceData is fetched
useEffect(() => {
if (AttendanceData?.attendanceRegister?.length > 0) {
const ids = AttendanceData.attendanceRegister[0].attendees.map(
(a) => a.individualId
);
setIndividualIds(ids);
}
}, [AttendanceData]);
useEffect(() => {
const attendees = AttendanceData?.attendanceRegister?.[0]?.attendees ?? [];
setIndividualIds(
Array.isArray(attendees)
? attendees.map(a => a.individualId).filter(Boolean)
: []
);
}, [AttendanceData]);
🤖 Prompt for AI Agents
In
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/editAttendeesPopUp.js
around lines 55 to 66, the useEffect assumes
AttendanceData.attendanceRegister[0].attendees always exists which can throw if
attendanceRegister or attendees is missing; update the extraction to use
optional chaining and a safe default (e.g., const ids =
AttendanceData?.attendanceRegister?.[0]?.attendees?.map(a => a.individualId) ??
[]; then call setIndividualIds(ids)); additionally, add a simple empty-state
render path in the component UI when individualIds.length === 0 to show a
user-friendly message or placeholder.

Comment on lines 100 to 117
const { isLoading: childrenDataLoading, data: childrenData } = Digit.Hooks.payments.useAttendanceBoundarySearch(reqCriteriaResource);

// Update the dropdown options and state when children data is fetched
useEffect(() => {
if (childrenData && childrenData.length > 0) {
setValue((prevState) => ({
...prevState,
[childrenData[0]?.boundary[0].boundaryType]: [childrenData[0]?.boundary[0]],
}));

const formattedData = createFormattedData(childrenData[0]?.boundary[0].boundaryType);
setBoundaryData(formattedData);
if (!initialValue) {

handleButtonClick(childrenData[0]?.boundary[0]);
}
}
}, [childrenData]);
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Guard against empty boundary arrays in API response

childrenData[0]?.boundary[0] can be undefined even when childrenData.length > 0.

-    useEffect(() => {
-        if (childrenData && childrenData.length > 0) {
-            setValue((prevState) => ({
-                ...prevState,
-                [childrenData[0]?.boundary[0].boundaryType]: [childrenData[0]?.boundary[0]],
-            }));
-            const formattedData = createFormattedData(childrenData[0]?.boundary[0].boundaryType);
-            setBoundaryData(formattedData);
-            if (!initialValue) {
-                handleButtonClick(childrenData[0]?.boundary[0]);
-            }
-        }
-    }, [childrenData]);
+    useEffect(() => {
+        const first = childrenData?.[0]?.boundary?.[0];
+        if (first?.boundaryType && first?.code) {
+            setValue((prevState) => ({
+                ...prevState,
+                [first.boundaryType]: [first],
+            }));
+            setBoundaryData(createFormattedData(first.boundaryType));
+            if (!initialValue) handleButtonClick(first);
+        }
+    }, [childrenData, initialValue]);
📝 Committable suggestion

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

Suggested change
const { isLoading: childrenDataLoading, data: childrenData } = Digit.Hooks.payments.useAttendanceBoundarySearch(reqCriteriaResource);
// Update the dropdown options and state when children data is fetched
useEffect(() => {
if (childrenData && childrenData.length > 0) {
setValue((prevState) => ({
...prevState,
[childrenData[0]?.boundary[0].boundaryType]: [childrenData[0]?.boundary[0]],
}));
const formattedData = createFormattedData(childrenData[0]?.boundary[0].boundaryType);
setBoundaryData(formattedData);
if (!initialValue) {
handleButtonClick(childrenData[0]?.boundary[0]);
}
}
}, [childrenData]);
const { isLoading: childrenDataLoading, data: childrenData } = Digit.Hooks.payments.useAttendanceBoundarySearch(reqCriteriaResource);
// Update the dropdown options and state when children data is fetched
useEffect(() => {
const first = childrenData?.[0]?.boundary?.[0];
if (first?.boundaryType && first?.code) {
setValue((prevState) => ({
...prevState,
[first.boundaryType]: [first],
}));
setBoundaryData(createFormattedData(first.boundaryType));
if (!initialValue) handleButtonClick(first);
}
}, [childrenData, initialValue]);
🤖 Prompt for AI Agents
In
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/SearchAttendeeBoundary.js
around lines 100 to 117, the code assumes childrenData[0].boundary[0] exists;
update the effect to guard against empty or missing boundary arrays by first
finding the first childrenData item that has a non-empty boundary (e.g., const
item = childrenData.find(c => Array.isArray(c.boundary) && c.boundary.length >
0)); only access item.boundary[0] after that null check; then use that safeItem
to setValue, compute formattedData and call handleButtonClick when initialValue
is falsy. Ensure all optional chaining is removed where necessary and return
early from the effect if no suitable item is found.

Comment on lines 228 to 235
<span
onClick={() => {
setReset(true);
}}
style={{ border: "1px solid #e0e0e0", padding: "6px", marginBottom: "10px", cursor: "pointer" }}
>
<SVG.AutoRenew width={"24px"} height={"24px"} fill={"#c84c0e"} />
</span>
Copy link
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick (assertive)

🛠️ Refactor suggestion

Fix a11y: interactive span without keyboard support

Use a button with proper role/label and keyboard handling. Also resolves Biome a11y errors.

-                <span
-                    onClick={() => {
-                        setReset(true);
-                    }}
-                    style={{ border: "1px solid #e0e0e0", padding: "6px", marginBottom: "10px", cursor: "pointer" }}
-                >
-                    <SVG.AutoRenew width={"24px"} height={"24px"} fill={"#c84c0e"} />
-                </span>
+                <button
+                    type="button"
+                    aria-label={t?.("RESET") || "Reset"}
+                    onClick={() => setReset(true)}
+                    style={{ border: "1px solid #e0e0e0", padding: "6px", marginBottom: "10px", cursor: "pointer", background: "transparent" }}
+                >
+                    <SVG.AutoRenew width={"24px"} height={"24px"} fill={"#c84c0e"} />
+                </button>

I can also replace this inline style with a themed class if you share the design token.

📝 Committable suggestion

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

Suggested change
<span
onClick={() => {
setReset(true);
}}
style={{ border: "1px solid #e0e0e0", padding: "6px", marginBottom: "10px", cursor: "pointer" }}
>
<SVG.AutoRenew width={"24px"} height={"24px"} fill={"#c84c0e"} />
</span>
<button
type="button"
aria-label={t?.("RESET") || "Reset"}
onClick={() => setReset(true)}
style={{
border: "1px solid #e0e0e0",
padding: "6px",
marginBottom: "10px",
cursor: "pointer",
background: "transparent"
}}
>
<SVG.AutoRenew width="24px" height="24px" fill="#c84c0e" />
</button>
🧰 Tools
🪛 Biome (2.1.2)

[error] 228-233: Static Elements should not be interactive.

To add interactivity such as a mouse or key event listener to a static element, give the element an appropriate role value.

(lint/a11y/noStaticElementInteractions)


[error] 228-233: Enforce to have the onClick mouse event with the onKeyUp, the onKeyDown, or the onKeyPress keyboard event.

Actions triggered using mouse events should have corresponding keyboard events to account for keyboard-only navigation.

(lint/a11y/useKeyWithClickEvents)

🤖 Prompt for AI Agents
In
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/SearchAttendeeBoundary.js
around lines 228-235, the interactive span lacks keyboard accessibility and
semantic meaning; replace the span with a <button type="button">, move the
inline styles to a themed CSS class (or keep styles but ensure focus styles are
visible), add an accessible label like aria-label="Reset" (or visually-hidden
text) and preserve the onClick handler as onClick={() => setReset(true)}; do not
add role attributes for a native button and ensure it remains focusable and
operable via keyboard.

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
health/micro-ui/web/micro-ui-internals/example/src/UICustomizations.js (1)

54-60: Epoch unit mismatch: comment says seconds, code returns milliseconds.

Align docs or logic.

-  // Convert the date to epoch time (seconds)
-  return Math.floor(date.getTime());
+  // Convert the date to epoch time (milliseconds)
+  return Math.floor(date.getTime());

If backend expects seconds, divide by 1000 instead and update all call sites accordingly.

♻️ Duplicate comments (10)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/pages/employee/AttendeeSearchAssign.js (1)

1-2: Remove unused imports (and unused React hook).

Neither useState, HeaderComponent, Toast, nor Loader are used. Clean up imports to satisfy linters and reduce bundle size.

-import React, { useState } from "react";
-import { InboxSearchComposer, HeaderComponent, Toast, Loader } from "@egovernments/digit-ui-components";
+import React from "react";
+import { InboxSearchComposer } from "@egovernments/digit-ui-components";
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/config/AttendeeInboxConfig.js (4)

132-134: Avoid hard-coded tenantId. Use current tenant.

"dev" will break in other envs.

           defaultValues: {
@@
-            tenantId: "dev",
+            tenantId: Digit.ULBService.getCurrentTenantId(),
@@
       requestParam: {
@@
-        tenantId: "dev",
+        tenantId: Digit.ULBService.getCurrentTenantId(),

Also applies to: 203-205


171-174: ASSIGNMENT column lacks jsonPath, will render empty.

Provide the correct path or remove the column.

           {
             label: "ASSIGNMENT",
-              //jsonPath: "assignments[0]",
+            jsonPath: "assignments[0]",
             additionalCustomization: true,
           },

175-179: Remove commented-out column block.

Dead code.

-            // {
-            //   label: "HR_EMPLOYMENT_DEPARTMENT_LABEL",
-            //   jsonPath: "assignments[0]",
-            //   additionalCustomization: true,
-            // },

214-214: Remove commented component reference.

Not used.

-    //component: BoundaryComponent,
health/micro-ui/web/micro-ui-internals/example/src/UICustomizations.js (5)

810-823: Duplicate/overwritten fields in MicroplanSearchConfig.preProcess.

name is set twice; status is overridden later by tab filter. Set each once.

-      const { name, status } = data?.state?.searchForm || {};
+      const { name, microplanName } = data?.state?.searchForm || {};
@@
-      data.body.PlanConfigurationSearchCriteria.name = name;
+      if (microplanName) {
+        data.body.PlanConfigurationSearchCriteria.name = microplanName;
+      } else if (name) {
+        data.body.PlanConfigurationSearchCriteria.name = name;
+      }
@@
-      data.body.PlanConfigurationSearchCriteria.status = status?.status;
-      data.body.PlanConfigurationSearchCriteria.name = data?.state?.searchForm?.microplanName;
+      // status set via tab mapping below

839-882: Invalid React Hook usage inside cell renderer (and switch-case scope leaks).

useState and data hooks are called inside additionalCustomizations; violates Hook rules. Also consts declared directly in case without block.

  • Extract ACTIONS cell into a React component and return it from the case.
  • Wrap each case with { } to satisfy noSwitchDeclarations.

Minimal change to scope the case:

-        case "ACTIONS":
+        case "ACTIONS": {
@@
-          return (
+          return (
             <>
               ...
             </>
           );
+        }

Recommended: move logic into a component:

// outside UICustomizations object
function MicroplanActionsCell({ row, t }) {
  const [showToast, setShowToast] = React.useState(false);
  const tenantId = Digit.ULBService.getCurrentTenantId();
  const microplanId = row?.id;
  const { data: rootEstimationApprover } = Digit.Hooks.microplanv1.usePlanSearchEmployeeWithTagging({/* as-is */});
  const { data: rootPopulationApprover } = Digit.Hooks.microplanv1.usePlanSearchEmployeeWithTagging({/* as-is */});
  const { data: rootFacilityMapper } = Digit.Hooks.microplanv1.usePlanSearchEmployeeWithTagging({/* as-is */});
  // handlers unchanged...
  return (/* existing JSX */);
}

Then:

-        case "ACTIONS": { /* long inline hook logic */ }
+        case "ACTIONS": {
+          return <MicroplanActionsCell row={row} t={t} />;
+        }

Also applies to: 884-967


1194-1218: Action button: remove no-op onClick; guard by file presence only.

Keeps props minimal and avoids misleading handler.

-              isSearchable={false}
-              title={t("MP_ACTIONS_FOR_MICROPLANS")}
-              label={t("MP_ACTIONS_FOR_MICROPLANS")}
-              isDisabled={!EstimationsfileId}
-              onClick={() => { }}
+              isSearchable={false}
+              title={t("MP_ACTIONS_FOR_MICROPLANS")}
+              label={t("MP_ACTIONS_FOR_MICROPLANS")}
+              isDisabled={!EstimationsfileId}

2621-2636: Remove console logs and guard string trims in AttendeeSearchInboxConfig.preProcess.

Prevent runtime errors when fields are absent and keep console clean.

-      console.log(data)
+      // logs removed
@@
-      const { phone, names, codes } = data.state.searchForm;
+      const { phone, names, codes } = data.state.searchForm || {};
@@
-      if (phone && phone.trim() !== "") {
+      if (typeof phone === "string" && phone.trim() !== "") {
         Individual.mobileNumber = [phone];
       }
@@
-      if (names && names.trim() !== "") {
+      if (typeof names === "string" && names.trim() !== "") {
         Individual.name = { givenName: names };
       }
@@
-      if (codes && codes.trim() !== "") {
+      if (typeof codes === "string" && codes.trim() !== "") {
         Individual.username = [codes];
       }
@@
-      if (boundaryCode && boundaryCode.trim() !== "") {
+      if (typeof boundaryCode === "string" && boundaryCode.trim() !== "") {
         Individual.locality = {
           id: null,
           tenantId: null,
           code: boundaryCode,
           geometry: null,
           auditDetails: null,
           additionalDetails: null,
         };
       }
@@
-      console.log("payload", data)
+      // logs removed

Also applies to: 2659-2694, 2707-2709


2767-2769: Avoid window.history.back() after assignment.

Post-success back navigation can be jarring. Prefer closing toast/modal and refreshing results.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4884c43 and be4bc7d.

⛔ Files ignored due to path filters (1)
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/package.json is excluded by !**/*.json
📒 Files selected for processing (3)
  • health/micro-ui/web/micro-ui-internals/example/src/UICustomizations.js (24 hunks)
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/config/AttendeeInboxConfig.js (1 hunks)
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/pages/employee/AttendeeSearchAssign.js (1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.js

⚙️ CodeRabbit configuration file

check

Files:

  • health/micro-ui/web/micro-ui-internals/example/src/UICustomizations.js
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/pages/employee/AttendeeSearchAssign.js
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/config/AttendeeInboxConfig.js
🧠 Learnings (8)
📚 Learning: 2024-11-07T11:02:33.520Z
Learnt from: rachana-egov
PR: egovernments/DIGIT-Frontend#1770
File: health/micro-ui/web/micro-ui-internals/packages/modules/microplan/src/pages/employee/viewVillage.js:320-322
Timestamp: 2024-11-07T11:02:33.520Z
Learning: In `health/micro-ui/web/micro-ui-internals/packages/modules/microplan/src/pages/employee/viewVillage.js`, the `data?.additionalFields` object is guaranteed to be defined, so checking for its existence before accessing its keys is unnecessary.

Applied to files:

  • health/micro-ui/web/micro-ui-internals/example/src/UICustomizations.js
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/config/AttendeeInboxConfig.js
📚 Learning: 2024-10-26T15:11:49.938Z
Learnt from: nabeelmd-eGov
PR: egovernments/DIGIT-Frontend#1680
File: health/micro-ui/web/micro-ui-internals/example/src/UICustomizations.js:1032-1094
Timestamp: 2024-10-26T15:11:49.938Z
Learning: In the DIGIT-Frontend project, when reviewing the `UICustomizations.js` file, avoid suggesting refactoring of repetitive rendering logic in switch cases into helper functions, unless explicitly requested.

Applied to files:

  • health/micro-ui/web/micro-ui-internals/example/src/UICustomizations.js
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/pages/employee/AttendeeSearchAssign.js
📚 Learning: 2024-11-07T07:17:27.636Z
Learnt from: jagankumar-egov
PR: egovernments/DIGIT-Frontend#1763
File: health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/MyCampaign.js:65-75
Timestamp: 2024-11-07T07:17:27.636Z
Learning: In `MyCampaign.js`, when suggesting code improvements for the `onClickRow` function, keep suggestions simple and avoid unnecessary complexity.

Applied to files:

  • health/micro-ui/web/micro-ui-internals/example/src/UICustomizations.js
📚 Learning: 2024-06-10T19:25:42.992Z
Learnt from: siddhant-nawale-egov
PR: egovernments/DIGIT-Frontend#698
File: micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanPreview.js:1-1
Timestamp: 2024-06-10T19:25:42.992Z
Learning: The imports in `MicroplanPreview.js` are from different libraries: `egovernments/digit-ui-components` and `egovernments/digit-ui-react-components`.

Applied to files:

  • health/micro-ui/web/micro-ui-internals/example/src/UICustomizations.js
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/pages/employee/AttendeeSearchAssign.js
📚 Learning: 2024-10-08T20:11:12.539Z
Learnt from: siddhant-nawale-egov
PR: egovernments/DIGIT-Frontend#691
File: micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/Upload.js:16-17
Timestamp: 2024-10-08T20:11:12.539Z
Learning: The components `Loader`, `Toast`, and `Modal` are from different libraries in the DIGIT-Frontend project, as clarified by the user.

Applied to files:

  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/pages/employee/AttendeeSearchAssign.js
📚 Learning: 2025-06-04T04:08:48.234Z
Learnt from: jagankumar-egov
PR: egovernments/DIGIT-Frontend#2488
File: micro-ui/web/micro-ui-internals/packages/modules/core/src/pages/employee/Login/login.js:152-152
Timestamp: 2025-06-04T04:08:48.234Z
Learning: In the employee login component (micro-ui/web/micro-ui-internals/packages/modules/core/src/pages/employee/Login/login.js), prefer using a `defaultTenant` variable to store `Digit.ULBService.getStateId()` instead of calling the function multiple times inline in the `defaultValue` object. This improves code readability and avoids function call duplication.

Applied to files:

  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/config/AttendeeInboxConfig.js
📚 Learning: 2025-01-02T04:41:15.957Z
Learnt from: jagankumar-egov
PR: egovernments/DIGIT-Frontend#2089
File: micro-ui/web/micro-ui-internals/packages/modules/workbench/src/pages/employee/MDMSAddV2.js:111-111
Timestamp: 2025-01-02T04:41:15.957Z
Learning: In micro-ui/web/micro-ui-internals/packages/modules/workbench/src/pages/employee/MDMSAddV2.js, always use "mdms[0].uniqueIdentifier" for the jsonPath instead of differentiating between "SOR" and other masters.

Applied to files:

  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/config/AttendeeInboxConfig.js
📚 Learning: 2025-07-15T04:58:30.634Z
Learnt from: Hari-egov
PR: egovernments/DIGIT-Frontend#2788
File: micro-ui/web/micro-ui-internals/packages/modules/hrms/src/components/pageComponents/jurisdiction.js:26-26
Timestamp: 2025-07-15T04:58:30.634Z
Learning: In the HRMS module (micro-ui/web/micro-ui-internals/packages/modules/hrms/src/components/pageComponents/jurisdiction.js), the team has moved away from using MDMS hooks for boundary data fetching and now uses direct API calls to the boundary service endpoint `/boundary-service/boundary-relationships/_search` instead of the `useHrmsMDMS` hook with "FetchBoundaries" parameter.

Applied to files:

  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/config/AttendeeInboxConfig.js
🧬 Code graph analysis (1)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/pages/employee/AttendeeSearchAssign.js (1)
micro-ui/web/micro-ui-internals/packages/react-components/src/hoc/InboxSearchComposer.js (1)
  • InboxSearchComposer (19-322)
🪛 Biome (2.1.2)
health/micro-ui/web/micro-ui-internals/example/src/UICustomizations.js

[error] 887-887: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.

The declaration is defined in this switch clause:

Safe fix: Wrap the declaration in a block.

(lint/correctness/noSwitchDeclarations)


[error] 888-888: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.

The declaration is defined in this switch clause:

Safe fix: Wrap the declaration in a block.

(lint/correctness/noSwitchDeclarations)


[error] 889-889: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.

The declaration is defined in this switch clause:

Safe fix: Wrap the declaration in a block.

(lint/correctness/noSwitchDeclarations)


[error] 890-890: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.

The declaration is defined in this switch clause:

Safe fix: Wrap the declaration in a block.

(lint/correctness/noSwitchDeclarations)


[error] 902-916: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.

The declaration is defined in this switch clause:

Safe fix: Wrap the declaration in a block.

(lint/correctness/noSwitchDeclarations)


[error] 918-962: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.

The declaration is defined in this switch clause:

Safe fix: Wrap the declaration in a block.

(lint/correctness/noSwitchDeclarations)


[error] 964-966: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.

The declaration is defined in this switch clause:

Safe fix: Wrap the declaration in a block.

(lint/correctness/noSwitchDeclarations)

⏰ Context from checks skipped due to timeout of 10000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (2)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/config/AttendeeInboxConfig.js (1)

181-189: Verify API response paths.

Confirm resultsJsonPath ("Individual") and totalCountJsonPath ("TotalCount") match the /health-individual/v1/_search response.

Would you confirm the exact keys returned by that endpoint so we can align the jsonPaths?

Also applies to: 192-213

health/micro-ui/web/micro-ui-internals/example/src/UICustomizations.js (1)

1587-1594: PGR preProcess cleanup looks good.

Range extraction and normalization are handled defensively. No action.

Also applies to: 1595-1602, 1613-1630, 1631-1641

Comment on lines 1442 to 1454
const tenantId = Digit.ULBService.getCurrentTenantId();
const {campaignId} = Digit.Hooks.useQueryParams();
const { campaignId } = Digit.Hooks.useQueryParams();
return {
url: `/project-factory/v1/project-type/search`,
params: { },
params: {},
body: {
CampaignDetails: {
"tenantId": tenantId,
"ids": [
campaignId
]
}
}
},
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Avoid calling useQueryParams() inside utility getFacilitySearchRequest.

Treat it as a pure function: read campaignId from props or additionalDetails.

-      const { campaignId } = Digit.Hooks.useQueryParams();
+      const { campaignId } = prop; // expect caller to pass campaignId
@@
-            "ids": [
-              campaignId
-            ]
+            "ids": [campaignId]

Update callers to pass { campaignId }.

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In health/micro-ui/web/micro-ui-internals/example/src/UICustomizations.js around
lines 1442-1454, getFacilitySearchRequest currently calls
Digit.Hooks.useQueryParams() to read campaignId inside the utility, which
violates purity; change the function to accept campaignId (e.g., via props or
additionalDetails) instead of calling useQueryParams(), remove the hook call
from the utility, and update every caller of getFacilitySearchRequest to pass {
campaignId } (or include it on additionalDetails) so the function remains a pure
utility that only builds and returns the request object.

Comment on lines 35 to 49
{/* { <div
// style={
// isMobile
// ? { marginLeft: "-12px", fontFamily: "calibri", color: "#FF0000" }
// : { marginLeft: "15px", fontFamily: "calibri", color: "#FF0000" }
// }
>
{
// <HeaderComponent className="digit-inbox-search-composer-header" styles={{ marginBottom: "1.5rem" }}>
// {t("HR_HOME_SEARCH_RESULTS_HEADING")}
// </HeaderComponent>
}
{t("HR_HOME_SEARCH_RESULTS_HEADING")}
</div>} */}
Copy link
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick (assertive)

Delete commented header block.

Dead comment noise. If you want a header, prefer passing headerLabel to InboxSearchComposer (see next comment).

-      {/* { <div
-        // style={
-        //   isMobile
-        //     ? { marginLeft: "-12px", fontFamily: "calibri", color: "#FF0000" }
-        //     : { marginLeft: "15px", fontFamily: "calibri", color: "#FF0000" }
-        // }
-      >
-        {
-        //   <HeaderComponent className="digit-inbox-search-composer-header" styles={{ marginBottom: "1.5rem" }}>
-        //     {t("HR_HOME_SEARCH_RESULTS_HEADING")}
-        //   </HeaderComponent>
-        }
-
-        {t("HR_HOME_SEARCH_RESULTS_HEADING")}
-      </div>} */}
+      {/* header intentionally omitted */}
📝 Committable suggestion

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

Suggested change
{/* { <div
// style={
// isMobile
// ? { marginLeft: "-12px", fontFamily: "calibri", color: "#FF0000" }
// : { marginLeft: "15px", fontFamily: "calibri", color: "#FF0000" }
// }
>
{
// <HeaderComponent className="digit-inbox-search-composer-header" styles={{ marginBottom: "1.5rem" }}>
// {t("HR_HOME_SEARCH_RESULTS_HEADING")}
// </HeaderComponent>
}
{t("HR_HOME_SEARCH_RESULTS_HEADING")}
</div>} */}
{/* header intentionally omitted */}
🤖 Prompt for AI Agents
In
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/pages/employee/AttendeeSearchAssign.js
around lines 35 to 49, remove the entire commented-out header block (the
JSX/HTML comment wrapping the unused div/HeaderComponent and style fragments) to
clean up dead comment noise; if a header is required later, pass headerLabel
into InboxSearchComposer instead of keeping this commented code.

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
health/micro-ui/web/micro-ui-internals/example/src/UICustomizations.js (3)

54-60: Comment mismatch: returns milliseconds, not seconds

Either rename or fix the comment to avoid confusion.

-  // Convert the date to epoch time (seconds)
+  // Convert the date to epoch time (milliseconds)

118-121: Hardcoded tenant in SearchDefaultConfig (Projects path)

tenantId: "mz" is hardcoded. Consider using Digit.ULBService.getCurrentTenantId() unless this is intentional for a sandbox view.

Also applies to: 652-654


171-177: Remove hardcoded tenantIds and debug logs in example UICustomizations

  • In health/micro-ui/web/micro-ui-internals/example/src/UICustomizations.js, line 534: replace tenantId: "tenantId" with dynamic retrieval.
  • In the same file, line 653: remove the hardcoded "mz" literal.
  • Remove all console.log calls at lines 1154, 2620, 2707 (and the commented debug on line 1502).
♻️ Duplicate comments (19)
health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/components/pageComponents/UserAssigment.js (9)

1-1: Rename file to fix typo and align imports

Use UserAssignment.js and update all imports (e.g., in Module.js).


2-12: Prune unused imports

useTranslation, HeaderComponent, Card, Button, Toast aren’t used.

Apply:

-import { useTranslation } from "react-i18next";
-import {
-    Dropdown,
-    Loader,
-    HeaderComponent,
-    Card,
-    LabelFieldPair,
-    Button,
-    Toast,
-    CardLabel
-} from "@egovernments/digit-ui-components";
+import {
+    Dropdown,
+    Loader,
+    LabelFieldPair,
+    CardLabel
+} from "@egovernments/digit-ui-components";

22-22: Use current tenant, not state

Align with HRMS usage patterns.

-    const tenantId = Digit.ULBService.getStateId();
+    const tenantId = Digit.ULBService.getCurrentTenantId();

24-26: Avoid hard-coded service path; honor INDIVIDUAL_CONTEXT_PATH

Keep endpoints configurable.

-    const reqCri = {
-        url: `/health-individual/v1/_search`,
+    const individualContextPath = window?.globalConfigs?.getConfig("INDIVIDUAL_CONTEXT_PATH") || "health-individual";
+    const reqCri = {
+        url: `/${individualContextPath}/v1/_search`,
+        method: "POST",

45-51: Guard fetch by boundary and remove debug log; harden selector

Prevent unnecessary calls and avoid PII logs.

         config: {
-            enabled: true,
-            select: (data) => {
-
-                console.log("data", data);
-                return data.Individual;
-            },
+            enabled: Boolean(boundaryCode),
+            select: (data) => data?.Individual ?? [],
         },

56-56: Remove PII-leaking debug log

Avoid logging user data in production.

-    console.log("assignTo", individualData);
+    // debug log removed

62-67: Harden option mapping and avoid blank labels

Fallback to username or a translated NA.

-        const result = individualData.map(item => ({
-            code: item.id,
-            name: item.name?.givenName || null
-        }));
+        const result = individualData.map((item) => ({
+            code: item?.id,
+            name: item?.name?.givenName || item?.userDetails?.username || (t ? t("NA") : "NA"),
+        }));

80-85: Don’t pass t to Dropdown for human names; remove fixed width

Passing t causes names to be run through i18n; also replace hard-coded width.

-                <Dropdown
-                    style={{ width: "40rem" }}
-                    t={t}
+                <Dropdown
+                    className="w-100"
                     option={options}
                     optionKey={"name"}
                     selected={selectedHierarchy}

76-79: Avoid inline width on label; prefer CSS class

Inline 50.1% is brittle; use a class for responsive layout.

-            <CardLabel style={{ width: "50.1%" }} className="digit-card-label-smaller">
+            <CardLabel className="digit-card-label-smaller user-assignment__label">

Add CSS: .user-assignment__label { /* responsive width rules */ }

health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/config/AttendeeInboxConfig.js (5)

171-174: ASSIGNMENT column lacks jsonPath

Add the correct jsonPath or remove the column to avoid an empty cell.

             {
               label: "ASSIGNMENT",
-              //jsonPath: "assignments[0]",
+              jsonPath: "assignments[0]", // verify payload shape; adjust if needed
               additionalCustomization: true,
             },

Would you like me to wire a renderer for this column similar to HRMS?


132-134: Remove hardcoded tenantId ("dev") in defaultValues

Use the current tenant dynamically.

-            tenantId: "dev",
+            tenantId: Digit.ULBService.getCurrentTenantId(),

175-179: Remove stale commented block

Clean up the commented HR_EMPLOYMENT_DEPARTMENT_LABEL column.

-            // {
-            //   label: "HR_EMPLOYMENT_DEPARTMENT_LABEL",
-            //   jsonPath: "assignments[0]",
-            //   additionalCustomization: true,
-            // },

203-205: Remove hardcoded tenantId ("dev") in apiDetails.requestParam

Use the runtime tenant.

-        tenantId: "dev",
+        tenantId: Digit.ULBService.getCurrentTenantId(),

214-214: Delete commented component entry

Drop the dead line to reduce noise.

-    //component: BoundaryComponent,
health/micro-ui/web/micro-ui-internals/example/src/UICustomizations.js (5)

1108-1218: Action button: remove redundant onClick and guard download

The action button passes a no-op onClick and should rely on onOptionSelect; ensure disabled when no file.

-            <ButtonNew
-              isSearchable={false}
-              title={t("MP_ACTIONS_FOR_MICROPLANS")}
-              label={t("MP_ACTIONS_FOR_MICROPLANS")}
-              isDisabled={!EstimationsfileId}
-              onClick={() => { }}
+            <ButtonNew
+              isSearchable={false}
+              title={t("MP_ACTIONS_FOR_MICROPLANS")}
+              label={t("MP_ACTIONS_FOR_MICROPLANS")}
+              isDisabled={!EstimationsfileId}
               variation="primary"
               onOptionSelect={(option) => onOptionSelect(option)}
               options={[ /* as-is */ ]}
               optionsKey="name"
               showBottom={true}
               style={{ width: "290px" }}
               type="actionButton"
               className="my-microplans-action-button"
             />

810-823: Duplicate assignments and unclear precedence in MicroplanSearchConfig.preProcess

name and status are assigned twice; tab filter overrides form without explanation. Simplify and document precedence.

-      const { name, status } = data?.state?.searchForm || {};
+      const { name } = data?.state?.searchForm || {};
@@
-      data.body.PlanConfigurationSearchCriteria.name = name;
+      data.body.PlanConfigurationSearchCriteria.name = name;
@@
-      data.body.PlanConfigurationSearchCriteria.status = status?.status;
-      data.body.PlanConfigurationSearchCriteria.name = data?.state?.searchForm?.microplanName;
+      // If microplanName is provided, it takes precedence over 'name'
+      if (data?.state?.searchForm?.microplanName) {
+        data.body.PlanConfigurationSearchCriteria.name = data.state.searchForm.microplanName;
+      }

Then tabId mapping below sets status once; keep only that.


1442-1454: Avoid using hooks inside utility (getFacilitySearchRequest)

useQueryParams() violates rules in a non-component. Accept campaignId via args.

-    getFacilitySearchRequest: (prop) => {
+    getFacilitySearchRequest: (prop) => {
       const tenantId = Digit.ULBService.getCurrentTenantId();
-      const { campaignId } = Digit.Hooks.useQueryParams();
+      const { campaignId } = prop; // pass in from caller
@@
-        body: {
+        body: {
           CampaignDetails: {
             "tenantId": tenantId,
             "ids": [
               campaignId
             ]
           }
         },

Update callers accordingly.


2614-2709: AttendeeSearchInboxConfig.preProcess: remove logs and guard trims

Avoid console noise; .trim() on non-strings can throw. Build Individual defensively.

-      console.log(data)
+      // console.log removed
@@
-      const { phone, names, codes } = data.state.searchForm;
+      const { phone, names, codes } = data.state.searchForm || {};
@@
-      const boundaryCode = data.state.filterForm.AttendeeBoundaryComponent
-        || Digit?.SessionStorage.get("selectedBoundary")?.code;
+      const boundaryCode = data?.state?.filterForm?.AttendeeBoundaryComponent
+        || Digit?.SessionStorage?.get("selectedBoundary")?.code;
@@
-      if (phone && phone.trim() !== "") {
+      if (typeof phone === "string" && phone.trim() !== "") {
         Individual.mobileNumber = [phone];
       }
@@
-      if (names && names.trim() !== "") {
+      if (typeof names === "string" && names.trim() !== "") {
         Individual.name = { givenName: names };
       }
@@
-      if (codes && codes.trim() !== "") {
+      if (typeof codes === "string" && codes.trim() !== "") {
         Individual.username = [codes];
       }
@@
-      if (boundaryCode && boundaryCode.trim() !== "") {
+      if (typeof boundaryCode === "string" && boundaryCode.trim() !== "") {
         Individual.locality = {
           id: null,
           tenantId: null,
           code: boundaryCode,
           geometry: null,
           auditDetails: null,
           additionalDetails: null,
         };
       }
@@
-      console.log("payload", data)
+      // console.log removed

839-906: Invalid Hook usage inside cell renderer; heavy logic in switch; dummy file id

Hooks (useState, data hooks) are called inside additionalCustomizations, violating React rules; case-level consts also hit noSwitchDeclarations; remove hardcoded dummy file id.

Minimal safe fix (wrap case in a block and drop dummy), or preferred refactor to a component:

Preferred (extract ACTIONS to component):

-    additionalCustomizations: (row, key, column, value, t, searchResult) => {
-      const [showToast, setShowToast] = useState(false);
-      const tenantId = Digit.ULBService.getCurrentTenantId();
-      const microplanId = row?.id;
-      const { data: rootEstimationApprover } = Digit.Hooks.microplanv1.usePlanSearchEmployeeWithTagging({ ... });
-      const { data: rootPopulationApprover } = Digit.Hooks.microplanv1.usePlanSearchEmployeeWithTagging({ ... });
-      const { data: rootFacilityMapper } = Digit.Hooks.microplanv1.usePlanSearchEmployeeWithTagging({ ... });
+    additionalCustomizations: (row, key, column, value, t, searchResult) => {
       switch (key) {
-        case "ACTIONS":
-          // TODO : Replace dummy file id with real file id when API is ready
-          const dummyFile = "c22a7676-d5d7-49b6-bcdb-83e9519f58df"
-          const microplanFileId = row?.campaignDetails?.additionalDetails?.microplanFileId || dummyFile;
-          const EstimationsfileId = row?.files.find((item) => item.templateIdentifier === "Estimations")?.filestoreId;
-          let options = [];
+        case "ACTIONS": {
+          return <MicroplanActionsCell row={row} t={t} />;
+        }
         case "NAME_OF_MICROPLAN":
           ...
       }
     },

Add component (outside the object):

function MicroplanActionsCell({ row, t }) {
  const [showToast, setShowToast] = React.useState(false);
  const tenantId = Digit.ULBService.getCurrentTenantId();
  const microplanId = row?.id;

  const { data: rootEstimationApprover } = Digit.Hooks.microplanv1.usePlanSearchEmployeeWithTagging({ tenantId, body:{ PlanEmployeeAssignmentSearchCriteria:{ tenantId, planConfigurationId: microplanId, role:["ROOT_PLAN_ESTIMATION_APPROVER"], active:true } }, config:{ enabled:true }});
  const { data: rootPopulationApprover } = Digit.Hooks.microplanv1.usePlanSearchEmployeeWithTagging({ tenantId, body:{ PlanEmployeeAssignmentSearchCriteria:{ tenantId, planConfigurationId: microplanId, role:["ROOT_POPULATION_DATA_APPROVER"], active:true } }, config:{ enabled:true }});
  const { data: rootFacilityMapper } = Digit.Hooks.microplanv1.usePlanSearchEmployeeWithTagging({ tenantId, body:{ PlanEmployeeAssignmentSearchCriteria:{ tenantId, planConfigurationId: microplanId, role:["ROOT_FACILITY_CATCHMENT_MAPPER"], active:true } }, config:{ enabled:true }});

  const EstimationsfileId = row?.files?.find((i) => i.templateIdentifier === "Estimations")?.filestoreId;
  const microplanFileId = row?.campaignDetails?.additionalDetails?.microplanFileId;

  const handleDownload = ({ type }) => {
    const template = type === "Estimations" ? "Estimations" : "DraftComplete";
    const fileId = row?.files?.find((i) => i.templateIdentifier === template)?.filestoreId;
    if (!fileId) { setShowToast({ label: t("NO_DRAFT_FILE_FOUND") }); return; }
    const campaignName = row?.name || "";
    const customName = type === "Estimations" ? campaignName : `${campaignName}_DRAFT`;
    Digit.Utils.campaign.downloadExcelWithCustomName({ fileStoreId: fileId, customName });
  };

  // ... keep onActionSelect / handleToast from current case, unchanged ...
  return (
    <>
      {microplanFileId && row?.status === "RESOURCE_ESTIMATIONS_APPROVED" ? (
        <ButtonNew style={{ width: "20rem" }} icon="DownloadIcon" onClick={() => handleDownload({ type: "Estimations" })} label={t("WBH_DOWNLOAD_MICROPLAN")} title={t("WBH_DOWNLOAD_MICROPLAN")} isDisabled={!EstimationsfileId} />
      ) : (
        <div className="action-button-open-microplan">
          <ButtonNew type="actionButton" variation="secondary" label={t("MP_ACTIONS_FOR_MICROPLAN_SEARCH")} title={t("MP_ACTIONS_FOR_MICROPLAN_SEARCH")} options={[/* as-is from code */]} style={{ width: "20rem" }} optionsKey="name" showBottom isSearchable={false} onOptionSelect={(item) => onActionSelect(item, row)} />
        </div>
      )}
      {showToast && <Toast type={showToast?.type || "warning"} label={showToast?.label} onClose={() => setShowToast(false)} />}
    </>
  );
}

If you prefer not to extract, at least wrap the case in {} and delete the dummy id.

Also applies to: 918-967, 968-997

📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between be4bc7d and 1246f82.

📒 Files selected for processing (3)
  • health/micro-ui/web/micro-ui-internals/example/src/UICustomizations.js (24 hunks)
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/components/pageComponents/UserAssigment.js (1 hunks)
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/config/AttendeeInboxConfig.js (1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.js

⚙️ CodeRabbit configuration file

check

Files:

  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/config/AttendeeInboxConfig.js
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/components/pageComponents/UserAssigment.js
  • health/micro-ui/web/micro-ui-internals/example/src/UICustomizations.js
🧠 Learnings (8)
📚 Learning: 2025-06-04T04:08:48.234Z
Learnt from: jagankumar-egov
PR: egovernments/DIGIT-Frontend#2488
File: micro-ui/web/micro-ui-internals/packages/modules/core/src/pages/employee/Login/login.js:152-152
Timestamp: 2025-06-04T04:08:48.234Z
Learning: In the employee login component (micro-ui/web/micro-ui-internals/packages/modules/core/src/pages/employee/Login/login.js), prefer using a `defaultTenant` variable to store `Digit.ULBService.getStateId()` instead of calling the function multiple times inline in the `defaultValue` object. This improves code readability and avoids function call duplication.

Applied to files:

  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/config/AttendeeInboxConfig.js
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/components/pageComponents/UserAssigment.js
📚 Learning: 2025-01-02T04:41:15.957Z
Learnt from: jagankumar-egov
PR: egovernments/DIGIT-Frontend#2089
File: micro-ui/web/micro-ui-internals/packages/modules/workbench/src/pages/employee/MDMSAddV2.js:111-111
Timestamp: 2025-01-02T04:41:15.957Z
Learning: In micro-ui/web/micro-ui-internals/packages/modules/workbench/src/pages/employee/MDMSAddV2.js, always use "mdms[0].uniqueIdentifier" for the jsonPath instead of differentiating between "SOR" and other masters.

Applied to files:

  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/config/AttendeeInboxConfig.js
📚 Learning: 2024-11-07T11:02:33.520Z
Learnt from: rachana-egov
PR: egovernments/DIGIT-Frontend#1770
File: health/micro-ui/web/micro-ui-internals/packages/modules/microplan/src/pages/employee/viewVillage.js:320-322
Timestamp: 2024-11-07T11:02:33.520Z
Learning: In `health/micro-ui/web/micro-ui-internals/packages/modules/microplan/src/pages/employee/viewVillage.js`, the `data?.additionalFields` object is guaranteed to be defined, so checking for its existence before accessing its keys is unnecessary.

Applied to files:

  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/config/AttendeeInboxConfig.js
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/components/pageComponents/UserAssigment.js
  • health/micro-ui/web/micro-ui-internals/example/src/UICustomizations.js
📚 Learning: 2025-07-15T04:58:30.634Z
Learnt from: Hari-egov
PR: egovernments/DIGIT-Frontend#2788
File: micro-ui/web/micro-ui-internals/packages/modules/hrms/src/components/pageComponents/jurisdiction.js:26-26
Timestamp: 2025-07-15T04:58:30.634Z
Learning: In the HRMS module (micro-ui/web/micro-ui-internals/packages/modules/hrms/src/components/pageComponents/jurisdiction.js), the team has moved away from using MDMS hooks for boundary data fetching and now uses direct API calls to the boundary service endpoint `/boundary-service/boundary-relationships/_search` instead of the `useHrmsMDMS` hook with "FetchBoundaries" parameter.

Applied to files:

  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/config/AttendeeInboxConfig.js
📚 Learning: 2024-06-10T19:25:42.992Z
Learnt from: siddhant-nawale-egov
PR: egovernments/DIGIT-Frontend#698
File: micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanPreview.js:1-1
Timestamp: 2024-06-10T19:25:42.992Z
Learning: The imports in `MicroplanPreview.js` are from different libraries: `egovernments/digit-ui-components` and `egovernments/digit-ui-react-components`.

Applied to files:

  • health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/components/pageComponents/UserAssigment.js
  • health/micro-ui/web/micro-ui-internals/example/src/UICustomizations.js
📚 Learning: 2024-10-26T15:11:49.938Z
Learnt from: nabeelmd-eGov
PR: egovernments/DIGIT-Frontend#1680
File: health/micro-ui/web/micro-ui-internals/example/src/UICustomizations.js:1032-1094
Timestamp: 2024-10-26T15:11:49.938Z
Learning: In the DIGIT-Frontend project, when reviewing the `UICustomizations.js` file, avoid suggesting refactoring of repetitive rendering logic in switch cases into helper functions, unless explicitly requested.

Applied to files:

  • health/micro-ui/web/micro-ui-internals/example/src/UICustomizations.js
📚 Learning: 2024-11-07T07:17:27.636Z
Learnt from: jagankumar-egov
PR: egovernments/DIGIT-Frontend#1763
File: health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/MyCampaign.js:65-75
Timestamp: 2024-11-07T07:17:27.636Z
Learning: In `MyCampaign.js`, when suggesting code improvements for the `onClickRow` function, keep suggestions simple and avoid unnecessary complexity.

Applied to files:

  • health/micro-ui/web/micro-ui-internals/example/src/UICustomizations.js
📚 Learning: 2024-09-30T05:45:14.549Z
Learnt from: ashish-egov
PR: egovernments/DIGIT-Frontend#1441
File: health/micro-ui/web/micro-ui-internals/packages/modules/microplan/src/hooks/useGenerateIdCampaign.js:1-1
Timestamp: 2024-09-30T05:45:14.549Z
Learning: In the `useGenerateIdCampaign` function, auto assignment of default parameter values is needed in parameter destructuring.

Applied to files:

  • health/micro-ui/web/micro-ui-internals/example/src/UICustomizations.js
🧬 Code graph analysis (2)
health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/components/pageComponents/UserAssigment.js (2)
health/micro-ui/web/micro-ui-internals/example/src/UICustomizations.js (37)
  • options (890-890)
  • options (1721-1724)
  • boundaryCode (2660-2661)
  • Digit (1443-1443)
  • Digit (2725-2725)
  • tenantId (391-391)
  • tenantId (757-757)
  • tenantId (840-840)
  • tenantId (1387-1387)
  • tenantId (1442-1442)
  • tenantId (1689-1689)
  • tenantId (1897-1897)
  • tenantId (2162-2162)
  • tenantId (2194-2194)
  • tenantId (2239-2239)
  • tenantId (2269-2269)
  • tenantId (2314-2314)
  • tenantId (2345-2345)
  • tenantId (2390-2390)
  • tenantId (2420-2420)
  • tenantId (2465-2465)
  • data (415-415)
  • data (517-517)
  • data (734-734)
  • data (794-794)
  • data (811-811)
  • data (1071-1071)
  • data (1333-1333)
  • data (1350-1350)
  • data (1351-1351)
  • data (1352-1352)
  • data (2164-2164)
  • data (2165-2165)
  • data (2241-2241)
  • data (2242-2242)
  • data (2316-2316)
  • data (2317-2317)
micro-ui/web/micro-ui-internals/packages/react-components/src/atoms/Dropdown.js (1)
  • Dropdown (94-281)
health/micro-ui/web/micro-ui-internals/example/src/UICustomizations.js (5)
health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/NewCampaignCreate/CampaignDetails.js (3)
  • url (156-156)
  • data (304-418)
  • showToast (152-152)
health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/NewCampaignCreate/AppModule.js (1)
  • url (24-24)
health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/configs/UICustomizations.js (34)
  • url (401-401)
  • url (593-593)
  • url (740-740)
  • url (935-935)
  • url (1031-1031)
  • url (1126-1126)
  • data (370-370)
  • data (371-371)
  • data (564-564)
  • data (565-565)
  • data (710-710)
  • data (711-711)
  • data (906-906)
  • data (907-907)
  • data (1002-1002)
  • data (1003-1003)
  • data (1098-1098)
  • data (1099-1099)
  • showToast (195-195)
  • tenantId (92-92)
  • tenantId (174-174)
  • tenantId (235-235)
  • tenantId (368-368)
  • tenantId (400-400)
  • tenantId (562-562)
  • tenantId (592-592)
  • tenantId (708-708)
  • tenantId (739-739)
  • tenantId (904-904)
  • tenantId (934-934)
  • tenantId (1000-1000)
  • tenantId (1030-1030)
  • tenantId (1096-1096)
  • tenantId (1125-1125)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/pages/employee/EditRegister.js (4)
  • data (44-44)
  • Digit (32-32)
  • showToast (48-48)
  • loading (49-49)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/SearchUserPopUp.js (1)
  • createMapping (15-15)
🪛 Biome (2.1.2)
health/micro-ui/web/micro-ui-internals/example/src/UICustomizations.js

[error] 887-887: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.

The declaration is defined in this switch clause:

Safe fix: Wrap the declaration in a block.

(lint/correctness/noSwitchDeclarations)


[error] 888-888: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.

The declaration is defined in this switch clause:

Safe fix: Wrap the declaration in a block.

(lint/correctness/noSwitchDeclarations)


[error] 889-889: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.

The declaration is defined in this switch clause:

Safe fix: Wrap the declaration in a block.

(lint/correctness/noSwitchDeclarations)


[error] 890-890: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.

The declaration is defined in this switch clause:

Safe fix: Wrap the declaration in a block.

(lint/correctness/noSwitchDeclarations)


[error] 902-916: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.

The declaration is defined in this switch clause:

Safe fix: Wrap the declaration in a block.

(lint/correctness/noSwitchDeclarations)


[error] 918-962: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.

The declaration is defined in this switch clause:

Safe fix: Wrap the declaration in a block.

(lint/correctness/noSwitchDeclarations)


[error] 964-966: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.

The declaration is defined in this switch clause:

Safe fix: Wrap the declaration in a block.

(lint/correctness/noSwitchDeclarations)


[error] 2858-2858: Avoid passing children using a prop

The canonical way to pass children in React is to use JSX elements

(lint/correctness/noChildrenProp)

🔇 Additional comments (6)
health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/components/pageComponents/UserAssigment.js (2)

70-72: Loading state handling looks good


86-89: Confirm expected form value shape before persisting

Upstream often expects an id/code rather than the whole object.

If only code is needed:

-                        setSelectedHierarchy(value)
-                         onSelect(config.key, value);
+                        setSelectedHierarchy(value);
+                        onSelect(config.key, value?.code);

If full object is required, keep as-is.

health/micro-ui/web/micro-ui-internals/example/src/UICustomizations.js (4)

37-44: MDMS URL helper looks good

V1/V2 fallback is correct and consistent with other modules.


1587-1611: PGR preProcess: logic looks correct

Date range normalization and locality mapping are sound.

Also applies to: 1624-1640


1806-1828: HRMSInbox preProcess: params enrichment is fine

Scoped updates via temporary object are clean.


263-270: Inbox helpers generally look fine

Mapping for AttendanceInbox and postProcess status options is consistent.

Also applies to: 271-343

Comment on lines 2711 to 2902
additionalCustomizations: (row, key, column, value, t, searchResult) => {

const tenantId = Digit.ULBService.getCurrentTenantId();

const [openPopUp, setOpenPopUp] = useState(false);
const [isTag, setIsTag] = useState(false);

const [toast, setToast] = useState(null);
const [modalOpen, setModalOpen] = useState(false);
const [sessionFormData, setSessionFormData] = useState({});
const [refreshKey, setRefreshKey,] = useState(Date.now());
const [selectedId, setSelectedId] = useState(null);
const [loading, setLoading] = useState(false);
const { mutate: createMapping } = Digit.Hooks.payments.useCreateAttendeeFromRegister(tenantId);
const { registerNumber, boundaryCode, registerId } = Digit.Hooks.useQueryParams();

const [tag, setTag] = useState("");

const handleToastClose = () => {
setToast(null);
};

const handleCreate = async (id) => {
setSelectedId(id);
setLoading(true);


await createMapping({
"attendees": [
tag == "" ?
{
registerId: registerId,
individualId: row.id,
enrollmentDate: new Date().getTime(),
tenantId: row.tenantId,

} : {
registerId: registerId,
individualId: row.id,
enrollmentDate: new Date().getTime(),
tenantId: row.tenantId,
tag: tag
}]
},
{
onError: async (error) => {

setLoading(false);
setSelectedId(null);
setTag("");

setIsTag(false);
setOpenPopUp(false);


const errorMessage = error?.response?.data?.Errors?.[0]?.message
setToast(
{ key: true, label: `${t(errorMessage)}`, type: "error" }

);



},
onSuccess: async (responseData) => {
setTag("");
setLoading(false);
setSelectedId(null);
setIsTag(false);
setOpenPopUp(false);


setToast({ key: "success", label: `${t(`HCM_AM_NEW_EMPLOYEE`)} (${row.name.givenName || ""}) ${t(`HCM_AM_ENROLLED`)}`, transitionTime: 3000 });

setTimeout(() => {
window.history.back();
}, 800);

},
}
);
}

switch (key) {
case "HR_EMP_MOBILE_LABEL":
return value ? `${value}` : t("ES_COMMON_NA");

case "HR_EMP_NAME_LABEL":
return value ? `${value}` : t("ES_COMMON_NA");

case "HR_ROLE_NO_LABEL":
return value?.length > 0 ? value?.length : t("ES_COMMON_NA");

case "HR_DESG_LABEL":
return value ? t(`${value.designation}`) : t("ES_COMMON_NA");

case "HR_EMPLOYMENT_DEPARTMENT_LABEL":
return value ? t(`${value.department}`) : t("ES_COMMON_NA");

case "HR_JURIDICTIONS_LABEL":
return value ? t(value) : (
t("ES_COMMON_NA")
);
case "ASSIGNMENT":

if (loading && (row.id === selectedId)) {
return <Loader />;
}

return <> <Button
key={refreshKey}
variation={"primary"}
label={t("ASSIGN")}
style={{ minWidth: "10rem" }}
onButtonClick={() => {

// handleCreate(row.id);

setOpenPopUp(true);
return;


}}
/>
{toast && (
<Toast
error={toast.key}
isDleteBtn={true}
label={t(toast.label)}
onClose={handleToastClose}
type={toast.type}
/>
)}
{
openPopUp && <PopUp
style={{ minWidth: "500px" }}
onClose={() => {
setTag("");
setIsTag(false);
setOpenPopUp(false);
}}
heading={t("Action Needed: Tag Code")}
onOverlayClick={() => {
setTag("");
setIsTag(false);
setOpenPopUp(false);
}}
children={[
!isTag ?
<div>Do you want to fill in the Tag Code? If yes, press Enter Tag. Otherwise, Assign it.</div>
: <div>
<span>Tag Code</span>
<TextInput type="text" name="title" placeholder={t("Enter Tag Name")} value={tag} onChange={(e) => setTag(e.target.value)} />
</div>

]}
footerChildren={[
<ButtonNew
type={"button"}
size={"large"}
variation={"primary"}
label={t(isTag ? "HCM_AM_CLOSE_BT" : "HCM_AM_ENTER_TAG")}
onClick={() => {
if (isTag) {
setTag("");
setOpenPopUp(false);
setIsTag(false);
} else {
setIsTag(true);
}
return;
}}
/>,
<ButtonNew
type={"button"}
size={"large"}
variation={"primary"}
label={t("Assign")}
onClick={() => {
handleCreate(row.id);
return;
}}
/>,
]}
sortFooterChildren={true}
/>
}
</>
default:
return t("ES_COMMON_NA");
}
},
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

⚠️ Potential issue

AttendeeSearchInboxConfig.additionalCustomizations: Hooks in renderer; PopUp children prop misuse

  • Hooks inside additionalCustomizations break React rules.
  • Pass JSX children instead of children prop to PopUp.

Refactor case to a component:

-      switch (key) {
+      switch (key) {
         case "HR_EMP_MOBILE_LABEL":
           ...
         case "ASSIGNMENT":
-          if (loading && (row.id === selectedId)) { return <Loader />; }
-          return <> ... <PopUp children={[...]} footerChildren={[...]} ... /> </>
+        {
+          return <AttendeeAssignCell row={row} t={t} />;
+        }
         default:
           return t("ES_COMMON_NA");
       }

And replace PopUp usage to JSX children (if you keep inline for now):

-              openPopUp && <PopUp
-                style={{ minWidth: "500px" }}
-                onClose={...}
-                heading={t("Action Needed: Tag Code")}
-                onOverlayClick={...}
-                children={[
-                  !isTag ? <div>...</div> : <div>...</div>
-                ]}
-                footerChildren={[
-                  <ButtonNew ... />,
-                  <ButtonNew ... />,
-                ]}
-                sortFooterChildren={true}
-              />
+              openPopUp && (
+                <PopUp style={{ minWidth: "500px" }} onClose={...} heading={t("Action Needed: Tag Code")} onOverlayClick={...} sortFooterChildren>
+                  {!isTag ? (
+                    <div>Do you want to fill in the Tag Code? If yes, press Enter Tag. Otherwise, Assign it.</div>
+                  ) : (
+                    <div>
+                      <span>Tag Code</span>
+                      <TextInput type="text" name="title" placeholder={t("Enter Tag Name")} value={tag} onChange={(e) => setTag(e.target.value)} />
+                    </div>
+                  )}
+                  {[
+                    <ButtonNew ... key="enter" />,
+                    <ButtonNew ... key="assign" />,
+                  ]}
+                </PopUp>
+              )

Add extracted component (outside config):

function AttendeeAssignCell({ row, t }) {
  const tenantId = Digit.ULBService.getCurrentTenantId();
  const [toast, setToast] = React.useState(null);
  const [openPopUp, setOpenPopUp] = React.useState(false);
  const [isTag, setIsTag] = React.useState(false);
  const [tag, setTag] = React.useState("");
  const [loading, setLoading] = React.useState(false);
  const [selectedId, setSelectedId] = React.useState(null);
  const { registerId } = Digit.Hooks.useQueryParams();
  const { mutate: createMapping } = Digit.Hooks.payments.useCreateAttendeeFromRegister(tenantId);

  const handleCreate = async (id) => {
    setSelectedId(id);
    setLoading(true);
    await createMapping(
      { attendees: [{ registerId, individualId: row.id, enrollmentDate: Date.now(), tenantId: row.tenantId, ...(tag ? { tag } : {}) }] },
      {
        onError: (error) => {
          setLoading(false); setSelectedId(null); setTag(""); setIsTag(false); setOpenPopUp(false);
          const msg = error?.response?.data?.Errors?.[0]?.message;
          setToast({ key: true, label: t(msg), type: "error" });
        },
        onSuccess: () => {
          setTag(""); setLoading(false); setSelectedId(null); setIsTag(false); setOpenPopUp(false);
          setToast({ key: "success", label: `${t("HCM_AM_NEW_EMPLOYEE")} (${row.name.givenName || ""}) ${t("HCM_AM_ENROLLED")}`, transitionTime: 3000 });
          setTimeout(() => window.history.back(), 800);
        },
      }
    );
  };

  if (loading && row.id === selectedId) return <Loader />;

  return (
    <>
      <Button key={row.id} variation="primary" label={t("ASSIGN")} style={{ minWidth: "10rem" }} onButtonClick={() => setOpenPopUp(true)} />
      {toast && <Toast error={toast.key} isDleteBtn label={t(toast.label)} onClose={() => setToast(null)} type={toast.type} />}
      {openPopUp && (
        <PopUp style={{ minWidth: "500px" }} onClose={() => { setTag(""); setIsTag(false); setOpenPopUp(false); }} heading={t("Action Needed: Tag Code")} onOverlayClick={() => { setTag(""); setIsTag(false); setOpenPopUp(false); }} sortFooterChildren>
          {!isTag ? (
            <div>Do you want to fill in the Tag Code? If yes, press Enter Tag. Otherwise, Assign it.</div>
          ) : (
            <div>
              <span>Tag Code</span>
              <TextInput type="text" name="title" placeholder={t("Enter Tag Name")} value={tag} onChange={(e) => setTag(e.target.value)} />
            </div>
          )}
          {[
            <ButtonNew key="enter" type="button" size="large" variation="primary" label={t(isTag ? "HCM_AM_CLOSE_BT" : "HCM_AM_ENTER_TAG")} onClick={() => (isTag ? (setTag(""), setOpenPopUp(false), setIsTag(false)) : setIsTag(true))} />,
            <ButtonNew key="assign" type="button" size="large" variation="primary" label={t("Assign")} onClick={() => handleCreate(row.id)} />,
          ]}
        </PopUp>
      )}
    </>
  );
}
🧰 Tools
🪛 Biome (2.1.2)

[error] 2858-2858: Avoid passing children using a prop

The canonical way to pass children in React is to use JSX elements

(lint/correctness/noChildrenProp)

🤖 Prompt for AI Agents
In health/micro-ui/web/micro-ui-internals/example/src/UICustomizations.js around
lines 2711-2902: Hooks (useState/useQueryParams/useMutation) are used inside the
renderer function additionalCustomizations which violates React rules, and PopUp
is passed children via a prop instead of real JSX children. Summary: move
hookful UI into a separate React component and render that component from
additionalCustomizations. Fix by extracting the entire Assign/PopUp logic into a
new functional component (e.g., AttendeeAssignCell) defined outside this config
file scope that uses the hooks (useState, useQueryParams,
useCreateAttendeeFromRegister) and implements PopUp with JSX children and footer
buttons; then replace the case "ASSIGNMENT" body with a simple render of
<AttendeeAssignCell row={row} t={t} /> (or equivalent call) and ensure
loading/toast state and callbacks are managed inside the new component.

Comment on lines 2858 to 2867
children={[
!isTag ?
<div>Do you want to fill in the Tag Code? If yes, press Enter Tag. Otherwise, Assign it.</div>
: <div>
<span>Tag Code</span>
<TextInput type="text" name="title" placeholder={t("Enter Tag Name")} value={tag} onChange={(e) => setTag(e.target.value)} />
</div>

]}
footerChildren={[
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

⚠️ Potential issue

Fix noChildrenProp: pass JSX children, not children prop

See refactor above; this resolves the linter error.

🧰 Tools
🪛 Biome (2.1.2)

[error] 2858-2858: Avoid passing children using a prop

The canonical way to pass children in React is to use JSX elements

(lint/correctness/noChildrenProp)

🤖 Prompt for AI Agents
In health/micro-ui/web/micro-ui-internals/example/src/UICustomizations.js around
lines 2858 to 2867, the code is passing an array to a children prop (children=[
... ]) which triggers the noChildrenProp lint error; change the component usage
to supply the JSX as actual children (i.e., put the conditional JSX between the
component's opening and closing tags) instead of using a children prop, moving
the conditional fragment or the two <div> branches into the component body;
ensure proper parentheses/fragment wrapping and any required keys are preserved.

Comment on lines +17 to +18
const [selectedHierarchy, setSelectedHierarchy] = useState(null);
const [options, setOptions] = useState([]);
Copy link
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick (assertive)

Initialize selection from formData (edit flows)

Pre-populate selectedHierarchy when editing.

-    const [selectedHierarchy, setSelectedHierarchy] = useState(null);
+    const [selectedHierarchy, setSelectedHierarchy] = useState(formData?.[config?.key] ?? null);
@@
     useEffect(() => {
-        if (!individualData) return; // wait until data is available
+        if (!individualData) return;

Optionally, after options load, reconcile existing formData[config.key] with fetched options.

Also applies to: 59-67

🤖 Prompt for AI Agents
In
health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/components/pageComponents/UserAssigment.js
around lines 17-18 (and also affecting lines 59-67), selectedHierarchy is always
initialized to null so edit flows don’t pre-populate the control; initialize
selectedHierarchy from formData[config.key] and, after options are loaded,
reconcile that value with the fetched options: when setting options (lines
~59-67) look up the matching option by id/value or label and call
setSelectedHierarchy(matchedOption) (or convert the stored primitive into an
option object), and add a useEffect that watches [formData, options] to set
selectedHierarchy when editing so the UI shows the existing selection. Ensure
you handle both primitive ids and full option objects and only run the
reconciliation after options are available.

Comment on lines 35 to 46
label: "HCM_AM_COMMON_TABLE_COL_FILTER",
isMandatory: false,
key: "AttendeeBoundaryComponent",
type: "component",
disable: false,
component: "AttendeeBoundaryComponent",

populators: {
name: "AttendeeBoundaryComponent",

},
},
Copy link
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick (assertive)

Boundary data source: confirm API usage (per learnings)

Ensure AttendeeBoundaryComponent fetches boundaries via /boundary-service/boundary-relationships/_search, not MDMS hooks (team standard).

I used your org’s prior learning here. If not aligned, I can generate the switch quickly.

Comment on lines +121 to +123
primaryLabel: "Search", // Label for primary search button

defaultValues: {
Copy link
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick (assertive)

Use i18n key for primary button label

Replace hardcoded "Search" with the standard i18n key.

-          primaryLabel: "Search", // Label for primary search button
+          primaryLabel: "ES_COMMON_SEARCH", // Label for primary search button
📝 Committable suggestion

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

Suggested change
primaryLabel: "Search", // Label for primary search button
defaultValues: {
primaryLabel: "ES_COMMON_SEARCH", // Label for primary search button
defaultValues: {
🤖 Prompt for AI Agents
In
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/config/AttendeeInboxConfig.js
around lines 121 to 123, the primaryLabel is hardcoded as "Search"; replace that
literal with the standard i18n key (e.g. "common.search") so the label uses the
app's translation system, updating the config to reference the i18n key instead
of the hardcoded English word.

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
health/micro-ui/web/micro-ui-internals/example/src/UICustomizations.js (1)

54-60: Fix epoch comment (ms vs seconds) and simplify return

The function returns milliseconds, not seconds. Align the comment and remove the unnecessary Math.floor.

-  // Convert the date to epoch time (seconds)
-  return Math.floor(date.getTime());
+  // Convert the date to epoch time (milliseconds)
+  return date.getTime();
health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/services/service.js (1)

132-138: Update path omits reportingTo; edits won’t persist.

Create payload sets reportingTo, but update mapping doesn’t. Editing the field in UI will be ignored server-side.

Add reportingTo to the assignment mapping during updates (illustrative patch):

requestdata.assignments = userExisting[0].assignments.map((j) => {
  const assigment = { ...j };
  assigment.department = data?.SelectEmployeeDepartment?.code || j.department;
  assigment.designation = data?.SelectEmployeeDesignation?.code || j.designation;
  // NEW: persist reportingTo when provided
  assigment.reportingTo = data?.UserAssignment ?? assigment.reportingTo ?? null;
  return assigment;
});
health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/services/urls.js (1)

1-55: Centralize endpoint constants into shared Urls service
Numerous modules still reference raw endpoint strings (e.g. /boundary-service/..., /health-attendance/..., /health-individual/...) instead of using the shared Urls object. Replace all hard-coded URLs (found in microplan/src/pages/employee/index.js:209; health-payments/src/services/attendance/attendanceService.js:33; health-hrms/src/services/hrms/SearchUser.js:33; etc.) with the corresponding entries in health-hrms/src/services/urls.js (for example, Urls.attendee.search, Urls.attendee.deenrollAttendee, Urls.boundarySearchPath) to enforce a single source of truth.

♻️ Duplicate comments (16)
health/micro-ui/web/micro-ui-internals/example/src/UICustomizations.js (9)

810-823: Duplicate/overwritten fields in MicroplanSearchConfig.preProcess

Set name once with clear precedence; don’t set status here if it’s overridden by the tab filter below.

-      const { name, status } = data?.state?.searchForm || {};
+      const { name, microplanName } = data?.state?.searchForm || {};
@@
-      data.body.PlanConfigurationSearchCriteria.name = name;
+      if (microplanName) {
+        data.body.PlanConfigurationSearchCriteria.name = microplanName;
+      } else if (name) {
+        data.body.PlanConfigurationSearchCriteria.name = name;
+      }
@@
-      data.body.PlanConfigurationSearchCriteria.status = status?.status;
-      data.body.PlanConfigurationSearchCriteria.name = data?.state?.searchForm?.microplanName;
+      // status is set from tab filter below

839-856: React Hooks inside cell renderer; and noSwitchDeclarations

Hooks (useState, data hooks) are used inside additionalCustomizations and declarations leak across cases. Extract the ACTIONS cell into a component (as previously suggested) or, at minimum, wrap each case in a block.

Minimal scope-fix (does not solve hook-rule violation):

-        case "ACTIONS":
+        case "ACTIONS": {
           // ...
-          return (
+          return (
             <>
               {/* ... */}
             </>
           );
+        }

Please adopt the earlier component extraction to resolve the Hook rule violation properly.

Also applies to: 884-966


886-889: Remove hard-coded dummy filestore id

Don’t fall back to a dummy file. Guard the UI on real availability.

-          // TODO : Replace dummy file id with real file id when API is ready
-          const dummyFile = "c22a7676-d5d7-49b6-bcdb-83e9519f58df"
-          const microplanFileId = row?.campaignDetails?.additionalDetails?.microplanFileId || dummyFile;
+          const microplanFileId = row?.campaignDetails?.additionalDetails?.microplanFileId;

1189-1218: Action button config: remove no-op onClick and rely on options+onOptionSelect

-            isSearchable={false}
-            title={t("MP_ACTIONS_FOR_MICROPLANS")}
-            label={t("MP_ACTIONS_FOR_MICROPLANS")}
-            isDisabled={!EstimationsfileId}
-            onClick={() => { }}
+            isSearchable={false}
+            title={t("MP_ACTIONS_FOR_MICROPLANS")}
+            label={t("MP_ACTIONS_FOR_MICROPLANS")}
+            isDisabled={!EstimationsfileId}

1442-1454: Avoid hook inside utility: pass campaignId into getFacilitySearchRequest

Treat the function as pure; accept campaignId via prop or caller.

-      const { campaignId } = Digit.Hooks.useQueryParams();
+      const { campaignId } = prop; // expect caller to pass campaignId

Also update callers to pass { campaignId }.


2223-2224: Remove empty additionalCustomizations stubs or add TODO

Drop these no-op functions to reduce bundle size, or replace with a shared noop and a brief TODO.

Also applies to: 2298-2299, 2374-2375, 2449-2450, 2524-2525, 2598-2599


2621-2621: AttendeeSearch preProcess: remove console logs; guard .trim; verify payload schema

  • Remove console logs.
  • Guard .trim() calls.
  • Confirm BE expects arrays for mobileNumber/username and boundaryCode at this path (vs locality object).
-      console.log(data)
+      // debug log removed
@@
-      if (phone && phone.trim() !== "") {
+      if (typeof phone === "string" && phone.trim() !== "") {
         Individual.mobileNumber = [phone];
       }
@@
-      if (names && names.trim() !== "") {
+      if (typeof names === "string" && names.trim() !== "") {
         Individual.name = { givenName: names };
       }
@@
-      if (codes && codes.trim() !== "") {
+      if (typeof codes === "string" && codes.trim() !== "") {
         Individual.username = [codes];
       }
@@
-      if (boundaryCode && boundaryCode.trim() !== "") {
+      if (typeof boundaryCode === "string" && boundaryCode.trim() !== "") {
         Individual.boundaryCode=boundaryCode
       }
@@
-      console.log("payload", data)
+      // debug log removed

Run to verify the expected request shape:

#!/bin/bash
# Look for attendee search payload contracts/usages
rg -nC2 -e 'AttendeeSearch|useCreateAttendeeFromRegister|Individual(\\.|")' --type js --type ts --type tsx

Also applies to: 2666-2678, 2681-2691, 2708-2709


2716-2765: Hooks inside renderer (rule-of-hooks)

useState, useQueryParams, and mutation hooks are used inside additionalCustomizations. Extract an AttendeeAssignCell component and render it from the "ASSIGNMENT" case. This also avoids repeated re-creation per cell and improves performance.

Also applies to: 2817-2844


2846-2897: Fix noChildrenProp: pass JSX children to PopUp

Render content between <PopUp>...</PopUp> instead of using children/footerChildren arrays.

-              openPopUp && <PopUp
+              openPopUp && (
+              <PopUp
                 style={{ minWidth: "500px" }}
                 onClose={() => {
                   setTag("");
                   setIsTag(false);
                   setOpenPopUp(false);
                 }}
                 heading={t("Action Needed: Tag Code")}
                 onOverlayClick={() => {
                   setTag("");
                   setIsTag(false);
                   setOpenPopUp(false);
                 }}
-                children={[
-                  !isTag ?
-                    <div>Do you want to fill in the Tag Code? If yes, press Enter Tag. Otherwise, Assign it.</div>
-                    : <div>
-                      <span>Tag Code</span>
-                      <TextInput type="text" name="title" placeholder={t("Enter Tag Name")} value={tag} onChange={(e) => setTag(e.target.value)} />
-                    </div>
-                ]}
-                footerChildren={[
-                  <ButtonNew ... />,
-                  <ButtonNew ... />,
-                ]}
-                sortFooterChildren={true}
-              />
+                sortFooterChildren={true}
+              >
+                {!isTag ? (
+                  <div>Do you want to fill in the Tag Code? If yes, press Enter Tag. Otherwise, Assign it.</div>
+                ) : (
+                  <div>
+                    <span>Tag Code</span>
+                    <TextInput type="text" name="title" placeholder={t("Enter Tag Name")} value={tag} onChange={(e) => setTag(e.target.value)} />
+                  </div>
+                )}
+                {[
+                  <ButtonNew key="enter" type="button" size="large" variation="primary" label={t(isTag ? "HCM_AM_CLOSE_BT" : "HCM_AM_ENTER_TAG")} onClick={() => { if (isTag) { setTag(""); setOpenPopUp(false); setIsTag(false); } else { setIsTag(true); } }} />,
+                  <ButtonNew key="assign" type="button" size="large" variation="primary" label={t("Assign")} onClick={() => { handleCreate(row.id); }} />,
+                ]}
+              </PopUp>
+              )
health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/services/service.js (1)

273-285: Use stable keys and verify selectedProject shape (id vs code); avoid empty-string sentinel.

Array index keys are fragile on reorder, and empty-string ids complicate truthy checks. Set selectedProject to null when absent.

-        ? data?.map((ele, index) => ({
-          key: index,
+        ? data?.map((ele, index) => ({
+          key: ele?.projectId ?? ele?.id ?? `row-${index}`,
           fromDate: ele.startDate ? convertEpochToDate(ele.startDate) : "",
           toDate: ele.endDate ? convertEpochToDate(ele.endDate) : "",
-          selectedProject: { id: ele.projectId },
+          selectedProject: ele?.projectId ? { id: ele.projectId } : null,
         }))
         : [
           {
-            key: 0,
+            key: "row-0",
             fromDate: "",
             toDate: "",
-            selectedProject: { id: "" },
+            selectedProject: null,
           },
         ],

If consumers expect a different shape (e.g., selectedProject: { code } or a plain id), align here accordingly.

health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/services/urls.js (3)

34-39: Duplicate hrms key; one will shadow the other.

Keep a single hrms block to prevent accidental overrides. This was flagged earlier as well.

Suggested change (outside this hunk): remove the duplicate at lines 34-39.


5-6: Unused constants.

boundarySearchPath and hierarchyType are declared but unused; delete to reduce noise.


49-52: Parameterize attendee/individual service paths (avoid hard-coded literals).

Use globalConfigs like other services for portability. Also aligns with prior review.

Apply within this hunk:

   attendee:{
-    deenrollAttendee:`/health-attendance/attendee/v1/_delete`,
-     search: `/health-individual/v1/_search`,
+    deenrollAttendee:`/${attendanceContextPath}/attendee/v1/_delete`,
+    search: `/${individualContextPath}/v1/_search`,
   }

Add (outside this hunk, near other context-path defs):

const attendanceContextPath = window?.globalConfigs?.getConfig("ATTENDANCE_CONTEXT_PATH") || "health-attendance";
const individualContextPath  = window?.globalConfigs?.getConfig("INDIVIDUAL_CONTEXT_PATH")  || "health-individual";
health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/components/pageComponents/UserAssigment.js (3)

1-12: Remove unused imports.

useTranslation, HeaderComponent, Card, Button, Toast not used. This was flagged earlier.

-import { useTranslation } from "react-i18next";
 import {
     Dropdown,
     Loader,
-    HeaderComponent,
-    Card,
     LabelFieldPair,
-    Button,
-    Toast,
     CardLabel, TextInput,
 } from "@egovernments/digit-ui-components";

24-24: Use getCurrentTenantId() instead of getStateId().

Aligns with other HRMS calls. Previously suggested.

-    const tenantId = Digit.ULBService.getStateId();
+    const tenantId = Digit.ULBService.getCurrentTenantId();

1-1: Filename typo: rename file.

Rename UserAssigment.jsUserAssignment.js and update imports/registry. Previously noted.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1246f82 and 0f597bb.

📒 Files selected for processing (10)
  • health/micro-ui/web/micro-ui-internals/example/src/UICustomizations.js (24 hunks)
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/Module.js (2 hunks)
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/components/pageComponents/SearchUserToReport.js (1 hunks)
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/components/pageComponents/SelectableList.js (1 hunks)
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/components/pageComponents/UserAssigment.js (1 hunks)
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/pages/employee/createEmployee.js (6 hunks)
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/services/hrms/AttendeeService.js (1 hunks)
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/services/hrms/SearchUser.js (1 hunks)
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/services/service.js (5 hunks)
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/services/urls.js (1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.js

⚙️ CodeRabbit configuration file

check

Files:

  • health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/Module.js
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/services/hrms/AttendeeService.js
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/components/pageComponents/SearchUserToReport.js
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/components/pageComponents/SelectableList.js
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/services/service.js
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/services/hrms/SearchUser.js
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/pages/employee/createEmployee.js
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/services/urls.js
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/components/pageComponents/UserAssigment.js
  • health/micro-ui/web/micro-ui-internals/example/src/UICustomizations.js
🧠 Learnings (12)
📚 Learning: 2025-07-15T04:58:30.634Z
Learnt from: Hari-egov
PR: egovernments/DIGIT-Frontend#2788
File: micro-ui/web/micro-ui-internals/packages/modules/hrms/src/components/pageComponents/jurisdiction.js:26-26
Timestamp: 2025-07-15T04:58:30.634Z
Learning: In the HRMS module (micro-ui/web/micro-ui-internals/packages/modules/hrms/src/components/pageComponents/jurisdiction.js), the team has moved away from using MDMS hooks for boundary data fetching and now uses direct API calls to the boundary service endpoint `/boundary-service/boundary-relationships/_search` instead of the `useHrmsMDMS` hook with "FetchBoundaries" parameter.

Applied to files:

  • health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/Module.js
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/services/hrms/SearchUser.js
📚 Learning: 2024-06-10T19:25:42.992Z
Learnt from: siddhant-nawale-egov
PR: egovernments/DIGIT-Frontend#606
File: micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/index.js:276-276
Timestamp: 2024-06-10T19:25:42.992Z
Learning: The `addResourcesToFilteredDataToShow` function in `micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/index.js` now includes checks for data integrity, such as validation of `previewData`, the common column, and `resources`, along with error logging for invalid data formats.

Applied to files:

  • health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/Module.js
📚 Learning: 2024-11-07T07:17:27.636Z
Learnt from: jagankumar-egov
PR: egovernments/DIGIT-Frontend#1763
File: health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/MyCampaign.js:65-75
Timestamp: 2024-11-07T07:17:27.636Z
Learning: In `MyCampaign.js`, when suggesting code improvements for the `onClickRow` function, keep suggestions simple and avoid unnecessary complexity.

Applied to files:

  • health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/services/service.js
  • health/micro-ui/web/micro-ui-internals/example/src/UICustomizations.js
📚 Learning: 2024-11-07T11:02:33.520Z
Learnt from: rachana-egov
PR: egovernments/DIGIT-Frontend#1770
File: health/micro-ui/web/micro-ui-internals/packages/modules/microplan/src/pages/employee/viewVillage.js:320-322
Timestamp: 2024-11-07T11:02:33.520Z
Learning: In `health/micro-ui/web/micro-ui-internals/packages/modules/microplan/src/pages/employee/viewVillage.js`, the `data?.additionalFields` object is guaranteed to be defined, so checking for its existence before accessing its keys is unnecessary.

Applied to files:

  • health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/services/service.js
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/pages/employee/createEmployee.js
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/components/pageComponents/UserAssigment.js
  • health/micro-ui/web/micro-ui-internals/example/src/UICustomizations.js
📚 Learning: 2025-01-02T04:41:15.957Z
Learnt from: jagankumar-egov
PR: egovernments/DIGIT-Frontend#2089
File: micro-ui/web/micro-ui-internals/packages/modules/workbench/src/pages/employee/MDMSAddV2.js:111-111
Timestamp: 2025-01-02T04:41:15.957Z
Learning: In micro-ui/web/micro-ui-internals/packages/modules/workbench/src/pages/employee/MDMSAddV2.js, always use "mdms[0].uniqueIdentifier" for the jsonPath instead of differentiating between "SOR" and other masters.

Applied to files:

  • health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/pages/employee/createEmployee.js
📚 Learning: 2025-06-04T04:08:48.234Z
Learnt from: jagankumar-egov
PR: egovernments/DIGIT-Frontend#2488
File: micro-ui/web/micro-ui-internals/packages/modules/core/src/pages/employee/Login/login.js:152-152
Timestamp: 2025-06-04T04:08:48.234Z
Learning: In the employee login component (micro-ui/web/micro-ui-internals/packages/modules/core/src/pages/employee/Login/login.js), prefer using a `defaultTenant` variable to store `Digit.ULBService.getStateId()` instead of calling the function multiple times inline in the `defaultValue` object. This improves code readability and avoids function call duplication.

Applied to files:

  • health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/pages/employee/createEmployee.js
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/components/pageComponents/UserAssigment.js
📚 Learning: 2025-02-05T10:01:29.668Z
Learnt from: Tulika-eGov
PR: egovernments/DIGIT-Frontend#2188
File: micro-ui/web/micro-ui-internals/packages/modules/core/src/pages/employee/Login/login.js:72-78
Timestamp: 2025-02-05T10:01:29.668Z
Learning: In the employee login form, defaultValues are dynamically generated from config[0].body based on populators.defaultValue, so spreading the entire defaultValues object is required rather than cherry-picking specific fields.

Applied to files:

  • health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/pages/employee/createEmployee.js
📚 Learning: 2024-06-10T19:25:42.992Z
Learnt from: siddhant-nawale-egov
PR: egovernments/DIGIT-Frontend#698
File: micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanPreview.js:1-1
Timestamp: 2024-06-10T19:25:42.992Z
Learning: The imports in `MicroplanPreview.js` are from different libraries: `egovernments/digit-ui-components` and `egovernments/digit-ui-react-components`.

Applied to files:

  • health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/components/pageComponents/UserAssigment.js
  • health/micro-ui/web/micro-ui-internals/example/src/UICustomizations.js
📚 Learning: 2024-06-10T19:25:42.992Z
Learnt from: nitish-egov
PR: egovernments/DIGIT-Frontend#0
File: :0-0
Timestamp: 2024-06-10T19:25:42.992Z
Learning: Validation for the presence of the `request` parameter in `autoGenerateBoundaryCodes` method of `dataManage.controller.ts` is handled at the entry level, making additional checks within the method unnecessary.

Applied to files:

  • health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/components/pageComponents/UserAssigment.js
📚 Learning: 2024-10-26T15:11:49.938Z
Learnt from: nabeelmd-eGov
PR: egovernments/DIGIT-Frontend#1680
File: health/micro-ui/web/micro-ui-internals/example/src/UICustomizations.js:1032-1094
Timestamp: 2024-10-26T15:11:49.938Z
Learning: In the DIGIT-Frontend project, when reviewing the `UICustomizations.js` file, avoid suggesting refactoring of repetitive rendering logic in switch cases into helper functions, unless explicitly requested.

Applied to files:

  • health/micro-ui/web/micro-ui-internals/example/src/UICustomizations.js
📚 Learning: 2024-09-30T05:45:14.549Z
Learnt from: ashish-egov
PR: egovernments/DIGIT-Frontend#1441
File: health/micro-ui/web/micro-ui-internals/packages/modules/microplan/src/hooks/useGenerateIdCampaign.js:1-1
Timestamp: 2024-09-30T05:45:14.549Z
Learning: In the `useGenerateIdCampaign` function, auto assignment of default parameter values is needed in parameter destructuring.

Applied to files:

  • health/micro-ui/web/micro-ui-internals/example/src/UICustomizations.js
📚 Learning: 2024-10-17T12:00:51.749Z
Learnt from: Ramkrishna-egov
PR: egovernments/DIGIT-Frontend#1545
File: health/micro-ui/web/micro-ui-internals/packages/modules/microplan/src/components/ActivityCard.js:30-35
Timestamp: 2024-10-17T12:00:51.749Z
Learning: In our codebase, the 'Card' component is commonly used by passing children via the 'children' prop.

Applied to files:

  • health/micro-ui/web/micro-ui-internals/example/src/UICustomizations.js
🧬 Code graph analysis (6)
health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/services/hrms/AttendeeService.js (2)
health/micro-ui/web/micro-ui-internals/example/src/UICustomizations.js (32)
  • tenantId (391-391)
  • tenantId (757-757)
  • tenantId (840-840)
  • tenantId (1387-1387)
  • tenantId (1442-1442)
  • tenantId (1689-1689)
  • tenantId (1897-1897)
  • tenantId (2162-2162)
  • tenantId (2194-2194)
  • tenantId (2239-2239)
  • tenantId (2269-2269)
  • tenantId (2314-2314)
  • tenantId (2345-2345)
  • tenantId (2390-2390)
  • tenantId (2420-2420)
  • tenantId (2465-2465)
  • data (415-415)
  • data (517-517)
  • data (734-734)
  • data (794-794)
  • data (811-811)
  • data (1071-1071)
  • data (1333-1333)
  • data (1350-1350)
  • data (1351-1351)
  • data (1352-1352)
  • data (2164-2164)
  • data (2165-2165)
  • data (2241-2241)
  • data (2242-2242)
  • data (2316-2316)
  • data (2317-2317)
health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/services/urls.js (1)
  • Urls (9-53)
health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/components/pageComponents/SelectableList.js (1)
health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/components/pageComponents/SearchUserToReport.js (1)
  • onSelect (70-74)
health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/services/service.js (2)
health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/constants/constants.js (2)
  • HRMS_CONSTANTS (1-7)
  • HRMS_CONSTANTS (1-7)
health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/components/Utils/index.js (2)
  • convertEpochToDate (2-15)
  • convertEpochToDate (2-15)
health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/services/hrms/SearchUser.js (1)
health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/services/hrms/AttendeeService.js (1)
  • AttendeeService (3-46)
health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/pages/employee/createEmployee.js (5)
health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/pages/employee/CampaignAssignmentInbox.js (1)
  • mdmsData (14-20)
health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/pages/employee/employeeDetails.js (2)
  • mdmsData (29-40)
  • Digit (49-49)
health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/pages/employee/Inbox.js (2)
  • mdmsData (12-18)
  • config (26-26)
health/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/pages/employee/CreateComplaint/createComplaintForm.js (1)
  • validatePhoneNumber (53-66)
health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/components/config/createEmployeeConfig.js (2)
  • CreateEmployeeConfig (6-321)
  • CreateEmployeeConfig (6-321)
health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/components/pageComponents/UserAssigment.js (2)
health/micro-ui/web/micro-ui-internals/example/src/UICustomizations.js (19)
  • boundaryCode (2660-2661)
  • Digit (1443-1443)
  • Digit (2726-2726)
  • tenantId (391-391)
  • tenantId (757-757)
  • tenantId (840-840)
  • tenantId (1387-1387)
  • tenantId (1442-1442)
  • tenantId (1689-1689)
  • tenantId (1897-1897)
  • tenantId (2162-2162)
  • tenantId (2194-2194)
  • tenantId (2239-2239)
  • tenantId (2269-2269)
  • tenantId (2314-2314)
  • tenantId (2345-2345)
  • tenantId (2390-2390)
  • tenantId (2420-2420)
  • tenantId (2465-2465)
health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/components/pageComponents/SearchUserToReport.js (3)
  • searchQuery (31-31)
  • onSelect (70-74)
  • SearchUserToReport (11-132)
🪛 Biome (2.1.2)
health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/components/pageComponents/SearchUserToReport.js

[error] 99-99: Avoid passing children using a prop

The canonical way to pass children in React is to use JSX elements

(lint/correctness/noChildrenProp)

health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/components/pageComponents/SelectableList.js

[error] 20-31: Static Elements should not be interactive.

To add interactivity such as a mouse or key event listener to a static element, give the element an appropriate role value.

(lint/a11y/noStaticElementInteractions)


[error] 20-31: Enforce to have the onClick mouse event with the onKeyUp, the onKeyDown, or the onKeyPress keyboard event.

Actions triggered using mouse events should have corresponding keyboard events to account for keyboard-only navigation.

(lint/a11y/useKeyWithClickEvents)

health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/pages/employee/createEmployee.js

[error] 76-76: This is an unexpected use of the debugger statement.

Unsafe fix: Remove debugger statement

(lint/suspicious/noDebugger)

health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/components/pageComponents/UserAssigment.js

[error] 90-95: Static Elements should not be interactive.

To add interactivity such as a mouse or key event listener to a static element, give the element an appropriate role value.

(lint/a11y/noStaticElementInteractions)


[error] 90-95: Enforce to have the onClick mouse event with the onKeyUp, the onKeyDown, or the onKeyPress keyboard event.

Actions triggered using mouse events should have corresponding keyboard events to account for keyboard-only navigation.

(lint/a11y/useKeyWithClickEvents)

health/micro-ui/web/micro-ui-internals/example/src/UICustomizations.js

[error] 887-887: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.

The declaration is defined in this switch clause:

Safe fix: Wrap the declaration in a block.

(lint/correctness/noSwitchDeclarations)


[error] 888-888: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.

The declaration is defined in this switch clause:

Safe fix: Wrap the declaration in a block.

(lint/correctness/noSwitchDeclarations)


[error] 889-889: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.

The declaration is defined in this switch clause:

Safe fix: Wrap the declaration in a block.

(lint/correctness/noSwitchDeclarations)


[error] 890-890: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.

The declaration is defined in this switch clause:

Safe fix: Wrap the declaration in a block.

(lint/correctness/noSwitchDeclarations)


[error] 902-916: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.

The declaration is defined in this switch clause:

Safe fix: Wrap the declaration in a block.

(lint/correctness/noSwitchDeclarations)


[error] 918-962: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.

The declaration is defined in this switch clause:

Safe fix: Wrap the declaration in a block.

(lint/correctness/noSwitchDeclarations)


[error] 964-966: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.

The declaration is defined in this switch clause:

Safe fix: Wrap the declaration in a block.

(lint/correctness/noSwitchDeclarations)


[error] 2859-2859: Avoid passing children using a prop

The canonical way to pass children in React is to use JSX elements

(lint/correctness/noChildrenProp)

⏰ Context from checks skipped due to timeout of 10000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (6)
health/micro-ui/web/micro-ui-internals/example/src/UICustomizations.js (1)

1587-1594: LGTM: clearing range and normalizing date filters

Deleting the raw range object after extracting from/to dates is correct and avoids BE confusion.

health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/Module.js (1)

20-22: Confirm registry keys match config usage and exports.

Ensure CreateEmployeeConfig (or any MDMS config) references these exact component keys: "UserAssignment", "SearchUserToReport", "SelectableList", and that each file default-exports the component.

Also applies to: 84-86

health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/pages/employee/createEmployee.js (3)

322-324: MDMS override: confirm intent to disable server-driven form config.

Hard-wiring fConfig to CreateEmployeeConfig and keeping MDMS enable: false blocks runtime config updates. If this was temporary, revert to MDMS-first with static fallback.

Proposed pattern:

-  const fConfig = CreateEmployeeConfig?.CreateEmployeeConfig?.[0];
-  //const fConfig = mdmsData ? mdmsData : CreateEmployeeConfig?.CreateEmployeeConfig?.[0];
+  const fConfig = mdmsData || CreateEmployeeConfig?.CreateEmployeeConfig?.[0];

And enable the MDMS hook when ready.


333-339: Verify updateDependent semantics for date fields.

Confirm that preProcessMDMSConfig treats these values as defaultValue (not min/max). If the intent is to set max for DOB (18 years ago) and default for DOE (today), wire them to the correct keys expected by the form engine.


349-353: Edit mode field filtering: confirm keys.

Ensure the config uses field.key for "employeePassword", "employeeConfirmPassword", and "Jurisdictions". If any field relies on populators.name instead, it may slip through.

health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/components/pageComponents/SearchUserToReport.js (1)

50-54: Remove debug logs (PII risk).

Logs of user input can leak PII.

-            if (/^\d+$/.test(name)) {
-                console.log("it is nummeric");
-            } else {
-                console.log("it is not nummeric");
-            }
+            // optionally branch on numeric vs text without logging PII

Likely an incorrect or invalid review comment.

Comment on lines 3 to 7
import { PopUp, Timeline, Loader, TextInput, Button } from '@egovernments/digit-ui-components';
import { useEffect } from "react";
import { useHistory } from "react-router-dom";
import AttendanceService from "../../services/hrms/SearchUser";
import SelectableList from "./SelectableList";
Copy link
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick (assertive)

Prune unused imports.

Timeline, Loader, useEffect, useHistory, and context-path vars are unused.

-import { PopUp, Timeline, Loader, TextInput, Button } from '@egovernments/digit-ui-components';
-import { useEffect } from "react";
-import { useHistory } from "react-router-dom";
+import { PopUp, TextInput, Button } from '@egovernments/digit-ui-components';

Also remove unused attendanceContextPath, individualContextPath, labels, labelWidth.

📝 Committable suggestion

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

Suggested change
import { PopUp, Timeline, Loader, TextInput, Button } from '@egovernments/digit-ui-components';
import { useEffect } from "react";
import { useHistory } from "react-router-dom";
import AttendanceService from "../../services/hrms/SearchUser";
import SelectableList from "./SelectableList";
import { PopUp, TextInput, Button } from '@egovernments/digit-ui-components';
import AttendanceService from "../../services/hrms/SearchUser";
import SelectableList from "./SelectableList";
🤖 Prompt for AI Agents
In
health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/components/pageComponents/SearchUserToReport.js
around lines 3 to 7, several imports and local variables are unused: remove
Timeline, Loader, useEffect, useHistory from the import list (keep only PopUp,
TextInput, Button and any others actually referenced), and delete any unused
context-path vars (attendanceContextPath, individualContextPath) plus labels and
labelWidth declarations; ensure you also remove any dead references to these
identifiers elsewhere in the file so the component builds cleanly.

Comment on lines 37 to 47
const searchUser = async (name) => {

try {

const locallity = Digit.SessionStorage.get("selectedBoundary")?.code || null;

if (locallity === null) {
setShowToast(
{ key: "error", label: t(`Locality is not selected`), transitionTime: 3000 }
);
return;
Copy link
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick (assertive)

Typo: locallitylocality (propagate to service signature).

Keeps naming consistent.

🤖 Prompt for AI Agents
In
health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/components/pageComponents/SearchUserToReport.js
around lines 37 to 47, the variable name "locallity" is a typo and should be
renamed to "locality" throughout this function and any service signatures or
calls that use it; update the variable declaration, all references in this file
(including setShowToast logic) and change the parameter name passed to
downstream services or helper functions to "locality" (and update those service
function signatures/implementations accordingly) to keep naming consistent and
avoid runtime mismatches.

Comment on lines 43 to 47
if (locallity === null) {
setShowToast(
{ key: "error", label: t(`Locality is not selected`), transitionTime: 3000 }
);
return;
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Runtime error: setShowToast is undefined.

Either wire a Toast state or remove the call. Minimal safe fix: early-return without toast.

-            if (locallity === null) {
-                setShowToast(
-                    { key: "error", label: t(`Locality is not selected`), transitionTime: 3000 }
-                );
-                return;
-            }
+            if (locallity === null) return;

Optionally, introduce a proper Toast via digit-ui-components.

📝 Committable suggestion

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

Suggested change
if (locallity === null) {
setShowToast(
{ key: "error", label: t(`Locality is not selected`), transitionTime: 3000 }
);
return;
- if (locallity === null) {
- setShowToast(
- { key: "error", label: t(`Locality is not selected`), transitionTime: 3000 }
- );
- return;
if (locallity === null) return;
🤖 Prompt for AI Agents
In
health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/components/pageComponents/SearchUserToReport.js
around lines 43-47, the code calls setShowToast when locallity is null but
setShowToast is not defined, causing a runtime error; fix by removing the
setShowToast call and simply early-return when locallity is null (or
alternatively wire a proper Toast state/hook from digit-ui-components and call
that instead if toast feedback is required). Ensure no references to
setShowToast remain in this branch so the function exits cleanly.

Comment on lines +81 to +84
onSubmit({
id: selectedUser?.userUuid,
name: selectedUser?.name?.givenName
})
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Wrong field: use id, not userUuid (downstream expects value.id).

This breaks selection in UserAssignment.

-        onSubmit({
-            id: selectedUser?.userUuid,
-            name: selectedUser?.name?.givenName
-        })
+        onSubmit({
+            id: selectedUser?.id,
+            name: selectedUser?.name?.givenName
+        })
📝 Committable suggestion

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

Suggested change
onSubmit({
id: selectedUser?.userUuid,
name: selectedUser?.name?.givenName
})
onSubmit({
id: selectedUser?.id,
name: selectedUser?.name?.givenName
})
🤖 Prompt for AI Agents
In
health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/components/pageComponents/SearchUserToReport.js
around lines 81-84, the onSubmit payload uses selectedUser?.userUuid but
downstream expects value.id; change the payload to use id: selectedUser?.id
(keep name: selectedUser?.name?.givenName) so the submitted object matches
downstream shape (value.id). Ensure any related tests or callers rely on id
rather than userUuid.

Comment on lines +56 to +62
url: "/health-attendance/attendee/v1/_delete",
useCache: false,
method: "POST",
userService: true,
body,
params,
});
Copy link
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick (assertive)

Parameterize attendee delete path (or reuse AttendeeService.delete).

Dedup endpoints and centralize.

-        url: "/health-attendance/attendee/v1/_delete",
+        url: `/${(window?.globalConfigs?.getConfig("ATTENDANCE_CONTEXT_PATH") || "health-attendance")}/attendee/v1/_delete`,

Or call AttendeeService.delete(...) instead of duplicating this method.

📝 Committable suggestion

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

Suggested change
url: "/health-attendance/attendee/v1/_delete",
useCache: false,
method: "POST",
userService: true,
body,
params,
});
url: `/${(window?.globalConfigs?.getConfig("ATTENDANCE_CONTEXT_PATH") || "health-attendance")}/attendee/v1/_delete`,
useCache: false,
method: "POST",
userService: true,
body,
params,
});
🤖 Prompt for AI Agents
In
health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/services/hrms/SearchUser.js
around lines 56 to 62, the code directly calls the hardcoded attendee delete
endpoint ("/health-attendance/attendee/v1/_delete") which duplicates existing
functionality; replace this duplication by calling the central
AttendeeService.delete(...) or extract the attendee delete path into a shared
constant used by both services. Update import to include AttendeeService (or the
shared constant), remove the hardcoded URL, and delegate the delete operation to
AttendeeService.delete(body, params) (or call the request util with the shared
PATH constant) so endpoint definition is centralized and deduplicated.

Comment on lines 75 to 105
searchIndividual: async ({ name, locallity, tenantId }) => {
try {

// if (data?.SelectEmployeePhoneNumber && data?.SelectEmployeePhoneNumber?.trim().length > 0) {
const result = await AttendeeService.search(tenantId, null, { limit: 10, offset: 0 }, {

"Individual": {

"name": {
"givenName": name
// "givenName": "Ava Taylor"
},

// "mobileNumber": null,

"locality": {
"id": null,
"tenantId": null,
"code": locallity,
"geometry": null,
"auditDetails": null,
"additionalDetails": null
}
}

});

return result.Individual;
} catch (error) {
throw error; // throw on error
}
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Normalize naming and slim payload.

  • Fix typo locallitylocality.
  • Send minimal locality object.
-  searchIndividual: async ({ name, locallity, tenantId }) => {
+  searchIndividual: async ({ name, locality, tenantId }) => {
@@
-      const result = await AttendeeService.search(tenantId, null, { limit: 10, offset: 0 }, {
+      const result = await AttendeeService.search(tenantId, {}, { limit: 10, offset: 0 }, {
@@
-          "locality": {
-            "id": null,
-            "tenantId": null,
-            "code": locallity,
-            "geometry": null,
-            "auditDetails": null,
-            "additionalDetails": null
-          }
+          "locality": { "code": locality }
📝 Committable suggestion

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

Suggested change
searchIndividual: async ({ name, locallity, tenantId }) => {
try {
// if (data?.SelectEmployeePhoneNumber && data?.SelectEmployeePhoneNumber?.trim().length > 0) {
const result = await AttendeeService.search(tenantId, null, { limit: 10, offset: 0 }, {
"Individual": {
"name": {
"givenName": name
// "givenName": "Ava Taylor"
},
// "mobileNumber": null,
"locality": {
"id": null,
"tenantId": null,
"code": locallity,
"geometry": null,
"auditDetails": null,
"additionalDetails": null
}
}
});
return result.Individual;
} catch (error) {
throw error; // throw on error
}
searchIndividual: async ({ name, locality, tenantId }) => {
try {
// if (data?.SelectEmployeePhoneNumber && data?.SelectEmployeePhoneNumber?.trim().length > 0) {
const result = await AttendeeService.search(tenantId, {}, { limit: 10, offset: 0 }, {
"Individual": {
"name": {
"givenName": name
// "givenName": "Ava Taylor"
},
"locality": { "code": locality }
}
});
return result.Individual;
} catch (error) {
throw error; // throw on error
}
🤖 Prompt for AI Agents
In
health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/services/hrms/SearchUser.js
around lines 75–105, fix the misspelled parameter and payload field `locallity`
→ `locality` (rename the function parameter and all uses) and reduce the
locality object sent to the API to a minimal shape (e.g., only include the
locality code: { code: locality }) instead of the large stubbed object; update
the request payload to reference the corrected variable name and remove
unused/null fields.

Comment on lines 79 to 103
const result = await AttendeeService.search(tenantId, null, { limit: 10, offset: 0 }, {

"Individual": {

"name": {
"givenName": name
// "givenName": "Ava Taylor"
},

// "mobileNumber": null,

"locality": {
"id": null,
"tenantId": null,
"code": locallity,
"geometry": null,
"auditDetails": null,
"additionalDetails": null
}
}

});

return result.Individual;
} catch (error) {
Copy link
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick (assertive)

Align with AttendeeService.search params fix.

Once filters spread is guarded, passing {} (not null) avoids surprises.

🤖 Prompt for AI Agents
In
health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/services/hrms/SearchUser.js
around lines 79 to 103, the call to AttendeeService.search passes null for the
filters argument which will break when the callee guards a spread over filters;
change the second argument from null to an empty object ({}), ensuring filters
is an object so spreads/merges behave correctly and avoid surprises.

Comment on lines +75 to 76
reportingTo: data?.UserAssignment || "undefined"
},
Copy link
Contributor

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Use null and confirm shape for reportingTo; avoid string literal "undefined".

Backends typically expect either a valid identifier or null. Persisting the string "undefined" risks data-quality issues and brittle filters.

-      reportingTo: data?.UserAssignment || "undefined"
+      reportingTo: data?.UserAssignment ?? null

Also confirm whether reportingTo must be an id/uuid, code, or an object (and whether it belongs on assignment vs. user). I can align both create and update payloads once the contract is confirmed.


🏁 Script executed:

#!/bin/bash
# Locate the service.js file for the health-hrms module
file=$(find . -type f -path '*health-hrms/src/services/service.js')
echo "Service file located at: $file"

# Display the first 150 lines to inspect data assignment and context
sed -n '1,150p' "$file"

# Search the entire codebase for occurrences of 'UserAssignment' to find its origin or type definitions
rg -n 'UserAssignment'

Length of output: 7540


Replace string literal “undefined” with null in reportingTo.

-      reportingTo: data?.UserAssignment || "undefined"
+      reportingTo: data?.UserAssignment ?? null

Confirm whether reportingTo should be an identifier (id/UUID/code) or an object and adjust the payload accordingly.

📝 Committable suggestion

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

Suggested change
reportingTo: data?.UserAssignment || "undefined"
},
reportingTo: data?.UserAssignment ?? null
},
🤖 Prompt for AI Agents
In
health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/services/service.js
around lines 75-76, the property reportingTo is being set to the literal string
"undefined" — replace that with null instead and avoid stringifying missing
values; also verify the intended shape of reportingTo (whether it should be an
identifier like id/UUID/code or a full object) and adjust the payload to send
either data?.UserAssignment?.id (or equivalent identifier field) when an id is
expected, or data?.UserAssignment (the object) when an object is expected,
defaulting to null when the value is absent.

Comment on lines 89 to 94
mobileNumber: data?.SelectEmployeePhoneNumber?.startsWith(HRMS_CONSTANTS.INDIA_COUNTRY_CODE)
? data?.SelectEmployeePhoneNumber?.substring(HRMS_CONSTANTS.INDIA_COUNTRY_CODE.length)
: (data?.SelectEmployeePhoneNumber?.startsWith(HRMS_CONSTANTS.MOZ_COUNTRY_CODE)
? data?.SelectEmployeePhoneNumber?.substring(HRMS_CONSTANTS.MOZ_COUNTRY_CODE.length)
: data?.SelectEmployeePhoneNumber) || null,
? data?.SelectEmployeePhoneNumber?.substring(HRMS_CONSTANTS.MOZ_COUNTRY_CODE.length)
: data?.SelectEmployeePhoneNumber) || null,
name: data?.SelectEmployeeName,
Copy link
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick (assertive)

Normalize phone consistently; collapse country-code logic.

The nested ternary is hard to read and misses whitespace/delimiter cases. Prefer a single normalizer to strip +91/+258 and non-digits.

Example:

const normalizeMobile = (v) => {
  const s = String(v || "").replace(/\D+/g, "");         // keep digits
  return s.startsWith("91") ? s.slice(2)
       : s.startsWith("258") ? s.slice(3)
       : s || null;
};

// usage
user: {
  mobileNumber: normalizeMobile(data?.SelectEmployeePhoneNumber),
  ...
}

If you want a minimal inline change, we can replace the current ternary with a call to normalizeMobile at both create/update sites.

Also applies to: 147-152

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/components/pageComponents/SearchUserToReport.js (1)

1-135: Fix 'locallity' typo and import mismatch for AttendanceService

  • Replace all occurrences of "locallity" → "locality" in service signatures, callers and object keys. Affected files found:

    • health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/services/hrms/SearchUser.js (searchIndividual param & usage)
    • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/services/attendance/attendanceService.js (searchIndividual param & "code": locallity)
    • health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/components/pageComponents/SearchUserToReport.js (const locallity = …; AttendanceService.searchIndividual({ name, locallity, tenantId }))
    • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/SearchUserPopUp.js (AttendanceService.searchIndividual({ name, locallity, tenantId }))
  • SearchUser.js exports AttendanceService as a named export (export const AttendanceService = { ... }). Update callers to use a named import:

    • change import AttendanceService from ".../SearchUser"import { AttendanceService } from ".../SearchUser" in callers (e.g., SearchUserToReport.js, SearchUserPopUp.js).
  • After making the changes, run build/tests to verify no runtime import or parameter-name regressions.

♻️ Duplicate comments (15)
health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/components/pageComponents/SearchUserToReport.js (11)

3-5: Prune unused imports.

Timeline, Loader, useEffect, and useHistory aren’t used.

-import { PopUp, Timeline, Loader, TextInput, Button } from '@egovernments/digit-ui-components';
-import { useEffect } from "react";
-import { useHistory } from "react-router-dom";
+import { PopUp, TextInput, Button } from '@egovernments/digit-ui-components';

15-23: Remove unused vars (history, context paths).

These constants are never referenced.

-    const history = useHistory();
-    // context path variables
-    const attendanceContextPath =
-        window?.globalConfigs?.getConfig("ATTENDANCE_CONTEXT_PATH") ||
-        "health-attendance";
-    const individualContextPath =
-        window?.globalConfigs?.getConfig("INDIVIDUAL_CONTEXT_PATH") ||
-        "health-individual";
+    // (removed unused history and context-path vars)

41-48: Do not call undefined setShowToast; early-return instead. Also fix “locality” spelling.

Prevents a runtime error and aligns naming.

-            const locallity = Digit.SessionStorage.get("selectedBoundary")?.code || null;
-
-            if (locallity === null) {
-                setShowToast(
-                    { key: "error", label: t(`Locality is not selected`), transitionTime: 3000 }
-                );
-                return;
-            }
+            const locality = boundaryCode || Digit.SessionStorage.get("selectedBoundary")?.code || null;
+            if (!locality) return;

81-84: Use id, not userUuid, in submit payload.

Downstream expects value.id.

-        onSubmit({
-            id: selectedUser?.userUuid,
-            name: selectedUser?.name?.givenName
-        })
+        onSubmit({
+            id: selectedUser?.id,
+            name: selectedUser?.name?.givenName
+        })

94-120: Render children as JSX, not via children prop.

Complies with Biome rule and React convention.

-        <PopUp
-            style={{ width: "500px" }}
-            onClose={onClose}
-            heading={t("HCM_AM_SEARCH_USER")}
-            onOverlayClick={onClose}
-            children={[
-                (
-                    <div style={{
-                        display: "flex",
-                        flexDirection: "column",
-                        gap: "16px", // same as Tailwind gap-4
-                    }} >
-                        <TextInput type="search" name="title" placeholder={t("HCM_AM_VIEW_REGISTER_PLACE_HOLDER")} value={searchQuery} onChange={(e) => setSearchQuery(e.target.value)} onKeyPress={(e) => {
-                            if (e.key === "Enter") {
-                                e.preventDefault(); // prevent form submit if inside a form
-                                searchUser(searchQuery); // call your API
-                            }
-                        }} />
-
-                        {searchedIndividual.length > 0 && <SelectableList selectableList={searchedIndividual} onSelect={onSelect} />}
-
-                    </div>
-                )
-            ]}
-            footerChildren={[
+        <PopUp
+            style={{ width: "500px" }}
+            onClose={onClose}
+            heading={t("HCM_AM_SEARCH_USER")}
+            onOverlayClick={onClose}
+        >
+            <div style={{ display: "flex", flexDirection: "column", gap: "16px" }}>
+                <TextInput
+                    type="search"
+                    name="title"
+                    placeholder={t("HCM_AM_VIEW_REGISTER_PLACE_HOLDER")}
+                    value={searchQuery}
+                    onChange={(e) => setSearchQuery(e.target.value)}
+                    onKeyDown={(e) => {
+                        if (e.key === "Enter") {
+                            e.preventDefault();
+                            searchUser(searchQuery);
+                        }
+                    }}
+                />
+                {searchedIndividual.length > 0 && (
+                    <SelectableList selectableList={searchedIndividual} onSelect={onSelect} />
+                )}
+            </div>
+        </PopUp>
+        {/* Footer remains below */}
+        <PopUp
+            style={{ display: "none" }}
+            footerChildren={[
                 <Button
                     type={"button"}
                     size={"large"}
                     variation={"primary"}
                     label={t("HCM_AM_ASSIGN_BT")}
                     onClick={handleEnrollAttendee}
                 />,
             ]}
             sortFooterChildren={true}
-        />
+        />

If the PopUp supports JSX children and a footer simultaneously (likely), prefer a single PopUp element with both children and footerChildren instead of the placeholder second PopUp wrapper above.


106-111: Use onKeyDown instead of deprecated onKeyPress.

-                        <TextInput ... onKeyPress={(e) => {
+                        <TextInput ... onKeyDown={(e) => {
                             if (e.key === "Enter") {
                               e.preventDefault();
                               searchUser(searchQuery);
                             }
                           }} />

121-127: Disable submit when no selection.

Prevents accidental empty submits; keep guard in handler too.

                 <Button
                     type={"button"}
                     size={"large"}
                     variation={"primary"}
                     label={t("HCM_AM_ASSIGN_BT")}
-                    onClick={handleEnrollAttendee}
+                    onClick={handleEnrollAttendee}
+                    isDisabled={!selectedUser}
                 />,

27-30: Remove unused label computations.

labels, maxLabelLength, and labelWidth are not used.

-    const labels = ["HCM_AM_ATTENDANCE_NOT_FIND_USER_LABEL", "HCM_AM_ATTENDANCE_USER_ASSIGN_REGISTER"];
-    const maxLabelLength = Math.max(...labels.map(label => label.length));
-    const labelWidth = `${maxLabelLength * 8}px`;
+    // (removed unused label computations)

77-90: Defensively no-op when nothing is selected.

Avoid submitting an empty payload.

     const handleEnrollAttendee = async () => {
-
-        // userUuid
-
-        onSubmit({
-            id: selectedUser?.userUuid,
-            name: selectedUser?.name?.givenName
-        })
-
-        onClose();
-        return ;
+        if (!selectedUser) return;
+        onSubmit({
+            id: selectedUser?.id,
+            name: selectedUser?.name?.givenName,
+        });
+        onClose();
     };

56-61: Pass locality (correctly spelled) to the service and trim query.

Also guard against empty query.

-            const result = await AttendanceService.searchIndividual(
-                { name, locallity, tenantId }
-            );
-
-            setSearchedIndividual(result)
+            const q = (name || "").trim();
+            if (!q) return;
+            const result = await AttendanceService.searchIndividual({ name: q, locality, tenantId });
+            setSearchedIndividual(Array.isArray(result) ? result : []);

Follow-up: Update the service signature and usage to locality (not locallity) in:

  • health-hrms/src/services/hrms/SearchUser.js → searchIndividual({ name, locality, tenantId }) and the body "code": locality.
    If other call sites use the misspelling, update them too.

37-68: Small UX hardening in searchUser: trim query, prefer prop over session, consistent naming.

Consolidated improvements without changing behavior.

-    const searchUser = async (name) => {
+    const searchUser = async (name) => {
       try {
-            const locallity = Digit.SessionStorage.get("selectedBoundary")?.code || null;
-            if (locallity === null) { /* toast removed */ return; }
+            const locality = boundaryCode || Digit.SessionStorage.get("selectedBoundary")?.code || null;
+            if (!locality) return;
-            const result = await AttendanceService.searchIndividual(
-                { name, locallity, tenantId }
-            );
-            setSearchedIndividual(result)
+            const q = (name || "").trim();
+            if (!q) return;
+            const result = await AttendanceService.searchIndividual({ name: q, locality, tenantId });
+            setSearchedIndividual(Array.isArray(result) ? result : []);
       } catch (error) {
-            /* swallow */
+            // optional: Digit.UserService?.notify? or log
       }
     }
health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/components/config/createEmployeeConfig.js (1)

294-305: Remove leftover “testing” placeholder and commented block.

This dead code adds noise and risks drift with the injected approach in CreateEmployee. Keep a single source of truth.

-            // // INFO:: testing
-
-            // {
-            //   type: "component",
-            //   isMandatory: true,
-            //   component: "UserAssignment",
-            //   key: "UserAssignment",
-            //   withoutLabel: true,
-            //   populators: {
-            //     name: "UserAssignment",
-            //   },
-            // },
health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/pages/employee/createEmployee.js (3)

331-339: Verify component registration and filename spelling.

Ensure the module registers UserAssignment and that the file is named UserAssignment.js (not UserAssigment.js) everywhere.

#!/bin/bash
# Check registration and spelling
rg -nP '(componentsToRegister|ComponentRegistryService).*UserAssignment|component:\s*"UserAssignment"'
fd -t f -a 'UserAssigment.js' 2>/dev/null || true

75-77: Remove debugger.

Breaks CI lint and can pause prod.

-    debugger
+

149-162: Don’t traverse config on each change; memoize the phone field config.

Precompute once and use it here to avoid null risks and repeated work.

-    // Validate mobile number
-    const contactFieldConfig = updatedConfig?.form?.flatMap(section => section?.body || [])
-      .find(field => field?.populators?.name === "SelectEmployeePhoneNumber");
-
-    if (EmployeeContactNumber && !validatePhoneNumber(EmployeeContactNumber, contactFieldConfig)) {
+    // Validate mobile number
+    if (EmployeeContactNumber && contactFieldConfig && !validatePhoneNumber(EmployeeContactNumber, contactFieldConfig)) {
       if (!formState.errors.SelectEmployeePhoneNumber) {
         setError("SelectEmployeePhoneNumber", {
           type: "custom",
           message: t("CORE_COMMON_APPLICANT_MOBILE_NUMBER_INVALID")
         },);
       }
     } else if (formState.errors.SelectEmployeePhoneNumber) {
       clearErrors("SelectEmployeePhoneNumber");
     }

Add this near the updatedConfig declaration (outside the selected range):

const contactFieldConfig = useMemo(
  () =>
    updatedConfig?.form
      ?.flatMap((s) => s?.body || [])
      ?.find((f) => f?.populators?.name === "SelectEmployeePhoneNumber"),
  [updatedConfig]
);
📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0f597bb and 2697ffb.

📒 Files selected for processing (3)
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/components/config/createEmployeeConfig.js (2 hunks)
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/components/pageComponents/SearchUserToReport.js (1 hunks)
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/pages/employee/createEmployee.js (6 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.js

⚙️ CodeRabbit configuration file

check

Files:

  • health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/components/config/createEmployeeConfig.js
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/components/pageComponents/SearchUserToReport.js
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/pages/employee/createEmployee.js
🧠 Learnings (7)
📚 Learning: 2024-11-07T11:02:33.520Z
Learnt from: rachana-egov
PR: egovernments/DIGIT-Frontend#1770
File: health/micro-ui/web/micro-ui-internals/packages/modules/microplan/src/pages/employee/viewVillage.js:320-322
Timestamp: 2024-11-07T11:02:33.520Z
Learning: In `health/micro-ui/web/micro-ui-internals/packages/modules/microplan/src/pages/employee/viewVillage.js`, the `data?.additionalFields` object is guaranteed to be defined, so checking for its existence before accessing its keys is unnecessary.

Applied to files:

  • health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/components/config/createEmployeeConfig.js
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/pages/employee/createEmployee.js
📚 Learning: 2024-06-10T19:25:42.992Z
Learnt from: siddhant-nawale-egov
PR: egovernments/DIGIT-Frontend#698
File: micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanPreview.js:1-1
Timestamp: 2024-06-10T19:25:42.992Z
Learning: The imports in `MicroplanPreview.js` are from different libraries: `egovernments/digit-ui-components` and `egovernments/digit-ui-react-components`.

Applied to files:

  • health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/components/pageComponents/SearchUserToReport.js
📚 Learning: 2025-01-02T04:41:15.957Z
Learnt from: jagankumar-egov
PR: egovernments/DIGIT-Frontend#2089
File: micro-ui/web/micro-ui-internals/packages/modules/workbench/src/pages/employee/MDMSAddV2.js:111-111
Timestamp: 2025-01-02T04:41:15.957Z
Learning: In micro-ui/web/micro-ui-internals/packages/modules/workbench/src/pages/employee/MDMSAddV2.js, always use "mdms[0].uniqueIdentifier" for the jsonPath instead of differentiating between "SOR" and other masters.

Applied to files:

  • health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/components/pageComponents/SearchUserToReport.js
📚 Learning: 2024-10-17T12:00:51.749Z
Learnt from: Ramkrishna-egov
PR: egovernments/DIGIT-Frontend#1545
File: health/micro-ui/web/micro-ui-internals/packages/modules/microplan/src/components/ActivityCard.js:30-35
Timestamp: 2024-10-17T12:00:51.749Z
Learning: In our codebase, the 'Card' component is commonly used by passing children via the 'children' prop.

Applied to files:

  • health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/components/pageComponents/SearchUserToReport.js
📚 Learning: 2024-06-10T19:25:42.992Z
Learnt from: siddhant-nawale-egov
PR: egovernments/DIGIT-Frontend#698
File: micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/resourceMapping.js:74-74
Timestamp: 2024-06-10T19:25:42.992Z
Learning: `onKeyPress` is deprecated and should be replaced with `onKeyDown` or `onKeyUp` for handling keyboard interactions.

Applied to files:

  • health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/components/pageComponents/SearchUserToReport.js
📚 Learning: 2025-06-04T04:08:48.234Z
Learnt from: jagankumar-egov
PR: egovernments/DIGIT-Frontend#2488
File: micro-ui/web/micro-ui-internals/packages/modules/core/src/pages/employee/Login/login.js:152-152
Timestamp: 2025-06-04T04:08:48.234Z
Learning: In the employee login component (micro-ui/web/micro-ui-internals/packages/modules/core/src/pages/employee/Login/login.js), prefer using a `defaultTenant` variable to store `Digit.ULBService.getStateId()` instead of calling the function multiple times inline in the `defaultValue` object. This improves code readability and avoids function call duplication.

Applied to files:

  • health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/pages/employee/createEmployee.js
📚 Learning: 2025-02-05T10:01:29.668Z
Learnt from: Tulika-eGov
PR: egovernments/DIGIT-Frontend#2188
File: micro-ui/web/micro-ui-internals/packages/modules/core/src/pages/employee/Login/login.js:72-78
Timestamp: 2025-02-05T10:01:29.668Z
Learning: In the employee login form, defaultValues are dynamically generated from config[0].body based on populators.defaultValue, so spreading the entire defaultValues object is required rather than cherry-picking specific fields.

Applied to files:

  • health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/pages/employee/createEmployee.js
🧬 Code graph analysis (2)
health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/components/pageComponents/SearchUserToReport.js (2)
health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/services/hrms/SearchUser.js (3)
  • result (79-100)
  • AttendanceService (4-108)
  • AttendanceService (4-108)
health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/components/pageComponents/SelectableList.js (1)
  • SelectableList (3-37)
health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/pages/employee/createEmployee.js (2)
health/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/pages/employee/CreateComplaint/createComplaintForm.js (1)
  • validatePhoneNumber (53-66)
health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/components/config/createEmployeeConfig.js (2)
  • CreateEmployeeConfig (6-322)
  • CreateEmployeeConfig (6-322)
🪛 Biome (2.1.2)
health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/components/pageComponents/SearchUserToReport.js

[error] 99-99: Avoid passing children using a prop

The canonical way to pass children in React is to use JSX elements

(lint/correctness/noChildrenProp)

health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/pages/employee/createEmployee.js

[error] 76-76: This is an unexpected use of the debugger statement.

Unsafe fix: Remove debugger statement

(lint/suspicious/noDebugger)

🔇 Additional comments (4)
health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/components/pageComponents/SearchUserToReport.js (1)

70-74: Selection wiring looks fine.

Parent receives the selected user object from SelectableList.

health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/pages/employee/createEmployee.js (3)

322-324: Delete commented-out assignments.
[ suggest_nitpick ]

-  //const fConfig = CreateEmployeeConfig?.CreateEmployeeConfig?.[0];
-  //const fConfig = mdmsData ? mdmsData : CreateEmployeeConfig?.CreateEmployeeConfig?.[0];
-

372-378: LGTM: dynamic max-date wiring.

Sets DOB and appointment max dates via preProcess; aligns with config.


386-393: Confirm edit-mode field removals.

You filter out password fields and Jurisdictions in edit flows. Validate this matches UX rules and that UserAssignment remains visible when editing.

import { PopUp, Timeline, Loader, TextInput, Button } from '@egovernments/digit-ui-components';
import { useEffect } from "react";
import { useHistory } from "react-router-dom";
import AttendanceService from "../../services/hrms/SearchUser";
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Fix incorrect import of AttendanceService (named export, not default).

SearchUser.js exports AttendanceService as a named export. Importing it as default will be undefined at runtime.

-import AttendanceService from "../../services/hrms/SearchUser";
+import { AttendanceService } from "../../services/hrms/SearchUser";
📝 Committable suggestion

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

Suggested change
import AttendanceService from "../../services/hrms/SearchUser";
import { AttendanceService } from "../../services/hrms/SearchUser";
🤖 Prompt for AI Agents
In
health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/components/pageComponents/SearchUserToReport.js
around line 6, the file incorrectly imports AttendanceService as a default
export; since SearchUser.js exports AttendanceService as a named export the
import will be undefined at runtime — change the import to a named import (e.g.
import { AttendanceService } from "../../services/hrms/SearchUser";), keeping
the same path and ensuring any usages match the named binding.

Comment on lines +50 to +55
if (/^\d+$/.test(name)) {
console.log("it is nummeric");
} else {
console.log("it is not nummeric");
}

Copy link
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick (assertive)

Drop console noise.

Remove debug logs (“nummeric” typo) to keep console clean.

-            if (/^\d+$/.test(name)) {
-                console.log("it is nummeric");
-            } else {
-                console.log("it is not nummeric");
-            }
+            // optional: handle numeric-only input if required by UX
📝 Committable suggestion

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

Suggested change
if (/^\d+$/.test(name)) {
console.log("it is nummeric");
} else {
console.log("it is not nummeric");
}
// optional: handle numeric-only input if required by UX
🤖 Prompt for AI Agents
In
health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/components/pageComponents/SearchUserToReport.js
around lines 50 to 55, remove the two console.log debug statements (which also
contain a typo "nummeric") to eliminate console noise; if logging is required
use the app's logger at an appropriate log level or return a boolean/result from
the function instead, and ensure any user-facing behavior relies on that return
value rather than console output.

Comment on lines +50 to 56
const { data: mdmsData, isLoading: isHRMSConfigLoading } = Digit.Hooks.useCommonMDMS(Digit.ULBService.getStateId(), "egov-hrms", ["CreateEmployeeConfig"], {
select: (data) => {
return data?.["egov-hrms"]?.CreateEmployeeConfig?.[0];
},
retry: false,
enable: false,
});
Copy link
Contributor

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Fix react-query option name: use enabled, not enable.

enable is ignored; the query behavior becomes implicit. Use enabled and set the intended value (likely true since MDMS-driven config is being used).

-  const { data: mdmsData, isLoading: isHRMSConfigLoading } = Digit.Hooks.useCommonMDMS(Digit.ULBService.getStateId(), "egov-hrms", ["CreateEmployeeConfig"], {
-    select: (data) => {
-      return data?.["egov-hrms"]?.CreateEmployeeConfig?.[0];
-    },
-    retry: false,
-    enable: false,
-  });
+  const { data: mdmsData, isLoading: isHRMSConfigLoading } = Digit.Hooks.useCommonMDMS(
+    Digit.ULBService.getStateId(),
+    "egov-hrms",
+    ["CreateEmployeeConfig"],
+    {
+      select: (data) => data?.["egov-hrms"]?.CreateEmployeeConfig?.[0],
+      retry: false,
+      enabled: true,
+    }
+  );

🏁 Script executed:

#!/bin/bash
# Verify convention across repo (should be `enabled`, not `enable`)
rg -nP 'useCommonMDMS\([^)]*\{\s*[^}]*enab\w*\s*:' -C2

Length of output: 0


🏁 Script executed:

#!/bin/bash
set -euo pipefail
printf "PWD: %s\n\n" "$(pwd)"
printf "Top-level files/directories:\n"
ls -la | sed -n '1,200p' || true

echo -e "\nSearching for files named createEmployee.js..."
rg -n --hidden -S "createEmployee\.js" -g '!**/node_modules/**' -C3 || true

echo -e "\nSearching for occurrences of 'useCommonMDMS'..."
rg -n --hidden -S "useCommonMDMS" -g '!**/node_modules/**' -C3 || true

echo -e "\nSearching for occurrences of 'Digit.Hooks.useCommonMDMS'..."
rg -n --hidden -S "Digit\.Hooks\.useCommonMDMS" -g '!**/node_modules/**' -C3 || true

echo -e "\nSearching repo-wide for 'enable:' in JS/TS files (excluding node_modules)..."
rg -n --hidden -S "\benable\s*:" -g '!**/node_modules/**' -t js -t ts -t jsx -t tsx -C2 || true

echo -e "\nSearching repo-wide for 'enabled:' in JS/TS files (excluding node_modules)..."
rg -n --hidden -S "\benabled\s*:" -g '!**/node_modules/**' -t js -t ts -t jsx -t tsx -C2 || true

TARGET="health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/pages/employee/createEmployee.js"
echo -e "\nChecking specific target file: $TARGET"
if [ -f "$TARGET" ]; then
  echo "---- File content (first 240 lines) ----"
  sed -n '1,240p' "$TARGET"
else
  echo "Target file not found: $TARGET"
fi

Length of output: 10170


Use react-query's enabled option (not enable)

In health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/pages/employee/createEmployee.js (lines 50-56) replace enable: false with enabled: trueenable is ignored by react-query.

🤖 Prompt for AI Agents
In
health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/pages/employee/createEmployee.js
around lines 50 to 56, the react-query option is misspelled as `enable: false`
(which is ignored); replace it with `enabled: true` so the hook actually runs
and returns data. Ensure you only change the option key from `enable` to
`enabled` and set it to `true`.

Comment on lines 326 to 362
// Original config assignment
const fConfig = mdmsData ? mdmsData : CreateEmployeeConfig?.CreateEmployeeConfig?.[0];

// Define your new component to be injected
const userAssignmentComponent = {
type: "component",
isMandatory: true,
component: "UserAssignment",
key: "UserAssignment",
withoutLabel: true,
populators: {
name: "UserAssignment",
},
};

// Find the section where you want to insert (HR_NEW_EMPLOYEE_FORM_HEADER)
const newEmployeeFormSection = fConfig?.form?.find(
(section) => section.head === "HR_NEW_EMPLOYEE_FORM_HEADER"
);

if (newEmployeeFormSection) {
const body = newEmployeeFormSection.body;

// Check if UserAssignment already exists
const alreadyExists = body.some((field) => field.key === "UserAssignment");

if (!alreadyExists) {
// Find index of RolesAssigned field
const index = body.findIndex((field) => field.key === "RolesAssigned");

if (index !== -1) {
// Insert UserAssignment right after RolesAssigned
body.splice(index + 1, 0, userAssignmentComponent);
}
}
}

Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Avoid mutating imported/MDMS config; clone and inject deterministically.

Current splice mutates fConfig (which may be shared). Clone and compute via useMemo for stability and idempotency.

-// Original config assignment
-const fConfig = mdmsData ? mdmsData : CreateEmployeeConfig?.CreateEmployeeConfig?.[0];
+// Base config (MDMS overrides static)
+const baseConfig = mdmsData ?? CreateEmployeeConfig?.CreateEmployeeConfig?.[0];

 // Define your new component to be injected
 const userAssignmentComponent = {
   type: "component",
   isMandatory: true,
   component: "UserAssignment",
   key: "UserAssignment",
   withoutLabel: true,
   populators: {
     name: "UserAssignment",
   },
 };

-// Find the section where you want to insert (HR_NEW_EMPLOYEE_FORM_HEADER)
-const newEmployeeFormSection = fConfig?.form?.find(
-  (section) => section.head === "HR_NEW_EMPLOYEE_FORM_HEADER"
-);
-
-if (newEmployeeFormSection) {
-  const body = newEmployeeFormSection.body;
-
-  // Check if UserAssignment already exists
-  const alreadyExists = body.some((field) => field.key === "UserAssignment");
-
-  if (!alreadyExists) {
-    // Find index of RolesAssigned field
-    const index = body.findIndex((field) => field.key === "RolesAssigned");
-
-    if (index !== -1) {
-      // Insert UserAssignment right after RolesAssigned
-      body.splice(index + 1, 0, userAssignmentComponent);
-    }
-  }
-}
+// Compute fConfig without side effects
+const fConfig = useMemo(() => {
+  if (!baseConfig) return baseConfig;
+  const cfg = typeof structuredClone === "function"
+    ? structuredClone(baseConfig)
+    : JSON.parse(JSON.stringify(baseConfig));
+  const section = cfg?.form?.find((s) => s.head === "HR_NEW_EMPLOYEE_FORM_HEADER");
+  if (!section || !Array.isArray(section.body)) return cfg;
+  const alreadyExists = section.body.some((f) => f?.key === "UserAssignment");
+  if (!alreadyExists) {
+    const index = section.body.findIndex((f) => f?.key === "RolesAssigned");
+    if (index !== -1) section.body.splice(index + 1, 0, userAssignmentComponent);
+  }
+  return cfg;
+}, [baseConfig]);
📝 Committable suggestion

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

Suggested change
// Original config assignment
const fConfig = mdmsData ? mdmsData : CreateEmployeeConfig?.CreateEmployeeConfig?.[0];
// Define your new component to be injected
const userAssignmentComponent = {
type: "component",
isMandatory: true,
component: "UserAssignment",
key: "UserAssignment",
withoutLabel: true,
populators: {
name: "UserAssignment",
},
};
// Find the section where you want to insert (HR_NEW_EMPLOYEE_FORM_HEADER)
const newEmployeeFormSection = fConfig?.form?.find(
(section) => section.head === "HR_NEW_EMPLOYEE_FORM_HEADER"
);
if (newEmployeeFormSection) {
const body = newEmployeeFormSection.body;
// Check if UserAssignment already exists
const alreadyExists = body.some((field) => field.key === "UserAssignment");
if (!alreadyExists) {
// Find index of RolesAssigned field
const index = body.findIndex((field) => field.key === "RolesAssigned");
if (index !== -1) {
// Insert UserAssignment right after RolesAssigned
body.splice(index + 1, 0, userAssignmentComponent);
}
}
}
// Base config (MDMS overrides static)
const baseConfig = mdmsData ?? CreateEmployeeConfig?.CreateEmployeeConfig?.[0];
// Define your new component to be injected
const userAssignmentComponent = {
type: "component",
isMandatory: true,
component: "UserAssignment",
key: "UserAssignment",
withoutLabel: true,
populators: {
name: "UserAssignment",
},
};
// Compute fConfig without side effects
const fConfig = useMemo(() => {
if (!baseConfig) return baseConfig;
const cfg = typeof structuredClone === "function"
? structuredClone(baseConfig)
: JSON.parse(JSON.stringify(baseConfig));
const section = cfg?.form?.find((s) => s.head === "HR_NEW_EMPLOYEE_FORM_HEADER");
if (!section || !Array.isArray(section.body)) return cfg;
const alreadyExists = section.body.some((f) => f?.key === "UserAssignment");
if (!alreadyExists) {
const index = section.body.findIndex((f) => f?.key === "RolesAssigned");
if (index !== -1) section.body.splice(index + 1, 0, userAssignmentComponent);
}
return cfg;
}, [baseConfig]);
🤖 Prompt for AI Agents
In
health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/pages/employee/createEmployee.js
around lines 326-362, the code mutates the imported/MDMS config via splice which
can affect shared references; instead create an immutable cloned config (deep
clone the relevant fConfig object or its form array), perform the injection on
the clone, and memoize the result with useMemo so the operation is deterministic
and idempotent; ensure the code checks for existing UserAssignment before
inserting, inserts into the cloned body at the computed index, and then use the
cloned/memoized config for rendering so the original MDMS data is never
modified.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

♻️ Duplicate comments (24)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/EditAttendanceManagementTable.js (8)

10-10: Remove unused import.

The AttendeeService import is not being used anywhere in this component. The component uses the hook useDeleteAttendeeFromRegister instead.

-import AttendeeService from "../services/attendance/attendee_service/attendeeService";
-

2-2: Remove unused imports and variables.

The history variable and useHistory import are not used in this component. Additionally, url from Digit.Hooks.useQueryParams() is also unused.

-import { useHistory } from "react-router-dom";
 const { t } = useTranslation();
-const history = useHistory();
-const url = Digit.Hooks.useQueryParams();

Also applies to: 34-35


41-41: Remove unused state variable.

The toast state variable is declared but never used. The component uses showToast instead.

-const [toast, setToast] = useState({ show: false, label: "", type: "" });
-

121-152: Clean up commented code.

This large block of commented code should be removed to improve code readability. If this functionality is needed in the future, it can be retrieved from version control.

-    // {
-    //   name: t("HCM_AM_ACTION"),
-    //   selector: (row) => {
-    //     return (
-    //       <div className="ellipsis-cell" title={t(row?.[5] || "0")}>
-    //         {row?.[5] == false ? <Tag label={t("HCM_AM_VIEW_REGISTER_DISABLED_TAG")} type="error" stroke={false} /> :
-    //           <Button
-    //             className="custom-class"
-    //             icon="Edit"
-    //             iconFill=""
-    //             label={t(`HCM_AM_VIEW_REGISTER_DISABLE_USER`)}
-    //             onClick={() => {
-    //               setSelectedRowId(row?.[0]);
-    //               setOpenAlertPopUp(true);
-    //               // handleDaysWorkedChange(row?.[0])
-    //             }}
-    //             options={[]}
-    //             optionsKey=""
-    //             size=""
-    //             style={{}}
-    //             title={t(`HCM_AM_VIEW_REGISTER_DISABLE_USER`)}
-    //             variation="secondary"
-    //           />
-    //         }
-    //       </div>
-    //     );
-    //   },
-    //   style: {
-    //     justifyContent: "flex-end",
-    //   },
-    // },

161-161: Use strict equality for boolean comparison.

Use strict equality (===) instead of loose equality (==) when comparing boolean values.

-              {row?.[5] == false ? <Tag label={t("HCM_AM_VIEW_REGISTER_DISABLED_TAG")} type="error" stroke={false} /> :
+              {row?.[5] === false ? <Tag label={t("HCM_AM_VIEW_REGISTER_DISABLED_TAG")} type="error" stroke={false} /> :

196-196: Fix timestamp calculation logic.

The denrollment date calculation seems incorrect. The current calculation Date.now() - (1 * 60 * 1000 + 30 * 1000) sets the date to 90 seconds ago, which doesn't seem meaningful for a denrollment date. Consider using the current time or a more appropriate business logic.

-      denrollmentDate: new Date(Date.now() - (1 * 60 * 1000 + 30 * 1000)).getTime(),
+      denrollmentDate: Date.now(),

201-212: Remove console.log statements.

Debug console.log statements should be removed before merging to production code.

         onError: async (error) => {
-
-          console.log("hello", error)
           setShowToast(
         onSuccess: async (responseData) => {
-
-          console.log("responseData", responseData);
-
           setShowToast({ key: "success", label: t(`HCM_AM_ATTENDEE_DE_ENROLL_SUCCESS_MESSAGE`), transitionTime: 3000 });

249-249: Remove commented code.

The commented error prop should be removed if it's not needed.

           type={showToast.key}
-          // error={showToast.key === "error"}
           transitionTime={showToast.transitionTime}
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/config/AttendeeInboxConfig.js (5)

132-133: Remove hardcoded tenantId value.

The tenantId is hardcoded to "dev" in both defaultValues and requestParam. This should be dynamically retrieved using Digit.ULBService.getCurrentTenantId() or passed as a parameter.

           defaultValues: {
             // Default search parameters
             codes: "",
             limit: 10,
             names: "",
             phone: "",
             roles: "",
             offset: 0,
-            tenantId: "dev",
+            tenantId: Digit.ULBService.getCurrentTenantId(),
             sortOrder: "DESC",
           },
       requestParam: {
         // Default request parameters for API call
         offset: 0,
-        tenantId: "dev",
+        tenantId: Digit.ULBService.getCurrentTenantId(),
       },

Also applies to: 203-204


171-174: Missing jsonPath for ASSIGNMENT column.

The ASSIGNMENT column is defined without a jsonPath, which means it won't display any data. Either provide the correct jsonPath or remove this column if it's not needed.

             {
               label: "HCM_ASSIGNMENT",
-              //jsonPath: "assignments[0]",
+              jsonPath: "assignments[0]", // or remove this column entirely
               additionalCustomization: true,
             },

175-179: Remove commented code block.

Clean up the commented code for the HR_EMPLOYMENT_DEPARTMENT_LABEL column.

-            // {
-            //   label: "HR_EMPLOYMENT_DEPARTMENT_LABEL",
-            //   jsonPath: "assignments[0]",
-            //   additionalCustomization: true,
-            // },

214-214: Remove commented component declaration.

The commented BoundaryComponent line should be removed.

     },
-    //component: BoundaryComponent,
-
     persistFormData: true, // Keeps form data persisted between searches

121-123: Use i18n key for primary button label

Replace hardcoded "Search" with the standard i18n key.

-          primaryLabel: "Search", // Label for primary search button
+          primaryLabel: "ES_COMMON_SEARCH", // Label for primary search button
health/micro-ui/web/micro-ui-internals/example/src/UICustomizations.js (6)

810-823: Duplicate/overwritten fields in MicroplanSearchConfig.preProcess

name is assigned twice; status is first read from form and later overridden by tab filter. Simplify to avoid confusion.


1108-1218: Remove redundant onClick prop in action button.

The action button in MyMicroplanSearchConfig has both onClick (empty function) and onOptionSelect handlers. The empty onClick prop is redundant and should be removed.

               isSearchable={false}
               title={t("MP_ACTIONS_FOR_MICROPLANS")}
               label={t("MP_ACTIONS_FOR_MICROPLANS")}
               isDisabled={!EstimationsfileId}
-              onClick={() => { }}
               variation="primary"
               onOptionSelect={(option) => onOptionSelect(option)}

2614-2709: AttendeeSearchInboxConfig: Remove console logs and make boundary code handling defensive.

Remove console.log statements and add defensive checks for boundaryCode operations.

-      console.log(data)
       if (data.state.filterForm && Object.keys(data.state.filterForm).length > 0) {
-      if (boundaryCode && boundaryCode.trim() !== "") {
+      if (typeof boundaryCode === "string" && boundaryCode.trim() !== "") {
         Individual.boundaryCode=boundaryCode
       }
-      console.log("payload", data)
       return data;

2223-2224: Remove empty additionalCustomizations stubs.

Multiple configs have empty additionalCustomizations functions that serve no purpose. Consider removing them to reduce bundle size.

-    additionalCustomizations: (row, key, column, value, searchResult) => { },

Also applies to: 2298-2299, 2374-2375, 2449-2450, 2524-2525, 2598-2599


839-967: Invalid Hook usage inside cell renderer and switch case declarations leak scope.

Hooks (useState, useDeleteAttendeeFromRegister, usePlanSearchEmployeeWithTagging) are called directly inside additionalCustomizations and within switch cases. This violates React Hook rules. Additionally, the switch case declarations can leak into other cases as indicated by Biome.

You need to refactor this in two ways:

  1. Extract the cell rendering logic into separate React components
  2. Wrap switch cases in block scopes to fix the noSwitchDeclarations lint errors

Here's how to fix the switch case scoping issue first:

      switch (key) {
-        case "ACTIONS":
+        case "ACTIONS": {
           const dummyFile = "c22a7676-d5d7-49b6-bcdb-83e9519f58df"
           const microplanFileId = row?.campaignDetails?.additionalDetails?.microplanFileId || dummyFile;
           // ... rest of the code
           return ( /* JSX */ );
+        }
-        case "NAME_OF_MICROPLAN":
+        case "NAME_OF_MICROPLAN": {
           // ... code
           return ( /* JSX */ );  
+        }
         // Apply same pattern for other cases
       }

For the hooks issue, create a separate component outside the config:

function MicroplanActionsCell({ row, t }) {
  const [showToast, setShowToast] = useState(false);
  const tenantId = Digit.ULBService.getCurrentTenantId();
  const microplanId = row?.id;
  
  const { data: rootEstimationApprover } = Digit.Hooks.microplanv1.usePlanSearchEmployeeWithTagging({ /* params */ });
  const { data: rootPopulationApprover } = Digit.Hooks.microplanv1.usePlanSearchEmployeeWithTagging({ /* params */ });
  const { data: rootFacilityMapper } = Digit.Hooks.microplanv1.usePlanSearchEmployeeWithTagging({ /* params */ });
  
  // Move all the handler functions and logic here
  
  return (
    // Return the JSX from the original case
  );
}

Then in the config:

    additionalCustomizations: (row, key, column, value, t, searchResult) => {
      switch (key) {
-        case "ACTIONS":
-          // Remove all hooks and logic
-          return ( /* complex JSX */ );
+        case "ACTIONS": {
+          return <MicroplanActionsCell row={row} t={t} />;
+        }
      }
    }

2859-2868: Fix noChildrenProp: Pass JSX children instead of children prop.

The PopUp component is receiving children as a prop instead of as JSX children, which violates React best practices.

-              openPopUp && <PopUp
-                style={{ minWidth: "500px" }}
-                onClose={() => { /* ... */ }}
-                heading={t("Action Needed: Tag Code")}
-                onOverlayClick={() => { /* ... */ }}
-                children={[
-                  !isTag ?
-                    <div>Do you want to fill in the Tag Code? If yes, press Enter Tag. Otherwise, Assign it.</div>
-                    : <div>
-                      <span>Tag Code</span>
-                      <TextInput type="text" name="title" placeholder={t("Enter Tag Name")} value={tag} onChange={(e) => setTag(e.target.value)} />
-                    </div>
-                ]}
+              openPopUp && (
+                <PopUp
+                  style={{ minWidth: "500px" }}
+                  onClose={() => { /* ... */ }}
+                  heading={t("Action Needed: Tag Code")}
+                  onOverlayClick={() => { /* ... */ }}>
+                  {!isTag ? (
+                    <div>Do you want to fill in the Tag Code? If yes, press Enter Tag. Otherwise, Assign it.</div>
+                  ) : (
+                    <div>
+                      <span>Tag Code</span>
+                      <TextInput type="text" name="title" placeholder={t("Enter Tag Name")} value={tag} onChange={(e) => setTag(e.target.value)} />
+                    </div>
+                  )}
+                </PopUp>
+              )
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/editAttendeesPopUp.js (5)

1-10: Remove unused imports to reduce bundle size

The following imports are not used in the component and should be removed:

  • Timeline from line 3
  • AttendeeService from line 7
  • useAttendanceSummary from line 9
-import { PopUp, Timeline, Loader, TextInput, Button } from '@egovernments/digit-ui-components';
+import { PopUp, Loader, TextInput, Button } from '@egovernments/digit-ui-components';
-import AttendeeService from "../services/attendance/attendee_service/attendeeService";
-
-import { useAttendanceSummary } from "../utils/update_attendance_summary";

59-66: Add defensive checks to prevent runtime errors when attendees data is missing

The current implementation assumes attendanceRegister[0].attendees always exists, which could cause runtime errors if the API returns empty or malformed data.

 useEffect(() => {
-    if (AttendanceData?.attendanceRegister?.length > 0) {
-        const ids = AttendanceData.attendanceRegister[0].attendees.map(
-            (a) => a.individualId
-        );
-        setIndividualIds(ids);
-    }
+    const attendees = AttendanceData?.attendanceRegister?.[0]?.attendees ?? [];
+    setIndividualIds(
+        Array.isArray(attendees)
+            ? attendees.map(a => a?.individualId).filter(Boolean)
+            : []
+    );
 }, [AttendanceData]);

183-227: Fix PopUp children prop usage and swapped registerId/registerNumber props

Multiple issues in the PopUp component usage:

  1. Children should be passed as JSX elements, not via the children prop (Biome warning)
  2. The registerId and registerNumber props passed to EditAttendanceManagementTable appear to be swapped based on the prop names
 <PopUp
     style={{ minWidth: "1000px" }}
     onClose={onClose}
     heading={t(heading)}
     onOverlayClick={onClose}
-    children={[
-        isAttendanceLoading || isAllIndividualsLoading ? (
+    footerChildren={[
+        <Button
+            type={"button"}
+            size={"large"}
+            variation={"primary"}
+            label={t("HCM_AM_SAVE_AND_CLOSE")}
+            onClick={onClose}
+        />,
+    ]}
+    sortFooterChildren={true}
+>
+    {isAttendanceLoading || isAllIndividualsLoading ? (
         <Loader />
     ) : (
         <div style={{
             display: "flex",
             flexDirection: "column",
             gap: "16px",
         }} >
             <TextInput type="search" name="title" placeholder={t("HCM_AM_VIEW_REGISTER_PLACE_HOLDER")} value={searchQuery} onChange={(e) => setSearchQuery(e.target.value)} />
             <EditAttendanceManagementTable
                 data={searchQuery != "" ? filteredData : attendanceSummary}
                 setAttendanceSummary={setAttendanceSummary}
                 disableUser={disableUser}
-                registerId={businessId}
-                registerNumber={registerId}
+                registerId={registerId}
+                registerNumber={businessId}
                 editAction={true}
             />
             <div style={{ display: "grid", gridTemplateColumns: `${labelWidth} auto`, rowGap: "10px", alignItems: "center" }}>
                 <div>{t(labels[1])}</div>
                 <Button label={t("HCM_AM_SEARCH_USER")} variation="link" onClick={() => {
                     history.push(`/${window?.contextPath}/employee/payments/attendee-inbox?registerId=${registerId}&boundaryCode=${boundaryCode}`)
                 }} />
             </div>
         </div>
-    )
-    ]}
-    footerChildren={[
-        <Button
-            type={"button"}
-            size={"large"}
-            variation={"primary"}
-            label={t("HCM_AM_SAVE_AND_CLOSE")}
-            onClick={ onClose}
-        />,
-    ]}
-    sortFooterChildren={true}
-/>
+    )}
+</PopUp>

194-194: Use strict inequality check for consistency

-data={searchQuery != "" ? filteredData : attendanceSummary}
+data={searchQuery !== "" ? filteredData : attendanceSummary}

94-123: Add error handling for missing attendanceRegister data

The getUserAttendanceSummary function assumes attendanceData.attendanceRegister[0] exists without checking, which could cause a runtime error.

 function getUserAttendanceSummary(attendanceData, individualsData, t) {
+    if (!attendanceData?.attendanceRegister?.[0]?.attendees) {
+        return [];
+    }
     const attendanceLogData =
         attendanceData.attendanceRegister[0].attendees.map((individualEntry) => {
📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2697ffb and e7f2100.

📒 Files selected for processing (4)
  • health/micro-ui/web/micro-ui-internals/example/src/UICustomizations.js (24 hunks)
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/EditAttendanceManagementTable.js (1 hunks)
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/editAttendeesPopUp.js (1 hunks)
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/config/AttendeeInboxConfig.js (1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.js

⚙️ CodeRabbit configuration file

check

Files:

  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/config/AttendeeInboxConfig.js
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/EditAttendanceManagementTable.js
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/editAttendeesPopUp.js
  • health/micro-ui/web/micro-ui-internals/example/src/UICustomizations.js
🧠 Learnings (9)
📚 Learning: 2025-06-04T04:08:48.234Z
Learnt from: jagankumar-egov
PR: egovernments/DIGIT-Frontend#2488
File: micro-ui/web/micro-ui-internals/packages/modules/core/src/pages/employee/Login/login.js:152-152
Timestamp: 2025-06-04T04:08:48.234Z
Learning: In the employee login component (micro-ui/web/micro-ui-internals/packages/modules/core/src/pages/employee/Login/login.js), prefer using a `defaultTenant` variable to store `Digit.ULBService.getStateId()` instead of calling the function multiple times inline in the `defaultValue` object. This improves code readability and avoids function call duplication.

Applied to files:

  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/config/AttendeeInboxConfig.js
📚 Learning: 2025-01-02T04:41:15.957Z
Learnt from: jagankumar-egov
PR: egovernments/DIGIT-Frontend#2089
File: micro-ui/web/micro-ui-internals/packages/modules/workbench/src/pages/employee/MDMSAddV2.js:111-111
Timestamp: 2025-01-02T04:41:15.957Z
Learning: In micro-ui/web/micro-ui-internals/packages/modules/workbench/src/pages/employee/MDMSAddV2.js, always use "mdms[0].uniqueIdentifier" for the jsonPath instead of differentiating between "SOR" and other masters.

Applied to files:

  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/config/AttendeeInboxConfig.js
📚 Learning: 2024-11-07T11:02:33.520Z
Learnt from: rachana-egov
PR: egovernments/DIGIT-Frontend#1770
File: health/micro-ui/web/micro-ui-internals/packages/modules/microplan/src/pages/employee/viewVillage.js:320-322
Timestamp: 2024-11-07T11:02:33.520Z
Learning: In `health/micro-ui/web/micro-ui-internals/packages/modules/microplan/src/pages/employee/viewVillage.js`, the `data?.additionalFields` object is guaranteed to be defined, so checking for its existence before accessing its keys is unnecessary.

Applied to files:

  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/config/AttendeeInboxConfig.js
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/EditAttendanceManagementTable.js
  • health/micro-ui/web/micro-ui-internals/example/src/UICustomizations.js
📚 Learning: 2025-07-15T04:58:30.634Z
Learnt from: Hari-egov
PR: egovernments/DIGIT-Frontend#2788
File: micro-ui/web/micro-ui-internals/packages/modules/hrms/src/components/pageComponents/jurisdiction.js:26-26
Timestamp: 2025-07-15T04:58:30.634Z
Learning: In the HRMS module (micro-ui/web/micro-ui-internals/packages/modules/hrms/src/components/pageComponents/jurisdiction.js), the team has moved away from using MDMS hooks for boundary data fetching and now uses direct API calls to the boundary service endpoint `/boundary-service/boundary-relationships/_search` instead of the `useHrmsMDMS` hook with "FetchBoundaries" parameter.

Applied to files:

  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/config/AttendeeInboxConfig.js
📚 Learning: 2024-11-07T07:17:27.636Z
Learnt from: jagankumar-egov
PR: egovernments/DIGIT-Frontend#1763
File: health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/MyCampaign.js:65-75
Timestamp: 2024-11-07T07:17:27.636Z
Learning: In `MyCampaign.js`, when suggesting code improvements for the `onClickRow` function, keep suggestions simple and avoid unnecessary complexity.

Applied to files:

  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/EditAttendanceManagementTable.js
  • health/micro-ui/web/micro-ui-internals/example/src/UICustomizations.js
📚 Learning: 2024-10-26T15:11:49.938Z
Learnt from: nabeelmd-eGov
PR: egovernments/DIGIT-Frontend#1680
File: health/micro-ui/web/micro-ui-internals/example/src/UICustomizations.js:1032-1094
Timestamp: 2024-10-26T15:11:49.938Z
Learning: In the DIGIT-Frontend project, when reviewing the `UICustomizations.js` file, avoid suggesting refactoring of repetitive rendering logic in switch cases into helper functions, unless explicitly requested.

Applied to files:

  • health/micro-ui/web/micro-ui-internals/example/src/UICustomizations.js
📚 Learning: 2024-09-30T05:45:14.549Z
Learnt from: ashish-egov
PR: egovernments/DIGIT-Frontend#1441
File: health/micro-ui/web/micro-ui-internals/packages/modules/microplan/src/hooks/useGenerateIdCampaign.js:1-1
Timestamp: 2024-09-30T05:45:14.549Z
Learning: In the `useGenerateIdCampaign` function, auto assignment of default parameter values is needed in parameter destructuring.

Applied to files:

  • health/micro-ui/web/micro-ui-internals/example/src/UICustomizations.js
📚 Learning: 2024-10-17T12:00:51.749Z
Learnt from: Ramkrishna-egov
PR: egovernments/DIGIT-Frontend#1545
File: health/micro-ui/web/micro-ui-internals/packages/modules/microplan/src/components/ActivityCard.js:30-35
Timestamp: 2024-10-17T12:00:51.749Z
Learning: In our codebase, the 'Card' component is commonly used by passing children via the 'children' prop.

Applied to files:

  • health/micro-ui/web/micro-ui-internals/example/src/UICustomizations.js
📚 Learning: 2024-06-10T19:25:42.992Z
Learnt from: siddhant-nawale-egov
PR: egovernments/DIGIT-Frontend#698
File: micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanPreview.js:1-1
Timestamp: 2024-06-10T19:25:42.992Z
Learning: The imports in `MicroplanPreview.js` are from different libraries: `egovernments/digit-ui-components` and `egovernments/digit-ui-react-components`.

Applied to files:

  • health/micro-ui/web/micro-ui-internals/example/src/UICustomizations.js
🧬 Code graph analysis (3)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/EditAttendanceManagementTable.js (3)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/utils/constants.js (4)
  • defaultRowsPerPageForEditAttendee (19-19)
  • defaultRowsPerPageForEditAttendee (19-19)
  • defaultPaginationValuesForEditAttendee (22-22)
  • defaultPaginationValuesForEditAttendee (22-22)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/table_inbox_custom_style.js (2)
  • editAttendeetableCustomStyle (227-334)
  • editAttendeetableCustomStyle (227-334)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/alertPopUp.js (1)
  • AlertPopUp (19-57)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/editAttendeesPopUp.js (3)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/EditAttendanceManagementTable.js (4)
  • history (34-34)
  • useTranslation (33-33)
  • tenantId (40-40)
  • EditAttendanceManagementTable (31-272)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/SearchUserPopUp.js (10)
  • history (16-16)
  • attendanceContextPath (18-20)
  • individualContextPath (21-23)
  • useTranslation (25-25)
  • tenantId (14-14)
  • labels (28-28)
  • maxLabelLength (29-29)
  • labelWidth (30-30)
  • searchQuery (32-32)
  • SearchUserPopUp (12-176)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/utils/update_attendance_summary.js (7)
  • attendanceContextPath (4-6)
  • individualContextPath (7-9)
  • attendanceSummary (12-12)
  • individualIds (11-11)
  • isAttendanceLoading (27-28)
  • allIndividualReqCriteria (41-58)
  • isAllIndividualsLoading (60-61)
health/micro-ui/web/micro-ui-internals/example/src/UICustomizations.js (7)
health/micro-ui/web/micro-ui-internals/packages/modules/microplan/src/configs/UICustomizations.js (11)
  • url (72-72)
  • url (334-334)
  • data (52-52)
  • data (308-308)
  • Digit (680-680)
  • dic (65-71)
  • dic (322-333)
  • tabId (74-74)
  • tabId (336-336)
  • showToast (80-80)
  • microplanId (82-82)
health/micro-ui/web/micro-ui-internals/packages/modules/microplan/src/pages/employee/PopInbox.js (4)
  • url (21-21)
  • showToast (40-40)
  • microplanId (22-22)
  • config (16-16)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/pages/employee/EditRegister.js (4)
  • data (44-44)
  • Digit (32-32)
  • showToast (48-48)
  • loading (49-49)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/services/attendance/attendanceService.js (3)
  • response (9-16)
  • response (32-39)
  • response (55-62)
health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/hooks/useUpdateAppConfig.js (1)
  • response (7-33)
health/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/Modal.js (1)
  • Modal (6-75)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/SearchUserPopUp.js (1)
  • createMapping (15-15)
🪛 Biome (2.1.2)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/editAttendeesPopUp.js

[error] 183-183: Avoid passing children using a prop

The canonical way to pass children in React is to use JSX elements

(lint/correctness/noChildrenProp)

health/micro-ui/web/micro-ui-internals/example/src/UICustomizations.js

[error] 887-887: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.

The declaration is defined in this switch clause:

Safe fix: Wrap the declaration in a block.

(lint/correctness/noSwitchDeclarations)


[error] 888-888: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.

The declaration is defined in this switch clause:

Safe fix: Wrap the declaration in a block.

(lint/correctness/noSwitchDeclarations)


[error] 889-889: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.

The declaration is defined in this switch clause:

Safe fix: Wrap the declaration in a block.

(lint/correctness/noSwitchDeclarations)


[error] 890-890: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.

The declaration is defined in this switch clause:

Safe fix: Wrap the declaration in a block.

(lint/correctness/noSwitchDeclarations)


[error] 902-916: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.

The declaration is defined in this switch clause:

Safe fix: Wrap the declaration in a block.

(lint/correctness/noSwitchDeclarations)


[error] 918-962: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.

The declaration is defined in this switch clause:

Safe fix: Wrap the declaration in a block.

(lint/correctness/noSwitchDeclarations)


[error] 964-966: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.

The declaration is defined in this switch clause:

Safe fix: Wrap the declaration in a block.

(lint/correctness/noSwitchDeclarations)


[error] 2859-2859: Avoid passing children using a prop

The canonical way to pass children in React is to use JSX elements

(lint/correctness/noChildrenProp)

⏰ Context from checks skipped due to timeout of 10000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: Build application amd64
  • GitHub Check: Build application arm64
  • GitHub Check: Analyze (javascript-typescript)

Comment on lines 2712 to 2903
additionalCustomizations: (row, key, column, value, t, searchResult) => {

const tenantId = Digit.ULBService.getCurrentTenantId();

const [openPopUp, setOpenPopUp] = useState(false);
const [isTag, setIsTag] = useState(false);

const [toast, setToast] = useState(null);
const [modalOpen, setModalOpen] = useState(false);
const [sessionFormData, setSessionFormData] = useState({});
const [refreshKey, setRefreshKey,] = useState(Date.now());
const [selectedId, setSelectedId] = useState(null);
const [loading, setLoading] = useState(false);
const { mutate: createMapping } = Digit.Hooks.payments.useCreateAttendeeFromRegister(tenantId);
const { registerNumber, boundaryCode, registerId } = Digit.Hooks.useQueryParams();

const [tag, setTag] = useState("");

const handleToastClose = () => {
setToast(null);
};

const handleCreate = async (id) => {
setSelectedId(id);
setLoading(true);


await createMapping({
"attendees": [
tag == "" ?
{
registerId: registerId,
individualId: row.id,
enrollmentDate: new Date().getTime(),
tenantId: row.tenantId,

} : {
registerId: registerId,
individualId: row.id,
enrollmentDate: new Date().getTime(),
tenantId: row.tenantId,
tag: tag
}]
},
{
onError: async (error) => {

setLoading(false);
setSelectedId(null);
setTag("");

setIsTag(false);
setOpenPopUp(false);


const errorMessage = error?.response?.data?.Errors?.[0]?.message
setToast(
{ key: true, label: `${t(errorMessage)}`, type: "error" }

);



},
onSuccess: async (responseData) => {
setTag("");
setLoading(false);
setSelectedId(null);
setIsTag(false);
setOpenPopUp(false);


setToast({ key: "success", label: `${t(`HCM_AM_NEW_EMPLOYEE`)} (${row.name.givenName || ""}) ${t(`HCM_AM_ENROLLED`)}`, transitionTime: 3000 });

setTimeout(() => {
window.history.back();
}, 800);

},
}
);
}

switch (key) {
case "HCM_HR_EMP_MOBILE_LABEL":
return value ? `${value}` : t("ES_COMMON_NA");

case "HCM_HR_EMP_NAME_LABEL":
return value ? `${value}` : t("ES_COMMON_NA");

case "HCM_HR_ROLE_NO_LABEL":
return value?.length > 0 ? value?.length : t("ES_COMMON_NA");

case "HR_DESG_LABEL":
return value ? t(`${value.designation}`) : t("ES_COMMON_NA");

case "HR_EMPLOYMENT_DEPARTMENT_LABEL":
return value ? t(`${value.department}`) : t("ES_COMMON_NA");

case "HCM_HR_JURIDICTIONS_LABEL":
return value ? t(value) : (
t("ES_COMMON_NA")
);
case "HCM_ASSIGNMENT":

if (loading && (row.id === selectedId)) {
return <Loader />;
}

return <> <Button
key={refreshKey}
variation={"primary"}
label={t("ASSIGN")}
style={{ minWidth: "10rem" }}
onButtonClick={() => {

// handleCreate(row.id);

setOpenPopUp(true);
return;


}}
/>
{toast && (
<Toast
error={toast.key}
isDleteBtn={true}
label={t(toast.label)}
onClose={handleToastClose}
type={toast.type}
/>
)}
{
openPopUp && <PopUp
style={{ minWidth: "500px" }}
onClose={() => {
setTag("");
setIsTag(false);
setOpenPopUp(false);
}}
heading={t("Action Needed: Tag Code")}
onOverlayClick={() => {
setTag("");
setIsTag(false);
setOpenPopUp(false);
}}
children={[
!isTag ?
<div>Do you want to fill in the Tag Code? If yes, press Enter Tag. Otherwise, Assign it.</div>
: <div>
<span>Tag Code</span>
<TextInput type="text" name="title" placeholder={t("Enter Tag Name")} value={tag} onChange={(e) => setTag(e.target.value)} />
</div>

]}
footerChildren={[
<ButtonNew
type={"button"}
size={"large"}
variation={"primary"}
label={t(isTag ? "HCM_AM_CLOSE_BT" : "HCM_AM_ENTER_TAG")}
onClick={() => {
if (isTag) {
setTag("");
setOpenPopUp(false);
setIsTag(false);
} else {
setIsTag(true);
}
return;
}}
/>,
<ButtonNew
type={"button"}
size={"large"}
variation={"primary"}
label={t("Assign")}
onClick={() => {
handleCreate(row.id);
return;
}}
/>,
]}
sortFooterChildren={true}
/>
}
</>
default:
return t("ES_COMMON_NA");
}
},
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Invalid React Hook usage inside AttendeeSearchInboxConfig cell renderer.

Hooks are called directly inside additionalCustomizations function which violates React Hook rules. This needs to be extracted into a separate component.

Extract the attendee assignment logic into a separate React component:

function AttendeeAssignCell({ row, t }) {
  const tenantId = Digit.ULBService.getCurrentTenantId();
  const [openPopUp, setOpenPopUp] = useState(false);
  const [isTag, setIsTag] = useState(false);
  const [toast, setToast] = useState(null);
  const [tag, setTag] = useState("");
  const [loading, setLoading] = useState(false);
  const [selectedId, setSelectedId] = useState(null);
  const { registerId } = Digit.Hooks.useQueryParams();
  const { mutate: createMapping } = Digit.Hooks.payments.useCreateAttendeeFromRegister(tenantId);
  
  const handleCreate = async (id) => {
    // Move the existing handleCreate logic here
  };
  
  // Return the existing JSX
  return (
    <>
      {/* Button, Toast, and PopUp JSX */}
    </>
  );
}

Then update the config:

    additionalCustomizations: (row, key, column, value, t, searchResult) => {
      switch (key) {
-        case "HCM_ASSIGNMENT":
-          // Remove all hooks and state
-          return <> ... </>;
+        case "HCM_ASSIGNMENT": {
+          return <AttendeeAssignCell row={row} t={t} />;
+        }
      }
    }
🧰 Tools
🪛 Biome (2.1.2)

[error] 2859-2859: Avoid passing children using a prop

The canonical way to pass children in React is to use JSX elements

(lint/correctness/noChildrenProp)

🤖 Prompt for AI Agents
In health/micro-ui/web/micro-ui-internals/example/src/UICustomizations.js around
lines 2712 to 2903, React Hooks (useState, custom hooks) are being called inside
the additionalCustomizations function which violates the Rules of Hooks; extract
the entire attendee-assignment UI and logic into a separate React component
(e.g., AttendeeAssignCell) that lives outside additionalCustomizations, move all
useState and Digit.Hooks.* calls and the handleCreate handler into that
component, accept props (row, t) plus any needed ids, return the existing
Button/Toast/PopUp JSX from the component, and then replace the case
"HCM_ASSIGNMENT" body in additionalCustomizations with a simple JSX return that
renders <AttendeeAssignCell row={row} t={t} /> (ensure React is imported and the
new component is exported/available in the same file or imported accordingly and
remove all hook usage from additionalCustomizations).

Comment on lines +155 to +160
const filteredData = searchQuery.length >= 3 ?
attendanceSummary.filter(
(row) =>
row[1].toLowerCase().includes(searchQuery.toLowerCase()) || // Name
row[2].toLowerCase().includes(searchQuery.toLowerCase()) // ID
) : attendanceSummary;
Copy link
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick (assertive)

Simplify search filtering logic

The current filter applies only when the search query has 3+ characters, otherwise shows all data. This creates an inconsistent UX where typing 1-2 characters shows everything.

-const filteredData = searchQuery.length >= 3 ?
-    attendanceSummary.filter(
-        (row) =>
-            row[1].toLowerCase().includes(searchQuery.toLowerCase()) || // Name
-            row[2].toLowerCase().includes(searchQuery.toLowerCase())    // ID
-    ) : attendanceSummary;
+const filteredData = searchQuery.trim() 
+    ? attendanceSummary.filter(
+        (row) =>
+            row[1]?.toLowerCase().includes(searchQuery.toLowerCase()) || // Name
+            row[2]?.toLowerCase().includes(searchQuery.toLowerCase())    // ID
+    ) 
+    : attendanceSummary;

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/editAttendeesPopUp.js
around lines 155 to 160, remove the conditional that only applies filtering when
searchQuery.length >= 3 and instead always apply the filter: if searchQuery is
empty return attendanceSummary, otherwise filter attendanceSummary by checking
row[1] and row[2] against searchQuery (both lowercased) so typing 1-2 characters
will filter results consistently.

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (9)
health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/appConfigurationRedesign/AppLocalisationWrapper.js (2)

13-37: Reducer default is incorrect; switch will return undefined on unknown actions

Use the default: branch (not case "default"). Without it, unknown actions break the reducer.

Apply this diff:

-  switch (action.type) {
+  switch (action.type) {
     case "SET_LOC":
       return action.payload.localisationData;
-    case "default":
-      return state;
+    default:
+      return state;

94-99: React Query key mismatch; cache might not be cleared

You fetch with queryKey "FOR_APP_LOCALISATION", but remove "SEARCH_APP_LOCALISATION". Align the keys.

Suggested fix:

-      queryClient.removeQueries(["SEARCH_APP_LOCALISATION", tenantId, localeModule]);
+      queryClient.removeQueries(["FOR_APP_LOCALISATION", tenantId, localeModule]);

Alternatively, remove by predicate if the internal hook composes a different key:

-      queryClient.removeQueries(["SEARCH_APP_LOCALISATION", tenantId, localeModule]);
+      queryClient.removeQueries({
+        predicate: (q) => Array.isArray(q.queryKey) && String(q.queryKey[0]).includes("LOCALISATION"),
+      });
health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/appConfigurationRedesign/RenderConditionalField.js (1)

8-18: Undefined identifiers in dependencyFieldWrapper; component will crash

parentState, screenConfig, selectedField, and handleExpressionChange are not in props; handleExpressionChange is not defined at all.

Apply these diffs:

  1. Accept the props with a safe default for onExpressionChange:
-export const RenderConditionalField = ({
+export const RenderConditionalField = ({
   cField,
   cIndex,
   cArray,
   setDrawerState,
   updateLocalization,
   state,
   drawerState,
   AppScreenLocalisationConfig,
-  disabled,
+  disabled,
+  parentState,
+  screenConfig,
+  selectedField,
+  onExpressionChange = () => {},
 }) => {
  1. Pass the correct variable to DependentFieldsWrapper:
-          onExpressionChange={handleExpressionChange}
+          onExpressionChange={onExpressionChange}

Also ensure the caller provides these props when rendering this component (see DrawerFieldComposer).

Also applies to: 221-229

health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/appConfigurationRedesign/DrawerFieldComposer.js (3)

122-219: Hooks used inside switch cases; violates React Hooks rules

useRef/useState inside case "toggle"/"text"/"DetailsCard" are conditional. This breaks hook ordering and can cause runtime errors.

Refactor each case into its own component so hooks are at the top-level of that component. Example:

function ToggleField({ t, drawerState, panelItem, setDrawerState, resourceData }) {
  const switchRef = useRef(null);
  const [showTooltip, setShowTooltip] = useState(false);
  const isDisabled = disableFieldForMandatory(drawerState, panelItem, resourceData);
  ...
  return (...);
}

Then in RenderField’s switch return <ToggleField ... /> etc. Repeat for TextField and DetailsTable cases. This keeps hooks unconditionally ordered.


Additionally, pass required props to RenderConditionalField (see next comment).


Also applies to: 288-378

---

`159-171`: **Pass required props to RenderConditionalField to support dependencyFieldWrapper**

Currently missing parentState/screenConfig/selectedField/onExpressionChange.

Apply this diff:

```diff
                   <RenderConditionalField
                     key={cIndex}
                     cField={cField}
                     cIndex={cIndex}
                     cArray={shouldShow}
                     setDrawerState={setDrawerState}
                     updateLocalization={updateLocalization}
                     state={state}
                     drawerState={drawerState}
                     AppScreenLocalisationConfig={AppScreenLocalisationConfig}
                     disabled={drawerState?.hidden}
+                    parentState={parentState}
+                    screenConfig={state?.screenConfig?.[0]}
+                    selectedField={state?.drawerField}
+                    onExpressionChange={() => {}}
                   />

Also update DrawerFieldComposer to accept and receive parentState (see AppConfigurationWrapper change).


469-483: Add a key to items returned from map

The wrapper div lacks a React key; add one to prevent reconciliation issues.

-        {currentDrawerState?.map((panelItem, index) => {
+        {currentDrawerState?.map((panelItem, index) => {
           if (isFieldVisible(panelItem)) {
             return (
-              <div className="drawer-toggle-field-container">
+              <div className="drawer-toggle-field-container" key={panelItem?.label || index}>
                 <RenderField
health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/appConfigurationRedesign/AppFieldScreenWrapper.js (1)

54-85: Add keys to mapped fragments

The map over currentCard.cards returns fragments without keys, causing React warnings.

-        return (
-          <>
+        return (
+          <React.Fragment key={index}>
             <div className="app-config-drawer-subheader">
               <div>{t("APPCONFIG_HEAD_FIELDS")}</div>
               <ConsoleTooltip className="app-config-tooltip" toolTipContent={t("TIP_APPCONFIG_HEAD_FIELDS")} />
             </div>
             <Divider />
             {headerFields?.map(({ type, label, active, required, value }, indx, cx) => (
               <AppFieldComposer
                 ...
               />
             ))}
             <Divider />
             ...
-          </>
+          </React.Fragment>
         );
health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/appConfigurationRedesign/AppConfigurationParentLayer.js (1)

90-103: MDMS v2 flag appears omitted; may call the wrong endpoint

Similar hooks elsewhere pass the mdmsv2 boolean. Add the final true arg to ensure v2.

-  const { isLoading: isLoadingAppConfigMdmsData, data: AppConfigMdmsData } = Digit.Hooks.useCustomMDMS(
+  const { isLoading: isLoadingAppConfigMdmsData, data: AppConfigMdmsData } = Digit.Hooks.useCustomMDMS(
     Digit.ULBService.getCurrentTenantId(),
     MODULE_CONSTANTS,
     [{ name: fieldTypeMaster, limit: 1000 }],
     {
       cacheTime: Infinity,
       staleTime: Infinity,
       select: (data) => {
         return data?.[MODULE_CONSTANTS];
       },
     },
-    { schemaCode: "BASE_APP_MASTER_DATA3" } //mdmsv2
+    { schemaCode: "BASE_APP_MASTER_DATA3" }, // mdmsv2
+    true
   );
health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/utils/template_components/RegistrationComponents.js (1)

127-148: Replace clickable div with button in TextButton

Use a semantic button for accessibility.

-  <div
-    style={{ display: "inline-flex", alignItems: "center", justifyContent: "center", gap: "8px", padding: "8px 16px", background: "#FFFFFF", color: "rgba(244, 119, 56, 1)", borderRadius: "4px", cursor: "pointer", fontWeight: 400, fontSize: "16px", lineHeight: "100%", border: "none" }}
-    className="digit-search-action"
-    onClick={props.onClick}
-  >
+  <button
+    type="button"
+    style={{ display: "inline-flex", alignItems: "center", justifyContent: "center", gap: "8px", padding: "8px 16px", background: "#FFFFFF", color: "rgba(244, 119, 56, 1)", borderRadius: "4px", cursor: "pointer", fontWeight: 400, fontSize: "16px", lineHeight: "100%", border: "1px solid transparent" }}
+    className="digit-search-action"
+    onClick={props.onClick}
+  >
     {props.addMember ? <CustomSVG.AddFilled width={"16px"} height={"16px"} fill={"#F47738"} /> : <EditIcon />}
     <span className="digit-search-text">{props?.label || "EDIT_LABEL"}</span>
-  </div>
+  </button>
📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9d30480 and ee4a13d.

📒 Files selected for processing (13)
  • health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/AppPreview.js (2 hunks)
  • health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/appConfigurationRedesign/AppConfigurationParentLayer.js (11 hunks)
  • health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/appConfigurationRedesign/AppConfigurationWrapper.js (5 hunks)
  • health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/appConfigurationRedesign/AppFieldScreenWrapper.js (6 hunks)
  • health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/appConfigurationRedesign/AppLocalisationWrapper.js (2 hunks)
  • health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/appConfigurationRedesign/DependentFieldsWrapper.js (1 hunks)
  • health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/appConfigurationRedesign/DrawerFieldComposer.js (3 hunks)
  • health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/appConfigurationRedesign/ImpelComponentWrapper.js (2 hunks)
  • health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/appConfigurationRedesign/NavigationLogicWrapper.js (1 hunks)
  • health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/appConfigurationRedesign/RenderConditionalField.js (5 hunks)
  • health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/appConfigurationRedesign/useCustomT.js (1 hunks)
  • health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/utils/appConfigHelpers.js (7 hunks)
  • health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/utils/template_components/RegistrationComponents.js (14 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.js

⚙️ CodeRabbit configuration file

check

Files:

  • health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/utils/appConfigHelpers.js
  • health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/appConfigurationRedesign/RenderConditionalField.js
  • health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/appConfigurationRedesign/useCustomT.js
  • health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/appConfigurationRedesign/AppLocalisationWrapper.js
  • health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/appConfigurationRedesign/DrawerFieldComposer.js
  • health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/AppPreview.js
  • health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/appConfigurationRedesign/AppConfigurationParentLayer.js
  • health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/appConfigurationRedesign/DependentFieldsWrapper.js
  • health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/appConfigurationRedesign/ImpelComponentWrapper.js
  • health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/appConfigurationRedesign/AppFieldScreenWrapper.js
  • health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/appConfigurationRedesign/NavigationLogicWrapper.js
  • health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/appConfigurationRedesign/AppConfigurationWrapper.js
  • health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/utils/template_components/RegistrationComponents.js
🧠 Learnings (2)
📚 Learning: 2025-02-05T10:18:29.947Z
Learnt from: Tulika-eGov
PR: egovernments/DIGIT-Frontend#2188
File: micro-ui/web/micro-ui-internals/packages/modules/pgr/src/pages/employee/new-inbox.js:34-47
Timestamp: 2025-02-05T10:18:29.947Z
Learning: In the DIGIT-Frontend codebase, translations within FormComposer are handled internally by the component itself, so the translation function 't' does not need to be added to useMemo dependency arrays even when used within the memoized function that generates form configurations.

Applied to files:

  • health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/appConfigurationRedesign/useCustomT.js
📚 Learning: 2025-06-26T10:38:13.794Z
Learnt from: Hari-egov
PR: egovernments/DIGIT-Frontend#2644
File: micro-ui/web/micro-ui-internals/packages/modules/sandbox/src/pages/employee/ProductDetails/ProductDetailsComponentUpdated.js:326-345
Timestamp: 2025-06-26T10:38:13.794Z
Learning: In the DIGIT Frontend sandbox module, configuration data comes from MDMS (Master Data Management System) which provides reliable, well-structured data for UI components, reducing the likelihood of malformed configuration data that would require extensive error handling.

Applied to files:

  • health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/appConfigurationRedesign/AppConfigurationParentLayer.js
🧬 Code graph analysis (11)
health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/appConfigurationRedesign/RenderConditionalField.js (2)
health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/appConfigurationRedesign/DependentFieldsWrapper.js (1)
  • useT (73-73)
health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/appConfigurationRedesign/useCustomT.js (2)
  • useCustomT (12-40)
  • useCustomT (12-40)
health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/appConfigurationRedesign/useCustomT.js (2)
health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/appConfigurationRedesign/AppConfigurationWrapper.js (2)
  • useAppLocalisationContext (317-317)
  • currentLocale (321-321)
health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/appConfigurationRedesign/AppLocalisationWrapper.js (2)
  • locState (46-46)
  • addMissingKey (53-55)
health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/appConfigurationRedesign/AppLocalisationWrapper.js (1)
health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/appConfigurationRedesign/AppConfigurationParentLayer.js (2)
  • localeModule (66-66)
  • parentState (60-60)
health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/appConfigurationRedesign/DrawerFieldComposer.js (1)
health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/appConfigurationRedesign/useCustomT.js (2)
  • useCustomT (12-40)
  • useCustomT (12-40)
health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/appConfigurationRedesign/AppConfigurationParentLayer.js (2)
health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/NewCampaignCreate/AppFeatures.js (4)
  • isCacheLoading (117-117)
  • Digit (75-75)
  • Digit (421-421)
  • reqCriteriaForm (97-115)
health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/appConfigurationRedesign/AppConfigurationTabLayer.js (1)
  • numberTabs (111-111)
health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/appConfigurationRedesign/DependentFieldsWrapper.js (2)
health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/appConfigurationRedesign/NavigationLogicWrapper.js (5)
  • tenantId (17-17)
  • module (18-18)
  • list (20-31)
  • options (33-36)
  • selectedOption (38-42)
micro-ui/web/micro-ui-internals/packages/react-components/src/atoms/Dropdown.js (1)
  • Dropdown (94-281)
health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/appConfigurationRedesign/ImpelComponentWrapper.js (1)
health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/appConfigurationRedesign/AppConfigurationParentLayer.js (3)
  • back (530-541)
  • localeModule (66-66)
  • parentState (60-60)
health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/appConfigurationRedesign/AppFieldScreenWrapper.js (5)
health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/appConfigurationRedesign/AppConfigurationWrapper.js (4)
  • useAppLocalisationContext (317-317)
  • searchParams (328-328)
  • useTranslation (320-320)
  • useT (315-315)
health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/appConfigurationRedesign/AppLocalisationWrapper.js (3)
  • useAppLocalisationContext (9-11)
  • useAppLocalisationContext (9-11)
  • searchParams (47-47)
health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/appConfigurationRedesign/useCustomT.js (3)
  • useAppLocalisationContext (13-13)
  • useCustomT (12-40)
  • useCustomT (12-40)
health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/appConfigurationRedesign/AppConfigurationParentLayer.js (3)
  • searchParams (53-53)
  • useTranslation (49-49)
  • parentState (60-60)
health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/ConsoleToolTip.js (1)
  • ConsoleTooltip (34-69)
health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/appConfigurationRedesign/NavigationLogicWrapper.js (1)
micro-ui/web/micro-ui-internals/packages/react-components/src/atoms/Dropdown.js (1)
  • Dropdown (94-281)
health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/appConfigurationRedesign/AppConfigurationWrapper.js (3)
health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/appConfigurationRedesign/AppConfigurationParentLayer.js (1)
  • parentState (60-60)
health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/appConfigurationRedesign/useCustomT.js (2)
  • useCustomT (12-40)
  • useCustomT (12-40)
health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/AppPreview.js (1)
  • AppPreview (172-281)
health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/utils/template_components/RegistrationComponents.js (1)
health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/RenderSelectionField.js (1)
  • RenderSelectionField (4-46)
🪛 Biome (2.1.2)
health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/appConfigurationRedesign/RenderConditionalField.js

[error] 38-38: This hook is being called conditionally, but all hooks must be called in the exact same order in every component render.

For React to preserve state between calls, hooks needs to be called unconditionally and always in the same order.
See https://reactjs.org/docs/hooks-rules.html#only-call-hooks-at-the-top-level

(lint/correctness/useHookAtTopLevel)


[error] 90-90: This hook is being called from a nested function, but all hooks must be called unconditionally from the top-level component.

For React to preserve state between calls, hooks needs to be called unconditionally and always in the same order.
See https://reactjs.org/docs/hooks-rules.html#only-call-hooks-at-the-top-level

(lint/correctness/useHookAtTopLevel)

health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/appConfigurationRedesign/DrawerFieldComposer.js

[error] 196-196: This hook is being called conditionally, but all hooks must be called in the exact same order in every component render.

For React to preserve state between calls, hooks needs to be called unconditionally and always in the same order.
See https://reactjs.org/docs/hooks-rules.html#only-call-hooks-at-the-top-level

(lint/correctness/useHookAtTopLevel)


[error] 355-355: This hook is being called from a nested function, but all hooks must be called unconditionally from the top-level component.

For React to preserve state between calls, hooks needs to be called unconditionally and always in the same order.
See https://reactjs.org/docs/hooks-rules.html#only-call-hooks-at-the-top-level

(lint/correctness/useHookAtTopLevel)

health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/appConfigurationRedesign/DependentFieldsWrapper.js

[error] 514-515: The elements with this role can be changed to the following elements:

For examples and more information, see WAI-ARIA Roles

(lint/a11y/useSemanticElements)


[error] 513-520: The HTML element with the interactive role "button" is not focusable.

A non-interactive HTML element that is not focusable may not be reachable for users that rely on keyboard navigation, even with an added role like "button".
Add a tabIndex attribute to make this element focusable.

(lint/a11y/useFocusableInteractive)


[error] 513-520: Enforce to have the onClick mouse event with the onKeyUp, the onKeyDown, or the onKeyPress keyboard event.

Actions triggered using mouse events should have corresponding keyboard events to account for keyboard-only navigation.

(lint/a11y/useKeyWithClickEvents)


[error] 528-529: The elements with this role can be changed to the following elements:

For examples and more information, see WAI-ARIA Roles

(lint/a11y/useSemanticElements)


[error] 527-534: Enforce to have the onClick mouse event with the onKeyUp, the onKeyDown, or the onKeyPress keyboard event.

Actions triggered using mouse events should have corresponding keyboard events to account for keyboard-only navigation.

(lint/a11y/useKeyWithClickEvents)


[error] 527-534: The HTML element with the interactive role "button" is not focusable.

A non-interactive HTML element that is not focusable may not be reachable for users that rely on keyboard navigation, even with an added role like "button".
Add a tabIndex attribute to make this element focusable.

(lint/a11y/useFocusableInteractive)


[error] 917-924: Static Elements should not be interactive.

To add interactivity such as a mouse or key event listener to a static element, give the element an appropriate role value.

(lint/a11y/noStaticElementInteractions)


[error] 917-924: Enforce to have the onClick mouse event with the onKeyUp, the onKeyDown, or the onKeyPress keyboard event.

Actions triggered using mouse events should have corresponding keyboard events to account for keyboard-only navigation.

(lint/a11y/useKeyWithClickEvents)


[error] 598-598: Avoid passing children using a prop

The canonical way to pass children in React is to use JSX elements

(lint/correctness/noChildrenProp)

health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/appConfigurationRedesign/AppFieldScreenWrapper.js

[error] 68-68: This hook is being called from a nested function, but all hooks must be called unconditionally from the top-level component.

For React to preserve state between calls, hooks needs to be called unconditionally and always in the same order.
See https://reactjs.org/docs/hooks-rules.html#only-call-hooks-at-the-top-level

(lint/correctness/useHookAtTopLevel)


[error] 94-94: This hook is being called from a nested function, but all hooks must be called unconditionally from the top-level component.

For React to preserve state between calls, hooks needs to be called unconditionally and always in the same order.
See https://reactjs.org/docs/hooks-rules.html#only-call-hooks-at-the-top-level

(lint/correctness/useHookAtTopLevel)


[error] 134-134: This hook is being called from a nested function, but all hooks must be called unconditionally from the top-level component.

For React to preserve state between calls, hooks needs to be called unconditionally and always in the same order.
See https://reactjs.org/docs/hooks-rules.html#only-call-hooks-at-the-top-level

(lint/correctness/useHookAtTopLevel)


[error] 135-135: This hook is being called from a nested function, but all hooks must be called unconditionally from the top-level component.

For React to preserve state between calls, hooks needs to be called unconditionally and always in the same order.
See https://reactjs.org/docs/hooks-rules.html#only-call-hooks-at-the-top-level

(lint/correctness/useHookAtTopLevel)


[error] 136-136: This hook is being called from a nested function, but all hooks must be called unconditionally from the top-level component.

For React to preserve state between calls, hooks needs to be called unconditionally and always in the same order.
See https://reactjs.org/docs/hooks-rules.html#only-call-hooks-at-the-top-level

(lint/correctness/useHookAtTopLevel)


[error] 229-229: This hook is being called conditionally, but all hooks must be called in the exact same order in every component render.

For React to preserve state between calls, hooks needs to be called unconditionally and always in the same order.
See https://reactjs.org/docs/hooks-rules.html#only-call-hooks-at-the-top-level

(lint/correctness/useHookAtTopLevel)

health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/appConfigurationRedesign/NavigationLogicWrapper.js

[error] 619-619: The elements with this role can be changed to the following elements:

For examples and more information, see WAI-ARIA Roles

(lint/a11y/useSemanticElements)


[error] 618-624: The HTML element with the interactive role "button" is not focusable.

A non-interactive HTML element that is not focusable may not be reachable for users that rely on keyboard navigation, even with an added role like "button".
Add a tabIndex attribute to make this element focusable.

(lint/a11y/useFocusableInteractive)


[error] 618-624: Enforce to have the onClick mouse event with the onKeyUp, the onKeyDown, or the onKeyPress keyboard event.

Actions triggered using mouse events should have corresponding keyboard events to account for keyboard-only navigation.

(lint/a11y/useKeyWithClickEvents)


[error] 633-633: The elements with this role can be changed to the following elements:

For examples and more information, see WAI-ARIA Roles

(lint/a11y/useSemanticElements)


[error] 632-638: Enforce to have the onClick mouse event with the onKeyUp, the onKeyDown, or the onKeyPress keyboard event.

Actions triggered using mouse events should have corresponding keyboard events to account for keyboard-only navigation.

(lint/a11y/useKeyWithClickEvents)


[error] 632-638: The HTML element with the interactive role "button" is not focusable.

A non-interactive HTML element that is not focusable may not be reachable for users that rely on keyboard navigation, even with an added role like "button".
Add a tabIndex attribute to make this element focusable.

(lint/a11y/useFocusableInteractive)


[error] 949-961: Enforce to have the onClick mouse event with the onKeyUp, the onKeyDown, or the onKeyPress keyboard event.

Actions triggered using mouse events should have corresponding keyboard events to account for keyboard-only navigation.

(lint/a11y/useKeyWithClickEvents)


[error] 960-960: The elements with this role can be changed to the following elements:

For examples and more information, see WAI-ARIA Roles

(lint/a11y/useSemanticElements)


[error] 949-961: The HTML element with the interactive role "button" is not focusable.

A non-interactive HTML element that is not focusable may not be reachable for users that rely on keyboard navigation, even with an added role like "button".
Add a tabIndex attribute to make this element focusable.

(lint/a11y/useFocusableInteractive)


[error] 689-689: Avoid passing children using a prop

The canonical way to pass children in React is to use JSX elements

(lint/correctness/noChildrenProp)

health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/appConfigurationRedesign/AppConfigurationWrapper.js

[error] 326-326: This hook is being called conditionally, but all hooks must be called in the exact same order in every component render.

For React to preserve state between calls, hooks needs to be called unconditionally and always in the same order.
See https://reactjs.org/docs/hooks-rules.html#only-call-hooks-at-the-top-level

(lint/correctness/useHookAtTopLevel)


[error] 755-755: This hook is being called conditionally, but all hooks must be called in the exact same order in every component render.

For React to preserve state between calls, hooks needs to be called unconditionally and always in the same order.
See https://reactjs.org/docs/hooks-rules.html#only-call-hooks-at-the-top-level

(lint/correctness/useHookAtTopLevel)

health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/utils/template_components/RegistrationComponents.js

[error] 39-39: Alternative text title element cannot be empty

For accessibility purposes, SVGs should have an alternative text, provided via title element. If the svg element has role="img", you should add the aria-label or aria-labelledby attribute.

(lint/a11y/noSvgWithoutTitle)


[error] 39-39: Enforce to have the onClick mouse event with the onKeyUp, the onKeyDown, or the onKeyPress keyboard event.

Actions triggered using mouse events should have corresponding keyboard events to account for keyboard-only navigation.

(lint/a11y/useKeyWithClickEvents)

⏰ Context from checks skipped due to timeout of 10000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (8)
health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/appConfigurationRedesign/AppLocalisationWrapper.js (1)

41-41: parentState propagation LGTM

New prop accepted and forwarded correctly.

Also applies to: 132-133

health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/appConfigurationRedesign/AppFieldScreenWrapper.js (1)

33-34: LGTM on translation alias and navigation logic block

useT adoption and NavigationLogicWrapper wiring look correct.

Also applies to: 194-214

health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/appConfigurationRedesign/ImpelComponentWrapper.js (1)

9-10: parentState propagation LGTM

Signature now accepts parentState and forwards it properly.

health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/appConfigurationRedesign/AppConfigurationWrapper.js (2)

582-583: AppPreview now consumes useT; good change

Passing the translator function aligns with the new localization flow.


661-666: Pass parentState to DrawerFieldComposer (needed for dependencyFieldWrapper flow)

Currently not provided.

-              <DrawerFieldComposer />
+              <DrawerFieldComposer parentState={parentState} />

Also ensure DrawerFieldComposer accepts this prop.

health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/utils/appConfigHelpers.js (1)

135-164: Restructure/reverseRestructure extensions look consistent

Flattening helpers and added properties (schemaCode/prefixText/suffixText/autoFillCondition/conditionalNavigateTo) are correctly propagated.

Also applies to: 179-264, 294-340

health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/appConfigurationRedesign/useCustomT.js (1)

12-40: Approve translator hook; no direct calls detected
useCustomT returns a stable translate function; scanning the codebase found no legacy direct calls. Continue using const t = useCustomT(); t('KEY') to avoid React Hooks rule violations.

health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/appConfigurationRedesign/AppConfigurationParentLayer.js (1)

530-541: Confirm previous-tab back-nav target
When on a tab’s first page, you dispatch PREVIOUS_TAB but reset currentStep to the global first step. Should back-nav instead compute and land on the previous tab’s last page (vs its first page)?

Comment on lines +140 to 142
case "textArea":
return "textarea";
case "time":
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Restore lowercase textarea mapping in getFieldType.

Changing the case label to "textArea" drops support for the existing "textarea" value. Any config row still sending "textarea" now falls through to the default and renders as a button, breaking those fields. Please keep the lowercase mapping (and optionally add the camel-case alias if needed).

-    case "textArea":
-      return "textarea";
+    case "textarea":
+    case "textArea":
+      return "textarea";
📝 Committable suggestion

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

Suggested change
case "textArea":
return "textarea";
case "time":
case "textarea":
case "textArea":
return "textarea";
case "time":
🤖 Prompt for AI Agents
In
health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/AppPreview.js
around lines 140 to 142, the switch in getFieldType removed the lowercase
"textarea" case which causes existing configs sending "textarea" to fall through
to default; restore the lowercase mapping by adding a case "textarea": return
"textarea"; (you may also keep or add the camelCase alias case "textArea":
return "textarea"; so both values are supported).

const { isLoading: isCacheLoading, data: cacheData, refetch: refetchCache, revalidate } = Digit.Hooks.useCustomAPIHook(reqCriteriaForm);
const { isLoading: isCacheLoading, data: cacheData, refetch: refetchCache } = Digit.Hooks.useCustomAPIHook(reqCriteriaForm);

const { mutate: updateMutate } = Digit.Hooks.campaign.useUpdateAppConfig(tenantId);
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

🧩 Analysis chain

Verify mutation API; avoid “await mutate” if not promise-based

If useUpdateAppConfig exposes mutate (callback), await won’t work and try/catch won’t catch. Prefer mutateAsync.

If mutateAsync exists, refactor:

-const { mutate: updateMutate } = Digit.Hooks.campaign.useUpdateAppConfig(tenantId);
+const { mutateAsync: updateAppConfig } = Digit.Hooks.campaign.useUpdateAppConfig(tenantId);

…and replace await updateMutate(...) with await updateAppConfig(...) across this file.


🏁 Script executed:

#!/bin/bash
# Inspect hook definition and exports to confirm whether mutateAsync is available
rg -nP 'useUpdateAppConfig\s*\(' -C3
rg -nP 'useMutation\(|mutateAsync|mutate\s*:\s*' -C3

Length of output: 104508


🏁 Script executed:

#!/bin/bash
rg -nP 'updateMutate\s*\(' -n health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/appConfigurationRedesign/AppConfigurationParentLayer.js

Length of output: 159


Switch to mutateAsync for useUpdateAppConfig
Refactor the hook and calls:

- const { mutate: updateMutate } = Digit.Hooks.campaign.useUpdateAppConfig(tenantId);
+ const { mutateAsync: updateAppConfig } = Digit.Hooks.campaign.useUpdateAppConfig(tenantId);

Replace all await updateMutate(...) calls (lines 364, 386, 440, 463, 498) with await updateAppConfig(...).

📝 Committable suggestion

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

Suggested change
const { mutate: updateMutate } = Digit.Hooks.campaign.useUpdateAppConfig(tenantId);
const { mutateAsync: updateAppConfig } = Digit.Hooks.campaign.useUpdateAppConfig(tenantId);
🤖 Prompt for AI Agents
In
health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/appConfigurationRedesign/AppConfigurationParentLayer.js
around line 131, the hook currently destructures mutate as updateMutate; change
it to destructure mutateAsync and name it updateAppConfig, and then replace all
awaited calls to updateMutate(...) (at lines ~364, 386, 440, 463, 498) with
awaited calls to updateAppConfig(...). Ensure the hook line reads to extract
mutateAsync as updateAppConfig and update every call site to use
updateAppConfig(...) with the same arguments.

Comment on lines +188 to +203
useEffect(() => {
const last = currentTabPages.length
? Number(currentTabPages[currentTabPages.length - 1].order)
: null;

const isLast = last != null && Math.abs(Number(currentStep) - last) < 1e-6;

// Check if there's only one page in the current tab - if so, disable Next
const isSinglePage = currentTabPages.length === 1;

// Dispatch immediately - this runs synchronously
window.dispatchEvent(new CustomEvent("lastButtonDisabled", {
detail: isLast || isSinglePage
}));
}, [currentStep, currentTabPages]);

Copy link
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Duplicate event dispatch for lastButtonDisabled

Both effects dispatch the same event; this can cause double-fires. Merge into one effect.

-useEffect(() => {
-  const last = currentTabPages.length
-    ? Number(currentTabPages[currentTabPages.length - 1].order)
-    : null;
-  const isLast = last != null && Math.abs(Number(currentStep) - last) < 1e-6;
-  const isSinglePage = currentTabPages.length === 1;
-  window.dispatchEvent(new CustomEvent("lastButtonDisabled", { 
-    detail: isLast || isSinglePage 
-  }));
-}, [currentStep, currentTabPages]);
-
-// ALSO ADD: Dispatch the event immediately when currentTabPages changes
-// Add this new useEffect right after the above one:
-useEffect(() => {
-  // This ensures the button state is set immediately when pages load
-  if (currentTabPages.length > 0) {
-    const last = Number(currentTabPages[currentTabPages.length - 1].order);
-    const isLast = Math.abs(Number(currentStep) - last) < 1e-6;
-    const isSinglePage = currentTabPages.length === 1;
-    window.dispatchEvent(new CustomEvent("lastButtonDisabled", { 
-      detail: isLast || isSinglePage 
-    }));
-  }
-}, [currentTabPages]); // Only dep
+useEffect(() => {
+  if (!currentTabPages.length) return;
+  const last = Number(currentTabPages[currentTabPages.length - 1]?.order);
+  const isLast = Number.isFinite(last) && Math.abs(Number(currentStep) - last) < 1e-6;
+  const isSinglePage = currentTabPages.length === 1;
+  window.dispatchEvent(new CustomEvent("lastButtonDisabled", { detail: isLast || isSinglePage }));
+}, [currentStep, currentTabPages]);

Also applies to: 208-220

🤖 Prompt for AI Agents
In
health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/appConfigurationRedesign/AppConfigurationParentLayer.js
around lines 188-203 (and also 208-220), there are two useEffect blocks both
dispatching the same "lastButtonDisabled" CustomEvent which can cause duplicate
event firing; consolidate the logic into a single useEffect that computes last,
isLast and isSinglePage from currentStep and currentTabPages and then dispatches
the CustomEvent once, remove the duplicate effect, and keep the dependency array
[currentStep, currentTabPages] so the event is emitted synchronously when those
values change.

Comment on lines +222 to +235
// Build the ordered list of valid steps once.
// 👉 Replace p.step / p.order / p.name with whatever your source-of-truth field is.
const availableSteps = React.useMemo(() => {
const raw = (parentState?.steps
|| parentState?.stepOrder
|| (parentState?.currentTemplate || []).map((p) => p?.step || p?.order || p?.name)
);

return (raw || [])
.map((x) => parseFloat(String(x)))
.filter((n) => Number.isFinite(n))
.sort((a, b) => a - b);
}, [parentState]);

Copy link
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Scope availableSteps to active tab (optional)

availableSteps is global. If navigation should be within the active tab, derive from currentTabPages instead.

-const availableSteps = React.useMemo(() => {
-  const raw = (parentState?.steps
-    || parentState?.stepOrder
-    || (parentState?.currentTemplate || []).map((p) => p?.step || p?.order || p?.name)
-  );
+const availableSteps = React.useMemo(() => {
+  const raw =
+    parentState?.steps ||
+    parentState?.stepOrder ||
+    currentTabPages.map((p) => p?.step || p?.order || p?.name);
   return (raw || [])
     .map((x) => parseFloat(String(x)))
     .filter((n) => Number.isFinite(n))
     .sort((a, b) => a - b);
-}, [parentState]);
+}, [currentTabPages, parentState?.steps, parentState?.stepOrder]);
📝 Committable suggestion

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

Suggested change
// Build the ordered list of valid steps once.
// 👉 Replace p.step / p.order / p.name with whatever your source-of-truth field is.
const availableSteps = React.useMemo(() => {
const raw = (parentState?.steps
|| parentState?.stepOrder
|| (parentState?.currentTemplate || []).map((p) => p?.step || p?.order || p?.name)
);
return (raw || [])
.map((x) => parseFloat(String(x)))
.filter((n) => Number.isFinite(n))
.sort((a, b) => a - b);
}, [parentState]);
// Build the ordered list of valid steps once.
// 👉 Replace p.step / p.order / p.name with whatever your source-of-truth field is.
const availableSteps = React.useMemo(() => {
const raw =
parentState?.steps ||
parentState?.stepOrder ||
currentTabPages.map((p) => p?.step || p?.order || p?.name);
return (raw || [])
.map((x) => parseFloat(String(x)))
.filter((n) => Number.isFinite(n))
.sort((a, b) => a - b);
}, [currentTabPages, parentState?.steps, parentState?.stepOrder]);
🤖 Prompt for AI Agents
In
health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/appConfigurationRedesign/AppConfigurationParentLayer.js
around lines 222 to 235, availableSteps is currently derived from the global
parentState steps/stepOrder/currentTemplate and thus applies across all tabs;
scope it to the active tab by deriving raw from parentState.currentTabPages (or
the existing currentTabPages variable) for the currently selected tab (falling
back to parentState.steps/stepOrder/currentTemplate if not present), extract the
step/order/name from that tab's pages, and update the useMemo dependency list to
include the active tab/currentTabPages so availableSteps only reflects the
active tab’s pages.

Comment on lines +283 to +306
case "PATCH_PAGE_CONDITIONAL_NAV": {
const { pageName, data } = action; // data is the array from onConditionalNavigateChange

const patchArray = (arr) => {
if (!Array.isArray(arr) || arr.length === 0) return arr;

// If pageName is provided, try to patch by name
if (pageName) {
const idx = arr.findIndex((p) => p?.name === pageName);
if (idx !== -1) {
return arr.map((p, i) => (i === idx ? { ...p, conditionalNavigateTo: data } : p));
}
}

// Fallback: patch the first page (your “current page is first” invariant)
return arr;
};

return {
...state,
screenConfig: patchArray(state.screenConfig),
screenData: patchArray(state.screenData),
};
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

PATCH_PAGE_CONDITIONAL_NAV fallback does nothing; implement first-page patch as commented

Currently returns arr unchanged. Apply actual fallback to avoid silent no-op.

-      const patchArray = (arr) => {
+      const patchArray = (arr) => {
         if (!Array.isArray(arr) || arr.length === 0) return arr;
-
-        // If pageName is provided, try to patch by name
+        // If pageName is provided, try to patch by name
         if (pageName) {
           const idx = arr.findIndex((p) => p?.name === pageName);
           if (idx !== -1) {
             return arr.map((p, i) => (i === idx ? { ...p, conditionalNavigateTo: data } : p));
           }
         }
-
-        // Fallback: patch the first page (your “current page is first” invariant)
-        return arr;
+        // Fallback: patch the first page
+        return arr.map((p, i) => (i === 0 ? { ...p, conditionalNavigateTo: data } : p));
       };
📝 Committable suggestion

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

Suggested change
case "PATCH_PAGE_CONDITIONAL_NAV": {
const { pageName, data } = action; // data is the array from onConditionalNavigateChange
const patchArray = (arr) => {
if (!Array.isArray(arr) || arr.length === 0) return arr;
// If pageName is provided, try to patch by name
if (pageName) {
const idx = arr.findIndex((p) => p?.name === pageName);
if (idx !== -1) {
return arr.map((p, i) => (i === idx ? { ...p, conditionalNavigateTo: data } : p));
}
}
// Fallback: patch the first page (your “current page is first” invariant)
return arr;
};
return {
...state,
screenConfig: patchArray(state.screenConfig),
screenData: patchArray(state.screenData),
};
}
case "PATCH_PAGE_CONDITIONAL_NAV": {
const { pageName, data } = action; // data is the array from onConditionalNavigateChange
const patchArray = (arr) => {
if (!Array.isArray(arr) || arr.length === 0) return arr;
// If pageName is provided, try to patch by name
if (pageName) {
const idx = arr.findIndex((p) => p?.name === pageName);
if (idx !== -1) {
return arr.map((p, i) =>
i === idx ? { ...p, conditionalNavigateTo: data } : p
);
}
}
// Fallback: patch the first page
return arr.map((p, i) =>
i === 0 ? { ...p, conditionalNavigateTo: data } : p
);
};
return {
...state,
screenConfig: patchArray(state.screenConfig),
screenData: patchArray(state.screenData),
};
}
🤖 Prompt for AI Agents
In
health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/appConfigurationRedesign/AppConfigurationWrapper.js
around lines 283 to 306, the PATCH_PAGE_CONDITIONAL_NAV case defines a
patchArray that, on fallback when pageName is not found, currently returns the
array unchanged — implement the commented fallback by returning a new array
where the first element (if any) is immutably replaced with a copy that sets
conditionalNavigateTo to data; ensure you still handle non-array / empty cases
by returning the original arr, and preserve immutability for screenConfig and
screenData updates so both get the patched-first-page object when pageName
lookup fails.

Comment on lines +682 to +689
{showPopUp && editorIndex !== null && rules[editorIndex] && (
<BodyPortal>
<div className="popup-portal-overlay">
<PopUp
className="digit-popup--fullscreen"
type={"default"}
heading={editLabel}
children={[
Copy link
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Prefer JSX children over the children prop for PopUp

Replace children={[...]} with nested JSX.

-<PopUp
-  className="digit-popup--fullscreen"
-  type={"default"}
-  heading={editLabel}
-  children={[
-    <div key="single-rule-editor" style={{ display: "grid", gap: "1rem" }}>
-      {(() => { /* ... */ })()}
-    </div>,
-  ]}
-  onOverlayClick={discardAndCloseEditor}
-  onClose={discardAndCloseEditor}
-  equalWidthButtons={false}
-  footerChildren={[ /* ... */ ]}
-/>
+<PopUp
+  className="digit-popup--fullscreen"
+  type="default"
+  heading={editLabel}
+  onOverlayClick={discardAndCloseEditor}
+  onClose={discardAndCloseEditor}
+  equalWidthButtons={false}
+  footerChildren={[ /* ... */ ]}
+>
+  <div style={{ display: "grid", gap: "1rem" }}>
+    {(() => { /* ... */ })()}
+  </div>
+</PopUp>
📝 Committable suggestion

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

Suggested change
{showPopUp && editorIndex !== null && rules[editorIndex] && (
<BodyPortal>
<div className="popup-portal-overlay">
<PopUp
className="digit-popup--fullscreen"
type={"default"}
heading={editLabel}
children={[
{showPopUp && editorIndex !== null && rules[editorIndex] && (
<BodyPortal>
<div className="popup-portal-overlay">
<PopUp
className="digit-popup--fullscreen"
type="default"
heading={editLabel}
onOverlayClick={discardAndCloseEditor}
onClose={discardAndCloseEditor}
equalWidthButtons={false}
footerChildren={[ /* ... */ ]}
>
<div style={{ display: "grid", gap: "1rem" }}>
{(() => { /* ... */ })()}
</div>
</PopUp>
</div>
</BodyPortal>
)}
🧰 Tools
🪛 Biome (2.1.2)

[error] 689-689: Avoid passing children using a prop

The canonical way to pass children in React is to use JSX elements

(lint/correctness/noChildrenProp)

🤖 Prompt for AI Agents
In
health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/appConfigurationRedesign/NavigationLogicWrapper.js
around lines 682-689, the PopUp is being passed content via the children prop
(children={[ ... ]}); change this to use JSX children instead: remove the
children={...} prop and place the array/JSX elements directly between the
<PopUp>...</PopUp> tags, preserving the same elements, keys and props, and
ensure proper indentation and closing tag.

Comment on lines +948 to +966
{/* Remove condition */}
<div
style={{
marginLeft: "auto",
display: "flex",
alignItems: "center",
gap: "0.25rem",
cursor: "pointer",
}}
onClick={() => removeCondition(editorIndex, idx)}
title={removeConditionLabel}
aria-label={removeConditionLabel}
role="button"
>
<SVG.Delete fill={"#C84C0E"} width={"1.25rem"} height={"1.25rem"} />
<span style={{ color: "#C84C0E", fontSize: "0.875rem", fontWeight: 500 }}>
{removeConditionLabel}
</span>
</div>
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Make “Remove condition” control accessible

Use a button with keyboard handlers.

-<div
-  style={{ marginLeft: "auto", display: "flex", alignItems: "center", gap: "0.25rem", cursor: "pointer" }}
-  onClick={() => removeCondition(editorIndex, idx)}
-  title={removeConditionLabel}
-  aria-label={removeConditionLabel}
-  role="button"
->
-  <SVG.Delete fill={"#C84C0E"} width={"1.25rem"} height={"1.25rem"} />
-  <span style={{ color: "#C84C0E", fontSize: "0.875rem", fontWeight: 500 }}>{removeConditionLabel}</span>
-</div>
+<button
+  type="button"
+  style={{ marginLeft: "auto", display: "flex", alignItems: "center", gap: "0.25rem", cursor: "pointer", background: "none", border: "none", padding: 0 }}
+  onClick={() => removeCondition(editorIndex, idx)}
+  onKeyDown={(e) => (e.key === "Enter" || e.key === " ") && removeCondition(editorIndex, idx)}
+  title={removeConditionLabel}
+  aria-label={removeConditionLabel}
+>
+  <SVG.Delete fill={"#C84C0E"} width={"1.25rem"} height={"1.25rem"} />
+  <span style={{ color: "#C84C0E", fontSize: "0.875rem", fontWeight: 500 }}>{removeConditionLabel}</span>
+  <span className="sr-only">{removeConditionLabel}</span>
+</button>
📝 Committable suggestion

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

Suggested change
{/* Remove condition */}
<div
style={{
marginLeft: "auto",
display: "flex",
alignItems: "center",
gap: "0.25rem",
cursor: "pointer",
}}
onClick={() => removeCondition(editorIndex, idx)}
title={removeConditionLabel}
aria-label={removeConditionLabel}
role="button"
>
<SVG.Delete fill={"#C84C0E"} width={"1.25rem"} height={"1.25rem"} />
<span style={{ color: "#C84C0E", fontSize: "0.875rem", fontWeight: 500 }}>
{removeConditionLabel}
</span>
</div>
{/* Remove condition */}
- <div
- style={{
- marginLeft: "auto",
- display: "flex",
- alignItems: "center",
- gap: "0.25rem",
- cursor: "pointer",
- }}
- onClick={() => removeCondition(editorIndex, idx)}
- title={removeConditionLabel}
- aria-label={removeConditionLabel}
- role="button"
- >
- <SVG.Delete fill={"#C84C0E"} width={"1.25rem"} height={"1.25rem"} />
- <span style={{ color: "#C84C0E", fontSize: "0.875rem", fontWeight: 500 }}>
- {removeConditionLabel}
- </span>
<button
type="button"
style={{
marginLeft: "auto",
display: "flex",
alignItems: "center",
gap: "0.25rem",
cursor: "pointer",
background: "none",
border: "none",
padding: 0,
}}
onClick={() => removeCondition(editorIndex, idx)}
onKeyDown={e => (e.key === "Enter" || e.key === " ") && removeCondition(editorIndex, idx)}
title={removeConditionLabel}
aria-label={removeConditionLabel}
>
<SVG.Delete fill={"#C84C0E"} width={"1.25rem"} height={"1.25rem"} />
<span style={{ color: "#C84C0E", fontSize: "0.875rem", fontWeight: 500 }}>
{removeConditionLabel}
</span>
<span className="sr-only">{removeConditionLabel}</span>
</button>
🧰 Tools
🪛 Biome (2.1.2)

[error] 949-961: Enforce to have the onClick mouse event with the onKeyUp, the onKeyDown, or the onKeyPress keyboard event.

Actions triggered using mouse events should have corresponding keyboard events to account for keyboard-only navigation.

(lint/a11y/useKeyWithClickEvents)


[error] 960-960: The elements with this role can be changed to the following elements:

For examples and more information, see WAI-ARIA Roles

(lint/a11y/useSemanticElements)


[error] 949-961: The HTML element with the interactive role "button" is not focusable.

A non-interactive HTML element that is not focusable may not be reachable for users that rely on keyboard navigation, even with an added role like "button".
Add a tabIndex attribute to make this element focusable.

(lint/a11y/useFocusableInteractive)

🤖 Prompt for AI Agents
In
health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/appConfigurationRedesign/NavigationLogicWrapper.js
around lines 948 to 966, the "Remove condition" element is a clickable div which
is not keyboard-accessible; replace the div with a semantic <button
type="button"> (remove role="button"), keep the onClick handler, ensure
aria-label is preserved, include the SVG and label inside the button, and ensure
button has visible focus styles and prevents unintended form submission; if any
custom key handling is required, add onKeyDown to handle Enter/Space, otherwise
rely on native button behavior for keyboard accessibility.

Comment on lines +38 to 45
const FilterIcon = (props) => (
<svg onClick={props?.onClick} width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
d="M0.250666 1.61C2.27067 4.2 6.00067 9 6.00067 9V15C6.00067 15.55 6.45067 16 7.00067 16H9.00067C9.55067 16 10.0007 15.55 10.0007 15V9C10.0007 9 13.7207 4.2 15.7407 1.61C16.2507 0.95 15.7807 0 14.9507 0H1.04067C0.210666 0 -0.259334 0.95 0.250666 1.61Z"
fill="#C84C0E"
/>
</svg>

);
const Filter = (props) => (
<div className="digit-search-action">
{/* <RoundedLabel count={props.filterCount}></RoundedLabel> */}
<FilterIcon /> <span className="digit-search-text">{props.t(props.field.label) || "LABEL"}</span>
</div>
);


const Toggle = (props) => (
<Switch
label={props.t(props.field?.label) || "LABEL"}
onToggle={null}
isCheckedInitially={true}
shapeOnOff
/>
);
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

SVG used as control; add semantics and keyboard support

Wrap in a button, provide accessible name.

-const FilterIcon = (props) => (
-  <svg onClick={props?.onClick} width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
-    <path d="M0.250666 1.61C2.27067 4.2 6.00067 9 6.00067 9V15C6.00067 15.55 6.45067 16 7.00067 16H9.00067C9.55067 16 10.0007 15.55 10.0007 15V9C10.0007 9 13.7207 4.2 15.7407 1.61C16.2507 0.95 15.7807 0 14.9507 0H1.04067C0.210666 0 -0.259334 0.95 0.250666 1.61Z" fill="#C84C0E"/>
-  </svg>
-);
+const FilterIcon = ({ onClick }) => (
+  <button type="button" aria-label="Filter" onClick={onClick} style={{ background: "none", border: "none", padding: 0, cursor: "pointer" }}>
+    <svg width="16" height="16" viewBox="0 0 16 16" role="img" aria-hidden="true" xmlns="http://www.w3.org/2000/svg">
+      <title>Filter</title>
+      <path d="M0.250666 1.61C2.27067 4.2 6.00067 9 6.00067 9V15C6.00067 15.55 6.45067 16 7.00067 16H9.00067C9.55067 16 10.0007 15.55 10.0007 15V9C10.0007 9 13.7207 4.2 15.7407 1.61C16.2507 0.95 15.7807 0 14.9507 0H1.04067C0.210666 0 -0.259334 0.95 0.250666 1.61Z" fill="#C84C0E"/>
+    </svg>
+  </button>
+);
📝 Committable suggestion

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

Suggested change
const FilterIcon = (props) => (
<svg onClick={props?.onClick} width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
d="M0.250666 1.61C2.27067 4.2 6.00067 9 6.00067 9V15C6.00067 15.55 6.45067 16 7.00067 16H9.00067C9.55067 16 10.0007 15.55 10.0007 15V9C10.0007 9 13.7207 4.2 15.7407 1.61C16.2507 0.95 15.7807 0 14.9507 0H1.04067C0.210666 0 -0.259334 0.95 0.250666 1.61Z"
fill="#C84C0E"
/>
</svg>
);
const Filter = (props) => (
<div className="digit-search-action">
{/* <RoundedLabel count={props.filterCount}></RoundedLabel> */}
<FilterIcon /> <span className="digit-search-text">{props.t(props.field.label) || "LABEL"}</span>
</div>
);
const Toggle = (props) => (
<Switch
label={props.t(props.field?.label) || "LABEL"}
onToggle={null}
isCheckedInitially={true}
shapeOnOff
/>
);
const FilterIcon = ({ onClick }) => (
<button
type="button"
aria-label="Filter"
onClick={onClick}
style={{ background: "none", border: "none", padding: 0, cursor: "pointer" }}
>
<svg
width="16"
height="16"
viewBox="0 0 16 16"
role="img"
aria-hidden="true"
xmlns="http://www.w3.org/2000/svg"
>
<title>Filter</title>
<path
d="M0.250666 1.61C2.27067 4.2 6.00067 9 6.00067 9V15C6.00067 15.55 6.45067 16 7.00067 16H9.00067C9.55067 16 10.0007 15.55 10.0007 15V9C10.0007 9 13.7207 4.2 15.7407 1.61C16.2507 0.95 15.7807 0 14.9507 0H1.04067C0.210666 0 -0.259334 0.95 0.250666 1.61Z"
fill="#C84C0E"
/>
</svg>
</button>
);
🧰 Tools
🪛 Biome (2.1.2)

[error] 39-39: Alternative text title element cannot be empty

For accessibility purposes, SVGs should have an alternative text, provided via title element. If the svg element has role="img", you should add the aria-label or aria-labelledby attribute.

(lint/a11y/noSvgWithoutTitle)


[error] 39-39: Enforce to have the onClick mouse event with the onKeyUp, the onKeyDown, or the onKeyPress keyboard event.

Actions triggered using mouse events should have corresponding keyboard events to account for keyboard-only navigation.

(lint/a11y/useKeyWithClickEvents)

🤖 Prompt for AI Agents
In
health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/utils/template_components/RegistrationComponents.js
around lines 38-45, the SVG is used as an interactive control without semantics
or keyboard support; replace it with a focusable <button type="button"> wrapper
(move onClick from the svg to the button), accept and pass an accessible name
via aria-label (or aria-labelledby) from props, ensure keyboard activation is
provided by the native button, remove onClick from the svg, and forward any
className/other props to the button so styling and event handling remain
consistent.

Comment on lines +87 to 88
const Toggle = (props) => <Switch label={props.t(props.field?.label) || "LABEL"} onToggle={null} isCheckedInitially={true} shapeOnOff />;

Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Provide a no-op handler for Toggle

Avoid passing null; supply a stable function.

-const Toggle = (props) => <Switch label={props.t(props.field?.label) || "LABEL"} onToggle={null} isCheckedInitially={true} shapeOnOff />;
+const Toggle = (props) => <Switch label={props.t(props.field?.label) || "LABEL"} onToggle={() => {}} isCheckedInitially={true} shapeOnOff />;
📝 Committable suggestion

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

Suggested change
const Toggle = (props) => <Switch label={props.t(props.field?.label) || "LABEL"} onToggle={null} isCheckedInitially={true} shapeOnOff />;
const Toggle = (props) => <Switch label={props.t(props.field?.label) || "LABEL"} onToggle={() => {}} isCheckedInitially={true} shapeOnOff />;
🤖 Prompt for AI Agents
In
health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/utils/template_components/RegistrationComponents.js
around lines 87-88, the Toggle component currently passes onToggle={null};
replace that with a stable no-op handler instead of null (e.g., a module-level
or memoized no-op function such as a useCallback(() => {}) or a shared const
noop = () => {}) so the prop always receives a callable function and avoids
passing null.

Comment on lines +156 to +167
const householdDetails = props.beneficiaryDetails
? props.beneficiaryDetails
: [
//TODO: Need this to be moved to config @Pitabsh, @ram
// { label: "HOUSEHOLD_HEAD", value: "Value" },
// { label: "ADMINSTRATIVE_AREA", value: "value" },
// { label: "MEMBER_COUNT", value: 5 },

{ label: "HouseHold Head", value: "Rohit" },
{ label: "Adminstrative Area", value: "Boundary A" },
{ label: "Member Count", value: 5 },
];
Copy link
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Avoid hardcoded placeholder PII in defaults

The fallback shows real-looking names/areas. Remove or gate behind config; default to translated placeholders.

-  const householdDetails = props.beneficiaryDetails
-    ? props.beneficiaryDetails
-    : [
-        { label: "HouseHold Head", value: "Rohit" },
-        { label: "Adminstrative Area", value: "Boundary A" },
-        { label: "Member Count", value: 5 },
-      ];
+  const householdDetails = Array.isArray(props.beneficiaryDetails)
+    ? props.beneficiaryDetails
+    : [];

If placeholders are required for design, prefer keys like "N/A" via t(..).

📝 Committable suggestion

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

Suggested change
const householdDetails = props.beneficiaryDetails
? props.beneficiaryDetails
: [
//TODO: Need this to be moved to config @Pitabsh, @ram
// { label: "HOUSEHOLD_HEAD", value: "Value" },
// { label: "ADMINSTRATIVE_AREA", value: "value" },
// { label: "MEMBER_COUNT", value: 5 },
{ label: "HouseHold Head", value: "Rohit" },
{ label: "Adminstrative Area", value: "Boundary A" },
{ label: "Member Count", value: 5 },
];
const householdDetails = Array.isArray(props.beneficiaryDetails)
? props.beneficiaryDetails
: [];
🤖 Prompt for AI Agents
In
health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/utils/template_components/RegistrationComponents.js
around lines 156 to 167, replace the hardcoded PII-like fallback data with
non-identifiable, translatable placeholders or configurable defaults: remove
real-looking name/area values and instead use either values from configuration
(if provided) or neutral placeholders such as t('N/A') /
t('placeholder.householdHead') / t('placeholder.administrativeArea') and numeric
defaults like 0 or null; ensure the fallback branch checks a config flag or env
to permit demo placeholders and document where to supply real defaults via props
or config.

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

♻️ Duplicate comments (3)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/attendance_inbox/table_inbox.js (3)

87-117: Fix misleading comments and simplify condition.

The comments at lines 99 and 104 are incorrect:

  • Line 99 says "Allowed → Navigate" but this branch executes when currentDate > endDate, meaning the project has expired (not "allowed" in the sense of active).
  • Line 104 says "Expired → handle case" but this branch executes when currentDate <= endDate, meaning the project is still active (not expired).

Additionally, the condition !(currentDate <= endDate) is confusing with its double negative.

Apply this diff to fix the comments and simplify the condition:

-                if (!(currentDate <= endDate)) {
-                  // Allowed → Navigate
+                if (currentDate > endDate) {
+                  // Expired project → Navigate to view-only mode
                   history.push(
                     `/${window?.contextPath}/employee/payments/view-attendance?registerNumber=${row?.id}&boundaryCode=${row?.boundary}`
                   );
                 } else {
-                  // Expired → handle case
+                  // Active project → Navigate to edit mode
                   history.push(
                     `/${window?.contextPath}/employee/payments/edit-register?registerNumber=${row?.id}&boundaryCode=${row?.boundary}&registerId=${row?.registerId}`
                   );
                 }

Note: This code segment also has the following issues previously flagged in earlier reviews that remain unaddressed:

  • Potential ms/sec date bug: Date.now() returns milliseconds, but endDate may be in seconds. Normalize before comparison.
  • Missing stopPropagation: The click handler doesn't stop event propagation, which can cause double navigation when combined with handleRowClick.
  • Session storage preference: Prefer the selectedProject prop over session storage to avoid stale data.
  • Console.warn vs user feedback: Replace console.warn with a user-visible toast notification.

242-252: Fix loader container height for proper centering.

The loader container uses height: "1vh" (very small) combined with paddingTop: "2rem" and marginTop: "2rem", which prevents proper vertical centering. This issue was previously flagged and remains unaddressed.

For consistency, the loader container should use a similar height to the NoResultsFound component.

Apply this diff:

                 {isLoading ?
                   <div style={{
                     display: "flex",
                     justifyContent: "center",
                     alignItems: "center",
-                    height: "1vh",
-                    paddingTop: "2rem",
-                    marginTop:"2rem"
+                    height: "50vh"
                   }}>
                     <Loader />
                   </div>

261-262: Remove redundant progressPending prop.

The progressPending={isLoading} prop is always false when the DataTable renders, since this code path only executes when isLoading is false (line 242 ternary). This was previously flagged and remains unaddressed.

-                    progressPending={isLoading}
-                    progressComponent={<Loader />}
📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ee4a13d and 65aceea.

📒 Files selected for processing (3)
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/attendance_inbox/attendance_inbox.js (2 hunks)
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/attendance_inbox/table_inbox.js (2 hunks)
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/pages/employee/attendance_inbox.js (1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.js

⚙️ CodeRabbit configuration file

check

Files:

  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/attendance_inbox/attendance_inbox.js
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/attendance_inbox/table_inbox.js
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/pages/employee/attendance_inbox.js
🧬 Code graph analysis (3)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/attendance_inbox/attendance_inbox.js (2)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/bill_inbox/BillInbox.js (1)
  • selectedProject (37-37)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/SearchResultsPlaceholder.js (1)
  • SearchResultsPlaceholder (17-31)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/attendance_inbox/table_inbox.js (3)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/pages/employee/EditRegister.js (2)
  • Digit (34-34)
  • history (27-27)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/pages/employee/ViewAttendance.js (2)
  • Digit (32-32)
  • history (24-24)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/bill_inbox/billInboxTable.js (3)
  • history (23-23)
  • columns (70-140)
  • handleRowClick (159-163)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/pages/employee/attendance_inbox.js (1)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/attendance_inbox/attendance_inbox.js (1)
  • AttendanceInboxComponent (14-244)
⏰ Context from checks skipped due to timeout of 10000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Build application amd64
  • GitHub Check: Build application arm64
🔇 Additional comments (4)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/attendance_inbox/table_inbox.js (1)

255-255: LGTM: NoResultsFound height adjustment.

The height change from the original value to 40vh appears intentional and aligns with the new layout design.

health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/pages/employee/attendance_inbox.js (1)

43-50: LGTM: Minor styling adjustments.

The fontSize reduction to 28px and the wrapper height adjustment to 160px appear to be intentional layout refinements. The explicit JSX braces around the wrapper are redundant but harmless.

health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/attendance_inbox/attendance_inbox.js (2)

200-200: LGTM: Consistent height styling.

Adding explicit height: "60vh" to the filter and table sections improves layout consistency and prevents content overflow.

Also applies to: 210-210


214-214: LGTM: JSX braces are redundant but harmless.

Wrapping <SearchResultsPlaceholder /> in explicit braces ({<SearchResultsPlaceholder />}) is unnecessary since JSX elements don't require wrapping, but it doesn't affect functionality.

Optionally, simplify to:

-                  {<SearchResultsPlaceholder placeholderText={"HCM_AM_FILTER_AND_CHOOSE_BOUNDARY_PLACEHOLDER_TEXT"} />}
+                  <SearchResultsPlaceholder placeholderText={"HCM_AM_FILTER_AND_CHOOSE_BOUNDARY_PLACEHOLDER_TEXT"} />

Comment on lines +194 to +197
<div className="custom-register-inbox-screen" style={{
// "minHeight":"20%",
// "maxHeight":"30%"
}}>
Copy link
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Remove commented-out code.

Lines 195-196 contain commented-out minHeight and maxHeight styles. Remove commented code to keep the codebase clean.

      <div className="custom-register-inbox-screen" style={{
-        // "minHeight":"20%",
-        // "maxHeight":"30%"
      }}>

If these styles are needed, uncomment and apply them; otherwise, remove them entirely.

🤖 Prompt for AI Agents
In
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/attendance_inbox/attendance_inbox.js
around lines 194 to 197, remove the commented-out inline style lines for
"minHeight" and "maxHeight" (lines 195-196) so the JSX contains only the active
style object; if those height constraints are actually required, instead of
leaving them commented, uncomment them and set appropriate numeric/string values
in the style object.

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

♻️ Duplicate comments (2)
health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/pages/employee/HierarchySelection.js (2)

96-101: Redundant session write persists.

The session storage write on line 98 is redundant since onHierarchySelect (line 69) already persists HIERARCHY_TYPE_SELECTED. Remove the duplicate write from this else block.

Apply this diff:

     else {
-
-      Digit.SessionStorage.set("HIERARCHY_TYPE_SELECTED", selectedHierarchy);
-
       onHierarchyChosen(selectedHierarchy);
     }

121-134: Unnecessary braces around Loader.

The centered loader improves UX consistency, but line 132 has unnecessary braces around the component.

Remove the braces:

-      {<Loader />}
+      <Loader />
📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 65aceea and dcbdcaf.

📒 Files selected for processing (1)
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/pages/employee/HierarchySelection.js (4 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.js

⚙️ CodeRabbit configuration file

check

Files:

  • health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/pages/employee/HierarchySelection.js
🧬 Code graph analysis (1)
health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/pages/employee/HierarchySelection.js (4)
health/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/components/HierarchySelection.js (3)
  • HierarchySelection (15-167)
  • selectedHierarchy (24-26)
  • isStoreLoading (45-51)
health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/hooks/boundaries/useFetchAllHierarchies.js (1)
  • Digit (21-30)
health/micro-ui/web/micro-ui-internals/packages/modules/pgr/src/hooks/boundary/useFetchAllHierarchies.js (1)
  • Digit (21-30)
health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/components/pageComponents/Jurisdictions.js (1)
  • selectedHierarchy (8-8)

<p className="description-type">{t(`HCM_HIERARCHY_TYPE_DESCRIPTION`)}</p>
<LabelFieldPair>
<div className="campaign-type">
<div className="">
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

Verify layout impact of removed className.

The className was changed from "campaign-type" to an empty string. If CSS rules target .campaign-type, this change may affect the label/field layout or spacing.

Run this script to check for CSS dependencies:


🏁 Script executed:

#!/bin/bash
# Description: Check if campaign-type class is defined in CSS/styling files

# Search for campaign-type class definitions in CSS/SCSS/styled files
rg -n --type-add 'style:*.{css,scss,styled.js,styles.js}' --type style 'campaign-type' -C 2

# Also check if it's used elsewhere in the codebase
rg -n 'className.*campaign-type' -C 1

Length of output: 25365


Re-add className="campaign-type" to the wrapper <div> – this class applies crucial margin styles defined in packages/css/src/pages/employee/campaign.scss (line 24) for correct layout spacing.

🤖 Prompt for AI Agents
In
health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/pages/employee/HierarchySelection.js
around line 144, the wrapper <div> lost its className="campaign-type" which
provides essential margin styles from
packages/css/src/pages/employee/campaign.scss (line 24); restore
className="campaign-type" on that <div> so the component regains the intended
layout spacing.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/pages/employee/my_bills.js (1)

63-67: Fix offset calculation to use new rows per page value.

The offset calculation on line 66 uses the stale rowsPerPage variable instead of the new currentRowsPerPage parameter. This will produce an incorrect offset when the user changes the rows per page setting.

Apply this diff to fix the calculation:

 const handlePerRowsChange = (currentRowsPerPage, currentPage) => {
     setRowsPerPage(currentRowsPerPage);
     setCurrentPage(1);
-    setLimitAndOffset({ limit: currentRowsPerPage, offset: (currentPage - 1) * rowsPerPage });
+    setLimitAndOffset({ limit: currentRowsPerPage, offset: 0 });
 }

Note: Since you're resetting to page 1 (line 65), the offset should be 0, not calculated from currentPage.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between dcbdcaf and 67edb4d.

📒 Files selected for processing (1)
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/pages/employee/my_bills.js (2 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.js

⚙️ CodeRabbit configuration file

check

Files:

  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/pages/employee/my_bills.js
🧬 Code graph analysis (1)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/pages/employee/my_bills.js (3)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/MyBillsSearch.js (1)
  • MyBillsSearch (13-88)
health/micro-ui/web/micro-ui-internals/packages/modules/health-dss/src/hooks/useInboxSearch.js (1)
  • isFetching (74-74)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/MyBillsTable.js (1)
  • MyBillsTable (21-227)
⏰ Context from checks skipped due to timeout of 10000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Build application arm64
  • GitHub Check: Build application amd64

import React, { useMemo, useState, useEffect } from "react";
import { useTranslation } from "react-i18next";
import { Header, InboxSearchComposer, Loader } from "@egovernments/digit-ui-react-components";
import { Header, InboxSearchComposer } from "@egovernments/digit-ui-react-components";
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Remove unused import.

InboxSearchComposer is imported but not used anywhere in this file.

Apply this diff to remove the unused import:

-import { Header, InboxSearchComposer } from "@egovernments/digit-ui-react-components";
+import { Header } from "@egovernments/digit-ui-react-components";
📝 Committable suggestion

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

Suggested change
import { Header, InboxSearchComposer } from "@egovernments/digit-ui-react-components";
import { Header } from "@egovernments/digit-ui-react-components";
🤖 Prompt for AI Agents
In
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/pages/employee/my_bills.js
around line 3, the imported symbol InboxSearchComposer is unused; remove it from
the import statement (leave Header) so the line only imports the used components
and save the file to clear the unused-import lint error.

Comment on lines +92 to +99
return <div style={{
display: "flex",
justifyContent: "center",
alignItems: "center",
height: "100vh" // full screen height
}}>
<Loader />
</div>
Copy link
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Consider extracting the full-page loader pattern.

The full-page centered loader implementation is correct, but according to the PR context, this pattern is duplicated across multiple HRMS-related components (HierarchySelection.js, Inbox.js, etc.).

Consider creating a reusable FullPageLoader component to reduce duplication:

// In a shared components file
const FullPageLoader = () => (
  <div style={{
    display: "flex",
    justifyContent: "center",
    alignItems: "center",
    height: "100vh"
  }}>
    <Loader />
  </div>
);

Then use it here:

 if (isBillLoading) {
-    return <div style={{
-        display: "flex",
-        justifyContent: "center",
-        alignItems: "center",
-        height: "100vh"   // full screen height
-    }}>
-        <Loader />
-    </div>
+    return <FullPageLoader />
 }

Note: Using 100vh can cause issues on mobile browsers where the viewport height changes as address bars show/hide. Consider using 100dvh (dynamic viewport height) for better mobile support if targeting modern browsers.

🤖 Prompt for AI Agents
In
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/pages/employee/my_bills.js
around lines 92-99, the full-page centered loader markup is duplicated across
multiple HRMS components; extract this into a reusable FullPageLoader component
in a shared components folder (e.g.,
packages/shared/components/FullPageLoader.js or similar), implement it to render
a centered Loader and prefer using height: "100dvh" for better mobile viewport
behavior, export it, and replace the inline div/Loader here with the imported
FullPageLoader component to remove duplication.

Comment on lines +104 to +106
{<Header styles={{ fontSize: "32px" }}>
{t("HCM_AM_MY_BILLS")}
</Header>
</Header>}
Copy link
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Remove unnecessary braces around JSX elements.

The Header (lines 104-106) and Card (lines 111-114) elements are wrapped in unnecessary braces. Since these are direct JSX elements without any conditional logic or expression evaluation, the braces add no value and reduce readability.

Apply this diff to simplify the JSX:

-    {<Header styles={{ fontSize: "32px" }}>
+    <Header styles={{ fontSize: "32px" }}>
         {t("HCM_AM_MY_BILLS")}
-    </Header>}
+    </Header>


     <MyBillsSearch onSubmit={onSubmit} onClear={onClear} />

-    {<Card>
+    <Card>
         {isFetching ? <Loader /> : tableData.length === 0 ? <NoResultsFound text={t(`HCM_AM_NO_DATA_FOUND_FOR_BILLS`)} /> : <MyBillsTable data={tableData} totalCount={totalCount} rowsPerPage={rowsPerPage} currentPage={currentPage} handlePageChange={handlePageChange}
             handlePerRowsChange={handlePerRowsChange} />}
-    </Card>}
+    </Card>

Also applies to: 111-114

🤖 Prompt for AI Agents
In
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/pages/employee/my_bills.js
around lines 104-106 and 111-114, there are unnecessary surrounding braces
wrapping JSX elements (Header and Card). Remove the extra { ... } tokens so the
JSX elements are rendered directly (e.g., replace `{<Header ...>...</Header>}`
with `<Header ...>...</Header>` and similarly for Card), preserving props,
children, and indentation; run a quick lint/format to ensure valid JSX after
removal.

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

♻️ Duplicate comments (5)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/editAttendeesPopUp.js (3)

212-268: Fix PopUp children API & missing keys (still failing lint).

Biome’s noChildrenProp / useJsxKeyInIterable errors persist because the popup still passes children/footerChildren arrays without keys—the build will continue to fail. Move the JSX inside <PopUp> as proper children and render the footer via a footer slot (or add stable keys if you must keep arrays).

-        <PopUp
-            style={{ minWidth: popupWidth, height: "650px" }}
-            onClose={onClose}
-            heading={t(heading)}
-            onOverlayClick={onClose}
-            children={[
-                isAttendanceLoading || isAllIndividualsLoading ? (
-                    <div style={{
-                        display: "flex",
-                        justifyContent: "center",
-                        alignItems: "center",
-                        height: "100vh"   // full screen height
-                    }}>
-                        <Loader />
-                    </div>
-                ) : (
-                    <div style={{
-                        display: "flex",
-                        flexDirection: "column",
-                        gap: "16px", // same as Tailwind gap-4
-                    }} >
-                        <TextInput type="search" name="title" placeholder={t("HCM_AM_VIEW_REGISTER_PLACE_HOLDER")} value={searchQuery} onChange={(e) => setSearchQuery(e.target.value)} />
-                        <EditAttendanceManagementTable
-                            height="320px"
-                            data={searchQuery != "" ? filteredData : attendanceSummary}
-                            setAttendanceSummary={setAttendanceSummary}
-                            disableUser={disableUser}
-                            registerId={businessId}
-                            registerNumber={registerId}
-                            editAction={true}
-                        />
-                        <div style={{ display: "grid", gridTemplateColumns: `${labelWidth} auto`, rowGap: "5px", alignItems: "center" }}>
-
-
-                            <div>{t(labels[1])}</div>
-                            <Button label={t("HCM_AM_SEARCH_USER")} variation="link" onClick={() => {
-
-
-
-                                history.push(`/${window?.contextPath}/employee/payments/attendee-inbox?registerId=${registerId}&boundaryCode=${boundaryCode}`)
-                            }} />
-                        </div>
-
-                    </div>
-                )
-            ]}
-            footerChildren={[
-                <Button
-                    type={"button"}
-                    size={"large"}
-                    variation={"primary"}
-                    label={t("HCM_AM_SAVE_AND_CLOSE")}
-                    onClick={onClose}
-                />,
-            ]}
-            sortFooterChildren={true}
-        />
+        <PopUp
+            style={{ minWidth: popupWidth, height: "650px" }}
+            onClose={onClose}
+            heading={t(heading)}
+            onOverlayClick={onClose}
+        >
+            {isAttendanceLoading || isAllIndividualsLoading ? (
+                <div
+                    style={{
+                        display: "flex",
+                        justifyContent: "center",
+                        alignItems: "center",
+                        height: "100vh",
+                    }}
+                >
+                    <Loader />
+                </div>
+            ) : (
+                <div
+                    style={{
+                        display: "flex",
+                        flexDirection: "column",
+                        gap: "16px",
+                    }}
+                >
+                    <TextInput
+                        type="search"
+                        name="title"
+                        placeholder={t("HCM_AM_VIEW_REGISTER_PLACE_HOLDER")}
+                        value={searchQuery}
+                        onChange={(e) => setSearchQuery(e.target.value)}
+                    />
+                    <EditAttendanceManagementTable
+                        height="320px"
+                        data={searchQuery !== "" ? filteredData : attendanceSummary}
+                        setAttendanceSummary={setAttendanceSummary}
+                        disableUser={disableUser}
+                        registerId={businessId}
+                        registerNumber={registerId}
+                        editAction={true}
+                    />
+                    <div
+                        style={{
+                            display: "grid",
+                            gridTemplateColumns: `${labelWidth} auto`,
+                            rowGap: "5px",
+                            alignItems: "center",
+                        }}
+                    >
+                        <div>{t(labels[1])}</div>
+                        <Button
+                            label={t("HCM_AM_SEARCH_USER")}
+                            variation="link"
+                            onClick={() =>
+                                history.push(
+                                    `/${window?.contextPath}/employee/payments/attendee-inbox?registerId=${registerId}&boundaryCode=${boundaryCode}`
+                                )
+                            }
+                        />
+                    </div>
+                </div>
+            )}
+            <div slot="footer">
+                <Button
+                    type="button"
+                    size="large"
+                    variation="primary"
+                    label={t("HCM_AM_SAVE_AND_CLOSE")}
+                    onClick={onClose}
+                />
+            </div>
+        </PopUp>

94-101: Guard against missing attendees before mapping.

AttendanceData.attendanceRegister[0].attendees is assumed to exist; when the API omits or nulls attendees, this effect throws and bricks the popup. Please default to an empty array (and filter falsy IDs) before mapping.

-    useEffect(() => {
-        if (AttendanceData?.attendanceRegister?.length > 0) {
-            const ids = AttendanceData.attendanceRegister[0].attendees.map(
-                (a) => a.individualId
-            );
-            setIndividualIds(ids);
-        }
-    }, [AttendanceData]);
+    useEffect(() => {
+        const attendees = AttendanceData?.attendanceRegister?.[0]?.attendees ?? [];
+        setIndividualIds(
+            Array.isArray(attendees)
+                ? attendees.map((a) => a?.individualId).filter(Boolean)
+                : []
+        );
+    }, [AttendanceData]);

127-164: Harden getUserAttendanceSummary before accessing register data.

This helper still indexes attendanceData.attendanceRegister[0].attendees unconditionally. If the register array or its attendees payload is missing/empty, the popup crashes. Guard the access and short-circuit to [].

-    function getUserAttendanceSummary(attendanceData, individualsData, t) {
-        const attendanceLogData =
-            attendanceData.attendanceRegister[0].attendees.map((individualEntry) => {
+    function getUserAttendanceSummary(attendanceData, individualsData, t) {
+        const attendees = attendanceData?.attendanceRegister?.[0]?.attendees;
+        if (!Array.isArray(attendees) || attendees.length === 0) return [];
+
+        const attendanceLogData = attendees.map((individualEntry) => {
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/pages/employee/EditRegister.js (2)

34-51: Fix destructuring fallback for location.state.

const { fromCampaignSupervisor } = location.state || false; will throw whenever the page is opened without navigation state (it tries to destructure from false). Default to an object before destructuring.

-    const { fromCampaignSupervisor } = location.state || false;
+    const { fromCampaignSupervisor = false } = location?.state || {};

145-167: getUserAttendanceSummary must handle missing attendees safely.

The helper still dereferences attendanceData.attendanceRegister[0].attendees without checks. If the register is empty, the whole page crashes. Guard the register lookup and bail out with [] when attendees are absent.

     function getUserAttendanceSummary(attendanceData, individualsData, t) {
-
-        const attendanceLogData = attendanceData.attendanceRegister[0].attendees.map((individualEntry) => {
+        const attendees = attendanceData?.attendanceRegister?.[0]?.attendees;
+        if (!Array.isArray(attendees) || attendees.length === 0) return [];
+
+        const attendanceLogData = attendees.map((individualEntry) => {
📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 67edb4d and 435f47f.

📒 Files selected for processing (3)
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/EditAttendanceManagementTable.js (1 hunks)
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/editAttendeesPopUp.js (1 hunks)
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/pages/employee/EditRegister.js (1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.js

⚙️ CodeRabbit configuration file

check

Files:

  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/editAttendeesPopUp.js
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/EditAttendanceManagementTable.js
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/pages/employee/EditRegister.js
🧠 Learnings (2)
📚 Learning: 2024-11-07T07:17:27.636Z
Learnt from: jagankumar-egov
PR: egovernments/DIGIT-Frontend#1763
File: health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/MyCampaign.js:65-75
Timestamp: 2024-11-07T07:17:27.636Z
Learning: In `MyCampaign.js`, when suggesting code improvements for the `onClickRow` function, keep suggestions simple and avoid unnecessary complexity.

Applied to files:

  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/EditAttendanceManagementTable.js
📚 Learning: 2024-11-07T11:02:33.520Z
Learnt from: rachana-egov
PR: egovernments/DIGIT-Frontend#1770
File: health/micro-ui/web/micro-ui-internals/packages/modules/microplan/src/pages/employee/viewVillage.js:320-322
Timestamp: 2024-11-07T11:02:33.520Z
Learning: In `health/micro-ui/web/micro-ui-internals/packages/modules/microplan/src/pages/employee/viewVillage.js`, the `data?.additionalFields` object is guaranteed to be defined, so checking for its existence before accessing its keys is unnecessary.

Applied to files:

  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/pages/employee/EditRegister.js
🧬 Code graph analysis (3)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/editAttendeesPopUp.js (3)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/EditAttendanceManagementTable.js (4)
  • history (34-34)
  • useTranslation (33-33)
  • tenantId (40-40)
  • EditAttendanceManagementTable (31-274)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/SearchUserPopUp.js (10)
  • history (16-16)
  • attendanceContextPath (18-20)
  • individualContextPath (21-23)
  • useTranslation (25-25)
  • tenantId (14-14)
  • labels (28-28)
  • maxLabelLength (29-29)
  • labelWidth (30-30)
  • searchQuery (32-32)
  • SearchUserPopUp (12-176)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/utils/update_attendance_summary.js (7)
  • attendanceContextPath (4-6)
  • individualContextPath (7-9)
  • attendanceSummary (12-12)
  • individualIds (11-11)
  • isAttendanceLoading (27-28)
  • allIndividualReqCriteria (41-58)
  • isAllIndividualsLoading (60-61)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/EditAttendanceManagementTable.js (3)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/utils/constants.js (4)
  • defaultRowsPerPageForEditAttendee (19-19)
  • defaultRowsPerPageForEditAttendee (19-19)
  • defaultPaginationValuesForEditAttendee (22-22)
  • defaultPaginationValuesForEditAttendee (22-22)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/table_inbox_custom_style.js (2)
  • editAttendeetableCustomStyle (227-334)
  • editAttendeetableCustomStyle (227-334)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/alertPopUp.js (1)
  • AlertPopUp (19-57)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/pages/employee/EditRegister.js (3)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/pages/employee/ViewAttendance.js (28)
  • useTranslation (23-23)
  • attendanceContextPath (27-27)
  • individualContextPath (29-29)
  • Digit (32-32)
  • attendanceDuration (35-35)
  • attendanceSummary (36-36)
  • initialAttendanceSummary (37-37)
  • isSubmitEnabled (38-38)
  • disabledAction (40-40)
  • individualIds (48-48)
  • triggerEstimate (49-49)
  • comment (50-50)
  • showToast (51-51)
  • loading (52-52)
  • showLogs (53-53)
  • showCommentLogPopup (54-54)
  • showDeEnrollPopup (57-57)
  • project (59-59)
  • AttendancereqCri (62-74)
  • isAttendanceLoading (76-76)
  • allIndividualReqCriteria (312-331)
  • isAllIndividualsLoading (333-333)
  • individualReqCriteria (335-357)
  • isIndividualsLoading (359-359)
  • closeActionBarPopUp (428-430)
  • handleDeEnrollClick (441-443)
  • onDeEnrollClose (445-447)
  • renderLabelPair (450-455)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/EditAttendanceManagementTable.js (4)
  • useTranslation (33-33)
  • tenantId (40-40)
  • showToast (36-36)
  • EditAttendanceManagementTable (31-274)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/editAttendeesPopUp.js (12)
  • useTranslation (24-24)
  • attendanceContextPath (17-19)
  • individualContextPath (20-22)
  • tenantId (25-25)
  • attendanceSummary (32-32)
  • individualIds (33-33)
  • AttendancereqCri (77-88)
  • isAttendanceLoading (90-91)
  • allIndividualReqCriteria (104-121)
  • isAllIndividualsLoading (123-124)
  • closeActionBarPopUp (206-208)
  • EditAttendeePopUp (14-282)
🪛 Biome (2.1.2)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/editAttendeesPopUp.js

[error] 218-218: Avoid passing children using a prop

The canonical way to pass children in React is to use JSX elements

(lint/correctness/noChildrenProp)


[error] 220-226: Missing key property for this element in iterable.

The order of the items may change, and having a key can help React identify which item was moved.
Check the React documentation.

(lint/correctness/useJsxKeyInIterable)


[error] 229-234: Missing key property for this element in iterable.

The order of the items may change, and having a key can help React identify which item was moved.
Check the React documentation.

(lint/correctness/useJsxKeyInIterable)


[error] 260-267: Missing key property for this element in iterable.

The order of the items may change, and having a key can help React identify which item was moved.
Check the React documentation.

(lint/correctness/useJsxKeyInIterable)

health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/pages/employee/EditRegister.js

[error] 327-328: Provide screen reader accessible content when using heading elements.

All headings on a page should have content that is accessible to screen readers.

(lint/a11y/useHeadingContent)

Comment on lines +80 to +137
if (AttendanceData) {
setAttendanceDuration(
Math.ceil((AttendanceData?.attendanceRegister[0]?.endDate - AttendanceData?.attendanceRegister[0]?.startDate) / (24 * 60 * 60 * 1000))
);

}
}, [AttendanceData])

useEffect(() => {
if (AttendanceData?.attendanceRegister?.length > 0) {
const ids = AttendanceData.attendanceRegister[0].attendees.map(
(a) => a.individualId
);
setIndividualIds(ids);
}
}, [AttendanceData]);


const allIndividualReqCriteria = {
url: `/${individualContextPath}/v1/_search`,
params: {
tenantId: tenantId,
limit: individualIds.length,
offset: 0,
},
body: {
Individual: {
id: individualIds,
},
},
config: {
enabled: individualIds.length > 0, // ✅ only fire when we have IDs
select: (datap) => datap,
},
changeQueryName: "allIndividuals",
};

const { isLoading: isAllIndividualsLoading, data: AllIndividualsData } = Digit.Hooks.useCustomAPIHook(allIndividualReqCriteria);

const individualReqCriteria = {
url: `/${individualContextPath}/v1/_search`,
params: {
tenantId: tenantId,
limit: 100,
offset: 0,
},
body: {
Individual: {
id: [AttendanceData?.attendanceRegister[0]?.staff?.find(
(staff) => staff?.staffType?.includes("OWNER")
)?.userId]
}
},
config: {
enabled: AttendanceData?.attendanceRegister.length === 1 && AttendanceData?.attendanceRegister[0]?.staff?.find(
(staff) => staff?.staffType?.includes("OWNER")
)?.userId ? true : false,
select: (data) => {
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Optional-chain attendanceRegister and guard attendees everywhere.

Several spots still assume attendanceRegister[0] and its attendees exist. When the API returns an empty register (or the property is missing), the page crashes:

  • Line 82: AttendanceData?.attendanceRegister[0]?.endDate should be AttendanceData?.attendanceRegister?.[0]?.endDate.
  • Lines 89‑94: AttendanceData.attendanceRegister[0].attendees.map(...) will throw if attendees is absent.
  • Lines 127‑136: both the request body and enabled flag index attendanceRegister[0] and .length without guarding attendanceRegister.

Please optional-chain attendanceRegister (?.[0]) in all these expressions and default attendees to [] before mapping.

-            setAttendanceDuration(
-                Math.ceil((AttendanceData?.attendanceRegister[0]?.endDate - AttendanceData?.attendanceRegister[0]?.startDate) / (24 * 60 * 60 * 1000))
-            );
+            const register = AttendanceData?.attendanceRegister?.[0];
+            if (register?.endDate && register?.startDate) {
+                setAttendanceDuration(
+                    Math.ceil((register.endDate - register.startDate) / (24 * 60 * 60 * 1000))
+                );
+            } else {
+                setAttendanceDuration(null);
+            }
@@
-        if (AttendanceData?.attendanceRegister?.length > 0) {
-            const ids = AttendanceData.attendanceRegister[0].attendees.map(
-                (a) => a.individualId
-            );
-            setIndividualIds(ids);
-        }
+        const attendees = AttendanceData?.attendanceRegister?.[0]?.attendees ?? [];
+        setIndividualIds(
+            Array.isArray(attendees)
+                ? attendees.map((a) => a?.individualId).filter(Boolean)
+                : []
+        );
@@
-            Individual: {
-                id: [AttendanceData?.attendanceRegister[0]?.staff?.find(
-                    (staff) => staff?.staffType?.includes("OWNER")
-                )?.userId]
-            }
+            Individual: {
+                id: [
+                    AttendanceData?.attendanceRegister?.[0]?.staff?.find((staff) =>
+                        staff?.staffType?.includes("OWNER")
+                    )?.userId,
+                ].filter(Boolean),
+            }
@@
-            enabled: AttendanceData?.attendanceRegister.length === 1 && AttendanceData?.attendanceRegister[0]?.staff?.find(
-                (staff) => staff?.staffType?.includes("OWNER")
-            )?.userId ? true : false,
+            enabled: Boolean(
+                AttendanceData?.attendanceRegister?.[0]?.staff?.find((staff) =>
+                    staff?.staffType?.includes("OWNER")
+                )?.userId
+            ),
📝 Committable suggestion

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

Suggested change
if (AttendanceData) {
setAttendanceDuration(
Math.ceil((AttendanceData?.attendanceRegister[0]?.endDate - AttendanceData?.attendanceRegister[0]?.startDate) / (24 * 60 * 60 * 1000))
);
}
}, [AttendanceData])
useEffect(() => {
if (AttendanceData?.attendanceRegister?.length > 0) {
const ids = AttendanceData.attendanceRegister[0].attendees.map(
(a) => a.individualId
);
setIndividualIds(ids);
}
}, [AttendanceData]);
const allIndividualReqCriteria = {
url: `/${individualContextPath}/v1/_search`,
params: {
tenantId: tenantId,
limit: individualIds.length,
offset: 0,
},
body: {
Individual: {
id: individualIds,
},
},
config: {
enabled: individualIds.length > 0, // ✅ only fire when we have IDs
select: (datap) => datap,
},
changeQueryName: "allIndividuals",
};
const { isLoading: isAllIndividualsLoading, data: AllIndividualsData } = Digit.Hooks.useCustomAPIHook(allIndividualReqCriteria);
const individualReqCriteria = {
url: `/${individualContextPath}/v1/_search`,
params: {
tenantId: tenantId,
limit: 100,
offset: 0,
},
body: {
Individual: {
id: [AttendanceData?.attendanceRegister[0]?.staff?.find(
(staff) => staff?.staffType?.includes("OWNER")
)?.userId]
}
},
config: {
enabled: AttendanceData?.attendanceRegister.length === 1 && AttendanceData?.attendanceRegister[0]?.staff?.find(
(staff) => staff?.staffType?.includes("OWNER")
)?.userId ? true : false,
select: (data) => {
useEffect(() => {
if (AttendanceData) {
const register = AttendanceData?.attendanceRegister?.[0];
if (register?.endDate && register?.startDate) {
setAttendanceDuration(
Math.ceil((register.endDate - register.startDate) / (24 * 60 * 60 * 1000))
);
} else {
setAttendanceDuration(null);
}
}
}, [AttendanceData]);
useEffect(() => {
const attendees = AttendanceData?.attendanceRegister?.[0]?.attendees ?? [];
setIndividualIds(
Array.isArray(attendees)
? attendees.map((a) => a?.individualId).filter(Boolean)
: []
);
}, [AttendanceData]);
// … (allIndividualReqCriteria and its hook stay unchanged)
const individualReqCriteria = {
url: `/${individualContextPath}/v1/_search`,
params: {
tenantId: tenantId,
limit: 100,
offset: 0,
},
body: {
Individual: {
id: [
AttendanceData?.attendanceRegister?.[0]?.staff?.find((staff) =>
staff?.staffType?.includes("OWNER")
)?.userId,
].filter(Boolean),
},
},
config: {
enabled: Boolean(
AttendanceData?.attendanceRegister?.[0]?.staff?.find((staff) =>
staff?.staffType?.includes("OWNER")
)?.userId
),
select: (data) => {
// …
},
},
};
🤖 Prompt for AI Agents
In
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/pages/employee/EditRegister.js
around lines 80 to 137, several expressions assume attendanceRegister[0] and its
attendees exist; change all occurrences to use optional chaining on the array
element (attendanceRegister?.[0]) and guard attendees by defaulting to an empty
array before mapping (e.g., (AttendanceData?.attendanceRegister?.[0]?.attendees
|| []) ). Also update checks that inspect length or access staff/userId to first
ensure attendanceRegister exists (e.g.,
AttendanceData?.attendanceRegister?.length and
AttendanceData?.attendanceRegister?.[0]?.staff) so the request body and enabled
flag only index [0] when attendanceRegister is present.

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

♻️ Duplicate comments (11)
health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/components/pageComponents/SearchUserToReport.js (11)

3-5: Remove unused imports.

Timeline, useEffect, and useHistory are imported but never used in this component.

Apply this diff:

-import { PopUp, Timeline, Loader, TextInput, Button, NoResultsFound } from '@egovernments/digit-ui-components';
-import { useEffect } from "react";
-import { useHistory } from "react-router-dom";
+import { PopUp, Loader, TextInput, Button, NoResultsFound } from '@egovernments/digit-ui-components';

Also remove the unused history declaration on line 18.


6-6: Critical: Fix incorrect import causing runtime undefined.

AttendanceService is exported as a named export from SearchUser.js, not as default. Importing it as default will result in undefined at runtime, causing all search operations to fail.

Apply this diff:

-import AttendanceService from "../../services/hrms/SearchUser";
+import { AttendanceService } from "../../services/hrms/SearchUser";

17-18: Remove commented-out code.

Dead code should be removed to keep the codebase clean.

Apply this diff:

     const tenantId = Digit.ULBService.getCurrentTenantId();
-    // const { mutate: createMapping } = Digit.Hooks.payments.useCreateAttendeeFromRegister(tenantId);
-    const history = useHistory();

20-32: Remove unused variable declarations.

attendanceContextPath, individualContextPath, labels, maxLabelLength, and labelWidth are declared but never used.

Apply this diff:

-    const attendanceContextPath =
-        window?.globalConfigs?.getConfig("ATTENDANCE_CONTEXT_PATH") ||
-        "health-attendance";
-    const individualContextPath =
-        window?.globalConfigs?.getConfig("INDIVIDUAL_CONTEXT_PATH") ||
-        "health-individual";
-
     const { t } = useTranslation();
-
-
-    const labels = ["HCM_AM_ATTENDANCE_NOT_FIND_USER_LABEL", "HCM_AM_ATTENDANCE_USER_ASSIGN_REGISTER"];
-    const maxLabelLength = Math.max(...labels.map(label => label.length));
-    const labelWidth = `${maxLabelLength * 8}px`;

57-57: Fix typo: locallitylocality.

The typo should be corrected throughout the file and in the service call to maintain consistency. Note that the service signature in SearchUser.js also uses the misspelling, which should be corrected there as well.

-            const locallity = Digit.SessionStorage.get("selectedBoundary")?.code || null;
+            const locality = Digit.SessionStorage.get("selectedBoundary")?.code || null;

Update all references in lines 59, 74 accordingly, and update the service signature.


59-65: Critical: Remove undefined setShowToast call.

setShowToast is not defined in this component, causing a runtime ReferenceError when locality validation fails. This completely breaks the search flow when no locality is selected.

Apply this diff to prevent the crash:

             if (locallity === null) {
-                setShowToast(
-                    { key: "error", label: t(`HCM_AM_LOCALITY_NOT_SELECTED`), transitionTime: 3000 }
-                );
                 setLoading(false);
                 return;
             }

To properly display the error to users, consider wiring a Toast component from @egovernments/digit-ui-components.


67-71: Remove debug console statements.

Console logs with a typo ("nummeric") serve no functional purpose and pollute the console.

Apply this diff:

-            if (/^\d+$/.test(name)) {
-                console.log("it is nummeric");
-            } else {
-                console.log("it is not nummeric");
-            }
-

101-104: Critical: Use id field, not userUuid.

The downstream consumer (likely UserAssignment) expects value.id in the submission payload. Using userUuid will break the assignment flow.

Apply this diff:

         onSubmit({
-            id: selectedUser?.userUuid,
+            id: selectedUser?.id,
             name: selectedUser?.name?.givenName
         })

119-210: Major: Fix PopUp children rendering and missing keys.

Three issues with the PopUp component:

  1. Passing content via children prop violates React conventions and triggers Biome's noChildrenProp lint error
  2. The child element in the children array lacks a key prop
  3. The footer button in footerChildren array also lacks a key prop

Apply this diff to move JSX content to be direct children and add keys:

         <PopUp
             style={{ width: "800px", minHeight: "430px" }}
             onClose={onClose}
             heading={t("HCM_AM_SEARCH_USER")}
             onOverlayClick={onClose}
-            children={[
-                (
-                    <div style={{
+            footerChildren={[
+                <Button
+                    key="assign-user"
+                    isDisabled={!selectedUser}
+                    type={"button"}
+                    size={"large"}
+                    variation={"primary"}
+                    label={t("HCM_AM_ASSIGN_BT")}
+                    onClick={handleEnrollAttendee}
+                />,
+            ]}
+            sortFooterChildren={true}
+        >
+            <div style={{
                         display: "flex",
                         flexDirection: "column",
                         gap: "16px",
                     }} >
                         {/* ...existing content... */}
-                    </div>
-                )
-            ]}
-            footerChildren={[
-                <Button
-                    isDisabled={selectedUser ? false : true}
-                    type={"button"}
-                    size={"large"}
-                    variation={"primary"}
-                    label={t("HCM_AM_ASSIGN_BT")}
-                    onClick={handleEnrollAttendee}
-                />,
-            ]}
-            sortFooterChildren={true}
-        />
+            </div>
+        </PopUp>

142-149: Replace deprecated onKeyPress with onKeyDown.

React has deprecated onKeyPress. Switch to onKeyDown to align with current APIs and avoid future breaking changes. Based on learnings.

Apply this diff:

-                                }} onKeyPress={(e) => {
+                                }} onKeyDown={(e) => {
                                     if (e.key === "Enter") {
                                         e.preventDefault();
                                         searchUser(searchQuery, 0, rowsPerPage);
                                     }
                                 }} />

213-213: Simplify boolean expression.

The ternary selectedUser ? false : true can be simplified to !selectedUser.

Apply this diff:

-                    isDisabled={selectedUser ? false : true}
+                    isDisabled={!selectedUser}
📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 435f47f and 44f8d8a.

📒 Files selected for processing (1)
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/components/pageComponents/SearchUserToReport.js (1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.js

⚙️ CodeRabbit configuration file

check

Files:

  • health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/components/pageComponents/SearchUserToReport.js
🧠 Learnings (1)
📚 Learning: 2024-06-10T19:25:42.992Z
Learnt from: siddhant-nawale-egov
PR: egovernments/DIGIT-Frontend#698
File: micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/resourceMapping.js:74-74
Timestamp: 2024-06-10T19:25:42.992Z
Learning: `onKeyPress` is deprecated and should be replaced with `onKeyDown` or `onKeyUp` for handling keyboard interactions.

Applied to files:

  • health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/components/pageComponents/SearchUserToReport.js
🧬 Code graph analysis (1)
health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/components/pageComponents/SearchUserToReport.js (2)
health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/components/pageComponents/ReportingUserSearchTable.js (2)
  • useTranslation (14-14)
  • ReportingUserSearchTable (5-109)
health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/services/hrms/SearchUser.js (3)
  • result (79-103)
  • AttendanceService (4-111)
  • AttendanceService (4-111)
🪛 Biome (2.1.2)
health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/components/pageComponents/SearchUserToReport.js

[error] 119-119: Avoid passing children using a prop

The canonical way to pass children in React is to use JSX elements

(lint/correctness/noChildrenProp)


[error] 121-126: Missing key property for this element in iterable.

The order of the items may change, and having a key can help React identify which item was moved.
Check the React documentation.

(lint/correctness/useJsxKeyInIterable)


[error] 212-219: Missing key property for this element in iterable.

The order of the items may change, and having a key can help React identify which item was moved.
Check the React documentation.

(lint/correctness/useJsxKeyInIterable)

⏰ Context from checks skipped due to timeout of 10000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Build application amd64
  • GitHub Check: Build application arm64

}


{!loading && searchQuery != "" && searchedIndividual.length === 0 && apiCall ==true && (
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Use strict equality operator.

Use === instead of == for comparison to avoid type coercion issues.

Apply this diff:

-                        {!loading && searchQuery != "" && searchedIndividual.length === 0 && apiCall ==true   && (
+                        {!loading && searchQuery !== "" && searchedIndividual.length === 0 && apiCall === true && (
📝 Committable suggestion

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

Suggested change
{!loading && searchQuery != "" && searchedIndividual.length === 0 && apiCall ==true && (
{!loading && searchQuery !== "" && searchedIndividual.length === 0 && apiCall === true && (
🤖 Prompt for AI Agents
In
health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/components/pageComponents/SearchUserToReport.js
around line 183, the conditional uses a loose equality check `apiCall == true`;
replace it with the strict equality operator (`apiCall === true`) so the
condition avoids type coercion and correctly checks the boolean value.

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/attendance_inbox/attendance_inbox.js (2)

54-54: Use strict equality operators.

Multiple locations use loose equality (==) instead of strict equality (===):

  • Line 54: totalNext == undefined
  • Lines 58-60: filterData?.code == undefined, filterData?.code == null, filterCriteria?.code == undefined, filterCriteria?.code == null
  • Line 63: status == undefined
  • Line 171: status.code == StatusEnum.PENDING_FOR_APPROVAL

Use === and !== for type-safe comparisons and to follow JavaScript best practices.

Example for line 54:

-            offset: totalNext == undefined ? (currentPage - 1) * rowsPerPage : (totalNext - 1) * totalRows,
+            offset: totalNext === undefined ? (currentPage - 1) * rowsPerPage : (totalNext - 1) * totalRows,

Apply similar changes to other locations with loose equality.

Also applies to: 58-60, 63-63, 171-171


58-62: Simplify nested ternary for localityCode.

The nested ternary expression for determining localityCode is difficult to read and maintain.

Consider extracting this logic into a helper function:

+const getLocalityCode = (filterData, filterCriteria) => {
+  if (filterData?.code != null) return filterData.code;
+  if (filterCriteria?.code != null) return filterCriteria.code;
+  return Digit.SessionStorage.get("paymentInbox").code;
+};
+
 const triggerAttendanceSearch = (filterData, status, totalRows, totalNext, selectedProject) => {
   try {
     setChildrenDataLoading(true);
     fetchRegisters.mutateAsync(
       {
         params: {
           tenantId: Digit.ULBService.getStateId(),
           limit: totalRows || rowsPerPage,
           offset: totalNext === undefined ? (currentPage - 1) * rowsPerPage : (totalNext - 1) * totalRows,
           referenceId: selectedProject?.id === undefined ? Digit.SessionStorage.get("paymentInbox").selectedProject?.id : selectedProject?.id,
           staffId: Digit.SessionStorage.get("UserIndividual")?.[0]?.id,
-          localityCode:
-            filterData?.code == undefined || filterData?.code == null
-              ? filterCriteria?.code == undefined || filterCriteria?.code == null
-                ? Digit.SessionStorage.get("paymentInbox").code
-                : filterCriteria?.code
-              : filterData?.code,
+          localityCode: getLocalityCode(filterData, filterCriteria),
           reviewStatus: status === undefined ? selectedStatus : status,
           isChildrenRequired: true,
         },
       },
♻️ Duplicate comments (14)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/attendance_inbox/attendance_inbox.js (1)

195-196: Remove commented-out code.

Lines 195-196 contain commented-out minHeight and maxHeight styles. This was previously flagged. Remove commented code to keep the codebase clean.

Apply this diff to remove the commented lines:

     <div className="custom-register-inbox-screen" style={{
-        // "minHeight":"20%",
-        // "maxHeight":"30%"
     }}>

If these styles are needed, uncomment and apply proper values; otherwise, remove them entirely.

health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/EditAttendanceManagementTable.js (1)

6-6: Remove unused type import.

TableProps is imported but never used. This appears to be a TypeScript type import in a JavaScript file.

Note: This is similar to the already-flagged unused imports. Based on past review comments, AttendeeService (line 10), useHistory (line 2), and variables history and url (lines 34-35) should also be removed.

health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/attendance_inbox/table_inbox.js (1)

253-254: Remove redundant progressPending prop.

The progressPending={isLoading} prop is always false when the DataTable renders, since this code path only executes when isLoading is false (line 235 ternary condition).

Apply this diff:

                 <DataTable
                   columns={columns}
                   className="search-component-table"
                   data={tableData}
-                  progressPending={isLoading}
-                  progressComponent={<Loader />}
                   pagination
                   paginationServer
health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/components/pageComponents/SearchUserToReport.js (11)

184-184: Use strict equality operator.

Replace loose equality (==) with strict equality (===) to avoid type coercion issues.

Apply this diff:

-                        {!loading && searchQuery != "" && searchedIndividual.length === 0 && apiCall ==true   && (
+                        {!loading && searchQuery !== "" && searchedIndividual.length === 0 && apiCall === true && (
                             <div>

214-214: Simplify boolean ternary.

The ternary expression can be simplified for better readability.

Apply this diff:

-                    isDisabled={selectedUser ? false : true}
+                    isDisabled={!selectedUser}

6-6: Critical: Fix incorrect import of AttendanceService (named export, not default).

AttendanceService is exported as a named export in SearchUser.js, but imported as default here. This will be undefined at runtime and crash when searchIndividual is called.

Apply this diff:

-import AttendanceService from "../../services/hrms/SearchUser";
+import { AttendanceService } from "../../services/hrms/SearchUser";

142-150: Use onKeyDown instead of deprecated onKeyPress.

React has deprecated onKeyPress. Switch to onKeyDown to align with current APIs. Based on learnings.

Apply this diff:

-                                }} onKeyPress={(e) => {
+                                }} onKeyDown={(e) => {
                                     if (e.key === "Enter") {
                                         e.preventDefault(); // prevent form submit if inside a form
                                         setApiCall(true);
                                         searchUser(searchQuery, 0, rowsPerPage); // call your API

17-17: Remove commented-out code.

This dead code serves no purpose and should be removed to keep the codebase clean.

Apply this diff:

     const tenantId = Digit.ULBService.getCurrentTenantId();
-    // const { mutate: createMapping } = Digit.Hooks.payments.useCreateAttendeeFromRegister(tenantId);
-    const history = useHistory();

57-57: Typo: locallitylocality (propagate to service signature).

The variable name contains a typo. Rename throughout this function and update the service call parameter to maintain consistency.

Apply this diff:

-            const locallity = Digit.SessionStorage.get("selectedBoundary")?.code || null;
+            const locality = Digit.SessionStorage.get("selectedBoundary")?.code || null;
 
-            if (locallity === null) {
+            if (locality === null) {
                 setLoading(false);
                 return;
             }
 
             const result = await AttendanceService.searchIndividual(
-                { name, locallity, tenantId, offset: currentoffset, limit }
+                { name, locality, tenantId, offset: currentoffset, limit }
             );

57-65: Critical: Remove undefined setShowToast call to avoid runtime crash.

setShowToast is not defined in this component. When locallity is null, the code will throw a ReferenceError and crash the modal.

Apply this diff:

             const locallity = Digit.SessionStorage.get("selectedBoundary")?.code || null;
 
             if (locallity === null) {
-                setShowToast(
-                    { key: "error", label: t(`HCM_AM_LOCALITY_NOT_SELECTED`), transitionTime: 3000 }
-                );
                 setLoading(false);
                 return;
             }

If toast feedback is required, wire a proper Toast state/hook from @egovernments/digit-ui-components.


3-5: Prune unused imports.

Timeline, Loader, useEffect, and useHistory are imported but never used in this component.

Apply this diff:

-import { PopUp, Timeline, Loader, TextInput, Button, NoResultsFound } from '@egovernments/digit-ui-components';
-import { useEffect } from "react";
-import { useHistory } from "react-router-dom";
+import { PopUp, TextInput, Button, NoResultsFound } from '@egovernments/digit-ui-components';

67-71: Drop console noise.

These debug logs (with typo "nummeric") only spam the console and should be removed.

Apply this diff:

-            if (/^\d+$/.test(name)) {
-                console.log("it is nummeric");
-            } else {
-                console.log("it is not nummeric");
-            }
-
             const result = await AttendanceService.searchIndividual(

18-32: Remove unused variables.

The variables history, attendanceContextPath, individualContextPath, labels, and labelWidth are declared but never used.

Apply this diff:

     const tenantId = Digit.ULBService.getCurrentTenantId();
-    const history = useHistory();
-    // context path variables
-    const attendanceContextPath =
-        window?.globalConfigs?.getConfig("ATTENDANCE_CONTEXT_PATH") ||
-        "health-attendance";
-    const individualContextPath =
-        window?.globalConfigs?.getConfig("INDIVIDUAL_CONTEXT_PATH") ||
-        "health-individual";
 
     const { t } = useTranslation();
 
-
-    const labels = ["HCM_AM_ATTENDANCE_NOT_FIND_USER_LABEL", "HCM_AM_ATTENDANCE_USER_ASSIGN_REGISTER"];
-    const maxLabelLength = Math.max(...labels.map(label => label.length));
-    const labelWidth = `${maxLabelLength * 8}px`;
-
     const [searchQuery, setSearchQuery] = useState("");

119-211: Fix PopUp children pattern to satisfy Biome and React correctness.

Passing content through the children prop array triggers Biome's noChildrenProp error and also lacks a key for the array element. Move the JSX inside the PopUp tags as normal children.

Apply this diff:

         <PopUp
             style={{ width: "800px", minHeight: "430px" }}
             onClose={onClose}
             heading={t("HCM_AM_SEARCH_USER")}
             onOverlayClick={onClose}
-            children={[
-                (
-                    <div style={{
+            footerChildren={[
+                <Button
+                    key="assign-user"
+                    isDisabled={!selectedUser}
+                    type={"button"}
+                    size={"large"}
+                    variation={"primary"}
+                    label={t("HCM_AM_ASSIGN_BT")}
+                    onClick={handleEnrollAttendee}
+                />,
+            ]}
+            sortFooterChildren={true}
+        >
+            <div style={{
                         display: "flex",
                         flexDirection: "column",
                         gap: "16px", // same as Tailwind gap-4
-                    }} >
+                    }} >
 
                         <div style={{ display: "flex", flexDirection: "column", gap: "2px" }}>
@@ -205,21 +205,8 @@
 
 
 
-                    </div>
-                )
-            ]}
-            footerChildren={[
-                <Button
-                    isDisabled={selectedUser ? false : true}
-                    type={"button"}
-                    size={"large"}
-                    variation={"primary"}
-                    label={t("HCM_AM_ASSIGN_BT")}
-                    onClick={handleEnrollAttendee}
-                />,
-            ]}
-            sortFooterChildren={true}
-        />
+            </div>
+        </PopUp>
📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f17b433 and 506d9bc.

📒 Files selected for processing (5)
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/components/pageComponents/SearchUserToReport.js (1 hunks)
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/EditAttendanceManagementTable.js (1 hunks)
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/attendance_inbox/attendance_inbox.js (3 hunks)
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/attendance_inbox/table_inbox.js (5 hunks)
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/pages/employee/attendance_inbox.js (1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.js

⚙️ CodeRabbit configuration file

check

Files:

  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/attendance_inbox/attendance_inbox.js
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/pages/employee/attendance_inbox.js
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/components/pageComponents/SearchUserToReport.js
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/attendance_inbox/table_inbox.js
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/EditAttendanceManagementTable.js
🧠 Learnings (2)
📚 Learning: 2024-06-10T19:25:42.992Z
Learnt from: siddhant-nawale-egov
PR: egovernments/DIGIT-Frontend#698
File: micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/resourceMapping.js:74-74
Timestamp: 2024-06-10T19:25:42.992Z
Learning: `onKeyPress` is deprecated and should be replaced with `onKeyDown` or `onKeyUp` for handling keyboard interactions.

Applied to files:

  • health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/components/pageComponents/SearchUserToReport.js
📚 Learning: 2024-11-07T07:17:27.636Z
Learnt from: jagankumar-egov
PR: egovernments/DIGIT-Frontend#1763
File: health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/MyCampaign.js:65-75
Timestamp: 2024-11-07T07:17:27.636Z
Learning: In `MyCampaign.js`, when suggesting code improvements for the `onClickRow` function, keep suggestions simple and avoid unnecessary complexity.

Applied to files:

  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/EditAttendanceManagementTable.js
🧬 Code graph analysis (5)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/attendance_inbox/attendance_inbox.js (1)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/SearchResultsPlaceholder.js (1)
  • SearchResultsPlaceholder (17-31)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/pages/employee/attendance_inbox.js (1)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/attendance_inbox/attendance_inbox.js (1)
  • AttendanceInboxComponent (14-244)
health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/components/pageComponents/SearchUserToReport.js (2)
health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/components/pageComponents/ReportingUserSearchTable.js (2)
  • useTranslation (14-14)
  • ReportingUserSearchTable (5-109)
health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/services/hrms/SearchUser.js (3)
  • result (79-103)
  • AttendanceService (4-111)
  • AttendanceService (4-111)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/attendance_inbox/table_inbox.js (3)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/pages/employee/EditRegister.js (1)
  • Digit (34-34)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/pages/employee/ViewAttendance.js (1)
  • Digit (32-32)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/bill_inbox/billInboxTable.js (1)
  • triggerMusterRollSearch (35-56)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/EditAttendanceManagementTable.js (3)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/utils/constants.js (4)
  • defaultRowsPerPageForEditAttendee (19-19)
  • defaultRowsPerPageForEditAttendee (19-19)
  • defaultPaginationValuesForEditAttendee (22-22)
  • defaultPaginationValuesForEditAttendee (22-22)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/table_inbox_custom_style.js (2)
  • editAttendeetableCustomStyle (227-334)
  • editAttendeetableCustomStyle (227-334)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/alertPopUp.js (1)
  • AlertPopUp (19-57)
🪛 Biome (2.1.2)
health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/components/pageComponents/SearchUserToReport.js

[error] 119-119: Avoid passing children using a prop

The canonical way to pass children in React is to use JSX elements

(lint/correctness/noChildrenProp)


[error] 121-126: Missing key property for this element in iterable.

The order of the items may change, and having a key can help React identify which item was moved.
Check the React documentation.

(lint/correctness/useJsxKeyInIterable)


[error] 213-220: Missing key property for this element in iterable.

The order of the items may change, and having a key can help React identify which item was moved.
Check the React documentation.

(lint/correctness/useJsxKeyInIterable)

⏰ Context from checks skipped due to timeout of 10000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: Build application arm64
  • GitHub Check: Build application amd64
  • GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (6)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/pages/employee/attendance_inbox.js (1)

43-43: LGTM: Header font size adjustment.

The reduction from 32px to 28px improves visual hierarchy consistency.

health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/attendance_inbox/attendance_inbox.js (1)

200-200: Verify height changes work across screen sizes.

The height was reduced from 80vh to 60vh in both the filter section (line 200) and table section (line 210). Ensure this change doesn't cause layout issues on smaller screens or when content overflows.

Consider testing the UI with:

  • Different viewport heights (mobile, tablet, desktop)
  • Maximum filter options expanded
  • Large datasets in the table

Also applies to: 210-210

health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/attendance_inbox/table_inbox.js (3)

235-245: LGTM! Loader container properly centered.

The loader container now uses height: "100%" within the flex layout, which properly centers the loader within the available vertical space. This addresses the past review concern about inadequate height.


114-132: LGTM! Conditional column rendering is well-structured.

The column definition correctly handles the different display requirements for pending vs approved states, with proper fallbacks to "NA" when data is unavailable.


186-272: LGTM! Well-structured layout with proper loading states.

The component properly separates concerns with:

  • Sticky tab section for navigation
  • Scrollable table section with appropriate overflow handling
  • Clear conditional rendering for loading, empty, and data states

The flexbox layout and sticky positioning are implemented correctly for a good user experience.

health/micro-ui/web/micro-ui-internals/packages/modules/health-hrms/src/components/pageComponents/SearchUserToReport.js (1)

101-104: Retain userUuid as id in onSubmit payload
seletctedValue handler expects value.id, and you’re correctly mapping selectedUser.userUuid to id; selectedUser.id doesn’t exist.

Likely an incorrect or invalid review comment.

<Card className="card-overide">
<div className="summary-sub-heading">{t(selectedProject?.name)}</div>
<SearchResultsPlaceholder placeholderText={"HCM_AM_FILTER_AND_CHOOSE_BOUNDARY_PLACEHOLDER_TEXT"} />
{<SearchResultsPlaceholder placeholderText={"HCM_AM_FILTER_AND_CHOOSE_BOUNDARY_PLACEHOLDER_TEXT"} />}
Copy link
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Remove unnecessary JSX expression wrapping.

The SearchResultsPlaceholder component is wrapped in an unnecessary JSX expression ({<SearchResultsPlaceholder ... />}). Direct JSX is cleaner and more idiomatic.

Apply this diff:

-                  {<SearchResultsPlaceholder placeholderText={"HCM_AM_FILTER_AND_CHOOSE_BOUNDARY_PLACEHOLDER_TEXT"} />}
+                  <SearchResultsPlaceholder placeholderText={"HCM_AM_FILTER_AND_CHOOSE_BOUNDARY_PLACEHOLDER_TEXT"} />
📝 Committable suggestion

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

Suggested change
{<SearchResultsPlaceholder placeholderText={"HCM_AM_FILTER_AND_CHOOSE_BOUNDARY_PLACEHOLDER_TEXT"} />}
<SearchResultsPlaceholder placeholderText={"HCM_AM_FILTER_AND_CHOOSE_BOUNDARY_PLACEHOLDER_TEXT"} />
🤖 Prompt for AI Agents
In
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/attendance_inbox/attendance_inbox.js
around line 214, remove the unnecessary JSX expression wrapping the component;
replace the wrapped form {<SearchResultsPlaceholder
placeholderText={"HCM_AM_FILTER_AND_CHOOSE_BOUNDARY_PLACEHOLDER_TEXT"} />} with
the direct JSX <SearchResultsPlaceholder
placeholderText={"HCM_AM_FILTER_AND_CHOOSE_BOUNDARY_PLACEHOLDER_TEXT"} /> so the
component is rendered directly without the extra {} expression.

Comment on lines +81 to 101
onClick={() => {
const existingPaymentInbox = Digit.SessionStorage.get("paymentInbox");
const endDate = existingPaymentInbox?.selectedProject?.endDate;

if (endDate) {
const currentDate = Date.now();
if (!(currentDate <= endDate)) {
history.push(
`/${window?.contextPath}/employee/payments/view-attendance?registerNumber=${row?.id}&boundaryCode=${row?.boundary}`
);
} else {
history.push(
`/${window?.contextPath}/employee/payments/edit-register?registerNumber=${row?.id}&boundaryCode=${row?.boundary}&registerId=${row?.registerId}`
);
}
} else {
console.warn("No endDate found in session storage");
history.push(
`/${window?.contextPath}/employee/payments/view-attendance?registerNumber=${row?.id}&boundaryCode=${row?.boundary}`
)
);
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Fix navigation logic: prevent double navigation, prefer prop over session storage, and handle date units correctly.

The click handler has multiple issues that need to be addressed:

  1. Double navigation risk: The button click does not stop event propagation, so both this handler and the row click handler (line 258) will fire, causing two navigations.
  2. Stale session data: Reading endDate from session storage (line 82-83) instead of the selectedProject prop can use outdated data if the prop has been updated.
  3. Date unit mismatch: Date.now() returns milliseconds, but endDate format is unknown. If endDate is in seconds (common in some APIs), the comparison will fail.
  4. Silent fallback: The console.warn (line 97) provides no user feedback when endDate is missing.

Apply this diff to fix all issues:

           <Button
             label={t(`${row.id}`)}
-            onClick={() => {
-              const existingPaymentInbox = Digit.SessionStorage.get("paymentInbox");
-              const endDate = existingPaymentInbox?.selectedProject?.endDate;
+            onClick={(e) => {
+              e.stopPropagation();
+              
+              const endDate = selectedProject?.endDate ?? Digit.SessionStorage.get("paymentInbox")?.selectedProject?.endDate;

               if (endDate) {
+                // Normalize endDate to milliseconds (some APIs return seconds)
+                const endDateMs = endDate < 1e12 ? endDate * 1000 : endDate;
                 const currentDate = Date.now();
-                if (!(currentDate <= endDate)) {
+                
+                if (currentDate > endDateMs) {
+                  // Project expired: read-only view
                   history.push(
                     `/${window?.contextPath}/employee/payments/view-attendance?registerNumber=${row?.id}&boundaryCode=${row?.boundary}`
                   );
                 } else {
+                  // Project active: allow editing
                   history.push(
                     `/${window?.contextPath}/employee/payments/edit-register?registerNumber=${row?.id}&boundaryCode=${row?.boundary}&registerId=${row?.registerId}`
                   );
                 }
               } else {
-                console.warn("No endDate found in session storage");
+                setShowToast({ 
+                  key: "warning", 
+                  label: t("HCM_AM_END_DATE_MISSING_VIEW_ONLY"), 
+                  transitionTime: 3000 
+                });
                 history.push(
                   `/${window?.contextPath}/employee/payments/view-attendance?registerNumber=${row?.id}&boundaryCode=${row?.boundary}`
                 );
               }
             }}

Note: You'll need to add the translation key HCM_AM_END_DATE_MISSING_VIEW_ONLY with a message like "End date missing - opened in view-only mode".

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In health/micro-ui/.../table_inbox.js around lines 81-101, the click handler
must be updated to (1) stop event propagation and prevent default to avoid
double navigation from the row click, (2) prefer the selectedProject prop over
session storage and only fall back to SessionStorage when the prop is absent,
(3) normalize endDate units before comparing to Date.now() (detect if endDate
looks like seconds and multiply by 1000, otherwise assume milliseconds), (4)
show a user-facing notification using the new translation key
HCM_AM_END_DATE_MISSING_VIEW_ONLY instead of console.warn when endDate is
missing, and (5) ensure navigation happens once and the handler returns
immediately after calling history.push.

Comment on lines +61 to +119
let columns = [
{
name: (
<div style={{ borderRight: "2px solid #787878", width: "100%", textAlign: "start" }}>
{t(`HCM_AM_FRONTLINE_WORKER`)}
</div>
),
selector: (row) => {
return (
<span className="ellipsis-cell">
{String(row?.[1] ? row?.[1] : t("ES_COMMON_NA"))}
</span>
);
},
},

{
name: (
<div style={{ borderRight: "2px solid #787878", width: "100%", textAlign: "start" }}>
{t("HCM_AM_WORKER_ID")}
</div>
),
selector: (row) => {
return (
<div className="ellipsis-cell" title={row?.[2] || t("NA")}>
{row?.[2] || t("NA")}
</div>
);
},
},
{
name: (
<div style={{ borderRight: "2px solid #787878", width: "100%", textAlign: "start" }}>
{t("HCM_AM_ROLE")}
</div>
),
selector: (row) => {
return (
<div className="ellipsis-cell" title={t(row?.[3]) || t("NA")}>
{t(row?.[3]) || t("NA")}
</div>
);
},
},

{
name: (
<div style={{ borderRight: "2px solid #787878", width: "100%", textAlign: "start" }}>
{t("HCM_AM_TAG_LABEL")}
</div>
),
selector: (row) => {
return (
<div className="ellipsis-cell" title={t(row?.[4]) || t("NA")}>
{t(row?.[4]) || t("NA")}
</div>
);
},
},
Copy link
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Consider using named properties instead of array indices.

The column selectors rely on array indices (row?.[1], row?.[2], etc.), which are fragile and make the code harder to understand. If the data structure permits, consider mapping the input data to objects with named properties for better maintainability and type safety.

Example:

 selector: (row) => {
   return (
     <span className="ellipsis-cell">
-      {String(row?.[1] ? row?.[1] : t("ES_COMMON_NA"))}
+      {String(row?.workerName ? row.workerName : t("ES_COMMON_NA"))}
     </span>
   );
 },

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/EditAttendanceManagementTable.js
around lines 61-119, the column selectors use fragile array indices (row?.[1],
row?.[2], etc.); replace this by converting the incoming row arrays into objects
with named fields (e.g., { name, workerId, role, tag }) before building the
columns or by updating the data source to provide objects, then update each
selector to read row.name, row.workerId, row.role, row.tag (and use the same
t(...) and fallbacks) so the code is self-descriptive and resistant to
index-shift bugs.

Comment on lines +162 to +178
<Button
className="custom-class"
icon="Edit"
iconFill=""
label={t(`HCM_AM_VIEW_REGISTER_DISABLE_USER`)}
onClick={() => {
setSelectedRowId(row?.[0]);
setOpenAlertPopUp(true);
// handleDaysWorkedChange(row?.[0])
}}
options={[]}
optionsKey=""
size=""
style={{}}
title={t(`HCM_AM_VIEW_REGISTER_DISABLE_USER`)}
variation="secondary"
/>
Copy link
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Remove commented code and clean up Button props.

Two issues:

  1. Line 170 contains a commented line that should be removed
  2. The Button component has several empty/default props that add noise

Apply this diff:

                  onClick={() => {
                    setSelectedRowId(row?.[0]);
                    setOpenAlertPopUp(true);
-                   // handleDaysWorkedChange(row?.[0])
                  }}
-                 options={[]}
-                 optionsKey=""
-                 size=""
-                 style={{}}
📝 Committable suggestion

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

Suggested change
<Button
className="custom-class"
icon="Edit"
iconFill=""
label={t(`HCM_AM_VIEW_REGISTER_DISABLE_USER`)}
onClick={() => {
setSelectedRowId(row?.[0]);
setOpenAlertPopUp(true);
// handleDaysWorkedChange(row?.[0])
}}
options={[]}
optionsKey=""
size=""
style={{}}
title={t(`HCM_AM_VIEW_REGISTER_DISABLE_USER`)}
variation="secondary"
/>
<Button
className="custom-class"
icon="Edit"
iconFill=""
label={t(`HCM_AM_VIEW_REGISTER_DISABLE_USER`)}
onClick={() => {
setSelectedRowId(row?.[0]);
setOpenAlertPopUp(true);
}}
title={t(`HCM_AM_VIEW_REGISTER_DISABLE_USER`)}
variation="secondary"
/>
🤖 Prompt for AI Agents
In
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/EditAttendanceManagementTable.js
around lines 162 to 178, remove the commented out
handleDaysWorkedChange(row?.[0]) on line 170 and clean up the Button props by
removing empty or default-valued props (iconFill, options, optionsKey, size,
style) and any redundant attributes so the Button keeps only meaningful props
(e.g., className, icon, label, onClick, variation and title if intentionally
used).

Comment on lines +190 to +219
const handleDaysWorkedChange = async (value) => {

const attendee = {
registerId: props.registerNumber,
individualId: value,
enrollmentDate: null,
denrollmentDate: new Date(Date.now() - (1 * 60 * 1000 + 30 * 1000)).getTime(),
tenantId: String(tenantId)
};
await updateMapping({ "attendees": [attendee] },
{
onError: async (error) => {


setShowToast(
{ key: "error", label: t(`HCM_AM_ERROR_MESSAGE`), transitionTime: 3000 }
);


},
onSuccess: async (responseData) => {

setShowToast({ key: "success", label: t(`HCM_AM_ATTENDEE_DE_ENROLL_SUCCESS_MESSAGE`), transitionTime: 3000 });
props.disableUser("");
},
}
)


};
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Handle mutation loading state.

The component doesn't display loading feedback while the de-enrollment mutation is in progress. Users may click the button multiple times or see no indication that their action is being processed.

Consider destructuring the mutation's isLoading state and disabling UI or showing a loader:

-const { mutate: updateMapping } = Digit.Hooks.payments.useDeleteAttendeeFromRegister(tenantId);
+const { mutate: updateMapping, isLoading: isDeletingAttendee } = Digit.Hooks.payments.useDeleteAttendeeFromRegister(tenantId);

Then conditionally render a loader or disable buttons during the operation.

📝 Committable suggestion

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

Suggested change
const handleDaysWorkedChange = async (value) => {
const attendee = {
registerId: props.registerNumber,
individualId: value,
enrollmentDate: null,
denrollmentDate: new Date(Date.now() - (1 * 60 * 1000 + 30 * 1000)).getTime(),
tenantId: String(tenantId)
};
await updateMapping({ "attendees": [attendee] },
{
onError: async (error) => {
setShowToast(
{ key: "error", label: t(`HCM_AM_ERROR_MESSAGE`), transitionTime: 3000 }
);
},
onSuccess: async (responseData) => {
setShowToast({ key: "success", label: t(`HCM_AM_ATTENDEE_DE_ENROLL_SUCCESS_MESSAGE`), transitionTime: 3000 });
props.disableUser("");
},
}
)
};
// Destructure loading state from the mutation hook:
const { mutate: updateMapping, isLoading: isDeletingAttendee } = Digit.Hooks.payments.useDeleteAttendeeFromRegister(tenantId);
// ... later in the component, you can use `isDeletingAttendee` to disable buttons
// or render a spinner while the de-enrollment is in progress.
🤖 Prompt for AI Agents
In
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/EditAttendanceManagementTable.js
around lines 190 to 219, the de-enrollment mutation call doesn't surface a
loading state so users can re-click or get no feedback; destructure the mutation
result to read isLoading (e.g. const [updateMapping, { isLoading }]) and use
that boolean to disable the de-enroll control and/or render a spinner while the
mutation is in progress, keep current onSuccess/onError handlers, and ensure the
button click early-returns when isLoading is true to prevent duplicate requests.

🛠️ Refactor suggestion | 🟠 Major

Rename function to match its actual purpose.

The function name handleDaysWorkedChange is misleading—it actually handles attendee de-enrollment. Consider renaming to handleAttendeeDeEnrollment or handleDisableUser for clarity.

Apply this diff:

-const handleDaysWorkedChange = async (value) => {
+const handleAttendeeDeEnrollment = async (value) => {

And update the call site on line 268:

-          handleDaysWorkedChange(selectedRowId);
+          handleAttendeeDeEnrollment(selectedRowId);
📝 Committable suggestion

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

Suggested change
const handleDaysWorkedChange = async (value) => {
const attendee = {
registerId: props.registerNumber,
individualId: value,
enrollmentDate: null,
denrollmentDate: new Date(Date.now() - (1 * 60 * 1000 + 30 * 1000)).getTime(),
tenantId: String(tenantId)
};
await updateMapping({ "attendees": [attendee] },
{
onError: async (error) => {
setShowToast(
{ key: "error", label: t(`HCM_AM_ERROR_MESSAGE`), transitionTime: 3000 }
);
},
onSuccess: async (responseData) => {
setShowToast({ key: "success", label: t(`HCM_AM_ATTENDEE_DE_ENROLL_SUCCESS_MESSAGE`), transitionTime: 3000 });
props.disableUser("");
},
}
)
};
const handleAttendeeDeEnrollment = async (value) => {
const attendee = {
registerId: props.registerNumber,
individualId: value,
enrollmentDate: null,
denrollmentDate: new Date(Date.now() - (1 * 60 * 1000 + 30 * 1000)).getTime(),
tenantId: String(tenantId)
};
await updateMapping(
{ attendees: [attendee] },
{
onError: async (error) => {
setShowToast(
{ key: "error", label: t(`HCM_AM_ERROR_MESSAGE`), transitionTime: 3000 }
);
},
onSuccess: async (responseData) => {
setShowToast(
{ key: "success", label: t(`HCM_AM_ATTENDEE_DE_ENROLL_SUCCESS_MESSAGE`), transitionTime: 3000 }
);
props.disableUser("");
},
}
);
};
Suggested change
const handleDaysWorkedChange = async (value) => {
const attendee = {
registerId: props.registerNumber,
individualId: value,
enrollmentDate: null,
denrollmentDate: new Date(Date.now() - (1 * 60 * 1000 + 30 * 1000)).getTime(),
tenantId: String(tenantId)
};
await updateMapping({ "attendees": [attendee] },
{
onError: async (error) => {
setShowToast(
{ key: "error", label: t(`HCM_AM_ERROR_MESSAGE`), transitionTime: 3000 }
);
},
onSuccess: async (responseData) => {
setShowToast({ key: "success", label: t(`HCM_AM_ATTENDEE_DE_ENROLL_SUCCESS_MESSAGE`), transitionTime: 3000 });
props.disableUser("");
},
}
)
};
handleAttendeeDeEnrollment(selectedRowId);
🤖 Prompt for AI Agents
In
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/EditAttendanceManagementTable.js
around lines 190 to 219, the function currently named handleDaysWorkedChange
actually performs attendee de-enrollment; rename the function to
handleAttendeeDeEnrollment (or handleDisableUser) and update its declaration and
any export or references accordingly, and also update the call site on line 268
to use the new name; ensure parameter and behavior remain unchanged and run
tests/lint to catch any missed references.

onSuccess: async (responseData) => {

setShowToast({ key: "success", label: t(`HCM_AM_ATTENDEE_DE_ENROLL_SUCCESS_MESSAGE`), transitionTime: 3000 });
props.disableUser("");
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Validate props.disableUser before calling.

Line 213 calls props.disableUser("") without checking if it exists or is a function, which could cause a runtime error.

Add a guard:

-         props.disableUser("");
+         props?.disableUser?.("");

Or validate in PropTypes/at component entry.

📝 Committable suggestion

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

Suggested change
props.disableUser("");
props?.disableUser?.("");
🤖 Prompt for AI Agents
In
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/EditAttendanceManagementTable.js
around line 213, props.disableUser("") is invoked without validation; update the
code to guard the call by checking that props.disableUser is defined and is a
function before calling it (or set a safe default in defaultProps and/or declare
it in PropTypes as a function), and only call props.disableUser("") when that
check passes so you avoid potential runtime errors.

Comment on lines +225 to +244
<DataTable
className="search-component-table"
columns={columns}
data={paginatedData}
progressPending={false}
progressComponent={<Loader />}
pagination
paginationServer
customStyles={editAttendeetableCustomStyle(false)}
paginationDefaultPage={currentPage}
onChangePage={handlePageChange}
onChangeRowsPerPage={handlePerRowsChange}
paginationTotalRows={props?.data.length}
paginationPerPage={defaultRowsPerPageForEditAttendee}
sortIcon={<CustomSVG.SortUp width={"16px"} height={"16px"} fill={"#0b4b66"} />}
paginationRowsPerPageOptions={defaultPaginationValuesForEditAttendee}
fixedHeader={true}
fixedHeaderScrollHeight={props.height ? props.height : "70vh"}
paginationComponentOptions={getCustomPaginationOptions(t)}

Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Fix pagination configuration mismatch.

The DataTable is configured with paginationServer={true} (line 232), but the data is sliced client-side (line 50: props.data.slice(...)). This is a configuration inconsistency.

For client-side pagination, set paginationServer={false} and remove the manual slicing since DataTable will handle it:

-const paginatedData = props.data.slice((currentPage - 1) * rowsPerPage, currentPage * rowsPerPage);
+// Remove manual slicing for client-side pagination

 <DataTable
   className="search-component-table"
   columns={columns}
-  data={paginatedData}
+  data={props.data}
   progressPending={false}
   progressComponent={<Loader />}
   pagination
-  paginationServer
+  paginationServer={false}

Alternatively, if server-side pagination is intended, implement proper server-side data fetching and remove the client-side slice.

📝 Committable suggestion

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

Suggested change
<DataTable
className="search-component-table"
columns={columns}
data={paginatedData}
progressPending={false}
progressComponent={<Loader />}
pagination
paginationServer
customStyles={editAttendeetableCustomStyle(false)}
paginationDefaultPage={currentPage}
onChangePage={handlePageChange}
onChangeRowsPerPage={handlePerRowsChange}
paginationTotalRows={props?.data.length}
paginationPerPage={defaultRowsPerPageForEditAttendee}
sortIcon={<CustomSVG.SortUp width={"16px"} height={"16px"} fill={"#0b4b66"} />}
paginationRowsPerPageOptions={defaultPaginationValuesForEditAttendee}
fixedHeader={true}
fixedHeaderScrollHeight={props.height ? props.height : "70vh"}
paginationComponentOptions={getCustomPaginationOptions(t)}
// Removed manual slicing for client-side pagination
// const paginatedData = props.data.slice((currentPage - 1) * rowsPerPage, currentPage * rowsPerPage);
<DataTable
className="search-component-table"
columns={columns}
data={props.data}
progressPending={false}
progressComponent={<Loader />}
pagination
paginationServer={false}
customStyles={editAttendeetableCustomStyle(false)}
paginationDefaultPage={currentPage}
onChangePage={handlePageChange}
onChangeRowsPerPage={handlePerRowsChange}
paginationTotalRows={props?.data.length}
paginationPerPage={defaultRowsPerPageForEditAttendee}
sortIcon={<CustomSVG.SortUp width={"16px"} height={"16px"} fill={"#0b4b66"} />}
paginationRowsPerPageOptions={defaultPaginationValuesForEditAttendee}
fixedHeader={true}
fixedHeaderScrollHeight={props.height ? props.height : "70vh"}
paginationComponentOptions={getCustomPaginationOptions(t)}
/>
🤖 Prompt for AI Agents
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/EditAttendanceManagementTable.js
lines 225-244: paginationServer is set true while the component slices
props.data client-side, causing a mismatch; either set paginationServer={false}
and remove the manual props.data.slice logic so the DataTable handles pagination
client-side, or keep paginationServer={true} and remove client-side slicing and
instead wire up server-side data fetching/requests (update
onChangePage/onChangeRowsPerPage to fetch the correct page and set paginatedData
from the server). Ensure only one pagination approach remains and keep
paginationTotalRows, paginationPerPage, and paginationComponentOptions
consistent with the chosen approach.

Comment on lines +46 to +50
{<div className="inbox-search-wrapper" style={{
height:"160px"
}}>
<AttendanceInboxComponent></AttendanceInboxComponent>
</div>
</React.Fragment>
</div>}
Copy link
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Remove unnecessary JSX braces and fix formatting.

The div element is wrapped in unnecessary JSX expression braces ({...}), and the inline style has inconsistent spacing.

Apply this diff:

-      {<div className="inbox-search-wrapper" style={{
-        height:"160px"
-      }}>
+      <div className="inbox-search-wrapper" style={{ height: "160px" }}>
         <AttendanceInboxComponent></AttendanceInboxComponent>
-      </div>}
+      </div>
📝 Committable suggestion

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

Suggested change
{<div className="inbox-search-wrapper" style={{
height:"160px"
}}>
<AttendanceInboxComponent></AttendanceInboxComponent>
</div>
</React.Fragment>
</div>}
<div className="inbox-search-wrapper" style={{ height: "160px" }}>
<AttendanceInboxComponent></AttendanceInboxComponent>
</div>
🤖 Prompt for AI Agents
In
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/pages/employee/attendance_inbox.js
around lines 46 to 50, remove the unnecessary JSX expression braces surrounding
the div (drop the outer { ... }) and normalize the inline style spacing (e.g.,
use consistent spacing around keys/values like height: "160px"); also tidy the
JSX formatting for readability (remove extra blank lines and ensure proper
indentation, and optionally convert
<AttendanceInboxComponent></AttendanceInboxComponent> to a concise self-closing
tag if preferred).

Comment on lines +46 to +48
{<div className="inbox-search-wrapper" style={{
height:"160px"
}}>
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

Verify the 160px height constraint.

The wrapper sets a fixed height: "160px", but the AttendanceInboxComponent contains sections with height: "60vh" (approximately 600px on a standard 1080p display). This constraint may cause overflow or clipping.

Run the following script to examine the inner component's height requirements:


🏁 Script executed:

#!/bin/bash
# Check height styles in AttendanceInboxComponent and related components
rg -n --type=js -C3 'height.*vh|height.*px' health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/attendance_inbox/

Length of output: 8255


🏁 Script executed:

#!/bin/bash
sed -n '1,100p' health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/pages/employee/attendance_inbox.js

Length of output: 2166


Remove fixed height: "160px" on .inbox-search-wrapper.

This wrapper encloses the entire AttendanceInboxComponent, whose inner sections use vh heights (60vh–80vh), causing overflow or clipping.
File: health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/pages/employee/attendance_inbox.js Lines: 46–48

🤖 Prompt for AI Agents
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/pages/employee/attendance_inbox.js
lines 46-48: the .inbox-search-wrapper currently has a fixed height: "160px"
which conflicts with inner sections using vh units and causes overflow/clipping;
remove the fixed height (or replace it with responsive CSS such as auto,
min-height, or use padding/margins) so the wrapper can grow/shrink with its
children and avoid clipping, and ensure layout consistency by testing with the
inner 60vh–80vh sections.

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

📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 84c87bd and 08db216.

📒 Files selected for processing (1)
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/bill_inbox/BillInbox.js (2 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.js

⚙️ CodeRabbit configuration file

check

Files:

  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/bill_inbox/BillInbox.js
🧠 Learnings (2)
📚 Learning: 2024-06-10T19:25:42.992Z
Learnt from: siddhant-nawale-egov
PR: egovernments/DIGIT-Frontend#698
File: micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanPreview.js:1-1
Timestamp: 2024-06-10T19:25:42.992Z
Learning: The imports in `MicroplanPreview.js` are from different libraries: `egovernments/digit-ui-components` and `egovernments/digit-ui-react-components`.

Applied to files:

  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/bill_inbox/BillInbox.js
📚 Learning: 2024-06-10T19:25:42.992Z
Learnt from: siddhant-nawale-egov
PR: egovernments/DIGIT-Frontend#0
File: :0-0
Timestamp: 2024-06-10T19:25:42.992Z
Learning: The Button component from `egovernments/digit-ui-components` has compatibility issues with the ActionBar, leading to the preference for using the Button from `egovernments/digit-ui-react-components` in certain scenarios.

Applied to files:

  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/bill_inbox/BillInbox.js
⏰ Context from checks skipped due to timeout of 10000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: Build application arm64
  • GitHub Check: Build application amd64
  • GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (1)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/bill_inbox/BillInbox.js (1)

5-5: Verify AlertCard alias and props usage: Ensure the AlertCard imported as InfoCard in BillInbox.js (lines 305–307) supports the populators, variant, style, label, and text props according to the @egovernments/digit-ui-components API.

import { useTranslation } from "react-i18next";
const { fromViewScreen } = location.state || false;
import { ActionBar, Button, Card, InfoCard, Loader, Tab, Toast } from "@egovernments/digit-ui-components";
import { ActionBar, Button, Card,AlertCard as InfoCard, Loader, Tab, Toast } from "@egovernments/digit-ui-components";
Copy link
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Minor formatting: Add space after comma in import statement.

The import statement is missing a space after the comma between Card and AlertCard.

Apply this diff to fix the formatting:

-import { ActionBar, Button, Card,AlertCard as InfoCard, Loader, Tab, Toast } from "@egovernments/digit-ui-components";
+import { ActionBar, Button, Card, AlertCard as InfoCard, Loader, Tab, Toast } from "@egovernments/digit-ui-components";
📝 Committable suggestion

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

Suggested change
import { ActionBar, Button, Card,AlertCard as InfoCard, Loader, Tab, Toast } from "@egovernments/digit-ui-components";
import { ActionBar, Button, Card, AlertCard as InfoCard, Loader, Tab, Toast } from "@egovernments/digit-ui-components";
🤖 Prompt for AI Agents
In
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/bill_inbox/BillInbox.js
around line 5, the import list lacks a space after the comma between Card and
AlertCard; update the import statement to insert a space after the comma so it
reads "... Card, AlertCard as InfoCard, Loader ..." to correct formatting.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

♻️ Duplicate comments (1)
health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/appConfigurationRedesign/AppConfigurationWrapper.js (1)

283-306: Implement the fallback logic for PATCH_PAGE_CONDITIONAL_NAV.

The fallback when pageName is not found currently returns the array unchanged (line 298). This creates a silent no-op when the page isn't found.

As flagged in previous review comments, apply this diff:

       const patchArray = (arr) => {
         if (!Array.isArray(arr) || arr.length === 0) return arr;

         // If pageName is provided, try to patch by name
         if (pageName) {
           const idx = arr.findIndex((p) => p?.name === pageName);
           if (idx !== -1) {
             return arr.map((p, i) => (i === idx ? { ...p, conditionalNavigateTo: data } : p));
           }
         }

         // Fallback: patch the first page
-        return arr;
+        return arr.map((p, i) => (i === 0 ? { ...p, conditionalNavigateTo: data } : p));
       };
📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 08db216 and 407d1d5.

📒 Files selected for processing (4)
  • health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/appConfigurationRedesign/AppConfigurationWrapper.js (5 hunks)
  • health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/appConfigurationRedesign/DependentFieldsWrapper.js (1 hunks)
  • health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/appConfigurationRedesign/DrawerFieldComposer.js (8 hunks)
  • health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/appConfigurationRedesign/RenderConditionalField.js (5 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.js

⚙️ CodeRabbit configuration file

check

Files:

  • health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/appConfigurationRedesign/DependentFieldsWrapper.js
  • health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/appConfigurationRedesign/RenderConditionalField.js
  • health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/appConfigurationRedesign/DrawerFieldComposer.js
  • health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/appConfigurationRedesign/AppConfigurationWrapper.js
🧠 Learnings (1)
📚 Learning: 2024-10-17T12:00:51.749Z
Learnt from: Ramkrishna-egov
PR: egovernments/DIGIT-Frontend#1545
File: health/micro-ui/web/micro-ui-internals/packages/modules/microplan/src/components/ActivityCard.js:30-35
Timestamp: 2024-10-17T12:00:51.749Z
Learning: In our codebase, the 'Card' component is commonly used by passing children via the 'children' prop.

Applied to files:

  • health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/appConfigurationRedesign/DependentFieldsWrapper.js
🧬 Code graph analysis (4)
health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/appConfigurationRedesign/DependentFieldsWrapper.js (1)
micro-ui/web/micro-ui-internals/packages/react-components/src/atoms/Dropdown.js (1)
  • Dropdown (94-281)
health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/appConfigurationRedesign/RenderConditionalField.js (4)
health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/appConfigurationRedesign/DrawerFieldComposer.js (6)
  • useTranslation (80-80)
  • useTranslation (391-391)
  • useT (89-89)
  • isLocalisable (81-83)
  • drawerState (396-398)
  • handleExpressionChange (413-423)
health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/appConfigurationRedesign/DependentFieldsWrapper.js (1)
  • useT (73-73)
health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/appConfigurationRedesign/useCustomT.js (2)
  • useCustomT (12-40)
  • useCustomT (12-40)
health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/appConfigurationRedesign/AppConfigurationParentLayer.js (1)
  • parentState (60-60)
health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/appConfigurationRedesign/DrawerFieldComposer.js (3)
health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/appConfigurationRedesign/useCustomT.js (2)
  • useCustomT (12-40)
  • useCustomT (12-40)
health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/appConfigurationRedesign/AppConfigurationParentLayer.js (1)
  • parentState (60-60)
health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/appConfigurationRedesign/AppLocalisationWrapper.js (1)
  • updateLocalization (56-62)
health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/appConfigurationRedesign/AppConfigurationWrapper.js (3)
health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/appConfigurationRedesign/AppConfigurationParentLayer.js (1)
  • parentState (60-60)
health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/appConfigurationRedesign/useCustomT.js (2)
  • useCustomT (12-40)
  • useCustomT (12-40)
health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/AppPreview.js (1)
  • AppPreview (172-281)
🪛 Biome (2.1.2)
health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/appConfigurationRedesign/DependentFieldsWrapper.js

[error] 514-515: The elements with this role can be changed to the following elements:

For examples and more information, see WAI-ARIA Roles

(lint/a11y/useSemanticElements)


[error] 513-520: The HTML element with the interactive role "button" is not focusable.

A non-interactive HTML element that is not focusable may not be reachable for users that rely on keyboard navigation, even with an added role like "button".
Add a tabIndex attribute to make this element focusable.

(lint/a11y/useFocusableInteractive)


[error] 513-520: Enforce to have the onClick mouse event with the onKeyUp, the onKeyDown, or the onKeyPress keyboard event.

Actions triggered using mouse events should have corresponding keyboard events to account for keyboard-only navigation.

(lint/a11y/useKeyWithClickEvents)


[error] 528-529: The elements with this role can be changed to the following elements:

For examples and more information, see WAI-ARIA Roles

(lint/a11y/useSemanticElements)


[error] 527-534: Enforce to have the onClick mouse event with the onKeyUp, the onKeyDown, or the onKeyPress keyboard event.

Actions triggered using mouse events should have corresponding keyboard events to account for keyboard-only navigation.

(lint/a11y/useKeyWithClickEvents)


[error] 527-534: The HTML element with the interactive role "button" is not focusable.

A non-interactive HTML element that is not focusable may not be reachable for users that rely on keyboard navigation, even with an added role like "button".
Add a tabIndex attribute to make this element focusable.

(lint/a11y/useFocusableInteractive)


[error] 917-924: Static Elements should not be interactive.

To add interactivity such as a mouse or key event listener to a static element, give the element an appropriate role value.

(lint/a11y/noStaticElementInteractions)


[error] 917-924: Enforce to have the onClick mouse event with the onKeyUp, the onKeyDown, or the onKeyPress keyboard event.

Actions triggered using mouse events should have corresponding keyboard events to account for keyboard-only navigation.

(lint/a11y/useKeyWithClickEvents)


[error] 598-598: Avoid passing children using a prop

The canonical way to pass children in React is to use JSX elements

(lint/correctness/noChildrenProp)

health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/appConfigurationRedesign/RenderConditionalField.js

[error] 42-42: This hook is being called conditionally, but all hooks must be called in the exact same order in every component render.

For React to preserve state between calls, hooks needs to be called unconditionally and always in the same order.
See https://reactjs.org/docs/hooks-rules.html#only-call-hooks-at-the-top-level

(lint/correctness/useHookAtTopLevel)


[error] 94-94: This hook is being called from a nested function, but all hooks must be called unconditionally from the top-level component.

For React to preserve state between calls, hooks needs to be called unconditionally and always in the same order.
See https://reactjs.org/docs/hooks-rules.html#only-call-hooks-at-the-top-level

(lint/correctness/useHookAtTopLevel)

health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/appConfigurationRedesign/DrawerFieldComposer.js

[error] 201-201: This hook is being called conditionally, but all hooks must be called in the exact same order in every component render.

For React to preserve state between calls, hooks needs to be called unconditionally and always in the same order.
See https://reactjs.org/docs/hooks-rules.html#only-call-hooks-at-the-top-level

(lint/correctness/useHookAtTopLevel)


[error] 360-360: This hook is being called from a nested function, but all hooks must be called unconditionally from the top-level component.

For React to preserve state between calls, hooks needs to be called unconditionally and always in the same order.
See https://reactjs.org/docs/hooks-rules.html#only-call-hooks-at-the-top-level

(lint/correctness/useHookAtTopLevel)

health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/appConfigurationRedesign/AppConfigurationWrapper.js

[error] 326-326: This hook is being called conditionally, but all hooks must be called in the exact same order in every component render.

For React to preserve state between calls, hooks needs to be called unconditionally and always in the same order.
See https://reactjs.org/docs/hooks-rules.html#only-call-hooks-at-the-top-level

(lint/correctness/useHookAtTopLevel)


[error] 755-755: This hook is being called conditionally, but all hooks must be called in the exact same order in every component render.

For React to preserve state between calls, hooks needs to be called unconditionally and always in the same order.
See https://reactjs.org/docs/hooks-rules.html#only-call-hooks-at-the-top-level

(lint/correctness/useHookAtTopLevel)

⏰ Context from checks skipped due to timeout of 10000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (6)
health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/appConfigurationRedesign/RenderConditionalField.js (1)

223-233: LGTM! Dependency field wrapper integration.

The new "dependencyFieldWrapper" case correctly passes all required props to DependentFieldsWrapper, enabling conditional display logic configuration.

health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/appConfigurationRedesign/DependentFieldsWrapper.js (1)

1-964: LGTM! Well-structured conditional navigation editor.

The component implements a comprehensive rule-based conditional navigation/display system with:

  • Proper state management for rules list
  • Tokenization and parsing of conditional expressions
  • Field type-aware operator options and value inputs
  • Clear UI for adding/editing/deleting rules

The implementation correctly handles different field types (DOB, dates, checkboxes, dropdowns, numeric fields) and provides appropriate input controls for each.

Note: Accessibility improvements for interactive divs (lines 513-520, 527-534, 891-927) and children prop usage (line 598) have been flagged in previous review comments.

health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/appConfigurationRedesign/AppConfigurationWrapper.js (2)

314-314: LGTM! Proper prop threading for parentState and translation hook.

The new parentState prop is correctly:

  1. Accepted in the function signature (line 314)
  2. Passed to child components (lines 661, 665)

The useT translation hook is properly initialized and passed to AppPreview (line 582).

Also applies to: 582-582, 661-661, 665-665


315-315: Critical: useT invoked conditionally in useMemo.

useT (a hook returned from useCustomT()) is being called inside useMemo callbacks (lines 326, 755), which are conditionally executed based on dependencies. This violates React's Rules of Hooks.

Move the translation calls outside of useMemo:

 function AppConfigurationWrapper({ screenConfig, localeModule, pageTag, parentState }) {
   const useT = useCustomT();
   const queryClient = useQueryClient();
   const { locState, addMissingKey, updateLocalization, onSubmit, back, showBack, parentDispatch } = useAppLocalisationContext();
   // ... other hooks
   
-  const addFieldDataLabel = useMemo(() => {
-    return addFieldData?.label ? useT(addFieldData?.label) : null;
-  }, [addFieldData]);
+  // Simply compute the label directly - useT is already stable from useCustomT
+  const addFieldDataLabel = addFieldData?.label ? useT(addFieldData?.label) : null;
   
   // ... rest of component
   
   {popupData && (
     <PopUp>
       <FieldV1
         required={true}
         type={"text"}
         label={`${t("ADD_FIELD_LABEL")}`}
-        value={addFieldData?.label ? useT(addFieldData?.label) : ""}
+        value={addFieldDataLabel || ""}
         // ... rest unchanged
       />
     </PopUp>
   )}
 }

The useT function returned by useCustomT() is already memoized internally, so you don't need additional useMemo wrapping.

Also applies to: 326-326, 755-755

⛔ Skipped due to learnings
Learnt from: Tulika-eGov
PR: egovernments/DIGIT-Frontend#2188
File: micro-ui/web/micro-ui-internals/packages/modules/pgr/src/pages/employee/new-inbox.js:34-47
Timestamp: 2025-02-05T10:18:29.947Z
Learning: In the DIGIT-Frontend codebase, translations within FormComposer are handled internally by the component itself, so the translation function 't' does not need to be added to useMemo dependency arrays even when used within the memoized function that generates form configurations.
Learnt from: Tulika-eGov
PR: egovernments/DIGIT-Frontend#2188
File: micro-ui/web/micro-ui-internals/packages/libraries/src/hooks/pgr/useComplaintSubType.js:14-14
Timestamp: 2025-02-05T10:05:37.433Z
Learning: In PGR's useComplaintSubType hook, the translation function 't' must be included in the useEffect dependency array to ensure complaint types are updated when the language changes.
health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/appConfigurationRedesign/DrawerFieldComposer.js (2)

413-423: LGTM! handleExpressionChange implementation.

The function correctly updates the visibilityCondition.expression in drawerState with proper immutability and guards against redundant updates.


78-79: LGTM! Proper prop threading for new conditional navigation features.

The new props (parentState, screenConfig, selectedField, handleExpressionChange) are correctly:

  1. Added to RenderField signature (lines 78-79)
  2. Passed to RenderConditionalField (lines 168-172)
  3. Added to DrawerFieldComposer signature (line 390)
  4. Passed to RenderField (lines 493-499)

This enables the DependentFieldsWrapper to access parent state and update conditional navigation logic.

Also applies to: 168-172, 390-390, 493-499

const tenantId = searchParams.get("tenantId");
const shouldShow = whenToShow(panelItem, drawerState);
const flowName = useMemo(() => state?.screenConfig?.[0]?.parent, [state?.screenConfig?.[0]]);
const useT = useCustomT();
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Critical: useT called conditionally inside switch and nested functions.

useT is a hook and must be called at the component's top level. Currently it's invoked inside:

  1. Line 201: Inside switch case "text" (conditionally based on panelItem?.fieldType)
  2. Line 360: Inside a .map() callback (nested function)

This violates React's Rules of Hooks and will corrupt state.

Refactor to call useT unconditionally:

 const RenderField = ({ state, panelItem, parentState, screenConfig, selectedField, drawerState, setDrawerState, updateLocalization, handleExpressionChange, AppScreenLocalisationConfig }) => {
   const { t } = useTranslation();
+  const useT = useCustomT();
+  
+  // Pre-compute localized values at top level
+  const localizedFieldValue = isLocalisable ? useT(drawerState?.[panelItem?.bindTo]) : null;
+  
   const isLocalisable = AppScreenLocalisationConfig?.fields
     ?.find((i) => i.fieldType === drawerState?.appType)
     ?.localisableProperties?.includes(panelItem?.label);
   const searchParams = new URLSearchParams(location.search);
   const projectType = searchParams.get("projectType");
   const tenantId = searchParams.get("tenantId");
   const shouldShow = whenToShow(panelItem, drawerState);
   const flowName = useMemo(() => state?.screenConfig?.[0]?.parent, [state?.screenConfig?.[0]]);
-  const useT = useCustomT();
   
   // ... rest of the logic
   
   switch (panelItem?.fieldType) {
     case "text": {
       return (
         <div>
           <FieldV1
             type={panelItem?.fieldType}
             label={t(Digit.Utils.locale.getTransformedLocale(`FIELD_DRAWER_LABEL_${panelItem?.label}`))}
             value={
-              isLocalisable
-                ? useT(drawerState?.[panelItem?.bindTo])
-                : drawerState?.[panelItem?.bindTo] === true
-                ? ""
-                : drawerState?.[panelItem?.bindTo]
+              localizedFieldValue !== null
+                ? localizedFieldValue
+                : drawerState?.[panelItem?.bindTo] === true
+                ? ""
+                : drawerState?.[panelItem?.bindTo]
             }
             // ... rest unchanged
           />
         </div>
       );
     }
     case "DetailsCard":
     case "Table": {
       const selectedOptions = drawerState?.[panelItem?.bindTo] || [];
+      // Pre-compute all localized option codes at the top level
+      const localizedOptions = selectedOptions
+        .filter((opt) => opt && typeof opt.code === "string" && opt.code.includes("."))
+        .map((opt) => ({
+          ...opt,
+          localizedValue: useT(opt.code)
+        }));
       
       return (
         <>
           {/* ... MultiSelectDropdown unchanged ... */}
           
-          {Array.isArray(selectedOptions) &&
-            selectedOptions
-              .filter((opt) => opt && typeof opt.code === "string" && opt.code.includes("."))
-              .map((option) => {
+          {localizedOptions.map((option) => {
                 const [entity, fieldKey] = option.code.split(".");

                 return (
                   <div key={option.code} style={{ marginTop: "16px" }}>
                     <FieldV1
                       label={`${t(entity)} - ${t(fieldKey)}`}
-                      value={useT(option.code)}
+                      value={option.localizedValue}
                       type="text"
                       // ... rest unchanged
                     />
                   </div>
                 );
               })}
         </>
       );
     }
   }
 };

Also applies to: 201-201, 360-360

disabled,
}) => {
const { t } = useTranslation();
const useT = useCustomT();
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Critical: Move useT to component top level.

useT is a hook and must be called unconditionally at the component's top level. Currently it's being invoked inside switch branches (lines 42, 94), which violates React's Rules of Hooks and will cause state to corrupt when the component re-renders with different cField.type values.

Apply this diff to fix:

 export const RenderConditionalField = ({
   cField,
   cIndex,
   cArray,
   setDrawerState,
   updateLocalization,
   state,
   parentState,
   drawerState,
   screenConfig,
   AppScreenLocalisationConfig,
   handleExpressionChange,
   selectedField,
   disabled,
 }) => {
   const { t } = useTranslation();
   const useT = useCustomT();
+  
+  // Pre-compute localized values at the top level
+  const localizedFieldValue = isLocalisable ? useT(drawerState?.[cField?.bindTo]) : null;
+  
   const isLocalisable = AppScreenLocalisationConfig?.fields
     ?.find((i) => i.fieldType === (drawerState?.appType || drawerState?.type))
     ?.localisableProperties?.includes(cField?.bindTo?.split(".")?.at(-1));
   const searchParams = new URLSearchParams(location.search);
   const projectType = searchParams.get("prefix");

   switch (cField?.type) {
     case "text":
     case "number":
     case "date":
     case "time":
       return (
         <FieldV1
           type={cField?.type}
           label={cField?.label}
           withoutLabel={Boolean(!cField?.label)}
           value={
-            isLocalisable ? useT(drawerState?.[cField?.bindTo]) : drawerState?.[cField?.bindTo] === true ? "" : drawerState?.[cField?.bindTo]
+            localizedFieldValue !== null ? localizedFieldValue : drawerState?.[cField?.bindTo] === true ? "" : drawerState?.[cField?.bindTo]
           }
           // ... rest unchanged
         />
       );
     case "options":
       return (
         <div
           style={{ padding: "1.5rem", border: "1px solid #c84c0e", borderRadius: "1rem", display: "flex", flexDirection: "column", gap: "1.5rem" }}
         >
           {(drawerState?.[cField?.bindTo] || []).map((item, index) => {
+            const localizedItemName = useT(item?.name);
             return (
               <div style={{ display: "flex", gap: "1rem" }} key={item.code || index}>
                 <TextInput
                   isRequired={true}
                   className=""
                   type={"text"}
                   name="title"
-                  value={useT(item?.name)}
+                  value={localizedItemName}
                   onChange={(event) => {
                     // ... rest unchanged
                   }}
                   placeholder={""}
                   disabled={disabled}
                 />
                 // ... rest unchanged
               </div>
             );
           })}
           // ... rest unchanged
         </div>
       );
     // ... other cases unchanged
   }
 };

Note: For the "options" case (line 94), since it's inside a .map(), you'll need to either:

  1. Pre-compute all localized names before the map
  2. Or use a custom child component that can safely call useT at its own top level

Also applies to: 42-42, 94-94

🤖 Prompt for AI Agents
In
health/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/appConfigurationRedesign/RenderConditionalField.js
(lines 24, 42, 94), the hook useCustomT is being called conditionally inside
switch branches which breaks the Rules of Hooks; move the hook call to the top
of the component (declare const t = useCustomT() immediately after the component
starts, before any switch/map/conditional) and replace in-branch calls with that
top-level t; for the "options" case where localization currently happens inside
a .map(), pre-compute an array of localized option labels using the top-level t
before mapping (or extract the option rendering into a small child component
that itself calls useCustomT at its own top level) so no hook is invoked
conditionally inside the map.

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

♻️ Duplicate comments (5)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/attendance_inbox/table_inbox.js (1)

76-107: Fix navigation helper: stop bubbling, use latest endDate, and compare millis correctly

Clicking the ID link currently fires both the button handler and the row handler, so we push two different URLs. On top of that, Date.now() (ms) is compared to an endDate that the APIs return in seconds, so every register looks expired and forces the read-only route. Finally, we keep ignoring the selectedProject prop and fall back to potentially stale session-state.

Combine these into a single helper that (a) calls event?.stopPropagation(), (b) prefers selectedProject?.endDate with session storage only as fallback, and (c) normalizes seconds ➝ milliseconds before comparing.

@@
-        <span className="link">
-          <Button
-            label={t(`${row.id}`)}
-            onClick={() => {
-              const existingPaymentInbox = Digit.SessionStorage.get("paymentInbox");
-              const endDate = existingPaymentInbox?.selectedProject?.endDate;
-
-              if (endDate) {
-                const currentDate = Date.now();
-                if (!(currentDate <= endDate)) {
-                  history.push(
-                    `/${window?.contextPath}/employee/payments/view-attendance?registerNumber=${row?.id}&boundaryCode=${row?.boundary}`
-                  );
-                } else {
-                  history.push(
-                    `/${window?.contextPath}/employee/payments/edit-register?registerNumber=${row?.id}&boundaryCode=${row?.boundary}&registerId=${row?.registerId}`
-                  );
-                }
-              } else {
-                console.warn("No endDate found in session storage");
-                history.push(
-                  `/${window?.contextPath}/employee/payments/view-attendance?registerNumber=${row?.id}&boundaryCode=${row?.boundary}`
-                );
-              }
-            }}
+        <span className="link">
+          <Button
+            label={t(`${row.id}`)}
+            onClick={(event) => navigateForRow(row, event)}
@@
-  const handleRowClick = (row) => {
-
-    const existingPaymentInbox = Digit.SessionStorage.get("paymentInbox");
-    const endDate = existingPaymentInbox?.selectedProject?.endDate;
-
-    if (endDate) {
-      const currentDate = Date.now();
-      if (!(currentDate <= endDate)) {
-        history.push(
-          `/${window?.contextPath}/employee/payments/view-attendance?registerNumber=${row?.id}&boundaryCode=${row?.boundary}`
-        );
-      } else {
-        history.push(
-          `/${window?.contextPath}/employee/payments/edit-register?registerNumber=${row?.id}&boundaryCode=${row?.boundary}&registerId=${row?.registerId}`
-        );
-      }
-    } else {
-      console.warn("No endDate found in session storage");
-      history.push(
-        `/${window?.contextPath}/employee/payments/view-attendance?registerNumber=${row?.id}&boundaryCode=${row?.boundary}`
-      );
-    }
-
-    // history.push(
-    //   `/${window?.contextPath}/employee/payments/view-attendance?registerNumber=${row?.id}&boundaryCode=${row?.boundary}`
-    // );
-  };
+  const navigateForRow = (row, event) => {
+    event?.stopPropagation();
+
+    const sessionProject = Digit.SessionStorage.get("paymentInbox")?.selectedProject;
+    const rawEndDate = selectedProject?.endDate ?? sessionProject?.endDate;
+
+    if (rawEndDate) {
+      const endDateMs = rawEndDate < 1e12 ? rawEndDate * 1000 : rawEndDate;
+      const isExpired = Date.now() > endDateMs;
+
+      history.push(
+        isExpired
+          ? `/${window?.contextPath}/employee/payments/view-attendance?registerNumber=${row?.id}&boundaryCode=${row?.boundary}`
+          : `/${window?.contextPath}/employee/payments/edit-register?registerNumber=${row?.id}&boundaryCode=${row?.boundary}&registerId=${row?.registerId}`
+      );
+      return;
+    }
+
+    setShowToast({
+      key: "warning",
+      label: t("HCM_AM_END_DATE_MISSING_VIEW_ONLY"),
+      transitionTime: 3000,
+    });
+    history.push(
+      `/${window?.contextPath}/employee/payments/view-attendance?registerNumber=${row?.id}&boundaryCode=${row?.boundary}`
+    );
+  };

Then wire the table with onRowClicked={(row) => navigateForRow(row)}. This keeps navigation consistent, avoids double pushes, and respects real expiry dates. Translation HCM_AM_END_DATE_MISSING_VIEW_ONLY needs to be added.

Also applies to: 169-191

health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/pages/employee/EditRegister.js (4)

35-35: Guard against missing location.state before destructuring.

When location.state is undefined, destructuring from false throws at render. Please default to an object and give the property its own fallback.

-    const { fromCampaignSupervisor } = location.state || false;
+    const { fromCampaignSupervisor = false } = location?.state || {};

82-95: Protect every attendanceRegister[0] access.

If /v1/_search returns no register rows, each direct [0] index or .length dereference will throw before the guard runs. Optional-chain the array element and default the attendee list before mapping, and reuse the derived owner id for the secondary search.

-        if (AttendanceData) {
-            setAttendanceDuration(
-                Math.ceil((AttendanceData?.attendanceRegister[0]?.endDate - AttendanceData?.attendanceRegister[0]?.startDate) / (24 * 60 * 60 * 1000))
-            );
-        }
+        const register = AttendanceData?.attendanceRegister?.[0];
+        if (register?.endDate && register?.startDate) {
+            setAttendanceDuration(
+                Math.ceil((register.endDate - register.startDate) / (24 * 60 * 60 * 1000))
+            );
+        } else {
+            setAttendanceDuration(null);
+        }
@@
-        if (AttendanceData?.attendanceRegister?.length > 0) {
-            const ids = AttendanceData.attendanceRegister[0].attendees.map(
-                (a) => a.individualId
-            );
-            setIndividualIds(ids);
-        }
+        const attendees = AttendanceData?.attendanceRegister?.[0]?.attendees ?? [];
+        setIndividualIds(
+            Array.isArray(attendees)
+                ? attendees.map((a) => a?.individualId).filter(Boolean)
+                : []
+        );
@@
-            Individual: {
-                id: [AttendanceData?.attendanceRegister[0]?.staff?.find(
-                    (staff) => staff?.staffType?.includes("OWNER")
-                )?.userId]
-            }
+            Individual: {
+                id: ownerUserId ? [ownerUserId] : []
+            }
@@
-            enabled: AttendanceData?.attendanceRegister.length === 1 && AttendanceData?.attendanceRegister[0]?.staff?.find(
-                (staff) => staff?.staffType?.includes("OWNER")
-            )?.userId ? true : false,
+            enabled: Boolean(ownerUserId),

and define just before individualReqCriteria:

+    const ownerUserId = AttendanceData?.attendanceRegister?.[0]?.staff?.find((staff) =>
+        staff?.staffType?.includes("OWNER")
+    )?.userId;

Also applies to: 128-135


145-176: Null-guard attendee mapping inside getUserAttendanceSummary.

attendanceData.attendanceRegister[0] explodes when the register array is empty or missing. Please short-circuit before touching [0], and reuse the guarded attendees array in the map.

-        if (attendanceData.attendanceRegister[0].attendees == null || attendanceData.attendanceRegister[0].attendees.length == 0) {
+        const register = attendanceData?.attendanceRegister?.[0];
+        const attendees = Array.isArray(register?.attendees) ? register.attendees : [];
+
+        if (attendees.length === 0) {
             return [];
         }
-        else {
-            const attendanceLogData = attendanceData.attendanceRegister[0].attendees.map((individualEntry) => {
+        else {
+            const attendanceLogData = attendees.map((individualEntry) => {

335-336: Remove empty <h2> to fix the a11y lint error.

Biome reports useHeadingContent here; an empty heading confuses screen readers. Either supply meaningful text or drop the heading altogether.

-                        <h2 className="card-heading-title"></h2>
+                        {/* Removed empty heading; add meaningful title if required */}
📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 407d1d5 and 42d5a65.

📒 Files selected for processing (2)
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/attendance_inbox/table_inbox.js (5 hunks)
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/pages/employee/EditRegister.js (1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.js

⚙️ CodeRabbit configuration file

check

Files:

  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/attendance_inbox/table_inbox.js
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/pages/employee/EditRegister.js
🧠 Learnings (1)
📚 Learning: 2024-11-07T11:02:33.520Z
Learnt from: rachana-egov
PR: egovernments/DIGIT-Frontend#1770
File: health/micro-ui/web/micro-ui-internals/packages/modules/microplan/src/pages/employee/viewVillage.js:320-322
Timestamp: 2024-11-07T11:02:33.520Z
Learning: In `health/micro-ui/web/micro-ui-internals/packages/modules/microplan/src/pages/employee/viewVillage.js`, the `data?.additionalFields` object is guaranteed to be defined, so checking for its existence before accessing its keys is unnecessary.

Applied to files:

  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/pages/employee/EditRegister.js
🧬 Code graph analysis (2)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/attendance_inbox/table_inbox.js (5)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/pages/employee/EditRegister.js (2)
  • Digit (34-34)
  • history (27-27)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/pages/employee/ViewAttendance.js (2)
  • Digit (32-32)
  • history (24-24)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/bill_inbox/billInboxTable.js (4)
  • history (23-23)
  • columns (70-140)
  • triggerMusterRollSearch (35-56)
  • handleRowClick (159-163)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/attendance_inbox/attendance_inbox.js (4)
  • selectedProject (23-23)
  • handlePaginationChange (160-164)
  • handleRowsPerPageChange (165-169)
  • rowsPerPage (25-25)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/table_inbox_custom_style.js (2)
  • tableCustomStyle (1-108)
  • tableCustomStyle (1-108)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/pages/employee/EditRegister.js (4)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/pages/employee/project_selection.js (5)
  • location (15-15)
  • useTranslation (16-16)
  • history (17-17)
  • showToast (27-27)
  • project (23-23)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/pages/employee/ViewAttendance.js (28)
  • location (22-22)
  • location (33-33)
  • useTranslation (23-23)
  • history (24-24)
  • Digit (32-32)
  • attendanceDuration (35-35)
  • attendanceSummary (36-36)
  • initialAttendanceSummary (37-37)
  • isSubmitEnabled (38-38)
  • disabledAction (40-40)
  • individualIds (48-48)
  • triggerEstimate (49-49)
  • comment (50-50)
  • showToast (51-51)
  • loading (52-52)
  • showLogs (53-53)
  • showCommentLogPopup (54-54)
  • showDeEnrollPopup (57-57)
  • project (59-59)
  • AttendancereqCri (62-74)
  • isAttendanceLoading (76-76)
  • allIndividualReqCriteria (312-331)
  • isAllIndividualsLoading (333-333)
  • individualReqCriteria (335-357)
  • closeActionBarPopUp (428-430)
  • handleDeEnrollClick (441-443)
  • onDeEnrollClose (445-447)
  • renderLabelPair (450-455)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/EditAttendanceManagementTable.js (5)
  • useTranslation (33-33)
  • history (34-34)
  • tenantId (40-40)
  • showToast (36-36)
  • EditAttendanceManagementTable (31-274)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/editAttendeesPopUp.js (11)
  • useTranslation (24-24)
  • history (15-15)
  • tenantId (25-25)
  • attendanceSummary (32-32)
  • individualIds (33-33)
  • AttendancereqCri (77-88)
  • isAttendanceLoading (90-91)
  • allIndividualReqCriteria (104-121)
  • isAllIndividualsLoading (123-124)
  • closeActionBarPopUp (206-208)
  • EditAttendeePopUp (14-282)
🪛 Biome (2.1.2)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/pages/employee/EditRegister.js

[error] 335-336: Provide screen reader accessible content when using heading elements.

All headings on a page should have content that is accessible to screen readers.

(lint/a11y/useHeadingContent)

⏰ Context from checks skipped due to timeout of 10000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Analyze (javascript-typescript)

Comment on lines +288 to +294
<Fragment>
{renderLabelPair('HCM_AM_ATTENDANCE_OFFICER', individualsData?.Individual?.[0]?.name?.givenName)}
{renderLabelPair('HCM_AM_ATTENDANCE_OFFICER_CONTACT_NUMBER', individualsData?.Individual?.[0]?.mobileNumber)}
{renderLabelPair('HCM_AM_NO_OF_ATTENDEE', AttendanceData?.attendanceRegister[0]?.attendees?.length || 0)}
{renderLabelPair('HCM_AM_CAMPAIGN_START_DATE', formatTimestampToDate(project?.[0]?.startDate))}
{renderLabelPair('HCM_AM_CAMPAIGN_END_DATE', formatTimestampToDate(project?.[0]?.endDate))}
{renderLabelPair('HCM_AM_EVENT_DURATION', attendanceDuration || 0)}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Render path still crashes when attendanceRegister is empty.

AttendanceData?.attendanceRegister[0]?.attendees will dereference [0] on undefined. Please optional-chain the element before reading attendees and length.

-                            {renderLabelPair('HCM_AM_NO_OF_ATTENDEE', AttendanceData?.attendanceRegister[0]?.attendees?.length || 0)}
+                            {renderLabelPair(
+                                'HCM_AM_NO_OF_ATTENDEE',
+                                AttendanceData?.attendanceRegister?.[0]?.attendees?.length ?? 0
+                            )}
🤖 Prompt for AI Agents
In
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/pages/employee/EditRegister.js
around lines 288 to 294, the expression
AttendanceData?.attendanceRegister[0]?.attendees?.length || 0 can throw when
attendanceRegister is undefined; update it to safely optional-chain the array
before indexing (e.g. AttendanceData?.attendanceRegister?.[0]?.attendees?.length
|| 0) so you never attempt to access [0] on undefined and the render path won't
crash.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants