Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Payment: Attendance Approval Flow #2097

Open
wants to merge 108 commits into
base: console
Choose a base branch
from

Conversation

rachana-egov
Copy link
Contributor

@rachana-egov rachana-egov commented Jan 3, 2025

Choose the appropriate template for your PR:

Feature PR

Feature Request

JIRA ID

Module

Description

Related Issues


Bugfix PR

Bugfix Request

JIRA ID

Module

Description

Root Cause

Related Issues


Release PR

Summary by CodeRabbit

Based on the comprehensive summary of changes, here are the updated release notes:

  • New Features

    • Added a new Payments module with enhanced functionality for health-related payments.
    • Introduced advanced search and filtering capabilities for bills and attendance.
    • Implemented breadcrumb navigation and custom inbox components.
    • Added support for project and boundary selection.
  • Components Added

    • Developed new UI components for bill management, attendance tracking, and project selection, including BreadCrumbs, CustomBillInbox, MyBillsSearch, DateRangePicker, AlertPopUp, ApproveCommentPopUp, CustomInboxSearchComposer, BillSearchBox, BillBoundaryFilter, BillInboxTable, CustomInboxTable, BoundaryComponent, CustomFilter, CustomSearchComponent, and CustomInboxSearchLinks.
    • Implemented responsive and interactive user interfaces.
  • Hooks and Services

    • Added custom hooks for project search, payments initialization, and attendance boundary searches, including useProjectSearch, usePaymentsInitialization, useAttendanceBoundarySearch, and useAttendanceBoundaryRegisterSearch.
    • Introduced new services for handling project and attendance-related API interactions, including AttendanceService and ProjectService.
  • Improvements

    • Enhanced routing capabilities with new private routes.
    • Improved state management using React hooks.
    • Added internationalization support.
    • Implemented robust error handling.

rachana-egov and others added 30 commits December 19, 2024 09:50
#2065)

HCMPRE-1717:: Load and store project details on Payments module initialization
attendance inbox in  progress
* attendance inbox in  progress

* composer in progress

* inboxserach composer replaced with custom inbox component
* attendance inbox in  progress

* composer in progress

* inboxserach composer replaced with custom inbox component

* boundary service API integration implemented for inbox screen

* Update filter_section.js

---------

Co-authored-by: rachana-egov <[email protected]>
* attendance inbox in  progress

* composer in progress

* inboxserach composer replaced with custom inbox component

* boundary service API integration implemented for inbox screen

* check box and register search API integration in progress
* attendance inbox in  progress

* composer in progress

* inboxserach composer replaced with custom inbox component

* boundary service API integration implemented for inbox screen

* check box and register search API integration in progress

* table data enriched
* attendance inbox in  progress

* composer in progress

* inboxserach composer replaced with custom inbox component

* boundary service API integration implemented for inbox screen

* check box and register search API integration in progress

* table data enriched

* removed debugger

* variable name changed
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: 15

♻️ Duplicate comments (35)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/custom_inbox_composer.js (1)

219-281: 🛠️ Refactor suggestion

Improve UI code organization and readability.

  1. Use self-closing tags for components without children
  2. Extract inline styles to styled-components or CSS modules
  3. Consider breaking down the large JSX structure into smaller components
-<CustomInboxSearchLinks headerText={"ATTENDANCE_INBOX_CARD"}></CustomInboxSearchLinks>
+<CustomInboxSearchLinks headerText={"ATTENDANCE_INBOX_CARD"} />

-<Card style={{ maxWidth: "100%", overflow: "auto", margin: "0px", padding: "0px" }}></Card>
+<Card style={{ maxWidth: "100%", overflow: "auto", margin: "0px", padding: "0px" }} />

-<CustomInboxTable {...props}></CustomInboxTable>
+<CustomInboxTable {...props} />
🧰 Tools
🪛 Biome (1.9.4)

[error] 225-225: JSX elements without children should be marked as self-closing. In JSX, it is valid for any element to be self-closing.

Unsafe fix: Use a SelfClosingElement instead

(lint/style/useSelfClosingElements)


[error] 240-246: JSX elements without children should be marked as self-closing. In JSX, it is valid for any element to be self-closing.

Unsafe fix: Use a SelfClosingElement instead

(lint/style/useSelfClosingElements)


[error] 253-253: JSX elements without children should be marked as self-closing. In JSX, it is valid for any element to be self-closing.

Unsafe fix: Use a SelfClosingElement instead

(lint/style/useSelfClosingElements)


[error] 255-264: JSX elements without children should be marked as self-closing. In JSX, it is valid for any element to be self-closing.

Unsafe fix: Use a SelfClosingElement instead

(lint/style/useSelfClosingElements)

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

30-31: 🧹 Nitpick (assertive)

Refactor repeated transformation logic for clarity

Currently, Digit.Utils.locale.getTransformedLocale(location.pathname.split("/").pop()) is being called multiple times. Extracting the transformed locale into a variable would reduce duplication and enhance readability.

Apply this diff to refactor the code:

+ const transformedPageName = Digit.Utils.locale.getTransformedLocale(location.pathname.split("/").pop());
...
  show:
-   Digit.Utils.locale.getTransformedLocale(location.pathname.split("/").pop()) === "VIEW_ATTENDANCE" ||
-   Digit.Utils.locale.getTransformedLocale(location.pathname.split("/").pop()) === "EDIT_ATTENDANCE"
+   transformedPageName === "VIEW_ATTENDANCE" || transformedPageName === "EDIT_ATTENDANCE"

46-46: ⚠️ Potential issue

Use optional chaining to prevent potential runtime errors

Accessing window.contextPath without optional chaining could cause a runtime error if window.contextPath is undefined. Consider using optional chaining like window?.contextPath.

Apply this diff to prevent potential errors:

- if (window.location.pathname !== `/${window.contextPath}/employee/`) {
+ if (window.location.pathname !== `/${window?.contextPath}/employee/`) {

50-50: 🧹 Nitpick (assertive)

Ensure consistent use of session storage handlers

You're using window.Digit.SessionStorage.del to delete session storage items, but for "selectedValues", you're using sessionStorage.removeItem. For consistency and to leverage any additional handling provided by the Digit.SessionStorage wrapper, consider using window.Digit.SessionStorage.del for all deletions.

Apply this diff for consistency:

-   sessionStorage.removeItem("selectedValues");
+   window.Digit.SessionStorage.del("selectedValues");

60-66: 🧹 Nitpick (assertive)

Avoid inline function components in routes for performance

Using inline arrow functions in component={() => <Component />} can lead to unnecessary re-renders. Instead, consider passing the component reference directly or use children within PrivateRoute for components requiring props.

Apply this diff to improve performance:

- <PrivateRoute path={`${path}/view-attendance`} component={() => <ViewAttendance />} />
+ <PrivateRoute path={`${path}/view-attendance`} component={ViewAttendance} />

- <PrivateRoute path={`${path}/edit-attendance`} component={() => <ViewAttendance editAttendance={true} />} />
+ <PrivateRoute path={`${path}/edit-attendance`}>
+   <ViewAttendance editAttendance={true} />
+ </PrivateRoute>

- <PrivateRoute path={`${path}/attendance-approve-success`} component={() => <Response />} />
+ <PrivateRoute path={`${path}/attendance-approve-success`} component={Response} />

- <PrivateRoute path={`${path}/attendance-approve-failed`} component={() => <Response />} />
+ <PrivateRoute path={`${path}/attendance-approve-failed`} component={Response} />

- <PrivateRoute path={`${path}/registers-inbox`} component={() => <AttendanceInbox />} />
+ <PrivateRoute path={`${path}/registers-inbox`} component={AttendanceInbox} />

- <PrivateRoute path={`${path}/generate-bill`} component={() => <BillInbox />} />
+ <PrivateRoute path={`${path}/generate-bill`} component={BillInbox} />

- <PrivateRoute path={`${path}/my-bills`} component={() => <MyBills />} />
+ <PrivateRoute path={`${path}/my-bills`} component={MyBills} />
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/pages/employee/ViewAttendance.js (8)

44-44: 🧹 Nitpick (assertive)

Simplify boolean expression

The ternary operator registerNumber ? true : false is unnecessary. You can use the truthiness of registerNumber directly.

Apply this diff to simplify the expression:

-      enabled: registerNumber ? true : false,
+      enabled: !!registerNumber,
🧰 Tools
🪛 Biome (1.9.4)

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

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

(lint/complexity/noUselessTernary)


85-85: 🧹 Nitpick (assertive)

Simplify boolean expression

The ternary AttendanceData ? true : false is redundant. Utilize the direct truthiness of AttendanceData.

Apply this diff:

-      enabled: ((AttendanceData ? true : false) && disabledAction && data?.[0]?.musterRollStatus !== "APPROVED") || triggerEstimate,
+      enabled: (AttendanceData && disabledAction && data?.[0]?.musterRollStatus !== "APPROVED") || triggerEstimate,
🧰 Tools
🪛 Biome (1.9.4)

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

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

(lint/complexity/noUselessTernary)


104-104: 🧹 Nitpick (assertive)

Simplify boolean expression

Remove the unnecessary ternary and use AttendanceData directly.

Apply this diff:

-      enabled: (AttendanceData ? true : false) && !disabledAction,
+      enabled: AttendanceData && !disabledAction,
🧰 Tools
🪛 Biome (1.9.4)

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

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

(lint/complexity/noUselessTernary)


279-279: 🧹 Nitpick (assertive)

Simplify boolean expression

There's no need for the ternary operator here. Use the truthiness of individualIds.length.

Apply this diff:

-      enabled: individualIds.length > 0 ? true : false,
+      enabled: individualIds.length > 0,
🧰 Tools
🪛 Biome (1.9.4)

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

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

(lint/complexity/noUselessTernary)


304-306: 🧹 Nitpick (assertive)

Simplify boolean expression

Simplify the conditional by using the direct truthiness of the expression.

Apply this diff:

-      enabled: AttendanceData?.attendanceRegister[0]?.staff?.find(
-        (staff) => staff?.staffType?.includes("OWNER")
-      )?.userId ? true : false,
+      enabled: !!AttendanceData?.attendanceRegister[0]?.staff?.find(
+        (staff) => staff?.staffType?.includes("OWNER")
+      )?.userId,
🧰 Tools
🪛 Biome (1.9.4)

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

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

(lint/complexity/noUselessTernary)


453-463: ⚠️ Potential issue

Add a unique key prop to elements in actionFields

When rendering elements conditionally within an array (actionFields), each element should have a unique key prop to help React identify which items have changed.

Apply this diff to add key props:

 disabledAction ? (
+  <Button
+    key="goBackButton"
     label={t(`HCM_AM_GO_BACK`)}
     ...
   />
 ) : editAttendance ? (
+  <Button
+    key="submitButton"
     ...
   />
 ) : (
+  <Button
+    key="actionsButton"
     ...
   />
 ),

Also applies to: 465-477, 479-508

🧰 Tools
🪛 Biome (1.9.4)

[error] 453-463: 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)


366-368: 🧹 Nitpick (assertive)

Handle loading states consistently

While loading states are managed, consider displaying error messages or fallback UI to enhance the user experience during data fetch failures.


18-23: 🧹 Nitpick (assertive)

Consider grouping related state variables

You have several related state variables declared separately. Grouping them into a single state object or using a custom hook can improve code readability and maintainability.

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

13-13: 🧹 Nitpick (assertive)

Use template literals instead of string concatenation

To enhance readability and follow modern JavaScript best practices, replace string concatenation with template literals in lines 13 and 47.

Apply these changes:

// Line 13
-link.download = fileName + ".xlsx";
+link.download = `${fileName}.xlsx`;

// Line 47
-link.download = fileName + ".pdf";
+link.download = `${fileName}.pdf`;

Also applies to: 47-47

🧰 Tools
🪛 Biome (1.9.4)

[error] 13-13: Template literals are preferred over string concatenation.

Unsafe fix: Use a template literal.

(lint/style/useTemplate)


134-163: ⚠️ Potential issue

Add key props to JSX elements in the rows array

Each JSX element in an array should have a unique key prop to help React identify which items have changed or been updated. This prevents potential rendering issues.

Apply these changes:

// In the Button component
reportDetails?.status === "COMPLETED" ? (
    <Button
+       key={`download-button-${index}`}
        className="custom-class"
        ...
    />
) : (
    <InfoButton
+       key={`info-button-${index}`}
        className="dm-workbench-download-template-btn"
        ...
    />
);
🧰 Tools
🪛 Biome (1.9.4)

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

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

(lint/complexity/noUselessTernary)


[error] 134-163: 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)


9-75: 🧹 Nitpick (assertive)

Refactor duplicated download functions into a single utility

The downloadExcelWithName and downloadPDFWithName functions share similar logic. Refactoring them into a single function with parameters for file type and MIME types will reduce code duplication and enhance maintainability.

Example refactored function:

export const downloadFileWithName = ({ fileStoreId = null, customName = null, fileType = "xlsx", mimeType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" }) => {
    const downloadFile = (blob, fileName) => {
        const link = document.createElement("a");
        link.href = URL.createObjectURL(blob);
        link.download = `${fileName}.${fileType}`;
        document.body.append(link);
        link.click();
        link.remove();
        setTimeout(() => URL.revokeObjectURL(link.href), 7000);
    };

    if (fileStoreId) {
        axios
            .get("/filestore/v1/files/id", {
                responseType: "arraybuffer",
                headers: {
                    "Content-Type": mimeType,
                    Accept: mimeType,
                    "auth-token": Digit.UserService.getUser()?.["access_token"],
                },
                params: {
                    tenantId: Digit.ULBService.getCurrentTenantId(),
                    fileStoreId: fileStoreId,
                },
            })
            .then(async (res) => {
                downloadFile(new Blob([res.data], { type: mimeType }), customName ? customName : "download");
            })
            .catch((error) => {
                console.error(`Error downloading the ${fileType.toUpperCase()} file:`, error);
                // Handle error appropriately, possibly with a toast notification
            });
    }
};

Then replace the original functions with calls to downloadFileWithName:

export const downloadExcelWithName = (params) => {
    downloadFileWithName({ ...params, fileType: "xlsx", mimeType: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" });
};

export const downloadPDFWithName = (params) => {
    downloadFileWithName({ ...params, fileType: "pdf", mimeType: "application/pdf" });
};
🧰 Tools
🪛 Biome (1.9.4)

[error] 13-13: Template literals are preferred over string concatenation.

Unsafe fix: Use a template literal.

(lint/style/useTemplate)


[error] 47-47: Template literals are preferred over string concatenation.

Unsafe fix: Use a template literal.

(lint/style/useTemplate)

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

38-38: 🧹 Nitpick (assertive)

Use self-closing tag for <TextBlock>

Since <TextBlock> has no children, it can be converted to a self-closing tag for cleaner code.

Apply this change:

-<TextBlock body={`${t("HCM_AM_BILL_ID")}`}></TextBlock>
+<TextBlock body={`${t("HCM_AM_BILL_ID")}`} />
🧰 Tools
🪛 Biome (1.9.4)

[error] 38-38: JSX elements without children should be marked as self-closing. In JSX, it is valid for any element to be self-closing.

Unsafe fix: Use a SelfClosingElement instead

(lint/style/useSelfClosingElements)


62-63: ⚠️ Potential issue

Add key props to elements in buttonsArray

Each element in the buttonsArray should have a unique key prop to prevent rendering issues in React when elements are added or removed.

Apply these changes:

buttonsArray={[
+    <Button key="clear-button" variation="teritiary" label={t(`HCM_AM_CLEAR`)} type="button" onClick={handleClear} size="large" />,
+    <Button key="search-button" variation="primary" label={t(`HCM_AM_SEARCH`)} type="button" onClick={handleSearch} size="large" />,
]}
🧰 Tools
🪛 Biome (1.9.4)

[error] 62-62: 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] 63-63: 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/my_bills.js (3)

37-37: 🧹 Nitpick (assertive)

Simplify boolean expression in config.enabled

The expression enabled: project ? true : false can be simplified to enabled: Boolean(project) for clarity and readability.

Apply this change:

-enabled: project ? true : false,
+enabled: Boolean(project),
🧰 Tools
🪛 Biome (1.9.4)

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

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

(lint/complexity/noUselessTernary)


79-84: 🧹 Nitpick (assertive)

Avoid hardcoded fallback values for reportDetails

Using hardcoded values for reportDetails may lead to inconsistent or inaccurate data. Consider handling the absence of reportDetails by providing a default object or handling it gracefully in the UI.

Apply this change:

// Before
const reportDetails = individualEntry?.additionalDetails?.reportDetails || {
    "status": "FAILED",
    "pdfReportId": "d5a504fb-ebb8-41be-afa0-24b4f1bd575b",
    "excelReportId": "de5f2b24-b60d-4d1f-b550-56abe1dabb2f",
    "errorMessage": "error message if status is failed"
};

// Suggested
const reportDetails = individualEntry?.additionalDetails?.reportDetails || defaultReportDetails;

Define defaultReportDetails in a constants file or at the top of the module:

const defaultReportDetails = {
    status: "PENDING",
    pdfReportId: "",
    excelReportId: "",
    errorMessage: ""
};

16-20: 🧹 Nitpick (assertive)

Consider using null for uninitialized date values

Using empty strings for date values may lead to type inconsistencies. Using null for uninitialized dates can make the state clearer and reduce potential errors when processing the dates.

Apply these changes:

const [dateRange, setDateRange] = useState({
-    startDate: '',
-    endDate: '',
+    startDate: null,
+    endDate: null,
    title: '',
});
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/sample.js (8)

6-6: ⚠️ Potential issue

Correct the spelling of 'updateSeeeionStorage'.

The prop updateSeeeionStorage appears to be misspelled. Please correct it to updateSessionStorage to ensure consistency and prevent potential errors.

Apply this diff to fix the spelling:

-const BoundaryComponent = ({ reset, makeReset, initialValue, updateSeeeionStorage, selectedProject, onChange, lowestLevel, isRequired }) => {
+const BoundaryComponent = ({ reset, makeReset, initialValue, updateSessionStorage, selectedProject, onChange, lowestLevel, isRequired }) => {

7-7: 🧹 Nitpick (assertive)

Rename 'kk' to improve code readability.

The variable kk is not descriptive. Consider renaming it to boundaryHierarchyCodes for better clarity and maintainability.

Apply this diff to rename the variable:

-  const kk = Digit.SessionStorage.get("boundaryHierarchyOrder").map((item) => item.code);
+  const boundaryHierarchyCodes = Digit.SessionStorage.get("boundaryHierarchyOrder").map((item) => item.code);

Remember to update all references to kk throughout the code.


32-33: 🧹 Nitpick (assertive)

Clarify the usage of 'lowest' versus 'lowestLevel'.

Both lowest and lowestLevel seem to represent similar concepts. Consider consolidating them or renaming one to avoid confusion and improve code clarity.


34-47: 🧹 Nitpick (assertive)

Remove commented-out code to clean up the codebase.

The commented-out code block from lines 34 to 47 is no longer needed and can be removed to improve code readability and maintainability.


88-104: 🧹 Nitpick (assertive)

Remove unnecessary commented-out code.

The commented-out code between lines 88 and 104 may clutter the codebase. If it's not required, please remove it to keep the code clean.


105-116: ⚠️ Potential issue

Add null checks before accessing nested properties.

In the useEffect hook, accessing childrenData[0]?.boundary[0].boundaryType without verifying that childrenData[0]?.boundary exists and has elements could lead to runtime errors. Please add appropriate null checks to ensure the code is safe.

For example:

      useEffect(() => {
        if (childrenData && childrenData.length > 0 && childrenData[0]?.boundary && childrenData[0].boundary.length > 0) {
          setValue((prevState) => ({
            ...prevState,
            [childrenData[0]?.boundary[0].boundaryType]: [childrenData[0]?.boundary[0]],
          }));

          const formattedData = createFormattedData(childrenData[0]?.boundary[0].boundaryType);
          setBoundaryData(formattedData);
        }
      }, [childrenData]);

156-158: ⚠️ Potential issue

Correct the spelling of 'updateSeeeionStorage' in the state update.

The function updateSeeeionStorage is misspelled here. Please correct it to updateSessionStorage for consistency.

Apply this diff:

        if (updateSeeeionStorage) {
-          updateSeeeionStorage(newSelectedValues);
+          updateSessionStorage(newSelectedValues);
        }

216-216: 🧹 Nitpick (assertive)

Simplify the boolean expression in 'isRequired' prop.

The ternary operator can be simplified for better readability.

Apply this diff:

-                    isRequired={isRequired == ScreenTypeEnum.BILL ? true : key == "DISTRICT" ? true : false}
+                    isRequired={isRequired === ScreenTypeEnum.BILL || key === "DISTRICT"}

This simplifies the expression by directly using logical operators.

🧰 Tools
🪛 Biome (1.9.4)

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

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

(lint/complexity/noUselessTernary)

health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/bill_inbox/bill_boundary_filter.js (6)

34-41: ⚠️ Potential issue

Include 'updateBoundaryFilters' in the dependency array of 'useEffect'.

The useEffect hook uses updateBoundaryFilters but does not include it in the dependency array. This could lead to unexpected behavior if updateBoundaryFilters changes without triggering the effect. Please include it in the dependency array.

Apply this diff:

        useEffect(() => {

            if (updateBoundaryFilters) {
                setResetFilters(true);
                setBoundary("");
            }

-        }, [levelSelected]);
+        }, [levelSelected, updateBoundaryFilters]);

68-78: 🛠️ Refactor suggestion

Add keyboard event handlers for accessibility.

The <div> element with an onClick handler should support keyboard interactions to improve accessibility. Please add appropriate keyboard event handlers like onKeyPress and set a tabIndex.

For example:

      <div
+       tabIndex="0"
        onClick={handleClearFilter}
+       onKeyPress={(e) => { if (e.key === 'Enter') handleClearFilter(); }}
        style={{
          cursor: "pointer",
          alignItems: "center",
          gap: ".75rem",
          marginBottom: "24px",
          display: "flex",
          flexDirection: "row",
          justifyContent: "space-between",
        }}
      >
🧰 Tools
🪛 Biome (1.9.4)

[error] 68-78: 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)


84-90: 🛠️ Refactor suggestion

Provide alternative text for SVG icons for accessibility.

The <svg> element lacks alternative text, which is important for users relying on screen readers. Please add a <title> element or aria-label attribute to describe the icon.

For example:

    <svg width="17" height="17" viewBox="0 0 16 22" fill="none" xmlns="http://www.w3.org/2000/svg" 
+     role="img" aria-label={t('Refresh')}>
+     <title>{t('Refresh')}</title>
🧰 Tools
🪛 Biome (1.9.4)

[error] 84-84: 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)


92-103: 🧹 Nitpick (assertive)

Remove commented-out code to clean up the codebase.

The commented code between lines 92 and 103 is unnecessary and can be removed to improve code readability.


105-120: 🧹 Nitpick (assertive)

Self-close <BoundaryComponent> since it has no children.

The <BoundaryComponent> does not contain any child elements and can be self-closed to simplify the JSX.

Apply this diff:

      <BoundaryComponent
        key={boundaryKey}
        isRequired={isRequired}
        reset={resetFilters}
        makeReset={() => {
          setResetFilters(false);
        }}
        initialValue={sessionStorage.getItem("selectedValues")}
        updateSeeeionStorage={(newSelectedValues) => {
          sessionStorage.setItem("selectedValues", JSON.stringify(newSelectedValues));
        }}
        onChange={onBoundaryChange}
        selectedProject={selectedProject}
        lowestLevel={selectedLevel.code}
-      >
-      </BoundaryComponent>
+      />

112-115: ⚠️ Potential issue

Correct the spelling of 'updateSeeeionStorage'.

The prop updateSeeeionStorage is misspelled. Please correct it to updateSessionStorage to prevent potential errors and improve code readability.

Apply this diff:

      updateSeeeionStorage={(newSelectedValues) => {
        sessionStorage.setItem("selectedValues", JSON.stringify(newSelectedValues));
      }}

Updated:

+     updateSessionStorage={(newSelectedValues) => {
+       sessionStorage.setItem("selectedValues", JSON.stringify(newSelectedValues));
+     }}
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 0c80699 and 54fe437.

📒 Files selected for processing (9)
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/MyBillsSearch.js (1 hunks)
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/MyBillsTable.js (1 hunks)
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/bill_inbox/BillInbox.js (1 hunks)
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/bill_inbox/bill_boundary_filter.js (1 hunks)
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/custom_inbox_composer.js (1 hunks)
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/sample.js (1 hunks)
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/pages/employee/ViewAttendance.js (2 hunks)
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/pages/employee/index.js (1 hunks)
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/pages/employee/my_bills.js (1 hunks)
🧰 Additional context used
📓 Path-based instructions (9)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/pages/employee/my_bills.js (1)

Pattern **/*.js: check

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

Pattern **/*.js: check

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

Pattern **/*.js: check

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

Pattern **/*.js: check

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

Pattern **/*.js: check

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

Pattern **/*.js: check

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

Pattern **/*.js: check

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

Pattern **/*.js: check

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

