Complete refactor of jobs detail screen.
This commit is contained in:
@@ -0,0 +1,9 @@
|
||||
import React from 'react'
|
||||
|
||||
export default function JobsAvailablePageComponent() {
|
||||
return (
|
||||
<div>
|
||||
JobsAvailablePageComponent
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
import React from 'react'
|
||||
import JobsAvailablePageComponent from './jobs-available.page.component'
|
||||
|
||||
export default function JobsAvailablePageContainer() {
|
||||
return (
|
||||
<div>
|
||||
<JobsAvailablePageComponent />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
181
client/src/pages/jobs-detail/jobs-detail.page.component.jsx
Normal file
181
client/src/pages/jobs-detail/jobs-detail.page.component.jsx
Normal file
@@ -0,0 +1,181 @@
|
||||
import { Form, Icon, Tabs } from "antd";
|
||||
import React from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { FaRegStickyNote } from "react-icons/fa";
|
||||
import JobLinesContainer from "../../components/job-lines/job-lines.container.component";
|
||||
import JobsDetailHeader from "../../components/jobs-detail-header/jobs-detail-header.component";
|
||||
import JobsDocumentsContainer from "../../components/jobs-documents/jobs-documents.container";
|
||||
import JobNotesContainer from "../../components/jobs-notes/jobs-notes.container";
|
||||
import JobsRatesContainer from "../../components/jobs-rates/jobs-rates.container";
|
||||
|
||||
export default function JobsDetailPage({
|
||||
job,
|
||||
mutationUpdateJob,
|
||||
mutationConvertJob,
|
||||
handleSubmit,
|
||||
handleChange,
|
||||
getFieldDecorator,
|
||||
refetch
|
||||
}) {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const formItemLayout = {
|
||||
labelCol: {
|
||||
xs: { span: 12 },
|
||||
sm: { span: 5 }
|
||||
},
|
||||
wrapperCol: {
|
||||
xs: { span: 24 },
|
||||
sm: { span: 12 }
|
||||
}
|
||||
};
|
||||
|
||||
// const TEMP = (
|
||||
// <div>
|
||||
// {" "}
|
||||
// <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>
|
||||
// <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>
|
||||
// </div>
|
||||
// );
|
||||
|
||||
return (
|
||||
<Form onSubmit={handleSubmit} {...formItemLayout}>
|
||||
<JobsDetailHeader
|
||||
job={job}
|
||||
mutationConvertJob={mutationConvertJob}
|
||||
refetch={refetch}
|
||||
getFieldDecorator={getFieldDecorator}
|
||||
/>
|
||||
|
||||
<Tabs defaultActiveKey='claimdetail'>
|
||||
<Tabs.TabPane
|
||||
tab={
|
||||
<span>
|
||||
<Icon type='bars' />
|
||||
{t("menus.jobsdetail.claimdetail")}
|
||||
</span>
|
||||
}
|
||||
key='claimdetail'>
|
||||
Claim detail
|
||||
</Tabs.TabPane>
|
||||
|
||||
<Tabs.TabPane
|
||||
tab={
|
||||
<span>
|
||||
<Icon type='bars' />
|
||||
{t("menus.jobsdetail.insurance")}
|
||||
</span>
|
||||
}
|
||||
key='insurance'>
|
||||
Insurance
|
||||
</Tabs.TabPane>
|
||||
|
||||
<Tabs.TabPane
|
||||
tab={
|
||||
<span>
|
||||
<Icon type='bars' />
|
||||
{t("menus.jobsdetail.repairdata")}
|
||||
</span>
|
||||
}
|
||||
key='repairdata'>
|
||||
<JobLinesContainer jobId={job.id} />
|
||||
</Tabs.TabPane>
|
||||
|
||||
<Tabs.TabPane
|
||||
tab={
|
||||
<span>
|
||||
<Icon type='dollar' />
|
||||
{t("menus.jobsdetail.financials")}
|
||||
</span>
|
||||
}
|
||||
key='financials'>
|
||||
<JobsRatesContainer />
|
||||
</Tabs.TabPane>
|
||||
|
||||
<Tabs.TabPane
|
||||
tab={
|
||||
<span>
|
||||
<Icon type='bars' />
|
||||
{t("menus.jobsdetail.partssublet")}
|
||||
</span>
|
||||
}
|
||||
key='partssublet'>
|
||||
Partssublet
|
||||
</Tabs.TabPane>
|
||||
|
||||
<Tabs.TabPane
|
||||
tab={
|
||||
<span>
|
||||
<Icon type='bars' />
|
||||
{t("menus.jobsdetail.labor")}
|
||||
</span>
|
||||
}
|
||||
key='labor'>
|
||||
Labor
|
||||
</Tabs.TabPane>
|
||||
|
||||
<Tabs.TabPane
|
||||
tab={
|
||||
<span>
|
||||
<Icon type='bars' />
|
||||
{t("menus.jobsdetail.dates")}
|
||||
</span>
|
||||
}
|
||||
key='dates'>
|
||||
Dates
|
||||
</Tabs.TabPane>
|
||||
|
||||
<Tabs.TabPane
|
||||
tab={
|
||||
<span>
|
||||
<Icon type='file-image' />
|
||||
{t("jobs.labels.documents")}
|
||||
</span>
|
||||
}
|
||||
key='#documents'>
|
||||
<JobsDocumentsContainer jobId={job.id} />
|
||||
</Tabs.TabPane>
|
||||
<Tabs.TabPane
|
||||
tab={
|
||||
<span>
|
||||
<Icon component={FaRegStickyNote} />
|
||||
{t("jobs.labels.notes")}
|
||||
</span>
|
||||
}
|
||||
key='#notes'>
|
||||
<JobNotesContainer jobId={job.id} />
|
||||
</Tabs.TabPane>
|
||||
</Tabs>
|
||||
</Form>
|
||||
);
|
||||
}
|
||||
@@ -1,38 +1,79 @@
|
||||
import { useQuery } from "@apollo/react-hooks";
|
||||
import { Form, notification } from "antd";
|
||||
import React, { useEffect } from "react";
|
||||
import { useMutation, useQuery } from "react-apollo";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import AlertComponent from "../../components/alert/alert.component";
|
||||
import SpinComponent from "../../components/loading-spinner/loading-spinner.component";
|
||||
import { GET_JOB_BY_PK } from "../../graphql/jobs.queries";
|
||||
import JobsDetailPage from "./jobs-detail.page";
|
||||
import {
|
||||
GET_JOB_BY_PK,
|
||||
UPDATE_JOB,
|
||||
CONVERT_JOB_TO_RO
|
||||
} from "../../graphql/jobs.queries";
|
||||
import JobsDetailPage from "./jobs-detail.page.component";
|
||||
|
||||
function JobsDetailPageContainer({ match, location }) {
|
||||
function JobsDetailPageContainer({ match, form }) {
|
||||
const { jobId } = match.params;
|
||||
const { hash } = location;
|
||||
const { t } = useTranslation();
|
||||
const { loading, error, data } = useQuery(GET_JOB_BY_PK, {
|
||||
|
||||
const { loading, error, data, refetch } = useQuery(GET_JOB_BY_PK, {
|
||||
variables: { id: jobId },
|
||||
fetchPolicy: "network-only"
|
||||
});
|
||||
const [mutationUpdateJob] = useMutation(UPDATE_JOB);
|
||||
const [mutationConvertJob] = useMutation(CONVERT_JOB_TO_RO);
|
||||
|
||||
useEffect(() => {
|
||||
document.title = loading
|
||||
? "..."
|
||||
: t("titles.jobsdetail", {
|
||||
ro_number: data.jobs_by_pk.ro_number
|
||||
document.title =
|
||||
loading && !error
|
||||
? "..."
|
||||
: t("titles.jobsdetail", {
|
||||
ro_number: data.jobs_by_pk.ro_number
|
||||
});
|
||||
}, [loading, data, t, error]);
|
||||
|
||||
const handleSubmit = e => {
|
||||
e.preventDefault();
|
||||
|
||||
form.validateFieldsAndScroll((err, values) => {
|
||||
if (err) {
|
||||
notification["error"]({
|
||||
message: t("jobs.errors.validationtitle"),
|
||||
description: t("jobs.errors.validation")
|
||||
});
|
||||
}, [loading, data, t]);
|
||||
}
|
||||
if (!err) {
|
||||
mutationUpdateJob({
|
||||
variables: { jobId: data.jobs_by_pk.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 });
|
||||
};
|
||||
|
||||
if (loading) return <SpinComponent />;
|
||||
if (error) return <AlertComponent message={error.message} type='error' />;
|
||||
|
||||
return (
|
||||
return data.jobs_by_pk ? (
|
||||
<JobsDetailPage
|
||||
hash={hash ? hash.substring(1) : "#lines"}
|
||||
data={data}
|
||||
jobId={jobId}
|
||||
match={match}
|
||||
job={data.jobs_by_pk}
|
||||
mutationUpdateJob={mutationUpdateJob}
|
||||
mutationConvertJob={mutationConvertJob}
|
||||
handleSubmit={handleSubmit}
|
||||
handleChange={handleChange}
|
||||
getFieldDecorator={form.getFieldDecorator}
|
||||
refetch={refetch}
|
||||
/>
|
||||
) : (
|
||||
<AlertComponent message={t("jobs.errors.noaccess")} type='error' />
|
||||
);
|
||||
}
|
||||
export default JobsDetailPageContainer;
|
||||
export default Form.create({ name: "JobsDetailPageContainer" })(
|
||||
JobsDetailPageContainer
|
||||
);
|
||||
|
||||
@@ -1,80 +0,0 @@
|
||||
import { Icon, Row, Tabs } from "antd";
|
||||
import React from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { FaRegStickyNote } from "react-icons/fa";
|
||||
import { withRouter } from "react-router-dom";
|
||||
import JobLinesContainer from "../../components/job-lines/job-lines.container.component";
|
||||
import JobTombstone from "../../components/job-tombstone/job-tombstone.component";
|
||||
import JobsDocumentsContainer from "../../components/jobs-documents/jobs-documents.container";
|
||||
import JobNotesContainer from "../../components/jobs-notes/jobs-notes.container";
|
||||
import JobsRatesContainer from "../../components/jobs-rates/jobs-rates.container";
|
||||
|
||||
function JobsDetailPage({ jobId, hash, data, match, history }) {
|
||||
const { t } = useTranslation();
|
||||
return (
|
||||
<div>
|
||||
<Row>
|
||||
<JobTombstone job={data.jobs_by_pk} />
|
||||
</Row>
|
||||
<Row>
|
||||
<Tabs
|
||||
defaultActiveKey={`#${hash}`}
|
||||
onChange={p => {
|
||||
history.push(p);
|
||||
}}>
|
||||
<Tabs.TabPane
|
||||
tab={
|
||||
<span>
|
||||
<Icon type='bars' />
|
||||
{t("jobs.labels.lines")}
|
||||
</span>
|
||||
}
|
||||
key='#lines'>
|
||||
<JobLinesContainer match={match} />
|
||||
</Tabs.TabPane>
|
||||
<Tabs.TabPane
|
||||
tab={
|
||||
<span>
|
||||
<Icon type='dollar' />
|
||||
{t("jobs.labels.rates")}
|
||||
</span>
|
||||
}
|
||||
key='#rates'>
|
||||
<JobsRatesContainer />
|
||||
</Tabs.TabPane>
|
||||
<Tabs.TabPane
|
||||
tab={
|
||||
<span>
|
||||
<Icon type='tool1' />
|
||||
{t("jobs.labels.parts")}
|
||||
</span>
|
||||
}
|
||||
key='#parts'>
|
||||
Estimate Parts
|
||||
</Tabs.TabPane>
|
||||
<Tabs.TabPane
|
||||
tab={
|
||||
<span>
|
||||
<Icon type='file-image' />
|
||||
{t("jobs.labels.documents")}
|
||||
</span>
|
||||
}
|
||||
key='#documents'>
|
||||
<JobsDocumentsContainer jobId={jobId} />
|
||||
</Tabs.TabPane>
|
||||
<Tabs.TabPane
|
||||
tab={
|
||||
<span>
|
||||
<Icon component={FaRegStickyNote} />
|
||||
{t("jobs.labels.notes")}
|
||||
</span>
|
||||
}
|
||||
key='#notes'>
|
||||
<JobNotesContainer jobId={jobId} />
|
||||
</Tabs.TabPane>
|
||||
</Tabs>
|
||||
</Row>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
export default withRouter(JobsDetailPage);
|
||||
@@ -20,6 +20,9 @@ const ProfilePage = lazy(() => import("../profile/profile.container.page"));
|
||||
const JobsDocumentsPage = lazy(() =>
|
||||
import("../../components/jobs-documents/jobs-documents.container")
|
||||
);
|
||||
const JobsAvailablePage = lazy(() =>
|
||||
import("../jobs-available/jobs-available.page.container")
|
||||
);
|
||||
|
||||
const { Header, Content, Footer } = Layout;
|
||||
//This page will handle all routing for the entire application.
|
||||
@@ -43,6 +46,7 @@ export default function Manage({ match }) {
|
||||
<Route exact path={`${match.path}`} component={WhiteBoardPage} />
|
||||
|
||||
<Route exact path={`${match.path}/jobs`} component={JobsPage} />
|
||||
|
||||
<Route
|
||||
exact
|
||||
path={`${match.path}/jobs/:jobId`}
|
||||
@@ -58,6 +62,12 @@ export default function Manage({ match }) {
|
||||
path={`${match.path}/profile`}
|
||||
component={ProfilePage}
|
||||
/>
|
||||
|
||||
<Route
|
||||
exact
|
||||
path={`${match.path}/available`}
|
||||
component={JobsAvailablePage}
|
||||
/>
|
||||
</Suspense>
|
||||
</ErrorBoundary>
|
||||
</Content>
|
||||
|
||||
Reference in New Issue
Block a user