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 BoardSectionCard from './board-section-card/board-section-card';
|
||||||
import BoardCreateSectionCard from './board-section-card/board-create-section-card';
|
import BoardCreateSectionCard from './board-section-card/board-create-section-card';
|
||||||
import { ITaskListGroup } from '@/types/tasks/taskList.types';
|
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 { setTaskAssignee, setTaskEndDate } from '@/features/task-drawer/task-drawer.slice';
|
||||||
import { fetchTaskAssignees } from '@/features/taskAttributes/taskMemberSlice';
|
import { fetchTaskAssignees } from '@/features/taskAttributes/taskMemberSlice';
|
||||||
import { SocketEvents } from '@/shared/socket-events';
|
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,
|
evt_project_task_list_context_menu_delete,
|
||||||
} from '@/shared/worklenz-analytics-events';
|
} from '@/shared/worklenz-analytics-events';
|
||||||
import logger from '@/utils/errorLogger';
|
import logger from '@/utils/errorLogger';
|
||||||
|
import { useAuthService } from '@/hooks/useAuth';
|
||||||
|
import PrioritySection from '@/components/board/taskCard/priority-section/priority-section';
|
||||||
|
|
||||||
interface IBoardViewTaskCardProps {
|
interface IBoardViewTaskCardProps {
|
||||||
task: IProjectTask;
|
task: IProjectTask;
|
||||||
@@ -65,7 +67,7 @@ const BoardViewTaskCard = ({ task, sectionId }: IBoardViewTaskCardProps) => {
|
|||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
const { t } = useTranslation('kanban-board');
|
const { t } = useTranslation('kanban-board');
|
||||||
const { trackMixpanelEvent } = useMixpanelTracking();
|
const { trackMixpanelEvent } = useMixpanelTracking();
|
||||||
|
const currentSession = useAuthService().getCurrentSession();
|
||||||
const themeMode = useAppSelector(state => state.themeReducer.mode);
|
const themeMode = useAppSelector(state => state.themeReducer.mode);
|
||||||
const projectId = useAppSelector(state => state.projectReducer.projectId);
|
const projectId = useAppSelector(state => state.projectReducer.projectId);
|
||||||
const [isSubTaskShow, setIsSubTaskShow] = useState(false);
|
const [isSubTaskShow, setIsSubTaskShow] = useState(false);
|
||||||
@@ -234,42 +236,11 @@ const BoardViewTaskCard = ({ task, sectionId }: IBoardViewTaskCardProps) => {
|
|||||||
},
|
},
|
||||||
], [t, handleAssignToMe, handleArchive, handleDelete, updatingAssignToMe]);
|
], [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(() => {
|
const renderLabels = useMemo(() => {
|
||||||
if (!task?.labels?.length) return null;
|
if (!task?.labels?.length) return null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{task.labels.slice(0, 2).map((label: any) => (
|
{task.labels.slice(0, 2).map((label: any) => (
|
||||||
@@ -313,20 +284,12 @@ const BoardViewTaskCard = ({ task, sectionId }: IBoardViewTaskCardProps) => {
|
|||||||
</Flex>
|
</Flex>
|
||||||
|
|
||||||
<Tooltip title={` ${task?.completed_count} / ${task?.total_tasks_count}`}>
|
<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>
|
</Tooltip>
|
||||||
</Flex>
|
</Flex>
|
||||||
|
|
||||||
{/* Action Icons */}
|
{/* Action Icons */}
|
||||||
<Flex gap={4}>
|
<PrioritySection task={task} />
|
||||||
{priorityIcon}
|
|
||||||
<Typography.Text
|
|
||||||
style={{ fontWeight: 500 }}
|
|
||||||
ellipsis={{ tooltip: task.name }}
|
|
||||||
>
|
|
||||||
{task.name}
|
|
||||||
</Typography.Text>
|
|
||||||
</Flex>
|
|
||||||
|
|
||||||
<Flex vertical gap={8}>
|
<Flex vertical gap={8}>
|
||||||
<Flex
|
<Flex
|
||||||
@@ -376,7 +339,7 @@ const BoardViewTaskCard = ({ task, sectionId }: IBoardViewTaskCardProps) => {
|
|||||||
<Skeleton active paragraph={{ rows: 2 }} title={false} style={{ marginTop: 8 }} />
|
<Skeleton active paragraph={{ rows: 2 }} title={false} style={{ marginTop: 8 }} />
|
||||||
</List.Item>
|
</List.Item>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{!task.sub_tasks_loading && task?.sub_tasks &&
|
{!task.sub_tasks_loading && task?.sub_tasks &&
|
||||||
task?.sub_tasks.map((subtask: any) => (
|
task?.sub_tasks.map((subtask: any) => (
|
||||||
<BoardSubTaskCard key={subtask.id} subtask={subtask} sectionId={sectionId} />
|
<BoardSubTaskCard key={subtask.id} subtask={subtask} sectionId={sectionId} />
|
||||||
|
|||||||
Reference in New Issue
Block a user