init
This commit is contained in:
@@ -0,0 +1,103 @@
|
||||
import { Button, Card, Popconfirm, Table, TableProps, Tooltip, Typography } from 'antd';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useAppSelector } from '@/hooks/useAppSelector';
|
||||
import { DeleteOutlined, EditOutlined } from '@ant-design/icons';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { useDocumentTitle } from '@/hooks/useDoumentTItle';
|
||||
import { projectTemplatesApiService } from '@/api/project-templates/project-templates.api.service';
|
||||
import logger from '@/utils/errorLogger';
|
||||
import { ICustomTemplate } from '@/types/project-templates/project-templates.types';
|
||||
|
||||
const ProjectTemplatesSettings = () => {
|
||||
const { t } = useTranslation('settings/project-templates');
|
||||
|
||||
const [projectTemplates, setProjectTemplates] = useState<ICustomTemplate[]>([]);
|
||||
const themeMode = useAppSelector(state => state.themeReducer.mode);
|
||||
const navigate = useNavigate();
|
||||
|
||||
useDocumentTitle('Project Templates');
|
||||
|
||||
const fetchProjectTemplates = async () => {
|
||||
try {
|
||||
const response = await projectTemplatesApiService.getCustomTemplates();
|
||||
setProjectTemplates(response.body);
|
||||
} catch (error) {
|
||||
logger.error('Failed to fetch project templates:', error);
|
||||
}
|
||||
};
|
||||
|
||||
const deleteProjectTemplate = async (id: string) => {
|
||||
try {
|
||||
const res = await projectTemplatesApiService.deleteCustomTemplate(id);
|
||||
if (res.done) {
|
||||
fetchProjectTemplates();
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error('Failed to delete project template:', error);
|
||||
}
|
||||
};
|
||||
|
||||
const columns: TableProps<ICustomTemplate>['columns'] = [
|
||||
{
|
||||
key: 'name',
|
||||
title: t('nameColumn'),
|
||||
dataIndex: 'name',
|
||||
},
|
||||
{
|
||||
key: 'button',
|
||||
render: record => (
|
||||
<div
|
||||
style={{ display: 'flex', gap: '10px', justifyContent: 'right' }}
|
||||
className="button-visibilty"
|
||||
>
|
||||
<Tooltip title={t('editToolTip')}>
|
||||
<Button
|
||||
size="small"
|
||||
onClick={() =>
|
||||
navigate(`/worklenz/settings/project-templates/edit/${record.id}/${record.name}`)
|
||||
}
|
||||
>
|
||||
<EditOutlined />
|
||||
</Button>
|
||||
</Tooltip>
|
||||
<Tooltip title={t('deleteToolTip')}>
|
||||
<Popconfirm
|
||||
title={
|
||||
<Typography.Text style={{ fontWeight: 400 }}>{t('confirmText')}</Typography.Text>
|
||||
}
|
||||
okText={t('okText')}
|
||||
cancelText={t('cancelText')}
|
||||
onConfirm={() => deleteProjectTemplate(record.id)}
|
||||
>
|
||||
<Button size="small">
|
||||
<DeleteOutlined />
|
||||
</Button>
|
||||
</Popconfirm>
|
||||
</Tooltip>
|
||||
</div>
|
||||
),
|
||||
},
|
||||
];
|
||||
|
||||
useEffect(() => {
|
||||
fetchProjectTemplates();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<Card style={{ width: '100%' }}>
|
||||
<Table
|
||||
columns={columns}
|
||||
dataSource={projectTemplates}
|
||||
size="small"
|
||||
pagination={{ size: 'small' }}
|
||||
rowClassName={(_, index) =>
|
||||
`no-border-row ${index % 2 === 0 ? '' : themeMode === 'dark' ? 'dark-alternate-row-color' : 'alternate-row-color'}`
|
||||
}
|
||||
rowKey="id"
|
||||
/>
|
||||
</Card>
|
||||
);
|
||||
};
|
||||
|
||||
export default ProjectTemplatesSettings;
|
||||
@@ -0,0 +1,104 @@
|
||||
import { Button, Flex, Select, Typography } from 'antd';
|
||||
import { useState } from 'react';
|
||||
import StatusGroupTables from '../../../projects/project-view-1/taskList/statusTables/StatusGroupTables';
|
||||
import { TaskType } from '../../../../types/task.types';
|
||||
import { useAppSelector } from '../../../../hooks/useAppSelector';
|
||||
import { PageHeader } from '@ant-design/pro-components';
|
||||
import { ArrowLeftOutlined, CaretDownFilled } from '@ant-design/icons';
|
||||
import { useNavigate, useParams } from 'react-router-dom';
|
||||
import SearchDropdown from '../../../projects/project-view-1/taskList/taskListFilters/SearchDropdown';
|
||||
import { useSelectedProject } from '../../../../hooks/useSelectedProject';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { toggleDrawer as togglePhaseDrawer } from '../../../../features/projects/singleProject/phase/phases.slice';
|
||||
import { toggleDrawer } from '../../../../features/projects/status/StatusSlice';
|
||||
import { useAppDispatch } from '../../../../hooks/useAppDispatch';
|
||||
import React from 'react';
|
||||
|
||||
const PhaseDrawer = React.lazy(() => import('@features/projects/singleProject/phase/PhaseDrawer'));
|
||||
const StatusDrawer = React.lazy(
|
||||
() => import('@/components/project-task-filters/create-status-drawer/create-status-drawer')
|
||||
);
|
||||
|
||||
const ProjectTemplateEditView = () => {
|
||||
const dataSource: TaskType[] = useAppSelector(state => state.taskReducer.tasks);
|
||||
const dispatch = useAppDispatch();
|
||||
const navigate = useNavigate();
|
||||
const { templateId, templateName } = useParams();
|
||||
type GroupTypes = 'status' | 'priority' | 'phase';
|
||||
|
||||
const [activeGroup, setActiveGroup] = useState<GroupTypes>('status');
|
||||
|
||||
const handleChange = (value: string) => {
|
||||
setActiveGroup(value as GroupTypes);
|
||||
};
|
||||
|
||||
const { t } = useTranslation('task-list-filters');
|
||||
|
||||
// get selected project from useSelectedPro
|
||||
const selectedProject = useSelectedProject();
|
||||
|
||||
//get phases details from phases slice
|
||||
const phase =
|
||||
useAppSelector(state => state.phaseReducer.phaseList).find(
|
||||
phase => phase.projectId === selectedProject?.id
|
||||
) || null;
|
||||
|
||||
const groupDropdownMenuItems = [
|
||||
{ key: 'status', value: 'status', label: t('statusText') },
|
||||
{ key: 'priority', value: 'priority', label: t('priorityText') },
|
||||
{
|
||||
key: 'phase',
|
||||
value: 'phase',
|
||||
label: phase ? phase?.phase : t('phaseText'),
|
||||
},
|
||||
];
|
||||
return (
|
||||
<div style={{ marginBlock: 80, minHeight: '80vh' }}>
|
||||
<PageHeader
|
||||
className="site-page-header"
|
||||
title={
|
||||
<Flex gap={8} align="center">
|
||||
<ArrowLeftOutlined style={{ fontSize: 16 }} onClick={() => navigate(-1)} />
|
||||
<Typography.Title level={4} style={{ marginBlockEnd: 0, marginInlineStart: 12 }}>
|
||||
{templateName}
|
||||
</Typography.Title>
|
||||
</Flex>
|
||||
}
|
||||
style={{ padding: 0, marginBlockEnd: 24 }}
|
||||
/>
|
||||
<Flex vertical gap={16}>
|
||||
<Flex gap={8} wrap={'wrap'}>
|
||||
<SearchDropdown />
|
||||
<Flex align="center" gap={4} style={{ marginInlineStart: 12 }}>
|
||||
{t('groupByText')}:
|
||||
<Select
|
||||
defaultValue={'status'}
|
||||
options={groupDropdownMenuItems}
|
||||
onChange={handleChange}
|
||||
suffixIcon={<CaretDownFilled />}
|
||||
/>
|
||||
</Flex>
|
||||
{activeGroup === 'phase' ? (
|
||||
<Button type="primary" onClick={() => dispatch(togglePhaseDrawer())}>
|
||||
{t('addPhaseButton')}
|
||||
</Button>
|
||||
) : activeGroup === 'status' ? (
|
||||
<Button type="primary" onClick={() => dispatch(toggleDrawer())}>
|
||||
{t('addStatusButton')}
|
||||
</Button>
|
||||
) : (
|
||||
''
|
||||
)}
|
||||
</Flex>
|
||||
|
||||
<StatusGroupTables datasource={dataSource} />
|
||||
{/* <PriorityGroupTables datasource={dataSource} /> */}
|
||||
</Flex>
|
||||
{/* phase drawer */}
|
||||
<PhaseDrawer />
|
||||
{/* status drawer */}
|
||||
<StatusDrawer />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
export default ProjectTemplateEditView;
|
||||
Reference in New Issue
Block a user