init
This commit is contained in:
221
worklenz-frontend/src/components/task-drawer/task-drawer.tsx
Normal file
221
worklenz-frontend/src/components/task-drawer/task-drawer.tsx
Normal file
@@ -0,0 +1,221 @@
|
||||
import { TabsProps, Tabs, Button } from 'antd';
|
||||
import Drawer from 'antd/es/drawer';
|
||||
import { InputRef } from 'antd/es/input';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useEffect, useRef, useState } from 'react';
|
||||
import { PlusOutlined } from '@ant-design/icons';
|
||||
|
||||
import { useAppSelector } from '@/hooks/useAppSelector';
|
||||
import { useAppDispatch } from '@/hooks/useAppDispatch';
|
||||
import {
|
||||
setSelectedTaskId,
|
||||
setShowTaskDrawer,
|
||||
setTaskFormViewModel,
|
||||
setTaskSubscribers,
|
||||
setTimeLogEditing,
|
||||
} from '@/features/task-drawer/task-drawer.slice';
|
||||
|
||||
import './task-drawer.css';
|
||||
import TaskDrawerHeader from './task-drawer-header/task-drawer-header';
|
||||
import TaskDrawerActivityLog from './shared/activity-log/task-drawer-activity-log';
|
||||
import TaskDrawerInfoTab from './shared/info-tab/task-drawer-info-tab';
|
||||
import TaskDrawerTimeLog from './shared/time-log/task-drawer-time-log';
|
||||
import TimeLogForm from './shared/time-log/time-log-form';
|
||||
import { DEFAULT_TASK_NAME } from '@/shared/constants';
|
||||
import useTaskDrawerUrlSync from '@/hooks/useTaskDrawerUrlSync';
|
||||
import InfoTabFooter from './shared/info-tab/info-tab-footer';
|
||||
import { Flex } from 'antd';
|
||||
|
||||
const TaskDrawer = () => {
|
||||
const { t } = useTranslation('task-drawer/task-drawer');
|
||||
const [activeTab, setActiveTab] = useState<string>('info');
|
||||
const [refreshTimeLogTrigger, setRefreshTimeLogTrigger] = useState(0);
|
||||
|
||||
const { showTaskDrawer, timeLogEditing } = useAppSelector(state => state.taskDrawerReducer);
|
||||
|
||||
const taskNameInputRef = useRef<InputRef>(null);
|
||||
const isClosingManually = useRef(false);
|
||||
|
||||
// Use the custom hook to sync the task drawer state with the URL
|
||||
const { clearTaskFromUrl } = useTaskDrawerUrlSync();
|
||||
|
||||
useEffect(() => {
|
||||
if (taskNameInputRef.current?.input?.value === DEFAULT_TASK_NAME) {
|
||||
taskNameInputRef.current.focus();
|
||||
}
|
||||
}, [showTaskDrawer]);
|
||||
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
const handleOnClose = () => {
|
||||
// Set flag to indicate we're manually closing the drawer
|
||||
isClosingManually.current = true;
|
||||
setActiveTab('info');
|
||||
|
||||
// Explicitly clear the task parameter from URL
|
||||
clearTaskFromUrl();
|
||||
|
||||
// Update the Redux state
|
||||
dispatch(setShowTaskDrawer(false));
|
||||
dispatch(setSelectedTaskId(null));
|
||||
dispatch(setTaskFormViewModel({}));
|
||||
dispatch(setTaskSubscribers([]));
|
||||
|
||||
// Reset the flag after a short delay
|
||||
setTimeout(() => {
|
||||
isClosingManually.current = false;
|
||||
}, 100);
|
||||
};
|
||||
|
||||
const handleTabChange = (key: string) => {
|
||||
setActiveTab(key);
|
||||
};
|
||||
|
||||
const handleCancelTimeLog = () => {
|
||||
dispatch(
|
||||
setTimeLogEditing({
|
||||
isEditing: false,
|
||||
logBeingEdited: null,
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
const handleAddTimeLog = () => {
|
||||
dispatch(
|
||||
setTimeLogEditing({
|
||||
isEditing: true,
|
||||
logBeingEdited: null,
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
// Function to trigger a refresh of the time log list
|
||||
const refreshTimeLogs = () => {
|
||||
setRefreshTimeLogTrigger(prev => prev + 1);
|
||||
};
|
||||
|
||||
const handleTimeLogSubmitSuccess = () => {
|
||||
// Close the form
|
||||
handleCancelTimeLog();
|
||||
// Trigger refresh of time logs
|
||||
refreshTimeLogs();
|
||||
};
|
||||
|
||||
const tabItems: TabsProps['items'] = [
|
||||
{
|
||||
key: 'info',
|
||||
label: t('taskInfoTab.title'),
|
||||
children: <TaskDrawerInfoTab t={t} />,
|
||||
},
|
||||
{
|
||||
key: 'timeLog',
|
||||
label: t('taskTimeLogTab.title'),
|
||||
children: <TaskDrawerTimeLog t={t} refreshTrigger={refreshTimeLogTrigger} />,
|
||||
},
|
||||
{
|
||||
key: 'activityLog',
|
||||
label: t('taskActivityLogTab.title'),
|
||||
children: <TaskDrawerActivityLog />,
|
||||
},
|
||||
];
|
||||
|
||||
// Render the appropriate footer based on the active tab
|
||||
const renderFooter = () => {
|
||||
if (activeTab === 'info') {
|
||||
return <InfoTabFooter />;
|
||||
} else if (activeTab === 'timeLog') {
|
||||
if (timeLogEditing.isEditing) {
|
||||
return (
|
||||
<TimeLogForm
|
||||
onCancel={handleCancelTimeLog}
|
||||
onSubmitSuccess={handleTimeLogSubmitSuccess}
|
||||
initialValues={timeLogEditing.logBeingEdited || undefined}
|
||||
mode={timeLogEditing.logBeingEdited ? 'edit' : 'create'}
|
||||
/>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<Flex justify="center" style={{ width: '100%', padding: '16px 0 0' }}>
|
||||
<Button
|
||||
type="primary"
|
||||
icon={<PlusOutlined />}
|
||||
onClick={handleAddTimeLog}
|
||||
style={{ width: '100%' }}
|
||||
>
|
||||
Add new time log
|
||||
</Button>
|
||||
</Flex>
|
||||
);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
// Create conditional footer styles based on active tab
|
||||
const getFooterStyle = () => {
|
||||
const baseStyle = {
|
||||
padding: '0 24px 16px',
|
||||
width: '100%',
|
||||
height: 'auto',
|
||||
boxSizing: 'border-box' as const,
|
||||
};
|
||||
|
||||
if (activeTab === 'timeLog') {
|
||||
return {
|
||||
...baseStyle,
|
||||
overflow: 'visible', // Remove scrolling for timeLog tab
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
...baseStyle,
|
||||
overflow: 'hidden',
|
||||
};
|
||||
};
|
||||
|
||||
// Get conditional body style
|
||||
const getBodyStyle = () => {
|
||||
const baseStyle = {
|
||||
padding: '24px',
|
||||
overflow: 'auto'
|
||||
};
|
||||
|
||||
if (activeTab === 'timeLog' && timeLogEditing.isEditing) {
|
||||
return {
|
||||
...baseStyle,
|
||||
height: 'calc(100% - 220px)', // More space for the timeLog form
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
...baseStyle,
|
||||
height: 'calc(100% - 180px)',
|
||||
};
|
||||
};
|
||||
|
||||
const drawerProps = {
|
||||
open: showTaskDrawer,
|
||||
onClose: handleOnClose,
|
||||
width: 720,
|
||||
style: { justifyContent: 'space-between' },
|
||||
destroyOnClose: true,
|
||||
title: <TaskDrawerHeader inputRef={taskNameInputRef} t={t} />,
|
||||
footer: renderFooter(),
|
||||
bodyStyle: getBodyStyle(),
|
||||
footerStyle: getFooterStyle(),
|
||||
};
|
||||
|
||||
return (
|
||||
<Drawer {...drawerProps}>
|
||||
<Tabs
|
||||
type="card"
|
||||
items={tabItems}
|
||||
destroyInactiveTabPane
|
||||
onChange={handleTabChange}
|
||||
activeKey={activeTab}
|
||||
/>
|
||||
</Drawer>
|
||||
);
|
||||
};
|
||||
|
||||
export default TaskDrawer;
|
||||
Reference in New Issue
Block a user