Pattern **/*.js: check

🪛 Biome (1.9.4)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/pages/employee/my_bills.js

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

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

(lint/complexity/noUselessTernary)

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

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

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

(lint/complexity/noUselessTernary)


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

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

(lint/complexity/noUselessTernary)


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

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

(lint/complexity/noUselessTernary)


[error] 186-194: JSX elements without children should be marked as self-closing. In JSX, it is valid for any element to be self-closing.

Unsafe fix: Use a SelfClosingElement instead

(lint/style/useSelfClosingElements)


[error] 197-198: JSX elements without children should be marked as self-closing. In JSX, it is valid for any element to be self-closing.

Unsafe fix: Use a SelfClosingElement instead

(lint/style/useSelfClosingElements)


[error] 211-217: JSX elements without children should be marked as self-closing. In JSX, it is valid for any element to be self-closing.

Unsafe fix: Use a SelfClosingElement instead

(lint/style/useSelfClosingElements)


[error] 254-263: JSX elements without children should be marked as self-closing. In JSX, it is valid for any element to be self-closing.

Unsafe fix: Use a SelfClosingElement instead

(lint/style/useSelfClosingElements)


[error] 273-285: 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] 296-312: 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/components/sample.js

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

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

(lint/complexity/noUselessTernary)

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

[error] 225-225: JSX elements without children should be marked as self-closing. In JSX, it is valid for any element to be self-closing.

Unsafe fix: Use a SelfClosingElement instead

(lint/style/useSelfClosingElements)


[error] 240-246: JSX elements without children should be marked as self-closing. In JSX, it is valid for any element to be self-closing.

Unsafe fix: Use a SelfClosingElement instead

(lint/style/useSelfClosingElements)


[error] 253-253: JSX elements without children should be marked as self-closing. In JSX, it is valid for any element to be self-closing.

Unsafe fix: Use a SelfClosingElement instead

(lint/style/useSelfClosingElements)


[error] 255-264: JSX elements without children should be marked as self-closing. In JSX, it is valid for any element to be self-closing.

Unsafe fix: Use a SelfClosingElement instead

(lint/style/useSelfClosingElements)

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

[error] 38-38: JSX elements without children should be marked as self-closing. In JSX, it is valid for any element to be self-closing.

Unsafe fix: Use a SelfClosingElement instead

(lint/style/useSelfClosingElements)


[error] 60-65: JSX elements without children should be marked as self-closing. In JSX, it is valid for any element to be self-closing.

Unsafe fix: Use a SelfClosingElement instead

(lint/style/useSelfClosingElements)


[error] 62-62: 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] 63-63: 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/components/MyBillsTable.js

[error] 13-13: Template literals are preferred over string concatenation.

Unsafe fix: Use a template literal.

(lint/style/useTemplate)


[error] 47-47: Template literals are preferred over string concatenation.

Unsafe fix: Use a template literal.

(lint/style/useTemplate)


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

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

(lint/complexity/noUselessTernary)


[error] 134-163: 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] 164-179: 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/components/bill_inbox/bill_boundary_filter.js

[error] 68-78: 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] 83-83: 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] 84-84: 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)

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

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

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

(lint/complexity/noUselessTernary)


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

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

(lint/complexity/noUselessTernary)


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

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

(lint/complexity/noUselessTernary)


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

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

(lint/complexity/noUselessTernary)


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

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

(lint/complexity/noUselessTernary)


[error] 453-463: 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] 465-477: 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] 479-508: 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)

🔇 Additional comments (17)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/custom_inbox_composer.js (1)

1-1: Remove unused and invalid import.

The use import from React is invalid and unused.

-import React, { useEffect, useReducer, useState, useMemo, use } from "react";
+import React, { useEffect, useReducer, useState, useMemo } from "react";
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/bill_inbox/BillInbox.js (15)

1-1: Remove unused and invalid imports

The imports useReducer, useMemo, and use are not used in this file. Additionally, use is not a valid React hook and may have been included by mistake. Please remove these to clean up the code.


5-5: Define location or use useLocation hook

The variable location is used but not defined in this scope. If you intend to access the browser's location or the route's state, consider importing useLocation from react-router-dom and using it to retrieve the location object.


23-23: Remove commented-out code

The commented-out line is unnecessary and can be removed to keep the code clean.


44-44: Use strict equality and optional chaining

Consider using === instead of == for strict equality comparison. Also, apply optional chaining to prevent potential runtime errors if the stored object is missing.


51-51: Simplify the boolean expression

Instead of using a ternary operator returning true/false, you can directly use the expression's truthiness.

🧰 Tools
🪛 Biome (1.9.4)

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

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

(lint/complexity/noUselessTernary)


186-194: Use a self-closing tag for <CustomInboxSearchLinks>

When a JSX element has no child content, prefer using a self-closing tag.

🧰 Tools
🪛 Biome (1.9.4)

[error] 186-194: JSX elements without children should be marked as self-closing. In JSX, it is valid for any element to be self-closing.

Unsafe fix: Use a SelfClosingElement instead

(lint/style/useSelfClosingElements)


197-198: Use a self-closing tag for <BillSearchBox>

JSX elements without child content should be self-closing.

🧰 Tools
🪛 Biome (1.9.4)

[error] 197-198: JSX elements without children should be marked as self-closing. In JSX, it is valid for any element to be self-closing.

Unsafe fix: Use a SelfClosingElement instead

(lint/style/useSelfClosingElements)


68-68: 🧹 Nitpick (assertive)

Simplify the boolean expression

The ternary operator can be simplified by directly using the truthiness of selectedBoundaryCode.

- enabled: selectedBoundaryCode ? true : false,
+ enabled: !!selectedBoundaryCode,

Likely invalid or redundant comment.

🧰 Tools
🪛 Biome (1.9.4)

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

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

(lint/complexity/noUselessTernary)


326-326: 🧹 Nitpick (assertive)

Commented-out prop in <Toast> component

The error prop in the <Toast> component is commented out. If it's no longer needed, consider removing it to clean up the code.

<Toast
  style={{ zIndex: 10001 }}
  label={showToast.label}
  type={showToast.key}
- // error={showToast.key === "error"}
  transitionTime={showToast.transitionTime}
  onClose={() => setShowToast(null)}
/>

Likely invalid or redundant comment.


48-48: 🧹 Nitpick (assertive)

Simplify the boolean expression

Instead of using a ternary operator returning true/false, you can directly use the expression's truthiness.

- isChildrenRequired: selectedLevel != null && selectedLevel?.code === "DISTRICT" ? true : false,
+ isChildrenRequired: selectedLevel != null && selectedLevel?.code === "DISTRICT",

Likely invalid or redundant comment.

🧰 Tools
🪛 Biome (1.9.4)

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

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

(lint/complexity/noUselessTernary)


300-303: ⚠️ Potential issue

Correct the logical condition in the onClick handler

The condition BillData?.bills?.length >= 0 will always evaluate to true because array lengths are always 0 or greater. This means triggerGenerateBill() may never be called as intended.

Consider revising the condition:

- !showGenerateBillAction || BillData?.bills?.length >= 0 ?
+ (!showGenerateBillAction || BillData?.bills?.length > 0) ?

This change ensures that triggerGenerateBill() is called when there are no bills and showGenerateBillAction is true.

Likely invalid or redundant comment.


273-285: 🧹 Nitpick (assertive)

Add a key prop to the Button component

When rendering elements in an array, each element should have a unique key prop to help React identify which items have changed.

<ActionBar
  actionFields={[
-   <Button
+   <Button
+     key="generate-bill-button"
      icon="CheckCircle"
      label={t(`HCM_AM_GENERATE_BILL_LABEL`)}
      onClick={() => {
        triggerGenerateBill();
      }}
      style={{
        minWidth: "14rem",
      }}
      type="button"
      variation="primary"
      isDisabled={generateBillMutation.isLoading}
    />,
  ]}
  ...
/>

Likely invalid or redundant comment.

🧰 Tools
🪛 Biome (1.9.4)

[error] 273-285: 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)


211-217: 🧹 Nitpick (assertive)

Use a self-closing tag for <BillBoundaryFilter>

Since <BillBoundaryFilter> has no children, it should be self-closing.

- <BillBoundaryFilter
-   isRequired={ScreenTypeEnum.BILL}
-   selectedProject={selectedProject}
-   selectedLevel={selectedLevel}
-   onFilterChange={handleFilterUpdate}
-   updateBoundaryFilters={updateFilters}
- ></BillBoundaryFilter>
+ <BillBoundaryFilter
+   isRequired={ScreenTypeEnum.BILL}
+   selectedProject={selectedProject}
+   selectedLevel={selectedLevel}
+   onFilterChange={handleFilterUpdate}
+   updateBoundaryFilters={updateFilters}
+ />

Likely invalid or redundant comment.

🧰 Tools
🪛 Biome (1.9.4)

[error] 211-217: JSX elements without children should be marked as self-closing. In JSX, it is valid for any element to be self-closing.

Unsafe fix: Use a SelfClosingElement instead

(lint/style/useSelfClosingElements)


254-263: 🧹 Nitpick (assertive)

Use a self-closing tag for <BillInboxTable>

JSX elements without children can be self-closed to improve readability.

- <BillInboxTable
-   isFetching={isFetching}
-   tableData={tableData}
-   currentPage={currentPage}
-   rowsPerPage={rowsPerPage}
-   handlePageChange={handlePageChange}
-   handlePerRowsChange={handlePerRowsChange}
-   totalCount={totalCount}
-   status={activeLink.code}
- ></BillInboxTable>
+ <BillInboxTable
+   isFetching={isFetching}
+   tableData={tableData}
+   currentPage={currentPage}
+   rowsPerPage={rowsPerPage}
+   handlePageChange={handlePageChange}
+   handlePerRowsChange={handlePerRowsChange}
+   totalCount={totalCount}
+   status={activeLink.code}
+ />

Likely invalid or redundant comment.

🧰 Tools
🪛 Biome (1.9.4)

[error] 254-263: JSX elements without children should be marked as self-closing. In JSX, it is valid for any element to be self-closing.

Unsafe fix: Use a SelfClosingElement instead

(lint/style/useSelfClosingElements)


296-312: 🧹 Nitpick (assertive)

Add a key prop to the Button component

Ensure that the Button component inside the array has a unique key prop.

<ActionBar
  actionFields={[
-   <Button
+   <Button
+     key="generate-bill-button"
      icon="CheckCircle"
      label={t(`HCM_AM_GENERATE_BILL_LABEL`)}
      onClick={() => {
        !showGenerateBillAction || BillData?.bills?.length >= 0
          ? setShowToast({ key: "info", label: t("HCM_AM_GENERATE_BILLS_CANNOT_BE_CALLED_INFO_MESSAGE"), transitionTime: 3000 })
          : triggerGenerateBill();
      }}
      style={{
        minWidth: "14rem",
        cursor: !showGenerateBillAction || BillData?.bills?.length >= 0 ? "not-allowed" : "pointer",
        opacity: !showGenerateBillAction || BillData?.bills?.length >= 0 ? 0.5 : 1,
      }}
      type="button"
      variation="primary"
      isDisabled={generateBillMutation.isLoading}
    />,
  ]}
  ...
/>

Likely invalid or redundant comment.

🧰 Tools
🪛 Biome (1.9.4)

[error] 296-312: 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/components/MyBillsSearch.js (1)

54-55: Verify epochStartDate and epochEndDate in DateRangePicker

The epochStartDate and epochEndDate are both set to the current timestamp, which may restrict the date range to a single moment. Ensure these values are set appropriately to allow users to select the desired date range.

Comment on lines +13 to +40
/**
* Business Flow Description:
* 1. In the search section, a project select dropdown is provided.
* - When a project is selected from the dropdown, the Boundary Search Service is invoked to fetch the boundary hierarchy.
* 2. On successful fetching of the boundary hierarchy from the service:
* - A dynamic list of boundary selection dropdowns is rendered in the filter section.
* 3. When filters are applied:
* - The Attendance Register Search API is called with the applied filter criteria.
* - On receiving a successful response, the table data is rendered accordingly.
* 4. Tab Functionality:
* - Tabs are implemented in the UI for additional functionality.
* - Based on the tab selection, the Attendance Register Search API is triggered with a custom payload specific to the selected tab.

*/

/**
* Reason for not using React Component - InboxComposer:
* 1. Restrictions in InboxComposer:
* - The component requires showing "No Results" initially, which does not align with our requirement.
* - Search should only be triggered after filters are applied.
* 2. Dynamic Boundary Filters:
* - The boundary filter options need to be dynamically determined based on the selected project.
* 3. Tab-Specific API Calls:
* - On tab selection, the same Attendance Register Search API must be called with different status filters,
* which is not inherently supported by the InboxComposer component.


*/
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)

Enhance JSDoc documentation with parameter and return type information.

While the business flow documentation is comprehensive, consider adding:

  • @param tags for component props
  • @returns tag describing the rendered output

Comment on lines +186 to +210
const handlePaginationChange = (page) => {
setCurrentPage(page);

triggerMusterRollApprove(filterCriteria, selectedStatus, rowsPerPage, page);
};
const handleRowsPerPageChange = (newPerPage, page) => {
setRowsPerPage(newPerPage); // Update the rows per page state
setCurrentPage(page); // Optionally reset the current page or maintain it
// refetchPlanEmployee();
// handleCreateRateAnalysis();
triggerMusterRollApprove(filterCriteria, selectedStatus, newPerPage, page);
};
const callServiceOnTap = (status) => {
if (status.code == StatusEnum.PENDING_FOR_APPROVAL) {
setRowsPerPage(5); // Update the rows per page state
setCurrentPage(1);
setSelectedStatus(StatusEnum.PENDING_FOR_APPROVAL);
triggerMusterRollApprove(Digit.SessionStorage.get("paymentInbox"), StatusEnum.PENDING_FOR_APPROVAL, 5, 1);
} else {
setRowsPerPage(5); // Update the rows per page state
setCurrentPage(1);
setSelectedStatus(StatusEnum.APPROVED);
triggerMusterRollApprove(Digit.SessionStorage.get("paymentInbox"), StatusEnum.APPROVED, 5, 1);
}
};
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)

Optimize event handlers and remove commented code.

  1. Add debouncing to pagination and row change handlers
  2. Remove commented out code (refetchPlanEmployee, handleCreateRateAnalysis)
  3. Extract duplicate validation logic
+const debouncedTriggerMusterRoll = _.debounce(triggerMusterRollApprove, 300);

 const handlePaginationChange = (page) => {
   setCurrentPage(page);
-  triggerMusterRollApprove(filterCriteria, selectedStatus, rowsPerPage, page);
+  debouncedTriggerMusterRoll(filterCriteria, selectedStatus, rowsPerPage, page);
 };

 const handleRowsPerPageChange = (newPerPage, page) => {
   setRowsPerPage(newPerPage);
   setCurrentPage(page);
-  // refetchPlanEmployee();
-  // handleCreateRateAnalysis();
-  triggerMusterRollApprove(filterCriteria, selectedStatus, newPerPage, page);
+  debouncedTriggerMusterRoll(filterCriteria, selectedStatus, newPerPage, page);
 };

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

Comment on lines +44 to +56
const [showToast, setShowToast] = useState(null);
const [filterCriteria, setFilterCriteria] = useState(null);
const [selectedProject, setSelectedProject] = useState({});
//-------//

const [currentPage, setCurrentPage] = useState(1);
const [rowsPerPage, setRowsPerPage] = useState(5);
const [selectedStatus, setSelectedStatus] = useState(StatusEnum.PENDING_FOR_APPROVAL);

const [card, setCard] = useState(false);

const [childrenDataLoading, setChildrenDataLoading] = useState(false);
const [childrenData, setchildrenData] = 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)

Consider consolidating related state variables.

Multiple state variables (filterCriteria, selectedProject, currentPage, rowsPerPage, selectedStatus) could be combined into a single state object for better state management.

-const [filterCriteria, setFilterCriteria] = useState(null);
-const [selectedProject, setSelectedProject] = useState({});
-const [currentPage, setCurrentPage] = useState(1);
-const [rowsPerPage, setRowsPerPage] = useState(5);
-const [selectedStatus, setSelectedStatus] = useState(StatusEnum.PENDING_FOR_APPROVAL);
+const [state, setState] = useState({
+  filterCriteria: null,
+  selectedProject: {},
+  currentPage: 1,
+  rowsPerPage: 5,
+  selectedStatus: StatusEnum.PENDING_FOR_APPROVAL
+});

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

Comment on lines 62 to 115
const triggerMusterRollApprove = (filterData, status, totalRows, totalNext, selectedProject) => {
try {
setChildrenDataLoading(true);
fetchRegisters.mutateAsync(
{
params: {
tenantId: Digit.ULBService.getStateId(),
limit: 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,
reviewStatus: status == undefined ? selectedStatus : status,
},
},
{
onSuccess: (data) => {
const rowData =
data?.attendanceRegister.length > 0
? data?.attendanceRegister?.map((item, index) => {
return {
id: item?.registerNumber,
//name: item?.name,
name: selectedProject?.name,
boundary: item?.localityCode,
status: item?.attendees == null ? 0 : item?.attendees.length || 0,
markby: item?.staff?.[0].additionalDetails?.staffName || "",
};
})
: [];
setChildrenDataLoading(false);
setCard(true);
setchildrenData({
data: rowData,
totalCount: data?.totalCount,
statusCount: data?.statusCount,
});
},
onError: (error) => {
setCard(true);
setChildrenDataLoading(false);
setShowToast({ key: "error", label: t("HCM_AM_ATTENDANCE_REGISTER_FETCH_FAILED"), transitionTime: 3000 });
},
}
);
} catch (error) {
/// will show estimate data only
}
};
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

Improve error handling and data transformation.

The triggerMusterRollApprove function needs improvements:

  1. Extract data transformation logic to a separate function
  2. Add proper error handling for the catch block
  3. Consider adding retry logic for API failures
+const transformAttendanceData = (data, selectedProject) => 
+  data?.attendanceRegister?.map((item) => ({
+    id: item?.registerNumber,
+    name: selectedProject?.name,
+    boundary: item?.localityCode,
+    status: item?.attendees?.length || 0,
+    markby: item?.staff?.[0]?.additionalDetails?.staffName || "",
+  })) || [];

 const triggerMusterRollApprove = (filterData, status, totalRows, totalNext, selectedProject) => {
   try {
     // ... existing code ...
     onSuccess: (data) => {
-      const rowData = data?.attendanceRegister.length > 0
-        ? data?.attendanceRegister?.map((item, index) => {
-          return {
-            id: item?.registerNumber,
-            name: selectedProject?.name,
-            boundary: item?.localityCode,
-            status: item?.attendees == null ? 0 : item?.attendees.length || 0,
-            markby: item?.staff?.[0].additionalDetails?.staffName || "",
-          };
-        })
-        : [];
+      const rowData = transformAttendanceData(data, selectedProject);
       // ... rest of the code ...
     }
   } catch (error) {
-    /// will show estimate data only
+    console.error('Failed to fetch attendance data:', error);
+    setShowToast({ 
+      key: "error", 
+      label: t("HCM_AM_ATTENDANCE_FETCH_ERROR"), 
+      transitionTime: 3000 
+    });
   }
 };
📝 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 triggerMusterRollApprove = (filterData, status, totalRows, totalNext, selectedProject) => {
try {
setChildrenDataLoading(true);
fetchRegisters.mutateAsync(
{
params: {
tenantId: Digit.ULBService.getStateId(),
limit: 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,
reviewStatus: status == undefined ? selectedStatus : status,
},
},
{
onSuccess: (data) => {
const rowData =
data?.attendanceRegister.length > 0
? data?.attendanceRegister?.map((item, index) => {
return {
id: item?.registerNumber,
//name: item?.name,
name: selectedProject?.name,
boundary: item?.localityCode,
status: item?.attendees == null ? 0 : item?.attendees.length || 0,
markby: item?.staff?.[0].additionalDetails?.staffName || "",
};
})
: [];
setChildrenDataLoading(false);
setCard(true);
setchildrenData({
data: rowData,
totalCount: data?.totalCount,
statusCount: data?.statusCount,
});
},
onError: (error) => {
setCard(true);
setChildrenDataLoading(false);
setShowToast({ key: "error", label: t("HCM_AM_ATTENDANCE_REGISTER_FETCH_FAILED"), transitionTime: 3000 });
},
}
);
} catch (error) {
/// will show estimate data only
}
};
const transformAttendanceData = (data, selectedProject) =>
data?.attendanceRegister?.map((item) => ({
id: item?.registerNumber,
name: selectedProject?.name,
boundary: item?.localityCode,
status: item?.attendees?.length || 0,
markby: item?.staff?.[0]?.additionalDetails?.staffName || "",
})) || [];
const triggerMusterRollApprove = (filterData, status, totalRows, totalNext, selectedProject) => {
try {
setChildrenDataLoading(true);
fetchRegisters.mutateAsync(
{
params: {
tenantId: Digit.ULBService.getStateId(),
limit: 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,
reviewStatus: status == undefined ? selectedStatus : status,
},
},
{
onSuccess: (data) => {
const rowData = transformAttendanceData(data, selectedProject);
setChildrenDataLoading(false);
setCard(true);
setchildrenData({
data: rowData,
totalCount: data?.totalCount,
statusCount: data?.statusCount,
});
},
onError: (error) => {
setCard(true);
setChildrenDataLoading(false);
setShowToast({ key: "error", label: t("HCM_AM_ATTENDANCE_REGISTER_FETCH_FAILED"), transitionTime: 3000 });
},
}
);
} catch (error) {
console.error('Failed to fetch attendance data:', error);
setShowToast({
key: "error",
label: t("HCM_AM_ATTENDANCE_FETCH_ERROR"),
transitionTime: 3000
});
}
};

Comment on lines 128 to 146
// useEffect(() => {
// const handlePopState = () => {
// sessionStorage.removeItem("Digit.paymentInbox");
// sessionStorage.removeItem("selectedValues");
// };

// const handleBeforeUnload = () => {
// sessionStorage.removeItem("Digit.paymentInbox");
// sessionStorage.removeItem("selectedValues");
// };

// window.addEventListener("popstate", handlePopState);
// window.addEventListener("beforeunload", handleBeforeUnload);

// return () => {
// window.removeEventListener("popstate", handlePopState);
// window.removeEventListener("beforeunload", handleBeforeUnload);
// };
// }, []);
Copy link
Contributor

Choose a reason for hiding this comment

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

💡 Codebase verification

Uncomment and implement the session cleanup logic

The cleanup logic in this component handles important scenarios not covered elsewhere:

  • Prevents stale data during browser navigation (back/forward)
  • Ensures cleanup when leaving the page

While other files handle session cleanup for specific actions, this implementation is necessary for proper session management during navigation events.

🔗 Analysis chain

Uncomment and implement session cleanup logic.

The commented out cleanup logic is important for preventing stale session data. Consider implementing this with a custom hook for better reusability.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check if session cleanup is implemented elsewhere
rg -l "sessionStorage.removeItem.*paymentInbox" --type js

Length of output: 371


Script:

#!/bin/bash
# Check implementations of session cleanup in all files
echo "=== PaymentsCard.js ==="
rg "sessionStorage\.removeItem.*paymentInbox" health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/PaymentsCard.js -A 2 -B 2

echo -e "\n=== sample.js ==="
rg "sessionStorage\.removeItem.*paymentInbox" health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/sample.js -A 2 -B 2

# Check for selectedValues cleanup
echo -e "\n=== Checking selectedValues cleanup ==="
rg "sessionStorage\.removeItem.*selectedValues" --type js -A 2 -B 2

Length of output: 5202

key={key} // Add key to force re-render
values={dateRange}
onFilterChange={handleFilterChange}
t={(key) => key} // Simple translation function
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 actual translation function in DateRangePicker

The DateRangePicker component receives a translation function t, but it's currently set to an identity function (key) => key. This may lead to missing or incorrect translations. Pass the t function from useTranslation() instead.

Apply this change:

-    t={(key) => key} // Simple translation function
+    t={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
t={(key) => key} // Simple translation function
t={t}


return (
<div style={{ width: "100%", marginTop: "14px" }}>
<TextBlock body={isRequired == true ? `${t(label)}*` : t(label)} />
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 the boolean check for 'isRequired' in 'TextBlock'.

You can simplify the condition isRequired == true to just isRequired for a cleaner expression.

Apply this diff:

-     <TextBlock body={isRequired == true ? `${t(label)}*` : t(label)} />
+     <TextBlock body={isRequired ? `${t(label)}*` : t(label)} />
📝 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
<TextBlock body={isRequired == true ? `${t(label)}*` : t(label)} />
<TextBlock body={isRequired ? `${t(label)}*` : t(label)} />

Comment on lines +187 to +196
const resetChildrenSelectedValues = (boundaryType) => {
const index = kk.indexOf(boundaryType);
const newSelectedValues = { ...selectedValues };

for (let i = index + 1; i < kk.length; i++) {
newSelectedValues[kk[i]] = null;
}

setSelectedValues(newSelectedValues);
};
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

Handle cases where 'boundaryType' is not found in 'kk'.

In the resetChildrenSelectedValues function, if boundaryType is not found in kk, kk.indexOf(boundaryType) will return -1, causing the loop to reset all selected values unexpectedly. Please add a check to handle this scenario.

For example:

      const index = kk.indexOf(boundaryType);
+     if (index === -1) {
+       console.error(`boundaryType ${boundaryType} not found in kk`);
+       return;
+     }
📝 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 resetChildrenSelectedValues = (boundaryType) => {
const index = kk.indexOf(boundaryType);
const newSelectedValues = { ...selectedValues };
for (let i = index + 1; i < kk.length; i++) {
newSelectedValues[kk[i]] = null;
}
setSelectedValues(newSelectedValues);
};
const resetChildrenSelectedValues = (boundaryType) => {
const index = kk.indexOf(boundaryType);
if (index === -1) {
console.error(`boundaryType ${boundaryType} not found in kk`);
return;
}
const newSelectedValues = { ...selectedValues };
for (let i = index + 1; i < kk.length; i++) {
newSelectedValues[kk[i]] = null;
}
setSelectedValues(newSelectedValues);
};

Comment on lines 16 to 18
if (boundaryType !== selectedLevel.code) {
setShowToast({ key: "error", label: t("HCM_AM_SELECT_BOUNDARY_TILL_LAST_LEVEL"), 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

Add null checks before comparing 'boundaryType' and 'selectedLevel.code'.

To prevent potential runtime errors, ensure that boundaryType and selectedLevel are defined before comparing them in the handleApplyFilter function.

For example:

      const handleApplyFilter = () => {
+       if (!boundaryType || !selectedLevel) {
+         setShowToast({ key: "error", label: t("HCM_AM_SELECT_BOUNDARY_TILL_LAST_LEVEL"), transitionTime: 3000 });
+         return;
+       }
        if (boundaryType !== selectedLevel.code) {
          setShowToast({ key: "error", label: t("HCM_AM_SELECT_BOUNDARY_TILL_LAST_LEVEL"), transitionTime: 3000 });
          return;
        }

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

Comment on lines +83 to +91
<span onClick={() => { }} style={{ border: "1px solid #E0E0E0", padding: "6px", marginBottom: "10px" }}>
<svg width="17" height="17" viewBox="0 0 16 22" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
d="M8 5V8L12 4L8 0V3C3.58 3 0 6.58 0 11C0 12.57 0.46 14.03 1.24 15.26L2.7 13.8C2.25 12.97 2 12.01 2 11C2 7.69 4.69 5 8 5ZM14.76 6.74L13.3 8.2C13.74 9.04 14 9.99 14 11C14 14.31 11.31 17 8 17V14L4 18L8 22V19C12.42 19 16 15.42 16 11C16 9.43 15.54 7.97 14.76 6.74Z"
fill="#505A5F"
/>
</svg>
</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.

🛠️ Refactor suggestion

Improve accessibility of the clickable 'span' element.

The <span> element with an onClick handler should support keyboard interactions and have appropriate accessibility attributes. Consider changing it to a <button> or adding tabIndex and onKeyPress.

For example:

-       <span onClick={() => { }} style={{ border: "1px solid #E0E0E0", padding: "6px", marginBottom: "10px" }}>
+       <button
+         onClick={() => { }}
+         style={{ border: "1px solid #E0E0E0", padding: "6px", marginBottom: "10px" }}
+         aria-label={t('Refresh')}
+       >

Or, if keeping as a <span>:

        <span
+         tabIndex="0"
          onClick={() => { }}
+         onKeyPress={(e) => { if (e.key === 'Enter') /* handle action */ }}
          style={{ border: "1px solid #E0E0E0", padding: "6px", marginBottom: "10px" }}
        >

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

🧰 Tools
🪛 Biome (1.9.4)

[error] 83-83: 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] 84-84: 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)

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 (11)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/bill_inbox/bill_boundary_filter.js (3)

85-85: 🛠️ Refactor suggestion

[Duplicate] Improve accessibility of clickable span element

The <span> element has an onClick handler without keyboard event support, which affects accessibility. Additionally, the onClick handler is empty, indicating incomplete functionality.

  • If the onClick handler is needed, implement the desired functionality.
  • Add tabIndex="0" and an onKeyDown handler to support keyboard navigation.
  • Consider using a <button> element for semantic correctness and built-in accessibility.

Example fix:

<span
+   tabIndex="0"
    onClick={() => { /* Implement the desired action */ }}
+   onKeyDown={(e) => { if (e.key === 'Enter') { /* Implement the desired action */ } }}
    style={{ ... }}
>
🧰 Tools
🪛 Biome (1.9.4)

[error] 85-85: 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)


94-105: 🧹 Nitpick (assertive)

[Duplicate] Remove commented-out code

Commented-out code is present, which can clutter the codebase and cause confusion.

Consider removing the commented code to enhance code clarity. If the code might be needed later, it's better managed through version control.


115-117: ⚠️ Potential issue

[Duplicate] Correct spelling of updateSeeeionStorage

The prop updateSeeeionStorage appears to be misspelled. Correcting it to updateSessionStorage will prevent potential bugs and improve readability.

Apply this diff to fix the typo:

<BoundaryComponent
    ...
-   updateSeeeionStorage={(newSelectedValues) => {
+   updateSessionStorage={(newSelectedValues) => {
        sessionStorage.setItem("selectedValues", JSON.stringify(newSelectedValues));
    }}
    ...
>
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/pages/employee/ViewAttendance.js (8)

47-47: 🧹 Nitpick (assertive)

Simplify boolean expression

The ternary operator here is unnecessary. You can directly use the truthiness of registerNumber.

- enabled: registerNumber ? true : false,
+ enabled: !!registerNumber,
🧰 Tools
🪛 Biome (1.9.4)

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

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

(lint/complexity/noUselessTernary)


88-88: 🧹 Nitpick (assertive)

Simplify boolean expression

Unnecessary use of a ternary operator. Simplify the condition by directly using AttendanceData.

- enabled: ((AttendanceData ? true : false) && disabledAction && data?.[0]?.musterRollStatus !== "APPROVED") || triggerEstimate,
+ enabled: (AttendanceData && disabledAction && data?.[0]?.musterRollStatus !== "APPROVED") || triggerEstimate,
🧰 Tools
🪛 Biome (1.9.4)

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

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

(lint/complexity/noUselessTernary)


107-107: 🧹 Nitpick (assertive)

Simplify boolean expression

The ternary operator is redundant here. Use the direct truthiness of AttendanceData.

- enabled: (AttendanceData ? true : false) && !disabledAction,
+ enabled: AttendanceData && !disabledAction,
🧰 Tools
🪛 Biome (1.9.4)

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

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

(lint/complexity/noUselessTernary)


282-282: 🧹 Nitpick (assertive)

Simplify boolean expression

You can simplify this condition by removing the unnecessary ternary operator.

- enabled: individualIds.length > 0 ? true : false,
+ enabled: individualIds.length > 0,
🧰 Tools
🪛 Biome (1.9.4)

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

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

(lint/complexity/noUselessTernary)


308-310: 🧹 Nitpick (assertive)

Simplify boolean expression

Avoid unnecessary ternary operators. Use the truthiness of the expression directly.

- )?.userId ? true : false,
+ !!AttendanceData?.attendanceRegister[0]?.staff?.find(
+   (staff) => staff?.staffType?.includes("OWNER")
+ )?.userId,

391-393: ⚠️ Potential issue

Ensure the loader component is returned

The <LoaderWithGap /> component inside the if block is not being returned, so it won't render. Wrap it with a return statement.

- if (updateMutation.isLoading) {
-   <LoaderWithGap />
- }
+ if (updateMutation.isLoading) {
+   return <LoaderWithGap />;
+ }

482-492: ⚠️ Potential issue

Add a unique key prop to elements

When rendering elements within an array in actionFields, each element should have a unique key prop to help React identify them correctly.

Apply the following changes to add key props:

actionFields={[
  disabledAction ? (
+   <Button
+     key="goBackButton"
      label={t(`HCM_AM_GO_BACK`)}
      ...
    />
  ) : editAttendance ? (
+   <Button
+     key="submitAttendanceButton"
      ...
    />
  ) : (
+   <Button
+     key="actionsMenuButton"
      ...
    />
  ),
]}

Also applies to: 494-506, 508-537

🧰 Tools
🪛 Biome (1.9.4)

[error] 482-492: 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)


16-16: ⚠️ Potential issue

Safely access location.state

Destructuring fromCampaignSupervisor from location.state || false might cause issues if location.state is not an object. Provide a default empty object to prevent errors.

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

Alternatively, use optional chaining:

const fromCampaignSupervisor = location.state?.fromCampaignSupervisor || false;
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 54fe437 and 47a8732.

📒 Files selected for processing (2)
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/bill_inbox/bill_boundary_filter.js (1 hunks)
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/pages/employee/ViewAttendance.js (2 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/bill_inbox/bill_boundary_filter.js (1)

Pattern **/*.js: check

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

Pattern **/*.js: check

🪛 Biome (1.9.4)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/bill_inbox/bill_boundary_filter.js

[error] 70-80: 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] 85-85: 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] 86-86: 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)

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

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

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

(lint/complexity/noUselessTernary)


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

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

(lint/complexity/noUselessTernary)


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

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

(lint/complexity/noUselessTernary)


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

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

(lint/complexity/noUselessTernary)


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

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

(lint/complexity/noUselessTernary)


[error] 482-492: 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] 494-506: 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] 508-537: 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)

