CLEANUP on Jobs page. Now uses search param instead of state.
This commit is contained in:
@@ -22,6 +22,7 @@
|
|||||||
"graphql": "^14.6.0",
|
"graphql": "^14.6.0",
|
||||||
"i18next": "^19.3.4",
|
"i18next": "^19.3.4",
|
||||||
"node-sass": "^4.13.1",
|
"node-sass": "^4.13.1",
|
||||||
|
"query-string": "^6.11.1",
|
||||||
"react": "^16.13.1",
|
"react": "^16.13.1",
|
||||||
"react-apollo": "^3.1.3",
|
"react-apollo": "^3.1.3",
|
||||||
"react-barcode": "^1.4.0",
|
"react-barcode": "^1.4.0",
|
||||||
|
|||||||
@@ -63,7 +63,6 @@ function JobDetailCards({ selectedJob, setInvoiceEnterContext }) {
|
|||||||
/>
|
/>
|
||||||
<PageHeader
|
<PageHeader
|
||||||
ghost={false}
|
ghost={false}
|
||||||
onBack={() => window.history.back()}
|
|
||||||
tags={
|
tags={
|
||||||
<span key="job-status">
|
<span key="job-status">
|
||||||
{data.jobs_by_pk.status ? (
|
{data.jobs_by_pk.status ? (
|
||||||
@@ -96,7 +95,7 @@ function JobDetailCards({ selectedJob, setInvoiceEnterContext }) {
|
|||||||
</Button>,
|
</Button>,
|
||||||
<Link
|
<Link
|
||||||
key="documents"
|
key="documents"
|
||||||
to={`/manage/jobs/${data.jobs_by_pk.id}#documents`}
|
to={`/manage/jobs/${data.jobs_by_pk.id}?documents`}
|
||||||
>
|
>
|
||||||
<Button>
|
<Button>
|
||||||
<FileImageFilled />
|
<FileImageFilled />
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ export default function JobDetailCardsNotesComponent({ loading, data }) {
|
|||||||
<CardTemplate
|
<CardTemplate
|
||||||
loading={loading}
|
loading={loading}
|
||||||
title={t("jobs.labels.cards.notes")}
|
title={t("jobs.labels.cards.notes")}
|
||||||
extraLink={`/manage/jobs/${data.id}#notes`}
|
extraLink={`/manage/jobs/${data.id}?notes`}
|
||||||
>
|
>
|
||||||
{data ? (
|
{data ? (
|
||||||
<Container>
|
<Container>
|
||||||
|
|||||||
@@ -7,15 +7,14 @@ import CurrencyFormatter from "../../utils/CurrencyFormatter";
|
|||||||
import PhoneFormatter from "../../utils/PhoneFormatter";
|
import PhoneFormatter from "../../utils/PhoneFormatter";
|
||||||
import { alphaSort } from "../../utils/sorters";
|
import { alphaSort } from "../../utils/sorters";
|
||||||
import StartChatButton from "../chat-open-button/chat-open-button.component";
|
import StartChatButton from "../chat-open-button/chat-open-button.component";
|
||||||
|
import { useHistory } from "react-router-dom";
|
||||||
|
|
||||||
export default withRouter(function JobsList({
|
export default withRouter(function JobsList({
|
||||||
searchTextState,
|
searchTextState,
|
||||||
refetch,
|
refetch,
|
||||||
loading,
|
loading,
|
||||||
jobs,
|
jobs,
|
||||||
selectedJob,
|
selectedJob
|
||||||
setSelectedJob,
|
|
||||||
history
|
|
||||||
}) {
|
}) {
|
||||||
const [state, setState] = useState({
|
const [state, setState] = useState({
|
||||||
sortedInfo: {},
|
sortedInfo: {},
|
||||||
@@ -23,7 +22,7 @@ export default withRouter(function JobsList({
|
|||||||
});
|
});
|
||||||
|
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
const history = useHistory();
|
||||||
const setSearchText = searchTextState[1];
|
const setSearchText = searchTextState[1];
|
||||||
const columns = [
|
const columns = [
|
||||||
{
|
{
|
||||||
@@ -31,22 +30,18 @@ export default withRouter(function JobsList({
|
|||||||
dataIndex: "ro_number",
|
dataIndex: "ro_number",
|
||||||
key: "ro_number",
|
key: "ro_number",
|
||||||
width: "8%",
|
width: "8%",
|
||||||
// onFilter: (value, record) => record.ro_number.includes(value),
|
|
||||||
// filteredValue: state.filteredInfo.text || null,
|
|
||||||
sorter: (a, b) =>
|
sorter: (a, b) =>
|
||||||
alphaSort(
|
alphaSort(
|
||||||
a.ro_number ? a.ro_number : "EST-" + a.est_number,
|
a.ro_number ? a.ro_number : a.est_number,
|
||||||
b.ro_number ? b.ro_number : "EST-" + b.est_number
|
b.ro_number ? b.ro_number : b.est_number
|
||||||
),
|
),
|
||||||
sortOrder:
|
sortOrder:
|
||||||
state.sortedInfo.columnKey === "ro_number" && state.sortedInfo.order,
|
state.sortedInfo.columnKey === "ro_number" && state.sortedInfo.order,
|
||||||
|
|
||||||
render: (text, record) => (
|
render: (text, record) => (
|
||||||
<span>
|
<Link to={"/manage/jobs/" + record.id}>
|
||||||
<Link to={"/manage/jobs/" + record.id}>
|
{record.ro_number ? record.ro_number : record.est_number}
|
||||||
{record.ro_number ? record.ro_number : "EST-" + record.est_number}
|
</Link>
|
||||||
</Link>
|
|
||||||
</span>
|
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -61,10 +56,9 @@ export default withRouter(function JobsList({
|
|||||||
render: (text, record) => {
|
render: (text, record) => {
|
||||||
return record.owner ? (
|
return record.owner ? (
|
||||||
<Link to={"/manage/owners/" + record.owner.id}>
|
<Link to={"/manage/owners/" + record.owner.id}>
|
||||||
{record.ownr_fn} {record.ownr_ln}
|
{`${record.ownr_fn} ${record.ownr_ln}`}
|
||||||
</Link>
|
</Link>
|
||||||
) : (
|
) : (
|
||||||
// t("jobs.errors.noowner")
|
|
||||||
<span>{`${record.ownr_fn} ${record.ownr_ln}`}</span>
|
<span>{`${record.ownr_fn} ${record.ownr_ln}`}</span>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -81,9 +75,7 @@ export default withRouter(function JobsList({
|
|||||||
<PhoneFormatter>{record.ownr_ph1}</PhoneFormatter>
|
<PhoneFormatter>{record.ownr_ph1}</PhoneFormatter>
|
||||||
<StartChatButton phone={record.ownr_ph1} />
|
<StartChatButton phone={record.ownr_ph1} />
|
||||||
</span>
|
</span>
|
||||||
) : (
|
) : null;
|
||||||
t("general.labels.unknown")
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -113,7 +105,8 @@ export default withRouter(function JobsList({
|
|||||||
""} ${record.v_model_desc || ""}`}
|
""} ${record.v_model_desc || ""}`}
|
||||||
</Link>
|
</Link>
|
||||||
) : (
|
) : (
|
||||||
t("jobs.errors.novehicle")
|
<span>{`${record.v_model_yr || ""} ${record.v_make_desc ||
|
||||||
|
""} ${record.v_model_desc || ""}`}</span>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -127,11 +120,7 @@ export default withRouter(function JobsList({
|
|||||||
sortOrder:
|
sortOrder:
|
||||||
state.sortedInfo.columnKey === "plate_no" && state.sortedInfo.order,
|
state.sortedInfo.columnKey === "plate_no" && state.sortedInfo.order,
|
||||||
render: (text, record) => {
|
render: (text, record) => {
|
||||||
return record.plate_no ? (
|
return record.plate_no ? record.plate_no : "";
|
||||||
<span>{record.plate_no}</span>
|
|
||||||
) : (
|
|
||||||
t("general.labels.unknown")
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -186,19 +175,12 @@ export default withRouter(function JobsList({
|
|||||||
setState({ ...state, filteredInfo: filters, sortedInfo: sorter });
|
setState({ ...state, filteredInfo: filters, sortedInfo: sorter });
|
||||||
};
|
};
|
||||||
|
|
||||||
// const handleChange = event => {
|
|
||||||
// const { value } = event.target;
|
|
||||||
// setState({ ...state, filterinfo: { text: [value] } });
|
|
||||||
// };
|
|
||||||
|
|
||||||
const handleOnRowClick = record => {
|
const handleOnRowClick = record => {
|
||||||
if (record) {
|
if (record) {
|
||||||
if (record.id) {
|
if (record.id) {
|
||||||
setSelectedJob(record.id);
|
history.push({ search: `selected=${record.id}` });
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
setSelectedJob(null);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -212,7 +194,7 @@ export default withRouter(function JobsList({
|
|||||||
<SyncOutlined />
|
<SyncOutlined />
|
||||||
</Button>
|
</Button>
|
||||||
<Input.Search
|
<Input.Search
|
||||||
placeholder="Search..."
|
placeholder={t("general.labels.search")}
|
||||||
onChange={e => {
|
onChange={e => {
|
||||||
setSearchText(e.target.value);
|
setSearchText(e.target.value);
|
||||||
}}
|
}}
|
||||||
@@ -226,7 +208,13 @@ export default withRouter(function JobsList({
|
|||||||
columns={columns.map(item => ({ ...item }))}
|
columns={columns.map(item => ({ ...item }))}
|
||||||
rowKey="id"
|
rowKey="id"
|
||||||
dataSource={jobs}
|
dataSource={jobs}
|
||||||
rowSelection={{ selectedRowKeys: [selectedJob] }}
|
rowSelection={{
|
||||||
|
onSelect: record => {
|
||||||
|
handleOnRowClick(record);
|
||||||
|
},
|
||||||
|
selectedRowKeys: [selectedJob],
|
||||||
|
type: "radio"
|
||||||
|
}}
|
||||||
onChange={handleTableChange}
|
onChange={handleTableChange}
|
||||||
onRow={(record, rowIndex) => {
|
onRow={(record, rowIndex) => {
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -1,5 +0,0 @@
|
|||||||
import React from "react";
|
|
||||||
|
|
||||||
export default function ErrorNotFound() {
|
|
||||||
return <div>Uh oh, we couldn't find the page you're looking for.</div>;
|
|
||||||
}
|
|
||||||
@@ -1,27 +1,22 @@
|
|||||||
import { useQuery } from "@apollo/react-hooks";
|
import { useQuery } from "@apollo/react-hooks";
|
||||||
|
import queryString from "query-string";
|
||||||
import React, { useEffect, useState } from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
|
import { connect } from "react-redux";
|
||||||
|
import { createStructuredSelector } from "reselect";
|
||||||
import AlertComponent from "../../components/alert/alert.component";
|
import AlertComponent from "../../components/alert/alert.component";
|
||||||
|
import EnterInvoiceModalContainer from "../../components/invoice-enter-modal/invoice-enter-modal.container";
|
||||||
import JobDetailCards from "../../components/job-detail-cards/job-detail-cards.component";
|
import JobDetailCards from "../../components/job-detail-cards/job-detail-cards.component";
|
||||||
import JobsList from "../../components/jobs-list/jobs-list.component";
|
import JobsList from "../../components/jobs-list/jobs-list.component";
|
||||||
import { QUERY_ALL_ACTIVE_JOBS } from "../../graphql/jobs.queries";
|
import { QUERY_ALL_ACTIVE_JOBS } from "../../graphql/jobs.queries";
|
||||||
|
|
||||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||||
|
|
||||||
import { connect } from "react-redux";
|
|
||||||
import { createStructuredSelector } from "reselect";
|
|
||||||
import EnterInvoiceModalContainer from "../../components/invoice-enter-modal/invoice-enter-modal.container";
|
|
||||||
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
bodyshop: selectBodyshop
|
bodyshop: selectBodyshop
|
||||||
});
|
});
|
||||||
|
|
||||||
export default connect(
|
export function JobsPage({ location, bodyshop }) {
|
||||||
mapStateToProps,
|
|
||||||
null
|
|
||||||
)(function JobsPage({ match, location, bodyshop }) {
|
|
||||||
const { loading, error, data, refetch } = useQuery(QUERY_ALL_ACTIVE_JOBS, {
|
const { loading, error, data, refetch } = useQuery(QUERY_ALL_ACTIVE_JOBS, {
|
||||||
fetchPolicy: "network-only",
|
|
||||||
variables: {
|
variables: {
|
||||||
statuses: bodyshop.md_ro_statuses.open_statuses || ["Open"]
|
statuses: bodyshop.md_ro_statuses.open_statuses || ["Open"]
|
||||||
}
|
}
|
||||||
@@ -32,8 +27,7 @@ export default connect(
|
|||||||
document.title = t("titles.jobs");
|
document.title = t("titles.jobs");
|
||||||
}, [t]);
|
}, [t]);
|
||||||
|
|
||||||
const { hash } = location;
|
const search = queryString.parse(location.search);
|
||||||
const [selectedJob, setSelectedJob] = useState(hash ? hash.substr(1) : null);
|
|
||||||
const searchTextState = useState("");
|
const searchTextState = useState("");
|
||||||
const searchText = searchTextState[0];
|
const searchText = searchTextState[0];
|
||||||
if (error) return <AlertComponent message={error.message} type="error" />;
|
if (error) return <AlertComponent message={error.message} type="error" />;
|
||||||
@@ -45,11 +39,11 @@ export default connect(
|
|||||||
searchTextState={searchTextState}
|
searchTextState={searchTextState}
|
||||||
refetch={refetch}
|
refetch={refetch}
|
||||||
loading={loading}
|
loading={loading}
|
||||||
selectedJob={selectedJob}
|
selectedJob={search.selected}
|
||||||
setSelectedJob={setSelectedJob}
|
//setSelectedJob={setSelectedJob}
|
||||||
jobs={
|
jobs={
|
||||||
data
|
data
|
||||||
? searchTextState[0] === ""
|
? searchText === ""
|
||||||
? data.jobs
|
? data.jobs
|
||||||
: data.jobs.filter(
|
: data.jobs.filter(
|
||||||
j =>
|
j =>
|
||||||
@@ -79,7 +73,9 @@ export default connect(
|
|||||||
: null
|
: null
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<JobDetailCards selectedJob={selectedJob} />
|
<JobDetailCards selectedJob={search.selected} />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
});
|
}
|
||||||
|
|
||||||
|
export default connect(mapStateToProps, null)(JobsPage);
|
||||||
|
|||||||
@@ -10643,6 +10643,15 @@ query-string@^4.1.0:
|
|||||||
object-assign "^4.1.0"
|
object-assign "^4.1.0"
|
||||||
strict-uri-encode "^1.0.0"
|
strict-uri-encode "^1.0.0"
|
||||||
|
|
||||||
|
query-string@^6.11.1:
|
||||||
|
version "6.11.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/query-string/-/query-string-6.11.1.tgz#ab021f275d463ce1b61e88f0ce6988b3e8fe7c2c"
|
||||||
|
integrity sha512-1ZvJOUl8ifkkBxu2ByVM/8GijMIPx+cef7u3yroO3Ogm4DOdZcF5dcrWTIlSHe3Pg/mtlt6/eFjObDfJureZZA==
|
||||||
|
dependencies:
|
||||||
|
decode-uri-component "^0.2.0"
|
||||||
|
split-on-first "^1.0.0"
|
||||||
|
strict-uri-encode "^2.0.0"
|
||||||
|
|
||||||
querystring-es3@^0.2.0:
|
querystring-es3@^0.2.0:
|
||||||
version "0.2.1"
|
version "0.2.1"
|
||||||
resolved "https://registry.yarnpkg.com/querystring-es3/-/querystring-es3-0.2.1.tgz#9ec61f79049875707d69414596fd907a4d711e73"
|
resolved "https://registry.yarnpkg.com/querystring-es3/-/querystring-es3-0.2.1.tgz#9ec61f79049875707d69414596fd907a4d711e73"
|
||||||
@@ -12583,6 +12592,11 @@ spdy@^4.0.1:
|
|||||||
select-hose "^2.0.0"
|
select-hose "^2.0.0"
|
||||||
spdy-transport "^3.0.0"
|
spdy-transport "^3.0.0"
|
||||||
|
|
||||||
|
split-on-first@^1.0.0:
|
||||||
|
version "1.1.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/split-on-first/-/split-on-first-1.1.0.tgz#f610afeee3b12bce1d0c30425e76398b78249a5f"
|
||||||
|
integrity sha512-43ZssAJaMusuKWL8sKUBQXHWOpq8d6CfN/u1p4gUzfJkM05C8rxTmYrkIPTXapZpORA6LkkzcUulJ8FqA7Uudw==
|
||||||
|
|
||||||
split-string@^3.0.1, split-string@^3.0.2:
|
split-string@^3.0.1, split-string@^3.0.2:
|
||||||
version "3.1.0"
|
version "3.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2"
|
resolved "https://registry.yarnpkg.com/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2"
|
||||||
@@ -12726,6 +12740,11 @@ strict-uri-encode@^1.0.0:
|
|||||||
resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz#279b225df1d582b1f54e65addd4352e18faa0713"
|
resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz#279b225df1d582b1f54e65addd4352e18faa0713"
|
||||||
integrity sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM=
|
integrity sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM=
|
||||||
|
|
||||||
|
strict-uri-encode@^2.0.0:
|
||||||
|
version "2.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz#b9c7330c7042862f6b142dc274bbcc5866ce3546"
|
||||||
|
integrity sha1-ucczDHBChi9rFC3CdLvMWGbONUY=
|
||||||
|
|
||||||
string-convert@^0.2.0:
|
string-convert@^0.2.0:
|
||||||
version "0.2.1"
|
version "0.2.1"
|
||||||
resolved "https://registry.yarnpkg.com/string-convert/-/string-convert-0.2.1.tgz#6982cc3049fbb4cd85f8b24568b9d9bf39eeff97"
|
resolved "https://registry.yarnpkg.com/string-convert/-/string-convert-0.2.1.tgz#6982cc3049fbb4cd85f8b24568b9d9bf39eeff97"
|
||||||
|
|||||||
Reference in New Issue
Block a user