feat: drag-and-drop functionality for category reordering in settings#1398
feat: drag-and-drop functionality for category reordering in settings#1398MrgSub merged 3 commits intoMail-0:stagingfrom
Conversation
WalkthroughThe mail categories settings page is refactored to support drag-and-drop reordering using the Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant CategoriesSettingsPage
participant SortableCategoryItem
User->>CategoriesSettingsPage: Drag category item
CategoriesSettingsPage->>CategoriesSettingsPage: handleDragEnd (update order)
User->>SortableCategoryItem: Toggle default switch
SortableCategoryItem->>CategoriesSettingsPage: toggleDefault (update default)
User->>CategoriesSettingsPage: Click Save
CategoriesSettingsPage->>CategoriesSettingsPage: Validate and save categories
Possibly related PRs
Suggested reviewers
Poem
✨ Finishing Touches
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. Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
apps/mail/app/(routes)/settings/categories/page.tsx (1)
291-294: Remove redundant order reassignment.The
handleDragEndfunction already updates the order property when categories are reordered. This reassignment is redundant.Apply this diff to simplify the code:
- const sortedCategories = categories.map((cat, index) => ({ - ...cat, - order: index, - })); try { - await saveUserSettings({ categories: sortedCategories }); + await saveUserSettings({ categories }); queryClient.setQueryData(trpc.settings.get.queryKey(), (updater: any) => { if (!updater) return; return { - settings: { ...updater.settings, categories: sortedCategories }, + settings: { ...updater.settings, categories }, }; }); - setCategories(sortedCategories); toast.success('Categories saved');
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
apps/mail/app/(routes)/settings/categories/page.tsx(5 hunks)
🔇 Additional comments (1)
apps/mail/app/(routes)/settings/categories/page.tsx (1)
228-235: Well-configured drag sensors!Good implementation of both pointer and keyboard sensors. The 8-pixel activation constraint helps prevent accidental drags when interacting with form elements.
There was a problem hiding this comment.
Actionable comments posted: 0
♻️ Duplicate comments (1)
apps/mail/app/(routes)/settings/categories/page.tsx (1)
206-214: Fix incomplete memo equality check to prevent stale closures.The custom equality check only compares a subset of props, omitting handler functions. This could lead to stale closures if these functions change.
Apply this diff to include all props in the equality check:
}, (prev, next) => { // Custom equality check to avoid unnecessary re-renders return ( prev.cat === next.cat && prev.isActiveAi === next.isActiveAi && prev.promptValue === next.promptValue && - prev.isGeneratingQuery === next.isGeneratingQuery + prev.isGeneratingQuery === next.isGeneratingQuery && + prev.setPromptValue === next.setPromptValue && + prev.setActiveAiCat === next.setActiveAiCat && + prev.generateSearchQuery === next.generateSearchQuery && + prev.handleFieldChange === next.handleFieldChange && + prev.toggleDefault === next.toggleDefault ); });Alternatively, consider removing the custom equality function entirely to use React's default shallow comparison.
🧹 Nitpick comments (1)
apps/mail/app/(routes)/settings/categories/page.tsx (1)
353-355: Optimize callback creation to prevent unnecessary re-renders.The
setPromptValuecallback is recreated on every render, which may cause unnecessary re-renders of the memoizedSortableCategoryItemcomponents.Consider memoizing this callback or moving it to a separate function:
+ const handlePromptValueChange = useCallback((catId: string, val: string) => { + setPromptValues((prev) => ({ ...prev, [catId]: val })); + }, []); // In the render section: - setPromptValue={(val) => - setPromptValues((prev) => ({ ...prev, [cat.id]: val })) - } + setPromptValue={(val) => handlePromptValueChange(cat.id, val)}
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
apps/mail/app/(routes)/settings/categories/page.tsx(5 hunks)
🔇 Additional comments (7)
apps/mail/app/(routes)/settings/categories/page.tsx (7)
8-53: LGTM: Clean imports and well-defined interface.The drag-and-drop imports are properly organized and the
SortableCategoryItemPropsinterface is comprehensive with appropriate TypeScript typing.
236-243: LGTM: Well-configured drag-and-drop sensors with accessibility support.The sensor configuration follows best practices with proper activation constraints and keyboard accessibility support.
245-252: LGTM: Well-implemented toggle function with proper memoization.The
toggleDefaultfunction correctly ensures only one category can be default at a time and is properly memoized.
273-291: LGTM: Solid drag-and-drop reordering implementation.The
handleDragEndfunction properly handles reordering witharrayMoveand updates order indices correctly. The early return for invalid drop targets is good defensive programming.
293-318: LGTM: Simplified save logic appropriate for drag-and-drop interface.The removal of manual order validation is correct since order is now managed through drag-and-drop. The function properly ensures exactly one default category exists.
328-328: LGTM: Updated description accurately reflects new functionality.The description change properly informs users about the drag-and-drop reordering capability.
338-364: LGTM: Proper drag-and-drop context implementation.The
DndContextandSortableContextare correctly configured with appropriate sensors, collision detection, and sorting strategy.
…mponent rendering logic.
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (1)
apps/mail/app/(routes)/settings/categories/page.tsx (1)
55-206: Solid component implementation with good drag-and-drop integration.The SortableCategoryItem component properly implements the drag-and-drop functionality and consolidates the previously inline UI logic. The use of React.memo without a custom equality function correctly addresses the previous review concern about stale closures.
Consider breaking this component down into smaller sub-components (e.g., CategoryHeader, CategoryFields, AIQueryPopover) for better maintainability and testing, but the current implementation is functional and well-structured.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
apps/mail/app/(routes)/settings/categories/page.tsx(5 hunks)
🔇 Additional comments (7)
apps/mail/app/(routes)/settings/categories/page.tsx (7)
8-8: LGTM! Comprehensive imports for drag-and-drop functionality.The imports are well-organized and include all necessary components from the @dnd-kit library for implementing drag-and-drop reordering.
Also applies to: 15-15, 24-42
43-53: Well-defined interface with comprehensive prop types.The interface properly types all props needed for the SortableCategoryItem component, including state management and callback functions.
228-235: Excellent sensors configuration for accessibility and UX.The sensors setup properly prevents accidental drags with the distance constraint and includes keyboard navigation support for accessibility compliance.
237-244: Proper implementation of default category toggling.The function is correctly memoized and enforces the business rule that only one category can be default at a time.
265-283: Robust drag-and-drop reordering implementation.The function properly handles drag events, uses the arrayMove utility correctly, and maintains data consistency by reassigning sequential order indices after reordering.
285-310: Appropriate simplification of save logic for drag-and-drop.The function correctly removes manual order validation since drag-and-drop now handles ordering, while maintaining the important business rule validation for default categories.
320-320: Clean integration of drag-and-drop context and rendering.The DndContext is properly configured with appropriate sensors, collision detection, and sorting strategy. The rendering refactor using SortableCategoryItem components improves code organization, and the description update accurately reflects the new drag-and-drop functionality.
Also applies to: 330-356
Before:

After:
Summary by CodeRabbit
New Features
Improvements