Skip to content

Conversation

@Kato-111
Copy link
Collaborator

@Kato-111 Kato-111 commented Aug 4, 2025

Summary by Sourcery

Refactor and enhance product category selection and inline editing across the UI by replacing the legacy SelectTree component with a context-driven SelectCategory API, introduce inline category displays, and unify filter state management using erxes-ui’s query state hooks.

New Features:

  • Add SelectCategory API with provider, value, content, badge, filter, inline cell, and form item components supporting single or multiple modes and search-driven category selection
  • Introduce CategoriesInline component with useCategoryInline and useCategoriesWithSearch hooks for inline category display and dynamic fetching
  • Integrate SelectBrand and SelectCategory filters into ProductsFilter bar and popover, highlighting active filters in the bar

Enhancements:

  • Replace legacy SelectTree dropdown with context-based popover patterns for category selection
  • Enable inline editing of product names and categories in the product table via RecordTablePopover and Input components
  • Migrate product detail routing and state from useSearchParams to erxes-ui useQueryState
  • Extend useProducts and useCustomers hooks with multi-query state filters, cursor-based pagination skip logic, and richer query variables
  • Update GraphQL schemas for products and categories to support search parameters, pagination, orderBy, and new fields

Chores:

  • Tighten IProductCategory and ProductDetail types to enforce non-nullable fields
  • Adjust CSS classes and improve record table cursor atom initialization logic

Important

Refactor product category selection and inline editing by replacing SelectTree with SelectCategory API, adding inline displays, and unifying filter state management.

  • Behavior:
    • Replaces SelectTree with SelectCategory API for category selection, supporting single/multiple modes and search-driven selection.
    • Adds CategoriesInline component for inline category display with useCategoryInline and useCategoriesWithSearch hooks.
    • Integrates SelectBrand and SelectCategory filters into ProductsFilter bar and popover.
  • Enhancements:
    • Enables inline editing of product names and categories in ProductColumns.tsx using RecordTablePopover and Input components.
    • Migrates product detail routing and state from useSearchParams to useQueryState in ProductDetailSheet.tsx.
    • Extends useProducts and useCustomers hooks with multi-query state filters and cursor-based pagination.
    • Updates GraphQL schemas in ProductsQueries.tsx to support search parameters, pagination, and new fields.
  • Chores:
    • Tightens IProductCategory and ProductDetail types to enforce non-nullable fields.
    • Adjusts CSS classes and improves record table cursor atom initialization logic in useRecordTableCursor.tsx.

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


Summary by CodeRabbit

  • New Features

    • Introduced an inline display component for product categories with flexible badge and tooltip rendering.
    • Added advanced, searchable, and multi-select category selection components, including filter bars and inline editing for product tables.
    • Added new hooks for fetching categories with search and for inline category detail retrieval.
    • Added context providers for managing category selection and inline category data.
  • Enhancements

    • Product table columns now support inline editing for product name and category.
    • Product filters now include brand and category options, with improved multi-query state management and filter bar UI.
    • Improved product detail and filter components for better query state and visual feedback.
    • GraphQL queries for products and categories now support additional fields and filtering options.
    • Added error toast notifications for product update failures.
    • Enhanced handling of query state and cursor management in customers, products, and record tables.
  • Bug Fixes

    • Improved handling of empty cursor and session storage states in record tables.
    • Adjusted fallback values for company data tables to prevent empty displays.
  • Refactor

    • Major refactor of category selection logic from tree-based to command palette style with context-driven state.
    • Updated internal and public types for stricter requirements and improved maintainability.
    • Replaced URL query parameter handling with a unified query state hook for product details.
    • Reformatted hooks for improved readability and safer query execution.
  • Style

    • Updated visual styling for category selectors and upload buttons in product detail forms.
  • Chores

    • Removed deprecated and unused components related to product table "more" actions.

Kato-111 and others added 25 commits July 3, 2025 13:42
…on fields; update PhoneField and TextField components for improved handling.
…ates; refactor hooks and improve input validation.
@sourcery-ai
Copy link

sourcery-ai bot commented Aug 4, 2025

Reviewer's Guide

This PR overhauls the product category selection UI into a composable, context-driven API, introduces inline category badges, migrates session/filter state to useQueryState/useMultiQueryState, enhances table inline editing for product name and category, and refines data-fetching hooks, GraphQL schemas, types, and minor UI polish for consistency.

Sequence diagram for inline product category editing in table

sequenceDiagram
  participant User as actor User
  participant Table as Product Table
  participant InlineCell as SelectCategory.InlineCell
  participant Context as SelectProductCategoryContext
  participant API as GraphQL API

  User->>Table: Clicks category cell
  Table->>InlineCell: Renders SelectCategory.InlineCell
  InlineCell->>Context: Provides category context
  InlineCell->>API: Fetches categories (with search)
  User->>InlineCell: Selects new category
  InlineCell->>Context: onValueChange(newCategoryId)
  InlineCell->>API: Triggers productsEdit mutation
  API-->>InlineCell: Returns updated product
  InlineCell->>Table: Updates cell display
Loading

Class diagram for new SelectCategory composable API

classDiagram
  class SelectCategory {
    +Provider
    +Value
    +Content
    +Badge
    +FilterItem
    +FilterView
    +FilterBar
    +InlineCell
    +FormItem
  }
  class SelectCategoryProvider {
    +mode: 'single' | 'multiple'
    +value: string[] | string
    +onValueChange(value)
    +categories: IProductCategory[]
  }
  class SelectCategoryValue
  class SelectCategoryContent
  class SelectCategoryBadge
  class SelectCategoryFilterItem
  class SelectCategoryFilterView
  class SelectCategoryFilterBar
  class SelectCategoryInlineCell
  class SelectCategoryFormItem

  SelectCategory --> SelectCategoryProvider
  SelectCategory --> SelectCategoryValue
  SelectCategory --> SelectCategoryContent
  SelectCategory --> SelectCategoryBadge
  SelectCategory --> SelectCategoryFilterItem
  SelectCategory --> SelectCategoryFilterView
  SelectCategory --> SelectCategoryFilterBar
  SelectCategory --> SelectCategoryInlineCell
  SelectCategory --> SelectCategoryFormItem
Loading

Class diagram for new category context and inline components

classDiagram
  class SelectProductCategoryContext {
    +categoryIds: string[]
    +categories: IProductCategory[]
    +setCategories(categories)
    +onSelect(category)
    +loading: boolean
    +error: string | null
  }
  class CategoriesInlineContext {
    +categories: IProductCategory[]
    +loading: boolean
    +categoryIds: string[]
    +placeholder: string
    +updateCategories(categories)
  }
  class CategoriesInline {
    +Provider
    +Title
  }
  SelectCategoryProvider --> SelectProductCategoryContext
  CategoriesInline.Provider --> CategoriesInlineContext
  CategoriesInline --> CategoriesInline.Provider
  CategoriesInline --> CategoriesInline.Title
Loading

Class diagram for updated IProductCategory and related types

classDiagram
  class IProductCategory {
    +_id: string
    +name: string
    +avatar?: IAttachment
    +attachment?: IAttachment
    +code: string
    +order: string
    +productCount: number
    +parentId?: string
  }
  class CategoriesInlineProps {
    +categoryIds?: string[]
    +categories?: IProductCategory[]
    +placeholder?: string
    +updateCategories(categories)
  }
  IProductCategory <|-- CategoriesInlineProps: uses
Loading

File-Level Changes

Change Details Files
Refactor SelectCategory into a context-driven, composable component set
  • Removed legacy SelectTree implementation
  • Introduced Provider/Value/Content/Badge subcomponents using Combobox, Popover, Filter
  • Added useCategoriesWithSearch hook with search/debounce and SelectProductCategoryContext
  • Created CategoriesInline component with its context and inline fetch hook
  • Updated GraphQL queries to support filtered productCategories and added productCategoryDetail
frontend/libs/ui-modules/src/modules/products/categories/components/selectCategory.tsx
frontend/libs/ui-modules/src/modules/products/categories/graphql/queries.ts
frontend/libs/ui-modules/src/modules/products/categories/types/category.ts
frontend/libs/ui-modules/src/modules/products/categories/contexts/SelectProductCategoryContext.tsx
frontend/libs/ui-modules/src/modules/products/categories/hooks/useCategoriesWithSearch.tsx
frontend/libs/ui-modules/src/modules/products/categories/hooks/useCategoryInline.tsx
frontend/libs/ui-modules/src/modules/products/categories/components/CategoriesInline.tsx
Migrate session and filter state to useQueryState/useMultiQueryState
  • Replaced useSearchParams with useQueryState in ProductDetailSheet and useProductDetail hook
  • Added skip logic in useCustomers and useProducts based on undefined cursor
  • Refined useRecordTableCursor to initialize as undefined when session storage is empty
  • Integrated useMultiQueryState/useFilterContext in products and customers filters
frontend/core-ui/src/modules/products/detail/components/ProductDetailSheet.tsx
frontend/core-ui/src/modules/products/detail/hooks/useProductDetail.tsx
frontend/libs/erxes-ui/src/modules/record-table/hooks/useRecordTableCursor.tsx
frontend/core-ui/src/modules/contacts/customers/hooks/useCustomers.tsx
frontend/core-ui/src/modules/products/components/ProductsFilter.tsx
Enhance table inline editing and fallback behavior
  • Wrapped product name cell in RecordTablePopover with Badge and Input for inline edit and detail toggle
  • Replaced static category display with SelectCategory.InlineCell for direct in-cell updates
  • Adjusted CompaniesRecordTable to use [{}] fallback when data is empty
frontend/core-ui/src/modules/products/components/ProductColumns.tsx
frontend/core-ui/src/modules/contacts/companies/components/CompaniesRecordTable.tsx
Extend and clean up data-fetching hooks and GraphQL schemas
  • Expanded useProducts and useCustomers hooks to build full queryVariables (filters, orderBy, pagination) and applied skip logic
  • Made useUom options optional
  • Updated GraphQL: added orderBy and category.code to productsMain, added cursor to GET_COMPANIES, refined ProductCategories queries
frontend/core-ui/src/modules/products/hooks/useProducts.tsx
frontend/core-ui/src/modules/contacts/customers/hooks/useCustomers.tsx
frontend/core-ui/src/modules/products/hooks/useUom.tsx
frontend/core-ui/src/modules/products/graphql/ProductsQueries.tsx
frontend/core-ui/src/modules/contacts/companies/graphql/queries/getCompanies.ts
Minor type refinements and UI polish
  • Marked IProductCategory.attachment optional and enforced required _id/name in detail types
  • Changed ProductsPath.Index to empty string
  • Updated recordTableCursorAtomFamily to allow undefined
  • Removed redundant loading spinner in ProductGeneral
  • Tweaked Filter.Trigger isFiltered, CommandInput styling, and FormItem button shadow
frontend/libs/ui-modules/src/modules/products/categories/types/category.ts
frontend/core-ui/src/modules/products/detail/types/detailTypes.ts
frontend/core-ui/src/modules/types/paths/ProductsPath.ts
frontend/libs/erxes-ui/src/modules/record-table/states/RecordTableCursorState.ts
frontend/core-ui/src/modules/products/detail/components/ProductGeneral.tsx
frontend/core-ui/src/modules/products/components/ProductsFilter.tsx
frontend/core-ui/src/modules/products/detail/components/ProductBasicField.tsx

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

