feat(assignee-selector, suspense-fallback, project-view): optimize component loading and enhance user experience
- Integrated synchronous imports for TaskListFilters and filter dropdowns to improve performance and reduce loading times. - Refactored AssigneeSelector to include a new invite member drawer functionality, enhancing user interaction. - Simplified SuspenseFallback components for better loading experiences, ensuring they do not block the main UI. - Updated project view constants to utilize InlineSuspenseFallback for lazy-loaded components, improving rendering efficiency.
This commit is contained in:
@@ -10,6 +10,8 @@ import { SocketEvents } from '@/shared/socket-events';
|
||||
import { useAuthService } from '@/hooks/useAuth';
|
||||
import { Avatar, Button, Checkbox } from '@/components';
|
||||
import { sortTeamMembers } from '@/utils/sort-team-members';
|
||||
import { useAppDispatch } from '@/hooks/useAppDispatch';
|
||||
import { toggleProjectMemberDrawer } from '@/features/projects/singleProject/members/projectMembersSlice';
|
||||
|
||||
interface AssigneeSelectorProps {
|
||||
task: IProjectTask;
|
||||
@@ -34,6 +36,7 @@ const AssigneeSelector: React.FC<AssigneeSelectorProps> = ({
|
||||
const members = useSelector((state: RootState) => state.teamMembersReducer.teamMembers);
|
||||
const currentSession = useAuthService().getCurrentSession();
|
||||
const { socket } = useSocket();
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
const filteredMembers = useMemo(() => {
|
||||
return teamMembers?.data?.filter(member =>
|
||||
@@ -149,6 +152,11 @@ const AssigneeSelector: React.FC<AssigneeSelectorProps> = ({
|
||||
return assignees?.includes(memberId) || false;
|
||||
};
|
||||
|
||||
const handleInviteProjectMemberDrawer = () => {
|
||||
setIsOpen(false); // Close the assignee dropdown first
|
||||
dispatch(toggleProjectMemberDrawer()); // Then open the invite drawer
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<button
|
||||
@@ -271,10 +279,7 @@ const AssigneeSelector: React.FC<AssigneeSelectorProps> = ({
|
||||
: 'text-blue-600 hover:bg-blue-50'
|
||||
}
|
||||
`}
|
||||
onClick={() => {
|
||||
// TODO: Implement invite member functionality
|
||||
console.log('Invite member clicked');
|
||||
}}
|
||||
onClick={handleInviteProjectMemberDrawer}
|
||||
>
|
||||
<UserAddOutlined />
|
||||
Invite member
|
||||
|
||||
@@ -1,50 +1,42 @@
|
||||
import React, { memo } from 'react';
|
||||
import { colors } from '@/styles/colors';
|
||||
import { getInitialTheme } from '@/utils/get-initial-theme';
|
||||
import { ConfigProvider, theme, Layout, Spin } from 'antd';
|
||||
import { Spin } from 'antd';
|
||||
|
||||
// Memoized loading component with theme awareness
|
||||
// Lightweight loading component - removed heavy theme calculations
|
||||
export const SuspenseFallback = memo(() => {
|
||||
const currentTheme = getInitialTheme();
|
||||
const isDark = currentTheme === 'dark';
|
||||
|
||||
// Memoize theme configuration to prevent unnecessary re-renders
|
||||
const themeConfig = React.useMemo(() => ({
|
||||
algorithm: isDark ? theme.darkAlgorithm : theme.defaultAlgorithm,
|
||||
components: {
|
||||
Layout: {
|
||||
colorBgLayout: isDark ? colors.darkGray : '#fafafa',
|
||||
},
|
||||
Spin: {
|
||||
colorPrimary: isDark ? '#fff' : '#1890ff',
|
||||
},
|
||||
},
|
||||
}), [isDark]);
|
||||
|
||||
// Memoize layout style to prevent object recreation
|
||||
const layoutStyle = React.useMemo(() => ({
|
||||
position: 'fixed' as const,
|
||||
width: '100vw',
|
||||
height: '100vh',
|
||||
background: 'transparent',
|
||||
transition: 'none',
|
||||
}), []);
|
||||
|
||||
// Memoize spin style to prevent object recreation
|
||||
const spinStyle = React.useMemo(() => ({
|
||||
position: 'absolute' as const,
|
||||
top: '50%',
|
||||
left: '50%',
|
||||
transform: 'translate(-50%, -50%)',
|
||||
}), []);
|
||||
|
||||
return (
|
||||
<ConfigProvider theme={themeConfig}>
|
||||
<Layout className="app-loading-container" style={layoutStyle}>
|
||||
<Spin size="large" style={spinStyle} />
|
||||
</Layout>
|
||||
</ConfigProvider>
|
||||
<div
|
||||
style={{
|
||||
position: 'fixed',
|
||||
width: '100vw',
|
||||
height: '100vh',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
background: 'transparent',
|
||||
zIndex: 9999,
|
||||
}}
|
||||
>
|
||||
<Spin size="large" />
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
// Lightweight fallback for internal components that doesn't cover the screen
|
||||
export const InlineSuspenseFallback = memo(() => {
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
padding: '40px 20px',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
minHeight: '200px',
|
||||
}}
|
||||
>
|
||||
<Spin size="large" />
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
SuspenseFallback.displayName = 'SuspenseFallback';
|
||||
InlineSuspenseFallback.displayName = 'InlineSuspenseFallback';
|
||||
|
||||
Reference in New Issue
Block a user