- Merge client update into test-beta
Signed-off-by: Dave Richer <dave@imexsystems.ca>
This commit is contained in:
@@ -183,6 +183,26 @@ jobs:
|
|||||||
- jira/notify
|
- jira/notify
|
||||||
|
|
||||||
|
|
||||||
|
app-beta-build:
|
||||||
|
docker:
|
||||||
|
- image: cimg/node:18.18.2
|
||||||
|
resource_class: large
|
||||||
|
working_directory: ~/repo/client
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- checkout:
|
||||||
|
path: ~/repo
|
||||||
|
- run:
|
||||||
|
name: Install Dependencies
|
||||||
|
command: npm i
|
||||||
|
|
||||||
|
- run: npm run build
|
||||||
|
|
||||||
|
- aws-s3/sync:
|
||||||
|
from: build
|
||||||
|
to: "s3://imex-online-beta/"
|
||||||
|
- jira/notify
|
||||||
|
|
||||||
test-hasura-migrate:
|
test-hasura-migrate:
|
||||||
docker:
|
docker:
|
||||||
- image: cimg/node:16.15.0
|
- image: cimg/node:16.15.0
|
||||||
@@ -233,6 +253,27 @@ jobs:
|
|||||||
to: "s3://imex-online-test/"
|
to: "s3://imex-online-test/"
|
||||||
- jira/notify
|
- jira/notify
|
||||||
|
|
||||||
|
test-app-beta-build:
|
||||||
|
docker:
|
||||||
|
- image: cimg/node:18.18.2
|
||||||
|
resource_class: large
|
||||||
|
working_directory: ~/repo/client
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- checkout:
|
||||||
|
path: ~/repo
|
||||||
|
|
||||||
|
- run:
|
||||||
|
name: Install Dependencies
|
||||||
|
command: npm i
|
||||||
|
|
||||||
|
- run: npm run build:test
|
||||||
|
|
||||||
|
- aws-s3/sync:
|
||||||
|
from: build
|
||||||
|
to: "s3://imex-online-test-beta/"
|
||||||
|
- jira/notify
|
||||||
|
|
||||||
admin-app-build:
|
admin-app-build:
|
||||||
docker:
|
docker:
|
||||||
- image: cimg/node:16.15.0
|
- image: cimg/node:16.15.0
|
||||||
@@ -274,6 +315,10 @@ workflows:
|
|||||||
filters:
|
filters:
|
||||||
branches:
|
branches:
|
||||||
only: master
|
only: master
|
||||||
|
- app-beta-build:
|
||||||
|
filters:
|
||||||
|
branches:
|
||||||
|
only: master-beta
|
||||||
- hasura-migrate:
|
- hasura-migrate:
|
||||||
secret: ${HASURA_PROD_SECRET}
|
secret: ${HASURA_PROD_SECRET}
|
||||||
filters:
|
filters:
|
||||||
@@ -296,6 +341,10 @@ workflows:
|
|||||||
filters:
|
filters:
|
||||||
branches:
|
branches:
|
||||||
only: test
|
only: test
|
||||||
|
- test-app-beta-build:
|
||||||
|
filters:
|
||||||
|
branches:
|
||||||
|
only: test-beta
|
||||||
- test-hasura-migrate:
|
- test-hasura-migrate:
|
||||||
secret: ${HASURA_TEST_SECRET}
|
secret: ${HASURA_TEST_SECRET}
|
||||||
filters:
|
filters:
|
||||||
|
|||||||
1
client/.npmrc
Normal file
1
client/.npmrc
Normal file
@@ -0,0 +1 @@
|
|||||||
|
legacy-peer-deps=true
|
||||||
@@ -2,6 +2,14 @@
|
|||||||
const TerserPlugin = require("terser-webpack-plugin");
|
const TerserPlugin = require("terser-webpack-plugin");
|
||||||
const CracoLessPlugin = require("craco-less");
|
const CracoLessPlugin = require("craco-less");
|
||||||
const SentryWebpackPlugin = require("@sentry/webpack-plugin");
|
const SentryWebpackPlugin = require("@sentry/webpack-plugin");
|
||||||
|
const {convertLegacyToken} = require('@ant-design/compatible/lib');
|
||||||
|
const {theme} = require('antd/lib');
|
||||||
|
|
||||||
|
const {defaultAlgorithm, defaultSeed} = theme;
|
||||||
|
|
||||||
|
const mapToken = defaultAlgorithm(defaultSeed);
|
||||||
|
const v4Token = convertLegacyToken(mapToken);
|
||||||
|
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
plugins: [
|
plugins: [
|
||||||
@@ -26,8 +34,10 @@ module.exports = {
|
|||||||
lessLoaderOptions: {
|
lessLoaderOptions: {
|
||||||
lessOptions: {
|
lessOptions: {
|
||||||
modifyVars: {
|
modifyVars: {
|
||||||
|
...v4Token,
|
||||||
|
// TODO: This will no longer work in AntD 5.0
|
||||||
...(process.env.NODE_ENV === "development"
|
...(process.env.NODE_ENV === "development"
|
||||||
? { "@primary-color": "#B22234" }
|
? {"colorPrimary": "#B22234"}
|
||||||
: {
|
: {
|
||||||
//"@primary-color": "#1DA57A"
|
//"@primary-color": "#1DA57A"
|
||||||
}),
|
}),
|
||||||
@@ -53,8 +63,14 @@ module.exports = {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
webpack: {
|
webpack: {
|
||||||
configure: (webpackConfig) => ({
|
configure: (webpackConfig) => {
|
||||||
|
return {
|
||||||
...webpackConfig,
|
...webpackConfig,
|
||||||
|
// Required for Dev Server
|
||||||
|
devServer: {
|
||||||
|
...webpackConfig.devServer,
|
||||||
|
allowedHosts: 'all',
|
||||||
|
},
|
||||||
optimization: {
|
optimization: {
|
||||||
...webpackConfig.optimization,
|
...webpackConfig.optimization,
|
||||||
// Workaround for CircleCI bug caused by the number of CPUs shown
|
// Workaround for CircleCI bug caused by the number of CPUs shown
|
||||||
@@ -67,7 +83,8 @@ module.exports = {
|
|||||||
return item;
|
return item;
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
}),
|
};
|
||||||
|
},
|
||||||
},
|
},
|
||||||
devtool: "source-map",
|
devtool: "source-map",
|
||||||
};
|
};
|
||||||
|
|||||||
17
client/cypress.config.js
Normal file
17
client/cypress.config.js
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
const { defineConfig } = require('cypress')
|
||||||
|
|
||||||
|
module.exports = defineConfig({
|
||||||
|
experimentalStudio: true,
|
||||||
|
env: {
|
||||||
|
FIREBASE_USERNAME: 'cypress@imex.test',
|
||||||
|
FIREBASE_PASSWORD: 'cypress',
|
||||||
|
},
|
||||||
|
e2e: {
|
||||||
|
// We've imported your old cypress plugins here.
|
||||||
|
// You may want to clean this up later by importing these.
|
||||||
|
setupNodeEvents(on, config) {
|
||||||
|
return require('./cypress/plugins/index.js')(on, config)
|
||||||
|
},
|
||||||
|
baseUrl: 'http://localhost:3000',
|
||||||
|
},
|
||||||
|
})
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
{
|
|
||||||
"baseUrl": "http://localhost:3000",
|
|
||||||
"experimentalStudio": true,
|
|
||||||
"env": {
|
|
||||||
"FIREBASE_USERNAME": "cypress@imex.test",
|
|
||||||
"FIREBASE_PASSWORD": "cypress"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -8872,13 +8872,13 @@
|
|||||||
│ ├─ email: luis@luisrudge.net
|
│ ├─ email: luis@luisrudge.net
|
||||||
│ ├─ path: /Users/pfic/Documents/Development/bodyshop/client/node_modules/postcss-flexbugs-fixes
|
│ ├─ path: /Users/pfic/Documents/Development/bodyshop/client/node_modules/postcss-flexbugs-fixes
|
||||||
│ └─ licenseFile: /Users/pfic/Documents/Development/bodyshop/client/node_modules/postcss-flexbugs-fixes/LICENSE
|
│ └─ licenseFile: /Users/pfic/Documents/Development/bodyshop/client/node_modules/postcss-flexbugs-fixes/LICENSE
|
||||||
├─ postcss-focus-visible@4.0.0
|
├─ postcss-focus-open@4.0.0
|
||||||
│ ├─ licenses: CC0-1.0
|
│ ├─ licenses: CC0-1.0
|
||||||
│ ├─ repository: https://github.com/jonathantneal/postcss-focus-visible
|
│ ├─ repository: https://github.com/jonathantneal/postcss-focus-open
|
||||||
│ ├─ publisher: Jonathan Neal
|
│ ├─ publisher: Jonathan Neal
|
||||||
│ ├─ email: jonathantneal@hotmail.com
|
│ ├─ email: jonathantneal@hotmail.com
|
||||||
│ ├─ path: /Users/pfic/Documents/Development/bodyshop/client/node_modules/postcss-focus-visible
|
│ ├─ path: /Users/pfic/Documents/Development/bodyshop/client/node_modules/postcss-focus-open
|
||||||
│ └─ licenseFile: /Users/pfic/Documents/Development/bodyshop/client/node_modules/postcss-focus-visible/LICENSE.md
|
│ └─ licenseFile: /Users/pfic/Documents/Development/bodyshop/client/node_modules/postcss-focus-open/LICENSE.md
|
||||||
├─ postcss-focus-within@3.0.0
|
├─ postcss-focus-within@3.0.0
|
||||||
│ ├─ licenses: CC0-1.0
|
│ ├─ licenses: CC0-1.0
|
||||||
│ ├─ repository: https://github.com/jonathantneal/postcss-focus-within
|
│ ├─ repository: https://github.com/jonathantneal/postcss-focus-within
|
||||||
|
|||||||
15965
client/package-lock.json
generated
15965
client/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -4,85 +4,83 @@
|
|||||||
"private": true,
|
"private": true,
|
||||||
"proxy": "http://localhost:4000",
|
"proxy": "http://localhost:4000",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@apollo/client": "^3.7.9",
|
"@ant-design/compatible": "^5.1.2",
|
||||||
|
"@ant-design/pro-layout": "^7.17.16",
|
||||||
|
"@apollo/client": "^3.8.10",
|
||||||
"@asseinfo/react-kanban": "^2.2.0",
|
"@asseinfo/react-kanban": "^2.2.0",
|
||||||
"@craco/craco": "^7.0.0",
|
"@craco/craco": "^7.1.0",
|
||||||
"@fingerprintjs/fingerprintjs": "^3.4.2",
|
"@fingerprintjs/fingerprintjs": "^4.2.1",
|
||||||
"@jsreport/browser-client": "^3.1.0",
|
"@jsreport/browser-client": "^3.1.0",
|
||||||
"@sentry/react": "^7.40.0",
|
"@reduxjs/toolkit": "^2.0.1",
|
||||||
"@sentry/tracing": "^7.40.0",
|
"@sentry/react": "^7.93.0",
|
||||||
"@splitsoftware/splitio-react": "^1.8.1",
|
"@sentry/tracing": "^7.93.0",
|
||||||
"@tanem/react-nprogress": "^5.0.8",
|
"@splitsoftware/splitio-react": "^1.11.0",
|
||||||
"antd": "^4.24.8",
|
"@tanem/react-nprogress": "^5.0.51",
|
||||||
|
"antd": "^5.12.8",
|
||||||
"apollo-link-logger": "^2.0.1",
|
"apollo-link-logger": "^2.0.1",
|
||||||
"axios": "^1.3.4",
|
"axios": "^1.6.5",
|
||||||
"craco-less": "^2.0.0",
|
"craco-less": "^3.0.1",
|
||||||
|
"dayjs": "^1.11.10",
|
||||||
|
"dayjs-business-days2": "^1.2.2",
|
||||||
"dinero.js": "^1.9.1",
|
"dinero.js": "^1.9.1",
|
||||||
"dotenv": "^16.0.1",
|
"dotenv": "^16.3.1",
|
||||||
"enquire-js": "^0.2.1",
|
"enquire-js": "^0.2.1",
|
||||||
"env-cmd": "^10.1.0",
|
"env-cmd": "^10.1.0",
|
||||||
"exifr": "^7.1.3",
|
"exifr": "^7.1.3",
|
||||||
"firebase": "^9.17.1",
|
"firebase": "^10.7.2",
|
||||||
"graphql": "^16.6.0",
|
"graphql": "^16.6.0",
|
||||||
"i18next": "^22.4.10",
|
"i18next": "^23.7.16",
|
||||||
"i18next-browser-languagedetector": "^7.0.1",
|
"i18next-browser-languagedetector": "^7.0.2",
|
||||||
"jsoneditor": "^9.9.0",
|
"jsoneditor": "^10.0.0",
|
||||||
"jsreport-browser-client-dist": "^1.3.0",
|
"jsreport-browser-client-dist": "^1.3.0",
|
||||||
"libphonenumber-js": "^1.10.21",
|
"libphonenumber-js": "^1.10.53",
|
||||||
"logrocket": "^3.0.1",
|
"logrocket": "^7.0.0",
|
||||||
"markerjs2": "^2.28.1",
|
"markerjs2": "^2.31.4",
|
||||||
"moment-business-days": "^1.2.0",
|
|
||||||
"moment-timezone": "^0.5.41",
|
|
||||||
"normalize-url": "^8.0.0",
|
"normalize-url": "^8.0.0",
|
||||||
"phone": "^3.1.35",
|
"phone": "^3.1.42",
|
||||||
"preval.macro": "^5.0.0",
|
"preval.macro": "^5.0.0",
|
||||||
"prop-types": "^15.8.1",
|
"prop-types": "^15.8.1",
|
||||||
"query-string": "^7.1.3",
|
"query-string": "^8.1.0",
|
||||||
"rc-queue-anim": "^2.0.0",
|
"rc-queue-anim": "^2.0.0",
|
||||||
"rc-scroll-anim": "^2.7.6",
|
"rc-scroll-anim": "^2.7.6",
|
||||||
"react": "^17.0.2",
|
"react": "^18.2.0",
|
||||||
"react-big-calendar": "^1.6.8",
|
"react-big-calendar": "^1.8.6",
|
||||||
"react-color": "^2.19.3",
|
"react-color": "^2.19.3",
|
||||||
"react-cookie": "^4.1.1",
|
"react-cookie": "^7.0.1",
|
||||||
"react-dom": "^17.0.2",
|
"react-dom": "^18.2.0",
|
||||||
"react-drag-listview": "^0.2.1",
|
"react-drag-listview": "^2.0.0",
|
||||||
"react-grid-gallery": "^1.0.0",
|
"react-grid-gallery": "^1.0.0",
|
||||||
"react-grid-layout": "^1.3.4",
|
"react-grid-layout": "1.3.4",
|
||||||
"react-i18next": "^12.2.0",
|
"react-i18next": "^14.0.0",
|
||||||
"react-icons": "^4.7.1",
|
"react-icons": "^5.0.1",
|
||||||
"react-image-lightbox": "^5.1.4",
|
"react-image-lightbox": "^5.1.4",
|
||||||
"react-intersection-observer": "^9.4.3",
|
"react-intersection-observer": "^9.5.3",
|
||||||
"react-number-format": "^5.1.3",
|
"react-number-format": "^5.1.4",
|
||||||
"react-redux": "^8.0.5",
|
"react-redux": "^9.1.0",
|
||||||
"react-resizable": "^3.0.4",
|
"react-resizable": "^3.0.5",
|
||||||
"react-router-dom": "^5.3.0",
|
"react-router-dom": "^6.21.3",
|
||||||
"react-scripts": "^5.0.1",
|
"react-scripts": "^5.0.1",
|
||||||
"react-sticky": "^6.0.3",
|
"react-sticky": "^6.0.3",
|
||||||
"react-sublime-video": "^0.2.5",
|
"react-sublime-video": "^0.2.5",
|
||||||
"react-virtualized": "^9.22.3",
|
"react-virtualized": "^9.22.5",
|
||||||
"recharts": "^2.4.3",
|
"recharts": "^2.10.4",
|
||||||
"redux": "^4.2.1",
|
"redux": "^5.0.1",
|
||||||
"redux-persist": "^6.0.0",
|
"redux-persist": "^6.0.0",
|
||||||
"redux-saga": "^1.2.2",
|
"redux-saga": "^1.3.0",
|
||||||
"redux-state-sync": "^3.1.4",
|
"redux-state-sync": "^3.1.4",
|
||||||
"reselect": "^4.1.7",
|
"reselect": "^5.1.0",
|
||||||
"sass": "^1.58.3",
|
"sass": "^1.70.0",
|
||||||
"socket.io-client": "^4.6.1",
|
"socket.io-client": "^4.7.4",
|
||||||
"styled-components": "^5.3.6",
|
"styled-components": "^6.1.8",
|
||||||
"subscriptions-transport-ws": "^0.11.0",
|
"subscriptions-transport-ws": "^0.11.0",
|
||||||
"web-vitals": "^2.1.4",
|
"terser-webpack-plugin": "^5.3.10",
|
||||||
"workbox-background-sync": "^6.5.3",
|
"web-vitals": "^3.5.1",
|
||||||
"workbox-broadcast-update": "^6.5.3",
|
"workbox-core": "^7.0.0",
|
||||||
"workbox-cacheable-response": "^6.5.3",
|
"workbox-expiration": "^7.0.0",
|
||||||
"workbox-core": "^6.5.3",
|
"workbox-navigation-preload": "^7.0.0",
|
||||||
"workbox-expiration": "^6.5.3",
|
"workbox-precaching": "^7.0.0",
|
||||||
"workbox-google-analytics": "^6.5.3",
|
"workbox-routing": "^7.0.0",
|
||||||
"workbox-navigation-preload": "^6.5.3",
|
"workbox-strategies": "^7.0.0",
|
||||||
"workbox-precaching": "^6.5.3",
|
|
||||||
"workbox-range-requests": "^6.5.3",
|
|
||||||
"workbox-routing": "^6.5.3",
|
|
||||||
"workbox-strategies": "^6.5.3",
|
|
||||||
"workbox-streams": "^6.5.3",
|
|
||||||
"yauzl": "^2.10.0"
|
"yauzl": "^2.10.0"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
@@ -119,12 +117,13 @@
|
|||||||
"react-error-overlay": "6.0.9"
|
"react-error-overlay": "6.0.9"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@sentry/webpack-plugin": "^1.20.0",
|
"@babel/plugin-proposal-private-property-in-object": "^7.21.11",
|
||||||
"@testing-library/cypress": "^8.0.3",
|
"@sentry/webpack-plugin": "^2.10.2",
|
||||||
"cypress": "^10.3.1",
|
"@testing-library/cypress": "^10.0.1",
|
||||||
"eslint-plugin-cypress": "^2.12.1",
|
"cypress": "^13.6.3",
|
||||||
|
"eslint-plugin-cypress": "^2.15.1",
|
||||||
"react-error-overlay": "6.0.11",
|
"react-error-overlay": "6.0.11",
|
||||||
"redux-logger": "^3.0.6",
|
"redux-logger": "^3.0.6",
|
||||||
"source-map-explorer": "^2.5.2"
|
"source-map-explorer": "^2.5.3"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -190,7 +190,7 @@ This package contains the following license and notice below:
|
|||||||
# @firebase/logger
|
# @firebase/logger
|
||||||
|
|
||||||
This package serves as the base of all logging in the JS SDK. Any logging that
|
This package serves as the base of all logging in the JS SDK. Any logging that
|
||||||
is intended to be visible to Firebase end developers should go through this
|
is intended to be open to Firebase end developers should go through this
|
||||||
module.
|
module.
|
||||||
|
|
||||||
## Basic Usage
|
## Basic Usage
|
||||||
@@ -9375,7 +9375,7 @@ parties to make or receive copies. Mere interaction with a user through
|
|||||||
a computer network, with no transfer of a copy, is not conveying.
|
a computer network, with no transfer of a copy, is not conveying.
|
||||||
|
|
||||||
An interactive user interface displays "Appropriate Legal Notices"
|
An interactive user interface displays "Appropriate Legal Notices"
|
||||||
to the extent that it includes a convenient and prominently visible
|
to the extent that it includes a convenient and prominently open
|
||||||
feature that (1) displays an appropriate copyright notice, and (2)
|
feature that (1) displays an appropriate copyright notice, and (2)
|
||||||
tells the user that there is no warranty for the work (except to the
|
tells the user that there is no warranty for the work (except to the
|
||||||
extent that warranties are provided), that licensees may convey the
|
extent that warranties are provided), that licensees may convey the
|
||||||
|
|||||||
@@ -1029,7 +1029,7 @@ The following NPM packages may be included in this product:
|
|||||||
- postcss-dir-pseudo-class@5.0.0
|
- postcss-dir-pseudo-class@5.0.0
|
||||||
- postcss-double-position-gradients@1.0.0
|
- postcss-double-position-gradients@1.0.0
|
||||||
- postcss-env-function@2.0.2
|
- postcss-env-function@2.0.2
|
||||||
- postcss-focus-visible@4.0.0
|
- postcss-focus-open@4.0.0
|
||||||
- postcss-focus-within@3.0.0
|
- postcss-focus-within@3.0.0
|
||||||
- postcss-gap-properties@2.0.0
|
- postcss-gap-properties@2.0.0
|
||||||
- postcss-image-set-function@3.0.1
|
- postcss-image-set-function@3.0.1
|
||||||
@@ -1699,7 +1699,7 @@ This package contains the following license and notice below:
|
|||||||
# @firebase/logger
|
# @firebase/logger
|
||||||
|
|
||||||
This package serves as the base of all logging in the JS SDK. Any logging that
|
This package serves as the base of all logging in the JS SDK. Any logging that
|
||||||
is intended to be visible to Firebase end developers should go through this
|
is intended to be open to Firebase end developers should go through this
|
||||||
module.
|
module.
|
||||||
|
|
||||||
## Basic Usage
|
## Basic Usage
|
||||||
@@ -24029,7 +24029,7 @@ parties to make or receive copies. Mere interaction with a user through
|
|||||||
a computer network, with no transfer of a copy, is not conveying.
|
a computer network, with no transfer of a copy, is not conveying.
|
||||||
|
|
||||||
An interactive user interface displays "Appropriate Legal Notices"
|
An interactive user interface displays "Appropriate Legal Notices"
|
||||||
to the extent that it includes a convenient and prominently visible
|
to the extent that it includes a convenient and prominently open
|
||||||
feature that (1) displays an appropriate copyright notice, and (2)
|
feature that (1) displays an appropriate copyright notice, and (2)
|
||||||
tells the user that there is no warranty for the work (except to the
|
tells the user that there is no warranty for the work (except to the
|
||||||
extent that warranties are provided), that licensees may convey the
|
extent that warranties are provided), that licensees may convey the
|
||||||
|
|||||||
@@ -2,14 +2,15 @@ import { ApolloProvider } from "@apollo/client";
|
|||||||
import { SplitFactory, SplitSdk } from "@splitsoftware/splitio-react";
|
import { SplitFactory, SplitSdk } from "@splitsoftware/splitio-react";
|
||||||
import { ConfigProvider } from "antd";
|
import { ConfigProvider } from "antd";
|
||||||
import enLocale from "antd/es/locale/en_US";
|
import enLocale from "antd/es/locale/en_US";
|
||||||
import moment from "moment";
|
import dayjs from "../utils/day";
|
||||||
|
import 'dayjs/locale/en';
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import GlobalLoadingBar from "../components/global-loading-bar/global-loading-bar.component";
|
import GlobalLoadingBar from "../components/global-loading-bar/global-loading-bar.component";
|
||||||
import client from "../utils/GraphQLClient";
|
import client from "../utils/GraphQLClient";
|
||||||
import App from "./App";
|
import App from "./App";
|
||||||
|
|
||||||
moment.locale("en-US");
|
dayjs.locale("en");
|
||||||
|
|
||||||
export const factory = SplitSdk({
|
export const factory = SplitSdk({
|
||||||
core: {
|
core: {
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
import { useClient } from "@splitsoftware/splitio-react";
|
import {useSplitClient} from "@splitsoftware/splitio-react";
|
||||||
import {Button, Result} from "antd";
|
import {Button, Result} from "antd";
|
||||||
import LogRocket from "logrocket";
|
import LogRocket from "logrocket";
|
||||||
import React, { lazy, Suspense, useEffect } from "react";
|
import React, {lazy, Suspense, useEffect, useState} from "react";
|
||||||
import {useTranslation} from "react-i18next";
|
import {useTranslation} from "react-i18next";
|
||||||
import {connect} from "react-redux";
|
import {connect} from "react-redux";
|
||||||
import { Route, Switch } from "react-router-dom";
|
import {Route, Routes} from "react-router-dom";
|
||||||
import {createStructuredSelector} from "reselect";
|
import {createStructuredSelector} from "reselect";
|
||||||
import DocumentEditorContainer from "../components/document-editor/document-editor.container";
|
import DocumentEditorContainer from "../components/document-editor/document-editor.container";
|
||||||
import ErrorBoundary from "../components/error-boundary/error-boundary.component";
|
import ErrorBoundary from "../components/error-boundary/error-boundary.component";
|
||||||
@@ -16,12 +16,10 @@ import TechPageContainer from "../pages/tech/tech.page.container";
|
|||||||
import {setOnline} from "../redux/application/application.actions";
|
import {setOnline} from "../redux/application/application.actions";
|
||||||
import {selectOnline} from "../redux/application/application.selectors";
|
import {selectOnline} from "../redux/application/application.selectors";
|
||||||
import {checkUserSession} from "../redux/user/user.actions";
|
import {checkUserSession} from "../redux/user/user.actions";
|
||||||
import {
|
import {selectBodyshop, selectCurrentUser,} from "../redux/user/user.selectors";
|
||||||
selectBodyshop,
|
import PrivateRoute from "../components/PrivateRoute";
|
||||||
selectCurrentUser,
|
|
||||||
} from "../redux/user/user.selectors";
|
|
||||||
import PrivateRoute from "../utils/private-route";
|
|
||||||
import "./App.styles.scss";
|
import "./App.styles.scss";
|
||||||
|
import handleBeta from "../utils/betaHandler";
|
||||||
|
|
||||||
const ResetPassword = lazy(() =>
|
const ResetPassword = lazy(() =>
|
||||||
import("../pages/reset-password/reset-password.component")
|
import("../pages/reset-password/reset-password.component")
|
||||||
@@ -33,7 +31,6 @@ const CsiPage = lazy(() => import("../pages/csi/csi.container.page"));
|
|||||||
const MobilePaymentContainer = lazy(() =>
|
const MobilePaymentContainer = lazy(() =>
|
||||||
import("../pages/mobile-payment/mobile-payment.container")
|
import("../pages/mobile-payment/mobile-payment.container")
|
||||||
);
|
);
|
||||||
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
currentUser: selectCurrentUser,
|
currentUser: selectCurrentUser,
|
||||||
online: selectOnline,
|
online: selectOnline,
|
||||||
@@ -44,14 +41,12 @@ const mapDispatchToProps = (dispatch) => ({
|
|||||||
setOnline: (isOnline) => dispatch(setOnline(isOnline)),
|
setOnline: (isOnline) => dispatch(setOnline(isOnline)),
|
||||||
});
|
});
|
||||||
|
|
||||||
export function App({
|
export function App({bodyshop, checkUserSession, currentUser, online, setOnline}) {
|
||||||
bodyshop,
|
|
||||||
checkUserSession,
|
const client = useSplitClient().client;
|
||||||
currentUser,
|
const [listenersAdded, setListenersAdded] = useState(false)
|
||||||
online,
|
const {t} = useTranslation();
|
||||||
setOnline,
|
|
||||||
}) {
|
|
||||||
const client = useClient();
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!navigator.onLine) {
|
if (!navigator.onLine) {
|
||||||
@@ -64,21 +59,38 @@ export function App({
|
|||||||
//const b = Grid.useBreakpoint();
|
//const b = Grid.useBreakpoint();
|
||||||
// console.log("Breakpoints:", b);
|
// console.log("Breakpoints:", b);
|
||||||
|
|
||||||
const { t } = useTranslation();
|
// Associate event listeners, memoize to prevent multiple listeners being added
|
||||||
|
useEffect(() => {
|
||||||
window.addEventListener("offline", function (e) {
|
const offlineListener = (e) => {
|
||||||
setOnline(false);
|
setOnline(false);
|
||||||
});
|
}
|
||||||
|
|
||||||
window.addEventListener("online", function (e) {
|
const onlineListener = (e) => {
|
||||||
setOnline(true);
|
setOnline(true);
|
||||||
});
|
}
|
||||||
|
|
||||||
|
if (!listenersAdded) {
|
||||||
|
console.log('Added events for offline and online');
|
||||||
|
window.addEventListener("offline", offlineListener);
|
||||||
|
window.addEventListener("online", onlineListener);
|
||||||
|
setListenersAdded(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
window.removeEventListener("offline", offlineListener);
|
||||||
|
window.removeEventListener("online", onlineListener);
|
||||||
|
}
|
||||||
|
}, [setOnline, listenersAdded]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (currentUser.authorized && bodyshop) {
|
if (currentUser.authorized && bodyshop) {
|
||||||
client.setAttribute("imexshopid", bodyshop.imexshopid);
|
client.setAttribute("imexshopid", bodyshop.imexshopid);
|
||||||
|
|
||||||
LogRocket.init("rome-online/rome-online");
|
if (
|
||||||
if (client.getTreatment("LogRocket_Tracking") === "on") {
|
client.getTreatment("LogRocket_Tracking") === "on" ||
|
||||||
|
window.location.hostname === 'beta.romeonline.io'
|
||||||
|
) {
|
||||||
|
console.log("LR Start");
|
||||||
LogRocket.init("rome-online/rome-online");
|
LogRocket.init("rome-online/rome-online");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -88,6 +100,8 @@ export function App({
|
|||||||
return <LoadingSpinner message={t("general.labels.loggingin")}/>;
|
return <LoadingSpinner message={t("general.labels.loggingin")}/>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
handleBeta();
|
||||||
|
|
||||||
if (!online)
|
if (!online)
|
||||||
return (
|
return (
|
||||||
<Result
|
<Result
|
||||||
@@ -107,54 +121,27 @@ export function App({
|
|||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Any route that is not assigned and matched will default to the Landing Page component
|
||||||
return (
|
return (
|
||||||
<Switch>
|
<Suspense fallback={<LoadingSpinner message="Rome Online"/>}>
|
||||||
<Suspense fallback={<LoadingSpinner />}>
|
<Routes>
|
||||||
<ErrorBoundary>
|
<Route path="*" element={<ErrorBoundary><LandingPage/></ErrorBoundary>}/>
|
||||||
<Route exact path="/" component={LandingPage} />
|
<Route path="/signin" element={<ErrorBoundary><SignInPage/></ErrorBoundary>}/>
|
||||||
</ErrorBoundary>
|
<Route path="/resetpassword" element={<ErrorBoundary><ResetPassword/></ErrorBoundary>}/>
|
||||||
<ErrorBoundary>
|
<Route path="/csi/:surveyId" element={<ErrorBoundary><CsiPage/></ErrorBoundary>}/>
|
||||||
<Route exact path="/signin" component={SignInPage} />
|
<Route path="/disclaimer" element={<ErrorBoundary><DisclaimerPage/></ErrorBoundary>}/>
|
||||||
</ErrorBoundary>
|
<Route path="/mp/:paymentIs" element={<ErrorBoundary><MobilePaymentContainer/></ErrorBoundary>}/>
|
||||||
<ErrorBoundary>
|
<Route path="/manage/*" element={<ErrorBoundary><PrivateRoute isAuthorized={currentUser.authorized}/></ErrorBoundary>}>
|
||||||
<Route exact path="/resetpassword" component={ResetPassword} />
|
<Route path="*" element={<ManagePage/>}/>
|
||||||
</ErrorBoundary>
|
</Route>
|
||||||
<ErrorBoundary>
|
<Route path="/tech/*" element={<ErrorBoundary><PrivateRoute isAuthorized={currentUser.authorized}/></ErrorBoundary>}>
|
||||||
<Route exact path="/csi/:surveyId" component={CsiPage} />
|
<Route path="*" element={<TechPageContainer/>}/>
|
||||||
</ErrorBoundary>
|
</Route>
|
||||||
<ErrorBoundary>
|
<Route path="/edit/*" element={<PrivateRoute isAuthorized={currentUser.authorized}/>}>
|
||||||
<Route exact path="/disclaimer" component={DisclaimerPage} />
|
<Route path="*" element={<DocumentEditorContainer/>}/>
|
||||||
</ErrorBoundary>
|
</Route>
|
||||||
<ErrorBoundary>
|
</Routes>
|
||||||
<Route
|
|
||||||
exact
|
|
||||||
path="/mp/:paymentIs"
|
|
||||||
component={MobilePaymentContainer}
|
|
||||||
/>
|
|
||||||
</ErrorBoundary>
|
|
||||||
<ErrorBoundary>
|
|
||||||
<PrivateRoute
|
|
||||||
isAuthorized={currentUser.authorized}
|
|
||||||
path="/manage"
|
|
||||||
component={ManagePage}
|
|
||||||
/>
|
|
||||||
</ErrorBoundary>
|
|
||||||
<ErrorBoundary>
|
|
||||||
<PrivateRoute
|
|
||||||
isAuthorized={currentUser.authorized}
|
|
||||||
path="/tech"
|
|
||||||
component={TechPageContainer}
|
|
||||||
/>
|
|
||||||
</ErrorBoundary>
|
|
||||||
<ErrorBoundary>
|
|
||||||
<PrivateRoute
|
|
||||||
isAuthorized={currentUser.authorized}
|
|
||||||
path="/edit"
|
|
||||||
component={DocumentEditorContainer}
|
|
||||||
/>
|
|
||||||
</ErrorBoundary>
|
|
||||||
</Suspense>
|
</Suspense>
|
||||||
</Switch>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,14 @@
|
|||||||
//Global Styles.
|
//Global Styles.
|
||||||
@import "react-big-calendar/lib/sass/styles";
|
@import "react-big-calendar/lib/sass/styles";
|
||||||
|
|
||||||
|
.ant-menu-item-divider {
|
||||||
|
border-bottom: 1px solid #74695c !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-menu-dark .ant-menu-item:hover {
|
||||||
|
background-color: #1890ff !important;
|
||||||
|
}
|
||||||
|
|
||||||
.imex-table-header {
|
.imex-table-header {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
|
|||||||
17
client/src/components/PrivateRoute.js
Normal file
17
client/src/components/PrivateRoute.js
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
import React, {useEffect} from "react";
|
||||||
|
import {Outlet, useLocation, useNavigate} from "react-router-dom";
|
||||||
|
|
||||||
|
function PrivateRoute({component: Component, isAuthorized, ...rest}) {
|
||||||
|
const location = useLocation();
|
||||||
|
const navigate = useNavigate();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!isAuthorized) {
|
||||||
|
navigate(`/signin?redirect=${location.pathname}`);
|
||||||
|
}
|
||||||
|
}, [isAuthorized, navigate, location]);
|
||||||
|
|
||||||
|
return <Outlet/>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default PrivateRoute;
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import { Input, Table, Checkbox, Card, Space } from "antd";
|
import {Card, Checkbox, Input, Space, Table} from "antd";
|
||||||
import React, {useState} from "react";
|
import React, {useState} from "react";
|
||||||
import {useTranslation} from "react-i18next";
|
import {useTranslation} from "react-i18next";
|
||||||
import {Link} from "react-router-dom";
|
import {Link} from "react-router-dom";
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { Select, Button, Popover, InputNumber } from "antd";
|
import {Button, InputNumber, Popover, Select} from "antd";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import {useTranslation} from "react-i18next";
|
import {useTranslation} from "react-i18next";
|
||||||
import {connect} from "react-redux";
|
import {connect} from "react-redux";
|
||||||
@@ -61,7 +61,7 @@ export function AllocationsAssignmentComponent({
|
|||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Popover content={popContent} visible={visibility}>
|
<Popover content={popContent} open={visibility}>
|
||||||
<Button onClick={() => setVisibility(true)}>
|
<Button onClick={() => setVisibility(true)}>
|
||||||
{t("allocations.actions.assign")}
|
{t("allocations.actions.assign")}
|
||||||
</Button>
|
</Button>
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ export default connect(
|
|||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Popover content={popContent} visible={visibility}>
|
<Popover content={popContent} open={visibility}>
|
||||||
<Button disabled={disabled} onClick={() => setVisibility(true)}>
|
<Button disabled={disabled} onClick={() => setVisibility(true)}>
|
||||||
{t("allocations.actions.assign")}
|
{t("allocations.actions.assign")}
|
||||||
</Button>
|
</Button>
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import React from "react";
|
|||||||
import {List} from "antd";
|
import {List} from "antd";
|
||||||
import Icon from "@ant-design/icons";
|
import Icon from "@ant-design/icons";
|
||||||
import {FaArrowRight} from "react-icons/fa";
|
import {FaArrowRight} from "react-icons/fa";
|
||||||
|
|
||||||
export default function AuditTrailValuesComponent({oldV, newV}) {
|
export default function AuditTrailValuesComponent({oldV, newV}) {
|
||||||
if (!oldV && !newV) return <div></div>;
|
if (!oldV && !newV) return <div></div>;
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
import { Tag, Popover } from "antd";
|
import {Popover, Tag} from "antd";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import Barcode from "react-barcode";
|
import Barcode from "react-barcode";
|
||||||
import {useTranslation} from "react-i18next";
|
import {useTranslation} from "react-i18next";
|
||||||
|
|
||||||
export default function BarcodePopupComponent({value, children}) {
|
export default function BarcodePopupComponent({value, children}) {
|
||||||
const {t} = useTranslation();
|
const {t} = useTranslation();
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import React, { useEffect } from "react";
|
|||||||
import {useTranslation} from "react-i18next";
|
import {useTranslation} from "react-i18next";
|
||||||
import ReadOnlyFormItemComponent from "../form-items-formatted/read-only-form-item.component";
|
import ReadOnlyFormItemComponent from "../form-items-formatted/read-only-form-item.component";
|
||||||
import "./bill-cm-returns-table.styles.scss";
|
import "./bill-cm-returns-table.styles.scss";
|
||||||
|
|
||||||
export default function BillCmdReturnsTableComponent({
|
export default function BillCmdReturnsTableComponent({
|
||||||
form,
|
form,
|
||||||
returnLoading,
|
returnLoading,
|
||||||
|
|||||||
@@ -1,17 +1,13 @@
|
|||||||
import {useMutation, useQuery} from "@apollo/client";
|
import {useMutation, useQuery} from "@apollo/client";
|
||||||
import { Button, Form, PageHeader, Popconfirm, Space } from "antd";
|
import {Button, Form, Popconfirm, Space} from "antd";
|
||||||
import moment from "moment";
|
import dayjs from "../../utils/day";
|
||||||
import queryString from "query-string";
|
import queryString from "query-string";
|
||||||
import React, {useState} from "react";
|
import React, {useState} from "react";
|
||||||
import {useTranslation} from "react-i18next";
|
import {useTranslation} from "react-i18next";
|
||||||
import {connect} from "react-redux";
|
import {connect} from "react-redux";
|
||||||
import {useLocation} from "react-router-dom";
|
import {useLocation} from "react-router-dom";
|
||||||
import {createStructuredSelector} from "reselect";
|
import {createStructuredSelector} from "reselect";
|
||||||
import {
|
import {DELETE_BILL_LINE, INSERT_NEW_BILL_LINES, UPDATE_BILL_LINE} from "../../graphql/bill-lines.queries";
|
||||||
DELETE_BILL_LINE,
|
|
||||||
INSERT_NEW_BILL_LINES,
|
|
||||||
UPDATE_BILL_LINE,
|
|
||||||
} from "../../graphql/bill-lines.queries";
|
|
||||||
import {QUERY_BILL_BY_PK, UPDATE_BILL} from "../../graphql/bills.queries";
|
import {QUERY_BILL_BY_PK, UPDATE_BILL} from "../../graphql/bills.queries";
|
||||||
import {insertAuditTrail} from "../../redux/application/application.actions";
|
import {insertAuditTrail} from "../../redux/application/application.actions";
|
||||||
import {setModalContext} from "../../redux/modals/modals.actions";
|
import {setModalContext} from "../../redux/modals/modals.actions";
|
||||||
@@ -26,6 +22,7 @@ import JobDocumentsGallery from "../jobs-documents-gallery/jobs-documents-galler
|
|||||||
import JobsDocumentsLocalGallery from "../jobs-documents-local-gallery/jobs-documents-local-gallery.container";
|
import JobsDocumentsLocalGallery from "../jobs-documents-local-gallery/jobs-documents-local-gallery.container";
|
||||||
import LoadingSkeleton from "../loading-skeleton/loading-skeleton.component";
|
import LoadingSkeleton from "../loading-skeleton/loading-skeleton.component";
|
||||||
import BillDetailEditReturn from "./bill-detail-edit-return.component";
|
import BillDetailEditReturn from "./bill-detail-edit-return.component";
|
||||||
|
import {PageHeader} from "@ant-design/pro-layout";
|
||||||
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
bodyshop: selectBodyshop,
|
bodyshop: selectBodyshop,
|
||||||
@@ -42,16 +39,12 @@ export default connect(
|
|||||||
mapDispatchToProps
|
mapDispatchToProps
|
||||||
)(BillDetailEditcontainer);
|
)(BillDetailEditcontainer);
|
||||||
|
|
||||||
export function BillDetailEditcontainer({
|
export function BillDetailEditcontainer({setPartsOrderContext, insertAuditTrail, bodyshop,}) {
|
||||||
setPartsOrderContext,
|
|
||||||
insertAuditTrail,
|
|
||||||
bodyshop,
|
|
||||||
}) {
|
|
||||||
const search = queryString.parse(useLocation().search);
|
const search = queryString.parse(useLocation().search);
|
||||||
|
|
||||||
const {t} = useTranslation();
|
const {t} = useTranslation();
|
||||||
const [form] = Form.useForm();
|
const [form] = Form.useForm();
|
||||||
const [visible, setVisible] = useState(false);
|
const [open, setOpen] = useState(false);
|
||||||
const [updateLoading, setUpdateLoading] = useState(false);
|
const [updateLoading, setUpdateLoading] = useState(false);
|
||||||
const [update_bill] = useMutation(UPDATE_BILL);
|
const [update_bill] = useMutation(UPDATE_BILL);
|
||||||
const [insertBillLine] = useMutation(INSERT_NEW_BILL_LINES);
|
const [insertBillLine] = useMutation(INSERT_NEW_BILL_LINES);
|
||||||
@@ -65,6 +58,8 @@ export function BillDetailEditcontainer({
|
|||||||
nextFetchPolicy: "network-only",
|
nextFetchPolicy: "network-only",
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// ... rest of the code remains the same
|
||||||
|
|
||||||
const handleSave = () => {
|
const handleSave = () => {
|
||||||
//It's got a previously deducted bill line!
|
//It's got a previously deducted bill line!
|
||||||
if (
|
if (
|
||||||
@@ -72,7 +67,7 @@ export function BillDetailEditcontainer({
|
|||||||
form.getFieldValue("billlines").filter((b) => b.deductedfromlbr).length >
|
form.getFieldValue("billlines").filter((b) => b.deductedfromlbr).length >
|
||||||
0
|
0
|
||||||
)
|
)
|
||||||
setVisible(true);
|
setOpen(true);
|
||||||
else {
|
else {
|
||||||
form.submit();
|
form.submit();
|
||||||
}
|
}
|
||||||
@@ -155,7 +150,7 @@ export function BillDetailEditcontainer({
|
|||||||
await refetch();
|
await refetch();
|
||||||
form.setFieldsValue(transformData(data));
|
form.setFieldsValue(transformData(data));
|
||||||
form.resetFields();
|
form.resetFields();
|
||||||
setVisible(false);
|
setOpen(false);
|
||||||
setUpdateLoading(false);
|
setUpdateLoading(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -179,9 +174,9 @@ export function BillDetailEditcontainer({
|
|||||||
<BillDetailEditReturn data={data}/>
|
<BillDetailEditReturn data={data}/>
|
||||||
<BillPrintButton billid={search.billid}/>
|
<BillPrintButton billid={search.billid}/>
|
||||||
<Popconfirm
|
<Popconfirm
|
||||||
visible={visible}
|
open={open}
|
||||||
onConfirm={() => form.submit()}
|
onConfirm={() => form.submit()}
|
||||||
onCancel={() => setVisible(false)}
|
onCancel={() => setOpen(false)}
|
||||||
okButtonProps={{loading: updateLoading}}
|
okButtonProps={{loading: updateLoading}}
|
||||||
title={t("bills.labels.editadjwarning")}
|
title={t("bills.labels.editadjwarning")}
|
||||||
>
|
>
|
||||||
@@ -246,7 +241,7 @@ const transformData = (data) => {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
}),
|
}),
|
||||||
date: data.bills_by_pk ? moment(data.bills_by_pk.date) : null,
|
date: data.bills_by_pk ? dayjs(data.bills_by_pk.date) : null,
|
||||||
}
|
}
|
||||||
: {};
|
: {};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import queryString from "query-string";
|
|||||||
import React, {useEffect, useState} from "react";
|
import React, {useEffect, useState} from "react";
|
||||||
import {useTranslation} from "react-i18next";
|
import {useTranslation} from "react-i18next";
|
||||||
import {connect} from "react-redux";
|
import {connect} from "react-redux";
|
||||||
import { useHistory, useLocation } from "react-router-dom";
|
import {useLocation, useNavigate} from "react-router-dom";
|
||||||
import {createStructuredSelector} from "reselect";
|
import {createStructuredSelector} from "reselect";
|
||||||
import {insertAuditTrail} from "../../redux/application/application.actions";
|
import {insertAuditTrail} from "../../redux/application/application.actions";
|
||||||
import {setModalContext} from "../../redux/modals/modals.actions";
|
import {setModalContext} from "../../redux/modals/modals.actions";
|
||||||
@@ -33,10 +33,10 @@ export function BillDetailEditReturn({
|
|||||||
disabled,
|
disabled,
|
||||||
}) {
|
}) {
|
||||||
const search = queryString.parse(useLocation().search);
|
const search = queryString.parse(useLocation().search);
|
||||||
const history = useHistory();
|
const history = useNavigate();
|
||||||
const {t} = useTranslation();
|
const {t} = useTranslation();
|
||||||
const [form] = Form.useForm();
|
const [form] = Form.useForm();
|
||||||
const [visible, setVisible] = useState(false);
|
const [open, setOpen] = useState(false);
|
||||||
|
|
||||||
const handleFinish = ({billlines}) => {
|
const handleFinish = ({billlines}) => {
|
||||||
const selectedLines = billlines.filter((l) => l.selected).map((l) => l.id);
|
const selectedLines = billlines.filter((l) => l.selected).map((l) => l.id);
|
||||||
@@ -67,18 +67,18 @@ export function BillDetailEditReturn({
|
|||||||
});
|
});
|
||||||
delete search.billid;
|
delete search.billid;
|
||||||
|
|
||||||
history.push({ search: queryString.stringify(search) });
|
history({search: queryString.stringify(search)});
|
||||||
setVisible(false);
|
setOpen(false);
|
||||||
};
|
};
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (visible === false) form.resetFields();
|
if (open === false) form.resetFields();
|
||||||
}, [visible, form]);
|
}, [open, form]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Modal
|
<Modal
|
||||||
visible={visible}
|
open={open}
|
||||||
onCancel={() => setVisible(false)}
|
onCancel={() => setOpen(false)}
|
||||||
destroyOnClose
|
destroyOnClose
|
||||||
title={t("bills.actions.return")}
|
title={t("bills.actions.return")}
|
||||||
onOk={() => form.submit()}
|
onOk={() => form.submit()}
|
||||||
@@ -175,7 +175,7 @@ export function BillDetailEditReturn({
|
|||||||
<Button
|
<Button
|
||||||
disabled={data.bills_by_pk.is_credit_memo || disabled}
|
disabled={data.bills_by_pk.is_credit_memo || disabled}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setVisible(true);
|
setOpen(true);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{t("bills.actions.return")}
|
{t("bills.actions.return")}
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
import {Drawer, Grid} from "antd";
|
import {Drawer, Grid} from "antd";
|
||||||
import queryString from "query-string";
|
import queryString from "query-string";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { useHistory, useLocation } from "react-router-dom";
|
import {useLocation, useNavigate} from "react-router-dom";
|
||||||
import BillDetailEditComponent from "./bill-detail-edit-component";
|
import BillDetailEditComponent from "./bill-detail-edit-component";
|
||||||
|
|
||||||
export default function BillDetailEditcontainer() {
|
export default function BillDetailEditcontainer() {
|
||||||
const search = queryString.parse(useLocation().search);
|
const search = queryString.parse(useLocation().search);
|
||||||
const history = useHistory();
|
const history = useNavigate();
|
||||||
|
|
||||||
const selectedBreakpoint = Object.entries(Grid.useBreakpoint())
|
const selectedBreakpoint = Object.entries(Grid.useBreakpoint())
|
||||||
.filter((screen) => !!screen[1])
|
.filter((screen) => !!screen[1])
|
||||||
@@ -29,10 +29,10 @@ export default function BillDetailEditcontainer() {
|
|||||||
width={drawerPercentage}
|
width={drawerPercentage}
|
||||||
onClose={() => {
|
onClose={() => {
|
||||||
delete search.billid;
|
delete search.billid;
|
||||||
history.push({ search: queryString.stringify(search) });
|
history({search: queryString.stringify(search)});
|
||||||
}}
|
}}
|
||||||
destroyOnClose
|
destroyOnClose
|
||||||
visible={search.billid}
|
open={search.billid}
|
||||||
>
|
>
|
||||||
<BillDetailEditComponent/>
|
<BillDetailEditComponent/>
|
||||||
</Drawer>
|
</Drawer>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import {useApolloClient, useMutation} from "@apollo/client";
|
import {useApolloClient, useMutation} from "@apollo/client";
|
||||||
import { useTreatments } from "@splitsoftware/splitio-react";
|
import {useSplitTreatments} from "@splitsoftware/splitio-react";
|
||||||
import { Button, Checkbox, Form, Modal, Space, notification } from "antd";
|
import {Button, Checkbox, Form, Modal, notification, Space} from "antd";
|
||||||
import _ from "lodash";
|
import _ from "lodash";
|
||||||
import React, {useEffect, useMemo, useState} from "react";
|
import React, {useEffect, useMemo, useState} from "react";
|
||||||
import {useTranslation} from "react-i18next";
|
import {useTranslation} from "react-i18next";
|
||||||
@@ -9,18 +9,12 @@ import { createStructuredSelector } from "reselect";
|
|||||||
import {INSERT_NEW_BILL} from "../../graphql/bills.queries";
|
import {INSERT_NEW_BILL} from "../../graphql/bills.queries";
|
||||||
import {UPDATE_INVENTORY_LINES} from "../../graphql/inventory.queries";
|
import {UPDATE_INVENTORY_LINES} from "../../graphql/inventory.queries";
|
||||||
import {UPDATE_JOB_LINE} from "../../graphql/jobs-lines.queries";
|
import {UPDATE_JOB_LINE} from "../../graphql/jobs-lines.queries";
|
||||||
import {
|
import {QUERY_JOB_LBR_ADJUSTMENTS, UPDATE_JOB,} from "../../graphql/jobs.queries";
|
||||||
QUERY_JOB_LBR_ADJUSTMENTS,
|
|
||||||
UPDATE_JOB,
|
|
||||||
} from "../../graphql/jobs.queries";
|
|
||||||
import {MUTATION_MARK_RETURN_RECEIVED} from "../../graphql/parts-orders.queries";
|
import {MUTATION_MARK_RETURN_RECEIVED} from "../../graphql/parts-orders.queries";
|
||||||
import {insertAuditTrail} from "../../redux/application/application.actions";
|
import {insertAuditTrail} from "../../redux/application/application.actions";
|
||||||
import {toggleModalVisible} from "../../redux/modals/modals.actions";
|
import {toggleModalVisible} from "../../redux/modals/modals.actions";
|
||||||
import {selectBillEnterModal} from "../../redux/modals/modals.selectors";
|
import {selectBillEnterModal} from "../../redux/modals/modals.selectors";
|
||||||
import {
|
import {selectBodyshop, selectCurrentUser,} from "../../redux/user/user.selectors";
|
||||||
selectBodyshop,
|
|
||||||
selectCurrentUser,
|
|
||||||
} from "../../redux/user/user.selectors";
|
|
||||||
import AuditTrailMapping from "../../utils/AuditTrailMappings";
|
import AuditTrailMapping from "../../utils/AuditTrailMappings";
|
||||||
import {GenerateDocument} from "../../utils/RenderTemplate";
|
import {GenerateDocument} from "../../utils/RenderTemplate";
|
||||||
import {TemplateList} from "../../utils/TemplateConstants";
|
import {TemplateList} from "../../utils/TemplateConstants";
|
||||||
@@ -64,11 +58,13 @@ function BillEnterModalContainer({
|
|||||||
"enter_bill_generate_label",
|
"enter_bill_generate_label",
|
||||||
false
|
false
|
||||||
);
|
);
|
||||||
const { Enhanced_Payroll } = useTreatments(
|
|
||||||
["Enhanced_Payroll"],
|
const {treatments: {Enhanced_Payroll}} = useSplitTreatments({
|
||||||
{},
|
attributes: {},
|
||||||
bodyshop.imexshopid
|
names: ["Enhanced_Payroll"],
|
||||||
);
|
splitKey: bodyshop.imexshopid,
|
||||||
|
});
|
||||||
|
|
||||||
const formValues = useMemo(() => {
|
const formValues = useMemo(() => {
|
||||||
return {
|
return {
|
||||||
...billEnterModal.context.bill,
|
...billEnterModal.context.bill,
|
||||||
@@ -399,18 +395,18 @@ function BillEnterModalContainer({
|
|||||||
}, [enterAgain, form]);
|
}, [enterAgain, form]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (billEnterModal.visible) {
|
if (billEnterModal.open) {
|
||||||
form.setFieldsValue(formValues);
|
form.setFieldsValue(formValues);
|
||||||
} else {
|
} else {
|
||||||
form.resetFields();
|
form.resetFields();
|
||||||
}
|
}
|
||||||
}, [billEnterModal.visible, form, formValues]);
|
}, [billEnterModal.open, form, formValues]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
title={t("bills.labels.new")}
|
title={t("bills.labels.new")}
|
||||||
width={"98%"}
|
width={"98%"}
|
||||||
visible={billEnterModal.visible}
|
open={billEnterModal.open}
|
||||||
okText={t("general.actions.save")}
|
okText={t("general.actions.save")}
|
||||||
keyboard="false"
|
keyboard="false"
|
||||||
onOk={() => form.submit()}
|
onOk={() => form.submit()}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import { useTranslation } from "react-i18next";
|
|||||||
import CurrencyFormatter from "../../utils/CurrencyFormatter";
|
import CurrencyFormatter from "../../utils/CurrencyFormatter";
|
||||||
import {alphaSort} from "../../utils/sorters";
|
import {alphaSort} from "../../utils/sorters";
|
||||||
import BillFormItemsExtendedFormItem from "./bill-form-lines.extended.formitem.component";
|
import BillFormItemsExtendedFormItem from "./bill-form-lines.extended.formitem.component";
|
||||||
|
|
||||||
export default function BillFormLinesExtended({
|
export default function BillFormLinesExtended({
|
||||||
lineData,
|
lineData,
|
||||||
discount,
|
discount,
|
||||||
|
|||||||
@@ -1,10 +1,6 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import {
|
import {MinusCircleFilled, PlusCircleFilled, WarningOutlined,} from "@ant-design/icons";
|
||||||
PlusCircleFilled,
|
import {Button, Form, Input, InputNumber, Select, Space, Switch} from "antd";
|
||||||
MinusCircleFilled,
|
|
||||||
WarningOutlined,
|
|
||||||
} from "@ant-design/icons";
|
|
||||||
import { Form, Button, InputNumber, Input, Select, Switch, Space } from "antd";
|
|
||||||
import {useTranslation} from "react-i18next";
|
import {useTranslation} from "react-i18next";
|
||||||
|
|
||||||
import {connect} from "react-redux";
|
import {connect} from "react-redux";
|
||||||
|
|||||||
@@ -1,18 +1,8 @@
|
|||||||
import Icon, {UploadOutlined} from "@ant-design/icons";
|
import Icon, {UploadOutlined} from "@ant-design/icons";
|
||||||
import {useApolloClient} from "@apollo/client";
|
import {useApolloClient} from "@apollo/client";
|
||||||
import { useTreatments } from "@splitsoftware/splitio-react";
|
import {useSplitTreatments} from "@splitsoftware/splitio-react";
|
||||||
import {
|
import {Alert, Divider, Form, Input, Select, Space, Statistic, Switch, Upload,} from "antd";
|
||||||
Alert,
|
import dayjs from "../../utils/day";
|
||||||
Divider,
|
|
||||||
Form,
|
|
||||||
Input,
|
|
||||||
Select,
|
|
||||||
Space,
|
|
||||||
Statistic,
|
|
||||||
Switch,
|
|
||||||
Upload,
|
|
||||||
} from "antd";
|
|
||||||
import moment from "moment";
|
|
||||||
import React, {useEffect, useState} from "react";
|
import React, {useEffect, useState} from "react";
|
||||||
import {useTranslation} from "react-i18next";
|
import {useTranslation} from "react-i18next";
|
||||||
import {MdOpenInNew} from "react-icons/md";
|
import {MdOpenInNew} from "react-icons/md";
|
||||||
@@ -50,21 +40,19 @@ export function BillFormComponent({
|
|||||||
job,
|
job,
|
||||||
loadOutstandingReturns,
|
loadOutstandingReturns,
|
||||||
loadInventory,
|
loadInventory,
|
||||||
preferredMake,
|
preferredMake
|
||||||
}) {
|
}) {
|
||||||
|
|
||||||
const {t} = useTranslation();
|
const {t} = useTranslation();
|
||||||
const client = useApolloClient();
|
const client = useApolloClient();
|
||||||
const [discount, setDiscount] = useState(0);
|
const [discount, setDiscount] = useState(0);
|
||||||
const { Extended_Bill_Posting } = useTreatments(
|
|
||||||
["Extended_Bill_Posting"],
|
const {treatments: {Extended_Bill_Posting, ClosingPeriod}} = useSplitTreatments({
|
||||||
{},
|
attributes: {},
|
||||||
bodyshop.imexshopid
|
names: ["Extended_Bill_Posting", "ClosingPeriod"],
|
||||||
);
|
splitKey: bodyshop.imexshopid,
|
||||||
const { ClosingPeriod } = useTreatments(
|
});
|
||||||
["ClosingPeriod"],
|
|
||||||
{},
|
|
||||||
bodyshop.imexshopid
|
|
||||||
);
|
|
||||||
|
|
||||||
const handleVendorSelect = (props, opt) => {
|
const handleVendorSelect = (props, opt) => {
|
||||||
setDiscount(opt.discount);
|
setDiscount(opt.discount);
|
||||||
@@ -288,17 +276,17 @@ export function BillFormComponent({
|
|||||||
bodyshop.accountingconfig.ClosingPeriod
|
bodyshop.accountingconfig.ClosingPeriod
|
||||||
) {
|
) {
|
||||||
if (
|
if (
|
||||||
moment(value)
|
dayjs(value)
|
||||||
.startOf("day")
|
.startOf("day")
|
||||||
.isSameOrAfter(
|
.isSameOrAfter(
|
||||||
moment(
|
dayjs(
|
||||||
bodyshop.accountingconfig.ClosingPeriod[0]
|
bodyshop.accountingconfig.ClosingPeriod[0]
|
||||||
).startOf("day")
|
).startOf("day")
|
||||||
) &&
|
) &&
|
||||||
moment(value)
|
dayjs(value)
|
||||||
.startOf("day")
|
.startOf("day")
|
||||||
.isSameOrBefore(
|
.isSameOrBefore(
|
||||||
moment(
|
dayjs(
|
||||||
bodyshop.accountingconfig.ClosingPeriod[1]
|
bodyshop.accountingconfig.ClosingPeriod[1]
|
||||||
).endOf("day")
|
).endOf("day")
|
||||||
)
|
)
|
||||||
@@ -396,27 +384,22 @@ export function BillFormComponent({
|
|||||||
>
|
>
|
||||||
<CurrencyInput min={0} disabled={disabled}/>
|
<CurrencyInput min={0} disabled={disabled}/>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
{
|
{/*<Form.Item*/}
|
||||||
// <Form.Item
|
{/* span={3}*/}
|
||||||
// span={3}
|
{/* label={t("bills.fields.local_tax_rate")}*/}
|
||||||
// label={t("bills.fields.local_tax_rate")}
|
{/* name="local_tax_rate"*/}
|
||||||
// name="local_tax_rate"
|
{/*>*/}
|
||||||
// >
|
{/* <CurrencyInput min={0} />*/}
|
||||||
// <CurrencyInput min={0} />
|
{/*</Form.Item>*/}
|
||||||
// </Form.Item>
|
{/* {bodyshop.pbs_serialnumber || bodyshop.cdk_dealerid ? (*/}
|
||||||
}
|
{/* <Form.Item*/}
|
||||||
{
|
{/* span={2}*/}
|
||||||
//Removed as a part of the merge to Rome Online. Federal tax not applicable.
|
{/* label={t("bills.labels.federal_tax_exempt")}*/}
|
||||||
// bodyshop.pbs_serialnumber || bodyshop.cdk_dealerid ? (
|
{/* name="federal_tax_exempt"*/}
|
||||||
// <Form.Item
|
{/* >*/}
|
||||||
// span={2}
|
{/* <Switch onChange={handleFederalTaxExemptSwitchToggle} />*/}
|
||||||
// label={t("bills.labels.federal_tax_exempt")}
|
{/* </Form.Item>*/}
|
||||||
// name="federal_tax_exempt"
|
{/* ) : null}*/}
|
||||||
// >
|
|
||||||
// <Switch onChange={handleFederalTaxExemptSwitchToggle} />
|
|
||||||
// </Form.Item>
|
|
||||||
// ) : null
|
|
||||||
}
|
|
||||||
<Form.Item shouldUpdate span={13}>
|
<Form.Item shouldUpdate span={13}>
|
||||||
{() => {
|
{() => {
|
||||||
const values = form.getFieldsValue([
|
const values = form.getFieldsValue([
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import {useLazyQuery, useQuery} from "@apollo/client";
|
import {useLazyQuery, useQuery} from "@apollo/client";
|
||||||
import { useTreatments } from "@splitsoftware/splitio-react";
|
import {useSplitTreatments} from "@splitsoftware/splitio-react";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import {connect} from "react-redux";
|
import {connect} from "react-redux";
|
||||||
import {createStructuredSelector} from "reselect";
|
import {createStructuredSelector} from "reselect";
|
||||||
@@ -23,11 +23,11 @@ export function BillFormContainer({
|
|||||||
disabled,
|
disabled,
|
||||||
disableInvNumber,
|
disableInvNumber,
|
||||||
}) {
|
}) {
|
||||||
const { Simple_Inventory } = useTreatments(
|
const {treatments: {Simple_Inventory}} = useSplitTreatments({
|
||||||
["Simple_Inventory"],
|
attributes: {},
|
||||||
{},
|
names: ["Simple_Inventory"],
|
||||||
bodyshop && bodyshop.imexshopid
|
splitKey: bodyshop && bodyshop.imexshopid,
|
||||||
);
|
});
|
||||||
|
|
||||||
const {data: VendorAutoCompleteData} = useQuery(
|
const {data: VendorAutoCompleteData} = useQuery(
|
||||||
SEARCH_VENDOR_AUTOCOMPLETE,
|
SEARCH_VENDOR_AUTOCOMPLETE,
|
||||||
@@ -79,4 +79,5 @@ export function BillFormContainer({
|
|||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default connect(mapStateToProps, null)(BillFormContainer);
|
export default connect(mapStateToProps, null)(BillFormContainer);
|
||||||
|
|||||||
@@ -1,17 +1,6 @@
|
|||||||
import {DeleteFilled, DollarCircleFilled} from "@ant-design/icons";
|
import {DeleteFilled, DollarCircleFilled} from "@ant-design/icons";
|
||||||
import { useTreatments } from "@splitsoftware/splitio-react";
|
import {useSplitTreatments} from "@splitsoftware/splitio-react";
|
||||||
import {
|
import {Button, Checkbox, Form, Input, InputNumber, Select, Space, Switch, Table, Tooltip,} from "antd";
|
||||||
Button,
|
|
||||||
Checkbox,
|
|
||||||
Form,
|
|
||||||
Input,
|
|
||||||
InputNumber,
|
|
||||||
Select,
|
|
||||||
Space,
|
|
||||||
Switch,
|
|
||||||
Table,
|
|
||||||
Tooltip,
|
|
||||||
} from "antd";
|
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import {useTranslation} from "react-i18next";
|
import {useTranslation} from "react-i18next";
|
||||||
import {connect} from "react-redux";
|
import {connect} from "react-redux";
|
||||||
@@ -42,17 +31,13 @@ export function BillEnterModalLinesComponent({
|
|||||||
}) {
|
}) {
|
||||||
const {t} = useTranslation();
|
const {t} = useTranslation();
|
||||||
const {setFieldsValue, getFieldsValue, getFieldValue} = form;
|
const {setFieldsValue, getFieldsValue, getFieldValue} = form;
|
||||||
const { Simple_Inventory } = useTreatments(
|
|
||||||
["Simple_Inventory"],
|
|
||||||
{},
|
|
||||||
bodyshop && bodyshop.imexshopid
|
|
||||||
);
|
|
||||||
|
|
||||||
const { Enhanced_Payroll } = useTreatments(
|
const {treatments: {Simple_Inventory, Enhanced_Payroll}} = useSplitTreatments({
|
||||||
["Enhanced_Payroll"],
|
attributes: {},
|
||||||
{},
|
names: ["Simple_Inventory", "Enhanced_Payroll"],
|
||||||
bodyshop.imexshopid
|
splitKey: bodyshop && bodyshop.imexshopid,
|
||||||
);
|
});
|
||||||
|
|
||||||
|
|
||||||
const columns = (remove) => {
|
const columns = (remove) => {
|
||||||
return [
|
return [
|
||||||
|
|||||||
@@ -15,7 +15,8 @@ const BillLineSearchSelect = (
|
|||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
ref={ref}
|
ref={ref}
|
||||||
showSearch
|
showSearch
|
||||||
dropdownMatchSelectWidth={false}
|
popupMatchSelectWidth={false}
|
||||||
|
optionLabelProp={"name"}
|
||||||
// optionFilterProp="line_desc"
|
// optionFilterProp="line_desc"
|
||||||
filterOption={(inputValue, option) => {
|
filterOption={(inputValue, option) => {
|
||||||
return (
|
return (
|
||||||
@@ -57,6 +58,9 @@ const BillLineSearchSelect = (
|
|||||||
style={{
|
style={{
|
||||||
...(item.removed ? {textDecoration: "line-through"} : {}),
|
...(item.removed ? {textDecoration: "line-through"} : {}),
|
||||||
}}
|
}}
|
||||||
|
name={`${item.removed ? `(REMOVED) ` : ""}${item.line_desc}${
|
||||||
|
item.oem_partno ? ` - ${item.oem_partno}` : ""
|
||||||
|
}${item.alt_partno ? ` (${item.alt_partno})` : ""}`.trim()}
|
||||||
>
|
>
|
||||||
<span>
|
<span>
|
||||||
{`${item.removed ? `(REMOVED) ` : ""}${item.line_desc}${
|
{`${item.removed ? `(REMOVED) ` : ""}${item.line_desc}${
|
||||||
|
|||||||
@@ -1,18 +1,14 @@
|
|||||||
import { useMutation } from "@apollo/client";
|
import {gql, useMutation} from "@apollo/client";
|
||||||
import {Button, notification} from "antd";
|
import {Button, notification} from "antd";
|
||||||
import { gql } from "@apollo/client";
|
|
||||||
import React, {useState} from "react";
|
import React, {useState} from "react";
|
||||||
import {useTranslation} from "react-i18next";
|
import {useTranslation} from "react-i18next";
|
||||||
|
|
||||||
import {connect} from "react-redux";
|
import {connect} from "react-redux";
|
||||||
import {createStructuredSelector} from "reselect";
|
import {createStructuredSelector} from "reselect";
|
||||||
import {
|
import {selectAuthLevel, selectBodyshop, selectCurrentUser,} from "../../redux/user/user.selectors";
|
||||||
selectAuthLevel,
|
|
||||||
selectBodyshop,
|
|
||||||
selectCurrentUser,
|
|
||||||
} from "../../redux/user/user.selectors";
|
|
||||||
import {HasRbacAccess} from "../rbac-wrapper/rbac-wrapper.component";
|
import {HasRbacAccess} from "../rbac-wrapper/rbac-wrapper.component";
|
||||||
import {INSERT_EXPORT_LOG} from "../../graphql/accounting.queries";
|
import {INSERT_EXPORT_LOG} from "../../graphql/accounting.queries";
|
||||||
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
bodyshop: selectBodyshop,
|
bodyshop: selectBodyshop,
|
||||||
authLevel: selectAuthLevel,
|
authLevel: selectAuthLevel,
|
||||||
|
|||||||
@@ -1,16 +1,13 @@
|
|||||||
import { useMutation } from "@apollo/client";
|
import {gql, useMutation} from "@apollo/client";
|
||||||
import {Button, notification} from "antd";
|
import {Button, notification} from "antd";
|
||||||
import { gql } from "@apollo/client";
|
|
||||||
import React, {useState} from "react";
|
import React, {useState} from "react";
|
||||||
import {useTranslation} from "react-i18next";
|
import {useTranslation} from "react-i18next";
|
||||||
|
|
||||||
import {connect} from "react-redux";
|
import {connect} from "react-redux";
|
||||||
import {createStructuredSelector} from "reselect";
|
import {createStructuredSelector} from "reselect";
|
||||||
import {
|
import {selectAuthLevel, selectBodyshop,} from "../../redux/user/user.selectors";
|
||||||
selectAuthLevel,
|
|
||||||
selectBodyshop,
|
|
||||||
} from "../../redux/user/user.selectors";
|
|
||||||
import {HasRbacAccess} from "../rbac-wrapper/rbac-wrapper.component";
|
import {HasRbacAccess} from "../rbac-wrapper/rbac-wrapper.component";
|
||||||
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
bodyshop: selectBodyshop,
|
bodyshop: selectBodyshop,
|
||||||
authLevel: selectAuthLevel,
|
authLevel: selectAuthLevel,
|
||||||
|
|||||||
@@ -2,15 +2,12 @@ import { FileAddFilled } from "@ant-design/icons";
|
|||||||
import {useMutation} from "@apollo/client";
|
import {useMutation} from "@apollo/client";
|
||||||
import {Button, notification, Tooltip} from "antd";
|
import {Button, notification, Tooltip} from "antd";
|
||||||
import {t} from "i18next";
|
import {t} from "i18next";
|
||||||
import moment from "moment";
|
import dayjs from "./../../utils/day";
|
||||||
import React, {useState} from "react";
|
import React, {useState} from "react";
|
||||||
import {connect} from "react-redux";
|
import {connect} from "react-redux";
|
||||||
import {createStructuredSelector} from "reselect";
|
import {createStructuredSelector} from "reselect";
|
||||||
import {INSERT_INVENTORY_AND_CREDIT} from "../../graphql/inventory.queries";
|
import {INSERT_INVENTORY_AND_CREDIT} from "../../graphql/inventory.queries";
|
||||||
import {
|
import {selectBodyshop, selectCurrentUser,} from "../../redux/user/user.selectors";
|
||||||
selectBodyshop,
|
|
||||||
selectCurrentUser,
|
|
||||||
} from "../../redux/user/user.selectors";
|
|
||||||
import {CalculateBillTotal} from "../bill-form/bill-form.totals.utility";
|
import {CalculateBillTotal} from "../bill-form/bill-form.totals.utility";
|
||||||
import queryString from "query-string";
|
import queryString from "query-string";
|
||||||
import {useLocation} from "react-router-dom";
|
import {useLocation} from "react-router-dom";
|
||||||
@@ -36,7 +33,6 @@ export function BilllineAddInventory({
|
|||||||
}) {
|
}) {
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const {billid} = queryString.parse(useLocation().search);
|
const {billid} = queryString.parse(useLocation().search);
|
||||||
|
|
||||||
const [insertInventoryLine] = useMutation(INSERT_INVENTORY_AND_CREDIT);
|
const [insertInventoryLine] = useMutation(INSERT_INVENTORY_AND_CREDIT);
|
||||||
|
|
||||||
const addToInventory = async () => {
|
const addToInventory = async () => {
|
||||||
@@ -50,7 +46,7 @@ export function BilllineAddInventory({
|
|||||||
jobid: jobid,
|
jobid: jobid,
|
||||||
isinhouse: true,
|
isinhouse: true,
|
||||||
is_credit_memo: true,
|
is_credit_memo: true,
|
||||||
date: moment().format("YYYY-MM-DD"),
|
date: dayjs().format("YYYY-MM-DD"),
|
||||||
federal_tax_rate: bodyshop.bill_tax_rates.federal_tax_rate,
|
federal_tax_rate: bodyshop.bill_tax_rates.federal_tax_rate,
|
||||||
state_tax_rate: bodyshop.bill_tax_rates.state_tax_rate,
|
state_tax_rate: bodyshop.bill_tax_rates.state_tax_rate,
|
||||||
local_tax_rate: bodyshop.bill_tax_rates.local_tax_rate,
|
local_tax_rate: bodyshop.bill_tax_rates.local_tax_rate,
|
||||||
@@ -92,7 +88,7 @@ export function BilllineAddInventory({
|
|||||||
pol: {
|
pol: {
|
||||||
returnfrombill: billid,
|
returnfrombill: billid,
|
||||||
vendorid: bodyshop.inhousevendorid,
|
vendorid: bodyshop.inhousevendorid,
|
||||||
deliver_by: moment().format("YYYY-MM-DD"),
|
deliver_by: dayjs().format("YYYY-MM-DD"),
|
||||||
parts_order_lines: {
|
parts_order_lines: {
|
||||||
data: [
|
data: [
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -229,6 +229,7 @@ export function BillsListTableComponent({
|
|||||||
</Card>
|
</Card>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default connect(
|
export default connect(
|
||||||
mapStateToProps,
|
mapStateToProps,
|
||||||
mapDispatchToProps
|
mapDispatchToProps
|
||||||
|
|||||||
@@ -2,15 +2,15 @@ import React, { useState } from "react";
|
|||||||
import {QUERY_ALL_VENDORS} from "../../graphql/vendors.queries";
|
import {QUERY_ALL_VENDORS} from "../../graphql/vendors.queries";
|
||||||
import {useQuery} from "@apollo/client";
|
import {useQuery} from "@apollo/client";
|
||||||
import queryString from "query-string";
|
import queryString from "query-string";
|
||||||
import { useHistory, useLocation } from "react-router-dom";
|
import {useLocation, useNavigate} from "react-router-dom";
|
||||||
import { Table, Input } from "antd";
|
import {Input, Table} from "antd";
|
||||||
import {useTranslation} from "react-i18next";
|
import {useTranslation} from "react-i18next";
|
||||||
import {alphaSort} from "../../utils/sorters";
|
import {alphaSort} from "../../utils/sorters";
|
||||||
import AlertComponent from "../alert/alert.component";
|
import AlertComponent from "../alert/alert.component";
|
||||||
|
|
||||||
export default function BillsVendorsList() {
|
export default function BillsVendorsList() {
|
||||||
const search = queryString.parse(useLocation().search);
|
const search = queryString.parse(useLocation().search);
|
||||||
const history = useHistory();
|
const history = useNavigate();
|
||||||
|
|
||||||
const {loading, error, data} = useQuery(QUERY_ALL_VENDORS, {
|
const {loading, error, data} = useQuery(QUERY_ALL_VENDORS, {
|
||||||
fetchPolicy: "network-only",
|
fetchPolicy: "network-only",
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import {HomeFilled} from "@ant-design/icons";
|
import {HomeFilled} from "@ant-design/icons";
|
||||||
import { Breadcrumb, Row, Col } from "antd";
|
import {Breadcrumb, Col, Row} from "antd";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import {connect} from "react-redux";
|
import {connect} from "react-redux";
|
||||||
import {Link} from "react-router-dom";
|
import {Link} from "react-router-dom";
|
||||||
@@ -9,7 +9,7 @@ import { selectBodyshop } from "../../redux/user/user.selectors";
|
|||||||
import GlobalSearch from "../global-search/global-search.component";
|
import GlobalSearch from "../global-search/global-search.component";
|
||||||
import GlobalSearchOs from "../global-search/global-search-os.component";
|
import GlobalSearchOs from "../global-search/global-search-os.component";
|
||||||
import "./breadcrumbs.styles.scss";
|
import "./breadcrumbs.styles.scss";
|
||||||
import { useTreatments } from "@splitsoftware/splitio-react";
|
import {useSplitTreatments} from "@splitsoftware/splitio-react";
|
||||||
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
breadcrumbs: selectBreadcrumbs,
|
breadcrumbs: selectBreadcrumbs,
|
||||||
@@ -17,33 +17,42 @@ const mapStateToProps = createStructuredSelector({
|
|||||||
});
|
});
|
||||||
|
|
||||||
export function BreadCrumbs({breadcrumbs, bodyshop}) {
|
export function BreadCrumbs({breadcrumbs, bodyshop}) {
|
||||||
const { OpenSearch } = useTreatments(
|
|
||||||
["OpenSearch"],
|
|
||||||
{},
|
|
||||||
bodyshop && bodyshop.imexshopid
|
|
||||||
);
|
|
||||||
|
|
||||||
|
const {treatments: {OpenSearch}} = useSplitTreatments({
|
||||||
|
attributes: {},
|
||||||
|
names: ["OpenSearch"],
|
||||||
|
splitKey: bodyshop && bodyshop.imexshopid,
|
||||||
|
});
|
||||||
|
// TODO - Client Update - Technically key is not doing anything here
|
||||||
return (
|
return (
|
||||||
<Row className="breadcrumb-container">
|
<Row className="breadcrumb-container">
|
||||||
<Col xs={24} sm={24} md={16}>
|
<Col xs={24} sm={24} md={16}>
|
||||||
<Breadcrumb separator=">">
|
<Breadcrumb
|
||||||
<Breadcrumb.Item>
|
separator=">"
|
||||||
<Link to={`/manage`}>
|
items={[
|
||||||
|
{
|
||||||
|
key: "home",
|
||||||
|
title: (
|
||||||
|
<Link to={`/manage/`}>
|
||||||
<HomeFilled/>{" "}
|
<HomeFilled/>{" "}
|
||||||
{(bodyshop && bodyshop.shopname && `(${bodyshop.shopname})`) ||
|
{(bodyshop && bodyshop.shopname && `(${bodyshop.shopname})`) ||
|
||||||
""}
|
""}
|
||||||
</Link>
|
</Link>
|
||||||
</Breadcrumb.Item>
|
),
|
||||||
{breadcrumbs.map((item) =>
|
},
|
||||||
item.link ? (
|
...breadcrumbs.map((item) =>
|
||||||
<Breadcrumb.Item key={item.label}>
|
item.link
|
||||||
<Link to={item.link}>{item.label} </Link>
|
? {
|
||||||
</Breadcrumb.Item>
|
key: item.label,
|
||||||
) : (
|
title: <Link to={item.link}>{item.label}</Link>,
|
||||||
<Breadcrumb.Item key={item.label}>{item.label}</Breadcrumb.Item>
|
}
|
||||||
)
|
: {
|
||||||
)}
|
key: item.label,
|
||||||
</Breadcrumb>
|
title: item.label,
|
||||||
|
}
|
||||||
|
),
|
||||||
|
]}
|
||||||
|
/>
|
||||||
</Col>
|
</Col>
|
||||||
<Col xs={24} sm={24} md={8}>
|
<Col xs={24} sm={24} md={8}>
|
||||||
{OpenSearch.treatment === "on" ? <GlobalSearchOs/> : <GlobalSearch/>}
|
{OpenSearch.treatment === "on" ? <GlobalSearchOs/> : <GlobalSearch/>}
|
||||||
@@ -51,4 +60,5 @@ export function BreadCrumbs({ breadcrumbs, bodyshop }) {
|
|||||||
</Row>
|
</Row>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default connect(mapStateToProps, null)(BreadCrumbs);
|
export default connect(mapStateToProps, null)(BreadCrumbs);
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ export function ContractsFindModalContainer({
|
|||||||
}) {
|
}) {
|
||||||
const {t} = useTranslation();
|
const {t} = useTranslation();
|
||||||
|
|
||||||
const { visible } = caBcEtfTableModal;
|
const {open} = caBcEtfTableModal;
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const [form] = Form.useForm();
|
const [form] = Form.useForm();
|
||||||
const EtfTemplate = TemplateList("special").ca_bc_etf_table;
|
const EtfTemplate = TemplateList("special").ca_bc_etf_table;
|
||||||
@@ -63,14 +63,14 @@ export function ContractsFindModalContainer({
|
|||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (visible) {
|
if (open) {
|
||||||
form.resetFields();
|
form.resetFields();
|
||||||
}
|
}
|
||||||
}, [visible, form]);
|
}, [open, form]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
visible={visible}
|
open={open}
|
||||||
width="70%"
|
width="70%"
|
||||||
title={t("payments.labels.findermodal")}
|
title={t("payments.labels.findermodal")}
|
||||||
onCancel={() => toggleModalVisible()}
|
onCancel={() => toggleModalVisible()}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { Button, Form, InputNumber, Popover } from "antd";
|
|||||||
import {logImEXEvent} from "../../firebase/firebase.utils";
|
import {logImEXEvent} from "../../firebase/firebase.utils";
|
||||||
import {useTranslation} from "react-i18next";
|
import {useTranslation} from "react-i18next";
|
||||||
import {CalculatorFilled} from "@ant-design/icons";
|
import {CalculatorFilled} from "@ant-design/icons";
|
||||||
|
|
||||||
export default function CABCpvrtCalculator({disabled, form}) {
|
export default function CABCpvrtCalculator({disabled, form}) {
|
||||||
const [visibility, setVisibility] = useState(false);
|
const [visibility, setVisibility] = useState(false);
|
||||||
|
|
||||||
@@ -38,7 +39,7 @@ export default function CABCpvrtCalculator({ disabled, form }) {
|
|||||||
<Popover
|
<Popover
|
||||||
destroyTooltipOnHide
|
destroyTooltipOnHide
|
||||||
content={popContent}
|
content={popContent}
|
||||||
visible={visibility}
|
open={visibility}
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
>
|
>
|
||||||
<Button disabled={disabled} onClick={() => setVisibility(true)}>
|
<Button disabled={disabled} onClick={() => setVisibility(true)}>
|
||||||
|
|||||||
@@ -1,27 +1,13 @@
|
|||||||
import {DeleteFilled} from "@ant-design/icons";
|
import {DeleteFilled} from "@ant-design/icons";
|
||||||
import {useLazyQuery, useMutation} from "@apollo/client";
|
import {useLazyQuery, useMutation} from "@apollo/client";
|
||||||
import {
|
import {Button, Card, Col, Form, Input, notification, Row, Space, Spin, Statistic,} from "antd";
|
||||||
Button,
|
|
||||||
Card,
|
|
||||||
Col,
|
|
||||||
Form,
|
|
||||||
Input,
|
|
||||||
Row,
|
|
||||||
Space,
|
|
||||||
Spin,
|
|
||||||
Statistic,
|
|
||||||
notification,
|
|
||||||
} from "antd";
|
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import moment from "moment";
|
import dayjs from "../../utils/day";
|
||||||
import React, {useState} from "react";
|
import React, {useState} from "react";
|
||||||
import {useTranslation} from "react-i18next";
|
import {useTranslation} from "react-i18next";
|
||||||
import {connect} from "react-redux";
|
import {connect} from "react-redux";
|
||||||
import {createStructuredSelector} from "reselect";
|
import {createStructuredSelector} from "reselect";
|
||||||
import {
|
import {INSERT_PAYMENT_RESPONSE, QUERY_RO_AND_OWNER_BY_JOB_PKS,} from "../../graphql/payment_response.queries";
|
||||||
INSERT_PAYMENT_RESPONSE,
|
|
||||||
QUERY_RO_AND_OWNER_BY_JOB_PKS,
|
|
||||||
} from "../../graphql/payment_response.queries";
|
|
||||||
import {INSERT_NEW_PAYMENT} from "../../graphql/payments.queries";
|
import {INSERT_NEW_PAYMENT} from "../../graphql/payments.queries";
|
||||||
import {insertAuditTrail} from "../../redux/application/application.actions";
|
import {insertAuditTrail} from "../../redux/application/application.actions";
|
||||||
import {toggleModalVisible} from "../../redux/modals/modals.actions";
|
import {toggleModalVisible} from "../../redux/modals/modals.actions";
|
||||||
@@ -117,7 +103,7 @@ const CardPaymentModalComponent = ({
|
|||||||
payer: t("payments.labels.customer"),
|
payer: t("payments.labels.customer"),
|
||||||
type: values.paymentResponse.cardbrand,
|
type: values.paymentResponse.cardbrand,
|
||||||
jobid: payment.jobid,
|
jobid: payment.jobid,
|
||||||
date: moment(Date.now()),
|
date: dayjs(Date.now()),
|
||||||
payment_responses: {
|
payment_responses: {
|
||||||
data: [
|
data: [
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ function CardPaymentModalContainer({
|
|||||||
toggleModalVisible,
|
toggleModalVisible,
|
||||||
bodyshop,
|
bodyshop,
|
||||||
}) {
|
}) {
|
||||||
const { visible } = cardPaymentModal;
|
const {open} = cardPaymentModal;
|
||||||
const {t} = useTranslation();
|
const {t} = useTranslation();
|
||||||
|
|
||||||
const handleCancel = () => {
|
const handleCancel = () => {
|
||||||
@@ -35,7 +35,7 @@ function CardPaymentModalContainer({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
open={visible}
|
open={open}
|
||||||
onOk={handleOK}
|
onOk={handleOK}
|
||||||
onCancel={handleCancel}
|
onCancel={handleCancel}
|
||||||
footer={[
|
footer={[
|
||||||
|
|||||||
@@ -4,20 +4,11 @@ import { Button, notification, Space } from "antd";
|
|||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import React, {useEffect} from "react";
|
import React, {useEffect} from "react";
|
||||||
import {useTranslation} from "react-i18next";
|
import {useTranslation} from "react-i18next";
|
||||||
import { connect } from "react-redux";
|
|
||||||
import { createStructuredSelector } from "reselect";
|
|
||||||
import {messaging, requestForToken} from "../../firebase/firebase.utils";
|
import {messaging, requestForToken} from "../../firebase/firebase.utils";
|
||||||
import { selectChatVisible } from "../../redux/messaging/messaging.selectors";
|
|
||||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
|
||||||
import FcmHandler from "../../utils/fcm-handler";
|
import FcmHandler from "../../utils/fcm-handler";
|
||||||
import ChatPopupComponent from "../chat-popup/chat-popup.component";
|
import ChatPopupComponent from "../chat-popup/chat-popup.component";
|
||||||
import "./chat-affix.styles.scss";
|
import "./chat-affix.styles.scss";
|
||||||
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
|
||||||
bodyshop: selectBodyshop,
|
|
||||||
chatVisible: selectChatVisible,
|
|
||||||
});
|
|
||||||
|
|
||||||
export function ChatAffixContainer({bodyshop, chatVisible}) {
|
export function ChatAffixContainer({bodyshop, chatVisible}) {
|
||||||
const {t} = useTranslation();
|
const {t} = useTranslation();
|
||||||
const client = useApolloClient();
|
const client = useApolloClient();
|
||||||
@@ -47,7 +38,6 @@ export function ChatAffixContainer({ bodyshop, chatVisible }) {
|
|||||||
<Button
|
<Button
|
||||||
onClick={async () => {
|
onClick={async () => {
|
||||||
await requestForToken();
|
await requestForToken();
|
||||||
|
|
||||||
SubscribeToTopic();
|
SubscribeToTopic();
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
@@ -81,16 +71,17 @@ export function ChatAffixContainer({ bodyshop, chatVisible }) {
|
|||||||
payload: (payload && payload.data && payload.data.data) || payload.data,
|
payload: (payload && payload.data && payload.data.data) || payload.data,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
let stopMessageListenr, channel;
|
|
||||||
|
let stopMessageListener, channel;
|
||||||
try {
|
try {
|
||||||
stopMessageListenr = onMessage(messaging, handleMessage);
|
stopMessageListener = onMessage(messaging, handleMessage);
|
||||||
channel = new BroadcastChannel("imex-sw-messages");
|
channel = new BroadcastChannel("imex-sw-messages");
|
||||||
channel.addEventListener("message", handleMessage);
|
channel.addEventListener("message", handleMessage);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log("Unable to set event listeners.");
|
console.log("Unable to set event listeners.");
|
||||||
}
|
}
|
||||||
return () => {
|
return () => {
|
||||||
stopMessageListenr && stopMessageListenr();
|
stopMessageListener && stopMessageListener();
|
||||||
channel && channel.removeEventListener("message", handleMessage);
|
channel && channel.removeEventListener("message", handleMessage);
|
||||||
};
|
};
|
||||||
}, [client]);
|
}, [client]);
|
||||||
@@ -103,4 +94,5 @@ export function ChatAffixContainer({ bodyshop, chatVisible }) {
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
export default connect(mapStateToProps, null)(ChatAffixContainer);
|
|
||||||
|
export default ChatAffixContainer;
|
||||||
@@ -1,19 +1,14 @@
|
|||||||
import { Badge, List, Tag } from "antd";
|
import {Badge, Card, List, Space, Tag} from "antd";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import {connect} from "react-redux";
|
import {connect} from "react-redux";
|
||||||
import {
|
import {AutoSizer, CellMeasurer, CellMeasurerCache, List as VirtualizedList,} from "react-virtualized";
|
||||||
AutoSizer,
|
|
||||||
CellMeasurer,
|
|
||||||
CellMeasurerCache,
|
|
||||||
List as VirtualizedList,
|
|
||||||
} from "react-virtualized";
|
|
||||||
import {createStructuredSelector} from "reselect";
|
import {createStructuredSelector} from "reselect";
|
||||||
import {setSelectedConversation} from "../../redux/messaging/messaging.actions";
|
import {setSelectedConversation} from "../../redux/messaging/messaging.actions";
|
||||||
import {selectSelectedConversation} from "../../redux/messaging/messaging.selectors";
|
import {selectSelectedConversation} from "../../redux/messaging/messaging.selectors";
|
||||||
import {TimeAgoFormatter} from "../../utils/DateFormatter";
|
import {TimeAgoFormatter} from "../../utils/DateFormatter";
|
||||||
import PhoneFormatter from "../../utils/PhoneFormatter";
|
import PhoneFormatter from "../../utils/PhoneFormatter";
|
||||||
import OwnerNameDisplay from "../owner-name-display/owner-name-display.component";
|
import {OwnerNameDisplayFunction} from "../owner-name-display/owner-name-display.component";
|
||||||
|
import _ from "lodash";
|
||||||
import "./chat-conversation-list.styles.scss";
|
import "./chat-conversation-list.styles.scss";
|
||||||
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
@@ -38,6 +33,36 @@ function ChatConversationListComponent({
|
|||||||
|
|
||||||
const rowRenderer = ({index, key, style, parent}) => {
|
const rowRenderer = ({index, key, style, parent}) => {
|
||||||
const item = conversationList[index];
|
const item = conversationList[index];
|
||||||
|
const cardContentRight =
|
||||||
|
<TimeAgoFormatter>{item.updated_at}</TimeAgoFormatter>;
|
||||||
|
const cardContentLeft = item.job_conversations.length > 0
|
||||||
|
? item.job_conversations.map((j, idx) => (
|
||||||
|
<Tag key={idx}>{j.job.ro_number}</Tag>
|
||||||
|
))
|
||||||
|
: null;
|
||||||
|
|
||||||
|
const names = <>{_.uniq(item.job_conversations.map((j, idx) =>
|
||||||
|
OwnerNameDisplayFunction(j.job)
|
||||||
|
))}</>
|
||||||
|
|
||||||
|
const cardTitle = <>
|
||||||
|
{item.label && <Tag color="blue">{item.label}</Tag>}
|
||||||
|
{item.job_conversations.length > 0 ? (
|
||||||
|
<Space direction="vertical">
|
||||||
|
{names}
|
||||||
|
</Space>
|
||||||
|
) : (
|
||||||
|
<Space>
|
||||||
|
<PhoneFormatter>{item.phone_num}</PhoneFormatter>
|
||||||
|
</Space>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
const cardExtra = <Badge count={item.messages_aggregate.aggregate.count || 0}/>
|
||||||
|
|
||||||
|
const getCardStyle = () =>
|
||||||
|
item.id === selectedConversation
|
||||||
|
? {backgroundColor: 'rgba(128, 128, 128, 0.2)'}
|
||||||
|
: {backgroundColor: index % 2 === 0 ? '#f0f2f5' : '#ffffff'};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<CellMeasurer
|
<CellMeasurer
|
||||||
@@ -49,44 +74,21 @@ function ChatConversationListComponent({
|
|||||||
>
|
>
|
||||||
<List.Item
|
<List.Item
|
||||||
onClick={() => setSelectedConversation(item.id)}
|
onClick={() => setSelectedConversation(item.id)}
|
||||||
className={`chat-list-item ${
|
style={style}
|
||||||
|
className={`chat-list-item
|
||||||
|
${
|
||||||
item.id === selectedConversation
|
item.id === selectedConversation
|
||||||
? "chat-list-selected-conversation"
|
? "chat-list-selected-conversation"
|
||||||
: null
|
: null
|
||||||
}`}
|
}`}
|
||||||
style={style}
|
|
||||||
>
|
>
|
||||||
|
<Card style={getCardStyle()} bordered={false} size="small" extra={cardExtra} title={cardTitle}>
|
||||||
|
<div style={{display: 'inline-block', width: '70%', textAlign: 'left'}}>
|
||||||
|
{cardContentLeft}
|
||||||
|
</div>
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{display: 'inline-block', width: '30%', textAlign: 'right'}}>{cardContentRight}</div>
|
||||||
display: "inline-block",
|
</Card>
|
||||||
}}
|
|
||||||
>
|
|
||||||
{item.label && <div className="chat-name">{item.label}</div>}
|
|
||||||
{item.job_conversations.length > 0 ? (
|
|
||||||
<div className="chat-name">
|
|
||||||
{item.job_conversations.map((j, idx) => (
|
|
||||||
<div key={idx}>
|
|
||||||
<OwnerNameDisplay ownerObject={j.job} />
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
) : (
|
|
||||||
<PhoneFormatter>{item.phone_num}</PhoneFormatter>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
<div style={{ display: "inline-block" }}>
|
|
||||||
<div>
|
|
||||||
{item.job_conversations.length > 0
|
|
||||||
? item.job_conversations.map((j, idx) => (
|
|
||||||
<Tag key={idx} className="ro-number-tag">
|
|
||||||
{j.job.ro_number}
|
|
||||||
</Tag>
|
|
||||||
))
|
|
||||||
: null}
|
|
||||||
</div>
|
|
||||||
<TimeAgoFormatter>{item.updated_at}</TimeAgoFormatter>
|
|
||||||
</div>
|
|
||||||
<Badge count={item.messages_aggregate.aggregate.count || 0} />
|
|
||||||
</List.Item>
|
</List.Item>
|
||||||
</CellMeasurer>
|
</CellMeasurer>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,27 +1,16 @@
|
|||||||
.chat-list-selected-conversation {
|
|
||||||
background-color: rgba(128, 128, 128, 0.2);
|
|
||||||
}
|
|
||||||
.chat-list-container {
|
.chat-list-container {
|
||||||
flex: 1;
|
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
border: 1px solid gainsboro;
|
border: 1px solid gainsboro;
|
||||||
}
|
}
|
||||||
|
|
||||||
.chat-list-item {
|
.chat-list-item {
|
||||||
display: flex;
|
.ant-card-head {
|
||||||
flex-direction: row;
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
color: #ff7a00;
|
color: #ff7a00;
|
||||||
}
|
}
|
||||||
.chat-name {
|
|
||||||
flex: 1;
|
|
||||||
display: inline;
|
|
||||||
}
|
|
||||||
.ro-number-tag {
|
|
||||||
align-self: baseline;
|
|
||||||
}
|
|
||||||
padding: 12px 24px;
|
|
||||||
border-bottom: 1px solid gainsboro;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,15 +2,13 @@ import { useMutation, useQuery, useSubscription } from "@apollo/client";
|
|||||||
import React, {useState} from "react";
|
import React, {useState} from "react";
|
||||||
import {connect} from "react-redux";
|
import {connect} from "react-redux";
|
||||||
import {createStructuredSelector} from "reselect";
|
import {createStructuredSelector} from "reselect";
|
||||||
import {
|
import {CONVERSATION_SUBSCRIPTION_BY_PK, GET_CONVERSATION_DETAILS,} from "../../graphql/conversations.queries";
|
||||||
CONVERSATION_SUBSCRIPTION_BY_PK,
|
|
||||||
GET_CONVERSATION_DETAILS,
|
|
||||||
} from "../../graphql/conversations.queries";
|
|
||||||
import {MARK_MESSAGES_AS_READ_BY_CONVERSATION} from "../../graphql/messages.queries";
|
import {MARK_MESSAGES_AS_READ_BY_CONVERSATION} from "../../graphql/messages.queries";
|
||||||
import {selectSelectedConversation} from "../../redux/messaging/messaging.selectors";
|
import {selectSelectedConversation} from "../../redux/messaging/messaging.selectors";
|
||||||
import ChatConversationComponent from "./chat-conversation.component";
|
import ChatConversationComponent from "./chat-conversation.component";
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import {selectBodyshop} from "../../redux/user/user.selectors";
|
import {selectBodyshop} from "../../redux/user/user.selectors";
|
||||||
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
selectedConversation: selectSelectedConversation,
|
selectedConversation: selectSelectedConversation,
|
||||||
bodyshop: selectBodyshop,
|
bodyshop: selectBodyshop,
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import { Input, notification, Spin, Tag, Tooltip } from "antd";
|
|||||||
import React, {useState} from "react";
|
import React, {useState} from "react";
|
||||||
import {useTranslation} from "react-i18next";
|
import {useTranslation} from "react-i18next";
|
||||||
import {UPDATE_CONVERSATION_LABEL} from "../../graphql/conversations.queries";
|
import {UPDATE_CONVERSATION_LABEL} from "../../graphql/conversations.queries";
|
||||||
|
|
||||||
export default function ChatLabel({conversation}) {
|
export default function ChatLabel({conversation}) {
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const [editing, setEditing] = useState(false);
|
const [editing, setEditing] = useState(false);
|
||||||
|
|||||||
@@ -9,7 +9,8 @@ import { GET_DOCUMENTS_BY_JOB } from "../../graphql/documents.queries";
|
|||||||
import {selectBodyshop} from "../../redux/user/user.selectors";
|
import {selectBodyshop} from "../../redux/user/user.selectors";
|
||||||
import AlertComponent from "../alert/alert.component";
|
import AlertComponent from "../alert/alert.component";
|
||||||
import JobDocumentsGalleryExternal from "../jobs-documents-gallery/jobs-documents-gallery.external.component";
|
import JobDocumentsGalleryExternal from "../jobs-documents-gallery/jobs-documents-gallery.external.component";
|
||||||
import JobDocumentsLocalGalleryExternal from "../jobs-documents-local-gallery/jobs-documents-local-gallery.external.component";
|
import JobDocumentsLocalGalleryExternal
|
||||||
|
from "../jobs-documents-local-gallery/jobs-documents-local-gallery.external.component";
|
||||||
import LoadingSpinner from "../loading-spinner/loading-spinner.component";
|
import LoadingSpinner from "../loading-spinner/loading-spinner.component";
|
||||||
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
@@ -27,7 +28,7 @@ export function ChatMediaSelector({
|
|||||||
conversation,
|
conversation,
|
||||||
}) {
|
}) {
|
||||||
const {t} = useTranslation();
|
const {t} = useTranslation();
|
||||||
const [visible, setVisible] = useState(false);
|
const [open, setOpen] = useState(false);
|
||||||
|
|
||||||
const {loading, error, data} = useQuery(GET_DOCUMENTS_BY_JOB, {
|
const {loading, error, data} = useQuery(GET_DOCUMENTS_BY_JOB, {
|
||||||
fetchPolicy: "network-only",
|
fetchPolicy: "network-only",
|
||||||
@@ -39,13 +40,13 @@ export function ChatMediaSelector({
|
|||||||
},
|
},
|
||||||
|
|
||||||
skip:
|
skip:
|
||||||
!visible ||
|
!open ||
|
||||||
!conversation.job_conversations ||
|
!conversation.job_conversations ||
|
||||||
conversation.job_conversations.length === 0,
|
conversation.job_conversations.length === 0,
|
||||||
});
|
});
|
||||||
|
|
||||||
const handleVisibleChange = (visible) => {
|
const handleVisibleChange = (change) => {
|
||||||
setVisible(visible);
|
setOpen(change);
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -65,7 +66,7 @@ export function ChatMediaSelector({
|
|||||||
externalMediaState={[selectedMedia, setSelectedMedia]}
|
externalMediaState={[selectedMedia, setSelectedMedia]}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{bodyshop.uselocalmediaserver && visible && (
|
{bodyshop.uselocalmediaserver && open && (
|
||||||
<JobDocumentsLocalGalleryExternal
|
<JobDocumentsLocalGalleryExternal
|
||||||
externalMediaState={[selectedMedia, setSelectedMedia]}
|
externalMediaState={[selectedMedia, setSelectedMedia]}
|
||||||
jobId={
|
jobId={
|
||||||
@@ -88,8 +89,8 @@ export function ChatMediaSelector({
|
|||||||
}
|
}
|
||||||
title={t("messaging.labels.selectmedia")}
|
title={t("messaging.labels.selectmedia")}
|
||||||
trigger="click"
|
trigger="click"
|
||||||
visible={visible}
|
open={open}
|
||||||
onVisibleChange={handleVisibleChange}
|
onOpenChange={handleVisibleChange}
|
||||||
>
|
>
|
||||||
<Badge count={selectedMedia.filter((s) => s.isSelected).length}>
|
<Badge count={selectedMedia.filter((s) => s.isSelected).length}>
|
||||||
<PictureFilled style={{margin: "0 .5rem"}}/>
|
<PictureFilled style={{margin: "0 .5rem"}}/>
|
||||||
|
|||||||
@@ -1,15 +1,10 @@
|
|||||||
import Icon from "@ant-design/icons";
|
import Icon from "@ant-design/icons";
|
||||||
import {Tooltip} from "antd";
|
import {Tooltip} from "antd";
|
||||||
import i18n from "i18next";
|
import i18n from "i18next";
|
||||||
import moment from "moment";
|
import dayjs from "../../utils/day";
|
||||||
import React, {useEffect, useRef} from "react";
|
import React, {useEffect, useRef} from "react";
|
||||||
import {MdDone, MdDoneAll} from "react-icons/md";
|
import {MdDone, MdDoneAll} from "react-icons/md";
|
||||||
import {
|
import {AutoSizer, CellMeasurer, CellMeasurerCache, List,} from "react-virtualized";
|
||||||
AutoSizer,
|
|
||||||
CellMeasurer,
|
|
||||||
CellMeasurerCache,
|
|
||||||
List,
|
|
||||||
} from "react-virtualized";
|
|
||||||
import {DateTimeFormatter} from "../../utils/DateFormatter";
|
import {DateTimeFormatter} from "../../utils/DateFormatter";
|
||||||
import "./chat-message-list.styles.scss";
|
import "./chat-message-list.styles.scss";
|
||||||
|
|
||||||
@@ -52,7 +47,7 @@ export default function ChatMessageListComponent({ messages }) {
|
|||||||
<div style={{fontSize: 10}}>
|
<div style={{fontSize: 10}}>
|
||||||
{i18n.t("messaging.labels.sentby", {
|
{i18n.t("messaging.labels.sentby", {
|
||||||
by: messages[index].userid,
|
by: messages[index].userid,
|
||||||
time: moment(messages[index].created_at).format(
|
time: dayjs(messages[index].created_at).format(
|
||||||
"MM/DD/YYYY @ hh:mm a"
|
"MM/DD/YYYY @ hh:mm a"
|
||||||
),
|
),
|
||||||
})}
|
})}
|
||||||
|
|||||||
@@ -44,6 +44,7 @@
|
|||||||
.yours {
|
.yours {
|
||||||
align-items: flex-start;
|
align-items: flex-start;
|
||||||
}
|
}
|
||||||
|
|
||||||
.msgmargin {
|
.msgmargin {
|
||||||
margin-top: 0.1rem;
|
margin-top: 0.1rem;
|
||||||
margin-bottom: 0.1rem;
|
margin-bottom: 0.1rem;
|
||||||
@@ -66,6 +67,7 @@
|
|||||||
background: #eee;
|
background: #eee;
|
||||||
border-bottom-right-radius: 15px;
|
border-bottom-right-radius: 15px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.yours .message.last:after {
|
.yours .message.last:after {
|
||||||
content: "";
|
content: "";
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
|||||||
@@ -5,9 +5,7 @@ import { useTranslation } from "react-i18next";
|
|||||||
import {connect} from "react-redux";
|
import {connect} from "react-redux";
|
||||||
import {createStructuredSelector} from "reselect";
|
import {createStructuredSelector} from "reselect";
|
||||||
import {openChatByPhone} from "../../redux/messaging/messaging.actions";
|
import {openChatByPhone} from "../../redux/messaging/messaging.actions";
|
||||||
import PhoneFormItem, {
|
import PhoneFormItem, {PhoneItemFormatterValidation,} from "../form-items-formatted/phone-form-item.component";
|
||||||
PhoneItemFormatterValidation,
|
|
||||||
} from "../form-items-formatted/phone-form-item.component";
|
|
||||||
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
//currentUser: selectCurrentUser
|
//currentUser: selectCurrentUser
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import PhoneNumberFormatter from "../../utils/PhoneFormatter";
|
|||||||
import {createStructuredSelector} from "reselect";
|
import {createStructuredSelector} from "reselect";
|
||||||
import {selectBodyshop} from "../../redux/user/user.selectors";
|
import {selectBodyshop} from "../../redux/user/user.selectors";
|
||||||
import {searchingForConversation} from "../../redux/messaging/messaging.selectors";
|
import {searchingForConversation} from "../../redux/messaging/messaging.selectors";
|
||||||
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
bodyshop: selectBodyshop,
|
bodyshop: selectBodyshop,
|
||||||
searchingForConversation: searchingForConversation,
|
searchingForConversation: searchingForConversation,
|
||||||
@@ -49,4 +50,5 @@ export function ChatOpenButton({
|
|||||||
</a>
|
</a>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default connect(mapStateToProps, mapDispatchToProps)(ChatOpenButton);
|
export default connect(mapStateToProps, mapDispatchToProps)(ChatOpenButton);
|
||||||
|
|||||||
@@ -1,24 +1,13 @@
|
|||||||
import {
|
import {InfoCircleOutlined, MessageOutlined, ShrinkOutlined, SyncOutlined,} from "@ant-design/icons";
|
||||||
InfoCircleOutlined,
|
|
||||||
MessageOutlined,
|
|
||||||
ShrinkOutlined,
|
|
||||||
SyncOutlined,
|
|
||||||
} from "@ant-design/icons";
|
|
||||||
import {useLazyQuery, useQuery} from "@apollo/client";
|
import {useLazyQuery, useQuery} from "@apollo/client";
|
||||||
import {Badge, Card, Col, Row, Space, Tag, Tooltip, Typography} from "antd";
|
import {Badge, Card, Col, Row, Space, Tag, Tooltip, Typography} from "antd";
|
||||||
import React, {useCallback, useEffect, useState} from "react";
|
import React, {useCallback, useEffect, useState} from "react";
|
||||||
import {useTranslation} from "react-i18next";
|
import {useTranslation} from "react-i18next";
|
||||||
import {connect} from "react-redux";
|
import {connect} from "react-redux";
|
||||||
import {createStructuredSelector} from "reselect";
|
import {createStructuredSelector} from "reselect";
|
||||||
import {
|
import {CONVERSATION_LIST_QUERY, UNREAD_CONVERSATION_COUNT,} from "../../graphql/conversations.queries";
|
||||||
CONVERSATION_LIST_QUERY,
|
|
||||||
UNREAD_CONVERSATION_COUNT,
|
|
||||||
} from "../../graphql/conversations.queries";
|
|
||||||
import {toggleChatVisible} from "../../redux/messaging/messaging.actions";
|
import {toggleChatVisible} from "../../redux/messaging/messaging.actions";
|
||||||
import {
|
import {selectChatVisible, selectSelectedConversation,} from "../../redux/messaging/messaging.selectors";
|
||||||
selectChatVisible,
|
|
||||||
selectSelectedConversation,
|
|
||||||
} from "../../redux/messaging/messaging.selectors";
|
|
||||||
import ChatConversationListComponent from "../chat-conversation-list/chat-conversation-list.component";
|
import ChatConversationListComponent from "../chat-conversation-list/chat-conversation-list.component";
|
||||||
import ChatConversationContainer from "../chat-conversation/chat-conversation.container";
|
import ChatConversationContainer from "../chat-conversation/chat-conversation.container";
|
||||||
import ChatNewConversation from "../chat-new-conversation/chat-new-conversation.component";
|
import ChatNewConversation from "../chat-new-conversation/chat-new-conversation.component";
|
||||||
@@ -140,4 +129,5 @@ export function ChatPopupComponent({
|
|||||||
</Badge>
|
</Badge>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default connect(mapStateToProps, mapDispatchToProps)(ChatPopupComponent);
|
export default connect(mapStateToProps, mapDispatchToProps)(ChatPopupComponent);
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.chat-popup-info-icon {
|
.chat-popup-info-icon {
|
||||||
margin-right: 5px;
|
margin-right: 5px;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import {PlusCircleOutlined} from "@ant-design/icons";
|
import {PlusCircleOutlined} from "@ant-design/icons";
|
||||||
import { Dropdown, Menu } from "antd";
|
import {Dropdown} from "antd";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import {connect} from "react-redux";
|
import {connect} from "react-redux";
|
||||||
import {createStructuredSelector} from "reselect";
|
import {createStructuredSelector} from "reselect";
|
||||||
@@ -16,24 +16,22 @@ const mapDispatchToProps = (dispatch) => ({
|
|||||||
});
|
});
|
||||||
|
|
||||||
export function ChatPresetsComponent({bodyshop, setMessage, className}) {
|
export function ChatPresetsComponent({bodyshop, setMessage, className}) {
|
||||||
const menu = (
|
|
||||||
<Menu>
|
const items = bodyshop.md_messaging_presets.map((i, idx) => ({
|
||||||
{bodyshop.md_messaging_presets.map((i, idx) => (
|
key: idx,
|
||||||
<Menu.Item onClick={() => setMessage(i.text)} key={idx}>
|
label: (i.label),
|
||||||
{i.label}
|
onClick: () => setMessage(i.text),
|
||||||
</Menu.Item>
|
}));
|
||||||
))}
|
|
||||||
</Menu>
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={className}>
|
<div className={className}>
|
||||||
<Dropdown trigger={["click"]} overlay={menu}>
|
<Dropdown trigger={["click"]} menu={{items}}>
|
||||||
<PlusCircleOutlined/>
|
<PlusCircleOutlined/>
|
||||||
</Dropdown>
|
</Dropdown>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default connect(
|
export default connect(
|
||||||
mapStateToProps,
|
mapStateToProps,
|
||||||
mapDispatchToProps
|
mapDispatchToProps
|
||||||
|
|||||||
@@ -16,44 +16,31 @@ const mapDispatchToProps = (dispatch) => ({
|
|||||||
export function ChatPrintButton({conversation}) {
|
export function ChatPrintButton({conversation}) {
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
|
|
||||||
|
const generateDocument = (type) => {
|
||||||
|
setLoading(true);
|
||||||
|
GenerateDocument(
|
||||||
|
{
|
||||||
|
name: TemplateList("messaging").conversation_list.key,
|
||||||
|
variables: {id: conversation.id},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
subject: TemplateList("messaging").conversation_list.subject,
|
||||||
|
},
|
||||||
|
type,
|
||||||
|
conversation.id
|
||||||
|
).catch(e => {
|
||||||
|
console.warn('Something went wrong generating a document.');
|
||||||
|
});
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Space wrap>
|
<Space wrap>
|
||||||
<PrinterOutlined
|
<PrinterOutlined onClick={() => generateDocument('p')}/>
|
||||||
onClick={() => {
|
<MailOutlined onClick={() => generateDocument('e')}/>
|
||||||
setLoading(true);
|
|
||||||
GenerateDocument(
|
|
||||||
{
|
|
||||||
name: TemplateList("messaging").conversation_list.key,
|
|
||||||
variables: { id: conversation.id },
|
|
||||||
},
|
|
||||||
{
|
|
||||||
subject: TemplateList("messaging").conversation_list.subject,
|
|
||||||
},
|
|
||||||
"p",
|
|
||||||
conversation.id
|
|
||||||
);
|
|
||||||
setLoading(false);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<MailOutlined
|
|
||||||
onClick={() => {
|
|
||||||
setLoading(true);
|
|
||||||
GenerateDocument(
|
|
||||||
{
|
|
||||||
name: TemplateList("messaging").conversation_list.key,
|
|
||||||
variables: { id: conversation.id },
|
|
||||||
},
|
|
||||||
{
|
|
||||||
subject: TemplateList("messaging").conversation_list.subject,
|
|
||||||
},
|
|
||||||
"e",
|
|
||||||
conversation.id
|
|
||||||
);
|
|
||||||
setLoading(false);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
{loading && <Spin/>}
|
{loading && <Spin/>}
|
||||||
</Space>
|
</Space>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default connect(mapStateToProps, mapDispatchToProps)(ChatPrintButton);
|
export default connect(mapStateToProps, mapDispatchToProps)(ChatPrintButton);
|
||||||
|
|||||||
@@ -5,14 +5,8 @@ import { useTranslation } from "react-i18next";
|
|||||||
import {connect} from "react-redux";
|
import {connect} from "react-redux";
|
||||||
import {createStructuredSelector} from "reselect";
|
import {createStructuredSelector} from "reselect";
|
||||||
import {logImEXEvent} from "../../firebase/firebase.utils";
|
import {logImEXEvent} from "../../firebase/firebase.utils";
|
||||||
import {
|
import {sendMessage, setMessage,} from "../../redux/messaging/messaging.actions";
|
||||||
sendMessage,
|
import {selectIsSending, selectMessage,} from "../../redux/messaging/messaging.selectors";
|
||||||
setMessage,
|
|
||||||
} from "../../redux/messaging/messaging.actions";
|
|
||||||
import {
|
|
||||||
selectIsSending,
|
|
||||||
selectMessage,
|
|
||||||
} from "../../redux/messaging/messaging.selectors";
|
|
||||||
import {selectBodyshop} from "../../redux/user/user.selectors";
|
import {selectBodyshop} from "../../redux/user/user.selectors";
|
||||||
import ChatMediaSelector from "../chat-media-selector/chat-media-selector.component";
|
import ChatMediaSelector from "../chat-media-selector/chat-media-selector.component";
|
||||||
import ChatPresetsComponent from "../chat-presets/chat-presets.component";
|
import ChatPresetsComponent from "../chat-presets/chat-presets.component";
|
||||||
@@ -110,6 +104,7 @@ function ChatSendMessageComponent({
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default connect(
|
export default connect(
|
||||||
mapStateToProps,
|
mapStateToProps,
|
||||||
mapDispatchToProps
|
mapDispatchToProps
|
||||||
|
|||||||
@@ -9,17 +9,17 @@ export default function ChatTagRoComponent({
|
|||||||
loading,
|
loading,
|
||||||
handleSearch,
|
handleSearch,
|
||||||
handleInsertTag,
|
handleInsertTag,
|
||||||
setVisible,
|
setOpen,
|
||||||
}) {
|
}) {
|
||||||
const {t} = useTranslation();
|
const {t} = useTranslation();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Space flex>
|
<Space>
|
||||||
<div style={{width: "15rem"}}>
|
<div style={{width: "15rem"}}>
|
||||||
<Select
|
<Select
|
||||||
showSearch
|
showSearch
|
||||||
autoFocus
|
autoFocus
|
||||||
dropdownMatchSelectWidth
|
popupMatchSelectWidth
|
||||||
placeholder={t("general.labels.search")}
|
placeholder={t("general.labels.search")}
|
||||||
filterOption={false}
|
filterOption={false}
|
||||||
onSearch={handleSearch}
|
onSearch={handleSearch}
|
||||||
@@ -38,7 +38,7 @@ export default function ChatTagRoComponent({
|
|||||||
{loading ? (
|
{loading ? (
|
||||||
<LoadingOutlined/>
|
<LoadingOutlined/>
|
||||||
) : (
|
) : (
|
||||||
<CloseCircleOutlined onClick={() => setVisible(false)} />
|
<CloseCircleOutlined onClick={() => setOpen(false)}/>
|
||||||
)}
|
)}
|
||||||
</Space>
|
</Space>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import ChatTagRo from "./chat-tag-ro.component";
|
|||||||
|
|
||||||
export default function ChatTagRoContainer({conversation}) {
|
export default function ChatTagRoContainer({conversation}) {
|
||||||
const {t} = useTranslation();
|
const {t} = useTranslation();
|
||||||
const [visible, setVisible] = useState(false);
|
const [open, setOpen] = useState(false);
|
||||||
|
|
||||||
const [loadRo, {loading, data}] = useLazyQuery(SEARCH_FOR_JOBS);
|
const [loadRo, {loading, data}] = useLazyQuery(SEARCH_FOR_JOBS);
|
||||||
|
|
||||||
@@ -33,7 +33,7 @@ export default function ChatTagRoContainer({ conversation }) {
|
|||||||
const handleInsertTag = (value, option) => {
|
const handleInsertTag = (value, option) => {
|
||||||
logImEXEvent("messaging_add_job_tag");
|
logImEXEvent("messaging_add_job_tag");
|
||||||
insertTag({variables: {jobId: option.key}});
|
insertTag({variables: {jobId: option.key}});
|
||||||
setVisible(false);
|
setOpen(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
const existingJobTags =
|
const existingJobTags =
|
||||||
@@ -47,16 +47,16 @@ export default function ChatTagRoContainer({ conversation }) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
{visible ? (
|
{open ? (
|
||||||
<ChatTagRo
|
<ChatTagRo
|
||||||
loading={loading}
|
loading={loading}
|
||||||
roOptions={roOptions}
|
roOptions={roOptions}
|
||||||
handleSearch={handleSearch}
|
handleSearch={handleSearch}
|
||||||
handleInsertTag={handleInsertTag}
|
handleInsertTag={handleInsertTag}
|
||||||
setVisible={setVisible}
|
setOpen={setOpen}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<Tag onClick={() => setVisible(true)}>
|
<Tag onClick={() => setOpen(true)}>
|
||||||
<PlusOutlined/>
|
<PlusOutlined/>
|
||||||
{t("messaging.actions.link")}
|
{t("messaging.actions.link")}
|
||||||
</Tag>
|
</Tag>
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import Rate from "./rate/rate.component";
|
|||||||
import Slider from "./slider/slider.component";
|
import Slider from "./slider/slider.component";
|
||||||
import Text from "./text/text.component";
|
import Text from "./text/text.component";
|
||||||
import Textarea from "./textarea/textarea.component";
|
import Textarea from "./textarea/textarea.component";
|
||||||
|
|
||||||
const e = {
|
const e = {
|
||||||
checkbox: CheckboxFormItem,
|
checkbox: CheckboxFormItem,
|
||||||
slider: Slider,
|
slider: Slider,
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import { Result, Button } from "antd";
|
import {Button, Result} from "antd";
|
||||||
import {useTranslation} from "react-i18next";
|
import {useTranslation} from "react-i18next";
|
||||||
|
|
||||||
export default function ConflictComponent() {
|
export default function ConflictComponent() {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import {useQuery} from "@apollo/client";
|
import {useQuery} from "@apollo/client";
|
||||||
import moment from "moment";
|
import dayjs from "../../utils/day";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import {QUERY_AVAILABLE_CC} from "../../graphql/courtesy-car.queries";
|
import {QUERY_AVAILABLE_CC} from "../../graphql/courtesy-car.queries";
|
||||||
import AlertComponent from "../alert/alert.component";
|
import AlertComponent from "../alert/alert.component";
|
||||||
@@ -7,7 +7,7 @@ import ContractCarsComponent from "./contract-cars.component";
|
|||||||
|
|
||||||
export default function ContractCarsContainer({selectedCarState, form}) {
|
export default function ContractCarsContainer({selectedCarState, form}) {
|
||||||
const {loading, error, data} = useQuery(QUERY_AVAILABLE_CC, {
|
const {loading, error, data} = useQuery(QUERY_AVAILABLE_CC, {
|
||||||
variables: { today: moment().format("YYYY-MM-DD") },
|
variables: {today: dayjs().format("YYYY-MM-DD")},
|
||||||
fetchPolicy: "network-only",
|
fetchPolicy: "network-only",
|
||||||
nextFetchPolicy: "network-only",
|
nextFetchPolicy: "network-only",
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,26 +1,14 @@
|
|||||||
import {useMutation} from "@apollo/client";
|
import {useMutation} from "@apollo/client";
|
||||||
import {
|
import {Button, Form, InputNumber, notification, Popover, Radio, Select, Space,} from "antd";
|
||||||
Button,
|
|
||||||
Form,
|
|
||||||
InputNumber,
|
|
||||||
notification,
|
|
||||||
Popover,
|
|
||||||
Radio,
|
|
||||||
Select,
|
|
||||||
Space,
|
|
||||||
} from "antd";
|
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import moment from "moment";
|
import dayjs from "../../utils/day";
|
||||||
import React, {useState} from "react";
|
import React, {useState} from "react";
|
||||||
import {useTranslation} from "react-i18next";
|
import {useTranslation} from "react-i18next";
|
||||||
import {connect} from "react-redux";
|
import {connect} from "react-redux";
|
||||||
import { useHistory } from "react-router-dom";
|
import {useNavigate} from "react-router-dom";
|
||||||
import {createStructuredSelector} from "reselect";
|
import {createStructuredSelector} from "reselect";
|
||||||
import {INSERT_NEW_JOB} from "../../graphql/jobs.queries";
|
import {INSERT_NEW_JOB} from "../../graphql/jobs.queries";
|
||||||
import {
|
import {selectBodyshop, selectCurrentUser,} from "../../redux/user/user.selectors";
|
||||||
selectBodyshop,
|
|
||||||
selectCurrentUser,
|
|
||||||
} from "../../redux/user/user.selectors";
|
|
||||||
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
//currentUser: selectCurrentUser
|
//currentUser: selectCurrentUser
|
||||||
@@ -38,17 +26,17 @@ export function ContractConvertToRo({
|
|||||||
disabled,
|
disabled,
|
||||||
}) {
|
}) {
|
||||||
const {t} = useTranslation();
|
const {t} = useTranslation();
|
||||||
const [visible, setVisible] = useState(false);
|
const [open, setOpen] = useState(false);
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const [insertJob] = useMutation(INSERT_NEW_JOB);
|
const [insertJob] = useMutation(INSERT_NEW_JOB);
|
||||||
const history = useHistory();
|
const history = useNavigate();
|
||||||
|
|
||||||
const handleFinish = async (values) => {
|
const handleFinish = async (values) => {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
|
|
||||||
const contractLength = moment(contract.actualreturn).diff(
|
const contractLength = dayjs(contract.actualreturn).diff(
|
||||||
moment(contract.start),
|
dayjs(contract.start),
|
||||||
"days"
|
"day"
|
||||||
);
|
);
|
||||||
const billingLines = [];
|
const billingLines = [];
|
||||||
if (contractLength > 0)
|
if (contractLength > 0)
|
||||||
@@ -306,7 +294,7 @@ export function ContractConvertToRo({
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
setVisible(false);
|
setOpen(false);
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -380,7 +368,7 @@ export function ContractConvertToRo({
|
|||||||
<Button type="primary" htmlType="submit" loading={loading}>
|
<Button type="primary" htmlType="submit" loading={loading}>
|
||||||
{t("contracts.actions.convertoro")}
|
{t("contracts.actions.convertoro")}
|
||||||
</Button>
|
</Button>
|
||||||
<Button onClick={() => setVisible(false)}>
|
<Button onClick={() => setOpen(false)}>
|
||||||
{t("general.actions.close")}
|
{t("general.actions.close")}
|
||||||
</Button>
|
</Button>
|
||||||
</Space>
|
</Space>
|
||||||
@@ -390,9 +378,9 @@ export function ContractConvertToRo({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<Popover content={popContent} visible={visible}>
|
<Popover content={popContent} open={open}>
|
||||||
<Button
|
<Button
|
||||||
onClick={() => setVisible(true)}
|
onClick={() => setOpen(true)}
|
||||||
loading={loading}
|
loading={loading}
|
||||||
disabled={!contract.dailyrate || !contract.actualreturn || disabled}
|
disabled={!contract.dailyrate || !contract.actualreturn || disabled}
|
||||||
>
|
>
|
||||||
@@ -402,6 +390,7 @@ export function ContractConvertToRo({
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default connect(
|
export default connect(
|
||||||
mapStateToProps,
|
mapStateToProps,
|
||||||
mapDispatchToProps
|
mapDispatchToProps
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { Button, notification } from "antd";
|
|||||||
import React, {useEffect} from "react";
|
import React, {useEffect} from "react";
|
||||||
import {useTranslation} from "react-i18next";
|
import {useTranslation} from "react-i18next";
|
||||||
import {GET_JOB_FOR_CC_CONTRACT} from "../../graphql/jobs.queries";
|
import {GET_JOB_FOR_CC_CONTRACT} from "../../graphql/jobs.queries";
|
||||||
|
|
||||||
export default function ContractCreateJobPrefillComponent({jobId, form}) {
|
export default function ContractCreateJobPrefillComponent({jobId, form}) {
|
||||||
const [call, {loading, error, data}] = useLazyQuery(
|
const [call, {loading, error, data}] = useLazyQuery(
|
||||||
GET_JOB_FOR_CC_CONTRACT
|
GET_JOB_FOR_CC_CONTRACT
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import {WarningFilled} from "@ant-design/icons";
|
import {WarningFilled} from "@ant-design/icons";
|
||||||
import {Form, Input, InputNumber, Space} from "antd";
|
import {Form, Input, InputNumber, Space} from "antd";
|
||||||
import moment from "moment";
|
import dayjs from "../../utils/day";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import {useTranslation} from "react-i18next";
|
import {useTranslation} from "react-i18next";
|
||||||
import {DateFormatter} from "../../utils/DateFormatter";
|
import {DateFormatter} from "../../utils/DateFormatter";
|
||||||
@@ -11,9 +11,7 @@ import CourtesyCarFuelSlider from "../courtesy-car-fuel-select/courtesy-car-fuel
|
|||||||
import FormDatePicker from "../form-date-picker/form-date-picker.component";
|
import FormDatePicker from "../form-date-picker/form-date-picker.component";
|
||||||
import FormDateTimePicker from "../form-date-time-picker/form-date-time-picker.component";
|
import FormDateTimePicker from "../form-date-time-picker/form-date-time-picker.component";
|
||||||
import FormFieldsChanged from "../form-fields-changed-alert/form-fields-changed-alert.component";
|
import FormFieldsChanged from "../form-fields-changed-alert/form-fields-changed-alert.component";
|
||||||
import InputPhone, {
|
import InputPhone, {PhoneItemFormatterValidation,} from "../form-items-formatted/phone-form-item.component";
|
||||||
PhoneItemFormatterValidation,
|
|
||||||
} from "../form-items-formatted/phone-form-item.component";
|
|
||||||
import LayoutFormRow from "../layout-form-row/layout-form-row.component";
|
import LayoutFormRow from "../layout-form-row/layout-form-row.component";
|
||||||
import ContractFormJobPrefill from "./contract-form-job-prefill.component";
|
import ContractFormJobPrefill from "./contract-form-job-prefill.component";
|
||||||
|
|
||||||
@@ -96,8 +94,8 @@ export default function ContractFormComponent({
|
|||||||
const dueForService =
|
const dueForService =
|
||||||
selectedCar &&
|
selectedCar &&
|
||||||
selectedCar.nextservicedate &&
|
selectedCar.nextservicedate &&
|
||||||
moment(selectedCar.nextservicedate).isBefore(
|
dayjs(selectedCar.nextservicedate).isBefore(
|
||||||
moment(form.getFieldValue("scheduledreturn"))
|
dayjs(form.getFieldValue("scheduledreturn"))
|
||||||
);
|
);
|
||||||
|
|
||||||
if (mileageOver || dueForService)
|
if (mileageOver || dueForService)
|
||||||
@@ -190,9 +188,9 @@ export default function ContractFormComponent({
|
|||||||
}
|
}
|
||||||
>
|
>
|
||||||
{() => {
|
{() => {
|
||||||
const dlExpiresBeforeReturn = moment(
|
const dlExpiresBeforeReturn = dayjs(
|
||||||
form.getFieldValue("driver_dlexpiry")
|
form.getFieldValue("driver_dlexpiry")
|
||||||
).isBefore(moment(form.getFieldValue("scheduledreturn")));
|
).isBefore(dayjs(form.getFieldValue("scheduledreturn")));
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import { useTranslation } from "react-i18next";
|
|||||||
import {Link} from "react-router-dom";
|
import {Link} from "react-router-dom";
|
||||||
import DataLabel from "../data-label/data-label.component";
|
import DataLabel from "../data-label/data-label.component";
|
||||||
import OwnerNameDisplay from "../owner-name-display/owner-name-display.component";
|
import OwnerNameDisplay from "../owner-name-display/owner-name-display.component";
|
||||||
|
|
||||||
export default function ContractJobBlock({job}) {
|
export default function ContractJobBlock({job}) {
|
||||||
const {t} = useTranslation();
|
const {t} = useTranslation();
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ const mapStateToProps = createStructuredSelector({
|
|||||||
//currentUser: selectCurrentUser
|
//currentUser: selectCurrentUser
|
||||||
bodyshop: selectBodyshop,
|
bodyshop: selectBodyshop,
|
||||||
});
|
});
|
||||||
|
|
||||||
export function ContractJobsContainer({selectedJobState, bodyshop}) {
|
export function ContractJobsContainer({selectedJobState, bodyshop}) {
|
||||||
const {loading, error, data} = useQuery(QUERY_ALL_ACTIVE_JOBS, {
|
const {loading, error, data} = useQuery(QUERY_ALL_ACTIVE_JOBS, {
|
||||||
variables: {
|
variables: {
|
||||||
@@ -36,4 +37,5 @@ export function ContractJobsContainer({ selectedJobState, bodyshop }) {
|
|||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default connect(mapStateToProps, null)(ContractJobsContainer);
|
export default connect(mapStateToProps, null)(ContractJobsContainer);
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import {Button, Input, Modal, Typography} from "antd";
|
import {Button, Input, Modal, Typography} from "antd";
|
||||||
import moment from "moment";
|
import dayjs from "../../utils/day";
|
||||||
import React, {useState} from "react";
|
import React, {useState} from "react";
|
||||||
import {useTranslation} from "react-i18next";
|
import {useTranslation} from "react-i18next";
|
||||||
import aamva from "../../utils/aamva";
|
import aamva from "../../utils/aamva";
|
||||||
@@ -26,8 +26,8 @@ export default function ContractLicenseDecodeButton({ form }) {
|
|||||||
|
|
||||||
const values = {
|
const values = {
|
||||||
driver_dlnumber: decodedBarcode.dl,
|
driver_dlnumber: decodedBarcode.dl,
|
||||||
driver_dlexpiry: moment(
|
driver_dlexpiry: dayjs(
|
||||||
`20${decodedBarcode.expiration_date}${moment(
|
`20${decodedBarcode.expiration_date}${dayjs(
|
||||||
decodedBarcode.birthday
|
decodedBarcode.birthday
|
||||||
).format("DD")}`
|
).format("DD")}`
|
||||||
),
|
),
|
||||||
@@ -38,7 +38,7 @@ export default function ContractLicenseDecodeButton({ form }) {
|
|||||||
driver_city: decodedBarcode.city,
|
driver_city: decodedBarcode.city,
|
||||||
driver_state: decodedBarcode.state,
|
driver_state: decodedBarcode.state,
|
||||||
driver_zip: decodedBarcode.postal_code,
|
driver_zip: decodedBarcode.postal_code,
|
||||||
driver_dob: moment(decodedBarcode.birthday),
|
driver_dob: dayjs(decodedBarcode.birthday),
|
||||||
};
|
};
|
||||||
|
|
||||||
form.setFieldsValue(values);
|
form.setFieldsValue(values);
|
||||||
@@ -55,7 +55,7 @@ export default function ContractLicenseDecodeButton({ form }) {
|
|||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<Modal
|
<Modal
|
||||||
visible={modalVisible}
|
open={modalVisible}
|
||||||
okText={t("contracts.actions.senddltoform")}
|
okText={t("contracts.actions.senddltoform")}
|
||||||
onOk={handleInsertForm}
|
onOk={handleInsertForm}
|
||||||
okButtonProps={{disabled: !!!decodedBarcode}}
|
okButtonProps={{disabled: !!!decodedBarcode}}
|
||||||
@@ -94,14 +94,14 @@ export default function ContractLicenseDecodeButton({ form }) {
|
|||||||
{decodedBarcode.address}
|
{decodedBarcode.address}
|
||||||
</DataLabel>
|
</DataLabel>
|
||||||
<DataLabel label={t("contracts.fields.driver_dlexpiry")}>
|
<DataLabel label={t("contracts.fields.driver_dlexpiry")}>
|
||||||
{moment(
|
{dayjs(
|
||||||
`20${decodedBarcode.expiration_date}${moment(
|
`20${decodedBarcode.expiration_date}${dayjs(
|
||||||
decodedBarcode.birthday
|
decodedBarcode.birthday
|
||||||
).format("DD")}`
|
).format("DD")}`
|
||||||
).format("MM/DD/YYYY")}
|
).format("MM/DD/YYYY")}
|
||||||
</DataLabel>
|
</DataLabel>
|
||||||
<DataLabel label={t("contracts.fields.driver_dob")}>
|
<DataLabel label={t("contracts.fields.driver_dob")}>
|
||||||
{moment(decodedBarcode.birthday).format("MM/DD/YYYY")}
|
{dayjs(decodedBarcode.birthday).format("MM/DD/YYYY")}
|
||||||
</DataLabel>
|
</DataLabel>
|
||||||
<div>
|
<div>
|
||||||
<Typography.Title level={4}>
|
<Typography.Title level={4}>
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import React, { useState, useEffect, forwardRef } from "react";
|
import React, {forwardRef, useEffect, useState} from "react";
|
||||||
import {Select} from "antd";
|
import {Select} from "antd";
|
||||||
import {useTranslation} from "react-i18next";
|
import {useTranslation} from "react-i18next";
|
||||||
|
|
||||||
const {Option} = Select;
|
const {Option} = Select;
|
||||||
|
|
||||||
const ContractStatusComponent = ({value, onChange}, ref) => {
|
const ContractStatusComponent = ({value, onChange}, ref) => {
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ export function ContractsFindModalContainer({
|
|||||||
}) {
|
}) {
|
||||||
const {t} = useTranslation();
|
const {t} = useTranslation();
|
||||||
|
|
||||||
const { visible } = contractFinderModal;
|
const {open} = contractFinderModal;
|
||||||
|
|
||||||
const [form] = Form.useForm();
|
const [form] = Form.useForm();
|
||||||
|
|
||||||
@@ -52,14 +52,14 @@ export function ContractsFindModalContainer({
|
|||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (visible) {
|
if (open) {
|
||||||
form.resetFields();
|
form.resetFields();
|
||||||
}
|
}
|
||||||
}, [visible, form]);
|
}, [open, form]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
visible={visible}
|
open={open}
|
||||||
width="70%"
|
width="70%"
|
||||||
title={t("contracts.labels.findermodal")}
|
title={t("contracts.labels.findermodal")}
|
||||||
onCancel={() => toggleModalVisible()}
|
onCancel={() => toggleModalVisible()}
|
||||||
|
|||||||
@@ -3,13 +3,13 @@ import { Button, Card, Input, Space, Table, Typography } from "antd";
|
|||||||
import queryString from "query-string";
|
import queryString from "query-string";
|
||||||
import React, {useState} from "react";
|
import React, {useState} from "react";
|
||||||
import {useTranslation} from "react-i18next";
|
import {useTranslation} from "react-i18next";
|
||||||
import { Link, useHistory, useLocation } from "react-router-dom";
|
import {Link, useLocation, useNavigate} from "react-router-dom";
|
||||||
import {setModalContext} from "../../redux/modals/modals.actions";
|
import {setModalContext} from "../../redux/modals/modals.actions";
|
||||||
import {DateTimeFormatter} from "../../utils/DateFormatter";
|
import {DateTimeFormatter} from "../../utils/DateFormatter";
|
||||||
import {alphaSort} from "../../utils/sorters";
|
import {alphaSort} from "../../utils/sorters";
|
||||||
import ContractsFindModalContainer from "../contracts-find-modal/contracts-find-modal.container";
|
import ContractsFindModalContainer from "../contracts-find-modal/contracts-find-modal.container";
|
||||||
|
|
||||||
import moment from "moment";
|
import dayjs from "../../utils/day";
|
||||||
import {connect} from "react-redux";
|
import {connect} from "react-redux";
|
||||||
import {createStructuredSelector} from "reselect";
|
import {createStructuredSelector} from "reselect";
|
||||||
import {selectBodyshop} from "../../redux/user/user.selectors";
|
import {selectBodyshop} from "../../redux/user/user.selectors";
|
||||||
@@ -39,7 +39,7 @@ export function ContractsList({
|
|||||||
sortedInfo: {},
|
sortedInfo: {},
|
||||||
filteredInfo: {text: ""},
|
filteredInfo: {text: ""},
|
||||||
});
|
});
|
||||||
const history = useHistory();
|
const history = useNavigate();
|
||||||
const search = queryString.parse(useLocation().search);
|
const search = queryString.parse(useLocation().search);
|
||||||
const {page} = search;
|
const {page} = search;
|
||||||
|
|
||||||
@@ -152,8 +152,8 @@ export function ContractsList({
|
|||||||
render: (text, record) =>
|
render: (text, record) =>
|
||||||
(record.actualreturn &&
|
(record.actualreturn &&
|
||||||
record.start &&
|
record.start &&
|
||||||
`${moment(record.actualreturn)
|
`${dayjs(record.actualreturn)
|
||||||
.diff(moment(record.start), "days", true)
|
.diff(dayjs(record.start), "day", true)
|
||||||
.toFixed(1)} days`) ||
|
.toFixed(1)} days`) ||
|
||||||
"",
|
"",
|
||||||
},
|
},
|
||||||
@@ -164,7 +164,7 @@ export function ContractsList({
|
|||||||
search.page = pagination.current;
|
search.page = pagination.current;
|
||||||
search.sortcolumn = sorter.columnKey;
|
search.sortcolumn = sorter.columnKey;
|
||||||
search.sortorder = sorter.order;
|
search.sortorder = sorter.order;
|
||||||
history.push({ search: queryString.stringify(search) });
|
history({search: queryString.stringify(search)});
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -179,7 +179,7 @@ export function ContractsList({
|
|||||||
<Button
|
<Button
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
delete search.search;
|
delete search.search;
|
||||||
history.push({ search: queryString.stringify(search) });
|
history({search: queryString.stringify(search)});
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{t("general.actions.clear")}
|
{t("general.actions.clear")}
|
||||||
@@ -196,7 +196,7 @@ export function ContractsList({
|
|||||||
placeholder={search.searh || t("general.labels.search")}
|
placeholder={search.searh || t("general.labels.search")}
|
||||||
onSearch={(value) => {
|
onSearch={(value) => {
|
||||||
search.search = value;
|
search.search = value;
|
||||||
history.push({ search: queryString.stringify(search) });
|
history({search: queryString.stringify(search)});
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</Space>
|
</Space>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import {DownOutlined} from "@ant-design/icons";
|
import {DownOutlined} from "@ant-design/icons";
|
||||||
import { Dropdown, Menu } from "antd";
|
import {Dropdown} from "antd";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import {useTranslation} from "react-i18next";
|
import {useTranslation} from "react-i18next";
|
||||||
import {connect} from "react-redux";
|
import {connect} from "react-redux";
|
||||||
@@ -18,20 +18,16 @@ export function ContractsRatesChangeButton({ disabled, form, bodyshop }) {
|
|||||||
form.setFieldsValue(rate);
|
form.setFieldsValue(rate);
|
||||||
};
|
};
|
||||||
|
|
||||||
const menu = (
|
const menuItems = bodyshop.md_ccc_rates.map((i, idx) => ({
|
||||||
<div>
|
key: idx,
|
||||||
<Menu onClick={handleClick}>
|
label: i.label,
|
||||||
{bodyshop.md_ccc_rates.map((rate, idx) => (
|
value: i,
|
||||||
<Menu.Item value={rate} key={idx}>
|
}));
|
||||||
{rate.label}
|
|
||||||
</Menu.Item>
|
const menu = {items: menuItems, onClick: handleClick};
|
||||||
))}
|
|
||||||
</Menu>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Dropdown overlay={menu} disabled={disabled}>
|
<Dropdown menu={menu} disabled={disabled}>
|
||||||
<a
|
<a
|
||||||
className="ant-dropdown-link"
|
className="ant-dropdown-link"
|
||||||
href=" #"
|
href=" #"
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { Card, Table } from "antd";
|
|||||||
import queryString from "query-string";
|
import queryString from "query-string";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import {useTranslation} from "react-i18next";
|
import {useTranslation} from "react-i18next";
|
||||||
import { Link, useHistory, useLocation } from "react-router-dom";
|
import {Link, useLocation, useNavigate} from "react-router-dom";
|
||||||
import {DateFormatter} from "../../utils/DateFormatter";
|
import {DateFormatter} from "../../utils/DateFormatter";
|
||||||
import {alphaSort} from "../../utils/sorters";
|
import {alphaSort} from "../../utils/sorters";
|
||||||
import {pageLimit} from "../../utils/config";
|
import {pageLimit} from "../../utils/config";
|
||||||
@@ -13,7 +13,7 @@ export default function CourtesyCarContractListComponent({
|
|||||||
}) {
|
}) {
|
||||||
const search = queryString.parse(useLocation().search);
|
const search = queryString.parse(useLocation().search);
|
||||||
const {page, sortcolumn, sortorder} = search;
|
const {page, sortcolumn, sortorder} = search;
|
||||||
const history = useHistory();
|
const history = useNavigate();
|
||||||
|
|
||||||
const {t} = useTranslation();
|
const {t} = useTranslation();
|
||||||
|
|
||||||
@@ -81,7 +81,7 @@ export default function CourtesyCarContractListComponent({
|
|||||||
search.page = pagination.current;
|
search.page = pagination.current;
|
||||||
search.sortcolumn = sorter.columnKey;
|
search.sortcolumn = sorter.columnKey;
|
||||||
search.sortorder = sorter.order;
|
search.sortorder = sorter.order;
|
||||||
history.push({ search: queryString.stringify(search) });
|
history({search: queryString.stringify(search)});
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
import {WarningFilled} from "@ant-design/icons";
|
import {WarningFilled} from "@ant-design/icons";
|
||||||
import {useApolloClient} from "@apollo/client";
|
import {useApolloClient} from "@apollo/client";
|
||||||
import { Button, Form, Input, InputNumber, PageHeader, Space } from "antd";
|
import {Button, Form, Input, InputNumber, Space} from "antd";
|
||||||
import moment from "moment";
|
import {PageHeader} from "@ant-design/pro-layout";
|
||||||
|
import dayjs from "../../utils/day";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import {useTranslation} from "react-i18next";
|
import {useTranslation} from "react-i18next";
|
||||||
import {CHECK_CC_FLEET_NUMBER} from "../../graphql/courtesy-car.queries";
|
import {CHECK_CC_FLEET_NUMBER} from "../../graphql/courtesy-car.queries";
|
||||||
@@ -263,7 +264,7 @@ export default function CourtesyCarCreateFormComponent({ form, saveLoading }) {
|
|||||||
const nextservicedate = form.getFieldValue("nextservicedate");
|
const nextservicedate = form.getFieldValue("nextservicedate");
|
||||||
const dueForService =
|
const dueForService =
|
||||||
nextservicedate &&
|
nextservicedate &&
|
||||||
moment(nextservicedate).endOf("day").isSameOrBefore(moment());
|
dayjs(nextservicedate).endOf("day").isSameOrBefore(dayjs());
|
||||||
|
|
||||||
if (dueForService)
|
if (dueForService)
|
||||||
return (
|
return (
|
||||||
@@ -304,7 +305,7 @@ export default function CourtesyCarCreateFormComponent({ form, saveLoading }) {
|
|||||||
const expires = form.getFieldValue("registrationexpires");
|
const expires = form.getFieldValue("registrationexpires");
|
||||||
|
|
||||||
const dateover =
|
const dateover =
|
||||||
expires && moment(expires).endOf("day").isBefore(moment());
|
expires && dayjs(expires).endOf("day").isBefore(dayjs());
|
||||||
|
|
||||||
if (dateover)
|
if (dateover)
|
||||||
return (
|
return (
|
||||||
@@ -340,7 +341,7 @@ export default function CourtesyCarCreateFormComponent({ form, saveLoading }) {
|
|||||||
const expires = form.getFieldValue("insuranceexpires");
|
const expires = form.getFieldValue("insuranceexpires");
|
||||||
|
|
||||||
const dateover =
|
const dateover =
|
||||||
expires && moment(expires).endOf("day").isBefore(moment());
|
expires && dayjs(expires).endOf("day").isBefore(dayjs());
|
||||||
|
|
||||||
if (dateover)
|
if (dateover)
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import {Select} from "antd";
|
import {Select} from "antd";
|
||||||
import React, {forwardRef, useEffect, useState} from "react";
|
import React, {forwardRef, useEffect, useState} from "react";
|
||||||
import {useTranslation} from "react-i18next";
|
import {useTranslation} from "react-i18next";
|
||||||
|
|
||||||
const {Option} = Select;
|
const {Option} = Select;
|
||||||
|
|
||||||
const CourtesyCarReadinessComponent = ({value, onChange}, ref) => {
|
const CourtesyCarReadinessComponent = ({value, onChange}, ref) => {
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import { toggleModalVisible } from "../../redux/modals/modals.actions";
|
|||||||
import {selectCourtesyCarReturn} from "../../redux/modals/modals.selectors";
|
import {selectCourtesyCarReturn} from "../../redux/modals/modals.selectors";
|
||||||
import {selectBodyshop} from "../../redux/user/user.selectors";
|
import {selectBodyshop} from "../../redux/user/user.selectors";
|
||||||
import CourtesyCarReturnModalComponent from "./courtesy-car-return-modal.component";
|
import CourtesyCarReturnModalComponent from "./courtesy-car-return-modal.component";
|
||||||
import moment from "moment";
|
import dayjs from "../../utils/day";
|
||||||
import {RETURN_CONTRACT} from "../../graphql/cccontracts.queries";
|
import {RETURN_CONTRACT} from "../../graphql/cccontracts.queries";
|
||||||
import {useMutation} from "@apollo/client";
|
import {useMutation} from "@apollo/client";
|
||||||
|
|
||||||
@@ -26,7 +26,7 @@ export function CCReturnModalContainer({
|
|||||||
bodyshop,
|
bodyshop,
|
||||||
}) {
|
}) {
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const { visible, context, actions } = courtesyCarReturnModal;
|
const {open, context, actions} = courtesyCarReturnModal;
|
||||||
const {t} = useTranslation();
|
const {t} = useTranslation();
|
||||||
const [form] = Form.useForm();
|
const [form] = Form.useForm();
|
||||||
const [updateContract] = useMutation(RETURN_CONTRACT);
|
const [updateContract] = useMutation(RETURN_CONTRACT);
|
||||||
@@ -64,7 +64,7 @@ export function CCReturnModalContainer({
|
|||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
title={t("courtesycars.labels.return")}
|
title={t("courtesycars.labels.return")}
|
||||||
visible={visible}
|
open={open}
|
||||||
onCancel={() => toggleModalVisible()}
|
onCancel={() => toggleModalVisible()}
|
||||||
width={"90%"}
|
width={"90%"}
|
||||||
okText={t("general.actions.save")}
|
okText={t("general.actions.save")}
|
||||||
@@ -74,7 +74,7 @@ export function CCReturnModalContainer({
|
|||||||
<Form
|
<Form
|
||||||
form={form}
|
form={form}
|
||||||
onFinish={handleFinish}
|
onFinish={handleFinish}
|
||||||
initialValues={{ fuel: 100, actualreturn: moment(new Date()) }}
|
initialValues={{fuel: 100, actualreturn: dayjs(new Date())}}
|
||||||
>
|
>
|
||||||
<CourtesyCarReturnModalComponent/>
|
<CourtesyCarReturnModalComponent/>
|
||||||
</Form>
|
</Form>
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import React, { useState, useEffect, forwardRef } from "react";
|
import React, {forwardRef, useEffect, useState} from "react";
|
||||||
import {Select} from "antd";
|
import {Select} from "antd";
|
||||||
import {useTranslation} from "react-i18next";
|
import {useTranslation} from "react-i18next";
|
||||||
|
|
||||||
const {Option} = Select;
|
const {Option} = Select;
|
||||||
|
|
||||||
const CourtesyCarStatusComponent = ({value, onChange}, ref) => {
|
const CourtesyCarStatusComponent = ({value, onChange}, ref) => {
|
||||||
|
|||||||
@@ -1,15 +1,6 @@
|
|||||||
import {SyncOutlined, WarningFilled} from "@ant-design/icons";
|
import {SyncOutlined, WarningFilled} from "@ant-design/icons";
|
||||||
import {
|
import {Button, Card, Dropdown, Input, Space, Table, Tooltip,} from "antd";
|
||||||
Button,
|
import dayjs from "../../utils/day";
|
||||||
Card,
|
|
||||||
Dropdown,
|
|
||||||
Input,
|
|
||||||
Menu,
|
|
||||||
Space,
|
|
||||||
Table,
|
|
||||||
Tooltip,
|
|
||||||
} from "antd";
|
|
||||||
import moment from "moment";
|
|
||||||
import React, {useState} from "react";
|
import React, {useState} from "react";
|
||||||
import {useTranslation} from "react-i18next";
|
import {useTranslation} from "react-i18next";
|
||||||
import {Link} from "react-router-dom";
|
import {Link} from "react-router-dom";
|
||||||
@@ -18,6 +9,7 @@ import { GenerateDocument } from "../../utils/RenderTemplate";
|
|||||||
import {TemplateList} from "../../utils/TemplateConstants";
|
import {TemplateList} from "../../utils/TemplateConstants";
|
||||||
import {alphaSort} from "../../utils/sorters";
|
import {alphaSort} from "../../utils/sorters";
|
||||||
import {OwnerNameDisplayFunction} from "../owner-name-display/owner-name-display.component";
|
import {OwnerNameDisplayFunction} from "../owner-name-display/owner-name-display.component";
|
||||||
|
|
||||||
export default function CourtesyCarsList({loading, courtesycars, refetch}) {
|
export default function CourtesyCarsList({loading, courtesycars, refetch}) {
|
||||||
const [state, setState] = useState({
|
const [state, setState] = useState({
|
||||||
sortedInfo: {},
|
sortedInfo: {},
|
||||||
@@ -77,8 +69,7 @@ export default function CourtesyCarsList({ loading, courtesycars, refetch }) {
|
|||||||
const mileageOver = nextservicekm ? nextservicekm <= mileage : false;
|
const mileageOver = nextservicekm ? nextservicekm <= mileage : false;
|
||||||
|
|
||||||
const dueForService =
|
const dueForService =
|
||||||
nextservicedate &&
|
nextservicedate && dayjs(nextservicedate).endOf('day').isSameOrBefore(dayjs());
|
||||||
moment(nextservicedate).endOf("day").isSameOrBefore(moment());
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Space>
|
<Space>
|
||||||
@@ -229,6 +220,27 @@ export default function CourtesyCarsList({ loading, courtesycars, refetch }) {
|
|||||||
(t(c.status) || "").toLowerCase().includes(searchText.toLowerCase())
|
(t(c.status) || "").toLowerCase().includes(searchText.toLowerCase())
|
||||||
)
|
)
|
||||||
: courtesycars;
|
: courtesycars;
|
||||||
|
|
||||||
|
const items = [
|
||||||
|
{
|
||||||
|
key: "courtesycar_inventory",
|
||||||
|
label: t("printcenter.courtesycarcontract.courtesy_car_inventory"),
|
||||||
|
onClick: () =>
|
||||||
|
GenerateDocument(
|
||||||
|
{
|
||||||
|
name: TemplateList("courtesycar").courtesy_car_inventory.key,
|
||||||
|
variables: {
|
||||||
|
//id: contract.id
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{},
|
||||||
|
"p"
|
||||||
|
),
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const menu = {items};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Card
|
<Card
|
||||||
title={t("menus.header.courtesycars")}
|
title={t("menus.header.courtesycars")}
|
||||||
@@ -237,30 +249,7 @@ export default function CourtesyCarsList({ loading, courtesycars, refetch }) {
|
|||||||
<Button onClick={() => refetch()}>
|
<Button onClick={() => refetch()}>
|
||||||
<SyncOutlined/>
|
<SyncOutlined/>
|
||||||
</Button>
|
</Button>
|
||||||
<Dropdown
|
<Dropdown trigger="click" menu={menu}>
|
||||||
trigger="click"
|
|
||||||
overlay={
|
|
||||||
<Menu>
|
|
||||||
<Menu.Item
|
|
||||||
onClick={() =>
|
|
||||||
GenerateDocument(
|
|
||||||
{
|
|
||||||
name: TemplateList("courtesycar").courtesy_car_inventory
|
|
||||||
.key,
|
|
||||||
variables: {
|
|
||||||
//id: contract.id
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{},
|
|
||||||
"p"
|
|
||||||
)
|
|
||||||
}
|
|
||||||
>
|
|
||||||
{t("printcenter.courtesycarcontract.courtesy_car_inventory")}
|
|
||||||
</Menu.Item>
|
|
||||||
</Menu>
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<Button>{t("general.labels.print")}</Button>
|
<Button>{t("general.labels.print")}</Button>
|
||||||
</Dropdown>
|
</Dropdown>
|
||||||
<Link to={`/manage/courtesycars/new`}>
|
<Link to={`/manage/courtesycars/new`}>
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { Button, Card, Table } from "antd";
|
|||||||
import queryString from "query-string";
|
import queryString from "query-string";
|
||||||
import React, {useState} from "react";
|
import React, {useState} from "react";
|
||||||
import {useTranslation} from "react-i18next";
|
import {useTranslation} from "react-i18next";
|
||||||
import { Link, useHistory, useLocation } from "react-router-dom";
|
import {Link, useLocation, useNavigate} from "react-router-dom";
|
||||||
import {DateFormatter} from "../../utils/DateFormatter";
|
import {DateFormatter} from "../../utils/DateFormatter";
|
||||||
import {alphaSort} from "../../utils/sorters";
|
import {alphaSort} from "../../utils/sorters";
|
||||||
import OwnerNameDisplay from "../owner-name-display/owner-name-display.component";
|
import OwnerNameDisplay from "../owner-name-display/owner-name-display.component";
|
||||||
@@ -17,7 +17,7 @@ export default function CsiResponseListPaginated({
|
|||||||
}) {
|
}) {
|
||||||
const search = queryString.parse(useLocation().search);
|
const search = queryString.parse(useLocation().search);
|
||||||
const {responseid, page, sortcolumn, sortorder} = search;
|
const {responseid, page, sortcolumn, sortorder} = search;
|
||||||
const history = useHistory();
|
const history = useNavigate();
|
||||||
const [state, setState] = useState({
|
const [state, setState] = useState({
|
||||||
sortedInfo: {},
|
sortedInfo: {},
|
||||||
filteredInfo: {text: ""},
|
filteredInfo: {text: ""},
|
||||||
@@ -80,18 +80,18 @@ export default function CsiResponseListPaginated({
|
|||||||
search.page = pagination.current;
|
search.page = pagination.current;
|
||||||
search.sortcolumn = sorter.columnKey;
|
search.sortcolumn = sorter.columnKey;
|
||||||
search.sortorder = sorter.order;
|
search.sortorder = sorter.order;
|
||||||
history.push({ search: queryString.stringify(search) });
|
history({search: queryString.stringify(search)});
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleOnRowClick = (record) => {
|
const handleOnRowClick = (record) => {
|
||||||
if (record) {
|
if (record) {
|
||||||
if (record.id) {
|
if (record.id) {
|
||||||
search.responseid = record.id;
|
search.responseid = record.id;
|
||||||
history.push({ search: queryString.stringify(search) });
|
history({search: queryString.stringify(search)});
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
delete search.responseid;
|
delete search.responseid;
|
||||||
history.push({ search: queryString.stringify(search) });
|
history({search: queryString.stringify(search)});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,19 +1,9 @@
|
|||||||
import {Card} from "antd";
|
import {Card} from "antd";
|
||||||
import _ from "lodash";
|
import _ from "lodash";
|
||||||
import moment from "moment";
|
import dayjs from "../../../utils/day";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import {useTranslation} from "react-i18next";
|
import {useTranslation} from "react-i18next";
|
||||||
import {
|
import {Bar, CartesianGrid, ComposedChart, Legend, Line, ResponsiveContainer, Tooltip, XAxis, YAxis,} from "recharts";
|
||||||
Bar,
|
|
||||||
CartesianGrid,
|
|
||||||
ComposedChart,
|
|
||||||
Legend,
|
|
||||||
Line,
|
|
||||||
ResponsiveContainer,
|
|
||||||
Tooltip,
|
|
||||||
XAxis,
|
|
||||||
YAxis,
|
|
||||||
} from "recharts";
|
|
||||||
import * as Utils from "../../scoreboard-targets-table/scoreboard-targets-table.util";
|
import * as Utils from "../../scoreboard-targets-table/scoreboard-targets-table.util";
|
||||||
import DashboardRefreshRequired from "../refresh-required.component";
|
import DashboardRefreshRequired from "../refresh-required.component";
|
||||||
|
|
||||||
@@ -27,7 +17,7 @@ export default function DashboardMonthlyEmployeeEfficiency({
|
|||||||
return <DashboardRefreshRequired {...cardProps} />;
|
return <DashboardRefreshRequired {...cardProps} />;
|
||||||
|
|
||||||
const ticketsByDate = _.groupBy(data.monthly_employee_efficiency, (item) =>
|
const ticketsByDate = _.groupBy(data.monthly_employee_efficiency, (item) =>
|
||||||
moment(item.date).format("YYYY-MM-DD")
|
dayjs(item.date).format("YYYY-MM-DD")
|
||||||
);
|
);
|
||||||
|
|
||||||
const listOfDays = Utils.ListOfDaysInCurrentMonth();
|
const listOfDays = Utils.ListOfDaysInCurrentMonth();
|
||||||
@@ -53,7 +43,7 @@ export default function DashboardMonthlyEmployeeEfficiency({
|
|||||||
((dailyHrs.productive - dailyHrs.actual) / dailyHrs.actual + 1) * 100;
|
((dailyHrs.productive - dailyHrs.actual) / dailyHrs.actual + 1) * 100;
|
||||||
|
|
||||||
const theValue = {
|
const theValue = {
|
||||||
date: moment(val).format("DD"),
|
date: dayjs(val).format("DD"),
|
||||||
// ...dailyHrs,
|
// ...dailyHrs,
|
||||||
actual: dailyHrs.actual.toFixed(1),
|
actual: dailyHrs.actual.toFixed(1),
|
||||||
productive: dailyHrs.productive.toFixed(1),
|
productive: dailyHrs.productive.toFixed(1),
|
||||||
@@ -159,9 +149,9 @@ export default function DashboardMonthlyEmployeeEfficiency({
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const DashboardMonthlyEmployeeEfficiencyGql = `
|
export const DashboardMonthlyEmployeeEfficiencyGql = `
|
||||||
monthly_employee_efficiency: timetickets(where: {_and: [{date: {_gte: "${moment()
|
monthly_employee_efficiency: timetickets(where: {_and: [{date: {_gte: "${dayjs()
|
||||||
.startOf("month")
|
.startOf("month")
|
||||||
.format("YYYY-MM-DD")}"}},{date: {_lte: "${moment()
|
.format("YYYY-MM-DD")}"}},{date: {_lte: "${dayjs()
|
||||||
.endOf("month")
|
.endOf("month")
|
||||||
.format("YYYY-MM-DD")}"}} ]}) {
|
.format("YYYY-MM-DD")}"}} ]}) {
|
||||||
actualhrs
|
actualhrs
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user