This update introduces a major refactor and feature enhancement for product category selection and display in the frontend. It replaces the previous tree-based category selector with a new context-driven, searchable, and paginated command-list UI. Inline display and editing of categories are now supported in tables and forms. Several new React contexts, hooks, and components are added for managing category selection and inline rendering. GraphQL queries for categories are extended, and related types/interfaces are updated for improved data handling and flexibility. Some obsolete components are removed, and minor improvements are made to related modules.

Changes

Cohort / File(s) Change Summary
Product Category Selection Refactor
frontend/libs/ui-modules/src/modules/products/categories/components/selectCategory.tsx
Complete refactor: replaces old tree-based selector with context-driven, searchable, command-list UI; adds new provider, value, command item, content, filter, inline cell, and form item components for flexible category selection and integration.
Inline Category Display Feature
frontend/libs/ui-modules/src/modules/products/categories/components/CategoriesInline.tsx,
frontend/libs/ui-modules/src/modules/products/categories/contexts/CategoriesInlineContext.tsx,
frontend/libs/ui-modules/src/modules/products/categories/hooks/useCategoryInline.tsx,
frontend/libs/ui-modules/src/modules/products/categories/types/category.ts
Adds new compound component for inline category display with context, effect-based fetching, and flexible rendering; introduces supporting context, hook, and types for inline category management.
Category Selection Context
frontend/libs/ui-modules/src/modules/products/contexts/SelectProductCategoryContext.tsx
Adds new context and hook for managing selected product categories, including state and error handling.
Category GraphQL Enhancements
frontend/libs/ui-modules/src/modules/products/categories/graphql/queries.ts,
frontend/libs/ui-modules/src/modules/products/categories/hooks/useCategoriesWithSearch.tsx
Extends productCategories query to accept search, parent, and child filters; adds new productCategoryDetail query; introduces a new hook for fetching categories with search support.
Product Table and Filtering Enhancements
frontend/core-ui/src/modules/products/components/ProductColumns.tsx,
frontend/core-ui/src/modules/products/components/ProductsFilter.tsx
Updates product table columns to support inline editing of name and category; integrates new category filter bar and popover UI using the refactored selector.
Product More Column Removal
frontend/core-ui/src/modules/products/components/ProductMoreColumn.tsx
Removes obsolete "more" column and cell component from product table.
Product Detail and Sheet Query State Refactor
frontend/core-ui/src/modules/products/detail/components/ProductDetailSheet.tsx,
frontend/core-ui/src/modules/products/detail/hooks/useProductDetail.tsx
Replaces usage of useSearchParams with useQueryState for managing product ID in URL query state.
Product Detail UI and Type Adjustments
frontend/core-ui/src/modules/products/detail/components/ProductBasicField.tsx,
frontend/core-ui/src/modules/products/detail/components/ProductGeneral.tsx,
frontend/core-ui/src/modules/products/detail/types/detailTypes.ts
Minor UI improvements (styling, loading spinner removal); makes _id and name required in product detail types.
Product GraphQL Query Updates
frontend/core-ui/src/modules/products/graphql/ProductsQueries.tsx
Adds orderBy input and category.code field to main products query; renames product categories query.
Product List Query/Hook Improvements
frontend/core-ui/src/modules/products/hooks/useProducts.tsx,
frontend/core-ui/src/modules/products/hooks/useUom.tsx
Enhances product list hook to use multi-query state for filters; makes UOM hook parameter optional.
Contacts/Companies Table and Query Adjustments
frontend/core-ui/src/modules/contacts/companies/components/CompaniesRecordTable.tsx,
frontend/core-ui/src/modules/contacts/companies/graphql/queries/getCompanies.ts
Changes fallback data handling in companies table; adds cursor field to companies GraphQL query.
Customers Hook Refactor
frontend/core-ui/src/modules/contacts/customers/hooks/useCustomers.tsx
Refactors for clarity and safety, adds skip logic to query if cursor is missing.
Record Table Cursor State Handling
frontend/libs/erxes-ui/src/modules/record-table/hooks/useRecordTableCursor.tsx,
frontend/libs/erxes-ui/src/modules/record-table/states/RecordTableCursorState.ts
Improves cursor state handling for empty string/null/undefined; updates atom family to support undefined.
Product HotKey Scope and Paths
frontend/core-ui/src/modules/products/types/ProductsHotKeyScope.ts,
frontend/core-ui/src/modules/types/paths/ProductsPath.ts
Adds new hotkey scope enum value for categories page; changes index path value from '/' to ''.
Products Edit Hook Enhancement
frontend/core-ui/src/modules/products/hooks/useProductsEdit.tsx
Adds toast notification on product update mutation error for user feedback.
Team Members Types Cleanup
frontend/libs/ui-modules/src/modules/team-members/types/TeamMembers.ts
Removes unused imports related to permission schema and zod library.

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant ProductTable
  participant SelectCategory
  participant CategoriesInline
  participant ApolloClient

  User->>ProductTable: Interacts with product row
  ProductTable->>SelectCategory: Opens category selector (inline/edit/filter)
  SelectCategory->>ApolloClient: Fetch categories with search/filter
  ApolloClient-->>SelectCategory: Return categories
  SelectCategory->>ProductTable: Update selected category
  ProductTable->>CategoriesInline: Display selected categories inline
  CategoriesInline->>ApolloClient: Fetch category details (if needed)
  ApolloClient-->>CategoriesInline: Return category info
  CategoriesInline->>ProductTable: Render badges/titles
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~40 minutes

Possibly related PRs

  • product detail #53: This PR previously added the now-removed ProductMoreColumn.tsx and its exports; the current PR removes those same entities, making them directly related but with inverse changes.

Poem

In the garden of code, where categories bloom,
A rabbit hops through filters, dispelling the gloom.
With badges and popovers, and context so neat,
Inline or in tables, selection’s a treat!
From queries to hooks, the carrots align—
A harvest of features, all working just fine.
🥕✨

Note

🔌 MCP (Model Context Protocol) integration is now available in Early Access!

Pro users can now connect to remote MCP servers under the Integrations page to get reviews and chat conversations that understand additional development context.

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch product-fix

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.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @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 comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai generate unit tests to generate unit tests for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

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

CodeRabbit Configuration File (.coderabbit.yaml)

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

Documentation and Community

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

Copy link

@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 @Kato-111 - I've reviewed your changes - here's some feedback:

  • Split the massive SelectCategory component into smaller, focused modules/files to improve readability and maintenance.
  • Align GraphQL operation names and definitions (e.g. the detail query is named ProductCategories) with their actual use to avoid confusion.
  • Remove or complete commented-out code and stub methods (e.g. the loading spinner in ProductDetailForm and handleFetchMore in useCategoriesWithSearch) before merging.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- Split the massive SelectCategory component into smaller, focused modules/files to improve readability and maintenance.
- Align GraphQL operation names and definitions (e.g. the detail query is named `ProductCategories`) with their actual use to avoid confusion.
- Remove or complete commented-out code and stub methods (e.g. the loading spinner in ProductDetailForm and handleFetchMore in useCategoriesWithSearch) before merging.

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.

Copy link

@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 ff8b238 in 1 minute and 52 seconds. Click for details.
  • Reviewed 1609 lines of code in 26 files
  • Skipped 0 files when reviewing.
  • Skipped posting 5 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. frontend/core-ui/src/modules/products/detail/types/detailTypes.ts:19
  • Draft comment:
    Making _id and name required in ProductDetail might break components expecting them as optional. Verify that the API always provides these fields.
  • 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 API always provides certain fields, which falls under asking the author to ensure behavior is intended or to double-check things. This violates the rules.
2. frontend/core-ui/src/modules/types/paths/ProductsPath.ts:2
  • Draft comment:
    The Index path is changed from '/' to an empty string ''. Confirm that this change aligns with the router configuration and does not affect navigation.
  • Reason this comment was not posted:
    Comment did not seem useful. Confidence is useful = 40% <= threshold 50% The comment is asking the PR author to confirm their intention regarding a change in the index path. This violates the rule against asking the author to confirm their intention or ensure behavior is intended. However, it does point out a specific change that could have implications, which might be useful for the author to consider. The comment could be rephrased to suggest checking the router configuration without asking for confirmation.
3. frontend/libs/ui-modules/src/modules/products/categories/components/selectCategory.tsx:90
  • Draft comment:
    In the multiple-selection onSelect logic, the use of setCategories with [...prev, category].filter(...) may lead to duplicates if not carefully managed. Review the logic to ensure the final list only contains unique selections.
  • Reason this comment was not posted:
    Comment looked like it was already resolved.
4. frontend/libs/ui-modules/src/modules/products/categories/components/selectCategory.tsx:109
  • Draft comment:
    The SelectCategoryProvider sets fixed values for loading (false) and error (null). If asynchronous fetching is anticipated, consider making these reactive.
  • 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 Provider component is just a wrapper for managing selected categories state. The actual loading/error states for fetching categories are handled by useCategoriesWithSearch hook in the Content component. The Provider doesn't need to manage loading/error states since that's not its responsibility - it just manages selection state. The comment seems to misunderstand the component's purpose. I could be wrong about the component architecture - maybe there are cases where the Provider should propagate loading states from somewhere else. Looking at the usage, the Provider is clearly focused on selection state management only. Loading states are properly handled where needed in the Content component. The comment should be deleted because it misunderstands the component's purpose - loading/error states are intentionally hardcoded in the Provider since it only manages selection state, while actual loading is handled elsewhere.
5. frontend/core-ui/src/modules/products/components/ProductColumns.tsx:15
  • Draft comment:
    Typo detected: 'CurrencyFormatedDisplay' might be intended to be 'CurrencyFormattedDisplay'. Please verify the correct spelling.
  • Reason this comment was not posted:
    Comment was on unchanged code.

Workflow ID: wflow_WDfROII0qrqD4k1Z

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

🔭 Outside diff range comments (1)
frontend/core-ui/src/modules/products/types/ProductsHotKeyScope.ts (1)

1-8: Replace enum with a const-map to comply with repo guidelines

The repo-wide guideline for *.{ts,tsx} explicitly says “Avoid enums; use maps instead.”
Adding another member continues the enum usage instead of moving toward the preferred pattern.

Consider refactoring the whole declaration to a const object + union type to stay future-proof and guideline-compliant:

-export enum ProductHotKeyScope {
-  ProductsPage = 'products-page',
-  ProductAddSheet = 'product-add-sheet',
-  ProductEditSheet = 'product-edit-sheet',
-  ProductAddSheetDescriptionField = 'product-add-sheet-description-field',
-  ProductAddSheetBarcodeDescriptionField = 'product-add-sheet-barcode-description-field',
-  CategoriesPage = 'categories-page',
-}
+export const ProductHotKeyScope = {
+  ProductsPage: 'products-page',
+  ProductAddSheet: 'product-add-sheet',
+  ProductEditSheet: 'product-edit-sheet',
+  ProductAddSheetDescriptionField: 'product-add-sheet-description-field',
+  ProductAddSheetBarcodeDescriptionField: 'product-add-sheet-barcode-description-field',
+  CategoriesPage: 'categories-page',
+} as const;
+
+export type ProductHotKeyScope =
+  typeof ProductHotKeyScope[keyof typeof ProductHotKeyScope];