🔇 Additional comments (3)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/bill_inbox/bill_boundary_filter.js (3)

36-43: 🛠️ Refactor suggestion

Include updateBoundaryFilters in useEffect dependency array

The useEffect hook uses updateBoundaryFilters but does not include it in the dependency array. This may lead to unexpected behavior if updateBoundaryFilters changes without triggering the effect.

Update the dependency array to include updateBoundaryFilters:

- }, [levelSelected]);
+ }, [levelSelected, updateBoundaryFilters]);

Likely invalid or redundant comment.


86-91: 🧹 Nitpick (assertive)

Add accessibility attributes to SVG

The SVG lacks accessibility attributes, which may hinder users relying on assistive technologies.

Add role="img" and an aria-label or include a <title> element within the SVG to provide a descriptive text.

Example:

<svg
    width="17"
    height="17"
    viewBox="0 0 16 22"
    fill="none"
    xmlns="http://www.w3.org/2000/svg"
+   role="img"
+   aria-label={t("Refresh Icon")}
>

Likely invalid or redundant comment.

🧰 Tools
🪛 Biome (1.9.4)

[error] 86-86: 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)


70-80: 🛠️ Refactor suggestion

Add keyboard event handler for accessibility

The <div> element with an onClick handler should support keyboard interactions to improve accessibility for keyboard-only users.

Consider adding tabIndex="0" and an onKeyDown handler:

<div
+   tabIndex="0"
    onClick={handleClearFilter}
+   onKeyDown={(e) => { if (e.key === 'Enter') handleClearFilter(); }}
    style={{ ... }}
>

Alternatively, use a <button> element for better semantics and built-in accessibility features.

Likely invalid or redundant comment.

🧰 Tools
🪛 Biome (1.9.4)

[error] 70-80: 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)

const { t } = useTranslation();
const [boundary, setBoundary] = useState(() => Digit.SessionStorage.get("boundary") || null);
const [showToast, setShowToast] = useState(null);
const [boundaryType, setBoundaryType] = useState("");
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 potential null reference and ensure boundaryType usage

The state variable boundaryType is initialized but never updated. In handleApplyFilter, you are accessing boundary.boundaryType, which may cause a runtime error if boundary is null or if boundary.boundaryType is undefined.

Consider updating onBoundaryChange to set boundaryType based on the selected boundary, or adjust your condition in handleApplyFilter to ensure boundary.boundaryType is valid. Also, add a null check for boundary before accessing its properties.

Example fix:

  • Update onBoundaryChange to set boundaryType:
const onBoundaryChange = (boundary) => {
    if (boundary) {
        setBoundary(boundary);
+       setBoundaryType(boundary.boundaryType); // Assuming 'boundaryType' is a property of 'boundary'
        Digit.SessionStorage.set("boundary", boundary);
    } else {
        setBoundary(null);
+       setBoundaryType("");
        Digit.SessionStorage.set("boundary", null);
    }
};
  • Add null check in handleApplyFilter:
const handleApplyFilter = () => {
+   if (!boundary || !boundary.boundaryType) {
+       setShowToast({ key: "error", label: t("HCM_AM_SELECT_BOUNDARY_TILL_LAST_LEVEL"), transitionTime: 3000 });
+       return;
+   }
    if (boundary.boundaryType !== selectedLevel.code) {
        setShowToast({ key: "error", label: t("HCM_AM_SELECT_BOUNDARY_TILL_LAST_LEVEL"), transitionTime: 3000 });
        return;
    }
    setShowToast(null);
    onFilterChange(boundary.code);
};

Also applies to: 17-19

@@ -0,0 +1,144 @@
import React, { useState, useEffect } from "react";
import { useTranslation } from "react-i18next";
import { CheckBox, SubmitBar } 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 (assertive)

Remove unused import CheckBox

The CheckBox component imported from @egovernments/digit-ui-components is not used in this file. Removing it will clean up the code.

Apply this diff to remove the unused import:

- import { CheckBox, SubmitBar } from "@egovernments/digit-ui-components";
+ import { SubmitBar } 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 { CheckBox, SubmitBar } from "@egovernments/digit-ui-components";
import { SubmitBar } from "@egovernments/digit-ui-components";

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

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 47a8732 and 4fbb011.

📒 Files selected for processing (4)
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/Module.js (2 hunks)
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/custom_comp/filter_section.js (1 hunks)
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/custom_inbox_composer.js (1 hunks)
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/utils/constants.js (1 hunks)
🧰 Additional context used
📓 Path-based instructions (4)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/utils/constants.js (1)

Pattern **/*.js: check

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

Pattern **/*.js: check

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

Pattern **/*.js: check

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

Pattern **/*.js: check

🪛 Biome (1.9.4)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/custom_inbox_composer.js

[error] 291-291: JSX elements without children should be marked as self-closing. In JSX, it is valid for any element to be self-closing.

Unsafe fix: Use a SelfClosingElement instead

(lint/style/useSelfClosingElements)


[error] 306-312: JSX elements without children should be marked as self-closing. In JSX, it is valid for any element to be self-closing.

Unsafe fix: Use a SelfClosingElement instead

(lint/style/useSelfClosingElements)


[error] 319-319: JSX elements without children should be marked as self-closing. In JSX, it is valid for any element to be self-closing.

Unsafe fix: Use a SelfClosingElement instead

(lint/style/useSelfClosingElements)


[error] 321-330: JSX elements without children should be marked as self-closing. In JSX, it is valid for any element to be self-closing.

Unsafe fix: Use a SelfClosingElement instead

(lint/style/useSelfClosingElements)

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

[error] 32-32: This let declares a variable that is only assigned once.

'user' is never reassigned.

Safe fix: Use const instead.

(lint/style/useConst)


[error] 42-42: Use Number.POSITIVE_INFINITY instead of the equivalent global.

ES2015 moved some globals into the Number namespace for consistency.
Safe fix: Use Number.POSITIVE_INFINITY instead.

(lint/style/useNumberNamespace)

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

[error] 92-97: 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] 98-98: 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] 107-107: JSX elements without children should be marked as self-closing. In JSX, it is valid for any element to be self-closing.

Unsafe fix: Use a SelfClosingElement instead

(lint/style/useSelfClosingElements)


[error] 135-148: JSX elements without children should be marked as self-closing. In JSX, it is valid for any element to be self-closing.

Unsafe fix: Use a SelfClosingElement instead

(lint/style/useSelfClosingElements)


[error] 41-41: This let declares a variable that is only assigned once.

'datak' is never reassigned.

Safe fix: Use const instead.

(lint/style/useConst)

🔇 Additional comments (16)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/custom_comp/filter_section.js (3)

92-104: Improve accessibility of the reset button.

The reset button needs keyboard interaction support and proper ARIA attributes.

 <span
   onClick={() => {
     setReset(true);
   }}
+  onKeyPress={(e) => {
+    if (e.key === "Enter") {
+      setReset(true);
+    }
+  }}
+  role="button"
+  tabIndex="0"
   style={{ border: "1px solid #e0e0e0", padding: "6px", marginBottom: "10px", cursor: "pointer" }}
 >
-  <svg width="17" height="17" viewBox="0 0 16 22" fill="none" xmlns="http://www.w3.org/2000/svg">
+  <svg
+    width="17"
+    height="17"
+    viewBox="0 0 16 22"
+    fill="none"
+    xmlns="http://www.w3.org/2000/svg"
+    aria-label="Reset filters"
+    role="img"
+  >
🧰 Tools
🪛 Biome (1.9.4)

[error] 92-97: 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] 98-98: 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)


107-107: Use self-closing tags for elements without children.

-<TextBlock body={`${t("ATTENDANCE_PROJECT_NAME")} *`}></TextBlock>
+<TextBlock body={`${t("ATTENDANCE_PROJECT_NAME")} *`} />

-<BoundaryComponent {...props}></BoundaryComponent>
+<BoundaryComponent {...props} />

Also applies to: 134-149

🧰 Tools
🪛 Biome (1.9.4)

[error] 107-107: JSX elements without children should be marked as self-closing. In JSX, it is valid for any element to be self-closing.

Unsafe fix: Use a SelfClosingElement instead

(lint/style/useSelfClosingElements)


39-53: 🛠️ Refactor suggestion

Improve the project initialization logic.

Several improvements can be made to this useEffect:

  1. Use strict equality comparison (===)
  2. Initialize with empty array as fallback instead of mapping an empty array
  3. Use const instead of let for datak
 useEffect(() => {
-  if (project.length == 0) {
+  if (project.length === 0) {
-    let datak =
-      Digit?.SessionStorage.get("staffProjects") ||
-      [].map((target) => ({
-        code: target.id,
-        projectType: target.projectType,
-        name: target.name,
-        boundary: target?.address?.boundary,
-        boundaryType: target?.address?.boundaryType,
-        projectHierarchy: target.projectHierarchy,
-      }));
+    const datak = Digit?.SessionStorage.get("staffProjects") || [];
     setProject(datak);
   }
 }, []);

Likely invalid or redundant comment.

🧰 Tools
🪛 Biome (1.9.4)

[error] 41-41: This let declares a variable that is only assigned once.

'datak' is never reassigned.

Safe fix: Use const instead.

(lint/style/useConst)

health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/Module.js (2)

2-2: Remove unused import useState

The useState import is not used in this file. Removing unused imports can improve code cleanliness and reduce clutter.


32-32: Use const instead of let

The variable user is never reassigned after its initial declaration. Using const improves immutability and readability.

🧰 Tools
🪛 Biome (1.9.4)

[error] 32-32: This let declares a variable that is only assigned once.

'user' is never reassigned.

Safe fix: Use const instead.

(lint/style/useConst)

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

1-1: Remove invalid import use from React

The named import use does not exist in React and will cause an error. Remove use from the import statement.


13-40: Enhance JSDoc with parameter and return types

While the business flow description is comprehensive, consider adding @param tags for component props and an @returns tag to describe the rendered output. This addition enhances code documentation and aids other developers.


128-146: Remove unnecessary commented-out code

The commented-out code for session cleanup can be removed if it's no longer needed. This helps maintain code clarity. If the cleanup logic is required, consider uncommenting and ensuring it functions correctly.


153-211: Eliminate large blocks of commented-out code

Removing extensive commented-out code enhances readability and reduces confusion. Utilize version control to access previous versions if needed.


291-291: Use self-closing tag for <CustomInboxSearchLinks>

Since <CustomInboxSearchLinks> has no children, it can be self-closed for cleaner syntax.

🧰 Tools
🪛 Biome (1.9.4)

[error] 291-291: JSX elements without children should be marked as self-closing. In JSX, it is valid for any element to be self-closing.

Unsafe fix: Use a SelfClosingElement instead

(lint/style/useSelfClosingElements)


306-312: Use self-closing tag for <CustomFilter>

The <CustomFilter> component does not contain children and can be self-closed to simplify the JSX.

🧰 Tools
🪛 Biome (1.9.4)

[error] 306-312: JSX elements without children should be marked as self-closing. In JSX, it is valid for any element to be self-closing.

Unsafe fix: Use a SelfClosingElement instead

(lint/style/useSelfClosingElements)


319-319: Use self-closing tag for <Card> component

The <Card> element is empty and can be self-closed to improve code brevity.

🧰 Tools
🪛 Biome (1.9.4)

[error] 319-319: JSX elements without children should be marked as self-closing. In JSX, it is valid for any element to be self-closing.

Unsafe fix: Use a SelfClosingElement instead

(lint/style/useSelfClosingElements)


321-330: Use self-closing tag for <CustomInboxTable>

Since <CustomInboxTable> does not have any child elements, use a self-closing tag for cleaner code.

🧰 Tools
🪛 Biome (1.9.4)

[error] 321-330: JSX elements without children should be marked as self-closing. In JSX, it is valid for any element to be self-closing.

Unsafe fix: Use a SelfClosingElement instead

(lint/style/useSelfClosingElements)


113-113: Improve error handling in triggerMusterRollApprove

The error handling in the catch block is incomplete. Consider logging the error or providing user feedback to facilitate debugging and enhance user experience.

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

2-2: Ensure consistent naming in StatusEnum

The string value for PENDING_FOR_APPROVAL is "PENDINGFORAPPROVAL", which lacks underscores. For consistency and clarity, consider changing it to "PENDING_FOR_APPROVAL".


6-7: Remove extra empty lines

There are multiple empty lines between the enums. Reducing them to a single empty line improves readability.

import React, { useState, useEffect } from "react";
import { useTranslation } from "react-i18next";
import { CheckBox, SubmitBar } from "@egovernments/digit-ui-components";
import BoundaryComponent from "../sample";
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)

Consider renaming the BoundaryComponent source file.

The import path "../sample" seems temporary or non-descriptive. Consider renaming it to better reflect its purpose, such as "boundary-component" or "boundary-selector".

Comment on lines +121 to +132
{/*project && <div style={{ maxWidth: "100%", width: "100%", marginBottom: "24px" }}>
<TextBlock body={`${t("ATTENDANCE_PROJECT_NAME")} *`}></TextBlock>
<Dropdown
t={t}
option={project}
name={"code"}
optionKey={"name"}
select={(value) => {
handleProjectChange(value);
}}
/>
</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)

Remove commented-out code.

If this code is no longer needed, it should be removed. If it's kept for future reference, consider documenting the reason in a comment or moving it to project documentation.

import { Card, SVG, Button, ButtonGroup, TextBlock, Dropdown, Toast } from "@egovernments/digit-ui-components";
import { lowerBoundaryDefaultSet } from "../../utils/constants";

const CustomFilter = ({ resetTable, isRequired, onProjectSelect, onFilterChange, projectData }) => {
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 prop projectData.

The projectData prop is declared but never used in the component. Consider removing it if it's not needed.

-const CustomFilter = ({ resetTable, isRequired, onProjectSelect, onFilterChange, projectData }) => {
+const CustomFilter = ({ resetTable, isRequired, onProjectSelect, onFilterChange }) => {
📝 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 CustomFilter = ({ resetTable, isRequired, onProjectSelect, onFilterChange, projectData }) => {
const CustomFilter = ({ resetTable, isRequired, onProjectSelect, onFilterChange }) => {

Comment on lines 141 to 143
initialValue={sessionStorage.getItem("selectedValues")}
updateSeeeionStorage={(newSelectedValues) => {
sessionStorage.setItem("selectedValues", JSON.stringify(newSelectedValues));
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)

Extract session storage key to a constant.

The session storage key "selectedValues" is used directly in the code. Consider extracting it to a constant for better maintainability.

+const SELECTED_VALUES_KEY = "selectedValues";

// Then use it in the component:
-initialValue={sessionStorage.getItem("selectedValues")}
+initialValue={sessionStorage.getItem(SELECTED_VALUES_KEY)}

-sessionStorage.setItem("selectedValues", JSON.stringify(newSelectedValues));
+sessionStorage.setItem(SELECTED_VALUES_KEY, JSON.stringify(newSelectedValues));

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

Comment on lines +20 to +23
const hierarchyType = "MICROPLAN";

// const hierarchyType = window?.globalConfigs?.getConfig("HIERARCHY_TYPE") || "ADMIN";
const moduleCode = ["payments", `boundary-${hierarchyType}`];
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)

Avoid hardcoding hierarchyType

Hardcoding hierarchyType to "MICROPLAN" may reduce flexibility. Consider retrieving it from configuration or global settings to allow dynamic adjustments in different environments.

"HCM",
[{ name: "BOUNDARYTYPES" }, { name: "paymentsConfig" }],
{
cacheTime: Infinity,
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 Number.POSITIVE_INFINITY instead of Infinity

For consistency and clarity, replace Infinity with Number.POSITIVE_INFINITY. This practice aligns with modern JavaScript standards.

🧰 Tools
🪛 Biome (1.9.4)

[error] 42-42: Use Number.POSITIVE_INFINITY instead of the equivalent global.

ES2015 moved some globals into the Number namespace for consistency.
Safe fix: Use Number.POSITIVE_INFINITY instead.

(lint/style/useNumberNamespace)

});


export const lowerBoundaryDefaultSet= "DISTRICT";
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 indentation for consistent formatting

Adjust the indentation of the export statement for lowerBoundaryDefaultSet to match the rest of the code. Consistent formatting enhances code readability.

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

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 4fbb011 and 40700e6.

📒 Files selected for processing (1)
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/pages/employee/my_bills.js (1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/pages/employee/my_bills.js (1)

Pattern **/*.js: check

🪛 Biome (1.9.4)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/pages/employee/my_bills.js

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

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

(lint/complexity/noUselessTernary)

Comment on lines 44 to 49
useEffect(() => {
window.Digit.SessionStorage.del("selectedLevel");
window.Digit.SessionStorage.del("selectedProject");
window.Digit.SessionStorage.del("selectedBoundaryCode");
sessionStorage.removeItem("selectedValues");
});
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 effect dependencies and consolidate storage cleanup.

Two issues need attention:

  1. Missing dependencies array could cause infinite re-renders
  2. Session storage cleanup could be consolidated
 useEffect(() => {
-    window.Digit.SessionStorage.del("selectedLevel");
-    window.Digit.SessionStorage.del("selectedProject");
-    window.Digit.SessionStorage.del("selectedBoundaryCode");
-    sessionStorage.removeItem("selectedValues");
-});
+    const keysToClean = ["selectedLevel", "selectedProject", "selectedBoundaryCode"];
+    keysToClean.forEach(key => window.Digit.SessionStorage.del(key));
+    sessionStorage.removeItem("selectedValues");
+}, []); // Add empty deps array for cleanup effect
📝 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(() => {
window.Digit.SessionStorage.del("selectedLevel");
window.Digit.SessionStorage.del("selectedProject");
window.Digit.SessionStorage.del("selectedBoundaryCode");
sessionStorage.removeItem("selectedValues");
});
useEffect(() => {
const keysToClean = ["selectedLevel", "selectedProject", "selectedBoundaryCode"];
keysToClean.forEach(key => window.Digit.SessionStorage.del(key));
sessionStorage.removeItem("selectedValues");
}, []); // Add empty deps array for cleanup effect

Comment on lines +32 to +33
...(billID ? { billNumbers: [billID] } : {}),
...(dateRange.startDate && dateRange.endDate ? { fromDate: new Date(dateRange.startDate).getTime(), toDate: new Date(dateRange.endDate).getTime() } : {})
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 and make date range transformation more robust.

The date range transformation could fail if the dates are invalid. Also, the transformation logic could be simplified.

-...(billID ? { billNumbers: [billID] } : {}),
-...(dateRange.startDate && dateRange.endDate ? { fromDate: new Date(dateRange.startDate).getTime(), toDate: new Date(dateRange.endDate).getTime() } : {})
+...(billID && { billNumbers: [billID] }),
+...(dateRange.startDate && dateRange.endDate && {
+  fromDate: Date.parse(dateRange.startDate),
+  toDate: Date.parse(dateRange.endDate)
+})
📝 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
...(billID ? { billNumbers: [billID] } : {}),
...(dateRange.startDate && dateRange.endDate ? { fromDate: new Date(dateRange.startDate).getTime(), toDate: new Date(dateRange.endDate).getTime() } : {})
...(billID && { billNumbers: [billID] }),
...(dateRange.startDate && dateRange.endDate && {
fromDate: Date.parse(dateRange.startDate),
toDate: Date.parse(dateRange.endDate)
})

Comment on lines +54 to +69
function formatTimestampToDate(timestamp) {
// Check if the timestamp is valid
if (!timestamp || typeof timestamp !== "number") {
return "Invalid timestamp";
}

// Convert timestamp to a JavaScript Date object
const date = new Date(timestamp);

// Format the date to a readable format (e.g., DD/MM/YYYY)
const day = date.getDate().toString().padStart(2, "0");
const month = (date.getMonth() + 1).toString().padStart(2, "0"); // Months are zero-indexed
const year = date.getFullYear();

return `${day}/${month}/${year}`;
}
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)

Enhance timestamp validation and formatting.

The timestamp formatting function could be more robust with better validation and localization support.

 function formatTimestampToDate(timestamp) {
-    // Check if the timestamp is valid
-    if (!timestamp || typeof timestamp !== "number") {
+    if (!timestamp || (typeof timestamp !== "number" && typeof timestamp !== "string")) {
         return "Invalid timestamp";
     }
 
-    // Convert timestamp to a JavaScript Date object
     const date = new Date(timestamp);
+    if (isNaN(date.getTime())) {
+        return "Invalid timestamp";
+    }
 
-    // Format the date to a readable format (e.g., DD/MM/YYYY)
-    const day = date.getDate().toString().padStart(2, "0");
-    const month = (date.getMonth() + 1).toString().padStart(2, "0"); // Months are zero-indexed
-    const year = date.getFullYear();
-
-    return `${day}/${month}/${year}`;
+    return date.toLocaleDateString(undefined, {
+        day: "2-digit",
+        month: "2-digit",
+        year: "numeric"
+    });
 }
📝 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
function formatTimestampToDate(timestamp) {
// Check if the timestamp is valid
if (!timestamp || typeof timestamp !== "number") {
return "Invalid timestamp";
}
// Convert timestamp to a JavaScript Date object
const date = new Date(timestamp);
// Format the date to a readable format (e.g., DD/MM/YYYY)
const day = date.getDate().toString().padStart(2, "0");
const month = (date.getMonth() + 1).toString().padStart(2, "0"); // Months are zero-indexed
const year = date.getFullYear();
return `${day}/${month}/${year}`;
}
function formatTimestampToDate(timestamp) {
if (!timestamp || (typeof timestamp !== "number" && typeof timestamp !== "string")) {
return "Invalid timestamp";
}
const date = new Date(timestamp);
if (isNaN(date.getTime())) {
return "Invalid timestamp";
}
return date.toLocaleDateString(undefined, {
day: "2-digit",
month: "2-digit",
year: "numeric"
});
}

title: '',
});

const project = Digit?.SessionStorage.get("staffProjects");
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

Add null check for SessionStorage access.

The project retrieval doesn't handle potential undefined values which could cause runtime errors.

-const project = Digit?.SessionStorage.get("staffProjects");
+const project = Digit?.SessionStorage?.get("staffProjects") ?? null;
📝 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 project = Digit?.SessionStorage.get("staffProjects");
const project = Digit?.SessionStorage?.get("staffProjects") ?? null;

Comment on lines +112 to +127
if (isBillLoading) {
return <LoaderScreen />
}

return (
<React.Fragment>
<Header styles={{ fontSize: "32px" }}>
{t("HCM_AM_MY_BILLS")}
</Header>


<MyBillsSearch onSubmit={onSubmit} onClear={onClear} />

<Card>
{isFetching ? <Loader /> : tableData.length === 0 ? <NoResultsFound text={t(`HCM_AM_NO_DATA_FOUND_FOR_BILLS`)} /> : <MyBillsTable data={tableData} />}
</Card>
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)

Consolidate loading states for better UX.

The component has two separate loading indicators (LoaderScreen and Loader) which might create an inconsistent user experience.

