diff --git a/src/containers/Projects/components/ChangeTypesSelect.tsx b/src/containers/Projects/components/ProjectTaskChargeTypeSelect.tsx similarity index 92% rename from src/containers/Projects/components/ChangeTypesSelect.tsx rename to src/containers/Projects/components/ProjectTaskChargeTypeSelect.tsx index 79335bd8e..db413bfe7 100644 --- a/src/containers/Projects/components/ChangeTypesSelect.tsx +++ b/src/containers/Projects/components/ProjectTaskChargeTypeSelect.tsx @@ -31,7 +31,7 @@ const chargeTypeSelectProps = { * @param param0 * @returns */ -export function ChangeTypesSelect({ items, ...rest }) { +export function ProjectTaskChargeTypeSelect({ items, ...rest }) { return ( } className={classNames('form-group--select-list', Classes.FILL)} > - + ); diff --git a/src/containers/Projects/containers/ProjectDetails/ProjectDetailsHeader.tsx b/src/containers/Projects/containers/ProjectDetails/ProjectDetailsHeader.tsx new file mode 100644 index 000000000..1039885c3 --- /dev/null +++ b/src/containers/Projects/containers/ProjectDetails/ProjectDetailsHeader.tsx @@ -0,0 +1,75 @@ +// @ts-nocheck +import React from 'react'; +import intl from 'react-intl-universal'; +import moment from 'moment'; +import styled from 'styled-components'; +import { Intent } from '@blueprintjs/core'; +import { FormatDate } from '@/components'; +import { + DetailFinancialCard, + DetailFinancialSection, + FinancialProgressBar, + FinancialCardText, +} from './components'; +import { calculateStatus } from '@/utils'; +import { useCalculateProject } from './utils'; + +import { useProjectDetailContext } from './ProjectDetailProvider'; + +/** + * Project details header. + * @returns + */ +export function ProjectDetailHeader() { + const { project } = useProjectDetailContext(); + + const { percentageOfInvoice, percentageOfExpense } = useCalculateProject(); + + return ( + + + + + {intl.get('project_details.label.of_project_estimate', { + value: percentageOfInvoice, + })} + + + + + + {intl.get('project_details.label.of_project_estimate', { + value: percentageOfExpense, + })} + + + + + + } + > + 4 days to go + + + ); +} diff --git a/src/containers/Projects/containers/ProjectDetails/ProjectTasks/components.tsx b/src/containers/Projects/containers/ProjectDetails/ProjectTasks/components.tsx index 22ae3051b..ef5266013 100644 --- a/src/containers/Projects/containers/ProjectDetails/ProjectTasks/components.tsx +++ b/src/containers/Projects/containers/ProjectDetails/ProjectTasks/components.tsx @@ -2,7 +2,7 @@ import React from 'react'; import intl from 'react-intl-universal'; import styled from 'styled-components'; -import { Icon } from '@/components'; +import { Icon, If, Choose, FormattedMessage as T } from '@/components'; import { Menu, MenuItem, Intent } from '@blueprintjs/core'; import { safeCallback } from '@/utils'; @@ -30,22 +30,39 @@ export function ActionsMenu({ ); } -export function TaskAccessor(row) { +/** + * + * @returns + */ +function TaskChrageType({ values: { charge_type, rate } }) { + return ( + + + + + + + + + + + + ); +} + +export function TaskAccessor(task) { return ( - {row.name} + {task.name} - {row.charge_type === 'TIME' - ? intl.get('project_task.rate', { - rate: row.rate, - }) - : row.charge_type} + + - {row.estimate_minutes && - intl.get('project_task.estimate_minutes', { - estimate_minutes: row.estimate_minutes, + {task.estimate_hours && + intl.get('project_task.estimate_hours', { + estimate_hours: task.estimate_hours, })} diff --git a/src/containers/Projects/containers/ProjectDetails/ProjectTasks/index.tsx b/src/containers/Projects/containers/ProjectDetails/ProjectTasks/index.tsx index 75a572f2a..4389916c0 100644 --- a/src/containers/Projects/containers/ProjectDetails/ProjectTasks/index.tsx +++ b/src/containers/Projects/containers/ProjectDetails/ProjectTasks/index.tsx @@ -2,14 +2,14 @@ import React from 'react'; import styled from 'styled-components'; -import { ProjectTasksHeader } from './ProjectTasksHeader'; +import { ProjectDetailHeader } from '../ProjectDetailsHeader'; import { ProjectTasksTable } from './ProjectTasksTable'; import { ProjectTaskProvider } from './ProjectTaskProvider'; export default function ProjectTasks() { return ( - + diff --git a/src/containers/Projects/containers/ProjectDetails/ProjectTimeSheets/index.tsx b/src/containers/Projects/containers/ProjectDetails/ProjectTimeSheets/index.tsx index ccf2419d7..8570e58ce 100644 --- a/src/containers/Projects/containers/ProjectDetails/ProjectTimeSheets/index.tsx +++ b/src/containers/Projects/containers/ProjectDetails/ProjectTimeSheets/index.tsx @@ -2,8 +2,8 @@ import React from 'react'; import styled from 'styled-components'; +import { ProjectDetailHeader } from '../ProjectDetailsHeader'; import { ProjectTimesheetsTable } from './ProjectTimesheetsTable'; -import { ProjectTimesheetsHeader } from './ProjectTimesheetsHeader'; import { ProjectTimesheetsProvider } from './ProjectTimesheetsProvider'; /** @@ -13,7 +13,7 @@ import { ProjectTimesheetsProvider } from './ProjectTimesheetsProvider'; export default function ProjectTimeSheets() { return ( - + diff --git a/src/containers/Projects/containers/ProjectDetails/utils.tsx b/src/containers/Projects/containers/ProjectDetails/utils.tsx new file mode 100644 index 000000000..d569cf181 --- /dev/null +++ b/src/containers/Projects/containers/ProjectDetails/utils.tsx @@ -0,0 +1,30 @@ +//@ts-nocheck + +import React from 'react'; +import moment from 'moment'; +import { subtract } from 'lodash'; +import { calculateStatus } from '@/utils'; +import { useProjectDetailContext } from './ProjectDetailProvider'; + +function calculateProject(costEstiate, totalAmount) { + return (costEstiate / totalAmount) * 100; +} + +export const useCalculateProject = () => { + const { project } = useProjectDetailContext(); + const percentageOfInvoice = calculateProject( + project?.total_invoiced, + project?.cost_estimate, + ); + + const percentageOfExpense = calculateProject( + project?.total_expenses, + project?.cost_estimate, + ); + + return { + percentageOfInvoice, + percentageOfExpense, + }; +}; + diff --git a/src/containers/Projects/containers/ProjectExpenseForm/ProjectExpenseFormFields.tsx b/src/containers/Projects/containers/ProjectExpenseForm/ProjectExpenseFormFields.tsx index 996cd9e70..6284d181c 100644 --- a/src/containers/Projects/containers/ProjectExpenseForm/ProjectExpenseFormFields.tsx +++ b/src/containers/Projects/containers/ProjectExpenseForm/ProjectExpenseFormFields.tsx @@ -14,7 +14,7 @@ import { import { ExpenseSelect, FInputGroupComponent, - ChangeTypesSelect, + ProjectTaskChargeTypeSelect, } from '../../components'; import ExpenseFormChargeFields from './ProjectExpenseFormChargeFields'; import { momentFormatter } from '@/utils'; @@ -100,7 +100,7 @@ export default function ProjectExpenseFormFields() { label={} className={classNames('form-group--select-list', Classes.FILL)} > - } className={classNames('form-group--select-list', Classes.FILL)} > - { - - {row.status_formatted} - + + + {row.status_formatted} + + - - - + + + + + ); @@ -167,7 +171,7 @@ export const useProjectsListColumns = () => { id: 'name', Header: '', accessor: ProjectsAccessor, - width: 240, + width: 140, className: 'name', clickable: true, }, @@ -232,7 +236,11 @@ const ProjectProgressBar = styled(ProgressBar)` } `; -const StatusTag = styled(Tag)` - min-width: 65px; - text-align: center; +const StatusTagWrap = styled.div` + display: flex; + justify-content: center; + .tag { + min-width: 65px; + text-align: center; + } `; diff --git a/src/lang/en/index.json b/src/lang/en/index.json index 65180dba4..26e1257f0 100644 --- a/src/lang/en/index.json +++ b/src/lang/en/index.json @@ -2083,8 +2083,10 @@ "project_task.dialog.edit_success_message": "The task has been edited successfully.", "project_task.action.edit_task": "Edit Task", "project_task.action.delete_task": "Delete Task", - "project_task.rate": "{rate} /hour", - "project_task.estimate_minutes": "• {estimate_minutes}h 0m estimated", + "project_task.rate": "{rate} / hour", + "project_task.fixed_price": "Fixed price", + "project_task.non_chargable": "Non-chargeable", + "project_task.estimate_hours": "• {estimate_hours}h 0m estimated", "project_task.alert.delete_message": "The deleted task has been deleted successfully.", "project_task.alert.once_delete_this_project": "Once you delete this task, you won't be able to restore it later. Are you sure you want to delete this task?", "fixed_price": "Fixed price", @@ -2095,7 +2097,7 @@ "project.schema.label.project_state": "Project state", "project.schema.label.project_cost": "Project cost", "project_task.schema.label.task_name": "Task name", - "project_task.schema.label.task_house": "Task house", + "project_task.schema.label.estimate_hours": "Estimate hours", "project_task.schema.label.charge_type": "Charge type", "project_task.schema.label.rate": "Rate", "project_task.schema.label.amount": "Amount", @@ -2112,6 +2114,11 @@ "project_details.new_invoicing": "New Invoicing", "project_details.new_expense": "New Expense", "project_details.new_estimated_expense": "New Estimated Expense", + "project_details.label.project_estimate": "Project estimate", + "project_details.label.invoiced": "Invoiced", + "project_details.label.time_expenses": "Time & Expenses", + "project_details.label.to_be_invoiced": "To be invoiced", + "project_details.label.of_project_estimate": "{value}% of project estimate", "timesheets.action.delete_timesheet": "Delete", "timesheets.action.edit_timesheet": "Edit Timesheet", "timesheets.column.date": "Date", @@ -2215,5 +2222,10 @@ "project_billable_entries.dialog.filter_by_type": "Filter by Type", "project_billable_entries.dialog.expense": "Expense", "project_billable_entries.dialog.task": "Task", - "project_billable_entries.dialog.bill": "Bill" + "project_billable_entries.dialog.bill": "Bill", + "project_billable_entries.dialog.add": "Add", + "project_billable_entries.dialog.show": "Show", + "project_billable_entries.alert.there_is_no_billable_entries": "There is no billable entries for that project.", + "project_billable_entries.billable_type": "Billable {value}", + "add_billable_entries": "Add Billable Entries" } \ No newline at end of file