diff --git a/client/src/components/jobs-list/jobs-list.component.jsx b/client/src/components/jobs-list/jobs-list.component.jsx index b7bd3141d..fb2e1daa6 100644 --- a/client/src/components/jobs-list/jobs-list.component.jsx +++ b/client/src/components/jobs-list/jobs-list.component.jsx @@ -1,120 +1,105 @@ -import {BranchesOutlined, ExclamationCircleFilled, PauseCircleOutlined, SyncOutlined,} from "@ant-design/icons"; -import {useQuery} from "@apollo/client"; -import {Button, Card, Grid, Input, Space, Table, Tooltip, Typography} from "antd"; +import { + SyncOutlined, + ExclamationCircleFilled, + PauseCircleOutlined, + BranchesOutlined, +} from "@ant-design/icons"; +import { useQuery } from "@apollo/client"; +import { Button, Card, Grid, Input, Space, Table, Tooltip } from "antd"; import queryString from "query-string"; -import React, {useEffect, useState} from "react"; -import {useTranslation} from "react-i18next"; -import {connect} from "react-redux"; -import {Link, useHistory, useLocation} from "react-router-dom"; -import {createStructuredSelector} from "reselect"; -import {QUERY_ALL_ACTIVE_JOBS_PAGINATED} from "../../graphql/jobs.queries"; -import {selectBodyshop} from "../../redux/user/user.selectors"; -import {onlyUnique} from "../../utils/arrayHelper"; +import React, { useState } from "react"; +import { useTranslation } from "react-i18next"; +import { connect } from "react-redux"; +import { Link, useHistory, useLocation } from "react-router-dom"; +import { createStructuredSelector } from "reselect"; +import { QUERY_ALL_ACTIVE_JOBS } from "../../graphql/jobs.queries"; +import { selectBodyshop } from "../../redux/user/user.selectors"; +import { onlyUnique } from "../../utils/arrayHelper"; import CurrencyFormatter from "../../utils/CurrencyFormatter"; +import { alphaSort } from "../../utils/sorters"; import AlertComponent from "../alert/alert.component"; import ChatOpenButton from "../chat-open-button/chat-open-button.component"; import OwnerNameDisplay from "../owner-name-display/owner-name-display.component"; -import {flattenDeep} from "lodash"; -import { pageLimit } from '../../utils/config'; -import axios from "axios"; const mapStateToProps = createStructuredSelector({ bodyshop: selectBodyshop, }); -const mapDispatchToProps = () => ({ -}); - -export function JobsList({bodyshop,}) { - const search = queryString.parse(useLocation().search); - const [openSearchResults, setOpenSearchResults] = useState([]); - const [searchLoading, setSearchLoading] = useState(false); - const {page, selected, sortorder, sortcolumn} = search; - +export function JobsList({ bodyshop }) { + const searchParams = queryString.parse(useLocation().search); + const { selected } = searchParams; const selectedBreakpoint = Object.entries(Grid.useBreakpoint()) .filter((screen) => !!screen[1]) .slice(-1)[0]; - - const {loading, error, data, refetch} = useQuery(QUERY_ALL_ACTIVE_JOBS_PAGINATED, { + const { loading, error, data, refetch } = useQuery(QUERY_ALL_ACTIVE_JOBS, { variables: { - offset: page ? (page - 1) * pageLimit : 0, - limit: pageLimit, statuses: bodyshop.md_ro_statuses.active_statuses || ["Open", "Open*"], - order: [ - { - [sortcolumn || "ro_number"]: - sortorder && sortorder !== "false" - ? (sortorder === "descend" - ? "desc" - : "asc") - : "desc", - }, - ], }, fetchPolicy: "network-only", nextFetchPolicy: "network-only", }); - const total = data?.jobs_aggregate?.aggregate?.count || 0; - const [state, setState] = useState({ - filteredInfo: {text: ""}, + sortedInfo: {}, + filteredInfo: { text: "" }, }); - const {t} = useTranslation(); + const { t } = useTranslation(); const history = useHistory(); + const [searchText, setSearchText] = useState(""); - const jobs = data?.jobs || []; + if (error) return ; + + const jobs = data + ? searchText === "" + ? data.jobs + : data.jobs.filter( + (j) => + (j.ro_number || "") + .toString() + .toLowerCase() + .includes(searchText.toLowerCase()) || + (j.ownr_co_nm || "") + .toLowerCase() + .includes(searchText.toLowerCase()) || + (j.comments || "") + .toLowerCase() + .includes(searchText.toLowerCase()) || + (j.ownr_fn || "") + .toLowerCase() + .includes(searchText.toLowerCase()) || + (j.ownr_ln || "") + .toLowerCase() + .includes(searchText.toLowerCase()) || + (j.clm_no || "").toLowerCase().includes(searchText.toLowerCase()) || + (j.plate_no || "") + .toLowerCase() + .includes(searchText.toLowerCase()) || + (j.v_model_desc || "") + .toLowerCase() + .includes(searchText.toLowerCase()) || + (j.est_ct_fn || "") + .toLowerCase() + .includes(searchText.toLowerCase()) || + (j.est_ct_ln || "") + .toLowerCase() + .includes(searchText.toLowerCase()) || + (j.v_make_desc || "") + .toLowerCase() + .includes(searchText.toLowerCase()) + ) + : []; const handleTableChange = (pagination, filters, sorter) => { - // TODO: Is this needed? - setState({...state, filteredInfo: filters}); - - search.page = pagination.current; - search.sortcolumn = sorter.column && sorter.column.key; - search.sortorder = sorter.order; - - if (filters.status) { - search.statusFilters = JSON.stringify(flattenDeep(filters.status)); - } else { - delete search.statusFilters; - } - - history.push({search: queryString.stringify(search)}); + setState({ ...state, filteredInfo: filters, sortedInfo: sorter }); }; - useEffect(() => { - if (search.search && search.search.trim() !== "") { - searchJobs().catch(e => { - console.error('Something went wrong searching for jobs in the job-list component', e); - }); - } - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); - - if (error) return ; - - async function searchJobs(value) { - try { - setSearchLoading(true); - const searchData = await axios.post("/search", { - search: value || search.search, - index: "jobs", - }); - setOpenSearchResults(searchData.data.hits.hits.map((s) => s._source)); - } catch (error) { - console.log("Error while fetching search results", error); - } finally { - setSearchLoading(false); - } - } - const handleOnRowClick = (record) => { if (record) { if (record.id) { history.push({ search: queryString.stringify({ - ...search, + ...searchParams, selected: record.id, }), }); @@ -127,9 +112,11 @@ export function JobsList({bodyshop,}) { title: t("jobs.fields.ro_number"), dataIndex: "ro_number", key: "ro_number", - sorter: true, + sorter: (a, b) => + parseInt((a.ro_number || "0").replace(/\D/g, "")) - + parseInt((b.ro_number || "0").replace(/\D/g, "")), sortOrder: - sortcolumn === "ro_number" && sortorder, + state.sortedInfo.columnKey === "ro_number" && state.sortedInfo.order, render: (text, record) => ( {record.ro_number || t("general.labels.na")} {record.production_vars && record.production_vars.alert ? ( - + ) : null} {record.suspended && ( - + )} {record.iouparent && ( - + )} @@ -158,20 +145,22 @@ export function JobsList({bodyshop,}) { dataIndex: "owner", key: "owner", ellipsis: true, + responsive: ["md"], - sorter: false, - sortOrder: sortcolumn === "owner" && sortorder, + sorter: (a, b) => alphaSort(a.ownr_ln, b.ownr_ln), + sortOrder: + state.sortedInfo.columnKey === "owner" && state.sortedInfo.order, render: (text, record) => { return record.ownerid ? ( e.stopPropagation()} > - + ) : ( - + ); }, @@ -183,7 +172,7 @@ export function JobsList({bodyshop,}) { ellipsis: true, responsive: ["md"], render: (text, record) => ( - + ), }, { @@ -193,7 +182,7 @@ export function JobsList({bodyshop,}) { ellipsis: true, responsive: ["md"], render: (text, record) => ( - + ), }, @@ -202,9 +191,10 @@ export function JobsList({bodyshop,}) { dataIndex: "status", key: "status", ellipsis: true, - sorter: true, + + sorter: (a, b) => alphaSort(a.status, b.status), sortOrder: - sortcolumn === "status" && sortorder, + state.sortedInfo.columnKey === "status" && state.sortedInfo.order, filters: (jobs && jobs @@ -219,6 +209,7 @@ export function JobsList({bodyshop,}) { [], onFilter: (value, record) => value.includes(record.status), }, + { title: t("jobs.fields.vehicle"), dataIndex: "vehicle", @@ -246,10 +237,11 @@ export function JobsList({bodyshop,}) { dataIndex: "plate_no", key: "plate_no", ellipsis: true, + responsive: ["md"], - sorter: true, + sorter: (a, b) => alphaSort(a.plate_no, b.plate_no), sortOrder: - sortcolumn === "plate_no" && sortorder, + state.sortedInfo.columnKey === "plate_no" && state.sortedInfo.order, }, { title: t("jobs.fields.clm_no"), @@ -257,9 +249,9 @@ export function JobsList({bodyshop,}) { key: "clm_no", ellipsis: true, responsive: ["md"], - sorter: true, + sorter: (a, b) => alphaSort(a.clm_no, b.clm_no), sortOrder: - sortcolumn === "clm_no" && sortorder, + state.sortedInfo.columnKey === "clm_no" && state.sortedInfo.order, render: (text, record) => `${record.clm_no || ""}${ record.po_number ? ` (PO: ${record.po_number})` : "" @@ -291,9 +283,10 @@ export function JobsList({bodyshop,}) { key: "clm_total", responsive: ["md"], ellipsis: true, - sorter: true, + + sorter: (a, b) => a.clm_total - b.clm_total, sortOrder: - sortcolumn === "clm_total" && sortorder, + state.sortedInfo.columnKey === "clm_total" && state.sortedInfo.order, render: (text, record) => ( {record.clm_total} ), @@ -356,57 +349,26 @@ export function JobsList({bodyshop,}) { title={t("titles.bc.jobs-active")} extra={ - {search.search && ( - <> - - {t("general.labels.searchresults", { search: search.search })} - - - - )} { - search.search = value; - history.push({ search: queryString.stringify(search) }); - searchJobs(value); + placeholder={t("general.labels.search")} + onChange={(e) => { + setSearchText(e.target.value); }} - loading={loading || searchLoading} + value={searchText} enterButton /> } > { + onRow={(record, rowIndex) => { return { - onClick: () => { + onClick: (event) => { handleOnRowClick(record); }, }; @@ -430,4 +392,4 @@ export function JobsList({bodyshop,}) { ); } -export default connect(mapStateToProps, mapDispatchToProps)(JobsList); +export default connect(mapStateToProps, null)(JobsList);