WIP Whiteboard Changes

This commit is contained in:
Patrick Fic
2019-12-31 11:44:02 -08:00
parent c46b2a301e
commit 14147ded53
16 changed files with 262 additions and 308 deletions

View File

@@ -22,7 +22,7 @@ class ErrorBoundary extends React.Component {
render() {
if (this.state.hasErrored === true) {
return <div>Uh oh, something went wrong. {this.state.error}</div>;
return <div>Uh oh, something went wrong.</div>;
} else {
return this.props.children;
}

View File

@@ -25,18 +25,17 @@ function searchResult(query) {
function renderOption(item) {
return (
<Option key={item.category} text={item.category}>
<div className="global-search-item">
<span className="global-search-item-desc">
<div className='global-search-item'>
<span className='global-search-item-desc'>
Found {item.query} on
<a
href={`https://s.taobao.com/search?q=${item.query}`}
target="_blank"
rel="noopener noreferrer"
>
target='_blank'
rel='noopener noreferrer'>
{item.category}
</a>
</span>
<span className="global-search-item-count">{item.count} results</span>
<span className='global-search-item-count'>{item.count} results</span>
</div>
</Option>
);
@@ -56,25 +55,26 @@ export default class GlobalSearch extends React.Component {
render() {
const { dataSource } = this.state;
return (
<div style={{ width: 300 }}>
<AutoComplete
size="large"
style={{ width: "100%" }}
dataSource={dataSource.map(renderOption)}
onSelect={onSelect}
onSearch={this.handleSearch}
placeholder="input here"
optionLabelProp="text"
>
<Input
suffix={
<Button style={{ marginRight: -12 }} size="large" type="primary">
<Icon type="search" />
</Button>
}
/>
</AutoComplete>
</div>
<div />
// <div style={{ width: 300 }}>
// <AutoComplete
// size="large"
// style={{ width: "100%" }}
// dataSource={dataSource.map(renderOption)}
// onSelect={onSelect}
// onSearch={this.handleSearch}
// placeholder="input here"
// optionLabelProp="text"
// >
// <Input
// suffix={
// <Button style={{ marginRight: -12 }} size="large" type="primary">
// <Icon type="search" />
// </Button>
// }
// />
// </AutoComplete>
// </div>
);
}
}

View File

@@ -33,8 +33,8 @@ function JobTombstone({ job, ...otherProps }) {
if (!job) {
return (
<AlertComponent
message="This job does not exist or you do not have access to it."
type="error"
message='This job does not exist or you do not have access to it.'
type='error'
/>
);
}
@@ -70,20 +70,19 @@ function JobTombstone({ job, ...otherProps }) {
+" " + jobContext.owner?.first_name
: "No owner"
}
tags={<Tag color="blue">{jobContext?.status}</Tag>}
tags={<Tag color='blue'>{jobContext?.job_status?.name}</Tag>}
extra={[
<Form.Item key="1">
<Button type="primary" htmlType="submit">
<Form.Item key='1'>
<Button type='primary' htmlType='submit'>
Save
</Button>
</Form.Item>
]}
>
<Descriptions size="small" column={3}>
<Descriptions.Item label="Claim Total">
]}>
<Descriptions size='small' column={3}>
<Descriptions.Item label='Claim Total'>
$ {jobContext.claim_total?.toFixed(2)}
</Descriptions.Item>
<Descriptions.Item label="Deductible">
<Descriptions.Item label='Deductible'>
$ {jobContext.deductible?.toFixed(2)}
</Descriptions.Item>
</Descriptions>
@@ -91,51 +90,51 @@ function JobTombstone({ job, ...otherProps }) {
<Row>
<Typography.Title level={4}>Information</Typography.Title>
<Form.Item label="RO #">
<Form.Item label='RO #'>
{getFieldDecorator("ro_number", {
initialValue: jobContext.ro_number
})(<Input name="ro_number" readOnly onChange={handleChange} />)}
})(<Input name='ro_number' readOnly onChange={handleChange} />)}
</Form.Item>
<Form.Item label="Estimate #">
<Form.Item label='Estimate #'>
{getFieldDecorator("est_number", {
initialValue: jobContext.est_number
})(<Input name="est_number" readOnly onChange={handleChange} />)}
})(<Input name='est_number' readOnly onChange={handleChange} />)}
</Form.Item>
</Row>
<Row>
<Typography.Title level={4}>Insurance Information</Typography.Title>
<Form.Item label="Insurance Company">
<Form.Item label='Insurance Company'>
{getFieldDecorator("est_co_nm", {
initialValue: jobContext.est_co_nm
})(<Input name="est_co_nm" onChange={handleChange} />)}
})(<Input name='est_co_nm' onChange={handleChange} />)}
</Form.Item>
<Col span={8}>
<Form.Item label="Estimator Last Name">
<Form.Item label='Estimator Last Name'>
{getFieldDecorator("est_ct_ln", {
initialValue: jobContext.est_ct_ln
})(<Input name="est_ct_ln" onChange={handleChange} />)}
})(<Input name='est_ct_ln' onChange={handleChange} />)}
</Form.Item>
<Form.Item label="Estimator First Name">
<Form.Item label='Estimator First Name'>
{getFieldDecorator("est_ct_fn", {
initialValue: jobContext.est_ct_fn
})(<Input name="est_ct_fn" onChange={handleChange} />)}
})(<Input name='est_ct_fn' onChange={handleChange} />)}
</Form.Item>
</Col>
<Col span={8}>
<Form.Item label="Estimator Phone #">
<Form.Item label='Estimator Phone #'>
{getFieldDecorator("est_ph1", {
initialValue: jobContext.est_ph1
})(
<FormItemPhone
customInput={Input}
name="est_ph1"
name='est_ph1'
onValueChange={handleChange}
/>
)}
</Form.Item>
<Form.Item label="Estimator Email">
<Form.Item label='Estimator Email'>
{getFieldDecorator("est_ea", {
initialValue: jobContext.est_ea,
rules: [
@@ -144,7 +143,7 @@ function JobTombstone({ job, ...otherProps }) {
message: "This is not a valid email address."
}
]
})(<Input name="est_ea" onChange={handleChange} />)}
})(<Input name='est_ea' onChange={handleChange} />)}
</Form.Item>
</Col>
</Row>