Benefits:

  • Aligns with established code standards.
  • Prevents TS runtime footprint that enums introduce.
  • Simplifies tree-shaking and minification.

If large-scale refactor is out-of-scope for this PR, at least add a TODO to migrate in a follow-up.

🧹 Nitpick comments (7)
frontend/libs/erxes-ui/src/modules/record-table/hooks/useRecordTableCursor.tsx (1)

14-18: Optimize sessionStorage access and improve readability.

The logic improvement to treat empty strings as null is good, but the current implementation calls sessionStorage.getItem(sessionKey) twice, which is inefficient.

-    setCursor(
-      sessionStorage.getItem(sessionKey) !== ''
-        ? sessionStorage.getItem(sessionKey)
-        : null,
-    );
+    const storedValue = sessionStorage.getItem(sessionKey);
+    setCursor(storedValue !== '' ? storedValue : null);
frontend/core-ui/src/modules/products/detail/components/ProductGeneral.tsx (2)

26-32: Remove commented code instead of leaving it in the codebase.

The commented-out loading spinner code should be removed entirely rather than left as comments. This follows clean code practices and prevents code bloat.

Apply this diff to remove the commented code:

-  // if (loading) {
-  //   return (
-  //     <div className="flex flex-col items-center justify-center h-full space-y-4">
-  //       <Spinner />
-  //     </div>
-  //   );
-  // }

21-52: Consider implementing alternative loading state management.

With the removal of the loading state from useProductDetail, there's no loading feedback for users while the product data is being fetched. Consider implementing an alternative loading state mechanism or using Suspense boundaries to maintain good UX.

frontend/core-ui/src/modules/products/detail/components/ProductDetailSheet.tsx (1)

18-22: Consider minimizing useEffect usage per coding guidelines.

While the current useEffect is functional, consider if the hotkey scope management could be handled differently to align with the guideline to minimize useEffect usage. Perhaps the hotkey scope could be managed directly in the setOpen function or through a derived state pattern.

- useEffect(() => {
-   if (productId) {
-     setHotkeyScope(ProductHotKeyScope.ProductEditSheet);
-   }
- }, [productId, setHotkeyScope]);

And integrate the scope setting directly in setOpen:

 const setOpen = (newProductId: string | null) => {
   if (newProductId) {
     setProductId(newProductId);
+    setHotkeyScope(ProductHotKeyScope.ProductEditSheet);
   } else {
     setProductId(null);
+    setHotkeyScope(ProductHotKeyScope.ProductsPage);
   }
-
-   if (!newProductId) {
-     setHotkeyScope(ProductHotKeyScope.ProductsPage);
-   }
 };
frontend/core-ui/src/modules/products/hooks/useProducts.tsx (1)

39-52: Consider extracting date filter logic for reusability

The date filter construction is complex and could be reused across different hooks. JSON stringification of filters might also cause parsing overhead.

Consider extracting this logic into a utility function:

function buildDateFilters(created: string, updated: string, lastSeen: string) {
  return {
    createdAt: {
      gte: parseDateRangeFromString(created)?.from,
      lte: parseDateRangeFromString(created)?.to,
    },
    updatedAt: {
      gte: parseDateRangeFromString(updated)?.from,
      lte: parseDateRangeFromString(updated)?.to,
    },
    lastSeenAt: {
      gte: parseDateRangeFromString(lastSeen)?.from,
      lte: parseDateRangeFromString(lastSeen)?.to,
    },
  };
}

Then use it as:

-    dateFilters: JSON.stringify({
-      createdAt: {
-        gte: parseDateRangeFromString(created)?.from,
-        lte: parseDateRangeFromString(created)?.to,
-      },
-      updatedAt: {
-        gte: parseDateRangeFromString(updated)?.from,
-        lte: parseDateRangeFromString(updated)?.to,
-      },
-      lastSeenAt: {
-        gte: parseDateRangeFromString(lastSeen)?.from,
-        lte: parseDateRangeFromString(lastSeen)?.to,
-      },
-    }),
+    dateFilters: JSON.stringify(buildDateFilters(created, updated, lastSeen)),
frontend/libs/ui-modules/src/modules/products/categories/hooks/useCategoriesWithSearch.tsx (1)

21-25: Consider making handleFetchMore implementation explicit

While the comment explains why pagination isn't needed, the empty function could be more explicit about being a no-op.

Make the no-op nature more explicit:

   // Simple fetch more simulation since categories don't have cursor pagination
   const handleFetchMore = () => {
     // Categories typically don't need pagination as they're usually a smaller dataset
     // This is here for API compatibility with brands
+    return;
   };
frontend/libs/ui-modules/src/modules/products/categories/components/CategoriesInline.tsx (1)

106-106: Remove incorrect ESLint disable comment

The ESLint disable comment references a rule that doesn't exist in the configuration.

Remove the ESLint disable comment since the proper dependencies should be included.

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between fd3286a and ff8b238.

📒 Files selected for processing (26)
  • frontend/core-ui/src/modules/contacts/companies/components/CompaniesRecordTable.tsx (1 hunks)
  • frontend/core-ui/src/modules/contacts/companies/graphql/queries/getCompanies.ts (1 hunks)
  • frontend/core-ui/src/modules/contacts/customers/hooks/useCustomers.tsx (1 hunks)
  • frontend/core-ui/src/modules/products/components/ProductColumns.tsx (3 hunks)
  • frontend/core-ui/src/modules/products/components/ProductMoreColumn.tsx (0 hunks)
  • frontend/core-ui/src/modules/products/components/ProductsFilter.tsx (1 hunks)
  • frontend/core-ui/src/modules/products/detail/components/ProductBasicField.tsx (2 hunks)
  • frontend/core-ui/src/modules/products/detail/components/ProductDetailSheet.tsx (3 hunks)
  • frontend/core-ui/src/modules/products/detail/components/ProductGeneral.tsx (1 hunks)
  • frontend/core-ui/src/modules/products/detail/hooks/useProductDetail.tsx (2 hunks)
  • frontend/core-ui/src/modules/products/detail/types/detailTypes.ts (2 hunks)
  • frontend/core-ui/src/modules/products/graphql/ProductsQueries.tsx (4 hunks)
  • frontend/core-ui/src/modules/products/hooks/useProducts.tsx (3 hunks)
  • frontend/core-ui/src/modules/products/hooks/useUom.tsx (1 hunks)
  • frontend/core-ui/src/modules/products/types/ProductsHotKeyScope.ts (1 hunks)
  • frontend/core-ui/src/modules/types/paths/ProductsPath.ts (1 hunks)
  • frontend/libs/erxes-ui/src/modules/record-table/hooks/useRecordTableCursor.tsx (1 hunks)
  • frontend/libs/erxes-ui/src/modules/record-table/states/RecordTableCursorState.ts (1 hunks)
  • frontend/libs/ui-modules/src/modules/products/categories/components/CategoriesInline.tsx (1 hunks)
  • frontend/libs/ui-modules/src/modules/products/categories/components/selectCategory.tsx (3 hunks)
  • frontend/libs/ui-modules/src/modules/products/categories/contexts/CategoriesInlineContext.tsx (1 hunks)
  • frontend/libs/ui-modules/src/modules/products/categories/graphql/queries.ts (2 hunks)
  • frontend/libs/ui-modules/src/modules/products/categories/hooks/useCategoriesWithSearch.tsx (1 hunks)
  • frontend/libs/ui-modules/src/modules/products/categories/hooks/useCategoryInline.tsx (1 hunks)
  • frontend/libs/ui-modules/src/modules/products/categories/types/category.ts (2 hunks)
  • frontend/libs/ui-modules/src/modules/products/contexts/SelectProductCategoryContext.tsx (1 hunks)
💤 Files with no reviewable changes (1)
  • frontend/core-ui/src/modules/products/components/ProductMoreColumn.tsx
🧰 Additional context used
📓 Path-based instructions (5)
**/*.{ts,tsx}

📄 CodeRabbit Inference Engine (.cursorrules)

**/*.{ts,tsx}: Use functional and declarative programming patterns; avoid classes.
Use TypeScript for all code; prefer interfaces over types.
Avoid enums; use maps instead.

Files:

  • frontend/core-ui/src/modules/products/detail/components/ProductBasicField.tsx
  • frontend/core-ui/src/modules/products/types/ProductsHotKeyScope.ts
  • frontend/core-ui/src/modules/products/detail/components/ProductGeneral.tsx
  • frontend/libs/erxes-ui/src/modules/record-table/hooks/useRecordTableCursor.tsx
  • frontend/libs/erxes-ui/src/modules/record-table/states/RecordTableCursorState.ts
  • frontend/core-ui/src/modules/contacts/companies/graphql/queries/getCompanies.ts
  • frontend/core-ui/src/modules/products/detail/types/detailTypes.ts
  • frontend/core-ui/src/modules/types/paths/ProductsPath.ts
  • frontend/core-ui/src/modules/products/hooks/useUom.tsx
  • frontend/core-ui/src/modules/products/detail/hooks/useProductDetail.tsx
  • frontend/libs/ui-modules/src/modules/products/categories/contexts/CategoriesInlineContext.tsx
  • frontend/core-ui/src/modules/products/graphql/ProductsQueries.tsx
  • frontend/core-ui/src/modules/contacts/companies/components/CompaniesRecordTable.tsx
  • frontend/libs/ui-modules/src/modules/products/categories/types/category.ts
  • frontend/core-ui/src/modules/products/detail/components/ProductDetailSheet.tsx
  • frontend/core-ui/src/modules/products/components/ProductColumns.tsx
  • frontend/libs/ui-modules/src/modules/products/contexts/SelectProductCategoryContext.tsx
  • frontend/libs/ui-modules/src/modules/products/categories/hooks/useCategoriesWithSearch.tsx
  • frontend/core-ui/src/modules/products/hooks/useProducts.tsx
  • frontend/libs/ui-modules/src/modules/products/categories/hooks/useCategoryInline.tsx
  • frontend/core-ui/src/modules/contacts/customers/hooks/useCustomers.tsx
  • frontend/core-ui/src/modules/products/components/ProductsFilter.tsx
  • frontend/libs/ui-modules/src/modules/products/categories/graphql/queries.ts
  • frontend/libs/ui-modules/src/modules/products/categories/components/CategoriesInline.tsx
  • frontend/libs/ui-modules/src/modules/products/categories/components/selectCategory.tsx
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit Inference Engine (.cursorrules)

