Complete refactor of jobs detail screen.
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { useQuery, useApolloClient } from "@apollo/react-hooks";
|
||||
import { useApolloClient, useQuery } from "@apollo/react-hooks";
|
||||
import { Avatar, Col, Dropdown, Icon, Menu, Row } from "antd";
|
||||
import i18next from "i18next";
|
||||
import React from "react";
|
||||
@@ -52,7 +52,7 @@ export default function CurrentUserDropdown() {
|
||||
);
|
||||
|
||||
if (loading) return null;
|
||||
if (error) return <AlertComponent message={error.message} />;
|
||||
if (error) return <AlertComponent message={error.message} type='error' />;
|
||||
|
||||
const { currentUser } = data;
|
||||
|
||||
@@ -62,10 +62,8 @@ export default function CurrentUserDropdown() {
|
||||
<Col span={8}>
|
||||
<Avatar size='large' alt='Avatar' src={UserImage} />
|
||||
</Col>
|
||||
<Col span={16}>
|
||||
<Link to='/manage/profile'>
|
||||
{currentUser?.displayName || t("general.labels.unknown")}
|
||||
</Link>
|
||||
<Col span={16} style={{ color: "white" }}>
|
||||
{currentUser.displayName || t("general.labels.unknown")}
|
||||
</Col>
|
||||
</Row>
|
||||
</Dropdown>
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import React, { useState } from "react";
|
||||
import { Row, Col, Button } from "antd";
|
||||
import ChatWindowContainer from "../chat-window/chat-window.container";
|
||||
import { Col, Row } from "antd";
|
||||
import React from "react";
|
||||
|
||||
export default function FooterComponent() {
|
||||
return (
|
||||
|
||||
@@ -1,44 +1,65 @@
|
||||
import { useApolloClient } from "@apollo/react-hooks";
|
||||
import { Col, Icon, Menu, Row } from "antd";
|
||||
import React from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Link } from "react-router-dom";
|
||||
import CurrentUserDropdown from "../current-user-dropdown/current-user-dropdown.component";
|
||||
import GlobalSearch from "../global-search/global-search.component";
|
||||
import ManageSignInButton from "../manage-sign-in-button/manage-sign-in-button.component";
|
||||
import "./header.styles.scss";
|
||||
|
||||
|
||||
export default ({ landingHeader, navItems, selectedNavItem }) => {
|
||||
const apolloClient = useApolloClient();
|
||||
|
||||
const { t } = useTranslation();
|
||||
const handleClick = e => {
|
||||
apolloClient.writeData({ data: { selectedNavItem: e.key } });
|
||||
};
|
||||
return (
|
||||
<Row type="flex" justify="space-around">
|
||||
<Row type='flex' justify='space-around'>
|
||||
<Col span={16}>
|
||||
<Menu
|
||||
theme="dark"
|
||||
className="header"
|
||||
theme='dark'
|
||||
className='header'
|
||||
onClick={handleClick}
|
||||
selectedKeys={selectedNavItem}
|
||||
mode="horizontal"
|
||||
>
|
||||
mode='horizontal'>
|
||||
<Menu.Item>
|
||||
<GlobalSearch />
|
||||
</Menu.Item>
|
||||
{navItems.map(navItem => (
|
||||
<Menu.Item key={navItem.title}>
|
||||
<Link to={navItem.path}>
|
||||
{navItem.icontype ? <Icon type={navItem.icontype} /> : null}
|
||||
{navItem.title}
|
||||
|
||||
<Menu.Item key='home'>
|
||||
<Link to='/manage'>
|
||||
<Icon type='home' />
|
||||
{t("menus.header.home")}
|
||||
</Link>
|
||||
</Menu.Item>
|
||||
<Menu.SubMenu title={t("menus.header.jobs")}>
|
||||
<Menu.Item key='jobs'>
|
||||
<Link to='/manage/jobs'>
|
||||
<Icon type='home' />
|
||||
{t("menus.header.activejobs")}
|
||||
</Link>
|
||||
</Menu.Item>
|
||||
))}
|
||||
<Menu.Item key='availablejobs'>
|
||||
<Link to='/manage/available'>
|
||||
<Icon type='home' />
|
||||
{t("menus.header.availablejobs")}
|
||||
</Link>
|
||||
</Menu.Item>
|
||||
</Menu.SubMenu>
|
||||
|
||||
{!landingHeader ? (
|
||||
null
|
||||
) : (
|
||||
{
|
||||
// navItems.map(navItem => (
|
||||
// <Menu.Item key={navItem.title}>
|
||||
// <Link to={navItem.path}>
|
||||
// {navItem.icontype ? <Icon type={navItem.icontype} /> : null}
|
||||
// {navItem.title}
|
||||
// </Link>
|
||||
// </Menu.Item>
|
||||
// ))
|
||||
}
|
||||
|
||||
{!landingHeader ? null : (
|
||||
<Menu.Item>
|
||||
<ManageSignInButton />
|
||||
</Menu.Item>
|
||||
|
||||
@@ -5,8 +5,7 @@ import AlertComponent from "../../components/alert/alert.component";
|
||||
|
||||
import { GET_JOB_LINES_BY_PK } from "../../graphql/jobs-lines.queries";
|
||||
|
||||
export default function JobLinesContainer({ match }) {
|
||||
const { jobId } = match.params;
|
||||
export default function JobLinesContainer({ jobId }) {
|
||||
|
||||
const { loading, error, data } = useQuery(GET_JOB_LINES_BY_PK, {
|
||||
variables: { id: jobId },
|
||||
|
||||
@@ -1,217 +0,0 @@
|
||||
import React, { useState } from "react";
|
||||
import { Link } from "react-router-dom";
|
||||
import AlertComponent from "../alert/alert.component";
|
||||
import {
|
||||
Form,
|
||||
Input,
|
||||
Row,
|
||||
Col,
|
||||
Button,
|
||||
Typography,
|
||||
PageHeader,
|
||||
Descriptions,
|
||||
Tag,
|
||||
notification,
|
||||
Avatar,
|
||||
Layout
|
||||
} from "antd";
|
||||
import { UPDATE_JOB, CONVERT_JOB_TO_RO } from "../../graphql/jobs.queries";
|
||||
import { useMutation } from "@apollo/react-hooks";
|
||||
import FormItemPhone from "../form-items-formatted/phone-form-item.component";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import CarImage from "../../assets/car.svg";
|
||||
|
||||
const { Content } = Layout;
|
||||
const formItemLayout = {
|
||||
// labelCol: {
|
||||
// xs: { span: 12 },
|
||||
// sm: { span: 5 }
|
||||
// },
|
||||
// wrapperCol: {
|
||||
// xs: { span: 24 },
|
||||
// sm: { span: 12 }
|
||||
// }
|
||||
};
|
||||
|
||||
function JobTombstone({ job, ...otherProps }) {
|
||||
const [jobContext, setJobContext] = useState(job);
|
||||
const [mutationUpdateJob] = useMutation(UPDATE_JOB);
|
||||
const [mutationConvertJob] = useMutation(CONVERT_JOB_TO_RO);
|
||||
const { t } = useTranslation();
|
||||
|
||||
if (!job) {
|
||||
return <AlertComponent message={t("jobs.errors.noaccess")} type='error' />;
|
||||
}
|
||||
|
||||
const handleSubmit = e => {
|
||||
e.preventDefault();
|
||||
|
||||
otherProps.form.validateFieldsAndScroll((err, values) => {
|
||||
if (err) {
|
||||
notification["error"]({
|
||||
message: t("jobs.errors.validationtitle"),
|
||||
description: t("jobs.errors.validation")
|
||||
});
|
||||
}
|
||||
if (!err) {
|
||||
mutationUpdateJob({
|
||||
variables: { jobId: jobContext.id, job: values }
|
||||
}).then(r =>
|
||||
notification["success"]({
|
||||
message: t("jobs.successes.savetitle")
|
||||
})
|
||||
);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const handleChange = event => {
|
||||
const { name, value } = event.target ? event.target : event;
|
||||
setJobContext({ ...jobContext, [name]: value });
|
||||
};
|
||||
|
||||
const { getFieldDecorator } = otherProps.form;
|
||||
|
||||
const tombstoneTitle = (
|
||||
<div>
|
||||
<Avatar size='large' alt='Vehicle Image' src={CarImage} />
|
||||
{`${t("jobs.fields.ro_number")} ${
|
||||
jobContext.ro_number ? jobContext.ro_number : t("general.labels.na")
|
||||
}`}
|
||||
</div>
|
||||
);
|
||||
|
||||
return (
|
||||
<Content>
|
||||
<Form onSubmit={handleSubmit} {...formItemLayout}>
|
||||
<PageHeader
|
||||
style={{
|
||||
border: "1px solid rgb(235, 237, 240)"
|
||||
}}
|
||||
title={tombstoneTitle}
|
||||
subTitle={
|
||||
jobContext.owner
|
||||
? (jobContext.owner?.first_name || "") +
|
||||
" " +
|
||||
(jobContext.owner?.last_name || "")
|
||||
: t("jobs.errors.noowner")
|
||||
}
|
||||
tags={
|
||||
<span key='job-status'>
|
||||
{jobContext.job_status ? (
|
||||
<Tag color='blue'>{jobContext.job_status.name}</Tag>
|
||||
) : null}
|
||||
</span>
|
||||
}
|
||||
extra={[
|
||||
<Button
|
||||
key='convert'
|
||||
type='dashed'
|
||||
disabled={jobContext.converted}
|
||||
onClick={() => {
|
||||
mutationConvertJob({
|
||||
variables: { jobId: jobContext.id }
|
||||
}).then(r => {
|
||||
console.log("r", r);
|
||||
setJobContext({
|
||||
...jobContext,
|
||||
converted: true,
|
||||
ro_number: r.data.update_jobs.returning[0].ro_number
|
||||
});
|
||||
|
||||
notification["success"]({
|
||||
message: t("jobs.successes.converted")
|
||||
});
|
||||
});
|
||||
}}>
|
||||
{t("jobs.actions.convert")}
|
||||
</Button>,
|
||||
<Button type='primary' key='submit' htmlType='submit'>
|
||||
{t("general.labels.save")}
|
||||
</Button>
|
||||
]}>
|
||||
<Descriptions size='small' column={5}>
|
||||
<Descriptions.Item label={t("jobs.fields.vehicle")}>
|
||||
<Link to={`/manage/vehicles/${jobContext.vehicle?.id}`}>
|
||||
{jobContext.vehicle?.v_model_yr || t("general.labels.na")}{" "}
|
||||
{jobContext.vehicle?.v_make_desc || t("general.labels.na")}{" "}
|
||||
{jobContext.vehicle?.v_model_desc || t("general.labels.na")} |{" "}
|
||||
{jobContext.vehicle?.plate_no || t("general.labels.na")}
|
||||
</Link>
|
||||
</Descriptions.Item>
|
||||
|
||||
<Descriptions.Item label={t("jobs.fields.est_number")}>
|
||||
{jobContext.est_number}
|
||||
</Descriptions.Item>
|
||||
|
||||
<Descriptions.Item label={t("jobs.fields.claim_total")}>
|
||||
$ {jobContext.claim_total?.toFixed(2)}
|
||||
</Descriptions.Item>
|
||||
|
||||
<Descriptions.Item label={t("jobs.fields.deductible")}>
|
||||
$ {jobContext.deductible?.toFixed(2)}
|
||||
</Descriptions.Item>
|
||||
</Descriptions>
|
||||
</PageHeader>
|
||||
|
||||
<Row>
|
||||
<Typography.Title level={4}>Information</Typography.Title>
|
||||
{
|
||||
// <Form.Item label='Estimate #'>
|
||||
// {getFieldDecorator("est_number", {
|
||||
// initialValue: jobContext.est_number
|
||||
// })(<Input name='est_number' readOnly onChange={handleChange} />)}
|
||||
// </Form.Item>
|
||||
}
|
||||
</Row>
|
||||
|
||||
<Row>
|
||||
<Typography.Title level={4}>Insurance Information</Typography.Title>
|
||||
<Form.Item label='Insurance Company'>
|
||||
{getFieldDecorator("est_co_nm", {
|
||||
initialValue: jobContext.est_co_nm
|
||||
})(<Input name='est_co_nm' onChange={handleChange} />)}
|
||||
</Form.Item>
|
||||
<Col span={8}>
|
||||
<Form.Item label='Estimator Last Name'>
|
||||
{getFieldDecorator("est_ct_ln", {
|
||||
initialValue: jobContext.est_ct_ln
|
||||
})(<Input name='est_ct_ln' onChange={handleChange} />)}
|
||||
</Form.Item>
|
||||
<Form.Item label='Estimator First Name'>
|
||||
{getFieldDecorator("est_ct_fn", {
|
||||
initialValue: jobContext.est_ct_fn
|
||||
})(<Input name='est_ct_fn' onChange={handleChange} />)}
|
||||
</Form.Item>
|
||||
</Col>
|
||||
<Col span={8}>
|
||||
<Form.Item label='Estimator Phone #'>
|
||||
{getFieldDecorator("est_ph1", {
|
||||
initialValue: jobContext.est_ph1
|
||||
})(
|
||||
<FormItemPhone
|
||||
customInput={Input}
|
||||
name='est_ph1'
|
||||
onValueChange={handleChange}
|
||||
/>
|
||||
)}
|
||||
</Form.Item>
|
||||
<Form.Item label='Estimator Email'>
|
||||
{getFieldDecorator("est_ea", {
|
||||
initialValue: jobContext.est_ea,
|
||||
rules: [
|
||||
{
|
||||
type: "email",
|
||||
message: "This is not a valid email address."
|
||||
}
|
||||
]
|
||||
})(<Input name='est_ea' onChange={handleChange} />)}
|
||||
</Form.Item>
|
||||
</Col>
|
||||
</Row>
|
||||
</Form>
|
||||
</Content>
|
||||
);
|
||||
}
|
||||
|
||||
export default Form.create({ name: "JobTombstone" })(JobTombstone);
|
||||
@@ -0,0 +1,117 @@
|
||||
import {
|
||||
Avatar,
|
||||
Button,
|
||||
Descriptions,
|
||||
notification,
|
||||
PageHeader,
|
||||
Tag,
|
||||
Input,
|
||||
Form,
|
||||
Checkbox
|
||||
} from "antd";
|
||||
import React from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import Moment from "react-moment";
|
||||
import { Link } from "react-router-dom";
|
||||
import CarImage from "../../assets/car.svg";
|
||||
import CurrencyFormatter from "../../utils/CurrencyFormatter";
|
||||
|
||||
export default function JobsDetailHeader({
|
||||
job,
|
||||
mutationConvertJob,
|
||||
refetch,
|
||||
getFieldDecorator
|
||||
}) {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const tombstoneTitle = (
|
||||
<div>
|
||||
<Avatar size='large' alt='Vehicle Image' src={CarImage} />
|
||||
{`${t("jobs.fields.ro_number")} ${
|
||||
job.ro_number ? job.ro_number : t("general.labels.na")
|
||||
}`}
|
||||
</div>
|
||||
);
|
||||
|
||||
const tombstoneSubtitle = (
|
||||
<div>
|
||||
{job.owner
|
||||
? (job.owner.first_name || "") + " " + (job.owner.last_name || "")
|
||||
: t("jobs.errors.noowner")}
|
||||
|
||||
{job.vehicle ? (
|
||||
<Link to={`/manage/vehicles/${job.vehicle.id}`}>
|
||||
{job.vehicle.v_model_yr || t("general.labels.na")}{" "}
|
||||
{job.vehicle.v_make_desc || t("general.labels.na")}{" "}
|
||||
{job.vehicle.v_model_desc || t("general.labels.na")} |{" "}
|
||||
{job.vehicle.plate_no || t("general.labels.na")} |{" "}
|
||||
{job.vehicle.v_vin || t("general.labels.na")}
|
||||
</Link>
|
||||
) : null}
|
||||
</div>
|
||||
);
|
||||
|
||||
const menuExtra = [
|
||||
<Button
|
||||
key='convert'
|
||||
type='dashed'
|
||||
disabled={job.converted}
|
||||
onClick={() => {
|
||||
mutationConvertJob({
|
||||
variables: { jobId: job.id }
|
||||
}).then(r => {
|
||||
refetch();
|
||||
|
||||
notification["success"]({
|
||||
message: t("jobs.successes.converted")
|
||||
});
|
||||
});
|
||||
}}>
|
||||
{t("jobs.actions.convert")}
|
||||
</Button>,
|
||||
<Button type='primary' key='submit' htmlType='submit'>
|
||||
{t("general.labels.save")}
|
||||
</Button>
|
||||
];
|
||||
|
||||
return (
|
||||
<PageHeader
|
||||
style={{
|
||||
border: "1px solid rgb(235, 237, 240)"
|
||||
}}
|
||||
title={tombstoneTitle}
|
||||
subTitle={tombstoneSubtitle}
|
||||
tags={
|
||||
<span key='job-status'>
|
||||
{job.job_status ? (
|
||||
<Tag color='blue'>{job.job_status.name}</Tag>
|
||||
) : null}
|
||||
</span>
|
||||
}
|
||||
extra={menuExtra}>
|
||||
<Descriptions size='small' column={5}>
|
||||
<Descriptions.Item label={t("jobs.fields.repairtotal")}>
|
||||
<CurrencyFormatter>{job.claim_total}</CurrencyFormatter>
|
||||
</Descriptions.Item>
|
||||
|
||||
<Descriptions.Item label={t("jobs.fields.customerowing")}>
|
||||
$NO BINDING YET
|
||||
</Descriptions.Item>
|
||||
|
||||
<Descriptions.Item label={t("jobs.fields.specialcoveragepolicy")}>
|
||||
<Checkbox checked={job.special_coverage_policy} />
|
||||
</Descriptions.Item>
|
||||
|
||||
<Descriptions.Item label={t("jobs.fields.scheduled_completion")}>
|
||||
{job.scheduled_completion ? (
|
||||
<Moment format='MM/DD/YYYY'>{job.scheduled_completion}</Moment>
|
||||
) : null}
|
||||
</Descriptions.Item>
|
||||
|
||||
<Descriptions.Item label={t("jobs.fields.servicecar")}>
|
||||
{job.service_car}
|
||||
</Descriptions.Item>
|
||||
</Descriptions>
|
||||
</PageHeader>
|
||||
);
|
||||
}
|
||||
@@ -37,12 +37,12 @@ export default function NoteUpsertModalContainer({
|
||||
]
|
||||
}
|
||||
}).then(r => {
|
||||
refetch();
|
||||
changeVisibility(!visible);
|
||||
notification["success"]({
|
||||
message: t("notes.successes.create")
|
||||
});
|
||||
});
|
||||
refetch();
|
||||
changeVisibility(!visible);
|
||||
};
|
||||
|
||||
const updateExistingNote = () => {
|
||||
|
||||
Reference in New Issue
Block a user