View File

@@ -38,7 +38,10 @@ export default function JobsPage({ loading, jobs }) {
sorter: (a, b) => alphaSort(a, b),
sortOrder:
state.sortedInfo.columnKey === "status" && state.sortedInfo.order,
ellipsis: true
ellipsis: true,
render: (text, record) => {
return record.job_status?.name ?? "";
}
},
{
title: "Customer",
@@ -75,9 +78,9 @@ export default function JobsPage({ loading, jobs }) {
render: (text, record) => (
<span>
Action {record.ro_number}
<Divider type="vertical" />
<Divider type="vertical" />
More actions <Icon type="down" />
<Divider type='vertical' />
<Divider type='vertical' />
More actions <Icon type='down' />
</span>
)
}
@@ -94,12 +97,12 @@ export default function JobsPage({ loading, jobs }) {
return (
<div>
<Input name="searchCriteria" onChange={handleChange} />
<Input name='searchCriteria' onChange={handleChange} />
<Table
loading={loading}
pagination={{ position: "bottom" }}
columns={columns.map(item => ({ ...item }))}
rowKey="id"
rowKey='id'
dataSource={jobs}
onChange={handleTableChange}
/>

View File

@@ -1,59 +1,75 @@
import React from "react";
import { Skeleton, Switch, Card, Icon, Avatar } from "antd";
import { Link } from "react-router-dom";
import { Menu, Dropdown, Card, Icon, Avatar, Button } from "antd";
const { Meta } = Card;
export default function WhiteBoardCard({ metadata }) {
// const {
// onClick,
// className,
// name,
// cardStyle,
// body,
// dueOn,
// cardColor,
// subTitle,
// tagStyle,
// escalationText,
// tags,
// showDeleteButton,
// onDelete
// } = this.props;
const menu = (
<Menu>
<Menu.Item key='images'>
<Icon type='file-image' />
View Job Images
</Menu.Item>
<Menu.Item key='printing'>
<Icon type='printer' />
Printing
</Menu.Item>
<Menu.Item key='notes'>
<Icon type='edit' />
Job Notes
</Menu.Item>
<Menu.Item key='postinvoices'>
<Icon type='shopping-cart' />
Post Invoices
</Menu.Item>
<Menu.Item key='receiveparts'>
<Icon type='inbox' />
Receive Parts
</Menu.Item>
<Menu.Item key='partstatus'>
<Icon type='tool' />
Parts Status
</Menu.Item>
</Menu>
);
class WhiteBoardCard extends React.Component {
state = {
loading: true
};
onChange = checked => {
this.setState({ loading: !checked });
};
render() {
const { loading } = this.state;
// const {
// onClick,
// className,
// name,
// cardStyle,
// body,
// dueOn,
// cardColor,
// subTitle,
// tagStyle,
// escalationText,
// tags,
// showDeleteButton,
// onDelete
// } = this.props;
return (
<div>
<Card
style={{ width: 300, marginTop: 16 }}
actions={[
<Icon type="setting" key="setting" />,
<Icon type="edit" key="edit" />,
<Icon type="ellipsis" key="ellipsis" />,
<Switch checked={!loading} onChange={this.onChange} />
]}
>
<Skeleton loading={loading} avatar active>
<Meta
avatar={
<Avatar src="https://zos.alipayobjects.com/rmsportal/ODTLcjxAfvqbxHnVXCYX.png" />
}
title="Card title"
description="This is the description"
/>
</Skeleton>
</Card>
</div>
);
}
return (
<div>
<Card
title={
(metadata.ro_number ?? metadata.est_number) +
" | " +
(metadata.owner?.first_name ?? "") +
" " +
(metadata.owner?.last_name ?? "")
}
style={{ width: 300, marginTop: 10 }}
actions={[
<Link to={`/manage/jobs/${metadata.id}`}>
<Icon type='eye' key='view' />
</Link>,
<Icon type='message' key='message' />,
<Dropdown overlay={menu} trigger={["click"]}>
<Icon type='ellipsis' />
</Dropdown>
]}>
<Avatar alt='Job' />
This is the card data.
</Card>
</div>
);
}
export default WhiteBoardCard;

View File

@@ -11,7 +11,7 @@ export default function WhiteBoardKanBan({ data, eventBus }) {
<Board
tagStyle={{ fontSize: "80%" }}
data={data}
draggable
laneDraggable={false}
eventBusHandle={setEventBus}
components={{ Card: WhiteBoardCard }}
onCardClick={(cardId, metadata) =>

View File

@@ -13,39 +13,34 @@ export default function WhiteBoardKanBanContainer() {
}
);
const static_data = {
lanes: [
{
id: "lane1",
title: "Planned Tasks",
label: "2/2",
cards: [
{
id: "Card1",
title: "Write Blog",
description: "Can AI make memes",
label: "30 mins"
},
{
id: "Card2",
title: "Pay Rent",
description: "Transfer via NEFT",
label: "5 mins",
metadata: { sha: "be312a1" }
}
]
},
{
id: "lane2",
title: "Completed",
label: "0/0",
cards: []
}
]
};
if (loading) return <LoadingSpinner />;
if (error) return <Alert message={error.message} />;
let eventBus;
return <WhiteBoardKanBan eventBus={eventBus} data={static_data} />;
let i = data.job_status.reduce((acc, value) => {
//Create a lane object for each row.
let newLane = {
id: value.name,
title: value.name,
label: "0",
cards: value.jobs.reduce((acc, value) => {
acc.push({
id: value.id,
title: value.ro_number,
description: value.est_number,
label: value.id,
metadata: value
});
return acc;
}, [])
};
acc.push(newLane);
return acc;
}, []);
let laneData = {
lanes: i
};
return <WhiteBoardKanBan eventBus={eventBus} data={laneData} />;
}