**/*.{ts,tsx,js,jsx}: Use descriptive variable names with auxiliary verbs (e.g., isLoading, hasError).
Avoid console logs.
Always use absolute paths when importing.
Use the "function" keyword for pure functions.
Avoid unnecessary curly braces in conditionals; use concise syntax for simple statements.

**/*.{ts,tsx,js,jsx}: Use descriptive variable names with auxiliary verbs (e.g., isLoading, hasError).
Use the "function" keyword for pure functions.
Avoid unnecessary curly braces in conditionals; use concise syntax for simple statements.
Use absolute path when import.

Files:

  • frontend/core-ui/src/modules/products/detail/components/ProductBasicField.tsx
  • frontend/core-ui/src/modules/products/types/ProductsHotKeyScope.ts
  • frontend/core-ui/src/modules/products/detail/components/ProductGeneral.tsx
  • frontend/libs/erxes-ui/src/modules/record-table/hooks/useRecordTableCursor.tsx
  • frontend/libs/erxes-ui/src/modules/record-table/states/RecordTableCursorState.ts
  • frontend/core-ui/src/modules/contacts/companies/graphql/queries/getCompanies.ts
  • frontend/core-ui/src/modules/products/detail/types/detailTypes.ts
  • frontend/core-ui/src/modules/types/paths/ProductsPath.ts
  • frontend/core-ui/src/modules/products/hooks/useUom.tsx
  • frontend/core-ui/src/modules/products/detail/hooks/useProductDetail.tsx
  • frontend/libs/ui-modules/src/modules/products/categories/contexts/CategoriesInlineContext.tsx
  • frontend/core-ui/src/modules/products/graphql/ProductsQueries.tsx
  • frontend/core-ui/src/modules/contacts/companies/components/CompaniesRecordTable.tsx
  • frontend/libs/ui-modules/src/modules/products/categories/types/category.ts
  • frontend/core-ui/src/modules/products/detail/components/ProductDetailSheet.tsx
  • frontend/core-ui/src/modules/products/components/ProductColumns.tsx
  • frontend/libs/ui-modules/src/modules/products/contexts/SelectProductCategoryContext.tsx
  • frontend/libs/ui-modules/src/modules/products/categories/hooks/useCategoriesWithSearch.tsx
  • frontend/core-ui/src/modules/products/hooks/useProducts.tsx
  • frontend/libs/ui-modules/src/modules/products/categories/hooks/useCategoryInline.tsx
  • frontend/core-ui/src/modules/contacts/customers/hooks/useCustomers.tsx
  • frontend/core-ui/src/modules/products/components/ProductsFilter.tsx
  • frontend/libs/ui-modules/src/modules/products/categories/graphql/queries.ts
  • frontend/libs/ui-modules/src/modules/products/categories/components/CategoriesInline.tsx
  • frontend/libs/ui-modules/src/modules/products/categories/components/selectCategory.tsx
**/*.{tsx,jsx}

📄 CodeRabbit Inference Engine (.cursorrules)

**/*.{tsx,jsx}: Favor named exports for components.
Use declarative JSX.
Use Shadcn UI, Radix, and Tailwind for components and styling.
Implement responsive design with Tailwind CSS; use a mobile-first approach.

**/*.{tsx,jsx}: Structure files: exported component, subcomponents, helpers, static content, types.
Favor named exports for components.
Use declarative JSX.
Use Shadcn UI, Radix, and Tailwind for components and styling.
Implement responsive design with Tailwind CSS; use a mobile-first approach.

Files:

  • frontend/core-ui/src/modules/products/detail/components/ProductBasicField.tsx
  • frontend/core-ui/src/modules/products/detail/components/ProductGeneral.tsx
  • frontend/libs/erxes-ui/src/modules/record-table/hooks/useRecordTableCursor.tsx
  • frontend/core-ui/src/modules/products/hooks/useUom.tsx
  • frontend/core-ui/src/modules/products/detail/hooks/useProductDetail.tsx
  • frontend/libs/ui-modules/src/modules/products/categories/contexts/CategoriesInlineContext.tsx
  • frontend/core-ui/src/modules/products/graphql/ProductsQueries.tsx
  • frontend/core-ui/src/modules/contacts/companies/components/CompaniesRecordTable.tsx
  • frontend/core-ui/src/modules/products/detail/components/ProductDetailSheet.tsx
  • frontend/core-ui/src/modules/products/components/ProductColumns.tsx
  • frontend/libs/ui-modules/src/modules/products/contexts/SelectProductCategoryContext.tsx
  • frontend/libs/ui-modules/src/modules/products/categories/hooks/useCategoriesWithSearch.tsx
  • frontend/core-ui/src/modules/products/hooks/useProducts.tsx
  • frontend/libs/ui-modules/src/modules/products/categories/hooks/useCategoryInline.tsx
  • frontend/core-ui/src/modules/contacts/customers/hooks/useCustomers.tsx
  • frontend/core-ui/src/modules/products/components/ProductsFilter.tsx
  • frontend/libs/ui-modules/src/modules/products/categories/components/CategoriesInline.tsx
  • frontend/libs/ui-modules/src/modules/products/categories/components/selectCategory.tsx
**/*.tsx

📄 CodeRabbit Inference Engine (.cursorrules)

**/*.tsx: Use functional components with TypeScript interfaces.
Minimize 'useEffect', and 'setState'.
Wrap client components in Suspense with fallback.
Use dynamic loading for non-critical components.
Limit 'use client': Favor server components and Next.js SSR. Use only for Web API access in small components. Avoid for data fetching or state management.

Files:

  • frontend/core-ui/src/modules/products/detail/components/ProductBasicField.tsx
  • frontend/core-ui/src/modules/products/detail/components/ProductGeneral.tsx
  • frontend/libs/erxes-ui/src/modules/record-table/hooks/useRecordTableCursor.tsx
  • frontend/core-ui/src/modules/products/hooks/useUom.tsx
  • frontend/core-ui/src/modules/products/detail/hooks/useProductDetail.tsx
  • frontend/libs/ui-modules/src/modules/products/categories/contexts/CategoriesInlineContext.tsx
  • frontend/core-ui/src/modules/products/graphql/ProductsQueries.tsx
  • frontend/core-ui/src/modules/contacts/companies/components/CompaniesRecordTable.tsx
  • frontend/core-ui/src/modules/products/detail/components/ProductDetailSheet.tsx
  • frontend/core-ui/src/modules/products/components/ProductColumns.tsx
  • frontend/libs/ui-modules/src/modules/products/contexts/SelectProductCategoryContext.tsx
  • frontend/libs/ui-modules/src/modules/products/categories/hooks/useCategoriesWithSearch.tsx
  • frontend/core-ui/src/modules/products/hooks/useProducts.tsx
  • frontend/libs/ui-modules/src/modules/products/categories/hooks/useCategoryInline.tsx
  • frontend/core-ui/src/modules/contacts/customers/hooks/useCustomers.tsx
  • frontend/core-ui/src/modules/products/components/ProductsFilter.tsx
  • frontend/libs/ui-modules/src/modules/products/categories/components/CategoriesInline.tsx
  • frontend/libs/ui-modules/src/modules/products/categories/components/selectCategory.tsx
**/*.{webp,tsx,jsx}

📄 CodeRabbit Inference Engine (.cursorrules)

Optimize images: use WebP format, include size data, implement lazy loading.

Files:

  • frontend/core-ui/src/modules/products/detail/components/ProductBasicField.tsx
  • frontend/core-ui/src/modules/products/detail/components/ProductGeneral.tsx
  • frontend/libs/erxes-ui/src/modules/record-table/hooks/useRecordTableCursor.tsx
  • frontend/core-ui/src/modules/products/hooks/useUom.tsx
  • frontend/core-ui/src/modules/products/detail/hooks/useProductDetail.tsx
  • frontend/libs/ui-modules/src/modules/products/categories/contexts/CategoriesInlineContext.tsx
  • frontend/core-ui/src/modules/products/graphql/ProductsQueries.tsx
  • frontend/core-ui/src/modules/contacts/companies/components/CompaniesRecordTable.tsx
  • frontend/core-ui/src/modules/products/detail/components/ProductDetailSheet.tsx
  • frontend/core-ui/src/modules/products/components/ProductColumns.tsx
  • frontend/libs/ui-modules/src/modules/products/contexts/SelectProductCategoryContext.tsx
  • frontend/libs/ui-modules/src/modules/products/categories/hooks/useCategoriesWithSearch.tsx
  • frontend/core-ui/src/modules/products/hooks/useProducts.tsx
  • frontend/libs/ui-modules/src/modules/products/categories/hooks/useCategoryInline.tsx
  • frontend/core-ui/src/modules/contacts/customers/hooks/useCustomers.tsx
  • frontend/core-ui/src/modules/products/components/ProductsFilter.tsx
  • frontend/libs/ui-modules/src/modules/products/categories/components/CategoriesInline.tsx
  • frontend/libs/ui-modules/src/modules/products/categories/components/selectCategory.tsx
🧠 Learnings (11)
📚 Learning: applies to **/*.{tsx,jsx} : use shadcn ui, radix, and tailwind for components and styling....
Learnt from: CR
PR: erxes/erxes-next#0
File: .cursorrules:0-0
Timestamp: 2025-07-21T06:09:41.203Z
Learning: Applies to **/*.{tsx,jsx} : Use Shadcn UI, Radix, and Tailwind for components and styling.

Applied to files:

  • frontend/core-ui/src/modules/products/detail/components/ProductBasicField.tsx
  • frontend/libs/ui-modules/src/modules/products/categories/components/CategoriesInline.tsx
  • frontend/libs/ui-modules/src/modules/products/categories/components/selectCategory.tsx
📚 Learning: applies to **/*.{ts,tsx} : avoid enums; use maps instead....
Learnt from: CR
PR: erxes/erxes-next#0
File: .windsurfrules:0-0
Timestamp: 2025-07-21T06:10:08.710Z
Learning: Applies to **/*.{ts,tsx} : Avoid enums; use maps instead.

Applied to files:

  • frontend/core-ui/src/modules/products/types/ProductsHotKeyScope.ts
  • frontend/core-ui/src/modules/types/paths/ProductsPath.ts
📚 Learning: applies to **/*.tsx : use dynamic loading for non-critical components....
Learnt from: CR
PR: erxes/erxes-next#0
File: .windsurfrules:0-0
Timestamp: 2025-07-21T06:10:08.710Z
Learning: Applies to **/*.tsx : Use dynamic loading for non-critical components.

Applied to files:

  • frontend/core-ui/src/modules/products/detail/components/ProductGeneral.tsx
  • frontend/libs/ui-modules/src/modules/products/categories/components/CategoriesInline.tsx
📚 Learning: applies to **/*.tsx : minimize 'useeffect', and 'setstate'....
Learnt from: CR
PR: erxes/erxes-next#0
File: .windsurfrules:0-0
Timestamp: 2025-07-21T06:10:08.710Z
Learning: Applies to **/*.tsx : Minimize 'useEffect', and 'setState'.

