Compare commits

...

171 Commits

Author SHA1 Message Date
Allan Carr
67008c35b8 IO-2626 Adjust Image Prop on customer page 2024-02-08 09:57:39 -08:00
Patrick Fic
3c7ede0155 IO-2626 Prevent crisp from loading on anon CSI page. 2024-02-06 10:04:59 -08:00
Allan Carr
4ccd912363 Merge branch 'feature/IO-2626-CSI-Pages' of bitbucket.org:snaptsoft/bodyshop into feature/IO-2626-CSI-Pages 2024-02-06 09:36:16 -08:00
Patrick Fic
dd5ca5d233 Add resource class to test build as well. 2024-02-06 09:29:22 -08:00
Allan Carr
616a4b04a0 IO-2626 Resource Class for Test 2024-02-06 09:10:32 -08:00
Allan Carr
3110be4703 IO-2626 CICD Resource Size Change 2024-02-06 08:52:51 -08:00
Allan Carr
7c303a5154 IO-2626 Change Server Variable Name for response 2024-02-05 20:06:28 -08:00
Allan Carr
9383b37a41 IO-2626 Modify seachparm and fix linking 2024-02-05 20:03:17 -08:00
Allan Carr
205d507097 IO-2626 Update Translations 2024-02-02 22:50:40 -08:00
Allan Carr
97a1bd66d1 IO-2626 Correct Sorting, Linking, Pagination and Update Response Container 2024-02-02 22:45:06 -08:00
Allan Carr
0d1ff6390c IO-2626 Correct Error Page footer 2024-02-02 12:35:18 -08:00
Allan Carr
830d2c87d2 IO-2626 CSI Pages
Move to Server side initial commit
2024-02-02 11:55:57 -08:00
Patrick Fic
c8fc1b0f68 Merged in feature/Sentry-Improvements (pull request #1246)
Change tracing targets.
2024-01-31 01:08:37 +00:00
Patrick Fic
da1ddb874f Change tracing targets. 2024-01-30 16:58:11 -08:00
Patrick Fic
771f9ceaa8 Merged in feature/Sentry-Improvements (pull request #1242)
Feature/Sentry Improvements
2024-01-30 21:45:22 +00:00
Patrick Fic
7daf7540b3 Resolve Typo in CI. 2024-01-30 13:32:58 -08:00
Patrick Fic
ce6940629d Exclude source map upload in CI. 2024-01-30 13:25:48 -08:00
Patrick Fic
b706b96d32 Remove sentry test button. 2024-01-30 13:14:27 -08:00
Patrick Fic
2427bc72f2 Updated CI. 2024-01-30 12:53:07 -08:00
Patrick Fic
8bc1a9d9ee Initial sentry improvements to deploy and verify against test. 2024-01-30 12:47:12 -08:00
Patrick Fic
ba30225ba1 Merged in release/2024-01-29 (pull request #1230)
IO-1532 resolve update logic issue for status timings.
2024-01-29 17:06:31 +00:00
Patrick Fic
cb4a6e8774 IO-1532 resolve update logic issue for status timings. 2024-01-29 09:05:46 -08:00
Dave Richer
23f640028d Merged in release/2024-01-26 (pull request #1227)
Release/2024 01 26
2024-01-27 02:25:22 +00:00
Dave Richer
3e5e6263fe Merged in feature/IO-1532-Tracking-Department-Cycle-Times (pull request #1223)
- updates from lifecyle component.
2024-01-26 23:07:02 +00:00
Dave Richer
48cef3e188 - updates from lifecyle component.
Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-01-26 18:06:14 -05:00
Dave Richer
8c0d6b2f6b Merged in feature/IO-1532-Tracking-Department-Cycle-Times (pull request #1221)
- Fix use hook
2024-01-26 21:34:17 +00:00
Dave Richer
22ee8acd0d - Fix use hook
Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-01-26 16:33:40 -05:00
Dave Richer
afdcfb7bf6 Merge branch 'feature/IO-1532-Tracking-Department-Cycle-Times' into release/2024-01-26 2024-01-26 16:14:01 -05:00
Dave Richer
c1f6d06128 - Finish department cycle times.
Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-01-26 16:10:24 -05:00
Dave Richer
120a8a4576 - Finish department cycle times.
Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-01-26 16:09:46 -05:00
Dave Richer
89224e871c - Progress Update
Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-01-26 12:57:06 -05:00
Allan Carr
fa0d472fb6 Merged in feature/IO-2543-AR-Aging (pull request #1216)
IO-2543 Add wrap to space components to maintain limits of card

Approved-by: Dave Richer
2024-01-26 16:52:59 +00:00
Dave Richer
b0f4ad7e4f - Progress Update
Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-01-26 11:48:43 -05:00
Allan Carr
7503d86c69 IO-2543 Add wrap to space components to maintain limits of card 2024-01-26 08:42:57 -08:00
Dave Richer
efd1c17033 - Revert Hasura
Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-01-26 08:21:43 -08:00
Dave Richer
c7a0072f2d - Revert Hasura
Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-01-26 11:19:03 -05:00
Allan Carr
908942ec09 IO-2543 Revert Lost Sales for Datedisable 2024-01-26 08:11:29 -08:00
Allan Carr
e4d3b53349 Merged in feature/IO-2543-AR-Aging (pull request #1215)
IO-2543 Revert Lost Sales for Datedisable

Approved-by: Dave Richer
2024-01-26 16:10:08 +00:00
Dave Richer
03ce5458b5 Merge branch 'release/2024-01-26' into feature/IO-1532-Tracking-Department-Cycle-Times 2024-01-25 14:00:26 -05:00
Dave Richer
61c03ee206 Merge branch 'release/2024-01-26' into feature/IO-1532-Tracking-Department-Cycle-Times 2024-01-25 13:56:25 -05:00
Dave Richer
0e4f5b8b2a - progress update.
Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-01-25 13:35:20 -05:00
Allan Carr
b5d4944ad8 Merged in feature/IO-2543-AR-Aging (pull request #1210)
IO-2543 AR Aging

Approved-by: Dave Richer
Approved-by: Patrick Fic
2024-01-25 18:33:20 +00:00
Patrick Fic
50f84d40e1 Allow negative balance for AR. 2024-01-25 10:30:03 -08:00
Dave Richer
a394d6b37e - Major Progress Commit
Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-01-25 12:38:32 -05:00
Dave Richer
f8408908b2 - Major Progress Commit
Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-01-24 21:40:05 -05:00
Allan Carr
eb8519dc1d IO-2543 Move queries to jobs.queries.js and correct layout 2024-01-24 18:37:41 -08:00
Allan Carr
36dd97394f IO-2543 Adjust for having no dates 2024-01-24 16:15:32 -08:00
Allan Carr
03d4e4dcd1 IO-2543 AR Aging 2024-01-24 16:01:48 -08:00
Dave Richer
6489a8666f - Progress
Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-01-24 18:39:59 -05:00
Dave Richer
5ea64ed805 - Progress
Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-01-24 17:18:43 -05:00
Dave Richer
d740446ccb - Progress
Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-01-24 10:07:07 -05:00
Dave Richer
d0a2bb7da0 - human readable dates
Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-01-23 12:58:57 -05:00
Dave Richer
5de4ef5d83 - human readable dates
Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-01-23 12:54:38 -05:00
Dave Richer
f59bdf9030 - Progress Update
Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-01-23 12:35:58 -05:00
Dave Richer
cfe0727447 - Rough in front end / backend
Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-01-23 10:20:26 -05:00
Dave Richer
09d112350a - Rough in front end / backend
Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-01-23 01:37:11 -05:00
Dave Richer
52f8eabd2b - Finish cleanup
Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-01-23 00:02:18 -05:00
Dave Richer
a162b275a3 - Finish cleanup
Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-01-22 23:11:10 -05:00
Dave Richer
2e7232bb65 - Finish cleanup
Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-01-22 23:00:31 -05:00
Dave Richer
82dc9e1c56 - Finish cleanup
Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-01-22 19:07:16 -05:00
Dave Richer
272a3f579a - Minor cleanup
Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-01-22 18:53:57 -05:00
Dave Richer
ff1ceb20cb - Minor cleanup
Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-01-22 18:39:27 -05:00
Dave Richer
343179d4fe - Minor cleanup
Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-01-22 18:05:35 -05:00
Dave Richer
eabbc2211b - Minor cleanup
Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-01-22 17:21:46 -05:00
Dave Richer
7f587680ca - Scaffolding.
Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-01-22 16:38:26 -05:00
Patrick Fic
d61ed03ef1 Merge in EULA changes & update to AR Tracking schema. 2024-01-22 11:52:42 -08:00
Dave Richer
166efdc877 progressUpdate
Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-01-22 14:25:21 -05:00
Allan Carr
9274742520 Merged in release/2024-01-19 (pull request #1206)
Release/2024 01 19
2024-01-20 01:03:59 +00:00
Patrick Fic
9b4c85c9e3 IO-2543 additional schema correction. 2024-01-19 13:50:14 -08:00
Allan Carr
66c64ce9e0 Merged in feature/IO-2599-Techstation-Linking (pull request #1204)
IO-2599 Remove Space and put Div in to space components

Approved-by: Patrick Fic
2024-01-19 21:18:39 +00:00
Patrick Fic
c9cbffdec8 IO-2543 Schema changes for AR calculation. 2024-01-19 13:15:06 -08:00
Allan Carr
ca3145ce0f IO-2599 Remove Space and put Div in to space components 2024-01-19 12:19:07 -08:00
Allan Carr
52f9106776 Merged in feature/IO-2608-Employee-Filter-and-Sort (pull request #1197)
IO-2608 Filter and Sort columns in Employee table

Approved-by: Dave Richer
2024-01-19 16:58:45 +00:00
Allan Carr
1a2cc5623d Merged in feature/IO-2598-Tech-Create-IOU (pull request #1201)
IO-2598 Restrict IOU from Tech Console

Approved-by: Dave Richer
2024-01-19 16:58:13 +00:00
Allan Carr
d06037df1f IO-2598 Restrict IOU from Tech Console 2024-01-19 08:47:17 -08:00
Allan Carr
cb8632641e IO-2608 Filter and Sort columns in Employee table 2024-01-18 17:28:46 -08:00
Dave Richer
adbfcddd9d Merged in feature/IO-1828-Beta-Updates-To-Test (pull request #1194)
Feature/IO-1828 Beta Updates To Test
2024-01-18 21:49:33 +00:00
Dave Richer
e3aea55e91 Merged in feature/IO-1828-Beta-Updates-To-Test (pull request #1193)
Feature/IO-1828 Beta Updates To Test
2024-01-18 21:48:51 +00:00
Dave Richer
bf6b1c202f - update handleBeta
Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-01-18 16:35:30 -05:00
Dave Richer
0cab47f984 - update handleBeta
Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-01-18 16:22:58 -05:00
Dave Richer
829e611692 - update handleBeta
Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-01-18 16:16:06 -05:00
Patrick Fic
e0e62a52be Cherry pick schema chengs from IO-2477 2024-01-18 13:08:39 -08:00
Dave Richer
23c0f8e383 - update handleBeta
Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-01-18 16:07:17 -05:00
Allan Carr
764a89e5bf Merged in feature/IO-2599-Techstation-Linking (pull request #1183)
Feature/IO-2599 Techstation Linking

Approved-by: Dave Richer
2024-01-18 19:33:20 +00:00
Allan Carr
f4908ed265 IO-2599 Tech Station Linking 2024-01-18 11:30:58 -08:00
Dave Richer
fcd9c19f0b Merged in feature/IO-1828-Beta-Switch-For-Test (pull request #1180)
Feature/IO-1828 Beta Switch For Test
2024-01-18 18:20:51 +00:00
Dave Richer
430823dde0 - remove source maps from prod
Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-01-18 13:20:04 -05:00
Dave Richer
7e919a7221 Merge branch 'master' into feature/IO-1828-Beta-Switch-For-Test 2024-01-18 13:19:09 -05:00
Allan Carr
7e7f055c34 Merged in feature/IO-2600-Tech-Job-Logout-Console-Log (pull request #1167)
IO-2600 Tech Console Job Logout Console Log

Approved-by: Dave Richer
2024-01-18 01:51:46 +00:00
Allan Carr
6e04ed7c83 Merged in feature/IO-2589-Manual-Job-Ownr-Validation (pull request #1168)
IO-2589 Allow Company Only for Customer Creation

Approved-by: Dave Richer
2024-01-18 01:51:30 +00:00
Allan Carr
5ec07f9620 Merged in feature/IO-2606-Schedule-Appointment-Modal-Close (pull request #1171)
IO-2606 Modal Closeable for Schedule Appointment

Approved-by: Dave Richer
2024-01-18 01:51:06 +00:00
Allan Carr
d3da4a8a1e Merged in feature/IO-2601-Tech-Console-Titles (pull request #1177)
IO-2601 Tech Console Titles

Approved-by: Dave Richer
2024-01-18 01:50:40 +00:00
Allan Carr
9ee10dc5f8 IO-2601 Tech Console Titles 2024-01-17 17:52:14 -08:00
Allan Carr
572963d987 IO-2606 Modal Closeable for Schedule Appointment 2024-01-17 17:09:17 -08:00
Allan Carr
636be8989e IO-2589 Allow Company Only for Customer Creation 2024-01-17 14:22:47 -08:00
Allan Carr
dea7fd71ef IO-2600 Tech Console Job Logout Console Log 2024-01-17 09:41:57 -08:00
Allan Carr
be08ed8551 Merged in feature/IO-2531-Retain-Filter-State-on-Jobs-Page (pull request #1166)
IO-2531 Retain Filtered Statue for Jobs Pages

Approved-by: Dave Richer
2024-01-16 20:22:04 +00:00
Allan Carr
65ce588287 Merged in feature/IO-2603-Open-Orders-Excel (pull request #1164)
IO-2603 Open Orders Excel

Approved-by: Dave Richer
2024-01-16 20:20:25 +00:00
Allan Carr
0cc367b25e IO-2531 Remove Console Log 2024-01-16 12:12:53 -08:00
Allan Carr
2ce8549502 IO-2531 Retain Filtered Statue for Jobs Pages 2024-01-16 12:11:18 -08:00
Allan Carr
7245d4eab2 IO-2603 Open Orders Excel 2024-01-15 18:54:28 -08:00
Allan Carr
260607cb72 Merged in release/2024-01-12 (pull request #1161)
IO-2520 Adjust to imexshopid instead of shopname & prettify
2024-01-13 05:12:28 +00:00
Allan Carr
810738539b Merged in release/2024-01-12 (pull request #1160)
IO-2520 Adjust to imexshopid instead of shopname & prettify
2024-01-13 05:05:25 +00:00
Allan Carr
80539949fb Merged in feature/IO-2520-Kaizen-Data-Pump (pull request #1159)
IO-2520 Adjust to imexshopid instead of shopname & prettify
2024-01-13 05:04:54 +00:00
Allan Carr
ebe5c5b113 IO-2520 Adjust to imexshopid instead of shopname & prettify 2024-01-12 21:06:39 -08:00
Dave Richer
525182c2a7 Merged in feature/IO-1828-Beta-Switch-For-Test (pull request #1158)
- Add in the Beta Switch on test
2024-01-13 02:07:43 +00:00
Dave Richer
3704c0cb12 - Add in the Beta Switch on test
Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-01-12 20:50:40 -05:00
Dave Richer
c8c844cfba Merged in feature/IO-1828-Beta-Switch-For-Test (pull request #1157)
- Add in the Beta Switch on test
2024-01-13 01:48:01 +00:00
Dave Richer
4c4e16b0c9 - Add in the Beta Switch on test
Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-01-12 20:47:06 -05:00
Allan Carr
69f727c4e5 Merged in release/2024-01-12 (pull request #1156)
IO-2520 Add in Server Key format
2024-01-13 00:34:42 +00:00
Allan Carr
04cff4acb1 IO-2520 Add in Server Key format 2024-01-12 16:26:09 -08:00
Allan Carr
4e4fcc3ae4 Merged in release/2024-01-12 (pull request #1154)
IO-2520 Add in Server Key format
2024-01-13 00:25:24 +00:00
Allan Carr
485f9d6025 Merged in feature/IO-2520-Kaizen-Data-Pump (pull request #1153)
IO-2520 Add in Server Key format
2024-01-13 00:24:19 +00:00
Allan Carr
a697ade93a Merged in release/2024-01-12 (pull request #1152)
IO-2602 Beta domain
2024-01-13 00:02:58 +00:00
Allan Carr
7db07b5a94 Merged in release/2024-01-12 (pull request #1151)
IO-2602 Beta domain
2024-01-12 23:41:38 +00:00
Allan Carr
9ec50875a2 Merged in feature/IO-2602-BETA-domain (pull request #1150)
IO-2602 Beta domain
2024-01-12 23:39:22 +00:00
Allan Carr
02b6875eec IO-2602 Beta domain 2024-01-12 15:41:10 -08:00
Allan Carr
e7e4c534bc Merged in release/2024-01-12 (pull request #1149)
Release/2024 01 12
2024-01-12 19:59:15 +00:00
Allan Carr
e438fa1d99 Merged in release/2024-01-12 (pull request #1148)
Release/2024 01 12
2024-01-12 18:50:45 +00:00
Allan Carr
4abbf50a46 Merged in feature/IO-2520-Kaizen-Data-Pump (pull request #1145)
IO-2520 Kaizen Data Pump
2024-01-12 18:16:07 +00:00
Allan Carr
3e9279d89a IO-2520 Change Query Time Bound 2024-01-09 12:00:24 -08:00
Allan Carr
1305277c09 IO-2520 Kaizen Data Pump 2024-01-09 11:08:02 -08:00
Allan Carr
3c47c672d4 Merged in feature/IO-2518-Warning-on-VIN-Length (pull request #1143)
IO-2518 Null coalesce for v_vin for warning
2024-01-08 19:18:24 +00:00
Allan Carr
258d99cd41 Merged in release/2024-01-12 (pull request #1142)
IO-2518 Null coalesce for v_vin for warning
2024-01-08 18:41:15 +00:00
Allan Carr
83356fa4ef Merged in feature/IO-2518-Warning-on-VIN-Length (pull request #1141)
IO-2518 Null coalesce for v_vin for warning
2024-01-08 18:40:43 +00:00
Allan Carr
25429e78f8 IO-2518 Null coalesce for v_vin for warning 2024-01-08 10:37:19 -08:00
Allan Carr
de90bd1bb0 Merged in release/2024-01-05 (pull request #1137)
Release/2024 01 05
2024-01-05 22:43:56 +00:00
Allan Carr
aa6cb4c1d2 Merged in release/2024-01-05 (pull request #1136)
IO-2514 Only Unique items in Menu
2024-01-05 21:08:10 +00:00
Allan Carr
e871ba600f Merged in feature/IO-2514-Production-Board-Estimators (pull request #1135)
IO-2514 Only Unique items in Menu
2024-01-05 21:07:36 +00:00
Allan Carr
fe3698980d IO-2514 Only Unique items in Menu 2024-01-05 13:09:15 -08:00
Allan Carr
89b640f71c Merged in release/2024-01-05 (pull request #1133)
Release/2024 01 05
2024-01-05 20:04:10 +00:00
Allan Carr
d13a9cd04a Merged in feature/IO-2522-Load-Level-Table (pull request #1134)
IO-2522 Load Level Table Change
2024-01-05 20:02:26 +00:00
Allan Carr
c0dab92d0e IO-2522 Load Level Table Change 2024-01-05 12:01:47 -08:00
Patrick Fic
9c897972ad Minor intellipay change. 2024-01-05 08:53:17 -08:00
Allan Carr
307e244475 Merged in feature/IO-2514-Production-Board-Estimators (pull request #1130)
Feature/IO-2514 Production Board Estimators

Approved-by: Dave Richer
2024-01-05 00:57:44 +00:00
Allan Carr
9d3aca646b IO-2514 Production Board Estimator filter by table data 2024-01-03 10:55:45 -08:00
Allan Carr
e6e61466df Merged in feature/IO-2518-Warning-on-VIN-Length (pull request #1129)
IO-2518 Dealership Vin Warning

Approved-by: Dave Richer
2024-01-02 15:01:51 +00:00
Allan Carr
db7f9fe2ab Merged in feature/IO-2517-All-Courtesy-Car-Warning (pull request #1128)
IO-2517 All Courtesy Car Warning Indicator

Approved-by: Dave Richer
2024-01-02 15:01:22 +00:00
Allan Carr
ded798fdf1 IO-2518 Dealership Vin Warning 2023-12-29 16:37:34 -08:00
Allan Carr
bfe94e3068 IO-2517 Add same check within C/C form 2023-12-29 16:17:37 -08:00
Allan Carr
823f07409a IO-2517 All Courtesy Car Warning Indicator 2023-12-29 16:03:40 -08:00
Allan Carr
1a4bc720c2 Merged in release/2023-12-29 (pull request #1127)
Release/2023 12 29
2023-12-29 22:08:52 +00:00
Allan Carr
73cacdec24 Merged in release/2023-12-29 (pull request #1126)
Release/2023 12 29
2023-12-29 21:29:21 +00:00
Allan Carr
18998c4dbe Merged in feature/IO-2489-Regi-#-in-Vehicle-Box (pull request #1125)
IO-2489 Registration # in Vehicle Info Box

Approved-by: Dave Richer
2023-12-28 18:56:27 +00:00
Allan Carr
e236d6e912 IO-2489 Registration # in Vehicle Info Box 2023-12-28 10:57:03 -08:00
Allan Carr
523df670df Merged in feature/IO-2512-Date-Estimated-Manual-Job (pull request #1122)
IO-2512 Date Esimated on Manual Created Jobs

Approved-by: Dave Richer
2023-12-28 18:22:43 +00:00
Allan Carr
ce58181fc3 Merged in feature/IO-2500-Courtesy-Car-Readiness-&-Fuel-Level (pull request #1123)
IO-2500 Readiness and Fuel Level

Approved-by: Dave Richer
2023-12-28 18:21:35 +00:00
Allan Carr
bed0669f73 Merged in feature/IO-2513-Fuel-Level-Tooltip (pull request #1124)
IO-2500 Courtesy Car Readiness

Approved-by: Dave Richer
2023-12-28 18:19:16 +00:00
Allan Carr
b0d077e104 IO-2514 Production Board Estimators 2023-12-28 10:12:59 -08:00
Allan Carr
bdb2951330 IO-2500 Courtesy Car Readiness 2023-12-27 13:55:31 -08:00
Allan Carr
87a01208fb IO-2500 Readiness and Fuel Level 2023-12-27 13:35:29 -08:00
Allan Carr
2daee84fbf IO-2512 Date Esimated on Manual Created Jobs 2023-12-27 11:07:17 -08:00
Allan Carr
cdbf58f3ac Merged in feature/IO-2511-Bill-Label-Reprint (pull request #1121)
IO-2511 Bill Label Reprint

Approved-by: Dave Richer
2023-12-27 16:18:44 +00:00
Allan Carr
ea72d44b42 Merged in release/2023-12-15 (pull request #1119)
IO-2501 Correct for missing query variables
2023-12-22 04:32:06 +00:00
Allan Carr
d1b9b5546b Merged in release/2023-12-15 (pull request #1117)
IO-2505 Conversation List Print
2023-12-21 17:39:49 +00:00
Allan Carr
84f0affaed Merged in release/2023-12-15 (pull request #1115)
Release/2023 12 15
2023-12-20 21:04:54 +00:00
Allan Carr
fc4b5c6b1d Merged in release/2023-12-15 (pull request #1112)
IO-2506 Correct for variable immutibility and nested ifs
2023-12-19 17:17:16 +00:00
Allan Carr
2c232a71d5 Merged in release/2023-12-15 (pull request #1110)
Release/2023 12 15
2023-12-19 16:38:10 +00:00
Allan Carr
f8e1758788 Merged in revert-pr-1097 (pull request #1098)
Revert "Revert "Revert "Revert "Fix issues with limits.
2023-12-01 02:37:45 +00:00
Allan Carr
5c95c72f40 Revert "Revert "Revert "Revert "Fix issues with limits. (pull request #1097)" 2023-12-01 02:37:10 +00:00
Allan Carr
98f816b069 Merged in revert-pr-1091 (pull request #1097)
Revert "Revert "Revert "Fix issues with limits.
2023-11-30 20:23:05 +00:00
Allan Carr
3ca6308dd2 Revert "Revert "Revert "Fix issues with limits. (pull request #1091)" 2023-11-30 20:22:42 +00:00
Allan Carr
a2c2aa11ac Merged in release/2023-12-01 (pull request #1096)
Release/2023 12 01
2023-11-30 16:58:33 +00:00
Allan Carr
b5b772d0c2 Merged in release/2023-12-01 (pull request #1093)
IO-2465 Adjust Headerfile override and comment out line
2023-11-30 01:16:39 +00:00
Allan Carr
4d8a2e635c Merged in revert-pr-1090 (pull request #1091)
Revert "Revert "Fix issues with limits.
2023-11-30 00:25:08 +00:00
Allan Carr
0852d55837 Revert "Revert "Fix issues with limits. (pull request #1090)" 2023-11-30 00:22:20 +00:00
Allan Carr
4c38ddf3cd Merged in revert-pr-1089 (pull request #1090)
Revert "Fix issues with limits.
2023-11-29 23:55:28 +00:00
Allan Carr
e15edeadb5 Revert "Fix issues with limits. (pull request #1089)" 2023-11-29 23:54:37 +00:00
Dave Richer
422c7baada Merged in release/2023-12-01 (pull request #1089)
Fix issues with limits.

Approved-by: Allan Carr
2023-11-29 22:30:12 +00:00
Dave Richer
2a2f8e51b3 Merged in release/2023-12-01 (pull request #1087)
Release/2023 12 01

Approved-by: Allan Carr
2023-11-29 21:27:34 +00:00
Dave Richer
85b1875a22 Merged in release/2023-12-01 (pull request #1085)
Release/2023 12 01

Approved-by: Allan Carr
2023-11-29 18:59:37 +00:00
180 changed files with 55172 additions and 3466 deletions

View File

@@ -42,31 +42,22 @@ jobs:
app-build: app-build:
docker: docker:
- image: cimg/node:16.15.0 - image: cimg/node:16.15.0
resource_class: large
working_directory: ~/repo/client working_directory: ~/repo/client
steps: steps:
- checkout: - checkout:
path: ~/repo path: ~/repo
- restore_cache:
name: Restore Yarn Package Cache
keys:
- yarn-packages-{{ checksum "yarn.lock" }}
- run: - run:
name: Install Dependencies name: Install Dependencies
command: yarn install --frozen-lockfile --cache-folder ~/.cache/yarn command: npm i
- save_cache:
name: Save Yarn Package Cache
key: yarn-packages-{{ checksum "yarn.lock" }}
paths:
- ~/.cache/yarn
- run: yarn run build - run: npm run build
- aws-s3/sync: - aws-s3/sync:
from: build from: build
to: "s3://imex-online-production/" to: "s3://imex-online-production/"
arguments: "--exclude '*.map'"
- jira/notify - jira/notify
test-hasura-migrate: test-hasura-migrate:
@@ -92,31 +83,22 @@ jobs:
test-app-build: test-app-build:
docker: docker:
- image: cimg/node:16.15.0 - image: cimg/node:16.15.0
resource_class: large
working_directory: ~/repo/client working_directory: ~/repo/client
steps: steps:
- checkout: - checkout:
path: ~/repo path: ~/repo
- restore_cache:
name: Restore Yarn Package Cache
keys:
- yarn-packages-{{ checksum "yarn.lock" }}
- run: - run:
name: Install Dependencies name: Install Dependencies
command: yarn install --frozen-lockfile --cache-folder ~/.cache/yarn command: npm i
- save_cache:
name: Save Yarn Package Cache
key: yarn-packages-{{ checksum "yarn.lock" }}
paths:
- ~/.cache/yarn
- run: yarn run build:test - run: npm run build:test
- aws-s3/sync: - aws-s3/sync:
from: build from: build
to: "s3://imex-online-test/" to: "s3://imex-online-test/"
arguments: "--exclude '*.map'"
- jira/notify - jira/notify
admin-app-build: admin-app-build:
@@ -177,4 +159,4 @@ workflows:
#- admin-app-build: #- admin-app-build:
#filters: #filters:
#branches: #branches:
#only: master #only: master

View File

@@ -1,4 +1,4 @@
GENERATE_SOURCEMAP=false GENERATE_SOURCEMAP=true
REACT_APP_GRAPHQL_ENDPOINT=https://db.imex.online/v1/graphql REACT_APP_GRAPHQL_ENDPOINT=https://db.imex.online/v1/graphql
REACT_APP_GRAPHQL_ENDPOINT_WS=wss://db.imex.online/v1/graphql REACT_APP_GRAPHQL_ENDPOINT_WS=wss://db.imex.online/v1/graphql
REACT_APP_GA_CODE=231103507 REACT_APP_GA_CODE=231103507

3
client/.gitignore vendored Normal file
View File

@@ -0,0 +1,3 @@
# Sentry Config File
.sentryclirc

View File

@@ -1,25 +1,25 @@
// craco.config.js // craco.config.js
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");
module.exports = { module.exports = {
plugins: [ plugins: [
{ // {
plugin: SentryWebpackPlugin, // plugin: SentryWebpackPlugin,
options: { // options: {
// sentry-cli configuration // // sentry-cli configuration
authToken: // authToken:
"6b45b028a02342db97a9a2f92c0959058665443d379d4a3a876430009e744260", // "6b45b028a02342db97a9a2f92c0959058665443d379d4a3a876430009e744260",
org: "snapt-software", // org: "snapt-software",
project: "imexonline", // project: "imexonline",
release: process.env.REACT_APP_GIT_SHA, // release: process.env.REACT_APP_GIT_SHA,
// webpack-specific configuration // // webpack-specific configuration
include: ".", // include: ".",
ignore: ["node_modules", "webpack.config.js"], // ignore: ["node_modules", "webpack.config.js"],
}, // },
}, // },
{ {
plugin: CracoLessPlugin, plugin: CracoLessPlugin,
options: { options: {

649
client/package-lock.json generated
View File

@@ -13,12 +13,14 @@
"@craco/craco": "^7.0.0", "@craco/craco": "^7.0.0",
"@fingerprintjs/fingerprintjs": "^3.4.2", "@fingerprintjs/fingerprintjs": "^3.4.2",
"@jsreport/browser-client": "^3.1.0", "@jsreport/browser-client": "^3.1.0",
"@sentry/react": "^7.40.0", "@sentry/cli": "^2.27.0",
"@sentry/react": "^7.99.0",
"@sentry/tracing": "^7.40.0", "@sentry/tracing": "^7.40.0",
"@splitsoftware/splitio-react": "^1.8.1", "@splitsoftware/splitio-react": "^1.8.1",
"@tanem/react-nprogress": "^5.0.8", "@tanem/react-nprogress": "^5.0.8",
"antd": "^4.24.8", "antd": "^4.24.8",
"apollo-link-logger": "^2.0.1", "apollo-link-logger": "^2.0.1",
"apollo-link-sentry": "^3.3.0",
"axios": "^1.3.4", "axios": "^1.3.4",
"craco-less": "^2.0.0", "craco-less": "^2.0.0",
"dinero.js": "^1.9.1", "dinero.js": "^1.9.1",
@@ -4214,40 +4216,195 @@
"integrity": "sha512-sXo/qW2/pAcmT43VoRKOJbDOfV3cYpq3szSVfIThQXNt+E4DfKj361vaAt3c88U5tPUxzEswam7GW48PJqtKAg==", "integrity": "sha512-sXo/qW2/pAcmT43VoRKOJbDOfV3cYpq3szSVfIThQXNt+E4DfKj361vaAt3c88U5tPUxzEswam7GW48PJqtKAg==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/@sentry/browser": { "node_modules/@sentry-internal/feedback": {
"version": "7.40.0", "version": "7.99.0",
"resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-7.40.0.tgz", "resolved": "https://registry.npmjs.org/@sentry-internal/feedback/-/feedback-7.99.0.tgz",
"integrity": "sha512-07rZ+cTcpmYB1r84/oZtmSPJJvLCxW8yIh/5s4MdKRyZpqIDKhOz6cCS/4j+l1V+MeLcNLZBjFtNdKA2eocTpg==", "integrity": "sha512-exIO1o+bE0MW4z30FxC0cYzJ4ZHSMlDPMHCBDPzU+MWGQc/fb8s58QUrx5Dnm6HTh9G3H+YlroCxIo9u0GSwGQ==",
"license": "MIT",
"dependencies": { "dependencies": {
"@sentry/core": "7.40.0", "@sentry/core": "7.99.0",
"@sentry/replay": "7.40.0", "@sentry/types": "7.99.0",
"@sentry/types": "7.40.0", "@sentry/utils": "7.99.0"
"@sentry/utils": "7.40.0", },
"tslib": "^1.9.3" "engines": {
"node": ">=12"
}
},
"node_modules/@sentry-internal/feedback/node_modules/@sentry/core": {
"version": "7.99.0",
"resolved": "https://registry.npmjs.org/@sentry/core/-/core-7.99.0.tgz",
"integrity": "sha512-vOAtzcAXEUtS/oW7wi3wMkZ3hsb5Ch96gKyrrj/mXdOp2zrcwdNV6N9/pawq2E9P/7Pw8AXw4CeDZztZrjQLuA==",
"dependencies": {
"@sentry/types": "7.99.0",
"@sentry/utils": "7.99.0"
}, },
"engines": { "engines": {
"node": ">=8" "node": ">=8"
} }
}, },
"node_modules/@sentry/browser/node_modules/tslib": { "node_modules/@sentry-internal/feedback/node_modules/@sentry/types": {
"version": "1.14.1", "version": "7.99.0",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", "resolved": "https://registry.npmjs.org/@sentry/types/-/types-7.99.0.tgz",
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", "integrity": "sha512-94qwOw4w40sAs5mCmzcGyj8ZUu/KhnWnuMZARRq96k+SjRW/tHFAOlIdnFSrt3BLPvSOK7R3bVAskZQ0N4FTmA==",
"license": "0BSD" "engines": {
"node": ">=8"
}
},
"node_modules/@sentry-internal/feedback/node_modules/@sentry/utils": {
"version": "7.99.0",
"resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-7.99.0.tgz",
"integrity": "sha512-cYZy5WNTkWs5GgggGnjfGqC44CWir0pAv4GVVSx0fsup4D4pMKBJPrtub15f9uC+QkUf3vVkqwpBqeFxtmJQTQ==",
"dependencies": {
"@sentry/types": "7.99.0"
},
"engines": {
"node": ">=8"
}
},
"node_modules/@sentry-internal/replay-canvas": {
"version": "7.99.0",
"resolved": "https://registry.npmjs.org/@sentry-internal/replay-canvas/-/replay-canvas-7.99.0.tgz",
"integrity": "sha512-PoIkfusToDq0snfl2M6HJx/1KJYtXxYhQplrn11kYadO04SdG0XGXf4h7wBTMEQ7LDEAtQyvsOu4nEQtTO3YjQ==",
"dependencies": {
"@sentry/core": "7.99.0",
"@sentry/replay": "7.99.0",
"@sentry/types": "7.99.0",
"@sentry/utils": "7.99.0"
},
"engines": {
"node": ">=12"
}
},
"node_modules/@sentry-internal/replay-canvas/node_modules/@sentry/core": {
"version": "7.99.0",
"resolved": "https://registry.npmjs.org/@sentry/core/-/core-7.99.0.tgz",
"integrity": "sha512-vOAtzcAXEUtS/oW7wi3wMkZ3hsb5Ch96gKyrrj/mXdOp2zrcwdNV6N9/pawq2E9P/7Pw8AXw4CeDZztZrjQLuA==",
"dependencies": {
"@sentry/types": "7.99.0",
"@sentry/utils": "7.99.0"
},
"engines": {
"node": ">=8"
}
},
"node_modules/@sentry-internal/replay-canvas/node_modules/@sentry/types": {
"version": "7.99.0",
"resolved": "https://registry.npmjs.org/@sentry/types/-/types-7.99.0.tgz",
"integrity": "sha512-94qwOw4w40sAs5mCmzcGyj8ZUu/KhnWnuMZARRq96k+SjRW/tHFAOlIdnFSrt3BLPvSOK7R3bVAskZQ0N4FTmA==",
"engines": {
"node": ">=8"
}
},
"node_modules/@sentry-internal/replay-canvas/node_modules/@sentry/utils": {
"version": "7.99.0",
"resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-7.99.0.tgz",
"integrity": "sha512-cYZy5WNTkWs5GgggGnjfGqC44CWir0pAv4GVVSx0fsup4D4pMKBJPrtub15f9uC+QkUf3vVkqwpBqeFxtmJQTQ==",
"dependencies": {
"@sentry/types": "7.99.0"
},
"engines": {
"node": ">=8"
}
},
"node_modules/@sentry-internal/tracing": {
"version": "7.99.0",
"resolved": "https://registry.npmjs.org/@sentry-internal/tracing/-/tracing-7.99.0.tgz",
"integrity": "sha512-z3JQhHjoM1KdM20qrHwRClKJrNLr2CcKtCluq7xevLtXHJWNAQQbafnWD+Aoj85EWXBzKt9yJMv2ltcXJ+at+w==",
"dependencies": {
"@sentry/core": "7.99.0",
"@sentry/types": "7.99.0",
"@sentry/utils": "7.99.0"
},
"engines": {
"node": ">=8"
}
},
"node_modules/@sentry-internal/tracing/node_modules/@sentry/core": {
"version": "7.99.0",
"resolved": "https://registry.npmjs.org/@sentry/core/-/core-7.99.0.tgz",
"integrity": "sha512-vOAtzcAXEUtS/oW7wi3wMkZ3hsb5Ch96gKyrrj/mXdOp2zrcwdNV6N9/pawq2E9P/7Pw8AXw4CeDZztZrjQLuA==",
"dependencies": {
"@sentry/types": "7.99.0",
"@sentry/utils": "7.99.0"
},
"engines": {
"node": ">=8"
}
},
"node_modules/@sentry-internal/tracing/node_modules/@sentry/types": {
"version": "7.99.0",
"resolved": "https://registry.npmjs.org/@sentry/types/-/types-7.99.0.tgz",
"integrity": "sha512-94qwOw4w40sAs5mCmzcGyj8ZUu/KhnWnuMZARRq96k+SjRW/tHFAOlIdnFSrt3BLPvSOK7R3bVAskZQ0N4FTmA==",
"engines": {
"node": ">=8"
}
},
"node_modules/@sentry-internal/tracing/node_modules/@sentry/utils": {
"version": "7.99.0",
"resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-7.99.0.tgz",
"integrity": "sha512-cYZy5WNTkWs5GgggGnjfGqC44CWir0pAv4GVVSx0fsup4D4pMKBJPrtub15f9uC+QkUf3vVkqwpBqeFxtmJQTQ==",
"dependencies": {
"@sentry/types": "7.99.0"
},
"engines": {
"node": ">=8"
}
},
"node_modules/@sentry/browser": {
"version": "7.99.0",
"resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-7.99.0.tgz",
"integrity": "sha512-bgfoUv3wkwwLgN5YUOe0ibB3y268ZCnamZh6nLFqnY/UBKC1+FXWFdvzVON/XKUm62LF8wlpCybOf08ebNj2yg==",
"dependencies": {
"@sentry-internal/feedback": "7.99.0",
"@sentry-internal/replay-canvas": "7.99.0",
"@sentry-internal/tracing": "7.99.0",
"@sentry/core": "7.99.0",
"@sentry/replay": "7.99.0",
"@sentry/types": "7.99.0",
"@sentry/utils": "7.99.0"
},
"engines": {
"node": ">=8"
}
},
"node_modules/@sentry/browser/node_modules/@sentry/core": {
"version": "7.99.0",
"resolved": "https://registry.npmjs.org/@sentry/core/-/core-7.99.0.tgz",
"integrity": "sha512-vOAtzcAXEUtS/oW7wi3wMkZ3hsb5Ch96gKyrrj/mXdOp2zrcwdNV6N9/pawq2E9P/7Pw8AXw4CeDZztZrjQLuA==",
"dependencies": {
"@sentry/types": "7.99.0",
"@sentry/utils": "7.99.0"
},
"engines": {
"node": ">=8"
}
},
"node_modules/@sentry/browser/node_modules/@sentry/types": {
"version": "7.99.0",
"resolved": "https://registry.npmjs.org/@sentry/types/-/types-7.99.0.tgz",
"integrity": "sha512-94qwOw4w40sAs5mCmzcGyj8ZUu/KhnWnuMZARRq96k+SjRW/tHFAOlIdnFSrt3BLPvSOK7R3bVAskZQ0N4FTmA==",
"engines": {
"node": ">=8"
}
},
"node_modules/@sentry/browser/node_modules/@sentry/utils": {
"version": "7.99.0",
"resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-7.99.0.tgz",
"integrity": "sha512-cYZy5WNTkWs5GgggGnjfGqC44CWir0pAv4GVVSx0fsup4D4pMKBJPrtub15f9uC+QkUf3vVkqwpBqeFxtmJQTQ==",
"dependencies": {
"@sentry/types": "7.99.0"
},
"engines": {
"node": ">=8"
}
}, },
"node_modules/@sentry/cli": { "node_modules/@sentry/cli": {
"version": "1.74.6", "version": "2.27.0",
"resolved": "https://registry.npmjs.org/@sentry/cli/-/cli-1.74.6.tgz", "resolved": "https://registry.npmjs.org/@sentry/cli/-/cli-2.27.0.tgz",
"integrity": "sha512-pJ7JJgozyjKZSTjOGi86chIngZMLUlYt2HOog+OJn+WGvqEkVymu8m462j1DiXAnex9NspB4zLLNuZ/R6rTQHg==", "integrity": "sha512-pc0opd71W8lGhYvmB1keQtJkarxzCS9f9ErKYv6TfXOOX6drvwkyA6vD/6xEnpzyvqGAuGRU4T4sEeLD3irwUQ==",
"dev": true,
"hasInstallScript": true, "hasInstallScript": true,
"license": "BSD-3-Clause",
"dependencies": { "dependencies": {
"https-proxy-agent": "^5.0.0", "https-proxy-agent": "^5.0.0",
"mkdirp": "^0.5.5",
"node-fetch": "^2.6.7", "node-fetch": "^2.6.7",
"npmlog": "^4.1.2",
"progress": "^2.0.3", "progress": "^2.0.3",
"proxy-from-env": "^1.1.0", "proxy-from-env": "^1.1.0",
"which": "^2.0.2" "which": "^2.0.2"
@@ -4256,7 +4413,124 @@
"sentry-cli": "bin/sentry-cli" "sentry-cli": "bin/sentry-cli"
}, },
"engines": { "engines": {
"node": ">= 8" "node": ">= 10"
},
"optionalDependencies": {
"@sentry/cli-darwin": "2.27.0",
"@sentry/cli-linux-arm": "2.27.0",
"@sentry/cli-linux-arm64": "2.27.0",
"@sentry/cli-linux-i686": "2.27.0",
"@sentry/cli-linux-x64": "2.27.0",
"@sentry/cli-win32-i686": "2.27.0",
"@sentry/cli-win32-x64": "2.27.0"
}
},
"node_modules/@sentry/cli-darwin": {
"version": "2.27.0",
"resolved": "https://registry.npmjs.org/@sentry/cli-darwin/-/cli-darwin-2.27.0.tgz",
"integrity": "sha512-/DOZlN5rK19g7YP2OaVNauQhUrRfJ88RDr6qURFiqdxYHDc3isPFGHZJmeZBTwOnDDepyZb4XLaOyfwvAOxHig==",
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": ">=10"
}
},
"node_modules/@sentry/cli-linux-arm": {
"version": "2.27.0",
"resolved": "https://registry.npmjs.org/@sentry/cli-linux-arm/-/cli-linux-arm-2.27.0.tgz",
"integrity": "sha512-JmMQ9zgFhkZUEN5WIYuJisu4Jif/ThRHDjbsbXBRbUkkgRn88hgUfg299djMvlZZxjpl3K9AEua+1TIUeQd0Sg==",
"cpu": [
"arm"
],
"optional": true,
"os": [
"linux",
"freebsd"
],
"engines": {
"node": ">=10"
}
},
"node_modules/@sentry/cli-linux-arm64": {
"version": "2.27.0",
"resolved": "https://registry.npmjs.org/@sentry/cli-linux-arm64/-/cli-linux-arm64-2.27.0.tgz",
"integrity": "sha512-f+zuB9XGfB8pNamNgSDhqsavuLuzi6saZxbr3uQf30bA5AESI5hspOd1zPcidOORCVZxiPzQe3+T7avBI1XLuw==",
"cpu": [
"arm64"
],
"optional": true,
"os": [
"linux",
"freebsd"
],
"engines": {
"node": ">=10"
}
},
"node_modules/@sentry/cli-linux-i686": {
"version": "2.27.0",
"resolved": "https://registry.npmjs.org/@sentry/cli-linux-i686/-/cli-linux-i686-2.27.0.tgz",
"integrity": "sha512-/4eyz7jnYp20mZqNtpvCEBkxFW0nEjEZRo2BiASQ5/7K8CmoJRe1vhpDA0WOfzi1zTFIfpdE1/RZm2CjHS6DHQ==",
"cpu": [
"x86",
"ia32"
],
"optional": true,
"os": [
"linux",
"freebsd"
],
"engines": {
"node": ">=10"
}
},
"node_modules/@sentry/cli-linux-x64": {
"version": "2.27.0",
"resolved": "https://registry.npmjs.org/@sentry/cli-linux-x64/-/cli-linux-x64-2.27.0.tgz",
"integrity": "sha512-ptu7wXecnYssihzHlxEOaqbFHWmNEfbepBKGXTdWK2kC+D51+7yHsR9xRdThwVID1bisFgjAveKmBQjmKuXjHQ==",
"cpu": [
"x64"
],
"optional": true,
"os": [
"linux",
"freebsd"
],
"engines": {
"node": ">=10"
}
},
"node_modules/@sentry/cli-win32-i686": {
"version": "2.27.0",
"resolved": "https://registry.npmjs.org/@sentry/cli-win32-i686/-/cli-win32-i686-2.27.0.tgz",
"integrity": "sha512-Db4/xmdE5qV4Aq7Yc8vRw22Y46JJdGMdsMsl5jIf0GVSQPgO23O/2uTiDGpPOdeq91K9EtvpH1zQfDLIfLMaXw==",
"cpu": [
"x86",
"ia32"
],
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=10"
}
},
"node_modules/@sentry/cli-win32-x64": {
"version": "2.27.0",
"resolved": "https://registry.npmjs.org/@sentry/cli-win32-x64/-/cli-win32-x64-2.27.0.tgz",
"integrity": "sha512-q7y/BH4iGfs0TD5PXh2Q8oqnTbOIufoT1NWJcKqvZcOiqCLK3PNUiq7xUeX1PMTrFYAh3Bm6EekOnMavqvbGmg==",
"cpu": [
"x64"
],
"optional": true,
"os": [
"win32"
],
"engines": {
"node": ">=10"
} }
}, },
"node_modules/@sentry/core": { "node_modules/@sentry/core": {
@@ -4280,16 +4554,15 @@
"license": "0BSD" "license": "0BSD"
}, },
"node_modules/@sentry/react": { "node_modules/@sentry/react": {
"version": "7.40.0", "version": "7.99.0",
"resolved": "https://registry.npmjs.org/@sentry/react/-/react-7.40.0.tgz", "resolved": "https://registry.npmjs.org/@sentry/react/-/react-7.99.0.tgz",
"integrity": "sha512-7yYagpOCdsXnVTtLL8Y7wAf2xXgsk2ncuju3O/G4kEckkLewZWmQeoknOSGFlAgVdGNhTaXc2WGzgOiBMOkhug==", "integrity": "sha512-RtHwgzMHJhzJfSQpVG0SDPQYMTGDX3Q37/YWI59S4ALMbSW4/F6n/eQAvGVYZKbh2UCSqgFuRWaXOYkSZT17wA==",
"license": "MIT",
"dependencies": { "dependencies": {
"@sentry/browser": "7.40.0", "@sentry/browser": "7.99.0",
"@sentry/types": "7.40.0", "@sentry/core": "7.99.0",
"@sentry/utils": "7.40.0", "@sentry/types": "7.99.0",
"hoist-non-react-statics": "^3.3.2", "@sentry/utils": "7.99.0",
"tslib": "^1.9.3" "hoist-non-react-statics": "^3.3.2"
}, },
"engines": { "engines": {
"node": ">=8" "node": ">=8"
@@ -4298,26 +4571,82 @@
"react": "15.x || 16.x || 17.x || 18.x" "react": "15.x || 16.x || 17.x || 18.x"
} }
}, },
"node_modules/@sentry/react/node_modules/tslib": { "node_modules/@sentry/react/node_modules/@sentry/core": {
"version": "1.14.1", "version": "7.99.0",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", "resolved": "https://registry.npmjs.org/@sentry/core/-/core-7.99.0.tgz",
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", "integrity": "sha512-vOAtzcAXEUtS/oW7wi3wMkZ3hsb5Ch96gKyrrj/mXdOp2zrcwdNV6N9/pawq2E9P/7Pw8AXw4CeDZztZrjQLuA==",
"license": "0BSD" "dependencies": {
"@sentry/types": "7.99.0",
"@sentry/utils": "7.99.0"
},
"engines": {
"node": ">=8"
}
},
"node_modules/@sentry/react/node_modules/@sentry/types": {
"version": "7.99.0",
"resolved": "https://registry.npmjs.org/@sentry/types/-/types-7.99.0.tgz",
"integrity": "sha512-94qwOw4w40sAs5mCmzcGyj8ZUu/KhnWnuMZARRq96k+SjRW/tHFAOlIdnFSrt3BLPvSOK7R3bVAskZQ0N4FTmA==",
"engines": {
"node": ">=8"
}
},
"node_modules/@sentry/react/node_modules/@sentry/utils": {
"version": "7.99.0",
"resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-7.99.0.tgz",
"integrity": "sha512-cYZy5WNTkWs5GgggGnjfGqC44CWir0pAv4GVVSx0fsup4D4pMKBJPrtub15f9uC+QkUf3vVkqwpBqeFxtmJQTQ==",
"dependencies": {
"@sentry/types": "7.99.0"
},
"engines": {
"node": ">=8"
}
}, },
"node_modules/@sentry/replay": { "node_modules/@sentry/replay": {
"version": "7.40.0", "version": "7.99.0",
"resolved": "https://registry.npmjs.org/@sentry/replay/-/replay-7.40.0.tgz", "resolved": "https://registry.npmjs.org/@sentry/replay/-/replay-7.99.0.tgz",
"integrity": "sha512-Y9Kvo9jKouUdrHQhHVv5SmWZClF5o7BFI6oVpLlv4zXORPQlyoZONM/9sxiMvvH73alDSpxzCoxyhlypAOH4ww==", "integrity": "sha512-gyN/I2WpQrLAZDT+rScB/0jnFL2knEVBo8U8/OVt8gNP20Pq8T/rDZKO/TG0cBfvULDUbJj2P4CJryn2p/O2rA==",
"license": "MIT",
"dependencies": { "dependencies": {
"@sentry/core": "7.40.0", "@sentry-internal/tracing": "7.99.0",
"@sentry/types": "7.40.0", "@sentry/core": "7.99.0",
"@sentry/utils": "7.40.0" "@sentry/types": "7.99.0",
"@sentry/utils": "7.99.0"
}, },
"engines": { "engines": {
"node": ">=12" "node": ">=12"
} }
}, },
"node_modules/@sentry/replay/node_modules/@sentry/core": {
"version": "7.99.0",
"resolved": "https://registry.npmjs.org/@sentry/core/-/core-7.99.0.tgz",
"integrity": "sha512-vOAtzcAXEUtS/oW7wi3wMkZ3hsb5Ch96gKyrrj/mXdOp2zrcwdNV6N9/pawq2E9P/7Pw8AXw4CeDZztZrjQLuA==",
"dependencies": {
"@sentry/types": "7.99.0",
"@sentry/utils": "7.99.0"
},
"engines": {
"node": ">=8"
}
},
"node_modules/@sentry/replay/node_modules/@sentry/types": {
"version": "7.99.0",
"resolved": "https://registry.npmjs.org/@sentry/types/-/types-7.99.0.tgz",
"integrity": "sha512-94qwOw4w40sAs5mCmzcGyj8ZUu/KhnWnuMZARRq96k+SjRW/tHFAOlIdnFSrt3BLPvSOK7R3bVAskZQ0N4FTmA==",
"engines": {
"node": ">=8"
}
},
"node_modules/@sentry/replay/node_modules/@sentry/utils": {
"version": "7.99.0",
"resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-7.99.0.tgz",
"integrity": "sha512-cYZy5WNTkWs5GgggGnjfGqC44CWir0pAv4GVVSx0fsup4D4pMKBJPrtub15f9uC+QkUf3vVkqwpBqeFxtmJQTQ==",
"dependencies": {
"@sentry/types": "7.99.0"
},
"engines": {
"node": ">=8"
}
},
"node_modules/@sentry/tracing": { "node_modules/@sentry/tracing": {
"version": "7.40.0", "version": "7.40.0",
"resolved": "https://registry.npmjs.org/@sentry/tracing/-/tracing-7.40.0.tgz", "resolved": "https://registry.npmjs.org/@sentry/tracing/-/tracing-7.40.0.tgz",
@@ -4381,6 +4710,27 @@
"node": ">= 8" "node": ">= 8"
} }
}, },
"node_modules/@sentry/webpack-plugin/node_modules/@sentry/cli": {
"version": "1.77.3",
"resolved": "https://registry.npmjs.org/@sentry/cli/-/cli-1.77.3.tgz",
"integrity": "sha512-c3eDqcDRmy4TFz2bFU5Y6QatlpoBPPa8cxBooaS4aMQpnIdLYPF1xhyyiW0LQlDUNc3rRjNF7oN5qKoaRoMTQQ==",
"dev": true,
"hasInstallScript": true,
"dependencies": {
"https-proxy-agent": "^5.0.0",
"mkdirp": "^0.5.5",
"node-fetch": "^2.6.7",
"progress": "^2.0.3",
"proxy-from-env": "^1.1.0",
"which": "^2.0.2"
},
"bin": {
"sentry-cli": "bin/sentry-cli"
},
"engines": {
"node": ">= 8"
}
},
"node_modules/@sinclair/typebox": { "node_modules/@sinclair/typebox": {
"version": "0.24.51", "version": "0.24.51",
"resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.24.51.tgz", "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.24.51.tgz",
@@ -6112,12 +6462,21 @@
"@apollo/client": "^3.0.0" "@apollo/client": "^3.0.0"
} }
}, },
"node_modules/aproba": { "node_modules/apollo-link-sentry": {
"version": "1.2.0", "version": "3.3.0",
"resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", "resolved": "https://registry.npmjs.org/apollo-link-sentry/-/apollo-link-sentry-3.3.0.tgz",
"integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", "integrity": "sha512-wLffWmo5sRw3rHN1Ck6azM0oxObvtaBBf3AC8cLX4SxhyjmkRIagGDji6CFkyAhxupPz0b9/H1u4Ocx+63lNug==",
"dev": true, "dependencies": {
"license": "ISC" "deepmerge": "^4.2.2",
"dot-prop": "^6.0.0",
"tslib": "^2.0.3",
"zen-observable-ts": "^1.2.5"
},
"peerDependencies": {
"@apollo/client": "^3.2.3",
"@sentry/browser": "^7.41.0",
"graphql": "15 - 16"
}
}, },
"node_modules/arch": { "node_modules/arch": {
"version": "2.2.0", "version": "2.2.0",
@@ -6140,17 +6499,6 @@
], ],
"license": "MIT" "license": "MIT"
}, },
"node_modules/are-we-there-yet": {
"version": "1.1.7",
"resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.7.tgz",
"integrity": "sha512-nxwy40TuMiUGqMyRHgCSWZ9FM4VAoRP4xUYSTv5ImRog+h9yISPbVH7H8fASCIzYn9wlEv4zvFL7uKDMCFQm3g==",
"dev": true,
"license": "ISC",
"dependencies": {
"delegates": "^1.0.0",
"readable-stream": "^2.0.6"
}
},
"node_modules/arg": { "node_modules/arg": {
"version": "5.0.2", "version": "5.0.2",
"resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz",
@@ -7571,16 +7919,6 @@
"node": ">=4" "node": ">=4"
} }
}, },
"node_modules/code-point-at": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz",
"integrity": "sha512-RpAVKQA5T63xEj6/giIbUEtZwJ4UFIc3ZtvEkiaUERylqe8xb5IvqcgOurZLahv93CLKfxcw5YI+DZcUBRyLXA==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/collect-v8-coverage": { "node_modules/collect-v8-coverage": {
"version": "1.0.1", "version": "1.0.1",
"resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz", "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz",
@@ -7743,13 +8081,6 @@
"node": ">=0.8" "node": ">=0.8"
} }
}, },
"node_modules/console-control-strings": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz",
"integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==",
"dev": true,
"license": "ISC"
},
"node_modules/content-disposition": { "node_modules/content-disposition": {
"version": "0.5.4", "version": "0.5.4",
"resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz",
@@ -8911,13 +9242,6 @@
"node": ">=0.4.0" "node": ">=0.4.0"
} }
}, },
"node_modules/delegates": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz",
"integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==",
"dev": true,
"license": "MIT"
},
"node_modules/denque": { "node_modules/denque": {
"version": "1.5.1", "version": "1.5.1",
"resolved": "https://registry.npmjs.org/denque/-/denque-1.5.1.tgz", "resolved": "https://registry.npmjs.org/denque/-/denque-1.5.1.tgz",
@@ -9218,6 +9542,28 @@
"tslib": "^2.0.3" "tslib": "^2.0.3"
} }
}, },
"node_modules/dot-prop": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-6.0.1.tgz",
"integrity": "sha512-tE7ztYzXHIeyvc7N+hR3oi7FIbf/NIjVP9hmAt3yMXzrQ072/fpjGLx2GxNxGxUl5V73MEqYzioOMoVhGMJ5cA==",
"dependencies": {
"is-obj": "^2.0.0"
},
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/dot-prop/node_modules/is-obj": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz",
"integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==",
"engines": {
"node": ">=8"
}
},
"node_modules/dotenv": { "node_modules/dotenv": {
"version": "16.0.1", "version": "16.0.1",
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.1.tgz", "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.0.1.tgz",
@@ -10464,6 +10810,8 @@
}, },
"node_modules/eventemitter2": { "node_modules/eventemitter2": {
"version": "6.4.7", "version": "6.4.7",
"resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-6.4.7.tgz",
"integrity": "sha512-tYUSVOGeQPKt/eC1ABfhHy5Xd96N3oIijJvN3O9+TsC28T5V9yX9oEfEK5faP0EFSNVOG97qtAS68GBrQB2hDg==",
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
@@ -11283,74 +11631,6 @@
"url": "https://github.com/sponsors/ljharb" "url": "https://github.com/sponsors/ljharb"
} }
}, },
"node_modules/gauge": {
"version": "2.7.4",
"resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz",
"integrity": "sha512-14x4kjc6lkD3ltw589k0NrPD6cCNTD6CWoVUNpB85+DrtONoZn+Rug6xZU5RvSC4+TZPxA5AnBibQYAvZn41Hg==",
"dev": true,
"license": "ISC",
"dependencies": {
"aproba": "^1.0.3",
"console-control-strings": "^1.0.0",
"has-unicode": "^2.0.0",
"object-assign": "^4.1.0",
"signal-exit": "^3.0.0",
"string-width": "^1.0.1",
"strip-ansi": "^3.0.1",
"wide-align": "^1.1.0"
}
},
"node_modules/gauge/node_modules/ansi-regex": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
"integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/gauge/node_modules/is-fullwidth-code-point": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz",
"integrity": "sha512-1pqUqRjkhPJ9miNq9SwMfdvi6lBJcd6eFxvfaivQhaH3SgisfiuudvFntdKOmxuee/77l+FPjKrQjWvmPjWrRw==",
"dev": true,
"license": "MIT",
"dependencies": {
"number-is-nan": "^1.0.0"
},
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/gauge/node_modules/string-width": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
"integrity": "sha512-0XsVpQLnVCXHJfyEs8tC0zpTVIr5PKKsQtkT29IwupnPTjtPmQ3xT/4yCREF9hYkV/3M3kzcUTSAZT6a6h81tw==",
"dev": true,
"license": "MIT",
"dependencies": {
"code-point-at": "^1.0.0",
"is-fullwidth-code-point": "^1.0.0",
"strip-ansi": "^3.0.0"
},
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/gauge/node_modules/strip-ansi": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
"integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==",
"dev": true,
"license": "MIT",
"dependencies": {
"ansi-regex": "^2.0.0"
},
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/gensync": { "node_modules/gensync": {
"version": "1.0.0-beta.2", "version": "1.0.0-beta.2",
"resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz",
@@ -11753,13 +12033,6 @@
"url": "https://github.com/sponsors/ljharb" "url": "https://github.com/sponsors/ljharb"
} }
}, },
"node_modules/has-unicode": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz",
"integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==",
"dev": true,
"license": "ISC"
},
"node_modules/he": { "node_modules/he": {
"version": "1.2.0", "version": "1.2.0",
"resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz",
@@ -15744,19 +16017,6 @@
"node": ">=8" "node": ">=8"
} }
}, },
"node_modules/npmlog": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz",
"integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==",
"dev": true,
"license": "ISC",
"dependencies": {
"are-we-there-yet": "~1.1.2",
"console-control-strings": "~1.1.0",
"gauge": "~2.7.3",
"set-blocking": "~2.0.0"
}
},
"node_modules/nth-check": { "node_modules/nth-check": {
"version": "2.1.1", "version": "2.1.1",
"resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz",
@@ -15769,16 +16029,6 @@
"url": "https://github.com/fb55/nth-check?sponsor=1" "url": "https://github.com/fb55/nth-check?sponsor=1"
} }
}, },
"node_modules/number-is-nan": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz",
"integrity": "sha512-4jbtZXNAsfZbAHiiqjLPBiCl16dES1zI4Hpzzxw61Tk+loF+sBDBKx1ICKKKwIqQ7M0mFn1TmkN7euSncWgHiQ==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/nwsapi": { "node_modules/nwsapi": {
"version": "2.2.1", "version": "2.2.1",
"resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.1.tgz", "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.1.tgz",
@@ -17794,7 +18044,6 @@
"version": "2.0.3", "version": "2.0.3",
"resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz",
"integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==",
"dev": true,
"license": "MIT", "license": "MIT",
"engines": { "engines": {
"node": ">=0.4.0" "node": ">=0.4.0"
@@ -20526,13 +20775,6 @@
"node": ">= 0.8.0" "node": ">= 0.8.0"
} }
}, },
"node_modules/set-blocking": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
"integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==",
"dev": true,
"license": "ISC"
},
"node_modules/setprototypeof": { "node_modules/setprototypeof": {
"version": "1.2.0", "version": "1.2.0",
"resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
@@ -22110,19 +22352,6 @@
"is-typedarray": "^1.0.0" "is-typedarray": "^1.0.0"
} }
}, },
"node_modules/typescript": {
"version": "4.9.5",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz",
"integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==",
"peer": true,
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"
},
"engines": {
"node": ">=4.2.0"
}
},
"node_modules/typescript-compare": { "node_modules/typescript-compare": {
"version": "0.0.2", "version": "0.0.2",
"resolved": "https://registry.npmjs.org/typescript-compare/-/typescript-compare-0.0.2.tgz", "resolved": "https://registry.npmjs.org/typescript-compare/-/typescript-compare-0.0.2.tgz",
@@ -23080,16 +23309,6 @@
"url": "https://github.com/sponsors/ljharb" "url": "https://github.com/sponsors/ljharb"
} }
}, },
"node_modules/wide-align": {
"version": "1.1.5",
"resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz",
"integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==",
"dev": true,
"license": "ISC",
"dependencies": {
"string-width": "^1.0.2 || 2 || 3 || 4"
}
},
"node_modules/wildcard": { "node_modules/wildcard": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.0.tgz", "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.0.tgz",

View File

@@ -9,12 +9,14 @@
"@craco/craco": "^7.0.0", "@craco/craco": "^7.0.0",
"@fingerprintjs/fingerprintjs": "^3.4.2", "@fingerprintjs/fingerprintjs": "^3.4.2",
"@jsreport/browser-client": "^3.1.0", "@jsreport/browser-client": "^3.1.0",
"@sentry/react": "^7.40.0", "@sentry/cli": "^2.27.0",
"@sentry/react": "^7.99.0",
"@sentry/tracing": "^7.40.0", "@sentry/tracing": "^7.40.0",
"@splitsoftware/splitio-react": "^1.8.1", "@splitsoftware/splitio-react": "^1.8.1",
"@tanem/react-nprogress": "^5.0.8", "@tanem/react-nprogress": "^5.0.8",
"antd": "^4.24.8", "antd": "^4.24.8",
"apollo-link-logger": "^2.0.1", "apollo-link-logger": "^2.0.1",
"apollo-link-sentry": "^3.3.0",
"axios": "^1.3.4", "axios": "^1.3.4",
"craco-less": "^2.0.0", "craco-less": "^2.0.0",
"dinero.js": "^1.9.1", "dinero.js": "^1.9.1",
@@ -88,13 +90,14 @@
"scripts": { "scripts": {
"analyze": "source-map-explorer 'build/static/js/*.js'", "analyze": "source-map-explorer 'build/static/js/*.js'",
"start": "craco start", "start": "craco start",
"build": "REACT_APP_GIT_SHA=`git rev-parse --short HEAD` craco build", "build": "REACT_APP_GIT_SHA=`git rev-parse --short HEAD` craco build && npm run sentry:sourcemaps",
"build:test": "env-cmd -f .env.test npm run build", "build:test": "env-cmd -f .env.test npm run build",
"build-deploy:test": "npm run build:test && s3cmd sync build/* s3://imex-online-test && echo '🚀 TESTING Deployed!'", "build-deploy:test": "npm run build:test && s3cmd sync build/* s3://imex-online-test && echo '🚀 TESTING Deployed!'",
"buildcra": "REACT_APP_GIT_SHA=`git rev-parse --short HEAD` craco build", "buildcra": "REACT_APP_GIT_SHA=`git rev-parse --short HEAD` craco build",
"test": "cypress open", "test": "cypress open",
"eject": "react-scripts eject", "eject": "react-scripts eject",
"madge": "madge --image ./madge-graph.svg --extensions js,jsx,ts,tsx --circular ." "madge": "madge --image ./madge-graph.svg --extensions js,jsx,ts,tsx --circular .",
"sentry:sourcemaps": "sentry-cli sourcemaps inject --org imex --project imexonline ./build && sentry-cli sourcemaps upload --org imex --project imexonline ./build"
}, },
"eslintConfig": { "eslintConfig": {
"extends": [ "extends": [

View File

@@ -8,6 +8,7 @@ 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";
import * as Sentry from "@sentry/react";
moment.locale("en-US"); moment.locale("en-US");
@@ -18,7 +19,7 @@ export const factory = SplitSdk({
}, },
}); });
export default function AppContainer() { function AppContainer() {
const { t } = useTranslation(); const { t } = useTranslation();
return ( return (
@@ -42,3 +43,5 @@ export default function AppContainer() {
</ApolloProvider> </ApolloProvider>
); );
} }
export default Sentry.withProfiler(AppContainer);

View File

@@ -22,6 +22,7 @@ import {
} from "../redux/user/user.selectors"; } from "../redux/user/user.selectors";
import PrivateRoute from "../utils/private-route"; import PrivateRoute from "../utils/private-route";
import "./App.styles.scss"; import "./App.styles.scss";
import handleBeta from "../utils/handleBeta";
const ResetPassword = lazy(() => const ResetPassword = lazy(() =>
import("../pages/reset-password/reset-password.component") import("../pages/reset-password/reset-password.component")
@@ -57,7 +58,6 @@ export function App({
if (!navigator.onLine) { if (!navigator.onLine) {
setOnline(false); setOnline(false);
} }
checkUserSession(); checkUserSession();
}, [checkUserSession, setOnline]); }, [checkUserSession, setOnline]);
@@ -73,6 +73,7 @@ export function App({
window.addEventListener("online", function (e) { window.addEventListener("online", function (e) {
setOnline(true); setOnline(true);
}); });
useEffect(() => { useEffect(() => {
if (currentUser.authorized && bodyshop) { if (currentUser.authorized && bodyshop) {
client.setAttribute("imexshopid", bodyshop.imexshopid); client.setAttribute("imexshopid", bodyshop.imexshopid);
@@ -107,6 +108,8 @@ export function App({
/> />
); );
handleBeta();
return ( return (
<Switch> <Switch>
<Suspense fallback={<LoadingSpinner message="ImEX Online" />}> <Suspense fallback={<LoadingSpinner message="ImEX Online" />}>

View File

@@ -35,6 +35,15 @@ export default function ContractsCarsComponent({
state.sortedInfo.columnKey === "status" && state.sortedInfo.order, state.sortedInfo.columnKey === "status" && state.sortedInfo.order,
render: (text, record) => <div>{t(record.status)}</div>, render: (text, record) => <div>{t(record.status)}</div>,
}, },
{
title: t("courtesycars.fields.readiness"),
dataIndex: "readiness",
key: "readiness",
sorter: (a, b) => alphaSort(a.readiness, b.readiness),
sortOrder:
state.sortedInfo.columnKey === "readiness" && state.sortedInfo.order,
render: (text, record) => t(record.readiness),
},
{ {
title: t("courtesycars.fields.year"), title: t("courtesycars.fields.year"),
dataIndex: "year", dataIndex: "year",

View File

@@ -7,6 +7,7 @@ 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";
import { DateFormatter } from "../../utils/DateFormatter"; import { DateFormatter } from "../../utils/DateFormatter";
import CourtesyCarFuelSlider from "../courtesy-car-fuel-select/courtesy-car-fuel-select.component"; import CourtesyCarFuelSlider from "../courtesy-car-fuel-select/courtesy-car-fuel-select.component";
import CourtesyCarReadiness from "../courtesy-car-readiness-select/courtesy-car-readiness-select.component";
import CourtesyCarStatus from "../courtesy-car-status-select/courtesy-car-status-select.component"; import CourtesyCarStatus from "../courtesy-car-status-select/courtesy-car-status-select.component";
import FormDatePicker from "../form-date-picker/form-date-picker.component"; import FormDatePicker from "../form-date-picker/form-date-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";
@@ -213,6 +214,9 @@ export default function CourtesyCarCreateFormComponent({ form, saveLoading }) {
> >
<CourtesyCarStatus /> <CourtesyCarStatus />
</Form.Item> </Form.Item>
<Form.Item label={t("courtesycars.fields.readiness")} name="readiness">
<CourtesyCarReadiness />
</Form.Item>
<div> <div>
<Form.Item <Form.Item
label={t("courtesycars.fields.nextservicekm")} label={t("courtesycars.fields.nextservicekm")}
@@ -227,8 +231,9 @@ export default function CourtesyCarCreateFormComponent({ form, saveLoading }) {
> >
{() => { {() => {
const nextservicekm = form.getFieldValue("nextservicekm"); const nextservicekm = form.getFieldValue("nextservicekm");
const mileageOver = const mileageOver = nextservicekm
nextservicekm && nextservicekm <= form.getFieldValue("mileage"); ? nextservicekm <= form.getFieldValue("mileage")
: false;
if (mileageOver) if (mileageOver)
return ( return (
<Space direction="vertical" style={{ color: "tomato" }}> <Space direction="vertical" style={{ color: "tomato" }}>

View File

@@ -34,6 +34,32 @@ const CourtesyCarFuelComponent = (props, ref) => {
step={null} step={null}
style={{ marginLeft: "2rem", marginRight: "2rem" }} style={{ marginLeft: "2rem", marginRight: "2rem" }}
{...props} {...props}
tooltip={{
formatter: (value) => {
switch (value) {
case 0:
return t("courtesycars.labels.fuel.empty");
case 13:
return t("courtesycars.labels.fuel.18");
case 25:
return t("courtesycars.labels.fuel.14");
case 38:
return t("courtesycars.labels.fuel.38");
case 50:
return t("courtesycars.labels.fuel.12");
case 63:
return t("courtesycars.labels.fuel.58");
case 75:
return t("courtesycars.labels.fuel.34");
case 88:
return t("courtesycars.labels.fuel.78");
case 100:
return t("courtesycars.labels.fuel.full");
default:
return value;
}
},
}}
/> />
); );
}; };

View File

@@ -0,0 +1,35 @@
import { Select } from "antd";
import React, { forwardRef, useEffect, useState } from "react";
import { useTranslation } from "react-i18next";
const { Option } = Select;
const CourtesyCarReadinessComponent = ({ value, onChange }, ref) => {
const [option, setOption] = useState(value);
const { t } = useTranslation();
useEffect(() => {
if (value !== option && onChange) {
onChange(option);
}
}, [value, option, onChange]);
return (
<Select
allowClear
ref={ref}
value={option}
style={{
width: 100,
}}
onChange={setOption}
>
<Option value="courtesycars.readiness.ready">
{t("courtesycars.readiness.ready")}
</Option>
<Option value="courtesycars.readiness.notready">
{t("courtesycars.readiness.notready")}
</Option>
</Select>
);
};
export default forwardRef(CourtesyCarReadinessComponent);

View File

@@ -74,10 +74,11 @@ export default function CourtesyCarsList({ loading, courtesycars, refetch }) {
render: (text, record) => { render: (text, record) => {
const { nextservicedate, nextservicekm, mileage } = record; const { nextservicedate, nextservicekm, mileage } = record;
const mileageOver = nextservicekm <= mileage; const mileageOver = nextservicekm ? nextservicekm <= mileage : false;
const dueForService = const dueForService =
nextservicedate && moment(nextservicedate).isBefore(moment()); nextservicedate &&
moment(nextservicedate).endOf("day").isSameOrBefore(moment());
return ( return (
<Space> <Space>
@@ -91,6 +92,26 @@ export default function CourtesyCarsList({ loading, courtesycars, refetch }) {
); );
}, },
}, },
{
title: t("courtesycars.fields.readiness"),
dataIndex: "readiness",
key: "readiness",
sorter: (a, b) => alphaSort(a.readiness, b.readiness),
filters: [
{
text: t("courtesycars.readiness.ready"),
value: "courtesycars.readiness.ready",
},
{
text: t("courtesycars.readiness.notready"),
value: "courtesycars.readiness.notready",
},
],
onFilter: (value, record) => value.includes(record.readiness),
sortOrder:
state.sortedInfo.columnKey === "readiness" && state.sortedInfo.order,
render: (text, record) => t(record.readiness),
},
{ {
title: t("courtesycars.fields.year"), title: t("courtesycars.fields.year"),
dataIndex: "year", dataIndex: "year",
@@ -131,6 +152,36 @@ export default function CourtesyCarsList({ loading, courtesycars, refetch }) {
sortOrder: sortOrder:
state.sortedInfo.columnKey === "plate" && state.sortedInfo.order, state.sortedInfo.columnKey === "plate" && state.sortedInfo.order,
}, },
{
title: t("courtesycars.fields.fuel"),
dataIndex: "fuel",
key: "fuel",
sorter: (a, b) => alphaSort(a.fuel, b.fuel),
sortOrder:
state.sortedInfo.columnKey === "fuel" && state.sortedInfo.order,
render: (text, record) => {
switch (record.fuel) {
case 100:
return t("courtesycars.labels.fuel.full");
case 88:
return t("courtesycars.labels.fuel.78");
case 63:
return t("courtesycars.labels.fuel.58");
case 50:
return t("courtesycars.labels.fuel.12");
case 38:
return t("courtesycars.labels.fuel.34");
case 25:
return t("courtesycars.labels.fuel.14");
case 13:
return t("courtesycars.labels.fuel.18");
case 0:
return t("courtesycars.labels.fuel.empty");
default:
return record.fuel;
}
},
},
{ {
title: t("courtesycars.labels.outwith"), title: t("courtesycars.labels.outwith"),
dataIndex: "outwith", dataIndex: "outwith",

View File

@@ -5,6 +5,7 @@ import React, { useEffect } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { useLocation } from "react-router-dom"; import { useLocation } from "react-router-dom";
import { QUERY_CSI_RESPONSE_BY_PK } from "../../graphql/csi.queries"; import { QUERY_CSI_RESPONSE_BY_PK } from "../../graphql/csi.queries";
import { DateFormatter } from "../../utils/DateFormatter";
import AlertComponent from "../alert/alert.component"; import AlertComponent from "../alert/alert.component";
import ConfigFormComponents from "../config-form-components/config-form-components.component"; import ConfigFormComponents from "../config-form-components/config-form-components.component";
import LoadingSpinner from "../loading-spinner/loading-spinner.component"; import LoadingSpinner from "../loading-spinner/loading-spinner.component";
@@ -44,6 +45,13 @@ export default function CsiResponseFormContainer() {
readOnly readOnly
componentList={data.csi_by_pk.csiquestion.config} componentList={data.csi_by_pk.csiquestion.config}
/> />
{data.csi_by_pk.validuntil ? (
<>
{t("csi.fields.validuntil")}
{": "}
<DateFormatter>{data.csi_by_pk.validuntil}</DateFormatter>
</>
) : null}
</Form> </Form>
</Card> </Card>
); );

View File

@@ -5,9 +5,11 @@ 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, useHistory, useLocation } from "react-router-dom";
import { DateFormatter } from "../../utils/DateFormatter"; import { DateFormatter } from "../../utils/DateFormatter";
import { alphaSort } from "../../utils/sorters"; import { pageLimit } from "../../utils/config";
import OwnerNameDisplay from "../owner-name-display/owner-name-display.component"; import { alphaSort, dateSort } from "../../utils/sorters";
import {pageLimit} from "../../utils/config"; import OwnerNameDisplay, {
OwnerNameDisplayFunction,
} from "../owner-name-display/owner-name-display.component";
export default function CsiResponseListPaginated({ export default function CsiResponseListPaginated({
refetch, refetch,
@@ -16,23 +18,23 @@ export default function CsiResponseListPaginated({
total, total,
}) { }) {
const search = queryString.parse(useLocation().search); const search = queryString.parse(useLocation().search);
const { responseid, page, sortcolumn, sortorder } = search; const { responseid } = search;
const history = useHistory(); const history = useHistory();
const { t } = useTranslation();
const [state, setState] = useState({ const [state, setState] = useState({
sortedInfo: {}, sortedInfo: {},
filteredInfo: { text: "" }, filteredInfo: { text: "" },
page: "",
}); });
const { t } = useTranslation();
const columns = [ const columns = [
{ {
title: t("jobs.fields.ro_number"), title: t("jobs.fields.ro_number"),
dataIndex: "ro_number", dataIndex: "ro_number",
key: "ro_number", key: "ro_number",
width: "8%",
sorter: (a, b) => alphaSort(a.job.ro_number, b.job.ro_number), sorter: (a, b) => alphaSort(a.job.ro_number, b.job.ro_number),
sortOrder: sortcolumn === "ro_number" && sortorder, sortOrder:
state.sortedInfo.columnKey === "ro_number" && state.sortedInfo.order,
render: (text, record) => ( render: (text, record) => (
<Link to={"/manage/jobs/" + record.job.id}> <Link to={"/manage/jobs/" + record.job.id}>
{record.job.ro_number || t("general.labels.na")} {record.job.ro_number || t("general.labels.na")}
@@ -41,15 +43,18 @@ export default function CsiResponseListPaginated({
}, },
{ {
title: t("jobs.fields.owner"), title: t("jobs.fields.owner"),
dataIndex: "owner", dataIndex: "owner_name",
key: "owner", key: "owner_name",
ellipsis: true, sorter: (a, b) =>
sorter: (a, b) => alphaSort(a.job.ownr_ln, b.job.ownr_ln), alphaSort(
width: "25%", OwnerNameDisplayFunction(a.job),
sortOrder: sortcolumn === "owner" && sortorder, OwnerNameDisplayFunction(b.job)
),
sortOrder:
state.sortedInfo.columnKey === "owner_name" && state.sortedInfo.order,
render: (text, record) => { render: (text, record) => {
return record.job.owner ? ( return record.job.ownerid ? (
<Link to={"/manage/owners/" + record.job.owner.id}> <Link to={"/manage/owners/" + record.job.ownerid}>
<OwnerNameDisplay ownerObject={record.job} /> <OwnerNameDisplay ownerObject={record.job} />
</Link> </Link>
) : ( ) : (
@@ -64,9 +69,9 @@ export default function CsiResponseListPaginated({
dataIndex: "completedon", dataIndex: "completedon",
key: "completedon", key: "completedon",
ellipsis: true, ellipsis: true,
sorter: (a, b) => a.completedon - b.completedon, sorter: (a, b) => dateSort(a.completedon, b.completedon),
width: "25%", sortOrder:
sortOrder: sortcolumn === "completedon" && sortorder, state.sortedInfo.columnKey === "completedon" && state.sortedInfo.order,
render: (text, record) => { render: (text, record) => {
return record.completedon ? ( return record.completedon ? (
<DateFormatter>{record.completedon}</DateFormatter> <DateFormatter>{record.completedon}</DateFormatter>
@@ -76,11 +81,12 @@ export default function CsiResponseListPaginated({
]; ];
const handleTableChange = (pagination, filters, sorter) => { const handleTableChange = (pagination, filters, sorter) => {
setState({ ...state, filteredInfo: filters, sortedInfo: sorter }); setState({
search.page = pagination.current; ...state,
search.sortcolumn = sorter.columnKey; filteredInfo: filters,
search.sortorder = sorter.order; sortedInfo: sorter,
history.push({ search: queryString.stringify(search) }); page: pagination.current,
});
}; };
const handleOnRowClick = (record) => { const handleOnRowClick = (record) => {
@@ -108,7 +114,7 @@ export default function CsiResponseListPaginated({
pagination={{ pagination={{
position: "top", position: "top",
pageSize: pageLimit, pageSize: pageLimit,
current: parseInt(page || 1), current: parseInt(state.page || 1),
total: total, total: total,
}} }}
columns={columns} columns={columns}
@@ -122,13 +128,6 @@ export default function CsiResponseListPaginated({
selectedRowKeys: [responseid], selectedRowKeys: [responseid],
type: "radio", type: "radio",
}} }}
onRow={(record, rowIndex) => {
return {
onClick: (event) => {
handleOnRowClick(record);
}, // click row
};
}}
/> />
</Card> </Card>
); );

View File

@@ -2,7 +2,7 @@ import { Button, Col, Collapse, Result, Row, Space } from "antd";
import React from "react"; import React from "react";
import { withTranslation } from "react-i18next"; import { withTranslation } from "react-i18next";
import { logImEXEvent } from "../../firebase/firebase.utils"; import { logImEXEvent } from "../../firebase/firebase.utils";
import * as Sentry from "@sentry/react";
import { connect } from "react-redux"; import { connect } from "react-redux";
import { createStructuredSelector } from "reselect"; import { createStructuredSelector } from "reselect";
import { import {
@@ -138,7 +138,6 @@ class ErrorBoundary extends React.Component {
} }
} }
export default connect( export default Sentry.withErrorBoundary(
mapStateToProps, connect(mapStateToProps, mapDispatchToProps)(withTranslation()(ErrorBoundary))
mapDispatchToProps );
)(withTranslation()(ErrorBoundary));

View File

@@ -13,7 +13,7 @@ import Icon, {
FileFilled, FileFilled,
//GlobalOutlined, //GlobalOutlined,
HomeFilled, HomeFilled,
ImportOutlined, ImportOutlined, InfoCircleOutlined,
LineChartOutlined, LineChartOutlined,
PaperClipOutlined, PaperClipOutlined,
PhoneOutlined, PhoneOutlined,
@@ -26,8 +26,8 @@ import Icon, {
UserOutlined, UserOutlined,
} from "@ant-design/icons"; } from "@ant-design/icons";
import { useTreatments } from "@splitsoftware/splitio-react"; import { useTreatments } from "@splitsoftware/splitio-react";
import { Layout, Menu } from "antd"; import {Layout, Menu, Switch, Tooltip} from "antd";
import React from "react"; import React, {useEffect, useState} from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { BsKanban } from "react-icons/bs"; import { BsKanban } from "react-icons/bs";
import { import {
@@ -52,6 +52,7 @@ import {
selectBodyshop, selectBodyshop,
selectCurrentUser, selectCurrentUser,
} from "../../redux/user/user.selectors"; } from "../../redux/user/user.selectors";
import {handleBeta, setBeta, checkBeta} from "../../utils/handleBeta";
const mapStateToProps = createStructuredSelector({ const mapStateToProps = createStructuredSelector({
currentUser: selectCurrentUser, currentUser: selectCurrentUser,
@@ -102,9 +103,21 @@ function Header({
{}, {},
bodyshop && bodyshop.imexshopid bodyshop && bodyshop.imexshopid
); );
const [betaSwitch, setBetaSwitch] = useState(false);
const { t } = useTranslation(); const { t } = useTranslation();
useEffect(() => {
const isBeta = checkBeta();
setBetaSwitch(isBeta);
}, []);
const betaSwitchChange = (checked) => {
setBeta(checked);
setBetaSwitch(checked);
handleBeta();
}
return ( return (
<Layout.Header> <Layout.Header>
<Menu <Menu
@@ -431,6 +444,17 @@ function Header({
</Menu.Item> </Menu.Item>
))} ))}
</Menu.SubMenu> </Menu.SubMenu>
<Menu.Item style={{marginLeft: 'auto'}} key="profile">
<Tooltip title="A more modern ImEX Online is ready for you to try! You can switch back at any time.">
<InfoCircleOutlined/>
<span style={{marginRight: 8}}>Try the new ImEX Online</span>
<Switch
checked={betaSwitch}
onChange={betaSwitchChange}
/>
</Tooltip>
</Menu.Item>
</Menu> </Menu>
</Layout.Header> </Layout.Header>
); );

View File

@@ -7,21 +7,31 @@ import { connect } from "react-redux";
import { useHistory } from "react-router"; import { useHistory } from "react-router";
import { createStructuredSelector } from "reselect"; import { createStructuredSelector } from "reselect";
import { UPDATE_JOB_LINES_IOU } from "../../graphql/jobs-lines.queries"; import { UPDATE_JOB_LINES_IOU } from "../../graphql/jobs-lines.queries";
import { selectTechnician } from "../../redux/tech/tech.selectors";
import { import {
selectBodyshop, selectBodyshop,
selectCurrentUser, selectCurrentUser,
} from "../../redux/user/user.selectors"; } from "../../redux/user/user.selectors";
import { CreateIouForJob } from "../jobs-detail-header-actions/jobs-detail-header-actions.duplicate.util"; import { CreateIouForJob } from "../jobs-detail-header-actions/jobs-detail-header-actions.duplicate.util";
const mapStateToProps = createStructuredSelector({ const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop, bodyshop: selectBodyshop,
currentUser: selectCurrentUser, currentUser: selectCurrentUser,
technician: selectTechnician,
}); });
const mapDispatchToProps = (dispatch) => ({ const mapDispatchToProps = (dispatch) => ({
//setUserLanguage: language => dispatch(setUserLanguage(language)) //setUserLanguage: language => dispatch(setUserLanguage(language))
}); });
export default connect(mapStateToProps, mapDispatchToProps)(JobCreateIOU); export default connect(mapStateToProps, mapDispatchToProps)(JobCreateIOU);
export function JobCreateIOU({ bodyshop, currentUser, job, selectedJobLines }) { export function JobCreateIOU({
bodyshop,
currentUser,
job,
selectedJobLines,
technician,
}) {
const { t } = useTranslation(); const { t } = useTranslation();
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
const client = useApolloClient(); const client = useApolloClient();
@@ -79,13 +89,19 @@ export function JobCreateIOU({ bodyshop, currentUser, job, selectedJobLines }) {
title={t("jobs.labels.createiouwarning")} title={t("jobs.labels.createiouwarning")}
onConfirm={handleCreateIou} onConfirm={handleCreateIou}
disabled={ disabled={
!selectedJobLines || selectedJobLines.length === 0 || !job.converted !selectedJobLines ||
selectedJobLines.length === 0 ||
!job.converted ||
technician
} }
> >
<Button <Button
loading={loading} loading={loading}
disabled={ disabled={
!selectedJobLines || selectedJobLines.length === 0 || !job.converted !selectedJobLines ||
selectedJobLines.length === 0 ||
!job.converted ||
technician
} }
> >
{t("jobs.actions.createiou")} {t("jobs.actions.createiou")}

View File

@@ -1,15 +1,37 @@
import React from "react";
import { Card } from "antd"; import { Card } from "antd";
import React from "react";
import { useTranslation } from "react-i18next";
import { connect } from "react-redux";
import { Link } from "react-router-dom"; import { Link } from "react-router-dom";
import { createStructuredSelector } from "reselect";
import { selectTechnician } from "../../redux/tech/tech.selectors";
export default function JobDetailCardTemplate({ const mapStateToProps = createStructuredSelector({
technician: selectTechnician,
});
const mapDispatchToProps = (dispatch) => ({
//setUserLanguage: language => dispatch(setUserLanguage(language))
});
export default connect(
mapStateToProps,
mapDispatchToProps
)(JobDetailCardTemplate);
export function JobDetailCardTemplate({
loading, loading,
title, title,
extraLink, extraLink,
technician,
...otherProps ...otherProps
}) { }) {
const { t } = useTranslation();
let extra; let extra;
if (extraLink) extra = { extra: <Link to={extraLink}>More</Link> }; if (extraLink && !technician)
extra = {
extra: <Link to={extraLink}>{t("jobs.labels.cards.more")}</Link>,
};
return ( return (
<Card <Card
size="small" size="small"

View File

@@ -0,0 +1,246 @@
import React, {useCallback, useEffect, useState} from 'react';
import moment from "moment";
import axios from 'axios';
import {Badge, Card, Space, Table, Tag} from 'antd';
import {gql, useQuery} from "@apollo/client";
import {DateTimeFormatterFunction} from "../../utils/DateFormatter";
import {isEmpty} from "lodash";
import {useTranslation} from "react-i18next";
require('./job-lifecycle.styles.scss');
// show text on bar if text can fit
export function JobLifecycleComponent({job, statuses, ...rest}) {
const [loading, setLoading] = useState(true);
const [lifecycleData, setLifecycleData] = useState(null);
const {t} = useTranslation(); // Used for tracking external state changes.
const {data} = useQuery(gql`
query get_job_test($id: uuid!){
jobs_by_pk(id:$id){
id
status
}
}
`, {
variables: {
id: job.id
},
fetchPolicy: 'cache-only'
});
/**
* Gets the lifecycle data for the job.
* @returns {Promise<void>}
*/
const getLifecycleData = useCallback(async () => {
if (job && job.id && statuses && statuses.statuses) {
try {
setLoading(true);
const response = await axios.post("/job/lifecycle", {
jobids: job.id,
statuses: statuses.statuses
});
const data = response.data.transition[job.id];
setLifecycleData(data);
} catch (err) {
console.error(`${t('job_lifecycle.errors.fetch')}: ${err.message}`);
} finally {
setLoading(false);
}
}
}, [job, statuses, t]);
useEffect(() => {
if (!data) return;
setTimeout(() => {
getLifecycleData().catch(err => console.error(`${t('job_lifecycle.errors.fetch')}: ${err.message}`));
}, 500);
}, [data, getLifecycleData, t]);
const columns = [
{
title: t('job_lifecycle.columns.value'),
dataIndex: 'value',
key: 'value',
},
{
title: t('job_lifecycle.columns.start'),
dataIndex: 'start',
key: 'start',
render: (text) => DateTimeFormatterFunction(text),
sorter: (a, b) => moment(a.start).unix() - moment(b.start).unix(),
},
{
title: t('job_lifecycle.columns.relative_start'),
dataIndex: 'start_readable',
key: 'start_readable',
},
{
title: t('job_lifecycle.columns.end'),
dataIndex: 'end',
key: 'end',
sorter: (a, b) => {
if (isEmpty(a.end) || isEmpty(b.end)) {
if (isEmpty(a.end) && isEmpty(b.end)) {
return 0;
}
return isEmpty(a.end) ? 1 : -1;
}
return moment(a.end).unix() - moment(b.end).unix();
},
render: (text) => isEmpty(text) ? t('job_lifecycle.content.not_available') : DateTimeFormatterFunction(text)
},
{
title: t('job_lifecycle.columns.relative_end'),
dataIndex: 'end_readable',
key: 'end_readable',
},
{
title: t('job_lifecycle.columns.duration'),
dataIndex: 'duration_readable',
key: 'duration_readable',
sorter: (a, b) => a.duration - b.duration,
},
];
return (
<Card loading={loading} title={t('job_lifecycle.content.title')}>
{!loading ? (
lifecycleData && lifecycleData.lifecycle && lifecycleData.durations ? (
<Space direction='vertical' style={{width: '100%'}}>
<Card
type='inner'
title={(
<Space direction='horizontal' size='small'>
<Badge status='processing' count={lifecycleData.durations.totalStatuses}/>
{t('job_lifecycle.content.title_durations')}
</Space>
)}
style={{width: '100%'}}
>
<div id="bar-container" style={{
display: 'flex',
width: '100%',
height: '100px',
textAlign: 'center',
borderRadius: '5px',
borderWidth: '5px',
borderStyle: 'solid',
borderColor: '#f0f2f5',
margin: 0,
padding: 0
}}>
{lifecycleData.durations.summations.map((key, index, array) => {
const isFirst = index === 0;
const isLast = index === array.length - 1;
return (
<div key={key.status} style={{
overflow: 'hidden',
display: 'flex',
flexDirection: 'column',
justifyContent: 'center',
alignItems: 'center',
margin: 0,
padding: 0,
borderTop: '1px solid #f0f2f5',
borderBottom: '1px solid #f0f2f5',
borderLeft: isFirst ? '1px solid #f0f2f5' : undefined,
borderRight: isLast ? '1px solid #f0f2f5' : undefined,
backgroundColor: key.color,
width: `${key.percentage}%`
}}
aria-label={`${key.status} | ${key.roundedPercentage} | ${key.humanReadable}`}
title={`${key.status} | ${key.roundedPercentage} | ${key.humanReadable}`}
>
{key.percentage > 15 ?
<>
<div>{key.roundedPercentage}</div>
<div style={{
backgroundColor: '#f0f2f5',
borderRadius: '5px',
paddingRight: '2px',
paddingLeft: '2px',
fontSize: '0.8rem',
}}>
{key.status}
</div>
</>
: null}
</div>
);
})}
</div>
<Card type='inner' title={t('job_lifecycle.content.legend_title')}
style={{marginTop: '10px'}}>
<div>
{lifecycleData.durations.summations.map((key) => (
<Tag color={key.color} style={{width: '13vh', padding: '4px', margin: '4px'}}>
<div
aria-label={`${key.status} | ${key.roundedPercentage} | ${key.humanReadable}`}
title={`${key.status} | ${key.roundedPercentage} | ${key.humanReadable}`}
style={{
backgroundColor: '#f0f2f5',
color: '#000',
padding: '4px',
textAlign: 'center'
}}>
{key.status} ({key.roundedPercentage})
</div>
</Tag>
))}
</div>
</Card>
{(lifecycleData?.durations?.humanReadableTotal) ||
(lifecycleData.lifecycle[0] && lifecycleData.lifecycle[0].value && lifecycleData?.durations?.totalCurrentStatusDuration?.humanReadable) ?
<Card style={{marginTop: '10px'}}>
<ul>
{lifecycleData.durations && lifecycleData.durations.humanReadableTotal &&
<li>
<span
style={{fontWeight: 'bold'}}>{t('job_lifecycle.content.previous_status_accumulated_time')}:</span> {lifecycleData.durations.humanReadableTotal}
</li>
}
{lifecycleData.lifecycle[0] && lifecycleData.lifecycle[0].value && lifecycleData?.durations?.totalCurrentStatusDuration?.humanReadable &&
<li>
<span
style={{fontWeight: 'bold'}}>{t('job_lifecycle.content.current_status_accumulated_time')} ({lifecycleData.lifecycle[0].value}):</span> {lifecycleData.durations.totalCurrentStatusDuration.humanReadable}
</li>
}
</ul>
</Card>
: null}
</Card>
<Card type='inner' title={(
<>
<Space direction="horizontal" size="small">
<Badge status='processing' count={lifecycleData.lifecycle.length}/>
{t('job_lifecycle.content.title_transitions')}
</Space>
</>
)}>
<Table style={{
overflow: 'auto',
width: '100%',
}} columns={columns} dataSource={lifecycleData.lifecycle}/>
</Card>
</Space>
) : (
<Card type='inner' style={{textAlign: 'center'}}>
{t('job_lifecycle.content.data_unavailable')}
</Card>
)
) : (
<Card type='inner' title={t('job_lifecycle.content.title_loading')}>
{t('job_lifecycle.content.loading')}
</Card>
)}
</Card>
);
}
export default JobLifecycleComponent;

View File

@@ -53,12 +53,14 @@ export function JobsAdminStatus({ insertAuditTrail, bodyshop, job }) {
); );
return ( return (
<Dropdown overlay={statusmenu} trigger={["click"]} key="changestatus"> <>
<Button shape="round"> <Dropdown overlay={statusmenu} trigger={["click"]} key="changestatus">
<span>{job.status}</span> <Button shape="round">
<span>{job.status}</span>
<DownCircleFilled /> <DownCircleFilled />
</Button> </Button>
</Dropdown> </Dropdown>
</>
); );
} }

View File

@@ -1,34 +1,18 @@
import { useMutation } from "@apollo/client"; import { useMutation } from "@apollo/client";
import { Button, notification } from "antd"; import { Button, Space, 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 {
DELETE_DELIVERY_CHECKLIST,
DELETE_INTAKE_CHECKLIST,
} from "../../graphql/jobs.queries";
export default function JobAdminDeleteIntake({ job }) { export default function JobAdminDeleteIntake({ job }) {
const { t } = useTranslation(); const { t } = useTranslation();
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
const [deleteIntake] = useMutation(gql`
mutation DELETE_INTAKE($jobId: uuid!) {
update_jobs_by_pk(
pk_columns: { id: $jobId }
_set: { intakechecklist: null }
) {
id
intakechecklist
}
}
`);
const [DELETE_DELIVERY] = useMutation(gql` const [deleteIntake] = useMutation(DELETE_INTAKE_CHECKLIST);
mutation DELETE_DELIVERY($jobId: uuid!) { const [deleteDelivery] = useMutation(DELETE_DELIVERY_CHECKLIST);
update_jobs_by_pk(
pk_columns: { id: $jobId }
_set: { deliverchecklist: null }
) {
id
deliverchecklist
}
}
`);
const handleDelete = async (values) => { const handleDelete = async (values) => {
setLoading(true); setLoading(true);
@@ -50,7 +34,7 @@ export default function JobAdminDeleteIntake({ job }) {
const handleDeleteDelivery = async (values) => { const handleDeleteDelivery = async (values) => {
setLoading(true); setLoading(true);
const result = await DELETE_DELIVERY({ const result = await deleteDelivery({
variables: { jobId: job.id }, variables: { jobId: job.id },
}); });
@@ -68,12 +52,22 @@ export default function JobAdminDeleteIntake({ job }) {
return ( return (
<> <>
<Button loading={loading} onClick={handleDelete}> <Space wrap>
{t("jobs.labels.deleteintake")} <Button
</Button> loading={loading}
<Button loading={loading} onClick={handleDeleteDelivery}> onClick={handleDelete}
{t("jobs.labels.deletedelivery")} disabled={!job.intakechecklist}
</Button> >
{t("jobs.labels.deleteintake")}
</Button>
<Button
loading={loading}
onClick={handleDeleteDelivery}
disabled={!job.deliverychecklist}
>
{t("jobs.labels.deletedelivery")}
</Button>
</Space>
</> </>
); );
} }

View File

@@ -1,5 +1,5 @@
import { gql, useMutation } from "@apollo/client"; import { useMutation } from "@apollo/client";
import { Button, notification } from "antd"; import { Button, Space, notification } from "antd";
import React, { useState } from "react"; import React, { useState } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
@@ -7,6 +7,11 @@ import moment from "moment";
import { connect } from "react-redux"; import { connect } from "react-redux";
import { createStructuredSelector } from "reselect"; import { createStructuredSelector } from "reselect";
import { INSERT_EXPORT_LOG } from "../../graphql/accounting.queries"; import { INSERT_EXPORT_LOG } from "../../graphql/accounting.queries";
import {
MARK_JOB_AS_EXPORTED,
MARK_JOB_AS_UNINVOICED,
MARK_JOB_FOR_REEXPORT,
} from "../../graphql/jobs.queries";
import { insertAuditTrail } from "../../redux/application/application.actions"; import { insertAuditTrail } from "../../redux/application/application.actions";
import { import {
selectBodyshop, selectBodyshop,
@@ -35,58 +40,18 @@ export function JobAdminMarkReexport({
const { t } = useTranslation(); const { t } = useTranslation();
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
const [insertExportLog] = useMutation(INSERT_EXPORT_LOG); const [insertExportLog] = useMutation(INSERT_EXPORT_LOG);
const [markJobForReexport] = useMutation(gql`
mutation MARK_JOB_FOR_REEXPORT($jobId: uuid!) {
update_jobs_by_pk(
pk_columns: { id: $jobId }
_set: { date_exported: null
status: "${bodyshop.md_ro_statuses.default_invoiced}"
}
) {
id
date_exported
status
date_invoiced
}
}
`);
const [markJobExported] = useMutation(gql` const [markJobForReexport] = useMutation(MARK_JOB_FOR_REEXPORT);
mutation MARK_JOB_AS_EXPORTED($jobId: uuid!, $date_exported: timestamptz!) { const [markJobExported] = useMutation(MARK_JOB_AS_EXPORTED);
update_jobs_by_pk( const [markJobUninvoiced] = useMutation(MARK_JOB_AS_UNINVOICED);
pk_columns: { id: $jobId }
_set: { date_exported: $date_exported
status: "${bodyshop.md_ro_statuses.default_exported}"
}
) {
id
date_exported
date_invoiced
status
}
}
`);
const [markJobUninvoiced] = useMutation(gql`
mutation MARK_JOB_AS_UNINVOICED($jobId: uuid!, ) {
update_jobs_by_pk(
pk_columns: { id: $jobId }
_set: { date_exported: null
date_invoiced: null
status: "${bodyshop.md_ro_statuses.default_delivered}"
}
) {
id
date_exported
date_invoiced
status
}
}
`);
const handleMarkForExport = async () => { const handleMarkForExport = async () => {
setLoading(true); setLoading(true);
const result = await markJobForReexport({ const result = await markJobForReexport({
variables: { jobId: job.id }, variables: {
jobId: job.id,
default_invoiced: bodyshop.md_ro_statuses.default_invoiced,
},
}); });
if (!result.errors) { if (!result.errors) {
@@ -108,7 +73,11 @@ export function JobAdminMarkReexport({
const handleMarkExported = async () => { const handleMarkExported = async () => {
setLoading(true); setLoading(true);
const result = await markJobExported({ const result = await markJobExported({
variables: { jobId: job.id, date_exported: moment() }, variables: {
jobId: job.id,
date_exported: moment(),
default_exported: bodyshop.md_ro_statuses.default_exported,
},
}); });
await insertExportLog({ await insertExportLog({
@@ -144,7 +113,10 @@ export function JobAdminMarkReexport({
const handleUninvoice = async () => { const handleUninvoice = async () => {
setLoading(true); setLoading(true);
const result = await markJobUninvoiced({ const result = await markJobUninvoiced({
variables: { jobId: job.id }, variables: {
jobId: job.id,
default_delivered: bodyshop.md_ro_statuses.default_delivered,
},
}); });
if (!result.errors) { if (!result.errors) {
@@ -165,27 +137,29 @@ export function JobAdminMarkReexport({
return ( return (
<> <>
<Button <Space wrap>
loading={loading} <Button
disabled={!job.date_exported} loading={loading}
onClick={handleMarkForExport} disabled={!job.date_exported}
> onClick={handleMarkForExport}
{t("jobs.labels.markforreexport")} >
</Button> {t("jobs.labels.markforreexport")}
<Button </Button>
loading={loading} <Button
disabled={job.date_exported} loading={loading}
onClick={handleMarkExported} disabled={job.date_exported}
> onClick={handleMarkExported}
{t("jobs.actions.markasexported")} >
</Button> {t("jobs.actions.markasexported")}
<Button </Button>
loading={loading} <Button
disabled={!job.date_invoiced || job.date_exported} loading={loading}
onClick={handleUninvoice} disabled={!job.date_invoiced || job.date_exported}
> onClick={handleUninvoice}
{t("jobs.actions.uninvoice")} >
</Button> {t("jobs.actions.uninvoice")}
</Button>
</Space>
</> </>
); );
} }

View File

@@ -0,0 +1,65 @@
import { useMutation } from "@apollo/client";
import { Switch, notification } from "antd";
import React, { useState } from "react";
import { useTranslation } from "react-i18next";
import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
import { UPDATE_REMOVE_FROM_AR } from "../../graphql/jobs.queries";
import { insertAuditTrail } from "../../redux/application/application.actions";
import AuditTrailMapping from "../../utils/AuditTrailMappings";
const mapStateToProps = createStructuredSelector({});
const mapDispatchToProps = (dispatch) => ({
insertAuditTrail: ({ jobid, operation }) =>
dispatch(insertAuditTrail({ jobid, operation })),
});
export default connect(mapStateToProps, mapDispatchToProps)(JobsAdminRemoveAR);
export function JobsAdminRemoveAR({ insertAuditTrail, job }) {
const { t } = useTranslation();
const [loading, setLoading] = useState(false);
const [switchValue, setSwitchValue] = useState(job.remove_from_ar);
const [mutationUpdateRemoveFromAR] = useMutation(UPDATE_REMOVE_FROM_AR);
const handleChange = async (value) => {
setLoading(true);
const result = await mutationUpdateRemoveFromAR({
variables: { jobId: job.id, remove_from_ar: value },
});
if (!result.errors) {
notification["success"]({ message: t("jobs.successes.save") });
insertAuditTrail({
jobid: job.id,
operation: AuditTrailMapping.admin_job_remove_from_ar(value),
});
setSwitchValue(value);
} else {
notification["error"]({
message: t("jobs.errors.saving", {
error: JSON.stringify(result.errors),
}),
});
}
setLoading(false);
};
return (
<>
<div style={{ display: "flex", alignItems: "center" }}>
<div style={{ marginRight: "10px" }}>
{t("jobs.labels.remove_from_ar")}:
</div>
<div>
<Switch
checked={switchValue}
loading={loading}
onChange={handleChange}
/>
</div>
</div>
</>
);
}

View File

@@ -1,9 +1,10 @@
import { gql, useMutation } from "@apollo/client"; import { useMutation } from "@apollo/client";
import { Button, notification } from "antd"; import { Button, notification } from "antd";
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 { UNVOID_JOB } from "../../graphql/jobs.queries";
import { insertAuditTrail } from "../../redux/application/application.actions"; import { insertAuditTrail } from "../../redux/application/application.actions";
import { import {
selectBodyshop, selectBodyshop,
@@ -29,66 +30,17 @@ export function JobsAdminUnvoid({
}) { }) {
const { t } = useTranslation(); const { t } = useTranslation();
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
const [updateJob] = useMutation(gql` const [mutationUnvoidJob] = useMutation(UNVOID_JOB);
mutation UNVOID_JOB($jobId: uuid!) {
update_jobs_by_pk(pk_columns: {id: $jobId}, _set: {voided: false, status: "${
bodyshop.md_ro_statuses.default_imported
}", date_void: null}) {
id
date_void
voided
status
}
insert_notes(objects: {jobid: $jobId, audit: true, created_by: "${
currentUser.email
}", text: "${t("jobs.labels.unvoidnote")}"}) {
returning {
id
}
}
}
`);
// const result = await voidJob({
// variables: {
// jobId: job.id,
// job: {
// status: bodyshop.md_ro_statuses.default_void,
// voided: true,
// },
// note: [
// {
// jobid: job.id,
// created_by: currentUser.email,
// audit: true,
// text: t("jobs.labels.voidnote", {
// date: moment().format("MM/DD/yyy"),
// time: moment().format("hh:mm a"),
// }),
// },
// ],
// },
// });
// if (!!!result.errors) {
// notification["success"]({
// message: t("jobs.successes.voided"),
// });
// //go back to jobs list.
// history.push(`/manage/`);
// } else {
// notification["error"]({
// message: t("jobs.errors.voiding", {
// error: JSON.stringify(result.errors),
// }),
// });
// }
const handleUpdate = async (values) => { const handleUpdate = async (values) => {
setLoading(true); setLoading(true);
const result = await updateJob({ const result = await mutationUnvoidJob({
variables: { jobId: job.id }, variables: {
jobId: job.id,
default_imported: bodyshop.md_ro_statuses.default_imported,
currentUserEmail: currentUser.email,
text: t("jobs.labels.unvoidnote"),
},
}); });
if (!result.errors) { if (!result.errors) {
@@ -110,8 +62,10 @@ mutation UNVOID_JOB($jobId: uuid!) {
}; };
return ( return (
<Button loading={loading} disabled={!job.voided} onClick={handleUpdate}> <>
{t("jobs.actions.unvoid")} <Button loading={loading} disabled={!job.voided} onClick={handleUpdate}>
</Button> {t("jobs.actions.unvoid")}
</Button>
</>
); );
} }

View File

@@ -19,10 +19,13 @@ export default function JobsCreateOwnerInfoNewComponent() {
label={t("owners.fields.ownr_ln")} label={t("owners.fields.ownr_ln")}
name={["owner", "data", "ownr_ln"]} name={["owner", "data", "ownr_ln"]}
rules={[ rules={[
{ ({ getFieldValue }) => ({
required: state.owner.new, required:
state.owner.new &&
(!getFieldValue(["owner", "data", "ownr_co_nm"]) ||
getFieldValue(["owner", "data", "ownr_co_nm"]) === ""),
//message: t("general.validation.required"), //message: t("general.validation.required"),
}, }),
]} ]}
> >
<Input disabled={!state.owner.new} /> <Input disabled={!state.owner.new} />
@@ -31,10 +34,13 @@ export default function JobsCreateOwnerInfoNewComponent() {
label={t("owners.fields.ownr_fn")} label={t("owners.fields.ownr_fn")}
name={["owner", "data", "ownr_fn"]} name={["owner", "data", "ownr_fn"]}
rules={[ rules={[
{ ({ getFieldValue }) => ({
required: state.owner.new, required:
state.owner.new &&
(!getFieldValue(["owner", "data", "ownr_co_nm"]) ||
getFieldValue(["owner", "data", "ownr_co_nm"]) === ""),
//message: t("general.validation.required"), //message: t("general.validation.required"),
}, }),
]} ]}
> >
<Input disabled={!state.owner.new} /> <Input disabled={!state.owner.new} />
@@ -51,6 +57,17 @@ export default function JobsCreateOwnerInfoNewComponent() {
<Form.Item <Form.Item
label={t("owners.fields.ownr_co_nm")} label={t("owners.fields.ownr_co_nm")}
name={["owner", "data", "ownr_co_nm"]} name={["owner", "data", "ownr_co_nm"]}
rules={[
({ getFieldValue }) => ({
required:
state.owner.new &&
(!getFieldValue(["owner", "data", "ownr_ln"]) ||
!getFieldValue(["owner", "data", "ownr_fn"]) ||
getFieldValue(["owner", "data", "ownr_ln"]) === "" ||
getFieldValue(["owner", "data", "ownr_fn"]) === ""),
//message: t("general.validation.required"),
}),
]}
> >
<Input disabled={!state.owner.new} /> <Input disabled={!state.owner.new} />
</Form.Item> </Form.Item>

View File

@@ -1,8 +1,8 @@
import { import {
BranchesOutlined,
ExclamationCircleFilled, ExclamationCircleFilled,
PauseCircleOutlined, PauseCircleOutlined,
WarningFilled, WarningFilled,
BranchesOutlined,
} from "@ant-design/icons"; } from "@ant-design/icons";
import { Card, Col, Row, Space, Tag, Tooltip } from "antd"; import { Card, Col, Row, Space, Tag, Tooltip } from "antd";
import React, { useState } from "react"; import React, { useState } from "react";
@@ -15,6 +15,7 @@ import { setModalContext } from "../../redux/modals/modals.actions";
import { selectBodyshop } from "../../redux/user/user.selectors"; import { selectBodyshop } from "../../redux/user/user.selectors";
import CurrencyFormatter from "../../utils/CurrencyFormatter"; import CurrencyFormatter from "../../utils/CurrencyFormatter";
import { DateTimeFormatter } from "../../utils/DateFormatter"; import { DateTimeFormatter } from "../../utils/DateFormatter";
import PhoneNumberFormatter from "../../utils/PhoneFormatter";
import ChatOpenButton from "../chat-open-button/chat-open-button.component"; import ChatOpenButton from "../chat-open-button/chat-open-button.component";
import DataLabel from "../data-label/data-label.component"; import DataLabel from "../data-label/data-label.component";
import JobAltTransportChange from "../job-at-change/job-at-change.component"; import JobAltTransportChange from "../job-at-change/job-at-change.component";
@@ -160,19 +161,35 @@ export function JobsDetailHeader({ job, bodyshop, disabled }) {
<Card <Card
style={{ height: "100%" }} style={{ height: "100%" }}
title={ title={
<Link to={disabled ? "#" : `/manage/owners/${job.owner.id}`}> disabled ? (
{ownerTitle.length > 0 <>
? ownerTitle {ownerTitle.length > 0
: t("owner.labels.noownerinfo")} ? ownerTitle
</Link> : t("owner.labels.noownerinfo")}
</>
) : (
<Link to={`/manage/owners/${job.owner.id}`}>
{ownerTitle.length > 0
? ownerTitle
: t("owner.labels.noownerinfo")}
</Link>
)
} }
> >
<div> <div>
<DataLabel key="2" label={t("jobs.fields.ownr_ph1")}> <DataLabel key="2" label={t("jobs.fields.ownr_ph1")}>
<ChatOpenButton phone={job.ownr_ph1} jobid={job.id} /> {disabled ? (
<PhoneNumberFormatter>{job.ownr_ph1}</PhoneNumberFormatter>
) : (
<ChatOpenButton phone={job.ownr_ph1} jobid={job.id} />
)}
</DataLabel> </DataLabel>
<DataLabel key="22" label={t("jobs.fields.ownr_ph2")}> <DataLabel key="22" label={t("jobs.fields.ownr_ph2")}>
<ChatOpenButton phone={job.ownr_ph2} jobid={job.id} /> {disabled ? (
<PhoneNumberFormatter>{job.ownr_ph2}</PhoneNumberFormatter>
) : (
<ChatOpenButton phone={job.ownr_ph2} jobid={job.id} />
)}
</DataLabel> </DataLabel>
<DataLabel key="3" label={t("owners.fields.address")}> <DataLabel key="3" label={t("owners.fields.address")}>
{`${job.ownr_addr1 || ""} ${job.ownr_addr2 || ""} ${ {`${job.ownr_addr1 || ""} ${job.ownr_addr2 || ""} ${
@@ -180,7 +197,11 @@ export function JobsDetailHeader({ job, bodyshop, disabled }) {
} ${job.ownr_st || ""} ${job.ownr_zip || ""}`} } ${job.ownr_st || ""} ${job.ownr_zip || ""}`}
</DataLabel> </DataLabel>
<DataLabel key="4" label={t("owners.fields.ownr_ea")}> <DataLabel key="4" label={t("owners.fields.ownr_ea")}>
{job.ownr_ea || ""} {disabled ? (
<>{job.ownr_ea || ""}</>
) : job.ownr_ea ? (
<a href={`mailto:${job.ownr_ea}`}>{job.ownr_ea}</a>
) : null}
</DataLabel> </DataLabel>
{job.owner?.tax_number && ( {job.owner?.tax_number && (
<DataLabel key="5" label={t("owners.fields.tax_number")}> <DataLabel key="5" label={t("owners.fields.tax_number")}>
@@ -195,17 +216,19 @@ export function JobsDetailHeader({ job, bodyshop, disabled }) {
style={{ height: "100%" }} style={{ height: "100%" }}
title={ title={
job.vehicle ? ( job.vehicle ? (
<Link disabled ? (
to={ <>
disabled {vehicleTitle.length > 0
? "#" ? vehicleTitle
: job.vehicle && `/manage/vehicles/${job.vehicle.id}` : t("vehicles.labels.novehinfo")}{" "}
} </>
> ) : (
{vehicleTitle.length > 0 <Link to={job.vehicle && `/manage/vehicles/${job.vehicle.id}`}>
? vehicleTitle {vehicleTitle.length > 0
: t("vehicles.labels.novehinfo")} ? vehicleTitle
</Link> : t("vehicles.labels.novehinfo")}
</Link>
)
) : ( ) : (
<span></span> <span></span>
) )
@@ -221,9 +244,19 @@ export function JobsDetailHeader({ job, bodyshop, disabled }) {
<VehicleVinDisplay> <VehicleVinDisplay>
{`${job.v_vin || t("general.labels.na")}`} {`${job.v_vin || t("general.labels.na")}`}
</VehicleVinDisplay> </VehicleVinDisplay>
{bodyshop.pbs_serialnumber || bodyshop.cdk_dealerid ? (
job.v_vin?.length !== 17 ? (
<WarningFilled
style={{ color: "tomato", marginLeft: ".3rem" }}
/>
) : null
) : null}
</DataLabel>
<DataLabel label={t("jobs.fields.regie_number")}>
{job.regie_number || t("general.labels.na")}
</DataLabel> </DataLabel>
<DataLabel label={t("jobs.labels.relatedros")}> <DataLabel label={t("jobs.labels.relatedros")}>
<JobsRelatedRos jobid={job.id} job={job} /> <JobsRelatedRos jobid={job.id} job={job} disabled={disabled} />
</DataLabel> </DataLabel>
{job.vehicle && job.vehicle.notes && ( {job.vehicle && job.vehicle.notes && (
<DataLabel <DataLabel

View File

@@ -10,9 +10,10 @@ import { Link, useHistory, useLocation } from "react-router-dom";
import { createStructuredSelector } from "reselect"; import { createStructuredSelector } from "reselect";
import { selectBodyshop } from "../../redux/user/user.selectors"; import { selectBodyshop } from "../../redux/user/user.selectors";
import CurrencyFormatter from "../../utils/CurrencyFormatter"; import CurrencyFormatter from "../../utils/CurrencyFormatter";
import { pageLimit } from "../../utils/config";
import useLocalStorage from "../../utils/useLocalStorage";
import StartChatButton from "../chat-open-button/chat-open-button.component"; import StartChatButton from "../chat-open-button/chat-open-button.component";
import OwnerNameDisplay from "../owner-name-display/owner-name-display.component"; import OwnerNameDisplay from "../owner-name-display/owner-name-display.component";
import {pageLimit} from "../../utils/config";
const mapStateToProps = createStructuredSelector({ const mapStateToProps = createStructuredSelector({
//currentUser: selectCurrentUser //currentUser: selectCurrentUser
bodyshop: selectBodyshop, bodyshop: selectBodyshop,
@@ -25,6 +26,7 @@ export function JobsList({ bodyshop, refetch, loading, jobs, total }) {
const search = queryString.parse(useLocation().search); const search = queryString.parse(useLocation().search);
const [openSearchResults, setOpenSearchResults] = useState([]); const [openSearchResults, setOpenSearchResults] = useState([]);
const [searchLoading, setSearchLoading] = useState(false); const [searchLoading, setSearchLoading] = useState(false);
const [filter, setFilter] = useLocalStorage("filter_jobs_all", null);
const { page, sortcolumn, sortorder } = search; const { page, sortcolumn, sortorder } = search;
const history = useHistory(); const history = useHistory();
@@ -93,6 +95,7 @@ export function JobsList({ bodyshop, refetch, loading, jobs, total }) {
render: (text, record) => { render: (text, record) => {
return record.status || t("general.labels.na"); return record.status || t("general.labels.na");
}, },
filteredValue: filter?.status || null,
filters: bodyshop.md_ro_statuses.statuses.map((s) => { filters: bodyshop.md_ro_statuses.statuses.map((s) => {
return { text: s, value: [s] }; return { text: s, value: [s] };
}), }),
@@ -189,6 +192,7 @@ export function JobsList({ bodyshop, refetch, loading, jobs, total }) {
} else { } else {
delete search.statusFilters; delete search.statusFilters;
} }
setFilter(filters);
history.push({ search: queryString.stringify(search) }); history.push({ search: queryString.stringify(search) });
}; };

View File

@@ -1,8 +1,8 @@
import { import {
SyncOutlined, BranchesOutlined,
ExclamationCircleFilled, ExclamationCircleFilled,
PauseCircleOutlined, PauseCircleOutlined,
BranchesOutlined, SyncOutlined,
} from "@ant-design/icons"; } from "@ant-design/icons";
import { useQuery } from "@apollo/client"; import { useQuery } from "@apollo/client";
import { Button, Card, Grid, Input, Space, Table, Tooltip } from "antd"; import { Button, Card, Grid, Input, Space, Table, Tooltip } from "antd";
@@ -14,382 +14,389 @@ import { Link, useHistory, useLocation } from "react-router-dom";
import { createStructuredSelector } from "reselect"; import { createStructuredSelector } from "reselect";
import { QUERY_ALL_ACTIVE_JOBS } from "../../graphql/jobs.queries"; import { QUERY_ALL_ACTIVE_JOBS } from "../../graphql/jobs.queries";
import { selectBodyshop } from "../../redux/user/user.selectors"; import { selectBodyshop } from "../../redux/user/user.selectors";
import { onlyUnique } from "../../utils/arrayHelper";
import CurrencyFormatter from "../../utils/CurrencyFormatter"; import CurrencyFormatter from "../../utils/CurrencyFormatter";
import { alphaSort } from "../../utils/sorters"; import { onlyUnique } from "../../utils/arrayHelper";
import { alphaSort, statusSort } from "../../utils/sorters";
import useLocalStorage from "../../utils/useLocalStorage";
import AlertComponent from "../alert/alert.component"; import AlertComponent from "../alert/alert.component";
import ChatOpenButton from "../chat-open-button/chat-open-button.component"; import ChatOpenButton from "../chat-open-button/chat-open-button.component";
import OwnerNameDisplay from "../owner-name-display/owner-name-display.component"; import OwnerNameDisplay from "../owner-name-display/owner-name-display.component";
const mapStateToProps = createStructuredSelector({ const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop, bodyshop: selectBodyshop,
}); });
export function JobsList({ bodyshop }) { export function JobsList({ bodyshop }) {
const searchParams = queryString.parse(useLocation().search); const searchParams = queryString.parse(useLocation().search);
const { selected } = searchParams; const { selected } = searchParams;
const selectedBreakpoint = Object.entries(Grid.useBreakpoint()) const selectedBreakpoint = Object.entries(Grid.useBreakpoint())
.filter((screen) => !!screen[1]) .filter((screen) => !!screen[1])
.slice(-1)[0]; .slice(-1)[0];
const { loading, error, data, refetch } = useQuery(QUERY_ALL_ACTIVE_JOBS, { const { loading, error, data, refetch } = useQuery(QUERY_ALL_ACTIVE_JOBS, {
variables: { variables: {
statuses: bodyshop.md_ro_statuses.active_statuses || ["Open", "Open*"], statuses: bodyshop.md_ro_statuses.active_statuses || ["Open", "Open*"],
}, },
fetchPolicy: "network-only", fetchPolicy: "network-only",
nextFetchPolicy: "network-only", nextFetchPolicy: "network-only",
}); });
const [state, setState] = useState({ const [state, setState] = useState({ sortedInfo: {} });
sortedInfo: {}, const [filter, setFilter] = useLocalStorage("filter_jobs_list", null);
filteredInfo: { text: "" },
});
const { t } = useTranslation(); const { t } = useTranslation();
const history = useHistory(); const history = useHistory();
const [searchText, setSearchText] = useState(""); const [searchText, setSearchText] = useState("");
if (error) return <AlertComponent message={error.message} type="error" />; if (error) return <AlertComponent message={error.message} type="error" />;
const jobs = data const jobs = data
? searchText === "" ? searchText === ""
? data.jobs ? data.jobs
: data.jobs.filter( : data.jobs.filter(
(j) => (j) =>
(j.ro_number || "") (j.ro_number || "")
.toString() .toString()
.toLowerCase() .toLowerCase()
.includes(searchText.toLowerCase()) || .includes(searchText.toLowerCase()) ||
(j.ownr_co_nm || "") (j.ownr_co_nm || "")
.toLowerCase() .toLowerCase()
.includes(searchText.toLowerCase()) || .includes(searchText.toLowerCase()) ||
(j.comments || "") (j.comments || "")
.toLowerCase() .toLowerCase()
.includes(searchText.toLowerCase()) || .includes(searchText.toLowerCase()) ||
(j.ownr_fn || "") (j.ownr_fn || "")
.toLowerCase() .toLowerCase()
.includes(searchText.toLowerCase()) || .includes(searchText.toLowerCase()) ||
(j.ownr_ln || "") (j.ownr_ln || "")
.toLowerCase() .toLowerCase()
.includes(searchText.toLowerCase()) || .includes(searchText.toLowerCase()) ||
(j.clm_no || "").toLowerCase().includes(searchText.toLowerCase()) || (j.clm_no || "").toLowerCase().includes(searchText.toLowerCase()) ||
(j.plate_no || "") (j.plate_no || "")
.toLowerCase() .toLowerCase()
.includes(searchText.toLowerCase()) || .includes(searchText.toLowerCase()) ||
(j.v_model_desc || "") (j.v_model_desc || "")
.toLowerCase() .toLowerCase()
.includes(searchText.toLowerCase()) || .includes(searchText.toLowerCase()) ||
(j.est_ct_fn || "") (j.est_ct_fn || "")
.toLowerCase() .toLowerCase()
.includes(searchText.toLowerCase()) || .includes(searchText.toLowerCase()) ||
(j.est_ct_ln || "") (j.est_ct_ln || "")
.toLowerCase() .toLowerCase()
.includes(searchText.toLowerCase()) || .includes(searchText.toLowerCase()) ||
(j.v_make_desc || "") (j.v_make_desc || "")
.toLowerCase() .toLowerCase()
.includes(searchText.toLowerCase()) .includes(searchText.toLowerCase())
) )
: []; : [];
const handleTableChange = (pagination, filters, sorter) => { const handleTableChange = (pagination, filters, sorter) => {
setState({ ...state, filteredInfo: filters, sortedInfo: sorter }); setState({ ...state, sortedInfo: sorter });
}; setFilter(filters);
};
const handleOnRowClick = (record) => { const handleOnRowClick = (record) => {
if (record) { if (record) {
if (record.id) { if (record.id) {
history.push({ history.push({
search: queryString.stringify({ search: queryString.stringify({
...searchParams, ...searchParams,
selected: record.id, selected: record.id,
}), }),
}); });
} }
} }
}; };
const columns = [ const columns = [
{ {
title: t("jobs.fields.ro_number"), title: t("jobs.fields.ro_number"),
dataIndex: "ro_number", dataIndex: "ro_number",
key: "ro_number", key: "ro_number",
sorter: (a, b) => sorter: (a, b) =>
parseInt((a.ro_number || "0").replace(/\D/g, "")) - parseInt((a.ro_number || "0").replace(/\D/g, "")) -
parseInt((b.ro_number || "0").replace(/\D/g, "")), parseInt((b.ro_number || "0").replace(/\D/g, "")),
sortOrder: sortOrder:
state.sortedInfo.columnKey === "ro_number" && state.sortedInfo.order, state.sortedInfo.columnKey === "ro_number" && state.sortedInfo.order,
render: (text, record) => (
render: (text, record) => ( <Link
<Link to={"/manage/jobs/" + record.id}
to={"/manage/jobs/" + record.id} onClick={(e) => e.stopPropagation()}
onClick={(e) => e.stopPropagation()} >
> <Space>
<Space> {record.ro_number || t("general.labels.na")}
{record.ro_number || t("general.labels.na")} {record.production_vars && record.production_vars.alert ? (
{record.production_vars && record.production_vars.alert ? ( <ExclamationCircleFilled className="production-alert" />
<ExclamationCircleFilled className="production-alert" /> ) : null}
) : null} {record.suspended && (
{record.suspended && ( <PauseCircleOutlined style={{ color: "orangered" }} />
<PauseCircleOutlined style={{ color: "orangered" }} /> )}
)} {record.iouparent && (
{record.iouparent && ( <Tooltip title={t("jobs.labels.iou")}>
<Tooltip title={t("jobs.labels.iou")}> <BranchesOutlined style={{ color: "orangered" }} />
<BranchesOutlined style={{ color: "orangered" }} /> </Tooltip>
</Tooltip> )}
)} </Space>
</Space> </Link>
</Link> ),
), },
}, {
{ title: t("jobs.fields.owner"),
title: t("jobs.fields.owner"), dataIndex: "owner",
dataIndex: "owner", key: "owner",
key: "owner", ellipsis: true,
ellipsis: true, responsive: ["md"],
sorter: (a, b) => alphaSort(a.ownr_ln, b.ownr_ln),
responsive: ["md"], sortOrder:
sorter: (a, b) => alphaSort(a.ownr_ln, b.ownr_ln), state.sortedInfo.columnKey === "owner" && state.sortedInfo.order,
sortOrder: render: (text, record) => {
state.sortedInfo.columnKey === "owner" && state.sortedInfo.order, return record.ownerid ? (
render: (text, record) => { <Link
return record.ownerid ? ( to={"/manage/owners/" + record.ownerid}
<Link onClick={(e) => e.stopPropagation()}
to={"/manage/owners/" + record.ownerid} >
onClick={(e) => e.stopPropagation()} <OwnerNameDisplay ownerObject={record} />
> </Link>
<OwnerNameDisplay ownerObject={record} /> ) : (
</Link> <span>
) : (
<span>
<OwnerNameDisplay ownerObject={record} /> <OwnerNameDisplay ownerObject={record} />
</span> </span>
); );
},
},
{
title: t("jobs.fields.ownr_ph1"),
dataIndex: "ownr_ph1",
key: "ownr_ph1",
ellipsis: true,
responsive: ["md"],
render: (text, record) => (
<ChatOpenButton phone={record.ownr_ph1} jobid={record.id} />
),
},
{
title: t("jobs.fields.ownr_ph2"),
dataIndex: "ownr_ph2",
key: "ownr_ph2",
ellipsis: true,
responsive: ["md"],
render: (text, record) => (
<ChatOpenButton phone={record.ownr_ph2} jobid={record.id} />
),
},
{
title: t("jobs.fields.status"),
dataIndex: "status",
key: "status",
ellipsis: true,
sorter: (a, b) => alphaSort(a.status, b.status),
sortOrder:
state.sortedInfo.columnKey === "status" && state.sortedInfo.order,
filteredValue: filter?.status || null,
filters:
(jobs &&
jobs
.map((j) => j.status)
.filter(onlyUnique)
.map((s) => {
return {
text: s || "No Status*",
value: [s],
};
})
.sort((a, b) =>
statusSort(
a.text,
b.text,
bodyshop.md_ro_statuses.active_statuses
)
)) ||
[],
onFilter: (value, record) => value.includes(record.status),
},
{
title: t("jobs.fields.vehicle"),
dataIndex: "vehicle",
key: "vehicle",
ellipsis: true,
render: (text, record) => {
return record.vehicleid ? (
<Link
to={"/manage/vehicles/" + record.vehicleid}
onClick={(e) => e.stopPropagation()}
>
{`${record.v_model_yr || ""} ${record.v_make_desc || ""} ${
record.v_model_desc || ""
}`}
</Link>
) : (
<span>{`${record.v_model_yr || ""} ${record.v_make_desc || ""} ${
record.v_model_desc || ""
}`}</span>
);
},
},
{
title: t("vehicles.fields.plate_no"),
dataIndex: "plate_no",
key: "plate_no",
ellipsis: true,
responsive: ["md"],
sorter: (a, b) => alphaSort(a.plate_no, b.plate_no),
sortOrder:
state.sortedInfo.columnKey === "plate_no" && state.sortedInfo.order,
},
{
title: t("jobs.fields.clm_no"),
dataIndex: "clm_no",
key: "clm_no",
ellipsis: true,
responsive: ["md"],
sorter: (a, b) => alphaSort(a.clm_no, b.clm_no),
sortOrder:
state.sortedInfo.columnKey === "clm_no" && state.sortedInfo.order,
render: (text, record) =>
`${record.clm_no || ""}${
record.po_number ? ` (PO: ${record.po_number})` : ""
}`,
},
{
title: t("jobs.fields.ins_co_nm"),
dataIndex: "ins_co_nm",
key: "ins_co_nm",
ellipsis: true,
filteredValue: filter?.ins_co_nm || null,
filters:
(jobs &&
jobs
.map((j) => j.ins_co_nm)
.filter(onlyUnique)
.map((s) => {
return {
text: s || "No Ins. Co.*",
value: [s],
};
})
.sort((a, b) => alphaSort(a.text, b.text))) ||
[],
onFilter: (value, record) => value.includes(record.ins_co_nm),
responsive: ["md"],
},
{
title: t("jobs.fields.clm_total"),
dataIndex: "clm_total",
key: "clm_total",
responsive: ["md"],
ellipsis: true,
sorter: (a, b) => a.clm_total - b.clm_total,
sortOrder:
state.sortedInfo.columnKey === "clm_total" && state.sortedInfo.order,
render: (text, record) => (
<CurrencyFormatter>{record.clm_total}</CurrencyFormatter>
),
},
{
title: t("jobs.labels.estimator"),
dataIndex: "jobs.labels.estimator",
key: "estimator",
ellipsis: true,
responsive: ["xl"],
filterSearch: true,
filteredValue: filter?.estimator || null,
filters:
(jobs &&
jobs
.map((j) => `${j.est_ct_fn || ""} ${j.est_ct_ln || ""}`.trim())
.filter(onlyUnique)
.map((s) => {
return {
text: s || "No Estimator*",
value: [s],
};
})
.sort((a, b) => alphaSort(a.text, b.text))) ||
[],
onFilter: (value, record) =>
value.includes(
`${record.est_ct_fn || ""} ${record.est_ct_ln || ""}`.trim()
),
render: (text, record) =>
`${record.est_ct_fn || ""} ${record.est_ct_ln || ""}`.trim(),
},
{
title: t("jobs.fields.comment"),
dataIndex: "comment",
key: "comment",
ellipsis: true,
responsive: ["md"],
},
// {
// title: t("jobs.fields.owner_owing"),
// dataIndex: "owner_owing",
// key: "owner_owing",
// responsive: ["md"],
// render: (text, record) => (
// <CurrencyFormatter>{record.owner_owing}</CurrencyFormatter>
// ),
// },
];
const scrollMapper = {
xs: true,
sm: true,
md: true,
lg: "100%",
xl: "100%",
xxl: "100%",
};
return (
<Card
title={t("titles.bc.jobs-active")}
extra={
<Space wrap>
<Button onClick={() => refetch()}>
<SyncOutlined />
</Button>
<Input.Search
placeholder={t("general.labels.search")}
onChange={(e) => {
setSearchText(e.target.value);
}}
value={searchText}
enterButton
/>
</Space>
}
>
<Table
loading={loading}
pagination={{ defaultPageSize: 50 }}
columns={columns}
rowKey="id"
dataSource={jobs}
scroll={{
x: selectedBreakpoint ? scrollMapper[selectedBreakpoint[0]] : "100%",
}}
rowSelection={{
onSelect: (record) => {
handleOnRowClick(record);
},
selectedRowKeys: [selected],
type: "radio",
}}
onChange={handleTableChange}
onRow={(record, rowIndex) => {
return {
onClick: (event) => {
handleOnRowClick(record);
}, },
}, };
{ }}
title: t("jobs.fields.ownr_ph1"), />
dataIndex: "ownr_ph1", </Card>
key: "ownr_ph1", );
ellipsis: true,
responsive: ["md"],
render: (text, record) => (
<ChatOpenButton phone={record.ownr_ph1} jobid={record.id} />
),
},
{
title: t("jobs.fields.ownr_ph2"),
dataIndex: "ownr_ph2",
key: "ownr_ph2",
ellipsis: true,
responsive: ["md"],
render: (text, record) => (
<ChatOpenButton phone={record.ownr_ph2} jobid={record.id} />
),
},
{
title: t("jobs.fields.status"),
dataIndex: "status",
key: "status",
ellipsis: true,
sorter: (a, b) => alphaSort(a.status, b.status),
sortOrder:
state.sortedInfo.columnKey === "status" && state.sortedInfo.order,
filters:
(jobs &&
jobs
.map((j) => j.status)
.filter(onlyUnique)
.map((s) => {
return {
text: s || "No Status*",
value: [s],
};
})) ||
[],
onFilter: (value, record) => value.includes(record.status),
},
{
title: t("jobs.fields.vehicle"),
dataIndex: "vehicle",
key: "vehicle",
ellipsis: true,
render: (text, record) => {
return record.vehicleid ? (
<Link
to={"/manage/vehicles/" + record.vehicleid}
onClick={(e) => e.stopPropagation()}
>
{`${record.v_model_yr || ""} ${record.v_make_desc || ""} ${
record.v_model_desc || ""
}`}
</Link>
) : (
<span>{`${record.v_model_yr || ""} ${record.v_make_desc || ""} ${
record.v_model_desc || ""
}`}</span>
);
},
},
{
title: t("vehicles.fields.plate_no"),
dataIndex: "plate_no",
key: "plate_no",
ellipsis: true,
responsive: ["md"],
sorter: (a, b) => alphaSort(a.plate_no, b.plate_no),
sortOrder:
state.sortedInfo.columnKey === "plate_no" && state.sortedInfo.order,
},
{
title: t("jobs.fields.clm_no"),
dataIndex: "clm_no",
key: "clm_no",
ellipsis: true,
responsive: ["md"],
sorter: (a, b) => alphaSort(a.clm_no, b.clm_no),
sortOrder:
state.sortedInfo.columnKey === "clm_no" && state.sortedInfo.order,
render: (text, record) =>
`${record.clm_no || ""}${
record.po_number ? ` (PO: ${record.po_number})` : ""
}`,
},
{
title: t("jobs.fields.ins_co_nm"),
dataIndex: "ins_co_nm",
key: "ins_co_nm",
ellipsis: true,
filters:
(jobs &&
jobs
.map((j) => j.ins_co_nm)
.filter(onlyUnique)
.map((s) => {
return {
text: s,
value: [s],
};
})) ||
[],
onFilter: (value, record) => value.includes(record.ins_co_nm),
responsive: ["md"],
},
{
title: t("jobs.fields.clm_total"),
dataIndex: "clm_total",
key: "clm_total",
responsive: ["md"],
ellipsis: true,
sorter: (a, b) => a.clm_total - b.clm_total,
sortOrder:
state.sortedInfo.columnKey === "clm_total" && state.sortedInfo.order,
render: (text, record) => (
<CurrencyFormatter>{record.clm_total}</CurrencyFormatter>
),
},
{
title: t("jobs.labels.estimator"),
dataIndex: "jobs.labels.estimator",
key: "jobs.labels.estimator",
ellipsis: true,
responsive: ["xl"],
filterSearch: true,
filters:
(jobs &&
jobs
.map((j) => `${j.est_ct_fn || ""} ${j.est_ct_ln || ""}`.trim())
.filter(onlyUnique)
.map((s) => {
return {
text: s || "N/A",
value: [s],
};
})) ||
[],
onFilter: (value, record) =>
value.includes(
`${record.est_ct_fn || ""} ${record.est_ct_ln || ""}`.trim()
),
render: (text, record) =>
`${record.est_ct_fn || ""} ${record.est_ct_ln || ""}`.trim(),
},
{
title: t("jobs.fields.comment"),
dataIndex: "comment",
key: "comment",
ellipsis: true,
responsive: ["md"],
},
// {
// title: t("jobs.fields.owner_owing"),
// dataIndex: "owner_owing",
// key: "owner_owing",
// responsive: ["md"],
// render: (text, record) => (
// <CurrencyFormatter>{record.owner_owing}</CurrencyFormatter>
// ),
// },
];
const scrollMapper = {
xs: true,
sm: true,
md: true,
lg: "100%",
xl: "100%",
xxl: "100%",
};
return (
<Card
title={t("titles.bc.jobs-active")}
extra={
<Space wrap>
<Button onClick={() => refetch()}>
<SyncOutlined />
</Button>
<Input.Search
placeholder={t("general.labels.search")}
onChange={(e) => {
setSearchText(e.target.value);
}}
value={searchText}
enterButton
/>
</Space>
}
>
<Table
loading={loading}
pagination={{ defaultPageSize: 50 }}
columns={columns}
rowKey="id"
dataSource={jobs}
scroll={{
x: selectedBreakpoint ? scrollMapper[selectedBreakpoint[0]] : "100%",
}}
rowSelection={{
onSelect: (record) => {
handleOnRowClick(record);
},
selectedRowKeys: [selected],
type: "radio",
}}
onChange={handleTableChange}
onRow={(record, rowIndex) => {
return {
onClick: (event) => {
handleOnRowClick(record);
},
};
}}
/>
</Card>
);
} }
export default connect(mapStateToProps, null)(JobsList); export default connect(mapStateToProps, null)(JobsList);

View File

@@ -16,11 +16,12 @@ import { QUERY_ALL_ACTIVE_JOBS } from "../../graphql/jobs.queries";
import { selectBodyshop } from "../../redux/user/user.selectors"; import { selectBodyshop } from "../../redux/user/user.selectors";
import CurrencyFormatter from "../../utils/CurrencyFormatter"; import CurrencyFormatter from "../../utils/CurrencyFormatter";
import { onlyUnique } from "../../utils/arrayHelper"; import { onlyUnique } from "../../utils/arrayHelper";
import { alphaSort } from "../../utils/sorters"; import { pageLimit } from "../../utils/config";
import { alphaSort, statusSort } from "../../utils/sorters";
import useLocalStorage from "../../utils/useLocalStorage";
import AlertComponent from "../alert/alert.component"; import AlertComponent from "../alert/alert.component";
import ChatOpenButton from "../chat-open-button/chat-open-button.component"; import ChatOpenButton from "../chat-open-button/chat-open-button.component";
import OwnerNameDisplay from "../owner-name-display/owner-name-display.component"; import OwnerNameDisplay from "../owner-name-display/owner-name-display.component";
import {pageLimit} from "../../utils/config";
const mapStateToProps = createStructuredSelector({ const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop, bodyshop: selectBodyshop,
@@ -53,10 +54,8 @@ export function JobsReadyList({ bodyshop }) {
nextFetchPolicy: "network-only", nextFetchPolicy: "network-only",
}); });
const [state, setState] = useState({ const [state, setState] = useState({ sortedInfo: {} });
sortedInfo: {}, const [filter, setFilter] = useLocalStorage("filter_jobs_ready", null);
filteredInfo: { text: "" },
});
const { t } = useTranslation(); const { t } = useTranslation();
const history = useHistory(); const history = useHistory();
@@ -105,7 +104,8 @@ export function JobsReadyList({ bodyshop }) {
: []; : [];
const handleTableChange = (pagination, filters, sorter) => { const handleTableChange = (pagination, filters, sorter) => {
setState({ ...state, filteredInfo: filters, sortedInfo: sorter }); setState({ ...state, sortedInfo: sorter });
setFilter(filters);
}; };
const handleOnRowClick = (record) => { const handleOnRowClick = (record) => {
@@ -129,7 +129,6 @@ export function JobsReadyList({ bodyshop }) {
sorter: (a, b) => alphaSort(a.ro_number, b.ro_number), sorter: (a, b) => alphaSort(a.ro_number, b.ro_number),
sortOrder: sortOrder:
state.sortedInfo.columnKey === "ro_number" && state.sortedInfo.order, state.sortedInfo.columnKey === "ro_number" && state.sortedInfo.order,
render: (text, record) => ( render: (text, record) => (
<Link <Link
to={"/manage/jobs/" + record.id} to={"/manage/jobs/" + record.id}
@@ -157,7 +156,6 @@ export function JobsReadyList({ bodyshop }) {
dataIndex: "owner", dataIndex: "owner",
key: "owner", key: "owner",
ellipsis: true, ellipsis: true,
responsive: ["md"], responsive: ["md"],
sorter: (a, b) => alphaSort(a.ownr_ln, b.ownr_ln), sorter: (a, b) => alphaSort(a.ownr_ln, b.ownr_ln),
sortOrder: sortOrder:
@@ -197,16 +195,15 @@ export function JobsReadyList({ bodyshop }) {
<ChatOpenButton phone={record.ownr_ph2} jobid={record.id} /> <ChatOpenButton phone={record.ownr_ph2} jobid={record.id} />
), ),
}, },
{ {
title: t("jobs.fields.status"), title: t("jobs.fields.status"),
dataIndex: "status", dataIndex: "status",
key: "status", key: "status",
ellipsis: true, ellipsis: true,
sorter: (a, b) => alphaSort(a.status, b.status), sorter: (a, b) => alphaSort(a.status, b.status),
sortOrder: sortOrder:
state.sortedInfo.columnKey === "status" && state.sortedInfo.order, state.sortedInfo.columnKey === "status" && state.sortedInfo.order,
filteredValue: filter?.status || null,
filters: filters:
(jobs && (jobs &&
jobs jobs
@@ -217,11 +214,17 @@ export function JobsReadyList({ bodyshop }) {
text: s || "No Status*", text: s || "No Status*",
value: [s], value: [s],
}; };
})) || })
.sort((a, b) =>
statusSort(
a.text,
b.text,
bodyshop.md_ro_statuses.active_statuses
)
)) ||
[], [],
onFilter: (value, record) => value.includes(record.status), onFilter: (value, record) => value.includes(record.status),
}, },
{ {
title: t("jobs.fields.vehicle"), title: t("jobs.fields.vehicle"),
dataIndex: "vehicle", dataIndex: "vehicle",
@@ -274,6 +277,7 @@ export function JobsReadyList({ bodyshop }) {
dataIndex: "ins_co_nm", dataIndex: "ins_co_nm",
key: "ins_co_nm", key: "ins_co_nm",
ellipsis: true, ellipsis: true,
filteredValue: filter?.ins_co_nm || null,
filters: filters:
(jobs && (jobs &&
jobs jobs
@@ -281,10 +285,11 @@ export function JobsReadyList({ bodyshop }) {
.filter(onlyUnique) .filter(onlyUnique)
.map((s) => { .map((s) => {
return { return {
text: s, text: s || "No Ins Co.*",
value: [s], value: [s],
}; };
})) || })
.sort((a, b) => alphaSort(a.text, b.text))) ||
[], [],
onFilter: (value, record) => value.includes(record.ins_co_nm), onFilter: (value, record) => value.includes(record.ins_co_nm),
responsive: ["md"], responsive: ["md"],
@@ -295,7 +300,6 @@ export function JobsReadyList({ bodyshop }) {
key: "clm_total", key: "clm_total",
responsive: ["md"], responsive: ["md"],
ellipsis: true, ellipsis: true,
sorter: (a, b) => a.clm_total - b.clm_total, sorter: (a, b) => a.clm_total - b.clm_total,
sortOrder: sortOrder:
state.sortedInfo.columnKey === "clm_total" && state.sortedInfo.order, state.sortedInfo.columnKey === "clm_total" && state.sortedInfo.order,
@@ -306,9 +310,10 @@ export function JobsReadyList({ bodyshop }) {
{ {
title: t("jobs.labels.estimator"), title: t("jobs.labels.estimator"),
dataIndex: "jobs.labels.estimator", dataIndex: "jobs.labels.estimator",
key: "jobs.labels.estimator", key: "estimator",
ellipsis: true, ellipsis: true,
responsive: ["xl"], responsive: ["xl"],
filteredValue: filter?.estimator || null,
filterSearch: true, filterSearch: true,
filters: filters:
(jobs && (jobs &&
@@ -317,10 +322,11 @@ export function JobsReadyList({ bodyshop }) {
.filter(onlyUnique) .filter(onlyUnique)
.map((s) => { .map((s) => {
return { return {
text: s || "N/A", text: s || "No Estimator*",
value: [s], value: [s],
}; };
})) || })
.sort((a, b) => alphaSort(a.text, b.text))) ||
[], [],
onFilter: (value, record) => onFilter: (value, record) =>
value.includes( value.includes(

View File

@@ -2,7 +2,7 @@ import { Space, Tag } from "antd";
import React from "react"; import React from "react";
import { Link } from "react-router-dom"; import { Link } from "react-router-dom";
export default function JobsRelatedRos({ jobid, job }) { export default function JobsRelatedRos({ jobid, job, disabled }) {
if (!(job && job.vehicle && job.vehicle.jobs)) return null; if (!(job && job.vehicle && job.vehicle.jobs)) return null;
return ( return (
<Space wrap> <Space wrap>
@@ -10,9 +10,15 @@ export default function JobsRelatedRos({ jobid, job }) {
.filter((j) => j.id !== job.id) .filter((j) => j.id !== job.id)
.map((j) => ( .map((j) => (
<Tag key={j.id}> <Tag key={j.id}>
<Link to={`/manage/jobs/${j?.id}`}>{`${j.ro_number || "N/A"}${ {disabled ? (
j.clm_no ? ` | ${j.clm_no}` : "" <>{`${j.ro_number || "N/A"}${j.clm_no ? ` | ${j.clm_no}` : ""}${
}${j.status ? ` | ${j.status}` : ""}`}</Link> j.status ? ` | ${j.status}` : ""
}`}</>
) : (
<Link to={`/manage/jobs/${j?.id}`}>{`${j.ro_number || "N/A"}${
j.clm_no ? ` | ${j.clm_no}` : ""
}${j.status ? ` | ${j.status}` : ""}`}</Link>
)}
</Tag> </Tag>
))} ))}
</Space> </Space>

View File

@@ -115,7 +115,7 @@ export function ProductionBoardKanbanComponent({
// console.log("==> New Card is somewhere in the middle"); // console.log("==> New Card is somewhere in the middle");
movedCardNewKanbanParent = newChildCard.kanbanparent; movedCardNewKanbanParent = newChildCard.kanbanparent;
} else { } else {
throw new Error("==> !!!!!!Couldn't find a parent.!!!! <=="); console.log("==> !!!!!!Couldn't find a parent.!!!! <==");
} }
const newChildCardNewParent = newChildCard ? card.id : null; const newChildCardNewParent = newChildCard ? card.id : null;
const update = await client.mutate({ const update = await client.mutate({
@@ -153,7 +153,7 @@ export function ProductionBoardKanbanComponent({
0 0
) )
.toFixed(1); .toFixed(1);
const totalLAB = data const totalLAB = data
.reduce( .reduce(
(acc, val) => acc + (val.labhrs?.aggregate?.sum?.mod_lb_hrs || 0), (acc, val) => acc + (val.labhrs?.aggregate?.sum?.mod_lb_hrs || 0),
0 0

View File

@@ -1,7 +1,7 @@
import React from "react";
import { Button, Dropdown, Menu } from "antd"; import { Button, Dropdown, Menu } from "antd";
import dataSource from "./production-list-columns.data"; import React from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import dataSource from "./production-list-columns.data";
import { connect } from "react-redux"; import { connect } from "react-redux";
import { createStructuredSelector } from "reselect"; import { createStructuredSelector } from "reselect";
@@ -24,6 +24,7 @@ export function ProductionColumnsComponent({
columnState, columnState,
technician, technician,
bodyshop, bodyshop,
data,
tableState, tableState,
}) { }) {
const [columns, setColumns] = columnState; const [columns, setColumns] = columnState;
@@ -36,6 +37,7 @@ export function ProductionColumnsComponent({
bodyshop, bodyshop,
technician, technician,
state: tableState, state: tableState,
data: data,
activeStatuses: bodyshop.md_ro_statuses.active_statuses, activeStatuses: bodyshop.md_ro_statuses.active_statuses,
}).filter((i) => i.key === e.key), }).filter((i) => i.key === e.key),
]); ]);
@@ -46,6 +48,7 @@ export function ProductionColumnsComponent({
technician, technician,
state: tableState, state: tableState,
activeStatuses: bodyshop.md_ro_statuses.active_statuses, activeStatuses: bodyshop.md_ro_statuses.active_statuses,
data: data,
}); });
const menu = ( const menu = (
<Menu <Menu

View File

@@ -1,4 +1,4 @@
import { PauseCircleOutlined, BranchesOutlined } from "@ant-design/icons"; import { BranchesOutlined, PauseCircleOutlined } from "@ant-design/icons";
import { Space, Tooltip } from "antd"; import { Space, Tooltip } from "antd";
import i18n from "i18next"; import i18n from "i18next";
import moment from "moment"; import moment from "moment";
@@ -6,6 +6,7 @@ import { Link } from "react-router-dom";
import CurrencyFormatter from "../../utils/CurrencyFormatter"; import CurrencyFormatter from "../../utils/CurrencyFormatter";
import { TimeFormatter } from "../../utils/DateFormatter"; import { TimeFormatter } from "../../utils/DateFormatter";
import PhoneFormatter from "../../utils/PhoneFormatter"; import PhoneFormatter from "../../utils/PhoneFormatter";
import { onlyUnique } from "../../utils/arrayHelper";
import { alphaSort, dateSort, statusSort } from "../../utils/sorters"; import { alphaSort, dateSort, statusSort } from "../../utils/sorters";
import JobAltTransportChange from "../job-at-change/job-at-change.component"; import JobAltTransportChange from "../job-at-change/job-at-change.component";
import JobPartsQueueCount from "../job-parts-queue-count/job-parts-queue-count.component"; import JobPartsQueueCount from "../job-parts-queue-count/job-parts-queue-count.component";
@@ -25,7 +26,7 @@ import ProductionListColumnCategory from "./production-list-columns.status.categ
import ProductionListColumnStatus from "./production-list-columns.status.component"; import ProductionListColumnStatus from "./production-list-columns.status.component";
import ProductionlistColumnTouchTime from "./prodution-list-columns.touchtime.component"; import ProductionlistColumnTouchTime from "./prodution-list-columns.touchtime.component";
const r = ({ technician, state, activeStatuses, bodyshop }) => { const r = ({ technician, state, activeStatuses, data, bodyshop }) => {
return [ return [
{ {
title: i18n.t("jobs.actions.viewdetail"), title: i18n.t("jobs.actions.viewdetail"),
@@ -75,7 +76,14 @@ const r = ({ technician, state, activeStatuses, bodyshop }) => {
dataIndex: "ownr", dataIndex: "ownr",
key: "ownr", key: "ownr",
ellipsis: true, ellipsis: true,
render: (text, record) => <OwnerNameDisplay ownerObject={record} />, render: (text, record) =>
technician ? (
<OwnerNameDisplay ownerObject={record} />
) : (
<Link to={`/manage/owners/${record.ownerid}`}>
<OwnerNameDisplay ownerObject={record} />
</Link>
),
sorter: (a, b) => alphaSort(a.ownr_ln, b.ownr_ln), sorter: (a, b) => alphaSort(a.ownr_ln, b.ownr_ln),
sortOrder: sortOrder:
state.sortedInfo.columnKey === "ownr" && state.sortedInfo.order, state.sortedInfo.columnKey === "ownr" && state.sortedInfo.order,
@@ -92,13 +100,18 @@ const r = ({ technician, state, activeStatuses, bodyshop }) => {
), ),
sortOrder: sortOrder:
state.sortedInfo.columnKey === "vehicle" && state.sortedInfo.order, state.sortedInfo.columnKey === "vehicle" && state.sortedInfo.order,
render: (text, record) => ( render: (text, record) =>
<Link to={`/manage/vehicles/${record.vehicleid}`}>{`${ technician ? (
record.v_model_yr || "" <>{`${record.v_model_yr || ""} ${record.v_make_desc || ""} ${
} ${record.v_make_desc || ""} ${record.v_model_desc || ""} ${ record.v_model_desc || ""
record.v_color || "" } ${record.v_color || ""} ${record.plate_no || ""}`}</>
} ${record.plate_no || ""}`}</Link> ) : (
), <Link to={`/manage/vehicles/${record.vehicleid}`}>{`${
record.v_model_yr || ""
} ${record.v_make_desc || ""} ${record.v_model_desc || ""} ${
record.v_color || ""
} ${record.plate_no || ""}`}</Link>
),
}, },
{ {
title: i18n.t("jobs.fields.actual_in"), title: i18n.t("jobs.fields.actual_in"),
@@ -536,6 +549,36 @@ const r = ({ technician, state, activeStatuses, bodyshop }) => {
<JobPartsQueueCount parts={record.joblines_status} record={record} /> <JobPartsQueueCount parts={record.joblines_status} record={record} />
), ),
}, },
{
title: i18n.t("jobs.labels.estimator"),
dataIndex: "estimator",
key: "estimator",
sorter: (a, b) =>
alphaSort(
`${a.est_ct_fn || ""} ${a.est_ct_ln || ""}`.trim(),
`${b.est_ct_fn || ""} ${b.est_ct_ln || ""}`.trim()
),
sortOrder:
state.sortedInfo.columnKey === "estimator" && state.sortedInfo.order,
filters:
(data &&
data
.map((j) => `${j.est_ct_fn || ""} ${j.est_ct_ln || ""}`.trim())
.filter(onlyUnique)
.map((s) => {
return {
text: s || "N/A",
value: [s],
};
})) ||
[],
onFilter: (value, record) =>
value.includes(
`${record.est_ct_fn || ""} ${record.est_ct_ln || ""}`.trim()
),
render: (text, record) =>
`${record.est_ct_fn || ""} ${record.est_ct_ln || ""}`.trim(),
},
//Added as a place holder for St Claude. Not implemented as it requires another join for a field used by only 1 client. //Added as a place holder for St Claude. Not implemented as it requires another join for a field used by only 1 client.
// { // {

View File

@@ -13,12 +13,14 @@ import { selectTechnician } from "../../redux/tech/tech.selectors";
import { selectBodyshop } from "../../redux/user/user.selectors"; import { selectBodyshop } from "../../redux/user/user.selectors";
import CurrencyFormatter from "../../utils/CurrencyFormatter"; import CurrencyFormatter from "../../utils/CurrencyFormatter";
import { DateFormatter } from "../../utils/DateFormatter"; import { DateFormatter } from "../../utils/DateFormatter";
import PhoneNumberFormatter from "../../utils/PhoneFormatter";
import AlertComponent from "../alert/alert.component"; import AlertComponent from "../alert/alert.component";
import StartChatButton from "../chat-open-button/chat-open-button.component"; import StartChatButton from "../chat-open-button/chat-open-button.component";
import JobAtChange from "../job-at-change/job-at-change.component"; import JobAtChange from "../job-at-change/job-at-change.component";
import JobDetailCardsDocumentsComponent from "../job-detail-cards/job-detail-cards.documents.component"; import JobDetailCardsDocumentsComponent from "../job-detail-cards/job-detail-cards.documents.component";
import JobDetailCardsNotesComponent from "../job-detail-cards/job-detail-cards.notes.component"; import JobDetailCardsNotesComponent from "../job-detail-cards/job-detail-cards.notes.component";
import JobDetailCardsPartsComponent from "../job-detail-cards/job-detail-cards.parts.component"; import JobDetailCardsPartsComponent from "../job-detail-cards/job-detail-cards.parts.component";
import CardTemplate from "../job-detail-cards/job-detail-cards.template.component";
import JobEmployeeAssignments from "../job-employee-assignments/job-employee-assignments.container"; import JobEmployeeAssignments from "../job-employee-assignments/job-employee-assignments.container";
import ScoreboardAddButton from "../job-scoreboard-add-button/job-scoreboard-add-button.component"; import ScoreboardAddButton from "../job-scoreboard-add-button/job-scoreboard-add-button.component";
import LoadingSkeleton from "../loading-skeleton/loading-skeleton.component"; import LoadingSkeleton from "../loading-skeleton/loading-skeleton.component";
@@ -103,7 +105,13 @@ export function ProductionListDetail({
{error && <AlertComponent error={JSON.stringify(error)} />} {error && <AlertComponent error={JSON.stringify(error)} />}
{!loading && data && ( {!loading && data && (
<div> <div>
<JobEmployeeAssignments job={data.jobs_by_pk} refetch={refetch} /> <CardTemplate
title={t("jobs.labels.employeeassignments")}
loading={loading}
>
<JobEmployeeAssignments job={data.jobs_by_pk} refetch={refetch} />
</CardTemplate>
<div style={{ height: "8px" }} />
<Descriptions bordered column={1}> <Descriptions bordered column={1}>
<Descriptions.Item label={t("jobs.fields.ro_number")}> <Descriptions.Item label={t("jobs.fields.ro_number")}>
{theJob.ro_number || ""} {theJob.ro_number || ""}
@@ -111,7 +119,7 @@ export function ProductionListDetail({
<Descriptions.Item label={t("jobs.fields.alt_transport")}> <Descriptions.Item label={t("jobs.fields.alt_transport")}>
<Space> <Space>
{data.jobs_by_pk.alt_transport || ""} {data.jobs_by_pk.alt_transport || ""}
<JobAtChange event={{ job: data.jobs_by_pk }} /> <JobAtChange job={data.jobs_by_pk} />
</Space> </Space>
</Descriptions.Item> </Descriptions.Item>
<Descriptions.Item label={t("jobs.fields.clm_no")}> <Descriptions.Item label={t("jobs.fields.clm_no")}>
@@ -121,15 +129,30 @@ export function ProductionListDetail({
{theJob.ins_co_nm || ""} {theJob.ins_co_nm || ""}
</Descriptions.Item> </Descriptions.Item>
<Descriptions.Item label={t("jobs.fields.owner")}> <Descriptions.Item label={t("jobs.fields.owner")}>
<OwnerNameDisplay ownerObject={theJob} /> <Space>
<StartChatButton <OwnerNameDisplay ownerObject={theJob} />
phone={data.jobs_by_pk.ownr_ph1} {!technician ? (
jobid={data.jobs_by_pk.id} <>
/> <StartChatButton
<StartChatButton phone={data.jobs_by_pk.ownr_ph1}
phone={data.jobs_by_pk.ownr_ph2} jobid={data.jobs_by_pk.id}
jobid={data.jobs_by_pk.id} />
/> <StartChatButton
phone={data.jobs_by_pk.ownr_ph2}
jobid={data.jobs_by_pk.id}
/>
</>
) : (
<>
<PhoneNumberFormatter>
{data.jobs_by_pk.ownr_ph1}
</PhoneNumberFormatter>
<PhoneNumberFormatter>
{data.jobs_by_pk.ownr_ph2}
</PhoneNumberFormatter>
</>
)}
</Space>
</Descriptions.Item> </Descriptions.Item>
<Descriptions.Item label={t("jobs.fields.vehicle")}> <Descriptions.Item label={t("jobs.fields.vehicle")}>
{`${theJob.v_model_yr || ""} ${theJob.v_color || ""} ${ {`${theJob.v_model_yr || ""} ${theJob.v_color || ""} ${
@@ -146,21 +169,24 @@ export function ProductionListDetail({
<DateFormatter>{theJob.scheduled_completion}</DateFormatter> <DateFormatter>{theJob.scheduled_completion}</DateFormatter>
</Descriptions.Item> </Descriptions.Item>
</Descriptions> </Descriptions>
<div style={{ height: "8px" }} />
<JobDetailCardsPartsComponent <JobDetailCardsPartsComponent
loading={loading} loading={loading}
data={data ? data.jobs_by_pk : null} data={data ? data.jobs_by_pk : null}
/> />
<div style={{ height: "8px" }} />
<JobDetailCardsNotesComponent <JobDetailCardsNotesComponent
loading={loading} loading={loading}
data={data ? data.jobs_by_pk : null} data={data ? data.jobs_by_pk : null}
/> />
{!bodyshop.uselocalmediaserver && ( {!bodyshop.uselocalmediaserver && (
<JobDetailCardsDocumentsComponent <>
loading={loading} <div style={{ height: "8px" }} />
data={data ? data.jobs_by_pk : null} <JobDetailCardsDocumentsComponent
/> loading={loading}
data={data ? data.jobs_by_pk : null}
/>
</>
)} )}
</div> </div>
)} )}

View File

@@ -24,6 +24,7 @@ export function ProductionListTable({
technician, technician,
currentUser, currentUser,
state, state,
data,
setColumns, setColumns,
setState, setState,
}) { }) {
@@ -41,6 +42,7 @@ export function ProductionListTable({
bodyshop, bodyshop,
technician, technician,
state, state,
data: data,
activeStatuses: bodyshop.md_ro_statuses.active_statuses, activeStatuses: bodyshop.md_ro_statuses.active_statuses,
}).find((e) => e.key === k.key), }).find((e) => e.key === k.key),
width: k.width, width: k.width,
@@ -95,6 +97,7 @@ export function ProductionListTable({
...ProductionListColumns({ ...ProductionListColumns({
technician, technician,
state, state,
data: data,
activeStatuses: bodyshop.md_ro_statuses.active_statuses, activeStatuses: bodyshop.md_ro_statuses.active_statuses,
}).find((e) => e.key === k.key), }).find((e) => e.key === k.key),
width: k.width, width: k.width,

View File

@@ -10,7 +10,7 @@ import {
Statistic, Statistic,
Table, Table,
} from "antd"; } from "antd";
import React, { useMemo, useState } from "react"; import React, { useEffect, useMemo, useState } from "react";
import ReactDragListView from "react-drag-listview"; import ReactDragListView from "react-drag-listview";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { connect } from "react-redux"; import { connect } from "react-redux";
@@ -79,6 +79,7 @@ export function ProductionListTable({
bodyshop, bodyshop,
technician, technician,
state, state,
data: data,
activeStatuses: bodyshop.md_ro_statuses.active_statuses, activeStatuses: bodyshop.md_ro_statuses.active_statuses,
}).find((e) => e.key === k.key), }).find((e) => e.key === k.key),
width: k.width ?? 100, width: k.width ?? 100,
@@ -87,6 +88,33 @@ export function ProductionListTable({
[] []
); );
useEffect(() => {
const newColumns =
(state &&
matchingColumnConfig &&
matchingColumnConfig.columns.columnKeys.map((k) => {
return {
...ProductionListColumns({
bodyshop,
technician,
state,
data: data,
activeStatuses: bodyshop.md_ro_statuses.active_statuses,
}).find((e) => e.key === k.key),
width: k.width ?? 100,
};
})) ||
[];
setColumns(newColumns);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [
//state,
matchingColumnConfig,
bodyshop,
technician,
data,
]); //State removed from dependency array as it causes race condition when removing columns from table view and is not needed.
const handleTableChange = (pagination, filters, sorter) => { const handleTableChange = (pagination, filters, sorter) => {
setState({ setState({
...state, ...state,
@@ -104,7 +132,8 @@ export function ProductionListTable({
const removeColumn = (e) => { const removeColumn = (e) => {
const { key } = e; const { key } = e;
setColumns(columns.filter((i) => i.key !== key)); const newColumns = columns.filter((i) => i.key !== key);
setColumns(newColumns);
}; };
const handleResize = const handleResize =
@@ -227,6 +256,7 @@ export function ProductionListTable({
<ProductionListColumnsAdd <ProductionListColumnsAdd
columnState={[columns, setColumns]} columnState={[columns, setColumns]}
tableState={state} tableState={state}
data={data}
/> />
<ProductionListSaveConfigButton <ProductionListSaveConfigButton
columns={columns} columns={columns}
@@ -237,6 +267,7 @@ export function ProductionListTable({
state={state} state={state}
setState={setState} setState={setState}
setColumns={setColumns} setColumns={setColumns}
data={data}
/> />
<Input <Input

View File

@@ -68,8 +68,8 @@ export function ReportCenterModalComponent({ reportCenterModal }) {
const handleFinish = async (values) => { const handleFinish = async (values) => {
setLoading(true); setLoading(true);
const start = values.dates[0]; const start = values.dates ? values.dates[0] : null;
const end = values.dates[1]; const end = values.dates ? values.dates[1] : null;
const { id } = values; const { id } = values;
await GenerateDocument( await GenerateDocument(
@@ -239,20 +239,30 @@ export function ReportCenterModalComponent({ reportCenterModal }) {
else return null; else return null;
}} }}
</Form.Item> </Form.Item>
<Form.Item <Form.Item style={{ margin: 0, padding: 0 }} dependencies={["key"]}>
name="dates" {() => {
label={t("reportcenter.labels.dates")} const key = form.getFieldValue("key");
rules={[ const datedisable = Templates[key] && Templates[key].datedisable;
{ if (datedisable !== true) {
required: true, return (
//message: t("general.validation.required"), <Form.Item
}, name="dates"
]} label={t("reportcenter.labels.dates")}
> rules={[
<DatePicker.RangePicker {
format="MM/DD/YYYY" required: true,
ranges={DatePIckerRanges} //message: t("general.validation.required"),
/> },
]}
>
<DatePicker.RangePicker
format="MM/DD/YYYY"
ranges={DatePIckerRanges}
/>
</Form.Item>
);
} else return null;
}}
</Form.Item> </Form.Item>
<Form.Item style={{ margin: 0, padding: 0 }} dependencies={["key"]}> <Form.Item style={{ margin: 0, padding: 0 }} dependencies={["key"]}>
{() => { {() => {

View File

@@ -216,6 +216,7 @@ export function ScheduleJobModalContainer({
okButtonProps={{ okButtonProps={{
loading: loading, loading: loading,
}} }}
closable={false}
> >
<Form <Form
form={form} form={form}

View File

@@ -1,5 +1,5 @@
import React from "react";
import { Form } from "antd"; import { Form } from "antd";
import React from "react";
import ConfigFormComponents from "../config-form-components/config-form-components.component"; import ConfigFormComponents from "../config-form-components/config-form-components.component";
export default function ShopCsiConfigForm({ selectedCsi }) { export default function ShopCsiConfigForm({ selectedCsi }) {
@@ -9,7 +9,7 @@ export default function ShopCsiConfigForm({ selectedCsi }) {
return ( return (
<div> <div>
The Config Form {readOnly} {readOnly}
{selectedCsi && ( {selectedCsi && (
<Form form={form} onFinish={handleFinish}> <Form form={form} onFinish={handleFinish}>
<ConfigFormComponents <ConfigFormComponents

View File

@@ -1,7 +1,7 @@
import { CheckCircleFilled } from "@ant-design/icons"; import { CheckCircleFilled } from "@ant-design/icons";
import { useQuery } from "@apollo/client";
import { Button, Col, List, Row } from "antd"; import { Button, Col, List, Row } from "antd";
import React, { useState } from "react"; import React, { useState } from "react";
import { useQuery } from "@apollo/client";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { GET_ALL_QUESTION_SETS } from "../../graphql/csi.queries"; import { GET_ALL_QUESTION_SETS } from "../../graphql/csi.queries";
import { DateFormatter } from "../../utils/DateFormatter"; import { DateFormatter } from "../../utils/DateFormatter";
@@ -21,7 +21,6 @@ export default function ShopCsiConfig() {
if (error) return <AlertComponent message={error.message} type="error" />; if (error) return <AlertComponent message={error.message} type="error" />;
return ( return (
<div> <div>
The Config Form
<Row> <Row>
<Col span={3}> <Col span={3}>
<List <List
@@ -42,7 +41,8 @@ export default function ShopCsiConfig() {
)} )}
/> />
</Col> </Col>
<Col span={21}> <Col span={1} />
<Col span={20}>
<ShopCsiConfigForm selectedCsi={selectedCsi} /> <ShopCsiConfigForm selectedCsi={selectedCsi} />
</Col> </Col>
</Row> </Row>

View File

@@ -1,14 +1,20 @@
import { Button, Table } from "antd"; import { Button, Table } from "antd";
import queryString from "query-string"; import queryString from "query-string";
import React from "react"; import React, { useState } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { useHistory, useLocation } from "react-router-dom"; import { useHistory, useLocation } from "react-router-dom";
import { alphaSort } from "../../utils/sorters";
export default function ShopEmployeesListComponent({ loading, employees }) { export default function ShopEmployeesListComponent({ loading, employees }) {
const { t } = useTranslation(); const { t } = useTranslation();
const history = useHistory(); const history = useHistory();
const search = queryString.parse(useLocation().search); const search = queryString.parse(useLocation().search);
const [state, setState] = useState({
sortedInfo: {},
filteredInfo: { text: "" },
});
const handleOnRowClick = (record) => { const handleOnRowClick = (record) => {
if (record) { if (record) {
search.employeeId = record.id; search.employeeId = record.id;
@@ -18,32 +24,82 @@ export default function ShopEmployeesListComponent({ loading, employees }) {
history.push({ search: queryString.stringify(search) }); history.push({ search: queryString.stringify(search) });
} }
}; };
const handleTableChange = (pagination, filters, sorter) => {
setState({ ...state, filteredInfo: filters, sortedInfo: sorter });
};
const columns = [ const columns = [
{ {
title: t("employees.fields.employee_number"), title: t("employees.fields.employee_number"),
dataIndex: "employee_number", dataIndex: "employee_number",
key: "employee_number", key: "employee_number",
sorter: (a, b) => alphaSort(a.employee_number, b.employee_number),
sortOrder:
state.sortedInfo.columnKey === "employee_number" &&
state.sortedInfo.order,
}, },
{ {
title: t("employees.fields.first_name"), title: t("employees.labels.name"),
dataIndex: "first_name", dataIndex: "employee_name",
key: "first_name", key: "employee_name",
sorter: (a, b) =>
alphaSort(
`${a.first_name || ""} ${a.last_name || ""}`.trim(),
`${b.first_name || ""} ${b.last_name || ""}`.trim()
),
sortOrder:
state.sortedInfo.columnKey === "employee_name" &&
state.sortedInfo.order,
render: (text, record) =>
`${record.first_name || ""} ${record.last_name || ""}`.trim(),
}, },
{
title: t("employees.fields.last_name"),
dataIndex: "last_name",
key: "last_name",
},
{ {
title: t("employees.labels.rate_type"), title: t("employees.labels.rate_type"),
dataIndex: "rate_type", dataIndex: "rate_type",
key: "rate_type", key: "rate_type",
sorter: (a, b) => Number(a.flat_rate) - Number(b.flat_rate),
sortOrder:
state.sortedInfo.columnKey === "rate_type" && state.sortedInfo.order,
filters: [
{
text: t("employees.labels.flat_rate"),
value: true,
},
{
text: t("employees.labels.straight_time"),
value: false,
},
],
onFilter: (value, record) => value === record.flate_rate,
render: (text, record) => render: (text, record) =>
record.flat_rate record.flat_rate
? t("employees.labels.flat_rate") ? t("employees.labels.flat_rate")
: t("employees.labels.straight_time"), : t("employees.labels.straight_time"),
}, },
{
title: t("employees.labels.status"),
dataIndex: "active",
key: "active",
sorter: (a, b) => Number(a.active) - Number(b.active),
sortOrder:
state.sortedInfo.columnKey === "active" && state.sortedInfo.order,
filters: [
{
text: t("employees.labels.active"),
value: true,
},
{
text: t("employees.labels.inactive"),
value: false,
},
],
onFilter: (value, record) => value === record.active,
render: (text, record) =>
record.active
? t("employees.labels.active")
: t("employees.labels.inactive"),
},
]; ];
return ( return (
<div> <div>
@@ -74,6 +130,7 @@ export default function ShopEmployeesListComponent({ loading, employees }) {
type: "radio", type: "radio",
selectedRowKeys: [search.employeeId], selectedRowKeys: [search.employeeId],
}} }}
onChange={handleTableChange}
onRow={(record, rowIndex) => { onRow={(record, rowIndex) => {
return { return {
onClick: (event) => { onClick: (event) => {

View File

@@ -166,9 +166,6 @@ export function TechClockOffButton({
}, },
({ getFieldValue }) => ({ ({ getFieldValue }) => ({
validator(rule, value) { validator(rule, value) {
console.log(
bodyshop.tt_enforce_hours_for_tech_console
);
if (!bodyshop.tt_enforce_hours_for_tech_console) { if (!bodyshop.tt_enforce_hours_for_tech_console) {
return Promise.resolve(); return Promise.resolve();
} }

View File

@@ -1,7 +1,8 @@
import { Button, Form, Input } from "antd"; import { Button, Form, Input } from "antd";
import React from "react"; import React, { useEffect } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { connect } from "react-redux"; import { connect } from "react-redux";
import { Redirect } from "react-router-dom";
import { createStructuredSelector } from "reselect"; import { createStructuredSelector } from "reselect";
import { techLoginStart } from "../../redux/tech/tech.actions"; import { techLoginStart } from "../../redux/tech/tech.actions";
import { import {
@@ -11,7 +12,6 @@ import {
} from "../../redux/tech/tech.selectors"; } from "../../redux/tech/tech.selectors";
import AlertComponent from "../alert/alert.component"; import AlertComponent from "../alert/alert.component";
import "./tech-login.styles.scss"; import "./tech-login.styles.scss";
import { Redirect } from "react-router-dom";
const mapStateToProps = createStructuredSelector({ const mapStateToProps = createStructuredSelector({
technician: selectTechnician, technician: selectTechnician,
@@ -35,6 +35,10 @@ export function TechLogin({
techLoginStart(values); techLoginStart(values);
}; };
useEffect(() => {
document.title = t("titles.techconsole");
}, [t]);
return ( return (
<div className="tech-login-container"> <div className="tech-login-container">
{technician ? <Redirect to={`/tech/joblookup`} /> : null} {technician ? <Redirect to={`/tech/joblookup`} /> : null}

View File

@@ -1,17 +1,21 @@
import { onError } from "@apollo/client/link/error"; import { onError } from "@apollo/client/link/error";
//https://stackoverflow.com/questions/57163454/refreshing-a-token-with-apollo-client-firebase-auth //https://stackoverflow.com/questions/57163454/refreshing-a-token-with-apollo-client-firebase-auth
import * as Sentry from "@sentry/react";
const errorLink = onError( const errorLink = onError(
({ graphQLErrors, networkError, operation, forward }) => { ({ graphQLErrors, networkError, operation, forward }) => {
if (graphQLErrors) if (graphQLErrors) {
graphQLErrors.forEach(({ message, locations, path }) => graphQLErrors.forEach(({ message, locations, path }) => {
console.log( console.log(
`[GraphQL error]: Message: ${message}, Location: ${locations}, Path: ${path}` `[GraphQL error]: Message: ${message}, Location: ${locations}, Path: ${path}`
) );
); Sentry.captureException({ message, locations, path });
});
}
if (networkError) if (networkError)
console.log(`[Network error]: ${JSON.stringify(networkError)}`); console.log(`[Network error]: ${JSON.stringify(networkError)}`);
console.log(operation.getContext()); console.log(operation.getContext());
return forward(operation);
} }
); );

View File

@@ -30,15 +30,15 @@ export const QUERY_AVAILABLE_CC = gql`
fuel fuel
id id
make make
model
plate
status
year
dailycost
mileage mileage
model
notes notes
nextservicekm nextservicekm
nextservicedate nextservicedate
plate
readiness
status
year
} }
} }
`; `;
@@ -68,19 +68,20 @@ export const QUERY_ALL_CC = gql`
insuranceexpires insuranceexpires
leaseenddate leaseenddate
make make
mileage
model model
nextservicedate nextservicedate
nextservicekm nextservicekm
notes notes
plate plate
purchasedate purchasedate
readiness
registrationexpires registrationexpires
serviceenddate serviceenddate
servicestartdate servicestartdate
status status
vin vin
year year
mileage
cccontracts( cccontracts(
where: { status: { _eq: "contracts.status.out" } } where: { status: { _eq: "contracts.status.out" } }
order_by: { contract_date: desc } order_by: { contract_date: desc }
@@ -90,10 +91,10 @@ export const QUERY_ALL_CC = gql`
scheduledreturn scheduledreturn
job { job {
id id
ro_number
ownr_fn ownr_fn
ownr_ln ownr_ln
ownr_co_nm ownr_co_nm
ro_number
} }
} }
} }
@@ -119,19 +120,20 @@ export const QUERY_CC_BY_PK = gql`
insuranceexpires insuranceexpires
leaseenddate leaseenddate
make make
mileage
model model
nextservicedate nextservicedate
nextservicekm nextservicekm
notes notes
plate plate
purchasedate purchasedate
readiness
registrationexpires registrationexpires
serviceenddate serviceenddate
servicestartdate servicestartdate
status status
vin vin
year year
mileage
cccontracts_aggregate { cccontracts_aggregate {
aggregate { aggregate {
count(distinct: true) count(distinct: true)
@@ -139,21 +141,20 @@ export const QUERY_CC_BY_PK = gql`
} }
cccontracts(offset: $offset, limit: $limit, order_by: $order) { cccontracts(offset: $offset, limit: $limit, order_by: $order) {
agreementnumber agreementnumber
driver_fn
driver_ln
id id
status
start
scheduledreturn
kmstart kmstart
kmend kmend
driver_ln scheduledreturn
driver_fn start
status
job { job {
ro_number id
ownr_ln ownr_ln
ownr_fn ownr_fn
ownr_co_nm ownr_co_nm
id ro_number
} }
} }
} }

View File

@@ -57,19 +57,15 @@ export const INSERT_CSI = gql`
`; `;
export const QUERY_CSI_RESPONSE_PAGINATED = gql` export const QUERY_CSI_RESPONSE_PAGINATED = gql`
query QUERY_CSI_RESPONSE_PAGINATED( query QUERY_CSI_RESPONSE_PAGINATED {
$offset: Int csi(order_by: { completedon: desc_nulls_last }) {
$limit: Int
$order: [csi_order_by!]!
) {
csi(offset: $offset, limit: $limit, order_by: $order) {
id id
completedon completedon
job { job {
ownr_fn ownr_fn
ownr_ln ownr_ln
ownerid
ro_number ro_number
id id
} }
} }
@@ -83,6 +79,7 @@ export const QUERY_CSI_RESPONSE_PAGINATED = gql`
export const QUERY_CSI_RESPONSE_BY_PK = gql` export const QUERY_CSI_RESPONSE_BY_PK = gql`
query QUERY_CSI_RESPONSE_BY_PK($id: uuid!) { query QUERY_CSI_RESPONSE_BY_PK($id: uuid!) {
csi_by_pk(id: $id) { csi_by_pk(id: $id) {
completedon
relateddata relateddata
valid valid
validuntil validuntil

View File

@@ -3,11 +3,12 @@ import { gql } from "@apollo/client";
export const QUERY_EMPLOYEES = gql` export const QUERY_EMPLOYEES = gql`
query QUERY_EMPLOYEES { query QUERY_EMPLOYEES {
employees(order_by: { employee_number: asc }) { employees(order_by: { employee_number: asc }) {
last_name active
id employee_number
first_name first_name
flat_rate flat_rate
employee_number id
last_name
} }
} }
`; `;

View File

@@ -5,7 +5,7 @@ export const QUERY_ALL_ACTIVE_JOBS_PAGINATED = gql`
$offset: Int $offset: Int
$limit: Int $limit: Int
$order: [jobs_order_by!] $order: [jobs_order_by!]
$statuses: [String!]!, $statuses: [String!]!
$isConverted: Boolean $isConverted: Boolean
) { ) {
jobs( jobs(
@@ -120,7 +120,9 @@ export const QUERY_PARTS_QUEUE = gql`
} }
} }
jobs( jobs(
where: { _and: [{ status: { _in: $statuses }, converted: { _eq: true } }] } where: {
_and: [{ status: { _in: $statuses }, converted: { _eq: true } }]
}
offset: $offset offset: $offset
limit: $limit limit: $limit
order_by: $order order_by: $order
@@ -336,6 +338,7 @@ export const QUERY_JOBS_IN_PRODUCTION = gql`
category category
iouparent iouparent
ro_number ro_number
ownerid
ownr_fn ownr_fn
ownr_ln ownr_ln
ownr_co_nm ownr_co_nm
@@ -364,6 +367,8 @@ export const QUERY_JOBS_IN_PRODUCTION = gql`
employee_refinish employee_refinish
employee_prep employee_prep
employee_csr employee_csr
est_ct_fn
est_ct_ln
suspended suspended
date_repairstarted date_repairstarted
joblines_status { joblines_status {
@@ -540,147 +545,166 @@ export const QUERY_JOB_COSTING_DETAILS = gql`
export const GET_JOB_BY_PK = gql` export const GET_JOB_BY_PK = gql`
query GET_JOB_BY_PK($id: uuid!) { query GET_JOB_BY_PK($id: uuid!) {
jobs_by_pk(id: $id) { jobs_by_pk(id: $id) {
updated_at actual_completion
actual_delivery
actual_in
adjustment_bottom_line
area_of_damage
auto_add_ats
available_jobs {
id
}
alt_transport
ca_bc_pvrt
ca_customer_gst
ca_gst_registrant
category
cccontracts {
agreementnumber
courtesycar {
fleetnumber
id
make
model
plate
year
}
id
scheduledreturn
start
status
}
cieca_ttl
class
clm_no
clm_total
comment
converted
csiinvites {
completedon
id
}
date_estimated
date_exported
date_invoiced
date_last_contacted
date_lost_sale
date_next_contact
date_open
date_rentalresp
date_repairstarted
date_scheduled
date_towin
date_void
ded_amt
ded_note
ded_status
deliverchecklist
depreciation_taxes
driveable
employee_body
employee_body_rel { employee_body_rel {
id id
first_name first_name
last_name last_name
} }
employee_refinish_rel { employee_csr
id
first_name
last_name
}
employee_prep_rel {
id
first_name
last_name
}
employee_csr_rel { employee_csr_rel {
id id
first_name first_name
last_name last_name
} }
employee_csr
employee_prep employee_prep
employee_prep_rel {
id
first_name
last_name
}
employee_refinish employee_refinish
employee_body employee_refinish_rel {
alt_transport id
intakechecklist first_name
invoice_final_note last_name
comment }
loss_desc est_co_nm
kmin est_ct_fn
kmout est_ct_ln
referral_source est_ea
referral_source_extra est_ph1
unit_number federal_tax_rate
po_number id
special_coverage_policy
scheduled_delivery
converted
lbr_adjustments
ro_number
po_number
clm_total
inproduction inproduction
vehicleid
plate_no
plate_st
v_vin
v_model_yr
v_model_desc
v_make_desc
v_color
vehicleid
driveable
towin
loss_of_use
lost_sale_reason
vehicle {
id
plate_no
plate_st
v_vin
v_model_yr
v_model_desc
v_make_desc
v_color
notes
v_paint_codes
jobs {
id
ro_number
status
clm_no
}
}
available_jobs {
id
}
ins_co_id
policy_no
loss_date
clm_no
area_of_damage
ins_co_nm
ins_addr1 ins_addr1
ins_city ins_city
ins_co_id
ins_co_nm
ins_ct_ln ins_ct_ln
ins_ct_fn ins_ct_fn
ins_ea ins_ea
ins_ph1 ins_ph1
est_co_nm intakechecklist
est_ct_fn invoice_final_note
est_ct_ln
est_ph1
est_ea
selling_dealer
servicing_dealer
selling_dealer_contact
servicing_dealer_contact
regie_number
scheduled_completion
id
ded_amt
ded_status
depreciation_taxes
other_amount_payable
towing_payable
storage_payable
adjustment_bottom_line
federal_tax_rate
state_tax_rate
local_tax_rate
tax_tow_rt
tax_str_rt
tax_paint_mat_rt
tax_shop_mat_rt
tax_sub_rt
tax_lbr_rt
tax_levies_rt
parts_tax_rates
job_totals
ownr_fn
ownr_ln
ownr_co_nm
ownr_ea
ownr_addr1
ownr_addr2
ownr_city
ownr_st
ownr_zip
ownr_ctry
ownr_ph1
ownr_ph2
production_vars
ca_gst_registrant
ownerid
ded_note
materials
auto_add_ats
rate_ats
iouparent iouparent
job_totals
joblines(where: { removed: { _eq: false } }, order_by: { line_no: asc }) {
act_price
ah_detail_line
alt_partm
alt_partno
billlines(limit: 1, order_by: { bill: { date: desc } }) {
actual_cost
actual_price
bill {
id
invoice_number
vendor {
id
name
}
}
joblineid
id
quantity
}
convertedtolbr
critical
db_hrs
db_price
db_ref
id
ioucreated
lbr_amt
lbr_op
line_desc
line_ind
line_no
line_ref
location
manual_line
mod_lb_hrs
mod_lbr_ty
notes
oem_partno
op_code_desc
part_qty
part_type
prt_dsmk_m
prt_dsmk_p
status
tax_part
unq_seq
}
kmin
kmout
labor_rate_desc
lbr_adjustments
local_tax_rate
loss_date
loss_desc
loss_of_use
lost_sale_reason
materials
other_amount_payable
owner { owner {
id id
ownr_fn ownr_fn
@@ -697,7 +721,40 @@ export const GET_JOB_BY_PK = gql`
ownr_ph2 ownr_ph2
tax_number tax_number
} }
labor_rate_desc owner_owing
ownerid
ownr_addr1
ownr_addr2
ownr_ctry
ownr_city
ownr_co_nm
ownr_ea
ownr_fn
ownr_ln
ownr_ph1
ownr_ph2
ownr_st
ownr_zip
parts_tax_rates
payments {
amount
created_at
date
exportedat
id
jobid
memo
payer
paymentnum
transactionid
type
}
plate_no
plate_st
po_number
policy_no
production_vars
rate_ats
rate_la1 rate_la1
rate_la2 rate_la2
rate_la3 rate_la3
@@ -721,121 +778,64 @@ export const GET_JOB_BY_PK = gql`
rate_mapa rate_mapa
rate_mash rate_mash
rate_matd rate_matd
actual_in regie_number
federal_tax_rate referral_source
local_tax_rate referral_source_extra
state_tax_rate remove_from_ar
ro_number
scheduled_completion scheduled_completion
scheduled_in
actual_completion
scheduled_delivery scheduled_delivery
actual_delivery scheduled_in
date_estimated selling_dealer
date_open servicing_dealer
date_scheduled selling_dealer_contact
date_invoiced servicing_dealer_contact
date_last_contacted special_coverage_policy
date_lost_sale state_tax_rate
date_next_contact
date_towin
date_rentalresp
date_exported
date_repairstarted
date_void
status status
owner_owing storage_payable
tax_registration_number
class
category
deliverchecklist
voided
ca_bc_pvrt
ca_customer_gst
suspended suspended
joblines(where: { removed: { _eq: false } }, order_by: { line_no: asc }) { tax_lbr_rt
tax_levies_rt
tax_paint_mat_rt
tax_registration_number
tax_shop_mat_rt
tax_str_rt
tax_sub_rt
tax_tow_rt
towin
towing_payable
unit_number
updated_at
v_vin
v_model_yr
v_model_desc
v_make_desc
v_color
vehicleid
vehicle {
id id
alt_partm jobs {
line_no clm_no
unq_seq id
line_ind ro_number
line_desc status
line_ref }
part_type
oem_partno
alt_partno
db_price
act_price
part_qty
mod_lbr_ty
db_hrs
mod_lb_hrs
lbr_op
lbr_amt
op_code_desc
status
notes notes
location plate_no
tax_part plate_st
db_ref v_color
manual_line v_make_desc
prt_dsmk_p v_model_desc
prt_dsmk_m v_model_yr
ioucreated v_paint_codes
convertedtolbr v_vin
ah_detail_line
critical
billlines(limit: 1, order_by: { bill: { date: desc } }) {
id
quantity
actual_cost
actual_price
joblineid
bill {
id
invoice_number
vendor {
id
name
}
}
}
}
payments {
id
jobid
amount
payer
paymentnum
created_at
transactionid
memo
date
type
exportedat
}
cccontracts {
id
status
start
scheduledreturn
agreementnumber
courtesycar {
id
make
model
year
plate
fleetnumber
}
}
cieca_ttl
csiinvites {
id
completedon
} }
voided
} }
} }
`; `;
export const GET_JOB_RECONCILIATION_BY_PK = gql` export const GET_JOB_RECONCILIATION_BY_PK = gql`
query GET_JOB_RECONCILIATION_BY_PK($id: uuid!) { query GET_JOB_RECONCILIATION_BY_PK($id: uuid!) {
bills(where: { jobid: { _eq: $id } }) { bills(where: { jobid: { _eq: $id } }) {
@@ -900,6 +900,7 @@ export const GET_JOB_RECONCILIATION_BY_PK = gql`
} }
} }
`; `;
export const QUERY_JOB_CARD_DETAILS = gql` export const QUERY_JOB_CARD_DETAILS = gql`
query QUERY_JOB_CARD_DETAILS($id: uuid!) { query QUERY_JOB_CARD_DETAILS($id: uuid!) {
jobs_by_pk(id: $id) { jobs_by_pk(id: $id) {
@@ -2220,3 +2221,120 @@ export const GET_JOB_LINE_ORDERS = gql`
} }
} }
`; `;
export const UPDATE_REMOVE_FROM_AR = gql`
mutation UPDATE_REMOVE_FROM_AR($jobId: uuid!, $remove_from_ar: Boolean!) {
update_jobs_by_pk(
pk_columns: { id: $jobId }
_set: { remove_from_ar: $remove_from_ar }
) {
id
remove_from_ar
}
}
`;
export const UNVOID_JOB = gql`
mutation UNVOID_JOB(
$jobId: uuid!
$default_imported: String!
$currentUserEmail: String!
$text: String!
) {
update_jobs_by_pk(
pk_columns: { id: $jobId }
_set: { voided: false, status: $default_imported, date_void: null }
) {
id
date_void
voided
status
}
insert_notes(
objects: {
jobid: $jobId
audit: true
created_by: $currentUserEmail
text: $text
}
) {
returning {
id
}
}
}
`;
export const DELETE_INTAKE_CHECKLIST = gql`
mutation DELETE_INTAKE($jobId: uuid!) {
update_jobs_by_pk(
pk_columns: { id: $jobId }
_set: { intakechecklist: null }
) {
id
intakechecklist
}
}
`;
export const DELETE_DELIVERY_CHECKLIST = gql`
mutation DELETE_DELIVERY($jobId: uuid!) {
update_jobs_by_pk(
pk_columns: { id: $jobId }
_set: { deliverchecklist: null }
) {
id
deliverchecklist
}
}
`;
export const MARK_JOB_FOR_REEXPORT = gql`
mutation MARK_JOB_FOR_REEXPORT($jobId: uuid!, $default_invoiced: String!) {
update_jobs_by_pk(
pk_columns: { id: $jobId }
_set: { date_exported: null, status: $default_invoiced }
) {
id
date_exported
status
date_invoiced
}
}
`;
export const MARK_JOB_AS_EXPORTED = gql`
mutation MARK_JOB_AS_EXPORTED(
$jobId: uuid!
$date_exported: timestamptz!
$default_exported: String!
) {
update_jobs_by_pk(
pk_columns: { id: $jobId }
_set: { date_exported: $date_exported, status: $default_exported }
) {
id
date_exported
date_invoiced
status
}
}
`;
export const MARK_JOB_AS_UNINVOICED = gql`
mutation MARK_JOB_AS_UNINVOICED($jobId: uuid!, $default_delivered: String!) {
update_jobs_by_pk(
pk_columns: { id: $jobId }
_set: {
date_exported: null
date_invoiced: null
status: $default_delivered
}
) {
id
date_exported
date_invoiced
status
}
}
`;

View File

@@ -14,38 +14,38 @@ import { persistor, store } from "./redux/store";
import reportWebVitals from "./reportWebVitals"; import reportWebVitals from "./reportWebVitals";
import "./translations/i18n"; import "./translations/i18n";
import "./utils/CleanAxios"; import "./utils/CleanAxios";
//import { BrowserTracing } from "@sentry/tracing"; //import { BrowserTracing } from "@sentry/tracing";
// Dinero.defaultCurrency = "CAD"; // Dinero.defaultCurrency = "CAD";
// Dinero.globalLocale = "en-CA"; // Dinero.globalLocale = "en-CA";
Dinero.globalRoundingMode = "HALF_EVEN"; Dinero.globalRoundingMode = "HALF_EVEN";
if (process.env.NODE_ENV !== "development") { //if (process.env.NODE_ENV !== "development") {
Sentry.init({ Sentry.init({
dsn: "https://fd7e89369b6b4bdc9c6c4c9f22fa4ee4@o492140.ingest.sentry.io/5651027", dsn: "https://fd7e89369b6b4bdc9c6c4c9f22fa4ee4@o492140.ingest.sentry.io/5651027",
ignoreErrors: [ ignoreErrors: [
"ResizeObserver loop", "ResizeObserver loop",
"Module specifier, 'fs' does not start", "Module specifier, 'fs' does not start",
"Module specifier, 'zlib' does not start with", "Module specifier, 'zlib' does not start with",
], ],
integrations: [ integrations: [
// new BrowserTracing(), Sentry.replayIntegration({
// new Sentry.Integrations.Breadcrumbs({ console: true }), maskAllText: false,
// new Sentry.Replay(), blockAllMedia: true,
], }),
// This sets the sample rate to be 10%. You may want this to be 100% while new Sentry.BrowserTracing({}),
// in development and sample at a lower rate in production ],
// replaysSessionSampleRate: 0.1, tracePropagationTargets: [
// // If the entire session is not sampled, use the below sample rate to sample "api.imex.online",
// // sessions when an error occurs. "api.test.imex.online",
// replaysOnErrorSampleRate: 1.0, "db.imex.online",
environment: process.env.NODE_ENV, ],
// tracesSampleRate: 0.2, tracesSampleRate: 1.0,
// We recommend adjusting this value in production, or using tracesSampler replaysOnErrorSampleRate: 1.0,
// for finer control environment: process.env.NODE_ENV,
// tracesSampleRate: 0.5, });
}); //}
}
ReactDOM.render( ReactDOM.render(
<Provider store={store}> <Provider store={store}>

View File

@@ -1,11 +1,14 @@
import { useMutation, useQuery } from "@apollo/client"; import { useMutation, useQuery } from "@apollo/client";
import { Form, notification } from "antd"; import { Form, notification } from "antd";
import moment from "moment"; import moment from "moment";
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 { useParams } from "react-router-dom"; import { useLocation, useParams } from "react-router-dom";
import AlertComponent from "../../components/alert/alert.component"; import AlertComponent from "../../components/alert/alert.component";
import LoadingSpinner from "../../components/loading-spinner/loading-spinner.component";
import NotFound from "../../components/not-found/not-found.component";
import RbacWrapper from "../../components/rbac-wrapper/rbac-wrapper.component"; import RbacWrapper from "../../components/rbac-wrapper/rbac-wrapper.component";
import { QUERY_CC_BY_PK, UPDATE_CC } from "../../graphql/courtesy-car.queries"; import { QUERY_CC_BY_PK, UPDATE_CC } from "../../graphql/courtesy-car.queries";
import { import {
@@ -13,13 +16,10 @@ import {
setBreadcrumbs, setBreadcrumbs,
setSelectedHeader, setSelectedHeader,
} from "../../redux/application/application.actions"; } from "../../redux/application/application.actions";
import { pageLimit } from "../../utils/config";
import { CreateRecentItem } from "../../utils/create-recent-item"; import { CreateRecentItem } from "../../utils/create-recent-item";
import UndefinedToNull from "./../../utils/undefinedtonull";
import CourtesyCarDetailPageComponent from "./courtesy-car-detail.page.component"; import CourtesyCarDetailPageComponent from "./courtesy-car-detail.page.component";
import NotFound from "../../components/not-found/not-found.component";
import LoadingSpinner from "../../components/loading-spinner/loading-spinner.component";
import queryString from "query-string";
import { useLocation } from "react-router-dom";
import {pageLimit} from "../../utils/config";
const mapDispatchToProps = (dispatch) => ({ const mapDispatchToProps = (dispatch) => ({
setBreadcrumbs: (breadcrumbs) => dispatch(setBreadcrumbs(breadcrumbs)), setBreadcrumbs: (breadcrumbs) => dispatch(setBreadcrumbs(breadcrumbs)),
@@ -112,7 +112,10 @@ export function CourtesyCarDetailPageContainer({
setSaveLoading(true); setSaveLoading(true);
const result = await updateCourtesyCar({ const result = await updateCourtesyCar({
variables: { cc: { ...values }, ccId: ccId }, variables: {
cc: { ...UndefinedToNull(values, ["readiness"]) },
ccId: ccId,
},
refetchQueries: ["QUERY_CC_BY_PK"], refetchQueries: ["QUERY_CC_BY_PK"],
awaitRefetchQueries: true, awaitRefetchQueries: true,
}); });

View File

@@ -1,88 +1,67 @@
import { useQuery, useMutation } from "@apollo/client"; // import { useMutation, useQuery } from "@apollo/client";
import { Form, Layout, Typography, Button, Result } from "antd"; import { Button, Form, Layout, Result, Typography } from "antd";
import React, { useState } from "react"; import axios from "axios";
import React, { useCallback, useEffect, useState } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { connect } from "react-redux";
import { useParams } from "react-router-dom"; import { useParams } from "react-router-dom";
import { createStructuredSelector } from "reselect";
import AlertComponent from "../../components/alert/alert.component"; import AlertComponent from "../../components/alert/alert.component";
import ConfigFormComponents from "../../components/config-form-components/config-form-components.component"; import ConfigFormComponents from "../../components/config-form-components/config-form-components.component";
import LoadingSpinner from "../../components/loading-spinner/loading-spinner.component"; import LoadingSpinner from "../../components/loading-spinner/loading-spinner.component";
import { QUERY_SURVEY, COMPLETE_SURVEY } from "../../graphql/csi.queries";
import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
import { selectCurrentUser } from "../../redux/user/user.selectors"; import { selectCurrentUser } from "../../redux/user/user.selectors";
import { DateTimeFormat } from "./../../utils/DateFormatter";
const mapStateToProps = createStructuredSelector({ const mapStateToProps = createStructuredSelector({
currentUser: selectCurrentUser, currentUser: selectCurrentUser,
}); });
const mapDispatchToProps = (dispatch) => ({ const mapDispatchToProps = (dispatch) => ({});
//setUserLanguage: language => dispatch(setUserLanguage(language))
});
export default connect(mapStateToProps, mapDispatchToProps)(CsiContainerPage); export default connect(mapStateToProps, mapDispatchToProps)(CsiContainerPage);
export function CsiContainerPage({ currentUser }) { export function CsiContainerPage({ currentUser }) {
const { surveyId } = useParams(); const { surveyId } = useParams();
const [form] = Form.useForm(); const [form] = Form.useForm();
const [axiosResponse, setAxiosResponse] = useState(null);
const [submitting, setSubmitting] = useState({ const [submitting, setSubmitting] = useState({
loading: false, loading: false,
submitted: false, submitted: false,
}); });
const { loading, error, data } = useQuery(QUERY_SURVEY, {
variables: { surveyId },
fetchPolicy: "network-only",
nextFetchPolicy: "network-only",
});
const { t } = useTranslation(); const { t } = useTranslation();
const [completeSurvey] = useMutation(COMPLETE_SURVEY);
if (loading) return <LoadingSpinner />;
if (error || !!!data.csi_by_pk) const getAxiosData = useCallback(async () => {
return ( try {
<div> try {
<Result window.$crisp.push(["do", "chat:hide"]);
status="error" } catch {
title={t("csi.errors.notfoundtitle")} console.log("Unable to attach to crisp instance. ");
subTitle={t("csi.errors.notfoundsubtitle")} }
> setSubmitting((prevSubmitting) => ({ ...prevSubmitting, loading: true }));
{error ? ( const response = await axios.post("/csi/lookup", { surveyId });
<div>ERROR: {error.graphQLErrors.map((e) => e.message)}</div> setSubmitting((prevSubmitting) => ({
) : null} ...prevSubmitting,
</Result>
</div>
);
const handleFinish = async (values) => {
setSubmitting({ ...submitting, loading: true });
const result = await completeSurvey({
variables: {
surveyId,
survey: {
response: values,
valid: false,
completedon: new Date(),
},
},
});
if (!!!result.errors) {
setSubmitting({ ...submitting, loading: false, submitted: true });
} else {
setSubmitting({
...submitting,
loading: false, loading: false,
error: JSON.stringify(result.errors), }));
setAxiosResponse(response.data);
} catch (error) {
console.error(`Something went wrong...: ${error.message}`);
console.dir({
stack: error?.stack,
message: error?.message,
}); });
} }
}; }, [setAxiosResponse, surveyId]);
const { useEffect(() => {
relateddata: { bodyshop, job }, getAxiosData().catch((err) =>
csiquestion: { config: csiquestions }, console.error(
} = data.csi_by_pk; `Something went wrong fetching axios data: ${err.message || ""}`
)
);
}, [getAxiosData]);
if (currentUser && currentUser.authorized) // Return if authorized
if (currentUser && currentUser.authorized) {
return ( return (
<Layout <Layout
style={{ height: "100vh", display: "flex", flexDirection: "column" }} style={{ height: "100vh", display: "flex", flexDirection: "column" }}
@@ -94,85 +73,176 @@ export function CsiContainerPage({ currentUser }) {
/> />
</Layout> </Layout>
); );
}
return ( if (submitting.loading) return <LoadingSpinner />;
<Layout
style={{ height: "100vh", display: "flex", flexDirection: "column" }} const handleFinish = async (values) => {
> try {
<div setSubmitting({ ...submitting, loading: true, submitting: true });
style={{ const result = await axios.post("/csi/submit", { surveyId, values });
display: "flex", console.log("result", result);
flexDirection: "column", if (!!!result.errors && result.data.update_csi.affected_rows > 0) {
alignItems: "center", setSubmitting({ ...submitting, loading: false, submitted: true });
}} }
> } catch (error) {
<div style={{ display: "flex", alignItems: "center", margin: "2em" }}> console.error(`Something went wrong...: ${error.message}`);
{bodyshop.logo_img_path && bodyshop.logo_img_path.src ? ( console.dir({
<img src={bodyshop.logo_img_path.src} alt="Logo" /> stack: error?.stack,
) : null} message: error?.message,
<div style={{ margin: "2em" }}> });
<strong>{bodyshop.shopname || ""}</strong> }
<div>{`${bodyshop.address1 || ""}`}</div> };
<div>{`${bodyshop.address2 || ""}`}</div>
<div>{`${bodyshop.city || ""} ${bodyshop.state || ""} ${ if (!axiosResponse || axiosResponse.csi_by_pk === null) {
bodyshop.zip_post || "" // Do something here , this is where you would return a loading box or something
}`}</div> return (
<>
<Layout style={{ display: "flex", flexDirection: "column" }}>
<Layout.Content
style={{
backgroundColor: "#fff",
margin: "2em 4em",
padding: "2em",
overflowY: "auto",
textAlign: "center",
display: "flex",
justifyContent: "center",
alignItems: "center",
}}
>
<Form>
<Result
status="error"
title={t("csi.errors.notfoundtitle")}
subTitle={t("csi.errors.notfoundsubtitle")}
/>
</Form>
</Layout.Content>
<Layout.Footer>
{t("csi.labels.copyright")}{" "}
{t("csi.fields.surveyid", { surveyId: surveyId })}
</Layout.Footer>
</Layout>
</>
);
} else {
const {
relateddata: { bodyshop, job },
csiquestion: { config: csiquestions },
} = axiosResponse.csi_by_pk;
return (
<Layout style={{ display: "flex", flexDirection: "column" }}>
<div
style={{
display: "flex",
flexDirection: "column",
alignItems: "center",
}}
>
<div style={{ display: "flex", alignItems: "center", margin: "2em" }}>
{bodyshop.logo_img_path && bodyshop.logo_img_path.src ? (
<img
src={bodyshop.logo_img_path.src}
alt={bodyshop.shopname.concat(" Logo")}
height={bodyshop.logo_img_path.height}
width={bodyshop.logo_img_path.width}
/>
) : null}
<div style={{ margin: "2em", verticalAlign: "middle" }}>
<Typography.Title level={4} style={{ margin: 0 }}>
{bodyshop.shopname || ""}
</Typography.Title>
<Typography.Paragraph style={{ margin: 0 }}>
{`${bodyshop.address1 || ""}${bodyshop.address2 ? ", " : ""}${
bodyshop.address2 || ""
}`.trim()}
</Typography.Paragraph>
<Typography.Paragraph style={{ margin: 0 }}>
{`${bodyshop.city || ""}${
bodyshop.city && bodyshop.state ? ", " : ""
}${bodyshop.state || ""} ${bodyshop.zip_post || ""}`.trim()}
</Typography.Paragraph>
</div>
</div> </div>
<Typography.Title>{t("csi.labels.title")}</Typography.Title>
<strong>
{t("csi.labels.greeting", {
name: job.ownr_co_nm || job.ownr_fn || "",
})}
</strong>
<Typography.Paragraph>
{t("csi.labels.intro", { shopname: bodyshop.shopname || "" })}
</Typography.Paragraph>
</div> </div>
<Typography.Title>{t("csi.labels.title")}</Typography.Title>
<strong>{`Hi ${job.ownr_co_nm || job.ownr_fn || ""}!`}</strong>
<Typography.Paragraph>
{`At ${
bodyshop.shopname || ""
}, we value your feedback. We would love to
hear what you have to say. Please fill out the form below.`}
</Typography.Paragraph>
</div>
{submitting.error ? ( {submitting.error ? (
<AlertComponent message={submitting.error} type="error" /> <AlertComponent message={submitting.error} type="error" />
) : null} ) : null}
{submitting.submitted ? ( {submitting.submitted ? (
<Layout.Content <Layout.Content
style={{ style={{
backgroundColor: "#fff", backgroundColor: "#fff",
margin: "2em 4em", margin: "2em 4em",
padding: "2em", padding: "2em",
overflowY: "auto", overflowY: "auto",
}} }}
> >
<Result <Result
status="success" status="success"
title={t("csi.successes.submitted")} title={t("csi.successes.submitted")}
subTitle={t("csi.successes.submittedsub")} subTitle={t("csi.successes.submittedsub")}
/> />
</Layout.Content> </Layout.Content>
) : ( ) : (
<Layout.Content <Layout.Content
style={{ style={{
backgroundColor: "#fff", backgroundColor: "#fff",
margin: "2em 4em", margin: "2em 4em",
padding: "2em", padding: "2em",
overflowY: "auto", overflowY: "auto",
}} }}
> >
<Form form={form} onFinish={handleFinish}> <Form form={form} onFinish={handleFinish}>
<ConfigFormComponents componentList={csiquestions} /> {axiosResponse.csi_by_pk.valid ? (
<Button <>
loading={submitting.loading} <ConfigFormComponents componentList={csiquestions} />
type="primary" <Button
htmlType="submit" loading={submitting.loading}
> type="primary"
{t("general.actions.submit")} htmlType="submit"
</Button> style={{ float: "right" }}
</Form> >
</Layout.Content> {t("general.actions.submit")}
)} </Button>
</>
<Layout.Footer> ) : (
{`Copyright ImEX.Online. Survey ID: ${surveyId}`} <>
</Layout.Footer> <Result
</Layout> title={t("csi.errors.surveycompletetitle")}
); status="warning"
subTitle={t("csi.errors.surveycompletesubtitle", {
date: DateTimeFormat(axiosResponse.csi_by_pk.completedon),
})}
/>
<Typography.Paragraph
type="secondary"
style={{ textAlign: "center" }}
>
{t("csi.successes.submittedsub")}
</Typography.Paragraph>
</>
)}
</Form>
</Layout.Content>
)}
<Layout.Footer>
{t("csi.labels.copyright")}{" "}
{t("csi.fields.surveyid", { surveyId: surveyId })}
</Layout.Footer>
</Layout>
);
}
} }

View File

@@ -7,16 +7,16 @@ import { useParams } from "react-router-dom";
import AlertComponent from "../../components/alert/alert.component"; import AlertComponent from "../../components/alert/alert.component";
import JobCalculateTotals from "../../components/job-calculate-totals/job-calculate-totals.component"; import JobCalculateTotals from "../../components/job-calculate-totals/job-calculate-totals.component";
import ScoreboardAddButton from "../../components/job-scoreboard-add-button/job-scoreboard-add-button.component"; import ScoreboardAddButton from "../../components/job-scoreboard-add-button/job-scoreboard-add-button.component";
import JobsAdminStatus from "../../components/jobs-admin-change-status/jobs-admin-change.status.component";
import JobsAdminClass from "../../components/jobs-admin-class/jobs-admin-class.component"; import JobsAdminClass from "../../components/jobs-admin-class/jobs-admin-class.component";
import JobsAdminDatesChange from "../../components/jobs-admin-dates/jobs-admin-dates.component"; import JobsAdminDatesChange from "../../components/jobs-admin-dates/jobs-admin-dates.component";
import JobsAdminDeleteIntake from "../../components/jobs-admin-delete-intake/jobs-admin-delete-intake.component"; import JobsAdminDeleteIntake from "../../components/jobs-admin-delete-intake/jobs-admin-delete-intake.component";
import JobsAdminMarkReexport from "../../components/jobs-admin-mark-reexport/jobs-admin-mark-reexport.component"; import JobsAdminMarkReexport from "../../components/jobs-admin-mark-reexport/jobs-admin-mark-reexport.component";
import JobAdminOwnerReassociate from "../../components/jobs-admin-owner-reassociate/jobs-admin-owner-reassociate.component"; import JobAdminOwnerReassociate from "../../components/jobs-admin-owner-reassociate/jobs-admin-owner-reassociate.component";
import JobsAdminRemoveAR from "../../components/jobs-admin-remove-ar/jobs-admin-remove-ar.component";
import JobsAdminUnvoid from "../../components/jobs-admin-unvoid/jobs-admin-unvoid.component"; import JobsAdminUnvoid from "../../components/jobs-admin-unvoid/jobs-admin-unvoid.component";
import JobAdminVehicleReassociate from "../../components/jobs-admin-vehicle-reassociate/jobs-admin-vehicle-reassociate.component"; import JobAdminVehicleReassociate from "../../components/jobs-admin-vehicle-reassociate/jobs-admin-vehicle-reassociate.component";
import LoadingSpinner from "../../components/loading-spinner/loading-spinner.component"; import LoadingSpinner from "../../components/loading-spinner/loading-spinner.component";
import JobsAdminStatus from "../../components/jobs-admin-change-status/jobs-admin-change.status.component";
import NotFound from "../../components/not-found/not-found.component"; import NotFound from "../../components/not-found/not-found.component";
import RbacWrapper from "../../components/rbac-wrapper/rbac-wrapper.component"; import RbacWrapper from "../../components/rbac-wrapper/rbac-wrapper.component";
import { GET_JOB_BY_PK } from "../../graphql/jobs.queries"; import { GET_JOB_BY_PK } from "../../graphql/jobs.queries";
@@ -104,6 +104,7 @@ export function JobsCloseContainer({ setBreadcrumbs, setSelectedHeader }) {
<JobsAdminMarkReexport job={data ? data.jobs_by_pk : {}} /> <JobsAdminMarkReexport job={data ? data.jobs_by_pk : {}} />
<JobsAdminUnvoid job={data ? data.jobs_by_pk : {}} /> <JobsAdminUnvoid job={data ? data.jobs_by_pk : {}} />
<JobsAdminStatus job={data ? data.jobs_by_pk : {}} /> <JobsAdminStatus job={data ? data.jobs_by_pk : {}} />
<JobsAdminRemoveAR job={data ? data.jobs_by_pk : {}} />
</Space> </Space>
</Card> </Card>
</Col> </Col>

View File

@@ -1,6 +1,6 @@
import _ from "lodash";
import { useLazyQuery, useMutation } from "@apollo/client"; import { useLazyQuery, useMutation } from "@apollo/client";
import { Form, notification } from "antd"; import { Form, notification } from "antd";
import _ from "lodash";
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";
@@ -90,6 +90,7 @@ function JobsCreateContainer({ bodyshop, setBreadcrumbs, setSelectedHeader }) {
{}, {},
values, values,
{ date_open: new Date() }, { date_open: new Date() },
{ date_estimated: new Date() },
{ {
vehicle: vehicle:
state.vehicle.selectedid || state.vehicle.none state.vehicle.selectedid || state.vehicle.none

View File

@@ -54,6 +54,7 @@ import { selectBodyshop } from "../../redux/user/user.selectors";
import AuditTrailMapping from "../../utils/AuditTrailMappings"; import AuditTrailMapping from "../../utils/AuditTrailMappings";
import UndefinedToNull from "../../utils/undefinedtonull"; import UndefinedToNull from "../../utils/undefinedtonull";
import { DateTimeFormat } from "./../../utils/DateFormatter"; import { DateTimeFormat } from "./../../utils/DateFormatter";
import JobLifecycleComponent from "../../components/job-lifecycle/job-lifecycle.component";
const mapStateToProps = createStructuredSelector({ const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop, bodyshop: selectBodyshop,
@@ -333,7 +334,15 @@ export function JobsDetailPage({
> >
<JobsDetailLaborContainer job={job} jobId={job.id} /> <JobsDetailLaborContainer job={job} jobId={job.id} />
</Tabs.TabPane> </Tabs.TabPane>
<Tabs.TabPane <Tabs.TabPane
forceRender
tab={<span><BarsOutlined />{t('menus.jobsdetail.lifecycle')}</span>}
key="lifecycle"
>
<JobLifecycleComponent job={job} statuses={bodyshop.md_ro_statuses}/>
</Tabs.TabPane>
<Tabs.TabPane
forceRender forceRender
tab={ tab={
<span> <span>

View File

@@ -1,22 +1,20 @@
import { Row, Col } from "antd";
import { useQuery } from "@apollo/client"; import { useQuery } from "@apollo/client";
import queryString from "query-string"; import { Col, Row } from "antd";
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 { connect } from "react-redux";
import { useLocation } from "react-router-dom";
import { createStructuredSelector } from "reselect"; import { createStructuredSelector } from "reselect";
import AlertComponent from "../../components/alert/alert.component"; import AlertComponent from "../../components/alert/alert.component";
import CsiResponseFormContainer from "../../components/csi-response-form/csi-response-form.container"; import CsiResponseFormContainer from "../../components/csi-response-form/csi-response-form.container";
import CsiResponseListPaginated from "../../components/csi-response-list-paginated/csi-response-list-paginated.component"; import CsiResponseListPaginated from "../../components/csi-response-list-paginated/csi-response-list-paginated.component";
import RbacWrapper from "../../components/rbac-wrapper/rbac-wrapper.component";
import { QUERY_CSI_RESPONSE_PAGINATED } from "../../graphql/csi.queries"; import { QUERY_CSI_RESPONSE_PAGINATED } from "../../graphql/csi.queries";
import { import {
setBreadcrumbs, setBreadcrumbs,
setSelectedHeader, setSelectedHeader,
} from "../../redux/application/application.actions"; } from "../../redux/application/application.actions";
import { selectBodyshop } from "../../redux/user/user.selectors"; import { selectBodyshop } from "../../redux/user/user.selectors";
import RbacWrapper from "../../components/rbac-wrapper/rbac-wrapper.component";
import {pageLimit} from "../../utils/config";
const mapStateToProps = createStructuredSelector({ const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop, bodyshop: selectBodyshop,
}); });
@@ -33,28 +31,11 @@ export function ShopCsiContainer({
}) { }) {
const { t } = useTranslation(); const { t } = useTranslation();
const searchParams = queryString.parse(useLocation().search);
const { page, sortcolumn, sortorder } = searchParams;
const { loading, error, data, refetch } = useQuery( const { loading, error, data, refetch } = useQuery(
QUERY_CSI_RESPONSE_PAGINATED, QUERY_CSI_RESPONSE_PAGINATED,
{ {
fetchPolicy: "network-only", fetchPolicy: "network-only",
nextFetchPolicy: "network-only", nextFetchPolicy: "network-only",
variables: {
//search: search || "",
offset: page ? (page - 1) * pageLimit : 0,
limit: pageLimit,
order: [
{
[sortcolumn || "completedon"]: sortorder
? sortorder === "descend"
? "desc_nulls_last"
: "asc"
: "desc_nulls_last",
},
],
},
} }
); );
@@ -73,12 +54,7 @@ export function ShopCsiContainer({
if (error) return <AlertComponent message={error.message} type="error" />; if (error) return <AlertComponent message={error.message} type="error" />;
return ( return (
<RbacWrapper <RbacWrapper action="csi:page">
action="csi:page"
// noauth={
// <AlertComponent message="You don't have acess to see this screen." />
// }
>
<Row gutter={16}> <Row gutter={16}>
<Col span={10}> <Col span={10}>
<CsiResponseListPaginated <CsiResponseListPaginated

View File

@@ -1,10 +1,17 @@
import { Divider } from "antd"; import { Divider } from "antd";
import React from "react"; import React, { useEffect } from "react";
import { useTranslation } from "react-i18next";
import TechClockInFormContainer from "../../components/tech-job-clock-in-form/tech-job-clock-in-form.container"; import TechClockInFormContainer from "../../components/tech-job-clock-in-form/tech-job-clock-in-form.container";
import TechClockedInList from "../../components/tech-job-clocked-in-list/tech-job-clocked-in-list.component"; import TechClockedInList from "../../components/tech-job-clocked-in-list/tech-job-clocked-in-list.component";
import TechJobStatistics from "../../components/tech-job-statistics/tech-job-statistics.component"; import TechJobStatistics from "../../components/tech-job-statistics/tech-job-statistics.component";
export default function TechClockComponent() { export default function TechClockComponent() {
const { t } = useTranslation();
useEffect(() => {
document.title = t("titles.techjobclock");
}, [t]);
return ( return (
<div> <div>
<TechJobStatistics /> <TechJobStatistics />

View File

@@ -1,9 +1,16 @@
import React from "react"; import React, { useEffect } from "react";
import { useTranslation } from "react-i18next";
import RbacWrapperComponent from "../../components/rbac-wrapper/rbac-wrapper.component"; import RbacWrapperComponent from "../../components/rbac-wrapper/rbac-wrapper.component";
import TechLookupJobsDrawer from "../../components/tech-lookup-jobs-drawer/tech-lookup-jobs-drawer.component"; import TechLookupJobsDrawer from "../../components/tech-lookup-jobs-drawer/tech-lookup-jobs-drawer.component";
import TechLookupJobsList from "../../components/tech-lookup-jobs-list/tech-lookup-jobs-list.component"; import TechLookupJobsList from "../../components/tech-lookup-jobs-list/tech-lookup-jobs-list.component";
export default function TechLookupContainer() { export default function TechLookupContainer() {
const { t } = useTranslation();
useEffect(() => {
document.title = t("titles.techjoblookup");
}, [t]);
return ( return (
<div> <div>
<RbacWrapperComponent action="jobs:list-active"> <RbacWrapperComponent action="jobs:list-active">

View File

@@ -1,7 +1,14 @@
import React from "react"; import React, { useEffect } from "react";
import { useTranslation } from "react-i18next";
import TimeTicketShift from "../../components/time-ticket-shift/time-ticket-shift.container"; import TimeTicketShift from "../../components/time-ticket-shift/time-ticket-shift.container";
export default function TechShiftClock() { export default function TechShiftClock() {
const { t } = useTranslation();
useEffect(() => {
document.title = t("titles.techshiftclock");
}, [t]);
return ( return (
<div> <div>
<TimeTicketShift isTechConsole /> <TimeTicketShift isTechConsole />

View File

@@ -99,6 +99,7 @@
}, },
"audit_trail": { "audit_trail": {
"messages": { "messages": {
"admin_job_remove_from_ar": "ADMIN: Remove from AR updated to: {{status}}",
"admin_jobmarkexported": "ADMIN: Job marked as exported.", "admin_jobmarkexported": "ADMIN: Job marked as exported.",
"admin_jobmarkforreexport": "ADMIN: Job marked for re-export.", "admin_jobmarkforreexport": "ADMIN: Job marked for re-export.",
"admin_jobuninvoice": "ADMIN: Job has been uninvoiced.", "admin_jobuninvoice": "ADMIN: Job has been uninvoiced.",
@@ -112,11 +113,11 @@
"jobassignmentchange": "Employee {{name}} assigned to {{operation}}", "jobassignmentchange": "Employee {{name}} assigned to {{operation}}",
"jobassignmentremoved": "Employee assignment removed for {{operation}}", "jobassignmentremoved": "Employee assignment removed for {{operation}}",
"jobchecklist": "Checklist type \"{{type}}\" completed. In production set to {{inproduction}}. Status set to {{status}}.", "jobchecklist": "Checklist type \"{{type}}\" completed. In production set to {{inproduction}}. Status set to {{status}}.",
"jobinvoiced": "Job has been invoiced.",
"jobconverted": "Job converted and assigned number {{ro_number}}.", "jobconverted": "Job converted and assigned number {{ro_number}}.",
"jobfieldchanged": "Job field $t(jobs.fields.{{field}}) changed to {{value}}.", "jobfieldchanged": "Job field $t(jobs.fields.{{field}}) changed to {{value}}.",
"jobimported": "Job imported.", "jobimported": "Job imported.",
"jobinproductionchange": "Job production status set to {{inproduction}}", "jobinproductionchange": "Job production status set to {{inproduction}}",
"jobinvoiced": "Job has been invoiced.",
"jobioucreated": "IOU Created.", "jobioucreated": "IOU Created.",
"jobmodifylbradj": "Labor adjustments modified {{mod_lbr_ty}} / {{hours}}.", "jobmodifylbradj": "Labor adjustments modified {{mod_lbr_ty}} / {{hours}}.",
"jobnoteadded": "Note added to Job.", "jobnoteadded": "Note added to Job.",
@@ -254,7 +255,6 @@
"saving": "Error encountered while saving. {{message}}" "saving": "Error encountered while saving. {{message}}"
}, },
"fields": { "fields": {
"ReceivableCustomField": "QBO Receivable Custom Field {{number}}",
"address1": "Address 1", "address1": "Address 1",
"address2": "Address 2", "address2": "Address 2",
"appt_alt_transport": "Appointment Alternative Transportation Options", "appt_alt_transport": "Appointment Alternative Transportation Options",
@@ -331,6 +331,9 @@
"md_ded_notes": "Deductible Notes", "md_ded_notes": "Deductible Notes",
"md_email_cc": "Auto Email CC: $t(printcenter.subjects.jobs.{{template}})", "md_email_cc": "Auto Email CC: $t(printcenter.subjects.jobs.{{template}})",
"md_from_emails": "Additional From Emails", "md_from_emails": "Additional From Emails",
"md_functionality_toggles": {
"parts_queue_toggle": "Auto Add Imported/Supplemented Jobs to Parts Queue"
},
"md_hour_split": { "md_hour_split": {
"paint": "Paint Hour Split", "paint": "Paint Hour Split",
"prep": "Prep Hour Split" "prep": "Prep Hour Split"
@@ -353,9 +356,6 @@
}, },
"md_payment_types": "Payment Types", "md_payment_types": "Payment Types",
"md_referral_sources": "Referral Sources", "md_referral_sources": "Referral Sources",
"md_functionality_toggles": {
"parts_queue_toggle": "Auto Add Imported/Supplemented Jobs to Parts Queue"
},
"md_tasks_presets": { "md_tasks_presets": {
"hourstype": "", "hourstype": "",
"memo": "", "memo": "",
@@ -473,6 +473,7 @@
"editaccess": "Users -> Edit access" "editaccess": "Users -> Edit access"
} }
}, },
"ReceivableCustomField": "QBO Receivable Custom Field {{number}}",
"responsibilitycenter": "Responsibility Center", "responsibilitycenter": "Responsibility Center",
"responsibilitycenter_accountdesc": "Account Description", "responsibilitycenter_accountdesc": "Account Description",
"responsibilitycenter_accountitem": "Item", "responsibilitycenter_accountitem": "Item",
@@ -786,6 +787,7 @@
"notes": "Notes", "notes": "Notes",
"plate": "Plate Number", "plate": "Plate Number",
"purchasedate": "Purchase Date", "purchasedate": "Purchase Date",
"readiness": "Readiness",
"registrationexpires": "Registration Expires On", "registrationexpires": "Registration Expires On",
"serviceenddate": "Usage End Date", "serviceenddate": "Usage End Date",
"servicestartdate": "Usage Start Date", "servicestartdate": "Usage Start Date",
@@ -813,6 +815,10 @@
"usage": "Usage", "usage": "Usage",
"vehicle": "Vehicle Description" "vehicle": "Vehicle Description"
}, },
"readiness": {
"notready": "Not Ready",
"ready": "Ready"
},
"status": { "status": {
"in": "Available", "in": "Available",
"inservice": "In Service", "inservice": "In Service",
@@ -832,20 +838,27 @@
"creating": "Error creating survey {{message}}", "creating": "Error creating survey {{message}}",
"notconfigured": "You do not have any current CSI Question Sets configured.", "notconfigured": "You do not have any current CSI Question Sets configured.",
"notfoundsubtitle": "We were unable to find a survey using the link you provided. Please ensure the URL is correct or reach out to your shop for more help.", "notfoundsubtitle": "We were unable to find a survey using the link you provided. Please ensure the URL is correct or reach out to your shop for more help.",
"notfoundtitle": "No survey found." "notfoundtitle": "No survey found.",
"surveycompletetitle": "Survey previously completed",
"surveycompletesubtitle": "This survey was already completed on {{date}}."
}, },
"fields": { "fields": {
"completedon": "Completed On", "completedon": "Completed On",
"created_at": "Created At" "created_at": "Created At",
"surveyid": "Survey ID {{surveyId}}",
"validuntil": "Valid Until"
}, },
"labels": { "labels": {
"nologgedinuser": "Please log out of ImEX Online", "nologgedinuser": "Please log out of $t(titles.app)",
"nologgedinuser_sub": "Users of ImEX Online cannot complete CSI surveys while logged in. Please log out and try again.", "nologgedinuser_sub": "Users of $t(titles.app) cannot complete CSI surveys while logged in. Please log out and try again.",
"noneselected": "No response selected.", "noneselected": "No response selected.",
"title": "Customer Satisfaction Survey" "title": "Customer Satisfaction Survey",
"greeting": "Hi {{name}}!",
"intro": "At {{shopname}}, we value your feedback. We would love to hear what you have to say. Please fill out the form below.",
"copyright": "Copyright © $t(titles.app). All Rights Reserved."
}, },
"successes": { "successes": {
"created": "CSI created successfully. ", "created": "CSI created successfully.",
"submitted": "Your responses have been submitted successfully.", "submitted": "Your responses have been submitted successfully.",
"submittedsub": "Your input is highly appreciated." "submittedsub": "Your input is highly appreciated."
} }
@@ -996,10 +1009,13 @@
}, },
"labels": { "labels": {
"actions": "Actions", "actions": "Actions",
"active": "Active",
"endmustbeafterstart": "End date must be after start date.", "endmustbeafterstart": "End date must be after start date.",
"flat_rate": "Flat Rate", "flat_rate": "Flat Rate",
"inactive": "Inactive",
"name": "Name", "name": "Name",
"rate_type": "Rate Type", "rate_type": "Rate Type",
"status": "Status",
"straight_time": "Straight Time" "straight_time": "Straight Time"
}, },
"successes": { "successes": {
@@ -1205,6 +1221,31 @@
"updated": "Inventory line updated." "updated": "Inventory line updated."
} }
}, },
"job_lifecycle": {
"columns": {
"duration": "Duration",
"end": "End",
"relative_end": "Relative End",
"relative_start": "Relative Start",
"start": "Start",
"value": "Value"
},
"content": {
"current_status_accumulated_time": "Current Status Accumulated Time",
"data_unavailable": " There is currently no Lifecycle data for this Job.",
"legend_title": "Legend",
"loading": "Loading Job Timelines....",
"not_available": "N/A",
"previous_status_accumulated_time": "Previous Status Accumulated Time",
"title": "Job Lifecycle Component",
"title_durations": "Historical Status Durations",
"title_loading": "Loading",
"title_transitions": "Transitions"
},
"errors": {
"fetch": "Error getting Job Lifecycle Data"
}
},
"job_payments": { "job_payments": {
"buttons": { "buttons": {
"goback": "Go Back", "goback": "Go Back",
@@ -1699,6 +1740,7 @@
"estimator": "Estimator", "estimator": "Estimator",
"filehandler": "File Handler", "filehandler": "File Handler",
"insurance": "Insurance Details", "insurance": "Insurance Details",
"more": "More",
"notes": "Notes", "notes": "Notes",
"parts": "Parts", "parts": "Parts",
"totals": "Totals", "totals": "Totals",
@@ -1824,6 +1866,7 @@
}, },
"reconciliationheader": "Parts & Sublet Reconciliation", "reconciliationheader": "Parts & Sublet Reconciliation",
"relatedros": "Related ROs", "relatedros": "Related ROs",
"remove_from_ar": "Remove from AR",
"returntotals": "Return Totals", "returntotals": "Return Totals",
"rosaletotal": "RO Parts Total", "rosaletotal": "RO Parts Total",
"sale_additional": "Sales - Additional", "sale_additional": "Sales - Additional",
@@ -2003,6 +2046,7 @@
"general": "General", "general": "General",
"insurance": "Insurance Information", "insurance": "Insurance Information",
"labor": "Labor", "labor": "Labor",
"lifecycle": "Lifecycle",
"partssublet": "Parts & Bills", "partssublet": "Parts & Bills",
"rates": "Rates", "rates": "Rates",
"repairdata": "Repair Data", "repairdata": "Repair Data",
@@ -2019,7 +2063,7 @@
"joblookup": "Job Lookup", "joblookup": "Job Lookup",
"login": "Login", "login": "Login",
"logout": "Logout", "logout": "Logout",
"productionboard": "Production Board - Visual", "productionboard": "Production Visual",
"productionlist": "Production List", "productionlist": "Production List",
"shiftclockin": "Shift Clock" "shiftclockin": "Shift Clock"
} }
@@ -2554,6 +2598,7 @@
}, },
"templates": { "templates": {
"anticipated_revenue": "Anticipated Revenue", "anticipated_revenue": "Anticipated Revenue",
"ar_aging": "AR Aging",
"attendance_detail": "Attendance (All Employees)", "attendance_detail": "Attendance (All Employees)",
"attendance_employee": "Employee Attendance", "attendance_employee": "Employee Attendance",
"attendance_summary": "Attendance Summary (All Employees)", "attendance_summary": "Attendance Summary (All Employees)",
@@ -2616,6 +2661,7 @@
"open_orders": "Open Orders by Date", "open_orders": "Open Orders by Date",
"open_orders_csr": "Open Orders by CSR", "open_orders_csr": "Open Orders by CSR",
"open_orders_estimator": "Open Orders by Estimator", "open_orders_estimator": "Open Orders by Estimator",
"open_orders_excel": "Open Orders - Excel",
"open_orders_ins_co": "Open Orders by Insurance Company", "open_orders_ins_co": "Open Orders by Insurance Company",
"open_orders_referral": "Open Orders by Referral Source", "open_orders_referral": "Open Orders by Referral Source",
"open_orders_specific_csr": "Open Orders filtered by CSR", "open_orders_specific_csr": "Open Orders filtered by CSR",
@@ -2896,7 +2942,7 @@
"parts-queue": "Parts Queue | $t(titles.app)", "parts-queue": "Parts Queue | $t(titles.app)",
"payments-all": "Payments | $t(titles.app)", "payments-all": "Payments | $t(titles.app)",
"phonebook": "Phonebook | $t(titles.app)", "phonebook": "Phonebook | $t(titles.app)",
"productionboard": "Production - Board", "productionboard": "Production Board - Visual | $t(titles.app)",
"productionlist": "Production Board - List | $t(titles.app)", "productionlist": "Production Board - List | $t(titles.app)",
"profile": "My Profile | $t(titles.app)", "profile": "My Profile | $t(titles.app)",
"readyjobs": "Ready Jobs | $t(titles.app)", "readyjobs": "Ready Jobs | $t(titles.app)",
@@ -2908,6 +2954,10 @@
"shop-csi": "CSI Responses | $t(titles.app)", "shop-csi": "CSI Responses | $t(titles.app)",
"shop-templates": "Shop Templates | $t(titles.app)", "shop-templates": "Shop Templates | $t(titles.app)",
"shop_vendors": "Vendors | $t(titles.app)", "shop_vendors": "Vendors | $t(titles.app)",
"techconsole": "Technician Console | $t(titles.app)",
"techjobclock": "Technician Job Clock | $t(titles.app)",
"techjoblookup": "Technician Job Lookup | $t(titles.app)",
"techshiftclock": "Technician Shift Clock | $t(titles.app)",
"temporarydocs": "Temporary Documents | $t(titles.app)", "temporarydocs": "Temporary Documents | $t(titles.app)",
"timetickets": "Time Tickets | $t(titles.app)", "timetickets": "Time Tickets | $t(titles.app)",
"ttapprovals": "", "ttapprovals": "",

View File

@@ -99,6 +99,7 @@
}, },
"audit_trail": { "audit_trail": {
"messages": { "messages": {
"admin_job_remove_from_ar": "",
"admin_jobmarkexported": "", "admin_jobmarkexported": "",
"admin_jobmarkforreexport": "", "admin_jobmarkforreexport": "",
"admin_jobuninvoice": "", "admin_jobuninvoice": "",
@@ -112,11 +113,11 @@
"jobassignmentchange": "", "jobassignmentchange": "",
"jobassignmentremoved": "", "jobassignmentremoved": "",
"jobchecklist": "", "jobchecklist": "",
"jobinvoiced": "",
"jobconverted": "", "jobconverted": "",
"jobfieldchanged": "", "jobfieldchanged": "",
"jobimported": "", "jobimported": "",
"jobinproductionchange": "", "jobinproductionchange": "",
"jobinvoiced": "",
"jobioucreated": "", "jobioucreated": "",
"jobmodifylbradj": "", "jobmodifylbradj": "",
"jobnoteadded": "", "jobnoteadded": "",
@@ -254,13 +255,9 @@
"saving": "" "saving": ""
}, },
"fields": { "fields": {
"ReceivableCustomField": "",
"address1": "", "address1": "",
"address2": "", "address2": "",
"appt_alt_transport": "", "appt_alt_transport": "",
"md_functionality_toggles": {
"parts_queue_toggle": ""
},
"appt_colors": { "appt_colors": {
"color": "", "color": "",
"label": "" "label": ""
@@ -334,6 +331,9 @@
"md_ded_notes": "", "md_ded_notes": "",
"md_email_cc": "", "md_email_cc": "",
"md_from_emails": "", "md_from_emails": "",
"md_functionality_toggles": {
"parts_queue_toggle": ""
},
"md_hour_split": { "md_hour_split": {
"paint": "", "paint": "",
"prep": "" "prep": ""
@@ -473,6 +473,7 @@
"editaccess": "" "editaccess": ""
} }
}, },
"ReceivableCustomField": "",
"responsibilitycenter": "", "responsibilitycenter": "",
"responsibilitycenter_accountdesc": "", "responsibilitycenter_accountdesc": "",
"responsibilitycenter_accountitem": "", "responsibilitycenter_accountitem": "",
@@ -786,6 +787,7 @@
"notes": "", "notes": "",
"plate": "", "plate": "",
"purchasedate": "", "purchasedate": "",
"readiness": "",
"registrationexpires": "", "registrationexpires": "",
"serviceenddate": "", "serviceenddate": "",
"servicestartdate": "", "servicestartdate": "",
@@ -813,6 +815,10 @@
"usage": "", "usage": "",
"vehicle": "" "vehicle": ""
}, },
"readiness": {
"notready": "",
"ready": ""
},
"status": { "status": {
"in": "", "in": "",
"inservice": "", "inservice": "",
@@ -832,17 +838,24 @@
"creating": "", "creating": "",
"notconfigured": "", "notconfigured": "",
"notfoundsubtitle": "", "notfoundsubtitle": "",
"notfoundtitle": "" "notfoundtitle": "",
"surveycompletetitle": "",
"surveycompletesubtitle": ""
}, },
"fields": { "fields": {
"completedon": "", "completedon": "",
"created_at": "" "created_at": "",
"surveyid": "",
"validuntil": ""
}, },
"labels": { "labels": {
"nologgedinuser": "", "nologgedinuser": "",
"nologgedinuser_sub": "", "nologgedinuser_sub": "",
"noneselected": "", "noneselected": "",
"title": "" "title": "",
"greeting": "",
"intro": "",
"copyright": ""
}, },
"successes": { "successes": {
"created": "", "created": "",
@@ -996,10 +1009,13 @@
}, },
"labels": { "labels": {
"actions": "", "actions": "",
"active": "",
"endmustbeafterstart": "", "endmustbeafterstart": "",
"flat_rate": "", "flat_rate": "",
"inactive": "",
"name": "", "name": "",
"rate_type": "", "rate_type": "",
"status": "",
"straight_time": "" "straight_time": ""
}, },
"successes": { "successes": {
@@ -1205,6 +1221,31 @@
"updated": "" "updated": ""
} }
}, },
"job_lifecycle": {
"columns": {
"duration": "",
"end": "",
"relative_end": "",
"relative_start": "",
"start": "",
"value": ""
},
"content": {
"current_status_accumulated_time": "",
"data_unavailable": "",
"legend_title": "",
"loading": "",
"not_available": "",
"previous_status_accumulated_time": "",
"title": "",
"title_durations": "",
"title_loading": "",
"title_transitions": ""
},
"errors": {
"fetch": "Error al obtener los datos del ciclo de vida del trabajo"
}
},
"job_payments": { "job_payments": {
"buttons": { "buttons": {
"goback": "", "goback": "",
@@ -1699,6 +1740,7 @@
"estimator": "Estimador", "estimator": "Estimador",
"filehandler": "File Handler", "filehandler": "File Handler",
"insurance": "detalles del seguro", "insurance": "detalles del seguro",
"more": "Más",
"notes": "Notas", "notes": "Notas",
"parts": "Partes", "parts": "Partes",
"totals": "Totales", "totals": "Totales",
@@ -1824,6 +1866,7 @@
}, },
"reconciliationheader": "", "reconciliationheader": "",
"relatedros": "", "relatedros": "",
"remove_from_ar": "",
"returntotals": "", "returntotals": "",
"rosaletotal": "", "rosaletotal": "",
"sale_additional": "", "sale_additional": "",
@@ -2003,6 +2046,7 @@
"general": "", "general": "",
"insurance": "", "insurance": "",
"labor": "Labor", "labor": "Labor",
"lifecycle": "",
"partssublet": "Piezas / Subarrendamiento", "partssublet": "Piezas / Subarrendamiento",
"rates": "", "rates": "",
"repairdata": "Datos de reparación", "repairdata": "Datos de reparación",
@@ -2554,6 +2598,7 @@
}, },
"templates": { "templates": {
"anticipated_revenue": "", "anticipated_revenue": "",
"ar_aging": "",
"attendance_detail": "", "attendance_detail": "",
"attendance_employee": "", "attendance_employee": "",
"attendance_summary": "", "attendance_summary": "",
@@ -2616,6 +2661,7 @@
"open_orders": "", "open_orders": "",
"open_orders_csr": "", "open_orders_csr": "",
"open_orders_estimator": "", "open_orders_estimator": "",
"open_orders_excel": "",
"open_orders_ins_co": "", "open_orders_ins_co": "",
"open_orders_referral": "", "open_orders_referral": "",
"open_orders_specific_csr": "", "open_orders_specific_csr": "",
@@ -2889,7 +2935,7 @@
"jobs-intake": "", "jobs-intake": "",
"jobsavailable": "Empleos disponibles | $t(titles.app)", "jobsavailable": "Empleos disponibles | $t(titles.app)",
"jobsdetail": "Trabajo {{ro_number}} | $t(titles.app)", "jobsdetail": "Trabajo {{ro_number}} | $t(titles.app)",
"jobsdocuments": "Documentos de trabajo {{ro_number}} | $ t (títulos.app)", "jobsdocuments": "Documentos de trabajo {{ro_number}} | $t(titles.app)",
"manageroot": "Casa | $t(titles.app)", "manageroot": "Casa | $t(titles.app)",
"owners": "Todos los propietarios | $t(titles.app)", "owners": "Todos los propietarios | $t(titles.app)",
"owners-detail": "", "owners-detail": "",
@@ -2908,6 +2954,10 @@
"shop-csi": "", "shop-csi": "",
"shop-templates": "", "shop-templates": "",
"shop_vendors": "Vendedores | $t(titles.app)", "shop_vendors": "Vendedores | $t(titles.app)",
"techconsole": "$t(titles.app)",
"techjobclock": "$t(titles.app)",
"techjoblookup": "$t(titles.app)",
"techshiftclock": "$t(titles.app)",
"temporarydocs": "", "temporarydocs": "",
"timetickets": "", "timetickets": "",
"ttapprovals": "", "ttapprovals": "",

View File

@@ -99,6 +99,7 @@
}, },
"audit_trail": { "audit_trail": {
"messages": { "messages": {
"admin_job_remove_from_ar": "",
"admin_jobmarkexported": "", "admin_jobmarkexported": "",
"admin_jobmarkforreexport": "", "admin_jobmarkforreexport": "",
"admin_jobuninvoice": "", "admin_jobuninvoice": "",
@@ -112,11 +113,11 @@
"jobassignmentchange": "", "jobassignmentchange": "",
"jobassignmentremoved": "", "jobassignmentremoved": "",
"jobchecklist": "", "jobchecklist": "",
"jobinvoiced": "",
"jobconverted": "", "jobconverted": "",
"jobfieldchanged": "", "jobfieldchanged": "",
"jobimported": "", "jobimported": "",
"jobinproductionchange": "", "jobinproductionchange": "",
"jobinvoiced": "",
"jobioucreated": "", "jobioucreated": "",
"jobmodifylbradj": "", "jobmodifylbradj": "",
"jobnoteadded": "", "jobnoteadded": "",
@@ -254,7 +255,6 @@
"saving": "" "saving": ""
}, },
"fields": { "fields": {
"ReceivableCustomField": "",
"address1": "", "address1": "",
"address2": "", "address2": "",
"appt_alt_transport": "", "appt_alt_transport": "",
@@ -331,13 +331,13 @@
"md_ded_notes": "", "md_ded_notes": "",
"md_email_cc": "", "md_email_cc": "",
"md_from_emails": "", "md_from_emails": "",
"md_functionality_toggles": {
"parts_queue_toggle": ""
},
"md_hour_split": { "md_hour_split": {
"paint": "", "paint": "",
"prep": "" "prep": ""
}, },
"md_functionality_toggles": {
"parts_queue_toggle": ""
},
"md_ins_co": { "md_ins_co": {
"city": "", "city": "",
"name": "", "name": "",
@@ -473,6 +473,7 @@
"editaccess": "" "editaccess": ""
} }
}, },
"ReceivableCustomField": "",
"responsibilitycenter": "", "responsibilitycenter": "",
"responsibilitycenter_accountdesc": "", "responsibilitycenter_accountdesc": "",
"responsibilitycenter_accountitem": "", "responsibilitycenter_accountitem": "",
@@ -786,6 +787,7 @@
"notes": "", "notes": "",
"plate": "", "plate": "",
"purchasedate": "", "purchasedate": "",
"readiness": "",
"registrationexpires": "", "registrationexpires": "",
"serviceenddate": "", "serviceenddate": "",
"servicestartdate": "", "servicestartdate": "",
@@ -813,6 +815,10 @@
"usage": "", "usage": "",
"vehicle": "" "vehicle": ""
}, },
"readiness": {
"notready": "",
"ready": ""
},
"status": { "status": {
"in": "", "in": "",
"inservice": "", "inservice": "",
@@ -832,17 +838,24 @@
"creating": "", "creating": "",
"notconfigured": "", "notconfigured": "",
"notfoundsubtitle": "", "notfoundsubtitle": "",
"notfoundtitle": "" "notfoundtitle": "",
"surveycompletetitle": "",
"surveycompletesubtitle": ""
}, },
"fields": { "fields": {
"completedon": "", "completedon": "",
"created_at": "" "created_at": "",
"surveyid": "",
"validuntil": ""
}, },
"labels": { "labels": {
"nologgedinuser": "", "nologgedinuser": "",
"nologgedinuser_sub": "", "nologgedinuser_sub": "",
"noneselected": "", "noneselected": "",
"title": "" "title": "",
"greeting": "",
"intro": "",
"copyright": ""
}, },
"successes": { "successes": {
"created": "", "created": "",
@@ -996,10 +1009,13 @@
}, },
"labels": { "labels": {
"actions": "", "actions": "",
"active": "",
"endmustbeafterstart": "", "endmustbeafterstart": "",
"flat_rate": "", "flat_rate": "",
"inactive": "",
"name": "", "name": "",
"rate_type": "", "rate_type": "",
"status": "",
"straight_time": "" "straight_time": ""
}, },
"successes": { "successes": {
@@ -1205,6 +1221,31 @@
"updated": "" "updated": ""
} }
}, },
"job_lifecycle": {
"columns": {
"duration": "",
"end": "",
"relative_end": "",
"relative_start": "",
"start": "",
"value": ""
},
"content": {
"current_status_accumulated_time": "",
"data_unavailable": "",
"legend_title": "",
"loading": "",
"not_available": "",
"previous_status_accumulated_time": "",
"title": "",
"title_durations": "",
"title_loading": "",
"title_transitions": ""
},
"errors": {
"fetch": "Erreur lors de l'obtention des données du cycle de vie des tâches"
}
},
"job_payments": { "job_payments": {
"buttons": { "buttons": {
"goback": "", "goback": "",
@@ -1699,6 +1740,7 @@
"estimator": "Estimateur", "estimator": "Estimateur",
"filehandler": "Gestionnaire de fichiers", "filehandler": "Gestionnaire de fichiers",
"insurance": "Détails de l'assurance", "insurance": "Détails de l'assurance",
"more": "Plus",
"notes": "Remarques", "notes": "Remarques",
"parts": "les pièces", "parts": "les pièces",
"totals": "Totaux", "totals": "Totaux",
@@ -1824,6 +1866,7 @@
}, },
"reconciliationheader": "", "reconciliationheader": "",
"relatedros": "", "relatedros": "",
"remove_from_ar": "",
"returntotals": "", "returntotals": "",
"rosaletotal": "", "rosaletotal": "",
"sale_additional": "", "sale_additional": "",
@@ -2003,6 +2046,7 @@
"general": "", "general": "",
"insurance": "", "insurance": "",
"labor": "La main d'oeuvre", "labor": "La main d'oeuvre",
"lifecycle": "",
"partssublet": "Pièces / Sous-location", "partssublet": "Pièces / Sous-location",
"rates": "", "rates": "",
"repairdata": "Données de réparation", "repairdata": "Données de réparation",
@@ -2554,6 +2598,7 @@
}, },
"templates": { "templates": {
"anticipated_revenue": "", "anticipated_revenue": "",
"ar_aging": "",
"attendance_detail": "", "attendance_detail": "",
"attendance_employee": "", "attendance_employee": "",
"attendance_summary": "", "attendance_summary": "",
@@ -2616,6 +2661,7 @@
"open_orders": "", "open_orders": "",
"open_orders_csr": "", "open_orders_csr": "",
"open_orders_estimator": "", "open_orders_estimator": "",
"open_orders_excel": "",
"open_orders_ins_co": "", "open_orders_ins_co": "",
"open_orders_referral": "", "open_orders_referral": "",
"open_orders_specific_csr": "", "open_orders_specific_csr": "",
@@ -2889,7 +2935,7 @@
"jobs-intake": "", "jobs-intake": "",
"jobsavailable": "Emplois disponibles | $t(titles.app)", "jobsavailable": "Emplois disponibles | $t(titles.app)",
"jobsdetail": "Travail {{ro_number}} | $t(titles.app)", "jobsdetail": "Travail {{ro_number}} | $t(titles.app)",
"jobsdocuments": "Documents de travail {{ro_number}} | $ t (titres.app)", "jobsdocuments": "Documents de travail {{ro_number}} | $t(titles.app)",
"manageroot": "Accueil | $t(titles.app)", "manageroot": "Accueil | $t(titles.app)",
"owners": "Tous les propriétaires | $t(titles.app)", "owners": "Tous les propriétaires | $t(titles.app)",
"owners-detail": "", "owners-detail": "",
@@ -2908,6 +2954,10 @@
"shop-csi": "", "shop-csi": "",
"shop-templates": "", "shop-templates": "",
"shop_vendors": "Vendeurs | $t(titles.app)", "shop_vendors": "Vendeurs | $t(titles.app)",
"techconsole": "$t(titles.app)",
"techjobclock": "$t(titles.app)",
"techjoblookup": "$t(titles.app)",
"techshiftclock": "$t(titles.app)",
"temporarydocs": "", "temporarydocs": "",
"timetickets": "", "timetickets": "",
"ttapprovals": "", "ttapprovals": "",

View File

@@ -1,54 +1,56 @@
import i18n from "i18next"; import i18n from "i18next";
const AuditTrailMapping = { const AuditTrailMapping = {
alertToggle: (status) => i18n.t("audit_trail.messages.alerttoggle", { status }), admin_job_remove_from_ar: (status) =>
i18n.t("audit_trail.messages.admin_job_remove_from_ar", { status }),
admin_jobfieldchange: (field, value) =>
"ADMIN: " +
i18n.t("audit_trail.messages.jobfieldchanged", { field, value }),
admin_jobmarkexported: () =>
i18n.t("audit_trail.messages.admin_jobmarkexported"),
admin_jobmarkforreexport: () =>
i18n.t("audit_trail.messages.admin_jobmarkforreexport"),
admin_jobstatuschange: (status) =>
"ADMIN: " + i18n.t("audit_trail.messages.jobstatuschange", { status }),
admin_jobuninvoice: () => i18n.t("audit_trail.messages.admin_jobuninvoice"),
admin_jobunvoid: () => i18n.t("audit_trail.messages.admin_jobunvoid"),
alertToggle: (status) =>
i18n.t("audit_trail.messages.alerttoggle", { status }),
appointmentcancel: (lost_sale_reason) => appointmentcancel: (lost_sale_reason) =>
i18n.t("audit_trail.messages.appointmentcancel", { lost_sale_reason }), i18n.t("audit_trail.messages.appointmentcancel", { lost_sale_reason }),
appointmentinsert: (start) => appointmentinsert: (start) =>
i18n.t("audit_trail.messages.appointmentinsert", { start }), i18n.t("audit_trail.messages.appointmentinsert", { start }),
jobstatuschange: (status) =>
i18n.t("audit_trail.messages.jobstatuschange", { status }),
admin_jobstatuschange: (status) =>
"ADMIN: " + i18n.t("audit_trail.messages.jobstatuschange", { status }),
jobsupplement: () => i18n.t("audit_trail.messages.jobsupplement"),
jobimported: () => i18n.t("audit_trail.messages.jobimported"),
jobinvoiced: () =>
i18n.t("audit_trail.messages.jobinvoiced"),
jobconverted: (ro_number) =>
i18n.t("audit_trail.messages.jobconverted", { ro_number }),
jobfieldchange: (field, value) =>
i18n.t("audit_trail.messages.jobfieldchanged", { field, value }),
admin_jobfieldchange: (field, value) =>
"ADMIN: " +
i18n.t("audit_trail.messages.jobfieldchanged", { field, value }),
jobspartsorder: (order_number) =>
i18n.t("audit_trail.messages.jobspartsorder", { order_number }),
jobspartsreturn: (order_number) =>
i18n.t("audit_trail.messages.jobspartsreturn", { order_number }),
jobmodifylbradj: ({ mod_lbr_ty, hours }) =>
i18n.t("audit_trail.messages.jobmodifylbradj", { mod_lbr_ty, hours }),
billposted: (invoice_number) => billposted: (invoice_number) =>
i18n.t("audit_trail.messages.billposted", { invoice_number }), i18n.t("audit_trail.messages.billposted", { invoice_number }),
billupdated: (invoice_number) => billupdated: (invoice_number) =>
i18n.t("audit_trail.messages.billupdated", { invoice_number }), i18n.t("audit_trail.messages.billupdated", { invoice_number }),
failedpayment: () => i18n.t("audit_trail.messages.failedpayment"),
jobassignmentchange: (operation, name) => jobassignmentchange: (operation, name) =>
i18n.t("audit_trail.messages.jobassignmentchange", { operation, name }), i18n.t("audit_trail.messages.jobassignmentchange", { operation, name }),
jobassignmentremoved: (operation) => jobassignmentremoved: (operation) =>
i18n.t("audit_trail.messages.jobassignmentremoved", { operation }), i18n.t("audit_trail.messages.jobassignmentremoved", { operation }),
jobinproductionchange: (inproduction) =>
i18n.t("audit_trail.messages.jobinproductionchange", { inproduction }),
jobchecklist: (type, inproduction, status) => jobchecklist: (type, inproduction, status) =>
i18n.t("audit_trail.messages.jobchecklist", { type, inproduction, status }), i18n.t("audit_trail.messages.jobchecklist", { type, inproduction, status }),
jobconverted: (ro_number) =>
i18n.t("audit_trail.messages.jobconverted", { ro_number }),
jobfieldchange: (field, value) =>
i18n.t("audit_trail.messages.jobfieldchanged", { field, value }),
jobimported: () => i18n.t("audit_trail.messages.jobimported"),
jobinproductionchange: (inproduction) =>
i18n.t("audit_trail.messages.jobinproductionchange", { inproduction }),
jobinvoiced: () => i18n.t("audit_trail.messages.jobinvoiced"),
jobmodifylbradj: ({ mod_lbr_ty, hours }) =>
i18n.t("audit_trail.messages.jobmodifylbradj", { mod_lbr_ty, hours }),
jobnoteadded: () => i18n.t("audit_trail.messages.jobnoteadded"), jobnoteadded: () => i18n.t("audit_trail.messages.jobnoteadded"),
jobnoteupdated: () => i18n.t("audit_trail.messages.jobnoteupdated"),
jobnotedeleted: () => i18n.t("audit_trail.messages.jobnotedeleted"), jobnotedeleted: () => i18n.t("audit_trail.messages.jobnotedeleted"),
admin_jobunvoid: () => i18n.t("audit_trail.messages.admin_jobunvoid"), jobnoteupdated: () => i18n.t("audit_trail.messages.jobnoteupdated"),
admin_jobuninvoice: () => i18n.t("audit_trail.messages.admin_jobuninvoice"), jobspartsorder: (order_number) =>
admin_jobmarkforreexport: () => i18n.t("audit_trail.messages.jobspartsorder", { order_number }),
i18n.t("audit_trail.messages.admin_jobmarkforreexport"), jobspartsreturn: (order_number) =>
admin_jobmarkexported: () => i18n.t("audit_trail.messages.jobspartsreturn", { order_number }),
i18n.t("audit_trail.messages.admin_jobmarkexported"), jobstatuschange: (status) =>
failedpayment: () => i18n.t("audit_trail.messages.failedpayment"), i18n.t("audit_trail.messages.jobstatuschange", { status }),
jobsupplement: () => i18n.t("audit_trail.messages.jobsupplement"),
}; };
export default AuditTrailMapping; export default AuditTrailMapping;

View File

@@ -17,6 +17,9 @@ export function DateTimeFormatter(props) {
) )
: null; : null;
} }
export function DateTimeFormatterFunction(date) {
return moment(date).format("MM/DD/YYYY hh:mm a");
}
export function TimeFormatter(props) { export function TimeFormatter(props) {
return props.children return props.children
? moment(props.children).format(props.format ? props.format : "hh:mm a") ? moment(props.children).format(props.format ? props.format : "hh:mm a")

View File

@@ -12,6 +12,8 @@ import apolloLogger from "apollo-link-logger";
//import axios from "axios"; //import axios from "axios";
import { auth } from "../firebase/firebase.utils"; import { auth } from "../firebase/firebase.utils";
import errorLink from "../graphql/apollo-error-handling"; import errorLink from "../graphql/apollo-error-handling";
import { SentryLink } from "apollo-link-sentry";
//import { store } from "../redux/store"; //import { store } from "../redux/store";
const httpLink = new HttpLink({ const httpLink = new HttpLink({
uri: process.env.REACT_APP_GRAPHQL_ENDPOINT, uri: process.env.REACT_APP_GRAPHQL_ENDPOINT,
@@ -105,18 +107,30 @@ const link = split(
const authLink = setContext((_, { headers }) => { const authLink = setContext((_, { headers }) => {
return ( return (
auth.currentUser && auth.currentUser &&
auth.currentUser.getIdToken().then((token) => { auth.currentUser
if (token) { .getIdToken()
return { .then((token) => {
headers: { if (token) {
...headers, return {
authorization: token ? `Bearer ${token}` : "", headers: {
}, ...headers,
}; authorization: token ? `Bearer ${token}` : "",
} else { },
};
} else {
console.error(
"Authentication error. Unable to add authorization token because it was empty."
);
return { headers };
}
})
.catch((error) => {
console.error(
"Authentication error. Unable to add authorization token.",
error.message
);
return { headers }; return { headers };
} })
})
); );
}); });
@@ -138,8 +152,10 @@ if (process.env.NODE_ENV === "development") {
} }
middlewares.push( middlewares.push(
roundTripLink.concat( new SentryLink().concat(
retryLink.concat(errorLink.concat(authLink.concat(link))) roundTripLink.concat(
retryLink.concat(errorLink.concat(authLink.concat(link)))
)
) )
); );

View File

@@ -2026,6 +2026,28 @@ export const TemplateList = (type, context) => {
}, },
group: "customers", group: "customers",
}, },
open_orders_excel: {
title: i18n.t("reportcenter.templates.open_orders_excel"),
subject: i18n.t("reportcenter.templates.open_orders_excel"),
key: "open_orders_excel",
//idtype: "vendor",
reporttype: "excel",
disabled: false,
rangeFilter: {
object: i18n.t("reportcenter.labels.objects.jobs"),
field: i18n.t("jobs.fields.date_open"),
},
group: "jobs",
},
ar_aging: {
title: i18n.t("reportcenter.templates.ar_aging"),
subject: i18n.t("reportcenter.templates.ar_aging"),
key: "ar_aging",
//idtype: "vendor",
disabled: false,
datedisable: true,
group: "customers",
},
} }
: {}), : {}),
...(!type || type === "courtesycarcontract" ...(!type || type === "courtesycarcontract"

View File

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

View File

@@ -53,7 +53,7 @@
jsonpointer "^5.0.0" jsonpointer "^5.0.0"
leven "^3.1.0" leven "^3.1.0"
"@apollo/client@^3.0.0", "@apollo/client@^3.7.9": "@apollo/client@^3.7.9":
version "3.7.9" version "3.7.9"
resolved "https://registry.npmjs.org/@apollo/client/-/client-3.7.9.tgz" resolved "https://registry.npmjs.org/@apollo/client/-/client-3.7.9.tgz"
integrity sha512-YnJvrJOVWrp4y/zdNvUaM8q4GuSHCEIecsRDTJhK/veT33P/B7lfqGJ24NeLdKMj8tDEuXYF7V0t+th4+rgC+Q== integrity sha512-YnJvrJOVWrp4y/zdNvUaM8q4GuSHCEIecsRDTJhK/veT33P/B7lfqGJ24NeLdKMj8tDEuXYF7V0t+th4+rgC+Q==
@@ -96,7 +96,7 @@
resolved "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.21.0.tgz" resolved "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.21.0.tgz"
integrity sha512-gMuZsmsgxk/ENC3O/fRw5QY8A9/uxQbbCEypnLIiYYc/qVJtEV7ouxC3EllIIwNzMqAQee5tanFabWsUOutS7g== integrity sha512-gMuZsmsgxk/ENC3O/fRw5QY8A9/uxQbbCEypnLIiYYc/qVJtEV7ouxC3EllIIwNzMqAQee5tanFabWsUOutS7g==
"@babel/core@^7.0.0", "@babel/core@^7.0.0-0", "@babel/core@^7.1.0", "@babel/core@^7.12.0", "@babel/core@^7.12.3", "@babel/core@^7.13.0", "@babel/core@^7.16.0", "@babel/core@^7.4.0-0", "@babel/core@^7.8.0", "@babel/core@>=7.11.0": "@babel/core@^7.1.0", "@babel/core@^7.12.3", "@babel/core@^7.16.0":
version "7.18.9" version "7.18.9"
resolved "https://registry.npmjs.org/@babel/core/-/core-7.18.9.tgz" resolved "https://registry.npmjs.org/@babel/core/-/core-7.18.9.tgz"
integrity sha512-1LIb1eL8APMy91/IMW+31ckrfBM4yCoLaVzoDhZUKSM4cu1L1nIidyxkCgzPAgrC5WEz36IPEr/eSeSF9pIn+g== integrity sha512-1LIb1eL8APMy91/IMW+31ckrfBM4yCoLaVzoDhZUKSM4cu1L1nIidyxkCgzPAgrC5WEz36IPEr/eSeSF9pIn+g==
@@ -159,6 +159,27 @@
json5 "^2.2.2" json5 "^2.2.2"
semver "^6.3.0" semver "^6.3.0"
"@babel/core@^7.8.0":
version "7.21.0"
resolved "https://registry.npmjs.org/@babel/core/-/core-7.21.0.tgz"
integrity sha512-PuxUbxcW6ZYe656yL3EAhpy7qXKq0DmYsrJLpbB8XrsCP9Nm+XCg9XFMb5vIDliPD7+U/+M+QJlH17XOcB7eXA==
dependencies:
"@ampproject/remapping" "^2.2.0"
"@babel/code-frame" "^7.18.6"
"@babel/generator" "^7.21.0"
"@babel/helper-compilation-targets" "^7.20.7"
"@babel/helper-module-transforms" "^7.21.0"
"@babel/helpers" "^7.21.0"
"@babel/parser" "^7.21.0"
"@babel/template" "^7.20.7"
"@babel/traverse" "^7.21.0"
"@babel/types" "^7.21.0"
convert-source-map "^1.7.0"
debug "^4.1.0"
gensync "^1.0.0-beta.2"
json5 "^2.2.2"
semver "^6.3.0"
"@babel/eslint-parser@^7.16.3": "@babel/eslint-parser@^7.16.3":
version "7.19.1" version "7.19.1"
resolved "https://registry.npmjs.org/@babel/eslint-parser/-/eslint-parser-7.19.1.tgz" resolved "https://registry.npmjs.org/@babel/eslint-parser/-/eslint-parser-7.19.1.tgz"
@@ -729,7 +750,7 @@
dependencies: dependencies:
"@babel/helper-plugin-utils" "^7.8.3" "@babel/helper-plugin-utils" "^7.8.3"
"@babel/plugin-syntax-flow@^7.14.5", "@babel/plugin-syntax-flow@^7.18.6": "@babel/plugin-syntax-flow@^7.18.6":
version "7.18.6" version "7.18.6"
resolved "https://registry.npmjs.org/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.18.6.tgz" resolved "https://registry.npmjs.org/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.18.6.tgz"
integrity sha512-LUbR+KNTBWCUAqRG9ex5Gnzu2IOkt8jRJbHHXFT9q+L9zm7M/QQbEqXyw1n1pohYvOyWC8CjeyjrSaIwiYjK7A== integrity sha512-LUbR+KNTBWCUAqRG9ex5Gnzu2IOkt8jRJbHHXFT9q+L9zm7M/QQbEqXyw1n1pohYvOyWC8CjeyjrSaIwiYjK7A==
@@ -1127,7 +1148,7 @@
dependencies: dependencies:
"@babel/plugin-transform-react-jsx" "^7.18.6" "@babel/plugin-transform-react-jsx" "^7.18.6"
"@babel/plugin-transform-react-jsx@^7.14.9", "@babel/plugin-transform-react-jsx@^7.18.6": "@babel/plugin-transform-react-jsx@^7.18.6":
version "7.18.6" version "7.18.6"
resolved "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.18.6.tgz" resolved "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.18.6.tgz"
integrity sha512-Mz7xMPxoy9kPS/JScj6fJs03TZ/fZ1dJPlMjRAgTaxaS0fUBk8FV/A2rRgfPsVCZqALNwMexD+0Uaf5zlcKPpw== integrity sha512-Mz7xMPxoy9kPS/JScj6fJs03TZ/fZ1dJPlMjRAgTaxaS0fUBk8FV/A2rRgfPsVCZqALNwMexD+0Uaf5zlcKPpw==
@@ -1568,7 +1589,7 @@
resolved "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz" resolved "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz"
integrity sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ== integrity sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==
"@craco/craco@^6.0.0", "@craco/craco@^7.0.0": "@craco/craco@^7.0.0":
version "7.0.0" version "7.0.0"
resolved "https://registry.npmjs.org/@craco/craco/-/craco-7.0.0.tgz" resolved "https://registry.npmjs.org/@craco/craco/-/craco-7.0.0.tgz"
integrity sha512-OyjL9zpURB6Ha1HO62Hlt27Xd7UYJ8DRiBNuE4DBB8Ue0iQ9q/xsv3ze7ROm6gCZqV6I2Gxjnq0EHCCye+4xDQ== integrity sha512-OyjL9zpURB6Ha1HO62Hlt27Xd7UYJ8DRiBNuE4DBB8Ue0iQ9q/xsv3ze7ROm6gCZqV6I2Gxjnq0EHCCye+4xDQ==
@@ -1844,7 +1865,7 @@
"@firebase/util" "1.9.2" "@firebase/util" "1.9.2"
tslib "^2.1.0" tslib "^2.1.0"
"@firebase/app-compat@0.2.3", "@firebase/app-compat@0.x": "@firebase/app-compat@0.2.3":
version "0.2.3" version "0.2.3"
resolved "https://registry.npmjs.org/@firebase/app-compat/-/app-compat-0.2.3.tgz" resolved "https://registry.npmjs.org/@firebase/app-compat/-/app-compat-0.2.3.tgz"
integrity sha512-sX6rD1KFX6K2CuCnQvc9jZLOgAFZ+sv2jKKahIl4SbTM561D682B8n4Jtx/SgDrvcTVTdb05g4NhZOws9hxYxA== integrity sha512-sX6rD1KFX6K2CuCnQvc9jZLOgAFZ+sv2jKKahIl4SbTM561D682B8n4Jtx/SgDrvcTVTdb05g4NhZOws9hxYxA==
@@ -1855,12 +1876,12 @@
"@firebase/util" "1.9.2" "@firebase/util" "1.9.2"
tslib "^2.1.0" tslib "^2.1.0"
"@firebase/app-types@0.9.0", "@firebase/app-types@0.x": "@firebase/app-types@0.9.0":
version "0.9.0" version "0.9.0"
resolved "https://registry.npmjs.org/@firebase/app-types/-/app-types-0.9.0.tgz" resolved "https://registry.npmjs.org/@firebase/app-types/-/app-types-0.9.0.tgz"
integrity sha512-AeweANOIo0Mb8GiYm3xhTEBVCmPwTYAu9Hcd2qSkLuga/6+j9b1Jskl5bpiSQWy9eJ/j5pavxj6eYogmnuzm+Q== integrity sha512-AeweANOIo0Mb8GiYm3xhTEBVCmPwTYAu9Hcd2qSkLuga/6+j9b1Jskl5bpiSQWy9eJ/j5pavxj6eYogmnuzm+Q==
"@firebase/app@0.9.3", "@firebase/app@0.x": "@firebase/app@0.9.3":
version "0.9.3" version "0.9.3"
resolved "https://registry.npmjs.org/@firebase/app/-/app-0.9.3.tgz" resolved "https://registry.npmjs.org/@firebase/app/-/app-0.9.3.tgz"
integrity sha512-G79JUceVDaHRZ4WkA11GyVldVXhdyRJRwWVQFFvAAVfQJLvy2TA6lQjeUn28F6FmeUWxDGwPC30bxCRWq7Op8Q== integrity sha512-G79JUceVDaHRZ4WkA11GyVldVXhdyRJRwWVQFFvAAVfQJLvy2TA6lQjeUn28F6FmeUWxDGwPC30bxCRWq7Op8Q==
@@ -2145,7 +2166,7 @@
node-fetch "2.6.7" node-fetch "2.6.7"
tslib "^2.1.0" tslib "^2.1.0"
"@firebase/util@1.9.2", "@firebase/util@1.x": "@firebase/util@1.9.2":
version "1.9.2" version "1.9.2"
resolved "https://registry.npmjs.org/@firebase/util/-/util-1.9.2.tgz" resolved "https://registry.npmjs.org/@firebase/util/-/util-1.9.2.tgz"
integrity sha512-9l0uMGPGw3GsoD5khjMmYCCcMq/OR/OOSViiWMN+s2Q0pxM+fYzrii1H+r8qC/uoMjSVXomjLZt0vZIyryCqtQ== integrity sha512-9l0uMGPGw3GsoD5khjMmYCCcMq/OR/OOSViiWMN+s2Q0pxM+fYzrii1H+r8qC/uoMjSVXomjLZt0vZIyryCqtQ==
@@ -3050,7 +3071,7 @@
resolved "https://registry.npmjs.org/@types/aria-query/-/aria-query-4.2.2.tgz" resolved "https://registry.npmjs.org/@types/aria-query/-/aria-query-4.2.2.tgz"
integrity sha512-HnYpAE1Y6kRyKM/XkEuiRQhTHvkzMBurTHnpFLYLBGPIylZNPs9jJcuOOYWxPLJCSEtmZT0Y8rHDokKN7rRTig== integrity sha512-HnYpAE1Y6kRyKM/XkEuiRQhTHvkzMBurTHnpFLYLBGPIylZNPs9jJcuOOYWxPLJCSEtmZT0Y8rHDokKN7rRTig==
"@types/babel__core@^7.0.0", "@types/babel__core@^7.1.12", "@types/babel__core@^7.1.9": "@types/babel__core@^7.0.0", "@types/babel__core@^7.1.12":
version "7.1.19" version "7.1.19"
resolved "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.19.tgz" resolved "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.19.tgz"
integrity sha512-WEOTgRsbYkvA/KCsDwVEGkd7WAr1e3g31VHQ8zy5gul/V1qKullU/BU5I68X5v7V3GnB9eotmom4v5a5gjxorw== integrity sha512-WEOTgRsbYkvA/KCsDwVEGkd7WAr1e3g31VHQ8zy5gul/V1qKullU/BU5I68X5v7V3GnB9eotmom4v5a5gjxorw==
@@ -3358,7 +3379,7 @@
hoist-non-react-statics "^3.3.0" hoist-non-react-statics "^3.3.0"
redux "^4.0.0" redux "^4.0.0"
"@types/react@*", "@types/react@^16.8 || ^17.0 || ^18.0", "@types/react@>=16.9.11": "@types/react@*", "@types/react@>=16.9.11":
version "18.0.15" version "18.0.15"
resolved "https://registry.npmjs.org/@types/react/-/react-18.0.15.tgz" resolved "https://registry.npmjs.org/@types/react/-/react-18.0.15.tgz"
integrity sha512-iz3BtLuIYH1uWdsv6wXYdhozhqj20oD4/Hk2DNXIn1kFsmp9x8d9QB6FnPhfkbhd2PgEONt9Q1x/ebkwjfFLow== integrity sha512-iz3BtLuIYH1uWdsv6wXYdhozhqj20oD4/Hk2DNXIn1kFsmp9x8d9QB6FnPhfkbhd2PgEONt9Q1x/ebkwjfFLow==
@@ -3474,7 +3495,7 @@
dependencies: dependencies:
"@types/node" "*" "@types/node" "*"
"@typescript-eslint/eslint-plugin@^4.0.0 || ^5.0.0", "@typescript-eslint/eslint-plugin@^5.5.0": "@typescript-eslint/eslint-plugin@^5.5.0":
version "5.54.0" version "5.54.0"
resolved "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.54.0.tgz" resolved "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.54.0.tgz"
integrity sha512-+hSN9BdSr629RF02d7mMtXhAJvDTyCbprNYJKrXETlul/Aml6YZwd90XioVbjejQeHbb3R8Dg0CkRgoJDxo8aw== integrity sha512-+hSN9BdSr629RF02d7mMtXhAJvDTyCbprNYJKrXETlul/Aml6YZwd90XioVbjejQeHbb3R8Dg0CkRgoJDxo8aw==
@@ -3497,7 +3518,7 @@
dependencies: dependencies:
"@typescript-eslint/utils" "5.54.0" "@typescript-eslint/utils" "5.54.0"
"@typescript-eslint/parser@^5.0.0", "@typescript-eslint/parser@^5.5.0": "@typescript-eslint/parser@^5.5.0":
version "5.54.0" version "5.54.0"
resolved "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.54.0.tgz" resolved "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.54.0.tgz"
integrity sha512-aAVL3Mu2qTi+h/r04WI/5PfNWvO6pdhpeMRWk9R7rEV4mwJNzoWf5CCU5vDKBsPIFQFjEq1xg7XBI2rjiMXQbQ== integrity sha512-aAVL3Mu2qTi+h/r04WI/5PfNWvO6pdhpeMRWk9R7rEV4mwJNzoWf5CCU5vDKBsPIFQFjEq1xg7XBI2rjiMXQbQ==
@@ -3779,11 +3800,6 @@ acorn-walk@^8.1.1:
resolved "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz" resolved "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz"
integrity sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA== integrity sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==
"acorn@^6.0.0 || ^7.0.0 || ^8.0.0", acorn@^8, acorn@^8.2.4, acorn@^8.4.1, acorn@^8.5.0, acorn@^8.7.1, acorn@^8.8.0:
version "8.8.2"
resolved "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz"
integrity sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==
acorn@^7.0.0: acorn@^7.0.0:
version "7.4.1" version "7.4.1"
resolved "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz" resolved "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz"
@@ -3794,6 +3810,11 @@ acorn@^7.1.1:
resolved "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz" resolved "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz"
integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A== integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==
acorn@^8.2.4, acorn@^8.4.1, acorn@^8.5.0, acorn@^8.7.1, acorn@^8.8.0:
version "8.8.2"
resolved "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz"
integrity sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==
address@^1.0.1, address@^1.1.2: address@^1.0.1, address@^1.1.2:
version "1.2.2" version "1.2.2"
resolved "https://registry.npmjs.org/address/-/address-1.2.2.tgz" resolved "https://registry.npmjs.org/address/-/address-1.2.2.tgz"
@@ -3841,7 +3862,7 @@ ajv-keywords@^5.0.0:
dependencies: dependencies:
fast-deep-equal "^3.1.3" fast-deep-equal "^3.1.3"
ajv@^6.10.0, ajv@^6.12.2, ajv@^6.12.4, ajv@^6.12.5, ajv@^6.12.6, ajv@^6.9.1: ajv@^6.10.0, ajv@^6.12.2, ajv@^6.12.4, ajv@^6.12.5, ajv@^6.12.6:
version "6.12.6" version "6.12.6"
resolved "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz" resolved "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz"
integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==
@@ -3851,7 +3872,7 @@ ajv@^6.10.0, ajv@^6.12.2, ajv@^6.12.4, ajv@^6.12.5, ajv@^6.12.6, ajv@^6.9.1:
json-schema-traverse "^0.4.1" json-schema-traverse "^0.4.1"
uri-js "^4.2.2" uri-js "^4.2.2"
ajv@^8.0.0, ajv@^8.8.0, ajv@^8.8.2: ajv@^8.0.0, ajv@^8.8.0:
version "8.12.0" version "8.12.0"
resolved "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz" resolved "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz"
integrity sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA== integrity sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==
@@ -3861,7 +3882,7 @@ ajv@^8.0.0, ajv@^8.8.0, ajv@^8.8.2:
require-from-string "^2.0.2" require-from-string "^2.0.2"
uri-js "^4.2.2" uri-js "^4.2.2"
ajv@^8.6.0, ajv@>=8: ajv@^8.6.0:
version "8.12.0" version "8.12.0"
resolved "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz" resolved "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz"
integrity sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA== integrity sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==
@@ -4561,7 +4582,7 @@ browser-process-hrtime@^1.0.0:
resolved "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz" resolved "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz"
integrity sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow== integrity sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==
browserslist@^4.0.0, browserslist@^4.14.5, browserslist@^4.18.1, browserslist@^4.20.2, browserslist@^4.21.2, browserslist@^4.21.3, browserslist@^4.21.4, browserslist@^4.21.5, "browserslist@>= 4", "browserslist@>= 4.21.0", browserslist@>=4: browserslist@^4.0.0, browserslist@^4.14.5, browserslist@^4.18.1, browserslist@^4.20.2, browserslist@^4.21.2, browserslist@^4.21.3, browserslist@^4.21.4, browserslist@^4.21.5:
version "4.21.5" version "4.21.5"
resolved "https://registry.npmjs.org/browserslist/-/browserslist-4.21.5.tgz" resolved "https://registry.npmjs.org/browserslist/-/browserslist-4.21.5.tgz"
integrity sha512-tUkiguQGW7S3IhB7N+c2MV/HZPSCPAAiYBZXLsBhFB/PCy6ZKKsZrmBayHV9fdGV/ARIfJ14NkxKzRDjvp7L6w== integrity sha512-tUkiguQGW7S3IhB7N+c2MV/HZPSCPAAiYBZXLsBhFB/PCy6ZKKsZrmBayHV9fdGV/ARIfJ14NkxKzRDjvp7L6w==
@@ -5363,7 +5384,7 @@ cuint@^0.2.2:
resolved "https://registry.npmjs.org/cuint/-/cuint-0.2.2.tgz" resolved "https://registry.npmjs.org/cuint/-/cuint-0.2.2.tgz"
integrity sha512-d4ZVpCW31eWwCMe1YT3ur7mUDnTXbgwyzaL320DrcRT45rfjYxkt5QWLrmOJ+/UEAI2+fQgKe/fCjR8l4TpRgw== integrity sha512-d4ZVpCW31eWwCMe1YT3ur7mUDnTXbgwyzaL320DrcRT45rfjYxkt5QWLrmOJ+/UEAI2+fQgKe/fCjR8l4TpRgw==
cypress@^10.3.1, "cypress@^2.1.0 || ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 || ^9.0.0 || ^10.0.0": cypress@^10.3.1:
version "10.11.0" version "10.11.0"
resolved "https://registry.npmjs.org/cypress/-/cypress-10.11.0.tgz" resolved "https://registry.npmjs.org/cypress/-/cypress-10.11.0.tgz"
integrity sha512-lsaE7dprw5DoXM00skni6W5ElVVLGAdRUUdZjX2dYsGjbY/QnpzWZ95Zom1mkGg0hAaO/QVTZoFVS7Jgr/GUPA== integrity sha512-lsaE7dprw5DoXM00skni6W5ElVVLGAdRUUdZjX2dYsGjbY/QnpzWZ95Zom1mkGg0hAaO/QVTZoFVS7Jgr/GUPA==
@@ -6020,7 +6041,7 @@ enquire.js@^2.1.6:
resolved "https://registry.npmjs.org/enquire.js/-/enquire.js-2.1.6.tgz" resolved "https://registry.npmjs.org/enquire.js/-/enquire.js-2.1.6.tgz"
integrity sha512-/KujNpO+PT63F7Hlpu4h3pE3TokKRHN26JYmQpPyjkRD/N57R7bPDNojMXdi7uveAKjYB7yQnartCxZnFWr0Xw== integrity sha512-/KujNpO+PT63F7Hlpu4h3pE3TokKRHN26JYmQpPyjkRD/N57R7bPDNojMXdi7uveAKjYB7yQnartCxZnFWr0Xw==
enquirer@^2.3.6, "enquirer@>= 2.3.0 < 3": enquirer@^2.3.6:
version "2.3.6" version "2.3.6"
resolved "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz" resolved "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz"
integrity sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg== integrity sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==
@@ -6370,7 +6391,7 @@ eslint-webpack-plugin@^3.1.1:
normalize-path "^3.0.0" normalize-path "^3.0.0"
schema-utils "^4.0.0" schema-utils "^4.0.0"
eslint@*, "eslint@^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8", "eslint@^3 || ^4 || ^5 || ^6 || ^7 || ^8", "eslint@^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0", "eslint@^6.0.0 || ^7.0.0 || ^8.0.0", "eslint@^7.0.0 || ^8.0.0", "eslint@^7.5.0 || ^8.0.0", eslint@^8.0.0, eslint@^8.1.0, eslint@^8.3.0, "eslint@>= 3.2.1", "eslint@>= 6", eslint@>=5: eslint@^8.3.0:
version "8.35.0" version "8.35.0"
resolved "https://registry.npmjs.org/eslint/-/eslint-8.35.0.tgz" resolved "https://registry.npmjs.org/eslint/-/eslint-8.35.0.tgz"
integrity sha512-BxAf1fVL7w+JLRQhWl2pzGeSiGqbWumV4WNvc9Rhp6tiCtm4oHnyPBSEtMGZwrQgudFQ+otqzWoPB7x+hxoWsw== integrity sha512-BxAf1fVL7w+JLRQhWl2pzGeSiGqbWumV4WNvc9Rhp6tiCtm4oHnyPBSEtMGZwrQgudFQ+otqzWoPB7x+hxoWsw==
@@ -7150,7 +7171,7 @@ graphql-tag@^2.12.6:
dependencies: dependencies:
tslib "^2.1.0" tslib "^2.1.0"
"graphql@^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0", "graphql@^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0", "graphql@^14.0.0 || ^15.0.0 || ^16.0.0", "graphql@^15.7.2 || ^16.0.0", graphql@^16.6.0: graphql@^16.6.0:
version "16.6.0" version "16.6.0"
resolved "https://registry.npmjs.org/graphql/-/graphql-16.6.0.tgz" resolved "https://registry.npmjs.org/graphql/-/graphql-16.6.0.tgz"
integrity sha512-KPIBPDlW7NxrbT/eh4qPXz5FiFdL5UbaA0XUNz2Rp3Z3hqBSkbj0GVjwFDztsWVauZUWsbKHgMg++sk8UX0bkw== integrity sha512-KPIBPDlW7NxrbT/eh4qPXz5FiFdL5UbaA0XUNz2Rp3Z3hqBSkbj0GVjwFDztsWVauZUWsbKHgMg++sk8UX0bkw==
@@ -7414,7 +7435,7 @@ i18next-browser-languagedetector@^7.0.1:
dependencies: dependencies:
"@babel/runtime" "^7.19.4" "@babel/runtime" "^7.19.4"
i18next@^22.4.10, "i18next@>= 19.0.0": i18next@^22.4.10:
version "22.4.10" version "22.4.10"
resolved "https://registry.npmjs.org/i18next/-/i18next-22.4.10.tgz" resolved "https://registry.npmjs.org/i18next/-/i18next-22.4.10.tgz"
integrity sha512-3EqgGK6fAJRjnGgfkNSStl4mYLCjUoJID338yVyLMj5APT67HUtWoqSayZewiiC5elzMUB1VEUwcmSCoeQcNEA== integrity sha512-3EqgGK6fAJRjnGgfkNSStl4mYLCjUoJID338yVyLMj5APT67HUtWoqSayZewiiC5elzMUB1VEUwcmSCoeQcNEA==
@@ -8247,7 +8268,7 @@ jest-resolve-dependencies@^27.5.1:
jest-regex-util "^27.5.1" jest-regex-util "^27.5.1"
jest-snapshot "^27.5.1" jest-snapshot "^27.5.1"
jest-resolve@*, jest-resolve@^27.4.2, jest-resolve@^27.5.1: jest-resolve@^27.4.2, jest-resolve@^27.5.1:
version "27.5.1" version "27.5.1"
resolved "https://registry.npmjs.org/jest-resolve/-/jest-resolve-27.5.1.tgz" resolved "https://registry.npmjs.org/jest-resolve/-/jest-resolve-27.5.1.tgz"
integrity sha512-FFDy8/9E6CV83IMbDpcjOhumAQPDyETnU2KZ1O98DwTnz8AOBsW/Xv3GySr1mOZdItLR+zDZ7I/UdTFbgSOVCw== integrity sha512-FFDy8/9E6CV83IMbDpcjOhumAQPDyETnU2KZ1O98DwTnz8AOBsW/Xv3GySr1mOZdItLR+zDZ7I/UdTFbgSOVCw==
@@ -8457,7 +8478,7 @@ jest-worker@^28.0.2:
merge-stream "^2.0.0" merge-stream "^2.0.0"
supports-color "^8.0.0" supports-color "^8.0.0"
"jest@^27.0.0 || ^28.0.0", jest@^27.4.3: jest@^27.4.3:
version "27.5.1" version "27.5.1"
resolved "https://registry.npmjs.org/jest/-/jest-27.5.1.tgz" resolved "https://registry.npmjs.org/jest/-/jest-27.5.1.tgz"
integrity sha512-Yn0mADZB89zTtjkPJEXwrac3LHudkQMR+Paqa8uxJHCBr9agxztUifWCyiYrjhMPBoUVBjyny0I7XH6ozDr7QQ== integrity sha512-Yn0mADZB89zTtjkPJEXwrac3LHudkQMR+Paqa8uxJHCBr9agxztUifWCyiYrjhMPBoUVBjyny0I7XH6ozDr7QQ==
@@ -8724,7 +8745,7 @@ less-loader@^7.3.0:
loader-utils "^2.0.0" loader-utils "^2.0.0"
schema-utils "^3.0.0" schema-utils "^3.0.0"
"less@^3.5.0 || ^4.0.0", less@^4.1.1: less@^4.1.1:
version "4.1.3" version "4.1.3"
resolved "https://registry.npmjs.org/less/-/less-4.1.3.tgz" resolved "https://registry.npmjs.org/less/-/less-4.1.3.tgz"
integrity sha512-w16Xk/Ta9Hhyei0Gpz9m7VS8F28nieJaL/VyShID7cYvP6IL5oHeL6p4TXSDJqZE/lNv0oJ2pGVjJsRkfwm5FA== integrity sha512-w16Xk/Ta9Hhyei0Gpz9m7VS8F28nieJaL/VyShID7cYvP6IL5oHeL6p4TXSDJqZE/lNv0oJ2pGVjJsRkfwm5FA==
@@ -9186,7 +9207,7 @@ moment-timezone@^0.5.40, moment-timezone@^0.5.41:
dependencies: dependencies:
moment "^2.29.4" moment "^2.29.4"
moment@^2.24.0, moment@^2.29.2, moment@^2.29.4, moment@2.x.x: moment@^2.24.0, moment@^2.29.2, moment@^2.29.4:
version "2.29.4" version "2.29.4"
resolved "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz" resolved "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz"
integrity sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w== integrity sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==
@@ -10298,15 +10319,6 @@ postcss-value-parser@^4.0.0, postcss-value-parser@^4.0.2, postcss-value-parser@^
resolved "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz" resolved "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz"
integrity sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ== integrity sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==
"postcss@^7.0.0 || ^8.0.1", postcss@^8, postcss@^8.0.0, postcss@^8.0.3, postcss@^8.0.9, postcss@^8.1.0, postcss@^8.1.4, postcss@^8.2, postcss@^8.2.14, postcss@^8.2.15, postcss@^8.2.2, postcss@^8.3, postcss@^8.3.5, postcss@^8.4, postcss@^8.4.19, postcss@^8.4.21, postcss@^8.4.4, postcss@^8.4.6, "postcss@>= 8", postcss@>=8, postcss@>=8.0.9:
version "8.4.21"
resolved "https://registry.npmjs.org/postcss/-/postcss-8.4.21.tgz"
integrity sha512-tP7u/Sn/dVxK2NnruI4H9BG+x+Wxz6oeZ1cJ8P6G/PZY0IKk4k/63TDsQf2kQq3+qoJeLm2kIBUNlZe3zgb4Zg==
dependencies:
nanoid "^3.3.4"
picocolors "^1.0.0"
source-map-js "^1.0.2"
postcss@^7.0.35: postcss@^7.0.35:
version "7.0.39" version "7.0.39"
resolved "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz" resolved "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz"
@@ -10315,6 +10327,15 @@ postcss@^7.0.35:
picocolors "^0.2.1" picocolors "^0.2.1"
source-map "^0.6.1" source-map "^0.6.1"
postcss@^8.0.9, postcss@^8.3.5, postcss@^8.4.19, postcss@^8.4.4:
version "8.4.21"
resolved "https://registry.npmjs.org/postcss/-/postcss-8.4.21.tgz"
integrity sha512-tP7u/Sn/dVxK2NnruI4H9BG+x+Wxz6oeZ1cJ8P6G/PZY0IKk4k/63TDsQf2kQq3+qoJeLm2kIBUNlZe3zgb4Zg==
dependencies:
nanoid "^3.3.4"
picocolors "^1.0.0"
source-map-js "^1.0.2"
prelude-ls@^1.2.1: prelude-ls@^1.2.1:
version "1.2.1" version "1.2.1"
resolved "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz" resolved "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz"
@@ -10389,7 +10410,7 @@ prompts@^2.0.1, prompts@^2.4.2:
kleur "^3.0.3" kleur "^3.0.3"
sisteransi "^1.0.5" sisteransi "^1.0.5"
prop-types@^15.0.0, prop-types@^15.5.10, prop-types@^15.5.8, prop-types@^15.6.0, prop-types@^15.6.1, prop-types@^15.6.2, prop-types@^15.7.2, prop-types@^15.8.1, prop-types@15.x: prop-types@^15.5.10, prop-types@^15.5.8, prop-types@^15.6.0, prop-types@^15.6.1, prop-types@^15.6.2, prop-types@^15.7.2, prop-types@^15.8.1, prop-types@15.x:
version "15.8.1" version "15.8.1"
resolved "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz" resolved "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz"
integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg== integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==
@@ -11119,7 +11140,7 @@ react-dev-utils@^12.0.1:
strip-ansi "^6.0.1" strip-ansi "^6.0.1"
text-table "^0.2.0" text-table "^0.2.0"
react-dom@*, "react-dom@^0.14 || ^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 || ^18.0.0", "react-dom@^0.14.0 || ^15.0.0 || ^16 || ^17 || ^18", "react-dom@^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0", "react-dom@^15.3.0 || ^16.0.0-alpha", "react-dom@^16.0.0 || ^17.0.0 || ^18.0.0", "react-dom@^16.14.0 || ^17 || ^18", "react-dom@^16.8 || ^17.0 || ^18.0", "react-dom@^16.8.0 || ^17.0.0", "react-dom@^16.8.0 || ^17.0.0 || ^18.0.0", "react-dom@^16.8.5 || ^17.0.0", react-dom@^17.0.2, "react-dom@>= 16.3.0", "react-dom@>= 16.8.0", react-dom@>=15, react-dom@>=15.0.0, react-dom@>=16.0.0, react-dom@>=16.11.0, react-dom@>=16.3.0, react-dom@>=16.9.0, "react-dom@16.x || 17.x": react-dom@^17.0.2:
version "17.0.2" version "17.0.2"
resolved "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz" resolved "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz"
integrity sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA== integrity sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA==
@@ -11191,7 +11212,7 @@ react-intersection-observer@^9.4.3:
resolved "https://registry.npmjs.org/react-intersection-observer/-/react-intersection-observer-9.4.3.tgz" resolved "https://registry.npmjs.org/react-intersection-observer/-/react-intersection-observer-9.4.3.tgz"
integrity sha512-WNRqMQvKpupr6MzecAQI0Pj0+JQong307knLP4g/nBex7kYfIaZsPpXaIhKHR+oV8z+goUbH9e10j6lGRnTzlQ== integrity sha512-WNRqMQvKpupr6MzecAQI0Pj0+JQong307knLP4g/nBex7kYfIaZsPpXaIhKHR+oV8z+goUbH9e10j6lGRnTzlQ==
react-is@^16.10.2, react-is@^16.12.0, react-is@^16.13.1, react-is@^16.6.0, react-is@^16.7.0, "react-is@>= 16.8.0": react-is@^16.10.2, react-is@^16.12.0, react-is@^16.13.1, react-is@^16.6.0, react-is@^16.7.0:
version "16.13.1" version "16.13.1"
resolved "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz" resolved "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz"
integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==
@@ -11271,7 +11292,7 @@ react-redux@^8.0.5:
react-is "^18.0.0" react-is "^18.0.0"
use-sync-external-store "^1.0.0" use-sync-external-store "^1.0.0"
react-refresh@^0.11.0, "react-refresh@>=0.10.0 <1.0.0": react-refresh@^0.11.0:
version "0.11.0" version "0.11.0"
resolved "https://registry.npmjs.org/react-refresh/-/react-refresh-0.11.0.tgz" resolved "https://registry.npmjs.org/react-refresh/-/react-refresh-0.11.0.tgz"
integrity sha512-F27qZr8uUqwhWZboondsPx8tnC3Ct3SxZA3V5WyEvujRyyNv0VYPhoBg1gZ8/MV5tubQp76Trw8lTv9hzRBa+A== integrity sha512-F27qZr8uUqwhWZboondsPx8tnC3Ct3SxZA3V5WyEvujRyyNv0VYPhoBg1gZ8/MV5tubQp76Trw8lTv9hzRBa+A==
@@ -11320,7 +11341,7 @@ react-router@5.3.3:
tiny-invariant "^1.0.2" tiny-invariant "^1.0.2"
tiny-warning "^1.0.0" tiny-warning "^1.0.0"
react-scripts@^5.0.0, react-scripts@^5.0.1: react-scripts@^5.0.1:
version "5.0.1" version "5.0.1"
resolved "https://registry.npmjs.org/react-scripts/-/react-scripts-5.0.1.tgz" resolved "https://registry.npmjs.org/react-scripts/-/react-scripts-5.0.1.tgz"
integrity sha512-8VAmEm/ZAwQzJ+GOMLbBsTdDKOpuZh7RPs0UymvBR2vRk4iZWCskjbFnxqjrzoIvlNNRZ3QJFx6/qDSi6zSnaQ== integrity sha512-8VAmEm/ZAwQzJ+GOMLbBsTdDKOpuZh7RPs0UymvBR2vRk4iZWCskjbFnxqjrzoIvlNNRZ3QJFx6/qDSi6zSnaQ==
@@ -11421,7 +11442,7 @@ react-virtualized@^9.22.3:
prop-types "^15.7.2" prop-types "^15.7.2"
react-lifecycles-compat "^3.0.4" react-lifecycles-compat "^3.0.4"
react@*, "react@^0.14 || ^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 || ^18.0.0", "react@^0.14.0 || ^15.0.0 || ^16 || ^17 || ^18", "react@^0.14.0 || ^15.0.0 || ^16.0.0 || ^17.0.0", "react@^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0", "react@^15.3.0 || ^16.0.0-alpha", "react@^16.0.0 || ^17.0.0 || ^18.0.0", "react@^16.14.0 || ^17 || ^18", "react@^16.8 || ^17.0 || ^18.0", "react@^16.8.0 || ^17.0.0", "react@^16.8.0 || ^17.0.0 || ^18.0.0", "react@^16.8.3 || ^17 || ^18", "react@^16.8.5 || ^17.0.0", react@^17.0.2, "react@>= 16", "react@>= 16.3", "react@>= 16.3.0", "react@>= 16.8.0", react@>=15, react@>=15.0.0, react@>=16.0.0, react@>=16.11.0, react@>=16.14.0, react@>=16.3.0, react@>=16.8.0, react@>=16.9.0, "react@15.x || 16.x || 17.x || 18.x", "react@16.x || 17.x", react@17.0.2: react@^17.0.2:
version "17.0.2" version "17.0.2"
resolved "https://registry.npmjs.org/react/-/react-17.0.2.tgz" resolved "https://registry.npmjs.org/react/-/react-17.0.2.tgz"
integrity sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA== integrity sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==
@@ -11552,7 +11573,7 @@ redux-state-sync@^3.1.4:
dependencies: dependencies:
broadcast-channel "^3.1.0" broadcast-channel "^3.1.0"
redux@^4, redux@^4.0.0, redux@^4.0.4, redux@^4.2.1, redux@>4.0.0: redux@^4.0.0, redux@^4.0.4, redux@^4.2.1:
version "4.2.1" version "4.2.1"
resolved "https://registry.npmjs.org/redux/-/redux-4.2.1.tgz" resolved "https://registry.npmjs.org/redux/-/redux-4.2.1.tgz"
integrity sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w== integrity sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w==
@@ -11818,7 +11839,7 @@ rollup-plugin-terser@^7.0.0:
serialize-javascript "^4.0.0" serialize-javascript "^4.0.0"
terser "^5.0.0" terser "^5.0.0"
"rollup@^1.20.0 || ^2.0.0", rollup@^1.20.0||^2.0.0, rollup@^2.0.0, rollup@^2.43.1: rollup@^2.43.1:
version "2.79.1" version "2.79.1"
resolved "https://registry.npmjs.org/rollup/-/rollup-2.79.1.tgz" resolved "https://registry.npmjs.org/rollup/-/rollup-2.79.1.tgz"
integrity sha512-uKxbd0IhMZOhjAiD5oAFp7BqvkA4Dv47qpOCtaNvng4HBwdbWtdOh8f5nZNuk2rp51PMGk3bzfWu5oayNEuYnw== integrity sha512-uKxbd0IhMZOhjAiD5oAFp7BqvkA4Dv47qpOCtaNvng4HBwdbWtdOh8f5nZNuk2rp51PMGk3bzfWu5oayNEuYnw==
@@ -11886,7 +11907,7 @@ sass-loader@^12.3.0:
klona "^2.0.4" klona "^2.0.4"
neo-async "^2.6.2" neo-async "^2.6.2"
sass@^1.3.0, sass@^1.58.3: sass@^1.58.3:
version "1.58.3" version "1.58.3"
resolved "https://registry.npmjs.org/sass/-/sass-1.58.3.tgz" resolved "https://registry.npmjs.org/sass/-/sass-1.58.3.tgz"
integrity sha512-Q7RaEtYf6BflYrQ+buPudKR26/lH+10EmO9bBqbmPh/KeLqv8bjpTNqxe71ocONqXq+jYiCbpPUmQMS+JJPk4A== integrity sha512-Q7RaEtYf6BflYrQ+buPudKR26/lH+10EmO9bBqbmPh/KeLqv8bjpTNqxe71ocONqXq+jYiCbpPUmQMS+JJPk4A==
@@ -12517,7 +12538,7 @@ style-utils@~0.2.0:
resolved "https://registry.npmjs.org/style-utils/-/style-utils-0.2.1.tgz" resolved "https://registry.npmjs.org/style-utils/-/style-utils-0.2.1.tgz"
integrity sha512-eKRIfWnUSdBqe2ko+qisUwBSlfWpHru89geRqzmScpDhkPW1ksmE04d//nDcXeF+TVK5cnBG90mMmHgxyxXleQ== integrity sha512-eKRIfWnUSdBqe2ko+qisUwBSlfWpHru89geRqzmScpDhkPW1ksmE04d//nDcXeF+TVK5cnBG90mMmHgxyxXleQ==
styled-components@^5.3.6, "styled-components@>= 2": styled-components@^5.3.6:
version "5.3.6" version "5.3.6"
resolved "https://registry.npmjs.org/styled-components/-/styled-components-5.3.6.tgz" resolved "https://registry.npmjs.org/styled-components/-/styled-components-5.3.6.tgz"
integrity sha512-hGTZquGAaTqhGWldX7hhfzjnIYBZ0IXQXkCYdvF1Sq3DsUaLx6+NTHC5Jj1ooM2F68sBiVz3lvhfwQs/S3l6qg== integrity sha512-hGTZquGAaTqhGWldX7hhfzjnIYBZ0IXQXkCYdvF1Sq3DsUaLx6+NTHC5Jj1ooM2F68sBiVz3lvhfwQs/S3l6qg==
@@ -12541,7 +12562,7 @@ stylehacks@^5.1.1:
browserslist "^4.21.4" browserslist "^4.21.4"
postcss-selector-parser "^6.0.4" postcss-selector-parser "^6.0.4"
subscriptions-transport-ws@^0.11.0, "subscriptions-transport-ws@^0.9.0 || ^0.11.0": subscriptions-transport-ws@^0.11.0:
version "0.11.0" version "0.11.0"
resolved "https://registry.npmjs.org/subscriptions-transport-ws/-/subscriptions-transport-ws-0.11.0.tgz" resolved "https://registry.npmjs.org/subscriptions-transport-ws/-/subscriptions-transport-ws-0.11.0.tgz"
integrity sha512-8D4C6DIH5tGiAIpp5I0wD/xRlNiZAPGHygzCe7VzyzUoxHtawzjNAY9SUTXU05/EY2NMY9/9GF0ycizkXr1CWQ== integrity sha512-8D4C6DIH5tGiAIpp5I0wD/xRlNiZAPGHygzCe7VzyzUoxHtawzjNAY9SUTXU05/EY2NMY9/9GF0ycizkXr1CWQ==
@@ -12896,7 +12917,7 @@ ts-invariant@^0.10.3:
dependencies: dependencies:
tslib "^2.1.0" tslib "^2.1.0"
ts-node@^10.7.0, ts-node@>=9.0.0: ts-node@^10.7.0:
version "10.9.1" version "10.9.1"
resolved "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz" resolved "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz"
integrity sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw== integrity sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==
@@ -13007,7 +13028,7 @@ type-fest@^0.16.0:
resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.16.0.tgz" resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.16.0.tgz"
integrity sha512-eaBzG6MxNzEn9kiwvtre90cXaNLkmadMWa1zQMs3XORCXNbsH/OewwbxC5ia9dCxIxnTAsSxXJaa/p5y8DlvJg== integrity sha512-eaBzG6MxNzEn9kiwvtre90cXaNLkmadMWa1zQMs3XORCXNbsH/OewwbxC5ia9dCxIxnTAsSxXJaa/p5y8DlvJg==
type-fest@^0.20.2, "type-fest@>=0.17.0 <4.0.0": type-fest@^0.20.2:
version "0.20.2" version "0.20.2"
resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz" resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz"
integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==
@@ -13060,11 +13081,6 @@ typescript-tuple@^2.2.1:
dependencies: dependencies:
typescript-compare "^0.0.2" typescript-compare "^0.0.2"
"typescript@^3.2.1 || ^4", "typescript@>= 2.7", typescript@>=2.7, "typescript@>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta", typescript@>=3:
version "4.9.5"
resolved "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz"
integrity sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==
unbox-primitive@^1.0.2: unbox-primitive@^1.0.2:
version "1.0.2" version "1.0.2"
resolved "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz" resolved "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz"
@@ -13370,7 +13386,7 @@ webpack-dev-middleware@^5.3.1:
range-parser "^1.2.1" range-parser "^1.2.1"
schema-utils "^4.0.0" schema-utils "^4.0.0"
webpack-dev-server@^4.6.0, "webpack-dev-server@3.x || 4.x": webpack-dev-server@^4.6.0:
version "4.11.1" version "4.11.1"
resolved "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.11.1.tgz" resolved "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.11.1.tgz"
integrity sha512-lILVz9tAUy1zGFwieuaQtYiadImb5M3d+H+L1zDYalYoDl0cksAB1UNyuE5MMWJrG6zR1tXkCP2fitl7yoUJiw== integrity sha512-lILVz9tAUy1zGFwieuaQtYiadImb5M3d+H+L1zDYalYoDl0cksAB1UNyuE5MMWJrG6zR1tXkCP2fitl7yoUJiw==
@@ -13442,7 +13458,7 @@ webpack-sources@^2.2.0:
source-list-map "^2.0.1" source-list-map "^2.0.1"
source-map "^0.6.1" source-map "^0.6.1"
"webpack@^4.0.0 || ^5.0.0", "webpack@^4.37.0 || ^5.0.0", "webpack@^4.4.0 || ^5.9.0", "webpack@^4.44.2 || ^5.47.0", webpack@^5.0.0, webpack@^5.1.0, webpack@^5.20.0, webpack@^5.64.4, "webpack@>= 4", webpack@>=2, "webpack@>=4.43.0 <6.0.0": webpack@^5.64.4:
version "5.75.0" version "5.75.0"
resolved "https://registry.npmjs.org/webpack/-/webpack-5.75.0.tgz" resolved "https://registry.npmjs.org/webpack/-/webpack-5.75.0.tgz"
integrity sha512-piaIaoVJlqMsPtX/+3KTTO6jfvrSYgauFVdt8cr9LTHKmcq/AMd4mhzsiP7ZF/PGRNPGA8336jldh9l2Kt2ogQ== integrity sha512-piaIaoVJlqMsPtX/+3KTTO6jfvrSYgauFVdt8cr9LTHKmcq/AMd4mhzsiP7ZF/PGRNPGA8336jldh9l2Kt2ogQ==

View File

@@ -1,3 +1,6 @@
- function:
name: jobs_ar_summary
schema: public
- function: - function:
name: search_bills name: search_bills
schema: public schema: public

View File

@@ -1388,60 +1388,62 @@
- active: - active:
_eq: true _eq: true
columns: columns:
- id
- created_at
- updated_at
- bodyshopid - bodyshopid
- make
- model
- year
- plate
- color - color
- vin - created_at
- fleetnumber
- purchasedate
- servicestartdate
- serviceenddate
- leaseenddate
- status
- nextservicekm
- nextservicedate
- damage
- notes
- fuel
- registrationexpires
- insuranceexpires
- dailycost - dailycost
- damage
- fleetnumber
- fuel
- id
- insuranceexpires
- leaseenddate
- make
- mileage - mileage
- model
- nextservicedate
- nextservicekm
- notes
- plate
- purchasedate
- readiness
- registrationexpires
- serviceenddate
- servicestartdate
- status
- updated_at
- vin
- year
select_permissions: select_permissions:
- role: user - role: user
permission: permission:
columns: columns:
- bodyshopid
- color
- created_at
- dailycost
- damage
- fleetnumber
- fuel
- id
- insuranceexpires - insuranceexpires
- leaseenddate - leaseenddate
- make
- mileage
- model
- nextservicedate - nextservicedate
- nextservicekm
- notes
- plate
- purchasedate - purchasedate
- readiness
- registrationexpires - registrationexpires
- serviceenddate - serviceenddate
- servicestartdate - servicestartdate
- dailycost
- fuel
- mileage
- nextservicekm
- color
- damage
- fleetnumber
- make
- model
- notes
- plate
- status - status
- updated_at
- vin - vin
- year - year
- created_at
- updated_at
- bodyshopid
- id
filter: filter:
bodyshop: bodyshop:
associations: associations:
@@ -1456,31 +1458,32 @@
- role: user - role: user
permission: permission:
columns: columns:
- bodyshopid
- color
- created_at
- dailycost
- damage
- fleetnumber
- fuel
- id
- insuranceexpires - insuranceexpires
- leaseenddate - leaseenddate
- make
- mileage
- model
- nextservicedate - nextservicedate
- nextservicekm
- notes
- plate
- purchasedate - purchasedate
- readiness
- registrationexpires - registrationexpires
- serviceenddate - serviceenddate
- servicestartdate - servicestartdate
- dailycost
- fuel
- mileage
- nextservicekm
- color
- damage
- fleetnumber
- make
- model
- notes
- plate
- status - status
- updated_at
- vin - vin
- year - year
- created_at
- updated_at
- bodyshopid
- id
filter: filter:
bodyshop: bodyshop:
associations: associations:
@@ -2020,24 +2023,24 @@
- active: - active:
_eq: true _eq: true
columns: columns:
- labor_rates
- percentage
- created_at - created_at
- updated_at
- employeeid - employeeid
- id - id
- labor_rates
- percentage
- teamid - teamid
- updated_at
select_permissions: select_permissions:
- role: user - role: user
permission: permission:
columns: columns:
- labor_rates
- percentage
- created_at - created_at
- updated_at
- employeeid - employeeid
- id - id
- labor_rates
- percentage
- teamid - teamid
- updated_at
filter: filter:
employee_team: employee_team:
bodyshop: bodyshop:
@@ -2052,13 +2055,13 @@
- role: user - role: user
permission: permission:
columns: columns:
- labor_rates
- percentage
- created_at - created_at
- updated_at
- employeeid - employeeid
- id - id
- labor_rates
- percentage
- teamid - teamid
- updated_at
filter: filter:
employee_team: employee_team:
bodyshop: bodyshop:
@@ -2120,21 +2123,23 @@
_eq: true _eq: true
columns: columns:
- active - active
- name
- created_at
- updated_at
- bodyshopid - bodyshopid
- created_at
- id - id
- max_load
- name
- updated_at
select_permissions: select_permissions:
- role: user - role: user
permission: permission:
columns: columns:
- active - active
- name
- created_at
- updated_at
- bodyshopid - bodyshopid
- created_at
- id - id
- max_load
- name
- updated_at
filter: filter:
bodyshop: bodyshop:
associations: associations:
@@ -2150,6 +2155,7 @@
columns: columns:
- active - active
- bodyshopid - bodyshopid
- max_load
- name - name
- updated_at - updated_at
filter: filter:
@@ -2417,6 +2423,73 @@
_eq: X-Hasura-User-Id _eq: X-Hasura-User-Id
- active: - active:
_eq: true _eq: true
- table:
name: eula_acceptances
schema: public
object_relationships:
- name: eula
using:
foreign_key_constraint_on: eulaid
- name: user
using:
foreign_key_constraint_on: useremail
insert_permissions:
- role: user
permission:
check:
user:
authid:
_eq: X-Hasura-User-Id
columns:
- address
- business_name
- date_accepted
- eulaid
- first_name
- last_name
- phone_number
- useremail
select_permissions:
- role: user
permission:
columns:
- address
- business_name
- first_name
- last_name
- phone_number
- useremail
- created_at
- date_accepted
- updated_at
- eulaid
- id
filter:
user:
authid:
_eq: X-Hasura-User-Id
- table:
name: eulas
schema: public
array_relationships:
- name: eula_acceptances
using:
foreign_key_constraint_on:
column: eulaid
table:
name: eula_acceptances
schema: public
select_permissions:
- role: user
permission:
columns:
- id
- created_at
- updated_at
- effective_date
- end_date
- content
filter: {}
- table: - table:
name: exportlog name: exportlog
schema: public schema: public
@@ -2600,6 +2673,34 @@
- table: - table:
name: ioevents name: ioevents
schema: public schema: public
- table:
name: job_ar_schema
schema: public
object_relationships:
- name: job
using:
foreign_key_constraint_on: id
select_permissions:
- role: user
permission:
columns:
- id
- ro_number
- clm_total
- total_payments
- balance
- date_invoiced
- shopid
filter:
job:
bodyshop:
associations:
_and:
- active:
_eq: true
- user:
authid:
_eq: X-Hasura-User-Id
- table: - table:
name: job_conversations name: job_conversations
schema: public schema: public
@@ -3739,6 +3840,7 @@
- referral_source - referral_source
- referral_source_extra - referral_source_extra
- regie_number - regie_number
- remove_from_ar
- ro_number - ro_number
- scheduled_completion - scheduled_completion
- scheduled_delivery - scheduled_delivery
@@ -4020,6 +4122,7 @@
- referral_source - referral_source
- referral_source_extra - referral_source_extra
- regie_number - regie_number
- remove_from_ar
- ro_number - ro_number
- scheduled_completion - scheduled_completion
- scheduled_delivery - scheduled_delivery
@@ -4086,6 +4189,11 @@
- name: job_status_transition - name: job_status_transition
definition: definition:
enable_manual: true enable_manual: true
insert:
columns: '*'
update:
columns:
- status
retry_conf: retry_conf:
interval_sec: 10 interval_sec: 10
num_retries: 0 num_retries: 0
@@ -5882,6 +5990,13 @@
table: table:
name: email_audit_trail name: email_audit_trail
schema: public schema: public
- name: eula_acceptances
using:
foreign_key_constraint_on:
column: useremail
table:
name: eula_acceptances
schema: public
- name: exportlogs - name: exportlogs
using: using:
foreign_key_constraint_on: foreign_key_constraint_on:

View File

@@ -0,0 +1,4 @@
-- Could not auto-generate a down migration.
-- Please write an appropriate down migration for the SQL below:
-- alter table "public"."courtesycars" add column "readiness" text
-- null;

View File

@@ -0,0 +1,2 @@
alter table "public"."courtesycars" add column "readiness" text
null;

View File

@@ -0,0 +1,4 @@
-- Could not auto-generate a down migration.
-- Please write an appropriate down migration for the SQL below:
-- alter table "public"."employee_team_members" add column "max_load" numeric
-- not null default '10000';

View File

@@ -0,0 +1,2 @@
alter table "public"."employee_team_members" add column "max_load" numeric
not null default '10000';

View File

@@ -0,0 +1,3 @@
alter table "public"."employee_team_members" alter column "max_load" set default '10000'::numeric;
alter table "public"."employee_team_members" alter column "max_load" drop not null;
alter table "public"."employee_team_members" add column "max_load" numeric;

View File

@@ -0,0 +1 @@
alter table "public"."employee_team_members" drop column "max_load" cascade;

View File

@@ -0,0 +1,4 @@
-- Could not auto-generate a down migration.
-- Please write an appropriate down migration for the SQL below:
-- alter table "public"."employee_teams" add column "max_load" numeric
-- not null default '10000';

View File

@@ -0,0 +1,2 @@
alter table "public"."employee_teams" add column "max_load" numeric
not null default '10000';

View File

@@ -0,0 +1 @@
DROP TABLE "public"."eulas";

View File

@@ -0,0 +1,18 @@
CREATE TABLE "public"."eulas" ("id" uuid NOT NULL DEFAULT gen_random_uuid(), "created_at" timestamptz NOT NULL DEFAULT now(), "updated_at" timestamptz NOT NULL DEFAULT now(), "effective_date" timestamptz NOT NULL, "end_date" timestamptz, "content" text NOT NULL, PRIMARY KEY ("id") );
CREATE OR REPLACE FUNCTION "public"."set_current_timestamp_updated_at"()
RETURNS TRIGGER AS $$
DECLARE
_new record;
BEGIN
_new := NEW;
_new."updated_at" = NOW();
RETURN _new;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER "set_public_eulas_updated_at"
BEFORE UPDATE ON "public"."eulas"
FOR EACH ROW
EXECUTE PROCEDURE "public"."set_current_timestamp_updated_at"();
COMMENT ON TRIGGER "set_public_eulas_updated_at" ON "public"."eulas"
IS 'trigger to set value of column "updated_at" to current timestamp on row update';
CREATE EXTENSION IF NOT EXISTS pgcrypto;

View File

@@ -0,0 +1 @@
DROP TABLE "public"."eula_acceptances";

View File

@@ -0,0 +1,18 @@
CREATE TABLE "public"."eula_acceptances" ("id" uuid NOT NULL DEFAULT gen_random_uuid(), "created_at" timestamptz NOT NULL DEFAULT now(), "updated_at" timestamptz NOT NULL DEFAULT now(), "eulaid" uuid NOT NULL, "date_accepted" timestamptz NOT NULL, "first_name" text NOT NULL, "last_name" text NOT NULL, "address" text NOT NULL, "phone_number" Text NOT NULL, "buisness_name" Text NOT NULL, "useremail" text NOT NULL, PRIMARY KEY ("id") , FOREIGN KEY ("eulaid") REFERENCES "public"."eulas"("id") ON UPDATE restrict ON DELETE restrict, FOREIGN KEY ("useremail") REFERENCES "public"."users"("email") ON UPDATE restrict ON DELETE restrict);
CREATE OR REPLACE FUNCTION "public"."set_current_timestamp_updated_at"()
RETURNS TRIGGER AS $$
DECLARE
_new record;
BEGIN
_new := NEW;
_new."updated_at" = NOW();
RETURN _new;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER "set_public_eula_acceptances_updated_at"
BEFORE UPDATE ON "public"."eula_acceptances"
FOR EACH ROW
EXECUTE PROCEDURE "public"."set_current_timestamp_updated_at"();
COMMENT ON TRIGGER "set_public_eula_acceptances_updated_at" ON "public"."eula_acceptances"
IS 'trigger to set value of column "updated_at" to current timestamp on row update';
CREATE EXTENSION IF NOT EXISTS pgcrypto;

View File

@@ -0,0 +1,33 @@
-- Could not auto-generate a down migration.
-- Please write an appropriate down migration for the SQL below:
-- CREATE OR REPLACE FUNCTION public.jobs_ar_summary ()
-- RETURNS SETOF jobs
-- LANGUAGE plpgsql
-- STABLE
-- AS $function$
-- BEGIN
--
-- RETURN query
-- select
-- j.id,
-- j.shopid,
-- j.ro_number,
-- j.clm_total,
-- p.total_payments,
-- j.clm_total - p.total_payments as balance
-- from
-- jobs j
-- left join (
-- select
-- p.jobid,
-- sum(p.amount) as total_payments
-- from
-- payments p
-- group by
-- p.jobid
-- ) p on
-- j.id = p.jobid ;
--
--
-- END
-- $function$;

View File

@@ -0,0 +1,31 @@
CREATE OR REPLACE FUNCTION public.jobs_ar_summary ()
RETURNS SETOF jobs
LANGUAGE plpgsql
STABLE
AS $function$
BEGIN
RETURN query
select
j.id,
j.shopid,
j.ro_number,
j.clm_total,
p.total_payments,
j.clm_total - p.total_payments as balance
from
jobs j
left join (
select
p.jobid,
sum(p.amount) as total_payments
from
payments p
group by
p.jobid
) p on
j.id = p.jobid ;
END
$function$;

View File

@@ -0,0 +1 @@
DROP TABLE "public"."job_ar_schema";

View File

@@ -0,0 +1 @@
CREATE TABLE "public"."job_ar_schema" ("id" uuid NOT NULL, "ro_number" text, "clm_total" numeric NOT NULL, "total_payments" numeric NOT NULL DEFAULT 0, "balance" numeric NOT NULL DEFAULT 0, PRIMARY KEY ("id") );

View File

@@ -0,0 +1,34 @@
-- Could not auto-generate a down migration.
-- Please write an appropriate down migration for the SQL below:
-- DROP FUNCTION public.jobs_ar_summary;
--
-- CREATE OR REPLACE FUNCTION public.jobs_ar_summary ()
-- RETURNS SETOF job_ar_schema
-- LANGUAGE plpgsql
-- STABLE
-- AS $function$
-- BEGIN
--
-- RETURN query
-- select
-- j.id,
-- j.ro_number,
-- j.clm_total,
-- p.total_payments,
-- j.clm_total - p.total_payments as balance
-- from
-- jobs j
-- left join (
-- select
-- p.jobid,
-- sum(p.amount) as total_payments
-- from
-- payments p
-- group by
-- p.jobid
-- ) p on
-- j.id = p.jobid ;
--
--
-- END
-- $function$;

View File

@@ -0,0 +1,32 @@
DROP FUNCTION public.jobs_ar_summary;
CREATE OR REPLACE FUNCTION public.jobs_ar_summary ()
RETURNS SETOF job_ar_schema
LANGUAGE plpgsql
STABLE
AS $function$
BEGIN
RETURN query
select
j.id,
j.ro_number,
j.clm_total,
p.total_payments,
j.clm_total - p.total_payments as balance
from
jobs j
left join (
select
p.jobid,
sum(p.amount) as total_payments
from
payments p
group by
p.jobid
) p on
j.id = p.jobid ;
END
$function$;

View File

@@ -0,0 +1,32 @@
-- Could not auto-generate a down migration.
-- Please write an appropriate down migration for the SQL below:
-- CREATE OR REPLACE FUNCTION public.jobs_ar_summary ()
-- RETURNS SETOF job_ar_schema
-- LANGUAGE plpgsql
-- STABLE
-- AS $function$
-- BEGIN
--
-- RETURN query
-- select
-- j.id,
-- j.ro_number,
-- j.clm_total,
-- p.total_payments,
-- j.clm_total - p.total_payments as balance
-- from
-- jobs j
-- left join (
-- select
-- p.jobid,
-- coalesce (sum(p.amount),0) as total_payments
-- from
-- payments p
-- group by
-- p.jobid
-- ) p on
-- j.id = p.jobid ;
--
--
-- END
-- $function$;

View File

@@ -0,0 +1,30 @@
CREATE OR REPLACE FUNCTION public.jobs_ar_summary ()
RETURNS SETOF job_ar_schema
LANGUAGE plpgsql
STABLE
AS $function$
BEGIN
RETURN query
select
j.id,
j.ro_number,
j.clm_total,
p.total_payments,
j.clm_total - p.total_payments as balance
from
jobs j
left join (
select
p.jobid,
coalesce (sum(p.amount),0) as total_payments
from
payments p
group by
p.jobid
) p on
j.id = p.jobid ;
END
$function$;

View File

@@ -0,0 +1,32 @@
-- Could not auto-generate a down migration.
-- Please write an appropriate down migration for the SQL below:
-- CREATE OR REPLACE FUNCTION public.jobs_ar_summary ()
-- RETURNS SETOF job_ar_schema
-- LANGUAGE plpgsql
-- STABLE
-- AS $function$
-- BEGIN
--
-- RETURN query
-- select
-- j.id,
-- j.ro_number,
-- j.clm_total,
-- p.total_payments,
-- j.clm_total - p.total_payments as balance
-- from
-- jobs j
-- left join (
-- select
-- p.jobid,
-- coalesce (sum(p.amount),0) as total_payments
-- from
-- payments p
-- group by
-- p.jobid
-- ) p on
-- j.id = p.jobid ;
--
--
-- END
-- $function$;

View File

@@ -0,0 +1,30 @@
CREATE OR REPLACE FUNCTION public.jobs_ar_summary ()
RETURNS SETOF job_ar_schema
LANGUAGE plpgsql
STABLE
AS $function$
BEGIN
RETURN query
select
j.id,
j.ro_number,
j.clm_total,
p.total_payments,
j.clm_total - p.total_payments as balance
from
jobs j
left join (
select
p.jobid,
coalesce (sum(p.amount),0) as total_payments
from
payments p
group by
p.jobid
) p on
j.id = p.jobid ;
END
$function$;

View File

@@ -0,0 +1,32 @@
-- Could not auto-generate a down migration.
-- Please write an appropriate down migration for the SQL below:
-- CREATE OR REPLACE FUNCTION public.jobs_ar_summary ()
-- RETURNS SETOF job_ar_schema
-- LANGUAGE plpgsql
-- STABLE
-- AS $function$
-- BEGIN
--
-- RETURN query
-- select
-- j.id,
-- j.ro_number,
-- j.clm_total,
-- coalesce (p.total_payments,0) as total_payments,
-- j.clm_total - coalesce (p.total_payments,0) as balance
-- from
-- jobs j
-- left join (
-- select
-- p.jobid,
-- coalesce (sum(p.amount),0) as total_payments
-- from
-- payments p
-- group by
-- p.jobid
-- ) p on
-- j.id = p.jobid ;
--
--
-- END
-- $function$;

View File

@@ -0,0 +1,30 @@
CREATE OR REPLACE FUNCTION public.jobs_ar_summary ()
RETURNS SETOF job_ar_schema
LANGUAGE plpgsql
STABLE
AS $function$
BEGIN
RETURN query
select
j.id,
j.ro_number,
j.clm_total,
coalesce (p.total_payments,0) as total_payments,
j.clm_total - coalesce (p.total_payments,0) as balance
from
jobs j
left join (
select
p.jobid,
coalesce (sum(p.amount),0) as total_payments
from
payments p
group by
p.jobid
) p on
j.id = p.jobid ;
END
$function$;

View File

@@ -0,0 +1,4 @@
-- Could not auto-generate a down migration.
-- Please write an appropriate down migration for the SQL below:
-- alter table "public"."jobs" add column "remove_from_ar" boolean
-- not null default 'false';

View File

@@ -0,0 +1,2 @@
alter table "public"."jobs" add column "remove_from_ar" boolean
not null default 'false';

View File

@@ -0,0 +1,33 @@
-- Could not auto-generate a down migration.
-- Please write an appropriate down migration for the SQL below:
-- CREATE OR REPLACE FUNCTION public.jobs_ar_summary ()
-- RETURNS SETOF job_ar_schema
-- LANGUAGE plpgsql
-- STABLE
-- AS $function$
-- BEGIN
--
-- RETURN query
-- select
-- j.id,
-- j.ro_number,
-- j.clm_total,
-- coalesce (p.total_payments,0) as total_payments,
-- j.clm_total - coalesce (p.total_payments,0) as balance
-- from
-- jobs j
-- left join (
-- select
-- p.jobid,
-- coalesce (sum(p.amount),0) as total_payments
-- from
-- payments p
-- group by
-- p.jobid
-- ) p on
-- j.id = p.jobid
-- where j.remove_from_ar = false;
--
--
-- END
-- $function$;

View File

@@ -0,0 +1,31 @@
CREATE OR REPLACE FUNCTION public.jobs_ar_summary ()
RETURNS SETOF job_ar_schema
LANGUAGE plpgsql
STABLE
AS $function$
BEGIN
RETURN query
select
j.id,
j.ro_number,
j.clm_total,
coalesce (p.total_payments,0) as total_payments,
j.clm_total - coalesce (p.total_payments,0) as balance
from
jobs j
left join (
select
p.jobid,
coalesce (sum(p.amount),0) as total_payments
from
payments p
group by
p.jobid
) p on
j.id = p.jobid
where j.remove_from_ar = false;
END
$function$;

View File

@@ -0,0 +1,4 @@
-- Could not auto-generate a down migration.
-- Please write an appropriate down migration for the SQL below:
-- alter table "public"."job_ar_schema" add column "date_invoiced" timestamptz
-- null;

Some files were not shown because too many files have changed in this diff Show More