-
Notifications
You must be signed in to change notification settings - Fork 1.2k
update #6102
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
update #6102
Conversation
Reviewer's GuideThis 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 usageclassDiagram
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
}
Flow diagram for item grouping and printing in Progress pageflowchart 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
File-Level Changes
Possibly linked issues
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
|
Note Other AI code review bot(s) detectedCodeRabbit 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. WalkthroughUpdates receipt progress and settings to support multiple category filter groups: store now persists Changes
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
Estimated code review effortπ― 4 (Complex) | β±οΈ ~35 minutes Possibly related PRs
Poem
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 detailsConfiguration used: CodeRabbit UI π‘ Knowledge Base configuration:
You can enable these sources in your CodeRabbit configuration. π Files selected for processing (1)
π§ Files skipped from review as they are similar to previous changes (1)
β° Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
β¨ Finishing Touches
π§ͺ Generate unit tests
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. πͺ§ TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. CodeRabbit Commands (Invoked using PR/Issue comments)Type Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey @ColeGN - I've reviewed your changes - here's some feedback:
- The variable name
categoryOrdersesis confusingβconsider renaming it to something clearer likecategoryGroupsorcategoriesToPrintGroups. - 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>Help me be more useful! Please click π or π on each comment and I'll use the feedback to improve your reviews.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Caution
Changes requested β
Reviewed everything up to 998c4d5 in 2 minutes and 2 seconds. Click for details.
- Reviewed
289lines of code in3files - Skipped
0files when reviewing. - Skipped posting
9draft 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%<= threshold50%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 namecategoryOrdersesappears to be a misspelling. Did you meancategoryOrders? - 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 namecategoryOrdersesis 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 likecategoryOrderGroups. 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 by changing your verbosity settings, reacting with π or π, replying to comments, or adding code review rules.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 3
π Outside diff range comments (1)
pos/app/reciept/progress/page.tsx (1)
128-144: Type inconsistency in printItems could cause runtime errorsThe
printItemsvariable can be eitherOrderItem[]orOrderItem[][]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 importThe
Xicon 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 groupCurrently, 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 emojiUsing 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
Xfrom 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 extractionThe 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
π 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)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Important
Looks good to me! π
Reviewed 4630542 in 1 minute and 28 seconds. Click for details.
- Reviewed
255lines of code in3files - Skipped
0files when reviewing. - Skipped posting
4draft 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%<= threshold50%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%<= threshold50%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%<= threshold50%None
Workflow ID: wflow_1jjvOuYn242n8lIq
You can customize by changing your verbosity settings, reacting with π or π, replying to comments, or adding code review rules.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
π Outside diff range comments (1)
pos/app/reciept/progress/page.tsx (1)
226-234: Guard against items being undefined when computing totalsCalling 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 insteadYou 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 typesToday 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 migrationThis 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 closuresThese 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 changeIndex-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 buttonAdd 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
π 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.filterUsing 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[][] shapemigrateCategoriesData 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 detectedAll 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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Important
Looks good to me! π
Reviewed 7a242ec in 1 minute and 18 seconds. Click for details.
- Reviewed
219lines of code in2files - Skipped
0files when reviewing. - Skipped posting
7draft 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%<= threshold50%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%<= threshold50%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%<= threshold50%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%<= threshold50%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%<= threshold50%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%<= threshold50%None
Workflow ID: wflow_3ek3qRNgyX19VZqL
You can customize by changing your verbosity settings, reacting with π or π, replying to comments, or adding code review rules.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 3
π Outside diff range comments (3)
pos/modules/settings/components/categoriesToPrint.tsx (2)
33-38: Guard against undefinedcategoriesinrootCategories
categories.find(...)will throw ifcategoriesis 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 ingetDirectChildrenwhencategoriesis undefinedUse 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 groupsThe callback uses a captured
categoriesToPrintvalue, 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 detectionGuarding with
printItems.length > 0before peeking at[0]addresses the fragility noted previously.
42-84: Add onError handler to avoid a stuck progress windowIf
getCategoryOrdersfails, 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 inupdateFilterto avoid OOB updatesPrevents 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 groupsThe 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
categoriesToPrintAtomto 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 crossFor 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
π 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 groupsUsing 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 matchWhen 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.
| useEffect(() => { | ||
| if (itemsToPrint.length > 0) { | ||
| window.print() | ||
| setTimeout(() => { | ||
| window.print() | ||
| }, 100) | ||
| } | ||
| }, [itemsToPrint]) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
π οΈ 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.
| 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.
| 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]) | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
π οΈ 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.
| 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.
| const removeFilter = (index: number) => { | ||
| if (categoriesToPrint.length > 1) { | ||
| setCategoriesToPrint((prev) => | ||
| prev.length > 1 ? prev.filter((_, i) => i !== index) : prev | ||
| ) | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
π οΈ 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.
| 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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Important
Looks good to me! π
Reviewed 17003f5 in 59 seconds. Click for details.
- Reviewed
65lines of code in1files - Skipped
0files when reviewing. - Skipped posting
2draft 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%<= threshold50%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%<= threshold50%None
Workflow ID: wflow_UXPOJM4cxnC80VlE
You can customize by changing your verbosity settings, reacting with π or π, replying to comments, or adding code review rules.
|
ISSUE
Context
Your context here. Additionally, any screenshots. Delete this line.
// Delete the below section once completed
PR Checklist
Summary by Sourcery
Implement multi-group category filter support for printing
New Features:
Enhancements:
Summary by CodeRabbit
New Features
UI
Behavior
Chores
Important
Add support for multiple category filter groups in printing, enhancing UI and logic in
page.tsxandcategoriesToPrint.tsx.page.tsxfor printing, with separators for grouped items.categoriesToPrint.tsx: Add/remove print groups with a button; remove button visible when multiple groups exist.page.tsx: Preserve "Only new items" filtering; refine auto-printing logic with delayed trigger and filter gating.index.tsx: MigratecategoriesToPrintAtomto nested storage format with compatibility handling.This description was created by
for 17003f5. You can customize this summary. It will automatically update as commits are pushed.