feat(assignee-selector): enhance real-time updates and UI interactions

- Added socket event handling for quick assignee updates, dispatching changes to the enhanced Kanban state.
- Updated AssigneeSelector component to prevent event propagation on dropdown interactions.
- Integrated AvatarGroup and LazyAssigneeSelectorWrapper in EnhancedKanbanTaskCard for improved assignee display and selection.
This commit is contained in:
shancds
2025-07-01 18:21:52 +05:30
parent 0a92d38ccf
commit 87f73ee4c2
2 changed files with 27 additions and 9 deletions

View File

@@ -14,6 +14,7 @@ import { sortTeamMembers } from '@/utils/sort-team-members';
import { useAppDispatch } from '@/hooks/useAppDispatch'; import { useAppDispatch } from '@/hooks/useAppDispatch';
import { toggleProjectMemberDrawer } from '@/features/projects/singleProject/members/projectMembersSlice'; import { toggleProjectMemberDrawer } from '@/features/projects/singleProject/members/projectMembersSlice';
import { updateTask } from '@/features/task-management/task-management.slice'; import { updateTask } from '@/features/task-management/task-management.slice';
import { updateEnhancedKanbanTaskAssignees } from '@/features/enhanced-kanban/enhanced-kanban.slice';
interface AssigneeSelectorProps { interface AssigneeSelectorProps {
task: IProjectTask; task: IProjectTask;
@@ -177,6 +178,12 @@ const AssigneeSelector: React.FC<AssigneeSelectorProps> = ({
// Emit socket event - the socket handler will update Redux with proper types // Emit socket event - the socket handler will update Redux with proper types
socket?.emit(SocketEvents.QUICK_ASSIGNEES_UPDATE.toString(), JSON.stringify(body)); socket?.emit(SocketEvents.QUICK_ASSIGNEES_UPDATE.toString(), JSON.stringify(body));
socket?.once(
SocketEvents.QUICK_ASSIGNEES_UPDATE.toString(),
(data: any) => {
dispatch(updateEnhancedKanbanTaskAssignees(data));
}
);
// Remove from pending changes after a short delay (optimistic) // Remove from pending changes after a short delay (optimistic)
setTimeout(() => { setTimeout(() => {
@@ -226,6 +233,7 @@ const AssigneeSelector: React.FC<AssigneeSelectorProps> = ({
{isOpen && createPortal( {isOpen && createPortal(
<div <div
ref={dropdownRef} ref={dropdownRef}
onClick={e => e.stopPropagation()}
className={` className={`
fixed z-9999 w-72 rounded-md shadow-lg border fixed z-9999 w-72 rounded-md shadow-lg border
${isDarkMode ${isDarkMode
@@ -284,12 +292,14 @@ const AssigneeSelector: React.FC<AssigneeSelectorProps> = ({
}} }}
> >
<div className="relative"> <div className="relative">
<Checkbox <span onClick={e => e.stopPropagation()}>
checked={checkMemberSelected(member.id || '')} <Checkbox
onChange={(checked) => handleMemberToggle(member.id || '', checked)} checked={checkMemberSelected(member.id || '')}
disabled={member.pending_invitation || pendingChanges.has(member.id || '')} onChange={(checked) => handleMemberToggle(member.id || '', checked)}
isDarkMode={isDarkMode} disabled={member.pending_invitation || pendingChanges.has(member.id || '')}
/> isDarkMode={isDarkMode}
/>
</span>
{pendingChanges.has(member.id || '') && ( {pendingChanges.has(member.id || '') && (
<div className={`absolute inset-0 flex items-center justify-center ${ <div className={`absolute inset-0 flex items-center justify-center ${
isDarkMode ? 'bg-gray-800/50' : 'bg-white/50' isDarkMode ? 'bg-gray-800/50' : 'bg-white/50'

View File

@@ -13,7 +13,6 @@ import { useAppDispatch } from '@/hooks/useAppDispatch';
import { setShowTaskDrawer, setSelectedTaskId } from '@/features/task-drawer/task-drawer.slice'; import { setShowTaskDrawer, setSelectedTaskId } from '@/features/task-drawer/task-drawer.slice';
import PrioritySection from '../board/taskCard/priority-section/priority-section'; import PrioritySection from '../board/taskCard/priority-section/priority-section';
import Typography from 'antd/es/typography'; import Typography from 'antd/es/typography';
import CustomAvatarGroup from '../board/custom-avatar-group';
import CustomDueDatePicker from '../board/custom-due-date-picker'; import CustomDueDatePicker from '../board/custom-due-date-picker';
import { themeWiseColor } from '@/utils/themeWiseColor'; import { themeWiseColor } from '@/utils/themeWiseColor';
import { ForkOutlined } from '@ant-design/icons'; import { ForkOutlined } from '@ant-design/icons';
@@ -29,6 +28,8 @@ import BoardSubTaskCard from '@/pages/projects/projectView/board/board-section/b
import BoardCreateSubtaskCard from '@/pages/projects/projectView/board/board-section/board-sub-task-card/board-create-sub-task-card'; import BoardCreateSubtaskCard from '@/pages/projects/projectView/board/board-section/board-sub-task-card/board-create-sub-task-card';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import EnhancedKanbanCreateSubtaskCard from './EnhancedKanbanCreateSubtaskCard'; import EnhancedKanbanCreateSubtaskCard from './EnhancedKanbanCreateSubtaskCard';
import LazyAssigneeSelectorWrapper from '@/components/task-management/lazy-assignee-selector';
import AvatarGroup from '@/components/AvatarGroup';
interface EnhancedKanbanTaskCardProps { interface EnhancedKanbanTaskCardProps {
task: IProjectTask; task: IProjectTask;
@@ -179,8 +180,15 @@ const EnhancedKanbanTaskCard: React.FC<EnhancedKanbanTaskCardProps> = React.memo
marginBlock: 8, marginBlock: 8,
}} }}
> >
{task && <CustomAvatarGroup task={task} sectionId={sectionId} />} <Flex align="center" gap={2}>
<AvatarGroup
members={task.names || []}
maxCount={3}
isDarkMode={themeMode === 'dark'}
size={24}
/>
<LazyAssigneeSelectorWrapper task={task} groupId={sectionId} isDarkMode={themeMode === 'dark'} />
</Flex>
<Flex gap={4} align="center"> <Flex gap={4} align="center">
<CustomDueDatePicker task={task} onDateChange={setDueDate} /> <CustomDueDatePicker task={task} onDateChange={setDueDate} />