feat(project-drawer): enhance project data fetching and error handling

- Updated project data fetching logic in the project drawer and related components to ensure the drawer opens only after successful data retrieval.
- Added detailed logging for successful and failed fetch attempts to improve debugging and user feedback.
- Introduced error handling to maintain user experience by allowing the drawer to open even if data fetching fails, displaying an error state.
- Refactored project list and project view components to optimize search functionality and improve loading states.
- Removed deprecated components related to task management to streamline the project view.
This commit is contained in:
chamikaJ
2025-07-07 17:07:45 +05:30
parent 978d9158c0
commit b0253135e5
12 changed files with 450 additions and 984 deletions

View File

@@ -124,10 +124,25 @@ const ProjectGroupList: React.FC<ProjectGroupListProps> = ({
// Action handlers
const handleSettingsClick = (e: React.MouseEvent, projectId: string) => {
e.stopPropagation();
console.log('Opening project drawer from project group for project:', projectId);
trackMixpanelEvent(evt_projects_settings_click);
// Set project ID first
dispatch(setProjectId(projectId));
dispatch(fetchProjectData(projectId));
dispatch(toggleProjectDrawer());
// Then fetch project data
dispatch(fetchProjectData(projectId))
.unwrap()
.then((projectData) => {
console.log('Project data fetched successfully from project group:', projectData);
// Open drawer after data is fetched
dispatch(toggleProjectDrawer());
})
.catch((error) => {
console.error('Failed to fetch project data from project group:', error);
// Still open drawer even if fetch fails, so user can see error state
dispatch(toggleProjectDrawer());
});
};
const handleArchiveClick = async (

View File

@@ -46,10 +46,25 @@ export const ActionButtons: React.FC<ActionButtonsProps> = ({
const handleSettingsClick = () => {
if (record.id) {
console.log('Opening project drawer for project:', record.id);
trackMixpanelEvent(evt_projects_settings_click);
// Set project ID first
dispatch(setProjectId(record.id));
dispatch(fetchProjectData(record.id));
dispatch(toggleProjectDrawer());
// Then fetch project data
dispatch(fetchProjectData(record.id))
.unwrap()
.then((projectData) => {
console.log('Project data fetched successfully:', projectData);
// Open drawer after data is fetched
dispatch(toggleProjectDrawer());
})
.catch((error) => {
console.error('Failed to fetch project data:', error);
// Still open drawer even if fetch fails, so user can see error state
dispatch(toggleProjectDrawer());
});
}
};

View File

@@ -72,6 +72,7 @@ const ProjectDrawer = ({ onClose }: { onClose: () => void }) => {
null
);
const [isFormValid, setIsFormValid] = useState<boolean>(true);
const [drawerVisible, setDrawerVisible] = useState<boolean>(false);
// Selectors
const { clients, loading: loadingClients } = useAppSelector(state => state.clientReducer);
@@ -131,6 +132,60 @@ const ProjectDrawer = ({ onClose }: { onClose: () => void }) => {
loadInitialData();
}, [dispatch]);
// New effect to handle form population when project data becomes available
useEffect(() => {
if (drawerVisible && projectId && project && !projectLoading) {
console.log('Populating form with project data:', project);
setEditMode(true);
try {
form.setFieldsValue({
...project,
start_date: project.start_date ? dayjs(project.start_date) : null,
end_date: project.end_date ? dayjs(project.end_date) : null,
working_days: project.working_days || 0,
use_manual_progress: project.use_manual_progress || false,
use_weighted_progress: project.use_weighted_progress || false,
use_time_progress: project.use_time_progress || false,
});
setSelectedProjectManager(project.project_manager || null);
setLoading(false);
console.log('Form populated successfully with project data');
} catch (error) {
console.error('Error setting form values:', error);
logger.error('Error setting form values in project drawer', error);
setLoading(false);
}
} else if (drawerVisible && !projectId) {
// Creating new project
console.log('Setting up drawer for new project creation');
setEditMode(false);
setLoading(false);
} else if (drawerVisible && projectId && !project && !projectLoading) {
// Project data failed to load or is empty
console.warn('Project drawer is visible but no project data available');
setLoading(false);
} else if (drawerVisible && projectId) {
console.log('Drawer visible, waiting for project data to load...');
}
}, [drawerVisible, projectId, project, projectLoading, form]);
// Additional effect to handle loading state when project data is being fetched
useEffect(() => {
if (drawerVisible && projectId && projectLoading) {
console.log('Project data is loading, maintaining loading state');
setLoading(true);
}
}, [drawerVisible, projectId, projectLoading]);
// Define resetForm function early to avoid declaration order issues
const resetForm = useCallback(() => {
setEditMode(false);
form.resetFields();
setSelectedProjectManager(null);
}, [form]);
useEffect(() => {
const startDate = form.getFieldValue('start_date');
const endDate = form.getFieldValue('end_date');
@@ -226,47 +281,33 @@ const ProjectDrawer = ({ onClose }: { onClose: () => void }) => {
return workingDays;
};
// Improved handleVisibilityChange to track drawer state without doing form operations
const handleVisibilityChange = useCallback(
(visible: boolean) => {
if (visible && projectId) {
setEditMode(true);
if (project) {
form.setFieldsValue({
...project,
start_date: project.start_date ? dayjs(project.start_date) : null,
end_date: project.end_date ? dayjs(project.end_date) : null,
working_days:
form.getFieldValue('start_date') && form.getFieldValue('end_date')
? calculateWorkingDays(
form.getFieldValue('start_date'),
form.getFieldValue('end_date')
)
: project.working_days || 0,
use_manual_progress: project.use_manual_progress || false,
use_weighted_progress: project.use_weighted_progress || false,
use_time_progress: project.use_time_progress || false,
});
setSelectedProjectManager(project.project_manager || null);
setLoading(false);
}
} else {
console.log('Drawer visibility changed:', visible, 'Project ID:', projectId);
setDrawerVisible(visible);
if (!visible) {
resetForm();
} else if (visible && !projectId) {
// Creating new project - reset form immediately
console.log('Opening drawer for new project');
setEditMode(false);
setLoading(false);
} else if (visible && projectId) {
// Editing existing project - loading state will be handled by useEffect
console.log('Opening drawer for existing project:', projectId);
setLoading(true);
}
},
[projectId, project]
[projectId, resetForm]
);
const resetForm = useCallback(() => {
setEditMode(false);
form.resetFields();
setSelectedProjectManager(null);
}, [form]);
const handleDrawerClose = useCallback(() => {
setLoading(true);
setDrawerVisible(false);
resetForm();
dispatch(setProjectData({} as IProjectViewModel));
// dispatch(setProjectId(null));
dispatch(setDrawerProjectId(null));
dispatch(toggleProjectDrawer());
onClose();
@@ -405,7 +446,7 @@ const ProjectDrawer = ({ onClose }: { onClose: () => void }) => {
{!isEditable && (
<Alert message={t('noPermission')} type="warning" showIcon style={{ marginBottom: 16 }} />
)}
<Skeleton active paragraph={{ rows: 12 }} loading={projectLoading}>
<Skeleton active paragraph={{ rows: 12 }} loading={loading || projectLoading}>
<Form
form={form}
layout="vertical"