Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Conversation

@ColeGN
Copy link
Collaborator

@ColeGN ColeGN commented Aug 12, 2025

ISSUE

Context

Your context here. Additionally, any screenshots. Delete this line.

// Delete the below section once completed

PR Checklist

  • Description is clearly stated under Context section
  • Screenshots and the additional verifications are attached

Summary by Sourcery

Implement multi-group category filter support for printing

New Features:

  • Allow users to create and remove multiple category filter groups in the print settings UI
  • Group and display receipt items by each defined category filter set with separators

Enhancements:

  • Change categoriesToPrintAtom to support nested filter groups and initialize with a single empty group
  • Update receipt progress logic to filter out completed items when printing only new items and apply category groups dynamically

Summary by CodeRabbit

  • New Features

    • Grouped printing: support multiple category filter groups and print per-group batches.
  • UI

    • Settings: add/remove print groups via β€œΠ¨ΠΈΠ½Ρ ΠΏΡ€ΠΈΠ½Ρ‚ нэмэх”; per-group remove shown when >1.
  • Behavior

    • Rendering adapts for customer vs non-customer views (grouped prints omit per-item prices); β€œonly new items” filtering preserved; auto-printing delayed and gated by filters/customer state.
  • Chores

    • Persisted filter groups migrated to a nested storage format with compatibility handling.

Important

Add support for multiple category filter groups in printing, enhancing UI and logic in page.tsx and categoriesToPrint.tsx.

  • New Features:
    • Support multiple category filter groups in page.tsx for printing, with separators for grouped items.
  • UI Enhancements:
    • categoriesToPrint.tsx: Add/remove print groups with a button; remove button visible when multiple groups exist.
  • Behavior Changes:
    • page.tsx: Preserve "Only new items" filtering; refine auto-printing logic with delayed trigger and filter gating.
  • Data Handling:
    • index.tsx: Migrate categoriesToPrintAtom to nested storage format with compatibility handling.

This description was created by Ellipsis for 17003f5. You can customize this summary. It will automatically update as commits are pushed.

@sourcery-ai
Copy link

sourcery-ai bot commented Aug 12, 2025

Reviewer's Guide

This PR refactors the category filtering mechanism to support multiple filter groups, updates the Progress page to process items per group with enhanced onlyNewItems logic and conditional printing, restructures the print layout to handle grouped or customer-specific rendering, and extends the CategoriesToPrint settings UI with dynamic add/remove filter group controls.

Class diagram for updated category filter state and usage

classDiagram
    class Progress {
        - categoryOrderses: string[][]
        - itemsToPrint: OrderItem[][]
        + useLazyQuery(...)
        + setItemsToPrint(...)
    }
    class CategoriesToPrint {
        - categoriesToPrint: string[][]
        + addNewFilter()
        + removeFilter(index)
        + updateFilter(index, value)
    }
    class Store {
        + categoriesToPrintAtom: string[][]
    }
    Progress --> Store : uses categoriesToPrintAtom
    CategoriesToPrint --> Store : uses categoriesToPrintAtom
    CategoriesToPrint --> Progress : filter structure used in printing
    class OrderItem {
        + productId: string
        + status: string
        + count: number
        + unitPrice: number
        + productName: string
    }
Loading

Flow diagram for item grouping and printing in Progress page

flowchart TD
    A[Start: Order loaded] --> B{forCustomer?}
    B -- Yes --> C[Render all items for customer]
    B -- No --> D{Has filter groups?}
    D -- Yes --> E[Process items per filter group]
    E --> F[Render grouped items]
    D -- No --> G{onlyNewItems?}
    G -- Yes --> H[Filter only new items]
    H --> I[Render items]
    G -- No --> J[Render all items]
    F --> K[Print]
    I --> K
    J --> K
Loading

File-Level Changes

Change Details Files
Convert categoriesToPrintAtom to support multiple filter groups
  • Change atom type from string[] to string[][]
  • Initialize default value as [[]] instead of []
pos/store/index.tsx
Refactor Progress page data processing to group filtered items
  • Rename categoryOrders to categoryOrderses and update state to OrderItem[][]
  • Loop through each filter group to apply filterProductsNeedProcess and status checks
  • Aggregate non-empty groups into itemsToPrint via setItemsToPrint
pos/app/reciept/progress/page.tsx
Improve print execution logic with hasFilters flag
  • Compute hasFilters from categoryOrderses instead of length check
  • Use hasFilters in onCompleted to trigger network vs print flow
  • Wrap fallback setItemsToPrint in array for consistency
pos/app/reciept/progress/page.tsx
Enhance printItems rendering for groups and customer view
  • Add ternary branches to render forCustomer, grouped items, or flat list
  • Insert separators between groups when rendering multi-group items
pos/app/reciept/progress/page.tsx
Enable dynamic filter groups in CategoriesToPrint component
  • Implement addNewFilter, removeFilter, and updateFilter handlers
  • Wrap FacetedFilter instances in a loop with remove buttons
  • Add button and icon imports for UI controls
pos/modules/settings/components/categoriesToPrint.tsx

Possibly linked issues

  • #0: The PR introduces UI changes for managing multiple print categories and updates the printing process.
  • #0: The PR adds multi-category printing filters, which improves the Erxes XOS app's receipt functionality.

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@coderabbitai
Copy link

coderabbitai bot commented Aug 12, 2025

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

Walkthrough

Updates receipt progress and settings to support multiple category filter groups: store now persists categoriesToPrint as string[][]; settings UI allows adding/removing/editing filter groups; progress page builds, renders, and prints order items as grouped (OrderItem[][]) or flat lists depending on filters and view.

Changes

