Compare commits
4 Commits
feature/IO
...
hotfix/202
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
154f9cdfe6 | ||
|
|
d20347d5dc | ||
|
|
038aa82087 | ||
|
|
4afff893c0 |
@@ -1,116 +1,96 @@
|
||||
// index.js
|
||||
|
||||
import express from 'express';
|
||||
import fetch from 'node-fetch';
|
||||
import {simpleParser} from 'mailparser';
|
||||
import express from "express";
|
||||
import fetch from "node-fetch";
|
||||
import { simpleParser } from "mailparser";
|
||||
|
||||
const app = express();
|
||||
const PORT = 3334;
|
||||
|
||||
app.get('/', async (req, res) => {
|
||||
try {
|
||||
const response = await fetch('http://localhost:4566/_aws/ses');
|
||||
if (!response.ok) {
|
||||
throw new Error('Network response was not ok');
|
||||
}
|
||||
const data = await response.json();
|
||||
const messagesHtml = await parseMessages(data.messages);
|
||||
res.send(renderHtml(messagesHtml));
|
||||
} catch (error) {
|
||||
console.error('Error fetching messages:', error);
|
||||
res.status(500).send('Error fetching messages');
|
||||
app.get("/", async (req, res) => {
|
||||
try {
|
||||
const response = await fetch("http://localhost:4566/_aws/ses");
|
||||
if (!response.ok) {
|
||||
throw new Error("Network response was not ok");
|
||||
}
|
||||
const data = await response.json();
|
||||
const messagesHtml = await parseMessages(data.messages);
|
||||
res.send(renderHtml(messagesHtml));
|
||||
} catch (error) {
|
||||
console.error("Error fetching messages:", error);
|
||||
res.status(500).send("Error fetching messages");
|
||||
}
|
||||
});
|
||||
|
||||
async function parseMessages(messages) {
|
||||
const parsedMessages = await Promise.all(
|
||||
messages.map(async (message, index) => {
|
||||
try {
|
||||
const parsed = await simpleParser(message.RawData);
|
||||
return `
|
||||
<div class="shadow-md rounded-lg p-4 mb-6" style="background-color: lightgray">
|
||||
<div class="shadow-md rounded-lg p-4 mb-6" style="background-color: white">
|
||||
<div class="mb-2">
|
||||
<span class="font-bold text-lg">Message ${index + 1}</span>
|
||||
</div>
|
||||
<div class="mb-2">
|
||||
<span class="font-semibold">From:</span> ${message.Source}
|
||||
</div>
|
||||
<div class="mb-2">
|
||||
<span class="font-semibold">Region:</span> ${message.Region}
|
||||
</div>
|
||||
<div class="mb-2">
|
||||
<span class="font-semibold">Timestamp:</span> ${message.Timestamp}
|
||||
</div>
|
||||
</div>
|
||||
<div class="prose">
|
||||
${parsed.html || parsed.textAsHtml || 'No HTML content available'}
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
} catch (error) {
|
||||
console.error('Error parsing email:', error);
|
||||
return `
|
||||
<div class="bg-white shadow-md rounded-lg p-4 mb-6">
|
||||
<div class="mb-2">
|
||||
<span class="font-bold text-lg">Message ${index + 1}</span>
|
||||
</div>
|
||||
<div class="mb-2">
|
||||
<span class="font-semibold">From:</span> ${message.Source}
|
||||
</div>
|
||||
<div class="mb-2">
|
||||
<span class="font-semibold">Region:</span> ${message.Region}
|
||||
</div>
|
||||
<div class="mb-2">
|
||||
<span class="font-semibold">Timestamp:</span> ${message.Timestamp}
|
||||
</div>
|
||||
<div class="text-red-500">
|
||||
Error parsing email content
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
})
|
||||
);
|
||||
return parsedMessages.join('');
|
||||
const parsedMessages = await Promise.all(
|
||||
messages.map(async (message, index) => {
|
||||
try {
|
||||
const parsed = await simpleParser(message.RawData);
|
||||
return `
|
||||
<div class="shadow-md rounded-lg p-4 mb-6" style="background-color: lightgray">
|
||||
<div class="shadow-md rounded-lg p-4 mb-6" style="background-color: white">
|
||||
<div class="mb-2"><span class="font-bold text-lg">Message ${index + 1}</span></div>
|
||||
<div class="mb-2"><span class="font-semibold">From:</span> ${message.Source}</div>
|
||||
<div class="mb-2"><span class="font-semibold">To:</span> ${parsed.to.text || "No To Address"}</div>
|
||||
<div class="mb-2"><span class="font-semibold">Subject:</span> ${parsed.subject || "No Subject"}</div>
|
||||
<div class="mb-2"><span class="font-semibold">Region:</span> ${message.Region}</div>
|
||||
<div class="mb-2"><span class="font-semibold">Timestamp:</span> ${message.Timestamp}</div>
|
||||
</div>
|
||||
<div class="prose">${parsed.html || parsed.textAsHtml || "No HTML content available"}</div>
|
||||
</div>
|
||||
`;
|
||||
} catch (error) {
|
||||
console.error("Error parsing email:", error);
|
||||
return `
|
||||
<div class="bg-white shadow-md rounded-lg p-4 mb-6">
|
||||
<div class="mb-2"><span class="font-bold text-lg">Message ${index + 1}</span></div>
|
||||
<div class="mb-2"><span class="font-semibold">From:</span> ${message.Source}</div>
|
||||
<div class="mb-2"><span class="font-semibold">Region:</span> ${message.Region}</div>
|
||||
<div class="mb-2"><span class="font-semibold">Timestamp:</span> ${message.Timestamp}</div>
|
||||
<div class="text-red-500">Error parsing email content</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
})
|
||||
);
|
||||
return parsedMessages.join("");
|
||||
}
|
||||
|
||||
function renderHtml(messagesHtml) {
|
||||
return `
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Email Messages Viewer</title>
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<style>
|
||||
body {
|
||||
background-color: #f3f4f6;
|
||||
font-family: Arial, sans-serif;
|
||||
}
|
||||
.container {
|
||||
max-width: 800px;
|
||||
margin: 50px auto;
|
||||
padding: 20px;
|
||||
}
|
||||
.prose {
|
||||
line-height: 1.6;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container bg-white shadow-lg rounded-lg p-6">
|
||||
<h1 class="text-2xl font-bold text-center mb-6">Email Messages Viewer</h1>
|
||||
<div id="messages-container">
|
||||
${messagesHtml}
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
`;
|
||||
return `
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Email Messages Viewer</title>
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<style>
|
||||
body {
|
||||
background-color: #f3f4f6;
|
||||
font-family: Arial, sans-serif;
|
||||
}
|
||||
.container {
|
||||
max-width: 800px;
|
||||
margin: 50px auto;
|
||||
padding: 20px;
|
||||
}
|
||||
.prose {
|
||||
line-height: 1.6;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container bg-white shadow-lg rounded-lg p-6">
|
||||
<h1 class="text-2xl font-bold text-center mb-6">Email Messages Viewer</h1>
|
||||
<div id="messages-container">${messagesHtml}</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
`;
|
||||
}
|
||||
|
||||
app.listen(PORT, () => {
|
||||
console.log(`Server is running on http://localhost:${PORT}`);
|
||||
});
|
||||
console.log(`Server is running on http://localhost:${PORT}`);
|
||||
});
|
||||
|
||||
42
_reference/localEmailViewer/package-lock.json
generated
42
_reference/localEmailViewer/package-lock.json
generated
@@ -10,7 +10,7 @@
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"express": "^5.1.0",
|
||||
"mailparser": "^3.7.2",
|
||||
"mailparser": "^3.7.4",
|
||||
"node-fetch": "^3.3.2"
|
||||
}
|
||||
},
|
||||
@@ -634,9 +634,9 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/libmime": {
|
||||
"version": "5.3.6",
|
||||
"resolved": "https://registry.npmjs.org/libmime/-/libmime-5.3.6.tgz",
|
||||
"integrity": "sha512-j9mBC7eiqi6fgBPAGvKCXJKJSIASanYF4EeA4iBzSG0HxQxmXnR3KbyWqTn4CwsKSebqCv2f5XZfAO6sKzgvwA==",
|
||||
"version": "5.3.7",
|
||||
"resolved": "https://registry.npmjs.org/libmime/-/libmime-5.3.7.tgz",
|
||||
"integrity": "sha512-FlDb3Wtha8P01kTL3P9M+ZDNDWPKPmKHWaU/cG/lg5pfuAwdflVpZE+wm9m7pKmC5ww6s+zTxBKS1p6yl3KpSw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"encoding-japanese": "2.2.0",
|
||||
@@ -661,31 +661,31 @@
|
||||
}
|
||||
},
|
||||
"node_modules/mailparser": {
|
||||
"version": "3.7.2",
|
||||
"resolved": "https://registry.npmjs.org/mailparser/-/mailparser-3.7.2.tgz",
|
||||
"integrity": "sha512-iI0p2TCcIodR1qGiRoDBBwboSSff50vQAWytM5JRggLfABa4hHYCf3YVujtuzV454xrOP352VsAPIzviqMTo4Q==",
|
||||
"version": "3.7.4",
|
||||
"resolved": "https://registry.npmjs.org/mailparser/-/mailparser-3.7.4.tgz",
|
||||
"integrity": "sha512-Beh4yyR4jLq3CZZ32asajByrXnW8dLyKCAQD3WvtTiBnMtFWhxO+wa93F6sJNjDmfjxXs4NRNjw3XAGLqZR3Vg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"encoding-japanese": "2.2.0",
|
||||
"he": "1.2.0",
|
||||
"html-to-text": "9.0.5",
|
||||
"iconv-lite": "0.6.3",
|
||||
"libmime": "5.3.6",
|
||||
"libmime": "5.3.7",
|
||||
"linkify-it": "5.0.0",
|
||||
"mailsplit": "5.4.2",
|
||||
"nodemailer": "6.9.16",
|
||||
"mailsplit": "5.4.5",
|
||||
"nodemailer": "7.0.4",
|
||||
"punycode.js": "2.3.1",
|
||||
"tlds": "1.255.0"
|
||||
"tlds": "1.259.0"
|
||||
}
|
||||
},
|
||||
"node_modules/mailsplit": {
|
||||
"version": "5.4.2",
|
||||
"resolved": "https://registry.npmjs.org/mailsplit/-/mailsplit-5.4.2.tgz",
|
||||
"integrity": "sha512-4cczG/3Iu3pyl8JgQ76dKkisurZTmxMrA4dj/e8d2jKYcFTZ7MxOzg1gTioTDMPuFXwTrVuN/gxhkrO7wLg7qA==",
|
||||
"version": "5.4.5",
|
||||
"resolved": "https://registry.npmjs.org/mailsplit/-/mailsplit-5.4.5.tgz",
|
||||
"integrity": "sha512-oMfhmvclR689IIaQmIcR5nODnZRRVwAKtqFT407TIvmhX2OLUBnshUTcxzQBt3+96sZVDud9NfSe1NxAkUNXEQ==",
|
||||
"license": "(MIT OR EUPL-1.1+)",
|
||||
"dependencies": {
|
||||
"libbase64": "1.3.0",
|
||||
"libmime": "5.3.6",
|
||||
"libmime": "5.3.7",
|
||||
"libqp": "2.1.1"
|
||||
}
|
||||
},
|
||||
@@ -793,9 +793,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/nodemailer": {
|
||||
"version": "6.9.16",
|
||||
"resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.9.16.tgz",
|
||||
"integrity": "sha512-psAuZdTIRN08HKVd/E8ObdV6NO7NTBY3KsC30F7M4H1OnmLCUNaS56FpYxyb26zWLSyYF9Ozch9KYHhHegsiOQ==",
|
||||
"version": "7.0.4",
|
||||
"resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-7.0.4.tgz",
|
||||
"integrity": "sha512-9O00Vh89/Ld2EcVCqJ/etd7u20UhME0f/NToPfArwPEe1Don1zy4mAIz6ariRr7mJ2RDxtaDzN0WJVdVXPtZaw==",
|
||||
"license": "MIT-0",
|
||||
"engines": {
|
||||
"node": ">=6.0.0"
|
||||
@@ -1114,9 +1114,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/tlds": {
|
||||
"version": "1.255.0",
|
||||
"resolved": "https://registry.npmjs.org/tlds/-/tlds-1.255.0.tgz",
|
||||
"integrity": "sha512-tcwMRIioTcF/FcxLev8MJWxCp+GUALRhFEqbDoZrnowmKSGqPrl5pqS+Sut2m8BgJ6S4FExCSSpGffZ0Tks6Aw==",
|
||||
"version": "1.259.0",
|
||||
"resolved": "https://registry.npmjs.org/tlds/-/tlds-1.259.0.tgz",
|
||||
"integrity": "sha512-AldGGlDP0PNgwppe2quAvuBl18UcjuNtOnDuUkqhd6ipPqrYYBt3aTxK1QTsBVknk97lS2JcafWMghjGWFtunw==",
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"tlds": "bin.js"
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
"description": "",
|
||||
"dependencies": {
|
||||
"express": "^5.1.0",
|
||||
"mailparser": "^3.7.2",
|
||||
"mailparser": "^3.7.4",
|
||||
"node-fetch": "^3.3.2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,5 +16,4 @@ TEST_USERNAME="test@imex.dev"
|
||||
TEST_PASSWORD="test123"
|
||||
VITE_PUBLIC_POSTHOG_KEY=phc_xtLmBIu0rjWwExY73Oj5DTH1bGbwq1G1Y8jnlTceien
|
||||
VITE_PUBLIC_POSTHOG_HOST=https://us.i.posthog.com
|
||||
VITE_APP_AMP_URL=https://vp8k908qy2.execute-api.ca-central-1.amazonaws.com
|
||||
VITE_APP_AMP_KEY=6228a598e57cd66875cfd41604f1f891
|
||||
VITE_APP_AMP_URL=https://vp8k908qy2.execute-api.ca-central-1.amazonaws.com
|
||||
@@ -18,5 +18,4 @@ TEST_USERNAME="test@imex.dev"
|
||||
TEST_PASSWORD="test123"
|
||||
VITE_PUBLIC_POSTHOG_KEY=phc_xtLmBIu0rjWwExY73Oj5DTH1bGbwq1G1Y8jnlTceien
|
||||
VITE_PUBLIC_POSTHOG_HOST=https://us.i.posthog.com
|
||||
VITE_APP_AMP_URL=https://vp8k908qy2.execute-api.ca-central-1.amazonaws.com
|
||||
VITE_APP_AMP_KEY=46b1193a867d4e3131ae4c3a64a3fc78
|
||||
VITE_APP_AMP_URL=https://vp8k908qy2.execute-api.ca-central-1.amazonaws.com
|
||||
@@ -15,5 +15,4 @@ VITE_APP_SPLIT_API=et9pjkik6bn67he5evpmpr1agoo7gactphgk
|
||||
VITE_APP_INSTANCE=IMEX
|
||||
VITE_PUBLIC_POSTHOG_KEY=phc_xtLmBIu0rjWwExY73Oj5DTH1bGbwq1G1Y8jnlTceien
|
||||
VITE_PUBLIC_POSTHOG_HOST=https://us.i.posthog.com
|
||||
VITE_APP_AMP_URL=https://vp8k908qy2.execute-api.ca-central-1.amazonaws.com
|
||||
VITE_APP_AMP_KEY=6228a598e57cd66875cfd41604f1f891
|
||||
VITE_APP_AMP_URL=https://vp8k908qy2.execute-api.ca-central-1.amazonaws.com
|
||||
@@ -15,5 +15,4 @@ VITE_APP_SPLIT_API=et9pjkik6bn67he5evpmpr1agoo7gactphgk
|
||||
VITE_APP_INSTANCE=ROME
|
||||
VITE_PUBLIC_POSTHOG_KEY=phc_xtLmBIu0rjWwExY73Oj5DTH1bGbwq1G1Y8jnlTceien
|
||||
VITE_PUBLIC_POSTHOG_HOST=https://us.i.posthog.com
|
||||
VITE_APP_AMP_URL=https://vp8k908qy2.execute-api.ca-central-1.amazonaws.com
|
||||
VITE_APP_AMP_KEY=46b1193a867d4e3131ae4c3a64a3fc78
|
||||
VITE_APP_AMP_URL=https://vp8k908qy2.execute-api.ca-central-1.amazonaws.com
|
||||
@@ -15,5 +15,4 @@ VITE_APP_SPLIT_API=ts615lqgnmk84thn72uk18uu5pgce6e0l4rc
|
||||
VITE_APP_INSTANCE=IMEX
|
||||
VITE_PUBLIC_POSTHOG_KEY=phc_xtLmBIu0rjWwExY73Oj5DTH1bGbwq1G1Y8jnlTceien
|
||||
VITE_PUBLIC_POSTHOG_HOST=https://us.i.posthog.com
|
||||
VITE_APP_AMP_URL=https://vp8k908qy2.execute-api.ca-central-1.amazonaws.com
|
||||
VITE_APP_AMP_KEY=6228a598e57cd66875cfd41604f1f891
|
||||
VITE_APP_AMP_URL=https://vp8k908qy2.execute-api.ca-central-1.amazonaws.com
|
||||
@@ -15,5 +15,4 @@ VITE_APP_SPLIT_API=ts615lqgnmk84thn72uk18uu5pgce6e0l4rc
|
||||
VITE_APP_INSTANCE=ROME
|
||||
VITE_PUBLIC_POSTHOG_KEY=phc_xtLmBIu0rjWwExY73Oj5DTH1bGbwq1G1Y8jnlTceien
|
||||
VITE_PUBLIC_POSTHOG_HOST=https://us.i.posthog.com
|
||||
VITE_APP_AMP_URL=https://vp8k908qy2.execute-api.ca-central-1.amazonaws.com
|
||||
VITE_APP_AMP_KEY=46b1193a867d4e3131ae4c3a64a3fc78
|
||||
VITE_APP_AMP_URL=https://vp8k908qy2.execute-api.ca-central-1.amazonaws.com
|
||||
@@ -142,16 +142,7 @@ export function AccountingReceivablesTableComponent({ bodyshop, loading, jobs, r
|
||||
refetch={refetch}
|
||||
/>
|
||||
<Link to={`/manage/jobs/${record.id}/close`}>
|
||||
<Button
|
||||
style={{
|
||||
overflow: "hidden",
|
||||
textOverflow: "ellipsis",
|
||||
whiteSpace: "nowrap",
|
||||
verticalAlign: "middle"
|
||||
}}
|
||||
>
|
||||
{t("jobs.labels.viewallocations")}
|
||||
</Button>
|
||||
<Button>{t("jobs.labels.viewallocations")}</Button>
|
||||
</Link>
|
||||
</Space>
|
||||
)
|
||||
|
||||
@@ -5,7 +5,6 @@ import { useTranslation } from "react-i18next";
|
||||
import { FaTasks } from "react-icons/fa";
|
||||
import { connect } from "react-redux";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import { logImEXEvent } from "../../firebase/firebase.utils";
|
||||
import { selectJobReadOnly } from "../../redux/application/application.selectors";
|
||||
import { setModalContext } from "../../redux/modals/modals.actions";
|
||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||
@@ -76,7 +75,6 @@ export function BillsListTableComponent({
|
||||
<Button
|
||||
title={t("tasks.buttons.create")}
|
||||
onClick={() => {
|
||||
logImEXEvent("bills_create_task", {});
|
||||
setTaskUpsertContext({
|
||||
context: {
|
||||
jobid: job.id,
|
||||
@@ -169,7 +167,6 @@ export function BillsListTableComponent({
|
||||
|
||||
const handleTableChange = (pagination, filters, sorter) => {
|
||||
setState({ ...state, filteredInfo: filters, sortedInfo: sorter });
|
||||
logImEXEvent("bills_list_sort_filter", { pagination, filters, sorter });
|
||||
};
|
||||
|
||||
const filteredBills = bills
|
||||
@@ -211,7 +208,6 @@ export function BillsListTableComponent({
|
||||
<Button
|
||||
disabled={!hasBillsAccess}
|
||||
onClick={() => {
|
||||
logImEXEvent("bills_reconcile", {});
|
||||
setReconciliationContext({
|
||||
actions: { refetch: billsQuery.refetch },
|
||||
context: {
|
||||
|
||||
@@ -14,7 +14,7 @@ import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||
import AuditTrailMapping from "../../utils/AuditTrailMappings";
|
||||
import CurrencyFormItemComponent from "../form-items-formatted/currency-form-item.component";
|
||||
import JobSearchSelectComponent from "../job-search-select/job-search-select.component";
|
||||
import { getCurrentUser, logImEXEvent } from "../../firebase/firebase.utils";
|
||||
import { getCurrentUser } from "../../firebase/firebase.utils";
|
||||
import { useNotification } from "../../contexts/Notifications/notificationContext.jsx";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
@@ -124,7 +124,6 @@ const CardPaymentModalComponent = ({
|
||||
const { payments } = form.getFieldsValue();
|
||||
|
||||
try {
|
||||
logImEXEvent("payment_cc_lightbox");
|
||||
const response = await axios.post("/intellipay/lightbox_credentials", {
|
||||
bodyshop,
|
||||
refresh: !!window.intellipay,
|
||||
@@ -172,7 +171,6 @@ const CardPaymentModalComponent = ({
|
||||
|
||||
try {
|
||||
const { payments } = form.getFieldsValue();
|
||||
logImEXEvent("payment_cc_shortlink");
|
||||
const response = await axios.post("/intellipay/generate_payment_url", {
|
||||
bodyshop,
|
||||
amount: payments.reduce((acc, val) => acc + (val?.amount || 0), 0),
|
||||
|
||||
@@ -34,6 +34,7 @@ export function ContractsFindModalContainer({ contractFinderModal, toggleModalVi
|
||||
logImEXEvent("contract_finder_search");
|
||||
|
||||
//Execute contract find
|
||||
|
||||
callSearch({
|
||||
variables: {
|
||||
plate: (values.plate && values.plate !== "" && values.plate) || undefined,
|
||||
|
||||
@@ -7,7 +7,6 @@ import { Link, useNavigate } from "react-router-dom";
|
||||
import PhoneNumberFormatter from "../../utils/PhoneFormatter";
|
||||
import OwnerNameDisplay, { OwnerNameDisplayFunction } from "../owner-name-display/owner-name-display.component";
|
||||
import VehicleVinDisplay from "../vehicle-vin-display/vehicle-vin-display.component";
|
||||
import { logImEXEvent } from "../../firebase/firebase.utils";
|
||||
|
||||
export default function GlobalSearchOs() {
|
||||
const { t } = useTranslation();
|
||||
@@ -20,8 +19,6 @@ export default function GlobalSearchOs() {
|
||||
if (v && v && v !== "" && v.length >= 3) {
|
||||
try {
|
||||
setLoading(true);
|
||||
logImEXEvent("global_search", { search: v });
|
||||
|
||||
const searchData = await axios.post("/search", {
|
||||
search: v
|
||||
});
|
||||
|
||||
@@ -4,7 +4,6 @@ import { Button, Card, Col, Row, Table, Tag } from "antd";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import { logImEXEvent } from "../../firebase/firebase.utils";
|
||||
import { QUERY_AUDIT_TRAIL } from "../../graphql/audit_trail.queries";
|
||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||
import { DateTimeFormatter } from "../../utils/DateFormatter";
|
||||
@@ -126,7 +125,6 @@ export function JobAuditTrail({ bodyshop, jobId }) {
|
||||
render: (text, record) => (
|
||||
<Button
|
||||
onClick={() => {
|
||||
logImEXEvent("jobs_audit_view_email", {});
|
||||
var win = window.open(
|
||||
"",
|
||||
"Title",
|
||||
|
||||
@@ -46,7 +46,6 @@ import PartsOrderModalContainer from "../parts-order-modal/parts-order-modal.con
|
||||
import JobLinesExpander from "./job-lines-expander.component";
|
||||
import JobLinesPartPriceChange from "./job-lines-part-price-change.component";
|
||||
import JobLinesExpanderSimple from "./jobs-lines-expander-simple.component";
|
||||
import { logImEXEvent } from "../../firebase/firebase.utils";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
bodyshop: selectBodyshop,
|
||||
@@ -398,7 +397,6 @@ export function JobLinesComponent({
|
||||
filteredInfo: filters,
|
||||
sortedInfo: sorter
|
||||
}));
|
||||
logImEXEvent("joblines_table_change", { pagination, filters, sorter });
|
||||
};
|
||||
|
||||
const handleMark = (e) => {
|
||||
@@ -415,7 +413,6 @@ export function JobLinesComponent({
|
||||
])
|
||||
);
|
||||
}
|
||||
logImEXEvent("joblines_mark_lines", {});
|
||||
};
|
||||
|
||||
const markMenu = {
|
||||
@@ -619,18 +616,12 @@ export function JobLinesComponent({
|
||||
expanded ? (
|
||||
<MinusCircleTwoTone onClick={(e) => onExpand(record, e)} />
|
||||
) : (
|
||||
<PlusCircleTwoTone
|
||||
onClick={(e) => {
|
||||
onExpand(record, e);
|
||||
logImEXEvent("joblines_expander", {});
|
||||
}}
|
||||
/>
|
||||
<PlusCircleTwoTone onClick={(e) => onExpand(record, e)} />
|
||||
)
|
||||
}}
|
||||
onRow={(record) => {
|
||||
return {
|
||||
onDoubleClick: () => {
|
||||
logImEXEvent("joblines_double_click_select", {});
|
||||
const notMatchingLines = selectedLines.filter((i) => i.id !== record.id);
|
||||
notMatchingLines.length !== selectedLines.length
|
||||
? setSelectedLines(notMatchingLines)
|
||||
|
||||
@@ -1,19 +1,18 @@
|
||||
import { gql, useQuery } from "@apollo/client";
|
||||
import { Badge, Card, Space, Table, Tag } from "antd";
|
||||
import axios from "axios";
|
||||
import { isEmpty } from "lodash";
|
||||
import { useCallback, useEffect, useState } from "react";
|
||||
import dayjs from "../../utils/day";
|
||||
import axios from "axios";
|
||||
import { Badge, Card, Space, Table, Tag } from "antd";
|
||||
import { gql, useQuery } from "@apollo/client";
|
||||
import { DateTimeFormatterFunction } from "../../utils/DateFormatter";
|
||||
import { isEmpty } from "lodash";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import "./job-lifecycle.styles.scss";
|
||||
import BlurWrapperComponent from "../feature-wrapper/blur-wrapper.component";
|
||||
import UpsellComponent, { upsellEnum } from "../upsell/upsell.component";
|
||||
import { HasFeatureAccess } from "../feature-wrapper/feature-wrapper.component";
|
||||
import { connect } from "react-redux";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import { logImEXEvent } from "../../firebase/firebase.utils";
|
||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||
import { DateTimeFormatterFunction } from "../../utils/DateFormatter";
|
||||
import dayjs from "../../utils/day";
|
||||
import BlurWrapperComponent from "../feature-wrapper/blur-wrapper.component";
|
||||
import { HasFeatureAccess } from "../feature-wrapper/feature-wrapper.component";
|
||||
import UpsellComponent, { upsellEnum } from "../upsell/upsell.component";
|
||||
import "./job-lifecycle.styles.scss";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
bodyshop: selectBodyshop
|
||||
@@ -58,7 +57,6 @@ export function JobLifecycleComponent({ bodyshop, job, statuses }) {
|
||||
jobids: job.id,
|
||||
statuses: statuses.statuses
|
||||
});
|
||||
logImEXEvent("jobs_lifecycle_data", {});
|
||||
const data = response.data.transition[job.id];
|
||||
setLifecycleData(data);
|
||||
} catch (err) {
|
||||
|
||||
@@ -10,7 +10,6 @@ import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||
import { insertAuditTrail } from "../../redux/application/application.actions";
|
||||
import AuditTrailMapping from "../../utils/AuditTrailMappings";
|
||||
import { useNotification } from "../../contexts/Notifications/notificationContext.jsx";
|
||||
import { logImEXEvent } from "../../firebase/firebase.utils.js";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
bodyshop: selectBodyshop,
|
||||
@@ -33,7 +32,6 @@ export function JoblineBulkAssign({ setSelectedLines, selectedLines, insertAudit
|
||||
const handleConvert = async (values) => {
|
||||
try {
|
||||
setLoading(true);
|
||||
logImEXEvent("joblines_bulk_assign", {});
|
||||
const result = await assignLines({
|
||||
variables: {
|
||||
jobline: {
|
||||
|
||||
@@ -12,7 +12,6 @@ import { selectBodyshop, selectCurrentUser } from "../../redux/user/user.selecto
|
||||
import { GenerateDocument } from "../../utils/RenderTemplate";
|
||||
import { TemplateList } from "../../utils/TemplateConstants";
|
||||
import { useNotification } from "../../contexts/Notifications/notificationContext.jsx";
|
||||
import { logImEXEvent } from "../../firebase/firebase.utils.js";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
bodyshop: selectBodyshop,
|
||||
@@ -47,7 +46,6 @@ export function JobLineDispatchButton({
|
||||
try {
|
||||
setLoading(true);
|
||||
//THIS HAS NOT YET BEEN TESTED. START BY FINISHING THIS FUNCTION.
|
||||
logImEXEvent("joblines_dispatch", {});
|
||||
const result = await dispatchLines({
|
||||
variables: {
|
||||
partsDispatch: {
|
||||
|
||||
@@ -4,7 +4,6 @@ import { useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { UPDATE_JOB } from "../../graphql/jobs.queries";
|
||||
import { useNotification } from "../../contexts/Notifications/notificationContext.jsx";
|
||||
import { logImEXEvent } from "../../firebase/firebase.utils.js";
|
||||
|
||||
export default function JobRemoveFromPartsQueue({ checked, jobId }) {
|
||||
const [updateJob] = useMutation(UPDATE_JOB);
|
||||
@@ -14,8 +13,6 @@ export default function JobRemoveFromPartsQueue({ checked, jobId }) {
|
||||
|
||||
const handleChange = async (e) => {
|
||||
setLoading(true);
|
||||
logImEXEvent("parts_queue_toggle", { estimators: e });
|
||||
|
||||
const result = await updateJob({
|
||||
variables: { jobId: jobId, job: { queued_for_parts: e.target.checked } }
|
||||
});
|
||||
|
||||
@@ -8,7 +8,6 @@ import { createStructuredSelector } from "reselect";
|
||||
import { useNotification } from "../../contexts/Notifications/notificationContext.jsx";
|
||||
import { selectPartnerVersion } from "../../redux/application/application.selectors";
|
||||
import { alphaSort } from "../../utils/sorters";
|
||||
import { logImEXEvent } from "../../firebase/firebase.utils.js";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
//currentUser: selectCurrentUser
|
||||
@@ -31,15 +30,11 @@ export function JobsAvailableScan({ partnerVersion, refetch }) {
|
||||
const notification = useNotification();
|
||||
|
||||
const handleTableChange = (pagination, filters, sorter) => {
|
||||
logImEXEvent("available_jobs_scan_sort_filter", { pagination, filters, sorter });
|
||||
|
||||
setState({ ...state, filteredInfo: filters, sortedInfo: sorter });
|
||||
};
|
||||
|
||||
const handleImport = async (filepath) => {
|
||||
setLoading(true);
|
||||
logImEXEvent("available_jobs_scan", {});
|
||||
|
||||
const response = await axios.post("http://localhost:1337/import/", {
|
||||
filepath
|
||||
});
|
||||
|
||||
@@ -12,7 +12,6 @@ import CurrencyFormatter from "../../utils/CurrencyFormatter";
|
||||
import { TimeAgoFormatter } from "../../utils/DateFormatter";
|
||||
import { alphaSort } from "../../utils/sorters";
|
||||
import { useNotification } from "../../contexts/Notifications/notificationContext.jsx";
|
||||
import { logImEXEvent } from "../../firebase/firebase.utils.js";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
bodyshop: selectBodyshop
|
||||
@@ -35,7 +34,6 @@ export function JobsAvailableComponent({ bodyshop, loading, data, refetch, addJo
|
||||
|
||||
const handleTableChange = (pagination, filters, sorter) => {
|
||||
setState({ ...state, filteredInfo: filters, sortedInfo: sorter });
|
||||
logImEXEvent("available_jobs_sort_filter", { pagination, filters, sorter });
|
||||
};
|
||||
|
||||
const columns = [
|
||||
|
||||
@@ -14,7 +14,6 @@ import AuditTrailMapping from "../../utils/AuditTrailMappings";
|
||||
import { DateTimeFormatterFunction } from "../../utils/DateFormatter";
|
||||
import FormDateTimePickerComponent from "../form-date-time-picker/form-date-time-picker.component";
|
||||
import LoadingSpinner from "../loading-spinner/loading-spinner.component.jsx";
|
||||
import { logImEXEvent } from "../../firebase/firebase.utils.js";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
//currentUser: selectCurrentUser,
|
||||
@@ -109,9 +108,6 @@ export function JobsDetailHeaderActionsToggleProduction({
|
||||
DateTimeFormatterFunction(values.actual_completion)
|
||||
)
|
||||
});
|
||||
|
||||
logImEXEvent(scenario === "pre" ? "job_intake_quick" : "job-deliver-quick", {});
|
||||
|
||||
setPopOverVisible(false);
|
||||
closeParentMenu();
|
||||
refetch();
|
||||
|
||||
@@ -15,7 +15,6 @@ import { alphaSort, statusSort } from "../../utils/sorters";
|
||||
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 { logImEXEvent } from "../../firebase/firebase.utils";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
//currentUser: selectCurrentUser
|
||||
@@ -178,7 +177,6 @@ export function JobsList({ bodyshop, refetch, loading, jobs, total }) {
|
||||
}
|
||||
setFilter(filters);
|
||||
history({ search: queryString.stringify(search) });
|
||||
logImEXEvent("jobs_all_list_sort_filter", { pagination, filters, sorter });
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
@@ -17,7 +17,6 @@ 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 { OwnerNameDisplayFunction } from "./../owner-name-display/owner-name-display.component";
|
||||
import { logImEXEvent } from "../../firebase/firebase.utils";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
bodyshop: selectBodyshop
|
||||
@@ -68,7 +67,6 @@ export function JobsList({ bodyshop }) {
|
||||
: [];
|
||||
|
||||
const handleTableChange = (pagination, filters, sorter) => {
|
||||
logImEXEvent("jobs_list_sort_filter", { pagination, filters, sorter });
|
||||
setState({ ...state, sortedInfo: sorter });
|
||||
setFilter(filters);
|
||||
};
|
||||
|
||||
@@ -1,18 +1,17 @@
|
||||
import { PageHeader } from "@ant-design/pro-layout";
|
||||
import { useApolloClient, useMutation } from "@apollo/client";
|
||||
import { Button, Form, Popconfirm } from "antd";
|
||||
import { phone } from "phone"; // Import phone utility for formatting
|
||||
import { PageHeader } from "@ant-design/pro-layout";
|
||||
import { useEffect, useState } from "react";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { useApolloClient, useMutation } from "@apollo/client";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import { useNotification } from "../../contexts/Notifications/notificationContext.jsx";
|
||||
import { logImEXEvent } from "../../firebase/firebase.utils.js";
|
||||
import { DELETE_OWNER, UPDATE_OWNER } from "../../graphql/owners.queries";
|
||||
import { selectBodyshop } from "../../redux/user/user.selectors"; // Adjust path
|
||||
import { phoneNumberOptOutService } from "../../utils/phoneOptOutService.js"; // Adjust path
|
||||
import OwnerDetailFormComponent from "./owner-detail-form.component";
|
||||
import { useNotification } from "../../contexts/Notifications/notificationContext.jsx";
|
||||
import { phone } from "phone"; // Import phone utility for formatting
|
||||
|
||||
// Connect to Redux to access bodyshop
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
@@ -56,7 +55,6 @@ function OwnerDetailFormContainer({ owner, refetch, bodyshop }) {
|
||||
|
||||
const handleDelete = async () => {
|
||||
setLoading(true);
|
||||
logImEXEvent("owner_delete", {});
|
||||
try {
|
||||
const result = await deleteOwner({
|
||||
variables: { id: owner.id }
|
||||
@@ -86,7 +84,6 @@ function OwnerDetailFormContainer({ owner, refetch, bodyshop }) {
|
||||
|
||||
const handleFinish = async (values) => {
|
||||
setLoading(true);
|
||||
logImEXEvent("owner_update", {});
|
||||
try {
|
||||
const result = await updateOwner({
|
||||
variables: { ownerId: owner.id, owner: values }
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { DownOutlined } from "@ant-design/icons";
|
||||
import { Dropdown, InputNumber, Space } from "antd";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { logImEXEvent } from "../../firebase/firebase.utils";
|
||||
|
||||
export default function PartsOrderModalPriceChange({ form, field }) {
|
||||
const { t } = useTranslation();
|
||||
const menu = {
|
||||
@@ -63,7 +63,6 @@ export default function PartsOrderModalPriceChange({ form, field }) {
|
||||
}
|
||||
],
|
||||
onClick: ({ key }) => {
|
||||
logImEXEvent("parts_order_manual_discount", {});
|
||||
if (key === "custom") return;
|
||||
const values = form.getFieldsValue();
|
||||
const { parts_order_lines } = values;
|
||||
|
||||
@@ -8,7 +8,6 @@ import AlertComponent from "../alert/alert.component";
|
||||
import JobsDetailHeader from "../jobs-detail-header/jobs-detail-header.component";
|
||||
import LoadingSpinner from "../loading-spinner/loading-spinner.component";
|
||||
import PartsQueueJobLinesComponent from "./parts-queue-job-lines.component";
|
||||
import { logImEXEvent } from "../../firebase/firebase.utils";
|
||||
|
||||
export default function PartsQueueDetailCard() {
|
||||
const selectedBreakpoint = Object.entries(Grid.useBreakpoint())
|
||||
@@ -38,8 +37,6 @@ export default function PartsQueueDetailCard() {
|
||||
const { t } = useTranslation();
|
||||
const handleDrawerClose = () => {
|
||||
delete searchParams.selected;
|
||||
logImEXEvent("parts_queue_drawer", {});
|
||||
|
||||
history({
|
||||
search: queryString.stringify({
|
||||
...searchParams
|
||||
|
||||
@@ -20,7 +20,6 @@ import JobPartsQueueCount from "../job-parts-queue-count/job-parts-queue-count.c
|
||||
import JobRemoveFromPartsQueue from "../job-remove-from-parst-queue/job-remove-from-parts-queue.component";
|
||||
import OwnerNameDisplay, { OwnerNameDisplayFunction } from "../owner-name-display/owner-name-display.component";
|
||||
import ProductionListColumnComment from "../production-list-columns/production-list-columns.comment.component";
|
||||
import { logImEXEvent } from "../../firebase/firebase.utils";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
bodyshop: selectBodyshop
|
||||
@@ -74,7 +73,6 @@ export function PartsQueueListComponent({ bodyshop }) {
|
||||
}
|
||||
setFilter(filters);
|
||||
history({ search: queryString.stringify(searchParams) });
|
||||
logImEXEvent("parts_queue_sort_filter", { pagination, filters, sorter });
|
||||
};
|
||||
|
||||
const handleOnRowClick = (record) => {
|
||||
|
||||
@@ -10,7 +10,6 @@ import {
|
||||
} from "@ant-design/icons";
|
||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||
import EmployeeSearchSelectComponent from "../employee-search-select/employee-search-select.component";
|
||||
import { logImEXEvent } from "../../firebase/firebase.utils";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
bodyshop: selectBodyshop
|
||||
@@ -27,12 +26,10 @@ export function ProductionBoardFilters({ bodyshop, filter, setFilter, loading })
|
||||
|
||||
const toggleAlertFilter = () => {
|
||||
setFilter({ ...filter, alert: !filter.alert });
|
||||
logImEXEvent("visual_board_filter_alert", {});
|
||||
};
|
||||
|
||||
const toggleUnassignedFilter = () => {
|
||||
setFilter({ ...filter, unassigned: !filter.unassigned });
|
||||
logImEXEvent("visual_board_filter_unassigned", {});
|
||||
};
|
||||
|
||||
return (
|
||||
@@ -43,7 +40,6 @@ export function ProductionBoardFilters({ bodyshop, filter, setFilter, loading })
|
||||
placeholder={t("general.labels.search")}
|
||||
onChange={(e) => {
|
||||
setFilter({ ...filter, search: e.target.value });
|
||||
logImEXEvent("visual_board_filter_search", { search: e.target.value });
|
||||
}}
|
||||
/>
|
||||
<EmployeeSearchSelectComponent
|
||||
@@ -51,10 +47,7 @@ export function ProductionBoardFilters({ bodyshop, filter, setFilter, loading })
|
||||
options={bodyshop.employees.filter((e) => e.active)}
|
||||
value={filter.employeeId}
|
||||
placeholder={t("production.labels.employeesearch")}
|
||||
onChange={(emp) => {
|
||||
setFilter({ ...filter, employeeId: emp });
|
||||
logImEXEvent("visual_board_filter_alert", { employeeId: emp });
|
||||
}}
|
||||
onChange={(emp) => setFilter({ ...filter, employeeId: emp })}
|
||||
allowClear
|
||||
/>
|
||||
<Button
|
||||
|
||||
@@ -5,7 +5,6 @@ import { useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { FaRegStickyNote } from "react-icons/fa";
|
||||
import { UPDATE_JOB } from "../../graphql/jobs.queries";
|
||||
import { logImEXEvent } from "../../firebase/firebase.utils";
|
||||
|
||||
export default function ProductionListColumnComment({ record }) {
|
||||
const { t } = useTranslation();
|
||||
@@ -29,7 +28,6 @@ export default function ProductionListColumnComment({ record }) {
|
||||
}).then(() => {
|
||||
if (record.refetch) record.refetch();
|
||||
});
|
||||
logImEXEvent("job_add_comment", { estimators: e });
|
||||
};
|
||||
|
||||
const handleChange = (e) => {
|
||||
|
||||
@@ -18,7 +18,6 @@ import ProductionListDetail from "../production-list-detail/production-list-deta
|
||||
import { ProductionListConfigManager } from "./production-list-config-manager.component.jsx";
|
||||
import ProductionListPrint from "./production-list-print.component";
|
||||
import ResizeableTitle from "./production-list-table.resizeable.component";
|
||||
import { logImEXEvent } from "../../firebase/firebase.utils.js";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
bodyshop: selectBodyshop,
|
||||
@@ -115,7 +114,6 @@ export function ProductionListTable({ loading, data, refetch, bodyshop, technici
|
||||
setState(newState);
|
||||
setHasUnsavedChanges(true);
|
||||
}
|
||||
logImEXEvent("production_list_sort_filter", { pagination, filters, sorter });
|
||||
};
|
||||
|
||||
const onDragEnd = (fromIndex, toIndex) => {
|
||||
@@ -136,7 +134,6 @@ export function ProductionListTable({ loading, data, refetch, bodyshop, technici
|
||||
setColumns(newColumns);
|
||||
setHasUnsavedChanges(true);
|
||||
}
|
||||
logImEXEvent("production_list_remove_column", { key });
|
||||
};
|
||||
|
||||
const handleResize =
|
||||
@@ -159,7 +156,6 @@ export function ProductionListTable({ loading, data, refetch, bodyshop, technici
|
||||
setColumns(updatedColumns);
|
||||
setHasUnsavedChanges(true);
|
||||
}
|
||||
logImEXEvent("production_list_add_column", { key: newColumn.key });
|
||||
};
|
||||
|
||||
const headerItem = (col) => {
|
||||
|
||||
@@ -5,7 +5,6 @@ import { useEffect } from "react";
|
||||
import { useCookies } from "react-cookie";
|
||||
import { useLocation, useNavigate } from "react-router-dom";
|
||||
import QboSignIn from "../../assets/qbo/C2QB_green_btn_med_default.svg";
|
||||
import { logImEXEvent } from "../../firebase/firebase.utils";
|
||||
|
||||
export default function QboAuthorizeComponent() {
|
||||
const location = useLocation();
|
||||
@@ -13,7 +12,6 @@ export default function QboAuthorizeComponent() {
|
||||
const [setCookie] = useCookies(["access_token", "refresh_token"]);
|
||||
|
||||
const handleQbSignIn = async () => {
|
||||
logImEXEvent("qbo_sign_in_clicked");
|
||||
const result = await Axios.post("/qbo/authorize");
|
||||
window.location.href = result.data;
|
||||
};
|
||||
|
||||
@@ -9,7 +9,6 @@ import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||
import BlurWrapperComponent from "../feature-wrapper/blur-wrapper.component";
|
||||
import { upsellEnum, UpsellMaskWrapper } from "../upsell/upsell.component";
|
||||
import { HasFeatureAccess } from "../feature-wrapper/feature-wrapper.component";
|
||||
import { logImEXEvent } from "../../firebase/firebase.utils";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
bodyshop: selectBodyshop
|
||||
@@ -80,12 +79,7 @@ export function ScheduleCalendarHeaderGraph({ bodyshop, loadData }) {
|
||||
);
|
||||
|
||||
return (
|
||||
<Popover
|
||||
trigger="hover"
|
||||
placement="bottom"
|
||||
onOpenChange={(open) => open && logImEXEvent("schedule_spider_graph", {})}
|
||||
content={popContent}
|
||||
>
|
||||
<Popover trigger="hover" placement="bottom" content={popContent}>
|
||||
<RadarChartOutlined />
|
||||
</Popover>
|
||||
);
|
||||
|
||||
@@ -19,7 +19,6 @@ import OwnerNameDisplay from "../owner-name-display/owner-name-display.component
|
||||
import ScheduleBlockDay from "../schedule-block-day/schedule-block-day.component";
|
||||
import UpsellComponent, { upsellEnum } from "../upsell/upsell.component";
|
||||
import ScheduleCalendarHeaderGraph from "./schedule-calendar-header-graph.component";
|
||||
import { logImEXEvent } from "../../firebase/firebase.utils";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
bodyshop: selectBodyshop,
|
||||
@@ -143,7 +142,6 @@ export function ScheduleCalendarHeaderComponent({ bodyshop, label, refetch, date
|
||||
content={jobsInPopup}
|
||||
trigger="hover"
|
||||
title={t("appointments.labels.arrivingjobs")}
|
||||
onOpenChange={(open) => open && logImEXEvent("schedule_popover_arriving_jobs", {})}
|
||||
>
|
||||
<Space size="small">
|
||||
<Icon component={MdFileDownload} style={{ color: "green" }} />
|
||||
@@ -161,7 +159,6 @@ export function ScheduleCalendarHeaderComponent({ bodyshop, label, refetch, date
|
||||
content={jobsOutPopup}
|
||||
trigger="hover"
|
||||
title={t("appointments.labels.completingjobs")}
|
||||
onOpenChange={(open) => open && logImEXEvent("schedule_popover_departing_jobs", {})}
|
||||
>
|
||||
<Space size="small">
|
||||
<Icon component={MdFileUpload} style={{ color: "red" }} />
|
||||
|
||||
@@ -13,7 +13,6 @@ import Event from "../job-at-change/schedule-event.container";
|
||||
import JobDetailCards from "../job-detail-cards/job-detail-cards.component";
|
||||
import local from "./localizer";
|
||||
import HeaderComponent from "./schedule-calendar-header.component";
|
||||
import { logImEXEvent } from "../../firebase/firebase.utils";
|
||||
import "./schedule-calendar.styles.scss";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
@@ -140,8 +139,6 @@ export function ScheduleCalendarWrapperComponent({
|
||||
}}
|
||||
onView={(view) => {
|
||||
search.view = view;
|
||||
logImEXEvent("schedule_change_view", { view });
|
||||
|
||||
history({ search: queryString.stringify(search) });
|
||||
}}
|
||||
step={15}
|
||||
|
||||
@@ -14,7 +14,6 @@ import { connect } from "react-redux";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||
import _ from "lodash";
|
||||
import { logImEXEvent } from "../../firebase/firebase.utils";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
bodyshop: selectBodyshop
|
||||
@@ -81,7 +80,6 @@ export function ScheduleCalendarComponent({ data, refetch, bodyshop }) {
|
||||
value={[...estimatorsFilter]}
|
||||
onChange={(e) => {
|
||||
setEstimatiorsFilter(e);
|
||||
logImEXEvent("schedule_filter_by_estimator", { estimators: e });
|
||||
}}
|
||||
options={estimators.map((e) => ({
|
||||
label: e,
|
||||
@@ -97,7 +95,6 @@ export function ScheduleCalendarComponent({ data, refetch, bodyshop }) {
|
||||
value={filter?.ins_co_nm ? filter.ins_co_nm : []}
|
||||
onChange={(e) => {
|
||||
setFilter({ ...filter, ins_co_nm: e });
|
||||
logImEXEvent("schedule_filter_by_ins_co_nm", { ins_co_nm: e });
|
||||
}}
|
||||
options={bodyshop.md_ins_cos.map((i) => ({
|
||||
label: i.name,
|
||||
|
||||
@@ -6,7 +6,6 @@ import { useTranslation } from "react-i18next";
|
||||
import { UPDATE_SCOREBOARD_ENTRY } from "../../graphql/scoreboard.queries";
|
||||
import DateTimePicker from "../form-date-time-picker/form-date-time-picker.component.jsx";
|
||||
import { useNotification } from "../../contexts/Notifications/notificationContext.jsx";
|
||||
import { logImEXEvent } from "../../firebase/firebase.utils.js";
|
||||
|
||||
export default function ScoreboardEntryEdit({ entry }) {
|
||||
const [open, setOpen] = useState(false);
|
||||
@@ -17,7 +16,6 @@ export default function ScoreboardEntryEdit({ entry }) {
|
||||
|
||||
const handleFinish = async (values) => {
|
||||
setLoading(true);
|
||||
logImEXEvent("scoreboard_edit_job", {});
|
||||
values.date = dayjs(values.date).format("YYYY-MM-DD");
|
||||
const result = await updateScoreboardentry({
|
||||
variables: { sbId: entry.id, sbInput: values }
|
||||
|
||||
@@ -6,7 +6,6 @@ import { useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import { selectBodyshop } from "../../redux/user/user.selectors.js";
|
||||
import { logImEXEvent } from "../../firebase/firebase.utils.js";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
bodyshop: selectBodyshop
|
||||
@@ -53,7 +52,6 @@ const ShareToTeamsComponent = ({
|
||||
const teamsShareUrl = `https://teams.microsoft.com/share?href=${currentUrl}&preText=${messageText}&title=${pageTitle}`;
|
||||
// Function to open the centered share link in a new window/tab
|
||||
const handleShare = () => {
|
||||
logImEXEvent("share_to_teams", {});
|
||||
const screenWidth = window.screen.width;
|
||||
const screenHeight = window.screen.height;
|
||||
const windowWidth = 600;
|
||||
|
||||
@@ -96,14 +96,14 @@ export function SimplifiedPartsJobsListComponent({
|
||||
|
||||
ellipsis: true,
|
||||
sorter: search?.search
|
||||
? (a, b) => statusSort(a.status, b.status, bodyshop.md_ro_statuses?.parts_active_statuses)
|
||||
? (a, b) => statusSort(a.status, b.status, bodyshop.md_ro_statuses.parts_active_statuses)
|
||||
: true,
|
||||
sortOrder: sortcolumn === "status" && sortorder,
|
||||
render: (text, record) => {
|
||||
return record.status || t("general.labels.na");
|
||||
},
|
||||
filteredValue: filter?.status || null,
|
||||
filters: bodyshop.md_ro_statuses?.parts_statuses.map((s) => {
|
||||
filters: bodyshop.md_ro_statuses.parts_statuses.map((s) => {
|
||||
return { text: s, value: [s] };
|
||||
}),
|
||||
onFilter: (value, record) => value.includes(record.status)
|
||||
|
||||
@@ -19,7 +19,6 @@ import { DateFormatter, DateTimeFormatter } from "../../utils/DateFormatter.jsx"
|
||||
import dayjs from "../../utils/day";
|
||||
import ShareToTeamsButton from "../share-to-teams/share-to-teams.component.jsx";
|
||||
import PriorityLabel from "../../utils/tasksPriorityLabel.jsx";
|
||||
import { logImEXEvent } from "../../firebase/firebase.utils.js";
|
||||
|
||||
/**
|
||||
* Task List Component
|
||||
@@ -290,7 +289,6 @@ function TaskListComponent({
|
||||
} else {
|
||||
delete search[param];
|
||||
}
|
||||
logImEXEvent("tasks_filter", { key: param });
|
||||
history({ search: queryString.stringify(search) });
|
||||
},
|
||||
[history, search]
|
||||
|
||||
@@ -13,7 +13,6 @@ import { createStructuredSelector } from "reselect";
|
||||
import { selectBodyshop, selectCurrentUser } from "../../redux/user/user.selectors.js";
|
||||
import dayjs from "../../utils/day";
|
||||
import { useNotification } from "../../contexts/Notifications/notificationContext.jsx";
|
||||
import { logImEXEvent } from "../../firebase/firebase.utils.js";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
bodyshop: selectBodyshop,
|
||||
@@ -108,7 +107,6 @@ export function TaskListContainer({
|
||||
})
|
||||
);
|
||||
}
|
||||
logImEXEvent("task_completed", {});
|
||||
|
||||
notification["success"]({
|
||||
message: t("tasks.successes.completed")
|
||||
@@ -162,7 +160,6 @@ export function TaskListContainer({
|
||||
);
|
||||
}
|
||||
|
||||
logImEXEvent("task_deleted", {});
|
||||
notification["success"]({
|
||||
message: t("tasks.successes.deleted")
|
||||
});
|
||||
|
||||
@@ -17,7 +17,6 @@ import AuditTrailMapping from "../../utils/AuditTrailMappings.js";
|
||||
import { isEqual } from "lodash";
|
||||
import refetchRouteMappings from "./task-upsert-modal.route.mappings";
|
||||
import { useNotification } from "../../contexts/Notifications/notificationContext.jsx";
|
||||
import { logImEXEvent } from "../../firebase/firebase.utils.js";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
currentUser: selectCurrentUser,
|
||||
@@ -181,7 +180,7 @@ export function TaskUpsertModalContainer({ bodyshop, currentUser, taskUpsert, to
|
||||
notification["success"]({
|
||||
message: t("tasks.successes.updated")
|
||||
});
|
||||
logImEXEvent("task_update", {});
|
||||
|
||||
toggleModalVisible();
|
||||
};
|
||||
|
||||
@@ -218,7 +217,7 @@ export function TaskUpsertModalContainer({ bodyshop, currentUser, taskUpsert, to
|
||||
|
||||
form.resetFields();
|
||||
toggleModalVisible();
|
||||
logImEXEvent("task_insert", {});
|
||||
|
||||
notification["success"]({
|
||||
message: t("tasks.successes.created")
|
||||
});
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
import { useState } from "react";
|
||||
import { Button, Form, Popconfirm } from "antd";
|
||||
import { PageHeader } from "@ant-design/pro-layout";
|
||||
import { useMutation } from "@apollo/client";
|
||||
import { Button, Form, Popconfirm } from "antd";
|
||||
import { useState } from "react";
|
||||
import VehicleDetailFormComponent from "./vehicle-detail-form.component";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import dayjs from "../../utils/day";
|
||||
import { DELETE_VEHICLE, UPDATE_VEHICLE } from "../../graphql/vehicles.queries";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { useNotification } from "../../contexts/Notifications/notificationContext.jsx";
|
||||
import { logImEXEvent } from "../../firebase/firebase.utils.js";
|
||||
import { DELETE_VEHICLE, UPDATE_VEHICLE } from "../../graphql/vehicles.queries";
|
||||
import dayjs from "../../utils/day";
|
||||
import VehicleDetailFormComponent from "./vehicle-detail-form.component";
|
||||
|
||||
function VehicleDetailFormContainer({ vehicle, refetch }) {
|
||||
const { t } = useTranslation();
|
||||
@@ -21,7 +20,6 @@ function VehicleDetailFormContainer({ vehicle, refetch }) {
|
||||
|
||||
const handleDelete = async () => {
|
||||
setLoading(true);
|
||||
logImEXEvent("vehicle_delete", {});
|
||||
const result = await deleteVehicle({
|
||||
variables: { id: vehicle.id }
|
||||
});
|
||||
@@ -44,7 +42,6 @@ function VehicleDetailFormContainer({ vehicle, refetch }) {
|
||||
|
||||
const handleFinish = async (values) => {
|
||||
setLoading(true);
|
||||
logImEXEvent("vehicle_update", {});
|
||||
const result = await updateVehicle({
|
||||
variables: { vehId: vehicle.id, vehicle: values }
|
||||
});
|
||||
|
||||
@@ -76,11 +76,9 @@ export const logImEXEvent = (eventName, additionalParams, stateProp = null) => {
|
||||
try {
|
||||
|
||||
const state = stateProp || store.getState();
|
||||
|
||||
const eventParams = {
|
||||
shop: (state.user && state.user.bodyshop && state.user.bodyshop.shopname) || null,
|
||||
user: (state.user && state.user.currentUser && state.user.currentUser.email) || null,
|
||||
partsManagementOnly: state?.user?.partsManagementOnly,
|
||||
...additionalParams
|
||||
};
|
||||
// axios.post("/ioevent", {
|
||||
@@ -91,12 +89,12 @@ export const logImEXEvent = (eventName, additionalParams, stateProp = null) => {
|
||||
// dbevent: false,
|
||||
// env: `master-AIO|${import.meta.env.VITE_APP_GIT_SHA_DATE}`
|
||||
// });
|
||||
console.log(
|
||||
"%c[Analytics]",
|
||||
"background-color: green ;font-weight:bold;",
|
||||
eventName,
|
||||
eventParams
|
||||
);
|
||||
// console.log(
|
||||
// "%c[Analytics]",
|
||||
// "background-color: green ;font-weight:bold;",
|
||||
// eventName,
|
||||
// eventParams
|
||||
// );
|
||||
logEvent(analytics, eventName, eventParams);
|
||||
amplitude.track(eventName, eventParams);
|
||||
posthog.capture(eventName, eventParams);
|
||||
|
||||
@@ -26,7 +26,7 @@ registerSW({ immediate: true });
|
||||
// Dinero.globalLocale = "en-CA";
|
||||
Dinero.globalRoundingMode = "HALF_EVEN";
|
||||
|
||||
amplitude.init(import.meta.env.VITE_APP_AMP_KEY, {
|
||||
amplitude.init("6228a598e57cd66875cfd41604f1f891", {
|
||||
defaultTracking: true,
|
||||
serverUrl: import.meta.env.VITE_APP_AMP_URL
|
||||
// {
|
||||
|
||||
@@ -18,7 +18,6 @@ import { pageLimit } from "../../utils/config";
|
||||
import { alphaSort, dateSort } from "../../utils/sorters";
|
||||
import useLocalStorage from "../../utils/useLocalStorage";
|
||||
import { QUERY_ALL_VENDORS } from "../../graphql/vendors.queries";
|
||||
import { logImEXEvent } from "../../firebase/firebase.utils";
|
||||
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
setBillEnterContext: (context) => dispatch(setModalContext({ context: context, modal: "billEnter" }))
|
||||
@@ -168,7 +167,6 @@ export function BillsListPage({ loading, data, refetch, total, setBillEnterConte
|
||||
const handleTableChange = (pagination, filters, sorter) => {
|
||||
// Persist filters (including vendorname) and sorting
|
||||
setState({ ...state, filteredInfo: { ...state.filteredInfo, ...filters }, sortedInfo: sorter });
|
||||
|
||||
search.page = pagination.current;
|
||||
if (sorter && sorter.column && sorter.column.sortObject) {
|
||||
search.searchObj = JSON.stringify(sorter.column.sortObject(sorter.order));
|
||||
@@ -179,7 +177,6 @@ export function BillsListPage({ loading, data, refetch, total, setBillEnterConte
|
||||
}
|
||||
search.sort = JSON.stringify({ [sorter.columnKey]: sorter.order });
|
||||
history({ search: queryString.stringify(search) });
|
||||
logImEXEvent("bills_list_sort_filter", { pagination, filters, sorter });
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
@@ -195,7 +192,6 @@ export function BillsListPage({ loading, data, refetch, total, setBillEnterConte
|
||||
search: value || search.search,
|
||||
index: "bills"
|
||||
});
|
||||
logImEXEvent("bills_search", { search: value || search.search, results: searchData?.data?.hits?.hits?.length });
|
||||
setOpenSearchResults(searchData.data.hits.hits.map((s) => s._source));
|
||||
} catch (error) {
|
||||
console.log("Error while fetching search results", error);
|
||||
|
||||
@@ -15,7 +15,6 @@ import InstanceRenderManager from "../../utils/instanceRenderMgr";
|
||||
import ContractCreatePageComponent from "./contract-create.page.component";
|
||||
import UpsellComponent, { upsellEnum } from "../../components/upsell/upsell.component";
|
||||
import { useNotification } from "../../contexts/Notifications/notificationContext.jsx";
|
||||
import { logImEXEvent } from "../../firebase/firebase.utils.js";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
bodyshop: selectBodyshop
|
||||
@@ -58,7 +57,6 @@ export function ContractCreatePageContainer({ bodyshop, setBreadcrumbs, setSelec
|
||||
|
||||
if (!result.errors) {
|
||||
//Update the courtesy car to have the damage.
|
||||
logImEXEvent("courtesy_car_contract_created", {});
|
||||
notification["success"]({
|
||||
message: t("contracts.successes.saved")
|
||||
});
|
||||
|
||||
@@ -14,7 +14,7 @@ import InstanceRenderManager from "../../utils/instanceRenderMgr";
|
||||
import JobsCreateComponent from "./jobs-create.component";
|
||||
import JobCreateContext from "./jobs-create.context";
|
||||
import { useNotification } from "../../contexts/Notifications/notificationContext.jsx";
|
||||
import { logImEXEvent } from "../../firebase/firebase.utils";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
bodyshop: selectBodyshop
|
||||
});
|
||||
@@ -70,7 +70,6 @@ function JobsCreateContainer({ bodyshop, setBreadcrumbs, setSelectedHeader }) {
|
||||
label: t("titles.bc.jobs-new")
|
||||
}
|
||||
]);
|
||||
logImEXEvent("manual_job_create_start", {});
|
||||
}, [t, setBreadcrumbs, setSelectedHeader]);
|
||||
|
||||
const runInsertJob = (job) => {
|
||||
@@ -82,7 +81,6 @@ function JobsCreateContainer({ bodyshop, setBreadcrumbs, setSelectedHeader }) {
|
||||
error: null,
|
||||
newJobId: resp.data.insert_jobs.returning[0].id
|
||||
});
|
||||
logImEXEvent("manual_job_create_completed", {});
|
||||
})
|
||||
.catch((error) => {
|
||||
notification["error"]({
|
||||
|
||||
@@ -220,7 +220,7 @@ export default defineConfig({
|
||||
|
||||
// Strip console/debugger in prod to shrink bundles
|
||||
esbuild: {
|
||||
//drop: ["console", "debugger"]
|
||||
drop: ["console", "debugger"]
|
||||
},
|
||||
|
||||
optimizeDeps: {
|
||||
|
||||
@@ -119,6 +119,7 @@ services:
|
||||
aws --endpoint-url=http://localstack:4566 s3api create-bucket --bucket imex-large-log --create-bucket-configuration LocationConstraint=ca-central-1
|
||||
aws --endpoint-url=http://localstack:4566 s3api create-bucket --bucket imex-job-totals --create-bucket-configuration LocationConstraint=ca-central-1
|
||||
aws --endpoint-url=http://localstack:4566 s3api create-bucket --bucket parts-estimates --create-bucket-configuration LocationConstraint=ca-central-1
|
||||
aws --endpoint-url=http://localstack:4566 s3api create-bucket --bucket imex-carfax-uploads --create-bucket-configuration LocationConstraint=ca-central-1
|
||||
"
|
||||
# Node App: The Main IMEX API
|
||||
node-app:
|
||||
|
||||
@@ -6,6 +6,15 @@
|
||||
headers:
|
||||
- name: x-imex-auth
|
||||
value_from_env: DATAPUMP_AUTH
|
||||
- name: CARFAX Data Pump
|
||||
webhook: '{{HASURA_API_URL}}/data/carfax'
|
||||
schedule: 0 7 * * 6
|
||||
include_in_metadata: true
|
||||
payload: {}
|
||||
headers:
|
||||
- name: x-imex-auth
|
||||
value_from_env: DATAPUMP_AUTH
|
||||
comment: Project Mexico
|
||||
- name: Chatter Data Pump
|
||||
webhook: '{{HASURA_API_URL}}/data/chatter'
|
||||
schedule: 45 5 * * *
|
||||
|
||||
@@ -6,7 +6,7 @@ const InstanceManager = require("../utils/instanceMgr").default;
|
||||
const { isString, isEmpty } = require("lodash");
|
||||
const fs = require("fs");
|
||||
const client = require("../graphql-client/graphql-client").client;
|
||||
const { sendServerEmail } = require("../email/sendemail");
|
||||
const { sendServerEmail, sendMexicoBillingEmail } = require("../email/sendemail");
|
||||
const { uploadFileToS3 } = require("../utils/s3");
|
||||
const crypto = require("crypto");
|
||||
|
||||
@@ -168,6 +168,32 @@ async function processShopData(shopsToProcess, start, end, skipUpload, ignoreDat
|
||||
await uploadViaSFTP(jsonObj);
|
||||
}
|
||||
|
||||
await sendMexicoBillingEmail({
|
||||
subject: `${shopid.toUpperCase()}_Mexico${InstanceManager({
|
||||
imex: "IO",
|
||||
rome: "RO"
|
||||
})}_${moment().format("MMDDYYYY")} ROs ${jsonObj.count} Error ${errorCode(jsonObj)}`,
|
||||
text: `Errors:\n${JSON.stringify(
|
||||
erroredJobs.map((ej) => ({
|
||||
ro_number: ej.job?.ro_number,
|
||||
jobid: ej.job?.id,
|
||||
error: ej.error
|
||||
})),
|
||||
null,
|
||||
2
|
||||
)}\n\nUploaded:\n${JSON.stringify(
|
||||
{
|
||||
bodyshopid: bodyshop.id,
|
||||
imexshopid: shopid,
|
||||
count: jsonObj.count,
|
||||
filename: jsonObj.filename,
|
||||
result: jsonObj.result
|
||||
},
|
||||
null,
|
||||
2
|
||||
)}`
|
||||
});
|
||||
|
||||
allXMLResults.push({
|
||||
bodyshopid: bodyshop.id,
|
||||
imexshopid: shopid,
|
||||
@@ -402,3 +428,14 @@ const generatePartType = (type) => {
|
||||
|
||||
return partTypeMap[type?.toLowerCase()] || null;
|
||||
};
|
||||
|
||||
const errorCode = ({ count, filename, results }) => {
|
||||
if (count === 0) return 1;
|
||||
if (!filename) return 3;
|
||||
const sftpErrorCode = results?.sftpError?.code;
|
||||
if (sftpErrorCode && ["ECONNREFUSED", "ENOTFOUND", "ETIMEDOUT", "ECONNRESET"].includes(sftpErrorCode)) {
|
||||
return 4;
|
||||
}
|
||||
if (sftpErrorCode) return 7;
|
||||
return 0;
|
||||
};
|
||||
|
||||
@@ -79,6 +79,41 @@ const sendServerEmail = async ({ subject, text }) => {
|
||||
}
|
||||
};
|
||||
|
||||
const sendMexicoBillingEmail = async ({ subject, text }) => {
|
||||
if (process.env.NODE_ENV === undefined) return;
|
||||
try {
|
||||
mailer.sendMail(
|
||||
{
|
||||
from: InstanceManager({
|
||||
imex: `ImEX Online API - ${process.env.NODE_ENV} <noreply@imex.online>`,
|
||||
rome: `Rome Online API - ${process.env.NODE_ENV} <noreply@romeonline.io>`
|
||||
}),
|
||||
to: ["mexico@rometech.zohodesk.com"],
|
||||
subject: subject,
|
||||
text: text,
|
||||
ses: {
|
||||
// optional extra arguments for SendRawEmail
|
||||
Tags: [
|
||||
{
|
||||
Name: "tag_name",
|
||||
Value: "tag_value"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
(err, info) => {
|
||||
logger.log("server-email-failure", err ? "error" : "debug", null, null, {
|
||||
message: err?.message,
|
||||
stack: err?.stack
|
||||
});
|
||||
}
|
||||
);
|
||||
} catch (error) {
|
||||
logger.log("server-email-failure", "error", null, null, { message: error?.message, stack: error?.stack });
|
||||
}
|
||||
};
|
||||
|
||||
const sendWelcomeEmail = async ({ to, resetLink, dateLine, features, bcc }) => {
|
||||
try {
|
||||
await mailer.sendMail({
|
||||
@@ -420,6 +455,7 @@ ${body.bounce?.bouncedRecipients.map(
|
||||
module.exports = {
|
||||
sendEmail,
|
||||
sendServerEmail,
|
||||
sendMexicoBillingEmail,
|
||||
sendTaskEmail,
|
||||
emailBounce,
|
||||
sendWelcomeEmail
|
||||
|
||||
Reference in New Issue
Block a user