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 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 CurrencyFormatter from "../../utils/CurrencyFormatter"; 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; const selectedBreakpoint = Object.entries(Grid.useBreakpoint()) .filter((screen) => !!screen[1]) .slice(-1)[0]; const {loading, error, data, refetch} = useQuery(QUERY_ALL_ACTIVE_JOBS_PAGINATED, { 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: ""}, }); const {t} = useTranslation(); const history = useHistory(); const jobs = data?.jobs || []; 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)}); }; 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, selected: record.id, }), }); } } }; const columns = [ { title: t("jobs.fields.ro_number"), dataIndex: "ro_number", key: "ro_number", sorter: true, sortOrder: sortcolumn === "ro_number" && sortorder, render: (text, record) => ( e.stopPropagation()} > {record.ro_number || t("general.labels.na")} {record.production_vars && record.production_vars.alert ? ( ) : null} {record.suspended && ( )} {record.iouparent && ( )} ), }, { title: t("jobs.fields.owner"), dataIndex: "owner", key: "owner", ellipsis: true, responsive: ["md"], sorter: false, sortOrder: sortcolumn === "owner" && sortorder, render: (text, record) => { return record.ownerid ? ( e.stopPropagation()} > ) : ( ); }, }, { title: t("jobs.fields.ownr_ph1"), dataIndex: "ownr_ph1", key: "ownr_ph1", ellipsis: true, responsive: ["md"], render: (text, record) => ( ), }, { title: t("jobs.fields.ownr_ph2"), dataIndex: "ownr_ph2", key: "ownr_ph2", ellipsis: true, responsive: ["md"], render: (text, record) => ( ), }, { title: t("jobs.fields.status"), dataIndex: "status", key: "status", ellipsis: true, sorter: true, sortOrder: sortcolumn === "status" && sortorder, filters: (jobs && jobs .map((j) => j.status) .filter(onlyUnique) .map((s) => { return { text: s || "No Status*", value: [s], }; })) || [], onFilter: (value, record) => value.includes(record.status), }, { title: t("jobs.fields.vehicle"), dataIndex: "vehicle", key: "vehicle", ellipsis: true, render: (text, record) => { return record.vehicleid ? ( e.stopPropagation()} > {`${record.v_model_yr || ""} ${record.v_make_desc || ""} ${ record.v_model_desc || "" }`} ) : ( {`${record.v_model_yr || ""} ${record.v_make_desc || ""} ${ record.v_model_desc || "" }`} ); }, }, { title: t("vehicles.fields.plate_no"), dataIndex: "plate_no", key: "plate_no", ellipsis: true, responsive: ["md"], sorter: true, sortOrder: sortcolumn === "plate_no" && sortorder, }, { title: t("jobs.fields.clm_no"), dataIndex: "clm_no", key: "clm_no", ellipsis: true, responsive: ["md"], sorter: true, sortOrder: sortcolumn === "clm_no" && sortorder, render: (text, record) => `${record.clm_no || ""}${ record.po_number ? ` (PO: ${record.po_number})` : "" }`, }, { title: t("jobs.fields.ins_co_nm"), dataIndex: "ins_co_nm", key: "ins_co_nm", ellipsis: true, filters: (jobs && jobs .map((j) => j.ins_co_nm) .filter(onlyUnique) .map((s) => { return { text: s, value: [s], }; })) || [], onFilter: (value, record) => value.includes(record.ins_co_nm), responsive: ["md"], }, { title: t("jobs.fields.clm_total"), dataIndex: "clm_total", key: "clm_total", responsive: ["md"], ellipsis: true, sorter: true, sortOrder: sortcolumn === "clm_total" && sortorder, render: (text, record) => ( {record.clm_total} ), }, { title: t("jobs.labels.estimator"), dataIndex: "jobs.labels.estimator", key: "jobs.labels.estimator", ellipsis: true, responsive: ["xl"], filterSearch: true, filters: (jobs && jobs .map((j) => `${j.est_ct_fn || ""} ${j.est_ct_ln || ""}`.trim()) .filter(onlyUnique) .map((s) => { return { text: s || "N/A", value: [s], }; })) || [], onFilter: (value, record) => value.includes( `${record.est_ct_fn || ""} ${record.est_ct_ln || ""}`.trim() ), render: (text, record) => `${record.est_ct_fn || ""} ${record.est_ct_ln || ""}`.trim(), }, { title: t("jobs.fields.comment"), dataIndex: "comment", key: "comment", ellipsis: true, responsive: ["md"], }, // { // title: t("jobs.fields.owner_owing"), // dataIndex: "owner_owing", // key: "owner_owing", // responsive: ["md"], // render: (text, record) => ( // {record.owner_owing} // ), // }, ]; const scrollMapper = { xs: true, sm: true, md: true, lg: "100%", xl: "100%", xxl: "100%", }; return ( {search.search && ( <> {t("general.labels.searchresults", { search: search.search })} )} { search.search = value; history.push({ search: queryString.stringify(search) }); searchJobs(value); }} loading={loading || searchLoading} enterButton /> } > { handleOnRowClick(record); }, selectedRowKeys: [selected], type: "radio", }} onChange={handleTableChange} onRow={(record) => { return { onClick: () => { handleOnRowClick(record); }, }; }} /> ); } export default connect(mapStateToProps, mapDispatchToProps)(JobsList);