Cohort / File(s) Summary of changes
Progress / printing flow
pos/app/reciept/progress/page.tsx
Items-to-print type changed from OrderItem[] β†’ OrderItem[][]. onCompleted handlers now build per-filter-group results, branch flow by hasFilters / forCustomer, update printItems to return 1D or 2D sets, add delayed auto-print effects, and render three paths (customer flat with prices, grouped non-customer without per-item prices and dashed separators, flat non-customer). Updated useEffect deps to depend on full categoryOrders.
Settings UI: multi-group filters
pos/modules/settings/components/categoriesToPrint.tsx
Replaced single FacetedFilter with mapped per-group FacetedFilters; categoriesToPrint is now string[][]; added addNewFilter, removeFilter, updateFilter; prunes invalid selections when categories update; per-group add/remove UI and layout changes (Plus button and per-group remove).
Store: nested categories atom
pos/store/index.tsx
categoriesToPrintAtom now string[][] with initial value [[]]; added migrateCategoriesData to normalize legacy shapes and a custom storage adapter (getItem/setItem/removeItem) for JSON storage and backward compatibility; minor typing/formatting tweaks elsewhere.

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant Settings
  participant Store
  participant Progress
  participant API

  User->>Settings: Add/edit/remove category groups
  Settings->>Store: Persist categoriesToPrint (string[][])
  Progress->>Store: Read categoriesToPrint
  Progress->>Progress: Determine hasFilters / onlyNewItems / forCustomer
  alt hasFilters
    Progress->>API: getCategoryOrders(ids per group)
    API-->>Progress: categoryOrders (per-group)
    Progress->>Progress: Build OrderItem[][] (allFilteredItems)
  else no filters
    Progress->>Progress: Build single-group items (apply onlyNewItems if set)
  end
  alt forCustomer
    Progress->>User: Render flat list with prices and trigger print
  else hasFilters
    Progress->>User: Render grouped lists (2D) with separators and trigger print
  else no filters
    Progress->>User: Render flat list (1D) and trigger print
  end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~35 minutes

Possibly related PRs

Poem

I’m a rabbit with a stack of hops and prints,
Grouping carrots, skipping DONE-with hints.
Dashed lines for borders, many baskets to fill,
Clickβ€”add a filter groupβ€”then watch the rollers thrill.
Hop, nibble, stamp: the printer hums until. πŸ‡πŸ–¨οΈ

Tip

πŸ”Œ Remote MCP (Model Context Protocol) integration is now available!

Pro plan users can now connect to remote MCP servers from the Integrations page. Connect with popular remote MCPs such as Notion and Linear to add more context to your reviews and chats.


πŸ“œ Recent review details

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

πŸ’‘ Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

πŸ“₯ Commits

Reviewing files that changed from the base of the PR and between 7a242ec and 17003f5.

