Compare commits

..

29 Commits

Author SHA1 Message Date
Dave Richer
18da11f593 - Merge master-aio, bump packages.
Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-08-19 12:27:30 -04:00
Dave Richer
82ecb5533f Merged in release/2024-08-16 (pull request #1625)
Release/2024 08 16

Approved-by: Allan Carr
2024-08-16 23:31:33 +00:00
Allan Carr
d3289d85f1 Merged in feature/IO-2879-936001-TOWING-to-QB (pull request #1627)
IO-2879 Adjust placement of variable
2024-08-16 19:25:14 +00:00
Allan Carr
e628b1364c IO-2879 Adjust placement of variable
Signed-off-by: Allan Carr <allan.carr@thinkimex.com>
2024-08-16 12:27:26 -07:00
Allan Carr
6c421c1447 Merged in feature/IO-2884-Filter-for-Production-Board-Alert (pull request #1620)
IO-2884 Production List Board Filter

Approved-by: Dave Richer
2024-08-16 16:16:53 +00:00
Dave Richer
99369e7040 Merged in feature/IO-2884-Add-Alert-Filter-To-Production-Board (pull request #1622)
- Add Alert Filter to visual production board
2024-08-16 16:15:54 +00:00
Dave Richer
01cbdf14a9 - Add Alert Filter to visual production board
Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-08-16 12:14:52 -04:00
Allan Carr
f691aca241 IO-2884 Production List Board Filter
Signed-off-by: Allan Carr <allan.carr@thinkimex.com>
2024-08-16 09:11:29 -07:00
Dave Richer
85495a11e3 Merged in feature/IO-2884-Add-Alert-Filter-To-Production-Board (pull request #1618)
Feature/IO-2884 Add Alert Filter To Production Board

Approved-by: Allan Carr
2024-08-16 15:38:29 +00:00
Dave Richer
134ce05d27 - Add Alert Filter to visual production board
Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-08-16 11:16:20 -04:00
Dave Richer
3498fbc8f1 - Add Alert Filter to visual production board
Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-08-16 11:14:32 -04:00
Dave Richer
f49f72ce7f - Revert ZOHO Change
Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-08-16 10:49:59 -04:00
Dave Richer
a5e3b6ce33 Merged in feature/IO-2882-Unsaved-Listview-Changes (pull request #1612)
- Production Board List View Unsaved Changes Prompt

Approved-by: Allan Carr
2024-08-16 00:45:48 +00:00
Dave Richer
0fd945b859 - fix
Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-08-15 20:42:18 -04:00
Dave Richer
879eba0247 - Add Alert
- Fix 2 bugs

Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-08-15 20:16:03 -04:00
Allan Carr
bb49dd77a1 Merged in feature/IO-2879-936001-TOWING-to-QB (pull request #1613)
IO-2879 936001 TOWING to QB

Approved-by: Dave Richer
2024-08-15 21:16:27 +00:00
Allan Carr
ae705322f8 IO-2879 936001 TOWING to QB
Prevent double sending 936001 Towing lines to QB

Signed-off-by: Allan Carr <allan.carr@thinkimex.com>
2024-08-15 13:41:33 -07:00
Dave Richer
36d92d4060 - Production Board List View Unsaved Changes Prompt
Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-08-15 14:59:47 -04:00
Dave Richer
3ce2b1ab19 - revert (put back in) zoho change
Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-08-15 13:35:18 -04:00
Dave Richer
52e756a78a Merged in feature/IO-2878-Enhance-Beta-Switch (pull request #1607)
- Improve handle beta code (AIO Version)
2024-08-15 15:21:09 +00:00
Dave Richer
5a36cb7cf1 - Improve handle beta code (AIO Version)
Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-08-15 11:19:59 -04:00
Allan Carr
9138f4be16 Merged in feature/IO-2856-Mark-Exported-Buttons (pull request #1601)
IO-2856 Mark Exported Button

Approved-by: Dave Richer
2024-08-14 18:40:51 +00:00
Allan Carr
df93357cec IO-2856 Mark Exported Button
Signed-off-by: Allan Carr <allan.carr@thinkimex.com>
2024-08-14 11:38:35 -07:00
Dave Richer
8ab23c4ca6 Merged in feature/IO-2878-Enhance-Beta-Switch (pull request #1599)
- Improve handle beta code (AIO Version)
2024-08-14 17:40:50 +00:00
Allan Carr
f179d69420 Merged in feature/IO-2876-Opensearch-Sorters (pull request #1598)
IO-2876 Filtered Search Sorters correction

Approved-by: Dave Richer
2024-08-14 17:39:06 +00:00
Dave Richer
730a7a233d - Improve handle beta code (AIO Version)
Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-08-14 13:29:35 -04:00
Dave Richer
84ad10fa9c Merged in feature/IO-2877-Package-Updates-Alert-Update (pull request #1597)
- Remove Joyride and its cause - Package updates (front + back)
2024-08-14 15:56:43 +00:00
Allan Carr
0bce921f69 IO-2876 Filtered Search Sorters correction
Signed-off-by: Allan Carr <allan.carr@thinkimex.com>
2024-08-13 16:00:17 -07:00
Dave Richer
136d52ec0b - Merge Master, update packages.
Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-07-22 14:47:44 -04:00
29 changed files with 635 additions and 394 deletions

View File

@@ -1,20 +1,20 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta charset="utf-8"/>
<% if (env.VITE_APP_INSTANCE === 'IMEX') { %>
<link rel="icon" href="/favicon.png" />
<link rel="icon" href="/favicon.png"/>
<% } %> <% if (env.VITE_APP_INSTANCE === 'ROME') { %>
<link rel="icon" href="/ro-favicon.png" />
<link rel="icon" href="/ro-favicon.png"/>
<% } %> <% if (env.VITE_APP_INSTANCE === 'PROMANAGER') { %>
<link rel="icon" href="/pm/pm-favicon.ico" />
<link rel="icon" href="/pm/pm-favicon.ico"/>
<% } %>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#1690ff" />
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<meta name="theme-color" content="#1690ff"/>
<!-- <link rel="apple-touch-icon" href="logo192.png" /> -->
<!-- TODO:AIo Update the individual logos for each.-->
<link rel="apple-touch-icon" href="public/logo192.png" />
<link rel="apple-touch-icon" href="public/logo192.png"/>
<link rel="mask-icon" href="/mask-icon.svg" color="#FFFFFF">
<!--
manifest.json provides metadata used when your web app is installed on a
@@ -30,7 +30,7 @@
Learn how to configure a non-root public URL by running `npm run build`.
-->
<% if (env.VITE_APP_INSTANCE === 'IMEX') { %>
<meta name="description" content="ImEX Online" />
<meta name="description" content="ImEX Online"/>
<title>ImEX Online</title>
<script type="text/javascript">
window.$crisp = [];
@@ -44,12 +44,13 @@
})();
</script>
<% } %> <% if (env.VITE_APP_INSTANCE === 'ROME') { %>
<meta name="description" content="Rome Online" />
<meta name="description" content="Rome Online"/>
<title>Rome Online</title>
<!--Use the below code snippet to provide real time updates to the live chat plugin without the need of copying and paste each time to your website when changes are made via PBX-->
<call-us-selector phonesystem-url=https://rometech.east.3cx.us:5001 party="LiveChat528346"></call-us-selector>
<call-us-selector phonesystem-url=https://rometech.east.3cx.us:5001
party="LiveChat528346"></call-us-selector>
<!--Incase you don't want real time updates to the live chat plugin when options are changed, use the below code snippet. Please note that each time you change the settings you will need to copy and paste the snippet code to your website-->
@@ -113,13 +114,13 @@
></call-us>-->
<script defer src=https://downloads-global.3cx.com/downloads/livechatandtalk/v1/callus.js id="tcx-callus-js" charset="utf-8"></script>
<script defer src=https://downloads-global.3cx.com/downloads/livechatandtalk/v1/callus.js
id="tcx-callus-js" charset="utf-8"></script>
<% } %> <% if (env.VITE_APP_INSTANCE === 'PROMANAGER') { %>
<title>ProManager</title>
<meta name="description" content="ProManager" />
<meta name="description" content="ProManager"/>
<% } %>
<script>
@@ -143,12 +144,14 @@
if (window.noticeable) console.warn('Noticeable SDK code snippet loaded more than once');
else {
var n = (window.noticeable = window.noticeable || []);
function t(e) {
return function () {
var t = Array.prototype.slice.call(arguments);
return t.unshift(e), n.push(t), n;
};
}
!(function () {
for (var o = 0; o < e.length; o++) {
var r = e[o];

179
client/package-lock.json generated
View File

@@ -19,7 +19,7 @@
"@splitsoftware/splitio-react": "^1.12.1",
"@tanem/react-nprogress": "^5.0.51",
"@vitejs/plugin-react": "^4.3.1",
"antd": "^5.20.1",
"antd": "^5.20.2",
"apollo-link-logger": "^2.0.1",
"apollo-link-sentry": "^3.3.0",
"autosize": "^6.0.1",
@@ -32,12 +32,12 @@
"dotenv": "^16.4.5",
"env-cmd": "^10.1.0",
"exifr": "^7.1.3",
"firebase": "^10.12.5",
"firebase": "^10.13.0",
"graphql": "^16.9.0",
"i18next": "^23.12.3",
"i18next": "^23.14.0",
"i18next-browser-languagedetector": "^8.0.0",
"immutability-helper": "^3.1.1",
"libphonenumber-js": "^1.11.5",
"libphonenumber-js": "^1.11.7",
"logrocket": "^8.1.2",
"markerjs2": "^2.32.1",
"memoize-one": "^6.0.0",
@@ -47,7 +47,7 @@
"query-string": "^9.1.0",
"raf-schd": "^4.0.3",
"react": "^18.3.1",
"react-big-calendar": "^1.13.2",
"react-big-calendar": "^1.13.3",
"react-color": "^2.19.3",
"react-cookie": "^7.2.0",
"react-dom": "^18.3.1",
@@ -60,10 +60,10 @@
"react-markdown": "^9.0.1",
"react-number-format": "^5.4.0",
"react-popopo": "^2.1.9",
"react-product-fruits": "^2.2.6",
"react-product-fruits": "^2.2.61",
"react-redux": "^9.1.2",
"react-resizable": "^3.0.5",
"react-router-dom": "^6.26.0",
"react-router-dom": "^6.26.1",
"react-sticky": "^6.0.3",
"react-virtualized": "^9.22.5",
"react-virtuoso": "^4.10.1",
@@ -103,7 +103,7 @@
"react-error-overlay": "6.0.11",
"redux-logger": "^3.0.6",
"source-map-explorer": "^2.5.3",
"vite": "^5.4.0",
"vite": "^5.4.1",
"vite-plugin-babel": "^1.2.0",
"vite-plugin-eslint": "^1.8.1",
"vite-plugin-legacy": "^2.1.0",
@@ -3498,9 +3498,9 @@
"license": "Apache-2.0"
},
"node_modules/@firebase/app": {
"version": "0.10.8",
"resolved": "https://registry.npmjs.org/@firebase/app/-/app-0.10.8.tgz",
"integrity": "sha512-xSLmW0/RShcnUEXH7l+wC0AFWaUtty4tUFF2loIgbtXTRmra0UH/SqYDf/IcfreUninRrCsusNmvoTidGkXJPw==",
"version": "0.10.9",
"resolved": "https://registry.npmjs.org/@firebase/app/-/app-0.10.9.tgz",
"integrity": "sha512-AmGlPg/4SoDhwCdvVDeZsN5Yn+czYD/m/NAEOOCOhwn3Cz1xmEFKAKcyZKKahLrh5QPmge5Adyw+sk3cBTubBg==",
"license": "Apache-2.0",
"dependencies": {
"@firebase/component": "0.6.8",
@@ -3554,12 +3554,12 @@
"license": "Apache-2.0"
},
"node_modules/@firebase/app-compat": {
"version": "0.2.38",
"resolved": "https://registry.npmjs.org/@firebase/app-compat/-/app-compat-0.2.38.tgz",
"integrity": "sha512-36ZrSvkYLW7QR01Sii2X+IY18ErMpRg6e2B2f/DVTtJBolthwXOnNBps+wvaVBvegdvdVPspgDXZUV0ppqh45w==",
"version": "0.2.39",
"resolved": "https://registry.npmjs.org/@firebase/app-compat/-/app-compat-0.2.39.tgz",
"integrity": "sha512-NnTFywe+M/jxZn751NIEhidgDePiDvlcfabvGxBy4YbU1E+b0TpEuJUnm3L6YDZtaZLVEz8ieoq9wbJkgGZ2rg==",
"license": "Apache-2.0",
"dependencies": {
"@firebase/app": "0.10.8",
"@firebase/app": "0.10.9",
"@firebase/component": "0.6.8",
"@firebase/logger": "0.4.2",
"@firebase/util": "1.9.7",
@@ -3573,9 +3573,9 @@
"license": "Apache-2.0"
},
"node_modules/@firebase/auth": {
"version": "1.7.6",
"resolved": "https://registry.npmjs.org/@firebase/auth/-/auth-1.7.6.tgz",
"integrity": "sha512-T+lA5xoug9CByGYkD5WkfTh2ujEYq/frGZPbk0H+fNU6fNl7nqg88KcsmzsC6Fsqbjm3LLEb/i6wJvF6NSNEig==",
"version": "1.7.7",
"resolved": "https://registry.npmjs.org/@firebase/auth/-/auth-1.7.7.tgz",
"integrity": "sha512-gMB0uRRNiIvYorEDLtIq1mc7x5D080EsoghTIph9xnbLqcQS3qRBREEC2o21nMEhviAeiGJMelRkKhAkkggjmA==",
"license": "Apache-2.0",
"dependencies": {
"@firebase/component": "0.6.8",
@@ -3595,12 +3595,12 @@
}
},
"node_modules/@firebase/auth-compat": {
"version": "0.5.11",
"resolved": "https://registry.npmjs.org/@firebase/auth-compat/-/auth-compat-0.5.11.tgz",
"integrity": "sha512-7rE3MkQDoWwI2qd8qsra4/QZCO2GzQSbCL6AVQpult9+Nbimg+5A+YeHxpLTcYAxUV6HDg2CqTDQreFLhcm1CQ==",
"version": "0.5.12",
"resolved": "https://registry.npmjs.org/@firebase/auth-compat/-/auth-compat-0.5.12.tgz",
"integrity": "sha512-K47inLqjTREez85D7pP0TmRv5aQcap22cJW67poLwJoJ6BVVH0I2NOfIoMqENetCrgGS+7vXSIZaLjvHFHwS+g==",
"license": "Apache-2.0",
"dependencies": {
"@firebase/auth": "1.7.6",
"@firebase/auth": "1.7.7",
"@firebase/auth-types": "0.12.2",
"@firebase/component": "0.6.8",
"@firebase/util": "1.9.7",
@@ -3675,9 +3675,9 @@
}
},
"node_modules/@firebase/firestore": {
"version": "4.6.5",
"resolved": "https://registry.npmjs.org/@firebase/firestore/-/firestore-4.6.5.tgz",
"integrity": "sha512-0+Ascaht4qUzj4pCopMPWmoAujk8HKjwCpaNYOOjbYMZ65RVfZPsfZwwbWi/zWMXj6xvPsai5oBiErUUkrLwNw==",
"version": "4.7.0",
"resolved": "https://registry.npmjs.org/@firebase/firestore/-/firestore-4.7.0.tgz",
"integrity": "sha512-wGOp84P1qa1pfpdct6lckfyowTuvIlUDHoiRcN8dFDT4WnZDh0tZW1X77SMiBUVejK8xIRLBCK3yDTejlRVrUA==",
"license": "Apache-2.0",
"dependencies": {
"@firebase/component": "0.6.8",
@@ -3697,13 +3697,13 @@
}
},
"node_modules/@firebase/firestore-compat": {
"version": "0.3.34",
"resolved": "https://registry.npmjs.org/@firebase/firestore-compat/-/firestore-compat-0.3.34.tgz",
"integrity": "sha512-OBP2F/Ccydl2U2j8XIfpKBxf0EnQHEhbZ4LTwbSS2QlG9+8TwhvKFkKk/ZljWYqaype+qFKPuXZ5flCqYEETeA==",
"version": "0.3.35",
"resolved": "https://registry.npmjs.org/@firebase/firestore-compat/-/firestore-compat-0.3.35.tgz",
"integrity": "sha512-VdYQtMIrPjsgZpuBwvry6LgcS0vbUhHzpebaKm5oc9oTTvP4K7oxvR/ZJdDjIE5rBugn1SdY++uGMatcIvBkZg==",
"license": "Apache-2.0",
"dependencies": {
"@firebase/component": "0.6.8",
"@firebase/firestore": "4.6.5",
"@firebase/firestore": "4.7.0",
"@firebase/firestore-types": "3.0.2",
"@firebase/util": "1.9.7",
"tslib": "^2.1.0"
@@ -3912,9 +3912,10 @@
"integrity": "sha512-0BC4+Ud7y2aPTyhXJTMTFfrGGLqdYXrUB9sJVAB8NiqJswDTc4/2qrE/yfUbnQJhbSi6ZaTTBKyG3n1nplssaA=="
},
"node_modules/@firebase/storage": {
"version": "0.12.6",
"resolved": "https://registry.npmjs.org/@firebase/storage/-/storage-0.12.6.tgz",
"integrity": "sha512-Zgb9WuehJxzhj7pGXUvkAEaH+3HvLjD9xSZ9nepuXf5f8378xME7oGJtREr/RnepdDA5YW0XIxe0QQBNHpe1nw==",
"version": "0.13.0",
"resolved": "https://registry.npmjs.org/@firebase/storage/-/storage-0.13.0.tgz",
"integrity": "sha512-3RQaYpkR4TwPnPR1XlmDUAXiYt5QVQRGRGY1+/yNyS9ohHOCNNgbcs6a+QYvaDInbYTywrdddKYMFFXKKb1pRg==",
"license": "Apache-2.0",
"dependencies": {
"@firebase/component": "0.6.8",
"@firebase/util": "1.9.7",
@@ -3926,12 +3927,13 @@
}
},
"node_modules/@firebase/storage-compat": {
"version": "0.3.9",
"resolved": "https://registry.npmjs.org/@firebase/storage-compat/-/storage-compat-0.3.9.tgz",
"integrity": "sha512-WWgAp5bTW961oIsCc9+98m4MIVKpEqztAlIngfHfwO/x3DYoBPRl/awMRG3CAXyVxG+7B7oHC5IsnqM+vTwx2A==",
"version": "0.3.10",
"resolved": "https://registry.npmjs.org/@firebase/storage-compat/-/storage-compat-0.3.10.tgz",
"integrity": "sha512-KcikeV5dK1H1cXi0zEb7gJ3IZ4dKKCjpyucVK8r/Qv5eNAqeQAzPgKKhsSv67wT1N6DTxmqsNEXwMo0dcrKOEg==",
"license": "Apache-2.0",
"dependencies": {
"@firebase/component": "0.6.8",
"@firebase/storage": "0.12.6",
"@firebase/storage": "0.13.0",
"@firebase/storage-types": "0.8.2",
"@firebase/util": "1.9.7",
"tslib": "^2.1.0"
@@ -3944,6 +3946,7 @@
"version": "0.8.2",
"resolved": "https://registry.npmjs.org/@firebase/storage-types/-/storage-types-0.8.2.tgz",
"integrity": "sha512-0vWu99rdey0g53lA7IShoA2Lol1jfnPovzLDUBuon65K7uKG9G+L5uO05brD9pMw+l4HRFw23ah3GwTGpEav6g==",
"license": "Apache-2.0",
"peerDependencies": {
"@firebase/app-types": "0.x",
"@firebase/util": "1.x"
@@ -4614,9 +4617,9 @@
}
},
"node_modules/@remix-run/router": {
"version": "1.19.0",
"resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.19.0.tgz",
"integrity": "sha512-zDICCLKEwbVYTS6TjYaWtHXxkdoUvD/QXvyVZjGCsWz5vyH7aFeONlPffPdW+Y/t6KT0MgXb2Mfjun9YpWN1dA==",
"version": "1.19.1",
"resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.19.1.tgz",
"integrity": "sha512-S45oynt/WH19bHbIXjtli6QmwNYvaz+vtnubvNpNDvUOoA/OWh6j1OikIP3G+v5GHdxyC6EXoChG3HgYGEUfcg==",
"license": "MIT",
"engines": {
"node": ">=14.0.0"
@@ -6333,9 +6336,9 @@
}
},
"node_modules/antd": {
"version": "5.20.1",
"resolved": "https://registry.npmjs.org/antd/-/antd-5.20.1.tgz",
"integrity": "sha512-YjVCYAfBjrTyNKsg+heAOR0Gm4qJNJoBZQcV1h1BX/ufwoLx0PC5RGs75g6gQFy/1nv8OrJH7DXUGdtwPMB3Vg==",
"version": "5.20.2",
"resolved": "https://registry.npmjs.org/antd/-/antd-5.20.2.tgz",
"integrity": "sha512-9d6Bs5ZKIV+JhB0eD7KxYnIfnhUh86kNtTGIuNiIxHFUhbuyT1DXN2SuMksDmtSfuRYZ82/C4hq+OJjWNNbmHg==",
"license": "MIT",
"dependencies": {
"@ant-design/colors": "^7.1.0",
@@ -6359,7 +6362,7 @@
"rc-dialog": "~9.5.2",
"rc-drawer": "~7.2.0",
"rc-dropdown": "~4.2.0",
"rc-field-form": "~2.3.0",
"rc-field-form": "~2.4.0",
"rc-image": "~7.9.0",
"rc-input": "~1.6.3",
"rc-input-number": "~9.2.0",
@@ -6368,7 +6371,7 @@
"rc-motion": "^2.9.2",
"rc-notification": "~5.6.0",
"rc-pagination": "~4.2.0",
"rc-picker": "~4.6.12",
"rc-picker": "~4.6.13",
"rc-progress": "~4.0.0",
"rc-rate": "~2.13.0",
"rc-resize-observer": "^1.4.0",
@@ -6383,7 +6386,7 @@
"rc-tooltip": "~6.2.0",
"rc-tree": "~5.8.8",
"rc-tree-select": "~5.22.1",
"rc-upload": "~4.6.0",
"rc-upload": "~4.7.0",
"rc-util": "^5.43.0",
"scroll-into-view-if-needed": "^3.1.0",
"throttle-debounce": "^5.0.2"
@@ -10149,24 +10152,24 @@
}
},
"node_modules/firebase": {
"version": "10.12.5",
"resolved": "https://registry.npmjs.org/firebase/-/firebase-10.12.5.tgz",
"integrity": "sha512-J0yL3yh12CfFprTkSOQ9HqBugERyqvWwOuOoo1j1QHmYe9cYLKnBmtNCvGIYInDcsVUnJoRXCM+hxbGf48oVhg==",
"version": "10.13.0",
"resolved": "https://registry.npmjs.org/firebase/-/firebase-10.13.0.tgz",
"integrity": "sha512-a8gm8c9CYO98QuXJn7m5W5Gj7kHV8fme81/mQ9dBs+VMz9uI5HdavnMVPXCILputpZFMFpiKK+u7VVsn5lQg+w==",
"license": "Apache-2.0",
"dependencies": {
"@firebase/analytics": "0.10.7",
"@firebase/analytics-compat": "0.2.13",
"@firebase/app": "0.10.8",
"@firebase/app": "0.10.9",
"@firebase/app-check": "0.8.7",
"@firebase/app-check-compat": "0.3.14",
"@firebase/app-compat": "0.2.38",
"@firebase/app-compat": "0.2.39",
"@firebase/app-types": "0.9.2",
"@firebase/auth": "1.7.6",
"@firebase/auth-compat": "0.5.11",
"@firebase/auth": "1.7.7",
"@firebase/auth-compat": "0.5.12",
"@firebase/database": "1.0.7",
"@firebase/database-compat": "1.0.7",
"@firebase/firestore": "4.6.5",
"@firebase/firestore-compat": "0.3.34",
"@firebase/firestore": "4.7.0",
"@firebase/firestore-compat": "0.3.35",
"@firebase/functions": "0.11.6",
"@firebase/functions-compat": "0.3.12",
"@firebase/installations": "0.6.8",
@@ -10177,8 +10180,8 @@
"@firebase/performance-compat": "0.2.8",
"@firebase/remote-config": "0.4.8",
"@firebase/remote-config-compat": "0.2.8",
"@firebase/storage": "0.12.6",
"@firebase/storage-compat": "0.3.9",
"@firebase/storage": "0.13.0",
"@firebase/storage-compat": "0.3.10",
"@firebase/util": "1.9.7",
"@firebase/vertexai-preview": "0.0.3"
}
@@ -10862,9 +10865,9 @@
}
},
"node_modules/i18next": {
"version": "23.12.3",
"resolved": "https://registry.npmjs.org/i18next/-/i18next-23.12.3.tgz",
"integrity": "sha512-DyigQmrR10V9U2N6pjhbfahW13GY7n8BQD9swN09JuRRropgsksWVi4vRLeex0Qf7zCPnBfIqQfhcBzdZBQBYw==",
"version": "23.14.0",
"resolved": "https://registry.npmjs.org/i18next/-/i18next-23.14.0.tgz",
"integrity": "sha512-Y5GL4OdA8IU2geRrt2+Uc1iIhsjICdHZzT9tNwQ3TVqdNzgxHToGCKf/TPRP80vTCAP6svg2WbbJL+Gx5MFQVA==",
"funding": [
{
"type": "individual",
@@ -11948,9 +11951,9 @@
}
},
"node_modules/libphonenumber-js": {
"version": "1.11.5",
"resolved": "https://registry.npmjs.org/libphonenumber-js/-/libphonenumber-js-1.11.5.tgz",
"integrity": "sha512-TwHR5BZxGRODtAfz03szucAkjT5OArXr+94SMtAM2pYXIlQNVMrxvb6uSCbnaJJV6QXEyICk7+l6QPgn72WHhg==",
"version": "1.11.7",
"resolved": "https://registry.npmjs.org/libphonenumber-js/-/libphonenumber-js-1.11.7.tgz",
"integrity": "sha512-x2xON4/Qg2bRIS11KIN9yCNYUjhtiEjNyptjX0mX+pyKHecxuJVLIpfX1lq9ZD6CrC/rB+y4GBi18c6CEcUR+A==",
"license": "MIT"
},
"node_modules/lie": {
@@ -14168,9 +14171,9 @@
}
},
"node_modules/rc-field-form": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/rc-field-form/-/rc-field-form-2.3.0.tgz",
"integrity": "sha512-QyiYrE3uweGGi21MJpxHFmDW+Tb1yt5hitM1k0EbWc5hKDiSf5imOBc6NLLHrYk+sdelrw2Ju/fD4uRQdhSqNg==",
"version": "2.4.0",
"resolved": "https://registry.npmjs.org/rc-field-form/-/rc-field-form-2.4.0.tgz",
"integrity": "sha512-XZ/lF9iqf9HXApIHQHqzJK5v2w4mkUMsVqAzOyWVzoiwwXEavY6Tpuw7HavgzIoD+huVff4JghSGcgEfX6eycg==",
"license": "MIT",
"dependencies": {
"@babel/runtime": "^7.18.0",
@@ -14609,9 +14612,10 @@
}
},
"node_modules/rc-upload": {
"version": "4.6.0",
"resolved": "https://registry.npmjs.org/rc-upload/-/rc-upload-4.6.0.tgz",
"integrity": "sha512-Zr0DT1NHw/ApxrP7UAoxOtGaVYuzarrrCVr0ld7RiEFsKX07uFhE1EpCBxwL11ruFn89GMcshOKWp+s6FLyAlA==",
"version": "4.7.0",
"resolved": "https://registry.npmjs.org/rc-upload/-/rc-upload-4.7.0.tgz",
"integrity": "sha512-eUwxYNHlsYe5vYhKFAUGrQG95JrnPzY+BmPi1Daq39fWNl/eOc7v4UODuWrVp2LFkQBuV3cMCG/I68iub6oBrg==",
"license": "MIT",
"dependencies": {
"@babel/runtime": "^7.18.3",
"classnames": "^2.2.5",
@@ -14670,9 +14674,9 @@
}
},
"node_modules/react-big-calendar": {
"version": "1.13.2",
"resolved": "https://registry.npmjs.org/react-big-calendar/-/react-big-calendar-1.13.2.tgz",
"integrity": "sha512-yzeVRM1I+JloeJXytrZx2lJWKUfLAi5bsgGuBjh3aFSHZrdFcGnfA7LE6pBacdyOG+NGP+332m2MziszkmQWcw==",
"version": "1.13.3",
"resolved": "https://registry.npmjs.org/react-big-calendar/-/react-big-calendar-1.13.3.tgz",
"integrity": "sha512-PaZEQMhZCPiInxkKeP9S1TgI1e0Gd4aPpueYXS97rMa89AfX2ZGEmoMjDyeOkIz+mA1utuYF/yQYaxGPNXS0Sg==",
"license": "MIT",
"dependencies": {
"@babel/runtime": "^7.20.7",
@@ -14939,9 +14943,10 @@
}
},
"node_modules/react-product-fruits": {
"version": "2.2.6",
"resolved": "https://registry.npmjs.org/react-product-fruits/-/react-product-fruits-2.2.6.tgz",
"integrity": "sha512-f57m1rCD+Cu8QfFQSpkHJjLaWauPbD01GNrbh4icQaOHA/6bHJGpcoSSEQfAtk3g2PyQBpsDdRvL9jC+hyxhhQ==",
"version": "2.2.61",
"resolved": "https://registry.npmjs.org/react-product-fruits/-/react-product-fruits-2.2.61.tgz",
"integrity": "sha512-zqmrtgwI6TLIR1g6pk9SzAutoKgC/7L1Y0ffsleymcAjSUxhHAla5A0bS2vMLq+WkgYKKH7Dl+Z9VxUywLEdeg==",
"license": "MIT",
"dependencies": {
"product-fruits": "^1.0.25"
},
@@ -14992,12 +14997,12 @@
}
},
"node_modules/react-router": {
"version": "6.26.0",
"resolved": "https://registry.npmjs.org/react-router/-/react-router-6.26.0.tgz",
"integrity": "sha512-wVQq0/iFYd3iZ9H2l3N3k4PL8EEHcb0XlU2Na8nEwmiXgIUElEH6gaJDtUQxJ+JFzmIXaQjfdpcGWaM6IoQGxg==",
"version": "6.26.1",
"resolved": "https://registry.npmjs.org/react-router/-/react-router-6.26.1.tgz",
"integrity": "sha512-kIwJveZNwp7teQRI5QmwWo39A5bXRyqpH0COKKmPnyD2vBvDwgFXSqDUYtt1h+FEyfnE8eXr7oe0MxRzVwCcvQ==",
"license": "MIT",
"dependencies": {
"@remix-run/router": "1.19.0"
"@remix-run/router": "1.19.1"
},
"engines": {
"node": ">=14.0.0"
@@ -15007,13 +15012,13 @@
}
},
"node_modules/react-router-dom": {
"version": "6.26.0",
"resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.26.0.tgz",
"integrity": "sha512-RRGUIiDtLrkX3uYcFiCIxKFWMcWQGMojpYZfcstc63A1+sSnVgILGIm9gNUA6na3Fm1QuPGSBQH2EMbAZOnMsQ==",
"version": "6.26.1",
"resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.26.1.tgz",
"integrity": "sha512-veut7m41S1fLql4pLhxeSW3jlqs+4MtjRLj0xvuCEXsxusJCbs6I8yn9BxzzDX2XDgafrccY6hwjmd/bL54tFw==",
"license": "MIT",
"dependencies": {
"@remix-run/router": "1.19.0",
"react-router": "6.26.0"
"@remix-run/router": "1.19.1",
"react-router": "6.26.1"
},
"engines": {
"node": ">=14.0.0"
@@ -17551,14 +17556,14 @@
}
},
"node_modules/vite": {
"version": "5.4.0",
"resolved": "https://registry.npmjs.org/vite/-/vite-5.4.0.tgz",
"integrity": "sha512-5xokfMX0PIiwCMCMb9ZJcMyh5wbBun0zUzKib+L65vAZ8GY9ePZMXxFrHbr/Kyll2+LSCY7xtERPpxkBDKngwg==",
"version": "5.4.1",
"resolved": "https://registry.npmjs.org/vite/-/vite-5.4.1.tgz",
"integrity": "sha512-1oE6yuNXssjrZdblI9AfBbHCC41nnyoVoEZxQnID6yvQZAFBzxxkqoFLtHUMkYunL8hwOLEjgTuxpkRxvba3kA==",
"dev": true,
"license": "MIT",
"dependencies": {
"esbuild": "^0.21.3",
"postcss": "^8.4.40",
"postcss": "^8.4.41",
"rollup": "^4.13.0"
},
"bin": {

View File

@@ -19,7 +19,7 @@
"@splitsoftware/splitio-react": "^1.12.1",
"@tanem/react-nprogress": "^5.0.51",
"@vitejs/plugin-react": "^4.3.1",
"antd": "^5.20.1",
"antd": "^5.20.2",
"apollo-link-logger": "^2.0.1",
"apollo-link-sentry": "^3.3.0",
"autosize": "^6.0.1",
@@ -32,12 +32,12 @@
"dotenv": "^16.4.5",
"env-cmd": "^10.1.0",
"exifr": "^7.1.3",
"firebase": "^10.12.5",
"firebase": "^10.13.0",
"graphql": "^16.9.0",
"i18next": "^23.12.3",
"i18next": "^23.14.0",
"i18next-browser-languagedetector": "^8.0.0",
"immutability-helper": "^3.1.1",
"libphonenumber-js": "^1.11.5",
"libphonenumber-js": "^1.11.7",
"logrocket": "^8.1.2",
"markerjs2": "^2.32.1",
"memoize-one": "^6.0.0",
@@ -47,7 +47,7 @@
"query-string": "^9.1.0",
"raf-schd": "^4.0.3",
"react": "^18.3.1",
"react-big-calendar": "^1.13.2",
"react-big-calendar": "^1.13.3",
"react-color": "^2.19.3",
"react-cookie": "^7.2.0",
"react-dom": "^18.3.1",
@@ -60,10 +60,10 @@
"react-markdown": "^9.0.1",
"react-number-format": "^5.4.0",
"react-popopo": "^2.1.9",
"react-product-fruits": "^2.2.6",
"react-product-fruits": "^2.2.61",
"react-redux": "^9.1.2",
"react-resizable": "^3.0.5",
"react-router-dom": "^6.26.0",
"react-router-dom": "^6.26.1",
"react-sticky": "^6.0.3",
"react-virtualized": "^9.22.5",
"react-virtuoso": "^4.10.1",
@@ -147,7 +147,7 @@
"react-error-overlay": "6.0.11",
"redux-logger": "^3.0.6",
"source-map-explorer": "^2.5.3",
"vite": "^5.4.0",
"vite": "^5.4.1",
"vite-plugin-babel": "^1.2.0",
"vite-plugin-eslint": "^1.8.1",
"vite-plugin-legacy": "^2.1.0",

View File

@@ -18,7 +18,7 @@ import { checkUserSession } from "../redux/user/user.actions";
import { selectBodyshop, selectCurrentEula, selectCurrentUser } from "../redux/user/user.selectors";
import PrivateRoute from "../components/PrivateRoute";
import "./App.styles.scss";
import handleBeta from "../utils/betaHandler";
import handleBeta from "../utils/handleBeta";
import Eula from "../components/eula/eula.component";
import InstanceRenderMgr from "../utils/instanceRenderMgr";
import ProductFruitsWrapper from "./ProductFruitsWrapper.jsx";

View File

@@ -13,6 +13,7 @@ import { createStructuredSelector } from "reselect";
import { selectBodyshop } from "../../redux/user/user.selectors";
import { DateFormatter } from "../../utils/DateFormatter";
import ExportLogsCountDisplay from "../export-logs-count-display/export-logs-count-display.component";
import JobMarkSelectedExported from "../jobs-mark-selected-exported/jobs-mark-selected-exported";
import OwnerNameDisplay, { OwnerNameDisplayFunction } from "../owner-name-display/owner-name-display.component";
import QboAuthorizeComponent from "../qbo-authorize/qbo-authorize.component";
@@ -170,13 +171,22 @@ export function AccountingReceivablesTableComponent({ bodyshop, loading, jobs, r
extra={
<Space wrap>
{!bodyshop.cdk_dealerid && !bodyshop.pbs_serialnumber && (
<JobsExportAllButton
jobIds={selectedJobs}
disabled={transInProgress || selectedJobs.length === 0}
loadingCallback={setTransInProgress}
completedCallback={setSelectedJobs}
refetch={refetch}
/>
<>
<JobMarkSelectedExported
jobIds={selectedJobs}
disabled={transInProgress || selectedJobs.length === 0}
loadingCallback={setTransInProgress}
completedCallback={setSelectedJobs}
refetch={refetch}
/>
<JobsExportAllButton
jobIds={selectedJobs}
disabled={transInProgress || selectedJobs.length === 0}
loadingCallback={setTransInProgress}
completedCallback={setSelectedJobs}
refetch={refetch}
/>
</>
)}
{bodyshop.accountingconfig && bodyshop.accountingconfig.qbo && <QboAuthorizeComponent />}
<Input.Search

View File

@@ -43,7 +43,7 @@ import { selectRecentItems, selectSelectedHeader } from "../../redux/application
import { setModalContext } from "../../redux/modals/modals.actions";
import { signOutStart } from "../../redux/user/user.actions";
import { selectBodyshop, selectCurrentUser } from "../../redux/user/user.selectors";
import { checkBeta, handleBeta, setBeta } from "../../utils/betaHandler";
import { checkBeta, handleBeta, setBeta } from "../../utils/handleBeta";
import InstanceRenderManager from "../../utils/instanceRenderMgr";
import { HasFeatureAccess } from "../feature-wrapper/feature-wrapper.component";

View File

@@ -11,6 +11,7 @@ import { createStructuredSelector } from "reselect";
import { selectBodyshop } from "../../redux/user/user.selectors";
import CurrencyFormatter from "../../utils/CurrencyFormatter";
import { pageLimit } from "../../utils/config";
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";
@@ -37,7 +38,10 @@ export function JobsList({ bodyshop, refetch, loading, jobs, total }) {
title: t("jobs.fields.ro_number"),
dataIndex: "ro_number",
key: "ro_number",
sorter: true, //(a, b) => alphaSort(a.ro_number, b.ro_number),
sorter: search?.search
? (a, b) =>
parseInt((a.ro_number || "0").replace(/\D/g, "")) - parseInt((b.ro_number || "0").replace(/\D/g, ""))
: true,
sortOrder: sortcolumn === "ro_number" && sortorder,
render: (text, record) => (
<Link to={"/manage/jobs/" + record.id}>{record.ro_number || t("general.labels.na")}</Link>
@@ -49,7 +53,6 @@ export function JobsList({ bodyshop, refetch, loading, jobs, total }) {
key: "ownr_ln",
ellipsis: true,
//sorter: true, // (a, b) => alphaSort(a.ownr_ln, b.ownr_ln),
//sortOrder: sortcolumn === "ownr_ln" && sortorder,
render: (text, record) => {
return record.ownerid ? (
@@ -67,7 +70,6 @@ export function JobsList({ bodyshop, refetch, loading, jobs, total }) {
title: t("jobs.fields.ownr_ph1"),
dataIndex: "ownr_ph1",
key: "ownr_ph1",
ellipsis: true,
render: (text, record) => <StartChatButton phone={record.ownr_ph1} jobid={record.id} />
},
@@ -75,7 +77,6 @@ export function JobsList({ bodyshop, refetch, loading, jobs, total }) {
title: t("jobs.fields.ownr_ph2"),
dataIndex: "ownr_ph2",
key: "ownr_ph2",
ellipsis: true,
render: (text, record) => <StartChatButton phone={record.ownr_ph2} jobid={record.id} />
},
@@ -85,7 +86,7 @@ export function JobsList({ bodyshop, refetch, loading, jobs, total }) {
key: "status",
ellipsis: true,
sorter: true, // (a, b) => alphaSort(a.status, b.status),
sorter: search?.search ? (a, b) => statusSort(a.status, b.status, bodyshop.md_ro_statuses.active_statuses) : true,
sortOrder: sortcolumn === "status" && sortorder,
render: (text, record) => {
return record.status || t("general.labels.na");
@@ -100,7 +101,6 @@ export function JobsList({ bodyshop, refetch, loading, jobs, total }) {
title: t("jobs.fields.vehicle"),
dataIndex: "vehicle",
key: "vehicle",
ellipsis: true,
render: (text, record) => {
return record.vehicleid ? (
@@ -117,7 +117,7 @@ export function JobsList({ bodyshop, refetch, loading, jobs, total }) {
dataIndex: "plate_no",
key: "plate_no",
ellipsis: true,
sorter: true, //(a, b) => alphaSort(a.plate_no, b.plate_no),
sorter: search?.search ? (a, b) => alphaSort(a.plate_no, b.plate_no) : true,
sortOrder: sortcolumn === "plate_no" && sortorder,
render: (text, record) => {
return record.plate_no ? record.plate_no : "";
@@ -128,7 +128,7 @@ export function JobsList({ bodyshop, refetch, loading, jobs, total }) {
dataIndex: "clm_no",
key: "clm_no",
ellipsis: true,
sorter: true, //(a, b) => alphaSort(a.clm_no, b.clm_no),
sorter: search?.search ? (a, b) => alphaSort(a.clm_no, b.clm_no) : true,
sortOrder: sortcolumn === "clm_no" && sortorder,
render: (text, record) => `${record.clm_no || ""}${record.po_number ? ` (PO: ${record.po_number})` : ""}`
},
@@ -142,8 +142,7 @@ export function JobsList({ bodyshop, refetch, loading, jobs, total }) {
title: t("jobs.fields.clm_total"),
dataIndex: "clm_total",
key: "clm_total",
sorter: true, //(a, b) => a.clm_total - b.clm_total,
sorter: search?.search ? (a, b) => a.clm_total - b.clm_total : true,
sortOrder: sortcolumn === "clm_total" && sortorder,
render: (text, record) => {
return record.clm_total ? (
@@ -157,7 +156,6 @@ export function JobsList({ bodyshop, refetch, loading, jobs, total }) {
title: t("jobs.fields.owner_owing"),
dataIndex: "owner_owing",
key: "owner_owing",
render: (text, record) => <CurrencyFormatter>{record.owner_owing}</CurrencyFormatter>
},
{

View File

@@ -0,0 +1,105 @@
import { useMutation } from "@apollo/client";
import { Button, notification, Popconfirm } from "antd";
import React, { useState } from "react";
import { useTranslation } from "react-i18next";
import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
import { INSERT_EXPORT_LOG } from "../../graphql/accounting.queries";
import { UPDATE_JOBS } from "../../graphql/jobs.queries";
import { insertAuditTrail } from "../../redux/application/application.actions";
import { selectBodyshop, selectCurrentUser } from "../../redux/user/user.selectors";
import AuditTrailMapping from "../../utils/AuditTrailMappings";
const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop,
currentUser: selectCurrentUser
});
const mapDispatchToProps = (dispatch) => ({
insertAuditTrail: ({ jobid, operation, type }) => dispatch(insertAuditTrail({ jobid, operation, type }))
});
export default connect(mapStateToProps, mapDispatchToProps)(JobMarkSelectedExported);
export function JobMarkSelectedExported({
bodyshop,
currentUser,
jobIds,
disabled,
loadingCallback,
completedCallback,
refetch,
insertAuditTrail
}) {
const { t } = useTranslation();
const [loading, setLoading] = useState(false);
const [open, setOpen] = useState(false);
const [insertExportLog] = useMutation(INSERT_EXPORT_LOG);
const [updateJob] = useMutation(UPDATE_JOBS);
const handleUpdate = async () => {
setLoading(true);
loadingCallback(true);
const result = await updateJob({
variables: {
jobIds: jobIds,
fields: {
status: bodyshop.md_ro_statuses.default_exported || "Exported*",
date_exported: new Date()
}
},
update(cache) {}
});
await insertExportLog({
variables: {
logs: jobIds.map((id) => {
return {
bodyshopid: bodyshop.id,
jobid: id,
successful: true,
message: JSON.stringify([t("general.labels.markedexported")]),
useremail: currentUser.email
};
})
}
});
if (!result.errors) {
notification["success"]({ message: t("jobs.successes.save") });
result.data.update_jobs.returning.forEach((job) => {
console.log("results job", job.id, "audit: ", AuditTrailMapping.admin_jobmarkexported());
insertAuditTrail({
jobid: job.id,
operation: AuditTrailMapping.admin_jobmarkexported(),
type: "admin_jobmarkexported"
});
});
} else {
notification["error"]({
message: t("jobs.errors.saving", {
error: JSON.stringify(result.errors)
})
});
}
loadingCallback(false);
completedCallback && completedCallback([]);
setLoading(false);
refetch && refetch();
setOpen(false);
};
return (
<Popconfirm
open={open}
title={t("general.labels.areyousure")}
onCancel={() => setOpen(false)}
onConfirm={handleUpdate}
disabled={disabled}
>
<Button loading={loading} disabled={disabled} onClick={() => setOpen(true)} type="primary" danger>
{t("jobs.actions.markasexported")}
</Button>
</Popconfirm>
);
}

View File

@@ -90,7 +90,7 @@ export function BillMarkSelectedExported({
onConfirm={handleUpdate}
disabled={disabled}
>
<Button loading={loading} disabled={disabled} onClick={() => setOpen(true)}>
<Button loading={loading} disabled={disabled} onClick={() => setOpen(true)} type="primary" danger>
{t("bills.labels.markexported")}
</Button>
</Popconfirm>

View File

@@ -90,7 +90,7 @@ export function PaymentMarkSelectedExported({
onConfirm={handleUpdate}
disabled={disabled}
>
<Button loading={loading} disabled={disabled} onClick={() => setOpen(true)}>
<Button loading={loading} disabled={disabled} onClick={() => setOpen(true)} type="primary" danger>
{t("bills.labels.markexported")}
</Button>
</Popconfirm>

View File

@@ -1,22 +1,32 @@
import { Input, Space, Spin } from "antd";
import React from "react";
import { Button, Input, Space, Spin } from "antd";
import React, { useState } from "react";
import { useTranslation } from "react-i18next";
import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
import { ExclamationCircleFilled, ExclamationCircleOutlined } from "@ant-design/icons";
import { selectBodyshop } from "../../redux/user/user.selectors";
import EmployeeSearchSelectComponent from "../employee-search-select/employee-search-select.component";
const mapStateToProps = createStructuredSelector({
//currentUser: selectCurrentUser
bodyshop: selectBodyshop
});
const mapDispatchToProps = (dispatch) => ({
//setUserLanguage: language => dispatch(setUserLanguage(language))
});
export default connect(mapStateToProps, mapDispatchToProps)(ProductionBoardFilters);
export function ProductionBoardFilters({ bodyshop, filter, setFilter, loading }) {
const { t } = useTranslation();
const [alertFilter, setAlertFilter] = useState(false);
const toggleAlertFilter = () => {
const newAlertFilter = !alertFilter;
setAlertFilter(newAlertFilter);
setFilter({ ...filter, alert: newAlertFilter });
};
return (
<Space wrap>
{loading && <Spin />}
@@ -35,6 +45,13 @@ export function ProductionBoardFilters({ bodyshop, filter, setFilter, loading })
onChange={(emp) => setFilter({ ...filter, employeeId: emp })}
allowClear
/>
<Button
type={alertFilter ? "primary" : "default"}
onClick={toggleAlertFilter}
icon={alertFilter ? <ExclamationCircleFilled /> : <ExclamationCircleOutlined />}
>
{t("production.labels.alerts")}
</Button>
</Space>
);
}

View File

@@ -21,7 +21,7 @@ import { createBoardData } from "./production-board-kanban.utils.js";
import ProductionBoardKanbanSettings from "./settings/production-board-kanban.settings.component.jsx";
import cloneDeep from "lodash/cloneDeep";
import isEqual from "lodash/isEqual";
import { mergeWithDefaults } from "./settings/defaultKanbanSettings.js";
import { defaultFilters, mergeWithDefaults } from "./settings/defaultKanbanSettings.js";
import NoteUpsertModal from "../../components/note-upsert-modal/note-upsert-modal.container";
const mapStateToProps = createStructuredSelector({
@@ -41,7 +41,7 @@ const mapDispatchToProps = (dispatch) => ({
function ProductionBoardKanbanComponent({ data, bodyshop, refetch, insertAuditTrail, associationSettings, statuses }) {
const [boardLanes, setBoardLanes] = useState({ lanes: [] });
const [filter, setFilter] = useState({ search: "", employeeId: null });
const [filter, setFilter] = useState(defaultFilters);
const [loading, setLoading] = useState(true);
const [isMoving, setIsMoving] = useState(false);
const [orientation, setOrientation] = useState("vertical");
@@ -187,11 +187,9 @@ function ProductionBoardKanbanComponent({ data, bodyshop, refetch, insertAuditTr
return mergeWithDefaults(kanbanSettings);
}, [associationSettings]);
const handleSettingsChange = useCallback((newSettings) => {
setLoading(true);
setOrientation(newSettings.orientation ? "vertical" : "horizontal");
setLoading(false);
}, []);
const handleSettingsChange = () => {
setFilter(defaultFilters);
};
if (loading) {
return <Skeleton active />;

View File

@@ -29,7 +29,7 @@ const sortByParentId = (arr) => {
// Function to create board data based on statuses and jobs, with optional filtering
export const createBoardData = ({ statuses, data, filter, cardSettings }) => {
const { search, employeeId } = filter;
const { search, employeeId, alert } = filter;
const lanes = statuses.map((status) => ({
id: status,
@@ -52,6 +52,11 @@ export const createBoardData = ({ statuses, data, filter, cardSettings }) => {
);
}
// Filter jobs by alert if alert filter is true
if (alert) {
filteredJobs = filteredJobs.filter((job) => job.production_vars?.alert);
}
const DataGroupedByStatus = groupBy(filteredJobs, "status");
Object.keys(DataGroupedByStatus).forEach((statusGroupKey) => {

View File

@@ -48,6 +48,8 @@ const defaultKanbanSettings = {
selectedEstimators: []
};
const defaultFilters = { search: "", employeeId: null, alert: false };
const mergeWithDefaults = (settings) => {
// Create a new object that starts with the default settings
const mergedSettings = { ...defaultKanbanSettings };
@@ -64,4 +66,4 @@ const mergeWithDefaults = (settings) => {
return mergedSettings;
};
export { defaultKanbanSettings, statisticsItems, mergeWithDefaults };
export { defaultKanbanSettings, statisticsItems, mergeWithDefaults, defaultFilters };

View File

@@ -9,8 +9,9 @@ import InformationSettings from "./InformationSettings.jsx";
import StatisticsSettings from "./StatisticsSettings.jsx";
import FilterSettings from "./FilterSettings.jsx";
import PropTypes from "prop-types";
import { isFunction } from "lodash";
function ProductionBoardKanbanSettings({ associationSettings, parentLoading, bodyshop, data }) {
function ProductionBoardKanbanSettings({ associationSettings, parentLoading, bodyshop, data, onSettingsChange }) {
const [form] = Form.useForm();
const [open, setOpen] = useState(false);
const [loading, setLoading] = useState(false);
@@ -61,6 +62,11 @@ function ProductionBoardKanbanSettings({ associationSettings, parentLoading, bod
setOpen(false);
setLoading(false);
parentLoading(false);
if (onSettingsChange && isFunction(onSettingsChange)) {
onSettingsChange(values);
}
setHasChanges(false);
};
@@ -156,6 +162,7 @@ ProductionBoardKanbanSettings.propTypes = {
associationSettings: PropTypes.object,
parentLoading: PropTypes.func.isRequired,
bodyshop: PropTypes.object.isRequired,
onSettingsChange: PropTypes.func,
data: PropTypes.array
};

View File

@@ -2,7 +2,6 @@ import React from "react";
import { Button, Dropdown } from "antd";
import dataSource from "./production-list-columns.data";
import { useTranslation } from "react-i18next";
import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
import { selectTechnician } from "../../redux/tech/tech.selectors";
@@ -10,16 +9,23 @@ import { selectBodyshop } from "../../redux/user/user.selectors";
import { useSplitTreatments } from "@splitsoftware/splitio-react";
const mapStateToProps = createStructuredSelector({
//currentUser: selectCurrentUser
technician: selectTechnician,
bodyshop: selectBodyshop
});
const mapDispatchToProps = (dispatch) => ({
//setUserLanguage: language => dispatch(setUserLanguage(language))
});
export default connect(mapStateToProps, mapDispatchToProps)(ProductionColumnsComponent);
export function ProductionColumnsComponent({ columnState, technician, bodyshop, data, tableState, refetch }) {
const mapDispatchToProps = (dispatch) => ({
// Add any necessary dispatch actions here
});
export function ProductionColumnsComponent({
columnState,
technician,
bodyshop,
data,
tableState,
refetch,
onColumnAdd
}) {
const [columns, setColumns] = columnState;
const { t } = useTranslation();
const {
@@ -29,18 +35,26 @@ export function ProductionColumnsComponent({ columnState, technician, bodyshop,
names: ["Enhanced_Payroll"],
splitKey: bodyshop.imexshopid
});
const handleAdd = (e) => {
setColumns([
...columns,
...dataSource({
bodyshop,
technician,
state: tableState,
data,
activeStatuses: bodyshop.md_ro_statuses.active_statuses,
treatments: { Enhanced_Payroll }
}).filter((i) => i.key === e.key)
]);
const newColumn = dataSource({
bodyshop,
technician,
state: tableState,
data,
activeStatuses: bodyshop.md_ro_statuses.active_statuses,
treatments: { Enhanced_Payroll }
}).find((i) => i.key === e.key);
if (newColumn) {
const updatedColumns = [...columns, newColumn];
setColumns(updatedColumns);
// Call the onColumnAdd function passed as a prop
if (onColumnAdd) {
onColumnAdd(newColumn);
}
}
};
const columnKeys = columns.map((i) => i.key);
@@ -76,12 +90,4 @@ export function ProductionColumnsComponent({ columnState, technician, bodyshop,
);
}
// <Transfer
// dataSource={dataSource}
// titles={["Source", "Target"]}
// targetKeys={columns.map((c) => c.key)}
// render={(item) => item.title}
// onChange={(nextTargetKeys, direction, moveKeys) => {
// setColumns(dataSource.filter((i) => nextTargetKeys.includes(i.key)));
// }}
// />
export default connect(mapStateToProps, mapDispatchToProps)(ProductionColumnsComponent);

View File

@@ -2,10 +2,13 @@ import { BranchesOutlined, PauseCircleOutlined } from "@ant-design/icons";
import { Checkbox, Space, Tooltip } from "antd";
import i18n from "i18next";
import { Link } from "react-router-dom";
import { setModalContext } from "../../redux/modals/modals.actions";
import { store } from "../../redux/store";
import CurrencyFormatter from "../../utils/CurrencyFormatter";
import { TimeFormatter } from "../../utils/DateFormatter";
import PhoneFormatter from "../../utils/PhoneFormatter";
import { onlyUnique } from "../../utils/arrayHelper";
import InstanceRenderManager from "../../utils/instanceRenderMgr";
import { alphaSort, dateSort, statusSort } from "../../utils/sorters";
import JobAltTransportChange from "../job-at-change/job-at-change.component";
import JobPartsQueueCount from "../job-parts-queue-count/job-parts-queue-count.component";
@@ -24,9 +27,6 @@ import ProductionListColumnNote from "./production-list-columns.productionnote.c
import ProductionListColumnCategory from "./production-list-columns.status.category";
import ProductionListColumnStatus from "./production-list-columns.status.component";
import ProductionListColumnTouchTime from "./prodution-list-columns.touchtime.component";
import { store } from "../../redux/store";
import { setModalContext } from "../../redux/modals/modals.actions";
import InstanceRenderManager from "../../utils/instanceRenderMgr";
const r = ({ technician, state, activeStatuses, data, bodyshop, refetch, treatments }) => {
const { Enhanced_Payroll } = treatments;
@@ -258,7 +258,7 @@ const r = ({ technician, state, activeStatuses, data, bodyshop, refetch, treatme
{ text: "True", value: true },
{ text: "False", value: false }
],
onFilter: (value, record) => value.includes(record.special_coverage_policy),
onFilter: (value, record) => value === record.special_coverage_policy,
render: (text, record) => <Checkbox checked={record.special_coverage_policy} />
},
@@ -349,6 +349,11 @@ const r = ({ technician, state, activeStatuses, data, bodyshop, refetch, treatme
key: "alert",
sorter: (a, b) => Number(a.production_vars?.alert || false) - Number(b.production_vars?.alert || false),
sortOrder: state.sortedInfo.columnKey === "alert" && state.sortedInfo.order,
filters: [
{ text: "True", value: true },
{ text: "False", value: false }
],
onFilter: (value, record) => value === (record.production_vars?.alert || false),
render: (text, record) => (
<ProductionListColumnAlert id={record.id} productionVars={record?.production_vars} refetch={refetch} />
)

View File

@@ -7,6 +7,7 @@ import { Button, Form, Input, notification, Popover, Space } from "antd";
import { useTranslation } from "react-i18next";
import { UPDATE_SHOP } from "../../graphql/bodyshop.queries";
import { logImEXEvent } from "../../firebase/firebase.utils";
import { isFunction } from "lodash";
const mapStateToProps = createStructuredSelector({
//currentUser: selectCurrentUser
@@ -16,7 +17,7 @@ const mapDispatchToProps = (dispatch) => ({
//setUserLanguage: language => dispatch(setUserLanguage(language))
});
export function ProductionListSaveConfigButton({ columns, bodyshop, tableState }) {
export function ProductionListSaveConfigButton({ columns, bodyshop, tableState, onSave }) {
const [updateShop] = useMutation(UPDATE_SHOP);
const [loading, setLoading] = useState(false);
const [open, setOpen] = useState(false);
@@ -49,6 +50,9 @@ export function ProductionListSaveConfigButton({ columns, bodyshop, tableState }
});
if (!!!result.errors) {
notification["success"]({ message: t("bodyshop.successes.save") });
if (onSave && isFunction(onSave)) {
onSave();
}
} else {
notification["error"]({
message: t("bodyshop.errors.saving", {

View File

@@ -11,6 +11,7 @@ import { selectTechnician } from "../../redux/tech/tech.selectors";
import { selectBodyshop, selectCurrentUser } from "../../redux/user/user.selectors";
import ProductionListColumns from "../production-list-columns/production-list-columns.data";
import { useSplitTreatments } from "@splitsoftware/splitio-react";
import { isFunction } from "lodash";
const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop,
@@ -18,7 +19,17 @@ const mapStateToProps = createStructuredSelector({
currentUser: selectCurrentUser
});
export function ProductionListTable({ refetch, bodyshop, technician, currentUser, state, data, setColumns, setState }) {
export function ProductionListTable({
refetch,
bodyshop,
technician,
currentUser,
state,
data,
setColumns,
setState,
onProfileChange
}) {
const { t } = useTranslation();
const [updateDefaultProdView] = useMutation(UPDATE_ACTIVE_PROD_LIST_VIEW);
const [updateShop] = useMutation(UPDATE_SHOP);
@@ -32,25 +43,25 @@ export function ProductionListTable({ refetch, bodyshop, technician, currentUser
});
const handleSelect = async (value, option) => {
setColumns(
bodyshop.production_config
.filter((pc) => pc.name === value)[0]
.columns.columnKeys.map((k) => {
return {
...ProductionListColumns({
bodyshop,
refetch,
technician,
state,
data: data,
activeStatuses: bodyshop.md_ro_statuses.active_statuses,
treatments: { Enhanced_Payroll }
}).find((e) => e.key === k.key),
width: k.width
};
})
);
setState(bodyshop.production_config.filter((pc) => pc.name === value)[0].columns.tableState);
const newColumns = bodyshop.production_config
.filter((pc) => pc.name === value)[0]
.columns.columnKeys.map((k) => {
return {
...ProductionListColumns({
bodyshop,
refetch,
technician,
state,
data: data,
activeStatuses: bodyshop.md_ro_statuses.active_statuses,
treatments: { Enhanced_Payroll }
}).find((e) => e.key === k.key),
width: k.width
};
});
setColumns(newColumns);
const newState = bodyshop.production_config.filter((pc) => pc.name === value)[0].columns.tableState;
setState(newState);
const assoc = bodyshop.associations.find((a) => a.useremail === currentUser.email);
@@ -72,6 +83,10 @@ export function ProductionListTable({ refetch, bodyshop, technician, currentUser
}
});
}
if (onProfileChange && isFunction(onProfileChange)) {
onProfileChange({ value, option, newColumns, newState, assoc });
}
};
const handleTrash = async (name) => {

View File

@@ -1,8 +1,6 @@
import { SyncOutlined } from "@ant-design/icons";
import { useSplitTreatments } from "@splitsoftware/splitio-react";
import React, { useEffect, useMemo, useRef, useState } from "react";
import { Button, Dropdown, Input, Space, Statistic, Table } from "antd";
import { PageHeader } from "@ant-design/pro-layout";
import React, { useEffect, useMemo, useState } from "react";
import ReactDragListView from "react-drag-listview";
import { useTranslation } from "react-i18next";
import { connect } from "react-redux";
@@ -16,6 +14,11 @@ import ProductionListSaveConfigButton from "../production-list-save-config-butto
import ProductionListPrint from "./production-list-print.component";
import ProductionListTableViewSelect from "./production-list-table-view-select.component";
import ResizeableTitle from "./production-list-table.resizeable.component";
import { useSplitTreatments } from "@splitsoftware/splitio-react";
import { SyncOutlined } from "@ant-design/icons";
import Prompt from "../../utils/prompt.js";
import _ from "lodash";
import AlertComponent from "../alert/alert.component.jsx";
const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop,
@@ -25,6 +28,7 @@ const mapStateToProps = createStructuredSelector({
export function ProductionListTable({ loading, data, refetch, bodyshop, technician, currentUser }) {
const [searchText, setSearchText] = useState("");
const [hasUnsavedChanges, setHasUnsavedChanges] = useState(false);
const {
treatments: { Production_List_Status_Colors, Enhanced_Payroll }
@@ -35,10 +39,9 @@ export function ProductionListTable({ loading, data, refetch, bodyshop, technici
});
const assoc = bodyshop.associations.find((a) => a.useremail === currentUser.email);
const defaultView = assoc && assoc.default_prod_list_view;
const [state, setState] = useState(
const initialStateRef = useRef(
(bodyshop.production_config &&
bodyshop.production_config.find((p) => p.name === defaultView)?.columns.tableState) ||
bodyshop.production_config[0]?.columns.tableState || {
@@ -47,80 +50,102 @@ export function ProductionListTable({ loading, data, refetch, bodyshop, technici
}
);
const { t } = useTranslation();
const matchingColumnConfig = useMemo(() => {
return bodyshop.production_config.find((p) => p.name === defaultView);
}, [bodyshop.production_config, defaultView]);
const [columns, setColumns] = useState(
(state &&
matchingColumnConfig &&
matchingColumnConfig.columns.columnKeys.map((k) => {
return {
...ProductionListColumns({
bodyshop,
refetch,
technician,
state,
data,
activeStatuses: bodyshop.md_ro_statuses.active_statuses,
treatments: { Production_List_Status_Colors, Enhanced_Payroll }
}).find((e) => e.key === k.key),
width: k.width ?? 100
};
})) ||
[]
);
useEffect(() => {
const newColumns =
(state &&
matchingColumnConfig &&
matchingColumnConfig.columns.columnKeys.map((k) => {
const initialColumnsRef = useRef(
(initialStateRef.current &&
bodyshop.production_config
.find((p) => p.name === defaultView)
?.columns.columnKeys.map((k) => {
return {
...ProductionListColumns({
bodyshop,
technician,
refetch,
state,
data: data,
technician,
state: initialStateRef.current,
data,
activeStatuses: bodyshop.md_ro_statuses.active_statuses,
treatments: { Production_List_Status_Colors, Enhanced_Payroll }
}).find((e) => e.key === k.key),
width: k.width ?? 100
};
})) ||
[];
setColumns(newColumns);
// eslint-disable-next-line react-hooks/exhaustive-deps
[]
);
const [state, setState] = useState(initialStateRef.current);
const [columns, setColumns] = useState(initialColumnsRef.current);
const { t } = useTranslation();
const matchingColumnConfig = useMemo(() => {
return bodyshop.production_config.find((p) => p.name === defaultView);
}, [bodyshop.production_config, defaultView]);
useEffect(() => {
const newColumns =
matchingColumnConfig?.columns.columnKeys.map((k) => {
return {
...ProductionListColumns({
bodyshop,
technician,
refetch,
state,
data: data,
activeStatuses: bodyshop.md_ro_statuses.active_statuses,
treatments: { Production_List_Status_Colors, Enhanced_Payroll }
}).find((e) => e.key === k.key),
width: k.width ?? 100
};
}) || [];
// Only update columns if they haven't been manually changed by the user
if (_.isEqual(initialColumnsRef.current, columns)) {
setColumns(newColumns);
}
}, [
//state,
matchingColumnConfig,
bodyshop,
technician,
data
]); //State removed from dependency array as it causes race condition when removing columns from table view and is not needed.
data,
Enhanced_Payroll,
Production_List_Status_Colors,
refetch,
state,
columns
]);
const handleTableChange = (pagination, filters, sorter) => {
setState({
const newState = {
...state,
filteredInfo: filters,
sortedInfo: { columnKey: sorter.columnKey, order: sorter.order }
});
};
if (!_.isEqual(newState, state)) {
setState(newState);
setHasUnsavedChanges(true);
}
};
const onDragEnd = (fromIndex, toIndex) => {
const columnsCopy = columns.slice();
const item = columnsCopy.splice(fromIndex, 1)[0];
columnsCopy.splice(toIndex, 0, item);
setColumns(columnsCopy);
if (fromIndex === toIndex) return;
const columnsCopy = [...columns];
const [movedItem] = columnsCopy.splice(fromIndex, 1);
columnsCopy.splice(toIndex, 0, movedItem);
if (!_.isEqual(columnsCopy, columns)) {
setColumns(columnsCopy);
setHasUnsavedChanges(true);
}
};
const removeColumn = (e) => {
const { key } = e;
const newColumns = columns.filter((i) => i.key !== key);
setColumns(newColumns);
if (!_.isEqual(newColumns, columns)) {
setColumns(newColumns);
setHasUnsavedChanges(true);
}
};
const handleResize =
@@ -131,9 +156,21 @@ export function ProductionListTable({ loading, data, refetch, bodyshop, technici
...nextColumns[index],
width: size.width
};
setColumns(nextColumns);
if (!_.isEqual(nextColumns, columns)) {
setColumns(nextColumns);
setHasUnsavedChanges(true);
}
};
const addColumn = (newColumn) => {
const updatedColumns = [...columns, newColumn];
if (!_.isEqual(updatedColumns, columns)) {
setColumns(updatedColumns);
setHasUnsavedChanges(true);
}
};
const headerItem = (col) => {
const menu = {
onClick: removeColumn,
@@ -152,29 +189,29 @@ export function ProductionListTable({ loading, data, refetch, bodyshop, technici
);
};
const dataSource =
searchText === ""
? data
: data.filter(
(j) =>
(j.ro_number || "").toString().toLowerCase().includes(searchText.toLowerCase()) ||
(j.ownr_co_nm || "").toLowerCase().includes(searchText.toLowerCase()) ||
(j.ownr_fn || "").toLowerCase().includes(searchText.toLowerCase()) ||
(j.ownr_ln || "").toLowerCase().includes(searchText.toLowerCase()) ||
(j.status || "").toLowerCase().includes(searchText.toLowerCase()) ||
(j.ins_co_nm || "").toLowerCase().includes(searchText.toLowerCase()) ||
(j.clm_no || "").toLowerCase().includes(searchText.toLowerCase()) ||
(j.v_model_desc || "").toLowerCase().includes(searchText.toLowerCase()) ||
(j.v_make_desc || "").toLowerCase().includes(searchText.toLowerCase())
);
const resetChanges = () => {
setState(initialStateRef.current);
setColumns(initialColumnsRef.current);
setHasUnsavedChanges(false);
};
// const handleSelectRecord = (record) => {
// if (selected !== record.id) {
// setSelected(record.id);
// } else {
// setSelected(null);
// }
// };
const filterData = (item, searchText) => {
const fieldsToSearch = [
item.ro_number,
item.ownr_co_nm,
item.ownr_fn,
item.ownr_ln,
item.status,
item.ins_co_nm,
item.clm_no,
item.v_model_desc,
item.v_make_desc
];
return fieldsToSearch.some((field) => (field || "").toString().toLowerCase().includes(searchText.toLowerCase()));
};
const dataSource = searchText === "" ? data : data.filter((j) => filterData(j, searchText));
if (!!!columns) return <div>No columns found.</div>;
@@ -186,8 +223,29 @@ export function ProductionListTable({ loading, data, refetch, bodyshop, technici
.toFixed(1);
const totalLAB = data.reduce((acc, val) => acc + (val.labhrs?.aggregate?.sum?.mod_lb_hrs || 0), 0).toFixed(1);
const totalLAR = data.reduce((acc, val) => acc + (val.larhrs?.aggregate?.sum?.mod_lb_hrs || 0), 0).toFixed(1);
return (
<div>
<Prompt when={hasUnsavedChanges} beforeUnload={true} message={t("general.messages.unsavedchangespopup")} />
{hasUnsavedChanges && (
<AlertComponent
type="warning"
message={
<div>
<span>{t("general.messages.unsavedchanges")} </span>
<span
onClick={resetChanges}
style={{
cursor: "pointer",
textDecoration: "underline"
}}
>
{t("general.actions.reset")}
</span>
</div>
}
/>
)}
<PageHeader
title={
<Space>
@@ -199,20 +257,37 @@ export function ProductionListTable({ loading, data, refetch, bodyshop, technici
}
extra={
<Space wrap>
<Button onClick={() => refetch && refetch()}>
<Button
onClick={() => {
refetch && refetch();
}}
>
<SyncOutlined />
</Button>
<ProductionListColumnsAdd columnState={[columns, setColumns]} tableState={state} data={data} />
<ProductionListSaveConfigButton columns={columns} tableState={state} />
<ProductionListColumnsAdd
columnState={[columns, setColumns]}
tableState={state}
data={data}
onColumnAdd={addColumn}
/>
<ProductionListSaveConfigButton
columns={columns}
tableState={state}
onSave={() => {
setHasUnsavedChanges(false);
}}
/>
<ProductionListTableViewSelect
state={state}
setState={setState}
setColumns={setColumns}
onProfileChange={() => {
initialStateRef.current = state;
setHasUnsavedChanges(false);
}}
refetch={refetch}
data={data}
/>
<Input
onChange={(e) => setSearchText(e.target.value)}
placeholder={t("general.labels.search")}

View File

@@ -1,7 +1,7 @@
import { gql } from "@apollo/client";
export const QUERY_ALL_ACTIVE_JOBS_PAGINATED = gql`
query QUERY_ALL_JOBS_PAGINATED_STATUS_FILTERED(
query QUERY_ALL_ACTIVE_JOBS_PAGINATED(
$offset: Int
$limit: Int
$order: [jobs_order_by!]

View File

@@ -2833,7 +2833,8 @@
"sublets": "Sublets",
"totalhours": "Total Hrs ",
"touchtime": "T/T",
"viewname": "View Name"
"viewname": "View Name",
"alerts": "Alerts"
},
"successes": {
"removed": "Job removed from production."

View File

@@ -2833,7 +2833,8 @@
"sublets": "",
"totalhours": "",
"touchtime": "",
"viewname": ""
"viewname": "",
"alerts": ""
},
"successes": {
"removed": ""

View File

@@ -2833,7 +2833,8 @@
"sublets": "",
"totalhours": "",
"touchtime": "",
"viewname": ""
"viewname": "",
"alerts": ""
},
"successes": {
"removed": ""

View File

@@ -1,36 +0,0 @@
export const BETA_KEY = "betaSwitchImex";
export const checkBeta = () => {
const cookie = document.cookie.split("; ").find((row) => row.startsWith(BETA_KEY));
return cookie ? cookie.split("=")[1] === "true" : false;
};
export const setBeta = (value) => {
const domain = window.location.hostname.split(".").slice(-2).join(".");
document.cookie = `${BETA_KEY}=${value}; path=/; domain=.${domain}`;
};
export const handleBeta = () => {
// If the current host name does not start with beta or test, then we don't need to do anything.
if (window.location.hostname.startsWith("localhost")) {
console.log("Not on beta or test, so no need to handle beta.");
return;
}
const isBeta = checkBeta();
const currentHostName = window.location.hostname;
// Beta is enabled, but the current host name does start with beta.
if (isBeta && !currentHostName.startsWith("beta")) {
const href = `${window.location.protocol}//beta.${currentHostName}${window.location.pathname}${window.location.search}${window.location.hash}`;
window.location.replace(href);
}
// Beta is not enabled, but the current host name does start with beta.
else if (!isBeta && currentHostName.startsWith("beta")) {
const href = `${window.location.protocol}//${currentHostName.replace("beta.", "")}${window.location.pathname}${window.location.search}${window.location.hash}`;
window.location.replace(href);
}
};
export default handleBeta;

View File

@@ -11,26 +11,37 @@ export const setBeta = (value) => {
};
export const handleBeta = () => {
// If the current host name does not start with beta or test, then we don't need to do anything.
if (window.location.hostname.startsWith("localhost")) {
console.log("Not on beta or test, so no need to handle beta.");
return;
}
const isBeta = checkBeta();
const currentHostName = window.location.hostname;
// Beta is enabled, but the current host name does start with beta.
if (isBeta && !currentHostName.startsWith("beta")) {
const href = `${window.location.protocol}//beta.${currentHostName}${window.location.pathname}${window.location.search}${window.location.hash}`;
window.location.replace(href);
}
// Determine if the host name starts with "beta" or "www.beta"
const isBetaHost = currentHostName.startsWith("beta.");
const isBetaHostWithWWW = currentHostName.startsWith("www.beta.");
// Beta is not enabled, but the current host name does start with beta.
else if (!isBeta && currentHostName.startsWith("beta")) {
const href = `${window.location.protocol}//${currentHostName.replace("beta.", "")}${window.location.pathname}${window.location.search}${window.location.hash}`;
window.location.replace(href);
if (isBeta) {
// If beta is on and we are not on a beta domain, redirect to the beta version
if (!isBetaHost && !isBetaHostWithWWW) {
const newHostName = currentHostName.startsWith("www.")
? `www.beta.${currentHostName.replace(/^www\./, "")}`
: `beta.${currentHostName}`;
const href = `${window.location.protocol}//${newHostName}${window.location.pathname}${window.location.search}${window.location.hash}`;
window.location.replace(href);
}
// Otherwise, if beta is on and we're already on a beta domain, stay there
} else {
// If beta is off and we are on a beta domain, redirect to the non-beta version
if (isBetaHost || isBetaHostWithWWW) {
const newHostName = currentHostName.replace(/^www\.beta\./, "www.").replace(/^beta\./, "");
const href = `${window.location.protocol}//${newHostName}${window.location.pathname}${window.location.search}${window.location.hash}`;
window.location.replace(href);
}
// Otherwise, if beta is off and we're not on a beta domain, stay there
}
};
export default handleBeta;

128
package-lock.json generated
View File

@@ -9,9 +9,9 @@
"version": "0.2.0",
"license": "UNLICENSED",
"dependencies": {
"@aws-sdk/client-secrets-manager": "^3.629.0",
"@aws-sdk/client-ses": "^3.629.0",
"@aws-sdk/credential-provider-node": "^3.629.0",
"@aws-sdk/client-secrets-manager": "^3.632.0",
"@aws-sdk/client-ses": "^3.632.0",
"@aws-sdk/credential-provider-node": "^3.632.0",
"@opensearch-project/opensearch": "^2.11.0",
"aws4": "^1.13.1",
"axios": "^1.7.4",
@@ -42,7 +42,7 @@
"node-mailjet": "^6.0.5",
"node-persist": "^4.0.3",
"nodemailer": "^6.9.14",
"phone": "^3.1.49",
"phone": "^3.1.50",
"recursive-diff": "^1.0.9",
"rimraf": "^6.0.1",
"soap": "^1.1.1",
@@ -180,24 +180,24 @@
}
},
"node_modules/@aws-sdk/client-secrets-manager": {
"version": "3.629.0",
"resolved": "https://registry.npmjs.org/@aws-sdk/client-secrets-manager/-/client-secrets-manager-3.629.0.tgz",
"integrity": "sha512-ZZKI9uTQ3WIdbCZK6sveccalLTWgyOZeebi+Gnwl5ztKMk4OfwZKxyhry1DXB8gMrlISniREDb3ZxUZdFNwqfQ==",
"version": "3.632.0",
"resolved": "https://registry.npmjs.org/@aws-sdk/client-secrets-manager/-/client-secrets-manager-3.632.0.tgz",
"integrity": "sha512-WsQhPHHK1yPfALcP1B7nBSGDzky6vFTUEXnUdfzb5Xy2cT+JTBTS6ChtQGqqOuGHDP/3t/9soqZ+L6rUCYBb/Q==",
"license": "Apache-2.0",
"dependencies": {
"@aws-crypto/sha256-browser": "5.2.0",
"@aws-crypto/sha256-js": "5.2.0",
"@aws-sdk/client-sso-oidc": "3.629.0",
"@aws-sdk/client-sts": "3.629.0",
"@aws-sdk/client-sso-oidc": "3.632.0",
"@aws-sdk/client-sts": "3.632.0",
"@aws-sdk/core": "3.629.0",
"@aws-sdk/credential-provider-node": "3.629.0",
"@aws-sdk/credential-provider-node": "3.632.0",
"@aws-sdk/middleware-host-header": "3.620.0",
"@aws-sdk/middleware-logger": "3.609.0",
"@aws-sdk/middleware-recursion-detection": "3.620.0",
"@aws-sdk/middleware-user-agent": "3.620.0",
"@aws-sdk/middleware-user-agent": "3.632.0",
"@aws-sdk/region-config-resolver": "3.614.0",
"@aws-sdk/types": "3.609.0",
"@aws-sdk/util-endpoints": "3.614.0",
"@aws-sdk/util-endpoints": "3.632.0",
"@aws-sdk/util-user-agent-browser": "3.609.0",
"@aws-sdk/util-user-agent-node": "3.614.0",
"@smithy/config-resolver": "^3.0.5",
@@ -245,24 +245,24 @@
}
},
"node_modules/@aws-sdk/client-ses": {
"version": "3.629.0",
"resolved": "https://registry.npmjs.org/@aws-sdk/client-ses/-/client-ses-3.629.0.tgz",
"integrity": "sha512-KreCdUAO/gIzWCgnPV1/dGUvLDDTdXI3fZzjjHUWFa1bE4wENjenNnWGw0qZgc8xB8pgiMdgPn7N+JvxJ7c/ZQ==",
"version": "3.632.0",
"resolved": "https://registry.npmjs.org/@aws-sdk/client-ses/-/client-ses-3.632.0.tgz",
"integrity": "sha512-hi01MPJF55LEK7NB1LZrqUV7b5GyjH08EToYuekFvQf9aNoR5mqWuMEDQ/dFAowYhUa2KqCdn67HnPn0ySQxHg==",
"license": "Apache-2.0",
"dependencies": {
"@aws-crypto/sha256-browser": "5.2.0",
"@aws-crypto/sha256-js": "5.2.0",
"@aws-sdk/client-sso-oidc": "3.629.0",
"@aws-sdk/client-sts": "3.629.0",
"@aws-sdk/client-sso-oidc": "3.632.0",
"@aws-sdk/client-sts": "3.632.0",
"@aws-sdk/core": "3.629.0",
"@aws-sdk/credential-provider-node": "3.629.0",
"@aws-sdk/credential-provider-node": "3.632.0",
"@aws-sdk/middleware-host-header": "3.620.0",
"@aws-sdk/middleware-logger": "3.609.0",
"@aws-sdk/middleware-recursion-detection": "3.620.0",
"@aws-sdk/middleware-user-agent": "3.620.0",
"@aws-sdk/middleware-user-agent": "3.632.0",
"@aws-sdk/region-config-resolver": "3.614.0",
"@aws-sdk/types": "3.609.0",
"@aws-sdk/util-endpoints": "3.614.0",
"@aws-sdk/util-endpoints": "3.632.0",
"@aws-sdk/util-user-agent-browser": "3.609.0",
"@aws-sdk/util-user-agent-node": "3.614.0",
"@smithy/config-resolver": "^3.0.5",
@@ -298,9 +298,9 @@
}
},
"node_modules/@aws-sdk/client-sso": {
"version": "3.629.0",
"resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.629.0.tgz",
"integrity": "sha512-2w8xU4O0Grca5HmT2dXZ5fF0g39RxODtmoqHJDsK5DSt750LqDG4w3ktmBvQs3+SrpkkJOjlX5v/hb2PCxVbww==",
"version": "3.632.0",
"resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.632.0.tgz",
"integrity": "sha512-iYWHiKBz44m3chCFvtvHnvCpL2rALzyr1e6tOZV3dLlOKtQtDUlPy6OtnXDu4y+wyJCniy8ivG3+LAe4klzn1Q==",
"license": "Apache-2.0",
"dependencies": {
"@aws-crypto/sha256-browser": "5.2.0",
@@ -309,10 +309,10 @@
"@aws-sdk/middleware-host-header": "3.620.0",
"@aws-sdk/middleware-logger": "3.609.0",
"@aws-sdk/middleware-recursion-detection": "3.620.0",
"@aws-sdk/middleware-user-agent": "3.620.0",
"@aws-sdk/middleware-user-agent": "3.632.0",
"@aws-sdk/region-config-resolver": "3.614.0",
"@aws-sdk/types": "3.609.0",
"@aws-sdk/util-endpoints": "3.614.0",
"@aws-sdk/util-endpoints": "3.632.0",
"@aws-sdk/util-user-agent-browser": "3.609.0",
"@aws-sdk/util-user-agent-node": "3.614.0",
"@smithy/config-resolver": "^3.0.5",
@@ -347,22 +347,22 @@
}
},
"node_modules/@aws-sdk/client-sso-oidc": {
"version": "3.629.0",
"resolved": "https://registry.npmjs.org/@aws-sdk/client-sso-oidc/-/client-sso-oidc-3.629.0.tgz",
"integrity": "sha512-3if0LauNJPqubGYf8vnlkp+B3yAeKRuRNxfNbHlE6l510xWGcKK/ZsEmiFmfePzKKSRrDh/cxMFMScgOrXptNg==",
"version": "3.632.0",
"resolved": "https://registry.npmjs.org/@aws-sdk/client-sso-oidc/-/client-sso-oidc-3.632.0.tgz",
"integrity": "sha512-Oh1fIWaoZluihOCb/zDEpRTi+6an82fgJz7fyRBugyLhEtDjmvpCQ3oKjzaOhoN+4EvXAm1ZS/ZgpvXBlIRTgw==",
"license": "Apache-2.0",
"dependencies": {
"@aws-crypto/sha256-browser": "5.2.0",
"@aws-crypto/sha256-js": "5.2.0",
"@aws-sdk/core": "3.629.0",
"@aws-sdk/credential-provider-node": "3.629.0",
"@aws-sdk/credential-provider-node": "3.632.0",
"@aws-sdk/middleware-host-header": "3.620.0",
"@aws-sdk/middleware-logger": "3.609.0",
"@aws-sdk/middleware-recursion-detection": "3.620.0",
"@aws-sdk/middleware-user-agent": "3.620.0",
"@aws-sdk/middleware-user-agent": "3.632.0",
"@aws-sdk/region-config-resolver": "3.614.0",
"@aws-sdk/types": "3.609.0",
"@aws-sdk/util-endpoints": "3.614.0",
"@aws-sdk/util-endpoints": "3.632.0",
"@aws-sdk/util-user-agent-browser": "3.609.0",
"@aws-sdk/util-user-agent-node": "3.614.0",
"@smithy/config-resolver": "^3.0.5",
@@ -396,27 +396,27 @@
"node": ">=16.0.0"
},
"peerDependencies": {
"@aws-sdk/client-sts": "^3.629.0"
"@aws-sdk/client-sts": "^3.632.0"
}
},
"node_modules/@aws-sdk/client-sts": {
"version": "3.629.0",
"resolved": "https://registry.npmjs.org/@aws-sdk/client-sts/-/client-sts-3.629.0.tgz",
"integrity": "sha512-RjOs371YwnSVGxhPjuluJKaxl4gcPYTAky0nPjwBime0i9/iS9nI8R8l5j7k7ec9tpFWjBPvNnThCU07pvjdzw==",
"version": "3.632.0",
"resolved": "https://registry.npmjs.org/@aws-sdk/client-sts/-/client-sts-3.632.0.tgz",
"integrity": "sha512-Ss5cBH09icpTvT+jtGGuQlRdwtO7RyE9BF4ZV/CEPATdd9whtJt4Qxdya8BUnkWR7h5HHTrQHqai3YVYjku41A==",
"license": "Apache-2.0",
"dependencies": {
"@aws-crypto/sha256-browser": "5.2.0",
"@aws-crypto/sha256-js": "5.2.0",
"@aws-sdk/client-sso-oidc": "3.629.0",
"@aws-sdk/client-sso-oidc": "3.632.0",
"@aws-sdk/core": "3.629.0",
"@aws-sdk/credential-provider-node": "3.629.0",
"@aws-sdk/credential-provider-node": "3.632.0",
"@aws-sdk/middleware-host-header": "3.620.0",
"@aws-sdk/middleware-logger": "3.609.0",
"@aws-sdk/middleware-recursion-detection": "3.620.0",
"@aws-sdk/middleware-user-agent": "3.620.0",
"@aws-sdk/middleware-user-agent": "3.632.0",
"@aws-sdk/region-config-resolver": "3.614.0",
"@aws-sdk/types": "3.609.0",
"@aws-sdk/util-endpoints": "3.614.0",
"@aws-sdk/util-endpoints": "3.632.0",
"@aws-sdk/util-user-agent-browser": "3.609.0",
"@aws-sdk/util-user-agent-node": "3.614.0",
"@smithy/config-resolver": "^3.0.5",
@@ -507,15 +507,15 @@
}
},
"node_modules/@aws-sdk/credential-provider-ini": {
"version": "3.629.0",
"resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.629.0.tgz",
"integrity": "sha512-r9fI7BABARvVDp77DBUImQzYdvarAIdhbvpCEZib0rlpvfWu3zxE9KZcapCAAi0MPjxeDfb7RMehFQIkAP7mYw==",
"version": "3.632.0",
"resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.632.0.tgz",
"integrity": "sha512-m6epoW41xa1ajU5OiHcmQHoGVtrbXBaRBOUhlCLZmcaqMLYsboM4iD/WZP8aatKEON5tTnVXh/4StV8D/+wemw==",
"license": "Apache-2.0",
"dependencies": {
"@aws-sdk/credential-provider-env": "3.620.1",
"@aws-sdk/credential-provider-http": "3.622.0",
"@aws-sdk/credential-provider-process": "3.620.1",
"@aws-sdk/credential-provider-sso": "3.629.0",
"@aws-sdk/credential-provider-sso": "3.632.0",
"@aws-sdk/credential-provider-web-identity": "3.621.0",
"@aws-sdk/types": "3.609.0",
"@smithy/credential-provider-imds": "^3.2.0",
@@ -528,20 +528,20 @@
"node": ">=16.0.0"
},
"peerDependencies": {
"@aws-sdk/client-sts": "^3.629.0"
"@aws-sdk/client-sts": "^3.632.0"
}
},
"node_modules/@aws-sdk/credential-provider-node": {
"version": "3.629.0",
"resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.629.0.tgz",
"integrity": "sha512-868hnVOLlXOBHk91Rl0jZIRgr/M4WJCa0nOrW9A9yidsQxuZp9P0vshDmm4hMvNZadmPIfo0Rra2MpA4RELoCw==",
"version": "3.632.0",
"resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.632.0.tgz",
"integrity": "sha512-cL8fuJWm/xQBO4XJPkeuZzl3XinIn9EExWgzpG48NRMKR5us1RI/ucv7xFbBBaG+r/sDR2HpYBIA3lVIpm1H3Q==",
"license": "Apache-2.0",
"dependencies": {
"@aws-sdk/credential-provider-env": "3.620.1",
"@aws-sdk/credential-provider-http": "3.622.0",
"@aws-sdk/credential-provider-ini": "3.629.0",
"@aws-sdk/credential-provider-ini": "3.632.0",
"@aws-sdk/credential-provider-process": "3.620.1",
"@aws-sdk/credential-provider-sso": "3.629.0",
"@aws-sdk/credential-provider-sso": "3.632.0",
"@aws-sdk/credential-provider-web-identity": "3.621.0",
"@aws-sdk/types": "3.609.0",
"@smithy/credential-provider-imds": "^3.2.0",
@@ -571,12 +571,12 @@
}
},
"node_modules/@aws-sdk/credential-provider-sso": {
"version": "3.629.0",
"resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.629.0.tgz",
"integrity": "sha512-Lf4XOuj6jamxgGZGrVojERh5S+NS2t2S4CUOnAu6tJ5U0GPlpjhINUKlcVxJBpsIXudMGW1nkumAd3+kazCPig==",
"version": "3.632.0",
"resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.632.0.tgz",
"integrity": "sha512-P/4wB6j7ym5QCPTL2xlMfvf2NcXSh+z0jmsZP4WW/tVwab4hvgabPPbLeEZDSWZ0BpgtxKGvRq0GSHuGeirQbA==",
"license": "Apache-2.0",
"dependencies": {
"@aws-sdk/client-sso": "3.629.0",
"@aws-sdk/client-sso": "3.632.0",
"@aws-sdk/token-providers": "3.614.0",
"@aws-sdk/types": "3.609.0",
"@smithy/property-provider": "^3.1.3",
@@ -650,13 +650,13 @@
}
},
"node_modules/@aws-sdk/middleware-user-agent": {
"version": "3.620.0",
"resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.620.0.tgz",
"integrity": "sha512-bvS6etn+KsuL32ubY5D3xNof1qkenpbJXf/ugGXbg0n98DvDFQ/F+SMLxHgbnER5dsKYchNnhmtI6/FC3HFu/A==",
"version": "3.632.0",
"resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.632.0.tgz",
"integrity": "sha512-yY/sFsHKwG9yzSf/DTclqWJaGPI2gPBJDCGBujSqTG1zlS7Ot4fqi91DZ6088BFWzbOorDzJFcAhAEFzc6LuQg==",
"license": "Apache-2.0",
"dependencies": {
"@aws-sdk/types": "3.609.0",
"@aws-sdk/util-endpoints": "3.614.0",
"@aws-sdk/util-endpoints": "3.632.0",
"@smithy/protocol-http": "^4.1.0",
"@smithy/types": "^3.3.0",
"tslib": "^2.6.2"
@@ -713,9 +713,10 @@
}
},
"node_modules/@aws-sdk/util-endpoints": {
"version": "3.614.0",
"resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.614.0.tgz",
"integrity": "sha512-wK2cdrXHH4oz4IomV/yrGkftU9A+ITB6nFL+rxxyO78is2ifHJpFdV4aqk4LSkXYPi6CXWNru/Dqc7yiKXgJPw==",
"version": "3.632.0",
"resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.632.0.tgz",
"integrity": "sha512-LlYMU8pAbcEQphOpE6xaNLJ8kPGhklZZTVzZVpVW477NaaGgoGTMYNXTABYHcxeF5E2lLrxql9OmVpvr8GWN8Q==",
"license": "Apache-2.0",
"dependencies": {
"@aws-sdk/types": "3.609.0",
"@smithy/types": "^3.3.0",
@@ -5797,9 +5798,10 @@
"integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ=="
},
"node_modules/phone": {
"version": "3.1.49",
"resolved": "https://registry.npmjs.org/phone/-/phone-3.1.49.tgz",
"integrity": "sha512-S+rHWXSQrllK5eQwz0sDbwfxQ2PzennWPgsP/jdpEPH3k7P5IBJZYjvYfU8e/RF5AwKCgOtzbTGTGJcBSLJVVw==",
"version": "3.1.50",
"resolved": "https://registry.npmjs.org/phone/-/phone-3.1.50.tgz",
"integrity": "sha512-TRmb2bX3sX+rrOrc8FRd8hmy4exoH2Lu3vjBP/dLgwwci1lv7DbjJ2iHMe7X4Hm8Pa0rJcfqTbq/O1vjU4NgxQ==",
"license": "MIT",
"engines": {
"node": ">=12"
}

View File

@@ -19,9 +19,9 @@
"makeitpretty": "prettier --write \"**/*.{css,js,json,jsx,scss}\""
},
"dependencies": {
"@aws-sdk/client-secrets-manager": "^3.629.0",
"@aws-sdk/client-ses": "^3.629.0",
"@aws-sdk/credential-provider-node": "^3.629.0",
"@aws-sdk/client-secrets-manager": "^3.632.0",
"@aws-sdk/client-ses": "^3.632.0",
"@aws-sdk/credential-provider-node": "^3.632.0",
"@opensearch-project/opensearch": "^2.11.0",
"aws4": "^1.13.1",
"axios": "^1.7.4",
@@ -52,7 +52,7 @@
"node-mailjet": "^6.0.5",
"node-persist": "^4.0.3",
"nodemailer": "^6.9.14",
"phone": "^3.1.49",
"phone": "^3.1.50",
"recursive-diff": "^1.0.9",
"rimraf": "^6.0.1",
"soap": "^1.1.1",

View File

@@ -30,8 +30,14 @@ exports.default = function ({ bodyshop, jobs_by_pk, qbo = false, items, taxCodes
if (jobline.db_ref === "936007") {
hasMashLine = true;
}
//Check if the line is a Towing Line and flag as such.
let isTowingLine = false;
if (jobline.db_ref === "936001" && jobline.line_desc.includes("Towing")) {
isTowingLine = true;
}
//Parts Lines Mappings.
if (jobline.profitcenter_part) {
if (!isTowingLine && jobline.profitcenter_part) {
//TODO:AIO This appears to be a net 0 change exept for default quantity as 0 instead of 1 for imex. Need to verify.
const discountAmount =
((jobline.prt_dsmk_m && jobline.prt_dsmk_m !== 0) || (jobline.prt_dsmk_p && jobline.prt_dsmk_p !== 0)) &&