-
Notifications
You must be signed in to change notification settings - Fork 3
Product fix #273
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Product fix #273
Conversation
…on fields; update PhoneField and TextField components for improved handling.
…ates; refactor hooks and improve input validation.
…nd remove unnecessary error display.
…oved accessibility
…able "cursor" state change
Reviewer's GuideThis 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 tablesequenceDiagram
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
Class diagram for new SelectCategory composable APIclassDiagram
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
Class diagram for new category context and inline componentsclassDiagram
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
Class diagram for updated IProductCategory and related typesclassDiagram
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
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
|
Note Other AI code review bot(s) detectedCodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review. WalkthroughThis 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
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
Estimated code review effort🎯 4 (Complex) | ⏱️ ~40 minutes Possibly related PRs
Poem
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 unit tests
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey @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.Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Caution
Changes requested ❌
Reviewed everything up to ff8b238 in 1 minute and 52 seconds. Click for details.
- Reviewed
1609lines of code in26files - Skipped
0files when reviewing. - Skipped posting
5draft 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%<= threshold50%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%<= threshold50%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 by changing your verbosity settings, reacting with 👍 or 👎, replying to comments, or adding code review rules.
frontend/core-ui/src/modules/contacts/companies/components/CompaniesRecordTable.tsx
Show resolved
Hide resolved
frontend/libs/erxes-ui/src/modules/record-table/hooks/useRecordTableCursor.tsx
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 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 guidelinesThe 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
constobject + 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 reusabilityThe 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 explicitWhile 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 commentThe 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
📒 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.tsxfrontend/core-ui/src/modules/products/types/ProductsHotKeyScope.tsfrontend/core-ui/src/modules/products/detail/components/ProductGeneral.tsxfrontend/libs/erxes-ui/src/modules/record-table/hooks/useRecordTableCursor.tsxfrontend/libs/erxes-ui/src/modules/record-table/states/RecordTableCursorState.tsfrontend/core-ui/src/modules/contacts/companies/graphql/queries/getCompanies.tsfrontend/core-ui/src/modules/products/detail/types/detailTypes.tsfrontend/core-ui/src/modules/types/paths/ProductsPath.tsfrontend/core-ui/src/modules/products/hooks/useUom.tsxfrontend/core-ui/src/modules/products/detail/hooks/useProductDetail.tsxfrontend/libs/ui-modules/src/modules/products/categories/contexts/CategoriesInlineContext.tsxfrontend/core-ui/src/modules/products/graphql/ProductsQueries.tsxfrontend/core-ui/src/modules/contacts/companies/components/CompaniesRecordTable.tsxfrontend/libs/ui-modules/src/modules/products/categories/types/category.tsfrontend/core-ui/src/modules/products/detail/components/ProductDetailSheet.tsxfrontend/core-ui/src/modules/products/components/ProductColumns.tsxfrontend/libs/ui-modules/src/modules/products/contexts/SelectProductCategoryContext.tsxfrontend/libs/ui-modules/src/modules/products/categories/hooks/useCategoriesWithSearch.tsxfrontend/core-ui/src/modules/products/hooks/useProducts.tsxfrontend/libs/ui-modules/src/modules/products/categories/hooks/useCategoryInline.tsxfrontend/core-ui/src/modules/contacts/customers/hooks/useCustomers.tsxfrontend/core-ui/src/modules/products/components/ProductsFilter.tsxfrontend/libs/ui-modules/src/modules/products/categories/graphql/queries.tsfrontend/libs/ui-modules/src/modules/products/categories/components/CategoriesInline.tsxfrontend/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.tsxfrontend/core-ui/src/modules/products/types/ProductsHotKeyScope.tsfrontend/core-ui/src/modules/products/detail/components/ProductGeneral.tsxfrontend/libs/erxes-ui/src/modules/record-table/hooks/useRecordTableCursor.tsxfrontend/libs/erxes-ui/src/modules/record-table/states/RecordTableCursorState.tsfrontend/core-ui/src/modules/contacts/companies/graphql/queries/getCompanies.tsfrontend/core-ui/src/modules/products/detail/types/detailTypes.tsfrontend/core-ui/src/modules/types/paths/ProductsPath.tsfrontend/core-ui/src/modules/products/hooks/useUom.tsxfrontend/core-ui/src/modules/products/detail/hooks/useProductDetail.tsxfrontend/libs/ui-modules/src/modules/products/categories/contexts/CategoriesInlineContext.tsxfrontend/core-ui/src/modules/products/graphql/ProductsQueries.tsxfrontend/core-ui/src/modules/contacts/companies/components/CompaniesRecordTable.tsxfrontend/libs/ui-modules/src/modules/products/categories/types/category.tsfrontend/core-ui/src/modules/products/detail/components/ProductDetailSheet.tsxfrontend/core-ui/src/modules/products/components/ProductColumns.tsxfrontend/libs/ui-modules/src/modules/products/contexts/SelectProductCategoryContext.tsxfrontend/libs/ui-modules/src/modules/products/categories/hooks/useCategoriesWithSearch.tsxfrontend/core-ui/src/modules/products/hooks/useProducts.tsxfrontend/libs/ui-modules/src/modules/products/categories/hooks/useCategoryInline.tsxfrontend/core-ui/src/modules/contacts/customers/hooks/useCustomers.tsxfrontend/core-ui/src/modules/products/components/ProductsFilter.tsxfrontend/libs/ui-modules/src/modules/products/categories/graphql/queries.tsfrontend/libs/ui-modules/src/modules/products/categories/components/CategoriesInline.tsxfrontend/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.tsxfrontend/core-ui/src/modules/products/detail/components/ProductGeneral.tsxfrontend/libs/erxes-ui/src/modules/record-table/hooks/useRecordTableCursor.tsxfrontend/core-ui/src/modules/products/hooks/useUom.tsxfrontend/core-ui/src/modules/products/detail/hooks/useProductDetail.tsxfrontend/libs/ui-modules/src/modules/products/categories/contexts/CategoriesInlineContext.tsxfrontend/core-ui/src/modules/products/graphql/ProductsQueries.tsxfrontend/core-ui/src/modules/contacts/companies/components/CompaniesRecordTable.tsxfrontend/core-ui/src/modules/products/detail/components/ProductDetailSheet.tsxfrontend/core-ui/src/modules/products/components/ProductColumns.tsxfrontend/libs/ui-modules/src/modules/products/contexts/SelectProductCategoryContext.tsxfrontend/libs/ui-modules/src/modules/products/categories/hooks/useCategoriesWithSearch.tsxfrontend/core-ui/src/modules/products/hooks/useProducts.tsxfrontend/libs/ui-modules/src/modules/products/categories/hooks/useCategoryInline.tsxfrontend/core-ui/src/modules/contacts/customers/hooks/useCustomers.tsxfrontend/core-ui/src/modules/products/components/ProductsFilter.tsxfrontend/libs/ui-modules/src/modules/products/categories/components/CategoriesInline.tsxfrontend/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.tsxfrontend/core-ui/src/modules/products/detail/components/ProductGeneral.tsxfrontend/libs/erxes-ui/src/modules/record-table/hooks/useRecordTableCursor.tsxfrontend/core-ui/src/modules/products/hooks/useUom.tsxfrontend/core-ui/src/modules/products/detail/hooks/useProductDetail.tsxfrontend/libs/ui-modules/src/modules/products/categories/contexts/CategoriesInlineContext.tsxfrontend/core-ui/src/modules/products/graphql/ProductsQueries.tsxfrontend/core-ui/src/modules/contacts/companies/components/CompaniesRecordTable.tsxfrontend/core-ui/src/modules/products/detail/components/ProductDetailSheet.tsxfrontend/core-ui/src/modules/products/components/ProductColumns.tsxfrontend/libs/ui-modules/src/modules/products/contexts/SelectProductCategoryContext.tsxfrontend/libs/ui-modules/src/modules/products/categories/hooks/useCategoriesWithSearch.tsxfrontend/core-ui/src/modules/products/hooks/useProducts.tsxfrontend/libs/ui-modules/src/modules/products/categories/hooks/useCategoryInline.tsxfrontend/core-ui/src/modules/contacts/customers/hooks/useCustomers.tsxfrontend/core-ui/src/modules/products/components/ProductsFilter.tsxfrontend/libs/ui-modules/src/modules/products/categories/components/CategoriesInline.tsxfrontend/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.tsxfrontend/core-ui/src/modules/products/detail/components/ProductGeneral.tsxfrontend/libs/erxes-ui/src/modules/record-table/hooks/useRecordTableCursor.tsxfrontend/core-ui/src/modules/products/hooks/useUom.tsxfrontend/core-ui/src/modules/products/detail/hooks/useProductDetail.tsxfrontend/libs/ui-modules/src/modules/products/categories/contexts/CategoriesInlineContext.tsxfrontend/core-ui/src/modules/products/graphql/ProductsQueries.tsxfrontend/core-ui/src/modules/contacts/companies/components/CompaniesRecordTable.tsxfrontend/core-ui/src/modules/products/detail/components/ProductDetailSheet.tsxfrontend/core-ui/src/modules/products/components/ProductColumns.tsxfrontend/libs/ui-modules/src/modules/products/contexts/SelectProductCategoryContext.tsxfrontend/libs/ui-modules/src/modules/products/categories/hooks/useCategoriesWithSearch.tsxfrontend/core-ui/src/modules/products/hooks/useProducts.tsxfrontend/libs/ui-modules/src/modules/products/categories/hooks/useCategoryInline.tsxfrontend/core-ui/src/modules/contacts/customers/hooks/useCustomers.tsxfrontend/core-ui/src/modules/products/components/ProductsFilter.tsxfrontend/libs/ui-modules/src/modules/products/categories/components/CategoriesInline.tsxfrontend/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.tsxfrontend/libs/ui-modules/src/modules/products/categories/components/CategoriesInline.tsxfrontend/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.tsfrontend/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.tsxfrontend/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.tsxfrontend/libs/erxes-ui/src/modules/record-table/hooks/useRecordTableCursor.tsxfrontend/core-ui/src/modules/products/detail/hooks/useProductDetail.tsxfrontend/core-ui/src/modules/products/detail/components/ProductDetailSheet.tsxfrontend/libs/ui-modules/src/modules/products/categories/hooks/useCategoriesWithSearch.tsxfrontend/core-ui/src/modules/products/hooks/useProducts.tsxfrontend/core-ui/src/modules/products/components/ProductsFilter.tsxfrontend/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.tsxfrontend/core-ui/src/modules/products/hooks/useUom.tsxfrontend/core-ui/src/modules/products/components/ProductColumns.tsxfrontend/libs/ui-modules/src/modules/products/categories/hooks/useCategoriesWithSearch.tsxfrontend/libs/ui-modules/src/modules/products/categories/hooks/useCategoryInline.tsxfrontend/core-ui/src/modules/products/components/ProductsFilter.tsxfrontend/libs/ui-modules/src/modules/products/categories/components/CategoriesInline.tsxfrontend/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.tsxfrontend/libs/ui-modules/src/modules/products/categories/contexts/CategoriesInlineContext.tsxfrontend/libs/ui-modules/src/modules/products/contexts/SelectProductCategoryContext.tsxfrontend/libs/ui-modules/src/modules/products/categories/graphql/queries.tsfrontend/libs/ui-modules/src/modules/products/categories/components/CategoriesInline.tsxfrontend/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.tsxfrontend/libs/ui-modules/src/modules/products/categories/components/CategoriesInline.tsxfrontend/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.tsxfrontend/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
dataprop in RecordTable.Provider is typed asany[], and company columns are defined with genericanyat runtime. Supplying[{}]whencompaniesisundefinedwon’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
SelectCategoryis 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-xsto 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
ChangingProductsPath.Indexfrom'/'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
ProductsRoutesunder 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
undefinedto the type union and changing the initial value fromnulltoundefinedimproves 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
cursorfield 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
loadingfromuseProductDetaildestructuring and simplifyinguseUom()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:_idandnameare always fetched
- The
productDetailGraphQL query in
frontend/core-ui/src/modules/products/detail/graphql/queries/productDetailQueries.tsx
explicitly selects both_idandname.- The
ProductsMainquery in
frontend/core-ui/src/modules/products/graphql/ProductsQueries.tsx
returns list items with_idandname.- The form hook (
useProductFormData) andProductDetailLayoutrely 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
useSearchParamstouseQueryStateand the change from'product_id'to'productId'(camelCase) improves consistency with JavaScript naming conventions and provides better type safety through theuseQueryStatehook'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
useQueryStateimport 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
setProductIdinstead of direct URL manipulation is cleaner and more maintainable. Good use of descriptive naming withnewProductIdparameter.frontend/core-ui/src/modules/products/graphql/ProductsQueries.tsx (3)
15-15: Good addition of orderBy support.The addition of the
$orderBy: JSONparameter 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
codefield 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
ProductCategoriestoProductCategoryDetailprovides 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
attachmentproperty follows the same pattern as the existingavatarproperty and enhances the interface's flexibility for category display.
25-30: Well-designed interface for inline category functionality.The
CategoriesInlinePropsinterface 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
ISelectProductCategoryContextinterface 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
nullas 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
ICategoriesInlineContextinterface 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
CategoriesInlinePropstype 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 conditionThe
skip: cursor === undefinedcondition 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 implementationThe 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 safetyGood improvements:
- Explicit extraction of
sessionKeyandcursorimproves readability- The
skip: cursor === undefinedprevents unnecessary queries- Optional chaining on
customersQueryVariablesadds safetyThese changes align well with the patterns in
useProductshook.frontend/core-ui/src/modules/products/components/ProductColumns.tsx (1)
120-122: No changes needed forcategoriesprop in SelectCategoryInlineCell
TheSelectCategoryInlineCellcomponent forwards all ofSelectCategoryProvider’s props (includingcategories?: IProductCategory[]) via...props. Passing an array of full category objects ([cell.row.original.category]) is type-compatible.• Ensure that
cell.row.original.categoryis of typeIProductCategory.frontend/libs/ui-modules/src/modules/products/categories/components/selectCategory.tsx (3)
358-358: Add displayName to SelectCategoryRoot for consistency
SelectCategoryFormItemhas a displayName butSelectCategoryRootis 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 categoriesThe
useCategoriesWithSearchhook is called with a debounced search value, which is good. The implementation looks correct.
271-279: Fix type safety issue with value.length checkThe condition
value.length > 0assumesvalueis 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.
| const [queries] = useMultiQueryState<{ | ||
| searchValue: string; | ||
| created: string; | ||
| updated: string; | ||
| lastSeen: string; | ||
| }>(['searchValue', 'created', 'updated', 'lastSeen']); | ||
| const { searchValue } = queries || {}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
| 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 = () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
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.
| 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.
| const [queries] = useMultiQueryState<{ | ||
| searchValue: string; | ||
| created: string; | ||
| updated: string; | ||
| lastSeen: string; | ||
| }>(['searchValue', 'created', 'updated', 'lastSeen']); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
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.
| 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.
| export enum ProductsPath { | ||
| Index = '/', | ||
| Index = '', | ||
| Categories = '/categories', | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
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.
| 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.
| 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]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
| 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.
| const productCategoryDetail = gql` | ||
| query ProductCategories($ids: [String]) { | ||
| productCategories(ids: $ids) { | ||
| _id | ||
| code | ||
| name | ||
| } | ||
| } | ||
| `; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
| 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.
| import { QueryHookOptions } from '@apollo/client'; | ||
| import { useQuery } from '@apollo/client'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
| 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'; | |||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 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 2Length 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.tsxLength 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.
| 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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Important
Looks good to me! 👍
Reviewed a708f0b in 48 seconds. Click for details.
- Reviewed
135lines of code in4files - Skipped
0files when reviewing. - Skipped posting
4draft comments. View those below. - Modify your settings and rules to customize what types of comments Ellipsis leaves. And don't forget to react with 👍 or 👎 to teach Ellipsis.
1. 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%<= threshold50%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%<= threshold50%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%<= threshold50%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 by changing your verbosity settings, reacting with 👍 or 👎, replying to comments, or adding code review rules.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
♻️ 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:
Duplicate hook call: The same
useMultiQueryStatehook is called with identical parameters in both the parent component and here, which is inefficient.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 mutationThe
productsEditmutation 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 updateThe 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
📒 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.tsxfrontend/core-ui/src/modules/products/components/ProductsFilter.tsxfrontend/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.tsxfrontend/core-ui/src/modules/products/components/ProductsFilter.tsxfrontend/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.tsxfrontend/core-ui/src/modules/products/components/ProductsFilter.tsxfrontend/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.tsxfrontend/core-ui/src/modules/products/components/ProductsFilter.tsxfrontend/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.tsxfrontend/core-ui/src/modules/products/components/ProductsFilter.tsxfrontend/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.tsxfrontend/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
brandIdandcategoryIdin 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
hasFilterscomputation correctly identifies active filters usingObject.values().some(), and the new SelectBrand and SelectCategory components are properly integrated following the established filter pattern.Also applies to: 74-82
| const name = cell.getValue() as string; | ||
| const [value, setValue] = useState(name); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
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.
| 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.
| onError: () => { | ||
| toast({ | ||
| title: 'Error', | ||
| description: 'Product update failed', | ||
| variant: 'destructive', | ||
| }); | ||
| }, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
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.
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:
Enhancements:
Chores:
Important
Refactor product category selection and inline editing by replacing
SelectTreewithSelectCategoryAPI, adding inline displays, and unifying filter state management.SelectTreewithSelectCategoryAPI for category selection, supporting single/multiple modes and search-driven selection.CategoriesInlinecomponent for inline category display withuseCategoryInlineanduseCategoriesWithSearchhooks.SelectBrandandSelectCategoryfilters intoProductsFilterbar and popover.ProductColumns.tsxusingRecordTablePopoverandInputcomponents.useSearchParamstouseQueryStateinProductDetailSheet.tsx.useProductsanduseCustomershooks with multi-query state filters and cursor-based pagination.ProductsQueries.tsxto support search parameters, pagination, and new fields.IProductCategoryandProductDetailtypes to enforce non-nullable fields.useRecordTableCursor.tsx.This description was created by
for a708f0b. You can customize this summary. It will automatically update as commits are pushed.
Summary by CodeRabbit
New Features
Enhancements
Bug Fixes
Refactor
Style
Chores