Merged in feature/IO-2531-Retain-Filter-State-on-Jobs-Page (pull request #1166)

IO-2531 Retain Filtered Statue for Jobs Pages

Approved-by: Dave Richer
This commit is contained in:
Allan Carr
2024-01-16 20:22:04 +00:00
committed by Dave Richer
3 changed files with 396 additions and 379 deletions

View File

@@ -10,9 +10,10 @@ import { Link, useHistory, useLocation } from "react-router-dom";
import { createStructuredSelector } from "reselect"; import { createStructuredSelector } from "reselect";
import { selectBodyshop } from "../../redux/user/user.selectors"; import { selectBodyshop } from "../../redux/user/user.selectors";
import CurrencyFormatter from "../../utils/CurrencyFormatter"; import CurrencyFormatter from "../../utils/CurrencyFormatter";
import { pageLimit } from "../../utils/config";
import useLocalStorage from "../../utils/useLocalStorage";
import StartChatButton from "../chat-open-button/chat-open-button.component"; import StartChatButton from "../chat-open-button/chat-open-button.component";
import OwnerNameDisplay from "../owner-name-display/owner-name-display.component"; import OwnerNameDisplay from "../owner-name-display/owner-name-display.component";
import {pageLimit} from "../../utils/config";
const mapStateToProps = createStructuredSelector({ const mapStateToProps = createStructuredSelector({
//currentUser: selectCurrentUser //currentUser: selectCurrentUser
bodyshop: selectBodyshop, bodyshop: selectBodyshop,
@@ -25,6 +26,7 @@ export function JobsList({ bodyshop, refetch, loading, jobs, total }) {
const search = queryString.parse(useLocation().search); const search = queryString.parse(useLocation().search);
const [openSearchResults, setOpenSearchResults] = useState([]); const [openSearchResults, setOpenSearchResults] = useState([]);
const [searchLoading, setSearchLoading] = useState(false); const [searchLoading, setSearchLoading] = useState(false);
const [filter, setFilter] = useLocalStorage("filter_jobs_all", null);
const { page, sortcolumn, sortorder } = search; const { page, sortcolumn, sortorder } = search;
const history = useHistory(); const history = useHistory();
@@ -93,6 +95,7 @@ export function JobsList({ bodyshop, refetch, loading, jobs, total }) {
render: (text, record) => { render: (text, record) => {
return record.status || t("general.labels.na"); return record.status || t("general.labels.na");
}, },
filteredValue: filter?.status || null,
filters: bodyshop.md_ro_statuses.statuses.map((s) => { filters: bodyshop.md_ro_statuses.statuses.map((s) => {
return { text: s, value: [s] }; return { text: s, value: [s] };
}), }),
@@ -189,6 +192,7 @@ export function JobsList({ bodyshop, refetch, loading, jobs, total }) {
} else { } else {
delete search.statusFilters; delete search.statusFilters;
} }
setFilter(filters);
history.push({ search: queryString.stringify(search) }); history.push({ search: queryString.stringify(search) });
}; };

View File

@@ -1,8 +1,8 @@
import { import {
SyncOutlined, BranchesOutlined,
ExclamationCircleFilled, ExclamationCircleFilled,
PauseCircleOutlined, PauseCircleOutlined,
BranchesOutlined, SyncOutlined,
} from "@ant-design/icons"; } from "@ant-design/icons";
import { useQuery } from "@apollo/client"; import { useQuery } from "@apollo/client";
import { Button, Card, Grid, Input, Space, Table, Tooltip } from "antd"; import { Button, Card, Grid, Input, Space, Table, Tooltip } from "antd";
@@ -14,9 +14,10 @@ import { Link, useHistory, useLocation } from "react-router-dom";
import { createStructuredSelector } from "reselect"; import { createStructuredSelector } from "reselect";
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 { onlyUnique } from "../../utils/arrayHelper";
import CurrencyFormatter from "../../utils/CurrencyFormatter"; import CurrencyFormatter from "../../utils/CurrencyFormatter";
import { alphaSort } from "../../utils/sorters"; import { onlyUnique } from "../../utils/arrayHelper";
import { alphaSort, statusSort } from "../../utils/sorters";
import useLocalStorage from "../../utils/useLocalStorage";
import AlertComponent from "../alert/alert.component"; import AlertComponent from "../alert/alert.component";
import ChatOpenButton from "../chat-open-button/chat-open-button.component"; import ChatOpenButton from "../chat-open-button/chat-open-button.component";
import OwnerNameDisplay from "../owner-name-display/owner-name-display.component"; import OwnerNameDisplay from "../owner-name-display/owner-name-display.component";
@@ -39,10 +40,8 @@ export function JobsList({ bodyshop }) {
nextFetchPolicy: "network-only", nextFetchPolicy: "network-only",
}); });
const [state, setState] = useState({ const [state, setState] = useState({ sortedInfo: {} });
sortedInfo: {}, const [filter, setFilter] = useLocalStorage("filter_jobs_list", null);
filteredInfo: { text: "" },
});
const { t } = useTranslation(); const { t } = useTranslation();
const history = useHistory(); const history = useHistory();
@@ -91,7 +90,8 @@ export function JobsList({ bodyshop }) {
: []; : [];
const handleTableChange = (pagination, filters, sorter) => { const handleTableChange = (pagination, filters, sorter) => {
setState({ ...state, filteredInfo: filters, sortedInfo: sorter }); setState({ ...state, sortedInfo: sorter });
setFilter(filters);
}; };
const handleOnRowClick = (record) => { const handleOnRowClick = (record) => {
@@ -117,7 +117,6 @@ export function JobsList({ bodyshop }) {
parseInt((b.ro_number || "0").replace(/\D/g, "")), parseInt((b.ro_number || "0").replace(/\D/g, "")),
sortOrder: sortOrder:
state.sortedInfo.columnKey === "ro_number" && state.sortedInfo.order, state.sortedInfo.columnKey === "ro_number" && state.sortedInfo.order,
render: (text, record) => ( render: (text, record) => (
<Link <Link
to={"/manage/jobs/" + record.id} to={"/manage/jobs/" + record.id}
@@ -145,7 +144,6 @@ export function JobsList({ bodyshop }) {
dataIndex: "owner", dataIndex: "owner",
key: "owner", key: "owner",
ellipsis: true, ellipsis: true,
responsive: ["md"], responsive: ["md"],
sorter: (a, b) => alphaSort(a.ownr_ln, b.ownr_ln), sorter: (a, b) => alphaSort(a.ownr_ln, b.ownr_ln),
sortOrder: sortOrder:
@@ -185,16 +183,15 @@ export function JobsList({ bodyshop }) {
<ChatOpenButton phone={record.ownr_ph2} jobid={record.id} /> <ChatOpenButton phone={record.ownr_ph2} jobid={record.id} />
), ),
}, },
{ {
title: t("jobs.fields.status"), title: t("jobs.fields.status"),
dataIndex: "status", dataIndex: "status",
key: "status", key: "status",
ellipsis: true, ellipsis: true,
sorter: (a, b) => alphaSort(a.status, b.status), sorter: (a, b) => alphaSort(a.status, b.status),
sortOrder: sortOrder:
state.sortedInfo.columnKey === "status" && state.sortedInfo.order, state.sortedInfo.columnKey === "status" && state.sortedInfo.order,
filteredValue: filter?.status || null,
filters: filters:
(jobs && (jobs &&
jobs jobs
@@ -205,7 +202,14 @@ export function JobsList({ bodyshop }) {
text: s || "No Status*", text: s || "No Status*",
value: [s], value: [s],
}; };
})) || })
.sort((a, b) =>
statusSort(
a.text,
b.text,
bodyshop.md_ro_statuses.active_statuses
)
)) ||
[], [],
onFilter: (value, record) => value.includes(record.status), onFilter: (value, record) => value.includes(record.status),
}, },
@@ -262,6 +266,7 @@ export function JobsList({ bodyshop }) {
dataIndex: "ins_co_nm", dataIndex: "ins_co_nm",
key: "ins_co_nm", key: "ins_co_nm",
ellipsis: true, ellipsis: true,
filteredValue: filter?.ins_co_nm || null,
filters: filters:
(jobs && (jobs &&
jobs jobs
@@ -269,10 +274,11 @@ export function JobsList({ bodyshop }) {
.filter(onlyUnique) .filter(onlyUnique)
.map((s) => { .map((s) => {
return { return {
text: s, text: s || "No Ins. Co.*",
value: [s], value: [s],
}; };
})) || })
.sort((a, b) => alphaSort(a.text, b.text))) ||
[], [],
onFilter: (value, record) => value.includes(record.ins_co_nm), onFilter: (value, record) => value.includes(record.ins_co_nm),
responsive: ["md"], responsive: ["md"],
@@ -283,7 +289,6 @@ export function JobsList({ bodyshop }) {
key: "clm_total", key: "clm_total",
responsive: ["md"], responsive: ["md"],
ellipsis: true, ellipsis: true,
sorter: (a, b) => a.clm_total - b.clm_total, sorter: (a, b) => a.clm_total - b.clm_total,
sortOrder: sortOrder:
state.sortedInfo.columnKey === "clm_total" && state.sortedInfo.order, state.sortedInfo.columnKey === "clm_total" && state.sortedInfo.order,
@@ -294,10 +299,11 @@ export function JobsList({ bodyshop }) {
{ {
title: t("jobs.labels.estimator"), title: t("jobs.labels.estimator"),
dataIndex: "jobs.labels.estimator", dataIndex: "jobs.labels.estimator",
key: "jobs.labels.estimator", key: "estimator",
ellipsis: true, ellipsis: true,
responsive: ["xl"], responsive: ["xl"],
filterSearch: true, filterSearch: true,
filteredValue: filter?.estimator || null,
filters: filters:
(jobs && (jobs &&
jobs jobs
@@ -305,10 +311,11 @@ export function JobsList({ bodyshop }) {
.filter(onlyUnique) .filter(onlyUnique)
.map((s) => { .map((s) => {
return { return {
text: s || "N/A", text: s || "No Estimator*",
value: [s], value: [s],
}; };
})) || })
.sort((a, b) => alphaSort(a.text, b.text))) ||
[], [],
onFilter: (value, record) => onFilter: (value, record) =>
value.includes( value.includes(

View File

@@ -16,11 +16,12 @@ import { QUERY_ALL_ACTIVE_JOBS } from "../../graphql/jobs.queries";
import { selectBodyshop } from "../../redux/user/user.selectors"; import { selectBodyshop } from "../../redux/user/user.selectors";
import CurrencyFormatter from "../../utils/CurrencyFormatter"; import CurrencyFormatter from "../../utils/CurrencyFormatter";
import { onlyUnique } from "../../utils/arrayHelper"; import { onlyUnique } from "../../utils/arrayHelper";
import { alphaSort } from "../../utils/sorters"; import { pageLimit } from "../../utils/config";
import { alphaSort, statusSort } from "../../utils/sorters";
import useLocalStorage from "../../utils/useLocalStorage";
import AlertComponent from "../alert/alert.component"; import AlertComponent from "../alert/alert.component";
import ChatOpenButton from "../chat-open-button/chat-open-button.component"; import ChatOpenButton from "../chat-open-button/chat-open-button.component";
import OwnerNameDisplay from "../owner-name-display/owner-name-display.component"; import OwnerNameDisplay from "../owner-name-display/owner-name-display.component";
import {pageLimit} from "../../utils/config";
const mapStateToProps = createStructuredSelector({ const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop, bodyshop: selectBodyshop,
@@ -53,10 +54,8 @@ export function JobsReadyList({ bodyshop }) {
nextFetchPolicy: "network-only", nextFetchPolicy: "network-only",
}); });
const [state, setState] = useState({ const [state, setState] = useState({ sortedInfo: {} });
sortedInfo: {}, const [filter, setFilter] = useLocalStorage("filter_jobs_ready", null);
filteredInfo: { text: "" },
});
const { t } = useTranslation(); const { t } = useTranslation();
const history = useHistory(); const history = useHistory();
@@ -105,7 +104,8 @@ export function JobsReadyList({ bodyshop }) {
: []; : [];
const handleTableChange = (pagination, filters, sorter) => { const handleTableChange = (pagination, filters, sorter) => {
setState({ ...state, filteredInfo: filters, sortedInfo: sorter }); setState({ ...state, sortedInfo: sorter });
setFilter(filters);
}; };
const handleOnRowClick = (record) => { const handleOnRowClick = (record) => {
@@ -129,7 +129,6 @@ export function JobsReadyList({ bodyshop }) {
sorter: (a, b) => alphaSort(a.ro_number, b.ro_number), sorter: (a, b) => alphaSort(a.ro_number, b.ro_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) => (
<Link <Link
to={"/manage/jobs/" + record.id} to={"/manage/jobs/" + record.id}
@@ -157,7 +156,6 @@ export function JobsReadyList({ bodyshop }) {
dataIndex: "owner", dataIndex: "owner",
key: "owner", key: "owner",
ellipsis: true, ellipsis: true,
responsive: ["md"], responsive: ["md"],
sorter: (a, b) => alphaSort(a.ownr_ln, b.ownr_ln), sorter: (a, b) => alphaSort(a.ownr_ln, b.ownr_ln),
sortOrder: sortOrder:
@@ -197,16 +195,15 @@ export function JobsReadyList({ bodyshop }) {
<ChatOpenButton phone={record.ownr_ph2} jobid={record.id} /> <ChatOpenButton phone={record.ownr_ph2} jobid={record.id} />
), ),
}, },
{ {
title: t("jobs.fields.status"), title: t("jobs.fields.status"),
dataIndex: "status", dataIndex: "status",
key: "status", key: "status",
ellipsis: true, ellipsis: true,
sorter: (a, b) => alphaSort(a.status, b.status), sorter: (a, b) => alphaSort(a.status, b.status),
sortOrder: sortOrder:
state.sortedInfo.columnKey === "status" && state.sortedInfo.order, state.sortedInfo.columnKey === "status" && state.sortedInfo.order,
filteredValue: filter?.status || null,
filters: filters:
(jobs && (jobs &&
jobs jobs
@@ -217,11 +214,17 @@ export function JobsReadyList({ bodyshop }) {
text: s || "No Status*", text: s || "No Status*",
value: [s], value: [s],
}; };
})) || })
.sort((a, b) =>
statusSort(
a.text,
b.text,
bodyshop.md_ro_statuses.active_statuses
)
)) ||
[], [],
onFilter: (value, record) => value.includes(record.status), onFilter: (value, record) => value.includes(record.status),
}, },
{ {
title: t("jobs.fields.vehicle"), title: t("jobs.fields.vehicle"),
dataIndex: "vehicle", dataIndex: "vehicle",
@@ -274,6 +277,7 @@ export function JobsReadyList({ bodyshop }) {
dataIndex: "ins_co_nm", dataIndex: "ins_co_nm",
key: "ins_co_nm", key: "ins_co_nm",
ellipsis: true, ellipsis: true,
filteredValue: filter?.ins_co_nm || null,
filters: filters:
(jobs && (jobs &&
jobs jobs
@@ -281,10 +285,11 @@ export function JobsReadyList({ bodyshop }) {
.filter(onlyUnique) .filter(onlyUnique)
.map((s) => { .map((s) => {
return { return {
text: s, text: s || "No Ins Co.*",
value: [s], value: [s],
}; };
})) || })
.sort((a, b) => alphaSort(a.text, b.text))) ||
[], [],
onFilter: (value, record) => value.includes(record.ins_co_nm), onFilter: (value, record) => value.includes(record.ins_co_nm),
responsive: ["md"], responsive: ["md"],
@@ -295,7 +300,6 @@ export function JobsReadyList({ bodyshop }) {
key: "clm_total", key: "clm_total",
responsive: ["md"], responsive: ["md"],
ellipsis: true, ellipsis: true,
sorter: (a, b) => a.clm_total - b.clm_total, sorter: (a, b) => a.clm_total - b.clm_total,
sortOrder: sortOrder:
state.sortedInfo.columnKey === "clm_total" && state.sortedInfo.order, state.sortedInfo.columnKey === "clm_total" && state.sortedInfo.order,
@@ -306,9 +310,10 @@ export function JobsReadyList({ bodyshop }) {
{ {
title: t("jobs.labels.estimator"), title: t("jobs.labels.estimator"),
dataIndex: "jobs.labels.estimator", dataIndex: "jobs.labels.estimator",
key: "jobs.labels.estimator", key: "estimator",
ellipsis: true, ellipsis: true,
responsive: ["xl"], responsive: ["xl"],
filteredValue: filter?.estimator || null,
filterSearch: true, filterSearch: true,
filters: filters:
(jobs && (jobs &&
@@ -317,10 +322,11 @@ export function JobsReadyList({ bodyshop }) {
.filter(onlyUnique) .filter(onlyUnique)
.map((s) => { .map((s) => {
return { return {
text: s || "N/A", text: s || "No Estimator*",
value: [s], value: [s],
}; };
})) || })
.sort((a, b) => alphaSort(a.text, b.text))) ||
[], [],
onFilter: (value, record) => onFilter: (value, record) =>
value.includes( value.includes(