feat: add timesheet & project details.

This commit is contained in:
elforjani13
2022-06-13 17:33:54 +02:00
parent 629c790430
commit 051681e6f3
11 changed files with 455 additions and 3 deletions

View File

@@ -0,0 +1,99 @@
import React from 'react';
import {
Button,
Classes,
NavbarDivider,
NavbarGroup,
Alignment,
} from '@blueprintjs/core';
import DashboardActionsBar from 'components/Dashboard/DashboardActionsBar';
import {
Icon,
FormattedMessage as T,
DashboardRowsHeightButton,
} from 'components';
import withSettings from '../../../Settings/withSettings';
import withSettingsActions from '../../../Settings/withSettingsActions';
import { compose } from 'utils';
/**
* Project detail actions bar.
* @returns
*/
function ProjectDetailActionsBar({
// #withSettings
timeSheetsTableSize,
// #withSettingsActions
addSetting,
}) {
// Handle new transaction button click.
const handleNewTransactionBtnClick = () => {};
// Handle table row size change.
const handleTableRowSizeChange = (size) => {
addSetting('timeSheets', 'tableSize', size);
};
// Handle the refresh button click.
const handleRefreshBtnClick = () => {};
return (
<DashboardActionsBar>
<NavbarGroup>
<Button
className={Classes.MINIMAL}
text={<T id={'projcet_details.action.new_transaction'} />}
onClick={handleNewTransactionBtnClick}
/>
<Button
className={Classes.MINIMAL}
text={<T id={'projcet_details.action.log_time'} />}
// onClick={}
/>
<Button
className={Classes.MINIMAL}
text={<T id={'projcet_details.action.edit_project'} />}
// onClick={}
/>
<NavbarDivider />
<Button
className={Classes.MINIMAL}
icon={<Icon icon={'print-16'} iconSize={'16'} />}
text={<T id={'print'} />}
/>
<Button
className={Classes.MINIMAL}
icon={<Icon icon={'file-import-16'} />}
text={<T id={'import'} />}
/>
<Button
className={Classes.MINIMAL}
icon={<Icon icon={'file-export-16'} iconSize={'16'} />}
text={<T id={'export'} />}
/>
<NavbarDivider />
<DashboardRowsHeightButton
initialValue={timeSheetsTableSize}
onChange={handleTableRowSizeChange}
/>
<NavbarDivider />
<Button icon={<Icon icon="more-vert" iconSize={16} />} minimal={true} />
</NavbarGroup>
<NavbarGroup align={Alignment.RIGHT}>
<Button
className={Classes.MINIMAL}
icon={<Icon icon="refresh-16" iconSize={14} />}
onClick={handleRefreshBtnClick}
/>
</NavbarGroup>
</DashboardActionsBar>
);
}
export default compose(
withSettingsActions,
withSettings(({ timeSheetsSettings }) => ({
timeSheetsTableSize: timeSheetsSettings?.tableSize,
})),
)(ProjectDetailActionsBar);

View File

@@ -0,0 +1,25 @@
// @ts-nocheck
import React from 'react';
const ProjectDetailContext = React.createContext();
/**
* Project detail provider.
* @returns
*/
function ProjectDetailProvider({
// #ownProps
...props
}) {
// State provider.
const provider = {};
return (
<React.Fragment>
<ProjectDetailContext.Provider value={provider} {...props} />
</React.Fragment>
);
}
const useProjectDetailContext = () => React.useContext(ProjectDetailContext);
export { ProjectDetailProvider, useProjectDetailContext };

View File

@@ -0,0 +1,65 @@
import React from 'react';
import styled from 'styled-components';
import intl from 'react-intl-universal';
import { Tabs, Tab } from '@blueprintjs/core';
import TimeSheetDataTable from './TimeSheet/TimeSheetDataTable';
/**
* Project detail tabs.
* @returns
*/
export default function ProjectDetailTabs() {
return (
<ProjectTabsContent>
<Tabs
animate={true}
large={true}
renderActiveTabPanelOnly={true}
defaultSelectedTabId={'overview'}
>
<Tab id="overview" title={intl.get('project_details.label.overview')} />
<Tab
id="timesheet"
title={intl.get('project_details.label.timesheet')}
panel={<TimeSheetDataTable />}
/>
<Tab
id="purchases"
title={intl.get('project_details.label.purchases')}
/>
<Tab id="sales" title={intl.get('project_details.label.sales')} />
<Tab id="journals" title={intl.get('project_details.label.journals')} />
</Tabs>
</ProjectTabsContent>
);
}
const ProjectTabsContent = styled.div`
.bp3-tabs {
.bp3-tab-list {
position: relative;
background-color: #fff;
padding: 0 20px;
border-bottom: 1px solid #d2dce2;
&.bp3-large > .bp3-tab {
font-size: 14px;
font-weight: 400;
color: #646a7d;
margin: 0 1rem;
&[aria-selected='true'],
&:not([aria-disabled='true']):hover {
color: #0052cc;
}
}
.bp3-tab-indicator-wrapper .bp3-tab-indicator {
height: 2px;
bottom: -2px;
}
}
.bp3-tab-panel {
margin-top: 0;
}
}
`;

