mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-18 13:50:31 +00:00
feat: add project timesheet.
This commit is contained in:
@@ -1,3 +1,4 @@
|
|||||||
|
// @ts-nocheck
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import {
|
import {
|
||||||
Button,
|
Button,
|
||||||
@@ -15,7 +16,7 @@ import {
|
|||||||
import withSettings from '../../../Settings/withSettings';
|
import withSettings from '../../../Settings/withSettings';
|
||||||
import withSettingsActions from '../../../Settings/withSettingsActions';
|
import withSettingsActions from '../../../Settings/withSettingsActions';
|
||||||
import withDialogActions from 'containers/Dialog/withDialogActions';
|
import withDialogActions from 'containers/Dialog/withDialogActions';
|
||||||
|
import { useProjectDetailContext } from './ProjectDetailProvider';
|
||||||
import { compose } from 'utils';
|
import { compose } from 'utils';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -32,16 +33,25 @@ function ProjectDetailActionsBar({
|
|||||||
// #withSettingsActions
|
// #withSettingsActions
|
||||||
addSetting,
|
addSetting,
|
||||||
}) {
|
}) {
|
||||||
|
const { projectId } = useProjectDetailContext();
|
||||||
|
|
||||||
// Handle new transaction button click.
|
// Handle new transaction button click.
|
||||||
const handleNewTransactionBtnClick = () => {};
|
const handleNewTransactionBtnClick = () => {};
|
||||||
|
|
||||||
|
const handleEditProjectBtnClick = () => {
|
||||||
|
openDialog('project-form', {
|
||||||
|
projectId,
|
||||||
|
});
|
||||||
|
};
|
||||||
// Handle table row size change.
|
// Handle table row size change.
|
||||||
const handleTableRowSizeChange = (size) => {
|
const handleTableRowSizeChange = (size) => {
|
||||||
addSetting('timesheets', 'tableSize', size);
|
addSetting('timesheets', 'tableSize', size);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleTimeEntryBtnClick = () => {
|
const handleTimeEntryBtnClick = () => {
|
||||||
openDialog('time-entry-form');
|
openDialog('time-entry-form', {
|
||||||
|
projectId,
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
// Handle the refresh button click.
|
// Handle the refresh button click.
|
||||||
@@ -58,14 +68,15 @@ function ProjectDetailActionsBar({
|
|||||||
/>
|
/>
|
||||||
<Button
|
<Button
|
||||||
className={Classes.MINIMAL}
|
className={Classes.MINIMAL}
|
||||||
text={<T id={'projcet_details.action.log_time'} />}
|
icon={<Icon icon={'time-24'} iconSize={16} />}
|
||||||
|
text={<T id={'projcet_details.action.time_entry'} />}
|
||||||
onClick={handleTimeEntryBtnClick}
|
onClick={handleTimeEntryBtnClick}
|
||||||
/>
|
/>
|
||||||
<Button
|
<Button
|
||||||
className={Classes.MINIMAL}
|
className={Classes.MINIMAL}
|
||||||
icon={<Icon icon="pen-18" />}
|
icon={<Icon icon="pen-18" />}
|
||||||
text={<T id={'projcet_details.action.edit_project'} />}
|
text={<T id={'projcet_details.action.edit_project'} />}
|
||||||
// onClick={}
|
onClick={handleEditProjectBtnClick}
|
||||||
/>
|
/>
|
||||||
<NavbarDivider />
|
<NavbarDivider />
|
||||||
<Button
|
<Button
|
||||||
|
|||||||
@@ -9,11 +9,14 @@ const ProjectDetailContext = React.createContext();
|
|||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
function ProjectDetailProvider({
|
function ProjectDetailProvider({
|
||||||
|
projectId,
|
||||||
// #ownProps
|
// #ownProps
|
||||||
...props
|
...props
|
||||||
}) {
|
}) {
|
||||||
// State provider.
|
// State provider.
|
||||||
const provider = {};
|
const provider = {
|
||||||
|
projectId,
|
||||||
|
};
|
||||||
return (
|
return (
|
||||||
<DashboardInsider class="timesheets">
|
<DashboardInsider class="timesheets">
|
||||||
<ProjectDetailContext.Provider value={provider} {...props} />
|
<ProjectDetailContext.Provider value={provider} {...props} />
|
||||||
|
|||||||
@@ -2,7 +2,8 @@ import React from 'react';
|
|||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
import intl from 'react-intl-universal';
|
import intl from 'react-intl-universal';
|
||||||
import { Tabs, Tab } from '@blueprintjs/core';
|
import { Tabs, Tab } from '@blueprintjs/core';
|
||||||
import TimesheetDataTable from './TimesheetDataTable';
|
|
||||||
|
import ProjectTimesheet from './ProjectTimesheet';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Project detail tabs.
|
* Project detail tabs.
|
||||||
@@ -21,7 +22,7 @@ export default function ProjectDetailTabs() {
|
|||||||
<Tab
|
<Tab
|
||||||
id="timesheet"
|
id="timesheet"
|
||||||
title={intl.get('project_details.label.timesheet')}
|
title={intl.get('project_details.label.timesheet')}
|
||||||
panel={<TimesheetDataTable />}
|
panel={<ProjectTimesheet />}
|
||||||
/>
|
/>
|
||||||
<Tab
|
<Tab
|
||||||
id="purchases"
|
id="purchases"
|
||||||
@@ -58,11 +59,9 @@ const ProjectTabsContent = styled.div`
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
.bp3-tab-panel {
|
.bp3-tab-panel {
|
||||||
border: 2px solid #f0f0f0;
|
margin-top: 20px;
|
||||||
border-radius: 10px;
|
margin-bottom: 20px;
|
||||||
padding: 30px 18px;
|
padding: 0 25px;
|
||||||
margin: 30px 15px;
|
|
||||||
background: #fff;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|||||||
@@ -0,0 +1,125 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import intl from 'react-intl-universal';
|
||||||
|
import styled from 'styled-components';
|
||||||
|
|
||||||
|
import { Intent, ProgressBar } from '@blueprintjs/core';
|
||||||
|
import { FormatDate } from 'components';
|
||||||
|
|
||||||
|
import { calculateStatus } from 'utils';
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Project Financial Section.
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export default function ProjectFinancialSection() {
|
||||||
|
return (
|
||||||
|
<ProjectFinancialSectionRoot>
|
||||||
|
<FinancialSectionCard>
|
||||||
|
<FinancialSectionContent>
|
||||||
|
<FinancialSectionTitle>Project estimate</FinancialSectionTitle>
|
||||||
|
<FinancialSectionValue>3.14</FinancialSectionValue>
|
||||||
|
</FinancialSectionContent>
|
||||||
|
</FinancialSectionCard>
|
||||||
|
|
||||||
|
<FinancialSectionCard>
|
||||||
|
<FinancialSectionContent>
|
||||||
|
<FinancialSectionTitle>Invoiced</FinancialSectionTitle>
|
||||||
|
<FinancialSectionValue>0.00</FinancialSectionValue>
|
||||||
|
<FinancialSectionStatus>
|
||||||
|
<FinancialSectionText>0% of project estimate</FinancialSectionText>
|
||||||
|
<FinancialSectionProgressBar
|
||||||
|
animate={false}
|
||||||
|
intent={Intent.NONE}
|
||||||
|
value={0}
|
||||||
|
/>
|
||||||
|
</FinancialSectionStatus>
|
||||||
|
</FinancialSectionContent>
|
||||||
|
</FinancialSectionCard>
|
||||||
|
|
||||||
|
<FinancialSectionCard>
|
||||||
|
<FinancialSectionContent>
|
||||||
|
<FinancialSectionTitle>Time & Expenses</FinancialSectionTitle>
|
||||||
|
<FinancialSectionValue>0.00</FinancialSectionValue>
|
||||||
|
<FinancialSectionStatus>
|
||||||
|
<FinancialSectionText>0% of project estimate</FinancialSectionText>
|
||||||
|
<FinancialSectionProgressBar
|
||||||
|
animate={false}
|
||||||
|
intent={Intent.NONE}
|
||||||
|
value={0}
|
||||||
|
/>
|
||||||
|
</FinancialSectionStatus>
|
||||||
|
</FinancialSectionContent>
|
||||||
|
</FinancialSectionCard>
|
||||||
|
|
||||||
|
<FinancialSectionCard>
|
||||||
|
<FinancialSectionContent>
|
||||||
|
<FinancialSectionTitle>To be invoiced</FinancialSectionTitle>
|
||||||
|
<FinancialSectionValue>3.14</FinancialSectionValue>
|
||||||
|
</FinancialSectionContent>
|
||||||
|
</FinancialSectionCard>
|
||||||
|
|
||||||
|
<FinancialSectionCard>
|
||||||
|
<FinancialSectionContent>
|
||||||
|
<FinancialSectionTitle>Deadline</FinancialSectionTitle>
|
||||||
|
<FinancialSectionValue>
|
||||||
|
<FormatDate value={'2022-06-08T22:00:00.000Z'} />
|
||||||
|
</FinancialSectionValue>
|
||||||
|
<FinancialSectionText>4 days to go</FinancialSectionText>
|
||||||
|
</FinancialSectionContent>
|
||||||
|
</FinancialSectionCard>
|
||||||
|
</ProjectFinancialSectionRoot>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export const ProjectFinancialSectionRoot = styled.div`
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
margin: 20px 20px 20px;
|
||||||
|
gap: 10px;
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const FinancialSectionCard = styled.div`
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
flex-shrink: 0;
|
||||||
|
border-radius: 3px;
|
||||||
|
width: 220px;
|
||||||
|
height: 116px;
|
||||||
|
background-color: #fff;
|
||||||
|
border: 1px solid #c8cad0; // #000a1e33 #f0f0f0
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const FinancialSectionContent = styled.div`
|
||||||
|
margin: 16px;
|
||||||
|
/* flex-direction: column; */
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const FinancialSectionTitle = styled.div`
|
||||||
|
font-size: 15px;
|
||||||
|
color: #000;
|
||||||
|
white-space: nowrap;
|
||||||
|
font-weight: 400;
|
||||||
|
line-height: 1.5rem;
|
||||||
|
`;
|
||||||
|
export const FinancialSectionValue = styled.div`
|
||||||
|
font-size: 21px;
|
||||||
|
line-height: 2rem;
|
||||||
|
font-weight: 700;
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const FinancialSectionStatus = styled.div``;
|
||||||
|
|
||||||
|
export const FinancialSectionText = styled.div`
|
||||||
|
font-size: 13px;
|
||||||
|
line-height: 1.5rem;
|
||||||
|
`;
|
||||||
|
export const FinancialSectionProgressBar = styled(ProgressBar)`
|
||||||
|
&.bp3-progress-bar {
|
||||||
|
height: 3px;
|
||||||
|
&,
|
||||||
|
.bp3-progress-meter {
|
||||||
|
border-radius: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
@@ -0,0 +1,124 @@
|
|||||||
|
// @ts-nocheck
|
||||||
|
import React from 'react';
|
||||||
|
import styled from 'styled-components';
|
||||||
|
import { DataTable } from 'components';
|
||||||
|
import TableSkeletonRows from 'components/Datatable/TableSkeletonRows';
|
||||||
|
import TableSkeletonHeader from 'components/Datatable/TableHeaderSkeleton';
|
||||||
|
import { useTimesheetColumns, ActionsMenu } from './components';
|
||||||
|
import { TABLES } from 'common/tables';
|
||||||
|
import { useMemorizedColumnsWidths } from 'hooks';
|
||||||
|
import withSettings from '../../../../Settings/withSettings';
|
||||||
|
|
||||||
|
import { compose } from 'utils';
|
||||||
|
|
||||||
|
const Timesheet = [
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
date: '2022-06-08T22:00:00.000Z',
|
||||||
|
name: 'Lighting',
|
||||||
|
display_name: 'Kyrie Rearden',
|
||||||
|
description: 'Laid paving stones',
|
||||||
|
duration: '12:00',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 2,
|
||||||
|
date: '2022-06-08T22:00:00.000Z',
|
||||||
|
name: 'Interior Decoration',
|
||||||
|
display_name: 'Project Sherwood',
|
||||||
|
description: 'Laid paving stones',
|
||||||
|
duration: '11:00',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Timesheet DataTable.
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
function TimesheetsTable({
|
||||||
|
// #withSettings
|
||||||
|
timesheetsTableSize,
|
||||||
|
}) {
|
||||||
|
// Retrieve timesheet table columns.
|
||||||
|
const columns = useTimesheetColumns();
|
||||||
|
|
||||||
|
// Handle delete timesheet.
|
||||||
|
const handleDeleteTimesheet = () => {};
|
||||||
|
|
||||||
|
// Local storage memorizing columns widths.
|
||||||
|
const [initialColumnsWidths, , handleColumnResizing] =
|
||||||
|
useMemorizedColumnsWidths(TABLES.TIMESHEETS);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<TimesheetDataTable
|
||||||
|
columns={columns}
|
||||||
|
data={Timesheet}
|
||||||
|
// loading={}
|
||||||
|
// headerLoading={}
|
||||||
|
// progressBarLoading={}
|
||||||
|
manualSortBy={true}
|
||||||
|
noInitialFetch={true}
|
||||||
|
sticky={true}
|
||||||
|
hideTableHeader={true}
|
||||||
|
ContextMenu={ActionsMenu}
|
||||||
|
TableLoadingRenderer={TableSkeletonRows}
|
||||||
|
TableHeaderSkeletonRenderer={TableSkeletonHeader}
|
||||||
|
initialColumnsWidths={initialColumnsWidths}
|
||||||
|
onColumnResizing={handleColumnResizing}
|
||||||
|
size={timesheetsTableSize}
|
||||||
|
payload={{
|
||||||
|
onDelete: handleDeleteTimesheet,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
export default compose(
|
||||||
|
withSettings(({ timesheetsSettings }) => ({
|
||||||
|
timesheetsTableSize: timesheetsSettings?.tableSize,
|
||||||
|
})),
|
||||||
|
)(TimesheetsTable);
|
||||||
|
|
||||||
|
const TimesheetDataTable = styled(DataTable)`
|
||||||
|
.table {
|
||||||
|
.thead .tr .th {
|
||||||
|
.resizer {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.tbody {
|
||||||
|
.tr .td {
|
||||||
|
padding: 0.5rem 0.8rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.avatar.td {
|
||||||
|
.avatar {
|
||||||
|
display: inline-block;
|
||||||
|
background: #adbcc9;
|
||||||
|
border-radius: 50%;
|
||||||
|
text-align: center;
|
||||||
|
font-weight: 400;
|
||||||
|
color: #fff;
|
||||||
|
|
||||||
|
&[data-size='medium'] {
|
||||||
|
height: 30px;
|
||||||
|
width: 30px;
|
||||||
|
line-height: 30px;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
&[data-size='small'] {
|
||||||
|
height: 25px;
|
||||||
|
width: 25px;
|
||||||
|
line-height: 25px;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-size--small {
|
||||||
|
.tbody .tr {
|
||||||
|
height: 45px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
@@ -0,0 +1,120 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import intl from 'react-intl-universal';
|
||||||
|
import styled from 'styled-components';
|
||||||
|
import { FormatDate, Icon, FormattedMessage as T } from 'components';
|
||||||
|
import { Menu, MenuItem, Intent } from '@blueprintjs/core';
|
||||||
|
import { safeCallback, firstLettersArgs } from 'utils';
|
||||||
|
import { chain } from 'lodash';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Table actions cell.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export function ActionsMenu({
|
||||||
|
payload: { onDelete, onViewDetails },
|
||||||
|
row: { original },
|
||||||
|
}) {
|
||||||
|
return (
|
||||||
|
<Menu>
|
||||||
|
<MenuItem
|
||||||
|
text={intl.get('timesheets.actions.delete_timesheet')}
|
||||||
|
intent={Intent.DANGER}
|
||||||
|
onClick={safeCallback(onDelete, original)}
|
||||||
|
icon={<Icon icon="trash-16" iconSize={16} />}
|
||||||
|
/>
|
||||||
|
</Menu>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Avatar cell.
|
||||||
|
*/
|
||||||
|
export const AvatarCell = ({ row: { original }, size }) => (
|
||||||
|
<span className="avatar" data-size={size}>
|
||||||
|
{firstLettersArgs(original?.display_name, original?.name)}
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Timesheet accessor.
|
||||||
|
*/
|
||||||
|
export const TimesheetAccessor = (timesheet) => (
|
||||||
|
<React.Fragment>
|
||||||
|
<TimesheetHeader>
|
||||||
|
<TimesheetTitle>{timesheet.display_name}</TimesheetTitle>
|
||||||
|
<TimesheetSubTitle>{timesheet.name}</TimesheetSubTitle>
|
||||||
|
</TimesheetHeader>
|
||||||
|
<TimesheetContent>
|
||||||
|
<FormatDate value={timesheet.date} />
|
||||||
|
<TimesheetDescription>{timesheet.description}</TimesheetDescription>
|
||||||
|
</TimesheetContent>
|
||||||
|
</React.Fragment>
|
||||||
|
);
|
||||||
|
|
||||||
|
const TimesheetHeader = styled.div`
|
||||||
|
display: flex;
|
||||||
|
align-items: baseline;
|
||||||
|
flex-flow: wrap;
|
||||||
|
`;
|
||||||
|
const TimesheetTitle = styled.span`
|
||||||
|
font-weight: 500;
|
||||||
|
margin-right: 12px;
|
||||||
|
line-height: 1.5rem;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const TimesheetSubTitle = styled.span``;
|
||||||
|
const TimesheetContent = styled.div`
|
||||||
|
display: block;
|
||||||
|
white-space: nowrap;
|
||||||
|
font-size: 13px;
|
||||||
|
opacity: 0.75;
|
||||||
|
margin-bottom: 0.1rem;
|
||||||
|
line-height: 1.2rem;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const TimesheetDescription = styled.span`
|
||||||
|
&::before {
|
||||||
|
content: '•';
|
||||||
|
margin: 0.3rem;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve timesheet list columns columns.
|
||||||
|
*/
|
||||||
|
export function useTimesheetColumns() {
|
||||||
|
return React.useMemo(
|
||||||
|
() => [
|
||||||
|
{
|
||||||
|
id: 'avatar',
|
||||||
|
Header: '',
|
||||||
|
Cell: AvatarCell,
|
||||||
|
className: 'avatar',
|
||||||
|
width: 45,
|
||||||
|
disableResizing: true,
|
||||||
|
disableSortBy: true,
|
||||||
|
clickable: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'name',
|
||||||
|
Header: 'Header',
|
||||||
|
accessor: TimesheetAccessor,
|
||||||
|
width: 100,
|
||||||
|
className: 'name',
|
||||||
|
clickable: true,
|
||||||
|
textOverview: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'duration',
|
||||||
|
Header: '',
|
||||||
|
accessor: 'duration',
|
||||||
|
width: 100,
|
||||||
|
className: 'duration',
|
||||||
|
align: 'right',
|
||||||
|
clickable: true,
|
||||||
|
textOverview: true,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
[],
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import styled from 'styled-components';
|
||||||
|
|
||||||
|
import TimesheetsTable from './TimesheetsTable';
|
||||||
|
import ProjectFinancialSection from '../ProjectFinancialSection';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Project Timesheet.
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export default function ProjectTimesheet() {
|
||||||
|
return (
|
||||||
|
<React.Fragment>
|
||||||
|
<ProjectFinancialSection />
|
||||||
|
|
||||||
|
<ProjectTimesheetTableCard>
|
||||||
|
<TimesheetsTable />
|
||||||
|
</ProjectTimesheetTableCard>
|
||||||
|
</React.Fragment>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const ProjectTimesheetTableCard = styled.div`
|
||||||
|
margin: 20px;
|
||||||
|
border: 1px solid #c8cad0; // #000a1e33 #f0f0f0
|
||||||
|
border-radius: 3px;
|
||||||
|
background: #fff;
|
||||||
|
`;
|
||||||
@@ -1,83 +0,0 @@
|
|||||||
import React from 'react';
|
|
||||||
import intl from 'react-intl-universal';
|
|
||||||
import { FormatDateCell, Icon } from 'components';
|
|
||||||
import { Menu, MenuDivider, MenuItem, Intent } from '@blueprintjs/core';
|
|
||||||
import { safeCallback } from 'utils';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Table actions cell.
|
|
||||||
*/
|
|
||||||
|
|
||||||
export function ActionsMenu({
|
|
||||||
payload: { onDelete, onViewDetails },
|
|
||||||
row: { original },
|
|
||||||
}) {
|
|
||||||
return (
|
|
||||||
<Menu>
|
|
||||||
<MenuItem
|
|
||||||
text={'Delete'}
|
|
||||||
intent={Intent.DANGER}
|
|
||||||
onClick={safeCallback(onDelete, original)}
|
|
||||||
icon={<Icon icon="trash-16" iconSize={16} />}
|
|
||||||
/>
|
|
||||||
</Menu>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieve timesheet list columns columns.
|
|
||||||
*/
|
|
||||||
export function useTimesheetColumns() {
|
|
||||||
return React.useMemo(
|
|
||||||
() => [
|
|
||||||
{
|
|
||||||
id: 'date',
|
|
||||||
Header: intl.get('timesheets.column.date'),
|
|
||||||
accessor: 'date',
|
|
||||||
Cell: FormatDateCell,
|
|
||||||
width: 100,
|
|
||||||
className: 'date',
|
|
||||||
clickable: true,
|
|
||||||
textOverview: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'task',
|
|
||||||
Header: intl.get('timesheets.column.task'),
|
|
||||||
accessor: 'task',
|
|
||||||
width: 100,
|
|
||||||
className: 'task',
|
|
||||||
clickable: true,
|
|
||||||
textOverview: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'user',
|
|
||||||
Header: intl.get('timesheets.column.user'),
|
|
||||||
accessor: 'user',
|
|
||||||
width: 100,
|
|
||||||
className: 'user',
|
|
||||||
clickable: true,
|
|
||||||
textOverview: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'time',
|
|
||||||
Header: intl.get('timesheets.column.time'),
|
|
||||||
accessor: 'time',
|
|
||||||
width: 100,
|
|
||||||
className: 'user',
|
|
||||||
align: 'right',
|
|
||||||
clickable: true,
|
|
||||||
textOverview: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'billingStatus',
|
|
||||||
Header: intl.get('timesheets.column.billing_status'),
|
|
||||||
accessor: 'billing_status',
|
|
||||||
width: 140,
|
|
||||||
className: 'billingStatus',
|
|
||||||
clickable: true,
|
|
||||||
textOverview: true,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
[],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,89 +0,0 @@
|
|||||||
// @ts-nocheck
|
|
||||||
import React from 'react';
|
|
||||||
import styled from 'styled-components';
|
|
||||||
import { DataTable, TableFastCell } from 'components';
|
|
||||||
import TableVirtualizedListRows from 'components/Datatable/TableVirtualizedRows';
|
|
||||||
import TableSkeletonRows from 'components/Datatable/TableSkeletonRows';
|
|
||||||
import TableSkeletonHeader from 'components/Datatable/TableHeaderSkeleton';
|
|
||||||
import { useTimesheetColumns, ActionsMenu } from './components';
|
|
||||||
import { TableStyle } from '../../../../../common';
|
|
||||||
import withSettings from '../../../../Settings/withSettings';
|
|
||||||
|
|
||||||
import { compose } from 'utils';
|
|
||||||
|
|
||||||
const Timesheet = [
|
|
||||||
{
|
|
||||||
id: 1,
|
|
||||||
data: '2020-01-01',
|
|
||||||
task: 'Task 1',
|
|
||||||
user: 'User 1',
|
|
||||||
time: '12:00Am',
|
|
||||||
billingStatus: '',
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Timesheet DataTable.
|
|
||||||
* @returns
|
|
||||||
*/
|
|
||||||
function TimesheetDataTable({
|
|
||||||
// #withSettings
|
|
||||||
timesheetsTableSize,
|
|
||||||
}) {
|
|
||||||
// Retrieve timesheet table columns.
|
|
||||||
const columns = useTimesheetColumns();
|
|
||||||
|
|
||||||
// Handle delete timesheet.
|
|
||||||
const handleDeleteTimesheet = () => {};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<TimesheetsTable
|
|
||||||
columns={columns}
|
|
||||||
data={Timesheet}
|
|
||||||
// loading={}
|
|
||||||
// headerLoading={}
|
|
||||||
noInitialFetch={true}
|
|
||||||
sticky={true}
|
|
||||||
expandColumnSpace={1}
|
|
||||||
expandToggleColumn={2}
|
|
||||||
selectionColumnWidth={45}
|
|
||||||
ContextMenu={ActionsMenu}
|
|
||||||
TableCellRenderer={TableFastCell}
|
|
||||||
TableLoadingRenderer={TableSkeletonRows}
|
|
||||||
TableRowsRenderer={TableVirtualizedListRows}
|
|
||||||
TableHeaderSkeletonRenderer={TableSkeletonHeader}
|
|
||||||
vListrowHeight={timesheetsTableSize === 'small' ? 32 : 40}
|
|
||||||
vListOverscanRowCount={0}
|
|
||||||
styleName={TableStyle.Constrant}
|
|
||||||
payload={{
|
|
||||||
onDelete: handleDeleteTimesheet,
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default compose(
|
|
||||||
withSettings(({ timesheetsSettings }) => ({
|
|
||||||
timesheetsTableSize: timesheetsSettings?.tableSize,
|
|
||||||
})),
|
|
||||||
)(TimesheetDataTable);
|
|
||||||
|
|
||||||
const TimesheetsTable = styled(DataTable)`
|
|
||||||
.table .tbody {
|
|
||||||
.tbody-inner .tr.no-results {
|
|
||||||
.td {
|
|
||||||
padding: 2rem 0;
|
|
||||||
font-size: 14px;
|
|
||||||
color: #888;
|
|
||||||
font-weight: 400;
|
|
||||||
border-bottom: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.tbody-inner {
|
|
||||||
.tr .td:not(:first-child) {
|
|
||||||
border-left: 1px solid #e6e6e6;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
@@ -17,15 +17,15 @@ function ProjectTabs({
|
|||||||
changePageTitle,
|
changePageTitle,
|
||||||
}) {
|
}) {
|
||||||
const {
|
const {
|
||||||
state: { name },
|
state: { projectName, projectId },
|
||||||
} = useLocation();
|
} = useLocation();
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
changePageTitle(name);
|
changePageTitle(projectName);
|
||||||
}, [changePageTitle, name]);
|
}, [changePageTitle, projectName]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ProjectDetailProvider>
|
<ProjectDetailProvider projectId={projectId}>
|
||||||
<ProjectDetailActionsBar />
|
<ProjectDetailActionsBar />
|
||||||
<DashboardPageContent>
|
<DashboardPageContent>
|
||||||
<ProjectDetailTabs />
|
<ProjectDetailTabs />
|
||||||
|
|||||||
Reference in New Issue
Block a user