-    if (isBillLoading) {
+    if (isBillLoading || isFetching) {
         return <LoaderScreen />
     }
 
     return (
         <React.Fragment>
             <Header styles={{ fontSize: "32px" }}>
                 {t("HCM_AM_MY_BILLS")}
             </Header>
 
             <MyBillsSearch onSubmit={onSubmit} onClear={onClear} />
 
             <Card>
-                {isFetching ? <Loader /> : tableData.length === 0 ? <NoResultsFound text={t(`HCM_AM_NO_DATA_FOUND_FOR_BILLS`)} /> : <MyBillsTable data={tableData} />}
+                {tableData.length === 0 ? <NoResultsFound text={t(`HCM_AM_NO_DATA_FOUND_FOR_BILLS`)} /> : <MyBillsTable data={tableData} />}
             </Card>
         </React.Fragment>
     );
📝 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 (isBillLoading) {
return <LoaderScreen />
}
return (
<React.Fragment>
<Header styles={{ fontSize: "32px" }}>
{t("HCM_AM_MY_BILLS")}
</Header>
<MyBillsSearch onSubmit={onSubmit} onClear={onClear} />
<Card>
{isFetching ? <Loader /> : tableData.length === 0 ? <NoResultsFound text={t(`HCM_AM_NO_DATA_FOUND_FOR_BILLS`)} /> : <MyBillsTable data={tableData} />}
</Card>
if (isBillLoading || isFetching) {
return <LoaderScreen />
}
return (
<React.Fragment>
<Header styles={{ fontSize: "32px" }}>
{t("HCM_AM_MY_BILLS")}
</Header>
<MyBillsSearch onSubmit={onSubmit} onClear={onClear} />
<Card>
{tableData.length === 0 ? <NoResultsFound text={t(`HCM_AM_NO_DATA_FOUND_FOR_BILLS`)} /> : <MyBillsTable data={tableData} />}
</Card>

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

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

16-16: 🧹 Nitpick (assertive)

Ensure safe access to location.state

Destructuring fromCampaignSupervisor from location.state || false can cause issues if location.state is null or not an object. Consider providing a default object to prevent errors.

Apply this diff to ensure safe access:

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

Alternatively, use optional chaining:

const fromCampaignSupervisor = location.state?.fromCampaignSupervisor || false;

47-47: 🧹 Nitpick (assertive)

Simplify boolean expression

Use the direct truthiness of registerNumber rather than a ternary operator.

Apply this diff to simplify the expression:

- enabled: registerNumber ? true : false,
+ enabled: !!registerNumber,
🧰 Tools
🪛 Biome (1.9.4)

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

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

(lint/complexity/noUselessTernary)


88-88: 🧹 Nitpick (assertive)

Simplify boolean expression

Use AttendanceData directly rather than a ternary operator.

Apply this diff to simplify the expression:

- enabled: ((AttendanceData ? true : false) && disabledAction && data?.[0]?.musterRollStatus !== "APPROVED") || triggerEstimate,
+ enabled: (AttendanceData && disabledAction && data?.[0]?.musterRollStatus !== "APPROVED") || triggerEstimate,
🧰 Tools
🪛 Biome (1.9.4)

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

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

(lint/complexity/noUselessTernary)


107-107: 🧹 Nitpick (assertive)

Simplify boolean expression

Eliminate unnecessary ternary operator for clarity.

Apply this diff:

- enabled: (AttendanceData ? true : false) && !disabledAction,
+ enabled: AttendanceData && !disabledAction,
🧰 Tools
🪛 Biome (1.9.4)

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

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

(lint/complexity/noUselessTernary)


282-282: 🧹 Nitpick (assertive)

Simplify boolean expression

Use individualIds.length directly for the enabled condition.

Apply this diff:

- enabled: individualIds.length > 0 ? true : false,
+ enabled: !!individualIds.length,
🧰 Tools
🪛 Biome (1.9.4)

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

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

(lint/complexity/noUselessTernary)


307-309: 🧹 Nitpick (assertive)

Simplify boolean expression

Simplify the enabled condition by removing the unnecessary ternary operator.

Apply this diff:

- enabled: AttendanceData?.attendanceRegister[0]?.staff?.find(
-   (staff) => staff?.staffType?.includes("OWNER")
- )?.userId ? true : false,
+ enabled: !!AttendanceData?.attendanceRegister[0]?.staff?.find(
+   (staff) => staff?.staffType?.includes("OWNER")
+ )?.userId,
🧰 Tools
🪛 Biome (1.9.4)

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

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

(lint/complexity/noUselessTernary)


391-393: ⚠️ Potential issue

Return the loader component to display it

The <LoaderWithGap /> component inside the if block is not returned or rendered, so it won't display as intended.

Apply this diff to ensure the loader is displayed:

- if (updateMutation.isLoading) {
-   <LoaderWithGap />
- }
+ if (updateMutation.isLoading) {
+   return <LoaderWithGap />;
+ }

482-492: ⚠️ Potential issue

Add a unique key prop for each child in actionFields array

When rendering an array of elements in actionFields, each element must have a unique key prop to aid React in identifying them.

Apply this diff to add key props:

actionFields={[
  disabledAction ? (
+   <Button
+     key="goBackButton"
      label={t(`HCM_AM_GO_BACK`)}
      ...
    />
  ) : editAttendance ? (
+   <Button
+     key="submitButton"
      icon="CheckCircle"
      label={t(`HCM_AM_SUBMIT_LABEL`)}
      ...
    />
  ) : (
+   <Button
+     key="actionsButton"
      className="custom-class"
      ...
    />
  ),
]}

Also applies to lines 494-506, 508-537.

🧰 Tools
🪛 Biome (1.9.4)

[error] 482-492: 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)


405-442: 🧹 Nitpick (assertive)

Extract repetitive label-value pairs into a reusable component

The repeated pattern of label pairs can be abstracted into a reusable component to improve code readability and maintainability.

Consider creating a LabelPair component:

const LabelPair = ({ heading, text }) => (
  <div className="label-pair">
    <span className="label-heading">{heading}</span>
    <span className="label-text">{text}</span>
  </div>
);

Then use it:

- <div className="label-pair">
-   <span className="label-heading">{t(`HCM_AM_ATTENDANCE_ID`)}</span>
-   <span className="label-text">{t(registerNumber)}</span>
- </div>
+ <LabelPair heading={t(`HCM_AM_ATTENDANCE_ID`)} text={t(registerNumber)} />

// Repeat for other label pairs
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 40700e6 and 74c3e13.

📒 Files selected for processing (1)
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/pages/employee/ViewAttendance.js (2 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/pages/employee/ViewAttendance.js (1)

Pattern **/*.js: check

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

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

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

(lint/complexity/noUselessTernary)


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

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

(lint/complexity/noUselessTernary)


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

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

(lint/complexity/noUselessTernary)


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

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

(lint/complexity/noUselessTernary)


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

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

(lint/complexity/noUselessTernary)


[error] 482-492: 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] 494-506: 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] 508-537: 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)

🔇 Additional comments (2)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/pages/employee/ViewAttendance.js (2)

149-153: Verify the correct use of mutation hooks

The approveMutation and updateMutation hooks use the same URL (/health-muster-roll/v1/_update). Ensure that the backend differentiates actions based on the workflow.action field and that this is the intended behavior.

If different endpoints are required for approve and update actions, adjust the URL accordingly.


381-387: 🧹 Nitpick (assertive)

Ensure consistent use of variables in pagination handlers

In the handlePerRowsChange function, when setting offset, ensure that you're using the correct variables to calculate the offset.

Apply this diff:

const handlePerRowsChange = (currentRowsPerPage, currentPage) => {
  setRowsPerPage(currentRowsPerPage);
  setCurrentPage(1);
- setLimitAndOffset({ limit: currentRowsPerPage, offset: (currentPage - 1) * rowsPerPage })
+ setLimitAndOffset({ limit: currentRowsPerPage, offset: 0 })
}

This resets the offset correctly when changing the number of rows per page.

Likely invalid or redundant comment.

Comment on lines +481 to +538
disabledAction ? (
<Button
label={t(`HCM_AM_GO_BACK`)}
title={t(`HCM_AM_GO_BACK`)}
onClick={() => {
fromCampaignSupervisor ? history.push(`/${window.contextPath}/employee/payments/generate-bill`, { fromViewScreen: true }) :
history.push(`/${window.contextPath}/employee/payments/registers-inbox`);
}}
type="button"
style={{ minWidth: "14rem" }}
variation="primary"
/>
) : editAttendance ? (
<Button
icon="CheckCircle"
label={t(`HCM_AM_SUBMIT_LABEL`)}
title={t(`HCM_AM_SUBMIT_LABEL`)}
onClick={() => {
setUpdateDisabled(true);
triggerMusterRollUpdate();
}}
style={{ minWidth: "14rem" }}
type="button"
variation="primary"
isDisabled={updateMutation.isLoading || updateDisabled || !isSubmitEnabled}
/>
) : (
<Button
className="custom-class"
iconFill=""
label={t(`HCM_AM_ACTIONS`)}
menuStyles={{
bottom: "40px",
}}
onOptionSelect={(value) => {
if (value.code === "EDIT_ATTENDANCE") {
setOpenEditAlertPopUp(true);
} else if (value.code === "APPROVE") {
setOpenApproveCommentPopUp(true);
}
}}
options={[
{
code: "EDIT_ATTENDANCE",
name: t(`HCM_AM_ACTIONS_EDIT_ATTENDANCE`),
},
{
code: "APPROVE",
name: t(`HCM_AM_ACTIONS_APPROVE`),
},
]}
optionsKey="name"
size=""
style={{ minWidth: "14rem" }}
title=""
type="actionButton"
/>
),
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)

Consider refactoring ActionBar button rendering

The current implementation of rendering buttons within the actionFields array could be improved for readability and maintainability. Consider extracting the button components into separate variables or functions.

For example:

const actionButton = disabledAction ? (
  <Button
    key="goBackButton"
    label={t(`HCM_AM_GO_BACK`)}
    onClick={...}
    ...
  />
) : editAttendance ? (
  <Button
    key="submitButton"
    icon="CheckCircle"
    label={t(`HCM_AM_SUBMIT_LABEL`)}
    onClick={...}
    ...
  />
) : (
  <Button
    key="actionsButton"
    className="custom-class"
    label={t(`HCM_AM_ACTIONS`)}
    options={[...]}
    onOptionSelect={...}
    ...
  />
);

<ActionBar
  actionFields={[actionButton]}
  ...
/>
🧰 Tools
🪛 Biome (1.9.4)

[error] 482-492: 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] 494-506: 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] 508-537: 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)

Comment on lines +363 to +374

if (hasChanged) {
if (!isSubmitEnabled) {
setIsSubmitEnabled(true);
}
} else {
if (isSubmitEnabled) {
setIsSubmitEnabled(false);
}
}
}

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)

Optimize attendance summary comparison

Using _.isEqual to compare large arrays can impact performance. If attendanceSummary is large, consider optimizing the comparison by checking for changes only in the fields that can be edited.

Alternatively, you could set a flag whenever an edit occurs instead of comparing the entire arrays.

Comment on lines +217 to +223
setShowToast({ key: "success", label: t("HCM_AM_ATTENDANCE_UPDATED_SUCCESSFULLY"), transitionTime: 3000 });
// Delay the navigation for 3 seconds
setTimeout(() => {
setUpdateDisabled(false);
history.push(`/${window.contextPath}/employee/payments/view-attendance?registerNumber=${registerNumber}&boundaryCode=${boundaryCode}`);
}, 3000);

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)

Avoid using setTimeout for navigation after showing toast

Using setTimeout to delay navigation can lead to unpredictable behavior if the UI experiences lag. Consider using a callback or promise resolution to ensure navigation occurs after the toast is displayed.

Apply this diff:

- setShowToast({ key: "success", label: t("HCM_AM_ATTENDANCE_UPDATED_SUCCESSFULLY"), transitionTime: 3000 });
- // Delay the navigation for 3 seconds
- setTimeout(() => {
-   setUpdateDisabled(false);
-   history.push(`/${window.contextPath}/employee/payments/view-attendance?registerNumber=${registerNumber}&boundaryCode=${boundaryCode}`);
- }, 3000);
+ setShowToast({ 
+   key: "success", 
+   label: t("HCM_AM_ATTENDANCE_UPDATED_SUCCESSFULLY"), 
+   transitionTime: 3000,
+   onClose: () => {
+     setUpdateDisabled(false);
+     history.push(`/${window.contextPath}/employee/payments/view-attendance?registerNumber=${registerNumber}&boundaryCode=${boundaryCode}`);
+   },
+ });

This ensures that navigation happens after the toast has closed.

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

Comment on lines +215 to +227
{
onSuccess: (data) => {
setShowToast({ key: "success", label: t("HCM_AM_ATTENDANCE_UPDATED_SUCCESSFULLY"), transitionTime: 3000 });
// Delay the navigation for 3 seconds
setTimeout(() => {
setUpdateDisabled(false);
history.push(`/${window.contextPath}/employee/payments/view-attendance?registerNumber=${registerNumber}&boundaryCode=${boundaryCode}`);
}, 3000);

},
onError: (error) => {
setUpdateDisabled(false);
setShowToast({ key: "error", label: t(error?.response?.data?.Errors?.[0]?.message), transitionTime: 3000 });
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

Handle possible undefined error messages

When handling errors, ensure that you have a default message in case error?.response?.data?.Errors is undefined or empty to prevent displaying undefined messages to the user.

Apply this diff:

onError: (error) => {
  setUpdateDisabled(false);
- setShowToast({ key: "error", label: t(error?.response?.data?.Errors?.[0]?.message), transitionTime: 3000 });
+ const errorMessage = error?.response?.data?.Errors?.[0]?.message || t("COMMON_ERROR_MESSAGE");
+ setShowToast({ key: "error", label: errorMessage, transitionTime: 3000 });
}
📝 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
{
onSuccess: (data) => {
setShowToast({ key: "success", label: t("HCM_AM_ATTENDANCE_UPDATED_SUCCESSFULLY"), transitionTime: 3000 });
// Delay the navigation for 3 seconds
setTimeout(() => {
setUpdateDisabled(false);
history.push(`/${window.contextPath}/employee/payments/view-attendance?registerNumber=${registerNumber}&boundaryCode=${boundaryCode}`);
}, 3000);
},
onError: (error) => {
setUpdateDisabled(false);
setShowToast({ key: "error", label: t(error?.response?.data?.Errors?.[0]?.message), transitionTime: 3000 });
{
onSuccess: (data) => {
setShowToast({ key: "success", label: t("HCM_AM_ATTENDANCE_UPDATED_SUCCESSFULLY"), transitionTime: 3000 });
// Delay the navigation for 3 seconds
setTimeout(() => {
setUpdateDisabled(false);
history.push(`/${window.contextPath}/employee/payments/view-attendance?registerNumber=${registerNumber}&boundaryCode=${boundaryCode}`);
}, 3000);
},
onError: (error) => {
setUpdateDisabled(false);
const errorMessage = error?.response?.data?.Errors?.[0]?.message || t("COMMON_ERROR_MESSAGE");
setShowToast({ key: "error", label: errorMessage, transitionTime: 3000 });

Comment on lines +318 to +339
function getUserAttendanceSummary(data, individualsData, t) {
return data[0].individualEntries.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?.modifiedTotalAttendance || individualEntry.actualTotalAttendance || 0;
const id = individualEntry.individualId || 0;

return [id, userName, userId, userRole, noOfDaysWorked];
} else {
// Handle cases where no match is found in individualsData
return ["N/A", "Unknown", "N/A", "Unassigned", individualEntry?.modifiedTotalAttendance || individualEntry.actualTotalAttendance || 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

Handle cases where matchingIndividual is undefined

In the getUserAttendanceSummary function, ensure that you handle cases where matchingIndividual is undefined to avoid potential runtime errors.

Currently, the code checks if matchingIndividual exists, but in the else block, the id is hardcoded as "N/A". If other parts of the code rely on the id being a specific type (e.g., a real ID), this could cause issues.

Consider adjusting the else block:

- return ["N/A", "Unknown", "N/A", "Unassigned", individualEntry?.modifiedTotalAttendance || individualEntry.actualTotalAttendance || 0];
+ return [individualEntry.individualId || "N/A", "Unknown", "N/A", "Unassigned", individualEntry?.modifiedTotalAttendance || individualEntry.actualTotalAttendance || 0];

This way, you retain the original individualId if available.

📝 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
function getUserAttendanceSummary(data, individualsData, t) {
return data[0].individualEntries.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?.modifiedTotalAttendance || individualEntry.actualTotalAttendance || 0;
const id = individualEntry.individualId || 0;
return [id, userName, userId, userRole, noOfDaysWorked];
} else {
// Handle cases where no match is found in individualsData
return ["N/A", "Unknown", "N/A", "Unassigned", individualEntry?.modifiedTotalAttendance || individualEntry.actualTotalAttendance || 0];
}
});
}
function getUserAttendanceSummary(data, individualsData, t) {
return data[0].individualEntries.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?.modifiedTotalAttendance || individualEntry.actualTotalAttendance || 0;
const id = individualEntry.individualId || 0;
return [id, userName, userId, userRole, noOfDaysWorked];
} else {
// Handle cases where no match is found in individualsData
return [individualEntry.individualId || "N/A", "Unknown", "N/A", "Unassigned", individualEntry?.modifiedTotalAttendance || individualEntry.actualTotalAttendance || 0];
}
});
}

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 (5)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/pages/employee/index.js (5)

18-18: ⚠️ Potential issue

Fix destructuring from potentially undefined state

Destructuring from false can cause a runtime error because you cannot destructure properties from a non-object. Defaulting to an empty object {} ensures safe destructuring when local.state is undefined.

Apply this diff to fix the issue:

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

30-31: 🧹 Nitpick (assertive)

Refactor to remove repeated transformation logic

The expression Digit.Utils.locale.getTransformedLocale(location.pathname.split("/").pop()) is used multiple times. Extracting it into a variable reduces duplication and enhances readability.

Apply this diff to refactor the code:

+  const transformedPageName = Digit.Utils.locale.getTransformedLocale(location.pathname.split("/").pop());
...
-      show:
-        Digit.Utils.locale.getTransformedLocale(location.pathname.split("/").pop()) === "VIEW_ATTENDANCE" ||
-        Digit.Utils.locale.getTransformedLocale(location.pathname.split("/").pop()) === "EDIT_ATTENDANCE"
+      show:
+        transformedPageName === "VIEW_ATTENDANCE" || transformedPageName === "EDIT_ATTENDANCE"

46-46: ⚠️ Potential issue

Use optional chaining to prevent potential runtime errors

window.contextPath might be undefined, which could cause a runtime error. Using optional chaining window?.contextPath ensures the code doesn't break if contextPath is not defined on window.

Apply this diff to fix the issue:

-    if (window.location.pathname !== `/${window.contextPath}/employee/`) {
+    if (window.location.pathname !== `/${window?.contextPath}/employee/`) {

51-51: 🧹 Nitpick (assertive)

Ensure consistent use of session storage handlers

For consistency and to leverage any additional handling provided by Digit.SessionStorage, use window.Digit.SessionStorage.del instead of sessionStorage.removeItem.

Apply this diff:

-      sessionStorage.removeItem("selectedValues");
+      window.Digit.SessionStorage.del("selectedValues");

61-67: 🧹 Nitpick (assertive)

Avoid inline functions in route components for better performance

Using inline arrow functions in the component prop can lead to unnecessary re-renders. Pass the component reference directly or use the children prop to improve performance.

Apply this diff:

-<PrivateRoute path={`${path}/view-attendance`} component={() => <ViewAttendance />} />
+<PrivateRoute path={`${path}/view-attendance`} component={ViewAttendance} />

-<PrivateRoute path={`${path}/edit-attendance`} component={() => <ViewAttendance editAttendance={true} />} />
+<PrivateRoute path={`${path}/edit-attendance`}>
+  <ViewAttendance editAttendance={true} />
+</PrivateRoute>

-<PrivateRoute path={`${path}/attendance-approve-success`} component={() => <Response />} />
+<PrivateRoute path={`${path}/attendance-approve-success`} component={Response} />

-<PrivateRoute path={`${path}/attendance-approve-failed`} component={() => <Response />} />
+<PrivateRoute path={`${path}/attendance-approve-failed`} component={Response} />

-<PrivateRoute path={`${path}/registers-inbox`} component={() => <AttendanceInbox />} />
+<PrivateRoute path={`${path}/registers-inbox`} component={AttendanceInbox} />

-<PrivateRoute path={`${path}/generate-bill`} component={() => <BillInbox />} />
+<PrivateRoute path={`${path}/generate-bill`} component={BillInbox} />

-<PrivateRoute path={`${path}/my-bills`} component={() => <MyBills />} />
+<PrivateRoute path={`${path}/my-bills`} component={MyBills} />
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 74c3e13 and a65ff03.

📒 Files selected for processing (3)
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/bill_inbox/bill_boundary_filter.js (1 hunks)
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/pages/employee/index.js (1 hunks)
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/pages/employee/my_bills.js (1 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/bill_inbox/bill_boundary_filter.js (1)

Pattern **/*.js: check

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

Pattern **/*.js: check

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

Pattern **/*.js: check

🪛 Biome (1.9.4)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/bill_inbox/bill_boundary_filter.js

[error] 71-81: 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] 86-86: 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] 87-87: 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)

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

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

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

(lint/complexity/noUselessTernary)

🔇 Additional comments (8)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/bill_inbox/bill_boundary_filter.js (6)

3-3: Remove unused import CheckBox

The CheckBox component is imported but not used in this file. Removing it will clean up the code.


115-115: Correct the prop name updateSeeeionStorage to updateSessionStorage

The prop updateSeeeionStorage appears to have a typo. Correcting it to updateSessionStorage will improve code readability and prevent potential bugs.

Apply this diff:

<BoundaryComponent
    // ... other props
-   updateSeeeionStorage={(newSelectedValues) => {
+   updateSessionStorage={(newSelectedValues) => {
        sessionStorage.setItem("selectedValues", JSON.stringify(newSelectedValues));
    }}
    // ... other props
/>

10-10: ⚠️ Potential issue

Initialize and update boundaryType properly

The state variable boundaryType is initialized but never updated. In handleApplyFilter, you check boundary.boundaryType, but setBoundaryType is not called anywhere. To avoid potential errors, consider updating boundaryType based on the selected boundary in onBoundaryChange.

Apply this diff to update boundaryType in onBoundaryChange:

const onBoundaryChange = (boundary) => {
    if (boundary) {
        setBoundary(boundary);
+       setBoundaryType(boundary.boundaryType);
        Digit.SessionStorage.set("boundary", boundary);
    } else {
        setBoundary(null);
+       setBoundaryType("");
        Digit.SessionStorage.set("boundary", null);
    }
};

Likely invalid or redundant comment.


86-86: 🛠️ Refactor suggestion

Ensure clickable element is keyboard accessible

The <span> element with an onClick handler should be accessible via keyboard. Add onKeyPress and tabIndex={0}, or use a <button> element.

Apply this diff:

- <span onClick={() => { }} style={{ border: "1px solid #E0E0E0", padding: "6px", marginBottom: "10px" }}>
+ <span onClick={() => { }}
+       onKeyPress={(e) => { if (e.key === 'Enter') { /* handle action */ } }}
+       tabIndex={0}
+       style={{ border: "1px solid #E0E0E0", padding: "6px", marginBottom: "10px" }}>

Or replace the <span> with a <button> element for improved accessibility.

Likely invalid or redundant comment.

🧰 Tools
🪛 Biome (1.9.4)

[error] 86-86: 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)


17-19: 🛠️ Refactor suggestion

Add null checks before accessing boundary.boundaryType

To prevent potential runtime errors, ensure that boundary is not null before accessing boundary.boundaryType in handleApplyFilter.

Apply this diff to add a null check:

const handleApplyFilter = () => {
+   if (!boundary || !boundary.boundaryType) {
+       setShowToast({ key: "error", label: t("HCM_AM_SELECT_BOUNDARY_TILL_LAST_LEVEL"), transitionTime: 3000 });
+       return;
+   }
    if (boundary.boundaryType !== selectedLevel.code) {
        setShowToast({ key: "error", label: t("HCM_AM_SELECT_BOUNDARY_TILL_LAST_LEVEL"), transitionTime: 3000 });
        return;
    }
    setShowToast(null);
    onFilterChange(boundary.code);
};

Likely invalid or redundant comment.


87-93: 🧹 Nitpick (assertive)

Add accessibility attributes to the SVG element

The SVG lacks alternative text for screen readers. Include role="img" and provide an aria-label or add a <title> tag within the SVG.

Apply this diff:

<svg width="17" height="17" viewBox="0 0 16 22" fill="none" xmlns="http://www.w3.org/2000/svg"
+     role="img" aria-label={t("Refresh Icon")}>
    <path
        d="M8 5V8L12 4L8 0V3C3.58 3 0 6.58 0 11C0 12.57 0.46 14.03 1.24 15.26L2.7 13.8C2.25 12.97 2 12.01 2 11C2 7.69 4.69 5 8 5ZM14.76 6.74L13.3 8.2C13.74 9.04 14 9.99 14 11C14 14.31 11.31 17 8 17V14L4 18L8 22V19C12.42 19 16 15.42 16 11C16 9.43 15.54 7.97 14.76 6.74Z"
        fill="#505A5F"
    />
</svg>

Alternatively, add a <title> element:

<svg width="17" height="17" viewBox="0 0 16 22" fill="none" xmlns="http://www.w3.org/2000/svg">
+   <title>{t("Refresh Icon")}</title>
    <path
        d="M8 5V8L12 4L8 0V3C3.58 3 0 6.58 0 11C0 12.57 0.46 14.03 1.24 15.26L2.7 13.8C2.25 12.97 2 12.01 2 11C2 7.69 4.69 5 8 5ZM14.76 6.74L13.3 8.2C13.74 9.04 14 9.99 14 11C14 14.31 11.31 17 8 17V14L4 18L8 22V19C12.42 19 16 15.42 16 11C16 9.43 15.54 7.97 14.76 6.74Z"
        fill="#505A5F"
    />
</svg>

Likely invalid or redundant comment.

🧰 Tools
🪛 Biome (1.9.4)

[error] 87-87: 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)

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

27-34: 🧹 Nitpick (assertive)

Enhance type safety and remove commented code.

The bill criteria object could benefit from better type safety and cleaner code:

  1. Remove commented out code
  2. Add type checking for project and boundary values
  3. Use optional chaining for safer property access
 billCriteria: {
     tenantId: tenantId,
-    // ids: ["6eaf462a-4d9a-44c9-9ef7-e127e3fb33f1"],
-    localityCode: project?.address?.boundary,
-    referenceIds: [project?.[0]?.id],
+    ...(project?.address?.boundary && { localityCode: project.address.boundary }),
+    ...(project?.[0]?.id && { referenceIds: [project[0].id] }),
     ...(billID && { billNumbers: [billID] }),
     ...(dateRange.startDate && dateRange.endDate && {
         fromDate: new Date(dateRange.startDate).getTime(),
         toDate: new Date(dateRange.endDate).getTime()
     })
 }

Likely invalid or redundant comment.


13-13: Add error handling for tenant ID retrieval.

The getCurrentTenantId() call could potentially fail if the Digit object or its methods are not properly initialized.

Add error handling:

-const tenantId = Digit.ULBService.getCurrentTenantId();
+const tenantId = Digit?.ULBService?.getCurrentTenantId?.() ?? null;
+if (!tenantId) {
+  // Handle the error case appropriately
+  console.error('Failed to retrieve tenant ID');
+}

Comment on lines +71 to +81
<div onClick={handleClearFilter}
style={{
cursor: "pointer",
alignItems: "center",
gap: ".75rem",
marginBottom: "24px",
display: "flex",
flexDirection: "row",
justifyContent: "space-between",
}}
>
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

Enhance accessibility by adding keyboard event handlers

The <div> element with an onClick handler should support keyboard interactions for accessibility. Add onKeyPress and tabIndex={0} to enable keyboard navigation.

Apply this diff:

- <div onClick={handleClearFilter}
+ <div onClick={handleClearFilter}
+      onKeyPress={(e) => { if (e.key === 'Enter') handleClearFilter(); }}
+      tabIndex={0}
       style={{
           cursor: "pointer",
           alignItems: "center",
           gap: ".75rem",
           marginBottom: "24px",
           display: "flex",
           flexDirection: "row",
           justifyContent: "space-between",
       }}
   >

Alternatively, consider using a <button> element for better semantic meaning.

📝 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 onClick={handleClearFilter}
style={{
cursor: "pointer",
alignItems: "center",
gap: ".75rem",
marginBottom: "24px",
display: "flex",
flexDirection: "row",
justifyContent: "space-between",
}}
>
<div onClick={handleClearFilter}
onKeyPress={(e) => { if (e.key === 'Enter') handleClearFilter(); }}
tabIndex={0}
style={{
cursor: "pointer",
alignItems: "center",
gap: ".75rem",
marginBottom: "24px",
display: "flex",
flexDirection: "row",
justifyContent: "space-between",
}}
>
🧰 Tools
🪛 Biome (1.9.4)

[error] 71-81: 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)

@@ -0,0 +1,134 @@
import React, { useMemo, useState, useEffect } from "react";
import { useTranslation } from "react-i18next";
import { Header, InboxSearchComposer, Loader } 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.

🧹 Nitpick (assertive)

Consider consolidating component imports.

Components are being imported from two similarly named packages: @egovernments/digit-ui-react-components and @egovernments/digit-ui-components. This could lead to confusion and maintenance issues.

Consider consolidating imports from a single package or document the reason for using two separate packages.

Also applies to: 5-5

Comment on lines +72 to +90
function getBillSummary(data) {
return data.map((individualEntry) => {
const billId = individualEntry?.billNumber;
const billDate = formatTimestampToDate(individualEntry.billDate);
const noOfRegisters = individualEntry?.additionalDetails?.noOfRegisters || 0;
const noOfWorkers = individualEntry?.billDetails?.length || 0;
const boundaryCode = t(individualEntry?.localityCode) || "NA";
const projectName = project?.[0]?.name || "NA";
const reportDetails = individualEntry?.additionalDetails?.reportDetails || {
"status": "FAILED", // INITIATED, COMPLETED, FAILED
"pdfReportId": "d5a504fb-ebb8-41be-afa0-24b4f1bd575b",
"excelReportId": "de5f2b24-b60d-4d1f-b550-56abe1dabb2f",
"errorMessage": "HCM_AM_BILL_REPORT_GENERATION_FAILED"
};

return [billId, billDate, noOfRegisters, noOfWorkers, boundaryCode, projectName, reportDetails];

});
}
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

Improve data transformation robustness.

The getBillSummary function has several areas for improvement:

  1. Returns an array of values which makes it prone to ordering errors
  2. Uses type coercion with || which doesn't handle 0 values correctly
  3. Lacks proper typing for the transformed data

Consider this improvement:

 function getBillSummary(data) {
     return data.map((individualEntry) => {
-        const billId = individualEntry?.billNumber;
-        const billDate = formatTimestampToDate(individualEntry.billDate);
-        const noOfRegisters = individualEntry?.additionalDetails?.noOfRegisters || 0;
-        const noOfWorkers = individualEntry?.billDetails?.length || 0;
-        const boundaryCode = t(individualEntry?.localityCode) || "NA";
-        const projectName = project?.[0]?.name || "NA";
-        return [billId, billDate, noOfRegisters, noOfWorkers, boundaryCode, projectName, reportDetails];
+        return {
+            billId: individualEntry?.billNumber ?? 'NA',
+            billDate: formatTimestampToDate(individualEntry?.billDate),
+            noOfRegisters: individualEntry?.additionalDetails?.noOfRegisters ?? 0,
+            noOfWorkers: individualEntry?.billDetails?.length ?? 0,
+            boundaryCode: individualEntry?.localityCode ? t(individualEntry.localityCode) : 'NA',
+            projectName: project?.[0]?.name ?? 'NA',
+            reportDetails
+        };
     });
 }
📝 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
function getBillSummary(data) {
return data.map((individualEntry) => {
const billId = individualEntry?.billNumber;
const billDate = formatTimestampToDate(individualEntry.billDate);
const noOfRegisters = individualEntry?.additionalDetails?.noOfRegisters || 0;
const noOfWorkers = individualEntry?.billDetails?.length || 0;
const boundaryCode = t(individualEntry?.localityCode) || "NA";
const projectName = project?.[0]?.name || "NA";
const reportDetails = individualEntry?.additionalDetails?.reportDetails || {
"status": "FAILED", // INITIATED, COMPLETED, FAILED
"pdfReportId": "d5a504fb-ebb8-41be-afa0-24b4f1bd575b",
"excelReportId": "de5f2b24-b60d-4d1f-b550-56abe1dabb2f",
"errorMessage": "HCM_AM_BILL_REPORT_GENERATION_FAILED"
};
return [billId, billDate, noOfRegisters, noOfWorkers, boundaryCode, projectName, reportDetails];
});
}
function getBillSummary(data) {
return data.map((individualEntry) => {
const reportDetails = individualEntry?.additionalDetails?.reportDetails || {
"status": "FAILED", // INITIATED, COMPLETED, FAILED
"pdfReportId": "d5a504fb-ebb8-41be-afa0-24b4f1bd575b",
"excelReportId": "de5f2b24-b60d-4d1f-b550-56abe1dabb2f",
"errorMessage": "HCM_AM_BILL_REPORT_GENERATION_FAILED"
};
return {
billId: individualEntry?.billNumber ?? 'NA',
billDate: formatTimestampToDate(individualEntry?.billDate),
noOfRegisters: individualEntry?.additionalDetails?.noOfRegisters ?? 0,
noOfWorkers: individualEntry?.billDetails?.length ?? 0,
boundaryCode: individualEntry?.localityCode ? t(individualEntry.localityCode) : 'NA',
projectName: project?.[0]?.name ?? 'NA',
reportDetails
};
});
}

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

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between a65ff03 and 2d20a68.

