refactor(board-section): optimize component rendering and enhance task card functionality
- Imported React to ensure proper usage of hooks. - Wrapped `BoardSectionCardContainer` in `React.memo` for performance optimization. - Integrated `useAuthService` to manage user session within `BoardViewTaskCard`. - Replaced priority icon rendering with a dedicated `PrioritySection` component for cleaner code and improved readability. - Cleaned up unused code and improved overall structure of task card rendering.
This commit is contained in:
@@ -0,0 +1,19 @@
|
||||
.priority-dropdown .ant-dropdown-menu {
|
||||
padding: 0 !important;
|
||||
margin-top: 8px !important;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.priority-dropdown .ant-dropdown-menu-item {
|
||||
padding: 0 !important;
|
||||
}
|
||||
|
||||
.priority-dropdown-card .ant-card-body {
|
||||
padding: 0 !important;
|
||||
}
|
||||
|
||||
.priority-menu .ant-menu-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 32px;
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
import { Flex, Typography } from 'antd';
|
||||
import './priority-section.css';
|
||||
import { useAppSelector } from '@/hooks/useAppSelector';
|
||||
import { useState, useEffect, useMemo } from 'react';
|
||||
import { IProjectTask } from '@/types/project/projectTasksViewModel.types';
|
||||
import { ITaskPriority } from '@/types/tasks/taskPriority.types';
|
||||
import { DoubleLeftOutlined, MinusOutlined, PauseOutlined } from '@ant-design/icons';
|
||||
|
||||
type PrioritySectionProps = {
|
||||
task: IProjectTask;
|
||||
};
|
||||
|
||||
const PrioritySection = ({ task }: PrioritySectionProps) => {
|
||||
const [selectedPriority, setSelectedPriority] = useState<ITaskPriority | undefined>(undefined);
|
||||
const priorityList = useAppSelector(state => state.priorityReducer.priorities);
|
||||
const themeMode = useAppSelector(state => state.themeReducer.mode);
|
||||
|
||||
// Update selectedPriority whenever task.priority or priorityList changes
|
||||
useEffect(() => {
|
||||
if (!task.priority || !priorityList.length) {
|
||||
setSelectedPriority(undefined);
|
||||
return;
|
||||
}
|
||||
|
||||
const foundPriority = priorityList.find(priority => priority.id === task.priority);
|
||||
setSelectedPriority(foundPriority);
|
||||
}, [task.priority, priorityList]);
|
||||
|
||||
const priorityIcon = useMemo(() => {
|
||||
if (!selectedPriority) return null;
|
||||
|
||||
const iconProps = {
|
||||
style: {
|
||||
color: themeMode === 'dark' ? selectedPriority.color_code_dark : selectedPriority.color_code,
|
||||
marginRight: '0.25rem',
|
||||
},
|
||||
};
|
||||
|
||||
switch (selectedPriority.name) {
|
||||
case 'Low':
|
||||
return <MinusOutlined {...iconProps} />;
|
||||
case 'Medium':
|
||||
return <PauseOutlined {...iconProps} style={{ ...iconProps.style, transform: 'rotate(90deg)' }} />;
|
||||
case 'High':
|
||||
return <DoubleLeftOutlined {...iconProps} style={{ ...iconProps.style, transform: 'rotate(90deg)' }} />;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}, [selectedPriority, themeMode]);
|
||||
|
||||
if (!task.priority || !selectedPriority) return null;
|
||||
|
||||
return (
|
||||
<Flex gap={4}>
|
||||
{priorityIcon}
|
||||
<Typography.Text
|
||||
style={{ fontWeight: 500 }}
|
||||
ellipsis={{ tooltip: task.name }}
|
||||
>
|
||||
{task.name}
|
||||
</Typography.Text>
|
||||
</Flex>
|
||||
);
|
||||
};
|
||||
|
||||
export default PrioritySection;
|
||||
@@ -3,7 +3,7 @@ import { SortableContext, horizontalListSortingStrategy } from '@dnd-kit/sortabl
|
||||
import BoardSectionCard from './board-section-card/board-section-card';
|
||||
import BoardCreateSectionCard from './board-section-card/board-create-section-card';
|
||||
import { ITaskListGroup } from '@/types/tasks/taskList.types';
|
||||
import { useEffect } from 'react';
|
||||
import React, { useEffect } from 'react';
|
||||
import { setTaskAssignee, setTaskEndDate } from '@/features/task-drawer/task-drawer.slice';
|
||||
import { fetchTaskAssignees } from '@/features/taskAttributes/taskMemberSlice';
|
||||
import { SocketEvents } from '@/shared/socket-events';
|
||||
@@ -113,4 +113,4 @@ const BoardSectionCardContainer = ({
|
||||
);
|
||||
};
|
||||
|
||||
export default BoardSectionCardContainer;
|
||||
export default React.memo(BoardSectionCardContainer);
|
||||
|
||||
@@ -55,6 +55,8 @@ import {
|
||||
evt_project_task_list_context_menu_delete,
|
||||
} from '@/shared/worklenz-analytics-events';
|
||||
import logger from '@/utils/errorLogger';
|
||||
import { useAuthService } from '@/hooks/useAuth';
|
||||
import PrioritySection from '@/components/board/taskCard/priority-section/priority-section';
|
||||
|
||||
interface IBoardViewTaskCardProps {
|
||||
task: IProjectTask;
|
||||
@@ -65,7 +67,7 @@ const BoardViewTaskCard = ({ task, sectionId }: IBoardViewTaskCardProps) => {
|
||||
const dispatch = useAppDispatch();
|
||||
const { t } = useTranslation('kanban-board');
|
||||
const { trackMixpanelEvent } = useMixpanelTracking();
|
||||
|
||||
const currentSession = useAuthService().getCurrentSession();
|
||||
const themeMode = useAppSelector(state => state.themeReducer.mode);
|
||||
const projectId = useAppSelector(state => state.projectReducer.projectId);
|
||||
const [isSubTaskShow, setIsSubTaskShow] = useState(false);
|
||||
@@ -234,42 +236,11 @@ const BoardViewTaskCard = ({ task, sectionId }: IBoardViewTaskCardProps) => {
|
||||
},
|
||||
], [t, handleAssignToMe, handleArchive, handleDelete, updatingAssignToMe]);
|
||||
|
||||
const priorityIcon = useMemo(() => {
|
||||
if (task.priority_value === 0) {
|
||||
return (
|
||||
<MinusOutlined
|
||||
style={{
|
||||
color: '#52c41a',
|
||||
marginRight: '0.25rem',
|
||||
}}
|
||||
/>
|
||||
);
|
||||
} else if (task.priority_value === 1) {
|
||||
return (
|
||||
<PauseOutlined
|
||||
style={{
|
||||
color: '#faad14',
|
||||
transform: 'rotate(90deg)',
|
||||
marginRight: '0.25rem',
|
||||
}}
|
||||
/>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<DoubleRightOutlined
|
||||
style={{
|
||||
color: '#f5222d',
|
||||
transform: 'rotate(-90deg)',
|
||||
marginRight: '0.25rem',
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}, [task.priority_value]);
|
||||
|
||||
|
||||
const renderLabels = useMemo(() => {
|
||||
if (!task?.labels?.length) return null;
|
||||
|
||||
|
||||
return (
|
||||
<>
|
||||
{task.labels.slice(0, 2).map((label: any) => (
|
||||
@@ -313,20 +284,12 @@ const BoardViewTaskCard = ({ task, sectionId }: IBoardViewTaskCardProps) => {
|
||||
</Flex>
|
||||
|
||||
<Tooltip title={` ${task?.completed_count} / ${task?.total_tasks_count}`}>
|
||||
<Progress type="circle" percent={task?.complete_ratio } size={26} strokeWidth={(task.complete_ratio || 0) >= 100 ? 9 : 7} />
|
||||
<Progress type="circle" percent={task?.complete_ratio} size={26} strokeWidth={(task.complete_ratio || 0) >= 100 ? 9 : 7} />
|
||||
</Tooltip>
|
||||
</Flex>
|
||||
|
||||
{/* Action Icons */}
|
||||
<Flex gap={4}>
|
||||
{priorityIcon}
|
||||
<Typography.Text
|
||||
style={{ fontWeight: 500 }}
|
||||
ellipsis={{ tooltip: task.name }}
|
||||
>
|
||||
{task.name}
|
||||
</Typography.Text>
|
||||
</Flex>
|
||||
<PrioritySection task={task} />
|
||||
|
||||
<Flex vertical gap={8}>
|
||||
<Flex
|
||||
@@ -376,7 +339,7 @@ const BoardViewTaskCard = ({ task, sectionId }: IBoardViewTaskCardProps) => {
|
||||
<Skeleton active paragraph={{ rows: 2 }} title={false} style={{ marginTop: 8 }} />
|
||||
</List.Item>
|
||||
)}
|
||||
|
||||
|
||||
{!task.sub_tasks_loading && task?.sub_tasks &&
|
||||
task?.sub_tasks.map((subtask: any) => (
|
||||
<BoardSubTaskCard key={subtask.id} subtask={subtask} sectionId={sectionId} />
|
||||
|
||||
Reference in New Issue
Block a user