Files
worklenz/worklenz-frontend/src/components/enhanced-kanban/EnhancedKanbanCreateTaskCard.tsx
shancds 4f7cbf3527 feat(enhanced-kanban): enhance EnhancedKanbanBoard with new task creation options and layout adjustments
- Updated the EnhancedKanbanBoard component to include a new section for creating tasks at both the top and bottom of each group.
- Adjusted the CSS for the kanban groups container to improve layout responsiveness.
- Refactored EnhancedKanbanGroup to manage task creation visibility and interactions more effectively, enhancing user experience during task management.
2025-06-24 12:24:54 +05:30

134 lines
4.4 KiB
TypeScript

import React, { useRef, useState, useEffect } from 'react';
import { Button, Flex, Input, InputRef } from 'antd';
import { useTranslation } from 'react-i18next';
import { nanoid } from '@reduxjs/toolkit';
import { useAppDispatch } from '@/hooks/useAppDispatch';
import { useAppSelector } from '@/hooks/useAppSelector';
import { themeWiseColor } from '@/utils/themeWiseColor';
import { useSocket } from '@/socket/socketContext';
import { SocketEvents } from '@/shared/socket-events';
import { useAuthService } from '@/hooks/useAuth';
import { IProjectTask } from '@/types/project/projectTasksViewModel.types';
import { ITaskCreateRequest } from '@/types/tasks/task-create-request';
import { addTaskToGroup } from '@/features/enhanced-kanban/enhanced-kanban.slice';
interface EnhancedKanbanCreateTaskCardProps {
sectionId: string;
setShowNewCard: (x: boolean) => void;
position?: 'top' | 'bottom';
}
const EnhancedKanbanCreateTaskCard: React.FC<EnhancedKanbanCreateTaskCardProps> = ({
sectionId,
setShowNewCard,
position = 'bottom',
}) => {
const { t } = useTranslation('kanban-board');
const dispatch = useAppDispatch();
const { socket } = useSocket();
const currentSession = useAuthService().getCurrentSession();
const [newTaskName, setNewTaskName] = useState('');
const [creatingTask, setCreatingTask] = useState(false);
const cardRef = useRef<HTMLDivElement>(null);
const inputRef = useRef<InputRef>(null);
const themeMode = useAppSelector(state => state.themeReducer.mode);
const projectId = useAppSelector(state => state.projectReducer.projectId);
const groupBy = useAppSelector(state => state.enhancedKanbanReducer.groupBy);
useEffect(() => {
setTimeout(() => {
inputRef.current?.focus();
}, 100);
}, []);
const createRequestBody = (): ITaskCreateRequest | null => {
if (!projectId || !currentSession) return null;
const body: ITaskCreateRequest = {
project_id: projectId,
name: newTaskName.trim(),
reporter_id: currentSession.id,
team_id: currentSession.team_id,
};
if (groupBy === 'status') body.status_id = sectionId;
else if (groupBy === 'priority') body.priority_id = sectionId;
else if (groupBy === 'phase') body.phase_id = sectionId;
return body;
};
const resetForm = () => {
setNewTaskName('');
setCreatingTask(false);
setShowNewCard(false);
setTimeout(() => {
inputRef.current?.focus();
}, 100);
};
const handleAddTask = async () => {
if (creatingTask || !projectId || !currentSession || newTaskName.trim() === '') return;
setCreatingTask(true);
const body = createRequestBody();
if (!body) return;
// Real-time socket event handler
const eventHandler = (task: IProjectTask) => {
setCreatingTask(false);
dispatch(addTaskToGroup({ sectionId, task: { ...task, id: task.id || nanoid(), name: task.name || newTaskName.trim() } }));
socket?.off(SocketEvents.QUICK_TASK.toString(), eventHandler);
resetForm();
};
socket?.once(SocketEvents.QUICK_TASK.toString(), eventHandler);
socket?.emit(SocketEvents.QUICK_TASK.toString(), JSON.stringify(body));
};
const handleCancel = () => {
setNewTaskName('');
setShowNewCard(false);
setCreatingTask(false);
};
return (
<Flex
ref={cardRef}
vertical
gap={12}
style={{
width: '100%',
padding: 12,
backgroundColor: themeWiseColor('#292929', '#fafafa', themeMode),
borderRadius: 6,
cursor: 'pointer',
overflow: 'hidden',
}}
className={`outline-1 ${themeWiseColor('outline-[#edeae9]', 'outline-[#6a696a]', themeMode)} hover:outline`}
>
<Input
ref={inputRef}
value={newTaskName}
onChange={e => setNewTaskName(e.target.value)}
onPressEnter={handleAddTask}
placeholder={t('newTaskNamePlaceholder')}
style={{
width: '100%',
borderRadius: 6,
padding: 8,
}}
disabled={creatingTask}
/>
{newTaskName.trim() && (
<Flex gap={8} justify="flex-end">
<Button size="small" onClick={handleCancel}>
{t('cancel')}
</Button>
<Button type="primary" size="small" onClick={handleAddTask} loading={creatingTask}>
{t('addTask')}
</Button>
</Flex>
)}
</Flex>
);
};
export default EnhancedKanbanCreateTaskCard;