diff --git a/client/src/components/jobs-list-paginated/jobs-list-paginated.component.jsx b/client/src/components/jobs-list-paginated/jobs-list-paginated.component.jsx index 15612af33..3b164466d 100644 --- a/client/src/components/jobs-list-paginated/jobs-list-paginated.component.jsx +++ b/client/src/components/jobs-list-paginated/jobs-list-paginated.component.jsx @@ -1,276 +1,282 @@ -import { SyncOutlined } from "@ant-design/icons"; -import { Button, Card, Input, Space, Table, Typography } from "antd"; +import {SyncOutlined} from "@ant-design/icons"; +import {Button, Card, Input, Space, Table, Typography} from "antd"; import axios from "axios"; import _ from "lodash"; import queryString from "query-string"; -import React, { useEffect, useState } from "react"; -import { useTranslation } from "react-i18next"; -import { connect } from "react-redux"; -import { Link, useNavigate, useLocation } from "react-router-dom"; -import { createStructuredSelector } from "reselect"; -import { selectBodyshop } from "../../redux/user/user.selectors"; +import React, {useEffect, useState} from "react"; +import {useTranslation} from "react-i18next"; +import {connect} from "react-redux"; +import {Link, useLocation, useNavigate} from "react-router-dom"; +import {createStructuredSelector} from "reselect"; +import {selectBodyshop} from "../../redux/user/user.selectors"; 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 OwnerNameDisplay from "../owner-name-display/owner-name-display.component"; -import {pageLimit} from "../../utils/config"; + const mapStateToProps = createStructuredSelector({ - //currentUser: selectCurrentUser - bodyshop: selectBodyshop, + //currentUser: selectCurrentUser + bodyshop: selectBodyshop, }); const mapDispatchToProps = (dispatch) => ({ - //setUserLanguage: language => dispatch(setUserLanguage(language)) + //setUserLanguage: language => dispatch(setUserLanguage(language)) }); -export function JobsList({ bodyshop, refetch, loading, jobs, total }) { - const search = queryString.parse(useLocation().search); - const [openSearchResults, setOpenSearchResults] = useState([]); - const [searchLoading, setSearchLoading] = useState(false); - const { page, sortcolumn, sortorder } = search; - const history = useNavigate(); +export function JobsList({bodyshop, refetch, loading, jobs, total}) { + const search = queryString.parse(useLocation().search); + const [openSearchResults, setOpenSearchResults] = useState([]); + const [searchLoading, setSearchLoading] = useState(false); + const [filter, setFilter] = useLocalStorage("filter_jobs_all", null); + const {page, sortcolumn, sortorder} = search; + const history = useNavigate(); - const { t } = useTranslation(); - const columns = [ - { - title: t("jobs.fields.ro_number"), - dataIndex: "ro_number", - key: "ro_number", - sorter: true, //(a, b) => alphaSort(a.ro_number, b.ro_number), - sortOrder: sortcolumn === "ro_number" && sortorder, - render: (text, record) => ( - - {record.ro_number || t("general.labels.na")} - - ), - }, - { - title: t("jobs.fields.owner"), - dataIndex: "ownr_ln", - key: "ownr_ln", - ellipsis: true, - //sorter: true, // (a, b) => alphaSort(a.ownr_ln, b.ownr_ln), + const {t} = useTranslation(); + const columns = [ + { + title: t("jobs.fields.ro_number"), + dataIndex: "ro_number", + key: "ro_number", + sorter: true, //(a, b) => alphaSort(a.ro_number, b.ro_number), + sortOrder: sortcolumn === "ro_number" && sortorder, + render: (text, record) => ( + + {record.ro_number || t("general.labels.na")} + + ), + }, + { + title: t("jobs.fields.owner"), + dataIndex: "ownr_ln", + key: "ownr_ln", + ellipsis: true, + //sorter: true, // (a, b) => alphaSort(a.ownr_ln, b.ownr_ln), - //sortOrder: sortcolumn === "ownr_ln" && sortorder, - render: (text, record) => { - return record.ownerid ? ( - - - - ) : ( - - + //sortOrder: sortcolumn === "ownr_ln" && sortorder, + render: (text, record) => { + return record.ownerid ? ( + + + + ) : ( + + - ); - }, - }, - { - title: t("jobs.fields.ownr_ph1"), - dataIndex: "ownr_ph1", - key: "ownr_ph1", + ); + }, + }, + { + title: t("jobs.fields.ownr_ph1"), + dataIndex: "ownr_ph1", + key: "ownr_ph1", - ellipsis: true, - render: (text, record) => ( - - ), - }, - { - title: t("jobs.fields.ownr_ph2"), - dataIndex: "ownr_ph2", - key: "ownr_ph2", + ellipsis: true, + render: (text, record) => ( + + ), + }, + { + title: t("jobs.fields.ownr_ph2"), + dataIndex: "ownr_ph2", + key: "ownr_ph2", - ellipsis: true, - render: (text, record) => ( - - ), - }, - { - title: t("jobs.fields.status"), - dataIndex: "status", - key: "status", + ellipsis: true, + render: (text, record) => ( + + ), + }, + { + title: t("jobs.fields.status"), + dataIndex: "status", + key: "status", - ellipsis: true, - sorter: true, // (a, b) => alphaSort(a.status, b.status), - sortOrder: sortcolumn === "status" && sortorder, - render: (text, record) => { - return record.status || t("general.labels.na"); - }, - filters: bodyshop.md_ro_statuses.statuses.map((s) => { - return { text: s, value: [s] }; - }), - onFilter: (value, record) => value.includes(record.status), - }, + ellipsis: true, + sorter: true, // (a, b) => alphaSort(a.status, b.status), + sortOrder: sortcolumn === "status" && sortorder, + render: (text, record) => { + return record.status || t("general.labels.na"); + }, + filteredValue: filter?.status || null, + filters: bodyshop.md_ro_statuses.statuses.map((s) => { + return {text: s, value: [s]}; + }), + onFilter: (value, record) => value.includes(record.status), + }, - { - title: t("jobs.fields.vehicle"), - dataIndex: "vehicle", - key: "vehicle", + { + title: t("jobs.fields.vehicle"), + dataIndex: "vehicle", + key: "vehicle", - ellipsis: true, - render: (text, record) => { - return record.vehicleid ? ( - - {`${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, - sorter: true, //(a, b) => alphaSort(a.plate_no, b.plate_no), - sortOrder: sortcolumn === "plate_no" && sortorder, - render: (text, record) => { - return record.plate_no ? record.plate_no : ""; - }, - }, - { - title: t("jobs.fields.clm_no"), - dataIndex: "clm_no", - key: "clm_no", - ellipsis: true, - sorter: true, //(a, b) => alphaSort(a.clm_no, b.clm_no), - 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, - }, - { - title: t("jobs.fields.clm_total"), - dataIndex: "clm_total", - key: "clm_total", + ellipsis: true, + render: (text, record) => { + return record.vehicleid ? ( + + {`${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, + sorter: true, //(a, b) => alphaSort(a.plate_no, b.plate_no), + sortOrder: sortcolumn === "plate_no" && sortorder, + render: (text, record) => { + return record.plate_no ? record.plate_no : ""; + }, + }, + { + title: t("jobs.fields.clm_no"), + dataIndex: "clm_no", + key: "clm_no", + ellipsis: true, + sorter: true, //(a, b) => alphaSort(a.clm_no, b.clm_no), + 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, + }, + { + title: t("jobs.fields.clm_total"), + dataIndex: "clm_total", + key: "clm_total", - sorter: true, //(a, b) => a.clm_total - b.clm_total, - sortOrder: sortcolumn === "clm_total" && sortorder, - render: (text, record) => { - return record.clm_total ? ( - {record.clm_total} - ) : ( - t("general.labels.unknown") - ); - }, - }, - { - title: t("jobs.fields.owner_owing"), - dataIndex: "owner_owing", - key: "owner_owing", + sorter: true, //(a, b) => a.clm_total - b.clm_total, + sortOrder: sortcolumn === "clm_total" && sortorder, + render: (text, record) => { + return record.clm_total ? ( + {record.clm_total} + ) : ( + t("general.labels.unknown") + ); + }, + }, + { + title: t("jobs.fields.owner_owing"), + dataIndex: "owner_owing", + key: "owner_owing", - render: (text, record) => ( - {record.owner_owing} - ), - }, - { - title: t("jobs.fields.comment"), - dataIndex: "comment", - key: "comment", - ellipsis: true, - }, - ]; + render: (text, record) => ( + {record.owner_owing} + ), + }, + { + title: t("jobs.fields.comment"), + dataIndex: "comment", + key: "comment", + ellipsis: true, + }, + ]; - const handleTableChange = (pagination, filters, sorter) => { - 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({ search: queryString.stringify(search) }); - }; - - useEffect(() => { - if (search.search && search.search.trim() !== "") { - searchJobs(); - } - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); - - 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); - } - } - - return ( - - {search.search && ( - <> - - {t("general.labels.searchresults", { search: search.search })} - - - - )} - - { - search.search = value; - history({ search: queryString.stringify(search) }); - searchJobs(value); - }} - loading={loading || searchLoading} - enterButton - /> - - } - > - { + 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; } - columns={columns} - rowKey="id" - dataSource={search?.search ? openSearchResults : jobs} - onChange={handleTableChange} - /> - - ); + setFilter(filters); + history({search: queryString.stringify(search)}); + }; + + useEffect(() => { + if (search.search && search.search.trim() !== "") { + searchJobs(); + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + + 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); + } + } + + return ( + + {search.search && ( + <> + + {t("general.labels.searchresults", {search: search.search})} + + + + )} + + { + search.search = value; + history({search: queryString.stringify(search)}); + searchJobs(value); + }} + loading={loading || searchLoading} + enterButton + /> + + } + > +
+ + ); } + export default connect(mapStateToProps, mapDispatchToProps)(JobsList); diff --git a/client/src/components/jobs-list/jobs-list.component.jsx b/client/src/components/jobs-list/jobs-list.component.jsx index 522fa484f..e5b708fed 100644 --- a/client/src/components/jobs-list/jobs-list.component.jsx +++ b/client/src/components/jobs-list/jobs-list.component.jsx @@ -1,22 +1,18 @@ -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 {BranchesOutlined, ExclamationCircleFilled, PauseCircleOutlined, SyncOutlined,} 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, { useState } from "react"; -import { useTranslation } from "react-i18next"; -import { connect } from "react-redux"; -import { Link, useNavigate, 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 React, {useState} from "react"; +import {useTranslation} from "react-i18next"; +import {connect} from "react-redux"; +import {Link, useLocation, useNavigate} 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 {alphaSort, statusSort} from "../../utils/sorters"; +import useLocalStorage from "../../utils/useLocalStorage"; 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"; @@ -25,13 +21,13 @@ const mapStateToProps = createStructuredSelector({ bodyshop: selectBodyshop, }); -export function JobsList({ bodyshop }) { +export function JobsList({bodyshop}) { const searchParams = queryString.parse(useLocation().search); - const { selected } = searchParams; + 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, { + const {loading, error, data, refetch} = useQuery(QUERY_ALL_ACTIVE_JOBS, { variables: { statuses: bodyshop.md_ro_statuses.active_statuses || ["Open", "Open*"], }, @@ -39,16 +35,14 @@ export function JobsList({ bodyshop }) { nextFetchPolicy: "network-only", }); - const [state, setState] = useState({ - sortedInfo: {}, - filteredInfo: { text: "" }, - }); + const [state, setState] = useState({sortedInfo: {}}); + const [filter, setFilter] = useLocalStorage("filter_jobs_list", null); - const { t } = useTranslation(); + const {t} = useTranslation(); const history = useNavigate(); const [searchText, setSearchText] = useState(""); - if (error) return ; + if (error) return ; const jobs = data ? searchText === "" @@ -91,7 +85,8 @@ export function JobsList({ bodyshop }) { : []; const handleTableChange = (pagination, filters, sorter) => { - setState({ ...state, filteredInfo: filters, sortedInfo: sorter }); + setState({...state, sortedInfo: sorter}); + setFilter(filters); }; const handleOnRowClick = (record) => { @@ -126,14 +121,14 @@ export function JobsList({ bodyshop }) { {record.ro_number || t("general.labels.na")} {record.production_vars && record.production_vars.alert ? ( - + ) : null} {record.suspended && ( - + )} {record.iouparent && ( - + )} @@ -156,11 +151,11 @@ export function JobsList({ bodyshop }) { to={"/manage/owners/" + record.ownerid} onClick={(e) => e.stopPropagation()} > - + ) : ( - + ); }, @@ -172,7 +167,7 @@ export function JobsList({ bodyshop }) { ellipsis: true, responsive: ["md"], render: (text, record) => ( - + ), }, { @@ -182,7 +177,7 @@ export function JobsList({ bodyshop }) { ellipsis: true, responsive: ["md"], render: (text, record) => ( - + ), }, @@ -195,6 +190,7 @@ export function JobsList({ bodyshop }) { sorter: (a, b) => alphaSort(a.status, b.status), sortOrder: state.sortedInfo.columnKey === "status" && state.sortedInfo.order, + filteredValue: filter?.status || null, filters: (jobs && jobs @@ -205,7 +201,14 @@ export function JobsList({ bodyshop }) { text: s || "No Status*", value: [s], }; - })) || + }) + .sort((a, b) => + statusSort( + a.text, + b.text, + bodyshop.md_ro_statuses.active_statuses + ) + )) || [], onFilter: (value, record) => value.includes(record.status), }, @@ -262,6 +265,7 @@ export function JobsList({ bodyshop }) { dataIndex: "ins_co_nm", key: "ins_co_nm", ellipsis: true, + filteredValue: filter?.ins_co_nm || null, filters: (jobs && jobs @@ -269,10 +273,11 @@ export function JobsList({ bodyshop }) { .filter(onlyUnique) .map((s) => { return { - text: s, + text: s || "No Ins. Co.*", value: [s], }; - })) || + }) + .sort((a, b) => alphaSort(a.text, b.text))) || [], onFilter: (value, record) => value.includes(record.ins_co_nm), responsive: ["md"], @@ -298,6 +303,7 @@ export function JobsList({ bodyshop }) { ellipsis: true, responsive: ["xl"], filterSearch: true, + filteredValue: filter?.estimator || null, filters: (jobs && jobs @@ -305,10 +311,11 @@ export function JobsList({ bodyshop }) { .filter(onlyUnique) .map((s) => { return { - text: s || "N/A", + text: s || "No Estimator*", value: [s], }; - })) || + }) + .sort((a, b) => alphaSort(a.text, b.text))) || [], onFilter: (value, record) => value.includes( @@ -350,7 +357,7 @@ export function JobsList({ bodyshop }) { extra={
!!screen[1]) - .slice(-1)[0]; +export function JobsReadyList({bodyshop}) { + const searchParams = queryString.parse(useLocation().search); + const {selected} = searchParams; + const selectedBreakpoint = Object.entries(Grid.useBreakpoint()) + .filter((screen) => !!screen[1]) + .slice(-1)[0]; - const readyStatuses = useMemo(() => { - if (bodyshop.md_ro_statuses.ready_statuses) - return bodyshop.md_ro_statuses.ready_statuses; + const readyStatuses = useMemo(() => { + if (bodyshop.md_ro_statuses.ready_statuses) + return bodyshop.md_ro_statuses.ready_statuses; - return bodyshop.md_ro_statuses.post_production_statuses.filter( - (s) => - s !== bodyshop.md_ro_statuses.default_invoiced && - s !== bodyshop.md_ro_statuses.default_exported - ); - }, [bodyshop.md_ro_statuses]); + return bodyshop.md_ro_statuses.post_production_statuses.filter( + (s) => + s !== bodyshop.md_ro_statuses.default_invoiced && + s !== bodyshop.md_ro_statuses.default_exported + ); + }, [bodyshop.md_ro_statuses]); - const { loading, error, data, refetch } = useQuery(QUERY_ALL_ACTIVE_JOBS, { - variables: { - statuses: readyStatuses, - isConverted: true, - }, - fetchPolicy: "network-only", - nextFetchPolicy: "network-only", - }); + const {loading, error, data, refetch} = useQuery(QUERY_ALL_ACTIVE_JOBS, { + variables: { + statuses: readyStatuses, + isConverted: true, + }, + fetchPolicy: "network-only", + nextFetchPolicy: "network-only", + }); - const [state, setState] = useState({ - sortedInfo: {}, - filteredInfo: { text: "" }, - }); + const [state, setState] = useState({sortedInfo: {}}); + const [filter, setFilter] = useLocalStorage("filter_jobs_ready", null); - const { t } = useTranslation(); - const history = useNavigate(); - const [searchText, setSearchText] = useState(""); + const {t} = useTranslation(); + const history = useNavigate(); + const [searchText, setSearchText] = useState(""); - if (error) return ; + 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 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) => { - setState({ ...state, filteredInfo: filters, sortedInfo: sorter }); - }; + const handleTableChange = (pagination, filters, sorter) => { + setState({...state, sortedInfo: sorter}); + setFilter(filters); + }; - const handleOnRowClick = (record) => { - if (record) { - if (record.id) { - history({ - search: queryString.stringify({ - ...searchParams, - selected: record.id, - }), - }); - } - } - }; + const handleOnRowClick = (record) => { + if (record) { + if (record.id) { + history({ + search: queryString.stringify({ + ...searchParams, + selected: record.id, + }), + }); + } + } + }; - const columns = [ - { - title: t("jobs.fields.ro_number"), - dataIndex: "ro_number", - key: "ro_number", - sorter: (a, b) => alphaSort(a.ro_number, b.ro_number), - sortOrder: - state.sortedInfo.columnKey === "ro_number" && state.sortedInfo.order, - - 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: (a, b) => alphaSort(a.ownr_ln, b.ownr_ln), - sortOrder: - state.sortedInfo.columnKey === "owner" && state.sortedInfo.order, - render: (text, record) => { - return record.owner ? ( - e.stopPropagation()} - > - - - ) : ( - - + const columns = [ + { + title: t("jobs.fields.ro_number"), + dataIndex: "ro_number", + key: "ro_number", + sorter: (a, b) => alphaSort(a.ro_number, b.ro_number), + sortOrder: + state.sortedInfo.columnKey === "ro_number" && state.sortedInfo.order, + 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: (a, b) => alphaSort(a.ownr_ln, b.ownr_ln), + sortOrder: + state.sortedInfo.columnKey === "owner" && state.sortedInfo.order, + render: (text, record) => { + return record.owner ? ( + 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: (a, b) => alphaSort(a.status, b.status), - sortOrder: - state.sortedInfo.columnKey === "status" && state.sortedInfo.order, - 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: (a, b) => alphaSort(a.plate_no, b.plate_no), - sortOrder: - state.sortedInfo.columnKey === "plate_no" && state.sortedInfo.order, - }, - { - title: t("jobs.fields.clm_no"), - dataIndex: "clm_no", - key: "clm_no", - ellipsis: true, - responsive: ["md"], - sorter: (a, b) => alphaSort(a.clm_no, b.clm_no), - sortOrder: - state.sortedInfo.columnKey === "clm_no" && state.sortedInfo.order, - 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: (a, b) => a.clm_total - b.clm_total, - sortOrder: - state.sortedInfo.columnKey === "clm_total" && state.sortedInfo.order, - 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 ( - - ({readyStatuses && readyStatuses.join(", ")}) - - { - setSearchText(e.target.value); - }} - value={searchText} - enterButton - /> - - } - > -
{ - handleOnRowClick(record); - }, - selectedRowKeys: [selected], - type: "radio", - }} - onChange={handleTableChange} - onRow={(record, rowIndex) => { - return { - onClick: (event) => { - handleOnRowClick(record); + ); }, - }; - }} - /> - - ); + }, + { + 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: (a, b) => alphaSort(a.status, b.status), + sortOrder: + state.sortedInfo.columnKey === "status" && state.sortedInfo.order, + filteredValue: filter?.status || null, + filters: + (jobs && + jobs + .map((j) => j.status) + .filter(onlyUnique) + .map((s) => { + return { + text: s || "No Status*", + value: [s], + }; + }) + .sort((a, b) => + statusSort( + a.text, + b.text, + bodyshop.md_ro_statuses.active_statuses + ) + )) || + [], + 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: (a, b) => alphaSort(a.plate_no, b.plate_no), + sortOrder: + state.sortedInfo.columnKey === "plate_no" && state.sortedInfo.order, + }, + { + title: t("jobs.fields.clm_no"), + dataIndex: "clm_no", + key: "clm_no", + ellipsis: true, + responsive: ["md"], + sorter: (a, b) => alphaSort(a.clm_no, b.clm_no), + sortOrder: + state.sortedInfo.columnKey === "clm_no" && state.sortedInfo.order, + 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, + filteredValue: filter?.ins_co_nm || null, + filters: + (jobs && + jobs + .map((j) => j.ins_co_nm) + .filter(onlyUnique) + .map((s) => { + return { + text: s || "No Ins Co.*", + value: [s], + }; + }) + .sort((a, b) => alphaSort(a.text, b.text))) || + [], + 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: (a, b) => a.clm_total - b.clm_total, + sortOrder: + state.sortedInfo.columnKey === "clm_total" && state.sortedInfo.order, + render: (text, record) => ( + {record.clm_total} + ), + }, + { + title: t("jobs.labels.estimator"), + dataIndex: "jobs.labels.estimator", + key: "estimator", + ellipsis: true, + responsive: ["xl"], + filteredValue: filter?.estimator || null, + filterSearch: true, + filters: + (jobs && + jobs + .map((j) => `${j.est_ct_fn || ""} ${j.est_ct_ln || ""}`.trim()) + .filter(onlyUnique) + .map((s) => { + return { + text: s || "No Estimator*", + value: [s], + }; + }) + .sort((a, b) => alphaSort(a.text, b.text))) || + [], + 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 ( + + ({readyStatuses && readyStatuses.join(", ")}) + + { + setSearchText(e.target.value); + }} + value={searchText} + enterButton + /> + + } + > +
{ + handleOnRowClick(record); + }, + selectedRowKeys: [selected], + type: "radio", + }} + onChange={handleTableChange} + onRow={(record, rowIndex) => { + return { + onClick: (event) => { + handleOnRowClick(record); + }, + }; + }} + /> + + ); } export default connect(mapStateToProps, null)(JobsReadyList); diff --git a/client/src/translations/en_us/common.json b/client/src/translations/en_us/common.json index 09798f0a5..46dfbe01f 100644 --- a/client/src/translations/en_us/common.json +++ b/client/src/translations/en_us/common.json @@ -2621,6 +2621,7 @@ "open_orders": "Open Orders by Date", "open_orders_csr": "Open Orders by CSR", "open_orders_estimator": "Open Orders by Estimator", + "open_orders_excel": "Open Orders - Excel", "open_orders_ins_co": "Open Orders by Insurance Company", "open_orders_referral": "Open Orders by Referral Source", "open_orders_specific_csr": "Open Orders filtered by CSR", diff --git a/client/src/translations/es/common.json b/client/src/translations/es/common.json index da9f6b4e0..e7688ca48 100644 --- a/client/src/translations/es/common.json +++ b/client/src/translations/es/common.json @@ -2621,6 +2621,7 @@ "open_orders": "", "open_orders_csr": "", "open_orders_estimator": "", + "open_orders_excel": "", "open_orders_ins_co": "", "open_orders_referral": "", "open_orders_specific_csr": "", diff --git a/client/src/translations/fr/common.json b/client/src/translations/fr/common.json index a4c1dc686..4121c0c21 100644 --- a/client/src/translations/fr/common.json +++ b/client/src/translations/fr/common.json @@ -2621,6 +2621,7 @@ "open_orders": "", "open_orders_csr": "", "open_orders_estimator": "", + "open_orders_excel": "", "open_orders_ins_co": "", "open_orders_referral": "", "open_orders_specific_csr": "", diff --git a/client/src/utils/TemplateConstants.js b/client/src/utils/TemplateConstants.js index 365b2431e..eeb937c3a 100644 --- a/client/src/utils/TemplateConstants.js +++ b/client/src/utils/TemplateConstants.js @@ -2026,6 +2026,19 @@ export const TemplateList = (type, context) => { }, group: "customers", }, + open_orders_excel: { + title: i18n.t("reportcenter.templates.open_orders_excel"), + subject: i18n.t("reportcenter.templates.open_orders_excel"), + key: "open_orders_excel", + //idtype: "vendor", + reporttype: "excel", + disabled: false, + rangeFilter: { + object: i18n.t("reportcenter.labels.objects.jobs"), + field: i18n.t("jobs.fields.date_open"), + }, + group: "jobs", + }, } : {}), ...(!type || type === "courtesycarcontract" diff --git a/server/data/kaizen.js b/server/data/kaizen.js index 0df82a9ce..0d3720d25 100644 --- a/server/data/kaizen.js +++ b/server/data/kaizen.js @@ -29,17 +29,24 @@ const ftpSetup = { password: process.env.KAIZEN_PASSWORD, debug: (message, ...data) => logger.log(message, "DEBUG", "api", null, data), algorithms: { - serverHostKey: ["ssh-rsa", "ssh-dss", "rsa-sha2-256", "rsa-sha2-512", "ecdsa-sha2-nistp256", "ecdsa-sha2-nistp384"], + serverHostKey: [ + "ssh-rsa", + "ssh-dss", + "rsa-sha2-256", + "rsa-sha2-512", + "ecdsa-sha2-nistp256", + "ecdsa-sha2-nistp384", + ], }, }; exports.default = async (req, res) => { //Query for the List of Bodyshop Clients. logger.log("kaizen-start", "DEBUG", "api", null, null); - const kaizenShopsNames = ["SUMMIT", "STRATHMORE", "SUNRIDGE"]; + const kaizenShopsIDs = ["SUMMIT", "STRATHMORE", "SUNRIDGE"]; const { bodyshops } = await client.request(queries.GET_KAIZEN_SHOPS, { - shopname: kaizenShopsNames, + imexshopid: kaizenShopsIDs, }); const specificShopIds = req.body.bodyshopIds; // ['uuid] diff --git a/server/graphql-client/queries.js b/server/graphql-client/queries.js index 554388afe..b9c491de7 100644 --- a/server/graphql-client/queries.js +++ b/server/graphql-client/queries.js @@ -1739,8 +1739,8 @@ exports.GET_ENTEGRAL_SHOPS = `query GET_ENTEGRAL_SHOPS { } }`; -exports.GET_KAIZEN_SHOPS = `query GET_KAIZEN_SHOPS($shopname: [String]) { - bodyshops(where: {shopname: {_in: $shopname}}){ +exports.GET_KAIZEN_SHOPS = `query GET_KAIZEN_SHOPS($imexshopid: [String]) { + bodyshops(where: {imexshopid: {_in: $imexshopid}}){ id shopname address1