Skip to content

Commit 366a31f

Browse files
committed
fix duplication issue in groups
1 parent 5b91fbc commit 366a31f

File tree

4 files changed

+166
-193
lines changed

4 files changed

+166
-193
lines changed

frontend/src/components/dashboard/base-items/widgets/GroupWidget.tsx

Lines changed: 32 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { arrayMove, SortableContext, useSortable } from '@dnd-kit/sortable';
33
import { CSS } from '@dnd-kit/utilities';
44
import AddIcon from '@mui/icons-material/Add';
55
import { Box, Grid2 as Grid, Typography } from '@mui/material';
6-
import React, { useCallback, useEffect, useMemo, useState } from 'react';
6+
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
77
import shortid from 'shortid';
88

99
import { WidgetContainer } from './WidgetContainer';
@@ -180,6 +180,9 @@ const GroupWidget: React.FC<GroupWidgetProps> = ({
180180
const [isDraggingOut, setIsDraggingOut] = useState(false);
181181
const [isCurrentDropTarget, setIsCurrentDropTarget] = useState(false);
182182

183+
// Add a ref to prevent duplicate execution
184+
const duplicationInProgress = useRef<Set<string>>(new Set());
185+
183186
// Detect mobile devices
184187
const isMobile = useMemo(() => {
185188
return (
@@ -418,43 +421,6 @@ const GroupWidget: React.FC<GroupWidgetProps> = ({
418421
setIsCurrentDropTarget(false);
419422
};
420423

421-
// Handle item duplicate
422-
const handleItemDuplicate = useCallback((itemId: string) => {
423-
// Find the item in the group
424-
const itemToDuplicate = items.find(item => item.id === itemId);
425-
if (!itemToDuplicate) {
426-
console.error('Could not find item to duplicate');
427-
return;
428-
}
429-
430-
// Create duplicated item with new ID
431-
const duplicatedItem: GroupItem = {
432-
...JSON.parse(JSON.stringify(itemToDuplicate)), // Deep clone
433-
id: shortid.generate() // New unique ID
434-
};
435-
436-
// Check if we've reached maximum capacity
437-
if (items.length >= MAX_ITEMS) {
438-
// Instead of showing error, pass the duplicated item to parent for adding to dashboard
439-
if (onItemDuplicate) {
440-
onItemDuplicate(duplicatedItem);
441-
}
442-
return;
443-
}
444-
445-
// Find the index of the original item
446-
const originalIndex = items.findIndex(item => item.id === itemId);
447-
448-
// Insert the duplicate after the original
449-
const updatedItems = [...items];
450-
updatedItems.splice(originalIndex + 1, 0, duplicatedItem);
451-
452-
// Update the group's items
453-
if (onItemsChange) {
454-
onItemsChange(updatedItems);
455-
}
456-
}, [items, MAX_ITEMS, onItemsChange, onItemDuplicate]);
457-
458424
// Handle item edit - Convert group item to dashboard item for edit form
459425
const handleItemEdit = useCallback((itemId: string) => {
460426
// Find the item in the group
@@ -593,7 +559,7 @@ const GroupWidget: React.FC<GroupWidgetProps> = ({
593559
id={id}
594560
onEdit={onEdit}
595561
onDelete={onRemove}
596-
onDuplicate={onDuplicate}
562+
onDuplicate={undefined}
597563
isHighlighted={isHighlighted}
598564
customHeight={layout === '2x3' || layout === '3x2' || layout === '4x2' ? DUAL_WIDGET_CONTAINER_HEIGHT : STANDARD_WIDGET_HEIGHT}
599565
>
@@ -682,10 +648,26 @@ const GroupWidget: React.FC<GroupWidgetProps> = ({
682648
onEdit={handleItemEdit}
683649
onDelete={handleItemDelete}
684650
onDuplicate={() => {
685-
// Create a duplicate with a new ID
651+
// Prevent double execution
652+
const duplicateKey = `${id}-${item.id}`;
653+
if (duplicationInProgress.current.has(duplicateKey)) {
654+
console.log('Duplication already in progress, ignoring');
655+
return;
656+
}
657+
658+
duplicationInProgress.current.add(duplicateKey);
659+
660+
// Clear the flag after a short delay to allow the operation to complete
661+
setTimeout(() => {
662+
duplicationInProgress.current.delete(duplicateKey);
663+
}, 1000);
664+
665+
// Create a duplicate with a new ID using timestamp for uniqueness
666+
const groupItemId = `group-${shortid.generate()}-${Date.now()}`;
667+
686668
const duplicatedItem: GroupItem = {
687669
...JSON.parse(JSON.stringify(item)), // Deep clone
688-
id: shortid.generate() // New unique ID
670+
id: groupItemId // Extra-unique ID for group items
689671
};
690672

691673
// Check if group is at capacity
@@ -695,8 +677,15 @@ const GroupWidget: React.FC<GroupWidgetProps> = ({
695677
onItemDuplicate(duplicatedItem);
696678
}
697679
} else {
698-
// Add within the group
699-
handleItemDuplicate(item.id);
680+
// Add within the group directly - bypass any external handlers
681+
const originalIndex = items.findIndex(groupItem => groupItem.id === item.id);
682+
const updatedItems = [...items];
683+
updatedItems.splice(originalIndex + 1, 0, duplicatedItem);
684+
685+
// Use React's functional state update to ensure we have the latest state
686+
if (onItemsChange) {
687+
onItemsChange(updatedItems);
688+
}
700689
}
701690
}}
702691
itemSize={gridSettings.itemSize}

0 commit comments

Comments
 (0)