Merge pull request #169 from Worklenz/imp/task-list-performance-fixes
Imp/task list performance fixes
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
import React, { useEffect } from 'react';
|
||||
import { Layout, Typography, Card, Space, Alert } from 'antd';
|
||||
import { useDispatch } from 'react-redux';
|
||||
import TaskListBoard from '@/components/task-management/TaskListBoard';
|
||||
import TaskListBoard from '@/components/task-management/task-list-board';
|
||||
import { AppDispatch } from '@/app/store';
|
||||
|
||||
const { Header, Content } = Layout;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { useEffect } from 'react';
|
||||
import { useEffect, memo, useMemo, useCallback } from 'react';
|
||||
import { useMediaQuery } from 'react-responsive';
|
||||
import Col from 'antd/es/col';
|
||||
import Flex from 'antd/es/flex';
|
||||
@@ -19,48 +19,72 @@ import { fetchProjectCategories } from '@/features/projects/lookups/projectCateg
|
||||
import { fetchProjectHealth } from '@/features/projects/lookups/projectHealth/projectHealthSlice';
|
||||
import { fetchProjects } from '@/features/home-page/home-page.slice';
|
||||
import { createPortal } from 'react-dom';
|
||||
import React from 'react';
|
||||
import React, { Suspense } from 'react';
|
||||
|
||||
const DESKTOP_MIN_WIDTH = 1024;
|
||||
const TASK_LIST_MIN_WIDTH = 500;
|
||||
const SIDEBAR_MAX_WIDTH = 400;
|
||||
|
||||
// Lazy load heavy components
|
||||
const TaskDrawer = React.lazy(() => import('@components/task-drawer/task-drawer'));
|
||||
const HomePage = () => {
|
||||
|
||||
const HomePage = memo(() => {
|
||||
const dispatch = useAppDispatch();
|
||||
const isDesktop = useMediaQuery({ query: `(min-width: ${DESKTOP_MIN_WIDTH}px)` });
|
||||
const isOwnerOrAdmin = useAuthService().isOwnerOrAdmin();
|
||||
|
||||
useDocumentTitle('Home');
|
||||
|
||||
useEffect(() => {
|
||||
const fetchLookups = async () => {
|
||||
const fetchPromises = [
|
||||
dispatch(fetchProjectHealth()),
|
||||
dispatch(fetchProjectCategories()),
|
||||
dispatch(fetchProjectStatuses()),
|
||||
dispatch(fetchProjects()),
|
||||
].filter(Boolean);
|
||||
// Memoize fetch function to prevent recreation on every render
|
||||
const fetchLookups = useCallback(async () => {
|
||||
const fetchPromises = [
|
||||
dispatch(fetchProjectHealth()),
|
||||
dispatch(fetchProjectCategories()),
|
||||
dispatch(fetchProjectStatuses()),
|
||||
dispatch(fetchProjects()),
|
||||
].filter(Boolean);
|
||||
|
||||
await Promise.all(fetchPromises);
|
||||
};
|
||||
fetchLookups();
|
||||
await Promise.all(fetchPromises);
|
||||
}, [dispatch]);
|
||||
|
||||
const CreateProjectButtonComponent = () =>
|
||||
isDesktop ? (
|
||||
useEffect(() => {
|
||||
fetchLookups();
|
||||
}, [fetchLookups]);
|
||||
|
||||
// Memoize project drawer close handler
|
||||
const handleProjectDrawerClose = useCallback(() => {}, []);
|
||||
|
||||
// Memoize desktop flex styles to prevent object recreation
|
||||
const desktopFlexStyle = useMemo(() => ({
|
||||
minWidth: TASK_LIST_MIN_WIDTH,
|
||||
width: '100%'
|
||||
}), []);
|
||||
|
||||
const sidebarFlexStyle = useMemo(() => ({
|
||||
width: '100%',
|
||||
maxWidth: SIDEBAR_MAX_WIDTH
|
||||
}), []);
|
||||
|
||||
// Memoize components to prevent unnecessary re-renders
|
||||
const CreateProjectButtonComponent = useMemo(() => {
|
||||
if (!isOwnerOrAdmin) return null;
|
||||
|
||||
return isDesktop ? (
|
||||
<div className="absolute right-0 top-1/2 -translate-y-1/2">
|
||||
{isOwnerOrAdmin && <CreateProjectButton />}
|
||||
<CreateProjectButton />
|
||||
</div>
|
||||
) : (
|
||||
isOwnerOrAdmin && <CreateProjectButton />
|
||||
<CreateProjectButton />
|
||||
);
|
||||
}, [isDesktop, isOwnerOrAdmin]);
|
||||
|
||||
const MainContent = () =>
|
||||
isDesktop ? (
|
||||
const MainContent = useMemo(() => {
|
||||
return isDesktop ? (
|
||||
<Flex gap={24} align="flex-start" className="w-full mt-12">
|
||||
<Flex style={{ minWidth: TASK_LIST_MIN_WIDTH, width: '100%' }}>
|
||||
<Flex style={desktopFlexStyle}>
|
||||
<TasksList />
|
||||
</Flex>
|
||||
<Flex vertical gap={24} style={{ width: '100%', maxWidth: SIDEBAR_MAX_WIDTH }}>
|
||||
<Flex vertical gap={24} style={sidebarFlexStyle}>
|
||||
<TodoList />
|
||||
<RecentAndFavouriteProjectList />
|
||||
</Flex>
|
||||
@@ -72,19 +96,31 @@ const HomePage = () => {
|
||||
<RecentAndFavouriteProjectList />
|
||||
</Flex>
|
||||
);
|
||||
}, [isDesktop, desktopFlexStyle, sidebarFlexStyle]);
|
||||
|
||||
return (
|
||||
<div className="my-24 min-h-[90vh]">
|
||||
<Col className="flex flex-col gap-6">
|
||||
<GreetingWithTime />
|
||||
<CreateProjectButtonComponent />
|
||||
{CreateProjectButtonComponent}
|
||||
</Col>
|
||||
|
||||
<MainContent />
|
||||
{createPortal(<TaskDrawer />, document.body, 'home-task-drawer')}
|
||||
{createPortal(<ProjectDrawer onClose={() => {}} />, document.body, 'project-drawer')}
|
||||
{MainContent}
|
||||
|
||||
{/* Use Suspense for lazy-loaded components */}
|
||||
<Suspense fallback={null}>
|
||||
{createPortal(<TaskDrawer />, document.body, 'home-task-drawer')}
|
||||
</Suspense>
|
||||
|
||||
{createPortal(
|
||||
<ProjectDrawer onClose={handleProjectDrawerClose} />,
|
||||
document.body,
|
||||
'project-drawer'
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
});
|
||||
|
||||
HomePage.displayName = 'HomePage';
|
||||
|
||||
export default HomePage;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import React from 'react';
|
||||
import { useAppSelector } from '@/hooks/useAppSelector';
|
||||
import TaskListBoard from '@/components/task-management/TaskListBoard';
|
||||
import TaskListBoard from '@/components/task-management/task-list-board';
|
||||
|
||||
const ProjectViewEnhancedTasks: React.FC = () => {
|
||||
const { project } = useAppSelector(state => state.projectReducer);
|
||||
|
||||
Reference in New Issue
Block a user