Merged in feature/IO-1828-Front-End-Package-Updates (pull request #1146)

Feature/IO-1828 Front End Package Updates
This commit is contained in:
Dave Richer
2024-01-09 23:39:53 +00:00
6 changed files with 169 additions and 162 deletions

View File

@@ -16,6 +16,7 @@ const BillLineSearchSelect = (
ref={ref} ref={ref}
showSearch showSearch
popupMatchSelectWidth={false} popupMatchSelectWidth={false}
optionLabelProp={"name"}
// optionFilterProp="line_desc" // optionFilterProp="line_desc"
filterOption={(inputValue, option) => { filterOption={(inputValue, option) => {
return ( return (
@@ -57,6 +58,9 @@ const BillLineSearchSelect = (
style={{ style={{
...(item.removed ? { textDecoration: "line-through" } : {}), ...(item.removed ? { textDecoration: "line-through" } : {}),
}} }}
name={`${item.removed ? `(REMOVED) ` : ""}${item.line_desc}${
item.oem_partno ? ` - ${item.oem_partno}` : ""
}${item.alt_partno ? ` (${item.alt_partno})` : ""}`.trim()}
> >
<span> <span>
{`${item.removed ? `(REMOVED) ` : ""}${item.line_desc}${ {`${item.removed ? `(REMOVED) ` : ""}${item.line_desc}${

View File

@@ -76,7 +76,7 @@ export default function CourtesyCarsList({ loading, courtesycars, refetch }) {
const mileageOver = nextservicekm ? nextservicekm <= mileage : false; const mileageOver = nextservicekm ? nextservicekm <= mileage : false;
const dueForService = const dueForService =
nextservicedate && dayjs(nextservicedate).end('day').isSameOrBefore(dayjs()); nextservicedate && dayjs(nextservicedate).endOf('day').isSameOrBefore(dayjs());
return ( return (
<Space> <Space>

View File

@@ -222,7 +222,7 @@ export function JobsDetailHeader({ job, bodyshop, disabled }) {
{`${job.v_vin || t("general.labels.na")}`} {`${job.v_vin || t("general.labels.na")}`}
</VehicleVinDisplay> </VehicleVinDisplay>
{bodyshop.pbs_serialnumber || bodyshop.cdk_dealerid ? ( {bodyshop.pbs_serialnumber || bodyshop.cdk_dealerid ? (
job.v_vin.length !== 17 ? ( job.v_vin?.length !== 17 ? (
<WarningFilled style={{ color: "tomato", marginLeft: ".3rem" }} /> <WarningFilled style={{ color: "tomato", marginLeft: ".3rem" }} />
) : null ) : null
) : null} ) : null}

View File

@@ -1,105 +1,105 @@
import _ from "lodash/"; import {groupBy} from "lodash";
const sortByParentId = (arr) => { const sortByParentId = (arr) => {
// return arr.reduce((accumulator, currentValue) => { // return arr.reduce((accumulator, currentValue) => {
// //Find the parent item. // //Find the parent item.
// let item = accumulator.find((x) => x.id === currentValue.kanbanparent); // let item = accumulator.find((x) => x.id === currentValue.kanbanparent);
// //Get index of praent item // //Get index of parent item
// let index = accumulator.indexOf(item); // let index = accumulator.indexOf(item);
// index = index !== -1 ? index + 1 : 0; // index = index !== -1 ? index + 1 : 0;
// accumulator.splice(index, 0, currentValue); // accumulator.splice(index, 0, currentValue);
// return accumulator; // return accumulator;
// }, []); // }, []);
var parentId = "-1"; let parentId = "-1";
var sortedList = []; const sortedList = [];
var byParentsIdsList = _.groupBy(arr, "kanbanparent"); // Create a new array with objects indexed by parentId const byParentsIdsList = groupBy(arr, "kanbanparent"); // Create a new array with objects indexed by parentId
//console.log("sortByParentId -> byParentsIdsList", byParentsIdsList); //console.log("sortByParentId -> byParentsIdsList", byParentsIdsList);
while (byParentsIdsList[parentId]) { while (byParentsIdsList[parentId]) {
sortedList.push(byParentsIdsList[parentId][0]); sortedList.push(byParentsIdsList[parentId][0]);
parentId = byParentsIdsList[parentId][0].id; parentId = byParentsIdsList[parentId][0].id;
} }
if (byParentsIdsList["null"]) if (byParentsIdsList["null"])
byParentsIdsList["null"].map((i) => sortedList.push(i)); byParentsIdsList["null"].map((i) => sortedList.push(i));
//Validate that the 2 arrays are of the same length and no children are missing. //Validate that the 2 arrays are of the same length and no children are missing.
if (arr.length !== sortedList.length) { if (arr.length !== sortedList.length) {
arr.map((origItem) => { arr.map((origItem) => {
if (!!!sortedList.find((s) => s.id === origItem.id)) { if (!!!sortedList.find((s) => s.id === origItem.id)) {
sortedList.push(origItem); sortedList.push(origItem);
console.log("DATA CONSISTENCY ERROR: ", origItem.ro_number); console.log("DATA CONSISTENCY ERROR: ", origItem.ro_number);
} }
return 1; return 1;
}); });
} }
return sortedList; return sortedList;
}; };
export const createBoardData = (AllStatuses, Jobs, filter) => { export const createBoardData = (AllStatuses, Jobs, filter) => {
const { search, employeeId } = filter; const {search, employeeId} = filter;
console.log("==========GENERATING BOARD DATA============="); const boardLanes = {
const boardLanes = { columns: AllStatuses.map((s) => {
columns: AllStatuses.map((s) => { return {
return { id: s,
id: s, title: s,
title: s, cards: [],
cards: [], };
}; }),
}), };
};
const filteredJobs = const filteredJobs =
(search === "" || !search) && !employeeId (search === "" || !search) && !employeeId
? Jobs ? Jobs
: Jobs.filter((j) => { : Jobs.filter((j) => {
let include = false; let include = false;
if (search && search !== "") { if (search && search !== "") {
include = CheckSearch(search, j); include = CheckSearch(search, j);
} }
if (!!employeeId) { if (!!employeeId) {
include = include =
include || include ||
j.employee_body === employeeId || j.employee_body === employeeId ||
j.employee_prep === employeeId || j.employee_prep === employeeId ||
j.employee_csr === employeeId || j.employee_csr === employeeId ||
j.employee_refinish === employeeId; j.employee_refinish === employeeId;
} }
return include; return include;
}); });
const DataGroupedByStatus = _.groupBy(filteredJobs, (d) => d.status); const DataGroupedByStatus = groupBy(filteredJobs, (d) => d.status);
Object.keys(DataGroupedByStatus).map((statusGroupKey) => { Object.keys(DataGroupedByStatus).map((statusGroupKey) => {
try { try {
boardLanes.columns.find((l) => l.id === statusGroupKey).cards = const needle = boardLanes.columns.find((l) => l.id === statusGroupKey);
sortByParentId(DataGroupedByStatus[statusGroupKey]); if (!needle?.cards) return null;
} catch (error) { needle.cards = sortByParentId(DataGroupedByStatus[statusGroupKey]);
console.log("Error while creating board card", error); } catch (error) {
} console.log("Error while creating board card", error);
return null; }
}); return null;
});
return boardLanes; return boardLanes;
}; };
const CheckSearch = (search, job) => { const CheckSearch = (search, job) => {
return ( return (
(job.ro_number || "").toLowerCase().includes(search.toLowerCase()) || (job.ro_number || "").toLowerCase().includes(search.toLowerCase()) ||
(job.ownr_fn || "").toLowerCase().includes(search.toLowerCase()) || (job.ownr_fn || "").toLowerCase().includes(search.toLowerCase()) ||
(job.ownr_co_nm || "").toLowerCase().includes(search.toLowerCase()) || (job.ownr_co_nm || "").toLowerCase().includes(search.toLowerCase()) ||
(job.ownr_ln || "").toLowerCase().includes(search.toLowerCase()) || (job.ownr_ln || "").toLowerCase().includes(search.toLowerCase()) ||
(job.status || "").toLowerCase().includes(search.toLowerCase()) || (job.status || "").toLowerCase().includes(search.toLowerCase()) ||
(job.v_make_desc || "").toLowerCase().includes(search.toLowerCase()) || (job.v_make_desc || "").toLowerCase().includes(search.toLowerCase()) ||
(job.v_model_desc || "").toLowerCase().includes(search.toLowerCase()) || (job.v_model_desc || "").toLowerCase().includes(search.toLowerCase()) ||
(job.clm_no || "").toLowerCase().includes(search.toLowerCase()) || (job.clm_no || "").toLowerCase().includes(search.toLowerCase()) ||
(job.plate_no || "").toLowerCase().includes(search.toLowerCase()) (job.plate_no || "").toLowerCase().includes(search.toLowerCase())
); );
}; };
// export const updateBoardOnMove = (board, card, source, destination) => { // export const updateBoardOnMove = (board, card, source, destination) => {

View File

@@ -1,89 +1,92 @@
import { HeartOutlined } from "@ant-design/icons"; import {HeartOutlined} from "@ant-design/icons";
import { Select, Space, Tag } from "antd"; import {Select, Space, Tag} from "antd";
import React, { forwardRef, useEffect, useState } from "react"; import React, {forwardRef, useEffect, useState} from "react";
import PhoneNumberFormatter from "../../utils/PhoneFormatter"; import PhoneNumberFormatter from "../../utils/PhoneFormatter";
const { Option } = Select;
const {Option} = Select;
//To be used as a form element only. //To be used as a form element only.
const VendorSearchSelect = ( const VendorSearchSelect = (
{ value, onChange, options, onSelect, disabled, preferredMake, showPhone }, {value, onChange, options, onSelect, disabled, preferredMake, showPhone},
ref ref
) => { ) => {
const [option, setOption] = useState(value); const [option, setOption] = useState(value);
useEffect(() => { useEffect(() => {
if (value !== option && onChange) { if (value !== option && onChange) {
onChange(option); onChange(option);
} }
}, [value, option, onChange]); }, [value, option, onChange]);
const favorites = const favorites =
preferredMake && options preferredMake && options
? options.filter( ? options.filter(
(o) => (o) =>
o.favorite.filter( o.favorite.filter(
(f) => f.toLowerCase() === preferredMake.toLowerCase() (f) => f.toLowerCase() === preferredMake.toLowerCase()
).length > 0 ).length > 0
) )
: []; : [];
return ( return (
<Select <Select
ref={ref} ref={ref}
showSearch showSearch
value={option} value={option}
style={{ style={{
width: "100%", width: "100%",
}} }}
popupMatchSelectWidth={false} popupMatchSelectWidth={false}
onChange={setOption} onChange={setOption}
optionFilterProp="name" optionFilterProp="name"
onSelect={onSelect} onSelect={onSelect}
disabled={disabled || false} disabled={disabled || false}
> optionLabelProp={"name"}
{favorites >
? favorites.map((o) => ( {favorites
<Option ? favorites.map((o) => (
key={`favorite-${o.id}`} <Option
value={o.id} key={`favorite-${o.id}`}
name={o.name} value={o.id}
discount={o.discount} name={o.name}
> discount={o.discount}
<div className="imex-flex-row"> >
<div style={{ flex: 1 }}>{o.name}</div> <div className="imex-flex-row">
<Space style={{ marginLeft: "1rem" }}> <div style={{flex: 1}}>{o.name}</div>
<HeartOutlined style={{ color: "red" }} /> <Space style={{marginLeft: "1rem"}}>
{o.phone && showPhone && ( <HeartOutlined style={{color: "red"}}/>
<PhoneNumberFormatter>{o.phone}</PhoneNumberFormatter> {o.phone && showPhone && (
)} <PhoneNumberFormatter>{o.phone}</PhoneNumberFormatter>
{o.discount && o.discount !== 0 ? ( )}
<Tag color="green">{`${o.discount * 100}%`}</Tag> {o.discount && o.discount !== 0 ? (
) : null} <Tag color="green">{`${o.discount * 100}%`}</Tag>
</Space> ) : null}
</div> </Space>
</Option> </div>
)) </Option>
: null} ))
{options : null}
? options.map((o) => ( {options
<Option key={o.id} value={o.id} name={o.name} discount={o.discount}> ? options.map((o) => (
<div className="imex-flex-row" style={{ width: "100%" }}> <Option key={o.id} value={o.id} name={o.name} discount={o.discount}>
<div style={{ flex: 1 }}>{o.name}</div> <div className="imex-flex-row" style={{width: "100%"}}>
<div style={{flex: 1}}>{o.name}</div>
<Space style={{ marginLeft: "1rem" }}> <Space style={{marginLeft: "1rem"}}>
{o.phone && showPhone && ( {o.phone && showPhone && (
<PhoneNumberFormatter>{o.phone}</PhoneNumberFormatter> <PhoneNumberFormatter>{o.phone}</PhoneNumberFormatter>
)} )}
{o.discount && o.discount !== 0 ? ( {o.discount && o.discount !== 0 ? (
<Tag color="green">{`${o.discount * 100}%`}</Tag> <Tag color="green">{`${o.discount * 100}%`}</Tag>
) : null} ) : null}
</Space> </Space>
</div> </div>
</Option> </Option>
))
: null} ))
</Select> : null}
); </Select>
);
}; };
export default forwardRef(VendorSearchSelect); export default forwardRef(VendorSearchSelect);

View File

@@ -1,6 +1,6 @@
import { useMutation, useQuery } from "@apollo/client"; import { useMutation, useQuery } from "@apollo/client";
import { Form, notification } from "antd"; import { Form, notification } from "antd";
import dayjs from "dayjs"; import dayjs from "../../utils/day";
import React, { useEffect, useState } from "react"; import React, { useEffect, useState } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { connect } from "react-redux"; import { connect } from "react-redux";