Applied to files:

  • frontend/core-ui/src/modules/products/detail/components/ProductGeneral.tsx
  • frontend/libs/erxes-ui/src/modules/record-table/hooks/useRecordTableCursor.tsx
  • frontend/core-ui/src/modules/products/detail/hooks/useProductDetail.tsx
  • frontend/core-ui/src/modules/products/detail/components/ProductDetailSheet.tsx
  • frontend/libs/ui-modules/src/modules/products/categories/hooks/useCategoriesWithSearch.tsx
  • frontend/core-ui/src/modules/products/hooks/useProducts.tsx
  • frontend/core-ui/src/modules/products/components/ProductsFilter.tsx
  • frontend/libs/ui-modules/src/modules/products/categories/components/selectCategory.tsx
📚 Learning: applies to **/*.tsx : use functional components with typescript interfaces....
Learnt from: CR
PR: erxes/erxes-next#0
File: .windsurfrules:0-0
Timestamp: 2025-07-21T06:10:08.710Z
Learning: Applies to **/*.tsx : Use functional components with TypeScript interfaces.

Applied to files:

  • frontend/core-ui/src/modules/products/detail/components/ProductGeneral.tsx
  • frontend/core-ui/src/modules/products/hooks/useUom.tsx
  • frontend/core-ui/src/modules/products/components/ProductColumns.tsx
  • frontend/libs/ui-modules/src/modules/products/categories/hooks/useCategoriesWithSearch.tsx
  • frontend/libs/ui-modules/src/modules/products/categories/hooks/useCategoryInline.tsx
  • frontend/core-ui/src/modules/products/components/ProductsFilter.tsx
  • frontend/libs/ui-modules/src/modules/products/categories/components/CategoriesInline.tsx
  • frontend/libs/ui-modules/src/modules/products/categories/components/selectCategory.tsx
📚 Learning: structure files: exported component, utils, contexts, hooks, types....
Learnt from: CR
PR: erxes/erxes-next#0
File: .cursorrules:0-0
Timestamp: 2025-07-21T06:09:41.203Z
Learning: Structure files: exported component, utils, contexts, hooks, types.

Applied to files:

  • frontend/core-ui/src/modules/products/detail/components/ProductGeneral.tsx
  • frontend/libs/ui-modules/src/modules/products/categories/contexts/CategoriesInlineContext.tsx
  • frontend/libs/ui-modules/src/modules/products/contexts/SelectProductCategoryContext.tsx
  • frontend/libs/ui-modules/src/modules/products/categories/graphql/queries.ts
  • frontend/libs/ui-modules/src/modules/products/categories/components/CategoriesInline.tsx
  • frontend/libs/ui-modules/src/modules/products/categories/components/selectCategory.tsx
📚 Learning: applies to **/*.{ts,tsx,js,jsx} : use absolute path when import....
Learnt from: CR
PR: erxes/erxes-next#0
File: .windsurfrules:0-0
Timestamp: 2025-07-21T06:10:08.710Z
Learning: Applies to **/*.{ts,tsx,js,jsx} : Use absolute path when import.

Applied to files:

  • frontend/core-ui/src/modules/types/paths/ProductsPath.ts
📚 Learning: applies to **/*.{ts,tsx,js,jsx} : always use absolute paths when importing....
Learnt from: CR
PR: erxes/erxes-next#0
File: .cursorrules:0-0
Timestamp: 2025-07-21T06:09:41.203Z
Learning: Applies to **/*.{ts,tsx,js,jsx} : Always use absolute paths when importing.

Applied to files:

  • frontend/core-ui/src/modules/types/paths/ProductsPath.ts
📚 Learning: applies to **/*.{tsx,jsx} : favor named exports for components....
Learnt from: CR
PR: erxes/erxes-next#0
File: .cursorrules:0-0
Timestamp: 2025-07-21T06:09:41.203Z
Learning: Applies to **/*.{tsx,jsx} : Favor named exports for components.

Applied to files:

  • frontend/core-ui/src/modules/products/components/ProductsFilter.tsx
  • frontend/libs/ui-modules/src/modules/products/categories/components/CategoriesInline.tsx
  • frontend/libs/ui-modules/src/modules/products/categories/components/selectCategory.tsx
📚 Learning: applies to **/*.{tsx,jsx} : structure files: exported component, subcomponents, helpers, static cont...
Learnt from: CR
PR: erxes/erxes-next#0
File: .windsurfrules:0-0
Timestamp: 2025-07-21T06:10:08.710Z
Learning: Applies to **/*.{tsx,jsx} : Structure files: exported component, subcomponents, helpers, static content, types.

Applied to files:

  • frontend/libs/ui-modules/src/modules/products/categories/components/CategoriesInline.tsx
  • frontend/libs/ui-modules/src/modules/products/categories/components/selectCategory.tsx
📚 Learning: applies to **/*.{tsx,jsx} : use declarative jsx....
Learnt from: CR
PR: erxes/erxes-next#0
File: .windsurfrules:0-0
Timestamp: 2025-07-21T06:10:08.710Z
Learning: Applies to **/*.{tsx,jsx} : Use declarative JSX.

Applied to files:

  • frontend/libs/ui-modules/src/modules/products/categories/components/selectCategory.tsx
🧬 Code Graph Analysis (5)
frontend/core-ui/src/modules/products/detail/components/ProductGeneral.tsx (3)
frontend/core-ui/src/modules/products/detail/hooks/useProductDetail.tsx (1)
  • useProductDetail (7-31)
frontend/core-ui/src/modules/products/hooks/useUom.tsx (1)
  • useUom (6-12)
frontend/core-ui/src/modules/products/detail/hooks/useProductFormData.tsx (1)
  • useProductFormData (12-35)
frontend/core-ui/src/modules/products/detail/hooks/useProductDetail.tsx (1)
frontend/libs/erxes-ui/src/hooks/use-query-state.tsx (1)
  • useQueryState (6-49)
frontend/core-ui/src/modules/products/detail/components/ProductDetailSheet.tsx (1)
frontend/libs/erxes-ui/src/hooks/use-query-state.tsx (1)
  • useQueryState (6-49)
frontend/libs/ui-modules/src/modules/products/categories/hooks/useCategoryInline.tsx (1)
frontend/libs/ui-modules/src/modules/products/categories/graphql/queries.ts (1)
  • categories (37-40)
frontend/core-ui/src/modules/products/components/ProductsFilter.tsx (6)
frontend/libs/erxes-ui/src/hooks/use-query-state.tsx (1)
  • useMultiQueryState (57-98)
frontend/libs/erxes-ui/src/modules/filter/components/Filter.tsx (1)
  • Filter (478-497)
frontend/core-ui/src/modules/products/constants/productsCursorSessionKey.ts (1)
  • PRODUCTS_CURSOR_SESSION_KEY (1-1)
frontend/libs/ui-modules/src/modules/tags/components/TagsFilter.tsx (1)
  • TagsFilter (82-85)
frontend/libs/ui-modules/src/modules/brands/components/SelectBrand.tsx (1)
  • SelectBrand (351-360)
frontend/libs/ui-modules/src/modules/products/categories/components/selectCategory.tsx (1)
  • SelectCategory (396-406)
🪛 ESLint
frontend/libs/ui-modules/src/modules/products/categories/components/CategoriesInline.tsx

[error] 106-106: Definition for rule 'react-hooks/exhaustive-deps' was not found.

(react-hooks/exhaustive-deps)

⏰ 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: core-ui
  • GitHub Check: frontline_ui-ci
  • GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (32)
frontend/core-ui/src/modules/contacts/companies/components/CompaniesRecordTable.tsx (1)

13-13: Ignore type-safety concerns around the {} fallback.

The data prop in RecordTable.Provider is typed as any[], and company columns are defined with generic any at runtime. Supplying [{}] when companies is undefined won’t introduce type errors or runtime crashes—column accessors will simply render blank cells until real data arrives.

Likely an incorrect or invalid review comment.

frontend/core-ui/src/modules/products/detail/components/ProductBasicField.tsx (2)

112-112: LGTM! Styling change aligns with category selection refactor.

Removing the border styling from SelectCategory is consistent with the broader refactor mentioned in the AI summary, where the category selection UI has been updated to a new context-driven implementation.


256-256: LGTM! Minor visual enhancement.

Adding shadow-xs to the PDF upload button provides a subtle visual enhancement that improves the button's appearance.

frontend/core-ui/src/modules/types/paths/ProductsPath.ts (1)

2-2: Verify nested routing for the empty-index path
Changing ProductsPath.Index from '/' to '' makes it a relative route. In React Router v6, an empty string inside a nested <Routes> will match its parent path rather than the app’s root. Please confirm:

  • frontend/core-ui/src/modules/app/components/ProductsRoutes.tsx defines
    <Route path={ProductsPath.Index} element={<ProductsIndexPage />} />
  • In your top-level route configuration (e.g. AppRoutes.tsx), ensure you render ProductsRoutes under a parent like
    <Route path="/products/*" element={<ProductsRoutes />} />
  • (Optional) For clarity, you can replace the empty‐string route with an explicit index route:
    <Route index element={<ProductsIndexPage />} />
frontend/core-ui/src/modules/products/hooks/useUom.tsx (1)

6-6: LGTM! Making options parameter optional improves hook flexibility.

This change aligns with the pattern mentioned in the AI summary where other product-related hooks also adopt optional query options, improving consistency across the codebase while maintaining backward compatibility.

frontend/libs/erxes-ui/src/modules/record-table/states/RecordTableCursorState.ts (1)

5-5: Improved type safety and semantic clarity for cursor state.

The addition of undefined to the type union and changing the initial value from null to undefined improves the semantic meaning of the cursor state. This clearly distinguishes between uninitialized (undefined) and intentionally empty (null) cursor states, which aligns with the related cursor state management improvements mentioned in the AI summary.

frontend/core-ui/src/modules/contacts/companies/graphql/queries/getCompanies.ts (1)

67-67: LGTM! Cursor field addition supports pagination.

Adding the cursor field to the company list query enables proper cursor-based pagination, which aligns with the pagination improvements across the codebase mentioned in the AI summary.

frontend/core-ui/src/modules/products/detail/components/ProductGeneral.tsx (1)

21-22: LGTM! Hook usage aligns with updated signatures.

The removal of loading from useProductDetail destructuring and simplifying useUom() call correctly align with the updated hook signatures mentioned in the relevant code snippets.

frontend/core-ui/src/modules/products/detail/types/detailTypes.ts (1)

19-20: Type safety confirmed: _id and name are always fetched

  • The productDetail GraphQL query in
    frontend/core-ui/src/modules/products/detail/graphql/queries/productDetailQueries.tsx
    explicitly selects both _id and name.
  • The ProductsMain query in
    frontend/core-ui/src/modules/products/graphql/ProductsQueries.tsx
    returns list items with _id and name.
  • The form hook (useProductFormData) and ProductDetailLayout rely on these fields and will never see them undefined.

No changes required.

frontend/core-ui/src/modules/products/detail/hooks/useProductDetail.tsx (2)

5-8: LGTM! Improved query state management with consistent naming.

The migration from useSearchParams to useQueryState and the change from 'product_id' to 'productId' (camelCase) improves consistency with JavaScript naming conventions and provides better type safety through the useQueryState hook's enhanced features.


25-30: Improved code formatting for better readability.

The reformatted return statement with proper line breaks enhances code readability while maintaining the same functionality.

frontend/core-ui/src/modules/products/detail/components/ProductDetailSheet.tsx (3)