📒 Files selected for processing (3)
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/bill_inbox/bill_boundary_filter.js (1 hunks)
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/pages/employee/ViewAttendance.js (2 hunks)
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/pages/employee/my_bills.js (1 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/bill_inbox/bill_boundary_filter.js (1)

Pattern **/*.js: check

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

Pattern **/*.js: check

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

Pattern **/*.js: check

🪛 Biome (1.9.4)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/bill_inbox/bill_boundary_filter.js

[error] 71-81: 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] 86-86: 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] 87-87: 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)

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

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

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

(lint/complexity/noUselessTernary)


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

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

(lint/complexity/noUselessTernary)


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

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

(lint/complexity/noUselessTernary)


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

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

(lint/complexity/noUselessTernary)


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

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

(lint/complexity/noUselessTernary)


[error] 482-492: 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] 494-506: 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] 508-537: 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/my_bills.js

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

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

(lint/complexity/noUselessTernary)

🔇 Additional comments (19)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/pages/employee/my_bills.js (2)

1-8: Consider consolidating component imports.

Components are being imported from two similarly named packages: @egovernments/digit-ui-react-components and @egovernments/digit-ui-components. Consider consolidating imports from a single package or document the reason for using two separate packages.


43-50: Fix effect dependencies and consolidate storage cleanup.

The effect is missing its dependencies array and the storage cleanup could be consolidated.

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

47-47: Simplify boolean expression

Use the truthiness of registerNumber directly instead of a ternary operator.

Apply this diff:

- enabled: registerNumber ? true : false,
+ enabled: !!registerNumber,
🧰 Tools
🪛 Biome (1.9.4)

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

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

(lint/complexity/noUselessTernary)


88-88: Simplify boolean expression

Use AttendanceData directly rather than using a ternary operator.

Apply this diff:

- enabled: ((AttendanceData ? true : false) && disabledAction && data?.[0]?.musterRollStatus !== "APPROVED") || triggerEstimate,
+ enabled: (AttendanceData && disabledAction && data?.[0]?.musterRollStatus !== "APPROVED") || triggerEstimate,
🧰 Tools
🪛 Biome (1.9.4)

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

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

(lint/complexity/noUselessTernary)


107-107: Simplify boolean expression

Rely on AttendanceData as a boolean indicator without a ternary operator.

Apply this diff:

- enabled: (AttendanceData ? true : false) && !disabledAction,
+ enabled: AttendanceData && !disabledAction,
🧰 Tools
🪛 Biome (1.9.4)

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

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

(lint/complexity/noUselessTernary)


282-282: Simplify boolean expression

Use a concise truthy check for individualIds.length instead of a ternary operator.

Apply this diff:

- enabled: individualIds.length > 0 ? true : false,
+ enabled: !!individualIds.length,
🧰 Tools
🪛 Biome (1.9.4)

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

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

(lint/complexity/noUselessTernary)


391-393: Return the loader component to display it

The <LoaderWithGap /> component inside the if block is not returned or rendered, so it won't display as intended.

Apply this diff to ensure the loader is displayed:

- if (updateMutation.isLoading) {
-   <LoaderWithGap />
- }
+ if (updateMutation.isLoading) {
+   return <LoaderWithGap />;
+ }

217-223: Avoid using setTimeout for navigation after showing toast

Using setTimeout to delay navigation can lead to unpredictable behavior if the UI experiences lag. Instead, use the onClose callback of the toast to ensure navigation occurs after the toast is dismissed.

Apply this diff:

- setShowToast({ key: "success", label: t("HCM_AM_ATTENDANCE_UPDATED_SUCCESSFULLY"), transitionTime: 3000 });
- // Delay the navigation for 3 seconds
- setTimeout(() => {
-   setUpdateDisabled(false);
-   history.push(`/${window.contextPath}/employee/payments/view-attendance?registerNumber=${registerNumber}&boundaryCode=${boundaryCode}`);
- }, 3000);
+ setShowToast({ 
+   key: "success", 
+   label: t("HCM_AM_ATTENDANCE_UPDATED_SUCCESSFULLY"), 
+   transitionTime: 3000,
+   onClose: () => {
+     setUpdateDisabled(false);
+     history.push(`/${window.contextPath}/employee/payments/view-attendance?registerNumber=${registerNumber}&boundaryCode=${boundaryCode}`);
+   },
+ });

226-228: Handle possible undefined error messages

Ensure that you have a default message in case error?.response?.data?.Errors is undefined or empty to prevent displaying undefined messages to the user.

Apply this diff:

- setShowToast({ key: "error", label: t(error?.response?.data?.Errors?.[0]?.message), transitionTime: 3000 });
+ const errorMessage = error?.response?.data?.Errors?.[0]?.message || t("COMMON_ERROR_MESSAGE");
+ setShowToast({ key: "error", label: errorMessage, transitionTime: 3000 });

508-537: Add a unique key prop for each child in the array

When rendering an array of elements in actionFields, each element should have a unique key prop to help React identify them.

Apply this diff to add key properties:

            actionFields={[
-             disabledAction ? (
+             disabledAction ? (
+               <Button
+                 key="goBackButton"
                  label={t(`HCM_AM_GO_BACK`)}
                  /* ...other props */
                />
              ) : editAttendance ? (
+               <Button
+                 key="submitButton"
                  /* ...other props */
                />
              ) : (
+               <Button
+                 key="actionsButton"
                  /* ...other props */
                />
              ),
            ]}
🧰 Tools
🪛 Biome (1.9.4)

[error] 508-537: 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)


341-346: 🧹 Nitpick (assertive)

Remove unnecessary comments or address TODOs

The comment /// need to update dependency may be outdated or unnecessary. Ensure that all comments are relevant, and remove any that are not needed.

Consider removing the comment if the dependencies are correctly set:

- }, [AllIndividualsData, data]); /// need to update dependency
+ }, [AllIndividualsData, data]);

Likely invalid or redundant comment.

health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/bill_inbox/bill_boundary_filter.js (8)

3-3: Remove unused import CheckBox

The CheckBox component is imported but not used in this file. Removing it will clean up the code.

Apply this diff to remove the unused import:

- import { CheckBox, SubmitBar } from "@egovernments/digit-ui-components";
+ import { SubmitBar } from "@egovernments/digit-ui-components";

71-81: Enhance accessibility by adding keyboard event handlers

The <div> element with an onClick handler should support keyboard interactions for accessibility. Please add onKeyPress and tabIndex={0} to enable keyboard navigation for keyboard-only users.

Apply this diff:

  <div
    onClick={handleClearFilter}
+   onKeyPress={(e) => { if (e.key === 'Enter') handleClearFilter(); }}
+   tabIndex={0}
    style={{
🧰 Tools
🪛 Biome (1.9.4)

[error] 71-81: 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)


86-86: Improve accessibility of the clickable <span> element

The <span> element with an onClick handler should support keyboard interactions and have appropriate accessibility attributes. Consider changing it to a <button> or adding tabIndex={0} and onKeyPress to enable keyboard navigation.

For example, change it to a <button>:

- <span onClick={() => { }} style={{ border: "1px solid #E0E0E0", padding: "6px", marginBottom: "10px" }}>
+ <button
+   onClick={() => { }}
+   style={{ border: "1px solid #E0E0E0", padding: "6px", marginBottom: "10px" }}
+   aria-label={t('Refresh')}
+ >
🧰 Tools
🪛 Biome (1.9.4)

[error] 86-86: 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)


87-92: Provide accessibility attributes for SVG

Include role="img" and an aria-label or a <title> element in the SVG for screen readers to improve accessibility.

Update the SVG element as follows:

<svg
  width="17"
  height="17"
  viewBox="0 0 16 22"
  fill="none"
  xmlns="http://www.w3.org/2000/svg"
+ role="img"
+ aria-label={t("HCM_REFRESH_ICON")}
>

Alternatively, add a <title> element inside the SVG:

<svg
  width="17"
  height="17"
  viewBox="0 0 16 22"
  fill="none"
  xmlns="http://www.w3.org/2000/svg"
>
+ <title>{t("HCM_REFRESH_ICON")}</title>
  <path
    ...
  />
</svg>
🧰 Tools
🪛 Biome (1.9.4)

[error] 87-87: 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)


95-106: Remove commented-out code

There is a block of commented-out code which should be removed to improve code cleanliness and maintainability. If this code might be needed later, you can retrieve it from version control.


36-44: Include updateBoundaryFilters in the dependency array

The useEffect hook uses updateBoundaryFilters, but it is not included in the dependency array. This could lead to unexpected behavior if updateBoundaryFilters changes without triggering the effect.

Update the dependency array as follows:

-    }, [levelSelected])
+    }, [levelSelected, updateBoundaryFilters])

116-116: Fix the spelling of updateSeeeionStorage prop

There's a typo in the prop name updateSeeeionStorage. It should be updateSessionStorage to ensure consistency and prevent confusion.

Apply this diff to correct the spelling:

-            updateSeeeionStorage={(newSelectedValues) => {
+            updateSessionStorage={(newSelectedValues) => {

10-10: 🧹 Nitpick (assertive)

Remove unused state variable boundaryType

The boundaryType state variable is declared but never updated or effectively used in the code. Since boundaryType is not utilized, consider removing it to simplify the code.

Apply this diff to remove boundaryType:

-    const [boundaryType, setBoundaryType] = useState("");

Likely invalid or redundant comment.

Comment on lines +14 to +20
const [tableData, setTableData] = useState([]);
const [billID, setBillID] = useState(null);
const [dateRange, setDateRange] = useState({
startDate: '',
endDate: '',
title: '',
});
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)

Consider using TypeScript or PropTypes for better type safety.

The component uses multiple state variables without type definitions. This could lead to type-related bugs, especially when handling dates and complex objects.

Consider:

  1. Migrating to TypeScript, or
  2. Adding PropTypes for runtime type checking:
MyBills.propTypes = {
  tableData: PropTypes.arrayOf(PropTypes.array).isRequired,
  dateRange: PropTypes.shape({
    startDate: PropTypes.string,
    endDate: PropTypes.string,
    title: PropTypes.string
  }).isRequired
};

Comment on lines +79 to +84
const reportDetails = individualEntry?.additionalDetails?.reportDetails || {
"status": "FAILED", // INITIATED, COMPLETED, FAILED
"pdfReportId": "d5a504fb-ebb8-41be-afa0-24b4f1bd575b",
"excelReportId": "de5f2b24-b60d-4d1f-b550-56abe1dabb2f",
"errorMessage": "HCM_AM_BILL_REPORT_GENERATION_FAILED"
};
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

Remove hardcoded report IDs from the code.

The hardcoded report IDs in the fallback object could pose a security risk if they're actual UUIDs from your system.

Consider:

  1. Using placeholder IDs for development
  2. Moving these values to environment configuration
  3. Generating new IDs for each report
 const reportDetails = individualEntry?.additionalDetails?.reportDetails || {
     "status": "FAILED",
-    "pdfReportId": "d5a504fb-ebb8-41be-afa0-24b4f1bd575b",
-    "excelReportId": "de5f2b24-b60d-4d1f-b550-56abe1dabb2f",
+    "pdfReportId": "",
+    "excelReportId": "",
     "errorMessage": "HCM_AM_BILL_REPORT_GENERATION_FAILED"
 };
📝 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 reportDetails = individualEntry?.additionalDetails?.reportDetails || {
"status": "FAILED", // INITIATED, COMPLETED, FAILED
"pdfReportId": "d5a504fb-ebb8-41be-afa0-24b4f1bd575b",
"excelReportId": "de5f2b24-b60d-4d1f-b550-56abe1dabb2f",
"errorMessage": "HCM_AM_BILL_REPORT_GENERATION_FAILED"
};
const reportDetails = individualEntry?.additionalDetails?.reportDetails || {
"status": "FAILED", // INITIATED, COMPLETED, FAILED
"pdfReportId": "",
"excelReportId": "",
"errorMessage": "HCM_AM_BILL_REPORT_GENERATION_FAILED"
};

Comment on lines +116 to +127
return (
<React.Fragment>
<Header styles={{ fontSize: "32px" }}>
{t("HCM_AM_MY_BILLS")}
</Header>


<MyBillsSearch onSubmit={onSubmit} onClear={onClear} />

<Card>
{isFetching ? <Loader /> : tableData.length === 0 ? <NoResultsFound text={t(`HCM_AM_NO_DATA_FOUND_FOR_BILLS`)} /> : <MyBillsTable data={tableData} />}
</Card>
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)

Improve accessibility of the bills table.

The table component lacks proper ARIA attributes for screen readers.

Add appropriate ARIA labels and roles:

 <Card>
-    {isFetching ? <Loader /> : tableData.length === 0 ? <NoResultsFound text={t(`HCM_AM_NO_DATA_FOUND_FOR_BILLS`)} /> : <MyBillsTable data={tableData} />}
+    <div role="region" aria-label={t("HCM_AM_MY_BILLS")}>
+        {isFetching ? (
+            <Loader aria-label={t("LOADING")} />
+        ) : tableData.length === 0 ? (
+            <NoResultsFound text={t(`HCM_AM_NO_DATA_FOUND_FOR_BILLS`)} role="alert" />
+        ) : (
+            <MyBillsTable data={tableData} aria-label={t("HCM_AM_BILLS_TABLE")} />
+        )}
+    </div>
 </Card>
📝 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
return (
<React.Fragment>
<Header styles={{ fontSize: "32px" }}>
{t("HCM_AM_MY_BILLS")}
</Header>
<MyBillsSearch onSubmit={onSubmit} onClear={onClear} />
<Card>
{isFetching ? <Loader /> : tableData.length === 0 ? <NoResultsFound text={t(`HCM_AM_NO_DATA_FOUND_FOR_BILLS`)} /> : <MyBillsTable data={tableData} />}
</Card>
return (
<React.Fragment>
<Header styles={{ fontSize: "32px" }}>
{t("HCM_AM_MY_BILLS")}
</Header>
<MyBillsSearch onSubmit={onSubmit} onClear={onClear} />
<Card>
<div role="region" aria-label={t("HCM_AM_MY_BILLS")}>
{isFetching ? (
<Loader aria-label={t("LOADING")} />
) : tableData.length === 0 ? (
<NoResultsFound text={t(`HCM_AM_NO_DATA_FOUND_FOR_BILLS`)} role="alert" />
) : (
<MyBillsTable data={tableData} aria-label={t("HCM_AM_BILLS_TABLE")} />
)}
</div>
</Card>

Comment on lines 24 to 41
const BillSearchCri = {
url: `/health-expense/bill/v1/_search`,
body: {
billCriteria: {
tenantId: tenantId,
localityCode: project?.address?.boundary,
referenceIds: [project?.[0]?.id],
...(billID ? { billNumbers: [billID] } : {}),
...(dateRange.startDate && dateRange.endDate ? { fromDate: new Date(dateRange.startDate).getTime(), toDate: new Date(dateRange.endDate).getTime() } : {})
}
},
config: {
enabled: project ? true : false,
select: (data) => {
return data;
},
},
};
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

Improve API configuration robustness.

Several improvements needed in the search criteria configuration:

  1. The boolean expression can be simplified
  2. The API configuration lacks error handling

Apply these improvements:

 const BillSearchCri = {
     url: `/health-expense/bill/v1/_search`,
     body: {
         billCriteria: {
             tenantId: tenantId,
-            localityCode: project?.address?.boundary,
+            localityCode: project?.address?.boundary ?? null,
             referenceIds: [project?.[0]?.id],
             ...(billID ? { billNumbers: [billID] } : {}),
             ...(dateRange.startDate && dateRange.endDate ? { fromDate: new Date(dateRange.startDate).getTime(), toDate: new Date(dateRange.endDate).getTime() } : {})
         }
     },
     config: {
-        enabled: project ? true : false,
+        enabled: Boolean(project),
         select: (data) => {
-            return data;
+            if (!data?.bills) {
+                throw new Error('Invalid response format');
+            }
+            return data;
         },
+        onError: (error) => {
+            console.error('Bill search failed:', error);
+            // Consider showing a user-friendly error message
+        }
     },
 };
📝 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 BillSearchCri = {
url: `/health-expense/bill/v1/_search`,
body: {
billCriteria: {
tenantId: tenantId,
localityCode: project?.address?.boundary,
referenceIds: [project?.[0]?.id],
...(billID ? { billNumbers: [billID] } : {}),
...(dateRange.startDate && dateRange.endDate ? { fromDate: new Date(dateRange.startDate).getTime(), toDate: new Date(dateRange.endDate).getTime() } : {})
}
},
config: {
enabled: project ? true : false,
select: (data) => {
return data;
},
},
};
const BillSearchCri = {
url: `/health-expense/bill/v1/_search`,
body: {
billCriteria: {
tenantId: tenantId,
localityCode: project?.address?.boundary ?? null,
referenceIds: [project?.[0]?.id],
...(billID ? { billNumbers: [billID] } : {}),
...(dateRange.startDate && dateRange.endDate ? { fromDate: new Date(dateRange.startDate).getTime(), toDate: new Date(dateRange.endDate).getTime() } : {})
}
},
config: {
enabled: Boolean(project),
select: (data) => {
if (!data?.bills) {
throw new Error('Invalid response format');
}
return data;
},
onError: (error) => {
console.error('Bill search failed:', error);
// Consider showing a user-friendly error message
}
},
};
🧰 Tools
🪛 Biome (1.9.4)

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

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

(lint/complexity/noUselessTernary)

const location = useLocation();
const { t } = useTranslation();
const history = useHistory();
const { registerNumber, boundaryCode } = Digit.Hooks.useQueryParams();
const { fromCampaignSupervisor } = location.state || false;
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

Ensure safe access to location.state

Destructuring fromCampaignSupervisor from location.state || false can cause issues if location.state is null or not an object. Consider providing a default object to prevent errors.

Apply this diff to fix the issue:

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

Alternatively, use optional chaining:

const fromCampaignSupervisor = location.state?.fromCampaignSupervisor || false;

Comment on lines +307 to +309
enabled: AttendanceData?.attendanceRegister[0]?.staff?.find(
(staff) => staff?.staffType?.includes("OWNER")
)?.userId ? true : false,
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 boolean expression

Simplify the condition by removing the unnecessary ternary operator.

Apply this diff:

- enabled: AttendanceData?.attendanceRegister[0]?.staff?.find(
-   (staff) => staff?.staffType?.includes("OWNER")
- )?.userId ? true : false,
+ enabled: !!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
enabled: AttendanceData?.attendanceRegister[0]?.staff?.find(
(staff) => staff?.staffType?.includes("OWNER")
)?.userId ? true : false,
enabled: !!AttendanceData?.attendanceRegister[0]?.staff?.find(
(staff) => staff?.staffType?.includes("OWNER")
)?.userId,
🧰 Tools
🪛 Biome (1.9.4)

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

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

(lint/complexity/noUselessTernary)

Comment on lines +345 to +346
setAttendanceSummary(getUserAttendanceSummary(data, AllIndividualsData, 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

Address the pending dependency update

The comment /// need to update dependency indicates that there might be a missing dependency in the useEffect hook. Ensure all necessary dependencies are included to prevent potential bugs.

Review the dependencies for the useEffect hook and include any missing ones. For example, if t is a dependency, update the hook:

- }, [AllIndividualsData, data]); /// need to update dependency
+ }, [AllIndividualsData, data, t]); // Updated dependencies

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


const handleClearFilter = () => {
setResetFilters(true);
setBoundary(""); // Clear the boundary value
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 consistent reset of boundary state

In handleClearFilter, the boundary state is reset using setBoundary(""), whereas in other parts of the code setBoundary(null) is used (e.g., lines 31 and 41). This inconsistency might lead to unexpected behavior. Consider using null consistently to represent an unset boundary.

Apply this diff to standardize the reset value:

-        setBoundary(""); // Clear the boundary value
+        setBoundary(null); // Clear the boundary value
📝 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
setBoundary(""); // Clear the boundary value
setBoundary(null); // Clear the boundary value

makeReset={() => {
setResetFilters(false);
}}
initialValue={sessionStorage.getItem("selectedValues")}
Copy link
Contributor

Choose a reason for hiding this comment

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

💡 Codebase verification

Standardize session storage access using Digit.SessionStorage

The codebase shows a clear preference for using the Digit.SessionStorage abstraction. Update the code to maintain consistency:

-            initialValue={sessionStorage.getItem("selectedValues")}
+            initialValue={Digit.SessionStorage.get("selectedValues")}
🔗 Analysis chain

Standardize the use of session storage

At line 115, sessionStorage.getItem("selectedValues") is used, whereas elsewhere in the code Digit.SessionStorage is used (e.g., lines 8, 13, 28). For consistency and to prevent potential issues, consider using Digit.SessionStorage throughout the code if it is the preferred abstraction.

Update the code as follows:

-            initialValue={sessionStorage.getItem("selectedValues")}
+            initialValue={Digit.SessionStorage.get("selectedValues")}
🏁 Scripts executed

The following scripts were executed for the analysis:

Error: No shell scripts found


Script:

#!/bin/bash
# Search for Digit.SessionStorage usage patterns
ast-grep --pattern 'Digit.SessionStorage.$_($_)'

# Search for direct sessionStorage usage
ast-grep --pattern 'sessionStorage.$_($_)'

# Backup search with ripgrep for both patterns
echo "=== Searching for Digit.SessionStorage usage ==="
rg "Digit\.SessionStorage\." -A 1 -B 1

echo "=== Searching for direct sessionStorage usage ==="
rg "sessionStorage\." -A 1 -B 1

Length of output: 66141

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

♻️ Duplicate comments (2)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/MyBillsSearch.js (1)

62-62: 🧹 Nitpick (assertive)

Use proper translation function in DateRangePicker.

Passing a simple identity function to the t prop may lead to missing translations. Use the actual t function from useTranslation().

Apply this change:

- t={(key) => key}
+ t={t}
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/pages/employee/my_bills.js (1)

36-36: 🧹 Nitpick (assertive)

Simplify boolean expression for enabled config.

The expression enabled: project ? true : false can be simplified by converting project to a boolean.

Apply this change:

- enabled: project ? true : false,
+ enabled: Boolean(project),
🧰 Tools
🪛 Biome (1.9.4)

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

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

(lint/complexity/noUselessTernary)

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 2d20a68 and 12b115b.

📒 Files selected for processing (6)
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/DateRangePicker.js (1 hunks)
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/MyBillsSearch.js (1 hunks)
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/MyBillsTable.js (1 hunks)
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/bill_inbox/BillInbox.js (1 hunks)
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/pages/employee/ViewAttendance.js (2 hunks)
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/pages/employee/my_bills.js (1 hunks)
🧰 Additional context used
📓 Path-based instructions (6)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/pages/employee/ViewAttendance.js (1)

Pattern **/*.js: check

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

Pattern **/*.js: check

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

Pattern **/*.js: check

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

Pattern **/*.js: check

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

Pattern **/*.js: check

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

Pattern **/*.js: check

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

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

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

(lint/complexity/noUselessTernary)


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

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

(lint/complexity/noUselessTernary)


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

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

(lint/complexity/noUselessTernary)


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

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

(lint/complexity/noUselessTernary)


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

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

(lint/complexity/noUselessTernary)


[error] 479-489: 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] 491-503: 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] 505-534: 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/my_bills.js

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

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

(lint/complexity/noUselessTernary)

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

[error] 49-49: JSX elements without children should be marked as self-closing. In JSX, it is valid for any element to be self-closing.

Unsafe fix: Use a SelfClosingElement instead

(lint/style/useSelfClosingElements)


[error] 71-76: JSX elements without children should be marked as self-closing. In JSX, it is valid for any element to be self-closing.

Unsafe fix: Use a SelfClosingElement instead

(lint/style/useSelfClosingElements)


[error] 73-73: 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] 74-74: 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/components/bill_inbox/BillInbox.js

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

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

(lint/complexity/noUselessTernary)


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

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

(lint/complexity/noUselessTernary)


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

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

(lint/complexity/noUselessTernary)


[error] 186-194: JSX elements without children should be marked as self-closing. In JSX, it is valid for any element to be self-closing.

Unsafe fix: Use a SelfClosingElement instead

(lint/style/useSelfClosingElements)


[error] 197-198: JSX elements without children should be marked as self-closing. In JSX, it is valid for any element to be self-closing.

Unsafe fix: Use a SelfClosingElement instead

(lint/style/useSelfClosingElements)


[error] 211-217: JSX elements without children should be marked as self-closing. In JSX, it is valid for any element to be self-closing.

Unsafe fix: Use a SelfClosingElement instead

(lint/style/useSelfClosingElements)


[error] 254-263: JSX elements without children should be marked as self-closing. In JSX, it is valid for any element to be self-closing.

Unsafe fix: Use a SelfClosingElement instead

(lint/style/useSelfClosingElements)


[error] 273-285: 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] 296-312: 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/components/MyBillsTable.js

[error] 13-13: Template literals are preferred over string concatenation.

Unsafe fix: Use a template literal.

(lint/style/useTemplate)


[error] 47-47: Template literals are preferred over string concatenation.

Unsafe fix: Use a template literal.

(lint/style/useTemplate)


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

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

(lint/complexity/noUselessTernary)


[error] 134-172: 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] 173-173: 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/components/DateRangePicker.js

[error] 197-197: JSX elements without children should be marked as self-closing. In JSX, it is valid for any element to be self-closing.

Unsafe fix: Use a SelfClosingElement instead

(lint/style/useSelfClosingElements)


[error] 128-128: This let declares a variable that is only assigned once.

'noOfDays' is never reassigned.

Safe fix: Use const instead.

(lint/style/useConst)

🔇 Additional comments (36)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/bill_inbox/BillInbox.js (10)

1-1: Remove unused and invalid imports

The imports useReducer, useMemo, and use are not used in this file. Additionally, use is not a valid React hook and may have been included by mistake. Please remove these to clean up the code.


5-5: Define location or use useLocation hook

The variable location is used but not defined in this scope. If you intend to access the browser's location or the route's state, consider importing useLocation from react-router-dom and using it to retrieve the location object.


23-23: Remove commented-out code

The commented-out line is unnecessary and can be removed to keep the code clean.


48-48: Simplify boolean expressions

The use of ternary operators returning boolean literals can be simplified by directly assigning the condition's result. This improves code readability.

Apply these changes:

At line 48:

- isChildrenRequired: selectedLevel != null && selectedLevel?.code === "DISTRICT" ? true : false,
+ isChildrenRequired: selectedLevel != null && selectedLevel?.code === "DISTRICT",

At line 51:

- enabled: selectedBoundaryCode && selectedProject ? true : false,
+ enabled: !!(selectedBoundaryCode && selectedProject),

At line 68:

- enabled: selectedBoundaryCode ? true : false,
+ enabled: !!selectedBoundaryCode,

Also applies to: 51-51, 68-68

🧰 Tools
🪛 Biome (1.9.4)

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

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

(lint/complexity/noUselessTernary)


186-194: Use a self-closing tag for <CustomInboxSearchLinks>

JSX elements without child content should be self-closing.

Apply this change:

<CustomInboxSearchLinks
    headerText={"HCM_AM_BILL_INBOX"}
    links={[
        {
            url: "/employee/payments/my-bills",
            text: "HCM_AM_MY_BILLS",
        },
    ]}
- ></CustomInboxSearchLinks>
+ />
🧰 Tools
🪛 Biome (1.9.4)

[error] 186-194: JSX elements without children should be marked as self-closing. In JSX, it is valid for any element to be self-closing.

Unsafe fix: Use a SelfClosingElement instead

(lint/style/useSelfClosingElements)


197-198: Use a self-closing tag for <BillSearchBox>

When a JSX element has no child content, prefer using a self-closing tag.

Apply this change:

<BillSearchBox
    onLevelSelect={handleSearchChange}
    initialProject={selectedProject}
    initialAggregationLevel={selectedLevel}
- ></BillSearchBox>
+ />
🧰 Tools
🪛 Biome (1.9.4)

[error] 197-198: JSX elements without children should be marked as self-closing. In JSX, it is valid for any element to be self-closing.

Unsafe fix: Use a SelfClosingElement instead

(lint/style/useSelfClosingElements)


211-217: Use a self-closing tag for <BillBoundaryFilter>

Prefer a self-closing tag for elements without children.

Apply this change:

<BillBoundaryFilter
    isRequired={ScreenTypeEnum.BILL}
    selectedProject={selectedProject}
    selectedLevel={selectedLevel}
    onFilterChange={handleFilterUpdate}
    updateBoundaryFilters={updateFilters}
- ></BillBoundaryFilter>
+ />
🧰 Tools
🪛 Biome (1.9.4)

[error] 211-217: JSX elements without children should be marked as self-closing. In JSX, it is valid for any element to be self-closing.

Unsafe fix: Use a SelfClosingElement instead

(lint/style/useSelfClosingElements)


254-263: Use a self-closing tag for <BillInboxTable>

JSX elements without child content should be self-closing.

Apply this change:

<Card>
  <BillInboxTable
      isFetching={isFetching}
      tableData={tableData}
      currentPage={currentPage}
      rowsPerPage={rowsPerPage}
      handlePageChange={handlePageChange}
      handlePerRowsChange={handlePerRowsChange}
      totalCount={totalCount}
      status={activeLink.code}
-   ></BillInboxTable>
+   />
</Card>
🧰 Tools
🪛 Biome (1.9.4)

[error] 254-263: JSX elements without children should be marked as self-closing. In JSX, it is valid for any element to be self-closing.

Unsafe fix: Use a SelfClosingElement instead

(lint/style/useSelfClosingElements)


273-285: Add a key property when returning elements in an array

Even if you only return a single element in an array, React recommends specifying a unique key to maintain stable identity across renders.

Apply these changes:

At lines 273-285:

actionFields={[
+  <Button
+    key="generate-bill-btn"
     icon="CheckCircle"
     label={t(`HCM_AM_GENERATE_BILL_LABEL`)}
     onClick={() => {
         triggerGenerateBill();
     }}
     style={{
         minWidth: "14rem",
     }}
     type="button"
     variation="primary"
     isDisabled={generateBillMutation.isLoading}
  />,
]}

At lines 296-312:

