- Fix the page layout, the footer was in the content section causing it not to remain at the bottom and just reside 'at the bottom' of the content section. Also added a 100% on the outer container height (100vh) so the grey background fills the page

Signed-off-by: Dave Richer <dave@imexsystems.ca>
This commit is contained in:
Dave Richer
2024-01-16 15:32:35 -05:00
9 changed files with 718 additions and 681 deletions

View File

@@ -6,13 +6,15 @@ 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 {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,
@@ -25,6 +27,7 @@ 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();
@@ -93,6 +96,7 @@ export function JobsList({ bodyshop, refetch, loading, jobs, total }) {
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]};
}),
@@ -189,6 +193,7 @@ export function JobsList({ bodyshop, refetch, loading, jobs, total }) {
} else {
delete search.statusFilters;
}
setFilter(filters);
history({search: queryString.stringify(search)});
};
@@ -273,4 +278,5 @@ export function JobsList({ bodyshop, refetch, loading, jobs, total }) {
</Card>
);
}
export default connect(mapStateToProps, mapDispatchToProps)(JobsList);

View File

@@ -1,22 +1,18 @@
import {
SyncOutlined,
ExclamationCircleFilled,
PauseCircleOutlined,
BranchesOutlined,
} from "@ant-design/icons";
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 {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";
@@ -39,10 +35,8 @@ 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 history = useNavigate();
@@ -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) => {
@@ -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(

View File

@@ -1,26 +1,22 @@
import {
BranchesOutlined,
ExclamationCircleFilled,
PauseCircleOutlined,
SyncOutlined,
} from "@ant-design/icons";
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, {useMemo, useState} from "react";
import {useTranslation} from "react-i18next";
import {connect} from "react-redux";
import { Link, useNavigate, useLocation } from "react-router-dom";
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 CurrencyFormatter from "../../utils/CurrencyFormatter";
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 ChatOpenButton 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({
bodyshop: selectBodyshop,
@@ -53,10 +49,8 @@ export function JobsReadyList({ bodyshop }) {
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();
@@ -105,7 +99,8 @@ export function JobsReadyList({ bodyshop }) {
: [];
const handleTableChange = (pagination, filters, sorter) => {
setState({ ...state, filteredInfo: filters, sortedInfo: sorter });
setState({...state, sortedInfo: sorter});
setFilter(filters);
};
const handleOnRowClick = (record) => {
@@ -129,7 +124,6 @@ export function JobsReadyList({ bodyshop }) {
sorter: (a, b) => alphaSort(a.ro_number, b.ro_number),
sortOrder:
state.sortedInfo.columnKey === "ro_number" && state.sortedInfo.order,
render: (text, record) => (
<Link
to={"/manage/jobs/" + record.id}
@@ -157,7 +151,6 @@ export function JobsReadyList({ bodyshop }) {
dataIndex: "owner",
key: "owner",
ellipsis: true,
responsive: ["md"],
sorter: (a, b) => alphaSort(a.ownr_ln, b.ownr_ln),
sortOrder:
@@ -197,16 +190,15 @@ export function JobsReadyList({ bodyshop }) {
<ChatOpenButton phone={record.ownr_ph2} jobid={record.id}/>
),
},
{
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
@@ -217,11 +209,17 @@ export function JobsReadyList({ 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),
},
{
title: t("jobs.fields.vehicle"),
dataIndex: "vehicle",
@@ -274,6 +272,7 @@ export function JobsReadyList({ bodyshop }) {
dataIndex: "ins_co_nm",
key: "ins_co_nm",
ellipsis: true,
filteredValue: filter?.ins_co_nm || null,
filters:
(jobs &&
jobs
@@ -281,10 +280,11 @@ export function JobsReadyList({ 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"],
@@ -295,7 +295,6 @@ export function JobsReadyList({ bodyshop }) {
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,
@@ -306,9 +305,10 @@ export function JobsReadyList({ bodyshop }) {
{
title: t("jobs.labels.estimator"),
dataIndex: "jobs.labels.estimator",
key: "jobs.labels.estimator",
key: "estimator",
ellipsis: true,
responsive: ["xl"],
filteredValue: filter?.estimator || null,
filterSearch: true,
filters:
(jobs &&
@@ -317,10 +317,11 @@ export function JobsReadyList({ 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(

View File

@@ -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",

View File

@@ -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": "",

View File

@@ -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": "",

View File

@@ -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"

View File

@@ -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]

View File

@@ -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