7-7: LGTM! Clean import addition.

The addition of useQueryState import follows the absolute import guideline and integrates well with the existing erxes-ui imports.


16-16: Good refactor from useSearchParams to useQueryState.

The switch to useQueryState('productId') provides better abstraction and consistency with the codebase's query state management pattern. The camelCase naming also follows better conventions.


24-34: Clean implementation of setOpen function.

The updated logic using setProductId instead of direct URL manipulation is cleaner and more maintainable. Good use of descriptive naming with newProductId parameter.

frontend/core-ui/src/modules/products/graphql/ProductsQueries.tsx (3)

15-15: Good addition of orderBy support.

The addition of the $orderBy: JSON parameter and its usage in the query provides flexible sorting capabilities. Using JSON type is appropriate for complex ordering criteria.

Also applies to: 29-29


51-51: LGTM! Added code field to category data.

Adding the code field to the category selection enhances the available category information, which aligns with the broader category management improvements in this PR.


69-69: Good query name improvement.

Renaming from ProductCategories to ProductCategoryDetail provides better clarity about the query's purpose and aligns with the actual query structure.

frontend/libs/ui-modules/src/modules/products/categories/types/category.ts (2)

8-8: LGTM! Consistent property addition.

The addition of the optional attachment property follows the same pattern as the existing avatar property and enhances the interface's flexibility for category display.


25-30: Well-designed interface for inline category functionality.

The CategoriesInlineProps interface is well-structured with:

  • Appropriate optional properties for flexibility
  • Clear and descriptive property names (categoryIds, updateCategories)
  • Proper typing with specific callback signature
  • Good use of TypeScript interfaces as per coding guidelines
frontend/libs/ui-modules/src/modules/products/contexts/SelectProductCategoryContext.tsx (3)

4-11: Well-designed context interface.

The ISelectProductCategoryContext interface is comprehensive and well-structured with:

  • Clear property names with descriptive types
  • Appropriate callback signature for onSelect
  • Loading and error state management
  • Follows TypeScript interface guidelines

13-14: LGTM! Proper context initialization.

Creating the context with null as the default value is the correct pattern for contexts that require a provider, enabling the error checking in the custom hook.


16-24: Excellent error handling in custom hook.

The custom hook implementation follows best practices:

  • Proper error throwing when used outside provider
  • Clear error message indicating the required provider name
  • Follows the pattern established in React context documentation
frontend/libs/ui-modules/src/modules/products/categories/contexts/CategoriesInlineContext.tsx (3)

4-10: Well-structured interface for inline category context.

The ICategoriesInlineContext interface is properly designed with:

  • Clear separation of data (categories) and state (loading)
  • Optional properties for flexibility (categoryIds, updateCategories)
  • Descriptive property names following coding guidelines
  • Consistent with the CategoriesInlineProps type from the category types file

12-13: LGTM! Consistent context creation pattern.

The context creation follows the same excellent pattern as the other context in this PR, with proper null initialization for provider-required usage.


15-23: Excellent consistency in custom hook implementation.

The custom hook follows the same high-quality pattern established in the SelectProductCategoryContext:

  • Proper provider requirement validation
  • Clear and descriptive error message
  • Consistent naming convention with the context name

This maintains excellent consistency across the codebase's context implementations.

frontend/core-ui/src/modules/products/hooks/useProducts.tsx (1)

64-64: Good addition of skip condition

The skip: cursor === undefined condition prevents unnecessary queries when cursor is not ready.

frontend/libs/ui-modules/src/modules/products/categories/hooks/useCategoriesWithSearch.tsx (1)

5-34: Well-structured hook implementation

The hook follows functional programming patterns, uses TypeScript interfaces properly, and provides a clean API for category fetching with search support.

frontend/core-ui/src/modules/contacts/customers/hooks/useCustomers.tsx (1)

84-96: Consistent pattern with improved safety

Good improvements:

  • Explicit extraction of sessionKey and cursor improves readability
  • The skip: cursor === undefined prevents unnecessary queries
  • Optional chaining on customersQueryVariables adds safety

These changes align well with the patterns in useProducts hook.

frontend/core-ui/src/modules/products/components/ProductColumns.tsx (1)

120-122: No changes needed for categories prop in SelectCategoryInlineCell
The SelectCategoryInlineCell component forwards all of SelectCategoryProvider’s props (including categories?: IProductCategory[]) via ...props. Passing an array of full category objects ([cell.row.original.category]) is type-compatible.

• Ensure that cell.row.original.category is of type IProductCategory.

frontend/libs/ui-modules/src/modules/products/categories/components/selectCategory.tsx (3)

358-358: Add displayName to SelectCategoryRoot for consistency

SelectCategoryFormItem has a displayName but SelectCategoryRoot is missing one.

Add displayName after line 394:

 SelectCategoryRoot.displayName = 'SelectCategoryRoot';
+

Note: The displayName is already present at line 394, so this is correctly implemented.

Also applies to: 394-394


148-161: Consider memoizing the filtered categories

The useCategoriesWithSearch hook is called with a debounced search value, which is good. The implementation looks correct.


271-279: Fix type safety issue with value.length check

The condition value.length > 0 assumes value is always an array, but it could be a string in single mode.

Apply this diff to fix the type checking:

         onValueChange={(value) => {
-          if (value.length > 0) {
+          if ((Array.isArray(value) && value.length > 0) || (typeof value === 'string' && value)) {
             setCategory(value as string[] | string);
           } else {
             setCategory(null);
           }
           setOpen(false);
           onValueChange?.(value);
         }}
⛔ Skipped due to learnings
Learnt from: CR
PR: erxes/erxes-next#0
File: .windsurfrules:0-0
Timestamp: 2025-07-21T06:10:08.710Z
Learning: Applies to **/*.tsx : Use functional components with TypeScript interfaces.
Learnt from: CR
PR: erxes/erxes-next#0
File: .cursorrules:0-0
Timestamp: 2025-07-21T06:09:41.203Z
Learning: Applies to **/*.tsx : Use functional components with TypeScript interfaces.
Learnt from: CR
PR: erxes/erxes-next#0
File: .cursorrules:0-0
Timestamp: 2025-07-21T06:09:41.203Z
Learning: Applies to **/*.tsx : Minimize 'useEffect', and 'setState'.
Learnt from: CR
PR: erxes/erxes-next#0
File: .windsurfrules:0-0
Timestamp: 2025-07-21T06:10:08.710Z
Learning: Applies to **/*.tsx : Minimize 'useEffect', and 'setState'.
Learnt from: CR
PR: erxes/erxes-next#0
File: .windsurfrules:0-0
Timestamp: 2025-07-21T06:10:08.710Z
Learning: Applies to **/*.{tsx,jsx} : Use declarative JSX.
Learnt from: CR
PR: erxes/erxes-next#0
File: .cursorrules:0-0
Timestamp: 2025-07-21T06:09:41.203Z
Learning: Applies to **/*.{tsx,jsx} : Use declarative JSX.
Learnt from: CR
PR: erxes/erxes-next#0
File: .windsurfrules:0-0
Timestamp: 2025-07-21T06:10:08.710Z
Learning: Applies to **/*.{ts,tsx,js,jsx} : Use descriptive variable names with auxiliary verbs (e.g., isLoading, hasError).
Learnt from: CR
PR: erxes/erxes-next#0
File: .cursorrules:0-0
Timestamp: 2025-07-21T06:09:41.203Z
Learning: Applies to **/*.{ts,tsx,js,jsx} : Use descriptive variable names with auxiliary verbs (e.g., isLoading, hasError).
Learnt from: CR
PR: erxes/erxes-next#0
File: .cursorrules:0-0
Timestamp: 2025-07-21T06:09:41.203Z
Learning: Applies to **/*.{ts,tsx} : Use functional and declarative programming patterns; avoid classes.
Learnt from: CR
PR: erxes/erxes-next#0
File: .windsurfrules:0-0
Timestamp: 2025-07-21T06:10:08.710Z
Learning: Applies to **/*.{ts,tsx} : Use functional and declarative programming patterns; avoid classes.

Comment on lines 8 to 14
const [queries] = useMultiQueryState<{
searchValue: string;
created: string;
updated: string;
lastSeen: string;
}>(['searchValue', 'created', 'updated', 'lastSeen']);
const { searchValue } = queries || {};
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Add missing 'brand' to query state type

The brand query parameter is used by SelectBrand.FilterBar but is missing from the type definition in useMultiQueryState.

Apply this diff to include the missing type:

   const [queries] = useMultiQueryState<{
     searchValue: string;
     created: string;
     updated: string;
     lastSeen: string;
+    brand: string;
-  }>(['searchValue', 'created', 'updated', 'lastSeen']);
+  }>(['searchValue', 'created', 'updated', 'lastSeen', 'brand']);
📝 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 [queries] = useMultiQueryState<{
searchValue: string;
created: string;
updated: string;
lastSeen: string;
}>(['searchValue', 'created', 'updated', 'lastSeen']);
const { searchValue } = queries || {};
const [queries] = useMultiQueryState<{
searchValue: string;
created: string;
updated: string;
lastSeen: string;
brand: string;
}>(['searchValue', 'created', 'updated', 'lastSeen', 'brand']);
🤖 Prompt for AI Agents
In frontend/core-ui/src/modules/products/components/ProductsFilter.tsx around
lines 8 to 14, the type definition for useMultiQueryState is missing the 'brand'
property, which is used by SelectBrand.FilterBar. Update the generic type
argument to include 'brand: string' along with the existing properties to ensure
the query state type correctly reflects all used query parameters.

};

