Merged in release/2024-12-06 (pull request #1985)
Release/2024 12 06 into test-AIO - IO-3047 IO-3046 IO-3048
This commit is contained in:
@@ -334,12 +334,47 @@ export const registerMessagingHandlers = ({ socket, client }) => {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case "tag-added":
|
case "tag-added":
|
||||||
|
// Ensure `job_conversations` is properly formatted
|
||||||
|
const formattedJobConversations = job_conversations.map((jc) => ({
|
||||||
|
__typename: "job_conversations",
|
||||||
|
jobid: jc.jobid || jc.job?.id,
|
||||||
|
conversationid: conversationId,
|
||||||
|
job: jc.job || {
|
||||||
|
__typename: "jobs",
|
||||||
|
id: data.selectedJob.id,
|
||||||
|
ro_number: data.selectedJob.ro_number,
|
||||||
|
ownr_co_nm: data.selectedJob.ownr_co_nm,
|
||||||
|
ownr_fn: data.selectedJob.ownr_fn,
|
||||||
|
ownr_ln: data.selectedJob.ownr_ln
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
client.cache.modify({
|
client.cache.modify({
|
||||||
id: client.cache.identify({ __typename: "conversations", id: conversationId }),
|
id: client.cache.identify({ __typename: "conversations", id: conversationId }),
|
||||||
fields: {
|
fields: {
|
||||||
job_conversations: (existing = []) => [...existing, ...job_conversations]
|
job_conversations: (existing = []) => {
|
||||||
|
// Ensure no duplicates based on `jobid`
|
||||||
|
const existingIds = new Set(
|
||||||
|
existing.map(
|
||||||
|
(jc) =>
|
||||||
|
client.cache.readFragment({
|
||||||
|
id: client.cache.identify(jc),
|
||||||
|
fragment: gql`
|
||||||
|
fragment JobConversationId on job_conversations {
|
||||||
|
jobid
|
||||||
|
}
|
||||||
|
`
|
||||||
|
})?.jobid
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
const newItems = formattedJobConversations.filter((jc) => !existingIds.has(jc.jobid));
|
||||||
|
|
||||||
|
return [...existing, ...newItems];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "tag-removed":
|
case "tag-removed":
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import React, { useEffect, useRef, useState } from "react";
|
import React, { useCallback, useEffect, useRef, useState } from "react";
|
||||||
import { Virtuoso } from "react-virtuoso";
|
import { Virtuoso } from "react-virtuoso";
|
||||||
import { renderMessage } from "./renderMessage";
|
import { renderMessage } from "./renderMessage";
|
||||||
import "./chat-message-list.styles.scss";
|
import "./chat-message-list.styles.scss";
|
||||||
@@ -16,7 +16,7 @@ export default function ChatMessageListComponent({ messages }) {
|
|||||||
loadedImagesRef.current = 0;
|
loadedImagesRef.current = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
const preloadImages = (imagePaths, onComplete) => {
|
const preloadImages = useCallback((imagePaths, onComplete) => {
|
||||||
resetImageLoadState();
|
resetImageLoadState();
|
||||||
|
|
||||||
if (imagePaths.length === 0) {
|
if (imagePaths.length === 0) {
|
||||||
@@ -34,7 +34,7 @@ export default function ChatMessageListComponent({ messages }) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
};
|
}, []);
|
||||||
|
|
||||||
// Ensure all images are loaded on initial render
|
// Ensure all images are loaded on initial render
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -51,7 +51,7 @@ export default function ChatMessageListComponent({ messages }) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}, [messages]);
|
}, [messages, preloadImages]);
|
||||||
|
|
||||||
// Handle scrolling when new messages are added
|
// Handle scrolling when new messages are added
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -69,7 +69,7 @@ export default function ChatMessageListComponent({ messages }) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}, [messages, atBottom]);
|
}, [messages, atBottom, preloadImages]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="chat">
|
<div className="chat">
|
||||||
|
|||||||
@@ -52,20 +52,26 @@ export function ChatTagRoContainer({ conversation, bodyshop }) {
|
|||||||
// Find the job details from the search data
|
// Find the job details from the search data
|
||||||
const selectedJob = data?.search_jobs.find((job) => job.id === option.key);
|
const selectedJob = data?.search_jobs.find((job) => job.id === option.key);
|
||||||
if (!selectedJob) return;
|
if (!selectedJob) return;
|
||||||
const newJobConversation = {
|
|
||||||
__typename: "job_conversations",
|
|
||||||
jobid: selectedJob.id,
|
|
||||||
conversationid: conversation.id,
|
|
||||||
job: {
|
|
||||||
__typename: "jobs",
|
|
||||||
...selectedJob
|
|
||||||
}
|
|
||||||
};
|
|
||||||
socket.emit("conversation-modified", {
|
socket.emit("conversation-modified", {
|
||||||
conversationId: conversation.id,
|
conversationId: conversation.id,
|
||||||
bodyshopId: bodyshop.id,
|
bodyshopId: bodyshop.id,
|
||||||
type: "tag-added",
|
type: "tag-added",
|
||||||
job_conversations: [newJobConversation]
|
selectedJob,
|
||||||
|
job_conversations: [
|
||||||
|
{
|
||||||
|
__typename: "job_conversations",
|
||||||
|
jobid: selectedJob.id,
|
||||||
|
conversationid: conversation.id,
|
||||||
|
job: {
|
||||||
|
__typename: "jobs",
|
||||||
|
id: selectedJob.id,
|
||||||
|
ro_number: selectedJob.ro_number,
|
||||||
|
ownr_co_nm: selectedJob.ownr_co_nm,
|
||||||
|
ownr_fn: selectedJob.ownr_fn,
|
||||||
|
ownr_ln: selectedJob.ownr_ln
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -25,6 +25,9 @@ export default function OwnerDetailFormComponent({ form, loading }) {
|
|||||||
<Form.Item label={t("owners.fields.ownr_co_nm")} name="ownr_co_nm">
|
<Form.Item label={t("owners.fields.ownr_co_nm")} name="ownr_co_nm">
|
||||||
<Input />
|
<Input />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
<Form.Item label={t("owners.fields.accountingid")} name="accountingid">
|
||||||
|
<Input disabled/>
|
||||||
|
</Form.Item>
|
||||||
</LayoutFormRow>
|
</LayoutFormRow>
|
||||||
<LayoutFormRow header={t("owners.forms.address")}>
|
<LayoutFormRow header={t("owners.forms.address")}>
|
||||||
<Form.Item label={t("owners.fields.ownr_addr1")} name="ownr_addr1">
|
<Form.Item label={t("owners.fields.ownr_addr1")} name="ownr_addr1">
|
||||||
|
|||||||
@@ -48,6 +48,7 @@ export const QUERY_OWNER_BY_ID = gql`
|
|||||||
query QUERY_OWNER_BY_ID($id: uuid!) {
|
query QUERY_OWNER_BY_ID($id: uuid!) {
|
||||||
owners_by_pk(id: $id) {
|
owners_by_pk(id: $id) {
|
||||||
id
|
id
|
||||||
|
accountingid
|
||||||
allow_text_message
|
allow_text_message
|
||||||
ownr_addr1
|
ownr_addr1
|
||||||
ownr_addr2
|
ownr_addr2
|
||||||
|
|||||||
@@ -2394,6 +2394,7 @@
|
|||||||
"selectexistingornew": "Select an existing owner record or create a new one. "
|
"selectexistingornew": "Select an existing owner record or create a new one. "
|
||||||
},
|
},
|
||||||
"fields": {
|
"fields": {
|
||||||
|
"accountingid": "Accounting ID",
|
||||||
"address": "Address",
|
"address": "Address",
|
||||||
"allow_text_message": "Permission to Text?",
|
"allow_text_message": "Permission to Text?",
|
||||||
"name": "Name",
|
"name": "Name",
|
||||||
@@ -3057,6 +3058,7 @@
|
|||||||
"production_not_production_status": "Production not in Production Status",
|
"production_not_production_status": "Production not in Production Status",
|
||||||
"production_over_time": "Production Level over Time",
|
"production_over_time": "Production Level over Time",
|
||||||
"psr_by_make": "Percent of Sales by Vehicle Make",
|
"psr_by_make": "Percent of Sales by Vehicle Make",
|
||||||
|
"purchase_return_ratio_excel": "Purchase & Return Ratio - Excel",
|
||||||
"purchase_return_ratio_grouped_by_vendor_detail": "Purchase & Return Ratio by Vendor (Detail)",
|
"purchase_return_ratio_grouped_by_vendor_detail": "Purchase & Return Ratio by Vendor (Detail)",
|
||||||
"purchase_return_ratio_grouped_by_vendor_summary": "Purchase & Return Ratio by Vendor (Summary)",
|
"purchase_return_ratio_grouped_by_vendor_summary": "Purchase & Return Ratio by Vendor (Summary)",
|
||||||
"purchases_by_cost_center_detail": "Purchases by Cost Center (Detail)",
|
"purchases_by_cost_center_detail": "Purchases by Cost Center (Detail)",
|
||||||
|
|||||||
@@ -2394,6 +2394,7 @@
|
|||||||
"selectexistingornew": ""
|
"selectexistingornew": ""
|
||||||
},
|
},
|
||||||
"fields": {
|
"fields": {
|
||||||
|
"accountingid": "",
|
||||||
"address": "Dirección",
|
"address": "Dirección",
|
||||||
"allow_text_message": "Permiso de texto?",
|
"allow_text_message": "Permiso de texto?",
|
||||||
"name": "Nombre",
|
"name": "Nombre",
|
||||||
@@ -3057,6 +3058,7 @@
|
|||||||
"production_not_production_status": "",
|
"production_not_production_status": "",
|
||||||
"production_over_time": "",
|
"production_over_time": "",
|
||||||
"psr_by_make": "",
|
"psr_by_make": "",
|
||||||
|
"purchase_return_ratio_excel": "",
|
||||||
"purchase_return_ratio_grouped_by_vendor_detail": "",
|
"purchase_return_ratio_grouped_by_vendor_detail": "",
|
||||||
"purchase_return_ratio_grouped_by_vendor_summary": "",
|
"purchase_return_ratio_grouped_by_vendor_summary": "",
|
||||||
"purchases_by_cost_center_detail": "",
|
"purchases_by_cost_center_detail": "",
|
||||||
|
|||||||
@@ -2394,6 +2394,7 @@
|
|||||||
"selectexistingornew": ""
|
"selectexistingornew": ""
|
||||||
},
|
},
|
||||||
"fields": {
|
"fields": {
|
||||||
|
"accountingid": "",
|
||||||
"address": "Adresse",
|
"address": "Adresse",
|
||||||
"allow_text_message": "Autorisation de texte?",
|
"allow_text_message": "Autorisation de texte?",
|
||||||
"name": "Prénom",
|
"name": "Prénom",
|
||||||
@@ -3057,6 +3058,7 @@
|
|||||||
"production_not_production_status": "",
|
"production_not_production_status": "",
|
||||||
"production_over_time": "",
|
"production_over_time": "",
|
||||||
"psr_by_make": "",
|
"psr_by_make": "",
|
||||||
|
"purchase_return_ratio_excel": "",
|
||||||
"purchase_return_ratio_grouped_by_vendor_detail": "",
|
"purchase_return_ratio_grouped_by_vendor_detail": "",
|
||||||
"purchase_return_ratio_grouped_by_vendor_summary": "",
|
"purchase_return_ratio_grouped_by_vendor_summary": "",
|
||||||
"purchases_by_cost_center_detail": "",
|
"purchases_by_cost_center_detail": "",
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { setContext } from "@apollo/client/link/context";
|
|||||||
import { HttpLink } from "@apollo/client/link/http"; //"apollo-link-http";
|
import { HttpLink } from "@apollo/client/link/http"; //"apollo-link-http";
|
||||||
import { RetryLink } from "@apollo/client/link/retry";
|
import { RetryLink } from "@apollo/client/link/retry";
|
||||||
import { WebSocketLink } from "@apollo/client/link/ws";
|
import { WebSocketLink } from "@apollo/client/link/ws";
|
||||||
import { getMainDefinition, offsetLimitPagination } from "@apollo/client/utilities";
|
import { getMainDefinition } from "@apollo/client/utilities";
|
||||||
//import { split } from "apollo-link";
|
//import { split } from "apollo-link";
|
||||||
import apolloLogger from "apollo-link-logger";
|
import apolloLogger from "apollo-link-logger";
|
||||||
//import axios from "axios";
|
//import axios from "axios";
|
||||||
@@ -143,36 +143,7 @@ middlewares.push(
|
|||||||
new SentryLink().concat(roundTripLink.concat(retryLink.concat(errorLink.concat(authLink.concat(link)))))
|
new SentryLink().concat(roundTripLink.concat(retryLink.concat(errorLink.concat(authLink.concat(link)))))
|
||||||
);
|
);
|
||||||
|
|
||||||
const cache = new InMemoryCache({
|
const cache = new InMemoryCache({});
|
||||||
typePolicies: {
|
|
||||||
conversations: {
|
|
||||||
fields: {
|
|
||||||
job_conversations: {
|
|
||||||
merge(existing = [], incoming = [], { readField }) {
|
|
||||||
const merged = new Map();
|
|
||||||
|
|
||||||
// Add existing data to the map
|
|
||||||
existing.forEach((jobConversation) => {
|
|
||||||
// Use `readField` to get the unique `jobid`, fallback to `__ref`
|
|
||||||
const jobId = readField("jobid", jobConversation) || jobConversation.__ref;
|
|
||||||
if (jobId) merged.set(jobId, jobConversation);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Add or replace with incoming data
|
|
||||||
incoming.forEach((jobConversation) => {
|
|
||||||
// Use `readField` to get the unique `jobid`, fallback to `__ref`
|
|
||||||
const jobId = readField("jobid", jobConversation) || jobConversation.__ref;
|
|
||||||
if (jobId) merged.set(jobId, jobConversation);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Return the merged data as an array
|
|
||||||
return Array.from(merged.values());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
const client = new ApolloClient({
|
const client = new ApolloClient({
|
||||||
link: ApolloLink.from(middlewares),
|
link: ApolloLink.from(middlewares),
|
||||||
cache,
|
cache,
|
||||||
|
|||||||
@@ -2184,6 +2184,19 @@ export const TemplateList = (type, context) => {
|
|||||||
},
|
},
|
||||||
group: "payroll",
|
group: "payroll",
|
||||||
adp_payroll: true
|
adp_payroll: true
|
||||||
|
},
|
||||||
|
purchase_return_ratio_excel: {
|
||||||
|
title: i18n.t("reportcenter.templates.purchase_return_ratio_excel"),
|
||||||
|
subject: i18n.t("reportcenter.templates.purchase_return_ratio_excel"),
|
||||||
|
key: "purchase_return_ratio_excel",
|
||||||
|
//idtype: "vendor",
|
||||||
|
reporttype: "excel",
|
||||||
|
disabled: false,
|
||||||
|
rangeFilter: {
|
||||||
|
object: i18n.t("reportcenter.labels.objects.bills"),
|
||||||
|
field: i18n.t("bills.fields.date")
|
||||||
|
},
|
||||||
|
group: "purchases"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
: {}),
|
: {}),
|
||||||
|
|||||||
Reference in New Issue
Block a user