fix: project form.

This commit is contained in:
elforjani13
2022-06-23 00:07:21 +02:00
parent 5a8fcc8fb5
commit 5128c021b0
6 changed files with 313 additions and 84 deletions

View File

@@ -0,0 +1,63 @@
import React from 'react';
import intl from 'react-intl-universal';
import { MenuItem, Button } from '@blueprintjs/core';
import { FSelect, FFormGroup } from 'components';
/**
*
* @param {*} query
* @param {*} project
* @param {*} _index
* @param {*} exactMatch
* @returns
*/
const projectItemPredicate = (query, project, _index, exactMatch) => {
const normalizedTitle = project.name.toLowerCase();
const normalizedQuery = query.toLowerCase();
if (exactMatch) {
return normalizedTitle === normalizedQuery;
} else {
return `${project.name}. ${normalizedTitle}`.indexOf(normalizedQuery) >= 0;
}
};
/**
*
* @param {*} project
* @param {*} param1
* @returns
*/
const projectItemRenderer = (project, { handleClick, modifiers, query }) => {
return (
<MenuItem
active={modifiers.active}
disabled={modifiers.disabled}
key={project.id}
onClick={handleClick}
text={project.name}
/>
);
};
const projectSelectProps = {
itemPredicate: projectItemPredicate,
itemRenderer: projectItemRenderer,
valueAccessor: 'id',
labelAccessor: 'name',
};
export function ProjectSelect({ projects, ...rest }) {
return (
<FSelect
items={projects}
{...projectSelectProps}
{...rest}
input={ProjectSelectButton}
/>
);
}
function ProjectSelectButton({ label }) {
return <Button text={label ? label : intl.get('find_or_choose_a_project')} />;
}

View File