actionFields={[
+  <Button
+    key="generate-bill-btn-conditional"
     icon="CheckCircle"
     label={t(`HCM_AM_GENERATE_BILL_LABEL`)}
     onClick={() => {
         !showGenerateBillAction || BillData?.bills?.length >= 0
             ? setShowToast({ key: "info", label: t("HCM_AM_GENERATE_BILLS_CANNOT_BE_CALLED_INFO_MESSAGE"), transitionTime: 3000 })
             : triggerGenerateBill();
     }}
     style={{
         minWidth: "14rem",
         cursor: !showGenerateBillAction || BillData?.bills?.length >= 0 ? "not-allowed" : "pointer",
         opacity: !showGenerateBillAction || BillData?.bills?.length >= 0 ? 0.5 : 1,
     }}
     type="button"
     variation="primary"
     isDisabled={generateBillMutation.isLoading}
/>,
]}

Also applies to: 296-312

🧰 Tools
🪛 Biome (1.9.4)

[error] 273-285: 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)


300-308: Logical error in the onClick handler condition

The condition BillData?.bills?.length >= 0 will always be true because an array's length is always 0 or greater. This means triggerGenerateBill() will never be called.

Consider revising the condition to correctly reflect the intended logic. If you intend to check if there are no bills, you might use:

!showGenerateBillAction || BillData?.bills?.length > 0

This ensures that triggerGenerateBill() is called when there are no bills.

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

16-16: Ensure safe access to location.state

Destructuring fromCampaignSupervisor from location.state || false can cause issues if location.state is null or not an object. Consider providing a default object to prevent errors.

Apply this diff:

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

47-47: Simplify boolean expression

Simplify the condition by removing the unnecessary ternary operator.

Apply this diff:

- enabled: registerNumber ? true : false,
+ enabled: !!registerNumber,
🧰 Tools
🪛 Biome (1.9.4)

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

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

(lint/complexity/noUselessTernary)


85-85: Simplify boolean expression

Simplify the condition by removing the unnecessary ternary operator.

Apply this diff:

- enabled: ((AttendanceData ? true : false) && disabledAction && AttendanceData?.attendanceRegister?.[0]?.reviewStatus !== "APPROVED") || triggerEstimate,
+ enabled: (AttendanceData && disabledAction && AttendanceData?.attendanceRegister?.[0]?.reviewStatus !== "APPROVED") || triggerEstimate,
🧰 Tools
🪛 Biome (1.9.4)

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

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

(lint/complexity/noUselessTernary)


104-104: Simplify boolean expression

Simplify the condition by removing the unnecessary ternary operator.

Apply this diff:

- enabled: (AttendanceData ? true : false) && (!disabledAction || AttendanceData?.attendanceRegister?.[0]?.reviewStatus === "APPROVED"),
+ enabled: AttendanceData && (!disabledAction || AttendanceData?.attendanceRegister?.[0]?.reviewStatus === "APPROVED"),
🧰 Tools
🪛 Biome (1.9.4)

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

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

(lint/complexity/noUselessTernary)


279-279: Simplify boolean expression

Simplify the condition by removing the unnecessary ternary operator.

Apply this diff:

- enabled: individualIds.length > 0 ? true : false,
+ enabled: !!individualIds.length,
🧰 Tools
🪛 Biome (1.9.4)

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

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

(lint/complexity/noUselessTernary)


304-306: Simplify boolean expression

Simplify the condition by removing the unnecessary ternary operator.

Apply this diff:

- enabled: AttendanceData?.attendanceRegister[0]?.staff?.find(
-   (staff) => staff?.staffType?.includes("OWNER")
- )?.userId ? true : false,
+ enabled: !!AttendanceData?.attendanceRegister[0]?.staff?.find(
+   (staff) => staff?.staffType?.includes("OWNER")
+ )?.userId,
🧰 Tools
🪛 Biome (1.9.4)

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

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

(lint/complexity/noUselessTernary)


315-336: Handle cases where matchingIndividual may be undefined

In the getUserAttendanceSummary function, ensure that you handle cases where matchingIndividual is undefined to avoid potential runtime errors.

Consider updating the else block to use the individualId if available:

- return ["N/A", "Unknown", "N/A", "Unassigned", individualEntry?.modifiedTotalAttendance || individualEntry.actualTotalAttendance || 0];
+ return [individualEntry.individualId || "N/A", "Unknown", "N/A", "Unassigned", individualEntry?.modifiedTotalAttendance || individualEntry.actualTotalAttendance || 0];

345-345: Update dependencies in useEffect hook

The comment /// need to update dependency indicates missing dependencies in the useEffect hook. Ensure all necessary dependencies are included to prevent potential bugs.

Review and update the dependency array as needed.


388-390: Ensure the loader component is returned to display correctly

The <LoaderWithGap /> component inside the if block is not returned or rendered, so it won't display as intended.

Apply this diff:

- if (updateMutation.isLoading) {
-   <LoaderWithGap />
- }
+ if (updateMutation.isLoading) {
+   return <LoaderWithGap />;
+ }

479-489: Add a unique key prop to each element in actionFields

When rendering elements in arrays, each element should have a unique key prop to help React identify them.

Apply this diff:

disabledAction ? (
+  <Button
+    key="goBackButton"
     label={t(`HCM_AM_GO_BACK`)}
     title={t(`HCM_AM_GO_BACK`)}
     onClick={() => {
       fromCampaignSupervisor
         ? history.push(`/${window.contextPath}/employee/payments/generate-bill`, { fromViewScreen: true })
         : history.push(`/${window.contextPath}/employee/payments/registers-inbox`);
     }}
     type="button"
     style={{ minWidth: "14rem" }}
     variation="primary"
   />
) : ...
🧰 Tools
🪛 Biome (1.9.4)

[error] 479-489: 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)


491-503: Add a unique key prop to each element in actionFields

When rendering elements in arrays, each element should have a unique key prop to help React identify them.

Apply this diff:

) : editAttendance ? (
+  <Button
+    key="submitButton"
     icon="CheckCircle"
     label={t(`HCM_AM_SUBMIT_LABEL`)}
     title={t(`HCM_AM_SUBMIT_LABEL`)}
     onClick={() => {
       setUpdateDisabled(true);
       triggerMusterRollUpdate();
     }}
     style={{ minWidth: "14rem" }}
     type="button"
     variation="primary"
     isDisabled={updateMutation.isLoading || updateDisabled || !isSubmitEnabled}
   />
) : ...
🧰 Tools
🪛 Biome (1.9.4)

[error] 491-503: 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)


505-534: Add a unique key prop to each element in actionFields

When rendering elements in arrays, each element should have a unique key prop to help React identify them.

Apply this diff:

) : (
+  <Button
+    key="actionsButton"
     className="custom-class"
     iconFill=""
     label={t(`HCM_AM_ACTIONS`)}
     menuStyles={{
       bottom: "40px",
     }}
     onOptionSelect={(value) => {
       if (value.code === "EDIT_ATTENDANCE") {
         setOpenEditAlertPopUp(true);
       } else if (value.code === "APPROVE") {
         setOpenApproveCommentPopUp(true);
       }
     }}
     options={[
       {
         code: "EDIT_ATTENDANCE",
         name: t(`HCM_AM_ACTIONS_EDIT_ATTENDANCE`),
       },
       {
         code: "APPROVE",
         name: t(`HCM_AM_ACTIONS_APPROVE`),
       },
     ]}
     optionsKey="name"
     size=""
     style={{ minWidth: "14rem" }}
     title=""
     type="actionButton"
   />
)
🧰 Tools
🪛 Biome (1.9.4)

[error] 505-534: 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)


215-221: Avoid using setTimeout for navigation after showing toast

Using setTimeout to delay navigation can lead to unpredictable behavior. Consider using a callback or promise resolution to navigate after the toast has been displayed.

Apply this diff:

setShowToast({
  key: "success",
  label: t("HCM_AM_ATTENDANCE_UPDATED_SUCCESSFULLY"),
  transitionTime: 3000,
+ onClose: () => {
+   setUpdateDisabled(false);
+   history.push(`/${window.contextPath}/employee/payments/view-attendance?registerNumber=${registerNumber}&boundaryCode=${boundaryCode}`);
+ },
});
- // Delay the navigation for 3 seconds
- setTimeout(() => {
-   setUpdateDisabled(false);
-   history.push(`/${window.contextPath}/employee/payments/view-attendance?registerNumber=${registerNumber}&boundaryCode=${boundaryCode}`);
- }, 3000);

224-225: Ensure a default error message is displayed

When handling errors, ensure that a default message is shown if error?.response?.data?.Errors is undefined or empty to prevent displaying undefined to the user.

Apply this diff:

onError: (error) => {
  setUpdateDisabled(false);
- setShowToast({ key: "error", label: t(error?.response?.data?.Errors?.[0]?.message), transitionTime: 3000 });
+ const errorMessage = error?.response?.data?.Errors?.[0]?.message || t("COMMON_ERROR_MESSAGE");
+ setShowToast({ key: "error", label: errorMessage, transitionTime: 3000 });
}
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/MyBillsTable.js (3)

140-140: 🧹 Nitpick (assertive)

Simplify boolean expression in showBottom prop.

The expression showBottom={isLastRow ? false : true} can be simplified by negating isLastRow, which enhances code clarity.

Apply this change:

- showBottom={isLastRow ? false : true}
+ showBottom={!isLastRow}

Likely invalid or redundant comment.

🧰 Tools
🪛 Biome (1.9.4)

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

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

(lint/complexity/noUselessTernary)


77-81: 🧹 Nitpick (assertive)

Destructure props instead of using spread operator.

Destructuring specific props improves readability and makes it explicit which props are being used.

Apply this change:

- const MyBillsTable = ({ ...props }) => {
+ const MyBillsTable = ({ data, handlePageChange, handlePerRowsChange, onRowSelect }) => {

Update all instances of props within the component to use the destructured variables.

Likely invalid or redundant comment.


225-237: 🧹 Nitpick (assertive)

Remove unnecessary placeholder functions.

The onFilter, onSelectedRowsChange, and customSortFunction props have placeholder functions that are not implemented. Consider removing them or providing actual implementations to clean up the code.

Apply these changes:

- onFilter={function noRefCheck() { }}
+ onFilter={null}
- selection={{
-     addCheckbox: false,
-     checkboxLabel: "",
-     initialSelectedRows: [],
-     onSelectedRowsChange: function noRefCheck() { },
-     showSelectedState: false,
- }}
+ selection={{
+     addCheckbox: false,
+     checkboxLabel: "",
+     initialSelectedRows: [],
+     onSelectedRowsChange: null,
+     showSelectedState: false,
+ }}
- sorting={{
-     customSortFunction: function noRefCheck() { },
-     initialSortOrder: "",
-     isTableSortable: false,
- }}
+ sorting={{
+     customSortFunction: null,
+     initialSortOrder: "",
+     isTableSortable: false,
+ }}

Likely invalid or redundant comment.

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

18-18: Avoid using state as a key prop.

Using state variables as keys in components like DateRangePicker can lead to unintended behavior. Instead, consider controlling re-renders through props or using a different approach.


49-49: 🧹 Nitpick (assertive)

Use self-closing tag for <TextBlock> component.

Since <TextBlock> has no children, it can be self-closed to improve code readability.

Apply this change:

- <TextBlock body={`${t("HCM_AM_BILL_ID")}`}></TextBlock>
+ <TextBlock body={`${t("HCM_AM_BILL_ID")}`} />

Likely invalid or redundant comment.

🧰 Tools
🪛 Biome (1.9.4)

[error] 49-49: JSX elements without children should be marked as self-closing. In JSX, it is valid for any element to be self-closing.

Unsafe fix: Use a SelfClosingElement instead

(lint/style/useSelfClosingElements)


71-76: 🧹 Nitpick (assertive)

Add key props to buttons in ButtonGroup.

Each child in an array should have a unique key prop to help React identify which items have changed.

Apply these changes:

<ButtonGroup
  buttonsArray={[
    <Button
+     key="clear-button"
      variation="teritiary"
      label={t(`HCM_AM_CLEAR`)}
      type="button"
      onClick={handleClear}
      size="large"
    />,
    <Button
+     key="search-button"
      variation="primary"
      label={t(`HCM_AM_SEARCH`)}
      type="button"
      onClick={handleSearch}
      size="large"
    />,
  ]}
/>

Likely invalid or redundant comment.

🧰 Tools
🪛 Biome (1.9.4)

[error] 71-76: JSX elements without children should be marked as self-closing. In JSX, it is valid for any element to be self-closing.

Unsafe fix: Use a SelfClosingElement instead

(lint/style/useSelfClosingElements)


[error] 73-73: 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] 74-74: 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/my_bills.js (4)

43-49: 🛠️ Refactor suggestion

Add dependency array to useEffect to prevent unnecessary re-renders.

The useEffect hook for cleaning up session storage lacks a dependency array, which can cause it to run on every render.

Add an empty dependency array to ensure it runs only once:

useEffect(() => {
  // Cleanup code
- });
+ }, []);

Likely invalid or redundant comment.


79-84: ⚠️ Potential issue

Remove hardcoded report IDs from reportDetails.

Hardcoding report IDs can lead to security risks and should be avoided. Use placeholder values or fetch them dynamically.

Apply this change:

const reportDetails = individualEntry?.additionalDetails?.reportDetails || {
  "status": "FAILED", // INITIATED, COMPLETED, FAILED
- "pdfReportId": "d5a504fb-ebb8-41be-afa0-24b4f1bd575b",
- "excelReportId": "de5f2b24-b60d-4d1f-b550-56abe1dabb2f",
+ "pdfReportId": "",
+ "excelReportId": "",
  "errorMessage": "HCM_AM_BILL_REPORT_GENERATION_FAILED"
};

Likely invalid or redundant comment.


54-69: 🧹 Nitpick (assertive)

Improve robustness of formatTimestampToDate function.

Enhance the function to handle various input types and invalid dates more gracefully.

Apply these changes:

function formatTimestampToDate(timestamp) {
  if (!timestamp || (typeof timestamp !== "number" && typeof timestamp !== "string")) {
    return t("INVALID_TIMESTAMP");
  }
  const date = new Date(timestamp);
+ if (isNaN(date.getTime())) {
+   return t("INVALID_DATE");
+ }
  // Existing date formatting
}

Likely invalid or redundant comment.


116-127: 🧹 Nitpick (assertive)

Add ARIA attributes for better accessibility.

Enhance the accessibility of your application by adding appropriate ARIA roles and labels to components.

Example:

<Card>
+ <div role="region" aria-label={t("HCM_AM_MY_BILLS")}>
  {isFetching ? (
    <Loader aria-label={t("LOADING")} />
  ) : tableData.length === 0 ? (
    <NoResultsFound text={t(`HCM_AM_NO_DATA_FOUND_FOR_BILLS`)} role="alert" />
  ) : (
    <MyBillsTable data={tableData} aria-label={t("HCM_AM_BILLS_TABLE")} />
  )}
+ </div>
</Card>

Likely invalid or redundant comment.

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

1-34: LGTM! Well-structured imports and utility functions.

The imports are well-organized and the utility functions are clear and focused.


197-197: Use self-closing tag for TextBlock component.

🧰 Tools
🪛 Biome (1.9.4)

[error] 197-197: JSX elements without children should be marked as self-closing. In JSX, it is valid for any element to be self-closing.

Unsafe fix: Use a SelfClosingElement instead

(lint/style/useSelfClosingElements)

const downloadExcel = (blob, fileName) => {
const link = document.createElement("a");
link.href = URL.createObjectURL(blob);
link.download = fileName + ".xlsx";
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 template literals instead of string concatenation.

In lines 13 and 47, you're using string concatenation to construct the download attribute for the link element. Using template literals improves readability and aligns with modern JavaScript best practices.

Apply these changes:

Line 13:

- link.download = fileName + ".xlsx";
+ link.download = `${fileName}.xlsx`;

Line 47:

- link.download = fileName + ".pdf";
+ link.download = `${fileName}.pdf`;

Also applies to: 47-47

🧰 Tools
🪛 Biome (1.9.4)

[error] 13-13: Template literals are preferred over string concatenation.

Unsafe fix: Use a template literal.

(lint/style/useTemplate)

Comment on lines +134 to +172
reportDetails?.status === "COMPLETED" ? <Button
className="custom-class"
iconFill=""
icon="FileDownload"
isSuffix
label={t(`HCM_AM_DOWNLOAD_BILLS`)}
showBottom={isLastRow ? false : true}
onOptionSelect={(value) => {
if (value.code === "HCM_AM_PDF") {
if (reportDetails?.pdfReportId) {
downloadPDFWithName({ fileStoreId: reportDetails?.pdfReportId, customName: `${billId}` })
} else {
setShowToast({ key: "error", label: t(`HCM_AM_PDF_GENERATION_FAILED`), transitionTime: 3000 });
}
} else if (value.code === "HCM_AM_EXCEL") {
if (reportDetails?.excelReportId) {
downloadExcelWithName({ fileStoreId: reportDetails?.excelReportId, customName: `${billId}` });
} else {
setShowToast({ key: "error", label: t(`HCM_AM_EXCEL_GENERATION_FAILED`), transitionTime: 3000 });
}

}
}}
options={[
{
code: "HCM_AM_EXCEL",
name: t(`HCM_AM_EXCEL`),
},
{
code: "HCM_AM_PDF",
name: t(`HCM_AM_PDF`),
},
]}
optionsKey="name"
size=""
style={{ minWidth: "15rem" }}
type="actionButton"
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 (assertive)

Add key props to elements in iterables.

When rendering lists in React, each element should have a unique key prop to help React identify which items have changed and manage re-renders efficiently.

Add key props to the elements in the array and JSX elements within the mapped rows.

Example for the array elements in line 127:

return [
  { label: billId, maxLength: 64, key: `billId-${index}` },
  { label: billDate, maxLength: 64, key: `billDate-${index}` },
  // ... other items
];

For the <Button> component in lines 134-172:

- reportDetails?.status === "COMPLETED" ? <Button
+ reportDetails?.status === "COMPLETED" ? <Button
+   key={`download-button-${index}`}
    // ...props
  />

For the <TooltipWrapper> component in lines 173-190:

- <TooltipWrapper
+ <TooltipWrapper
+   key={`tooltip-${index}`}
    // ...props
  >

Also applies to: 173-190

🧰 Tools
🪛 Biome (1.9.4)

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

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

(lint/complexity/noUselessTernary)


[error] 134-172: 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)

Comment on lines +21 to +40
axios
.get("/filestore/v1/files/id", {
responseType: "arraybuffer",
headers: {
"Content-Type": "application/json",
Accept: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
"auth-token": Digit.UserService.getUser()?.["access_token"],
},
params: {
tenantId: Digit.ULBService.getCurrentTenantId(),
fileStoreId: fileStoreId,
},
})
.then(async (res) => {
downloadExcel(
new Blob([res.data], { type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" }),
customName ? customName : "download"
);
});
}
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

Update MIME types and headers in download functions.

In both downloadExcelWithName and downloadPDFWithName, the MIME types and headers are set for Excel files, even in the PDF function. This could cause incorrect file downloads.

Update the MIME types and headers in downloadPDFWithName to match PDF specifications.

Apply these changes in downloadPDFWithName:

Headers (lines 59-62):

headers: {
-   "Content-Type": "application/json",
-   Accept: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
+   "Content-Type": "application/pdf",
+   Accept: "application/pdf",
    "auth-token": Digit.UserService.getUser()?.["access_token"],
},

Blob creation (line 70):

downloadExcel(
-   new Blob([res.data], { type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" }),
+   new Blob([res.data], { type: "application/pdf" }),
    customName ? customName : "download"
);

Also applies to: 55-74

Comment on lines +257 to +265
<Toast
style={{ zIndex: 10001 }}
label={showToast.label}
type={showToast.key}
// error={showToast.key === "error"}
transitionTime={showToast.transitionTime}
onClose={() => setShowToast(null)}
/>
)}
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)

Avoid inline styles for Toast component.

Using inline styles can make the code harder to maintain. Consider using a CSS class or a styled component instead.

Example:

<Toast
-   style={{ zIndex: 10001 }}
    label={showToast.label}
    type={showToast.key}
    transitionTime={showToast.transitionTime}
    onClose={() => setShowToast(null)}
/>

And in your CSS:

.toast-custom {
  z-index: 10001;
}

Then apply the class:

<Toast
  className="toast-custom"
  // ...other props
/>

const history = useHistory();
const url = Digit.Hooks.useQueryParams();
const [showToast, setShowToast] = useState(null);
const tenantId = Digit.ULBService.getCurrentTenantId();
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 state variable showToast if not needed.

If showToast is not being used elsewhere in the code, consider removing it to clean up the state management.

Comment on lines +36 to +242
},
selectedText: {
color: "#ffffff", // White text
},
hoverDay: {
backgroundColor: "#81c784", // Light green on hover
color: "#000000", // Black text on hover
},
};

const handleSelect = (ranges) => {
const { range1: selection } = ranges;
const { startDate, endDate, title, duration } = selection;
setInitialDate((prevState) => ({
...prevState, // Keep the previous values
startDate: startDate, // Update only the `startDate`
}));
if (isStartDateFocused(focusedRange[1])) {
setSelectionRange(selection);
}
if (isEndDateFocused(focusedRange[1])) {
setSelectionRange({ title, duration, startDate, endDate: addSeconds(addMinutes(addHours(endDate, 23), 59), 59) });
setIsModalOpen(false);
}
};

const handleFocusChange = (focusedRange) => {
const [rangeIndex, rangeStep] = focusedRange;
setFocusedRange(focusedRange);
};

const handleClose = () => {
setIsModalOpen(false);
};

function formatDateRange(selectionRange) {
const startDate = new Date(selectionRange.startDate);
const endDate = new Date(selectionRange.endDate);

const format = (date) => {
const day = String(date.getDate()).padStart(2, '0');
const month = String(date.getMonth() + 1).padStart(2, '0'); // Months are 0-indexed
const year = date.getFullYear();
return `${day}/${month}/${year}`;
};

return `${format(startDate)}-${format(endDate)}`;
}


return (
<div className="">
<div className="row border-none date-range-pair">

<TextBlock body={t(`${title}`)}></TextBlock>
<div className="employee-select-wrap attendence-date-picker" style={{ marginBottom: "0" }} ref={wrapperRef}>

<TextInput type="text" className="cursorPointer" onIconSelection={() => {

setIsModalOpen((prevState) => !prevState);
}} onChange={() => { }} populators={{ customIcon: "DateRange" }} value={initialDate.startDate === "" ? null : formatDateRange(selectionRange)}
/>

{isModalOpen && (
<div className="options-card" style={{ overflow: "visible", width: "unset", maxWidth: "fit-content" }}>
<DateRange
className="pickerShadow"
focusedRange={focusedRange}
values={values}
ranges={[selectionRange]}
// rangeColors={["#fbeee8"]}
maxDate={new Date()}
onChange={handleSelect}
onRangeFocusChange={setFocusedRange}
retainEndDateOnFirstSelection={true}
showSelectionPreview={true}
staticRanges={staticRanges}
inputRanges={[]}
// dayContentRenderer={(date) => {
// const isSelected =
// date >= selectionRange.startDate && date <= selectionRange.endDate;
// return (
// <div
// style={{
// ...styles.selectedRange,
// ...(isSelected && styles.selectedText),
// }}
// >
// {date.getDate()}
// </div>
// );
// }}
/>
</div>
)}
</div>
</div>
</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)

Consider performance optimizations for the DateRangePicker component.

While the component is well-structured, consider these architectural improvements:

  1. Memoize callback functions using useCallback
  2. Extract the DateRange modal into a separate component
  3. Consider using a date management library like date-fns-tz for better timezone handling
🧰 Tools
🪛 Biome (1.9.4)

[error] 197-197: JSX elements without children should be marked as self-closing. In JSX, it is valid for any element to be self-closing.

Unsafe fix: Use a SelfClosingElement instead

(lint/style/useSelfClosingElements)


[error] 128-128: This let declares a variable that is only assigned once.

'noOfDays' is never reassigned.

Safe fix: Use const instead.

(lint/style/useConst)

Comment on lines +221 to +235
// dayContentRenderer={(date) => {
// const isSelected =
// date >= selectionRange.startDate && date <= selectionRange.endDate;
// return (
// <div
// style={{
// ...styles.selectedRange,
// ...(isSelected && styles.selectedText),
// }}
// >
// {date.getDate()}
// </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)

Remove commented code.

The commented dayContentRenderer code should either be implemented or removed to maintain clean code.

- // dayContentRenderer={(date) => {
-   const isSelected =
-     date >= selectionRange.startDate && date <= selectionRange.endDate;
-   return (
-     <div
-       style={{
-         ...styles.selectedRange,
-         ...(isSelected && styles.selectedText),
-       }}
-     >
-       {date.getDate()}
-     </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
// dayContentRenderer={(date) => {
// const isSelected =
// date >= selectionRange.startDate && date <= selectionRange.endDate;
// return (
// <div
// style={{
// ...styles.selectedRange,
// ...(isSelected && styles.selectedText),
// }}
// >
// {date.getDate()}
// </div>
// );
// }}
/>
/>

Comment on lines +43 to +61
useEffect(() => {
setSelectionRange(
{
startDate: new Date(epochStartDate),
endDate: new Date(epochEndDate)
})
}, [])

useEffect(() => {
const handleClickOutside = (event) => {
if (wrapperRef.current && !wrapperRef.current.contains(event.target)) {
setIsModalOpen(false);
}
};
document.addEventListener("mousedown", handleClickOutside);
return () => {
document.removeEventListener("mousedown", handleClickOutside);
};
}, [wrapperRef]);
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)

Add cleanup for click outside handler.

The click outside handler is properly set up, but consider using a ref for the handler function to prevent unnecessary re-renders.

+ const handleClickOutside = useRef((event) => {
+   if (wrapperRef.current && !wrapperRef.current.contains(event.target)) {
+     setIsModalOpen(false);
+   }
+ }).current;

  useEffect(() => {
-   const handleClickOutside = (event) => {
-     if (wrapperRef.current && !wrapperRef.current.contains(event.target)) {
-       setIsModalOpen(false);
-     }
-   };
-   document.addEventListener("mousedown", handleClickOutside);
+   document.addEventListener("mousedown", handleClickOutside);
    return () => {
      document.removeEventListener("mousedown", handleClickOutside);
    };
- }, [wrapperRef]);
+ }, [handleClickOutside]);
📝 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(() => {
setSelectionRange(
{
startDate: new Date(epochStartDate),
endDate: new Date(epochEndDate)
})
}, [])
useEffect(() => {
const handleClickOutside = (event) => {
if (wrapperRef.current && !wrapperRef.current.contains(event.target)) {
setIsModalOpen(false);
}
};
document.addEventListener("mousedown", handleClickOutside);
return () => {
document.removeEventListener("mousedown", handleClickOutside);
};
}, [wrapperRef]);
useEffect(() => {
setSelectionRange(
{
startDate: new Date(epochStartDate),
endDate: new Date(epochEndDate)
})
}, [])
const handleClickOutside = useRef((event) => {
if (wrapperRef.current && !wrapperRef.current.contains(event.target)) {
setIsModalOpen(false);
}
}).current;
useEffect(() => {
document.addEventListener("mousedown", handleClickOutside);
return () => {
document.removeEventListener("mousedown", handleClickOutside);
};
}, [handleClickOutside]);

