Compare commits

...

220 Commits

Author SHA1 Message Date
Allan Carr
b8836c7ae1 Merged in feature/IO-3030-QBO-Payment-Private-Note (pull request #1934)
IO-3030 Null Check memo
2024-11-18 16:40:15 +00:00
Allan Carr
eca31c5618 IO-3030 Null Check memo
Signed-off-by: Allan Carr <allan.carr@thinkimex.com>
2024-11-18 08:42:52 -08:00
Allan Carr
7140b8d585 Merged in feature/IO-3031-Appointment-Schedule-View-Day (pull request #1931)
IO-3031 Appointment Schedule View Day
2024-11-16 01:33:29 +00:00
Allan Carr
5eed8d9809 IO-3031 Appointment Schedule View Day
Signed-off-by: Allan Carr <allan.carr@thinkimex.com>
2024-11-15 17:35:49 -08:00
Allan Carr
f266ee1cfe Merged in feature/IO-3028-Word-Wrap-Line-Description (pull request #1928)
IO-3028 Adjust to TextArea with autoSize
2024-11-15 20:54:44 +00:00
Allan Carr
9550de5131 IO-3028 Adjust to TextArea with autoSize
Signed-off-by: Allan Carr <allan.carr@thinkimex.com>
2024-11-15 12:57:08 -08:00
Patrick Fic
1f76ff882c Remove IO Event Logging. 2024-11-15 11:03:10 -08:00
Patrick Fic
749f73a272 Merged in feature/IO-2920-cash-discounting (pull request #1927)
IO-2920 Update config & totals for discount.
2024-11-15 18:58:54 +00:00
Patrick Fic
9c1774c417 Merge branch 'release/2024-11-15' into feature/IO-2920-cash-discounting 2024-11-15 10:58:22 -08:00
Allan Carr
26b3a43ce5 Merge branch 'feature/IO-3027-Datapumps-Refactor' into release/2024-11-15
Signed-off-by: Allan Carr <allan.carr@thinkimex.com>

# Conflicts:
#	.vscode/settings.json
2024-11-15 10:05:08 -08:00
Allan Carr
78678dd3dc IO-3027 Datapumps Refactor
Signed-off-by: Allan Carr <allan.carr@thinkimex.com>
2024-11-15 10:04:03 -08:00
Allan Carr
9dc4546b2e Merged in feature/IO-3033-Total-Loss-Indicator (pull request #1925)
IO-3033 Total Loss Indicator

Approved-by: Dave Richer
2024-11-15 17:47:56 +00:00
Allan Carr
95aa0e45a6 IO-3033 Total Loss Indicator
Signed-off-by: Allan Carr <allan.carr@thinkimex.com>
2024-11-14 16:47:35 -08:00
Allan Carr
ce9a77efcf IO-3027 Datapumps Refactor
Signed-off-by: Allan Carr <allan.carr@thinkimex.com>
2024-11-14 16:15:17 -08:00
Dave Richer
e9e1e820a7 release/2024-11-15 - Expose S3 client through createS3Client
Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-11-14 11:57:40 -08:00
Allan Carr
b027a4e618 IO-3031 Adjust prop
Signed-off-by: Allan Carr <allan.carr@thinkimex.com>
2024-11-14 11:52:47 -08:00
Allan Carr
c7fc75aa5c Merged in feature/IO-3031-Appointment-Schedule-View-Day (pull request #1922)
IO-3031 View Day when Scheduling

Approved-by: Dave Richer
2024-11-14 19:50:34 +00:00
Allan Carr
98d2372daf Merged in feature/IO-3030-QBO-Payment-Private-Note (pull request #1920)
IO-3030 QBO Payment Private Note

Approved-by: Dave Richer
2024-11-14 19:40:20 +00:00
Allan Carr
bf51380167 IO-3031 View Day when Scheduling
Signed-off-by: Allan Carr <allan.carr@thinkimex.com>
2024-11-14 11:19:09 -08:00
Dave Richer
1ec827097f Merged in feature/IO-3029-Enhanced-Logging-File-Based (pull request #1921)
feature/IO-3029-Enhanced-Logging-File-Based: Adjust XML and JSON log to always upload
2024-11-14 18:55:57 +00:00
Dave Richer
89fabf85e1 feature/IO-3029-Enhanced-Logging-File-Based: Adjust XML and JSON log to always upload
Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-11-14 10:55:14 -08:00
Allan Carr
ff7dd7d3ea IO-3030 QBO Payment Private Note
Signed-off-by: Allan Carr <allan.carr@thinkimex.com>
2024-11-14 10:37:08 -08:00
Dave Richer
8cc4f88fa7 Merged in feature/IO-3029-Enhanced-Logging-File-Based (pull request #1918)
feature/IO-3029-Enhanced-Logging-File-Based: Final Enhancements
2024-11-14 16:36:13 +00:00
Dave Richer
2439755f9e feature/IO-3029-Enhanced-Logging-File-Based: Final Enhancements
Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-11-14 08:34:21 -08:00
Dave Richer
7e6ab3a5ff Merged in feature/IO-3029-Enhanced-Logging-File-Based (pull request #1916)
feature/IO-3029-Enhanced-Logging-File-Based: Update Stream Key name
2024-11-14 04:14:54 +00:00
Dave Richer
763384f05f feature/IO-3029-Enhanced-Logging-File-Based: Update Stream Key name
Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-11-13 20:14:17 -08:00
Dave Richer
34f876f838 Merged in feature/IO-3029-Enhanced-Logging-File-Based (pull request #1914)
feature/IO-3029-Enhanced-Logging-File-Based: Add File based S3 Logging.
2024-11-14 03:57:24 +00:00
Dave Richer
cba2da8da7 feature/IO-3029-Enhanced-Logging-File-Based: Add fix bugs
Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-11-13 13:09:37 -08:00
Dave Richer
f3d8aa3438 feature/IO-3029-Enhanced-Logging-File-Based: Add File based S3 Logging.
Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-11-13 12:59:56 -08:00
Allan Carr
2f3eccf3d8 Merged in feature/IO-3028-Word-Wrap-Line-Description (pull request #1912)
IO-3028 Extend to Notes
2024-11-13 18:50:32 +00:00
Allan Carr
2b3e64d607 IO-3028 Extend to Notes
Signed-off-by: Allan Carr <allan.carr@thinkimex.com>
2024-11-13 10:49:47 -08:00
Allan Carr
05b20505bb Merged in feature/IO-3028-Word-Wrap-Line-Description (pull request #1910)
IO-3028 Word Wrap Line Description

Approved-by: Dave Richer
2024-11-13 18:17:34 +00:00
Allan Carr
bddeae945c IO-3028 Word Wrap Line Description
Signed-off-by: Allan Carr <allan.carr@thinkimex.com>
2024-11-13 10:06:01 -08:00
Patrick Fic
5b267f03b9 Add additional GIN indexes for db. 2024-11-12 20:21:43 -08:00
Dave Richer
357d916e0a Merged in release/2024-11-15 (pull request #1908)
[DO NOT MERGE] - Release/2024 11 15

Approved-by: Patrick Fic
2024-11-13 00:30:22 +00:00
Dave Richer
6ed12ebe7d Merged in feature/IO-3026-Enhanced-Notifications (pull request #1909)
feature/IO-3026-Enhanced-Notifications - final revisions
2024-11-12 22:52:13 +00:00
Dave Richer
6703bc025d feature/IO-3026-Enhanced-Notifications - final revisions
Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-11-12 14:51:50 -08:00
Dave Richer
387dac6779 Merged in feature/IO-3026-Enhanced-Notifications (pull request #1906)
Feature/IO-3026 Enhanced Notifications
2024-11-12 22:23:35 +00:00
Dave Richer
6f454dd4cb feature/IO-3026-Enhanced-Notifications - final revisions
Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-11-12 14:20:49 -08:00
Dave Richer
1440a60228 feature/IO-3026-Enhanced-Notifications - Initial commit
Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-11-12 12:31:46 -08:00
Allan Carr
f2aa3960aa Merged in release/2024-11-08 (pull request #1905)
Release/2024 11 08 IO-2921 IO-3025
2024-11-09 08:37:27 +00:00
Allan Carr
06508f3ad8 Merged in feature/IO-2921-CARSTAR-Canada-Chatter-Integration (pull request #1903)
Feature/IO-2921 CARSTAR Canada Chatter Integration
2024-11-09 08:33:32 +00:00
Allan Carr
8d4195b596 IO-2921 Adjust SFTP setup
Signed-off-by: Allan Carr <allan.carr@thinkimex.com>
2024-11-09 00:35:18 -08:00
Allan Carr
9e190e7fb7 Merged in feature/IO-3025-Autohouse-Datapump-Refactor (pull request #1902)
IO-3025 Adjust for promise and change processing
2024-11-09 08:32:49 +00:00
Allan Carr
5cbf00b0c8 IO-3025 Adjust for promise and change processing
Signed-off-by: Allan Carr <allan.carr@thinkimex.com>
2024-11-09 00:32:51 -08:00
Allan Carr
655aeb86fc IO-2921 Adjust for Promise and change processing
Signed-off-by: Allan Carr <allan.carr@thinkimex.com>
2024-11-08 23:43:18 -08:00
Allan Carr
225549275d Merged in release/2024-11-08 (pull request #1901)
Release/2024 11 08 IO-2921 IO-3025
2024-11-09 06:33:14 +00:00
Allan Carr
f0717b8b36 IO-2921 Shift Email outside of Batch
Signed-off-by: Allan Carr <allan.carr@thinkimex.com>
2024-11-08 22:30:22 -08:00
Allan Carr
78771ae750 IO-3025 Shift Email send to outside of batch
Signed-off-by: Allan Carr <allan.carr@thinkimex.com>
2024-11-08 22:28:02 -08:00
Allan Carr
0389908398 Merged in feature/IO-2921-CARSTAR-Canada-Chatter-Integration (pull request #1899)
IO-2921 Shift Email outside of Batch
2024-11-09 06:27:57 +00:00
Allan Carr
54bee763df Merged in feature/IO-3025-Autohouse-Datapump-Refactor (pull request #1898)
IO-3025 Shift Email send to outside of batch
2024-11-09 06:25:39 +00:00
Dave Richer
1117a94930 Merged in release/2024-11-08 (pull request #1897)
release/2024-11-08 - Small fix to font script
2024-11-09 05:21:03 +00:00
Dave Richer
5fbfb992c7 release/2024-11-08 - Small fix to font script
Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-11-08 21:18:58 -08:00
Dave Richer
87b3b65f3e Merged in release/2024-11-08 (pull request #1893)
Release/2024-11-08 into master-AIO - IO-2921, IO-2969, IO-3001, IO-3015, IO-3017, IO-3018, IO-3025

Approved-by: Allan Carr
2024-11-09 04:52:01 +00:00
Allan Carr
9970190909 Merged in feature/IO-3025-Autohouse-Datapump-Refactor (pull request #1894)
IO-3025 Autohouse Datapump Refactor
2024-11-09 03:31:37 +00:00
Allan Carr
8eee371a90 IO-3025 Autohouse Datapump Refactor
Signed-off-by: Allan Carr <allan.carr@thinkimex.com>
2024-11-08 19:30:33 -08:00
Dave Richer
ba97b1efef Merged in feature/IO-3015-addl-prod-indexes (pull request #1891)
Feature/IO-3015 addl prod indexes
2024-11-08 17:57:47 +00:00
Allan Carr
8d8887c28e Merged in feature/IO-3017-Lifecycle-Average-Time (pull request #1889)
IO-3017 Lifecycle Average Time

Approved-by: Dave Richer
2024-11-08 17:33:31 +00:00
Dave Richer
3b19432974 feature/IO-3017-Lifecycle-Average-Time - Small fixes
Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-11-08 09:32:58 -08:00
Allan Carr
a14b2340b0 IO-3017 Lifecycle NaN prevention
Signed-off-by: Allan Carr <allan.carr@thinkimex.com>
2024-11-08 09:24:58 -08:00
Allan Carr
624f8e77cb IO-3017 Lifecycle Average Time
Signed-off-by: Allan Carr <allan.carr@thinkimex.com>
2024-11-07 13:56:53 -08:00
Dave Richer
fb624c817d Merged in feature/IO-2969-Fonts-For-Production (pull request #1888)
Feature/IO-2969 Fonts For Production into release
2024-11-07 20:42:26 +00:00
Dave Richer
c2b4b66ed1 hotfix/IO-2969-Fonts-For-Production
Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-11-07 12:40:13 -08:00
Dave Richer
ffec03ab6c Merge remote-tracking branch 'origin/master-AIO' into hotfix/IO-2969-Fonts-For-Production 2024-11-07 12:37:01 -08:00
Allan Carr
552163d7b9 IO-2921 Upload directory
Signed-off-by: Allan Carr <allan.carr@thinkimex.com>
2024-11-06 15:53:51 -08:00
Allan Carr
db1f59578c Merged in feature/IO-2921-CARSTAR-Canada-Chatter-Integration (pull request #1887)
IO-2921 Re-factor as batch and get docker compose dev working for sftp testing

Approved-by: Dave Richer
2024-11-06 23:51:46 +00:00
Allan Carr
8ec5831ec5 IO-2921 Re-factor as batch and get docker compose dev working for sftp testing
Signed-off-by: Allan Carr <allan.carr@thinkimex.com>
2024-11-06 15:42:14 -08:00
Allan Carr
0146ac5b7b Merged in feature/IO-3018-QBO-Standarize-name (pull request #1886)
IO-3018 QBO Standardize name

Approved-by: Dave Richer
2024-11-06 16:37:47 +00:00
Allan Carr
a603e5c0b8 Merged in feature/IO-2921-CARSTAR-Canada-Chatter-Integration (pull request #1885)
IO-2921 Adjustment for SFTP Private Key

Approved-by: Dave Richer
2024-11-06 16:36:52 +00:00
Patrick Fic
9aab47d8f8 IO-2920 Update config & totals for discount. 2024-11-05 16:37:21 -08:00
Patrick Fic
f2f84e2da8 Merge branch 'master-AIO' into feature/IO-2920-cash-discounting 2024-11-05 16:00:47 -08:00
Allan Carr
338906e288 IO-3018 QBO Standardize name
Trim StandardizeName

Signed-off-by: Allan Carr <allan.carr@thinkimex.com>
2024-11-05 11:53:42 -08:00
Allan Carr
542997b1a7 IO-2921 Adjustment for SFTP Private Key
Signed-off-by: Allan Carr <allan.carr@thinkimex.com>
2024-11-05 11:02:18 -08:00
Dave Richer
5fce548666 Merged in release/2024-11-01 (pull request #1884)
Release/2024-11-01 into master-AIO - IO-2921, IO-3006, IO-3008, IO-3009, IO-3010
2024-11-02 15:14:06 +00:00
Dave Richer
80322caad0 release/2024-11-01 - Update Trigger for job_updated - Make the callback work with old and new Hasura
Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-11-02 08:11:22 -07:00
Patrick Fic
56472d24d9 IO-3015 add additional indexs. 2024-11-01 21:33:03 -07:00
Patrick Fic
db5dcc271d IO-30015 add new indexes to production. 2024-11-01 20:35:44 -07:00
Allan Carr
73ab02225e IO-2921 Adjustment to getting Secret
Signed-off-by: Allan Carr <allan.carr@thinkimex.com>
2024-11-01 17:55:33 -07:00
Allan Carr
83a1b7690d Merged in feature/IO-2921-CARSTAR-Canada-Chatter-Integration (pull request #1881)
IO-2921 Adjustment to getting Secret
2024-11-02 00:54:56 +00:00
Allan Carr
c9e28b1ed2 Merge branch 'master-AIO' into feature/IO-2921-CARSTAR-Canada-Chatter-Integration
Signed-off-by: Allan Carr <allan.carr@thinkimex.com>
2024-11-01 17:52:54 -07:00
Allan Carr
c25c66d00f Merged in feature/IO-3009-Clear-Dates (pull request #1879)
IO-3009 Correction for nulls
2024-11-01 17:16:23 +00:00
Allan Carr
d319ab49d4 IO-3009 Correction for nulls
Signed-off-by: Allan Carr <allan.carr@thinkimex.com>
2024-11-01 10:18:14 -07:00
Allan Carr
a069989ea7 Merged in feature/IO-3014-Timeticket-UI-Sort (pull request #1876)
IO-3014 Change Polling Intervals

Approved-by: Dave Richer
2024-10-31 18:13:51 +00:00
Dave Richer
8e3aa186cb Merged in hotfix/2024-10-31-Database-Issues (pull request #1877)
Hotfix/2024 10 31 Database Issues into master-AIO - IO-3012 IO-3009 IO-3014
2024-10-31 18:06:08 +00:00
Allan Carr
01c55d6277 IO-3014 Change Polling Intervals
Signed-off-by: Allan Carr <allan.carr@thinkimex.com>
2024-10-31 11:04:05 -07:00
Dave Richer
3438907d8d Merge remote-tracking branch 'origin/feature/IO-3014-Timeticket-UI-Sort' into hotfix/2024-10-31-Database-Issues 2024-10-31 11:02:09 -07:00
Allan Carr
ae020b651e IO-3014 Further Query Refinements for T/T
Signed-off-by: Allan Carr <allan.carr@thinkimex.com>
2024-10-31 10:56:05 -07:00
Allan Carr
d22988df15 Merged in feature/IO-3014-Timeticket-UI-Sort (pull request #1875)
IO-3014 TimeTicket UI Sort

Approved-by: Dave Richer
2024-10-31 17:54:36 +00:00
Dave Richer
8136a56ad2 Merge remote-tracking branch 'origin/feature/IO-3014-Timeticket-UI-Sort' into hotfix/2024-10-31-Database-Issues 2024-10-31 10:53:56 -07:00
Allan Carr
830f6c0eea IO-3014 TimeTicket UI Sort
Signed-off-by: Allan Carr <allan.carr@thinkimex.com>
2024-10-31 10:48:40 -07:00
Dave Richer
4c1849289a Merge remote-tracking branch 'origin/feature/IO-3014-Timeticket-UI-Sort' into hotfix/2024-10-31-Database-Issues 2024-10-31 10:46:21 -07:00
Dave Richer
c45a4780e3 Merge remote-tracking branch 'origin/feature/IO-3012-Remove-Sort-for-SB-TimeTickets-Query' into hotfix/2024-10-31-Database-Issues 2024-10-31 10:34:56 -07:00
Allan Carr
d4adc4c1aa Merged in feature/IO-3009-Clear-Dates (pull request #1872)
IO-3009 Clear Dates

Approved-by: Dave Richer
2024-10-31 17:06:38 +00:00
Allan Carr
d9e71423f5 Merged in feature/IO-3010-Task-Table-UI-Mods (pull request #1873)
IO-3010 Task Table UI refactor

Approved-by: Dave Richer
2024-10-31 17:06:02 +00:00
Allan Carr
6cac0f9594 IO-3010 Task Table UI refactor
Signed-off-by: Allan Carr <allan.carr@thinkimex.com>
2024-10-30 17:38:09 -07:00
Allan Carr
2ab4615642 IO-3009 Clear Dates
Signed-off-by: Allan Carr <allan.carr@thinkimex.com>
2024-10-30 12:48:27 -07:00
Dave Richer
dd5961d419 release/2024-11-01 - Update Trigger for job_updated
Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-10-30 12:07:50 -07:00
Allan Carr
8190958ba3 Merged in feature/IO-3012-Remove-Sort-for-SB-TimeTickets-Query (pull request #1871)
IO-3012 Remove Sort from SB Timeticket Query

Approved-by: Dave Richer
2024-10-30 19:03:18 +00:00
Allan Carr
77e009f316 IO-3012 Remove Sort from SB Timeticket Query
Signed-off-by: Allan Carr <allan.carr@thinkimex.com>
2024-10-30 11:19:46 -07:00
Dave Richer
2b2738a8d1 Merge branch 'release/2024-11-01' of bitbucket.org:snaptsoft/bodyshop into release/2024-11-01 2024-10-30 09:38:56 -07:00
Dave Richer
3d10c9da7f release/2024-11-01 - Misc fixes
Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-10-30 09:38:27 -07:00
Allan Carr
e82c77d119 Merged in feature/IO-3008-Save-&-New-Time-Ticket (pull request #1868)
IO-3008 Save and New Flat Rate value

Approved-by: Dave Richer
2024-10-30 16:12:21 +00:00
Allan Carr
855a78be05 Merged in feature/IO-3006-CDK-PBS-Error-Log-INSERT_EXPORT_LOG (pull request #1867)
IO-3006 CDK PBS Error Log on INSERT_EXPORT_LOG

Approved-by: Dave Richer
2024-10-30 16:11:49 +00:00
Dave Richer
a29e840797 release/2024-11-01 - Misc fixes
Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-10-30 09:09:16 -07:00
Allan Carr
1b30c1ab58 IO-3008 Save and New Flat Rate value
Signed-off-by: Allan Carr <allan.carr@thinkimex.com>
2024-10-29 20:03:58 -07:00
Allan Carr
80f235f12e IO-3006 CDK PBS Error Log on INSERT_EXPORT_LOG
Signed-off-by: Allan Carr <allan.carr@thinkimex.com>
2024-10-29 13:33:40 -07:00
Dave Richer
9b67148522 Merged in release/2024-11-01 (pull request #1866)
Release/2024-11-01 into master-AIO - IO-2979 - Misc Logger related fixes
2024-10-29 20:10:02 +00:00
Dave Richer
6b501e4619 release/2024-11-01 - Misc fixes
Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-10-29 11:02:08 -07:00
Dave Richer
42f1d6fa13 release/2024-11-01 - Misc fixes
Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-10-29 10:53:09 -07:00
Dave Richer
3f247a9227 release/2024-11-01 - Misc fixes
Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-10-29 09:54:45 -07:00
Dave Richer
63b914731b release/2024-11-01 - Misc fixes
Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-10-29 08:25:54 -07:00
Dave Richer
23f8f69bbe release/2024-11-01 - Misc fixes
Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-10-29 08:19:58 -07:00
Dave Richer
fc3ea2bdf8 release/2024-11-01 - Misc fixes
Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-10-29 07:37:40 -07:00
Dave Richer
96e970faf7 release/2024-11-01 - Misc fixes
Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-10-28 18:16:48 -07:00
Dave Richer
c133195607 release/2024-11-01 - Misc fixes
Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-10-28 17:48:43 -07:00
Dave Richer
d75ea2b1a6 release/2024-11-01 - Misc fixes
Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-10-28 17:38:46 -07:00
Dave Richer
ec0fd840e4 Merged in feature/IO-2979-DST (pull request #1856)
IO-2979-DST into release/2024-11-01 - DST Related Fixes
2024-10-28 21:05:57 +00:00
Dave Richer
971a81fc27 feature/IO-2979-DST - Finish DST Stuff
Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-10-28 14:04:14 -07:00
Dave Richer
19050d31f7 Merged in release/2024-11-01 (pull request #1853)
Release/2024-11-01 into master-AIO  - Fix Logging Issues
2024-10-28 20:39:28 +00:00
Dave Richer
e605433379 Merge remote-tracking branch 'origin/release/2024-11-01' into feature/IO-2979-DST 2024-10-28 13:10:08 -07:00
Dave Richer
b9ebb70b7a release/2024-11-01 - Remove Trace Log Level
Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-10-28 13:06:47 -07:00
Dave Richer
79ed6f2388 release/2024-11-01 - Remove Trace Log Level
Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-10-28 12:24:40 -07:00
Dave Richer
785449a986 release/2024-11-01 - Remove Trace Log Level
Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-10-28 12:03:48 -07:00
Dave Richer
0b7d469e0e feature/IO-2979-DST - Finish DST
Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-10-28 11:55:13 -07:00
Dave Richer
a57156756e feature/IO-2979-DST - Normalize usages of dayjs to dayjs not day, move locale hook
Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-10-28 11:03:30 -07:00
Dave Richer
c4c30d98d4 release/2024-11-01 - Adjust hostname check
Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-10-28 10:07:10 -07:00
Dave Richer
d4e8803b13 release/2024-11-01 - Adjust client body buffer size
Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-10-28 09:47:27 -07:00
Dave Richer
1f2786ddec release/2024-11-01 - Fix some log things
Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-10-28 09:31:37 -07:00
Dave Richer
e90cda07e4 Merged in release/2024-10-25 (pull request #1848)
Release/2024-10-25 - IO-2921, IO-2966, IO-2973, IO-2974, IO-2978, IO-2992, IO-2996, IO-2998
2024-10-26 04:48:05 +00:00
Dave Richer
9793daa04c release/2024-10-25 - Add The local email viewer to the reference folder.
Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-10-25 11:58:50 -07:00
Allan Carr
117ced8fe7 Merged in feature/IO-2973-Created-By-Tasks (pull request #1846)
IO-2973 Created By Tasks

Approved-by: Dave Richer
2024-10-25 18:53:11 +00:00
Dave Richer
e7909205d1 feature/IO-2973-Created-By-Tasks - Merge in release, fix conflicts
Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-10-25 11:50:11 -07:00
Dave Richer
18028a70ab feature/IO-2973-Created-By-Tasks - Merge in release, fix conflicts
Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-10-25 11:22:59 -07:00
Dave Richer
eeb8d8d26f release/2024-10-25 - Clean up referenceDocuments
Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-10-25 11:21:10 -07:00
Allan Carr
23659fc412 IO-2973 Created By Tasks
Signed-off-by: Allan Carr <allan.carr@thinkimex.com>
2024-10-25 11:19:40 -07:00
Patrick Fic
ba65057782 Merged in feature/IO-2974-add-comment-to-schedule (pull request #1842)
IO-2974 add comment to schedule.

Approved-by: Dave Richer
2024-10-25 17:03:06 +00:00
Dave Richer
60a859cac8 Merged in feature/IO-2998-enhanced-api-logging (pull request #1843)
feature/IO-2998-enhanced-api-logging - Missing package
2024-10-25 15:38:46 +00:00
Dave Richer
0cfe26093c feature/IO-2998-enhanced-api-logging - Missing package
Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-10-25 08:37:56 -07:00
Patrick Fic
d085a9c7c9 IO-2974 add comment to schedule. 2024-10-25 08:33:17 -07:00
Dave Richer
ec518a0593 Merged in feature/IO-2998-enhanced-api-logging (pull request #1840)
feature/IO-2998-enhanced-api-logging - Missing package
2024-10-25 15:30:26 +00:00
Dave Richer
1cd64ab6f1 feature/IO-2998-enhanced-api-logging - Missing package
Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-10-25 08:29:51 -07:00
Dave Richer
26836f662a Merged in feature/IO-2998-enhanced-api-logging (pull request #1838)
feature/IO-2998-enhanced-api-logging - Finish
2024-10-25 15:12:24 +00:00
Dave Richer
111f280674 feature/IO-2998-enhanced-api-logging - Finish
Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-10-25 08:11:33 -07:00
Dave Richer
6e88faa9d8 Merged in feature/IO-2998-enhanced-api-logging (pull request #1836)
Feature/IO-2998 into Release/2024-10-25
2024-10-25 14:11:26 +00:00
Dave Richer
1ca8b2a78d feature/IO-2998-enhanced-api-logging - Finish
Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-10-24 14:36:35 -07:00
Dave Richer
cd2a7cad7f feature/IO-2998-enhanced-api-logging - Finish
Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-10-24 14:21:35 -07:00
Dave Richer
ed16156957 Merge remote-tracking branch 'origin/release/2024-10-25' into feature/IO-2998-enhanced-api-logging 2024-10-24 13:18:21 -07:00
Patrick Fic
8dc1f7e08f IO-2998 remove graylog and additional erroneous console logs. 2024-10-24 12:18:39 -07:00
Patrick Fic
2d3c13c587 IO-2998 Add winston and replace logger.js 2024-10-24 11:50:54 -07:00
Allan Carr
5486907639 Merged in feature/IO-2978-Production-not-in-Production-Status (pull request #1834)
IO-2978 Production not in Production Status

Approved-by: Dave Richer
2024-10-24 16:49:59 +00:00
Allan Carr
9233cef23a IO-2978 Production not in Production Status
Signed-off-by: Allan Carr <allan.carr@thinkimex.com>
2024-10-23 17:02:45 -07:00
Dave Richer
c16eafe892 Merged in feature/IO-2996-Package-Updates-Docker-Debugging (pull request #1832)
feature/IO-2996-Package-Updates-Docker-Debugging - Maintenance
2024-10-23 17:03:44 +00:00
Dave Richer
b479684fe4 feature/IO-2996-Package-Updates-Docker-Debugging - Maintenance
Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-10-23 13:00:51 -04:00
Allan Carr
4201f61548 Merged in feature/IO-2966-Contract-Create-Page-Leave-Warning (pull request #1831)
IO-2966 Contract Create Page Leave Warning

Approved-by: Dave Richer
2024-10-23 14:58:22 +00:00
Allan Carr
d04fc76840 IO-2966 Contract Create Page Leave Warning
Signed-off-by: Allan Carr <allan.carr@thinkimex.com>
2024-10-22 17:48:40 -07:00
Allan Carr
0f84adc752 IO-2966 Contract Create Page Leave Warning
Signed-off-by: Allan Carr <allan.carr@thinkimex.com>
2024-10-22 17:35:54 -07:00
Allan Carr
fbefd80959 Merged in feature/IO-2921-CARSTAR-Canada-Chatter-Integration (pull request #1830)
IO-2921 CHATTER correct secertmanager call from undefined variable to string

Approved-by: Dave Richer
2024-10-22 15:08:11 +00:00
Allan Carr
6a691b54c8 Merged in feature/IO-2992-Bill-Line-UI-Table (pull request #1829)
IO-2992 Bill Line column Width with Word Breaks

Approved-by: Dave Richer
2024-10-22 15:07:43 +00:00
Allan Carr
fc75717d32 IO-2921 CHATTER correct secertmanager call from undefined variable to string
Signed-off-by: Allan Carr <allan.carr@thinkimex.com>
2024-10-21 12:43:20 -07:00
Allan Carr
1459c6e993 Merge branch 'master-AIO' into feature/IO-2921-CARSTAR-Canada-Chatter-Integration
Signed-off-by: Allan Carr <allan.carr@thinkimex.com>
2024-10-21 12:42:45 -07:00
Allan Carr
f50292f9bf IO-2992 Bill Line column Width with Word Breaks
Signed-off-by: Allan Carr <allan.carr@thinkimex.com>
2024-10-21 10:53:32 -07:00
Dave Richer
5b81912bd3 Merged in release/2024-10-18 (pull request #1828)
Release/2024-10-18 into master-AIO - IO-2971, IO-2976, IO-2977, IO-2984, IO-2985, IO-2987, IO-2988, IO-2989
2024-10-19 03:47:08 +00:00
Dave Richer
3c98a94c38 Merged in feature/IO-2976-GlobalSearch-First-link-Navigate (pull request #1826)
feature/IO-2976-GlobalSearch-First-link-Navigate - Fix global search so it goes to the first url if it is available, added an ID for rome tours.
2024-10-18 19:25:09 +00:00
Dave Richer
1d98de6d4d feature/IO-2976-GlobalSearch-First-link-Navigate - Fix global search so it goes to the first url if it is available, added an ID for rome tours.
Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-10-18 15:22:56 -04:00
Allan Carr
0ce5d9063a Merged in feature/IO-2989-jobexported-missing-translation (pull request #1823)
IO-2989 jobexported missing en_us translation

Approved-by: Dave Richer
2024-10-18 16:30:02 +00:00
Dave Richer
3b84e1d6ec Merged in feature/IO-2977-Replace-On-Board-with-In-View (pull request #1824)
feature/IO-2977-Replace-On-Board-with-In-View - Replace production board terminology for Imex, on board vs in view
2024-10-18 16:29:25 +00:00
Dave Richer
d62f6e2116 feature/IO-2977-Replace-On-Board-with-In-View - Replace production board terminology for Imex, on board vs in view
Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-10-18 12:28:01 -04:00
Allan Carr
71a26cc4ac IO-2989 jobexported missing en_us translation
Signed-off-by: Allan Carr <allan.carr@thinkimex.com>
2024-10-18 08:45:13 -07:00
Allan Carr
32441e9406 Merged in feature/IO-2988-Jobline-Upsert-Undefined (pull request #1821)
IO-2988 Jobline Upsert Undefined handling

Approved-by: Dave Richer
2024-10-18 01:55:31 +00:00
Allan Carr
e6dade1206 IO-2988 Jobline Upsert Undefined handling
Signed-off-by: Allan Carr <allan.carr@thinkimex.com>
2024-10-17 17:03:40 -07:00
Allan Carr
43d34cae07 Merged in feature/IO-2987-Non-Production-Board-Status-Status-Change (pull request #1820)
IO-2987 Non Production Board Status - Status Changes

Approved-by: Dave Richer
2024-10-17 22:27:53 +00:00
Allan Carr
a72a7948fe IO-2987 Non Production Board Status - Status Changes
Signed-off-by: Allan Carr <allan.carr@thinkimex.com>
2024-10-17 15:22:05 -07:00
Dave Richer
a24f6639a1 Merged in feature/IO-2985-Production-List-View-Null-Handling (pull request #1818)
IO-2985-Production-List-View-Null-Handling - Handle Null md_production_config
2024-10-17 17:09:48 +00:00
Allan Carr
b2a0af32e9 Merged in feature/IO-2984-Open-in-Explorer (pull request #1817)
IO-2984 Open in Explorer correction

Approved-by: Dave Richer
2024-10-17 17:09:36 +00:00
Allan Carr
cc58d14d32 Merged in feature/IO-2971-Export-Table-Size (pull request #1816)
IO-2971 Export Table Size limit to 10

Approved-by: Dave Richer
2024-10-17 17:03:27 +00:00
Dave Richer
9ce419b949 feature/IO-2985-Production-List-View-Null-Handling - Handle Null md_production_config
Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-10-17 11:42:03 -04:00
Allan Carr
5053816be7 IO-2984 Open in Explorer correction
encodeURL

Signed-off-by: Allan Carr <allan.carr@thinkimex.com>
2024-10-16 16:38:59 -07:00
Allan Carr
30ca34ea93 IO-2971 Export Table Size limit to 10
Signed-off-by: Allan Carr <allan.carr@thinkimex.com>
2024-10-16 13:43:25 -07:00
Dave Richer
68d1a404b3 release/2024-10-18: Fixes from Docker meeting
Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-10-16 15:28:04 -04:00
Dave Richer
85e82b85ea Merged in release/2024-10-11 (pull request #1815)
release/2024-10-11: Remove Task Emails Cleanup
2024-10-16 17:19:52 +00:00
Dave Richer
23467280b4 release/2024-10-11: Remove Task Emails Cleanup
Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-10-16 13:18:48 -04:00
Dave Richer
aedad1c48f Merged in release/2024-10-11 (pull request #1814)
release/2024-10-11: Hotfix
2024-10-12 16:28:40 +00:00
Dave Richer
05cc4dd188 release/2024-10-11: Hotfix
Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-10-12 12:26:30 -04:00
Dave Richer
ea6351ea06 Merged in release/2024-10-11 (pull request #1813)
release/2024-10-11: Hotfix
2024-10-12 16:06:06 +00:00
Dave Richer
87d3ceb408 release/2024-10-11: Hotfix
Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-10-12 12:05:13 -04:00
Dave Richer
d08dd2b506 Merged in release/2024-10-11 (pull request #1812)
release/2024-10-11: Final touchups
2024-10-12 03:59:37 +00:00
Dave Richer
8a047d14a1 release/2024-10-11: Final touchups
Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-10-11 23:51:39 -04:00
Dave Richer
e103772aa4 Merged in release/2024-10-11 (pull request #1811)
Release/2024-10-11 into master-AIO - IO-2791, IO-2962, IO-2971, IO-2972, IO-2979
2024-10-12 03:09:09 +00:00
Dave Richer
c332699dc8 Merge branch 'release/2024-10-11' of bitbucket.org:snaptsoft/bodyshop into release/2024-10-11 2024-10-11 23:02:17 -04:00
Dave Richer
25e6e61d10 release/2024-10-11: Final touchups
Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-10-11 22:59:44 -04:00
Patrick Fic
cdcd6b636a Merged in feature/IO-2971-export-mutation-refactor (pull request #1809)
IO-2791 Stop gap change to limit exports to 10 records at a time.

Approved-by: Dave Richer
2024-10-11 20:07:59 +00:00
Patrick Fic
7879591bcf IO-2971 add null coalescing 2024-10-11 16:05:30 -04:00
Patrick Fic
7fc6556866 IO-2791 Stop gap change to limit exports to 10 records at a time. 2024-10-11 16:03:40 -04:00
Dave Richer
3f5489ce7e Merged in feature/IO-2979-DST-Handling (pull request #1808)
feature/IO-2979-DST-Handling - Checkpoint
2024-10-11 17:18:33 +00:00
Dave Richer
5a90854861 feature/IO-2979-DST-Handling
- Checkpoint

Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-10-10 13:01:36 -04:00
Dave Richer
8347a8c098 Merged in feature/IO-2979-DST-Handling (pull request #1806)
feature/IO-2979-DST-Handling - Add LocalStack and Adjust local Emailing
2024-10-09 17:03:19 +00:00
Dave Richer
2bf074d85a feature/IO-2979-DST-Handling
- Add LocalStack and Adjust local Emailing

Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-10-09 13:00:16 -04:00
Dave Richer
50d47cd679 Merged in feature/IO-2962-Task-Email-Footer-Timestamps (pull request #1804)
feature/IO-2962-Task-Email-Footer-Timestamps - Localize Date in Task Email Footer
2024-10-07 20:22:13 +00:00
Dave Richer
3a4e06eaa2 Merged in feature/IO-2972-Final-Redis-Sockets-Fixes (pull request #1803)
Feature/IO-2972 Final Redis Sockets Fixes
2024-10-07 20:21:41 +00:00
Dave Richer
4be71726d4 feature/IO-2972-Final-Redis-Sockets-Add Redis Cluster aware logic
Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-10-07 16:18:11 -04:00
Dave Richer
c78db7eb08 feature/IO-2972-Final-Redis-Sockets-Fixes - Cleanup
Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-10-04 13:52:09 -04:00
Dave Richer
e4dc711481 docker-redis - final cleanup
Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-10-04 13:43:45 -04:00
Dave Richer
5114138c67 docker-redis - final cleanup
Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-10-03 16:30:15 -04:00
Dave Richer
68b8743002 docker-redis - improve lockfile for redis, add redis-insights, make sure app image has all it needs to build canvas
Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-10-03 13:17:04 -04:00
Dave Richer
8f312bfffb docker-redis - local refactors
Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-10-03 13:12:42 -04:00
Dave Richer
7e7e109cfe docker-redis - local refactors
Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-10-03 11:59:42 -04:00
Dave Richer
05e5545466 docker-redis - local tests
Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-10-02 01:04:05 -04:00
Dave Richer
ddb0990645 docker-redis - local tests
Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-10-02 00:50:40 -04:00
Dave Richer
04dec6d91c docker-redis - local tests
Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-10-02 00:27:11 -04:00
Dave Richer
a883b817b0 release/2024-10-04: Hotfix
Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-10-01 13:37:34 -04:00
Dave Richer
5b00ded5f6 hotfix/IO-2969-Fonts-For-Production - Register fonts
Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-09-27 19:29:26 -04:00
Dave Richer
c5b19d8f22 hotfix/IO-2969-Fonts-For-Production - Register fonts
Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-09-27 19:20:19 -04:00
Dave Richer
b7423aebf6 Merged in release/2024-09-27 (pull request #1800)
Release/2024 09 27 into master-AIO - IO-2967
2024-09-27 22:36:31 +00:00
Dave Richer
ee70aeb952 release/2024-09-27 - Remove cors line
Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-09-27 18:33:01 -04:00
Dave Richer
f6f6fab5ba Merged in feature/IO-2967-Better-Refetch-Handling (pull request #1799)
Feature/IO-2967 Better Refetch Handling

Approved-by: Patrick Fic
2024-09-27 19:20:20 +00:00
Dave Richer
699ffc822a feature/IO-2967-Better-Refetch-Handling - Remove unused include
Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-09-27 15:07:35 -04:00
Dave Richer
4e35f5402c feature/IO-2967-Better-Refetch-Handling - Add note to server.js
Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-09-27 15:06:52 -04:00
Dave Richer
9b997d0924 feature/IO-2967-Better-Refetch-Handling - match broadcast room name to match redis naming convention
Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-09-27 15:00:25 -04:00
Dave Richer
d705f8211e feature/IO-2967-Better-Refetch-Handling - Bug fixes and hardening
Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-09-27 14:52:38 -04:00
Dave Richer
03761bbb2a feature/IO-2967-Better-Refetch-Handling - Implementation
Signed-off-by: Dave Richer <dave@imexsystems.ca>
2024-09-27 13:32:59 -04:00
176 changed files with 14629 additions and 9239 deletions

24
.dockerignore Normal file
View File

@@ -0,0 +1,24 @@
# Directories to exclude
.circleci
.idea
.platform
.vscode
_reference
client
redis/dockerdata
hasura
node_modules
# Files to exclude
.ebignore
.editorconfig
.eslintrc.json
.gitignore
.prettierrc.js
Dockerfile
README.MD
bodyshop_translations.babel
docker-compose.yml
ecosystem.config.js
# Optional: Exclude logs and temporary files
*.log

1
.gitattributes vendored Normal file
View File

@@ -0,0 +1 @@
* text eol=lf

0
.localstack/.gitkeep Normal file
View File

View File

@@ -0,0 +1,24 @@
#!/bin/bash
# Install required packages
dnf install -y fontconfig freetype
# Move to the /tmp directory for temporary download and extraction
cd /tmp
# Download the Montserrat font zip file
wget https://images.imex.online/fonts/montserrat.zip -O montserrat.zip
# Unzip the downloaded font file
unzip montserrat.zip -d montserrat
# Move the font files to the system fonts directory
mv montserrat/montserrat/*.ttf /usr/share/fonts
# Rebuild the font cache
fc-cache -fv
# Clean up
rm -rf /tmp/montserrat /tmp/montserrat.zip
echo "Montserrat fonts installed and cached successfully."

View File

@@ -1 +1,2 @@
client_max_body_size 50M;
client_max_body_size 50M;
client_body_buffer_size 5M;

15
.vscode/launch.json vendored
View File

@@ -14,6 +14,21 @@
"request": "launch",
"url": "http://localhost:3000",
"webRoot": "${workspaceRoot}/client/src"
},
{
"name": "Attach to Node.js in Docker",
"type": "node",
"request": "attach",
"address": "localhost",
"port": 9229,
"localRoot": "${workspaceFolder}",
"remoteRoot": "/app",
"protocol": "inspector",
"restart": true,
"sourceMaps": true,
"skipFiles": [
"<node_internals>/**"
]
}
]
}

30
.vscode/settings.json vendored
View File

@@ -8,5 +8,35 @@
"pattern": "**/IMEX.xml",
"systemId": "logs/IMEX.xsd"
}
],
"cSpell.words": [
"antd",
"appointmentconfirmation",
"appt",
"autohouse",
"autohouseid",
"billlines",
"bodyshop",
"bodyshopid",
"bodyshops",
"CIECA",
"claimscorp",
"claimscorpid",
"Dinero",
"driveable",
"IMEX",
"imexshopid",
"jobid",
"joblines",
"Kaizen",
"labhrs",
"larhrs",
"mixdata",
"ownr",
"promanager",
"shopname",
"smartscheduling",
"timetickets",
"touchtime"
]
}

47
Dockerfile Normal file
View File

@@ -0,0 +1,47 @@
# Use Amazon Linux 2023 as the base image
FROM amazonlinux:2023
# Install Git and Node.js (Amazon Linux 2023 uses the DNF package manager)
RUN dnf install -y git \
&& curl -sL https://rpm.nodesource.com/setup_20.x | bash - \
&& dnf install -y nodejs \
&& dnf clean all
# Install dependencies required by node-canvas
RUN dnf install -y \
gcc \
gcc-c++ \
cairo-devel \
pango-devel \
libjpeg-turbo-devel \
giflib-devel \
libpng-devel \
make \
python3 \
python3-pip \
&& dnf clean all
# Set the working directory
WORKDIR /app
# This is because our test route uses a git commit hash
RUN git config --global --add safe.directory /app
# Copy package.json and package-lock.json
COPY package.json ./
# Install Nodemon
RUN npm install -g nodemon
# Install dependencies
RUN npm i --no-package-lock
# Copy the rest of your application code
COPY . .
# Expose the port your app runs on (adjust if necessary)
EXPOSE 4000 9229
# Start the application
CMD ["nodemon", "--legacy-watch", "--inspect=0.0.0.0:9229", "server.js"]

View File

@@ -0,0 +1,64 @@
# Setting up External Networking and Static IP for WSL2 using Hyper-V
This guide will walk you through the steps to configure your WSL2 (Windows Subsystem for Linux) instance to use an external Hyper-V virtual switch, enabling it to connect directly to your local network. Additionally, you'll learn how to assign a static IP address to your WSL2 instance.
## Prerequisites
1. **Windows 11**
2. **Docker Desktop For Windows (Latest Version)
# Docker Setup
Inside the root of the project exists the `docker-compose.yaml` file, you can simply run
`docker-compose up` to launch the backend.
Things to note:
- When installing NPM packages, you will need to rebuild the `node-app` container
- Making changes to the server files will restart the `node-app`
# Local Stack
- LocalStack Front end (Optional) - https://apps.microsoft.com/detail/9ntrnft9zws2?hl=en-us&gl=US
- http://localhost:4566/_aws/ses will allow you to see emails sent
# Docker Commands
## General `docker-compose` Commands:
1. Bring up the services, force a rebuild of all services, and do not use the cache: `docker-compose up --build --no-cache`
2. Start Containers in Detached Mode: This will run the containers in the background (detached mode): `docker-compose up -d`
3. Stop and Remove Containers: Stops and removes the containers gracefully: `docker-compose down`
4. Stop containers without removing them: `docker-compose stop`
5. Remove Containers, Volumes, and Networks: `docker-compose down --volumes`
6. Force rebuild of containers: `docker-compose build --no-cache`
7. View running Containers: `docker-compose ps`
8. View a specific containers logs: `docker-compose logs <container-name>`
9. Scale services (multiple instances of a service): `docker-compose up --scale <container-name>=<instances number> -d`
10. Watch a specific containers logs in realtime with timestamps: `docker-compose logs -f --timestamps <container-name>`
## Volume Management Commands
1. List Docker volumes: `docker volume ls`
2. Remove Unused volumes `docker volume prune`
3. Remove specific volumes `docker volume rm <volume-name>`
4. Inspect a volume: `docker volume inspect <volume-name>`
## Container Image Management Commands:
1. List running containers: `docker ps`
2. List all containers: `docker os -a`
3. Remove Stopped containers: `docker container prune`
4. Remove a specific container: `docker container rm <container-name>`
5. Remove a specific image: `docker rmi <image-name>:<version>`
6. Remove all unused images: `docker image prune -a`
## Network Management Commands:
1. List networks: `docker network ls`
2. Inspect a specific network: `docker network inspect <network-name>`
3. Remove a specific network: `docker network rm <network-name>`
4. Remove unused networks: `docker network prune`
## Debugging and maintenance:
1. Enter a Running container: `docker exec -it <container name> /bin/bash` (could also be `/bin/sh` or for example `redis-cli` on a redis node)
2. View container resource usage: `docker stats`
3. Check Disk space used by Docker: `docker system df`
4. Remove all unused Data (Nuclear option): `docker system prune`
## Specific examples
1. To simulate a Clean state, one should run `docker system prune` followed by `docker volume prune -a`
2. You can run `docker-compose up` without the `-d` option, and you will get what is identical to the experience you were used to, this includes being able to control-c and bring the entire stack down

View File

@@ -0,0 +1 @@
node_modules

View File

@@ -0,0 +1,7 @@
This will connect to your dockers local stack session and render the email in HTML.
```shell
node index.js
```
http://localhost:3334

View File

@@ -0,0 +1,116 @@
// index.js
import express from 'express';
import fetch from 'node-fetch';
import {simpleParser} from 'mailparser';
const app = express();
const PORT = 3334;
app.get('/', async (req, res) => {
try {
const response = await fetch('http://localhost:4566/_aws/ses');
if (!response.ok) {
throw new Error('Network response was not ok');
}
const data = await response.json();
const messagesHtml = await parseMessages(data.messages);
res.send(renderHtml(messagesHtml));
} catch (error) {
console.error('Error fetching messages:', error);
res.status(500).send('Error fetching messages');
}
});
async function parseMessages(messages) {
const parsedMessages = await Promise.all(
messages.map(async (message, index) => {
try {
const parsed = await simpleParser(message.RawData);
return `
<div class="shadow-md rounded-lg p-4 mb-6" style="background-color: lightgray">
<div class="shadow-md rounded-lg p-4 mb-6" style="background-color: white">
<div class="mb-2">
<span class="font-bold text-lg">Message ${index + 1}</span>
</div>
<div class="mb-2">
<span class="font-semibold">From:</span> ${message.Source}
</div>
<div class="mb-2">
<span class="font-semibold">Region:</span> ${message.Region}
</div>
<div class="mb-2">
<span class="font-semibold">Timestamp:</span> ${message.Timestamp}
</div>
</div>
<div class="prose">
${parsed.html || parsed.textAsHtml || 'No HTML content available'}
</div>
</div>
`;
} catch (error) {
console.error('Error parsing email:', error);
return `
<div class="bg-white shadow-md rounded-lg p-4 mb-6">
<div class="mb-2">
<span class="font-bold text-lg">Message ${index + 1}</span>
</div>
<div class="mb-2">
<span class="font-semibold">From:</span> ${message.Source}
</div>
<div class="mb-2">
<span class="font-semibold">Region:</span> ${message.Region}
</div>
<div class="mb-2">
<span class="font-semibold">Timestamp:</span> ${message.Timestamp}
</div>
<div class="text-red-500">
Error parsing email content
</div>
</div>
`;
}
})
);
return parsedMessages.join('');
}
function renderHtml(messagesHtml) {
return `
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Email Messages Viewer</title>
<script src="https://cdn.tailwindcss.com"></script>
<style>
body {
background-color: #f3f4f6;
font-family: Arial, sans-serif;
}
.container {
max-width: 800px;
margin: 50px auto;
padding: 20px;
}
.prose {
line-height: 1.6;
}
</style>
</head>
<body>
<div class="container bg-white shadow-lg rounded-lg p-6">
<h1 class="text-2xl font-bold text-center mb-6">Email Messages Viewer</h1>
<div id="messages-container">
${messagesHtml}
</div>
</div>
</body>
</html>
`;
}
app.listen(PORT, () => {
console.log(`Server is running on http://localhost:${PORT}`);
});

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,18 @@
{
"name": "localemailviewer",
"version": "1.0.0",
"main": "index.js",
"type": "module",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"description": "",
"dependencies": {
"express": "^4.21.1",
"mailparser": "^3.7.1",
"node-fetch": "^3.3.2"
}
}

View File

@@ -11156,6 +11156,27 @@
</translation>
</translations>
</concept_node>
<concept_node>
<name>imexpay</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node>
<name>insurancecos</name>
<definition_loaded>false</definition_loaded>
@@ -11198,27 +11219,6 @@
</translation>
</translations>
</concept_node>
<concept_node>
<name>intellipay</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node>
<name>intellipay_cash_discount</name>
<definition_loaded>false</definition_loaded>
@@ -11747,6 +11747,48 @@
</translation>
</translations>
</concept_node>
<concept_node>
<name>ttl_adjustment</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node>
<name>ttl_tax_adjustment</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
</children>
</folder_node>
<folder_node>
@@ -11775,6 +11817,27 @@
</concept_node>
</children>
</folder_node>
<concept_node>
<name>romepay</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node>
<name>scheduling</name>
<definition_loaded>false</definition_loaded>
@@ -36253,6 +36316,27 @@
</translation>
</translations>
</concept_node>
<concept_node>
<name>total_cust_payable_cash_discount</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node>
<name>total_repairs</name>
<definition_loaded>false</definition_loaded>
@@ -48360,6 +48444,27 @@
</translation>
</translations>
</concept_node>
<concept_node>
<name>tasks_in_view</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node>
<name>tasks_on_board</name>
<definition_loaded>false</definition_loaded>
@@ -48402,6 +48507,27 @@
</translation>
</translations>
</concept_node>
<concept_node>
<name>total_amount_in_view</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node>
<name>total_amount_on_board</name>
<definition_loaded>false</definition_loaded>
@@ -48444,6 +48570,27 @@
</translation>
</translations>
</concept_node>
<concept_node>
<name>total_hours_in_view</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node>
<name>total_hours_on_board</name>
<definition_loaded>false</definition_loaded>
@@ -48465,6 +48612,27 @@
</translation>
</translations>
</concept_node>
<concept_node>
<name>total_jobs_in_view</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node>
<name>total_jobs_on_board</name>
<definition_loaded>false</definition_loaded>
@@ -48507,6 +48675,27 @@
</translation>
</translations>
</concept_node>
<concept_node>
<name>total_lab_in_view</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node>
<name>total_lab_on_board</name>
<definition_loaded>false</definition_loaded>
@@ -48549,6 +48738,27 @@
</translation>
</translations>
</concept_node>
<concept_node>
<name>total_lar_in_view</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node>
<name>total_lar_on_board</name>
<definition_loaded>false</definition_loaded>
@@ -48724,6 +48934,27 @@
</translation>
</translations>
</concept_node>
<concept_node>
<name>tasks_in_view</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node>
<name>tasks_on_board</name>
<definition_loaded>false</definition_loaded>
@@ -48766,6 +48997,27 @@
</translation>
</translations>
</concept_node>
<concept_node>
<name>total_amount_in_view</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node>
<name>total_amount_on_board</name>
<definition_loaded>false</definition_loaded>
@@ -48808,6 +49060,27 @@
</translation>
</translations>
</concept_node>
<concept_node>
<name>total_hours_in_view</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node>
<name>total_hours_on_board</name>
<definition_loaded>false</definition_loaded>
@@ -48829,6 +49102,27 @@
</translation>
</translations>
</concept_node>
<concept_node>
<name>total_jobs_in_view</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node>
<name>total_jobs_on_board</name>
<definition_loaded>false</definition_loaded>
@@ -48871,6 +49165,27 @@
</translation>
</translations>
</concept_node>
<concept_node>
<name>total_lab_in_view</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node>
<name>total_lab_on_board</name>
<definition_loaded>false</definition_loaded>
@@ -48913,6 +49228,27 @@
</translation>
</translations>
</concept_node>
<concept_node>
<name>total_lar_in_view</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node>
<name>total_lar_on_board</name>
<definition_loaded>false</definition_loaded>
@@ -51761,6 +52097,27 @@
</translation>
</translations>
</concept_node>
<concept_node>
<name>production_not_production_status</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node>
<name>production_over_time</name>
<definition_loaded>false</definition_loaded>
@@ -54225,6 +54582,27 @@
</translation>
</translations>
</concept_node>
<concept_node>
<name>created_by</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node>
<name>description</name>
<definition_loaded>false</definition_loaded>
@@ -54487,6 +54865,27 @@
</translation>
</translations>
</concept_node>
<concept_node>
<name>related_items</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node>
<name>remind_at</name>
<definition_loaded>false</definition_loaded>

27
certs/id_rsa Normal file
View File

@@ -0,0 +1,27 @@
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABFwAAAAdzc2gtcn
NhAAAAAwEAAQAAAQEAvNl5fuVmLNv72BZNxnTqX5CHf5Xi8UxjYaYxHITSCx7blnhpVYLd
qXvcOWXzbsfjch/den73QiW4n2FYz75oGMhUGlOYzdWKA9I9Sj09Qy1R06RhwDiZGd5qaM
swEeXpkNmi2u4Qd2kJeDfUQUigjC09V81O/vrniGtQAJScfiG/itdm+Ufn09Z4MYk0HWjq
iDokNEskoEPsibYIrb+Q6vdtuPkZO+wU/smXhPtgw5ST6oQdmm/gVNsRg5XNzxrire+z1G
WatnnVL3hPnnfpnf8W589dyms7GGJwhPerSGTN1bn0T4+9C69Cd7LBJtxiuFdRmdlGLLLP
RR48Rur71wAAA9AEfVsdBH1bHQAAAAdzc2gtcnNhAAABAQC82Xl+5WYs2/vYFk3GdOpfkI
d/leLxTGNhpjEchNILHtuWeGlVgt2pe9w5ZfNux+NyH916fvdCJbifYVjPvmgYyFQaU5jN
1YoD0j1KPT1DLVHTpGHAOJkZ3mpoyzAR5emQ2aLa7hB3aQl4N9RBSKCMLT1XzU7++ueIa1
AAlJx+Ib+K12b5R+fT1ngxiTQdaOqIOiQ0SySgQ+yJtgitv5Dq9224+Rk77BT+yZeE+2DD
lJPqhB2ab+BU2xGDlc3PGuKt77PUZZq2edUveE+ed+md/xbnz13KazsYYnCE96tIZM3Vuf
RPj70Lr0J3ssEm3GK4V1GZ2UYsss9FHjxG6vvXAAAAAwEAAQAAAQAQTosSLQbMmtY9S3e9
yjyusdExcCTfhyQRu4MEHmfws+JsNMuLqbgwOVTD1AzYJQR7x0qdmDcLjCxL/uDnV16vvS
Sd/Vf1dhnryIyoS29tzI0DRG94ZKq7tBvmHp1w/jRT4KcSVnovhW9e5Rs74+SRFhr06PKI
S+wQOIv48Nwue9+QUMsMCpWgKXHx7SHNTHvnAfqdhi9O29SWlMA+v+mELZ5Cl+HU0UTt2I
A1BxOe1N8FjN7KE2viJexsl3is1PuqMkpLl/wyHBJTVzUadl6DRALJQIm7/YO5goE72YOV
Lpo27do3zjhC87dlKdATvZUzfKV0LuUVdxq/PNDZMUbBAAAAgQDShAqDZiDrdTUaGXfUVm
QzcnVNbh2/KgZh4uux9QNHST562W6cnN7qxoRwVrM4BCOk1Kl73QQZW4nDvXX3PVC5j038
8AXkcBHS9j9f4h72ue7D2jqlbHFa7aGU9zYgk9mbBF+GX3tDntkAIQjLtwOLfj1iiJ/clX
mHFUAY1V4L8AAAAIEA3E4t/v0yU5D9AOI0r17UNYqfeyDoKAEDR4QbbFjO1l0kLnEJy7Zx
Mhj18GilYg2y0P0v8dSM/oWXS8Hua2t5i9Exlv6gHhGlQ80mwYcVGIxewZ/pPeCPw0U+kt
EKUjt09m9Oe7+6xHQsTBj9hY8/vqPmQwRalZFcLdhHiDiVKTcAAACBANtykaPXdVzEFx7D
UOlsjVL7zM0EVOFXf9JJQ6BhazhmsEI2PYt3IpgGMo8cXkoUofAOIYjf421AabN1BqSO5J
XTMxM0ZV3JmLLi804Mu9h1iFrVTBdLYOMJdc2VCo1EwHWpo9SXOyjxce/znvcIOU04aZhu
TaPg816X+E+gw5JhAAAAFGRhdmVARGF2ZVJpY2hlci1JTUVYAQIDBAUG
-----END OPENSSH PRIVATE KEY-----

1
certs/id_rsa.pub Normal file
View File

@@ -0,0 +1 @@
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC82Xl+5WYs2/vYFk3GdOpfkId/leLxTGNhpjEchNILHtuWeGlVgt2pe9w5ZfNux+NyH916fvdCJbifYVjPvmgYyFQaU5jN1YoD0j1KPT1DLVHTpGHAOJkZ3mpoyzAR5emQ2aLa7hB3aQl4N9RBSKCMLT1XzU7++ueIa1AAlJx+Ib+K12b5R+fT1ngxiTQdaOqIOiQ0SySgQ+yJtgitv5Dq9224+Rk77BT+yZeE+2DDlJPqhB2ab+BU2xGDlc3PGuKt77PUZZq2edUveE+ed+md/xbnz13KazsYYnCE96tIZM3VufRPj70Lr0J3ssEm3GK4V1GZ2UYsss9FHjxG6vvX dave@DaveRicher-IMEX

View File

@@ -2,8 +2,6 @@ import { ApolloProvider } from "@apollo/client";
import { SplitFactoryProvider, SplitSdk } from "@splitsoftware/splitio-react";
import { ConfigProvider } from "antd";
import enLocale from "antd/es/locale/en_US";
import dayjs from "../utils/day";
import "dayjs/locale/en";
import React from "react";
import { useTranslation } from "react-i18next";
import GlobalLoadingBar from "../components/global-loading-bar/global-loading-bar.component";
@@ -19,8 +17,6 @@ if (import.meta.env.DEV) {
Userpilot.initialize("NX-69145f08");
}
dayjs.locale("en");
const config = {
core: {
authorizationKey: import.meta.env.VITE_APP_SPLIT_API,

View File

@@ -9,7 +9,7 @@ import { logImEXEvent } from "../../firebase/firebase.utils";
import { selectBodyshop } from "../../redux/user/user.selectors";
import CurrencyFormatter from "../../utils/CurrencyFormatter";
import { DateFormatter } from "../../utils/DateFormatter";
import { pageLimit } from "../../utils/config";
import { exportPageLimit } from "../../utils/config";
import { alphaSort, dateSort } from "../../utils/sorters";
import ExportLogsCountDisplay from "../export-logs-count-display/export-logs-count-display.component";
import PayableExportAll from "../payable-export-all-button/payable-export-all-button.component";
@@ -175,7 +175,7 @@ export function AccountingPayablesTableComponent({ bodyshop, loading, bills, ref
<Table
loading={loading}
dataSource={dataSource}
pagination={{ position: "top", pageSize: pageLimit }}
pagination={{ position: "top", pageSize: exportPageLimit }}
columns={columns}
rowKey="id"
onChange={handleTableChange}

View File

@@ -8,7 +8,7 @@ import { logImEXEvent } from "../../firebase/firebase.utils";
import { selectBodyshop } from "../../redux/user/user.selectors";
import CurrencyFormatter from "../../utils/CurrencyFormatter";
import { DateFormatter, DateTimeFormatter } from "../../utils/DateFormatter";
import { pageLimit } from "../../utils/config";
import { exportPageLimit } from "../../utils/config";
import { alphaSort, dateSort } from "../../utils/sorters";
import ExportLogsCountDisplay from "../export-logs-count-display/export-logs-count-display.component";
import OwnerNameDisplay, { OwnerNameDisplayFunction } from "../owner-name-display/owner-name-display.component";
@@ -177,7 +177,7 @@ export function AccountingPayablesTableComponent({ bodyshop, loading, payments,
<Table
loading={loading}
dataSource={dataSource}
pagination={{ position: "top", pageSize: pageLimit }}
pagination={{ position: "top", pageSize: exportPageLimit }}
columns={columns}
rowKey="id"
onChange={handleTableChange}

View File

@@ -1,18 +1,18 @@
import { Button, Card, Input, Space, Table } from "antd";
import React, { useState } from "react";
import { useTranslation } from "react-i18next";
import { connect } from "react-redux";
import { Link } from "react-router-dom";
import { createStructuredSelector } from "reselect";
import { logImEXEvent } from "../../firebase/firebase.utils";
import { selectBodyshop } from "../../redux/user/user.selectors";
import { exportPageLimit } from "../../utils/config";
import CurrencyFormatter from "../../utils/CurrencyFormatter";
import { DateFormatter } from "../../utils/DateFormatter";
import { alphaSort, dateSort, statusSort } from "../../utils/sorters";
import ExportLogsCountDisplay from "../export-logs-count-display/export-logs-count-display.component";
import JobExportButton from "../jobs-close-export-button/jobs-close-export-button.component";
import JobsExportAllButton from "../jobs-export-all-button/jobs-export-all-button.component";
import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
import { selectBodyshop } from "../../redux/user/user.selectors";
import { DateFormatter } from "../../utils/DateFormatter";
import ExportLogsCountDisplay from "../export-logs-count-display/export-logs-count-display.component";
import JobMarkSelectedExported from "../jobs-mark-selected-exported/jobs-mark-selected-exported";
import OwnerNameDisplay, { OwnerNameDisplayFunction } from "../owner-name-display/owner-name-display.component";
import QboAuthorizeComponent from "../qbo-authorize/qbo-authorize.component";
@@ -201,7 +201,7 @@ export function AccountingReceivablesTableComponent({ bodyshop, loading, jobs, r
<Table
loading={loading}
dataSource={dataSource}
pagination={{ position: "top" }}
pagination={{ position: "top", pageSize: exportPageLimit }}
columns={columns}
rowKey="id"
onChange={handleTableChange}

View File

@@ -7,10 +7,10 @@ import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
import { selectBodyshop } from "../../redux/user/user.selectors";
import CiecaSelect from "../../utils/Ciecaselect";
import InstanceRenderManager from "../../utils/instanceRenderMgr";
import BillLineSearchSelect from "../bill-line-search-select/bill-line-search-select.component";
import BilllineAddInventory from "../billline-add-inventory/billline-add-inventory.component";
import CurrencyInput from "../form-items-formatted/currency-form-item.component";
import InstanceRenderManager from "../../utils/instanceRenderMgr";
const mapStateToProps = createStructuredSelector({
//currentUser: selectCurrentUser
@@ -72,7 +72,14 @@ export function BillEnterModalLinesComponent({
<BillLineSearchSelect
disabled={disabled}
options={lineData}
style={{ width: "100%", minWidth: "10rem" }}
style={{
width: "20rem",
maxWidth: "20rem",
minWidth: "10rem",
whiteSpace: "normal",
height: "auto",
minHeight: "32px" // default height of Ant Design inputs
}}
allowRemoved={form.getFieldValue("is_credit_memo") || false}
onSelect={(value, opt) => {
setFieldsValue({
@@ -105,7 +112,7 @@ export function BillEnterModalLinesComponent({
title: t("billlines.fields.line_desc"),
dataIndex: "line_desc",
editable: true,
width: "20rem",
formItemProps: (field) => {
return {
key: `${field.index}line_desc`,
@@ -119,7 +126,7 @@ export function BillEnterModalLinesComponent({
]
};
},
formInput: (record, index) => <Input disabled={disabled} />
formInput: (record, index) => <Input.TextArea disabled={disabled} autoSize />
},
{
title: t("billlines.fields.quantity"),

View File

@@ -11,7 +11,7 @@ const BillLineSearchSelect = ({ options, disabled, allowRemoved, ...restProps },
disabled={disabled}
ref={ref}
showSearch
popupMatchSelectWidth={false}
popupMatchSelectWidth={true}
optionLabelProp={"name"}
// optionFilterProp="line_desc"
filterOption={(inputValue, option) => {
@@ -43,7 +43,7 @@ const BillLineSearchSelect = ({ options, disabled, allowRemoved, ...restProps },
item.oem_partno ? ` - ${item.oem_partno}` : ""
}${item.alt_partno ? ` (${item.alt_partno})` : ""}`.trim(),
label: (
<>
<div style={{ whiteSpace: 'normal', wordBreak: 'break-word' }}>
<span>
{`${item.removed ? `(REMOVED) ` : ""}${item.line_desc}${
item.oem_partno ? ` - ${item.oem_partno}` : ""
@@ -57,7 +57,7 @@ const BillLineSearchSelect = ({ options, disabled, allowRemoved, ...restProps },
<span style={{ float: "right", paddingleft: "1rem" }}>
{item.act_price ? `$${item.act_price && item.act_price.toFixed(2)}` : ``}
</span>
</>
</div>
)
}))
]}

View File

@@ -45,7 +45,7 @@ export function ChatPopupComponent({ chatVisible, selectedConversation, toggleCh
if (fcmToken) {
setpollInterval(0);
} else {
setpollInterval(60000);
setpollInterval(90000);
}
}, [fcmToken]);

View File

@@ -1,15 +1,17 @@
import { WarningFilled } from "@ant-design/icons";
import { Form, Input, InputNumber, Space } from "antd";
import dayjs from "../../utils/day";
import React from "react";
import { useTranslation } from "react-i18next";
import { DateFormatter } from "../../utils/DateFormatter";
import dayjs from "../../utils/day";
//import ContractLicenseDecodeButton from "../contract-license-decode-button/contract-license-decode-button.component";
import ContractStatusSelector from "../contract-status-select/contract-status-select.component";
import ContractsRatesChangeButton from "../contracts-rates-change-button/contracts-rates-change-button.component";
import CourtesyCarFuelSlider from "../courtesy-car-fuel-select/courtesy-car-fuel-select.component";
import FormDateTimePicker from "../form-date-time-picker/form-date-time-picker.component";
import DateTimePicker from "../form-date-time-picker/form-date-time-picker.component";
import {
default as DateTimePicker,
default as FormDateTimePicker
} from "../form-date-time-picker/form-date-time-picker.component";
import FormFieldsChanged from "../form-fields-changed-alert/form-fields-changed-alert.component";
import InputPhone, { PhoneItemFormatterValidation } from "../form-items-formatted/phone-form-item.component";
import LayoutFormRow from "../layout-form-row/layout-form-row.component";
@@ -18,10 +20,10 @@ import ContractFormJobPrefill from "./contract-form-job-prefill.component";
export default function ContractFormComponent({ form, create = false, selectedJobState, selectedCar }) {
const { t } = useTranslation();
return (
<div>
<FormFieldsChanged form={form} />
<>
{!create && <FormFieldsChanged form={form} />}
<LayoutFormRow>
{create ? null : (
{!create && (
<Form.Item
label={t("contracts.fields.status")}
name="status"
@@ -50,7 +52,7 @@ export default function ContractFormComponent({ form, create = false, selectedJo
<Form.Item label={t("contracts.fields.scheduledreturn")} name="scheduledreturn">
<FormDateTimePicker />
</Form.Item>
{create ? null : (
{!create && (
<Form.Item label={t("contracts.fields.actualreturn")} name="actualreturn">
<FormDateTimePicker />
</Form.Item>
@@ -122,7 +124,7 @@ export default function ContractFormComponent({ form, create = false, selectedJo
}}
</Form.Item>
)}
{create ? null : (
{!create && (
<Form.Item label={t("contracts.fields.kmend")} name="kmend">
<InputNumber />
</Form.Item>
@@ -145,25 +147,21 @@ export default function ContractFormComponent({ form, create = false, selectedJo
>
<CourtesyCarFuelSlider />
</Form.Item>
{create ? null : (
{!create && (
<Form.Item label={t("contracts.fields.fuelin")} name="fuelin" span={8}>
<CourtesyCarFuelSlider />
</Form.Item>
)}
</LayoutFormRow>
<div>
<Space wrap>
{selectedJobState && (
<div>
<ContractFormJobPrefill jobId={selectedJobState && selectedJobState[0]} form={form} />
</div>
)}
{
//<ContractLicenseDecodeButton form={form} />
}
</Space>
</div>
<LayoutFormRow header={t("contracts.labels.driverinformation")}>
<Space wrap>
{create && selectedJobState && (
<ContractFormJobPrefill jobId={selectedJobState && selectedJobState[0]} form={form} />
)}
{/* {<ContractLicenseDecodeButton form={form} />} */}
</Space>
</LayoutFormRow>
<LayoutFormRow noDivider={true}>
<Form.Item
label={t("contracts.fields.driver_dlnumber")}
name="driver_dlnumber"
@@ -183,9 +181,8 @@ export default function ContractFormComponent({ form, create = false, selectedJo
const dlExpiresBeforeReturn = dayjs(form.getFieldValue("driver_dlexpiry")).isBefore(
dayjs(form.getFieldValue("scheduledreturn"))
);
return (
<div>
<>
<Form.Item
label={t("contracts.fields.driver_dlexpiry")}
name="driver_dlexpiry"
@@ -204,11 +201,10 @@ export default function ContractFormComponent({ form, create = false, selectedJo
<span>{t("contracts.labels.dlexpirebeforereturn")}</span>
</Space>
)}
</div>
</>
);
}}
</Form.Item>
<Form.Item label={t("contracts.fields.driver_dlst")} name="driver_dlst">
<Input />
</Form.Item>
@@ -315,6 +311,6 @@ export default function ContractFormComponent({ form, create = false, selectedJo
<InputNumber precision={2} />
</Form.Item>
</LayoutFormRow>
</div>
</>
);
}

View File

@@ -1,10 +1,10 @@
import { Card, Table, Tag } from "antd";
import LoadingSkeleton from "../../loading-skeleton/loading-skeleton.component";
import { useTranslation } from "react-i18next";
import React, { useEffect, useState } from "react";
import dayjs from "../../../utils/day";
import DashboardRefreshRequired from "../refresh-required.component";
import axios from "axios";
import React, { useEffect, useState } from "react";
import { useTranslation } from "react-i18next";
import dayjs from "../../../utils/day";
import LoadingSkeleton from "../../loading-skeleton/loading-skeleton.component";
import DashboardRefreshRequired from "../refresh-required.component";
const fortyFiveDaysAgo = () => dayjs().subtract(45, "day").toLocaleString();
@@ -46,6 +46,11 @@ export default function JobLifecycleDashboardComponent({ data, bodyshop, ...card
dataIndex: "humanReadable",
key: "humanReadable"
},
{
title: t("job_lifecycle.columns.average_human_readable"),
dataIndex: "averageHumanReadable",
key: "averageHumanReadable"
},
{
title: t("job_lifecycle.columns.status_count"),
key: "statusCount",

View File

@@ -40,13 +40,11 @@ export function DmsLogEvents({ socket, logs, bodyshop }) {
function LogLevelHierarchy(level) {
switch (level) {
case "TRACE":
return "pink";
case "DEBUG":
return "orange";
case "INFO":
return "blue";
case "WARNING":
case "WARN":
return "yellow";
case "ERROR":
return "red";

View File

@@ -8,7 +8,7 @@ import { INSERT_EULA_ACCEPTANCE } from "../../graphql/user.queries";
import { useMutation } from "@apollo/client";
import { acceptEula } from "../../redux/user/user.actions";
import { useTranslation } from "react-i18next";
import day from "../../utils/day";
import dayjs from "../../utils/day";
import "./eula.styles.scss";
import DateTimePicker from "../form-date-time-picker/form-date-time-picker.component.jsx";
@@ -208,7 +208,7 @@ const EulaFormComponent = ({ form, handleChange, onFinish, t }) => (
{
required: true,
validator: (_, value) => {
if (day(value).isSame(day(), "day")) {
if (dayjs(value).isSame(dayjs(), "day")) {
return Promise.resolve();
}
return Promise.reject(new Error(t("eula.messages.date_accepted")));

View File

@@ -1,22 +1,40 @@
import { DatePicker } from "antd";
import { DatePicker, Space, TimePicker } from "antd";
import PropTypes from "prop-types";
import React, { useCallback, useState } from "react";
import { useTranslation } from "react-i18next";
import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
import { selectBodyshop } from "../../redux/user/user.selectors.js";
import dayjs from "../../utils/day";
import { fuzzyMatchDate } from "./formats.js";
const DateTimePicker = ({ value, onChange, onBlur, id, onlyFuture, onlyToday, isDateOnly = false, ...restProps }) => {
const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop
});
const DateTimePicker = ({
value,
onChange,
onBlur,
id,
onlyFuture,
onlyToday,
isDateOnly = false,
isSeparatedTime = false,
bodyshop,
...restProps
}) => {
const [isManualInput, setIsManualInput] = useState(false);
const { t } = useTranslation();
const handleChange = useCallback(
(newDate) => {
if (onChange) {
onChange(newDate || null);
onChange(bodyshop?.timezone && newDate ? dayjs(newDate).tz(bodyshop.timezone, true) : newDate);
}
setIsManualInput(false);
},
[onChange]
[onChange, bodyshop?.timezone]
);
const handleBlur = useCallback(
@@ -70,24 +88,57 @@ const DateTimePicker = ({ value, onChange, onBlur, id, onlyFuture, onlyToday, is
return (
<div onKeyDown={handleKeyDown} id={id} style={{ width: "100%" }}>
<DatePicker
showTime={
isDateOnly
? false
: {
format: "hh:mm a",
minuteStep: 15,
defaultValue: dayjs(dayjs(), "HH:mm:ss")
}
}
format={isDateOnly ? "MM/DD/YYYY" : "MM/DD/YYYY hh:mm a"}
value={value ? dayjs(value) : null}
onChange={handleChange}
placeholder={isDateOnly ? t("general.labels.date") : t("general.labels.datetime")}
onBlur={onBlur || handleBlur}
disabledDate={handleDisabledDate}
{...restProps}
/>
{isSeparatedTime && (
<Space direction="vertical" style={{ width: "100%" }}>
<DatePicker
showTime={false}
format="MM/DD/YYYY"
value={value ? dayjs(value) : null}
onChange={handleChange}
placeholder={t("general.labels.date")}
onBlur={handleBlur}
disabledDate={handleDisabledDate}
isDateOnly={true}
{...restProps}
/>
{value && (
<TimePicker
format="hh:mm a"
minuteStep={15}
defaultOpenValue={dayjs(value)
.hour(dayjs().hour())
.minute(Math.floor(dayjs().minute() / 15) * 15)
.second(0)}
onChange={(value) => {
handleChange(value);
onBlur();
}}
placeholder={t("general.labels.time")}
{...restProps}
/>
)}
</Space>
)}
{!isSeparatedTime && (
<DatePicker
showTime={
isDateOnly
? false
: {
format: "hh:mm a",
minuteStep: 15,
defaultValue: dayjs(dayjs(), "HH:mm:ss")
}
}
format={isDateOnly ? "MM/DD/YYYY" : "MM/DD/YYYY hh:mm a"}
value={value ? dayjs(value) : null}
onChange={handleChange}
placeholder={isDateOnly ? t("general.labels.date") : t("general.labels.datetime")}
onBlur={onBlur || handleBlur}
disabledDate={handleDisabledDate}
{...restProps}
/>
)}
</div>
);
};
@@ -99,7 +150,8 @@ DateTimePicker.propTypes = {
id: PropTypes.string,
onlyFuture: PropTypes.bool,
onlyToday: PropTypes.bool,
isDateOnly: PropTypes.bool
isDateOnly: PropTypes.bool,
isSeparatedTime: PropTypes.bool
};
export default React.memo(DateTimePicker);
export default connect(mapStateToProps, null)(DateTimePicker);

View File

@@ -3,13 +3,15 @@ import axios from "axios";
import _ from "lodash";
import React, { useState } from "react";
import { useTranslation } from "react-i18next";
import { Link } from "react-router-dom";
import { Link, useNavigate } from "react-router-dom";
import PhoneNumberFormatter from "../../utils/PhoneFormatter";
import OwnerNameDisplay, { OwnerNameDisplayFunction } from "../owner-name-display/owner-name-display.component";
import VehicleVinDisplay from "../vehicle-vin-display/vehicle-vin-display.component";
export default function GlobalSearchOs() {
const { t } = useTranslation();
const navigate = useNavigate();
const [loading, setLoading] = useState(false);
const [data, setData] = useState(false);
@@ -177,7 +179,18 @@ export default function GlobalSearchOs() {
};
return (
<AutoComplete options={data} onSearch={handleSearch} defaultActiveFirstOption onClear={() => setData([])}>
<AutoComplete
options={data}
onSearch={handleSearch}
onKeyDown={(e) => {
if (e.key !== "Enter") return;
const firstUrlForSearch = data?.[0]?.options?.[0]?.label?.props?.to;
if (!firstUrlForSearch) return;
navigate(firstUrlForSearch);
}}
defaultActiveFirstOption
onClear={() => setData([])}
>
<Input.Search
size="large"
placeholder={t("general.labels.globalsearch")}

View File

@@ -3,7 +3,7 @@ import { AutoComplete, Divider, Input, Space } from "antd";
import _ from "lodash";
import React from "react";
import { useTranslation } from "react-i18next";
import { Link } from "react-router-dom";
import { Link, useNavigate } from "react-router-dom";
import { GLOBAL_SEARCH_QUERY } from "../../graphql/search.queries";
import PhoneNumberFormatter from "../../utils/PhoneFormatter";
import AlertComponent from "../alert/alert.component";
@@ -13,6 +13,7 @@ import VehicleVinDisplay from "../vehicle-vin-display/vehicle-vin-display.compon
export default function GlobalSearch() {
const { t } = useTranslation();
const [callSearch, { loading, error, data }] = useLazyQuery(GLOBAL_SEARCH_QUERY);
const navigate = useNavigate();
const executeSearch = (v) => {
if (v && v.variables.search && v.variables.search !== "" && v.variables.search.length >= 3) callSearch(v);
@@ -20,7 +21,6 @@ export default function GlobalSearch() {
const debouncedExecuteSearch = _.debounce(executeSearch, 750);
const handleSearch = (value) => {
console.log("Handle Search");
debouncedExecuteSearch({ variables: { search: value } });
};
@@ -156,7 +156,17 @@ export default function GlobalSearch() {
if (error) return <AlertComponent message={error.message} type="error" />;
return (
<AutoComplete options={options} onSearch={handleSearch} defaultActiveFirstOption>
<AutoComplete
options={options}
onSearch={handleSearch}
defaultActiveFirstOption
onKeyDown={(e) => {
if (e.key !== "Enter") return;
const firstUrlForSearch = options?.[0]?.options?.[0]?.label?.props?.to;
if (!firstUrlForSearch) return;
navigate(firstUrlForSearch);
}}
>
<Input.Search
size="large"
placeholder={t("general.labels.globalsearch")}

View File

@@ -116,18 +116,15 @@ function Header({
const { t } = useTranslation();
const deleteBetaCookie = () => {
const cookieExists = document.cookie.split("; ").some((row) => row.startsWith(`betaSwitchImex=`));
if (cookieExists) {
const domain = window.location.hostname.split(".").slice(-2).join(".");
document.cookie = `betaSwitchImex=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/; domain=.${domain}`;
console.log(`betaSwitchImex cookie deleted`);
} else {
console.log(`betaSwitchImex cookie does not exist`);
}
};
deleteBetaCookie();
// const deleteBetaCookie = () => {
// const cookieExists = document.cookie.split("; ").some((row) => row.startsWith(`betaSwitchImex=`));
// if (cookieExists) {
// const domain = window.location.hostname.split(".").slice(-2).join(".");
// document.cookie = `betaSwitchImex=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/; domain=.${domain}`;
// }
// };
//
// deleteBetaCookie();
const accountingChildren = [];

View File

@@ -23,6 +23,7 @@ import ScheduleEventColor from "./schedule-event.color.component";
import ScheduleEventNote from "./schedule-event.note.component";
import { useMutation } from "@apollo/client";
import { UPDATE_APPOINTMENT } from "../../graphql/appointments.queries";
import ProductionListColumnComment from "../production-list-columns/production-list-columns.comment.component";
const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop
@@ -127,6 +128,9 @@ export function ScheduleEventComponent({
{(event.job && event.job.alt_transport) || ""}
<ScheduleAtChange job={event && event.job} />
</DataLabel>
<DataLabel label={t("jobs.fields.comment")} valueStyle={{ overflow: "hidden", textOverflow: "ellipsis" }}>
<ProductionListColumnComment record={event && event.job} />
</DataLabel>
<ScheduleEventNote event={event} />
</div>
) : (
@@ -316,6 +320,7 @@ export function ScheduleEventComponent({
})`}
{event.job && event.job.alt_transport && <div style={{ margin: ".1rem" }}>{event.job.alt_transport}</div>}
{event?.job?.comment && `C: ${event.job.comment}`}
</Space>
) : (
<div

View File

@@ -118,8 +118,7 @@ export function JobLinesComponent({
...(record.critical ? { boxShadow: " -.5em 0 0 #FFC107" } : {})
}
}),
sortOrder: state.sortedInfo.columnKey === "line_desc" && state.sortedInfo.order,
ellipsis: true
sortOrder: state.sortedInfo.columnKey === "line_desc" && state.sortedInfo.order
},
{
title: t("joblines.fields.oem_partno"),

View File

@@ -1,5 +1,5 @@
import React, { useCallback, useEffect, useState } from "react";
import day from "../../utils/day";
import dayjs from "../../utils/day";
import axios from "axios";
import { Badge, Card, Space, Table, Tag } from "antd";
import { gql, useQuery } from "@apollo/client";
@@ -72,7 +72,7 @@ export function JobLifecycleComponent({ job, statuses, ...rest }) {
dataIndex: "start",
key: "start",
render: (text) => DateTimeFormatterFunction(text),
sorter: (a, b) => day(a.start).unix() - day(b.start).unix()
sorter: (a, b) => dayjs(a.start).unix() - dayjs(b.start).unix()
},
{
title: t("job_lifecycle.columns.relative_start"),
@@ -90,7 +90,7 @@ export function JobLifecycleComponent({ job, statuses, ...rest }) {
}
return isEmpty(a.end) ? 1 : -1;
}
return day(a.end).unix() - day(b.end).unix();
return dayjs(a.end).unix() - dayjs(b.end).unix();
},
render: (text) => (isEmpty(text) ? t("job_lifecycle.content.not_available") : DateTimeFormatterFunction(text))
},

View File

@@ -2,7 +2,7 @@ import React, { useState } from "react";
import { useMutation } from "@apollo/client";
import { Button, Form, notification, Popover, Select, Space } from "antd";
import day from "../../utils/day";
import dayjs from "../../utils/day";
import { useTranslation } from "react-i18next";
import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
@@ -48,7 +48,7 @@ export function JobLineDispatchButton({
const result = await dispatchLines({
variables: {
partsDispatch: {
dispatched_at: day(),
dispatched_at: dayjs(),
employeeid: values.employeeid,
jobid: job.id,
dispatched_by: currentUser.email,
@@ -138,7 +138,11 @@ export function JobLineDispatchButton({
return (
<Popover open={visible} content={popMenu}>
<Button disabled={selectedLines.length === 0 || jobRO || disabled} loading={loading} onClick={() => setVisible(true)}>
<Button
disabled={selectedLines.length === 0 || jobRO || disabled}
loading={loading}
onClick={() => setVisible(true)}
>
{t("joblines.actions.dispatchparts", { count: selectedLines.length })}
</Button>
</Popover>

View File

@@ -45,7 +45,8 @@ export default function JobLineNotePopup({ jobline, disabled }) {
if (editing)
return (
<div>
<Input
<Input.TextArea
autoSize
autoFocus
suffix={loading ? <LoadingSpinner /> : null}
value={note}

View File

@@ -1,10 +1,10 @@
import { useSplitTreatments } from "@splitsoftware/splitio-react";
import { Form, Input, InputNumber, Modal, Select, Switch } from "antd";
import React, { useEffect } from "react";
import { useTranslation } from "react-i18next";
import InputCurrency from "../form-items-formatted/currency-form-item.component";
import LayoutFormRow from "../layout-form-row/layout-form-row.component";
import JoblinesPreset from "../job-lines-preset-button/job-lines-preset-button.component";
import { useSplitTreatments } from "@splitsoftware/splitio-react";
import LayoutFormRow from "../layout-form-row/layout-form-row.component";
import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
@@ -61,7 +61,7 @@ export function JobLinesUpsertModalComponent({ bodyshop, open, jobLine, handleCa
]}
name="line_desc"
>
<Input />
<Input.TextArea autoSize />
</Form.Item>
<JoblinesPreset form={form} />
</LayoutFormRow>

View File

@@ -1,5 +1,8 @@
import { useMutation } from "@apollo/client";
import { useSplitTreatments } from "@splitsoftware/splitio-react";
import { notification } from "antd";
import Axios from "axios";
import Dinero from "dinero.js";
import React, { useState } from "react";
import { useTranslation } from "react-i18next";
import { connect } from "react-redux";
@@ -7,13 +10,10 @@ import { createStructuredSelector } from "reselect";
import { INSERT_NEW_JOB_LINE, UPDATE_JOB_LINE } from "../../graphql/jobs-lines.queries";
import { toggleModalVisible } from "../../redux/modals/modals.actions";
import { selectJobLineEditModal } from "../../redux/modals/modals.selectors";
import { selectBodyshop } from "../../redux/user/user.selectors";
import CriticalPartsScan from "../../utils/criticalPartsScan";
import UndefinedToNull from "../../utils/undefinedtonull";
import JobLinesUpdsertModal from "./job-lines-upsert-modal.component";
import Axios from "axios";
import Dinero from "dinero.js";
import CriticalPartsScan from "../../utils/criticalPartsScan";
import { selectBodyshop } from "../../redux/user/user.selectors";
import { useSplitTreatments } from "@splitsoftware/splitio-react";
const mapStateToProps = createStructuredSelector({
jobLineEditModal: selectJobLineEditModal,
@@ -82,13 +82,15 @@ function JobLinesUpsertModalContainer({ jobLineEditModal, toggleModalVisible, bo
variables: {
lineId: jobLineEditModal.context.id,
line: {
...values,
prt_dsmk_m: Dinero({
amount: Math.round(values.act_price * 100)
...UndefinedToNull({
...values,
prt_dsmk_m: Dinero({
amount: Math.round(values.act_price * 100)
})
.percentage(Math.abs(values.prt_dsmk_p || 0))
.multiply(values.prt_dsmk_p >= 0 ? 1 : -1)
.toFormat(0.0)
})
.percentage(Math.abs(values.prt_dsmk_p || 0))
.multiply(values.prt_dsmk_p >= 0 ? 1 : -1)
.toFormat(0.0)
}
},
refetchQueries: ["GET_LINE_TICKET_BY_PK"]

View File

@@ -141,14 +141,16 @@ export function JobTotalsTableTotals({ bodyshop, job }) {
key: t("jobs.fields.ded_amt"),
total: job.job_totals.totals.custPayable.deductible
},
...(InstanceRenderManager({
imex: [{
key: t("jobs.fields.federal_tax_payable"),
total: job.job_totals.totals.custPayable.federal_tax
}],
...InstanceRenderManager({
imex: [
{
key: t("jobs.fields.federal_tax_payable"),
total: job.job_totals.totals.custPayable.federal_tax
}
],
rome: [],
promanager: "USE_ROME"
})),
}),
{
key: t("jobs.fields.other_amount_payable"),
total: job.job_totals.totals.custPayable.other_customer_amount
@@ -158,11 +160,32 @@ export function JobTotalsTableTotals({ bodyshop, job }) {
total: job.job_totals.totals.custPayable.dep_taxes
},
{
key: t("jobs.labels.total_cust_payable"),
total: job.job_totals.totals.custPayable.total,
bold: true
},
...(bodyshop.intellipay_config?.enable_cash_discount
? [
{
key: t("jobs.labels.total_cust_payable_cash_discount"),
total: job.job_totals.totals.custPayable.total,
bold: true
},
{
key: t("jobs.labels.total_cust_payable"),
total: Dinero(job.job_totals.totals.custPayable.total)
.add(
Dinero(job.job_totals.totals.custPayable.total).percentage(
bodyshop.intellipay_config?.cash_discount_percentage || 0
)
)
.toJSON(),
bold: true
}
]
: [
{
key: t("jobs.labels.total_cust_payable"),
total: job.job_totals.totals.custPayable.total,
bold: true
}
]),
{
key: t("jobs.labels.net_repairs"),
total: job.job_totals.totals.net_repairs,

View File

@@ -5,6 +5,7 @@ import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
import { selectJobReadOnly } from "../../redux/application/application.selectors";
import { selectBodyshop } from "../../redux/user/user.selectors";
import DateTimePicker from "../form-date-time-picker/form-date-time-picker.component.jsx";
import CurrencyInput from "../form-items-formatted/currency-form-item.component";
import FormItemEmail from "../form-items-formatted/email-form-item.component";
import FormItemPhone, { PhoneItemFormatterValidation } from "../form-items-formatted/phone-form-item.component";
@@ -12,7 +13,6 @@ import Car from "../job-damage-visual/job-damage-visual.component";
import JobsDetailChangeEstimator from "../jobs-detail-change-estimator/jobs-detail-change-estimator.component";
import JobsDetailChangeFileHandler from "../jobs-detail-change-filehandler/jobs-detail-change-filehandler.component";
import FormRow from "../layout-form-row/layout-form-row.component";
import DateTimePicker from "../form-date-time-picker/form-date-time-picker.component.jsx";
const mapStateToProps = createStructuredSelector({
jobRO: selectJobReadOnly,
@@ -185,6 +185,9 @@ export function JobsDetailGeneral({ bodyshop, jobRO, job, form }) {
<Form.Item label={t("jobs.fields.towin")} name="towin" valuePropName="checked">
<Switch disabled={jobRO} />
</Form.Item>
<Form.Item label={t("jobs.fields.tlos_ind")} name="tlos_ind" valuePropName="checked">
<Switch disabled={jobRO} />
</Form.Item>
</FormRow>
</Col>
<Col {...lossColDamage}>

View File

@@ -219,7 +219,7 @@ export function JobsExportAllButton({
};
return (
<Button onClick={handleQbxml} loading={loading} disabled={disabled}>
<Button onClick={handleQbxml} loading={loading} disabled={disabled || jobIds?.length > 10}>
{t("jobs.actions.exportselected")}
</Button>
);

View File

@@ -1,6 +1,6 @@
import { useMutation } from "@apollo/client";
import { Button, Card, Col, notification, Row, Table } from "antd";
import day from "../../utils/day";
import dayjs from "../../utils/day";
import React from "react";
import { useTranslation } from "react-i18next";
import { UPDATE_PARTS_DISPATCH_LINE } from "../../graphql/parts-dispatch.queries";
@@ -11,7 +11,7 @@ export default function PartsDispatchExpander({ dispatch, job }) {
const [updateDispatchLine] = useMutation(UPDATE_PARTS_DISPATCH_LINE);
const handleAccept = async ({ partsDispatchLineId }) => {
const accepted_at = day();
const accepted_at = dayjs();
const result = await updateDispatchLine({
variables: { id: partsDispatchLineId, line: { accepted_at } },
optimisticResponse: {

View File

@@ -242,7 +242,8 @@ export function PartsOrderListTableComponent({
title: t("general.labels.actions"),
dataIndex: "actions",
key: "actions",
render: (text, record) => recordActions(record, true)
render: (text, record) => recordActions(record, true),
id: "parts-order-list-table-actions"
}
];

View File

@@ -200,7 +200,7 @@ export function PayableExportAll({
);
return (
<Button onClick={handleQbxml} loading={loading} disabled={disabled}>
<Button onClick={handleQbxml} loading={loading} disabled={disabled || billids?.length > 10}>
{t("jobs.actions.exportselected")}
</Button>
);

View File

@@ -180,7 +180,7 @@ export function PaymentsExportAllButton({
};
return (
<Button onClick={handleQbxml} loading={loading} disabled={disabled}>
<Button onClick={handleQbxml} loading={loading} disabled={disabled || paymentIds?.length > 10}>
{t("jobs.actions.exportselected")}
</Button>
);

View File

@@ -1,12 +1,14 @@
import { SyncOutlined } from "@ant-design/icons";
import { useApolloClient } from "@apollo/client";
import Board from "./trello-board/index";
import { Button, notification, Skeleton, Space } from "antd";
import { PageHeader } from "@ant-design/pro-layout";
import { useApolloClient } from "@apollo/client";
import { Button, notification, Skeleton, Space } from "antd";
import cloneDeep from "lodash/cloneDeep";
import isEqual from "lodash/isEqual";
import React, { useCallback, useEffect, useMemo, useState } from "react";
import { useTranslation } from "react-i18next";
import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
import NoteUpsertModal from "../../components/note-upsert-modal/note-upsert-modal.container";
import { logImEXEvent } from "../../firebase/firebase.utils";
import { generate_UPDATE_JOB_KANBAN } from "../../graphql/jobs.queries";
import { insertAuditTrail } from "../../redux/application/application.actions";
@@ -15,14 +17,13 @@ import AuditTrailMapping from "../../utils/AuditTrailMappings";
import IndefiniteLoading from "../indefinite-loading/indefinite-loading.component";
import ProductionBoardFilters from "../production-board-filters/production-board-filters.component";
import ProductionListDetailComponent from "../production-list-detail/production-list-detail.component";
import ProductionListPrint from "../production-list-table/production-list-print.component.jsx";
import CardColorLegend from "./production-board-kanban-card-color-legend.component.jsx";
import "./production-board-kanban.styles.scss";
import { createBoardData } from "./production-board-kanban.utils.js";
import ProductionBoardKanbanSettings from "./settings/production-board-kanban.settings.component.jsx";
import cloneDeep from "lodash/cloneDeep";
import isEqual from "lodash/isEqual";
import { defaultFilters, mergeWithDefaults } from "./settings/defaultKanbanSettings.js";
import NoteUpsertModal from "../../components/note-upsert-modal/note-upsert-modal.container";
import ProductionBoardKanbanSettings from "./settings/production-board-kanban.settings.component.jsx";
import Board from "./trello-board/index";
const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop
@@ -185,7 +186,7 @@ function ProductionBoardKanbanComponent({ data, bodyshop, refetch, insertAuditTr
const cardSettings = useMemo(() => {
const kanbanSettings = associationSettings?.kanban_settings;
return mergeWithDefaults(kanbanSettings);
}, [associationSettings]);
}, [associationSettings?.kanban_settings]);
const handleSettingsChange = () => {
setFilter(defaultFilters);
@@ -214,6 +215,7 @@ function ProductionBoardKanbanComponent({ data, bodyshop, refetch, insertAuditTr
bodyshop={bodyshop}
data={data}
/>
<ProductionListPrint />
</Space>
}
/>

View File

@@ -23,6 +23,9 @@ function ProductionBoardKanbanContainer({ bodyshop, currentUser, subscriptionTyp
const fired = useRef(false);
const client = useApolloClient();
const { socket } = useContext(SocketContext); // Get the socket from context
const reconnectTimeout = useRef(null); // To store the reconnect timeout
const disconnectTime = useRef(null); // To track disconnection time
const acceptableReconnectTime = 2000; // 2 seconds threshold
const {
treatments: { Websocket_Production }
@@ -126,19 +129,44 @@ function ProductionBoardKanbanContainer({ bodyshop, currentUser, subscriptionTyp
}
};
const handleReconnect = () => {
//If we were disconnected from the board, we missed stuff. We need to refresh it entirely.
if (refetch) refetch();
const handleDisconnect = () => {
// Capture the disconnection time
disconnectTime.current = Date.now();
};
// Listen for 'job-changed' events
const handleReconnect = () => {
const reconnectTime = Date.now();
const disconnectionDuration = reconnectTime - disconnectTime.current;
// Only refetch if disconnection was longer than the acceptable reconnect time
if (disconnectionDuration >= acceptableReconnectTime) {
if (!reconnectTimeout.current) {
reconnectTimeout.current = setTimeout(() => {
const randomDelay = Math.floor(Math.random() * (30000 - 10000 + 1)) + 10000; // Random delay between 10 and 30 seconds
setTimeout(() => {
if (refetch) refetch().catch((err) => console.error(`Issue `));
reconnectTimeout.current = null; // Clear the timeout reference after refetch
}, randomDelay);
}, acceptableReconnectTime);
}
}
};
// Listen for 'job-changed', 'disconnect', and 'connect' events
socket.on("production-job-updated", handleJobUpdates);
socket.on("reconnect", handleReconnect);
socket.on("disconnect", handleDisconnect);
socket.on("connect", handleReconnect);
// Clean up on unmount or when dependencies change
return () => {
socket.off("production-job-updated", handleJobUpdates);
socket.off("reconnect", handleReconnect);
socket.off("disconnect", handleDisconnect);
socket.off("connect", handleReconnect);
if (reconnectTimeout.current) {
clearTimeout(reconnectTimeout.current);
}
};
}, [subscriptionEnabled, socket, bodyshop, data, client, refetch]);
}, [subscriptionEnabled, socket, bodyshop, client, refetch]);
const filteredAssociationSettings = useMemo(() => {
return associationSettings?.associations[0] || null;

View File

@@ -1,15 +1,66 @@
import InstanceRenderManager from "../../../utils/instanceRenderMgr.js";
const statisticsItems = [
{ id: 0, name: "totalHrs", label: "total_hours_in_production" },
{ id: 1, name: "totalAmountInProduction", label: "total_amount_in_production" },
{ id: 2, name: "totalLAB", label: "total_lab_in_production" },
{ id: 3, name: "totalLAR", label: "total_lar_in_production" },
{ id: 4, name: "jobsInProduction", label: "jobs_in_production" },
{ id: 5, name: "totalHrsOnBoard", label: "total_hours_on_board" },
{ id: 6, name: "totalAmountOnBoard", label: "total_amount_on_board" },
{ id: 7, name: "totalLABOnBoard", label: "total_lab_on_board" },
{ id: 8, name: "totalLAROnBoard", label: "total_lar_on_board" },
{ id: 9, name: "jobsOnBoard", label: "total_jobs_on_board" },
{ id: 10, name: "tasksOnBoard", label: "tasks_on_board" },
{
id: 5,
name: "totalHrsOnBoard",
label: InstanceRenderManager({
imex: "total_hours_in_view",
rome: "total_hours_on_board",
promanager: "total_hours_on_board"
})
},
{
id: 6,
name: "totalAmountOnBoard",
label: InstanceRenderManager({
imex: "total_amount_in_view",
rome: "total_amount_on_board",
promanager: "total_amount_on_board"
})
},
{
id: 7,
name: "totalLABOnBoard",
label: InstanceRenderManager({
imex: "total_lab_in_view",
rome: "total_lab_on_board",
promanager: "total_lab_on_board"
})
},
{
id: 8,
name: "totalLAROnBoard",
label: InstanceRenderManager({
imex: "total_lar_in_view",
rome: "total_lar_on_board",
promanager: "total_lar_on_board"
})
},
{
id: 9,
name: "jobsOnBoard",
label: InstanceRenderManager({
imex: "total_jobs_in_view",
rome: "total_jobs_on_board",
promanager: "total_jobs_on_board"
})
},
{
id: 10,
name: "tasksOnBoard",
label: InstanceRenderManager({
imex: "tasks_in_view",
rome: "tasks_on_board",
promanager: "tasks_on_board"
})
},
{ id: 11, name: "tasksInProduction", label: "tasks_in_production" }
];

View File

@@ -21,25 +21,26 @@ export function ProductionListColumnStatus({ record, bodyshop, insertAuditTrail
const [loading, setLoading] = useState(false);
const handleSetStatus = async (e) => {
logImEXEvent("production_change_status");
// e.stopPropagation();
setLoading(true);
const { key } = e;
await updateJob({
variables: {
jobId: record.id,
job: {
status: key
if (bodyshop.md_ro_statuses.production_statuses.includes(record.status) && !bodyshop.md_ro_statuses.post_production_statuses.includes(record.status)) {
logImEXEvent("production_change_status");
// e.stopPropagation();
setLoading(true);
const { key } = e;
await updateJob({
variables: {
jobId: record.id,
job: {
status: key
}
}
}
});
insertAuditTrail({
jobid: record.id,
operation: AuditTrailMapping.jobstatuschange(key),
type: "jobstatuschange"
});
setLoading(false);
});
insertAuditTrail({
jobid: record.id,
operation: AuditTrailMapping.jobstatuschange(key),
type: "jobstatuschange"
});
setLoading(false);
}
};
const menu = {

View File

@@ -457,41 +457,42 @@ export function ProductionListConfigManager({
value={activeView}
disabled={open || isAddingNewProfile} // Disable the Select box when the popover is open or adding a new profile
>
{bodyshop.production_config
.slice()
.sort((a, b) =>
a.name === t("production.constants.main_profile")
? -1
: b.name === t("production.constants.main_profile")
? 1
: 0
) //
.map((config) => (
<Select.Option key={config.name} label={config.name}>
<div style={{ display: "flex", justifyContent: "space-between", alignItems: "center" }}>
<span
style={{
flex: 1,
maxWidth: "80%",
marginRight: "1rem",
textOverflow: "ellipsis"
}}
>
{config.name}
</span>
{config.name !== t("production.constants.main_profile") && (
<Popconfirm
placement="right"
title={t("general.labels.areyousure")}
onConfirm={() => handleTrash(config.name)}
onCancel={(e) => e.stopPropagation()}
{bodyshop?.production_config &&
bodyshop.production_config
.slice()
.sort((a, b) =>
a.name === t("production.constants.main_profile")
? -1
: b.name === t("production.constants.main_profile")
? 1
: 0
) //
.map((config) => (
<Select.Option key={config.name} label={config.name}>
<div style={{ display: "flex", justifyContent: "space-between", alignItems: "center" }}>
<span
style={{
flex: 1,
maxWidth: "80%",
marginRight: "1rem",
textOverflow: "ellipsis"
}}
>
<DeleteOutlined onClick={(e) => e.stopPropagation()} />
</Popconfirm>
)}
</div>
</Select.Option>
))}
{config.name}
</span>
{config.name !== t("production.constants.main_profile") && (
<Popconfirm
placement="right"
title={t("general.labels.areyousure")}
onConfirm={() => handleTrash(config.name)}
onCancel={(e) => e.stopPropagation()}
>
<DeleteOutlined onClick={(e) => e.stopPropagation()} />
</Popconfirm>
)}
</div>
</Select.Option>
))}
<Select.Option key="add_new" label={t("production.labels.addnewprofile")}>
<div style={{ display: "flex", alignItems: "center" }}>
<PlusOutlined style={{ marginRight: "0.5rem" }} />

View File

@@ -51,8 +51,8 @@ export function ProductionListTable({ loading, data, refetch, bodyshop, technici
const initialColumnsRef = useRef(
(initialStateRef.current &&
bodyshop.production_config
.find((p) => p.name === defaultView)
bodyshop?.production_config
?.find((p) => p.name === defaultView)
?.columns.columnKeys.map((k) => {
return {
...ProductionListColumns({
@@ -76,7 +76,7 @@ export function ProductionListTable({ loading, data, refetch, bodyshop, technici
const { t } = useTranslation();
const matchingColumnConfig = useMemo(() => {
return bodyshop.production_config.find((p) => p.name === defaultView);
return bodyshop?.production_config?.find((p) => p.name === defaultView);
}, [bodyshop.production_config, defaultView]);
useEffect(() => {

View File

@@ -1,5 +1,5 @@
import { useApolloClient, useQuery, useSubscription } from "@apollo/client";
import React, { useContext, useEffect, useState } from "react";
import React, { useContext, useEffect, useState, useRef } from "react";
import {
QUERY_EXACT_JOB_IN_PRODUCTION,
QUERY_EXACT_JOBS_IN_PRODUCTION,
@@ -16,6 +16,10 @@ export default function ProductionListTableContainer({ bodyshop, subscriptionTyp
const client = useApolloClient();
const { socket } = useContext(SocketContext);
const [joblist, setJoblist] = useState([]);
const reconnectTimeout = useRef(null); // To store the reconnect timeout
const disconnectTime = useRef(null); // To store the time of disconnection
const acceptableReconnectTime = 2000; // 2 seconds threshold
// Get Split treatment
const {
@@ -128,18 +132,47 @@ export default function ProductionListTableContainer({ bodyshop, subscriptionTyp
}
}
};
const handleReconnect = () => {
//If we were disconnected from the board, we missed stuff. We need to refresh it entirely.
if (refetch) refetch();
const handleDisconnect = () => {
// Capture the time when the disconnection happens
disconnectTime.current = Date.now();
};
// Listen for 'production-job-updated' events
const handleReconnect = () => {
// Calculate how long the disconnection lasted
const reconnectTime = Date.now();
const disconnectionDuration = reconnectTime - disconnectTime.current;
// If disconnection lasted less than acceptable reconnect time, do nothing
if (disconnectionDuration < acceptableReconnectTime) {
return;
}
// Schedule a refetch with a random delay between 10 and 30 seconds
if (!reconnectTimeout.current) {
reconnectTimeout.current = setTimeout(() => {
const randomDelay = Math.floor(Math.random() * (30000 - 10000 + 1)) + 10000; // Random delay between 10 and 30 seconds
setTimeout(() => {
if (refetch) refetch();
reconnectTimeout.current = null; // Clear the timeout reference after refetch
}, randomDelay);
}, acceptableReconnectTime);
}
};
// Listen for 'production-job-updated', 'disconnect', and 'connect' events
socket.on("production-job-updated", handleJobUpdates);
socket.on("reconnect", handleReconnect);
socket.on("disconnect", handleDisconnect);
socket.on("connect", handleReconnect);
// Clean up on unmount or when dependencies change
return () => {
socket.off("production-job-updated", handleJobUpdates);
socket.off("reconnect", handleReconnect);
socket.off("disconnect", handleDisconnect);
socket.off("connect", handleReconnect);
if (reconnectTimeout.current) {
clearTimeout(reconnectTimeout.current);
}
};
}, [subscriptionEnabled, socket, bodyshop, client, refetch]);
@@ -151,6 +184,7 @@ export default function ProductionListTableContainer({ bodyshop, subscriptionTyp
fetchPolicy: "network-only"
});
};
const getUpdatedJobsData = (jobIds) => {
client.query({
query: QUERY_EXACT_JOBS_IN_PRODUCTION,

View File

@@ -120,14 +120,6 @@ var formats = {
};
const localizer = (dayjsLib) => {
// load dayjs plugins
dayjsLib.extend(isBetween);
dayjsLib.extend(isSameOrAfter);
dayjsLib.extend(isSameOrBefore);
dayjsLib.extend(localeData);
dayjsLib.extend(localizedFormat);
dayjsLib.extend(minMax);
dayjsLib.extend(utc);
var locale = function locale(dj, c) {
return c ? dj.locale(c) : dj;
};
@@ -136,7 +128,8 @@ const localizer = (dayjsLib) => {
// then use the timezone aware version
//TODO This was the issue entirely...
// var dayjs = dayjsLib.tz ? dayjsLib.tz : dayjsLib;
// var dayjs = dayjsLib.tz ? dayjsLib.tz : dayjsLib;
var dayjs = dayjsLib;
function getTimezoneOffset(date) {

View File

@@ -20,6 +20,7 @@ const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop,
problemJobs: selectProblemJobs
});
const localizer = local(dayjs);
export function ScheduleCalendarWrapperComponent({

View File

@@ -1,6 +1,5 @@
import { Button, Col, Form, Input, Row, Select, Space, Switch, Typography } from "antd";
import axios from "axios";
import dayjs from "../../utils/day";
import React, { useState } from "react";
import { useTranslation } from "react-i18next";
import { connect } from "react-redux";
@@ -8,13 +7,14 @@ import { createStructuredSelector } from "reselect";
import { calculateScheduleLoad } from "../../redux/application/application.actions";
import { selectBodyshop } from "../../redux/user/user.selectors";
import { DateFormatter } from "../../utils/DateFormatter";
import dayjs from "../../utils/day";
import InstanceRenderManager from "../../utils/instanceRenderMgr";
import DateTimePicker from "../form-date-time-picker/form-date-time-picker.component";
import EmailInput from "../form-items-formatted/email-form-item.component";
import LayoutFormRow from "../layout-form-row/layout-form-row.component";
import ScheduleDayViewContainer from "../schedule-day-view/schedule-day-view.container";
import ScheduleExistingAppointmentsList from "../schedule-existing-appointments-list/schedule-existing-appointments-list.component";
import "./schedule-job-modal.scss";
import InstanceRenderManager from "../../utils/instanceRenderMgr";
const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop
@@ -84,7 +84,7 @@ export function ScheduleJobModalComponent({
}
]}
>
<DateTimePicker onBlur={handleDateBlur} onlyFuture />
<DateTimePicker onBlur={handleDateBlur} onlyFuture isSeparatedTime />
</Form.Item>
<Form.Item
name="scheduled_completion"

View File

@@ -4,12 +4,12 @@ import ScoreboardChart from "../scoreboard-chart/scoreboard-chart.component";
import ScoreboardLastDays from "../scoreboard-last-days/scoreboard-last-days.component";
import ScoreboardTargetsTable from "../scoreboard-targets-table/scoreboard-targets-table.component";
import { useApolloClient, useQuery } from "@apollo/client";
import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
import { GET_BLOCKED_DAYS, QUERY_SCOREBOARD } from "../../graphql/scoreboard.queries";
import { selectBodyshop } from "../../redux/user/user.selectors";
import dayjs from "../../utils/day";
import { useApolloClient, useQuery } from "@apollo/client";
import { GET_BLOCKED_DAYS, QUERY_SCOREBOARD } from "../../graphql/scoreboard.queries";
const mapStateToProps = createStructuredSelector({
//currentUser: selectCurrentUser
@@ -26,7 +26,7 @@ export function ScoreboardDisplayComponent({ bodyshop }) {
start: dayjs().startOf("month"),
end: dayjs().endOf("month")
},
pollInterval: 60000
pollInterval: 60000*5
});
const { data } = scoreboardSubscription;

View File

@@ -1,13 +1,13 @@
import { useQuery } from "@apollo/client";
import { Col, Row } from "antd";
import _ from "lodash";
import dayjs from "../../utils/day";
import React, { useMemo } from "react";
import { useTranslation } from "react-i18next";
import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
import { QUERY_TIME_TICKETS_IN_RANGE_SB } from "../../graphql/timetickets.queries";
import { selectBodyshop } from "../../redux/user/user.selectors";
import dayjs from "../../utils/day";
import AlertComponent from "../alert/alert.component";
import LoadingSpinner from "../loading-spinner/loading-spinner.component";
import * as Utils from "../scoreboard-targets-table/scoreboard-targets-table.util";
@@ -86,7 +86,7 @@ export function ScoreboardTimeTicketsStats({ bodyshop }) {
},
fetchPolicy: "network-only",
nextFetchPolicy: "network-only",
pollInterval: 60000,
pollInterval: 60000*5,
skip: !fixedPeriods
});

View File

@@ -1,11 +1,11 @@
import { useQuery } from "@apollo/client";
import { Col, Row } from "antd";
import _ from "lodash";
import dayjs from "../../utils/day";
import queryString from "query-string";
import React, { useMemo } from "react";
import { useLocation } from "react-router-dom";
import { QUERY_TIME_TICKETS_IN_RANGE_SB } from "../../graphql/timetickets.queries";
import dayjs from "../../utils/day";
import AlertComponent from "../alert/alert.component";
import LoadingSpinner from "../loading-spinner/loading-spinner.component";
import * as Utils from "../scoreboard-targets-table/scoreboard-targets-table.util";
@@ -68,7 +68,7 @@ export default function ScoreboardTimeTickets() {
},
fetchPolicy: "network-only",
nextFetchPolicy: "network-only",
pollInterval: 60000,
pollInterval: 60000*5,
skip: !fixedPeriods
});

View File

@@ -142,7 +142,7 @@ export function ShopInfoComponent({ bodyshop, form, saveLoading }) {
rome: [
{
key: "intellipay",
label: t("bodyshop.labels.intellipay"),
label: InstanceRenderManager({ rome: t("bodyshop.labels.romepay"), imex: t("bodyshop.labels.imexpay") }),
children: <ShopInfoIntellipay form={form} />
}
],

View File

@@ -676,7 +676,7 @@ export function ShopInfoGeneral({ form, bodyshop }) {
}
]}
>
<Input.TextArea rows={3} />
<Input.TextArea autoSize />
</Form.Item>
<Space wrap>
<DeleteFilled
@@ -737,7 +737,7 @@ export function ShopInfoGeneral({ form, bodyshop }) {
}
]}
>
<Input.TextArea rows={3} />
<Input.TextArea autoSize />
</Form.Item>
<Space wrap>
<DeleteFilled
@@ -1187,7 +1187,7 @@ export function ShopInfoGeneral({ form, bodyshop }) {
key={`${index}line_desc`}
name={[field.name, "line_desc"]}
>
<Input />
<Input.TextArea autoSize />
</Form.Item>
<Form.Item
label={t("joblines.fields.mod_lbr_ty")}
@@ -1330,7 +1330,7 @@ export function ShopInfoGeneral({ form, bodyshop }) {
}
]}
>
<Input />
<Input.TextArea autoSize />
</Form.Item>
<Space wrap>

View File

@@ -39,14 +39,13 @@ export function ShopInfoIntellipay({ bodyshop, form }) {
</Form.Item>
<Form.Item
label={t("bodyshop.fields.intellipay_config.cash_discount_percentage")}
valuePropName="checked"
dependencies={[["intellipay_config", "enable_cash_discount"]]}
name={["intellipay_config", "cash_discount_percentage"]}
rules={[
({ getFieldsValue }) => ({ required: form.getFieldValue(["intellipay_config", "enable_cash_discount"]) })
]}
>
<InputNumber min={0} max={100} precision={1} suffix='%'/>
<InputNumber min={0} max={100} precision={1} suffix="%" />
</Form.Item>
</LayoutFormRow>
</>

View File

@@ -1,10 +1,3 @@
import { Button, Card, Space, Switch, Table } from "antd";
import queryString from "query-string";
import React, { useCallback, useEffect } from "react";
import { useTranslation } from "react-i18next";
import { Link, useLocation, useNavigate } from "react-router-dom";
import { pageLimit } from "../../utils/config";
import dayjs from "../../utils/day";
import {
CheckCircleFilled,
CheckCircleOutlined,
@@ -15,9 +8,16 @@ import {
PlusCircleFilled,
SyncOutlined
} from "@ant-design/icons";
import { DateFormatter, DateTimeFormatter } from "../../utils/DateFormatter.jsx";
import { Button, Card, Space, Switch, Table } from "antd";
import queryString from "query-string";
import React, { useCallback, useEffect } from "react";
import { useTranslation } from "react-i18next";
import { connect } from "react-redux";
import { Link, useLocation, useNavigate } from "react-router-dom";
import { setModalContext } from "../../redux/modals/modals.actions";
import { pageLimit } from "../../utils/config";
import { DateFormatter, DateTimeFormatter } from "../../utils/DateFormatter.jsx";
import dayjs from "../../utils/day";
/**
* Task List Component
@@ -140,6 +140,17 @@ function TaskListComponent({
render: (text, record) => <DateTimeFormatter>{record.created_at}</DateTimeFormatter>
});
columns.push({
title: t("tasks.fields.created_by"),
dataIndex: "created_by",
key: "created_by",
width: "8%",
defaultSortOrder: "descend",
sorter: true,
sortOrder: sortcolumn === "created_by" && sortorder,
render: (text, record) => record.created_by
});
if (!onlyMine) {
columns.push({
title: t("tasks.fields.assigned_to"),
@@ -155,65 +166,70 @@ function TaskListComponent({
});
}
if (showRo) {
columns.push({
title: t("tasks.fields.job.ro_number"),
dataIndex: ["job", "ro_number"],
key: "job.ro_number",
width: "8%",
render: (text, record) =>
record.job ? (
<Link to={`/manage/jobs/${record.job.id}?tab=tasks`}>{record.job.ro_number || t("general.labels.na")}</Link>
) : (
t("general.labels.na")
)
});
}
columns.push({
title: t("tasks.fields.related_items"),
key: "related_items",
width: "12%",
render: (text, record) => {
const items = [];
// Job
if (showRo && record.job) {
items.push(
<Link key="job" to={`/manage/jobs/${record.job.id}?tab=tasks`}>
{t("tasks.fields.job.ro_number")}: {record.job.ro_number}
</Link>
);
}
if (showRo && !record.job) {
items.push(`${t("tasks.fields.job.ro_number")}: ${t("general.labels.na")}`);
}
// Jobline
if (record.jobline?.line_desc) {
items.push(
<span key="jobline">
{t("tasks.fields.jobline")}: {record.jobline.line_desc}
</span>
);
}
// Parts Order
if (record.parts_order) {
const { order_number, vendor } = record.parts_order;
const partsOrderText =
order_number && vendor?.name ? `${order_number} - ${vendor.name}` : t("general.labels.na");
items.push(
<Link
key="parts_order"
to={`/manage/jobs/${record.job.id}?partsorderid=${record.parts_order.id}&tab=partssublet`}
>
{t("tasks.fields.parts_order")}: {partsOrderText}
</Link>
);
}
// Bill
if (record.bill) {
const { invoice_number, vendor } = record.bill;
const billText = invoice_number && vendor?.name ? `${invoice_number} - ${vendor.name}` : t("general.labels.na");
items.push(
<Link key="bill" to={`/manage/jobs/${record.job.id}?billid=${record.bill.id}&tab=partssublet`}>
{t("tasks.fields.bill")}: {billText}
</Link>
);
}
return items.length > 0 ? <Space direction="vertical">{items}</Space> : null;
}
});
columns.push(
{
title: t("tasks.fields.jobline"),
dataIndex: ["jobline", "id"],
key: "jobline.id",
width: "8%",
render: (text, record) => record?.jobline?.line_desc || ""
},
{
title: t("tasks.fields.parts_order"),
dataIndex: ["parts_order", "id"],
key: "part_order.id",
width: "8%",
render: (text, record) =>
record.parts_order ? (
<Link to={`/manage/jobs/${record.job.id}?partsorderid=${record.parts_order.id}&tab=partssublet`}>
{record.parts_order.order_number && record.parts_order.vendor && record.parts_order.vendor.name
? `${record.parts_order.order_number} - ${record.parts_order.vendor.name}`
: t("general.labels.na")}
</Link>
) : (
""
)
},
{
title: t("tasks.fields.bill"),
dataIndex: ["bill", "id"],
key: "bill.id",
width: "10%",
render: (text, record) =>
record.bill ? (
<Link to={`/manage/jobs/${record.job.id}?billid=${record.bill.id}&tab=partssublet`}>
{record.bill.invoice_number && record.bill.vendor && record.bill.vendor.name
? `${record.bill.invoice_number} - ${record.bill.vendor.name}`
: t("general.labels.na")}
</Link>
) : (
""
)
},
{
title: t("tasks.fields.title"),
dataIndex: "title",
key: "title",
minWidth: "20%",
sorter: true,
sortOrder: sortcolumn === "title" && sortorder
},
@@ -247,7 +263,7 @@ function TaskListComponent({
{
title: t("tasks.fields.actions"),
key: "toggleCompleted",
width: "5%",
width: "8%",
render: (text, record) => (
<Space direction="horizontal">
<Button

View File

@@ -39,7 +39,7 @@ export function TimeTicketList({
extra
}) {
const [state, setState] = useState({
sortedInfo: {},
sortedInfo: { columnKey: 'date', order: 'descend' },
filteredInfo: { text: "" }
});

View File

@@ -1,7 +1,7 @@
import { useMutation, useQuery } from "@apollo/client";
import { Button, Form, Modal, notification, Space } from "antd";
import { PageHeader } from "@ant-design/pro-layout";
import dayjs from "../../utils/day";
import { useMutation, useQuery } from "@apollo/client";
import { useSplitTreatments } from "@splitsoftware/splitio-react";
import { Button, Form, Modal, notification, Space } from "antd";
import React, { useEffect, useState } from "react";
import { useTranslation } from "react-i18next";
import { connect } from "react-redux";
@@ -11,9 +11,9 @@ import { INSERT_NEW_TIME_TICKET, UPDATE_TIME_TICKET } from "../../graphql/timeti
import { toggleModalVisible } from "../../redux/modals/modals.actions";
import { selectTimeTicket } from "../../redux/modals/modals.selectors";
import { selectBodyshop } from "../../redux/user/user.selectors";
import TimeTicketModalComponent from "./time-ticket-modal.component";
import dayjs from "../../utils/day";
import TimeTicketsCommitToggleComponent from "../time-tickets-commit-toggle/time-tickets-commit-toggle.component";
import { useSplitTreatments } from "@splitsoftware/splitio-react";
import TimeTicketModalComponent from "./time-ticket-modal.component";
const mapStateToProps = createStructuredSelector({
timeTicketModal: selectTimeTicket,
@@ -87,7 +87,7 @@ export function TimeTicketModalContainer({ timeTicketModal, toggleModalVisible,
if (enterAgain) {
//Capture the existing information and repopulate it.
const prev = form.getFieldsValue(["date", "employeeid"]);
const prev = form.getFieldsValue(["date", "employeeid", "flat_rate"]);
form.resetFields();

View File

@@ -1,6 +1,6 @@
import { useMutation } from "@apollo/client";
import { Button, notification } from "antd";
import day from "../../utils/day";
import dayjs from "../../utils/day";
import React, { useState } from "react";
import { useTranslation } from "react-i18next";
import { connect } from "react-redux";
@@ -29,7 +29,7 @@ export function TimeTicketsCommit({ bodyshop, currentUser, timeticket, disabled,
? { commited_by: null, committed_at: null }
: {
commited_by: currentUser.email,
committed_at: day()
committed_at: dayjs()
};
const result = await updateTimeTicket({

View File

@@ -1,6 +1,6 @@
import { useMutation } from "@apollo/client";
import { Button, notification } from "antd";
import day from "../../utils/day";
import dayjs from "../../utils/day";
import React, { useState } from "react";
import { useTranslation } from "react-i18next";
import { connect } from "react-redux";
@@ -34,7 +34,7 @@ export function TimeTicketsCommit({
timeticketIds: timetickets.map((ticket) => ticket.id),
timeticket: {
commited_by: currentUser.email,
committed_at: day()
committed_at: dayjs()
}
},
update(cache) {
@@ -47,7 +47,7 @@ export function TimeTicketsCommit({
return {
...ticket,
commited_by: currentUser.email,
committed_at: day()
committed_at: dayjs()
};
}
return ticket;

View File

@@ -1,7 +1,7 @@
import { useApolloClient } from "@apollo/client";
import { Button, notification } from "antd";
import _ from "lodash";
import day from "../../utils/day";
import dayjs from "../../utils/day";
import React, { useState } from "react";
import { useTranslation } from "react-i18next";
import { connect } from "react-redux";
@@ -49,7 +49,7 @@ export function TtApproveButton({
})),
approvalIds: selectedTickets,
approvalUpdate: {
approved_at: day(),
approved_at: dayjs(),
approved_by: currentUser.email
}
}

View File

@@ -1,8 +1,9 @@
import { useEffect, useState, useRef } from "react";
import { useEffect, useRef, useState } from "react";
import SocketIO from "socket.io-client";
import { auth } from "../../firebase/firebase.utils";
import { store } from "../../redux/store";
import { setWssStatus } from "../../redux/application/application.actions";
import { addAlerts, setWssStatus } from "../../redux/application/application.actions";
const useSocket = (bodyshop) => {
const socketRef = useRef(null);
const [clientId, setClientId] = useState(null);
@@ -31,6 +32,14 @@ const useSocket = (bodyshop) => {
socketRef.current = socketInstance;
const handleBodyshopMessage = (message) => {
if (!message || !message?.type) return;
switch (message.type) {
case "alert-update":
store.dispatch(addAlerts(message.payload));
break;
}
if (!import.meta.env.DEV) return;
console.log(`Received message for bodyshop ${bodyshop.id}:`, message);
};
@@ -39,22 +48,22 @@ const useSocket = (bodyshop) => {
console.log("Socket connected:", socketInstance.id);
socketInstance.emit("join-bodyshop-room", bodyshop.id);
setClientId(socketInstance.id);
store.dispatch(setWssStatus("connected"))
store.dispatch(setWssStatus("connected"));
};
const handleReconnect = (attempt) => {
console.log(`Socket reconnected after ${attempt} attempts`);
store.dispatch(setWssStatus("connected"))
store.dispatch(setWssStatus("connected"));
};
const handleConnectionError = (err) => {
console.error("Socket connection error:", err);
store.dispatch(setWssStatus("error"))
store.dispatch(setWssStatus("error"));
};
const handleDisconnect = () => {
console.log("Socket disconnected");
store.dispatch(setWssStatus("disconnected"))
store.dispatch(setWssStatus("disconnected"));
};
socketInstance.on("connect", handleConnect);

View File

@@ -81,14 +81,14 @@ export const logImEXEvent = (eventName, additionalParams, stateProp = null) => {
user: (state.user && state.user.currentUser && state.user.currentUser.email) || null,
...additionalParams
};
axios.post("/ioevent", {
useremail: (state.user && state.user.currentUser && state.user.currentUser.email) || null,
bodyshopid: (state.user && state.user.bodyshop && state.user.bodyshop.id) || null,
operationName: eventName,
variables: additionalParams,
dbevent: false,
env: `master-AIO|${import.meta.env.VITE_APP_GIT_SHA_DATE}`
});
// axios.post("/ioevent", {
// useremail: (state.user && state.user.currentUser && state.user.currentUser.email) || null,
// bodyshopid: (state.user && state.user.bodyshop && state.user.bodyshop.id) || null,
// operationName: eventName,
// variables: additionalParams,
// dbevent: false,
// env: `master-AIO|${import.meta.env.VITE_APP_GIT_SHA_DATE}`
// });
// console.log(
// "%c[Analytics]",
// "background-color: green ;font-weight:bold;",

View File

@@ -48,6 +48,7 @@ export const QUERY_ALL_ACTIVE_APPOINTMENTS = gql`
v_model_desc
est_ct_fn
est_ct_ln
comment
labhrs: joblines_aggregate(where: { mod_lbr_ty: { _neq: "LAR" }, removed: { _eq: false } }) {
aggregate {
sum {

View File

@@ -692,6 +692,7 @@ export const GET_JOB_BY_PK = gql`
tax_str_rt
tax_sub_rt
tax_tow_rt
tlos_ind
towin
towing_payable
unit_number

View File

@@ -2,7 +2,7 @@ import { gql } from "@apollo/client";
export const QUERY_TICKETS_BY_JOBID = gql`
query QUERY_TICKETS_BY_JOBID($jobid: uuid!) {
timetickets(where: { jobid: { _eq: $jobid } }, order_by: { date: desc_nulls_first }) {
timetickets(where: { jobid: { _eq: $jobid } }) {
actualhrs
cost_center
ciecacode
@@ -26,7 +26,7 @@ export const QUERY_TICKETS_BY_JOBID = gql`
export const QUERY_TIME_TICKETS_IN_RANGE = gql`
query QUERY_TIME_TICKETS_IN_RANGE($start: date!, $end: date!) {
timetickets(where: { date: { _gte: $start, _lte: $end } }, order_by: { date: desc_nulls_first }) {
timetickets(where: { date: { _gte: $start, _lte: $end } }) {
actualhrs
ciecacode
clockoff
@@ -69,7 +69,6 @@ export const QUERY_TIME_TICKETS_TECHNICIAN_IN_RANGE = gql`
) {
timetickets(
where: { date: { _gte: $start, _lte: $end }, employeeid: { _eq: $employeeid } }
order_by: { date: desc_nulls_first }
) {
actualhrs
ciecacode
@@ -101,7 +100,6 @@ export const QUERY_TIME_TICKETS_TECHNICIAN_IN_RANGE = gql`
}
fixedperiod: timetickets(
where: { date: { _gte: $fixedStart, _lte: $fixedEnd }, employeeid: { _eq: $employeeid } }
order_by: { date: desc_nulls_first }
) {
actualhrs
ciecacode
@@ -145,7 +143,6 @@ export const QUERY_TIME_TICKETS_IN_RANGE_SB = gql`
) {
timetickets(
where: { date: { _gte: $start, _lte: $end }, cost_center: { _neq: "timetickets.labels.shift" } }
order_by: { date: desc_nulls_first }
) {
actualhrs
ciecacode
@@ -180,7 +177,6 @@ export const QUERY_TIME_TICKETS_IN_RANGE_SB = gql`
}
fixedperiod: timetickets(
where: { date: { _gte: $fixedStart, _lte: $fixedEnd }, cost_center: { _neq: "timetickets.labels.shift" } }
order_by: { date: desc_nulls_first }
) {
actualhrs
ciecacode
@@ -335,7 +331,6 @@ export const UPDATE_TIME_TICKETS = gql`
export const QUERY_ACTIVE_TIME_TICKETS = gql`
query QUERY_ACTIVE_TIME_TICKETS($employeeId: uuid) {
timetickets(
order_by: { date: desc_nulls_first }
where: {
_and: {
clockoff: { _is_null: true }

View File

@@ -71,7 +71,7 @@ export function DmsContainer({ bodyshop, setBreadcrumbs, setSelectedHeader }) {
...logs,
{
timestamp: new Date(),
level: "WARNING",
level: "WARN",
message: "Reconnected to CDK Export Service"
}
];
@@ -123,10 +123,9 @@ export function DmsContainer({ bodyshop, setBreadcrumbs, setSelectedHeader }) {
socket.emit("set-log-level", value);
}}
>
<Select.Option key="TRACE">TRACE</Select.Option>
<Select.Option key="DEBUG">DEBUG</Select.Option>
<Select.Option key="INFO">INFO</Select.Option>
<Select.Option key="WARNING">WARNING</Select.Option>
<Select.Option key="WARN">WARN</Select.Option>
<Select.Option key="ERROR">ERROR</Select.Option>
</Select>
<Button onClick={() => setLogs([])}>Clear Logs</Button>

View File

@@ -90,7 +90,7 @@ export function DmsContainer({ bodyshop, setBreadcrumbs, setSelectedHeader, inse
...logs,
{
timestamp: new Date(),
level: "WARNING",
level: "warn",
message: "Reconnected to CDK Export Service"
}
];
@@ -173,10 +173,9 @@ export function DmsContainer({ bodyshop, setBreadcrumbs, setSelectedHeader, inse
socket.emit("set-log-level", value);
}}
>
<Select.Option key="TRACE">TRACE</Select.Option>
<Select.Option key="DEBUG">DEBUG</Select.Option>
<Select.Option key="INFO">INFO</Select.Option>
<Select.Option key="WARNING">WARNING</Select.Option>
<Select.Option key="WARN">WARN</Select.Option>
<Select.Option key="ERROR">ERROR</Select.Option>
</Select>
<Button onClick={() => setLogs([])}>Clear Logs</Button>

View File

@@ -1,4 +1,4 @@
import { FloatButton, Layout, Spin } from "antd";
import { FloatButton, Layout, notification, Spin } from "antd";
// import preval from "preval.macro";
import React, { lazy, Suspense, useContext, useEffect, useState } from "react";
import { useTranslation } from "react-i18next";
@@ -21,11 +21,12 @@ import ShopSubStatusComponent from "../../components/shop-sub-status/shop-sub-st
import { requestForToken } from "../../firebase/firebase.utils";
import SocketContext from "../../contexts/SocketIO/socketContext.jsx";
import { selectBodyshop, selectInstanceConflict } from "../../redux/user/user.selectors";
import UpdateAlert from "../../components/update-alert/update-alert.component";
import InstanceRenderManager from "../../utils/instanceRenderMgr.js";
import "./manage.page.styles.scss";
import WssStatusDisplayComponent from "../../components/wss-status-display/wss-status-display.component.jsx";
import { selectAlerts } from "../../redux/application/application.selectors.js";
import { addAlerts } from "../../redux/application/application.actions.js";
const JobsPage = lazy(() => import("../jobs/jobs.page"));
@@ -104,16 +105,80 @@ const { Content, Footer } = Layout;
const mapStateToProps = createStructuredSelector({
conflict: selectInstanceConflict,
bodyshop: selectBodyshop
bodyshop: selectBodyshop,
alerts: selectAlerts
});
const mapDispatchToProps = (dispatch) => ({});
const ALERT_FILE_URL = InstanceRenderManager({
imex: "https://images.imex.online/alerts/alerts-imex.json",
rome: "https://images.imex.online/alerts/alerts-rome.json"
});
export function Manage({ conflict, bodyshop }) {
const mapDispatchToProps = (dispatch) => ({
setAlerts: (alerts) => dispatch(addAlerts(alerts))
});
export function Manage({ conflict, bodyshop, alerts, setAlerts }) {
const { t } = useTranslation();
const [chatVisible] = useState(false);
const { socket, clientId } = useContext(SocketContext);
// State to track displayed alerts
const [displayedAlertIds, setDisplayedAlertIds] = useState([]);
// Fetch displayed alerts from localStorage on mount
useEffect(() => {
const displayedAlerts = JSON.parse(localStorage.getItem("displayedAlerts") || "[]");
setDisplayedAlertIds(displayedAlerts);
}, []);
// Fetch alerts from the JSON file and dispatch to Redux store
useEffect(() => {
const fetchAlerts = async () => {
try {
const response = await fetch(ALERT_FILE_URL);
const fetchedAlerts = await response.json();
setAlerts(fetchedAlerts);
} catch (error) {
console.error("Error fetching alerts:", error);
}
};
fetchAlerts();
}, []);
// Use useEffect to watch for new alerts
useEffect(() => {
if (alerts && Object.keys(alerts).length > 0) {
// Convert the alerts object into an array
const alertArray = Object.values(alerts);
// Filter out alerts that have already been dismissed
const newAlerts = alertArray.filter((alert) => !displayedAlertIds.includes(alert.id));
newAlerts.forEach((alert) => {
// Display the notification
notification.open({
key: "notification-alerts-" + alert.id,
message: alert.message,
description: alert.description,
type: alert.type || "info",
duration: 0,
placement: "bottomRight",
closable: true,
onClose: () => {
// When the notification is closed, update displayed alerts state and localStorage
setDisplayedAlertIds((prevIds) => {
const updatedIds = [...prevIds, alert.id];
localStorage.setItem("displayedAlerts", JSON.stringify(updatedIds));
return updatedIds;
});
}
});
});
}
}, [alerts, displayedAlertIds]);
useEffect(() => {
const widgetId = InstanceRenderManager({
imex: "IABVNO4scRKY11XBQkNr",

View File

@@ -67,6 +67,12 @@ export const setUpdateAvailable = (isUpdateAvailable) => ({
type: ApplicationActionTypes.SET_UPDATE_AVAILABLE,
payload: isUpdateAvailable
});
export const addAlerts = (alerts) => ({
type: ApplicationActionTypes.ADD_ALERTS,
payload: alerts
});
export const setWssStatus = (status) => ({
type: ApplicationActionTypes.SET_WSS_STATUS,
payload: status

View File

@@ -15,7 +15,8 @@ const INITIAL_STATE = {
error: null
},
jobReadOnly: false,
partnerVersion: null
partnerVersion: null,
alerts: {}
};
const applicationReducer = (state = INITIAL_STATE, action) => {
@@ -91,6 +92,18 @@ const applicationReducer = (state = INITIAL_STATE, action) => {
case ApplicationActionTypes.SET_WSS_STATUS: {
return { ...state, wssStatus: action.payload };
}
case ApplicationActionTypes.ADD_ALERTS: {
const newAlertsMap = { ...state.alerts };
action.payload.alerts.forEach((alert) => {
newAlertsMap[alert.id] = alert;
});
return {
...state,
alerts: newAlertsMap
};
}
default:
return state;
}

View File

@@ -23,3 +23,4 @@ export const selectOnline = createSelector([selectApplication], (application) =>
export const selectProblemJobs = createSelector([selectApplication], (application) => application.problemJobs);
export const selectUpdateAvailable = createSelector([selectApplication], (application) => application.updateAvailable);
export const selectWssStatus = createSelector([selectApplication], (application) => application.wssStatus);
export const selectAlerts = createSelector([selectApplication], (application) => application.alerts);

View File

@@ -13,6 +13,7 @@ const ApplicationActionTypes = {
INSERT_AUDIT_TRAIL: "INSERT_AUDIT_TRAIL",
SET_PROBLEM_JOBS: "SET_PROBLEM_JOBS",
SET_UPDATE_AVAILABLE: "SET_UPDATE_AVAILABLE",
SET_WSS_STATUS: "SET_WSS_STATUS"
SET_WSS_STATUS: "SET_WSS_STATUS",
ADD_ALERTS: "ADD_ALERTS"
};
export default ApplicationActionTypes;

View File

@@ -28,7 +28,7 @@ import {
} from "../../firebase/firebase.utils";
import { QUERY_EULA } from "../../graphql/bodyshop.queries";
import client from "../../utils/GraphQLClient";
import day from "../../utils/day";
import dayjs from "../../utils/day";
import InstanceRenderManager from "../../utils/instanceRenderMgr";
import {
checkInstanceId,
@@ -96,7 +96,7 @@ export function* isUserAuthenticated() {
const eulaQuery = yield client.query({
query: QUERY_EULA,
variables: {
now: day()
now: dayjs()
}
});
@@ -314,8 +314,7 @@ export function* SetAuthLevelFromShopDetails({ payload }) {
try {
const userEmail = yield select((state) => state.user.currentUser.email);
try {
//console.log("Setting shop timezone.");
// dayjs.tz.setDefault(payload.timezone);
dayjs.tz.setDefault(payload.timezone);
} catch (error) {
console.log(error);
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

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