@@ -37,7 +37,7 @@ function ProjectFormFields() {
<FastField name={'contact'}>
{({ form, field: { value }, meta: { error, touched } }) => (
<FormGroup
label={intl.get('projects.label.contact')}
label={intl.get('projects.dialog.contact')}
className={classNames('form-group--select-list', Classes.FILL)}
intent={inputIntent({ error, touched })}
>
@@ -56,14 +56,14 @@ function ProjectFormFields() {
</FastField>
{/*------------ Project Name -----------*/}
<FFormGroup
label={intl.get('projects.label.project_name')}
label={intl.get('projects.dialog.project_name')}
name={'projectName'}
>
<FInputGroup name="projectName" />
</FFormGroup>
{/*------------ DeadLine -----------*/}
<FFormGroup
label={intl.get('projects.label.deadline')}
label={intl.get('projects.dialog.deadline')}
name={'projectDeadline'}
className={classNames(CLASSES.FILL, 'form-group--date')}
>
@@ -82,13 +82,13 @@ function ProjectFormFields() {
<FFormGroup name={'projectState'}>
<FCheckbox
name="projectState"
label={intl.get('projects.label.calculator_expenses')}
label={intl.get('projects.dialog.calculator_expenses')}
/>
</FFormGroup>
{/*------------ Cost Estimate -----------*/}
<FFormGroup
name={'projectCost'}
label={intl.get('projects.label.cost_estimate')}
label={intl.get('projects.dialog.cost_estimate')}
>
<ControlGroup>
<InputPrependText text={'USD'} />

View File

@@ -1,4 +1,5 @@
import React from 'react';
import styled from 'styled-components';
import { useHistory } from 'react-router-dom';
import { DataTable } from 'components';
import { TABLES } from 'common/tables';
@@ -16,21 +17,21 @@ import { compose } from 'utils';
const projects = [
{
id: 1,
name: 'Project 1',
description: 'Project 1 description',
status: 'Active',
name: 'Maroon Bronze',
deadline: '2022-06-08T22:00:00.000Z',
display_name: 'Kyrie Rearden',
cost_estimate: '4000',
task_amount: '1000',
is_in_process: true,
},
{
id: 2,
name: 'Project 2',
description: 'Project 2 description',
status: 'Active',
},
{
id: 3,
name: 'Project 3',
description: 'Project 3 description',
status: 'Active',
name: 'Project Sherwood',
deadline: '2022-06-08T22:00:00.000Z',
display_name: 'Ella-Grace Miller',
cost_estimate: '0',
task_amount: '1000',
is_in_process: true,
},
];
@@ -81,16 +82,16 @@ function ProjectsDataTable({
};
return (
<DataTable
<ProjectsTable
columns={columns}
data={projects}
// loading={}
// headerLoading={}
// progressBarLoading={}
manualSortBy={true}
selectionColumn={true}
noInitialFetch={true}
sticky={true}
hideTableHeader={true}
TableLoadingRenderer={TableSkeletonRows}
TableHeaderSkeletonRenderer={TableSkeletonHeader}
ContextMenu={ActionsMenu}
@@ -114,3 +115,40 @@ export default compose(
projectsTableSize: projectSettings?.tableSize,
})),
)(ProjectsDataTable);
const ProjectsTable = styled(DataTable)`
.tbody {
.tr .td {
padding: 0.8rem;
}
.avatar.td {
.avatar {
display: inline-block;
background: #adbcc9;
border-radius: 8%;
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;
}
}
`;

View File

@@ -0,0 +1,187 @@
import React from 'react';
import intl from 'react-intl-universal';
import styled from 'styled-components';
import {
Menu,
MenuDivider,
MenuItem,
Tag,
Intent,
ProgressBar,
} from '@blueprintjs/core';
import { Icon, FormatDate, Choose, FormattedMessage as T } from 'components';
import { safeCallback, firstLettersArgs, calculateStatus } from 'utils';
/**
* project status.
*/
export function ProjectStatus({ project }) {
return (
<ProjectStatusRoot>
{project.task_amount}
<ProjectProgressBar
animate={false}
intent={Intent.NONE}
value={calculateStatus(project.task_amount, project.cost_estimate)}
/>
</ProjectStatusRoot>
);
}
/**
* project status accessor.
*/
export const ProjectStatusAccessor = (row) => {
return (
<Choose>
<Choose.When condition={row.is_in_process}>
<ProjectStatus project={row} />
</Choose.When>
<Choose.Otherwise>
<Tag round={true} minimal={true}>
<T id={'draft'} />
</Tag>
</Choose.Otherwise>
</Choose>
);
};
/**
* Avatar cell.
*/
export const AvatarCell = ({ row: { original }, size }) => (
<span className="avatar" data-size={size}>
{firstLettersArgs(original?.display_name, original?.name)}
</span>
);
/**
* Table actions cell.
*/
export const ActionsMenu = ({
row: { original },
payload: { onEdit, onDelete, onViewDetails, onNewTask },
}) => (
<Menu>
<MenuItem
icon={<Icon icon="reader-18" />}
text={intl.get('view_details')}
onClick={safeCallback(onViewDetails, original)}
/>
<MenuDivider />
<MenuItem
icon={<Icon icon="pen-18" />}
text={intl.get('projects.action.edit_project')}
onClick={safeCallback(onEdit, original)}
/>
<MenuItem
icon={<Icon icon="plus" />}
text={intl.get('projects.action.new_task')}
onClick={safeCallback(onNewTask, original)}
/>
<MenuDivider />
<MenuItem
text={intl.get('projects.action.delete_project')}
icon={<Icon icon="trash-16" iconSize={16} />}
intent={Intent.DANGER}
onClick={safeCallback(onDelete, original)}
/>
</Menu>
);
/**
* Projects accessor.
*/
export const ProjectsAccessor = (row) => (
<ProjectItemsWrap>
<ProjectItemsHeader>
<ProjectItemContactName>{row.display_name}</ProjectItemContactName>
<ProjectItemProjectName>{row.name}</ProjectItemProjectName>
</ProjectItemsHeader>
<ProjectItemDescription>
<FormatDate value={row.deadline} />
{intl.get('projects.label.cost_estimate', {
value: row.cost_estimate,
})}
</ProjectItemDescription>
</ProjectItemsWrap>
);
/**
* Retrieve projects list columns columns.
*/
export const useProjectsListColumns = () => {
return React.useMemo(
() => [
{
id: 'avatar',
Header: '',
Cell: AvatarCell,
className: 'avatar',
width: 45,
disableResizing: true,
disableSortBy: true,
clickable: true,
},
{
id: 'name',
Header: 'Project Name',
accessor: ProjectsAccessor,
width: 240,
className: 'name',
clickable: true,
},
{
id: 'status',
Header: 'status',
accessor: ProjectStatusAccessor,
width: 80,
className: 'status',
clickable: true,
},
],
[],
);
};
const ProjectItemsWrap = styled.div``;
const ProjectItemsHeader = styled.div`
display: flex;
align-items: baseline;
`;
const ProjectItemContactName = styled.div`
font-weight: 600;
padding-right: 4px;
`;
const ProjectItemProjectName = styled.div``;
const ProjectItemDescription = styled.div`
display: inline-block;
font-size: 13px;
opacity: 0.75;
margin-top: 4px;
`;
const ProjectStatusRoot = styled.div`
display: flex;
align-items: center;
flex-direction: row-reverse;
margin: 0 20px;
`;
const ProjectProgressBar = styled(ProgressBar)`
&.bp3-progress-bar {
margin-right: 20px;
flex-shrink: 0;
height: 3px;
max-width: 130px;
&,
.bp3-progress-meter {
border-radius: 0;
}
}
`;

View File

@@ -1,60 +0,0 @@
import React from 'react';
import intl from 'react-intl-universal';
import { Menu, MenuDivider, MenuItem, Intent } from '@blueprintjs/core';
import { Icon } from 'components';
import { safeCallback } from 'utils';
/**
* Table actions cell.
*/
export const ActionsMenu = ({
row: { original },
payload: { onEdit, onDelete, onViewDetails, onNewTask },
}) => (
<Menu>
<MenuItem
icon={<Icon icon="reader-18" />}
text={intl.get('view_details')}
onClick={safeCallback(onViewDetails, original)}
/>
<MenuDivider />
<MenuItem
icon={<Icon icon="pen-18" />}
text={intl.get('projects.action.edit_project')}
onClick={safeCallback(onEdit, original)}
/>
<MenuItem
icon={<Icon icon="plus" />}
text={intl.get('projects.action.new_task')}
onClick={safeCallback(onNewTask, original)}
/>
<MenuDivider />
<MenuItem
text={intl.get('projects.action.delete_project')}
icon={<Icon icon="trash-16" iconSize={16} />}
intent={Intent.DANGER}
onClick={safeCallback(onDelete, original)}
/>
</Menu>
);
/**
* Retrieve projects list columns columns.
*/
export const useProjectsListColumns = () => {
return React.useMemo(
() => [
{
id: 'name',
Header: 'Project Name',
accessor: 'name',
width: 100,
className: 'name',
clickable: true,
},
],
[],
);
};

View File

@@ -2050,12 +2050,13 @@
"projects.action.new_task": "New Task",
"projects.action.delete_project": "Delete Project",
"projects.label.new_project": "New Project",
"projects.label.contact": "Contact",
"projects.label.project_name": "Project Name",
"projects.label.deadline": "Deadline",
"projects.label.calculator_expenses": "Calculator from tasks & estimated expenses",
"projects.label.cost_estimate": "Cost Estimate",
"projects.dialog.contact": "Contact",
"projects.dialog.project_name": "Project Name",
"projects.dialog.deadline": "Deadline",
"projects.dialog.calculator_expenses": "Calculator from tasks & estimated expenses",
"projects.dialog.cost_estimate": "Cost Estimate",
"projects.label.create": "Create",
"projects.label.cost_estimate":" • Estimate {value}",
"task.label.new_task": "New Task",
"task.label.task_name": "Task Name",
"task.label.estimated_hours": "Task Name",