πŸ“’ Files selected for processing (1)
  • pos/app/reciept/progress/page.tsx (6 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • pos/app/reciept/progress/page.tsx
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: runtest
  • GitHub Check: pos-ui
  • GitHub Check: Analyze (javascript-typescript)
✨ Finishing Touches
  • πŸ“ Generate Docstrings
πŸ§ͺ Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch categoriesPrint

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

❀️ Share
πŸͺ§ Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

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

Hey @ColeGN - I've reviewed your changes - here's some feedback:

  • The variable name categoryOrderses is confusingβ€”consider renaming it to something clearer like categoryGroups or categoriesToPrintGroups.
  • The filtering logic in the onCompleted handlers is very similar in multiple places; extract that into a shared helper function to reduce duplication.
  • The nested ternaries and repeated JSX in the printItems rendering are hard to follow; refactor into smaller components or helper render functions for clarity.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- The variable name `categoryOrderses` is confusingβ€”consider renaming it to something clearer like `categoryGroups` or `categoriesToPrintGroups`.
- The filtering logic in the onCompleted handlers is very similar in multiple places; extract that into a shared helper function to reduce duplication.
- The nested ternaries and repeated JSX in the printItems rendering are hard to follow; refactor into smaller components or helper render functions for clarity.

## Individual Comments

### Comment 1
<location> `pos/app/reciept/progress/page.tsx:182` </location>
<code_context>
+                </span>
+              </div>
+            ))
+          : Array.isArray(printItems[0])
+          ? 
+            printItems.map((groupItems: OrderItem[], groupIndex: number) => (
</code_context>

<issue_to_address>
Using 'Array.isArray(printItems[0])' for type checking is fragile.

This approach may fail if 'printItems' is empty or contains mixed types. Use a more reliable method to differentiate between grouped and flat lists.
</issue_to_address>

### Comment 2
<location> `pos/modules/settings/components/categoriesToPrint.tsx:20` </location>
<code_context>
   const { isActive, isPrint } = config?.kitchenScreen || {}
   const { loading, categories } = useProductCategories((cats) => {
+    const validOrders = cats.map((c: ICategory) => c.order)
     setCategoriesToPrint(
-      categoriesToPrint.filter((cat) =>
-        cats.map((c: ICategory) => c.order).includes(cat)
+      categoriesToPrint.map((filterGroup) =>
+        filterGroup.filter((cat) => validOrders.includes(cat))
       )
</code_context>

<issue_to_address>
Filtering logic for valid categories may leave empty filter groups.

Remove any filter groups that are empty after filtering to prevent unnecessary UI elements.
</issue_to_address>

<suggested_fix>
<<<<<<< SEARCH
    setCategoriesToPrint(
      categoriesToPrint.map((filterGroup) =>
        filterGroup.filter((cat) => validOrders.includes(cat))
      )
    )
=======
    setCategoriesToPrint(
      categoriesToPrint
        .map((filterGroup) =>
          filterGroup.filter((cat) => validOrders.includes(cat))
        )
        .filter((filteredGroup) => filteredGroup.length > 0)
    )
>>>>>>> REPLACE

</suggested_fix>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click πŸ‘ or πŸ‘Ž on each comment and I'll use the feedback to improve your reviews.

@ColeGN ColeGN requested a review from munkhsaikhan August 12, 2025 20:57
Copy link
Contributor

@ellipsis-dev ellipsis-dev bot left a comment

Choose a reason for hiding this comment

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

Caution

Changes requested ❌

Reviewed everything up to 998c4d5 in 2 minutes and 2 seconds. Click for details.
  • Reviewed 289 lines of code in 3 files
  • Skipped 0 files when reviewing.
  • Skipped posting 9 draft comments. View those below.
  • Modify your settings and rules to customize what types of comments Ellipsis leaves. And don't forget to react with πŸ‘ or πŸ‘Ž to teach Ellipsis.
1. pos/app/reciept/progress/page.tsx:39
  • Draft comment:
    Changing the state type to OrderItem[][] means downstream logic now must handle nested arrays. Consider refactoring or adding comments to clarify the intent.
  • Reason this comment was not posted:
    Decided after close inspection that this draft comment was likely wrong and/or not actionable: usefulness confidence = 0% vs. threshold = 50% The code shows that the nested array structure is intentional and all downstream logic has been properly updated to handle it. The change appears to be for grouping items, with a border between groups (line 187). The comment suggests adding documentation but the code is already clear in its intent and implementation. The comment raises a valid point about code clarity, and documentation could help future maintainers understand the grouping purpose more quickly. While documentation could help, the code is already well-structured and the nested array usage is clear from the implementation. The comment doesn't identify any actual issues that need fixing. The comment should be deleted as it doesn't identify any actual problems - the code already handles the nested arrays correctly and the intent is clear from the implementation.
2. pos/app/reciept/progress/page.tsx:55
  • Draft comment:
    Inside the getCategoryOrders onCompleted, filtering uses 'items' from outer scope. Ensure 'items' is defined when this callback runs to avoid runtime issues.
  • Reason this comment was not posted:
    Comment looked like it was already resolved.
3. pos/app/reciept/progress/page.tsx:128
  • Draft comment:
    The useMemo block returns different types (array of OrderItem vs. array of OrderItem[]), leading to complex rendering checks. Consider unifying the type or refactoring the render logic.
  • Reason this comment was not posted:
    Comment was not on a location in the diff, so it can't be submitted as a review comment.
4. pos/store/index.tsx:79
  • Draft comment:
    Changing categoriesToPrintAtom's type from string[] to string[][] affects all consumers. Verify that all components (e.g., progress page and settings) correctly handle this nested array.
  • Reason this comment was not posted:
    Comment did not seem useful. Confidence is useful = 0% <= threshold 50% The comment is asking the PR author to verify that all components handle the change correctly, which is against the rules. It doesn't provide a specific suggestion or point out a specific issue with the code.
5. pos/app/reciept/progress/page.tsx:122
  • Draft comment:
    The useEffect triggering window.print() on changes to 'itemsToPrint' might result in multiple prints if the state changes often. Consider ensuring it only triggers once per print.
  • Reason this comment was not posted:
    Comment was not on a location in the diff, so it can't be submitted as a review comment.
6. pos/app/reciept/progress/page.tsx:38
  • Draft comment:
    Typo found: The variable name "categoryOrderses" appears to be an incorrect plural form. Consider renaming it to "categoryOrders" (or another appropriate name) for clarity and consistency.
  • Reason this comment was not posted:
    Decided after close inspection that this draft comment was likely wrong and/or not actionable: usefulness confidence = 10% vs. threshold = 50% The variable name categoryOrderses, while unusual, is actually semantically correct - it represents multiple groups of category orders. The code handles it as an array of arrays throughout. Renaming it to categoryOrders would actually make it less clear that we're dealing with multiple groups. The unusual plural form could be confusing to some developers. Perhaps there's a more elegant name that could better convey the grouped nature of the data. While the name is unconventional, it's technically correct and changing it could make the code less clear about the data structure being an array of arrays. The comment should be deleted as the current name, while unusual, is actually more accurate for the data structure than the suggested alternative.
7. pos/app/reciept/progress/page.tsx:79
  • Draft comment:
    Typo alert: The variable name categoryOrderses appears to be a misspelling. Did you mean categoryOrders?
  • Reason this comment was not posted:
    Decided after close inspection that this draft comment was likely wrong and/or not actionable: usefulness confidence = 0% vs. threshold = 50% The name categoryOrderses is unconventional but appears to be intentionally changed to reflect that it's now handling multiple groups of category orders. The code is working with this new structure throughout, including in the filtering logic and rendering. This isn't a typo - it's a deliberate change to match new functionality. The name is unusual English and could be improved to something like categoryOrderGroups. However, the current name is consistently used and functional. While the naming could be better, this isn't a typo - it's an intentional change that matches the new data structure and functionality. The comment should be deleted because it incorrectly identifies an intentional change as a typo.
8. pos/app/reciept/progress/page.tsx:132
  • Draft comment:
    Typo noticed: The variable name 'categoryOrderses' appears, which seems to be a typo. It likely should be 'categoryOrders'.
  • Reason this comment was not posted:
    Decided after close inspection that this draft comment was likely wrong and/or not actionable: usefulness confidence = 10% vs. threshold = 50% The variable name seems intentional, not a typo. The code was changed from a single array (categoryOrders) to an array of arrays, and the name was updated to reflect that. The plural form, while unusual, accurately represents the data structure. The code is consistent in its usage throughout. I could be wrong about the intention - maybe it really was a typo and just happened to work. Also, even if intentional, it might not follow the team's naming conventions. The consistent usage and the fact that it matches the new data structure (array of arrays) strongly suggests this was an intentional rename, not a typo. The code works correctly with this name. The comment should be deleted because the variable name appears to be intentionally changed to reflect its new plural nature as an array of arrays, not a typo.
9. pos/app/reciept/progress/page.tsx:144
  • Draft comment:
    Typo in the dependency array: 'categoryOrderses' is used here, but it seems it should be 'categoryOrders' for consistency.
  • Reason this comment was not posted:
    Comment looked like it was already resolved.

Workflow ID: wflow_Ujja7mAVh0fLSK5L

You can customize Ellipsis by changing your verbosity settings, reacting with πŸ‘ or πŸ‘Ž, replying to comments, or adding code review rules.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

πŸ”­ Outside diff range comments (1)
pos/app/reciept/progress/page.tsx (1)

128-144: Type inconsistency in printItems could cause runtime errors

The printItems variable can be either OrderItem[] or OrderItem[][] depending on the conditions, but TypeScript won't catch this mixed type usage. This could lead to runtime errors if the wrong type is assumed elsewhere.

Consider maintaining consistent types or using a discriminated union:

// Add proper typing at the component level
type PrintItemsType = {
  isGrouped: true;
  items: OrderItem[][];
} | {
  isGrouped: false;
  items: OrderItem[];
}

// Then update the useMemo:
const printItems = useMemo((): PrintItemsType => {
  if (forCustomer) {
    return { isGrouped: false, items: items || [] }
  }
  const hasFilters = categoryOrderses.some((group) => group.length > 0)
  if (hasFilters) {
    return { isGrouped: true, items: itemsToPrint }
  }
  if (onlyNewItems) {
    return {
      isGrouped: false,
      items: items?.filter(
        (item: OrderItem) => item.status !== ORDER_ITEM_STATUSES.DONE
      ) || []
    }
  }
  return { isGrouped: false, items: items || [] }
}, [forCustomer, onlyNewItems, categoryOrderses, itemsToPrint, items])
🧹 Nitpick comments (4)
pos/modules/settings/components/categoriesToPrint.tsx (3)

5-5: Remove unused import

The X icon from lucide-react is imported but never used in the component. The remove button uses an emoji (❌) instead.

-import { Plus, X } from "lucide-react"
+import { Plus } from "lucide-react"

67-71: UX improvement: Warn before removing the last filter group

Currently, the function silently prevents removal of the last filter group. Users might be confused when clicking the remove button has no effect.

Consider providing user feedback or disabling the button instead:

 const removeFilter = (index: number) => {
   if (categoriesToPrint.length > 1) {
     setCategoriesToPrint(categoriesToPrint.filter((_, i) => i !== index))
+  } else {
+    // Consider showing a toast: "At least one filter group must be maintained"
   }
 }

Or better yet, since you're already conditionally rendering the remove button (line 95), this check is redundant:

-const removeFilter = (index: number) => {
-  if (categoriesToPrint.length > 1) {
-    setCategoriesToPrint(categoriesToPrint.filter((_, i) => i !== index))
-  }
-}
+const removeFilter = (index: number) => {
+  setCategoriesToPrint(categoriesToPrint.filter((_, i) => i !== index))
+}

95-104: Consider using a proper icon component instead of emoji

Using an emoji (❌) for the remove button is inconsistent with the Plus icon used for the add button. This could cause rendering issues across different platforms and browsers.

Since you've already imported X from lucide-react, use it for consistency:

 {categoriesToPrint.length > 1 && (
   <Button
     variant="ghost"
     size="sm"
     onClick={() => removeFilter(index)}
     className="h-8 w-8 p-0 text-red-500 hover:text-red-600 hover:bg-red-50"
   >
-    ❌
+    <X className="h-4 w-4" />
   </Button>
 )}
pos/app/reciept/progress/page.tsx (1)

168-209: Complex rendering logic could benefit from extraction

The nested ternary operators and type checking make this rendering logic hard to follow and maintain. The three different rendering paths (customer view, grouped items, flat items) would be clearer as separate functions or components.

Consider extracting the rendering logic into separate functions:

+const renderCustomerItems = (items: OrderItem[]) => (
+  <>
+    {items.map((item: OrderItem) => (
+      <div className="flex items-center" key={item._id}>
+        <span className="flex-auto">{item.productName}</span>
+        <span>
+          x{item.count}{" "}
+          {item.status === ORDER_ITEM_STATUSES.CONFIRM && "!!!"}
+        </span>
+        <span className="ml-1 w-1/4 text-right">
+          {(item.unitPrice * item.count).toLocaleString()}
+        </span>
+      </div>
+    ))}
+  </>
+)
+
+const renderGroupedItems = (groups: OrderItem[][]) => (
+  <>
+    {groups.map((groupItems: OrderItem[], groupIndex: number) => (
+      <div key={groupIndex}>
+        {groupIndex > 0 && (
+          <div className="my-3 border-t border-dashed" />
+        )}
+        {groupItems.map((item: OrderItem) => (
+          <div className="flex items-center" key={item._id}>
+            <span className="flex-auto">{item.productName}</span>
+            <span>
+              x{item.count}{" "}
+              {item.status === ORDER_ITEM_STATUSES.CONFIRM && "!!!"}
+            </span>
+          </div>
+        ))}
+      </div>
+    ))}
+  </>
+)
+
+const renderFlatItems = (items: OrderItem[]) => (
+  <>
+    {items.map((item: OrderItem) => (
+      <div className="flex items-center" key={item._id}>
+        <span className="flex-auto">{item.productName}</span>
+        <span>
+          x{item.count}{" "}
+          {item.status === ORDER_ITEM_STATUSES.CONFIRM && "!!!"}
+        </span>
+      </div>
+    ))}
+  </>
+)

 // Then in the JSX:
-{forCustomer
-  ?
-    printItems.map((item: OrderItem) => (
-      // ... customer view
-    ))
-  : Array.isArray(printItems[0])
-  ? 
-    printItems.map((groupItems: OrderItem[], groupIndex: number) => (
-      // ... grouped view
-    ))
-  : 
-    printItems.map((item: OrderItem) => (
-      // ... flat view
-    ))}
+{forCustomer
+  ? renderCustomerItems(printItems)
+  : Array.isArray(printItems[0])
+  ? renderGroupedItems(printItems)
+  : renderFlatItems(printItems)}
πŸ“œ Review details

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

πŸ“₯ Commits

Reviewing files that changed from the base of the PR and between 0f7590e and 998c4d5.

πŸ“’ Files selected for processing (3)
  • pos/app/reciept/progress/page.tsx (5 hunks)
  • pos/modules/settings/components/categoriesToPrint.tsx (3 hunks)
  • pos/store/index.tsx (1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (2)
pos/modules/settings/components/categoriesToPrint.tsx (1)
packages/ui-sales/src/boards/styles/popup.ts (1)
  • Button (31-51)
pos/app/reciept/progress/page.tsx (2)
pos/store/index.tsx (1)
  • categoriesToPrintAtom (79-82)
packages/plugin-posclient-api/src/graphql/resolvers/queries/products.ts (1)
  • poscProducts (303-380)
πŸͺ› Biome (2.1.2)
pos/app/reciept/progress/page.tsx

[error] 57-57: Unsafe usage of optional chaining.

If it short-circuits with 'undefined' the evaluation will throw TypeError here:

(lint/correctness/noUnsafeOptionalChaining)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: runtest
  • GitHub Check: pos-ui
  • GitHub Check: Analyze (javascript-typescript)

Copy link
Contributor

@ellipsis-dev ellipsis-dev bot left a comment

Choose a reason for hiding this comment

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

Important

Looks good to me! πŸ‘

Reviewed 4630542 in 1 minute and 28 seconds. Click for details.
  • Reviewed 255 lines of code in 3 files
  • Skipped 0 files when reviewing.
  • Skipped posting 4 draft comments. View those below.
  • Modify your settings and rules to customize what types of comments Ellipsis leaves. And don't forget to react with πŸ‘ or πŸ‘Ž to teach Ellipsis.
1. pos/app/reciept/progress/page.tsx:55
  • Draft comment:
    Using 'items' from the outer scope inside the getCategoryOrders onCompleted callback might risk stale data if the outer 'items' changes. Consider passing the current orderDetail.items explicitly to ensure data consistency.
  • Reason this comment was not posted:
    Comment was on unchanged code.
2. pos/app/reciept/progress/page.tsx:166
  • Draft comment:
    Consider extracting the inline IIFE rendering logic (lines 166–214) into a separate render function for improved readability and maintainability.
  • Reason this comment was not posted:
    Confidence changes required: 33% <= threshold 50% None
3. pos/modules/settings/components/categoriesToPrint.tsx:82
  • Draft comment:
    List items are keyed using an index-based key (e.g., category-filter-${index}). If possible, consider using a stable unique identifier to prevent potential issues during reordering.
  • Reason this comment was not posted:
    Confidence changes required: 33% <= threshold 50% None
4. pos/store/index.tsx:91
  • Draft comment:
    The migrateCategoriesData function is a solid approach for ensuring backward compatibility with previously stored data. Verify that all legacy data formats are adequately handled.
  • Reason this comment was not posted:
    Confidence changes required: 33% <= threshold 50% None

Workflow ID: wflow_1jjvOuYn242n8lIq

You can customize Ellipsis by changing your verbosity settings, reacting with πŸ‘ or πŸ‘Ž, replying to comments, or adding code review rules.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

πŸ”­ Outside diff range comments (1)
pos/app/reciept/progress/page.tsx (1)

226-234: Guard against items being undefined when computing totals

Calling reduce on undefined will throw if orderDetail.items is missing. Use a safe default.

Apply this diff:

-              {items
+              {(items || [])
                 .reduce(
                   (acc: number, item: OrderItem) =>
                     acc + item.unitPrice * item.count,
                   0
                 )
                 .toLocaleString()}
♻️ Duplicate comments (2)
pos/app/reciept/progress/page.tsx (1)

182-186: Avoid fragile Array.isArray(printItems[0]) check; use has-filters signal instead

You already derive grouping from the presence of non-empty filter groups. Rely on that instead of inspecting runtime shapes.

Apply this diff:

-          const hasMultipleGroups = Array.isArray(printItems) && 
-            printItems.length > 0 && 
-            Array.isArray(printItems[0])
+          const hasMultipleGroups = categoryOrders.some((group) => group.length > 0)

This keeps the render logic aligned with the decision used to construct printItems and avoids brittle shape introspection.

pos/modules/settings/components/categoriesToPrint.tsx (1)

19-24: Prune empty groups after filtering invalid categories (and ensure at least one group remains)

Avoid rendering empty filter rows after categories change. Keep UX clean and deterministic.

Apply this diff:

-  const { loading, categories } = useProductCategories((cats) => {
-    const validOrders = cats.map((c: ICategory) => c.order)
-    setCategoriesToPrint(
-      categoriesToPrint.map((filterGroup) =>
-        filterGroup.filter((cat) => validOrders.includes(cat))
-      )
-    )
-  }, isActive || !isPrint)
+  const { loading, categories } = useProductCategories((cats) => {
+    const validOrders = cats.map((c: ICategory) => c.order)
+    setCategoriesToPrint((prev) => {
+      const updated = prev
+        .map((filterGroup) => filterGroup.filter((cat) => validOrders.includes(cat)))
+        .filter((filteredGroup) => filteredGroup.length > 0)
+      return updated.length > 0 ? updated : [[]] // keep at least one group
+    })
+  }, isActive || !isPrint)
🧹 Nitpick comments (5)
pos/app/reciept/progress/page.tsx (1)

126-142: Unify print data model to simplify rendering and types

Today printItems is sometimes OrderItem[] and sometimes OrderItem[][]. This forces runtime shape checks and casts. Normalize to a discriminated model or always use a 2D array (wrap flat lists as a single group). This simplifies both memo and render, improves type-safety, and removes the need for shape probing.

Example (minimal change outside current structure):

  • In the memo, when no filters, return [flatItems] instead of flatItems.
  • In the render, always iterate groups and items; keep the customer branch as-is.

If you want, I can provide a full diff converting printItems to always be OrderItem[][] and updating the render accordingly.

Also applies to: 166-214

pos/store/index.tsx (1)

106-127: Consider delegating JSON handling to createJSONStorage and layering migration

This keeps behavior consistent with other atoms using JSON storage and centralizes serialization concerns. Layer migration on top of the JSON storage getItem.

Apply this diff:

-import { atomWithStorage } from "jotai/utils"
+import { atomWithStorage, createJSONStorage } from "jotai/utils"
@@
-export const categoriesToPrintAtom = atomWithStorage<string[][]>(
-  "categoriesToPrint",
-  [[]],
-  {
-    getItem: (key, initialValue) => {
-      try {
-        const stored = localStorage.getItem(key)
-        if (stored === null) return initialValue
-        const parsed = JSON.parse(stored)
-        return migrateCategoriesData(parsed)
-      } catch {
-        return initialValue
-      }
-    },
-    setItem: (key, value) => {
-      localStorage.setItem(key, JSON.stringify(value))
-    },
-    removeItem: (key) => {
-      localStorage.removeItem(key)
-    },
-  }
-)
+const jsonStorage = createJSONStorage<string[][]>(() => localStorage)
+export const categoriesToPrintAtom = atomWithStorage<string[][]>(
+  "categoriesToPrint",
+  [[]],
+  {
+    getItem: (key, initialValue) => {
+      try {
+        const parsed = jsonStorage.getItem(key, initialValue)
+        return migrateCategoriesData(parsed)
+      } catch {
+        return initialValue
+      }
+    },
+    setItem: (key, value) => jsonStorage.setItem(key, value),
+    removeItem: (key) => jsonStorage.removeItem(key),
+  }
+)
pos/modules/settings/components/categoriesToPrint.tsx (3)

63-77: Use functional state updates to avoid stale closures

These setters depend on the previous state; use functional updates for correctness under rapid interactions.

Apply this diff:

-  const addNewFilter = () => {
-    setCategoriesToPrint([...categoriesToPrint, []])
-  }
+  const addNewFilter = () => {
+    setCategoriesToPrint((prev) => [...prev, []])
+  }
@@
-  const removeFilter = (index: number) => {
-    if (categoriesToPrint.length > 1) {
-      setCategoriesToPrint(categoriesToPrint.filter((_, i) => i !== index))
-    }
-  }
+  const removeFilter = (index: number) => {
+    setCategoriesToPrint((prev) => (prev.length > 1 ? prev.filter((_, i) => i !== index) : prev))
+  }
@@
-  const updateFilter = (index: number, value: string[]) => {
-    const updated = [...categoriesToPrint]
-    updated[index] = value
-    setCategoriesToPrint(updated)
-  }
+  const updateFilter = (index: number, value: string[]) => {
+    setCategoriesToPrint((prev) => {
+      const updated = [...prev]
+      updated[index] = value
+      return updated
+    })
+  }

82-85: Stabilize keys to reduce re-mounting when groups change

Index-only keys can cause unnecessary re-mounts and state loss across edits/removals.

Apply this diff:

-        <div
-          key={`category-filter-${index}`}
+        <div
+          key={`category-filter-${index}-${(filterGroup || []).join("|")}`}

If users can reorder or duplicate groups, consider storing a generated id per group for truly stable keys.


98-107: Improve accessibility for the remove button

Add an aria-label so screen readers announce the action meaningfully.

Apply this diff:

           {categoriesToPrint.length > 1 && (
             <Button
               variant="ghost"
               size="sm"
               onClick={() => removeFilter(index)}
               className="h-8 w-8 p-0 text-red-500 hover:text-red-600 hover:bg-red-50"
+              aria-label={`Remove filter group ${index + 1}`}
             >
               ❌
             </Button>
           )}
πŸ“œ Review details

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

πŸ“₯ Commits

Reviewing files that changed from the base of the PR and between 998c4d5 and 4630542.

πŸ“’ Files selected for processing (3)
  • pos/app/reciept/progress/page.tsx (5 hunks)
  • pos/modules/settings/components/categoriesToPrint.tsx (3 hunks)
  • pos/store/index.tsx (2 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (2)
pos/modules/settings/components/categoriesToPrint.tsx (1)
packages/ui-sales/src/boards/styles/popup.ts (1)
  • Button (31-51)
pos/app/reciept/progress/page.tsx (1)
packages/plugin-posclient-api/src/graphql/resolvers/queries/products.ts (1)
  • poscProducts (303-380)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: pos-ui
  • GitHub Check: runtest
  • GitHub Check: Analyze (javascript-typescript)
πŸ”‡ Additional comments (3)
pos/app/reciept/progress/page.tsx (1)

55-61: Good fix: removed unsafe optional chaining on items.filter

Using a safe fallback via baseItems avoids calling .filter on undefined and addresses the prior lint finding.

pos/store/index.tsx (2)

91-105: Solid, defensive migration to the new string[][] shape

migrateCategoriesData correctly normalizes legacy string[] values and corrupt data to the new [[]] default. This should prevent breakage for existing users.


91-105: No direct localStorage access for categoriesToPrint detected

All reads and writes go through categoriesToPrintAtom (via atomWithStorage) and are consumed with useAtom/useAtomValue. No localStorage.getItem/setItem('categoriesToPrint') calls were found after scanning. No further action needed.

Copy link
Contributor

@ellipsis-dev ellipsis-dev bot left a comment

Choose a reason for hiding this comment

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

Important

Looks good to me! πŸ‘

Reviewed 7a242ec in 1 minute and 18 seconds. Click for details.
  • Reviewed 219 lines of code in 2 files
  • Skipped 0 files when reviewing.
  • Skipped posting 7 draft comments. View those below.
  • Modify your settings and rules to customize what types of comments Ellipsis leaves. And don't forget to react with πŸ‘ or πŸ‘Ž to teach Ellipsis.
1. pos/app/reciept/progress/page.tsx:49
  • Draft comment:
    Refactor: Added braces for the 'if (filterGroup.length === 0)' check improves readability. Ensure consistent control flow style throughout the file.
  • Reason this comment was not posted:
    Confidence changes required: 33% <= threshold 50% None
2. pos/app/reciept/progress/page.tsx:73
  • Draft comment:
    Logic Change: When no filter groups match, the fallback now prints all (or only new) items. Confirm that this behavior is intentional.
  • Reason this comment was not posted:
    Comment looked like it was already resolved.
3. pos/app/reciept/progress/page.tsx:134
  • Draft comment:
    Timing Consideration: Wrapped window.print() in a setTimeout (100ms delay) to allow rendering to complete. Verify that this delay consistently addresses render timing issues across devices.
  • Reason this comment was not posted:
    Comment did not seem useful. Confidence is useful = 0% <= threshold 50% The comment is asking the PR author to verify that the delay consistently addresses render timing issues across devices. This falls under the rule of not asking the PR author to ensure behavior is intended or to double-check things. Therefore, this comment should be removed.
4. pos/app/reciept/progress/page.tsx:141
  • Draft comment:
    Dependency Check: The additional useEffect (triggering window.print after 200ms) relies on several dependencies. Double-check that these dependencies cover all necessary state and that this does not inadvertently trigger multiple prints.
  • Reason this comment was not posted:
    Comment did not seem useful. Confidence is useful = 0% <= threshold 50% The comment is asking the PR author to double-check dependencies and ensure that the behavior is intended, which violates the rules. It does not provide a specific suggestion or point out a clear issue with the code.
5. pos/modules/settings/components/categoriesToPrint.tsx:64
  • Draft comment:
    Good Practice: Using a functional update (prev => [...prev, []]) with setCategoriesToPrint ensures state accuracy.
  • Reason this comment was not posted:
    Confidence changes required: 0% <= threshold 50% None
6. pos/modules/settings/components/categoriesToPrint.tsx:69
  • Draft comment:
    Good Practice: Functional update in removeFilter ensures the latest state is used. Nice job!
  • Reason this comment was not posted:
    Confidence changes required: 0% <= threshold 50% None
7. pos/modules/settings/components/categoriesToPrint.tsx:87
  • Draft comment:
    Improvement: Enhanced key attribute by concatenating filter values reduces potential key collisions.
  • Reason this comment was not posted:
    Confidence changes required: 0% <= threshold 50% None

Workflow ID: wflow_3ek3qRNgyX19VZqL

You can customize Ellipsis by changing your verbosity settings, reacting with πŸ‘ or πŸ‘Ž, replying to comments, or adding code review rules.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

πŸ”­ Outside diff range comments (3)
pos/modules/settings/components/categoriesToPrint.tsx (2)

33-38: Guard against undefined categories in rootCategories

categories.find(...) will throw if categories is undefined. Use a safe default.

   const rootCategories = (categories || []).filter(
     (category) =>
-      !categories.find(
+      !(categories || []).find(
         (cat) => cat._id !== category._id && category.order.includes(cat.order)
       )
   )

43-49: Prevent potential crash in getDirectChildren when categories is undefined

Use a safe default for categories.

-  return categories.filter(
+  return (categories || []).filter(
     (cat) =>
       cat._id !== parentCat._id &&
       getGen(cat.order) === getGen(parentCat.order) + 1 &&
       cat.order.includes(parentCat.order)
   )
pos/app/reciept/progress/page.tsx (1)

86-96: Potential duplicate prints; gate with a ref

window.print() is invoked here and also in effects below, which can cause double prints. Gate all print calls via a single ref.

   onCompleted({ orderDetail }) {
     const hasFilters = categoryOrders.some((group) => group.length > 0)
     if (forCustomer) {
-      return window.print()
+      if (!didRequestPrintRef.current) {
+        didRequestPrintRef.current = true
+        return window.print()
+      }
+      return
     }
     if (!onlyNewItems && !hasFilters) {
-      return window.print()
+      if (!didRequestPrintRef.current) {
+        didRequestPrintRef.current = true
+        return window.print()
+      }
+      return
     }

Additions required outside this hunk:

  • Import and ref initialization:
// add to imports
import { useCallback, useEffect, useMemo, useRef, useState } from "react"

// declare once near other state
const didRequestPrintRef = useRef(false)
♻️ Duplicate comments (3)
pos/modules/settings/components/categoriesToPrint.tsx (1)

19-24: Fix stale state update and prune empty filter groups

The callback uses a captured categoriesToPrint value, which can be stale. Use a functional state update. Also, prune empty groups after filtering to avoid rendering empty UI rows. This aligns with prior feedback.

-    const validOrders = cats.map((c: ICategory) => c.order)
-    setCategoriesToPrint(
-      categoriesToPrint.map((filterGroup) =>
-        filterGroup.filter((cat) => validOrders.includes(cat))
-      )
-    )
+    const validOrders = cats.map((c: ICategory) => c.order)
+    setCategoriesToPrint((prev) =>
+      prev
+        .map((filterGroup) =>
+          filterGroup.filter((cat) => validOrders.includes(cat))
+        )
+        .filter((filteredGroup) => filteredGroup.length > 0)
+    )
pos/app/reciept/progress/page.tsx (2)

208-212: LGTM: safer multiple-groups detection

Guarding with printItems.length > 0 before peeking at [0] addresses the fragility noted previously.


42-84: Add onError handler to avoid a stuck progress window

If getCategoryOrders fails, the UI can hang. Close gracefully.

 const [getCategoryOrders, ordersQuery] = useLazyQuery(
   productQueries.getCategoryOrders,
   {
     onCompleted({ poscProducts }) {
       const allFilteredItems: OrderItem[][] = []
@@
       },
+    onError() {
+      // Avoid leaving the progress window hanging on network/server errors
+      handleAfterPrint()
+    },
   }
 )
🧹 Nitpick comments (3)
pos/modules/settings/components/categoriesToPrint.tsx (3)

75-81: Add bounds check in updateFilter to avoid OOB updates

Prevents accidental runtime issues if the index becomes stale (e.g., during rapid add/remove).

 const updateFilter = (index: number, value: string[]) => {
   setCategoriesToPrint((prev) => {
+    if (index < 0 || index >= prev.length) return prev
     const updated = [...prev]
     updated[index] = value
     return updated
   })
 }

85-114: Consider stable keys for dynamic filter groups

The key combines index + joined values. This can still cause remounts and state leakage on reordering/removal. Ideally, each group would have a stable id.

Would you consider evolving categoriesToPrintAtom to store { id: string; values: string[] }[]? I can help generate a small migration helper if desired.


102-112: Use a consistent icon instead of a Unicode cross

For consistency with the rest of the UI, prefer lucide-react’s X icon.

-          {categoriesToPrint.length > 1 && (
+          {categoriesToPrint.length > 1 && (
             <Button
               variant="ghost"
               size="sm"
               onClick={() => removeFilter(index)}
               className="h-8 w-8 p-0 text-red-500 hover:text-red-600 hover:bg-red-50"
               aria-label={`Remove filter group ${index + 1}`}
             >
-              ❌
+              <X className="h-4 w-4" aria-hidden="true" />
             </Button>
           )}

Additionally, update the import:

-import { Plus } from "lucide-react"
+import { Plus, X } from "lucide-react"
πŸ“œ Review details

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

πŸ“₯ Commits

Reviewing files that changed from the base of the PR and between 4630542 and 7a242ec.

πŸ“’ Files selected for processing (2)
  • pos/app/reciept/progress/page.tsx (5 hunks)
  • pos/modules/settings/components/categoriesToPrint.tsx (3 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (2)
pos/app/reciept/progress/page.tsx (2)
packages/plugin-posclient-api/src/graphql/resolvers/queries/products.ts (1)
  • poscProducts (303-380)
packages/plugin-posclient-api/src/graphql/resolvers/queries/orders.ts (1)
  • orderDetail (196-215)
pos/modules/settings/components/categoriesToPrint.tsx (1)
packages/ui-sales/src/boards/styles/popup.ts (1)
  • Button (31-51)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: runtest
  • GitHub Check: pos-ui
  • GitHub Check: Analyze (javascript-typescript)
πŸ”‡ Additional comments (2)
pos/modules/settings/components/categoriesToPrint.tsx (1)

63-66: LGTM: clean additive API for new filter groups

Using a functional update to append a new, empty group is correct and future-proof.

pos/app/reciept/progress/page.tsx (1)

72-81: Confirm fallback behavior when no filter groups match

When all groups produce zero items, the code falls back to printing all (or only new) items. Is this the intended UX? Alternatively, you might close without printing or display a β€œno items matched” message.

I can switch this to an early handleAfterPrint() if that better matches product expectations.

Comment on lines 133 to 139
useEffect(() => {
if (itemsToPrint.length > 0) {
window.print()
setTimeout(() => {
window.print()
}, 100)
}
}, [itemsToPrint])
Copy link

Choose a reason for hiding this comment

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

πŸ› οΈ Refactor suggestion

Debounced print should also be gated to avoid double invocation

Use the same print guard here.

-  useEffect(() => {
-    if (itemsToPrint.length > 0) {
-      setTimeout(() => {
-        window.print()
-      }, 100)
-    }
-  }, [itemsToPrint])
+  useEffect(() => {
+    if (itemsToPrint.length > 0 && !didRequestPrintRef.current) {
+      didRequestPrintRef.current = true
+      setTimeout(() => {
+        window.print()
+      }, 100)
+    }
+  }, [itemsToPrint])
πŸ“ Committable suggestion

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

Suggested change
useEffect(() => {
if (itemsToPrint.length > 0) {
window.print()
setTimeout(() => {
window.print()
}, 100)
}
}, [itemsToPrint])
useEffect(() => {
if (itemsToPrint.length > 0 && !didRequestPrintRef.current) {
didRequestPrintRef.current = true
setTimeout(() => {
window.print()
}, 100)
}
}, [itemsToPrint])
πŸ€– Prompt for AI Agents
In pos/app/reciept/progress/page.tsx around lines 133–139, the useEffect
triggers a debounced window.print() but lacks the same print guard used
elsewhere, allowing double invocation; update the effect to first check the
existing print guard state (e.g., isPrinted or hasPrinted) and return if already
set, set the guard to true before scheduling/performing the print, and ensure
you store/clear the timeout on cleanup to avoid duplicate prints or leaks;
mirror the exact guard variable and update pattern used in the other print
location so behavior is consistent.

Comment on lines +141 to +151
useEffect(() => {
if (data?.orderDetail && !loading && !ordersQuery.loading) {
const hasFilters = categoryOrders.some((group) => group.length > 0)
if (!forCustomer && !hasFilters && !onlyNewItems && itemsToPrint.length === 0) {
setTimeout(() => {
window.print()
}, 200)
}
}
}, [data, loading, ordersQuery.loading, categoryOrders, forCustomer, onlyNewItems, itemsToPrint.length])

Copy link

Choose a reason for hiding this comment

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

πŸ› οΈ Refactor suggestion

Second auto-print path can also double-fire; gate it too

Prevent duplicate auto-prints in the no-filter, not-only-new path.

   useEffect(() => {
     if (data?.orderDetail && !loading && !ordersQuery.loading) {
       const hasFilters = categoryOrders.some((group) => group.length > 0)
-      if (!forCustomer && !hasFilters && !onlyNewItems && itemsToPrint.length === 0) {
-        setTimeout(() => {
-          window.print()
-        }, 200)
-      }
+      if (!forCustomer && !hasFilters && !onlyNewItems && itemsToPrint.length === 0 && !didRequestPrintRef.current) {
+        didRequestPrintRef.current = true
+        setTimeout(() => {
+          window.print()
+        }, 200)
+      }
     }
   }, [data, loading, ordersQuery.loading, categoryOrders, forCustomer, onlyNewItems, itemsToPrint.length])
πŸ“ Committable suggestion

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

Suggested change
useEffect(() => {
if (data?.orderDetail && !loading && !ordersQuery.loading) {
const hasFilters = categoryOrders.some((group) => group.length > 0)
if (!forCustomer && !hasFilters && !onlyNewItems && itemsToPrint.length === 0) {
setTimeout(() => {
window.print()
}, 200)
}
}
}, [data, loading, ordersQuery.loading, categoryOrders, forCustomer, onlyNewItems, itemsToPrint.length])
useEffect(() => {
if (data?.orderDetail && !loading && !ordersQuery.loading) {
const hasFilters = categoryOrders.some((group) => group.length > 0)
if (
!forCustomer &&
!hasFilters &&
!onlyNewItems &&
itemsToPrint.length === 0 &&
!didRequestPrintRef.current
) {
didRequestPrintRef.current = true
setTimeout(() => {
window.print()
}, 200)
}
}
}, [
data,
loading,
ordersQuery.loading,
categoryOrders,
forCustomer,
onlyNewItems,
itemsToPrint.length,
])
πŸ€– Prompt for AI Agents
In pos/app/reciept/progress/page.tsx around lines 141 to 151, the second
auto-print branch (no filters, not forCustomer, not onlyNewItems, itemsToPrint
empty) can fire twice; add a guard so it runs only once by tracking a one-time
flag. Introduce a ref or state (e.g., printTriggeredRef) initialized false,
check it before scheduling window.print(), set it to true immediately when
scheduling/printing, and reset only on component unmount if needed; update the
effect to consult this flag so the setTimeout/print path cannot double-fire.

Comment on lines +67 to +73
const removeFilter = (index: number) => {
if (categoriesToPrint.length > 1) {
setCategoriesToPrint((prev) =>
prev.length > 1 ? prev.filter((_, i) => i !== index) : prev
)
}
}
Copy link

Choose a reason for hiding this comment

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

πŸ› οΈ Refactor suggestion

Simplify removeFilter and avoid stale closure

No need to read categoriesToPrint outside the setter; rely solely on the functional updater and keep the β€œat least one group remains” rule there.

-const removeFilter = (index: number) => {
-  if (categoriesToPrint.length > 1) {
-    setCategoriesToPrint((prev) =>
-      prev.length > 1 ? prev.filter((_, i) => i !== index) : prev
-    )
-  }
-}
+const removeFilter = (index: number) => {
+  setCategoriesToPrint((prev) =>
+    prev.length > 1 ? prev.filter((_, i) => i !== index) : prev
+  )
+}
πŸ“ 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 removeFilter = (index: number) => {
if (categoriesToPrint.length > 1) {
setCategoriesToPrint((prev) =>
prev.length > 1 ? prev.filter((_, i) => i !== index) : prev
)
}
}
const removeFilter = (index: number) => {
setCategoriesToPrint((prev) =>
prev.length > 1 ? prev.filter((_, i) => i !== index) : prev
)
}
πŸ€– Prompt for AI Agents
In pos/modules/settings/components/categoriesToPrint.tsx around lines 67 to 73,
remove the external read of categoriesToPrint and simplify removeFilter to use
only the functional state updater: call setCategoriesToPrint(prev => { const
next = prev.filter((_, i) => i !== index); return next.length ? next : prev; })
so the "at least one group remains" rule is enforced inside the updater and
avoid stale closure issues.

Copy link
Contributor

@ellipsis-dev ellipsis-dev bot left a comment

Choose a reason for hiding this comment

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

Important

Looks good to me! πŸ‘

Reviewed 17003f5 in 59 seconds. Click for details.
  • Reviewed 65 lines of code in 1 files
  • Skipped 0 files when reviewing.
  • Skipped posting 2 draft comments. View those below.
  • Modify your settings and rules to customize what types of comments Ellipsis leaves. And don't forget to react with πŸ‘ or πŸ‘Ž to teach Ellipsis.
1. pos/app/reciept/progress/page.tsx:26
  • Draft comment:
    Minor formatting changes in the arrow function callback are applied. Ensure consistent indentation and formatting across similar functions.
  • Reason this comment was not posted:
    Confidence changes required: 33% <= threshold 50% None
2. pos/app/reciept/progress/page.tsx:218
  • Draft comment:
    The new group header markup (rendered for groupIndex > 0) duplicates layout details. Consider extracting this repeated block into a separate component or helper function for improved readability and maintainability. Also, if 'modifiedAt' is constant, memoize its formatted value to avoid redundant formatting.
  • Reason this comment was not posted:
    Confidence changes required: 33% <= threshold 50% None

Workflow ID: wflow_UXPOJM4cxnC80VlE

You can customize Ellipsis by changing your verbosity settings, reacting with πŸ‘ or πŸ‘Ž, replying to comments, or adding code review rules.

@sonarqubecloud
Copy link

@munkhsaikhan munkhsaikhan merged commit 9953c50 into master Aug 15, 2025
10 of 11 checks passed
@munkhsaikhan munkhsaikhan deleted the categoriesPrint branch August 15, 2025 05:58
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.

3 participants