Comment on lines +153 to +167
const handleSelect = (ranges) => {
const { range1: selection } = ranges;
const { startDate, endDate, title, duration } = selection;
setInitialDate((prevState) => ({
...prevState, // Keep the previous values
startDate: startDate, // Update only the `startDate`
}));
if (isStartDateFocused(focusedRange[1])) {
setSelectionRange(selection);
}
if (isEndDateFocused(focusedRange[1])) {
setSelectionRange({ title, duration, startDate, endDate: addSeconds(addMinutes(addHours(endDate, 23), 59), 59) });
setIsModalOpen(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

Extract time constants and improve error handling.

The handleSelect function uses magic numbers for time manipulation and lacks error handling for invalid dates.

+ const TIME_CONSTANTS = {
+   HOURS_IN_DAY: 23,
+   MINUTES_IN_HOUR: 59,
+   SECONDS_IN_MINUTE: 59
+ };

  const handleSelect = (ranges) => {
+   if (!ranges?.range1) {
+     console.error('Invalid range selection');
+     return;
+   }
    const { range1: selection } = ranges;
    const { startDate, endDate, title, duration } = selection;
+   if (!(startDate instanceof Date) || !(endDate instanceof Date)) {
+     console.error('Invalid date objects');
+     return;
+   }
    setInitialDate((prevState) => ({
      ...prevState,
      startDate: startDate,
    }));
    if (isStartDateFocused(focusedRange[1])) {
      setSelectionRange(selection);
    }
    if (isEndDateFocused(focusedRange[1])) {
      setSelectionRange({ 
        title, 
        duration, 
        startDate, 
-       endDate: addSeconds(addMinutes(addHours(endDate, 23), 59), 59)
+       endDate: addSeconds(
+         addMinutes(
+           addHours(endDate, TIME_CONSTANTS.HOURS_IN_DAY),
+           TIME_CONSTANTS.MINUTES_IN_HOUR
+         ),
+         TIME_CONSTANTS.SECONDS_IN_MINUTE
+       )
      });
      setIsModalOpen(false);
    }
  };
📝 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 handleSelect = (ranges) => {
const { range1: selection } = ranges;
const { startDate, endDate, title, duration } = selection;
setInitialDate((prevState) => ({
...prevState, // Keep the previous values
startDate: startDate, // Update only the `startDate`
}));
if (isStartDateFocused(focusedRange[1])) {
setSelectionRange(selection);
}
if (isEndDateFocused(focusedRange[1])) {
setSelectionRange({ title, duration, startDate, endDate: addSeconds(addMinutes(addHours(endDate, 23), 59), 59) });
setIsModalOpen(false);
}
};
const TIME_CONSTANTS = {
HOURS_IN_DAY: 23,
MINUTES_IN_HOUR: 59,
SECONDS_IN_MINUTE: 59
};
const handleSelect = (ranges) => {
if (!ranges?.range1) {
console.error('Invalid range selection');
return;
}
const { range1: selection } = ranges;
const { startDate, endDate, title, duration } = selection;
if (!(startDate instanceof Date) || !(endDate instanceof Date)) {
console.error('Invalid date objects');
return;
}
setInitialDate((prevState) => ({
...prevState,
startDate: startDate,
}));
if (isStartDateFocused(focusedRange[1])) {
setSelectionRange(selection);
}
if (isEndDateFocused(focusedRange[1])) {
setSelectionRange({
title,
duration,
startDate,
endDate: addSeconds(
addMinutes(
addHours(endDate, TIME_CONSTANTS.HOURS_IN_DAY),
TIME_CONSTANTS.MINUTES_IN_HOUR
),
TIME_CONSTANTS.SECONDS_IN_MINUTE
)
});
setIsModalOpen(false);
}
};

Comment on lines +127 to +138
const getDuration = (startDate, endDate) => {
let noOfDays = (new Date(endDate).getTime() - new Date(startDate).getTime()) / (1000 * 3600 * 24);
if (noOfDays > 91) {
return "month";
}
if (noOfDays < 90 && noOfDays >= 14) {
return "week";
}
if (noOfDays <= 14) {
return "day";
}
};
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)

Extract magic numbers into named constants.

The getDuration function uses magic numbers which makes the code less maintainable and harder to understand.

+ const DURATION_THRESHOLDS = {
+   QUARTER: 91,  // days in a quarter
+   FORTNIGHT: 14 // two weeks
+ };
+ 
+ const DURATION_TYPES = {
+   MONTH: 'month',
+   WEEK: 'week',
+   DAY: 'day'
+ };

  const getDuration = (startDate, endDate) => {
-   let noOfDays = (new Date(endDate).getTime() - new Date(startDate).getTime()) / (1000 * 3600 * 24);
+   const noOfDays = (new Date(endDate).getTime() - new Date(startDate).getTime()) / (1000 * 3600 * 24);
-   if (noOfDays > 91) {
-     return "month";
+   if (noOfDays > DURATION_THRESHOLDS.QUARTER) {
+     return DURATION_TYPES.MONTH;
    }
-   if (noOfDays < 90 && noOfDays >= 14) {
-     return "week";
+   if (noOfDays < DURATION_THRESHOLDS.QUARTER && noOfDays >= DURATION_THRESHOLDS.FORTNIGHT) {
+     return DURATION_TYPES.WEEK;
    }
-   if (noOfDays <= 14) {
-     return "day";
+   if (noOfDays <= DURATION_THRESHOLDS.FORTNIGHT) {
+     return DURATION_TYPES.DAY;
    }
  };
📝 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 getDuration = (startDate, endDate) => {
let noOfDays = (new Date(endDate).getTime() - new Date(startDate).getTime()) / (1000 * 3600 * 24);
if (noOfDays > 91) {
return "month";
}
if (noOfDays < 90 && noOfDays >= 14) {
return "week";
}
if (noOfDays <= 14) {
return "day";
}
};
const DURATION_THRESHOLDS = {
QUARTER: 91, // days in a quarter
FORTNIGHT: 14 // two weeks
};
const DURATION_TYPES = {
MONTH: 'month',
WEEK: 'week',
DAY: 'day'
};
const getDuration = (startDate, endDate) => {
const noOfDays = (new Date(endDate).getTime() - new Date(startDate).getTime()) / (1000 * 3600 * 24);
if (noOfDays > DURATION_THRESHOLDS.QUARTER) {
return DURATION_TYPES.MONTH;
}
if (noOfDays < DURATION_THRESHOLDS.QUARTER && noOfDays >= DURATION_THRESHOLDS.FORTNIGHT) {
return DURATION_TYPES.WEEK;
}
if (noOfDays <= DURATION_THRESHOLDS.FORTNIGHT) {
return DURATION_TYPES.DAY;
}
};
🧰 Tools
🪛 Biome (1.9.4)

[error] 128-128: This let declares a variable that is only assigned once.

'noOfDays' is never reassigned.

Safe fix: Use const instead.

(lint/style/useConst)

* attendance inbox in  progress

* composer in progress

* inboxserach composer replaced with custom inbox component

* boundary service API integration implemented for inbox screen

* check box and register search API integration in progress

* table data enriched

* removed debugger

* variable name changed

* tab section functionlity added

* attendance register param changed

* localization code and table value changed

* inbox pagination and status register count fixed

* table component css style changed

* padding removed from table style

* console removed

* HCMPRE-1774: point-1 project drop down is put in the filter section and search section is not required as per last demo

* fliter boundary dropdown in progress

* staffName key changed for attendance mark by

* bug fixes

* code comment added why not used inboxsearch composer

* boundary service made dynamic

* boundary component made dynamic

* boundary component issue fixed for mandatory filed and drop down reset

* commented code removed

* bug fixes done

* ticket: HCMPRE-1822, boundary option reloaded and error scenation handled for project selection and boundary selection in attendance register inbox

* HCMPRE-1822::table rows per page issue fixed, and digit.session storage implemented
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 (28)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/PaymentsCard.js (1)

16-19: ⚠️ Potential issue

Maintain consistent URL pattern across the codebase

The hardcoded /payments-ui/ prefix deviates from the codebase's pattern of using ${window.contextPath}. This could cause routing issues across different environments.

Apply this diff to maintain consistency:

-      link: `/payments-ui/employee/payments/${pathSuffix}`,
+      link: `/${window.contextPath}/employee/payments/${pathSuffix}`,
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/sample.js (9)

6-6: ⚠️ Potential issue

Correct the typo in the prop name updateSeeeionStorage.

The prop updateSeeeionStorage in the BoundaryComponent has a misspelling. It should be updateSessionStorage to match the intended functionality and maintain consistency.

Apply this diff to fix the typo:

-const BoundaryComponent = ({ reset, makeReset, initialValue, updateSeeeionStorage, selectedProject, onChange, lowestLevel, isRequired }) => {
+const BoundaryComponent = ({ reset, makeReset, initialValue, updateSessionStorage, selectedProject, onChange, lowestLevel, isRequired }) => {

7-7: ⚠️ Potential issue

Add null check before accessing boundaryHierarchyOrder.

The variable kk directly accesses map on Digit.SessionStorage.get("boundaryHierarchyOrder") without checking if it's null or undefined. This can cause runtime errors if boundaryHierarchyOrder is not set.

Apply this diff to add a null check:

-  const kk = Digit.SessionStorage.get("boundaryHierarchyOrder").map((item) => item.code);
+  const boundaryHierarchyOrder = Digit.SessionStorage.get("boundaryHierarchyOrder") || [];
+  const kk = boundaryHierarchyOrder.map((item) => item.code);

7-7: 🧹 Nitpick (assertive)

Rename variable kk for better readability.

The variable name kk is not descriptive. Renaming it to something like boundaryHierarchyCodes improves code readability and maintainability.

Apply this diff:

-  const kk = Digit.SessionStorage.get("boundaryHierarchyOrder").map((item) => item.code);
+  const boundaryHierarchyCodes = Digit.SessionStorage.get("boundaryHierarchyOrder").map((item) => item.code);

32-32: 🧹 Nitpick (assertive)

Clarify the usage of lowest vs. lowestLevel.

Both lowest and lowestLevel seem to represent similar concepts. Consider consolidating them or renaming to avoid confusion.


105-115: ⚠️ Potential issue

Add null checks before accessing nested properties in childrenData.

When accessing childrenData[0]?.boundary[0].boundaryType, there's a risk of undefined if boundary or its first element does not exist. This can cause runtime errors.

Apply this diff to ensure safe access:

-    if (childrenData && childrenData.length > 0) {
+    if (childrenData?.length > 0 && childrenData[0]?.boundary?.length > 0 && childrenData[0]?.boundary[0]?.boundaryType) {
       setValue((prevState) => ({
         ...prevState,
         [childrenData[0]?.boundary[0].boundaryType]: [childrenData[0]?.boundary[0]],
       }));

       const formattedData = createFormattedData(childrenData[0]?.boundary[0].boundaryType);
       setBoundaryData(formattedData);
     }

216-216: 🧹 Nitpick (assertive)

⚠️ Potential issue

Simplify the boolean expression for isRequired.

The ternary operations with true and false are unnecessary and can be simplified for clarity.

Apply this diff:

-                    isRequired={isRequired == ScreenTypeEnum.BILL ? true : key == "DISTRICT" ? true : false}
+                    isRequired={isRequired === ScreenTypeEnum.BILL || key === "DISTRICT"}

This removes redundant ternary checks and makes the condition more readable.

🧰 Tools
🪛 Biome (1.9.4)

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

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

(lint/complexity/noUselessTernary)


248-248: 🧹 Nitpick (assertive)

Simplify the condition in TextBlock component.

The check isRequired == true can be simplified to just isRequired.

Apply this diff:

-          <TextBlock body={isRequired == true ? `${t(label)}*` : t(label)} />
+          <TextBlock body={isRequired ? `${t(label)}*` : t(label)} />

34-47: 🧹 Nitpick (assertive)

Remove commented-out code to clean up the file.

Large blocks of commented-out code can clutter the file and should be removed if not needed.

Apply this diff to remove the commented code:

-  // useEffect(() => {
-  //   debugger;
-  //   if (initialValue) {
-  //     setSelectedValues(JSON.parse(initialValue));
-  //     const data = JSON.parse(initialValue);
-  //     const updatedValues = kk.reduce((acc, boundary) => {
-  //       acc[boundary] = data[boundary] ? [data[boundary]] : [];
-  //       return acc;
-  //     }, {});
-
-  //     debugger;
-  //     setValue(updatedValues);
-  //   }
-  // }, []);

88-104: 🧹 Nitpick (assertive)

Remove unused commented-out useEffect block.

The code from lines 88 to 104 is commented out and should be removed if it's no longer needed to keep the codebase clean.

Apply this diff:

-  // useEffect(() => {
-  //   if (selectedProject) {
-  //     setSelectedValues(defaultSelectData);
-  //     setValue(
-  //       kk.reduce((acc, curr) => {
-  //         acc[curr] = [];
-  //         return acc;
-  //       }, {})
-  //     );
-  //     setBoundaryData(defaultBoundaryData);
-  //   }
-
-  //   // if (updateSeeeionStorage) {
-  //   //   updateSeeeionStorage(defaultSelectData);
-  //   // }
-  // }, [selectedProject]);
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/custom_comp/filter_section.js (8)

4-4: 🧹 Nitpick (assertive)

Rename the import path for BoundaryComponent for clarity.

The import path "../sample" is non-descriptive and could be confusing. Consider renaming the file to something more meaningful like "../BoundaryComponent" or updating the import statement to reflect the component's purpose.

Apply this diff:

-import BoundaryComponent from "../sample";
+import BoundaryComponent from "../BoundaryComponent";

41-41: 🧹 Nitpick (assertive)

Use const instead of let for datak.

Since datak is not reassigned, it should be declared with const to prevent accidental reassignment.

Apply this diff:

-      let datak =
+      const datak =
        Digit?.SessionStorage.get("staffProjects") || ...
🧰 Tools
🪛 Biome (1.9.4)

[error] 41-41: This let declares a variable that is only assigned once.

'datak' is never reassigned.

Safe fix: Use const instead.

(lint/style/useConst)


98-104: ⚠️ Potential issue

Provide descriptive text for the SVG icon for accessibility.

The SVG lacks alternative text, making it inaccessible to screen readers. Add an aria-label or <title> to convey its purpose.

Apply this diff:

             <svg
               width="17"
               height="17"
               viewBox="0 0 16 22"
               fill="none"
+              aria-label="Refresh icon"
               xmlns="http://www.w3.org/2000/svg"
             >
🧰 Tools
🪛 Biome (1.9.4)

[error] 98-98: 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)


107-107: 🧹 Nitpick (assertive)

Use self-closing tag for <TextBlock> without children.

When a JSX element has no children, it should be self-closed for cleaner syntax.

Apply this diff:

-      <TextBlock body={`${t("ATTENDANCE_PROJECT_NAME")} *`}></TextBlock>
+      <TextBlock body={`${t("ATTENDANCE_PROJECT_NAME")} *"} />
🧰 Tools
🪛 Biome (1.9.4)

[error] 107-107: JSX elements without children should be marked as self-closing. In JSX, it is valid for any element to be self-closing.

Unsafe fix: Use a SelfClosingElement instead

(lint/style/useSelfClosingElements)


121-121: 🧹 Nitpick (assertive)

Use self-closing tag for <Divider> component.

The <Divider> component has no children and should be self-closed.

Apply this diff:

-      <Divider></Divider>
+      <Divider />
🧰 Tools
🪛 Biome (1.9.4)

[error] 121-121: JSX elements without children should be marked as self-closing. In JSX, it is valid for any element to be self-closing.

Unsafe fix: Use a SelfClosingElement instead

(lint/style/useSelfClosingElements)


137-151: 🧹 Nitpick (assertive)

Convert BoundaryComponent to a self-closing tag.

Since BoundaryComponent does not have children, it should be self-closed.

Apply this diff:

                 <BoundaryComponent
                   reset={reset}
                   makeReset={() => {
                     setReset(false);
                   }}
                   isRequired={isRequired}
                   initialValue={Digit.SessionStorage.get("selectedValues")}
                   updateSeeeionStorage={(newSelectedValues) => {
                     Digit.SessionStorage.set("selectedValues", JSON.stringify(newSelectedValues));
                   }}
                   onChange={onChangeId}
                   selectedProject={projectSelected}
                   lowestLevel={Digit.SessionStorage.get("paymentConfig")?.lowestLevelBoundary || lowerBoundaryDefaultSet}
-                ></BoundaryComponent>
+                />
🧰 Tools
🪛 Biome (1.9.4)

[error] 137-150: JSX elements without children should be marked as self-closing. In JSX, it is valid for any element to be self-closing.

Unsafe fix: Use a SelfClosingElement instead

(lint/style/useSelfClosingElements)


123-134: 🧹 Nitpick (assertive)

Remove commented-out code to keep the codebase clean.

The section from lines 123 to 134 is commented out. If it's no longer needed, consider removing it.

Apply this diff:

-            {/*project && <div style={{ maxWidth: "100%", width: "100%", marginBottom: "24px" }}>
-              <TextBlock body={`${t("ATTENDANCE_PROJECT_NAME")} *`}></TextBlock>
-              <Dropdown
-                t={t}
-                option={project}
-                name={"code"}
-                optionKey={"name"}
-                select={(value) => {
-                  handleProjectChange(value);
-                }}
-              />
-            </div>*/}

8-8: 🧹 Nitpick (assertive)

Remove unused prop projectData.

The projectData prop is declared but never used within CustomFilter. Removing it will clean up the component's interface.

Apply this diff:

-const CustomFilter = ({ resetTable, isRequired, onProjectSelect, onFilterChange, projectData }) => {
+const CustomFilter = ({ resetTable, isRequired, onProjectSelect, onFilterChange }) => {
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/custom_inbox_composer.js (10)

1-1: ⚠️ Potential issue

Remove the unused named import use from React.

The use hook is not a valid named export from React and will cause an error.

Apply this diff:

-import React, { useEffect, useReducer, useState, useMemo, use } from "react";
+import React, { useEffect, useReducer, useState, useMemo } from "react";

13-40: 🧹 Nitpick (assertive)

Consolidate and avoid duplication in JSDoc comments.

The business flow description is duplicated in multiple comment blocks. Consider consolidating them into one block to reduce redundancy.


44-56: 🧹 Nitpick (assertive)

Consider consolidating related state variables into a single state object.

Combining related state variables (filterCriteria, selectedProject, currentPage, etc.) into a single state object can simplify state management.


68-68: 🧹 Nitpick (assertive)

Simplify boolean expression in setCard.

The ternary operator returning true or false is unnecessary. You can directly assign the condition's result.

Apply this diff:

-      setCard(data?.totalCount > 0 ? true : false);
+      setCard(data?.totalCount > 0);

237-237: 🧹 Nitpick (assertive)

Use self-closing tag for <Card> component without children.

The <Card> component on line 237 has no children and should be self-closed.

Apply this diff:

                    <Card style={{ maxWidth: "100%", overflow: "auto", margin: "0px", padding: "0px" }}></Card>
+                   <Card style={{ maxWidth: "100%", overflow: "auto", margin: "0px", padding: "0px" }} />
🧰 Tools
🪛 Biome (1.9.4)

[error] 237-237: JSX elements without children should be marked as self-closing. In JSX, it is valid for any element to be self-closing.

Unsafe fix: Use a SelfClosingElement instead

(lint/style/useSelfClosingElements)


239-248: 🧹 Nitpick (assertive)

Convert <CustomInboxTable> to a self-closing tag.

Since <CustomInboxTable> has no children, it can be self-closed for cleaner syntax.

Apply this diff:

                    <CustomInboxTable
                      statusCount={childrenData?.statusCount}
                      handleTabChange={callServiceOnTap}
                      rowsPerPage={rowsPerPage}
                      customHandleRowsPerPageChange={handleRowsPerPageChange}
                      customHandlePaginationChange={handlePaginationChange}
                      isLoading={childrenDataLoading}
                      tableData={childrenData?.data}
                      totalCount={childrenData?.totalCount}
-                    ></CustomInboxTable>
+                    />
🧰 Tools
🪛 Biome (1.9.4)

[error] 239-248: JSX elements without children should be marked as self-closing. In JSX, it is valid for any element to be self-closing.

Unsafe fix: Use a SelfClosingElement instead

(lint/style/useSelfClosingElements)


224-230: 🧹 Nitpick (assertive)

Convert <CustomFilter> to a self-closing tag.

The <CustomFilter> component does not have children and can be self-closed.

Apply this diff:

                  <CustomFilter
                    resetTable={resetTable}
                    isRequired={ScreenTypeEnum.REGISTER}
                    onProjectSelect={handleProjectChange}
                    projectData={selectedProject}
                    onFilterChange={handleFilterUpdate}
-                  ></CustomFilter>
+                  />
🧰 Tools
🪛 Biome (1.9.4)

[error] 224-230: JSX elements without children should be marked as self-closing. In JSX, it is valid for any element to be self-closing.

Unsafe fix: Use a SelfClosingElement instead

(lint/style/useSelfClosingElements)


209-209: 🧹 Nitpick (assertive)

Use self-closing tag for <CustomInboxSearchLinks> component.

The <CustomInboxSearchLinks> component has no children and should be self-closed.

Apply this diff:

                <CustomInboxSearchLinks headerText={"ATTENDANCE_INBOX_CARD"}></CustomInboxSearchLinks>
+               <CustomInboxSearchLinks headerText={"ATTENDANCE_INBOX_CARD"} />
🧰 Tools
🪛 Biome (1.9.4)

[error] 209-209: JSX elements without children should be marked as self-closing. In JSX, it is valid for any element to be self-closing.

Unsafe fix: Use a SelfClosingElement instead

(lint/style/useSelfClosingElements)


113-113: 🧹 Nitpick (assertive)

Remove or clarify the commented-out error handling.

The comment /// will show estimate data only is ambiguous. Clarify its purpose or remove it if it's obsolete.


170-194: 🧹 Nitpick (assertive)

Optimize event handlers and remove commented code.

Consider debouncing the triggerMusterRollApprove calls to prevent excessive API calls. Also, remove any commented-out code if it's no longer needed.

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 12b115b and a619132.

📒 Files selected for processing (5)
  • 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/bill_inbox/bill_boundary_filter.js (1 hunks)
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/custom_comp/filter_section.js (1 hunks)
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/custom_inbox_composer.js (1 hunks)
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/sample.js (1 hunks)
🧰 Additional context used
📓 Path-based instructions (5)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/PaymentsCard.js (1)

Pattern **/*.js: check

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

Pattern **/*.js: check

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

Pattern **/*.js: check

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

Pattern **/*.js: check

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

Pattern **/*.js: check

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

[error] 24-24: Avoid unnecessary callback in flatMap call.

You can just use flat to flatten the array.
Safe fix: Replace unnecessary flatMap call to flat instead.

(lint/correctness/noFlatMapIdentity)

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

[error] 209-209: JSX elements without children should be marked as self-closing. In JSX, it is valid for any element to be self-closing.

Unsafe fix: Use a SelfClosingElement instead

(lint/style/useSelfClosingElements)


[error] 224-230: JSX elements without children should be marked as self-closing. In JSX, it is valid for any element to be self-closing.

Unsafe fix: Use a SelfClosingElement instead

(lint/style/useSelfClosingElements)


[error] 237-237: JSX elements without children should be marked as self-closing. In JSX, it is valid for any element to be self-closing.

Unsafe fix: Use a SelfClosingElement instead

(lint/style/useSelfClosingElements)


[error] 239-248: JSX elements without children should be marked as self-closing. In JSX, it is valid for any element to be self-closing.

Unsafe fix: Use a SelfClosingElement instead

(lint/style/useSelfClosingElements)

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

[error] 71-81: 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] 86-86: 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] 87-87: 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)

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

[error] 92-97: 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] 98-98: 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] 107-107: JSX elements without children should be marked as self-closing. In JSX, it is valid for any element to be self-closing.

Unsafe fix: Use a SelfClosingElement instead

(lint/style/useSelfClosingElements)


[error] 121-121: JSX elements without children should be marked as self-closing. In JSX, it is valid for any element to be self-closing.

Unsafe fix: Use a SelfClosingElement instead

(lint/style/useSelfClosingElements)


[error] 137-150: JSX elements without children should be marked as self-closing. In JSX, it is valid for any element to be self-closing.

Unsafe fix: Use a SelfClosingElement instead

(lint/style/useSelfClosingElements)


[error] 41-41: This let declares a variable that is only assigned once.

'datak' is never reassigned.

Safe fix: Use const instead.

(lint/style/useConst)

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

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

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

(lint/complexity/noUselessTernary)

🔇 Additional comments (12)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/PaymentsCard.js (5)

11-12: Document the session storage cleanup rationale

The addition of session storage cleanup could affect state persistence. Please add comments explaining why these items need to be cleared on component mount.

Could you verify if this cleanup:

  1. Is intentional and necessary
  2. Won't cause issues if the component remounts while the user is actively using it
  3. Won't affect other components that might depend on this data

29-31: LGTM! Well-structured link generation with role-based access

The link generation is well-organized with appropriate role-based access control for each functionality.


34-36: LGTM! Clear and concise role validation

The role checking logic is well-implemented with proper null checks and role validation.


44-44: Verify styling class name convention

Please confirm that "microplan-employee-module-card" follows the project's naming conventions for CSS classes.

Run this script to check for consistent class naming patterns:

#!/bin/bash
# Search for similar class naming patterns in the codebase
rg -i 'className.*employee.*module.*card' health/micro-ui/web/micro-ui-internals/

23-23: 🧹 Nitpick (assertive)

Optimize array flattening operation

The flatMap usage can be simplified.

Apply this diff to optimize the array flattening:

-if (!Digit.Utils.didEmployeeHasAtleastOneRole(Object.values(ROLES).flatMap((e) => e))) {
+if (!Digit.Utils.didEmployeeHasAtleastOneRole(Object.values(ROLES).flat())) {

Likely invalid or redundant comment.

health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/bill_inbox/bill_boundary_filter.js (6)

116-116: 🛠️ Refactor suggestion

Fix typo in prop name

The prop name updateSeeeionStorage contains a typo.

-   updateSeeeionStorage={(newSelectedValues) => {
+   updateSessionStorage={(newSelectedValues) => {

Likely invalid or redundant comment.


3-3: 🛠️ Refactor suggestion

Remove unused import CheckBox

The CheckBox component is imported but never used in this file.

- import { CheckBox, SubmitBar } from "@egovernments/digit-ui-components";
+ import { SubmitBar } from "@egovernments/digit-ui-components";

Likely invalid or redundant comment.


51-55: 🛠️ Refactor suggestion

Use consistent state reset values

The boundary state is reset using an empty string in handleClearFilter but null elsewhere in the code. This inconsistency could lead to bugs.

    const handleClearFilter = () => {
        setResetFilters(true);
-       setBoundary(""); // Clear the boundary value
+       setBoundary(null); // Clear the boundary value
        setBoundaryKey((prevKey) => prevKey + 1);
    };

Likely invalid or redundant comment.


36-44: ⚠️ Potential issue

Add missing dependency to useEffect

The updateBoundaryFilters value is used inside the effect but not included in the dependency array. This could lead to stale closures.

    }, [levelSelected])
+   }, [levelSelected, updateBoundaryFilters])

Likely invalid or redundant comment.


71-81: ⚠️ Potential issue

Add keyboard event handlers for accessibility

The div with onClick handler should support keyboard navigation.

    <div 
        onClick={handleClearFilter}
+       onKeyPress={(e) => { if (e.key === 'Enter') handleClearFilter(); }}
+       role="button"
+       tabIndex={0}
        style={{

Likely invalid or redundant comment.

🧰 Tools
🪛 Biome (1.9.4)

[error] 71-81: 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)


87-92: ⚠️ Potential issue

Add accessibility attributes to SVG

SVG elements should have proper accessibility attributes for screen readers.

    <svg 
+       role="img"
+       aria-label={t("HCM_AM_REFRESH")}
        width="17" 
        height="17" 
        viewBox="0 0 16 22"
    >

Likely invalid or redundant comment.

🧰 Tools
🪛 Biome (1.9.4)

[error] 87-87: 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)

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

92-97: ⚠️ Potential issue

Add keyboard event handling for accessibility.

The <span> element with an onClick handler should also handle keyboard events to be accessible for users who navigate via keyboard.

Apply this diff:

               onClick={() => {
                 setReset(true);
               }}
+              onKeyPress={(e) => {
+                if (e.key === "Enter") {
+                  setReset(true);
+                }
+              }}
               style={{ border: "1px solid #e0e0e0", padding: "6px", marginBottom: "10px", cursor: "pointer" }}
               tabIndex="0"
               role="button"

This ensures that the element is accessible via keyboard navigation.

Likely invalid or redundant comment.

🧰 Tools
🪛 Biome (1.9.4)

[error] 92-97: 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)

import { CheckBox, SubmitBar } from "@egovernments/digit-ui-components";
import BoundaryComponent from "../sample";
import { Card, SVG, Button, ButtonGroup, TextBlock, Dropdown, Toast } from "@egovernments/digit-ui-components";
const BillBoundaryFilter = ({ isRequired, selectedProject, selectedLevel, onFilterChange, updateBoundaryFilters }) => {
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)

Add PropTypes or TypeScript definitions

Add prop type definitions to improve code maintainability and catch potential type-related issues early.

Example with PropTypes:

import PropTypes from 'prop-types';

BillBoundaryFilter.propTypes = {
  isRequired: PropTypes.bool,
  selectedProject: PropTypes.object,
  selectedLevel: PropTypes.object,
  onFilterChange: PropTypes.func.isRequired,
  updateBoundaryFilters: PropTypes.bool
};

Comment on lines +95 to +106
{/*project && <div style={{ maxWidth: "100%", width: "100%", marginBottom: "24px" }}>
<TextBlock body={`${t("ATTENDANCE_PROJECT_NAME")} *`}></TextBlock>
<Dropdown
t={t}
option={project}
name={"code"}
optionKey={"name"}
select={(value) => {
handleProjectChange(value);
}}
/>
</div>*/}
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 commented code

Remove the commented-out code block. If this code might be needed later, track it in version control instead.

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

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

79-84: ⚠️ Potential issue

Security: Remove hardcoded report IDs.

The presence of hardcoded UUIDs could pose a security risk if these are actual production IDs.

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between a619132 and a4b50c7.

📒 Files selected for processing (7)
  • 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/bill_inbox/BillInbox.js (1 hunks)
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/bill_inbox/bill_boundary_filter.js (1 hunks)
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/custom_inbox_composer.js (1 hunks)
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/sample.js (1 hunks)
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/pages/employee/index.js (1 hunks)
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/pages/employee/my_bills.js (1 hunks)
🧰 Additional context used
📓 Path-based instructions (7)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/PaymentsCard.js (1)

Pattern **/*.js: check

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

Pattern **/*.js: check

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

Pattern **/*.js: check

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

Pattern **/*.js: check

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

Pattern **/*.js: check

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

Pattern **/*.js: check

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

Pattern **/*.js: check

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

[error] 29-29: Avoid unnecessary callback in flatMap call.

You can just use flat to flatten the array.
Safe fix: Replace unnecessary flatMap call to flat instead.

(lint/correctness/noFlatMapIdentity)

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

[error] 210-210: JSX elements without children should be marked as self-closing. In JSX, it is valid for any element to be self-closing.

Unsafe fix: Use a SelfClosingElement instead

(lint/style/useSelfClosingElements)


[error] 225-231: JSX elements without children should be marked as self-closing. In JSX, it is valid for any element to be self-closing.

Unsafe fix: Use a SelfClosingElement instead

(lint/style/useSelfClosingElements)


[error] 238-238: JSX elements without children should be marked as self-closing. In JSX, it is valid for any element to be self-closing.

Unsafe fix: Use a SelfClosingElement instead

(lint/style/useSelfClosingElements)


[error] 240-249: JSX elements without children should be marked as self-closing. In JSX, it is valid for any element to be self-closing.

Unsafe fix: Use a SelfClosingElement instead

(lint/style/useSelfClosingElements)

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

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

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

(lint/complexity/noUselessTernary)

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

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

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

(lint/complexity/noUselessTernary)


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

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

(lint/complexity/noUselessTernary)


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

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

(lint/complexity/noUselessTernary)


[error] 193-201: JSX elements without children should be marked as self-closing. In JSX, it is valid for any element to be self-closing.

Unsafe fix: Use a SelfClosingElement instead

(lint/style/useSelfClosingElements)


[error] 204-205: JSX elements without children should be marked as self-closing. In JSX, it is valid for any element to be self-closing.

Unsafe fix: Use a SelfClosingElement instead

(lint/style/useSelfClosingElements)


[error] 218-225: JSX elements without children should be marked as self-closing. In JSX, it is valid for any element to be self-closing.

Unsafe fix: Use a SelfClosingElement instead

(lint/style/useSelfClosingElements)


[error] 262-271: JSX elements without children should be marked as self-closing. In JSX, it is valid for any element to be self-closing.

Unsafe fix: Use a SelfClosingElement instead

(lint/style/useSelfClosingElements)


[error] 281-293: 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] 304-320: 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/components/sample.js

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

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

(lint/complexity/noUselessTernary)

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

[error] 75-85: 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] 90-90: 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] 91-91: 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)

🔇 Additional comments (40)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/pages/employee/my_bills.js (5)

1-8: Optimize imports for better maintainability.

  1. Consolidate imports from similar packages (@egovernments/digit-ui-react-components and @egovernments/digit-ui-components)
  2. Remove unused imports: useMemo, InboxSearchComposer

16-20: Initialize date state with null values for consistency.


22-22: Add null check for SessionStorage access.


43-50: Fix effect dependencies and consolidate storage cleanup.


112-127: Improve loading states and accessibility.

health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/bill_inbox/bill_boundary_filter.js (7)

3-3: Remove unused import CheckBox

The CheckBox component imported from @egovernments/digit-ui-components is not used in this file. Removing it will clean up the code.


45-45: Add updateBoundaryFilters to the dependency array in useEffect

The useEffect hook uses updateBoundaryFilters but does not include it in the dependency array. This could lead to unexpected behavior if updateBoundaryFilters changes without triggering the effect.


54-54: Ensure consistent reset of boundary state

In handleClearFilter, you reset boundary using setBoundary(""), whereas in other parts of the code, setBoundary(null) is used. For consistency and to prevent potential issues, consider using null throughout to represent an unset boundary.


75-85: Enhance accessibility by adding keyboard event handlers

The <div> element with an onClick handler should support keyboard interactions for accessibility. Add onKeyPress and tabIndex={0} to enable keyboard navigation for users who rely on keyboards.

🧰 Tools
🪛 Biome (1.9.4)

[error] 75-85: 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)


90-90: Improve accessibility of the clickable <span> element

The <span> element with an onClick handler should support keyboard interactions and have appropriate accessibility attributes. Consider changing it to a <button> or adding tabIndex and onKeyPress to enhance accessibility.

🧰 Tools
🪛 Biome (1.9.4)

[error] 90-90: 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)


91-91: Provide alternative text for SVG elements

The <svg> element should include accessibility attributes such as role="img" and aria-label or a <title> element to describe the image for assistive technologies.

🧰 Tools
🪛 Biome (1.9.4)

[error] 91-91: 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)


120-120: Fix the spelling of updateSeeeionStorage

The prop updateSeeeionStorage appears to be misspelled. Correcting it to updateSessionStorage will improve code readability and avoid confusion.

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

6-6: Fix the spelling of updateSeeeionStorage

The prop updateSeeeionStorage in BoundaryComponent is misspelled. Correcting it to updateSessionStorage will improve readability and prevent potential confusion.


7-7: Add null check before accessing boundaryHierarchyOrder

Ensure that Digit.SessionStorage.get("boundaryHierarchyOrder") returns a valid array before calling .map on it to avoid potential runtime errors if the session storage item is null or undefined.


32-33: Clarify the usage of lowest versus lowestLevel

Variables lowest and lowestLevel seem to represent similar concepts. Consider consolidating them or renaming one to enhance code clarity and reduce confusion.


216-216: Simplify the boolean expression for isRequired

The conditional assignment to isRequired can be simplified for better readability. Instead of using a ternary operator, you can use logical expressions.

🧰 Tools
🪛 Biome (1.9.4)

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

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

(lint/complexity/noUselessTernary)


248-248: Simplify the boolean check for isRequired in TextBlock

You can simplify the expression isRequired == true to just isRequired for cleaner and more concise code.

health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/bill_inbox/BillInbox.js (12)

1-1: Remove unused and invalid imports

The imports useReducer, useMemo, and use are not used in this file. Additionally, use is not a valid React hook and may have been included by mistake. Please remove these to clean up the code.

Apply this diff:

- import React, { useEffect, useReducer, useState, useMemo, use } from "react";
+ import React, { useEffect, useState } from "react";

5-5: Define location or use useLocation hook

The variable location is used but not defined in this scope. If you intend to access the browser's location or the route's state, consider importing useLocation from react-router-dom and using it to retrieve the location object.

Apply this diff to import useLocation and update the code:

+ import { useLocation } from "react-router-dom";

...

- const { fromViewScreen } = location.state || false;
+ const location = useLocation();
+ const { fromViewScreen } = location.state || {};

23-23: Remove commented-out code

The commented-out line is unnecessary and can be removed to keep the code clean.

Apply this diff:

- // const [selectedBoundaryCode, setSelectedBoundaryCode] = useState(null);

44-44: Use triple equals and optional chaining for session storage

Using triple equals avoids subtle type-coercion pitfalls. Also, consider optional chaining on Digit.SessionStorage.get("paymentInbox") to prevent potential runtime errors if the stored object is missing.

Apply this diff:

- referenceId: selectedProject == undefined ? Digit.SessionStorage.get("paymentInbox").selectedProject?.id : selectedProject?.id,
+ referenceId: selectedProject === undefined
+   ? Digit.SessionStorage.get("paymentInbox")?.selectedProject?.id
+   : selectedProject?.id,

48-48: Simplify the boolean expression

Instead of using a ternary operator returning true/false from a logical expression, you can directly assign the expression's result.

Apply this diff:

- isChildrenRequired: selectedLevel != null && selectedLevel?.code === "DISTRICT" ? true : false,
+ isChildrenRequired: !!(selectedLevel != null && selectedLevel?.code === "DISTRICT"),
🧰 Tools
🪛 Biome (1.9.4)

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

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

(lint/complexity/noUselessTernary)


51-51: Simplify the boolean expression

Instead of using a ternary operator returning true/false from a logical expression, you can directly assign the expression's result.

Apply this diff:

- enabled: selectedBoundaryCode && selectedProject ? true : false,
+ enabled: !!(selectedBoundaryCode && selectedProject),
🧰 Tools
🪛 Biome (1.9.4)

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

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

(lint/complexity/noUselessTernary)


193-201: Use a self-closing tag for <CustomInboxSearchLinks>

When a JSX element has no child content, prefer using a self-closing tag.

Apply this diff:

- <CustomInboxSearchLinks
-     headerText={"HCM_AM_BILL_INBOX"}
-     links={[
-         {
-             url: "/employee/payments/my-bills",
-             text: "HCM_AM_MY_BILLS",
-         },
-     ]}
- ></CustomInboxSearchLinks>
+ <CustomInboxSearchLinks
+     headerText={"HCM_AM_BILL_INBOX"}
+     links={[
+         {
+             url: "/employee/payments/my-bills",
+             text: "HCM_AM_MY_BILLS",
+         },
+     ]}
+ />
🧰 Tools
🪛 Biome (1.9.4)

[error] 193-201: JSX elements without children should be marked as self-closing. In JSX, it is valid for any element to be self-closing.

Unsafe fix: Use a SelfClosingElement instead

(lint/style/useSelfClosingElements)


204-205: Use a self-closing tag for <BillSearchBox>

JSX elements without child content should be self-closing.

Apply this diff:

- <BillSearchBox onLevelSelect={handleSearchChange} initialProject={selectedProject}
-     initialAggregationLevel={selectedLevel}></BillSearchBox>
+ <BillSearchBox onLevelSelect={handleSearchChange} initialProject={selectedProject}
+     initialAggregationLevel={selectedLevel} />
🧰 Tools
🪛 Biome (1.9.4)

[error] 204-205: JSX elements without children should be marked as self-closing. In JSX, it is valid for any element to be self-closing.

Unsafe fix: Use a SelfClosingElement instead

(lint/style/useSelfClosingElements)


281-293: Add a key property when returning elements in an array

When returning an array of elements in JSX, each element should have a unique key prop to help React identify which items have changed.

Apply this diff:

 actionFields={[
-    <Button
+    <Button
+        key="generate-bill-btn"
         icon="CheckCircle"
         label={t(`HCM_AM_GENERATE_BILL_LABEL`)}
         onClick={() => {
             triggerGenerateBill();
         }}
         style={{
             minWidth: "14rem",
         }}
         type="button"
         variation="primary"
         isDisabled={generateBillMutation.isLoading}
     />,
 ]}
🧰 Tools
🪛 Biome (1.9.4)

[error] 281-293: 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)


304-320: Add a key property when returning elements in an array

When returning an array of elements in JSX, each element should have a unique key prop to help React identify which items have changed.

Apply this diff:

 actionFields={[
-    <Button
+    <Button
+        key="generate-bill-btn"
         icon="CheckCircle"
         label={t(`HCM_AM_GENERATE_BILL_LABEL`)}
         onClick={() => {
             !showGenerateBillAction || BillData?.bills?.length >= 0
                 ? setShowToast({ key: "info", label: t("HCM_AM_GENERATE_BILLS_CANNOT_BE_CALLED_INFO_MESSAGE"), transitionTime: 5000 })
                 : triggerGenerateBill();
         }}
         style={{
             minWidth: "14rem",
             cursor: !showGenerateBillAction || BillData?.bills?.length >= 0 ? "not-allowed" : "pointer",
             opacity: !showGenerateBillAction || BillData?.bills?.length >= 0 ? 0.5 : 1,
         }}
         type="button"
         variation="primary"
         isDisabled={generateBillMutation.isLoading}
     />,
 ]}
🧰 Tools
🪛 Biome (1.9.4)

[error] 304-320: 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)


308-310: Logical error in the onClick handler condition

The condition in the onClick handler may contain a logical error. The expression BillData?.bills?.length >= 0 will always be true when length is 0 or more, meaning it will always evaluate to true, and triggerGenerateBill() will not be called.

Consider revising the condition to correctly reflect the intended logic. If you intend to check if there are no bills, you might use:

- !showGenerateBillAction || BillData?.bills?.length >= 0
+ !showGenerateBillAction || BillData?.bills?.length > 0

Alternatively, adjust the condition to match your intended logic.


68-68: 🧹 Nitpick (assertive)

Simplify the boolean expression

Instead of using a ternary operator returning true/false from a logical expression, you can directly assign the expression's result.

Apply this diff:

- enabled: selectedBoundaryCode ? true : false,
+ enabled: !!selectedBoundaryCode,

Likely invalid or redundant comment.

🧰 Tools
🪛 Biome (1.9.4)

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

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

(lint/complexity/noUselessTernary)

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

18-18: Handle potential undefined state in useLocation

Destructuring from local?.state || false may cause an error if local.state is undefined because destructuring properties from false is invalid. Consider defaulting to an empty object {} instead to ensure safe destructuring.

Apply this diff to fix the issue:

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

46-46: Use optional chaining with window.contextPath to prevent runtime errors

Accessing window.contextPath without optional chaining may cause a runtime error if contextPath is undefined. Consider using window?.contextPath.

Apply this diff to fix the issue:

- if (window.location.pathname !== `/${window.contextPath}/employee/`) {
+ if (window.location.pathname !== `/${window?.contextPath}/employee/`) {

61-67: Avoid inline function components in routes for performance

Using inline arrow functions in component={() => <Component />} can lead to unnecessary re-renders. Instead, pass the component reference directly or use children to enhance performance.

Apply this diff to refactor:

- <PrivateRoute path={`${path}/view-attendance`} component={() => <ViewAttendance />} />
- <PrivateRoute path={`${path}/edit-attendance`} component={() => <ViewAttendance editAttendance={true} />} />
- <PrivateRoute path={`${path}/attendance-approve-success`} component={() => <Response />} />
- <PrivateRoute path={`${path}/attendance-approve-failed`} component={() => <Response />} />
- <PrivateRoute path={`${path}/registers-inbox`} component={() => <AttendanceInbox />} />
- <PrivateRoute path={`${path}/generate-bill`} component={() => <BillInbox />} />
- <PrivateRoute path={`${path}/my-bills`} component={() => <MyBills />} />
+ <PrivateRoute path={`${path}/view-attendance`} component={ViewAttendance} />
+ <PrivateRoute path={`${path}/edit-attendance`}>
+   <ViewAttendance editAttendance={true} />
+ </PrivateRoute>
+ <PrivateRoute path={`${path}/attendance-approve-success`} component={Response} />
+ <PrivateRoute path={`${path}/attendance-approve-failed`} component={Response} />
+ <PrivateRoute path={`${path}/registers-inbox`} component={AttendanceInbox} />
+ <PrivateRoute path={`${path}/generate-bill`} component={BillInbox} />
+ <PrivateRoute path={`${path}/my-bills`} component={MyBills} />
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/components/custom_inbox_composer.js (6)

1-1: Remove the unused named import use from React

There is no use named export from react, and attempting to import it will cause an error. Please remove it to prevent compilation issues.

Apply this diff to fix the issue:

- import React, { useEffect, useReducer, useState, useMemo, use } from "react";
+ import React, { useEffect, useReducer, useState, useMemo } from "react";

13-40: Enhance JSDoc documentation with parameter and return type information

While the business flow documentation is comprehensive, consider adding @param tags for component props and an @returns tag describing the rendered output for better clarity.


210-210: Use self-closing tag for JSX elements without children

The CustomInboxSearchLinks component has no children and can be self-closed to improve readability.

Apply this diff:

- <CustomInboxSearchLinks headerText={"ATTENDANCE_INBOX_CARD"}></CustomInboxSearchLinks>
+ <CustomInboxSearchLinks headerText={"ATTENDANCE_INBOX_CARD"} />
🧰 Tools
🪛 Biome (1.9.4)

[error] 210-210: JSX elements without children should be marked as self-closing. In JSX, it is valid for any element to be self-closing.

Unsafe fix: Use a SelfClosingElement instead

(lint/style/useSelfClosingElements)


238-238: Use self-closing tag for <Card> component without children

The <Card> component has no children and can be self-closed to improve readability.

Apply this diff:

- <Card style={{ maxWidth: "100%", overflow: "auto", margin: "0px", padding: "0px" }}></Card>
+ <Card style={{ maxWidth: "100%", overflow: "auto", margin: "0px", padding: "0px" }} />
🧰 Tools
🪛 Biome (1.9.4)

[error] 238-238: JSX elements without children should be marked as self-closing. In JSX, it is valid for any element to be self-closing.

Unsafe fix: Use a SelfClosingElement instead

(lint/style/useSelfClosingElements)


225-231: 🧹 Nitpick (assertive)

Use self-closing tag for <CustomFilter> component

Since <CustomFilter> does not contain children, it can be self-closed to enhance code clarity.

Apply this diff:

- <CustomFilter
    resetTable={resetTable}
    isRequired={ScreenTypeEnum.REGISTER}
    onProjectSelect={handleProjectChange}
    projectData={selectedProject}
    onFilterChange={handleFilterUpdate}
  ></CustomFilter>
+ <CustomFilter
    resetTable={resetTable}
    isRequired={ScreenTypeEnum.REGISTER}
    onProjectSelect={handleProjectChange}
    projectData={selectedProject}
    onFilterChange={handleFilterUpdate}
  />

Likely invalid or redundant comment.

🧰 Tools
🪛 Biome (1.9.4)

[error] 225-231: JSX elements without children should be marked as self-closing. In JSX, it is valid for any element to be self-closing.

Unsafe fix: Use a SelfClosingElement instead

(lint/style/useSelfClosingElements)


240-249: 🧹 Nitpick (assertive)

Use self-closing tag for <CustomInboxTable> component

Since <CustomInboxTable> does not contain children, it can be self-closed to enhance code clarity.

Apply this diff:

- <CustomInboxTable
    statusCount={childrenData?.statusCount}
    handleTabChange={callServiceOnTap}
    rowsPerPage={rowsPerPage}
    customHandleRowsPerPageChange={handleRowsPerPageChange}
    customHandlePaginationChange={handlePaginationChange}
    isLoading={childrenDataLoading}
    tableData={childrenData?.data}
    totalCount={childrenData?.totalCount}
  ></CustomInboxTable>
+ <CustomInboxTable
    statusCount={childrenData?.statusCount}
    handleTabChange={callServiceOnTap}
    rowsPerPage={rowsPerPage}
    customHandleRowsPerPageChange={handleRowsPerPageChange}
    customHandlePaginationChange={handlePaginationChange}
    isLoading={childrenDataLoading}
    tableData={childrenData?.data}
    totalCount={childrenData?.totalCount}
  />

Likely invalid or redundant comment.

🧰 Tools
🪛 Biome (1.9.4)

[error] 240-249: JSX elements without children should be marked as self-closing. In JSX, it is valid for any element to be self-closing.

Unsafe fix: Use a SelfClosingElement instead

(lint/style/useSelfClosingElements)

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

11-17: Ensure consistent session storage management

The addition of multiple Digit.SessionStorage.del calls enhances session management by clearing specific data upon component mount. Ensure that this aligns with the application's overall session handling strategy.


29-29: Simplify flatMap usage to flat

The callback in Object.values(ROLES).flatMap((e) => e) is unnecessary as it returns the elements directly. Simplify by using flat() instead.

Apply this diff:

- if (!Digit.Utils.didEmployeeHasAtleastOneRole(Object.values(ROLES).flatMap((e) => e))) {
+ if (!Digit.Utils.didEmployeeHasAtleastOneRole(Object.values(ROLES).flat())) {
🧰 Tools
🪛 Biome (1.9.4)

[error] 29-29: Avoid unnecessary callback in flatMap call.

You can just use flat to flatten the array.
Safe fix: Replace unnecessary flatMap call to flat instead.

(lint/correctness/noFlatMapIdentity)

Comment on lines +24 to +41
const BillSearchCri = {
url: `/health-expense/bill/v1/_search`,
body: {
billCriteria: {
tenantId: tenantId,
// ...(project?.[0]?.address?.boundaryType !== "COUNTRY" ? { localityCode: project?.[0]?.address?.boundary } : {}),
referenceIds: [project?.[0]?.id],
...(billID ? { billNumbers: [billID] } : {}),
...(dateRange.startDate && dateRange.endDate ? { fromDate: new Date(dateRange.startDate).getTime(), toDate: new Date(dateRange.endDate).getTime() } : {})
}
},
config: {
enabled: project ? true : false,
select: (data) => {
return data;
},
},
};
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

Add error handling for API failures.

The API configuration lacks proper error handling which could lead to silent failures. Consider adding error boundaries or error states to handle API failures gracefully.

 const BillSearchCri = {
     config: {
         enabled: Boolean(project),
         select: (data) => {
+            if (!data?.bills) {
+                throw new Error('Invalid response format');
+            }
             return data;
         },
+        onError: (error) => {
+            console.error('Bill search failed:', error);
+            Digit.NotificationService.error(
+                t('HCM_AM_BILL_FETCH_ERROR'),
+                error.message
+            );
+        }
     },
 };

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

🧰 Tools
🪛 Biome (1.9.4)

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

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

(lint/complexity/noUselessTernary)

Comment on lines +218 to +225
<BillBoundaryFilter
isRequired={ScreenTypeEnum.BILL}
selectedProject={selectedProject}
selectedLevel={selectedLevel}
onFilterChange={handleFilterUpdate}
updateBoundaryFilters={updateFilters}
resetBoundaryFilter={resetBoundaryFilter}
></BillBoundaryFilter>
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 a self-closing tag for <BillBoundaryFilter>

JSX elements without child content should be self-closing.

Apply this diff:

- <BillBoundaryFilter
-     isRequired={ScreenTypeEnum.BILL}
-     selectedProject={selectedProject}
-     selectedLevel={selectedLevel}
-     onFilterChange={handleFilterUpdate}
-     updateBoundaryFilters={updateFilters}
-     resetBoundaryFilter={resetBoundaryFilter}
- ></BillBoundaryFilter>
+ <BillBoundaryFilter
+     isRequired={ScreenTypeEnum.BILL}
+     selectedProject={selectedProject}
+     selectedLevel={selectedLevel}
+     onFilterChange={handleFilterUpdate}
+     updateBoundaryFilters={updateFilters}
+     resetBoundaryFilter={resetBoundaryFilter}
+ />
📝 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
<BillBoundaryFilter
isRequired={ScreenTypeEnum.BILL}
selectedProject={selectedProject}
selectedLevel={selectedLevel}
onFilterChange={handleFilterUpdate}
updateBoundaryFilters={updateFilters}
resetBoundaryFilter={resetBoundaryFilter}
></BillBoundaryFilter>
<BillBoundaryFilter
isRequired={ScreenTypeEnum.BILL}
selectedProject={selectedProject}
selectedLevel={selectedLevel}
onFilterChange={handleFilterUpdate}
updateBoundaryFilters={updateFilters}
resetBoundaryFilter={resetBoundaryFilter}
/>
🧰 Tools
🪛 Biome (1.9.4)

[error] 218-225: JSX elements without children should be marked as self-closing. In JSX, it is valid for any element to be self-closing.

Unsafe fix: Use a SelfClosingElement instead

(lint/style/useSelfClosingElements)

Comment on lines +262 to +271
<BillInboxTable
isFetching={isFetching}
tableData={tableData}
currentPage={currentPage}
rowsPerPage={rowsPerPage}
handlePageChange={handlePageChange}
handlePerRowsChange={handlePerRowsChange}
totalCount={totalCount}
status={activeLink.code}
></BillInboxTable>
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 a self-closing tag for <BillInboxTable>

JSX elements without child content should be self-closing.

Apply this diff:

- <BillInboxTable
-     isFetching={isFetching}
-     tableData={tableData}
-     currentPage={currentPage}
-     rowsPerPage={rowsPerPage}
-     handlePageChange={handlePageChange}
-     handlePerRowsChange={handlePerRowsChange}
-     totalCount={totalCount}
-     status={activeLink.code}
- ></BillInboxTable>
+ <BillInboxTable
+     isFetching={isFetching}
+     tableData={tableData}
+     currentPage={currentPage}
+     rowsPerPage={rowsPerPage}
+     handlePageChange={handlePageChange}
+     handlePerRowsChange={handlePerRowsChange}
+     totalCount={totalCount}
+     status={activeLink.code}
+ />
📝 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
<BillInboxTable
isFetching={isFetching}
tableData={tableData}
currentPage={currentPage}
rowsPerPage={rowsPerPage}
handlePageChange={handlePageChange}
handlePerRowsChange={handlePerRowsChange}
totalCount={totalCount}
status={activeLink.code}
></BillInboxTable>
<BillInboxTable
isFetching={isFetching}
tableData={tableData}
currentPage={currentPage}
rowsPerPage={rowsPerPage}
handlePageChange={handlePageChange}
handlePerRowsChange={handlePerRowsChange}
totalCount={totalCount}
status={activeLink.code}
/>
🧰 Tools
🪛 Biome (1.9.4)

[error] 262-271: JSX elements without children should be marked as self-closing. In JSX, it is valid for any element to be self-closing.

Unsafe fix: Use a SelfClosingElement instead

(lint/style/useSelfClosingElements)

Comment on lines +74 to +78
filterData?.code == undefined || filterData?.code == null
? filterCriteria?.code == undefined || filterCriteria?.code == null
? Digit.SessionStorage.get("paymentInbox").code
: filterCriteria?.code
: filterData?.code,
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 nested ternary operators for better readability

The nested ternary operators in the localityCode parameter make the code difficult to read and maintain. Consider refactoring to improve clarity.

You can refactor the code as follows:

let localityCode;

if (filterData?.code !== undefined && filterData?.code !== null) {
  localityCode = filterData.code;
} else if (filterCriteria?.code !== undefined && filterCriteria?.code !== null) {
  localityCode = filterCriteria.code;
} else {
  localityCode = Digit.SessionStorage.get("paymentInbox")?.code;
}

// Update the params object
params: {
  // ... other params
  localityCode: localityCode,
  // ... other params
}

return {
label: t(labelKey),
link: `/${window?.contextPath}/employee/payments/${pathSuffix}`,
link: `/payments-ui/employee/payments/${pathSuffix}`,
Copy link
Contributor

Choose a reason for hiding this comment

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

💡 Codebase verification

Use window.contextPath instead of hardcoded /payments-ui prefix

The hardcoded path /payments-ui/employee/payments/${pathSuffix} should be changed to /${window.contextPath}/employee/payments/${pathSuffix} to:

  • Align with the application's routing configuration
  • Maintain consistency with other URLs in the health-payments module
  • Support different environments where CONTEXT_PATH may be configured differently
🔗 Analysis chain

Verify the hardcoded URL path

The link in generateLink uses a hardcoded path /payments-ui/employee/payments/${pathSuffix}. Confirm that this hardcoded path aligns with the application's routing configuration and will work correctly in different environments.

Run the following script to check the usage of window.contextPath in the codebase:

This will help ensure consistent usage and avoid potential routing issues.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Search for usage of window.contextPath in link generation

rg 'window\.contextPath'

Length of output: 34839

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

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 30ffe96 and b095cba.

📒 Files selected for processing (1)
  • health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/pages/employee/ViewAttendance.js (2 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/pages/employee/ViewAttendance.js (1)

Pattern **/*.js: check

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

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

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

(lint/complexity/noUselessTernary)


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

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

(lint/complexity/noUselessTernary)


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

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

(lint/complexity/noUselessTernary)


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

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

(lint/complexity/noUselessTernary)


[error] 480-490: 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] 492-504: 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] 506-535: 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)

🔇 Additional comments (6)
health/micro-ui/web/micro-ui-internals/packages/modules/health-payments/src/pages/employee/ViewAttendance.js (6)

48-48: Simplify boolean expression

The ternary operator is unnecessary here. You can simplify the expression.

🧰 Tools
🪛 Biome (1.9.4)

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

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

(lint/complexity/noUselessTernary)


103-103: Simplify boolean expression

The ternary operator is unnecessary here. You can simplify the expression.

🧰 Tools
🪛 Biome (1.9.4)

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

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

(lint/complexity/noUselessTernary)


305-307: Simplify boolean expression

The ternary operator is unnecessary here. You can simplify the expression.

🧰 Tools
🪛 Biome (1.9.4)

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

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

(lint/complexity/noUselessTernary)


480-490: Add a unique key prop to elements in actionFields

When rendering an array of elements in actionFields, each element should have a unique key prop to help React identify them.

Also applies to: 492-504, 506-535

🧰 Tools
🪛 Biome (1.9.4)

[error] 480-490: 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)


389-391: Return the loader component to display it

The <LoaderWithGap /> component inside the if block is not returned or rendered, so it won't display as intended.


557-557: Overall implementation looks good

The ViewAttendance component effectively manages state and side effects using React hooks. Data fetching and conditional rendering are handled appropriately.

Comment on lines +230 to +232
} catch (error) {
/// will show estimate data only
}
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

Handle errors appropriately in catch block

Empty catch blocks can hide errors and make debugging difficult. Please add error handling or logging within the catch block to ensure any issues are surfaced during execution.

Consider adding error logging:

        } catch (error) {
-          /// will show estimate data only
+          console.error('Error updating muster roll:', error);
          /// will show estimate data only
        }
📝 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
} catch (error) {
/// will show estimate data only
}
} catch (error) {
console.error('Error updating muster roll:', error);
/// will show estimate data only
}

Comment on lines +187 to +189
} catch (error) {
/// will show estimate data only
}
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

Handle errors appropriately in catch block

Empty catch blocks can hide errors and make debugging difficult. Please add error handling or logging within the catch block to ensure any issues are surfaced during execution.

Consider adding error logging:

        } catch (error) {
-          /// will show estimate data only
+          console.error('Error approving muster roll:', error);
          /// will show estimate data only
        }
📝 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
} catch (error) {
/// will show estimate data only
}
} catch (error) {
console.error('Error approving muster roll:', error);
/// will show estimate data only
}

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.

4 participants