Compare commits

...

54 Commits

Author SHA1 Message Date
Patrick Fic
f0d6c5e1b1 IO-233 CDK WIP 2021-07-06 09:31:01 -07:00
Patrick Fic
84b39f3d2b IO-233 WIP CDK 2021-07-02 12:53:18 -07:00
Patrick Fic
4ab0947cc8 IO-233 Add customer insert actions. 2021-06-30 16:04:01 -07:00
Patrick Fic
105ecd4221 IO-233 CDK 2021-06-30 13:41:00 -07:00
Patrick Fic
11af41f3c0 Merged in hotfix/2021-06-30 (pull request #123)
hotfix/2021-06-30

Approved-by: Patrick Fic
2021-06-30 20:05:17 +00:00
Patrick Fic
6a24c10225 Update loading page. 2021-06-29 14:46:33 -07:00
Patrick Fic
8c50589eba Merged in hotfix/2021-06-30 (pull request #122)
Add crisp changes & auto triggers.

Approved-by: Patrick Fic
2021-06-29 20:47:08 +00:00
Patrick Fic
eaa134d474 Add crisp changes & auto triggers. 2021-06-29 13:45:05 -07:00
Patrick Fic
3d61d95e44 Merged in hotfix/2021-06-30 (pull request #121)
hotfix/2021-06-30

Approved-by: Patrick Fic
2021-06-29 20:16:33 +00:00
Patrick Fic
d9d3c899a1 Improved Landing page 2021-06-29 13:12:53 -07:00
Patrick Fic
00f71eba77 Added landing page. 2021-06-29 07:09:57 -07:00
Patrick Fic
1e547f1815 Upsize global search bar. 2021-06-28 17:22:41 -07:00
Patrick Fic
4b7bbe686a IO-1222 Add preview to schedule view. 2021-06-28 13:38:09 -07:00
Patrick Fic
f744acd131 IO-1217 Allow remove and add production always 2021-06-28 10:51:27 -07:00
Patrick Fic
2be61379f8 Merged in feature/2021-06-25 (pull request #120)
feature/2021-06-25
2021-06-25 21:38:25 +00:00
Patrick Fic
227a1034cd Merged in feature/2021-06-25 (pull request #119)
Remove multi print center.

Approved-by: Patrick Fic
2021-06-25 21:12:04 +00:00
Patrick Fic
a2f3d9a1b6 Remove multi print center. 2021-06-25 14:09:19 -07:00
Patrick Fic
33f863e1e6 Merged in feature/2021-06-25 (pull request #118)
Added missing template.

Approved-by: Patrick Fic
2021-06-25 19:07:29 +00:00
Patrick Fic
630dacd8bf Added missing template. 2021-06-25 12:06:35 -07:00
Patrick Fic
4e161248b3 Merged in feature/2021-06-25 (pull request #117)
feature/2021-06-25
2021-06-25 14:46:53 +00:00
Patrick Fic
2172cc2d04 IO-233 WS Updates and templat eadditions 2021-06-25 07:42:49 -07:00
Patrick Fic
b49555e111 IO-1211 Feature Restrictions 2021-06-23 14:15:41 -07:00
Patrick Fic
d634fcd4cf IO-1218 CLM_NO Ui fix on payments enter. 2021-06-23 13:31:25 -07:00
Patrick Fic
a7e972b3ce IO-1213 Recalc after line delete. 2021-06-23 13:22:03 -07:00
Patrick Fic
35273c64bd IO-233 Add soap request structure 2021-06-23 12:19:51 -07:00
Patrick Fic
5be2d7bd39 IO-233 WIP CDK. 2021-06-23 10:57:57 -07:00
Patrick Fic
749dfc0fba Merged in feature/2021-06-25 (pull request #116)
feature/2021-06-25

Approved-by: Patrick Fic
2021-06-22 20:47:17 +00:00
Patrick Fic
4f6bb02ab7 IO-233 Base websocket setup for CDK. 2021-06-22 13:45:36 -07:00
Patrick Fic
5a109c5752 IO-1215 Roudning on dashboard graph. 2021-06-21 11:58:09 -07:00
Patrick Fic
756e363e92 IO-1208 Update missing translation. 2021-06-21 11:50:43 -07:00
Patrick Fic
d90a0cd0c8 IO-1212 Missing stripe hyperlinks. 2021-06-21 11:48:48 -07:00
Patrick Fic
6de9007c3a IO-1213 Recalc totals on jobline insert. 2021-06-21 09:36:03 -07:00
Patrick Fic
0b2584e2f1 IO-1130 Update schedule job modal styles. 2021-06-21 09:22:24 -07:00
Patrick Fic
1f59d114e8 IO-1186 Export customer data. 2021-06-21 09:11:28 -07:00
Patrick Fic
69ac8617da Merged in feature/2021-06-18 (pull request #115)
RO form items for checklist dates.

Approved-by: Patrick Fic
2021-06-18 20:51:47 +00:00
Patrick Fic
ed00b4550c Merged in feature/2021-06-18 (pull request #114)
RO form items for checklist dates.

Approved-by: Patrick Fic
2021-06-18 20:50:42 +00:00
Patrick Fic
471c918ac3 Merged in feature/2021-06-18 (pull request #113)
Add delivery to checklist & remove jria submit on error.

Approved-by: Patrick Fic
2021-06-18 18:24:07 +00:00
Patrick Fic
0c23c16f3b Merged in feature/2021-06-18 (pull request #112)
feature/2021-06-18

Approved-by: Patrick Fic
2021-06-17 17:39:00 +00:00
Patrick Fic
0adb34b4d3 Merged in feature/2021-06-18 (pull request #111)
Feature/2021 06 18
2021-06-16 21:25:18 +00:00
Patrick Fic
859522b028 Merged in feature/2021-06-18 (pull request #110)
Feature/2021 06 18
2021-06-16 19:09:02 +00:00
Patrick Fic
e6cb804055 Merged in feature/2021-06-18 (pull request #109)
Feature/2021 06 18
2021-06-15 23:42:24 +00:00
Patrick Fic
a218564a24 Merged in feature/2021-06-18 (pull request #108)
Feature/2021 06 18
2021-06-15 02:38:39 +00:00
Patrick Fic
4071abcb56 Merged in feature/2021-06-18 (pull request #107)
Feature/2021 06 18
2021-06-14 17:48:14 +00:00
Patrick Fic
2368aeb5e8 Merged in feature/2021-06-18 (pull request #106)
Feature/2021 06 18
2021-06-11 17:04:23 +00:00
Patrick Fic
f81e026e12 Merged in feature/2021-06-18 (pull request #105)
Package updates.
2021-06-11 15:58:35 +00:00
Patrick Fic
21a1791e7a Merged in feature/2021-06-18 (pull request #104)
Update documents transformations + crisp.
2021-06-11 15:10:19 +00:00
Patrick Fic
0615e46d8a Merged in feature/2021-06-18 (pull request #103)
Feature/2021 06 18
2021-06-09 18:34:35 +00:00
Patrick Fic
9ddb83a761 Merged in hotfix/2021-06-08 (pull request #101)
Emergency Hotfix 2021-06-8 - Add rounding for depreciation.
2021-06-08 22:57:09 +00:00
Patrick Fic
9b881ee11a Merged in hotfix/2021-06-08 (pull request #100)
Add rounding for depreciation.
2021-06-08 22:42:53 +00:00
Patrick Fic
170f03979e Merged in feature/2021-06-18 (pull request #99)
Feature/2021 06 18
2021-06-08 17:41:26 +00:00
Patrick Fic
7c6b2faa1a Merged in feature/2020-06-04 (pull request #97)
Feature/2020 06 04
2021-06-04 20:20:49 +00:00
Patrick Fic
dbe3944089 Merged in feature/2020-06-04 (pull request #96)
Feature/2020 06 04
2021-06-03 17:33:36 +00:00
Patrick Fic
0b50f424fa Merged in feature/2020-06-04 (pull request #94)
Feature/2020 06 04
2021-06-02 23:10:45 +00:00
Patrick Fic
701a52dd22 Merged in feature/2020-06-04 (pull request #93)
Feature/2020 06 04
2021-06-02 17:09:31 +00:00
119 changed files with 6669 additions and 334 deletions

File diff suppressed because one or more lines are too long

View File

@@ -301,6 +301,27 @@
</translation>
</translations>
</concept_node>
<concept_node>
<name>preview</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>reschedule</name>
<definition_loaded>false</definition_loaded>
@@ -2543,6 +2564,27 @@
</translation>
</translations>
</concept_node>
<concept_node>
<name>reexport</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>
@@ -14289,6 +14331,27 @@
</translation>
</translations>
</concept_node>
<concept_node>
<name>nofeatureaccess</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>noshop</name>
<definition_loaded>false</definition_loaded>
@@ -16285,6 +16348,27 @@
</translation>
</translations>
</concept_node>
<concept_node>
<name>exportcustdata</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>exportselected</name>
<definition_loaded>false</definition_loaded>
@@ -24045,6 +24129,612 @@
</folder_node>
</children>
</folder_node>
<folder_node>
<name>landing</name>
<children>
<folder_node>
<name>bigfeature</name>
<children>
<concept_node>
<name>subtitle</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>title</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>
<name>footer</name>
<children>
<folder_node>
<name>company</name>
<children>
<concept_node>
<name>about</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>contact</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>disclaimers</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>name</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>privacypolicy</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>
<name>io</name>
<children>
<concept_node>
<name>help</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>name</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>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>
</children>
</folder_node>
<concept_node>
<name>slogan</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>
<name>hero</name>
<children>
<concept_node>
<name>button</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>title</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>
<name>labels</name>
<children>
<concept_node>
<name>features</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>managemyshop</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>pricing</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>
<name>pricing</name>
<children>
<folder_node>
<name>basic</name>
<children>
<concept_node>
<name>name</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>sub</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>
<name>essentials</name>
<children>
<concept_node>
<name>name</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>sub</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>
<concept_node>
<name>pricingtitle</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>
<folder_node>
<name>pro</name>
<children>
<concept_node>
<name>name</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>sub</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>
<concept_node>
<name>title</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>
<folder_node>
<name>unlimited</name>
<children>
<concept_node>
<name>name</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>sub</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>
</children>
</folder_node>
</children>
</folder_node>
<folder_node>
<name>menus</name>
<children>
@@ -28938,6 +29628,27 @@
</translation>
</translations>
</concept_node>
<concept_node>
<name>courtesy_car_impound</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>courtesy_car_terms</name>
<definition_loaded>false</definition_loaded>
@@ -32319,6 +33030,111 @@
</translation>
</translations>
</concept_node>
<concept_node>
<name>production_by_csr</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_by_last_name</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_by_repair_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_by_ro</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_by_target_date</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>purchases_by_cost_center_detail</name>
<definition_loaded>false</definition_loaded>

View File

@@ -12,7 +12,9 @@ module.exports = {
modifyVars: {
...(process.env.NODE_ENV === "development"
? { "@primary-color": "#a51d1d" }
: { "@primary-color": "#1DA57A" }),
: {
//"@primary-color": "#1DA57A"
}),
// "@primary-color": " #1890ff", // primary color for all components
// "@link-color": "#1890ff", // link color
// "@success-color": "#52c41a", // success state color

View File

@@ -19,6 +19,7 @@
"craco-less": "^1.17.1",
"dinero.js": "^1.8.1",
"dotenv": "^9.0.2",
"enquire-js": "^0.2.1",
"env-cmd": "^10.1.0",
"exifr": "^7.0.0",
"firebase": "^8.6.0",
@@ -35,6 +36,8 @@
"preval.macro": "^5.0.0",
"prop-types": "^15.7.2",
"query-string": "^7.0.0",
"rc-queue-anim": "^1.8.5",
"rc-scroll-anim": "^2.7.6",
"react": "^17.0.1",
"react-big-calendar": "^0.33.2",
"react-color": "^2.19.3",
@@ -49,6 +52,7 @@
"react-resizable": "^3.0.1",
"react-router-dom": "^5.2.0",
"react-scripts": "^4.0.3",
"react-sublime-video": "^0.2.5",
"react-virtualized": "^9.22.3",
"recharts": "^2.0.7",
"redux": "^4.1.0",
@@ -57,6 +61,7 @@
"redux-state-sync": "^3.1.2",
"reselect": "^4.0.0",
"sass": "^1.32.13",
"socket.io-client": "^4.1.2",
"styled-components": "^5.3.0",
"subscriptions-transport-ws": "^0.9.18",
"web-vitals": "^1.1.2",

View File

@@ -8,7 +8,17 @@
<meta name="description" content="ImEX Online" />
<!-- <link rel="apple-touch-icon" href="logo192.png" /> -->
<link rel="apple-touch-icon" href="logo192.png" />
<script type="text/javascript">
window.$crisp = [];
window.CRISP_WEBSITE_ID = "36724f62-2eb0-4b29-9cdd-9905fb99913e";
(function () {
d = document;
s = d.createElement("script");
s.src = "https://client.crisp.chat/l.js";
s.async = 1;
d.getElementsByTagName("head")[0].appendChild(s);
})();
</script>
<script>
!(function () {
"use strict";

View File

@@ -3,12 +3,11 @@ import { ConfigProvider } from "antd";
import enLocale from "antd/es/locale/en_US";
import LogRocket from "logrocket";
import moment from "moment";
import React, { useEffect } from "react";
import React from "react";
import { useTranslation } from "react-i18next";
import GlobalLoadingBar from "../components/global-loading-bar/global-loading-bar.component";
import client from "../utils/GraphQLClient";
import App from "./App";
import { useTranslation } from "react-i18next";
import JiraSupportComponent from "../components/jira-support-widget/jira-support-widget.component";
moment.locale("en-US");
if (process.env.NODE_ENV === "production") LogRocket.init("gvfvfw/bodyshopapp");
@@ -16,21 +15,6 @@ if (process.env.NODE_ENV === "production") LogRocket.init("gvfvfw/bodyshopapp");
export default function AppContainer() {
const { t } = useTranslation();
useEffect(() => {
// Include the Crisp code here, without the <script></script> tags
window.$crisp = [];
window.CRISP_WEBSITE_ID = "36724f62-2eb0-4b29-9cdd-9905fb99913e";
var d = document;
var s = d.createElement("script");
s.src = "https://client.crisp.chat/l.js";
s.async = 1;
d.getElementsByTagName("head")[0].appendChild(s);
return () => {
d.getElementsByTagName("head")[0].removeChild(s);
};
}, []);
return (
<ApolloProvider client={client}>
<ConfigProvider
@@ -46,7 +30,6 @@ export default function AppContainer() {
>
<GlobalLoadingBar />
<App />
<JiraSupportComponent />
</ConfigProvider>
</ApolloProvider>
);

View File

@@ -8,7 +8,7 @@ import DocumentEditorContainer from "../components/document-editor/document-edit
import ErrorBoundary from "../components/error-boundary/error-boundary.component";
//Component Imports
import LoadingSpinner from "../components/loading-spinner/loading-spinner.component";
import AboutPage from "../pages/about/about.page";
import DisclaimerPage from "../pages/disclaimer/disclaimer.page";
import TechPageContainer from "../pages/tech/tech.page.container";
import { setOnline } from "../redux/application/application.actions";
import { selectOnline } from "../redux/application/application.selectors";
@@ -17,7 +17,7 @@ import { selectCurrentUser } from "../redux/user/user.selectors";
import PrivateRoute from "../utils/private-route";
import "./App.styles.scss";
const LandingPage = lazy(() => import("../pages/landing/landing.page"));
import LandingPage from "../pages/landing/landing.page";
const ResetPassword = lazy(() =>
import("../pages/reset-password/reset-password.component")
);
@@ -100,7 +100,7 @@ export function App({ checkUserSession, currentUser, online, setOnline }) {
<Route exact path="/csi/:surveyId" component={CsiPage} />
</ErrorBoundary>
<ErrorBoundary>
<Route exact path="/about" component={AboutPage} />
<Route exact path="/disclaimer" component={DisclaimerPage} />
</ErrorBoundary>
<ErrorBoundary>
<Route

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 272 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 237 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 177 KiB

View File

@@ -0,0 +1,5 @@
<?xml version="1.0" ?><svg style="enable-background:new 0 0 128 128;" version="1.1" viewBox="0 0 128 128" xml:space="preserve" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><style type="text/css">
.st0{fill:none;stroke:#000000;stroke-width:8;stroke-miterlimit:10;}
.st1{display:none;}
.st2{display:inline;opacity:0.25;fill:#F45EFD;}
</style><g id="_x31_2_3D_Printing"/><g id="_x31_1_VR_Gear"/><g id="_x31_0_Virtual_reality"/><g id="_x39__Augmented_reality"/><g id="_x38__Teleport"/><g id="_x37__Glassess"/><g id="_x36__Folding_phone"/><g id="_x35__Drone"/><g id="_x34__Retina_scan"/><g id="_x33__Smartwatch"/><g id="_x32__Bionic_Arm"/><g id="_x31__Chip"><g><path d="M108,40c-5.2,0-9.6,3.3-11.3,8H84V32h-8V20h-8v12h-8V20h-8v12h-8v16H24v-8.7c4.7-1.7,8-6.1,8-11.3c0-6.6-5.4-12-12-12 S8,21.4,8,28c0,5.2,3.3,9.6,8,11.3V56h28v8H16v16.7c-4.7,1.7-8,6.1-8,11.3c0,6.6,5.4,12,12,12s12-5.4,12-12c0-5.2-3.3-9.6-8-11.3 V72h20v16h8v12h8V88h8v12h8V88h8V72h8v16.7c-4.7,1.7-8,6.1-8,11.3c0,6.6,5.4,12,12,12s12-5.4,12-12c0-5.2-3.3-9.6-8-11.3V64H84v-8 h12.7c1.7,4.7,6.1,8,11.3,8c6.6,0,12-5.4,12-12S114.6,40,108,40z M20,32c-2.2,0-4-1.8-4-4s1.8-4,4-4s4,1.8,4,4S22.2,32,20,32z M20,96c-2.2,0-4-1.8-4-4s1.8-4,4-4s4,1.8,4,4S22.2,96,20,96z M76,80H52V40h24V80z M96,96c2.2,0,4,1.8,4,4s-1.8,4-4,4s-4-1.8-4-4 S93.8,96,96,96z M108,56c-2.2,0-4-1.8-4-4s1.8-4,4-4s4,1.8,4,4S110.2,56,108,56z"/><rect height="8" width="8" x="56" y="64"/></g></g><g class="st1" id="Guide"><path class="st2" d="M120,8v112H8V8H120 M128,0H0v128h128V0L128,0z"/></g></svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@@ -47,7 +47,9 @@ export function BillMarkForReexportButton({ bodyshop, authLevel, bill }) {
});
if (!result.errors) {
notification["success"]({ message: t("bills.successes.save") });
notification["success"]({
message: t("bills.successes.reexport"),
});
} else {
notification["error"]({
message: t("bills.errors.saving", {

View File

@@ -1,5 +1,5 @@
import { HomeFilled } from "@ant-design/icons";
import { Breadcrumb } from "antd";
import { Breadcrumb, Row, Col } from "antd";
import React from "react";
import { connect } from "react-redux";
import { Link } from "react-router-dom";
@@ -14,27 +14,29 @@ const mapStateToProps = createStructuredSelector({
export function BreadCrumbs({ breadcrumbs }) {
return (
<div className="breadcrumb-container imex-flex-row">
<Breadcrumb separator=">" style={{ flex: 1 }}>
<Breadcrumb.Item>
<Link to={`/manage`}>
<HomeFilled />
</Link>
</Breadcrumb.Item>
{breadcrumbs.map((item) =>
item.link ? (
<Breadcrumb.Item key={item.label}>
<Link to={item.link}>{item.label} </Link>
</Breadcrumb.Item>
) : (
<Breadcrumb.Item key={item.label}>{item.label}</Breadcrumb.Item>
)
)}
</Breadcrumb>
<div>
<Row className="breadcrumb-container">
<Col xs={24} sm={24} md={16}>
<Breadcrumb separator=">">
<Breadcrumb.Item>
<Link to={`/manage`}>
<HomeFilled />
</Link>
</Breadcrumb.Item>
{breadcrumbs.map((item) =>
item.link ? (
<Breadcrumb.Item key={item.label}>
<Link to={item.link}>{item.label} </Link>
</Breadcrumb.Item>
) : (
<Breadcrumb.Item key={item.label}>{item.label}</Breadcrumb.Item>
)
)}
</Breadcrumb>
</Col>
<Col xs={24} sm={24} md={8}>
<GlobalSearch />
</div>
</div>
</Col>
</Row>
);
}
export default connect(mapStateToProps, null)(BreadCrumbs);

View File

@@ -5,10 +5,6 @@ import { useTranslation } from "react-i18next";
import { TOGGLE_CONVERSATION_ARCHIVE } from "../../graphql/conversations.queries";
export default function ChatArchiveButton({ conversation }) {
console.log(
"🚀 ~ file: chat-archive-button.component.jsx ~ line 6 ~ conversation",
conversation
);
const [loading, setLoading] = useState(false);
const { t } = useTranslation();
const [updateConversation] = useMutation(TOGGLE_CONVERSATION_ARCHIVE);

View File

@@ -63,7 +63,9 @@ export default function DashboardMonthlyRevenueGraph({ data, ...cardProps }) {
<CartesianGrid stroke="#f5f5f5" />
<XAxis dataKey="date" />
<YAxis />
<Tooltip />
<Tooltip
formatter={(value, name, props) => value && value.toFixed(2)}
/>
<Legend />
<Area
type="monotone"

View File

@@ -0,0 +1,77 @@
import { Button, Table } from "antd";
import React, { useState } from "react";
import { useTranslation } from "react-i18next";
import { socket } from "../../pages/dms/dms.container";
import PhoneFormatter from "../../utils/PhoneFormatter";
import { alphaSort } from "../../utils/sorters";
export default function DmsCustomerSelector() {
const { t } = useTranslation();
const [customerList, setcustomerList] = useState([]);
const [visible, setVisible] = useState(false);
const [selectedCustomer, setSelectedCustomer] = useState(null);
socket.on("cdk-select-customer", (customerList, callback) => {
setVisible(true);
setcustomerList(customerList);
});
const onOk = () => {
setVisible(false);
socket.emit("cdk-selected-customer", selectedCustomer);
};
const columns = [
{
title: t("dms.fields.name1"),
dataIndex: ["name1", "fullName"],
key: "name1",
sorter: (a, b) => alphaSort(a.name1?.fullName, b.name1?.fullName),
},
{
title: t("dms.fields.name2"),
dataIndex: ["name2", "fullName"],
key: "name2",
sorter: (a, b) => alphaSort(a.name2?.fullName, b.name2?.fullName),
},
{
title: t("dms.fields.phone"),
dataIndex: ["contactInfo", "mainTelephoneNumber", "value"],
key: "phone",
render: (record, value) => (
<PhoneFormatter>
{record.contactInfo?.mainTelephoneNumber?.value}
</PhoneFormatter>
),
},
{
title: t("dms.fields.address"),
//dataIndex: ["name2", "fullName"],
key: "address",
render: (record, value) =>
`${record.address?.addressLine[0]}, ${record.address?.city} ${record.address?.stateOrProvince} ${record.address?.postalCode}`,
},
];
if (!visible) return <></>;
return (
<Table
title={() => (
<div>
<Button onClick={onOk}>Select</Button>
</div>
)}
pagination={{ position: "top" }}
columns={columns}
rowKey={(record) => record.id.value}
dataSource={customerList}
//onChange={handleTableChange}
rowSelection={{
onSelect: (props) => {
setSelectedCustomer(props.id.value);
},
type: "radio",
selectedRowKeys: [selectedCustomer],
}}
/>
);
}

View File

@@ -73,7 +73,6 @@ class ErrorBoundary extends React.Component {
};
render() {
console.log("this.props :>> ", this.props);
const { t } = this.props;
const { error, info } = this.state;
if (this.state.hasErrored === true) {

View File

@@ -0,0 +1,50 @@
import moment from "moment";
import React from "react";
import { useTranslation } from "react-i18next";
import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
import { selectBodyshop } from "../../redux/user/user.selectors";
import AlertComponent from "../alert/alert.component";
const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop,
});
function FeatureWrapper({
bodyshop,
featureName,
noauth,
children,
...restProps
}) {
const { t } = useTranslation();
if (HasFeatureAccess({ featureName, bodyshop })) return children;
return (
noauth || (
<AlertComponent
message={t("general.messages.nofeatureaccess")}
type="warning"
/>
)
);
}
export function HasFeatureAccess({ featureName, bodyshop }) {
return (
bodyshop.features.allAccess ||
moment(bodyshop.features[featureName]).isAfter(moment())
);
}
export default connect(mapStateToProps, null)(FeatureWrapper);
/*
dashboard
production-board
scoreboard
csi
tech-console
mobile-imaging
*/

View File

@@ -37,7 +37,7 @@ export default function GlobalSearch() {
value: job.ro_number,
label: (
<Link to={`/manage/jobs/${job.id}`}>
<Space wrap split={<Divider type="vertical" />}>
<Space size="small" split={<Divider type="vertical" />}>
<strong>{job.ro_number || t("general.labels.na")}</strong>
<span>{`${job.ownr_fn || ""} ${job.ownr_ln || ""} ${
job.ownr_co_nm || ""
@@ -62,7 +62,7 @@ export default function GlobalSearch() {
}`,
label: (
<Link to={`/manage/owners/${owner.id}`}>
<Space wrap split={<Divider type="vertical" />}>
<Space size="small" split={<Divider type="vertical" />}>
<span>{`${owner.ownr_fn || ""} ${owner.ownr_ln || ""} ${
owner.ownr_co_nm || ""
}`}</span>
@@ -85,7 +85,7 @@ export default function GlobalSearch() {
} ${vehicle.v_model_desc || ""}`,
label: (
<Link to={`/manage/vehicles/${vehicle.id}`}>
<Space wrap split={<Divider type="vertical" />}>
<Space size="small" split={<Divider type="vertical" />}>
<span>
{`${vehicle.v_model_yr || ""} ${
vehicle.v_make_desc || ""
@@ -107,7 +107,7 @@ export default function GlobalSearch() {
value: `${payment.job.ro_number} ${payment.payer} ${payment.amount}`,
label: (
<Link to={`/manage/jobs/${payment.job.id}`}>
<Space wrap split={<Divider type="vertical" />}>
<Space size="small" split={<Divider type="vertical" />}>
<span>{payment.job.ro_number}</span>
<span>{payment.job.memo}</span>
<span>{payment.job.amount}</span>
@@ -126,7 +126,7 @@ export default function GlobalSearch() {
value: `${bill.invoice_number} - ${bill.vendor.name}`,
label: (
<Link to={`/manage/bills?billid=${bill.id}`}>
<Space wrap split={<Divider type="vertical" />}>
<Space size="small" split={<Divider type="vertical" />}>
<span>{bill.invoice_number}</span>
<span>{bill.vendor.name}</span>
<span>{bill.date}</span>
@@ -146,7 +146,7 @@ export default function GlobalSearch() {
}`,
label: (
<Link to={`/manage/phonebook?phonebookentry=${pb.id}`}>
<Space wrap split={<Divider type="vertical" />}>
<Space size="small" split={<Divider type="vertical" />}>
<span>{`${pb.firstname || ""} ${pb.lastname || ""} ${
pb.company || ""
}`}</span>
@@ -165,8 +165,6 @@ export default function GlobalSearch() {
return (
<AutoComplete
key="globalsearch"
dropdownMatchSelectWidth={"false"}
options={options}
onSearch={handleSearch}
allowClear

View File

@@ -202,8 +202,8 @@ function Header({
context: null,
});
}}
icon={<Icon component={FaCreditCard} />}
>
<Icon component={FaCreditCard} />
{t("menus.header.enterpayment")}
</Menu.Item>
<Menu.Divider key="div5" />

View File

@@ -1,28 +0,0 @@
import React from "react";
export default function JiraSupportComponent() {
//useScript();
return <div></div>;
}
// const useScript = () => {
// useEffect(() => {
// const script = document.createElement("script");
// script.src = "https://jsd-widget.atlassian.com/assets/embed.js";
// script.setAttribute("data-jsd-embedded", true);
// script.setAttribute("data-key", "d69bb65c-1dd3-483f-b109-66a970d03f44");
// script.setAttribute("data-base-url", "https://jsd-widget.atlassian.com");
// //script.async = true;
// script.onload = () => {
// var DOMContentLoaded_event = document.createEvent("Event");
// DOMContentLoaded_event.initEvent("DOMContentLoaded", true, true);
// window.document.dispatchEvent(DOMContentLoaded_event);
// };
// document.head.appendChild(script);
// return () => {
// document.head.removeChild(script);
// };
// }, []);
// };

View File

@@ -2,7 +2,7 @@ import { Button, Popover, Space } from "antd";
import React, { useState } from "react";
import { useTranslation } from "react-i18next";
import { connect } from "react-redux";
import { Link } from "react-router-dom";
import { Link, useHistory, useLocation } from "react-router-dom";
import { setModalContext } from "../../redux/modals/modals.actions";
import CurrencyFormatter from "../../utils/CurrencyFormatter";
import PhoneFormatter from "../../utils/PhoneFormatter";
@@ -11,6 +11,8 @@ import { TemplateList } from "../../utils/TemplateConstants";
import DataLabel from "../data-label/data-label.component";
import ScheduleAtChange from "./job-at-change.component";
import ScheduleEventColor from "./schedule-event.color.component";
import queryString from "query-string";
const mapDispatchToProps = (dispatch) => ({
setScheduleContext: (context) =>
dispatch(setModalContext({ context: context, modal: "schedule" })),
@@ -24,6 +26,8 @@ export function ScheduleEventComponent({
}) {
const { t } = useTranslation();
const [visible, setVisible] = useState(false);
const history = useHistory();
const searchParams = queryString.parse(useLocation().search);
const blockContent = (
<div>
@@ -88,6 +92,20 @@ export function ScheduleEventComponent({
<Button>{t("appointments.actions.viewjob")}</Button>
</Link>
) : null}
{event.job ? (
<Button
onClick={() => {
history.push({
search: queryString.stringify({
...searchParams,
selected: event.job.id,
}),
});
}}
>
{t("appointments.actions.preview")}
</Button>
) : null}
<Button
onClick={() => {
const Template = TemplateList("job").appointment_reminder;

View File

@@ -16,6 +16,7 @@ import {
Table,
Tag,
} from "antd";
import axios from "axios";
import React, { useState } from "react";
import { useTranslation } from "react-i18next";
import { connect } from "react-redux";
@@ -291,8 +292,8 @@ export function JobLinesComponent({
</Button>
<Button
disabled={jobRO}
onClick={() =>
deleteJobLine({
onClick={async () => {
await deleteJobLine({
variables: { joblineId: record.id },
update(cache) {
cache.modify({
@@ -306,8 +307,12 @@ export function JobLinesComponent({
},
});
},
})
}
});
await axios.post("/job/totalsssu", {
id: job.id,
});
refetch && refetch();
}}
>
<DeleteFilled />
</Button>
@@ -395,7 +400,7 @@ export function JobLinesComponent({
setState({
...state,
filteredInfo: {
part_type: ["PAN,PAL,PAA,PAP,PAS,PASL"],
part_type: ["PAN,PAC,PAR,PAL,PAA,PAM,PAP,PAS,PASL"],
},
});
}}

View File

@@ -12,7 +12,7 @@ import { toggleModalVisible } from "../../redux/modals/modals.actions";
import { selectJobLineEditModal } from "../../redux/modals/modals.selectors";
import UndefinedToNull from "../../utils/undefinedtonull";
import JobLinesUpdsertModal from "./job-lines-upsert-modal.component";
import Axios from "axios";
const mapStateToProps = createStructuredSelector({
jobLineEditModal: selectJobLineEditModal,
});
@@ -29,10 +29,10 @@ function JobLinesUpsertModalContainer({
const [updateJobLine] = useMutation(UPDATE_JOB_LINE);
const [loading, setLoading] = useState(false);
const handleFinish = (values) => {
const handleFinish = async (values) => {
setLoading(true);
if (!jobLineEditModal.context.id) {
insertJobLine({
const r = await insertJobLine({
variables: {
lineInput: [
{
@@ -44,42 +44,44 @@ function JobLinesUpsertModalContainer({
},
],
},
})
.then((r) => {
if (jobLineEditModal.actions.refetch)
jobLineEditModal.actions.refetch();
//Need to recalcuate totals.
toggleModalVisible();
notification["success"]({
message: t("joblines.successes.created"),
});
})
.catch((error) => {
notification["error"]({
message: t("joblines.errors.creating", {
message: error.message,
}),
});
});
if (!r.errors) {
await Axios.post("/job/totalsssu", {
id: jobLineEditModal.context.jobid,
});
if (jobLineEditModal.actions.refetch)
jobLineEditModal.actions.refetch();
//Need to recalcuate totals.
toggleModalVisible();
notification["success"]({
message: t("joblines.successes.created"),
});
} else {
notification["error"]({
message: t("joblines.errors.creating", {
message: JSON.stringify(r.errors.message),
}),
});
}
} else {
updateJobLine({
const r = await updateJobLine({
variables: {
lineId: jobLineEditModal.context.id,
line: values,
},
})
.then((r) => {
notification["success"]({
message: t("joblines.successes.updated"),
});
})
.catch((error) => {
notification["success"]({
message: t("joblines.errors.updating", {
message: error.message,
}),
});
});
if (!r.errors) {
notification["success"]({
message: t("joblines.successes.updated"),
});
} else {
notification["success"]({
message: t("joblines.errors.updating", {
message: JSON.stringify(r.errors.message),
}),
});
}
if (jobLineEditModal.actions.submit) {
jobLineEditModal.actions.submit();
} else {

View File

@@ -80,7 +80,7 @@ const JobSearchSelect = (
{theOptions
? theOptions.map((o) => (
<Option key={o.id} value={o.id} status={o.status}>
{`${clm_no ? `${o.clm_no} | ` : ""}${
{`${clm_no && o.clm_no ? `${o.clm_no} | ` : ""}${
o.ro_number || t("general.labels.na")
} | ${o.ownr_ln || ""} ${o.ownr_fn || ""} ${
o.ownr_co_nm ? ` ${o.ownr_co_num}` : ""

View File

@@ -17,6 +17,7 @@ import {
import AddToProduction from "./jobs-detail-header-actions.addtoproduction.util";
import JobsDetaiLheaderCsi from "./jobs-detail-header-actions.csi.component";
import DuplicateJob from "./jobs-detail-header-actions.duplicate.util";
import JobsDetailHeaderActionsExportcustdataComponent from "./jobs-detail-header-actions.exportcustdata.component";
const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop,
@@ -180,7 +181,7 @@ export function JobsDetailHeaderActions({
{job.inproduction ? (
<Menu.Item
key="addtoproduction"
disabled={!!!job.converted || jobRO}
disabled={!job.converted}
onClick={() => AddToProduction(client, job.id, refetch, true)}
>
{t("jobs.actions.removefromproduction")}
@@ -188,7 +189,7 @@ export function JobsDetailHeaderActions({
) : (
<Menu.Item
key="addtoproduction"
disabled={!!!job.converted || !!job.inproduction || jobRO}
disabled={!job.converted}
onClick={() => AddToProduction(client, job.id, refetch)}
>
{t("jobs.actions.addtoproduction")}
@@ -316,6 +317,7 @@ export function JobsDetailHeaderActions({
{t("menus.jobsactions.admin")}
</Link>
</Menu.Item>
<JobsDetailHeaderActionsExportcustdataComponent job={job} />
<JobsDetaiLheaderCsi job={job} />
<Menu.Item
key="jobcosting"

View File

@@ -19,6 +19,7 @@ import {
import { selectBodyshop } from "../../redux/user/user.selectors";
import { DateTimeFormatter } from "../../utils/DateFormatter";
import { TemplateList } from "../../utils/TemplateConstants";
import { HasFeatureAccess } from "../feature-wrapper/feature-wrapper.component";
const mapStateToProps = createStructuredSelector({
//currentUser: selectCurrentUser'
@@ -179,6 +180,8 @@ export function JobsDetailHeaderCsi({
}
};
if (!HasFeatureAccess({ featureName: "csi", bodyshop })) return <></>;
return (
<Menu.SubMenu
key="sendcsi"

View File

@@ -0,0 +1,107 @@
import { Menu, notification } from "antd";
import axios from "axios";
import React from "react";
import { useTranslation } from "react-i18next";
import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
import { auth, logImEXEvent } from "../../firebase/firebase.utils";
import { selectBodyshop } from "../../redux/user/user.selectors";
const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop,
});
const mapDispatchToProps = (dispatch) => ({});
export function JobsDetailHeaderActionexportCustomerData({
bodyshop,
job,
...props
}) {
const { t } = useTranslation();
const handleExportCustData = async (e) => {
logImEXEvent("job_export_cust_data");
let QbXmlResponse;
try {
QbXmlResponse = await axios.post(
"/accounting/qbxml/receivables",
{ jobIds: [job.id], custDataOnly: true },
{
headers: {
Authorization: `Bearer ${await auth.currentUser.getIdToken()}`,
},
}
);
console.log("handle -> XML", QbXmlResponse);
} catch (error) {
console.log("Error getting QBXML from Server.", error);
notification["error"]({
message: t("jobs.errors.exporting", {
error: "Unable to retrieve QBXML. " + JSON.stringify(error.message),
}),
});
return;
}
let PartnerResponse;
try {
PartnerResponse = await axios.post(
"http://localhost:1337/qb/",
QbXmlResponse.data,
{
headers: {
Authorization: `Bearer ${await auth.currentUser.getIdToken()}`,
},
}
);
} catch (error) {
console.log("Error connecting to quickbooks or partner.", error);
notification["error"]({
message: t("jobs.errors.exporting-partner"),
});
return;
}
//Check to see if any of them failed. If they didn't don't execute the update.
const failedTransactions = PartnerResponse.data.filter((r) => !r.success);
if (failedTransactions.length > 0) {
//Uh oh. At least one was no good.
failedTransactions.forEach((ft) => {
//insert failed export log
notification.open({
// key: "failedexports",
type: "error",
message: t("jobs.errors.exporting", {
error: ft.errorMessage || "",
}),
});
});
//Handle Failures.
} else {
//Insert success export log.
notification.open({
type: "success",
key: "jobsuccessexport",
message: t("jobs.successes.exported"),
});
}
};
return (
<Menu.Item
{...props}
onClick={handleExportCustData}
key="exportcustdata"
disabled={!job.converted}
>
{t("jobs.actions.exportcustdata")}
</Menu.Item>
);
}
export default connect(
mapStateToProps,
mapDispatchToProps
)(JobsDetailHeaderActionexportCustomerData);

View File

@@ -50,8 +50,8 @@ export function JobsList({ bodyshop, refetch, loading, jobs, total }) {
width: "25%",
//sortOrder: sortcolumn === "ownr_ln" && sortorder,
render: (text, record) => {
return record.owner ? (
<Link to={"/manage/owners/" + record.owner.id}>
return record.ownerid ? (
<Link to={"/manage/owners/" + record.ownerid}>
{`${record.ownr_fn || ""} ${record.ownr_ln || ""} ${
record.ownr_co_nm || ""
}`}

View File

@@ -15,6 +15,8 @@ import { TemplateList } from "../../utils/TemplateConstants";
import CaBcEtfTableModalContainer from "../ca-bc-etf-table-modal/ca-bc-etf-table-modal.container";
import PrintWrapperComponent from "../print-wrapper/print-wrapper.component";
const stripeTestEnv = process.env.REACT_APP_STRIPE_PUBLIC_KEY; //.includes("test");
const mapStateToProps = createStructuredSelector({
//currentUser: selectCurrentUser
bodyshop: selectBodyshop,
@@ -128,6 +130,18 @@ export function PaymentsListPaginated({
title: t("payments.fields.stripeid"),
dataIndex: "stripeid",
key: "stripeid",
render: (text, record) =>
record.stripeid ? (
<a
href={
stripeTestEnv
? `https://dashboard.stripe.com/${bodyshop.stripe_acct_id}/test/payments/${record.stripeid}`
: `https://dashboard.stripe.com/${bodyshop.stripe_acct_id}/payments/${record.stripeid}`
}
>
{record.stripeid}
</a>
) : null,
},
{
title: t("payments.fields.created_at"),

View File

@@ -26,7 +26,9 @@ export function PrintCenterJobsComponent({ printCenterModal }) {
const filteredJobsReportsList =
search !== ""
? JobsReportsList.filter((r) => r.title.toLowerCase().includes(search))
? JobsReportsList.filter((r) =>
r.title.toLowerCase().includes(search.toLowerCase())
)
: JobsReportsList;
//Group it, create cards, and then filter out.

View File

@@ -0,0 +1,42 @@
import { Button, Dropdown, Menu } from "antd";
import React, { useState } from "react";
import { TemplateList } from "../../utils/TemplateConstants";
import { useTranslation } from "react-i18next";
import { GenerateDocument } from "../../utils/RenderTemplate";
const ProdTemplates = TemplateList("production");
export default function ProductionListPrint() {
const { t } = useTranslation();
const [loading, setLoading] = useState(false);
return (
<Dropdown
trigger="click"
overlay={
<Menu>
{Object.keys(ProdTemplates).map((key) => (
<Menu.Item
key={key}
onClick={async () => {
setLoading(true);
await GenerateDocument(
{
name: ProdTemplates[key].key,
// variables: { id: contract.id },
},
{},
"p"
);
setLoading(false);
}}
>
{ProdTemplates[key].title}
</Menu.Item>
))}
</Menu>
}
>
<Button loading={loading}>{t("general.labels.print")}</Button>
</Dropdown>
);
}

View File

@@ -13,6 +13,7 @@ import ProductionListColumnsAdd from "../production-list-columns/production-list
import ProductionListColumns from "../production-list-columns/production-list-columns.data";
import ProductionListDetail from "../production-list-detail/production-list-detail.component";
import ProductionListSaveConfigButton from "../production-list-save-config-button/production-list-save-config-button.component";
import ProductionListPrint from "./production-list-print.component";
import ProductionListTableViewSelect from "./production-list-table-view-select.component";
import ResizeableTitle from "./production-list-table.resizeable.component";
@@ -88,14 +89,16 @@ export function ProductionListTable({
setColumns(columns.filter((i) => i.key !== key));
};
const handleResize = (index) => (e, { size }) => {
const nextColumns = [...columns];
nextColumns[index] = {
...nextColumns[index],
width: size.width,
const handleResize =
(index) =>
(e, { size }) => {
const nextColumns = [...columns];
nextColumns[index] = {
...nextColumns[index],
width: size.width,
};
setColumns(nextColumns);
};
setColumns(nextColumns);
};
const headerItem = (col) => (
<Dropdown
@@ -178,6 +181,7 @@ export function ProductionListTable({
placeholder={t("general.labels.search")}
value={searchText}
/>
<ProductionListPrint />
</Space>
}
/>

View File

@@ -9,6 +9,7 @@ import { selectBodyshop } from "../../redux/user/user.selectors";
import Event from "../job-at-change/schedule-event.container";
import HeaderComponent from "./schedule-calendar-header.component";
import "./schedule-calendar.styles.scss";
import JobDetailCards from "../job-detail-cards/job-detail-cards.component";
const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop,
@@ -45,45 +46,48 @@ export function ScheduleCalendarWrapperComponent({
const selectedDate = new Date(date || moment(search.date) || Date.now());
return (
<Calendar
events={data}
defaultView={search.view || defaultView || "week"}
date={selectedDate}
onNavigate={(date, view, action) => {
search.date = date.toISOString().substr(0, 10);
history.push({ search: queryString.stringify(search) });
}}
onRangeChange={(start, end) => {
if (setDateRangeCallback) setDateRangeCallback({ start, end });
}}
onView={(view) => {
search.view = view;
history.push({ search: queryString.stringify(search) });
}}
step={15}
// timeslots={1}
showMultiDayTimes
localizer={localizer}
min={
bodyshop.schedule_start_time
? new Date(bodyshop.schedule_start_time)
: new Date("2020-01-01T06:00:00")
}
max={
bodyshop.schedule_end_time
? new Date(bodyshop.schedule_end_time)
: new Date("2020-01-01T20:00:00")
}
eventPropGetter={handleEventPropStyles}
components={{
event: (e) =>
Event({ bodyshop: bodyshop, event: e.event, refetch: refetch }),
header: (p) => (
<HeaderComponent {...p} events={data} refetch={refetch} />
),
}}
{...otherProps}
/>
<>
<JobDetailCards />
<Calendar
events={data}
defaultView={search.view || defaultView || "week"}
date={selectedDate}
onNavigate={(date, view, action) => {
search.date = date.toISOString().substr(0, 10);
history.push({ search: queryString.stringify(search) });
}}
onRangeChange={(start, end) => {
if (setDateRangeCallback) setDateRangeCallback({ start, end });
}}
onView={(view) => {
search.view = view;
history.push({ search: queryString.stringify(search) });
}}
step={15}
// timeslots={1}
showMultiDayTimes
localizer={localizer}
min={
bodyshop.schedule_start_time
? new Date(bodyshop.schedule_start_time)
: new Date("2020-01-01T06:00:00")
}
max={
bodyshop.schedule_end_time
? new Date(bodyshop.schedule_end_time)
: new Date("2020-01-01T20:00:00")
}
eventPropGetter={handleEventPropStyles}
components={{
event: (e) =>
Event({ bodyshop: bodyshop, event: e.event, refetch: refetch }),
header: (p) => (
<HeaderComponent {...p} events={data} refetch={refetch} />
),
}}
{...otherProps}
/>
</>
);
}

View File

@@ -9,6 +9,7 @@ export default function ScheduleCalendarComponent({ data, refetch }) {
return (
<Row gutter={[16, 16]}>
<ScheduleModal />
<Col span={24}>
<PageHeader
extra={

View File

@@ -12,7 +12,7 @@ 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";
const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop,
});
@@ -170,7 +170,7 @@ export function ScheduleJobModalComponent({
const values = form.getFieldsValue();
return (
<div style={{ height: "70vh" }}>
<div className="schedule-job-modal">
<ScheduleDayViewContainer day={values.start} />
</div>
);

View File

@@ -0,0 +1,10 @@
.schedule-job-modal {
height: 70vh;
.rbc-calendar {
.rbc-toolbar {
.rbc-btn-group {
display: none;
}
}
}
}

View File

@@ -89,6 +89,8 @@ export const QUERY_BODYSHOP = gql`
website
jc_hourly_rates
md_jobline_presets
cdk_dealerid
features
employees {
id
active
@@ -175,6 +177,7 @@ export const UPDATE_SHOP = gql`
website
jc_hourly_rates
md_jobline_presets
cdk_dealerid
employees {
id
first_name

View File

@@ -1611,6 +1611,7 @@ export const QUERY_ALL_JOBS_PAGINATED_STATUS_FILTERED = gql`
) {
ownr_fn
ownr_ln
ownerid
ownr_ph1
ownr_ea
plate_no

View File

@@ -1,10 +1,7 @@
import { AlertOutlined } from "@ant-design/icons";
import * as Sentry from "@sentry/react";
import { Button, notification, Space } from "antd";
//import "antd/dist/antd.css";
import "antd/dist/antd.less";
import Dinero from "dinero.js";
import i18n from "i18next";
import React from "react";
import ReactDOM from "react-dom";
import { Provider } from "react-redux";
@@ -15,7 +12,6 @@ import LoadingSpinner from "./components/loading-spinner/loading-spinner.compone
import "./index.css";
import { persistor, store } from "./redux/store";
import reportWebVitals from "./reportWebVitals";
import * as serviceWorkerRegistration from "./serviceWorkerRegistration";
import "./translations/i18n";
import "./utils/CleanAxios";
require("dotenv").config();
@@ -52,44 +48,44 @@ ReactDOM.render(
document.getElementById("root")
);
const onServiceWorkerUpdate = (registration) => {
console.log("onServiceWorkerUpdate", registration);
// const onServiceWorkerUpdate = (registration) => {
// console.log("onServiceWorkerUpdate", registration);
const btn = (
<Space flex>
<Button
onClick={async () => {
window.open("https://imex-online.noticeable.news/", "_blank");
}}
>
{i18n.t("general.actions.viewreleasenotes")}
</Button>
<Button
type="primary"
onClick={async () => {
if (registration && registration.waiting) {
await registration.unregister();
// Makes Workbox call skipWaiting()
registration.waiting.postMessage({ type: "SKIP_WAITING" });
// Once the service worker is unregistered, we can reload the page to let
// the browser download a fresh copy of our app (invalidating the cache)
window.location.reload();
}
}}
>
{i18n.t("general.actions.refresh")}
</Button>
</Space>
);
notification.open({
icon: <AlertOutlined />,
message: i18n.t("general.messages.newversiontitle"),
description: i18n.t("general.messages.newversionmessage"),
duration: 0,
btn,
key: "updateavailable",
});
};
// const btn = (
// <Space flex>
// <Button
// onClick={async () => {
// window.open("https://imex-online.noticeable.news/", "_blank");
// }}
// >
// {i18n.t("general.actions.viewreleasenotes")}
// </Button>
// <Button
// type="primary"
// onClick={async () => {
// if (registration && registration.waiting) {
// await registration.unregister();
// // Makes Workbox call skipWaiting()
// registration.waiting.postMessage({ type: "SKIP_WAITING" });
// // Once the service worker is unregistered, we can reload the page to let
// // the browser download a fresh copy of our app (invalidating the cache)
// window.location.reload();
// }
// }}
// >
// {i18n.t("general.actions.refresh")}
// </Button>
// </Space>
// );
// notification.open({
// icon: <AlertOutlined />,
// message: i18n.t("general.messages.newversiontitle"),
// description: i18n.t("general.messages.newversionmessage"),
// duration: 0,
// btn,
// key: "updateavailable",
// });
// };
serviceWorkerRegistration.register({ onUpdate: onServiceWorkerUpdate });
// serviceWorkerRegistration.register({ onUpdate: onServiceWorkerUpdate });
reportWebVitals();

View File

@@ -0,0 +1,53 @@
import React from 'react';
import { Button } from 'antd';
import { DownOutlined } from '@ant-design/icons';
import QueueAnim from 'rc-queue-anim';
import TweenOne from 'rc-tween-one';
import { isImg } from './utils';
class Banner extends React.PureComponent {
render() {
const { ...currentProps } = this.props;
const { dataSource } = currentProps;
delete currentProps.dataSource;
delete currentProps.isMobile;
return (
<div {...currentProps} {...dataSource.wrapper}>
<QueueAnim
key="QueueAnim"
type={['bottom', 'top']}
delay={200}
{...dataSource.textWrapper}
>
<div key="title" {...dataSource.title}>
{typeof dataSource.title.children === 'string' &&
dataSource.title.children.match(isImg) ? (
<img src={dataSource.title.children} width="100%" alt="img" />
) : (
dataSource.title.children
)}
</div>
<div key="content" {...dataSource.content}>
{dataSource.content.children}
</div>
<Button ghost key="button" {...dataSource.button}>
{dataSource.button.children}
</Button>
</QueueAnim>
<TweenOne
animation={{
y: '-=20',
yoyo: true,
repeat: -1,
duration: 1000,
}}
className="banner0-icon"
key="icon"
>
<DownOutlined />
</TweenOne>
</div>
);
}
}
export default Banner;

View File

@@ -0,0 +1,49 @@
import React from 'react';
import QueueAnim from 'rc-queue-anim';
import { Row, Col } from 'antd';
import OverPack from 'rc-scroll-anim/lib/ScrollOverPack';
import { getChildrenToRender } from './utils';
class Content extends React.PureComponent {
render() {
const { dataSource, isMobile, ...props } = this.props;
const {
wrapper,
titleWrapper,
page,
OverPack: overPackData,
childWrapper,
} = dataSource;
return (
<div {...props} {...wrapper}>
<div {...page}>
<div {...titleWrapper}>
{titleWrapper.children.map(getChildrenToRender)}
</div>
<OverPack {...overPackData}>
<QueueAnim
type="bottom"
key="block"
leaveReverse
component={Row}
componentProps={childWrapper}
>
{childWrapper.children.map((block, i) => {
const { children: item, ...blockProps } = block;
return (
<Col key={i.toString()} {...blockProps}>
<div {...item}>
{item.children.map(getChildrenToRender)}
</div>
</Col>
);
})}
</QueueAnim>
</OverPack>
</div>
</div>
);
}
}
export default Content;

View File

@@ -0,0 +1,70 @@
import React from 'react';
import QueueAnim from 'rc-queue-anim';
import TweenOne from 'rc-tween-one';
import { Row, Col } from 'antd';
import OverPack from 'rc-scroll-anim/lib/ScrollOverPack';
function Content1(props) {
const { ...tagProps } = props;
const { dataSource, isMobile } = tagProps;
delete tagProps.dataSource;
delete tagProps.isMobile;
const animType = {
queue: isMobile ? 'bottom' : 'right',
one: isMobile
? {
scaleY: '+=0.3',
opacity: 0,
type: 'from',
ease: 'easeOutQuad',
}
: {
x: '-=30',
opacity: 0,
type: 'from',
ease: 'easeOutQuad',
},
};
return (
<div {...tagProps} {...dataSource.wrapper}>
<OverPack {...dataSource.OverPack} component={Row}>
<TweenOne
key="img"
animation={animType.one}
resetStyle
{...dataSource.imgWrapper}
component={Col}
componentProps={{
md: dataSource.imgWrapper.md,
xs: dataSource.imgWrapper.xs,
}}
>
<span {...dataSource.img}>
<img src={dataSource.img.children} width="100%" alt="img" />
</span>
</TweenOne>
<QueueAnim
key="text"
type={animType.queue}
leaveReverse
ease={['easeOutQuad', 'easeInQuad']}
{...dataSource.textWrapper}
component={Col}
componentProps={{
md: dataSource.textWrapper.md,
xs: dataSource.textWrapper.xs,
}}
>
<h2 key="h1" {...dataSource.title}>
{dataSource.title.children}
</h2>
<div key="p" {...dataSource.content}>
{dataSource.content.children}
</div>
</QueueAnim>
</OverPack>
</div>
);
}
export default Content1;

View File

@@ -0,0 +1,60 @@
import React from 'react';
import { Row, Col } from 'antd';
import { TweenOneGroup } from 'rc-tween-one';
import OverPack from 'rc-scroll-anim/lib/ScrollOverPack';
import { getChildrenToRender } from './utils';
class Content12 extends React.PureComponent {
getChildrenToRender = (data) =>
data.map((item) => {
return (
<Col key={item.name} {...item}>
<div {...item.children.wrapper}>
<span {...item.children.img}>
<img src={item.children.img.children} alt="img" />
</span>
</div>
</Col>
);
});
render() {
const { ...props } = this.props;
const { dataSource } = props;
delete props.dataSource;
delete props.isMobile;
const childrenToRender = this.getChildrenToRender(
dataSource.block.children
);
return (
<div {...props} {...dataSource.wrapper}>
<div {...dataSource.page}>
<div key="title" {...dataSource.titleWrapper}>
{dataSource.titleWrapper.children.map(getChildrenToRender)}
</div>
<OverPack
className={`content-template ${props.className}`}
{...dataSource.OverPack}
>
<TweenOneGroup
component={Row}
key="ul"
enter={{
y: '+=30',
opacity: 0,
type: 'from',
ease: 'easeOutQuad',
}}
leave={{ y: '+=30', opacity: 0, ease: 'easeOutQuad' }}
{...dataSource.block}
>
{childrenToRender}
</TweenOneGroup>
</OverPack>
</div>
</div>
);
}
}
export default Content12;

View File

@@ -0,0 +1,94 @@
import React from 'react';
import QueueAnim from 'rc-queue-anim';
import TweenOne from 'rc-tween-one';
import { Row, Col } from 'antd';
import OverPack from 'rc-scroll-anim/lib/ScrollOverPack';
import { getChildrenToRender } from './utils';
class Content3 extends React.PureComponent {
getDelay = (e, b) => (e % b) * 100 + Math.floor(e / b) * 100 + b * 100;
render() {
const { ...props } = this.props;
const { dataSource, isMobile } = props;
delete props.dataSource;
delete props.isMobile;
let clearFloatNum = 0;
const children = dataSource.block.children.map((item, i) => {
const childObj = item.children;
const delay = isMobile ? i * 50 : this.getDelay(i, 24 / item.md);
const liAnim = {
opacity: 0,
type: 'from',
ease: 'easeOutQuad',
delay,
};
const childrenAnim = { ...liAnim, x: '+=10', delay: delay + 100 };
clearFloatNum += item.md;
clearFloatNum = clearFloatNum > 24 ? 0 : clearFloatNum;
return (
<TweenOne
component={Col}
animation={liAnim}
key={item.name}
{...item}
componentProps={{ md: item.md, xs: item.xs }}
className={
!clearFloatNum
? `${item.className || ''} clear-both`.trim()
: item.className
}
>
<TweenOne
animation={{
x: '-=10',
opacity: 0,
type: 'from',
ease: 'easeOutQuad',
}}
key="img"
{...childObj.icon}
>
<img src={childObj.icon.children} width="100%" alt="img" />
</TweenOne>
<div {...childObj.textWrapper}>
<TweenOne
key="h2"
animation={childrenAnim}
component="h2"
{...childObj.title}
>
{childObj.title.children}
</TweenOne>
<TweenOne
key="p"
animation={{ ...childrenAnim, delay: delay + 200 }}
component="div"
{...childObj.content}
>
{childObj.content.children}
</TweenOne>
</div>
</TweenOne>
);
});
return (
<div {...props} {...dataSource.wrapper}>
<div {...dataSource.page}>
<div {...dataSource.titleWrapper}>
{dataSource.titleWrapper.children.map(getChildrenToRender)}
</div>
<OverPack {...dataSource.OverPack}>
<QueueAnim key="u" type="bottom">
<Row key="row" {...dataSource.block}>
{children}
</Row>
</QueueAnim>
</OverPack>
</div>
</div>
);
}
}
export default Content3;

View File

@@ -0,0 +1,59 @@
import React from 'react';
import TweenOne from 'rc-tween-one';
import OverPack from 'rc-scroll-anim/lib/ScrollOverPack';
import VideoPlay from 'react-sublime-video';
import { getChildrenToRender } from './utils';
function Content4(props) {
const { ...tagProps } = props;
const { dataSource, isMobile } = tagProps;
delete tagProps.dataSource;
delete tagProps.isMobile;
const animation = {
y: '+=30',
opacity: 0,
type: 'from',
ease: 'easeOutQuad',
};
const videoChildren = dataSource.video.children.video;
const videoNameArray = videoChildren.split('.');
const type = videoNameArray[videoNameArray.length - 1];
return (
<div {...tagProps} {...dataSource.wrapper}>
<div {...dataSource.page}>
<div key="title" {...dataSource.titleWrapper}>
{dataSource.titleWrapper.children.map(getChildrenToRender)}
</div>
<OverPack {...dataSource.OverPack}>
<TweenOne
key="video"
animation={{ ...animation, delay: 300 }}
{...dataSource.video}
>
{isMobile ? (
<video
width="100%"
loop
controls
poster={dataSource.video.children.image}
>
<source src={videoChildren} type={`video/${type}`} />
<track kind="captions" />
</video>
) : (
<VideoPlay
loop
width="100%"
poster={dataSource.video.children.image}
>
<source src={videoChildren} type={`video/${type}`} />
</VideoPlay>
)}
</TweenOne>
</OverPack>
</div>
</div>
);
}
export default Content4;

View File

@@ -0,0 +1,69 @@
import React from 'react';
import TweenOne from 'rc-tween-one';
import OverPack from 'rc-scroll-anim/lib/ScrollOverPack';
import QueueAnim from 'rc-queue-anim';
import { Row, Col } from 'antd';
import { getChildrenToRender } from './utils';
import { isImg } from './utils';
class Footer extends React.Component {
static defaultProps = {
className: 'footer1',
};
getLiChildren = (data) =>
data.map((item, i) => {
const { title, childWrapper, ...itemProps } = item;
return (
<Col key={i.toString()} {...itemProps} title={null} content={null}>
<h2 {...title}>
{typeof title.children === 'string' &&
title.children.match(isImg) ? (
<img src={title.children} width="100%" alt="img" />
) : (
title.children
)}
</h2>
<div {...childWrapper}>
{childWrapper.children.map(getChildrenToRender)}
</div>
</Col>
);
});
render() {
const { ...props } = this.props;
const { dataSource } = props;
delete props.dataSource;
delete props.isMobile;
const childrenToRender = this.getLiChildren(dataSource.block.children);
return (
<div {...props} {...dataSource.wrapper}>
<OverPack {...dataSource.OverPack}>
<QueueAnim
type="bottom"
key="ul"
leaveReverse
component={Row}
{...dataSource.block}
>
{childrenToRender}
</QueueAnim>
<TweenOne
animation={{ y: '+=30', opacity: 0, type: 'from' }}
key="copyright"
{...dataSource.copyrightWrapper}
>
<div {...dataSource.copyrightPage}>
<div {...dataSource.copyright}>
{dataSource.copyright.children}
</div>
</div>
</TweenOne>
</OverPack>
</div>
);
}
}
export default Footer;

135
client/src/landing/Nav0.jsx Normal file
View File

@@ -0,0 +1,135 @@
import React from 'react';
import TweenOne from 'rc-tween-one';
import { Menu } from 'antd';
import { getChildrenToRender } from './utils';
const { Item, SubMenu } = Menu;
class Header extends React.Component {
constructor(props) {
super(props);
this.state = {
phoneOpen: undefined,
};
}
phoneClick = () => {
const phoneOpen = !this.state.phoneOpen;
this.setState({
phoneOpen,
});
};
render() {
const { dataSource, isMobile, ...props } = this.props;
const { phoneOpen } = this.state;
const navData = dataSource.Menu.children;
const navChildren = navData.map((item) => {
const { children: a, subItem, ...itemProps } = item;
if (subItem) {
return (
<SubMenu
key={item.name}
{...itemProps}
title={
<div
{...a}
className={`header0-item-block ${a.className}`.trim()}
>
{a.children.map(getChildrenToRender)}
</div>
}
popupClassName="header0-item-child"
>
{subItem.map(($item, ii) => {
const { children: childItem } = $item;
const child = childItem.href ? (
<a {...childItem}>
{childItem.children.map(getChildrenToRender)}
</a>
) : (
<div {...childItem}>
{childItem.children.map(getChildrenToRender)}
</div>
);
return (
<Item key={$item.name || ii.toString()} {...$item}>
{child}
</Item>
);
})}
</SubMenu>
);
}
return (
<Item key={item.name} {...itemProps}>
<a {...a} className={`header0-item-block ${a.className}`.trim()}>
{a.children.map(getChildrenToRender)}
</a>
</Item>
);
});
const moment = phoneOpen === undefined ? 300 : null;
return (
<TweenOne
component="header"
animation={{ opacity: 0, type: 'from' }}
{...dataSource.wrapper}
{...props}
>
<div
{...dataSource.page}
className={`${dataSource.page.className}${phoneOpen ? ' open' : ''}`}
>
<TweenOne
animation={{ x: -30, type: 'from', ease: 'easeOutQuad' }}
{...dataSource.logo}
>
<img width="100%" src={dataSource.logo.children} alt="img" />
</TweenOne>
{isMobile && (
<div
{...dataSource.mobileMenu}
onClick={() => {
this.phoneClick();
}}
>
<em />
<em />
<em />
</div>
)}
<TweenOne
{...dataSource.Menu}
animation={
isMobile
? {
height: 0,
duration: 300,
onComplete: (e) => {
if (this.state.phoneOpen) {
e.target.style.height = 'auto';
}
},
ease: 'easeInOutQuad',
}
: null
}
moment={moment}
reverse={!!phoneOpen}
>
<Menu
mode={isMobile ? 'inline' : 'horizontal'}
defaultSelectedKeys={['sub0']}
theme="dark"
>
{navChildren}
</Menu>
</TweenOne>
</div>
</TweenOne>
);
}
}
export default Header;

View File

@@ -0,0 +1,73 @@
import React from 'react';
import OverPack from 'rc-scroll-anim/lib/ScrollOverPack';
import QueueAnim from 'rc-queue-anim';
import { Row, Col, Button } from 'antd';
import { getChildrenToRender } from './utils';
class Pricing1 extends React.PureComponent {
getChildrenToRender = (item) => {
const {
wrapper,
topWrapper,
name,
buttonWrapper,
line,
content,
money,
} = item.children;
return (
<Col key={item.name} {...item}>
<QueueAnim type="bottom" {...wrapper}>
<div {...topWrapper}>
<div {...name} key="name">
{name.children}
</div>
<h1 {...money} key="money">
{money.children}
</h1>
</div>
<div {...content} key="content">
{content.children}
</div>
<i {...line} key="line" />
<div {...buttonWrapper} key="button">
<Button {...buttonWrapper.children.a}>
{buttonWrapper.children.a.children}
</Button>
</div>
</QueueAnim>
</Col>
);
};
render() {
const { ...props } = this.props;
const { dataSource } = props;
delete props.dataSource;
delete props.isMobile;
const { block } = dataSource;
const childrenToRender = block.children.map(this.getChildrenToRender);
return (
<div {...props} {...dataSource.wrapper}>
<div {...dataSource.page}>
<div key="title" {...dataSource.titleWrapper}>
{dataSource.titleWrapper.children.map(getChildrenToRender)}
</div>
<OverPack {...dataSource.OverPack}>
<QueueAnim
type="bottom"
component={Row}
leaveReverse
ease={['easeOutQuad', 'easeInOutQuad']}
key="content"
>
{childrenToRender}
</QueueAnim>
</OverPack>
</div>
</div>
);
}
}
export default Pricing1;

View File

@@ -0,0 +1,114 @@
import React from 'react';
import OverPack from 'rc-scroll-anim/lib/ScrollOverPack';
import QueueAnim from 'rc-queue-anim';
import { Table } from 'antd';
import { getChildrenToRender, isImg } from './utils';
class Pricing2 extends React.PureComponent {
getColumns = (columns) => {
return columns.map((item) => {
const { childWrapper, ...$item } = item;
return {
align: 'center',
...$item,
title: (
<div {...childWrapper}>
{childWrapper.children.map(getChildrenToRender)}
</div>
),
};
});
};
getDataSource = (dataSource, columns) =>
dataSource.map((item, i) => {
const obj = { key: i.toString() };
item.children.forEach(($item, ii) => {
if (columns[ii]) {
obj[columns[ii].key] = (
<div {...$item}>
{typeof $item.children === 'string' &&
$item.children.match(isImg) ? (
<img src={$item.children} alt="img" />
) : (
$item.children
)}
</div>
);
}
});
return obj;
});
getMobileChild = (table) => {
const { columns, dataSource, ...tableProps } = table;
const names = columns.children.filter(
(item) => item.key.indexOf('name') >= 0
);
const newColumns = columns.children.filter(
(item) => item.key.indexOf('name') === -1
);
return newColumns.map((item, i) => {
const items = [].concat(names[0], item).filter((c) => c);
if (items.length > 1) {
items[0].colSpan = 0;
items[1].colSpan = 2;
}
const dataSources = dataSource.children.map(($item) => {
const child = $item.children.filter(
(c) => c.name.indexOf('name') === -1
);
const n = $item.children.filter((c) => c.name.indexOf('name') >= 0);
return {
...$item,
children: [].concat(n[0], child[i]).filter((c) => c),
};
});
const props = {
...tableProps,
columns: this.getColumns(items),
dataSource: this.getDataSource(dataSources, items),
};
return (
<Table key={i.toString()} {...props} pagination={false} bordered />
);
});
};
render() {
const { dataSource, isMobile, ...props } = this.props;
const { Table: table, wrapper, page, titleWrapper } = dataSource;
const { columns, dataSource: tableData, ...$table } = table;
const tableProps = {
...$table,
columns: this.getColumns(columns.children),
dataSource: this.getDataSource(tableData.children, columns.children),
};
const childrenToRender = isMobile ? (
this.getMobileChild(table)
) : (
<Table key="table" {...tableProps} pagination={false} bordered />
);
return (
<div {...props} {...wrapper}>
<div {...page}>
<div key="title" {...titleWrapper}>
{titleWrapper.children.map(getChildrenToRender)}
</div>
<OverPack {...dataSource.OverPack}>
<QueueAnim
type="bottom"
leaveReverse
ease={['easeOutQuad', 'easeInOutQuad']}
key="content"
>
{childrenToRender}
</QueueAnim>
</OverPack>
</div>
</div>
);
}
}
export default Pricing2;

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,4 @@
# 如何使用:
- umi 里如何使用[请查看](https://landing.ant.design/docs/use/umi)。
- 其它脚手架使用[请查看](https://landing.ant.design/docs/use/getting-started)。

View File

@@ -0,0 +1,146 @@
/* eslint no-undef: 0 */
/* eslint arrow-parens: 0 */
import { enquireScreen } from "enquire-js";
import React from "react";
import Banner0 from "./Banner0";
// import Content4 from "./Content4";
import Content0 from "./Content0";
import Content1 from "./Content1";
import {
Banner00DataSource,
// Content40DataSource,
Content00DataSource,
Content10DataSource,
// Pricing11DataSource,
// Content30DataSource,
// Content120DataSource,
Footer10DataSource,
Nav00DataSource,
Pricing20DataSource,
} from "./data.source";
// import Pricing1 from "./Pricing1";
// import Content3 from "./Content3";
// import Content12 from "./Content12";
import Footer1 from "./Footer1";
import "./less/antMotionStyle.less";
import Nav0 from "./Nav0";
import Pricing2 from "./Pricing2";
let isMobile;
enquireScreen((b) => {
isMobile = b;
});
const { location = {} } = typeof window !== "undefined" ? window : {};
export default class Home extends React.Component {
constructor(props) {
super(props);
this.state = {
isMobile,
show: !location.port, // 如果不是 dva 2.0 请删除
};
}
componentDidMount() {
// 适配手机屏幕;
enquireScreen((b) => {
this.setState({ isMobile: !!b });
});
// dva 2.0 样式在组件渲染之后动态加载,导致滚动组件不生效;线上不影响;
/* 如果不是 dva 2.0 请删除 start */
if (location.port) {
// 样式 build 时间在 200-300ms 之间;
setTimeout(() => {
this.setState({
show: true,
});
}, 500);
}
/* 如果不是 dva 2.0 请删除 end */
console.log("Setting $crisp segments", ["lead"]);
window.$crisp.push(["set", "session:segments", [["lead"]]]);
window.$crisp.push([
"set",
"session:event",
[[["landing-page", {}, "green"]]],
]);
}
render() {
const children = [
<Nav0
id="Nav0_0"
key="Nav0_0"
dataSource={Nav00DataSource}
isMobile={this.state.isMobile}
/>,
<Banner0
id="Banner0_0"
key="Banner0_0"
dataSource={Banner00DataSource}
isMobile={this.state.isMobile}
/>,
// <Content4
// id="Content4_0"
// key="Content4_0"
// dataSource={Content40DataSource}
// isMobile={this.state.isMobile}
// />,
<Content1
id="Content1_0"
key="Content1_0"
dataSource={Content10DataSource}
isMobile={this.state.isMobile}
/>,
<Content0
id="Content0_0"
key="Content0_0"
dataSource={Content00DataSource}
isMobile={this.state.isMobile}
/>,
<Pricing2
id="Pricing2_0"
key="Pricing2_0"
dataSource={Pricing20DataSource}
isMobile={this.state.isMobile}
/>,
// <Pricing1
// id="Pricing1_1"
// key="Pricing1_1"
// dataSource={Pricing11DataSource}
// isMobile={this.state.isMobile}
// />,
// <Content3
// id="Content3_0"
// key="Content3_0"
// dataSource={Content30DataSource}
// isMobile={this.state.isMobile}
// />,
// <Content12
// id="Content12_0"
// key="Content12_0"
// dataSource={Content120DataSource}
// isMobile={this.state.isMobile}
// />,
<Footer1
id="Footer1_0"
key="Footer1_0"
dataSource={Footer10DataSource}
isMobile={this.state.isMobile}
/>,
];
return (
<div
className="templates-wrapper"
ref={(d) => {
this.dom = d;
}}
>
{/* 如果不是 dva 2.0 替换成 {children} start */}
{this.state.show && children}
{/* 如果不是 dva 2.0 替换成 {children} end */}
</div>
);
}
}

View File

@@ -0,0 +1,14 @@
@import './common.less';
@import './custom.less';
@import './content.less';
@import './nav0.less';
@import './banner0.less';
@import './content4.less';
@import './content0.less';
@import './content1.less';
@import './pricing2.less';
@import './pricing1.less';
@import './content3.less';
@import './content12.less';
@import './footer1.less';
@import './edit.less';

View File

@@ -0,0 +1,84 @@
@banner0: banner0;
.@{banner0} {
// 如果在第一屏且导航位置为 relative, 一屏为 height: calc(~"100vh - 64px");
width: 100%;
height: 100vh;
position: relative;
text-align: center;
border-color: #666;
background-image: url("../../assets/banner1.jpeg");
background-size: cover;
background-attachment: fixed;
background-position: center;
& &-text-wrapper {
display: inline-block;
position: absolute;
top: 20%;
margin: auto;
left: 0;
right: 0;
font-size: 14px;
color: @template-text-color-light;
width: 550px;
> .queue-anim-leaving {
position: relative !important;
}
}
& &-title {
width: 350px;
//left: 30px;
min-height: 60px;
margin: auto;
display: inline-block;
font-size: 40px;
position: relative;
}
& &-content {
margin-bottom: 20px;
word-wrap: break-word;
min-height: 24px;
}
& &-button {
border: 1px solid #fff;
color: #fff;
background: transparent;
box-shadow: 0 0 0 transparent;
font-size: 16px;
height: 40px;
transition: background 0.45s @ease-out, box-shadow 0.45s @ease-out;
&:hover {
color: #fff;
border-color: #fff;
background: rgba(255, 255, 255, 0.1);
box-shadow: 0 0 10px rgba(50, 250, 255, 0.75);
}
&:focus {
color: #fff;
border-color: #fff;
}
&.queue-anim-leaving {
width: auto;
}
}
& &-icon {
bottom: 20px;
font-size: 24px;
position: absolute;
left: 50%;
margin-left: -12px;
color: @template-text-color-light;
}
}
@media screen and (max-width: 767px) {
.@{banner0} {
background-attachment: inherit;
& &-text-wrapper {
width: 90%;
}
& &-title {
width: 90%;
left: 0;
}
}
}

View File

@@ -0,0 +1,42 @@
// @import "~antd/lib/style/v2-compatible-reset.less";
body {
word-wrap: break-word;
}
body,
div,
dl,
dt,
dd,
ul,
ol,
li,
h1,
h2,
h3,
h4,
h5,
h6 {
margin: 0;
padding: 0;
}
/* .content-wrapper > .tween-one-leaving,
.queue-anim-leaving {
// position: absolute !important;
// width: 100%;
} */
.video {
max-width: 800px;
}
#react-content {
min-height: 100%;
}
.home-page-wrapper p {
padding: 0;
margin: 0;
}

View File

@@ -0,0 +1,44 @@
@homepage: home-page;
.@{homepage}-wrapper {
width: 100%;
position: relative;
overflow: hidden;
.@{homepage} {
height: 100%;
max-width: 1200px;
position: relative;
margin: auto;
will-change: transform;
}
.title-wrapper > h1, > h1 {
font-size: 32px;
color: @text-color;
margin-bottom: 16px;
}
.title-wrapper {
margin: 0 auto 64px;
text-align: center;
}
}
.@{homepage} {
padding: 128px 24px;
}
@media screen and (max-width: 767px) {
.@{homepage}-wrapper {
.@{homepage} {
padding: 56px 24px;
>h1 {
font-size: 24px;
margin: 0 auto 32px;
&.title-h1 {
margin-bottom: 8px;
}
}
>p {
margin-bottom: 32px;
}
}
}
}

View File

@@ -0,0 +1,55 @@
@content0: content0;
.@{content0}-wrapper {
min-height: 446px;
overflow: hidden;
.@{content0} {
height: 100%;
padding: 64px 24px;
>.title-wrapper {
margin: 0 auto 48px;
}
&-block {
padding: 0 4%;
display: inline-block;
text-align: center;
min-height: 200px;
margin-bottom: 24px;
img {
width: 100%;
}
&-wrapper {
position: relative;
height: 100%;
top: 25%;
padding: 20px 0;
}
&.queue-anim-leaving {
position: relative !important;
}
&-icon {
width: 100px;
height: 100px;
margin: auto;
}
&-title {
line-height: 32px;
margin: 10px auto;
font-size: 24px;
}
}
}
}
@media screen and (max-width: 767px) {
.@{content0}-wrapper {
min-height: 880px;
}
}

View File

@@ -0,0 +1,76 @@
@content1: content1;
.@{content1}-wrapper {
height: 360px;
.@{content1} {
height: 100%;
padding: 0 24px;
&-img {
height: 100%;
transform-origin: top;
padding: 0 32px;
display: flex;
align-items: center;
justify-content: center;
span {
display: block;
width: 250px;
img {
display: block;
}
}
}
&-text {
padding: 0 32px;
height: 100%;
.@{content1}-content,
.@{content1}-title {
position: relative !important;
}
.@{content1}-title {
font-size: 32px;
font-weight: normal;
color: #404040;
margin-top: 120px;
}
.content {
margin-top: 20px;
}
}
}
}
@media screen and (max-width: 767px) {
.@{content1}-wrapper {
height: 600px;
.@{content1} {
&-img {
height: 200px;
padding: 0;
text-align: center;
margin-top: 64px;
span {
display: inline-block;
width: 180px;
height: 200px;
line-height: 200px;
margin: auto;
}
}
&-text {
height: auto;
margin-bottom: 20px;
text-align: center;
padding: 0;
.@{content1}-content,
.@{content1}-title {
width: 100%;
top: auto;
}
.@{content1}-title {
margin: 32px auto 16px;
font-size: 24px;
}
}
}
}
}

View File

@@ -0,0 +1,52 @@
@content12: content12;
.@{content12}-wrapper {
background-color: #fafafa;
min-height: 470px;
.@{content12} {
padding: 64px 24px;
>p {
text-align: center;
}
}
.img-wrapper {
margin: 0 auto;
left: 0;
right: 0;
.block {
margin-bottom: 40px;
.block-content {
display: flex;
border-radius: 4px;
text-align: center;
position: relative;
overflow: hidden;
border: none;
height: 64px;
align-items: center;
transition: box-shadow .3s @ease-out, transform .3s @ease-out;
& > span {
width: 100%;
display: block;
}
}
}
}
}
@media screen and (max-width: 767px) {
.@{content12}-wrapper {
overflow: hidden;
.@{content12} {
ul {
li {
display: block;
width: 100%;
padding: 2%;
span {
height: 168px;
}
}
}
}
}
}

View File

@@ -0,0 +1,52 @@
@content3: content3;
.@{content3}-wrapper {
min-height: 764px;
.@{content3} {
height: 100%;
overflow: hidden;
& .title-content {
text-align: center;
}
&-block-wrapper {
position: relative;
.@{content3}-block {
display: inline-block;
padding: 48px 24px;
vertical-align: top;
.@{content3}-icon {
display: inline-block;
width: 15%;
vertical-align: top;
}
.@{content3}-text {
width: 85%;
display: inline-block;
padding-left: 8%;
}
&.clear-both {
clear: both;
}
}
}
}
}
@media screen and (max-width: 767px) {
.@{content3}-wrapper {
min-height: 1080px;
.@{content3} {
&-block-wrapper {
margin: 20px auto;
height: auto;
.@{content3}-block {
.@{content3}-title {
font-size: 20px;
}
&.queue-anim-leaving {
position: relative !important;
}
}
}
}
}
}

View File

@@ -0,0 +1,37 @@
@content4: content4;
.@{content4}-wrapper {
min-height: 720px;
background: #fafafa;
.@{content4} {
height: 100%;
overflow: hidden;
&-video {
border-radius: 4px;
overflow: hidden;
max-width: 800px;
margin: auto;
background: #fff;
box-shadow: 0 4px 8px rgba(0, 0, 0, .15);
video {
display: block;
margin: auto;
}
}
}
}
@media screen and (max-width: 767px) {
.@{content4}-wrapper {
min-height: 350px;
.@{content4} {
overflow: hidden;
width: 90%;
margin: auto;
&-video {
top: 15%;
background: url("https://zos.alipayobjects.com/rmsportal/HZgzhugQZkqUwBVeNyfz.jpg") no-repeat center;
background-size: cover;
}
}
}
}

View File

@@ -0,0 +1,35 @@
@import "~antd/lib/style/themes/default.less";
@line-color: #e9e9e9;
@shadow-color: rgba(0, 0, 0, 0.15);
@bottom-bar-bg-color: #262626;
@bottom-bar-line-color: #000;
@template-bg-color: #001529;
@template-bg-color-light: #ececec;
@template-nav-bg-color: #001529;
@template-text-color: #ccc;
@template-text-title-color: #bcbcbc;
@template-text-color-light: #fff;
@template-footer-text-color: #999;
@animate-duration: .45s;
/* 详细页图片或框框的样式;
*/
.page-shadow() {
box-shadow: 0 5px 8px @shadow-color;
}
.page-pro() {
border-radius: 6px;
border: 1px solid @line-color;
transform: translateY(0);
transition: transform .3s @ease-out, box-shadow .3s @ease-out;
&:hover {
.page-shadow();
transform: translateY(-5px);
}
}

View File

View File

@@ -0,0 +1,98 @@
.footer1-wrapper {
background: @template-bg-color;
overflow: hidden;
position: relative;
min-height: 360px;
color: @template-footer-text-color;
.footer1 {
.home-page {
padding: 64px 24px 80px;
}
}
.block {
padding: 0 32px;
.logo {
max-width: 180px;
}
.slogan {
font-size: 12px;
margin-top: -20px;
}
>h2 {
margin-bottom: 24px;
color: @template-text-color;
}
a {
color: @template-footer-text-color;
margin-bottom: 12px;
float: left;
clear: both;
&:hover {
color: @primary-color;
}
}
}
.copyright-wrapper {
width: 100%;
border-top: 1px solid fade(@line-color, 10);
.home-page {
padding: 0 24px;
overflow: hidden;
}
.copyright {
height: 80px;
text-align: center;
line-height: 80px;
}
}
}
@media screen and (max-width: 767px) {
.footer1 {
min-height: 550px;
&-wrapper {
.footer1 {
.home-page {
padding: 64px 24px 32px;
}
}
}
.logo {
margin: 0 auto 24px;
}
.block {
text-align: center;
margin-bottom: 32px;
padding: 0;
}
>ul {
width: 90%;
margin: 20px auto 0;
padding: 10px 0;
>li {
width: 100%;
h2 {
margin-bottom: 10px;
}
li {
display: inline-block;
margin-right: 10px;
}
}
}
.copyright {
&-wrapper {
.home-page {
padding: 0;
.copyright {
font-size: 12px;
}
}
}
span {
width: 90%;
}
}
}
}

View File

@@ -0,0 +1,187 @@
@header0: header0;
.@{header0} {
background: @template-nav-bg-color;
width: 100%;
z-index: 1;
box-shadow: 0 5px 8px fade(#000, 15);
position: relative;
top: 0;
.home-page {
padding: 0 24px;
}
&-logo {
display: inline-block;
position: relative;
width: 150px;
line-height: 64px;
& img {
vertical-align: middle;
display: inline-block;
}
& a {
display: block;
}
}
&-menu {
float: right;
.ant-menu {
line-height: 62px;
height: 64px;
a {
display: block;
}
}
}
&-item {
&-block {
padding: 0 8px;
>* {
display: inline-block;
}
}
}
&-item,
&-item-child,
&-menu {
.ant-menu-sub .ant-menu-item,
.ant-menu-inline .ant-menu-item {
height: auto;
line-height: 1.5;
}
.item {
&-sub-item {
display: block;
padding: 8px 24px;
}
&-image {
float: left;
margin-right: 16px;
margin-top: 4px;
position: relative;
z-index: 1;
}
&-title {
font-size: 14px;
color: #fff;
margin-left: 46px;
}
&-content {
font-size: 12px;
color: fade(#fff, 75);
margin-left: 46px;
}
}
}
}
@media screen and (max-width: 767px) {
.@{header0} {
&-logo {
z-index: 101;
}
&.home-page-wrapper .home-page {
padding: 0 24px;
}
&-menu {
height: auto;
float: inherit;
position: relative;
left: -24px;
width: ~"calc(100% + 48px)";
opacity: 0;
transition: opacity .3s @ease-in-out;
& li {
padding: 0 24px;
&.ant-menu-submenu {
padding: 0;
}
}
.item {
&-sub-item {
padding: 8px 0;
}
}
}
&-mobile-menu {
width: 16px;
height: 14px;
cursor: pointer;
position: absolute;
top: 24px;
right: 24px;
z-index: 100;
em {
display: block;
width: 100%;
height: 2px;
background: #fff;
margin-top: 4px;
transition: transform .3s @ease-in-out, opacity .3s @ease-in-out;
}
:first-child {
margin-top: 0;
}
}
.ant-menu {
height: auto;
overflow: hidden;
.ant-menu-item-selected {
border: none;
}
}
& .open {
height: auto;
.@{header0}-mobile-menu {
em {
&:nth-child(1) {
transform: translateY(6px) rotate(45deg);
}
&:nth-child(2) {
opacity: 0;
}
&:nth-child(3) {
transform: translateY(-6px) rotate(-45deg);
}
}
}
>.@{header0}-menu {
opacity: 1;
pointer-events: auto;
}
}
&-item-block {
height: 40px;
line-height: 40px;
}
}
}

View File

@@ -0,0 +1,85 @@
@pricing1: pricing1;
.@{pricing1}-wrapper {
min-height: 760px;
.@{pricing1} {
>p {
text-align: center;
}
&-content-wrapper {
min-height: 400px;
}
&-block-box {
width: 260px;
border-radius: 4px;
background: #eef0f3;
text-align: center;
color: #666;
min-height: 400px;
margin: auto;
border: 1px solid transparent;
.page-pro();
&.active {
border-color: @primary-color;
background: #fff;
.@{pricing1} {
&-top-wrapper {
background: @primary-color;
}
&-name,
&-money,
&-button {
color: #fff;
}
&-button {
background: @primary-color;
}
}
}
}
&-block {
margin-bottom: 24px;
}
&-top-wrapper {
width: 100%;
padding: 16px 24px;
}
&-name {
font-size: 14px;
}
&-money {
font-family: 'Helvetica Neue', sans-serif;
font-size: 32px;
color: #666;
}
&-content {
font-size: 12px;
line-height: 2;
font-weight: 300;
margin: 32px 24px 48px;
}
&-line {
display: block;
height: 1px;
background: #d9d9d9;
margin: 0 24px;
}
&-button-wrapper {
margin: 18px 24px;
}
&-button {
padding: 0 24px;
}
}
&.home-page-wrapper {
.@{pricing1}-title-wrapper {
margin-bottom: 64px;
text-align: center;
}
}
}
@media screen and (max-width: 767px) {
.@{pricing1}-wrapper {
padding-bottom: 0;
}
}

View File

@@ -0,0 +1,59 @@
@pricing2: pricing2;
.@{pricing2}-wrapper {
min-height: 760px;
.@{pricing2} {
>p {
text-align: center;
}
&-content-wrapper {
min-height: 400px;
}
&-table-name-block {
text-align: center;
color: #666;
width: 100%;
}
&-table-name {
font-size: 24px;
}
&-table-money {
font-size: 16px;
margin: 8px 0 16px;
}
&-table-content {
text-align: center;
color: #666;
&-name {
color: #666;
text-align: center;
}
}
}
&.home-page-wrapper {
.@{pricing2}-title-wrapper {
margin-bottom: 64px;
text-align: center;
}
}
}
@media screen and (max-width: 767px) {
.@{pricing2} {
&-wrapper {
padding-bottom: 0;
}
&-table {
margin-bottom: 24px;
}
}
}

View File

@@ -0,0 +1,18 @@
import React from 'react';
import { Button } from 'antd';
export const isImg = /^http(s)?:\/\/([\w-]+\.)+[\w-]+(\/[\w-./?%&=]*)?/;
export const getChildrenToRender = (item, i) => {
let tag = item.name.indexOf('title') === 0 ? 'h1' : 'div';
tag = item.href ? 'a' : tag;
let children = typeof item.children === 'string' && item.children.match(isImg)
? React.createElement('img', { src: item.children, alt: 'img' })
: item.children;
if (item.name.indexOf('button') === 0 && typeof item.children === 'object') {
children = React.createElement(Button, {
...item.children
});
}
return React.createElement(tag, { key: i.toString(), ...item }, children);
};

View File

@@ -110,6 +110,23 @@ export function ContractDetailPage({
"printcenter.courtesycarcontract.courtesy_car_terms"
)}
</Menu.Item>
<Menu.Item
onClick={() =>
GenerateDocument(
{
name: TemplateList("courtesycarcontract")
.courtesy_car_impound.key,
variables: { id: contract.id },
},
{},
"p"
)
}
>
{t(
"printcenter.courtesycarcontract.courtesy_car_impound"
)}
</Menu.Item>
</Menu>
}
>

View File

@@ -7,6 +7,7 @@ import {
setBreadcrumbs,
setSelectedHeader,
} from "../../redux/application/application.actions";
import FeatureWrapper from "../../components/feature-wrapper/feature-wrapper.component";
const mapDispatchToProps = (dispatch) => ({
setBreadcrumbs: (breadcrumbs) => dispatch(setBreadcrumbs(breadcrumbs)),
@@ -28,9 +29,11 @@ export function ExportsLogPageContainer({ setBreadcrumbs, setSelectedHeader }) {
}, [setBreadcrumbs, t, setSelectedHeader]);
return (
<RbacWrapper action="shop:dashboard">
<DashboardGridComponent />
</RbacWrapper>
<FeatureWrapper featureName="dashboard">
<RbacWrapper action="shop:dashboard">
<DashboardGridComponent />
</RbacWrapper>
</FeatureWrapper>
);
}
export default connect(null, mapDispatchToProps)(ExportsLogPageContainer);

View File

@@ -0,0 +1,171 @@
import { Result, Timeline, Space, Tag, Divider, Button, Select } from "antd";
import React, { useEffect, useState } from "react";
import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
import {
setBreadcrumbs,
setSelectedHeader,
} from "../../redux/application/application.actions";
import { selectBodyshop } from "../../redux/user/user.selectors";
import { useTranslation } from "react-i18next";
import SocketIO from "socket.io-client";
import { auth } from "../../firebase/firebase.utils";
import moment from "moment";
import DmsCustomerSelector from "../../components/dms-customer-selector/dms-customer-selector.component";
const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop,
});
const mapDispatchToProps = (dispatch) => ({
setBreadcrumbs: (breadcrumbs) => dispatch(setBreadcrumbs(breadcrumbs)),
setSelectedHeader: (key) => dispatch(setSelectedHeader(key)),
});
export default connect(mapStateToProps, mapDispatchToProps)(DmsContainer);
export const socket = SocketIO(
process.env.NODE_ENV === "production"
? process.env.REACT_APP_AXIOS_BASE_API_URL
: window.location.origin,
{
path: "/ws",
auth: async (callback) => {
const token = auth.currentUser && (await auth.currentUser.getIdToken());
callback({ token });
},
}
);
export function DmsContainer({ bodyshop, setBreadcrumbs, setSelectedHeader }) {
const { t } = useTranslation();
const [logLevel, setLogLevel] = useState("DEBUG");
const [logs, setLogs] = useState([]);
useEffect(() => {
document.title = t("titles.dms");
setSelectedHeader("dms");
setBreadcrumbs([
{
link: "/manage/dms",
label: t("titles.bc.dms"),
},
]);
}, [t, setBreadcrumbs, setSelectedHeader]);
useEffect(() => {
socket.on("connected", () => {
console.log("Connected again.");
});
socket.on("reconnect", () => {
console.log("Connected again.");
setLogs((logs) => {
return [
...logs,
{
timestamp: new Date(),
level: "WARNING",
message: "Reconnected to CDK Export Service",
},
];
});
});
socket.on("log-event", (payload) => {
setLogs((logs) => {
return [...logs, payload];
});
});
socket.connect();
socket.emit("set-log-level", logLevel);
return () => {
socket.removeAllListeners();
socket.disconnect();
};
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
if (!bodyshop.cdk_dealerid) return <Result status="404" />;
const dmsType = determineDmsType(bodyshop);
return (
<div>
<Space>
<Select
placeholder="Log Level"
value={logLevel}
onChange={(value) => {
setLogLevel(value);
socket.emit("set-log-level", value);
}}
>
<Select.Option>TRACE</Select.Option>
<Select.Option>DEBUG</Select.Option>
<Select.Option>INFO</Select.Option>
<Select.Option>WARNING</Select.Option>
<Select.Option>ERROR</Select.Option>
</Select>
<Button
onClick={() => {
socket.emit(
`${dmsType}-export-job`,
"752a4f5f-22ab-414b-b182-98d4e62227ef"
);
}}
>
Export
</Button>
<Button
onClick={() => {
setLogs([]);
socket.disconnect();
socket.connect();
}}
>
Reconnect
</Button>
<Button onClick={() => setLogs([])}>Clear Logs</Button>
</Space>
<DmsCustomerSelector />
<Timeline pending={socket.connected && "Processing..."} reverse={true}>
{logs.map((log, idx) => (
<Timeline.Item key={idx} color={LogLevelHierarchy(log.level)}>
<Space wrap align="start" style={{}}>
<Tag color={LogLevelHierarchy(log.level)}>{log.level}</Tag>
<span>{moment(log.timestamp).format("MM/DD/YYYY HH:MM:ss")}</span>
<Divider type="vertical" />
<span style={{ whiteSpace: "pre-line" }}>{log.message}</span>
</Space>
</Timeline.Item>
))}
</Timeline>
</div>
);
}
function LogLevelHierarchy(level) {
switch (level) {
case "TRACE":
return "pink";
case "DEBUG":
return "green";
case "INFO":
return "blue";
case "WARNING":
return "orange";
case "ERROR":
return "red";
default:
return 0;
}
}
const determineDmsType = (bodyshop) => {
if (bodyshop.cdk_dealerid) return "cdk";
else {
return "pbs";
}
};

View File

@@ -3,6 +3,7 @@ import { connect } from "react-redux";
import { Redirect } from "react-router-dom";
import { createStructuredSelector } from "reselect";
import { selectCurrentUser } from "../../redux/user/user.selectors";
import LandingPageStatic from "../../landing/index";
const mapStateToProps = createStructuredSelector({
currentUser: selectCurrentUser,
@@ -13,5 +14,6 @@ export default connect(mapStateToProps, null)(LandingPage);
export function LandingPage({ currentUser }) {
if (currentUser.authorized) return <Redirect to={"/manage"} />;
return <Redirect to={"/signin"} />;
return <LandingPageStatic />;
//return <Redirect to={"/signin"} />;
}

View File

@@ -15,7 +15,6 @@ import FcmNotification from "../../components/fcm-notification/fcm-notification.
//import FooterComponent from "../../components/footer/footer.component";
//Component Imports
import HeaderContainer from "../../components/header/header.container";
import JiraSupportComponent from "../../components/jira-support-widget/jira-support-widget.component";
import LoadingSpinner from "../../components/loading-spinner/loading-spinner.component";
import PartnerPingComponent from "../../components/partner-ping/partner-ping.component";
import PrintCenterModalContainer from "../../components/print-center-modal/print-center-modal.container";
@@ -159,6 +158,7 @@ const EmailTest = lazy(() =>
import("../../components/email-test/email-test-component")
);
const Dashboard = lazy(() => import("../dashboard/dashboard.container"));
const Dms = lazy(() => import("../dms/dms.container"));
const { Content, Footer } = Layout;
@@ -367,6 +367,7 @@ export function Manage({ match, conflict, bodyshop }) {
<Route exact path={`${match.path}/help`} component={Help} />
<Route exact path={`${match.path}/emailtest`} component={EmailTest} />
<Route exact path={`${match.path}/dashboard`} component={Dashboard} />
<Route exact path={`${match.path}/dms`} component={Dms} />
</Suspense>
);
@@ -406,10 +407,9 @@ export function Manage({ match, conflict, bodyshop }) {
</div>
<div id="noticeable-widget" style={{ marginLeft: "1rem" }} />
</div>
<Link to="/about" target="_blank" style={{ color: "#ccc" }}>
<Link to="/disclaimer" target="_blank" style={{ color: "#ccc" }}>
Disclaimer & Notices
</Link>
<JiraSupportComponent />
</div>
</Footer>
</Content>

View File

@@ -7,6 +7,7 @@ import LoadingSpinner from "../../components/loading-spinner/loading-spinner.com
import { QUERY_BODYSHOP } from "../../graphql/bodyshop.queries";
import { setBodyshop } from "../../redux/user/user.actions";
import ManagePage from "./manage.page.component";
import "../../utils/RegisterSw";
const mapDispatchToProps = (dispatch) => ({
setBodyshop: (bs) => dispatch(setBodyshop(bs)),

View File

@@ -9,6 +9,7 @@ import {
} from "../../redux/application/application.actions";
import { selectBodyshop } from "../../redux/user/user.selectors";
import ProductionBoardComponent from "./production-board.component";
import FeatureWrapper from "../../components/feature-wrapper/feature-wrapper.component";
const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop,
@@ -38,9 +39,11 @@ export function ProductionBoardContainer({
}, [t, setBreadcrumbs, setSelectedHeader]);
return (
<RbacWrapper action="production:board">
<ProductionBoardComponent />
</RbacWrapper>
<FeatureWrapper featureName="production-board">
<RbacWrapper action="production:board">
<ProductionBoardComponent />
</RbacWrapper>
</FeatureWrapper>
);
}
export default connect(

View File

@@ -12,6 +12,7 @@ import { useSubscription } from "@apollo/client";
import { SUBSCRIPTION_SCOREBOARD } from "../../graphql/scoreboard.queries";
import moment from "moment";
import RbacWrapper from "../../components/rbac-wrapper/rbac-wrapper.component";
import FeatureWrapper from "../../components/feature-wrapper/feature-wrapper.component";
const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop,
@@ -44,9 +45,11 @@ export function ScoreboardContainer({ setBreadcrumbs, setSelectedHeader }) {
}, [t, setBreadcrumbs, setSelectedHeader]);
return (
<RbacWrapper action="scoreboard:view">
<ScoreboardDisplay scoreboardSubscription={scoreboardSubscription} />
</RbacWrapper>
<FeatureWrapper featureName="scoreboard">
<RbacWrapper action="scoreboard:view">
<ScoreboardDisplay scoreboardSubscription={scoreboardSubscription} />
</RbacWrapper>
</FeatureWrapper>
);
}
export default connect(

View File

@@ -10,6 +10,7 @@ import LoadingSpinner from "../../components/loading-spinner/loading-spinner.com
import TechHeader from "../../components/tech-header/tech-header.component";
import TechSider from "../../components/tech-sider/tech-sider.component";
import { selectTechnician } from "../../redux/tech/tech.selectors";
import FeatureWrapper from "../../components/feature-wrapper/feature-wrapper.component";
import "./tech.page.styles.scss";
const TimeTicketModalContainer = lazy(() =>
import("../../components/time-ticket-modal/time-ticket-modal.container")
@@ -51,52 +52,55 @@ export function TechPage({ technician, match }) {
}, [t]);
return (
<Layout className='tech-layout-container'>
<Layout className="tech-layout-container">
<TechSider />
<Layout>
{technician ? null : <Redirect to={`${match.path}/login`} />}
<TechHeader />
<Content className='tech-content-container'>
<Content className="tech-content-container">
<FcmNotification />
<ErrorBoundary>
<Suspense
fallback={
<LoadingSpinner message={t("general.labels.loadingapp")} />
}>
<TimeTicketModalContainer />
<PrintCenterModalContainer />
<Switch>
<Route
exact
path={`${match.path}/login`}
component={TechLogin}
/>
<Route
exact
path={`${match.path}/joblookup`}
component={TechLookup}
/>
<Route
exact
path={`${match.path}/list`}
component={ProductionListPage}
/>
<Route
exact
path={`${match.path}/jobclock`}
component={TechJobClock}
/>
<Route
exact
path={`${match.path}/shiftclock`}
component={TechShiftClock}
/>
<Route
exact
path={`${match.path}/board`}
component={ProductionBoardPage}
/>
</Switch>
}
>
<FeatureWrapper featureName="tech-console">
<TimeTicketModalContainer />
<PrintCenterModalContainer />
<Switch>
<Route
exact
path={`${match.path}/login`}
component={TechLogin}
/>
<Route
exact
path={`${match.path}/joblookup`}
component={TechLookup}
/>
<Route
exact
path={`${match.path}/list`}
component={ProductionListPage}
/>
<Route
exact
path={`${match.path}/jobclock`}
component={TechJobClock}
/>
<Route
exact
path={`${match.path}/shiftclock`}
component={TechShiftClock}
/>
<Route
exact
path={`${match.path}/board`}
component={ProductionBoardPage}
/>
</Switch>
</FeatureWrapper>
</Suspense>
</ErrorBoundary>

View File

@@ -7,12 +7,19 @@ import { setBodyshop } from "../../redux/user/user.actions";
import TechPage from "./tech.page.component";
import LoadingSpinner from "../../components/loading-spinner/loading-spinner.component";
import { useTranslation } from "react-i18next";
import { selectBodyshop } from "../../redux/user/user.selectors";
import { createStructuredSelector } from "reselect";
import "../../utils/RegisterSw";
const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop,
});
const mapDispatchToProps = (dispatch) => ({
setBodyshop: (bs) => dispatch(setBodyshop(bs)),
});
export function TechPageContainer({ setBodyshop, match }) {
export function TechPageContainer({ bodyshop, setBodyshop, match }) {
const { loading, error, data } = useQuery(QUERY_BODYSHOP, {
fetchPolicy: "network-only",
});
@@ -21,10 +28,10 @@ export function TechPageContainer({ setBodyshop, match }) {
if (data) setBodyshop(data.bodyshops[0]);
}, [data, setBodyshop]);
if (loading)
if (loading || !bodyshop)
return <LoadingSpinner message={t("general.labels.loadingshop")} />;
if (error) return <AlertComponent message={error.message} type="error" />;
return <TechPage match={match} />;
}
export default connect(null, mapDispatchToProps)(TechPageContainer);
export default connect(mapStateToProps, mapDispatchToProps)(TechPageContainer);

View File

@@ -17,7 +17,7 @@ export function* onCalculateScheduleLoad() {
}
export function* calculateScheduleLoad({ payload: end }) {
//REMINDER: Moment.js is not immutable. Today WILL change when adjusted.
const today = moment(new Date()).startOf("day");
const today = moment().startOf("day");
const state = yield select();
const buckets = state.user.bodyshop.ssbuckets;
@@ -42,6 +42,7 @@ export function* calculateScheduleLoad({ payload: end }) {
});
prodJobs.forEach((item) => {
//Add all of the jobs currently in production to the buckets so that we have a starting point.
const bucketId = CheckJobBucket(buckets, item);
if (bucketId) {
load.productionTotal[bucketId].count =

View File

@@ -0,0 +1,6 @@
import DmsActions from "./dms.types";
export const endLoading = (options) => ({
// type: DmsActions.END_LOADING,
payload: options,
});

View File

@@ -0,0 +1,20 @@
import DmsActionTypes from "./dms.types";
const INITIAL_STATE = {
eventLog: [],
};
const dmsReducer = (state = INITIAL_STATE, action) => {
switch (action.type) {
// case ApplicationActionTypes.SET_SELECTED_HEADER:
// return {
// ...state,
// selectedHeader: action.payload,
// };
default:
return state;
}
};
export default dmsReducer;

View File

@@ -0,0 +1,14 @@
import { all, call } from "redux-saga/effects";
//import DmsActionTypes from "./dms.types";
export function* onCalculateScheduleLoad() {
// yield takeLatest(
// DmsActionTypes.CALCULATE_SCHEDULE_LOAD,
// calculateScheduleLoad
// );
}
export function* calculateScheduleLoad({ payload: end }) {}
export function* dmsSagas() {
yield all([call()]);
}

View File

@@ -0,0 +1,8 @@
import { createSelector } from "reselect";
const selectDms = (state) => state.dms;
export const selectEventLog = createSelector(
[selectDms],
(dms) => dms.eventLog
);

View File

@@ -0,0 +1,4 @@
const DmsActionTypes = {
ADD_EVENT: "ADD_EVENT",
};
export default DmsActionTypes;

View File

@@ -166,11 +166,14 @@ export function* signInSuccessSaga({ payload }) {
LogRocket.identify(payload.email);
try {
// window.$crisp.push(["set", "user:email", [payload.email]]);
console.log("$crisp set nickname", [payload.displayName || payload.email]);
window.$crisp.push([
"set",
"user:nickname",
[payload.displayName || payload.email],
]);
console.log("Setting $crisp segments", ["user"]);
window.$crisp.push(["set", "session:segments", [["user"]]]);
} catch (error) {
console.log("Error updating Crisp settings.", error);
}

View File

@@ -24,6 +24,7 @@
"cancel": "Cancel",
"intake": "Intake",
"new": "New Appointment",
"preview": "Preview",
"reschedule": "Reschedule",
"sendreminder": "Send Reminder",
"viewjob": "View Job"
@@ -165,7 +166,8 @@
"successes": {
"created": "Invoice added successfully.",
"deleted": "Bill deleted successfully.",
"exported": "Bill(s) exported successfully."
"exported": "Bill(s) exported successfully.",
"reexport": "Bill marked for re-export."
},
"validation": {
"manualinhouse": "Manual posting to the in house vendor is restricted. ",
@@ -898,6 +900,7 @@
"newversionmessage": "Click refresh below to update to the latest available version of ImEX Online. Please make sure all other tabs and windows are closed.",
"newversiontitle": "New version of ImEX Online Available",
"noacctfilepath": "There is no accounting file path set. You will not be able to export any items.",
"nofeatureaccess": "You do not have access to this feature of ImEX Online. Please contact support to request a license for this feature.",
"noshop": "You do not have access to any shops. Please reach out to your shop manager or technical support. ",
"notfoundsub": "Please make sure that you have access to the data or that the link is correct.",
"notfoundtitle": "We couldn't find what you're looking for...",
@@ -1023,6 +1026,7 @@
"convert": "Convert",
"deliver": "Deliver",
"export": "Export",
"exportcustdata": "Export Customer Data",
"exportselected": "Export Selected",
"filterpartsonly": "Filter Parts Only",
"generatecsi": "Generate CSI & Copy Link",
@@ -1419,6 +1423,56 @@
"voided": "Job voided successfully."
}
},
"landing": {
"bigfeature": {
"subtitle": "ImEX Online is built using world class technology by experts in the collision repair industry. This translates to software that is tailor made for the unique challenges faced by repair facilities with no compromises. ",
"title": "Bringing the latest technology to the automotive repair industry. "
},
"footer": {
"company": {
"about": "About Us",
"contact": "Contact",
"disclaimers": "Disclaimers",
"name": "Company",
"privacypolicy": "Privacy Policy"
},
"io": {
"help": "Help",
"name": "ImEX Online",
"status": "System Status"
},
"slogan": "The future of shop management systems. "
},
"hero": {
"button": "Learn More",
"title": "Bringing the future to the collision repair process."
},
"labels": {
"features": "Features",
"managemyshop": "Manage my Shop",
"pricing": "Pricing"
},
"pricing": {
"basic": {
"name": "Basic",
"sub": "Best suited for shops looking to increase their volume."
},
"essentials": {
"name": "Essentials",
"sub": "Best suited for small and low volume shops."
},
"pricingtitle": "Features",
"pro": {
"name": "Pro",
"sub": "Empower your shop with the tools to operate at peak capacity."
},
"title": "Features",
"unlimited": {
"name": "Unlimited",
"sub": "Everything you need and more for the high volume shop."
}
}
},
"menus": {
"currentuser": {
"languageselector": "Language",
@@ -1733,6 +1787,7 @@
},
"courtesycarcontract": {
"courtesy_car_contract": "Courtesy Car Contract",
"courtesy_car_impound": "Impound Charges",
"courtesy_car_terms": "Courtesy Car Terms"
},
"errors": {
@@ -1931,6 +1986,11 @@
"parts_backorder": "Backordered Parts",
"payments_by_date": "Payments by Date",
"payments_by_date_type": "Payments by Date and Type",
"production_by_csr": "Production by CSR",
"production_by_last_name": "Production by Last Name",
"production_by_repair_status": "Production by Status",
"production_by_ro": "Production by RO",
"production_by_target_date": "Production by Target Date",
"purchases_by_cost_center_detail": "Purchases by Cost Center (Detail)",
"purchases_by_cost_center_summary": "Purchases by Cost Center (Summary)",
"purchases_by_date_range_detail": "Purchases by Date - Detail",

View File

@@ -24,6 +24,7 @@
"cancel": "Cancelar",
"intake": "Consumo",
"new": "Nueva cita",
"preview": "",
"reschedule": "Reprogramar",
"sendreminder": "",
"viewjob": "Ver trabajo"
@@ -165,7 +166,8 @@
"successes": {
"created": "",
"deleted": "",
"exported": ""
"exported": "",
"reexport": ""
},
"validation": {
"manualinhouse": "",
@@ -898,6 +900,7 @@
"newversionmessage": "",
"newversiontitle": "",
"noacctfilepath": "",
"nofeatureaccess": "",
"noshop": "",
"notfoundsub": "",
"notfoundtitle": "",
@@ -1023,6 +1026,7 @@
"convert": "Convertir",
"deliver": "",
"export": "",
"exportcustdata": "",
"exportselected": "",
"filterpartsonly": "",
"generatecsi": "",
@@ -1419,6 +1423,56 @@
"voided": ""
}
},
"landing": {
"bigfeature": {
"subtitle": "",
"title": ""
},
"footer": {
"company": {
"about": "",
"contact": "",
"disclaimers": "",
"name": "",
"privacypolicy": ""
},
"io": {
"help": "",
"name": "",
"status": ""
},
"slogan": ""
},
"hero": {
"button": "",
"title": ""
},
"labels": {
"features": "",
"managemyshop": "",
"pricing": ""
},
"pricing": {
"basic": {
"name": "",
"sub": ""
},
"essentials": {
"name": "",
"sub": ""
},
"pricingtitle": "",
"pro": {
"name": "",
"sub": ""
},
"title": "",
"unlimited": {
"name": "",
"sub": ""
}
}
},
"menus": {
"currentuser": {
"languageselector": "idioma",
@@ -1733,6 +1787,7 @@
},
"courtesycarcontract": {
"courtesy_car_contract": "",
"courtesy_car_impound": "",
"courtesy_car_terms": ""
},
"errors": {
@@ -1931,6 +1986,11 @@
"parts_backorder": "",
"payments_by_date": "",
"payments_by_date_type": "",
"production_by_csr": "",
"production_by_last_name": "",
"production_by_repair_status": "",
"production_by_ro": "",
"production_by_target_date": "",
"purchases_by_cost_center_detail": "",
"purchases_by_cost_center_summary": "",
"purchases_by_date_range_detail": "",

View File

@@ -24,6 +24,7 @@
"cancel": "annuler",
"intake": "Admission",
"new": "Nouveau rendez-vous",
"preview": "",
"reschedule": "Replanifier",
"sendreminder": "",
"viewjob": "Voir le travail"
@@ -165,7 +166,8 @@
"successes": {
"created": "",
"deleted": "",
"exported": ""
"exported": "",
"reexport": ""
},
"validation": {
"manualinhouse": "",
@@ -898,6 +900,7 @@
"newversionmessage": "",
"newversiontitle": "",
"noacctfilepath": "",
"nofeatureaccess": "",
"noshop": "",
"notfoundsub": "",
"notfoundtitle": "",
@@ -1023,6 +1026,7 @@
"convert": "Convertir",
"deliver": "",
"export": "",
"exportcustdata": "",
"exportselected": "",
"filterpartsonly": "",
"generatecsi": "",
@@ -1419,6 +1423,56 @@
"voided": ""
}
},
"landing": {
"bigfeature": {
"subtitle": "",
"title": ""
},
"footer": {
"company": {
"about": "",
"contact": "",
"disclaimers": "",
"name": "",
"privacypolicy": ""
},
"io": {
"help": "",
"name": "",
"status": ""
},
"slogan": ""
},
"hero": {
"button": "",
"title": ""
},
"labels": {
"features": "",
"managemyshop": "",
"pricing": ""
},
"pricing": {
"basic": {
"name": "",
"sub": ""
},
"essentials": {
"name": "",
"sub": ""
},
"pricingtitle": "",
"pro": {
"name": "",
"sub": ""
},
"title": "",
"unlimited": {
"name": "",
"sub": ""
}
}
},
"menus": {
"currentuser": {
"languageselector": "La langue",
@@ -1733,6 +1787,7 @@
},
"courtesycarcontract": {
"courtesy_car_contract": "",
"courtesy_car_impound": "",
"courtesy_car_terms": ""
},
"errors": {
@@ -1931,6 +1986,11 @@
"parts_backorder": "",
"payments_by_date": "",
"payments_by_date_type": "",
"production_by_csr": "",
"production_by_last_name": "",
"production_by_repair_status": "",
"production_by_ro": "",
"production_by_target_date": "",
"purchases_by_cost_center_detail": "",
"purchases_by_cost_center_summary": "",
"purchases_by_date_range_detail": "",

View File

@@ -1,9 +1,9 @@
import i18n from "i18next";
import { initReactI18next } from "react-i18next";
import LanguageDetector from "i18next-browser-languagedetector";
import { initReactI18next } from "react-i18next";
import en_Translation from "./en_us/common.json";
import fr_Translation from "./fr/common.json";
import es_Translation from "./es/common.json";
import fr_Translation from "./fr/common.json";
// the translations
// (tip move them in a JSON file and import them)

View File

@@ -0,0 +1,46 @@
import { AlertOutlined } from "@ant-design/icons";
import { Button, notification, Space } from "antd";
import i18n from "i18next";
import React from "react";
import * as serviceWorkerRegistration from "../serviceWorkerRegistration";
const onServiceWorkerUpdate = (registration) => {
console.log("onServiceWorkerUpdate", registration);
const btn = (
<Space flex>
<Button
onClick={async () => {
window.open("https://imex-online.noticeable.news/", "_blank");
}}
>
{i18n.t("general.actions.viewreleasenotes")}
</Button>
<Button
type="primary"
onClick={async () => {
if (registration && registration.waiting) {
await registration.unregister();
// Makes Workbox call skipWaiting()
registration.waiting.postMessage({ type: "SKIP_WAITING" });
// Once the service worker is unregistered, we can reload the page to let
// the browser download a fresh copy of our app (invalidating the cache)
window.location.reload();
}
}}
>
{i18n.t("general.actions.refresh")}
</Button>
</Space>
);
notification.open({
icon: <AlertOutlined />,
message: i18n.t("general.messages.newversiontitle"),
description: i18n.t("general.messages.newversionmessage"),
duration: 0,
btn,
key: "updateavailable",
});
};
serviceWorkerRegistration.register({ onUpdate: onServiceWorkerUpdate });

View File

@@ -326,8 +326,16 @@ export const TemplateList = (type, context) => {
key: "parts_label_single",
subject: i18n.t("printcenter.jobs.parts_label_single"),
disabled: false,
group: "post",
group: "ro",
},
// parts_label_multi: {
// title: i18n.t("printcenter.jobs.parts_label_multi"),
// description: "Thank You Letter by RO",
// key: "parts_label_multi",
// subject: i18n.t("printcenter.jobs.parts_label_multi"),
// disabled: false,
// group: "ro",
// },
}
: {}),
...(!type || type === "job_special"
@@ -1085,6 +1093,17 @@ export const TemplateList = (type, context) => {
key: "courtesy_car_terms",
disabled: false,
},
courtesy_car_impound: {
title: i18n.t(
"printcenter.courtesycarcontract.courtesy_car_impound"
),
description: "Est Detail",
subject: i18n.t(
"printcenter.courtesycarcontract.courtesy_car_impound"
),
key: "courtesy_car_impound",
disabled: false,
},
}
: {}),
...(!type || type === "bill"
@@ -1129,6 +1148,53 @@ export const TemplateList = (type, context) => {
},
}
: {}),
...(!type || type === "production"
? {
production_by_last_name: {
title: i18n.t("reportcenter.templates.production_by_last_name"),
description: "",
subject: i18n.t("reportcenter.templates.production_by_last_name"),
key: "production_by_last_name",
//idtype: "vendor",
disabled: false,
},
production_by_repair_status: {
title: i18n.t("reportcenter.templates.production_by_repair_status"),
description: "",
subject: i18n.t(
"reportcenter.templates.production_by_repair_status"
),
key: "production_by_repair_status",
//idtype: "vendor",
disabled: false,
},
production_by_target_date: {
title: i18n.t("reportcenter.templates.production_by_target_date"),
description: "",
subject: i18n.t("reportcenter.templates.production_by_target_date"),
key: "production_by_target_date",
//idtype: "vendor",
disabled: false,
},
production_by_ro: {
title: i18n.t("reportcenter.templates.production_by_ro"),
description: "",
subject: i18n.t("reportcenter.templates.production_by_ro"),
key: "production_by_ro",
//idtype: "vendor",
disabled: false,
},
production_by_csr: {
title: i18n.t("reportcenter.templates.production_by_csr"),
description: "",
subject: i18n.t("reportcenter.templates.production_by_csr"),
key: "production_by_csr",
//idtype: "vendor",
disabled: false,
},
}
: {}),
...(!type || type === "special"
? {
ca_bc_etf_table: {

View File

@@ -0,0 +1,5 @@
import React from "react";
export function PartsLabelMulti() {
return <div></div>;
}

View File

@@ -2271,6 +2271,11 @@
dependencies:
"@babel/types" "^7.3.0"
"@types/component-emitter@^1.2.10":
version "1.2.10"
resolved "https://registry.yarnpkg.com/@types/component-emitter/-/component-emitter-1.2.10.tgz#ef5b1589b9f16544642e473db5ea5639107ef3ea"
integrity sha512-bsjleuRKWmGqajMerkzox19aGbscQX5rmmvvXl3wlIp5gMG1HgkiwPxsN5p070fBDKTNSPgojVbuY1+HWMbFhg==
"@types/d3-path@^1":
version "1.0.9"
resolved "https://registry.npmjs.org/@types/d3-path/-/d3-path-1.0.9.tgz"
@@ -3467,7 +3472,7 @@ babel-preset-react-app@^10.0.0:
babel-plugin-macros "2.8.0"
babel-plugin-transform-react-remove-prop-types "0.4.24"
babel-runtime@^6.26.0:
babel-runtime@6.x, babel-runtime@^6.26.0:
version "6.26.0"
resolved "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz"
integrity sha1-llxwWGaOgrVde/4E/yM3vItWR/4=
@@ -3480,7 +3485,7 @@ babylon@^6.18.0:
resolved "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz"
integrity sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==
backo2@^1.0.2:
backo2@^1.0.2, backo2@~1.0.2:
version "1.0.2"
resolved "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz"
integrity sha1-MasayLEpNjRj41s+u2n038+6eUc=
@@ -3490,6 +3495,11 @@ balanced-match@^1.0.0:
resolved "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz"
integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==
base64-arraybuffer@0.1.4:
version "0.1.4"
resolved "https://registry.yarnpkg.com/base64-arraybuffer/-/base64-arraybuffer-0.1.4.tgz#9818c79e059b1355f97e0428a017c838e90ba812"
integrity sha1-mBjHngWbE1X5fgQooBfIOOkLqBI=
base64-js@^1.0.2:
version "1.5.1"
resolved "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz"
@@ -4194,7 +4204,7 @@ commondir@^1.0.1:
resolved "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz"
integrity sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=
component-emitter@^1.2.1:
component-emitter@^1.2.1, component-emitter@~1.3.0:
version "1.3.0"
resolved "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz"
integrity sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==
@@ -4838,7 +4848,7 @@ debug@2.6.9, debug@^2.2.0, debug@^2.3.3, debug@^2.6.0, debug@^2.6.9:
dependencies:
ms "2.0.0"
debug@4, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1:
debug@4, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@~4.3.1:
version "4.3.1"
resolved "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz"
integrity sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==
@@ -4882,6 +4892,13 @@ deep-diff@^0.3.5:
resolved "https://registry.npmjs.org/deep-diff/-/deep-diff-0.3.8.tgz"
integrity sha1-wB3mPvsO7JeYgB1Ax+Da4ltYLIQ=
deep-eql@~3.0.1:
version "3.0.1"
resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-3.0.1.tgz#dfc9404400ad1c8fe023e7da1df1c147c4b444df"
integrity sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw==
dependencies:
type-detect "^4.0.0"
deep-equal@^1.0.1:
version "1.1.1"
resolved "https://registry.npmjs.org/deep-equal/-/deep-equal-1.1.1.tgz"
@@ -5272,6 +5289,28 @@ end-of-stream@^1.0.0, end-of-stream@^1.1.0:
dependencies:
once "^1.4.0"
engine.io-client@~5.1.1:
version "5.1.1"
resolved "https://registry.yarnpkg.com/engine.io-client/-/engine.io-client-5.1.1.tgz#f5c3aaaef1bdc9443aac6ffde48b3b2fb2dc56fc"
integrity sha512-jPFpw2HLL0lhZ2KY0BpZhIJdleQcUO9W1xkIpo0h3d6s+5D6+EV/xgQw9qWOmymszv2WXef/6KUUehyxEKomlQ==
dependencies:
base64-arraybuffer "0.1.4"
component-emitter "~1.3.0"
debug "~4.3.1"
engine.io-parser "~4.0.1"
has-cors "1.1.0"
parseqs "0.0.6"
parseuri "0.0.6"
ws "~7.4.2"
yeast "0.1.2"
engine.io-parser@~4.0.1:
version "4.0.2"
resolved "https://registry.yarnpkg.com/engine.io-parser/-/engine.io-parser-4.0.2.tgz#e41d0b3fb66f7bf4a3671d2038a154024edb501e"
integrity sha512-sHfEQv6nmtJrq6TKuIz5kyEKH/qSdK56H/A+7DnAuUPWosnIZAS2NHNcPLmyjtY3cGS/MqJdZbUjW97JU72iYg==
dependencies:
base64-arraybuffer "0.1.4"
enhanced-resolve@^4.3.0:
version "4.5.0"
resolved "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-4.5.0.tgz"
@@ -5281,6 +5320,18 @@ enhanced-resolve@^4.3.0:
memory-fs "^0.5.0"
tapable "^1.0.0"
enquire-js@^0.2.1:
version "0.2.1"
resolved "https://registry.yarnpkg.com/enquire-js/-/enquire-js-0.2.1.tgz#f2478cf5808d42f54e8231f20fa133493e7f0fcb"
integrity sha512-4vbcWD0ncK6VQ5M5giOImQb2hFPrKDZH5U+uRX9S6e9vfC6Q5PX6A38PVS6RMnCdr/luDTtJjjLuJinH/+a+Lw==
dependencies:
enquire.js "^2.1.6"
enquire.js@^2.1.6:
version "2.1.6"
resolved "https://registry.yarnpkg.com/enquire.js/-/enquire.js-2.1.6.tgz#3e8780c9b8b835084c3f60e166dbc3c2a3c89814"
integrity sha1-PoeAybi4NQhMP2DhZtvDwqPImBQ=
enquirer@^2.3.5:
version "2.3.6"
resolved "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz"
@@ -6394,6 +6445,11 @@ has-bigints@^1.0.1:
resolved "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.1.tgz"
integrity sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA==
has-cors@1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/has-cors/-/has-cors-1.1.0.tgz#5e474793f7ea9843d1bb99c23eef49ff126fff39"
integrity sha1-XkdHk/fqmEPRu5nCPu9J/xJv/zk=
has-flag@^3.0.0:
version "3.0.0"
resolved "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz"
@@ -9172,6 +9228,16 @@ parse5@6.0.1:
resolved "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz"
integrity sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==
parseqs@0.0.6:
version "0.0.6"
resolved "https://registry.yarnpkg.com/parseqs/-/parseqs-0.0.6.tgz#8e4bb5a19d1cdc844a08ac974d34e273afa670d5"
integrity sha512-jeAGzMDbfSHHA091hr0r31eYfTig+29g3GKKE/PPbEQ65X0lmMwlEoqmhzu0iztID5uJpZsFlUPDP8ThPL7M8w==
parseuri@0.0.6:
version "0.0.6"
resolved "https://registry.yarnpkg.com/parseuri/-/parseuri-0.0.6.tgz#e1496e829e3ac2ff47f39a4dd044b32823c4a25a"
integrity sha512-AUjen8sAkGgao7UyCX6Ahv0gIK2fABKmYjvP4xmy5JaKvcbTRueIqIPHLAfq30xJddqSE033IOMUSOMCcK3Sow==
parseurl@~1.3.2, parseurl@~1.3.3:
version "1.3.3"
resolved "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz"
@@ -10132,7 +10198,7 @@ prompts@2.4.0, prompts@^2.0.1:
kleur "^3.0.3"
sisteransi "^1.0.5"
prop-types@15.x, prop-types@^15.0.0, prop-types@^15.5.10, prop-types@^15.5.8, prop-types@^15.6.0, prop-types@^15.6.2, prop-types@^15.7.2:
prop-types@15.x, prop-types@^15.0.0, prop-types@^15.5.10, prop-types@^15.5.8, prop-types@^15.6.0, prop-types@^15.6.1, prop-types@^15.6.2, prop-types@^15.7.2:
version "15.7.2"
resolved "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz"
integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==
@@ -10288,7 +10354,7 @@ raf-schd@^4.0.2:
resolved "https://registry.npmjs.org/raf-schd/-/raf-schd-4.0.3.tgz"
integrity sha512-tQkJl2GRWh83ui2DiPTJz9wEiMN20syf+5oKfB03yYP7ioZcJwsIK8FjrtLwH1m7C7e+Tt2yYBlrOpdT+dyeIQ==
raf@^3.4.0, raf@^3.4.1:
raf@3.x, raf@^3.4.0, raf@^3.4.1, raf@~3.4.0:
version "3.4.1"
resolved "https://registry.npmjs.org/raf/-/raf-3.4.1.tgz"
integrity sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA==
@@ -10505,6 +10571,16 @@ rc-progress@~3.1.0:
"@babel/runtime" "^7.10.1"
classnames "^2.2.6"
rc-queue-anim@^1.8.5:
version "1.8.5"
resolved "https://registry.yarnpkg.com/rc-queue-anim/-/rc-queue-anim-1.8.5.tgz#01ef3872bdfa0b70bb915ef9a637fc404244a589"
integrity sha512-vTbZXBu7L3NcXUPjkFN7R80BE+1VYL1QBI10EioYYqZMk6A0iVbjoVAgfoK/Z4gIIxp399gJ8LqbMnQA1AhcXA==
dependencies:
babel-runtime "6.x"
prop-types "^15.6.0"
rc-tween-one "^2.5.0"
react-lifecycles-compat "^3.0.4"
rc-rate@~2.9.0:
version "2.9.1"
resolved "https://registry.npmjs.org/rc-rate/-/rc-rate-2.9.1.tgz"
@@ -10524,6 +10600,18 @@ rc-resize-observer@^1.0.0:
rc-util "^5.0.0"
resize-observer-polyfill "^1.5.1"
rc-scroll-anim@^2.7.6:
version "2.7.6"
resolved "https://registry.yarnpkg.com/rc-scroll-anim/-/rc-scroll-anim-2.7.6.tgz#f7e6622f2930ca3e1e258f7275bc2e1c26ce791c"
integrity sha512-VwXJYXjZy9TtH1wcQIG7/yjt/Ay3VEjQl/TITaWzK9O7ujjOXRVOYY/tqKshmBMgaJ2oGeFQNmCN8zTwXguq0g==
dependencies:
babel-runtime "6.x"
prop-types "^15.6.0"
raf "3.x"
rc-tween-one "^2.4.0"
react-lifecycles-compat "^3.0.4"
tween-functions "1.x"
rc-select@^12.0.0, rc-select@~12.1.6:
version "12.1.10"
resolved "https://registry.npmjs.org/rc-select/-/rc-select-12.1.10.tgz"
@@ -10640,6 +10728,30 @@ rc-trigger@^5.0.0, rc-trigger@^5.0.4, rc-trigger@^5.1.2, rc-trigger@^5.2.1:
rc-motion "^2.0.0"
rc-util "^5.5.0"
rc-tween-one@^1.2.5:
version "1.8.1"
resolved "https://registry.yarnpkg.com/rc-tween-one/-/rc-tween-one-1.8.1.tgz#5b3b464b9bf2c369efc16c816cccf57bc16ae253"
integrity sha512-Avg8EXHdt6ABV9WnmTmh6zEaAzUvl4bFZKbP3y6BE8UGBGp1qUhlIgCB83gL+5eA0VECdM/b9PsEBRrcxzSpGw==
dependencies:
babel-runtime "6.x"
deep-eql "~3.0.1"
prop-types "^15.6.1"
raf "~3.4.0"
style-utils "~0.1.13"
tween-functions "~1.2.0"
rc-tween-one@^2.4.0, rc-tween-one@^2.5.0:
version "2.7.3"
resolved "https://registry.yarnpkg.com/rc-tween-one/-/rc-tween-one-2.7.3.tgz#c9d3c44743e25c654d65c22ec3934afd79923fae"
integrity sha512-n4OPRLO6VMZHj61unq5KKxHMMfBz52bxob94fN3U5M9GqFg3H+T3TXnpHPnAK+cq/xBGo70ik2vB4Fpjo/txcA==
dependencies:
babel-runtime "6.x"
prop-types "^15.6.1"
raf "~3.4.0"
react-lifecycles-compat "^3.0.4"
style-utils "~0.2.0"
tween-functions "~1.2.0"
rc-upload@~4.3.0:
version "4.3.1"
resolved "https://registry.npmjs.org/rc-upload/-/rc-upload-4.3.1.tgz"
@@ -11017,6 +11129,14 @@ react-smooth@^2.0.0:
raf "^3.4.0"
react-transition-group "2.9.0"
react-sublime-video@^0.2.5:
version "0.2.5"
resolved "https://registry.yarnpkg.com/react-sublime-video/-/react-sublime-video-0.2.5.tgz#c967b8e9a374b36d6a5d1b63b93fa6ec02e54842"
integrity sha1-yWe46aN0s21qXRtjuT+m7ALlSEI=
dependencies:
prop-types "^15.5.10"
rc-tween-one "^1.2.5"
react-transition-group@2, react-transition-group@2.9.0:
version "2.9.0"
resolved "https://registry.npmjs.org/react-transition-group/-/react-transition-group-2.9.0.tgz"
@@ -11940,6 +12060,28 @@ snapdragon@^0.8.1:
source-map-resolve "^0.5.0"
use "^3.1.0"
socket.io-client@^4.1.2:
version "4.1.2"
resolved "https://registry.yarnpkg.com/socket.io-client/-/socket.io-client-4.1.2.tgz#95ad7113318ea01fba0860237b96d71e1b1fd2eb"
integrity sha512-RDpWJP4DQT1XeexmeDyDkm0vrFc0+bUsHDKiVGaNISJvJonhQQOMqV9Vwfg0ZpPJ27LCdan7iqTI92FRSOkFWQ==
dependencies:
"@types/component-emitter" "^1.2.10"
backo2 "~1.0.2"
component-emitter "~1.3.0"
debug "~4.3.1"
engine.io-client "~5.1.1"
parseuri "0.0.6"
socket.io-parser "~4.0.4"
socket.io-parser@~4.0.4:
version "4.0.4"
resolved "https://registry.yarnpkg.com/socket.io-parser/-/socket.io-parser-4.0.4.tgz#9ea21b0d61508d18196ef04a2c6b9ab630f4c2b0"
integrity sha512-t+b0SS+IxG7Rxzda2EVvyBZbvFPBCjJoyHuE0P//7OAsN23GItzDRdWa6ALxZI/8R5ygK7jAR6t028/z+7295g==
dependencies:
"@types/component-emitter" "^1.2.10"
component-emitter "~1.3.0"
debug "~4.3.1"
sockjs-client@^1.5.0:
version "1.5.1"
resolved "https://registry.npmjs.org/sockjs-client/-/sockjs-client-1.5.1.tgz"
@@ -12372,6 +12514,16 @@ style-loader@1.3.0:
loader-utils "^2.0.0"
schema-utils "^2.7.0"
style-utils@~0.1.13:
version "0.1.24"
resolved "https://registry.yarnpkg.com/style-utils/-/style-utils-0.1.24.tgz#fc0675d79a0b201bf86fc5d5a1dd202f838de544"
integrity sha512-MVZSKubpU/vIfpmOsi8/0ckWxb0WmGBmyNoEDGWZM9cM8n8sCL6DJftl3lEf8Uy5zKQ9+O1XdJxscWTDosCQpQ==
style-utils@~0.2.0:
version "0.2.1"
resolved "https://registry.yarnpkg.com/style-utils/-/style-utils-0.2.1.tgz#c78fe6696214f4ab12701959f09553e9d81dd45b"
integrity sha512-eKRIfWnUSdBqe2ko+qisUwBSlfWpHru89geRqzmScpDhkPW1ksmE04d//nDcXeF+TVK5cnBG90mMmHgxyxXleQ==
styled-components@^5.3.0:
version "5.3.0"
resolved "https://registry.npmjs.org/styled-components/-/styled-components-5.3.0.tgz"
@@ -12779,6 +12931,11 @@ tty-browserify@0.0.0:
resolved "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz"
integrity sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY=
tween-functions@1.x, tween-functions@~1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/tween-functions/-/tween-functions-1.2.0.tgz#1ae3a50e7c60bb3def774eac707acbca73bbc3ff"
integrity sha1-GuOlDnxguz3vd06scHrLynO7w/8=
type-check@^0.4.0, type-check@~0.4.0:
version "0.4.0"
resolved "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz"
@@ -12793,7 +12950,7 @@ type-check@~0.3.2:
dependencies:
prelude-ls "~1.1.2"
type-detect@4.0.8:
type-detect@4.0.8, type-detect@^4.0.0:
version "4.0.8"
resolved "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz"
integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==
@@ -13702,7 +13859,7 @@ write-file-atomic@^3.0.0:
signal-exit "^3.0.2"
typedarray-to-buffer "^3.1.5"
"ws@^5.2.0 || ^6.0.0 || ^7.0.0", ws@^7.4.5:
"ws@^5.2.0 || ^6.0.0 || ^7.0.0", ws@^7.4.5, ws@~7.4.2:
version "7.4.6"
resolved "https://registry.npmjs.org/ws/-/ws-7.4.6.tgz"
integrity sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A==
@@ -13826,6 +13983,11 @@ yargs@^16.2.0:
y18n "^5.0.5"
yargs-parser "^20.2.2"
yeast@0.1.2:
version "0.1.2"
resolved "https://registry.yarnpkg.com/yeast/-/yeast-0.1.2.tgz#008e06d8094320c372dbc2f8ed76a0ca6c8ac419"
integrity sha1-AI4G2AlDIMNy28L47XagymyKxBk=
yocto-queue@^0.1.0:
version "0.1.0"
resolved "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz"

View File

@@ -0,0 +1,5 @@
- args:
cascade: false
read_only: false
sql: ALTER TABLE "public"."bodyshops" DROP COLUMN "cdk_dealerid";
type: run_sql

View File

@@ -0,0 +1,5 @@
- args:
cascade: false
read_only: false
sql: ALTER TABLE "public"."bodyshops" ADD COLUMN "cdk_dealerid" text NULL;
type: run_sql

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