export const ProductsFilterPopover = () => {
const ProductsFilterPopover = () => {
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Use named export for ProductsFilterPopover

Per the coding guidelines, components should use named exports rather than local constants.

Apply this diff to export the component:

-const ProductsFilterPopover = () => {
+export const ProductsFilterPopover = () => {
📝 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 ProductsFilterPopover = () => {
export const ProductsFilterPopover = () => {
🤖 Prompt for AI Agents
In frontend/core-ui/src/modules/products/components/ProductsFilter.tsx at line
40, change the declaration of ProductsFilterPopover from a local constant to a
named export by adding the export keyword before the component definition. This
aligns with the coding guidelines requiring components to use named exports.

Comment on lines 41 to 46
const [queries] = useMultiQueryState<{
searchValue: string;
created: string;
updated: string;
lastSeen: string;
}>(['searchValue', 'created', 'updated', 'lastSeen']);
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Remove duplicate useMultiQueryState call

The same useMultiQueryState hook is called again in ProductsFilterPopover with identical parameters. Consider passing the queries as props to avoid redundant hook calls.

Apply this diff to optimize:

-const ProductsFilterPopover = () => {
-  const [queries] = useMultiQueryState<{
-    searchValue: string;
-    created: string;
-    updated: string;
-    lastSeen: string;
-  }>(['searchValue', 'created', 'updated', 'lastSeen']);
+const ProductsFilterPopover = ({ queries }: { queries: any }) => {

And update the usage:

-        <ProductsFilterPopover />
+        <ProductsFilterPopover queries={queries} />
📝 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 [queries] = useMultiQueryState<{
searchValue: string;
created: string;
updated: string;
lastSeen: string;
}>(['searchValue', 'created', 'updated', 'lastSeen']);
// In frontend/core-ui/src/modules/products/components/ProductsFilter.tsx
// --- Parent component: lift the hook up and pass queries down ---
export function ProductsFilter() {
const [queries] = useMultiQueryState<{
searchValue: string;
created: string;
updated: string;
lastSeen: string;
}>(['searchValue', 'created', 'updated', 'lastSeen']);
return (
<div>
{/* other filter UI */}
- <ProductsFilterPopover />
+ <ProductsFilterPopover queries={queries} />
</div>
);
}
// --- Child component: accept queries as a prop instead of re-calling the hook ---
interface ProductsFilterPopoverProps {
queries: {
searchValue: string;
created: string;
updated: string;
lastSeen: string;
};
}
export function ProductsFilterPopover({ queries }: ProductsFilterPopoverProps) {
// Removed duplicate useMultiQueryState call here—
// use the `queries` prop directly to render your filters.
return (
<div>
{/* render filter inputs, e.g.: */}
<input value={queries.searchValue} /* … */ />
{/* etc. */}
</div>
);
}
🤖 Prompt for AI Agents
In frontend/core-ui/src/modules/products/components/ProductsFilter.tsx around
lines 41 to 46, the useMultiQueryState hook is called redundantly both here and
in ProductsFilterPopover with the same parameters. To fix this, remove the
duplicate useMultiQueryState call from ProductsFilterPopover and instead pass
the queries state obtained here as props to ProductsFilterPopover. Update
ProductsFilterPopover to accept these props and use them directly, eliminating
the redundant hook invocation.

Comment on lines 1 to 4
export enum ProductsPath {
Index = '/',
Index = '',
Categories = '/categories',
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Replace enum with map to follow coding guidelines.

The coding guidelines specify to "Avoid enums; use maps instead" for TypeScript files. Consider refactoring this enum to use a map or const object.

-export enum ProductsPath {
-  Index = '',
-  Categories = '/categories',
-}
+export const ProductsPath = {
+  Index: '',
+  Categories: '/categories',
+} as const;
+
+export type ProductsPathType = typeof ProductsPath[keyof typeof ProductsPath];
📝 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
export enum ProductsPath {
Index = '/',
Index = '',
Categories = '/categories',
}
export const ProductsPath = {
Index: '',
Categories: '/categories',
} as const;
export type ProductsPathType = typeof ProductsPath[keyof typeof ProductsPath];
🤖 Prompt for AI Agents
In frontend/core-ui/src/modules/types/paths/ProductsPath.ts at lines 1 to 4,
replace the enum ProductsPath with a constant object or map to follow the coding
guidelines that discourage enums. Define a const object with the same keys and
values as the enum, ensuring it is typed appropriately for usage in the
codebase.

Comment on lines +90 to +107
useEffect(() => {
const newCategories = [...categories].filter((c) => c._id !== categoryId);

if (category) {
const transformedCategory: IProductCategory = {
...category,
attachment: category.attachment
? {
url: category.attachment.url,
name: '',
}
: undefined,
avatar: undefined,
};
updateCategories?.([...newCategories, transformedCategory]);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [category]);
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Fix missing dependencies and potential infinite loop

The useEffect hook is missing dependencies (categories, updateCategories) which could lead to stale closures. Additionally, the current implementation could cause infinite loops if updateCategories reference changes.

Apply this diff to fix the dependencies and prevent infinite loops:

   useEffect(() => {
+    if (!category || categories.some((c) => c._id === categoryId)) return;
+    
     const newCategories = [...categories].filter((c) => c._id !== categoryId);
-
-    if (category) {
       const transformedCategory: IProductCategory = {
         ...category,
         attachment: category.attachment
           ? {
               url: category.attachment.url,
               name: '',
             }
           : undefined,
         avatar: undefined,
       };
       updateCategories?.([...newCategories, transformedCategory]);
-    }
-    // eslint-disable-next-line react-hooks/exhaustive-deps
-  }, [category]);
+  }, [category, categoryId, categories, updateCategories]);
📝 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(() => {
const newCategories = [...categories].filter((c) => c._id !== categoryId);
if (category) {
const transformedCategory: IProductCategory = {
...category,
attachment: category.attachment
? {
url: category.attachment.url,
name: '',
}
: undefined,
avatar: undefined,
};
updateCategories?.([...newCategories, transformedCategory]);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [category]);
useEffect(() => {
if (!category || categories.some((c) => c._id === categoryId)) return;
const newCategories = [...categories].filter((c) => c._id !== categoryId);
const transformedCategory: IProductCategory = {
...category,
attachment: category.attachment
? {
url: category.attachment.url,
name: '',
}
: undefined,
avatar: undefined,
};
updateCategories?.([...newCategories, transformedCategory]);
}, [category, categoryId, categories, updateCategories]);
🧰 Tools
🪛 ESLint

[error] 106-106: Definition for rule 'react-hooks/exhaustive-deps' was not found.

(react-hooks/exhaustive-deps)

🤖 Prompt for AI Agents
In
frontend/libs/ui-modules/src/modules/products/categories/components/CategoriesInline.tsx
around lines 90 to 107, the useEffect hook is missing dependencies categories
and updateCategories, which can cause stale closures and potential infinite
loops if updateCategories changes. To fix this, add categories and
updateCategories to the dependency array of the useEffect hook, and ensure that
updateCategories is memoized or stable to prevent triggering the effect
repeatedly. This will keep the effect in sync with the latest values and avoid
infinite re-renders.

Comment on lines +27 to +35
const productCategoryDetail = gql`
query ProductCategories($ids: [String]) {
productCategories(ids: $ids) {
_id
code
name
}
}
`;
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Fix query name to match export name

The GraphQL query name ProductCategories doesn't match its export name productCategoryDetail. This inconsistency could cause confusion and maintenance issues.

Apply this diff to fix the naming:

 const productCategoryDetail = gql`
-  query ProductCategories($ids: [String]) {
+  query ProductCategoryDetail($ids: [String]) {
   productCategories(ids: $ids) {
     _id
     code
     name
   }
 }
 `;
📝 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 productCategoryDetail = gql`
query ProductCategories($ids: [String]) {
productCategories(ids: $ids) {
_id
code
name
}
}
`;
const productCategoryDetail = gql`
query ProductCategoryDetail($ids: [String]) {
productCategories(ids: $ids) {
_id
code
name
}
}
`;
🤖 Prompt for AI Agents
In frontend/libs/ui-modules/src/modules/products/categories/graphql/queries.ts
around lines 27 to 35, the GraphQL query name `ProductCategories` does not match
the export name `productCategoryDetail`. Rename the query from
`ProductCategories` to `productCategoryDetail` to ensure consistency between the
query name and its export, improving clarity and maintainability.

Comment on lines +1 to +2
import { QueryHookOptions } from '@apollo/client';
import { useQuery } from '@apollo/client';
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Remove duplicate import statement

QueryHookOptions and useQuery are imported twice from the same module.

Combine the imports:

-import { QueryHookOptions } from '@apollo/client';
-import { useQuery } from '@apollo/client';
+import { QueryHookOptions, useQuery } from '@apollo/client';
📝 Committable suggestion

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

Suggested change
import { QueryHookOptions } from '@apollo/client';
import { useQuery } from '@apollo/client';
import { QueryHookOptions, useQuery } from '@apollo/client';
🤖 Prompt for AI Agents
In
frontend/libs/ui-modules/src/modules/products/categories/hooks/useCategoryInline.tsx
at lines 1 to 2, there are duplicate import statements importing from
'@apollo/client'. Combine the imports into a single statement that imports both
QueryHookOptions and useQuery together to remove redundancy.

@@ -0,0 +1,37 @@
import { QueryHookOptions } from '@apollo/client';
import { useQuery } from '@apollo/client';
import { IProductCategory } from '../types/category';
Copy link

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Unused import and potential type duplication

IProductCategory is imported but not used. Consider whether ICategoryInline duplicates an existing type.

Also applies to: 6-16


🏁 Script executed:

#!/bin/bash
# Check if IProductCategory and ICategoryInline have similar structures
echo "=== Searching for IProductCategory type definition ==="
ast-grep --pattern 'interface IProductCategory {
  $$$
}'

echo -e "\n=== Checking usage of IProductCategory in the codebase ==="
rg "IProductCategory" -A 5 -B 2

Length of output: 59958


🏁 Script executed:

#!/bin/bash
# Display the content of useCategoryInline.tsx for detailed inspection
cat frontend/libs/ui-modules/src/modules/products/categories/hooks/useCategoryInline.tsx

Length of output: 881


Remove unused import in useCategoryInline.tsx

The IProductCategory import on line 3 of useCategoryInline.tsx isn’t used and should be removed. Also, note that ICategoryInline overlaps most fields of IProductCategory—if you don’t need a pared-down type, consider reusing IProductCategory instead of duplicating its structure.

• File: frontend/libs/ui-modules/src/modules/products/categories/hooks/useCategoryInline.tsx
– Remove:
diff - import { IProductCategory } from '../types/category';

📝 Committable suggestion

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

Suggested change
import { IProductCategory } from '../types/category';
@@ -3,1 +3,0
-import { IProductCategory } from '../types/category';
🤖 Prompt for AI Agents
In
frontend/libs/ui-modules/src/modules/products/categories/hooks/useCategoryInline.tsx
at line 3, remove the unused import of IProductCategory. Additionally, review
the ICategoryInline type and if it largely duplicates IProductCategory, refactor
the code to use IProductCategory directly to avoid redundant type definitions.

Copy link

@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 a708f0b in 48 seconds. Click for details.
  • Reviewed 135 lines of code in 4 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. frontend/core-ui/src/modules/products/components/ProductColumns.tsx:36
  • Draft comment:
    Using useState to initialize 'value' from cell data may lead to out-of-sync state if the cell value changes externally. Consider syncing the local state via useEffect if external updates are possible.
  • Reason this comment was not posted:
    Confidence changes required: 33% <= threshold 50% None
2. frontend/core-ui/src/modules/products/components/ProductsFilter.tsx:8
  • Draft comment:
    Extended filter keys now include 'brandId' and 'categoryId'. Ensure that their default values and type consistency (e.g., handling empty strings vs null) align with filter logic elsewhere.
  • Reason this comment was not posted:
    Confidence changes required: 33% <= threshold 50% None
3. frontend/core-ui/src/modules/products/hooks/useProductsEdit.tsx:29
  • Draft comment:
    Passing 'optimistic: true' to cache.modify may not be supported by Apollo Client. Consider using the 'optimisticResponse' option to properly implement optimistic UI updates.
  • 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. frontend/libs/ui-modules/src/modules/team-members/types/TeamMembers.ts:1
  • Draft comment:
    Good cleanup: unused imports have been removed.
  • Reason this comment was not posted:
    Comment did not seem useful. Confidence is useful = 0% <= threshold 50% This comment is purely informative, as it only acknowledges the removal of unused imports without providing any actionable feedback or suggestions. It does not align with the rules for useful comments.

Workflow ID: wflow_4Nr1tUUoDxylXeCX

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

♻️ Duplicate comments (3)
frontend/core-ui/src/modules/products/components/ProductsFilter.tsx (1)

42-50: Address duplicate useMultiQueryState call and export pattern.

This component has two issues from previous reviews that remain unaddressed:

  1. Duplicate hook call: The same useMultiQueryState hook is called with identical parameters in both the parent component and here, which is inefficient.

  2. Export pattern: The coding guidelines require named exports for components, but this was changed from a named export to a local constant.

Consider passing the queries as props to avoid the duplicate hook call:

-const ProductsFilterPopover = () => {
-  const [queries] = useMultiQueryState<{
-    searchValue: string;
-    created: string;
-    updated: string;
-    lastSeen: string;
-    brandId: string;
-    categoryId: string;
-  }>(['searchValue', 'created', 'updated', 'lastSeen', 'brandId', 'categoryId']);
+export const ProductsFilterPopover = ({ queries }: { 
+  queries: {
+    searchValue: string;
+    created: string;
+    updated: string;
+    lastSeen: string;
+    brandId: string;
+    categoryId: string;
+  } | null;
+}) => {

And update the parent component usage:

-        <ProductsFilterPopover />
+        <ProductsFilterPopover queries={queries} />
frontend/core-ui/src/modules/products/components/ProductColumns.tsx (2)

45-50: Add error handling for mutation

The productsEdit mutation should handle errors to prevent silent failures.

             if (!open) {
               productsEdit({
                 variables: {
                   _id: cell.row.original._id,
                   name: value,
                 },
-              });
+              }).catch((error) => {
+                console.error('Failed to update product name:', error);
+                // Reset to original value on error
+                setValue(name);
+              });
             }

134-141: Add error handling for category update

The mutation lacks error handling which could lead to silent failures.

           onValueChange={(value) => {
             productsEdit({
               variables: {
                 _id: cell.row.original._id,
                 categoryId: value,
               },
-            });
+            }).catch((error) => {
+              console.error('Failed to update product category:', error);
+            });
           }}
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between ff8b238 and a708f0b.

📒 Files selected for processing (4)
  • frontend/core-ui/src/modules/products/components/ProductColumns.tsx (4 hunks)
  • frontend/core-ui/src/modules/products/components/ProductsFilter.tsx (1 hunks)
  • frontend/core-ui/src/modules/products/hooks/useProductsEdit.tsx (2 hunks)
  • frontend/libs/ui-modules/src/modules/team-members/types/TeamMembers.ts (0 hunks)
💤 Files with no reviewable changes (1)
  • frontend/libs/ui-modules/src/modules/team-members/types/TeamMembers.ts
🧰 Additional context used
📓 Path-based instructions (5)
**/*.{ts,tsx}

📄 CodeRabbit Inference Engine (.cursorrules)

**/*.{ts,tsx}: Use functional and declarative programming patterns; avoid classes.
Use TypeScript for all code; prefer interfaces over types.
Avoid enums; use maps instead.

Files:

  • frontend/core-ui/src/modules/products/hooks/useProductsEdit.tsx
  • frontend/core-ui/src/modules/products/components/ProductsFilter.tsx
  • frontend/core-ui/src/modules/products/components/ProductColumns.tsx
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit Inference Engine (.cursorrules)

**/*.{ts,tsx,js,jsx}: Use descriptive variable names with auxiliary verbs (e.g., isLoading, hasError).
Avoid console logs.
Always use absolute paths when importing.
Use the "function" keyword for pure functions.
Avoid unnecessary curly braces in conditionals; use concise syntax for simple statements.

**/*.{ts,tsx,js,jsx}: Use descriptive variable names with auxiliary verbs (e.g., isLoading, hasError).
Use the "function" keyword for pure functions.
Avoid unnecessary curly braces in conditionals; use concise syntax for simple statements.
Use absolute path when import.

Files:

  • frontend/core-ui/src/modules/products/hooks/useProductsEdit.tsx
  • frontend/core-ui/src/modules/products/components/ProductsFilter.tsx
  • frontend/core-ui/src/modules/products/components/ProductColumns.tsx
**/*.{tsx,jsx}

📄 CodeRabbit Inference Engine (.cursorrules)

**/*.{tsx,jsx}: Favor named exports for components.
Use declarative JSX.
Use Shadcn UI, Radix, and Tailwind for components and styling.
Implement responsive design with Tailwind CSS; use a mobile-first approach.

**/*.{tsx,jsx}: Structure files: exported component, subcomponents, helpers, static content, types.
Favor named exports for components.
Use declarative JSX.
Use Shadcn UI, Radix, and Tailwind for components and styling.
Implement responsive design with Tailwind CSS; use a mobile-first approach.

Files:

  • frontend/core-ui/src/modules/products/hooks/useProductsEdit.tsx
  • frontend/core-ui/src/modules/products/components/ProductsFilter.tsx
  • frontend/core-ui/src/modules/products/components/ProductColumns.tsx
**/*.tsx

📄 CodeRabbit Inference Engine (.cursorrules)

**/*.tsx: Use functional components with TypeScript interfaces.
Minimize 'useEffect', and 'setState'.
Wrap client components in Suspense with fallback.
Use dynamic loading for non-critical components.
Limit 'use client': Favor server components and Next.js SSR. Use only for Web API access in small components. Avoid for data fetching or state management.

Files:

  • frontend/core-ui/src/modules/products/hooks/useProductsEdit.tsx
  • frontend/core-ui/src/modules/products/components/ProductsFilter.tsx
  • frontend/core-ui/src/modules/products/components/ProductColumns.tsx
**/*.{webp,tsx,jsx}

📄 CodeRabbit Inference Engine (.cursorrules)

Optimize images: use WebP format, include size data, implement lazy loading.

Files:

  • frontend/core-ui/src/modules/products/hooks/useProductsEdit.tsx
  • frontend/core-ui/src/modules/products/components/ProductsFilter.tsx
  • frontend/core-ui/src/modules/products/components/ProductColumns.tsx
🧠 Learnings (5)
📚 Learning: 2025-07-21T06:10:08.710Z
Learnt from: CR
PR: erxes/erxes-next#0
File: .windsurfrules:0-0
Timestamp: 2025-07-21T06:10:08.710Z
Learning: Applies to **/*.tsx : Minimize 'useEffect', and 'setState'.

Applied to files:

  • frontend/core-ui/src/modules/products/components/ProductsFilter.tsx
📚 Learning: 2025-07-21T06:10:08.710Z
Learnt from: CR
PR: erxes/erxes-next#0
File: .windsurfrules:0-0
Timestamp: 2025-07-21T06:10:08.710Z
Learning: Applies to **/*.{tsx,jsx} : Favor named exports for components.

Applied to files:

  • frontend/core-ui/src/modules/products/components/ProductsFilter.tsx
📚 Learning: 2025-07-21T06:10:08.710Z
Learnt from: CR
PR: erxes/erxes-next#0
File: .windsurfrules:0-0
Timestamp: 2025-07-21T06:10:08.710Z
Learning: Applies to **/*.tsx : Use functional components with TypeScript interfaces.

Applied to files:

  • frontend/core-ui/src/modules/products/components/ProductsFilter.tsx
  • frontend/core-ui/src/modules/products/components/ProductColumns.tsx
📚 Learning: 2025-07-21T06:10:08.710Z
Learnt from: CR
PR: erxes/erxes-next#0
File: .windsurfrules:0-0
Timestamp: 2025-07-21T06:10:08.710Z
Learning: Applies to **/*.{ts,tsx,js,jsx} : Use descriptive variable names with auxiliary verbs (e.g., isLoading, hasError).

Applied to files:

  • frontend/core-ui/src/modules/products/components/ProductsFilter.tsx
📚 Learning: 2025-07-21T06:10:08.710Z
Learnt from: CR
PR: erxes/erxes-next#0
File: .windsurfrules:0-0
Timestamp: 2025-07-21T06:10:08.710Z
Learning: Applies to **/*.{tsx,jsx} : Use Shadcn UI, Radix, and Tailwind for components and styling.

Applied to files:

  • frontend/core-ui/src/modules/products/components/ProductsFilter.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: frontline_ui-ci
  • GitHub Check: core-ui
  • GitHub Check: Analyze (javascript-typescript)
🔇 Additional comments (4)
frontend/core-ui/src/modules/products/components/ProductsFilter.tsx (4)

3-4: LGTM! Type definition properly expanded for new filters.

The import additions and type definition updates correctly support the new brand and category filtering functionality. The inclusion of brandId and categoryId in the type definition addresses the previous concern about missing filter parameters.

Also applies to: 8-16


21-32: Good implementation of conditional filter display.

The conditional rendering of the search filter item follows React best practices with declarative JSX and proper component composition.


33-35: Clean integration of additional filter components.

The new filter bar components follow the established pattern and integrate well with the existing filter system.


52-54: Good implementation of filter state detection and component integration.

The hasFilters computation correctly identifies active filters using Object.values().some(), and the new SelectBrand and SelectCategory components are properly integrated following the established filter pattern.

Also applies to: 74-82

Comment on lines +35 to +36
const name = cell.getValue() as string;
const [value, setValue] = useState(name);
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Sync local state with prop changes

The local state should update when the product name changes externally.

Add a useEffect to sync the state:

       const name = cell.getValue() as string;
       const [value, setValue] = useState(name);
+      useEffect(() => {
+        setValue(name);
+      }, [name]);

Don't forget to import useEffect:

-import { useState } from 'react';
+import { useState, useEffect } from 'react';
📝 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 name = cell.getValue() as string;
const [value, setValue] = useState(name);
// At the top of the file, update the import:
-import { useState } from 'react';
+import { useState, useEffect } from 'react';
// ...
// Inside your component, after initializing state:
const name = cell.getValue() as string;
const [value, setValue] = useState(name);
+useEffect(() => {
+ setValue(name);
+}, [name]);
// ...
🤖 Prompt for AI Agents
In frontend/core-ui/src/modules/products/components/ProductColumns.tsx around
lines 35 to 36, the local state variable 'value' initialized from the prop
'name' does not update when 'name' changes externally. To fix this, import
useEffect from React and add a useEffect hook that listens for changes to 'name'
and updates the local state 'value' accordingly, ensuring the component stays in
sync with prop changes.

Comment on lines +15 to +21
onError: () => {
toast({
title: 'Error',
description: 'Product update failed',
variant: 'destructive',
});
},
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Improve error handling with specific error messages

The error handler should log the actual error and provide more specific feedback to users.

-      onError: () => {
+      onError: (error) => {
+        console.error('Product update failed:', error);
         toast({
           title: 'Error',
-          description: 'Product update failed',
+          description: error.message || 'Product update failed',
           variant: 'destructive',
         });
       },
🤖 Prompt for AI Agents
In frontend/core-ui/src/modules/products/hooks/useProductsEdit.tsx around lines
15 to 21, the onError handler currently shows a generic error toast without
logging the error or providing specific feedback. Modify the onError function to
accept the error object, log the error details for debugging, and update the
toast description to include a more specific message based on the error content.

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