View File

@@ -0,0 +1,117 @@
// @ts-nocheck
import React from 'react';
import styled from 'styled-components';
import { DataTable, TableFastCell, DashboardContentTable } from 'components';
import TableVirtualizedListRows from 'components/Datatable/TableVirtualizedRows';
import TableSkeletonRows from 'components/Datatable/TableSkeletonRows';
import TableSkeletonHeader from 'components/Datatable/TableHeaderSkeleton';
import { useTimeSheetColumns, ActionMenu } 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: '',
},
{
id: 2,
data: '2021-01-01',
task: 'Task 2',
user: 'User 2',
time: '12:00Am',
billingStatus: '',
},
{
id: 3,
data: '2022-01-01',
task: 'Task 3',
user: 'User 3',
time: '12:00Am',
billingStatus: '',
},
];
/**
* TimeSheet DataTable.
* @returns
*/
function TimeSheetDataTable({
// #withSettings
timeSheetsTableSize,
}) {
// Retrieve timesheet table columns.
const columns = useTimeSheetColumns();
return (
<DashboardContentTable>
<TimeSheetsTable
columns={columns}
data={TimeSheet}
// loading={}
// headerLoading={}
noInitialFetch={true}
sticky={true}
expandColumnSpace={1}
expandToggleColumn={2}
selectionColumnWidth={45}
TableCellRenderer={TableFastCell}
TableLoadingRenderer={TableSkeletonRows}
TableRowsRenderer={TableVirtualizedListRows}
TableHeaderSkeletonRenderer={TableSkeletonHeader}
vListrowHeight={timeSheetsTableSize === 'small' ? 32 : 40}
vListOverscanRowCount={0}
styleName={TableStyle.Constrant}
// payload={{}}
/>
</DashboardContentTable>
);
}
export default compose(
withSettings(({ timeSheetsSettings }) => ({
timeSheetsTableSize: timeSheetsSettings?.tableSize,
})),
)(TimeSheetDataTable);
const DashboardConstrantTable = styled(DataTable)`
.table {
.thead {
.th {
background: #fff;
}
}
.tbody {
.tr:last-child .td {
border-bottom: 0;
}
}
}
`;
const TimeSheetsTable = styled(DashboardConstrantTable)`
.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;
}
}
}
`;

View File

@@ -0,0 +1,67 @@
import React from 'react';
import intl from 'react-intl-universal';
import { FormatDateCell } from 'components';
import { Menu, MenuDivider, MenuItem, Intent } from '@blueprintjs/core';
/**
* Table actions cell.
*/
export const ActionMenu = ({ row: { original }, payload: {} }) => <Menu></Menu>;
/**
* Retrieve timesheet list columns columns.
*/
export const useTimeSheetColumns = () => {
return React.useMemo(
() => [
{
id: 'date',
Header: intl.get('timesheets.column.date'),
accessor: 'date',
Cell: FormatDateCell,
width: 115,
className: 'date',
clickable: true,
textOverview: true,
},
{
id: 'task',
Header: intl.get('timesheets.column.task'),
accessor: 'task',
width: 115,
className: 'task',
clickable: true,
textOverview: true,
},
{
id: 'user',
Header: intl.get('timesheets.column.user'),
accessor: 'user',
width: 115,
className: 'user',
clickable: true,
textOverview: true,
},
{
id: 'time',
Header: intl.get('timesheets.column.time'),
accessor: 'time',
width: 115,
className: 'user',
align: 'right',
clickable: true,
textOverview: true,
},
{
id: 'billingStatus',
Header: intl.get('timesheets.column.billing_status'),
accessor: 'billing_status',
width: 160,
className: 'billingStatus',
clickable: true,
textOverview: true,
},
],
[],
);
};

View File

