Merge branch 'master-AIO' into feature/IO-3092-imgproxy
This commit is contained in:
@@ -42,8 +42,7 @@ export function ChatPopupComponent({ chatVisible, selectedConversation, toggleCh
|
||||
const { data: unreadData } = useQuery(UNREAD_CONVERSATION_COUNT, {
|
||||
fetchPolicy: "network-only",
|
||||
nextFetchPolicy: "network-only",
|
||||
skip: chatVisible, // Skip when chat is visible
|
||||
...(pollInterval > 0 ? { pollInterval } : {})
|
||||
pollInterval: 60 * 1000 // TODO: This is a fix for now, should be coming from sockets
|
||||
});
|
||||
|
||||
// Socket connection status
|
||||
@@ -85,29 +84,25 @@ export function ChatPopupComponent({ chatVisible, selectedConversation, toggleCh
|
||||
|
||||
// Get unread count from the cache
|
||||
const unreadCount = (() => {
|
||||
if (chatVisible) {
|
||||
try {
|
||||
const cachedData = client.readQuery({
|
||||
query: CONVERSATION_LIST_QUERY,
|
||||
variables: { offset: 0 }
|
||||
});
|
||||
try {
|
||||
const cachedData = client.readQuery({
|
||||
query: CONVERSATION_LIST_QUERY,
|
||||
variables: { offset: 0 }
|
||||
});
|
||||
|
||||
if (!cachedData?.conversations) return 0;
|
||||
|
||||
// Aggregate unread message count
|
||||
return cachedData.conversations.reduce((total, conversation) => {
|
||||
const unread = conversation.messages_aggregate?.aggregate?.count || 0;
|
||||
return total + unread;
|
||||
}, 0);
|
||||
} catch (error) {
|
||||
console.warn("Unread count not found in cache:", error);
|
||||
return 0; // Fallback if not in cache
|
||||
if (!cachedData?.conversations) {
|
||||
return unreadData?.messages_aggregate?.aggregate?.count;
|
||||
}
|
||||
} else if (unreadData?.messages_aggregate?.aggregate?.count) {
|
||||
// Use the unread count from the query result
|
||||
return unreadData.messages_aggregate.aggregate.count;
|
||||
|
||||
// Aggregate unread message count
|
||||
return cachedData.conversations.reduce((total, conversation) => {
|
||||
const unread = conversation.messages_aggregate?.aggregate?.count || 0;
|
||||
return total + unread;
|
||||
}, 0);
|
||||
} catch (error) {
|
||||
console.warn("Unread count not found in cache:", error);
|
||||
return 0; // Fallback if not in cache
|
||||
}
|
||||
return 0;
|
||||
})();
|
||||
|
||||
return (
|
||||
|
||||
@@ -1,16 +1,15 @@
|
||||
import i18next from "i18next";
|
||||
import React from "react";
|
||||
import { connect } from "react-redux";
|
||||
import { setUserLanguage } from "../../redux/user/user.actions";
|
||||
import HeaderComponent from "./header.component";
|
||||
import { logImEXEvent } from "../../firebase/firebase.utils";
|
||||
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
setUserLanguage: (language) => dispatch(setUserLanguage(language))
|
||||
});
|
||||
// const mapDispatchToProps = (dispatch) => ({
|
||||
// setUserLanguage: (language) => dispatch(setUserLanguage(language))
|
||||
// });
|
||||
|
||||
export function HeaderContainer({ setUserLanguage }) {
|
||||
const handleMenuClick = (e) => {
|
||||
// setUserLanguage was removed from signature because it is not used in the component, and it is throwing a deprecation warning
|
||||
export function HeaderContainer() {
|
||||
// Commented out the handleMenuClick function because it is not used in the component, and it is throwing a deprecation warning
|
||||
|
||||
/* const handleMenuClick = (e) => {
|
||||
if (e.item.props.actiontype === "lang-select") {
|
||||
i18next.changeLanguage(e.key, (err, t) => {
|
||||
if (err) {
|
||||
@@ -23,9 +22,10 @@ export function HeaderContainer({ setUserLanguage }) {
|
||||
setUserLanguage(e.key);
|
||||
});
|
||||
}
|
||||
};
|
||||
};*/
|
||||
// return <HeaderComponent handleMenuClick={handleMenuClick} />;
|
||||
|
||||
return <HeaderComponent handleMenuClick={handleMenuClick} />;
|
||||
return <HeaderComponent />;
|
||||
}
|
||||
|
||||
export default connect(null, mapDispatchToProps)(HeaderContainer);
|
||||
export default connect(null, null)(HeaderContainer);
|
||||
|
||||
@@ -62,6 +62,9 @@ function JobLinesUpsertModalContainer({ jobLineEditModal, toggleModalVisible, bo
|
||||
refetchQueries: ["GET_LINE_TICKET_BY_PK"]
|
||||
});
|
||||
if (!r.errors) {
|
||||
if (CriticalPartsScanning.treatment === "on") {
|
||||
await CriticalPartsScan(jobLineEditModal.context.jobid, notification);
|
||||
}
|
||||
await Axios.post("/job/totalsssu", {
|
||||
id: jobLineEditModal.context.jobid
|
||||
});
|
||||
@@ -107,7 +110,9 @@ function JobLinesUpsertModalContainer({ jobLineEditModal, toggleModalVisible, bo
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
if (CriticalPartsScanning.treatment === "on") {
|
||||
await CriticalPartsScan(jobLineEditModal.context.jobid, notification);
|
||||
}
|
||||
if (jobLineEditModal.actions.submit) {
|
||||
jobLineEditModal.actions.submit();
|
||||
} else {
|
||||
@@ -115,9 +120,7 @@ function JobLinesUpsertModalContainer({ jobLineEditModal, toggleModalVisible, bo
|
||||
}
|
||||
toggleModalVisible();
|
||||
}
|
||||
if (CriticalPartsScanning.treatment === "on") {
|
||||
CriticalPartsScan(jobLineEditModal.context.jobid, notification);
|
||||
}
|
||||
|
||||
setLoading(false);
|
||||
};
|
||||
|
||||
|
||||
@@ -172,13 +172,13 @@ export function JobsAvailableContainer({ bodyshop, currentUser, insertAuditTrail
|
||||
job: newJob
|
||||
}
|
||||
});
|
||||
if (CriticalPartsScanning.treatment === "on") {
|
||||
await CriticalPartsScan(r.data.insert_jobs.returning[0].id, notification);
|
||||
}
|
||||
await Axios.post("/job/totalsssu", {
|
||||
id: r.data.insert_jobs.returning[0].id
|
||||
});
|
||||
|
||||
if (CriticalPartsScanning.treatment === "on") {
|
||||
CriticalPartsScan(r.data.insert_jobs.returning[0].id, notification);
|
||||
}
|
||||
notification["success"]({
|
||||
message: t("jobs.successes.created"),
|
||||
onClick: () => {
|
||||
@@ -281,6 +281,7 @@ export function JobsAvailableContainer({ bodyshop, currentUser, insertAuditTrail
|
||||
if (CriticalPartsScanning.treatment === "on") {
|
||||
CriticalPartsScan(updateResult.data.update_jobs.returning[0].id, notification);
|
||||
}
|
||||
|
||||
if (updateResult.errors) {
|
||||
//error while inserting
|
||||
notification["error"]({
|
||||
|
||||
@@ -1,16 +1,27 @@
|
||||
import {DeleteFilled} from "@ant-design/icons";
|
||||
import {Button, Col, Form, Input, Row, Select, Space, Switch} from "antd";
|
||||
import React, {useMemo} from "react";
|
||||
import {useTranslation} from "react-i18next";
|
||||
import { DeleteFilled } from "@ant-design/icons";
|
||||
import { Button, Col, Form, Input, Row, Select, Space, Switch } from "antd";
|
||||
import { useMemo } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import FormListMoveArrows from "../form-list-move-arrows/form-list-move-arrows.component";
|
||||
import LayoutFormRow from "../layout-form-row/layout-form-row.component";
|
||||
import i18n from "i18next";
|
||||
|
||||
const predefinedPartTypes = [
|
||||
"PAN", "PAC", "PAR", "PAL", "PAA", "PAM", "PAP", "PAS", "PASL", "PAG"
|
||||
];
|
||||
const predefinedPartTypes = ["PAN", "PAC", "PAR", "PAL", "PAA", "PAM", "PAP", "PAS", "PASL", "PAG"];
|
||||
const predefinedModLbrTypes = [
|
||||
"LAA", "LAB", "LAD", "LAE", "LAF", "LAG", "LAM", "LAR", "LAS", "LAU",
|
||||
"LA1", "LA2", "LA3", "LA4"
|
||||
"LAA",
|
||||
"LAB",
|
||||
"LAD",
|
||||
"LAE",
|
||||
"LAF",
|
||||
"LAG",
|
||||
"LAM",
|
||||
"LAR",
|
||||
"LAS",
|
||||
"LAU",
|
||||
"LA1",
|
||||
"LA2",
|
||||
"LA3",
|
||||
"LA4"
|
||||
];
|
||||
|
||||
const getFieldType = (field) => {
|
||||
@@ -20,30 +31,46 @@ const getFieldType = (field) => {
|
||||
return null;
|
||||
};
|
||||
|
||||
export default function ShopInfoPartsScan({form}) {
|
||||
const {t} = useTranslation();
|
||||
const fieldSelectOptions = [
|
||||
{ label: i18n.t("joblines.fields.line_desc"), value: "line_desc" },
|
||||
{ label: i18n.t("joblines.fields.part_type"), value: "part_type" },
|
||||
{ label: i18n.t("joblines.fields.act_price"), value: "act_price" },
|
||||
{ label: i18n.t("joblines.fields.part_qty"), value: "part_qty" },
|
||||
{ label: i18n.t("joblines.fields.mod_lbr_ty"), value: "mod_lbr_ty" },
|
||||
|
||||
{
|
||||
label: `${i18n.t("joblines.fields.oem_partno")} / ${i18n.t("joblines.fields.alt_partno")}`,
|
||||
value: "part_number"
|
||||
},
|
||||
{ label: i18n.t("joblines.fields.op_code_desc"), value: "op_code_desc" }
|
||||
];
|
||||
export default function ShopInfoPartsScan({ form }) {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const watchedFields = Form.useWatch("md_parts_scan", form);
|
||||
|
||||
const operationOptions = useMemo(() => ({
|
||||
string: [
|
||||
{label: t("bodyshop.operations.contains"), value: "contains"},
|
||||
{label: t("bodyshop.operations.equals"), value: "equals"},
|
||||
{label: t("bodyshop.operations.starts_with"), value: "startsWith"},
|
||||
{label: t("bodyshop.operations.ends_with"), value: "endsWith"},
|
||||
],
|
||||
number: [
|
||||
{label: t("bodyshop.operations.equals"), value: "="},
|
||||
{label: t("bodyshop.operations.greater_than"), value: ">"},
|
||||
{label: t("bodyshop.operations.less_than"), value: "<"},
|
||||
],
|
||||
}), [t]);
|
||||
const operationOptions = useMemo(
|
||||
() => ({
|
||||
string: [
|
||||
{ label: t("bodyshop.operations.contains"), value: "contains" },
|
||||
{ label: t("bodyshop.operations.equals"), value: "equals" },
|
||||
{ label: t("bodyshop.operations.starts_with"), value: "startsWith" },
|
||||
{ label: t("bodyshop.operations.ends_with"), value: "endsWith" }
|
||||
],
|
||||
number: [
|
||||
{ label: t("bodyshop.operations.equals"), value: "=" },
|
||||
{ label: t("bodyshop.operations.greater_than"), value: ">" },
|
||||
{ label: t("bodyshop.operations.less_than"), value: "<" }
|
||||
]
|
||||
}),
|
||||
[t]
|
||||
);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<LayoutFormRow header={t("bodyshop.labels.md_parts_scan")}>
|
||||
<Form.List name={["md_parts_scan"]}>
|
||||
{(fields, {add, remove, move}) => (
|
||||
{(fields, { add, remove, move }) => (
|
||||
<div>
|
||||
{fields.map((field, index) => {
|
||||
const selectedField = watchedFields?.[index]?.field || "line_desc";
|
||||
@@ -61,28 +88,17 @@ export default function ShopInfoPartsScan({form}) {
|
||||
{
|
||||
required: true,
|
||||
message: t("general.validation.required", {
|
||||
label: t("bodyshop.fields.md_parts_scan.field"),
|
||||
}),
|
||||
},
|
||||
label: t("bodyshop.fields.md_parts_scan.field")
|
||||
})
|
||||
}
|
||||
]}
|
||||
>
|
||||
<Select
|
||||
options={[
|
||||
{label: t("joblines.fields.line_desc"), value: "line_desc"},
|
||||
{label: t("joblines.fields.part_type"), value: "part_type"},
|
||||
{label: t("joblines.fields.act_price"), value: "act_price"},
|
||||
{label: t("joblines.fields.part_qty"), value: "part_qty"},
|
||||
{label: t("joblines.fields.mod_lbr_ty"), value: "mod_lbr_ty"},
|
||||
{label: t("joblines.fields.mod_lb_hrs"), value: "mod_lb_hrs"},
|
||||
{
|
||||
label: `${t("joblines.fields.oem_partno")} / ${t("joblines.fields.alt_partno")}`,
|
||||
value: "part_number"
|
||||
},
|
||||
]}
|
||||
options={fieldSelectOptions}
|
||||
onChange={() => {
|
||||
form.setFields([
|
||||
{name: ["md_parts_scan", index, "operation"], value: "contains"},
|
||||
{name: ["md_parts_scan", index, "value"], value: undefined},
|
||||
{ name: ["md_parts_scan", index, "operation"], value: "contains" },
|
||||
{ name: ["md_parts_scan", index, "value"], value: undefined }
|
||||
]);
|
||||
}}
|
||||
/>
|
||||
@@ -99,12 +115,12 @@ export default function ShopInfoPartsScan({form}) {
|
||||
{
|
||||
required: true,
|
||||
message: t("general.validation.required", {
|
||||
label: t("bodyshop.fields.md_parts_scan.operation"),
|
||||
}),
|
||||
},
|
||||
label: t("bodyshop.fields.md_parts_scan.operation")
|
||||
})
|
||||
}
|
||||
]}
|
||||
>
|
||||
<Select options={operationOptions[fieldType]}/>
|
||||
<Select options={operationOptions[fieldType]} />
|
||||
</Form.Item>
|
||||
</Col>
|
||||
)}
|
||||
@@ -119,9 +135,9 @@ export default function ShopInfoPartsScan({form}) {
|
||||
{
|
||||
required: true,
|
||||
message: t("general.validation.required", {
|
||||
label: t("bodyshop.fields.md_parts_scan.value"),
|
||||
}),
|
||||
},
|
||||
label: t("bodyshop.fields.md_parts_scan.value")
|
||||
})
|
||||
}
|
||||
]}
|
||||
>
|
||||
{fieldType === "predefined" ? (
|
||||
@@ -129,17 +145,17 @@ export default function ShopInfoPartsScan({form}) {
|
||||
options={
|
||||
selectedField === "part_type"
|
||||
? predefinedPartTypes.map((type) => ({
|
||||
label: type,
|
||||
value: type
|
||||
}))
|
||||
label: type,
|
||||
value: type
|
||||
}))
|
||||
: predefinedModLbrTypes.map((type) => ({
|
||||
label: type,
|
||||
value: type
|
||||
}))
|
||||
label: type,
|
||||
value: type
|
||||
}))
|
||||
}
|
||||
/>
|
||||
) : (
|
||||
<Input/>
|
||||
<Input />
|
||||
)}
|
||||
</Form.Item>
|
||||
</Col>
|
||||
@@ -152,19 +168,70 @@ export default function ShopInfoPartsScan({form}) {
|
||||
label={t("bodyshop.fields.md_parts_scan.caseInsensitive")}
|
||||
name={[field.name, "caseInsensitive"]}
|
||||
valuePropName="checked"
|
||||
labelCol={{span: 14}}
|
||||
wrapperCol={{span: 10}}
|
||||
initialValue={true}
|
||||
labelCol={{ span: 14 }}
|
||||
wrapperCol={{ span: 10 }}
|
||||
>
|
||||
<Switch defaultChecked={true}/>
|
||||
<Switch />
|
||||
</Form.Item>
|
||||
</Col>
|
||||
)}
|
||||
|
||||
{/* Mark Line as Critical */}
|
||||
<Col span={4}>
|
||||
<Form.Item
|
||||
label={t("bodyshop.fields.md_parts_scan.mark_critical")}
|
||||
name={[field.name, "mark_critical"]}
|
||||
valuePropName="checked"
|
||||
initialValue={true}
|
||||
labelCol={{ span: 14 }}
|
||||
wrapperCol={{ span: 10 }}
|
||||
>
|
||||
<Switch />
|
||||
</Form.Item>
|
||||
</Col>
|
||||
|
||||
{/* Update Field */}
|
||||
<Col span={4}>
|
||||
<Form.Item
|
||||
label={t("bodyshop.fields.md_parts_scan.update_field")}
|
||||
name={[field.name, "update_field"]}
|
||||
>
|
||||
<Select
|
||||
options={fieldSelectOptions}
|
||||
allowClear
|
||||
onClear={() =>
|
||||
form.setFields([{ name: ["md_parts_scan", index, "update_field"], value: null }])
|
||||
}
|
||||
/>
|
||||
</Form.Item>
|
||||
</Col>
|
||||
|
||||
{/* Update Field */}
|
||||
<Col span={4}>
|
||||
<Form.Item
|
||||
label={t("bodyshop.fields.md_parts_scan.update_value")}
|
||||
name={[field.name, "update_value"]}
|
||||
dependencies={[["md_parts_scan", index, "update_field"]]}
|
||||
tooltip={t("bodyshop.tooltips.md_parts_scan.update_value_tooltip")}
|
||||
rules={[
|
||||
{
|
||||
required: form.getFieldValue(["md_parts_scan", index, "update_field"]),
|
||||
message: t("general.validation.required", {
|
||||
label: t("bodyshop.fields.md_parts_scan.update_value")
|
||||
})
|
||||
}
|
||||
]}
|
||||
>
|
||||
<Input />
|
||||
</Form.Item>
|
||||
</Col>
|
||||
|
||||
{/* Actions */}
|
||||
<Col span={2}>
|
||||
<Space>
|
||||
<DeleteFilled onClick={() => remove(field.name)}/>
|
||||
<FormListMoveArrows move={move} index={index} total={fields.length}/>
|
||||
<DeleteFilled onClick={() => remove(field.name)} />
|
||||
<FormListMoveArrows move={move} index={index} total={fields.length} />
|
||||
</Space>
|
||||
</Col>
|
||||
</Row>
|
||||
@@ -175,8 +242,8 @@ export default function ShopInfoPartsScan({form}) {
|
||||
<Form.Item>
|
||||
<Button
|
||||
type="dashed"
|
||||
onClick={() => add({field: "line_desc", operation: "contains"})}
|
||||
style={{width: "100%"}}
|
||||
onClick={() => add({ field: "line_desc", operation: "contains" })}
|
||||
style={{ width: "100%" }}
|
||||
>
|
||||
{t("bodyshop.actions.addpartsrule")}
|
||||
</Button>
|
||||
|
||||
Reference in New Issue
Block a user