From 8e62594eff8d93e46cc3ac1b80ded7b7feeeac5e Mon Sep 17 00:00:00 2001 From: shancds Date: Mon, 7 Jul 2025 15:17:33 +0530 Subject: [PATCH 1/6] fix(TaskCard): update background color for improved UI consistency - Changed the background color of the TaskCard component from '#f0f0f0' to '#E2EAF4' in light mode to enhance visual consistency and user experience. --- .../enhanced-kanban/EnhancedKanbanBoardNativeDnD/TaskCard.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/worklenz-frontend/src/components/enhanced-kanban/EnhancedKanbanBoardNativeDnD/TaskCard.tsx b/worklenz-frontend/src/components/enhanced-kanban/EnhancedKanbanBoardNativeDnD/TaskCard.tsx index b103aeff..e6b855fb 100644 --- a/worklenz-frontend/src/components/enhanced-kanban/EnhancedKanbanBoardNativeDnD/TaskCard.tsx +++ b/worklenz-frontend/src/components/enhanced-kanban/EnhancedKanbanBoardNativeDnD/TaskCard.tsx @@ -210,7 +210,7 @@ const TaskCard: React.FC = memo(({ >
From fa9e765e372779b45d337a8c7d6bc1a37969f219 Mon Sep 17 00:00:00 2001 From: shancds Date: Mon, 7 Jul 2025 17:20:34 +0530 Subject: [PATCH 2/6] refactor(KanbanGroup, TaskCard): enhance drag-and-drop indicators and task rendering - Added visual drop indicators before and after task cards in the KanbanGroup component to improve user experience during drag-and-drop operations. - Removed the isDropIndicator prop from TaskCard as the drop indicator logic is now handled within the KanbanGroup, simplifying the TaskCard component. - Updated drag-and-drop event handling in TaskCard to better manage task positioning during drag operations, enhancing overall functionality. --- .../KanbanGroup.tsx | 32 +++++++++++++------ .../EnhancedKanbanBoardNativeDnD/TaskCard.tsx | 27 ++++++---------- 2 files changed, 31 insertions(+), 28 deletions(-) diff --git a/worklenz-frontend/src/components/enhanced-kanban/EnhancedKanbanBoardNativeDnD/KanbanGroup.tsx b/worklenz-frontend/src/components/enhanced-kanban/EnhancedKanbanBoardNativeDnD/KanbanGroup.tsx index d5e814ba..0e3e8a6d 100644 --- a/worklenz-frontend/src/components/enhanced-kanban/EnhancedKanbanBoardNativeDnD/KanbanGroup.tsx +++ b/worklenz-frontend/src/components/enhanced-kanban/EnhancedKanbanBoardNativeDnD/KanbanGroup.tsx @@ -517,17 +517,29 @@ const KanbanGroup: React.FC = memo(({ )} {group.tasks.map((task, idx) => ( - + + {/* Drop indicator before this card */} + {hoveredGroupId === group.id && hoveredTaskIdx === idx && ( +
+
+
+ )} + + ))} + {/* Drop indicator at the end of the group */} + {hoveredGroupId === group.id && hoveredTaskIdx === group.tasks.length && ( +
+
+
+ )} {/* Create card at bottom */} {showNewCardBottom && ( diff --git a/worklenz-frontend/src/components/enhanced-kanban/EnhancedKanbanBoardNativeDnD/TaskCard.tsx b/worklenz-frontend/src/components/enhanced-kanban/EnhancedKanbanBoardNativeDnD/TaskCard.tsx index e6b855fb..0a503ba2 100644 --- a/worklenz-frontend/src/components/enhanced-kanban/EnhancedKanbanBoardNativeDnD/TaskCard.tsx +++ b/worklenz-frontend/src/components/enhanced-kanban/EnhancedKanbanBoardNativeDnD/TaskCard.tsx @@ -28,7 +28,6 @@ interface TaskCardProps { onTaskDragOver: (e: React.DragEvent, groupId: string, taskIdx: number) => void; onTaskDrop: (e: React.DragEvent, groupId: string, taskIdx: number) => void; groupId: string; - isDropIndicator: boolean; idx: number; } @@ -46,7 +45,6 @@ const TaskCard: React.FC = memo(({ onTaskDragOver, onTaskDrop, groupId, - isDropIndicator, idx }) => { const { socket } = useSocket(); @@ -198,29 +196,22 @@ const TaskCard: React.FC = memo(({ while (week.length < 7) week.push(null); weeks.push(week); } + const [isDown, setIsDown] = useState(false); return ( <> - {isDropIndicator && ( -
onTaskDragStart(e, task.id!, groupId)} - onDragOver={e => onTaskDragOver(e, groupId, idx)} - onDrop={e => onTaskDrop(e, groupId, idx)} - > -
-
- )}
onTaskDragStart(e, task.id!, groupId)} - onDragOver={e => onTaskDragOver(e, groupId, idx)} + onDragOver={e => { + e.preventDefault(); + const rect = e.currentTarget.getBoundingClientRect(); + const offsetY = e.clientY - rect.top; + const isDown = offsetY > rect.height / 2; + setIsDown(isDown); + onTaskDragOver(e, groupId, isDown ? idx + 1 : idx); + }} onDrop={e => onTaskDrop(e, groupId, idx)} onClick={e => handleCardClick(e, task.id!)} From d150747f83fa4bcf597c7cb0f9cdc61050b3f2d5 Mon Sep 17 00:00:00 2001 From: shancds Date: Tue, 8 Jul 2025 10:57:34 +0530 Subject: [PATCH 3/6] refactor(ProjectViewEnhancedBoard): remove unused EnhancedKanbanBoard import --- .../projectView/enhancedBoard/project-view-enhanced-board.tsx | 2 -- 1 file changed, 2 deletions(-) diff --git a/worklenz-frontend/src/pages/projects/projectView/enhancedBoard/project-view-enhanced-board.tsx b/worklenz-frontend/src/pages/projects/projectView/enhancedBoard/project-view-enhanced-board.tsx index 39ec6c4c..62e6dd03 100644 --- a/worklenz-frontend/src/pages/projects/projectView/enhancedBoard/project-view-enhanced-board.tsx +++ b/worklenz-frontend/src/pages/projects/projectView/enhancedBoard/project-view-enhanced-board.tsx @@ -1,6 +1,5 @@ import React from 'react'; import { useAppSelector } from '@/hooks/useAppSelector'; -import EnhancedKanbanBoard from '@/components/enhanced-kanban/EnhancedKanbanBoard'; import EnhancedKanbanBoardNativeDnD from '@/components/enhanced-kanban/EnhancedKanbanBoardNativeDnD/EnhancedKanbanBoardNativeDnD'; const ProjectViewEnhancedBoard: React.FC = () => { @@ -12,7 +11,6 @@ const ProjectViewEnhancedBoard: React.FC = () => { return (
- {/* */}
); From 2aab2a21b6e4b718f1f7bb724e4c75c66a1d70b2 Mon Sep 17 00:00:00 2001 From: shancds Date: Tue, 8 Jul 2025 12:13:23 +0530 Subject: [PATCH 4/6] feat(EnhancedKanbanBoard): implement drag end handling for improved task interaction - Added handleDragEnd function to reset hovered task and group states after drag operations in EnhancedKanbanBoard. - Updated KanbanGroup and TaskCard components to support onDragEnd prop, enhancing drag-and-drop functionality and user experience during task management. --- .../EnhancedKanbanBoardNativeDnD.tsx | 6 ++++ .../KanbanGroup.tsx | 30 +++++++++++++++---- .../EnhancedKanbanBoardNativeDnD/TaskCard.tsx | 6 ++-- 3 files changed, 35 insertions(+), 7 deletions(-) diff --git a/worklenz-frontend/src/components/enhanced-kanban/EnhancedKanbanBoardNativeDnD/EnhancedKanbanBoardNativeDnD.tsx b/worklenz-frontend/src/components/enhanced-kanban/EnhancedKanbanBoardNativeDnD/EnhancedKanbanBoardNativeDnD.tsx index fcddff24..1b81906e 100644 --- a/worklenz-frontend/src/components/enhanced-kanban/EnhancedKanbanBoardNativeDnD/EnhancedKanbanBoardNativeDnD.tsx +++ b/worklenz-frontend/src/components/enhanced-kanban/EnhancedKanbanBoardNativeDnD/EnhancedKanbanBoardNativeDnD.tsx @@ -263,6 +263,11 @@ const EnhancedKanbanBoardNativeDnD: React.FC<{ projectId: string }> = ({ project setDragType(null); }; + const handleDragEnd = () => { + setHoveredGroupId(null); + setHoveredTaskIdx(null); + }; + useEffect(() => { if (!socket) return; @@ -332,6 +337,7 @@ const EnhancedKanbanBoardNativeDnD: React.FC<{ projectId: string }> = ({ project onTaskDragStart={handleTaskDragStart} onTaskDragOver={handleTaskDragOver} onTaskDrop={handleTaskDrop} + onDragEnd={handleDragEnd} hoveredTaskIdx={hoveredGroupId === group.id ? hoveredTaskIdx : null} hoveredGroupId={hoveredGroupId} /> diff --git a/worklenz-frontend/src/components/enhanced-kanban/EnhancedKanbanBoardNativeDnD/KanbanGroup.tsx b/worklenz-frontend/src/components/enhanced-kanban/EnhancedKanbanBoardNativeDnD/KanbanGroup.tsx index 0e3e8a6d..24b42c04 100644 --- a/worklenz-frontend/src/components/enhanced-kanban/EnhancedKanbanBoardNativeDnD/KanbanGroup.tsx +++ b/worklenz-frontend/src/components/enhanced-kanban/EnhancedKanbanBoardNativeDnD/KanbanGroup.tsx @@ -34,6 +34,7 @@ interface KanbanGroupProps { onTaskDragStart: (e: React.DragEvent, taskId: string, groupId: string) => void; onTaskDragOver: (e: React.DragEvent, groupId: string, taskIdx: number | null) => void; onTaskDrop: (e: React.DragEvent, groupId: string, taskIdx: number | null) => void; + onDragEnd: (e: React.DragEvent) => void; hoveredTaskIdx: number | null; hoveredGroupId: string | null; } @@ -46,6 +47,7 @@ const KanbanGroup: React.FC = memo(({ onTaskDragStart, onTaskDragOver, onTaskDrop, + onDragEnd, hoveredTaskIdx, hoveredGroupId }) => { @@ -259,6 +261,7 @@ const KanbanGroup: React.FC = memo(({ onDragStart={e => onGroupDragStart(e, group.id)} onDragOver={onGroupDragOver} onDrop={e => onGroupDrop(e, group.id)} + onDragEnd={onDragEnd} >
= memo(({ {/* Drop indicator before this card */} {hoveredGroupId === group.id && hoveredTaskIdx === idx && ( -
-
+
onTaskDragOver(e, group.id, idx)} + onDrop={e => onTaskDrop(e, group.id, idx)} + > +
)} = memo(({ onTaskDrop={onTaskDrop} groupId={group.id} idx={idx} + onDragEnd={onDragEnd} /> ))} {/* Drop indicator at the end of the group */} {hoveredGroupId === group.id && hoveredTaskIdx === group.tasks.length && ( -
-
-
+
onTaskDragOver(e, group.id, group.tasks.length)} + onDrop={e => onTaskDrop(e, group.id, group.tasks.length)} + > +
+
)} {/* Create card at bottom */} diff --git a/worklenz-frontend/src/components/enhanced-kanban/EnhancedKanbanBoardNativeDnD/TaskCard.tsx b/worklenz-frontend/src/components/enhanced-kanban/EnhancedKanbanBoardNativeDnD/TaskCard.tsx index 0a503ba2..fea952f0 100644 --- a/worklenz-frontend/src/components/enhanced-kanban/EnhancedKanbanBoardNativeDnD/TaskCard.tsx +++ b/worklenz-frontend/src/components/enhanced-kanban/EnhancedKanbanBoardNativeDnD/TaskCard.tsx @@ -29,6 +29,7 @@ interface TaskCardProps { onTaskDrop: (e: React.DragEvent, groupId: string, taskIdx: number) => void; groupId: string; idx: number; + onDragEnd: (e: React.DragEvent) => void; // <-- add this } function getDaysInMonth(year: number, month: number) { @@ -45,7 +46,8 @@ const TaskCard: React.FC = memo(({ onTaskDragOver, onTaskDrop, groupId, - idx + idx, + onDragEnd // <-- add this }) => { const { socket } = useSocket(); const themeMode = useSelector((state: RootState) => state.themeReducer.mode); @@ -213,7 +215,7 @@ const TaskCard: React.FC = memo(({ onTaskDragOver(e, groupId, isDown ? idx + 1 : idx); }} onDrop={e => onTaskDrop(e, groupId, idx)} - + onDragEnd={onDragEnd} // <-- add this onClick={e => handleCardClick(e, task.id!)} >
From ee6055934c0700376d9d2cda8da57814adbaa833 Mon Sep 17 00:00:00 2001 From: shancds Date: Tue, 8 Jul 2025 12:49:49 +0530 Subject: [PATCH 5/6] refactor(AssigneeSelector): streamline component logic and enhance dropdown behavior - Removed unused kanbanMode prop and related logic to simplify the AssigneeSelector component. - Updated dropdown position handling to improve visibility and responsiveness during interactions. - Optimized member selection logic for better performance and user feedback. - Enhanced the rendering of team members with improved visual feedback for pending changes. --- .../src/components/AssigneeSelector.tsx | 379 ++++++++---------- 1 file changed, 169 insertions(+), 210 deletions(-) diff --git a/worklenz-frontend/src/components/AssigneeSelector.tsx b/worklenz-frontend/src/components/AssigneeSelector.tsx index 5f2bffcc..91866b7d 100644 --- a/worklenz-frontend/src/components/AssigneeSelector.tsx +++ b/worklenz-frontend/src/components/AssigneeSelector.tsx @@ -5,29 +5,25 @@ import { PlusOutlined, UserAddOutlined } from '@ant-design/icons'; import { RootState } from '@/app/store'; import { IProjectTask } from '@/types/project/projectTasksViewModel.types'; import { ITeamMembersViewModel } from '@/types/teamMembers/teamMembersViewModel.types'; -import { InlineMember } from '@/types/teamMembers/inlineMember.types'; import { useSocket } from '@/socket/socketContext'; import { SocketEvents } from '@/shared/socket-events'; import { useAuthService } from '@/hooks/useAuth'; -import { Avatar, Checkbox } from '@/components'; +import { Avatar, Button, Checkbox } from '@/components'; import { sortTeamMembers } from '@/utils/sort-team-members'; import { useAppDispatch } from '@/hooks/useAppDispatch'; import { toggleProjectMemberDrawer } from '@/features/projects/singleProject/members/projectMembersSlice'; -import { updateTaskAssignees } from '@/features/task-management/task-management.slice'; -import { ITeamMemberViewModel } from '@/types/teamMembers/teamMembersGetResponse.types'; +import { updateEnhancedKanbanTaskAssignees } from '@/features/enhanced-kanban/enhanced-kanban.slice'; interface AssigneeSelectorProps { task: IProjectTask; groupId?: string | null; isDarkMode?: boolean; - kanbanMode?: boolean; // <-- Add this prop } -const AssigneeSelector: React.FC = ({ - task, - groupId = null, - isDarkMode = false, - kanbanMode = false, // <-- Default to false +const AssigneeSelector: React.FC = ({ + task, + groupId = null, + isDarkMode = false }) => { const [isOpen, setIsOpen] = useState(false); const [searchQuery, setSearchQuery] = useState(''); @@ -35,12 +31,6 @@ const AssigneeSelector: React.FC = ({ const [dropdownPosition, setDropdownPosition] = useState({ top: 0, left: 0 }); const [optimisticAssignees, setOptimisticAssignees] = useState([]); // For optimistic updates const [pendingChanges, setPendingChanges] = useState>(new Set()); // Track pending member changes - - // Initialize optimistic assignees from task data on mount or when task changes - useEffect(() => { - const currentAssigneeIds = task?.assignees?.map(a => a.team_member_id) || []; - setOptimisticAssignees(currentAssigneeIds); - }, [task?.assignees]); const dropdownRef = useRef(null); const buttonRef = useRef(null); const searchInputRef = useRef(null); @@ -61,16 +51,9 @@ const AssigneeSelector: React.FC = ({ const updateDropdownPosition = useCallback(() => { if (buttonRef.current) { const rect = buttonRef.current.getBoundingClientRect(); - const viewportHeight = window.innerHeight; - const dropdownHeight = 280; // More accurate height: header(40) + max-height(192) + footer(40) + padding - - // Check if dropdown would go below viewport - const spaceBelow = viewportHeight - rect.bottom; - const shouldShowAbove = spaceBelow < dropdownHeight && rect.top > dropdownHeight; - setDropdownPosition({ - top: shouldShowAbove ? rect.top - dropdownHeight - 4 : rect.bottom + 4, - left: rect.left, + top: rect.bottom + window.scrollY + 2, + left: rect.left + window.scrollX, }); } }, []); @@ -78,21 +61,27 @@ const AssigneeSelector: React.FC = ({ // Close dropdown when clicking outside and handle scroll useEffect(() => { const handleClickOutside = (event: MouseEvent) => { - if ( - dropdownRef.current && - !dropdownRef.current.contains(event.target as Node) && - buttonRef.current && - !buttonRef.current.contains(event.target as Node) - ) { + if (dropdownRef.current && !dropdownRef.current.contains(event.target as Node) && + buttonRef.current && !buttonRef.current.contains(event.target as Node)) { setIsOpen(false); } }; - const handleScroll = (event: Event) => { + const handleScroll = () => { if (isOpen) { - // Only close dropdown if scrolling happens outside the dropdown - if (dropdownRef.current && !dropdownRef.current.contains(event.target as Node)) { - setIsOpen(false); + // Check if the button is still visible in the viewport + if (buttonRef.current) { + const rect = buttonRef.current.getBoundingClientRect(); + const isVisible = rect.top >= 0 && rect.left >= 0 && + rect.bottom <= window.innerHeight && + rect.right <= window.innerWidth; + + if (isVisible) { + updateDropdownPosition(); + } else { + // Hide dropdown if button is not visible + setIsOpen(false); + } } } }; @@ -107,7 +96,7 @@ const AssigneeSelector: React.FC = ({ document.addEventListener('mousedown', handleClickOutside); window.addEventListener('scroll', handleScroll, true); window.addEventListener('resize', handleResize); - + return () => { document.removeEventListener('mousedown', handleClickOutside); window.removeEventListener('scroll', handleScroll, true); @@ -122,22 +111,19 @@ const AssigneeSelector: React.FC = ({ const handleDropdownToggle = (e: React.MouseEvent) => { e.preventDefault(); e.stopPropagation(); - + if (!isOpen) { updateDropdownPosition(); - - // Prepare team members data when opening - use optimistic assignees for current state - const currentAssigneeIds = optimisticAssignees.length > 0 - ? optimisticAssignees - : task?.assignees?.map(assignee => assignee.team_member_id) || []; - const membersData: (ITeamMembersViewModel & { selected?: boolean })[] = (members?.data || []).map(member => ({ + // Prepare team members data when opening + const assignees = task?.assignees?.map(assignee => assignee.team_member_id); + const membersData = (members?.data || []).map(member => ({ ...member, - selected: currentAssigneeIds.includes(member.id), + selected: assignees?.includes(member.id), })); const sortedMembers = sortTeamMembers(membersData); setTeamMembers({ data: sortedMembers }); - + setIsOpen(true); // Focus search input after opening setTimeout(() => { @@ -154,20 +140,16 @@ const AssigneeSelector: React.FC = ({ // Add to pending changes for visual feedback setPendingChanges(prev => new Set(prev).add(memberId)); - // Get the current list of assignees, prioritizing optimistic updates for immediate feedback - const currentAssigneeIds = optimisticAssignees.length > 0 - ? optimisticAssignees - : task?.assignees?.map(a => a.team_member_id) || []; - + // OPTIMISTIC UPDATE: Update local state immediately for instant UI feedback + const currentAssignees = task?.assignees?.map(a => a.team_member_id) || []; let newAssigneeIds: string[]; if (checked) { - // Adding assignee: ensure no duplicates - const uniqueIds = new Set([...currentAssigneeIds, memberId]); - newAssigneeIds = Array.from(uniqueIds); + // Adding assignee + newAssigneeIds = [...currentAssignees, memberId]; } else { // Removing assignee - newAssigneeIds = currentAssigneeIds.filter(id => id !== memberId); + newAssigneeIds = currentAssignees.filter(id => id !== memberId); } // Update optimistic state for immediate UI feedback in dropdown @@ -176,9 +158,11 @@ const AssigneeSelector: React.FC = ({ // Update local team members state for dropdown UI setTeamMembers(prev => ({ ...prev, - data: (prev.data || []).map(member => - member.id === memberId ? { ...member, selected: checked } : member - ), + data: (prev.data || []).map(member => + member.id === memberId + ? { ...member, selected: checked } + : member + ) })); const body = { @@ -192,35 +176,17 @@ const AssigneeSelector: React.FC = ({ // Emit socket event - the socket handler will update Redux with proper types socket?.emit(SocketEvents.QUICK_ASSIGNEES_UPDATE.toString(), JSON.stringify(body)); - socket?.once(SocketEvents.QUICK_ASSIGNEES_UPDATE.toString(), (data: any) => { - // Instead of updating enhancedKanbanSlice, update the main taskManagementSlice - // Filter members to get the actual InlineMember objects for the new assignees - const updatedAssigneeNames: InlineMember[] = (members?.data || []) - .filter((member): member is ITeamMemberViewModel & { id: string; name: string } => { - return typeof member.id === 'string' && typeof member.name === 'string' && newAssigneeIds.includes(member.id); - }) - .map(member => ({ - name: member.name || '', - id: member.id || '', - team_member_id: member.id || '', - avatar_url: member.avatar_url || '', - color_code: member.color_code || '', - })); - - dispatch(updateTaskAssignees({ - taskId: task.id || '', - assigneeIds: newAssigneeIds, - assigneeNames: updatedAssigneeNames, - })); - if (kanbanMode) { + socket?.once( + SocketEvents.QUICK_ASSIGNEES_UPDATE.toString(), + (data: any) => { dispatch(updateEnhancedKanbanTaskAssignees(data)); } - }); + ); // Remove from pending changes after a short delay (optimistic) setTimeout(() => { setPendingChanges(prev => { - const newSet = new Set(Array.from(prev)); + const newSet = new Set(prev); newSet.delete(memberId); return newSet; }); @@ -229,8 +195,11 @@ const AssigneeSelector: React.FC = ({ const checkMemberSelected = (memberId: string) => { if (!memberId) return false; - // Always use optimistic assignees for dropdown display - return optimisticAssignees.includes(memberId); + // Use optimistic assignees if available, otherwise fall back to task assignees + const assignees = optimisticAssignees.length > 0 + ? optimisticAssignees + : task?.assignees?.map(assignee => assignee.team_member_id) || []; + return assignees.includes(memberId); }; const handleInviteProjectMemberDrawer = () => { @@ -246,159 +215,149 @@ const AssigneeSelector: React.FC = ({ className={` w-5 h-5 rounded-full border border-dashed flex items-center justify-center transition-colors duration-200 - ${ - isOpen - ? isDarkMode - ? 'border-blue-500 bg-blue-900/20 text-blue-400' - : 'border-blue-500 bg-blue-50 text-blue-600' - : isDarkMode - ? 'border-gray-600 hover:border-gray-500 hover:bg-gray-800 text-gray-400' - : 'border-gray-300 hover:border-gray-400 hover:bg-gray-100 text-gray-600' + ${isOpen + ? isDarkMode + ? 'border-blue-500 bg-blue-900/20 text-blue-400' + : 'border-blue-500 bg-blue-50 text-blue-600' + : isDarkMode + ? 'border-gray-600 hover:border-gray-500 hover:bg-gray-800 text-gray-400' + : 'border-gray-300 hover:border-gray-400 hover:bg-gray-100 text-gray-600' } `} > - {isOpen && - createPortal( -
e.stopPropagation()} - className={` + {isOpen && createPortal( +
e.stopPropagation()} + className={` fixed z-9999 w-72 rounded-md shadow-lg border - ${isDarkMode ? 'bg-gray-800 border-gray-600' : 'bg-white border-gray-200'} + ${isDarkMode + ? 'bg-gray-800 border-gray-600' + : 'bg-white border-gray-200' + } `} - style={{ - top: dropdownPosition.top, - left: dropdownPosition.left, - }} - > - {/* Header */} -
- setSearchQuery(e.target.value)} - placeholder="Search members..." - className={` + style={{ + top: dropdownPosition.top, + left: dropdownPosition.left, + }} + > + {/* Header */} +
+ setSearchQuery(e.target.value)} + placeholder="Search members..." + className={` w-full px-2 py-1 text-xs rounded border - ${ - isDarkMode - ? 'bg-gray-700 border-gray-600 text-gray-100 placeholder-gray-400 focus:border-blue-500' - : 'bg-white border-gray-300 text-gray-900 placeholder-gray-500 focus:border-blue-500' + ${isDarkMode + ? 'bg-gray-700 border-gray-600 text-gray-100 placeholder-gray-400 focus:border-blue-500' + : 'bg-white border-gray-300 text-gray-900 placeholder-gray-500 focus:border-blue-500' } focus:outline-none focus:ring-1 focus:ring-blue-500 `} - /> -
+ /> +
- {/* Members List */} -
- {filteredMembers && filteredMembers.length > 0 ? ( - filteredMembers.map(member => ( -
+ {filteredMembers && filteredMembers.length > 0 ? ( + filteredMembers.map((member) => ( +
{ - if (!member.pending_invitation) { - const isSelected = checkMemberSelected(member.id || ''); - handleMemberToggle(member.id || '', !isSelected); - } - }} - style={{ - // Add visual feedback for immediate response - transition: 'all 0.15s ease-in-out', - }} - > -
- e.stopPropagation()}> - handleMemberToggle(member.id || '', checked)} - disabled={ - member.pending_invitation || pendingChanges.has(member.id || '') - } - isDarkMode={isDarkMode} - /> - - {pendingChanges.has(member.id || '') && ( -
-
-
+ onClick={() => { + if (!member.pending_invitation) { + const isSelected = checkMemberSelected(member.id || ''); + handleMemberToggle(member.id || '', !isSelected); + } + }} + style={{ + // Add visual feedback for immediate response + transition: 'all 0.15s ease-in-out', + }} + > +
+ e.stopPropagation()}> + handleMemberToggle(member.id || '', checked)} + disabled={member.pending_invitation || pendingChanges.has(member.id || '')} + isDarkMode={isDarkMode} + /> + + {pendingChanges.has(member.id || '') && ( +
+
+
+ )} +
+ + + +
+
+ {member.name} +
+
+ {member.email} + {member.pending_invitation && ( + (Pending) )}
- - - -
-
- {member.name} -
-
- {member.email} - {member.pending_invitation && ( - (Pending) - )} -
-
- )) - ) : ( -
-
No members found
- )} -
+ )) + ) : ( +
+
No members found
+
+ )} +
- {/* Footer */} -
- -
-
, - document.body - )} + onClick={handleInviteProjectMemberDrawer} + > + + Invite member + +
+
, + document.body + )} ); }; -export default AssigneeSelector; +export default AssigneeSelector; \ No newline at end of file From e2e57fbf266529e8b0978c64d374bd93b61c7a20 Mon Sep 17 00:00:00 2001 From: shancds Date: Tue, 8 Jul 2025 12:59:31 +0530 Subject: [PATCH 6/6] fix(KanbanGroup): enhance input focus behavior to select text on focus - Updated the focus handling in KanbanGroup to select all text in the input field when focused, improving user experience during task editing. --- .../EnhancedKanbanBoardNativeDnD/KanbanGroup.tsx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/worklenz-frontend/src/components/enhanced-kanban/EnhancedKanbanBoardNativeDnD/KanbanGroup.tsx b/worklenz-frontend/src/components/enhanced-kanban/EnhancedKanbanBoardNativeDnD/KanbanGroup.tsx index 24b42c04..23b6613a 100644 --- a/worklenz-frontend/src/components/enhanced-kanban/EnhancedKanbanBoardNativeDnD/KanbanGroup.tsx +++ b/worklenz-frontend/src/components/enhanced-kanban/EnhancedKanbanBoardNativeDnD/KanbanGroup.tsx @@ -199,7 +199,10 @@ const KanbanGroup: React.FC = memo(({ setIsEditable(true); setShowDropdown(false); setTimeout(() => { - inputRef.current?.focus(); + if (inputRef.current) { + inputRef.current.focus(); + inputRef.current.select(); // Select all text on focus + } }, 100); };