@@ -0,0 +1,37 @@
//@ts-nocheck
import React from 'react';
import { useLocation } from 'react-router-dom';
import ProjectDetailActionsBar from './ProjectDetailActionsBar';
import ProjectDetailTabs from './ProjectDetailTabs';
import { DashboardPageContent } from 'components';
import { ProjectDetailProvider } from './ProjectDetailProvider';
import withDashboardActions from 'containers/Dashboard/withDashboardActions';
import { compose } from 'utils';
/**
* Project tabs.
* @returns
*/
function ProjectTabs({
// #withDashboardActions
changePageTitle,
}) {
const {
state: { original },
} = useLocation();
React.useEffect(() => {
changePageTitle(original.name);
}, [changePageTitle, original]);
return (
<ProjectDetailProvider>
<ProjectDetailActionsBar />
<DashboardPageContent>
<ProjectDetailTabs />
</DashboardPageContent>
</ProjectDetailProvider>
);
}
export default compose(withDashboardActions)(ProjectTabs);

View File

@@ -1,4 +1,5 @@
import React from 'react';
import { useHistory } from 'react-router-dom';
import { DataTable } from 'components';
import { TABLES } from 'common/tables';
import TableSkeletonRows from 'components/Datatable/TableSkeletonRows';
@@ -44,11 +45,17 @@ function ProjectsDataTable({
// #withSettings
projectsTableSize,
}) {
const history = useHistory();
// Retrieve projects table columns.
const columns = useProjectsListColumns();
// Handle cell click.
const handleCellClick = (cell, event) => {};
const handleCellClick = ({ row: { original } }) => {
return history.push(`/projects/${original?.id}/details`, {
original,
});
};
// Handle edit project.
const handleEditProject = (project) => {
@@ -66,6 +73,13 @@ function ProjectsDataTable({
const [initialColumnsWidths, , handleColumnResizing] =
useMemorizedColumnsWidths(TABLES.PROJECTS);
// Handle view detail project.
const handleViewDetailProject = (project) => {
return history.push(`/projects/${project.id}/details`, {
original: project.name,
});
};
return (
<DataTable
columns={columns}
@@ -85,6 +99,7 @@ function ProjectsDataTable({
onColumnResizing={handleColumnResizing}
size={projectsTableSize}
payload={{
onViewDetails: handleViewDetailProject,
onEdit: handleEditProject,
onNewTask: handleNewTaskButtonClick,
}}

View File

@@ -22,7 +22,8 @@ export default (mapState) => {
creditNoteSettings: state.settings.data.creditNote,
vendorsCreditNoteSetting: state.settings.data.vendorCredit,
warehouseTransferSettings: state.settings.data.warehouseTransfers,
projectSettings:state.settings.data.projects
projectSettings:state.settings.data.projects,
timeSheetsSettings:state.settings.data.timeSheets
};
return mapState ? mapState(mapped, state, props) : mapped;
};

View File

@@ -2069,5 +2069,18 @@
"task.schema.label.task_name": "Task name",
"task.schema.label.task_house": "Task house",
"task.schema.label.charge": "Charge",
"task.schema.label.amount": "Amount"
"task.schema.label.amount": "Amount",
"projcet_details.action.new_transaction": "New Transaction",
"projcet_details.action.log_time": "Log Time",
"projcet_details.action.edit_project": "Edit Project",
"project_details.label.overview": "Overview",
"project_details.label.timesheet": "Timesheet",
"project_details.label.purchases": "Purchases",
"project_details.label.sales": "Sales",
"project_details.label.journals": "Journals",
"timesheets.column.date": "Date",
"timesheets.column.task": "Task",
"timesheets.column.user": "User",
"timesheets.column.time": "Time",
"timesheets.column.billing_status": "Billing Status"
}

View File

@@ -969,6 +969,15 @@ export const getDashboardRoutes = () => [
),
pageTitle: intl.get('sidebar.transactions_locaking'),
},
{
path: '/projects/:id/details',
component: lazy(() =>
import('../containers/Projects/containers/ProjectDetails'),
),
sidebarExpand: false,
backLink: true,
},
{
path: '/projects',
component: lazy(() =>
@@ -976,6 +985,7 @@ export const getDashboardRoutes = () => [
),
pageTitle: intl.get('sidebar.projects'),
},
// Homepage
{
path: `/`,

View File

@@ -64,6 +64,9 @@ const initialState = {
projects: {
tableSize: 'medium',
},
timeSheets: {
tableSize: 'medium',
},
},
};