Compare commits
601 Commits
feature/IO
...
feature/IO
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6cac0f9594 | ||
|
|
9b67148522 | ||
|
|
6b501e4619 | ||
|
|
42f1d6fa13 | ||
|
|
3f247a9227 | ||
|
|
63b914731b | ||
|
|
23f8f69bbe | ||
|
|
fc3ea2bdf8 | ||
|
|
96e970faf7 | ||
|
|
c133195607 | ||
|
|
d75ea2b1a6 | ||
|
|
ec0fd840e4 | ||
|
|
971a81fc27 | ||
|
|
19050d31f7 | ||
|
|
e605433379 | ||
|
|
b9ebb70b7a | ||
|
|
79ed6f2388 | ||
|
|
785449a986 | ||
|
|
0b7d469e0e | ||
|
|
a57156756e | ||
|
|
c4c30d98d4 | ||
|
|
d4e8803b13 | ||
|
|
1f2786ddec | ||
|
|
e90cda07e4 | ||
|
|
9793daa04c | ||
|
|
117ced8fe7 | ||
|
|
e7909205d1 | ||
|
|
18028a70ab | ||
|
|
eeb8d8d26f | ||
|
|
23659fc412 | ||
|
|
ba65057782 | ||
|
|
60a859cac8 | ||
|
|
0cfe26093c | ||
|
|
d085a9c7c9 | ||
|
|
ec518a0593 | ||
|
|
1cd64ab6f1 | ||
|
|
26836f662a | ||
|
|
111f280674 | ||
|
|
6e88faa9d8 | ||
|
|
1ca8b2a78d | ||
|
|
cd2a7cad7f | ||
|
|
ed16156957 | ||
|
|
8dc1f7e08f | ||
|
|
2d3c13c587 | ||
|
|
5486907639 | ||
|
|
9233cef23a | ||
|
|
c16eafe892 | ||
|
|
b479684fe4 | ||
|
|
4201f61548 | ||
|
|
d04fc76840 | ||
|
|
0f84adc752 | ||
|
|
fbefd80959 | ||
|
|
6a691b54c8 | ||
|
|
fc75717d32 | ||
|
|
1459c6e993 | ||
|
|
f50292f9bf | ||
|
|
5b81912bd3 | ||
|
|
3c98a94c38 | ||
|
|
1d98de6d4d | ||
|
|
0ce5d9063a | ||
|
|
3b84e1d6ec | ||
|
|
d62f6e2116 | ||
|
|
71a26cc4ac | ||
|
|
32441e9406 | ||
|
|
e6dade1206 | ||
|
|
43d34cae07 | ||
|
|
a72a7948fe | ||
|
|
a24f6639a1 | ||
|
|
b2a0af32e9 | ||
|
|
cc58d14d32 | ||
|
|
9ce419b949 | ||
|
|
5053816be7 | ||
|
|
30ca34ea93 | ||
|
|
68d1a404b3 | ||
|
|
85e82b85ea | ||
|
|
23467280b4 | ||
|
|
aedad1c48f | ||
|
|
05cc4dd188 | ||
|
|
ea6351ea06 | ||
|
|
87d3ceb408 | ||
|
|
d08dd2b506 | ||
|
|
8a047d14a1 | ||
|
|
e103772aa4 | ||
|
|
c332699dc8 | ||
|
|
25e6e61d10 | ||
|
|
cdcd6b636a | ||
|
|
7879591bcf | ||
|
|
7fc6556866 | ||
|
|
3f5489ce7e | ||
|
|
5a90854861 | ||
|
|
8347a8c098 | ||
|
|
2bf074d85a | ||
|
|
50d47cd679 | ||
|
|
3a4e06eaa2 | ||
|
|
4be71726d4 | ||
|
|
c78db7eb08 | ||
|
|
e4dc711481 | ||
|
|
5114138c67 | ||
|
|
68b8743002 | ||
|
|
8f312bfffb | ||
|
|
7e7e109cfe | ||
|
|
05e5545466 | ||
|
|
ddb0990645 | ||
|
|
04dec6d91c | ||
|
|
a883b817b0 | ||
|
|
b7423aebf6 | ||
|
|
ee70aeb952 | ||
|
|
74d95e7cbb | ||
|
|
f6f6fab5ba | ||
|
|
699ffc822a | ||
|
|
4e35f5402c | ||
|
|
9b997d0924 | ||
|
|
d705f8211e | ||
|
|
03761bbb2a | ||
|
|
4d0794e90e | ||
|
|
e615c4a55b | ||
|
|
51eb3423f3 | ||
|
|
f6318666d9 | ||
|
|
544d4b8136 | ||
|
|
edf4846d55 | ||
|
|
f3754de843 | ||
|
|
3d920ad151 | ||
|
|
575f056360 | ||
|
|
716d9affb5 | ||
|
|
b01dd52da2 | ||
|
|
c75fddc2c0 | ||
|
|
db0c16f31d | ||
|
|
b286ab2439 | ||
|
|
fa57828ebd | ||
|
|
8052767002 | ||
|
|
932f572fb5 | ||
|
|
328a64eb90 | ||
|
|
c661fce8f1 | ||
|
|
60d1396011 | ||
|
|
3b647dfd37 | ||
|
|
50fe588949 | ||
|
|
0ced053d21 | ||
|
|
b8cf4a4d75 | ||
|
|
ff72657a82 | ||
|
|
92a96fdae6 | ||
|
|
b1a96d55ad | ||
|
|
49657816c6 | ||
|
|
7094b6ffbf | ||
|
|
ed7c2574eb | ||
|
|
45a9e37342 | ||
|
|
9e6a458203 | ||
|
|
55a279a700 | ||
|
|
82e2e332cf | ||
|
|
103d7c2bb2 | ||
|
|
f5f0b75617 | ||
|
|
c163554c3f | ||
|
|
bd75f593c2 | ||
|
|
fbc1866363 | ||
|
|
6480f7f2aa | ||
|
|
4cb3a79429 | ||
|
|
ca521eaeba | ||
|
|
f287ba2dac | ||
|
|
ff46bbbb3f | ||
|
|
cafca35500 | ||
|
|
9803841617 | ||
|
|
4dffbfe6fa | ||
|
|
6e61159608 | ||
|
|
3c85de3e34 | ||
|
|
1b5cddd371 | ||
|
|
6a7005299a | ||
|
|
1a4c9faab1 | ||
|
|
bfbf34e11d | ||
|
|
646754732d | ||
|
|
439d9e7b74 | ||
|
|
464f7044f0 | ||
|
|
7cde2f64af | ||
|
|
f674fff930 | ||
|
|
efc1157653 | ||
|
|
0677712d6e | ||
|
|
2e106a5d07 | ||
|
|
da7b97042e | ||
|
|
f018a2b2a6 | ||
|
|
c3f7d7bad2 | ||
|
|
70d857bfec | ||
|
|
f3265901b6 | ||
|
|
7c8ac50426 | ||
|
|
8ad39fe855 | ||
|
|
13b6218c43 | ||
|
|
bece3278f4 | ||
|
|
4c0a1960ad | ||
|
|
47324422a6 | ||
|
|
3b1da6901d | ||
|
|
fc6ec54233 | ||
|
|
64928d0849 | ||
|
|
56a580b1e7 | ||
|
|
f7af3b407b | ||
|
|
9a0674f5d7 | ||
|
|
cc30ea658e | ||
|
|
59869def31 | ||
|
|
a5d3f2caf1 | ||
|
|
4ad87a522c | ||
|
|
453812222b | ||
|
|
145cf7cc93 | ||
|
|
c09e22ed96 | ||
|
|
cdb2d4d2d6 | ||
|
|
29f0031c1e | ||
|
|
e8099e130a | ||
|
|
1cbca1ddf0 | ||
|
|
eeed004fe2 | ||
|
|
5a180b86fb | ||
|
|
e3059b41ae | ||
|
|
1a5c71048c | ||
|
|
fc4e97c9b5 | ||
|
|
3cd3d7414d | ||
|
|
1bb2212e4a | ||
|
|
a088f27f1d | ||
|
|
0e9ad1258d | ||
|
|
2a33f462a3 | ||
|
|
cbc164dbeb | ||
|
|
0bfc7033a9 | ||
|
|
2ec0d90a58 | ||
|
|
6382fdf19c | ||
|
|
9287e6608d | ||
|
|
0fcee5b25e | ||
|
|
d221763064 | ||
|
|
b39a5b755e | ||
|
|
30cb4ef562 | ||
|
|
449330441a | ||
|
|
fcab5e6ef2 | ||
|
|
0212b837ea | ||
|
|
e7438a099e | ||
|
|
b3303e3c38 | ||
|
|
c69c86d193 | ||
|
|
73ec8b8a70 | ||
|
|
af09796df8 | ||
|
|
954504de8d | ||
|
|
0aba040338 | ||
|
|
c3bfe87674 | ||
|
|
9aa1279144 | ||
|
|
4e6c45b195 | ||
|
|
4fdb939bd2 | ||
|
|
062a1dcc72 | ||
|
|
7b420b1855 | ||
|
|
40f61bbc8f | ||
|
|
f5d821c394 | ||
|
|
3958ec9189 | ||
|
|
1e4f52e541 | ||
|
|
5cc5cb444e | ||
|
|
4acf0c59ca | ||
|
|
2858a5e871 | ||
|
|
24496d3ee1 | ||
|
|
0a5df69b12 | ||
|
|
80efea02c6 | ||
|
|
9f5c282b41 | ||
|
|
b2602c3385 | ||
|
|
0e584af424 | ||
|
|
cdc3de2a33 | ||
|
|
3bfa556b02 | ||
|
|
44cb7577e2 | ||
|
|
46d2b08477 | ||
|
|
0193ff9e65 | ||
|
|
fd9a51209f | ||
|
|
d0a7b87e04 | ||
|
|
799b24c90e | ||
|
|
3e1a8c87d1 | ||
|
|
c886d874de | ||
|
|
4dfb020089 | ||
|
|
bc6f05acbc | ||
|
|
2701bbd501 | ||
|
|
1f2040d97c | ||
|
|
43963a3e91 | ||
|
|
4287311adb | ||
|
|
d0e8589a76 | ||
|
|
c4bab72947 | ||
|
|
aa4b4998fa | ||
|
|
ed4566e00f | ||
|
|
5c2cdfe16c | ||
|
|
12c75357b5 | ||
|
|
d40f3ee45a | ||
|
|
96a0def846 | ||
|
|
1fd595d0de | ||
|
|
52cf4f3d1f | ||
|
|
4d9be1d232 | ||
|
|
fb2bc20b4f | ||
|
|
744593e96a | ||
|
|
1e9308be9b | ||
|
|
411605e121 | ||
|
|
1da8d6abb3 | ||
|
|
cdcef798df | ||
|
|
f7207a9f3f | ||
|
|
7a54b55bd4 | ||
|
|
991dfc2ad5 | ||
|
|
718c8291a8 | ||
|
|
f1e84c348b | ||
|
|
2a2d399a98 | ||
|
|
5f513a8bef | ||
|
|
4b96d5a707 | ||
|
|
220f3d4410 | ||
|
|
841f62bd84 | ||
|
|
f3f16b78d5 | ||
|
|
91e2e7931b | ||
|
|
1e855799f8 | ||
|
|
3c6faf8473 | ||
|
|
c994eaaa8e | ||
|
|
517d8f4163 | ||
|
|
9deb2964a5 | ||
|
|
9cf9f8b844 | ||
|
|
ad46ea74c0 | ||
|
|
2a28855e4b | ||
|
|
8d25f60097 | ||
|
|
982a51f16e | ||
|
|
68d02648d7 | ||
|
|
6e8122849a | ||
|
|
b04ae84941 | ||
|
|
932979d5fb | ||
|
|
f7ef32c58d | ||
|
|
f7108b4b8c | ||
|
|
882038a794 | ||
|
|
aec23fe46b | ||
|
|
89d5b1cfe4 | ||
|
|
35ac0b0c6a | ||
|
|
2a2a0f8961 | ||
|
|
d9902b9744 | ||
|
|
f82478a362 | ||
|
|
bb3d3fbe72 | ||
|
|
4fa0593bb5 | ||
|
|
41517ca7d4 | ||
|
|
35c9f649ad | ||
|
|
ad2f2e55a5 | ||
|
|
41c446ddb3 | ||
|
|
7d6aa8489d | ||
|
|
63f1e0f07c | ||
|
|
98f4423624 | ||
|
|
1ac4cbb59f | ||
|
|
24ebfbfbf5 | ||
|
|
7ff1051d3c | ||
|
|
8af3364660 | ||
|
|
02f4677aef | ||
|
|
11785f3b86 | ||
|
|
90532427b6 | ||
|
|
cc9979ff4b | ||
|
|
c89e4f1b41 | ||
|
|
c3e6d3dc48 | ||
|
|
ad1ce7b220 | ||
|
|
fd4dbdfb3a | ||
|
|
153cf6a840 | ||
|
|
a567d0d6dd | ||
|
|
297599a45b | ||
|
|
678ca591c1 | ||
|
|
c19f8167e8 | ||
|
|
cc2d474fda | ||
|
|
9058aca16e | ||
|
|
1c186f7fa5 | ||
|
|
46da3285f8 | ||
|
|
b419929ad7 | ||
|
|
8018daa2dc | ||
|
|
1e7c285fef | ||
|
|
0b072e6089 | ||
|
|
4fd6203987 | ||
|
|
51d264098c | ||
|
|
680a66b156 | ||
|
|
481a14e529 | ||
|
|
f3e43334c4 | ||
|
|
0054b00d01 | ||
|
|
82ecb5533f | ||
|
|
d3289d85f1 | ||
|
|
e628b1364c | ||
|
|
6c421c1447 | ||
|
|
99369e7040 | ||
|
|
01cbdf14a9 | ||
|
|
f691aca241 | ||
|
|
85495a11e3 | ||
|
|
134ce05d27 | ||
|
|
3498fbc8f1 | ||
|
|
f49f72ce7f | ||
|
|
a5e3b6ce33 | ||
|
|
0fd945b859 | ||
|
|
879eba0247 | ||
|
|
bb49dd77a1 | ||
|
|
ae705322f8 | ||
|
|
36d92d4060 | ||
|
|
3ce2b1ab19 | ||
|
|
52e756a78a | ||
|
|
5a36cb7cf1 | ||
|
|
9138f4be16 | ||
|
|
df93357cec | ||
|
|
8ab23c4ca6 | ||
|
|
f179d69420 | ||
|
|
730a7a233d | ||
|
|
84ad10fa9c | ||
|
|
b1cda41f56 | ||
|
|
0bce921f69 | ||
|
|
97282740f5 | ||
|
|
150ae02978 | ||
|
|
70058b6bd4 | ||
|
|
67c63f81d9 | ||
|
|
abeffb2a19 | ||
|
|
fb8452b2bb | ||
|
|
1f281e8439 | ||
|
|
223c705e8f | ||
|
|
00d8b533f4 | ||
|
|
3b25a8fe07 | ||
|
|
a57b9cddb5 | ||
|
|
064ed1bb8b | ||
|
|
efda254981 | ||
|
|
3fa6b8b6ac | ||
|
|
4603643240 | ||
|
|
f82b02958f | ||
|
|
5d1f61753b | ||
|
|
883043cde3 | ||
|
|
85ce7c638d | ||
|
|
547e279693 | ||
|
|
b9bdefe898 | ||
|
|
c963cb6fcc | ||
|
|
fa6d4cce2a | ||
|
|
c7188d5a71 | ||
|
|
c333d72743 | ||
|
|
2a1ec4eff3 | ||
|
|
190b2e5b5c | ||
|
|
3e2a517272 | ||
|
|
a6cd35bd06 | ||
|
|
ba3032e553 | ||
|
|
20fd452335 | ||
|
|
8f83a5f5e6 | ||
|
|
4e417d1b10 | ||
|
|
3ee63a503a | ||
|
|
8dd0e12398 | ||
|
|
253b4d0ddc | ||
|
|
a8b0931659 | ||
|
|
11a182c68a | ||
|
|
2583d21cf1 | ||
|
|
aa6032d74f | ||
|
|
e1bac5fe9f | ||
|
|
0c74848c54 | ||
|
|
1c4f2d2de0 | ||
|
|
d67d2aa064 | ||
|
|
208f3281a9 | ||
|
|
fb7e3bc812 | ||
|
|
884adb963c | ||
|
|
29c4df9f76 | ||
|
|
f1940a320c | ||
|
|
a297bba193 | ||
|
|
375a3fe386 | ||
|
|
d837754ef6 | ||
|
|
49a1f0c42c | ||
|
|
a5033e10cd | ||
|
|
00f0952ab2 | ||
|
|
ec5b636c26 | ||
|
|
7126cc0d56 | ||
|
|
568d8887ce | ||
|
|
4927e84a88 | ||
|
|
d2d8039cb9 | ||
|
|
5da242d785 | ||
|
|
87f25b1ed4 | ||
|
|
4f9afc8578 | ||
|
|
defadf70e3 | ||
|
|
82be3853f0 | ||
|
|
ff184926fc | ||
|
|
0e9768c0f6 | ||
|
|
805c924a15 | ||
|
|
10ff8fc432 | ||
|
|
e2db0bab9f | ||
|
|
92ee5169ab | ||
|
|
5cf2345dca | ||
|
|
0accf6a18f | ||
|
|
52e46aad86 | ||
|
|
43f49e5e51 | ||
|
|
60908b123d | ||
|
|
5169fd178a | ||
|
|
bbc446ef01 | ||
|
|
65bb8c6f26 | ||
|
|
171f40819c | ||
|
|
4baa26cb25 | ||
|
|
01da7fde31 | ||
|
|
3c8234d715 | ||
|
|
866f242465 | ||
|
|
f690596825 | ||
|
|
5f494e4b78 | ||
|
|
7b814329da | ||
|
|
2fc0e1cf50 | ||
|
|
ba3f98aeb4 | ||
|
|
f49818ade3 | ||
|
|
b37c70494b | ||
|
|
ff1db26f41 | ||
|
|
3550c97966 | ||
|
|
956c686360 | ||
|
|
508b0d7711 | ||
|
|
abb1464e30 | ||
|
|
704d5415d6 | ||
|
|
6cc1cfd1b0 | ||
|
|
e6455a7fd3 | ||
|
|
a9aad2a751 | ||
|
|
1bf745345d | ||
|
|
63c71ed923 | ||
|
|
3a844aefa0 | ||
|
|
93c92e8976 | ||
|
|
9523e5534d | ||
|
|
d20048026c | ||
|
|
15c7b6f1c8 | ||
|
|
3149c3cfc6 | ||
|
|
f91e0ec39f | ||
|
|
c31d4096c6 | ||
|
|
118f14ed4c | ||
|
|
0d0791cc41 | ||
|
|
f45aa69917 | ||
|
|
4b44ff29ee | ||
|
|
f15f5d7309 | ||
|
|
ea55b1a797 | ||
|
|
668366e886 | ||
|
|
eb1b2aef55 | ||
|
|
906430add5 | ||
|
|
f8fbbd2323 | ||
|
|
adab6ef0c6 | ||
|
|
ddfd91617f | ||
|
|
8418b4cb91 | ||
|
|
e593943d99 | ||
|
|
b58b5e65dc | ||
|
|
6d393987e8 | ||
|
|
852231b503 | ||
|
|
870878d151 | ||
|
|
cdf7bcf839 | ||
|
|
8a4fee7aea | ||
|
|
fa578efee4 | ||
|
|
4b6b4c0c63 | ||
|
|
8199ab83ef | ||
|
|
8e50d0ba53 | ||
|
|
7d72d66a97 | ||
|
|
3454694887 | ||
|
|
2a51c8a2bf | ||
|
|
524f623fd4 | ||
|
|
7ab7e18d96 | ||
|
|
6f2c8dba5a | ||
|
|
162d8bfffe | ||
|
|
61569d97cb | ||
|
|
975622a31c | ||
|
|
7524d06126 | ||
|
|
7f75eeadb9 | ||
|
|
4db2b73397 | ||
|
|
2f493c63f8 | ||
|
|
2761356f02 | ||
|
|
8207a52b6b | ||
|
|
8bbe7a1f0f | ||
|
|
2b052b3d43 | ||
|
|
94e7bf3f92 | ||
|
|
64e3f5f2ac | ||
|
|
bb7f7deb50 | ||
|
|
55c10890bd | ||
|
|
edef0b194d | ||
|
|
37f0c98e75 | ||
|
|
48f18514af | ||
|
|
76c13700be | ||
|
|
8ae8737fe2 | ||
|
|
36f7b7a1a1 | ||
|
|
b0a5f2d998 | ||
|
|
19c980bc3b | ||
|
|
78d6b9699b | ||
|
|
82d8cb22df | ||
|
|
9c41af82d7 | ||
|
|
2997dd4e4d | ||
|
|
4602648fe5 | ||
|
|
a8f2ca5643 | ||
|
|
cd055f7344 | ||
|
|
c43709395f | ||
|
|
10f60752c8 | ||
|
|
870f8463db | ||
|
|
5567a69142 | ||
|
|
762fec1d9a | ||
|
|
0946b0d3a3 | ||
|
|
976dd2cbfb | ||
|
|
b6956b3649 | ||
|
|
6cf4a50a83 | ||
|
|
b2b4902d23 | ||
|
|
6f69129829 | ||
|
|
d846894d22 | ||
|
|
7d3101c877 | ||
|
|
c3f0e6f10c | ||
|
|
d0da2dd66c | ||
|
|
877b3ab39c | ||
|
|
8f031a78c1 | ||
|
|
69b36a4c34 | ||
|
|
c7b8df5655 | ||
|
|
d85768b2ac | ||
|
|
a569c1f4f9 | ||
|
|
07a8e5b216 | ||
|
|
38bf58c613 | ||
|
|
ba90d72d55 | ||
|
|
9889bee924 | ||
|
|
a19e4e8f16 | ||
|
|
5121852fbc | ||
|
|
1d1ff5d20b | ||
|
|
ec00697d31 | ||
|
|
c25714b68e | ||
|
|
dc0147c5f9 | ||
|
|
296afdbeee | ||
|
|
2f8f058c5c | ||
|
|
133d593689 | ||
|
|
68784018e6 | ||
|
|
19dfec2a34 | ||
|
|
55d729339f | ||
|
|
c3108a17f4 | ||
|
|
d47ae64bd6 | ||
|
|
5206ba7a74 | ||
|
|
095e1e9789 | ||
|
|
a0b9f99dd3 | ||
|
|
a33a92207b | ||
|
|
f647e1ff11 |
@@ -5,6 +5,7 @@ orbs:
|
|||||||
aws-s3: circleci/aws-s3@4.0.0
|
aws-s3: circleci/aws-s3@4.0.0
|
||||||
aws-cli: circleci/aws-cli@4.0
|
aws-cli: circleci/aws-cli@4.0
|
||||||
eb: circleci/aws-elastic-beanstalk@2.0.1
|
eb: circleci/aws-elastic-beanstalk@2.0.1
|
||||||
|
jira: circleci/jira@2.1.0
|
||||||
jobs:
|
jobs:
|
||||||
imex-api-deploy:
|
imex-api-deploy:
|
||||||
docker:
|
docker:
|
||||||
@@ -18,6 +19,12 @@ jobs:
|
|||||||
eb status --verbose
|
eb status --verbose
|
||||||
eb deploy
|
eb deploy
|
||||||
eb status
|
eb status
|
||||||
|
- jira/notify:
|
||||||
|
environment: Production (ImEX) - API
|
||||||
|
environment_type: production
|
||||||
|
job_type: deployment
|
||||||
|
pipeline_id: << pipeline.id >>
|
||||||
|
pipeline_number: << pipeline.number >>
|
||||||
|
|
||||||
imex-hasura-migrate:
|
imex-hasura-migrate:
|
||||||
docker:
|
docker:
|
||||||
@@ -33,11 +40,16 @@ jobs:
|
|||||||
- run:
|
- run:
|
||||||
name: Execute migration
|
name: Execute migration
|
||||||
command: |
|
command: |
|
||||||
npm install hasura-cli -g
|
curl -L https://github.com/hasura/graphql-engine/raw/stable/cli/get.sh | bash
|
||||||
hasura migrate apply --endpoint https://db.imex.online/ --admin-secret << parameters.secret >>
|
hasura migrate apply --endpoint https://db.imex.online/ --admin-secret << parameters.secret >>
|
||||||
hasura metadata apply --endpoint https://db.imex.online/ --admin-secret << parameters.secret >>
|
hasura metadata apply --endpoint https://db.imex.online/ --admin-secret << parameters.secret >>
|
||||||
hasura metadata reload --endpoint https://db.imex.online/ --admin-secret << parameters.secret >>
|
hasura metadata reload --endpoint https://db.imex.online/ --admin-secret << parameters.secret >>
|
||||||
|
- jira/notify:
|
||||||
|
environment: Production (ImEX) - Hasura
|
||||||
|
environment_type: production
|
||||||
|
pipeline_id: << pipeline.id >>
|
||||||
|
job_type: deployment
|
||||||
|
pipeline_number: << pipeline.number >>
|
||||||
imex-app-build:
|
imex-app-build:
|
||||||
docker:
|
docker:
|
||||||
- image: cimg/node:18.18.2
|
- image: cimg/node:18.18.2
|
||||||
@@ -62,6 +74,7 @@ jobs:
|
|||||||
to: "s3://imex-online-production/"
|
to: "s3://imex-online-production/"
|
||||||
arguments: "--exclude '*.map'"
|
arguments: "--exclude '*.map'"
|
||||||
|
|
||||||
|
|
||||||
imex-app-beta-build:
|
imex-app-beta-build:
|
||||||
docker:
|
docker:
|
||||||
- image: cimg/node:18.18.2
|
- image: cimg/node:18.18.2
|
||||||
@@ -86,6 +99,12 @@ jobs:
|
|||||||
from: dist
|
from: dist
|
||||||
to: "s3://imex-online-beta/"
|
to: "s3://imex-online-beta/"
|
||||||
arguments: "--exclude '*.map'"
|
arguments: "--exclude '*.map'"
|
||||||
|
- jira/notify:
|
||||||
|
environment: Production (ImEX) - Front End
|
||||||
|
environment_type: production
|
||||||
|
pipeline_id: << pipeline.id >>
|
||||||
|
job_type: deployment
|
||||||
|
pipeline_number: << pipeline.number >>
|
||||||
|
|
||||||
rome-api-deploy:
|
rome-api-deploy:
|
||||||
docker:
|
docker:
|
||||||
@@ -99,7 +118,12 @@ jobs:
|
|||||||
eb status --verbose
|
eb status --verbose
|
||||||
eb deploy
|
eb deploy
|
||||||
eb status
|
eb status
|
||||||
|
- jira/notify:
|
||||||
|
environment: Production (Rome) - API
|
||||||
|
environment_type: production
|
||||||
|
pipeline_id: << pipeline.id >>
|
||||||
|
job_type: deployment
|
||||||
|
pipeline_number: << pipeline.number >>
|
||||||
rome-hasura-migrate:
|
rome-hasura-migrate:
|
||||||
docker:
|
docker:
|
||||||
- image: cimg/node:18.18.2
|
- image: cimg/node:18.18.2
|
||||||
@@ -114,11 +138,16 @@ jobs:
|
|||||||
- run:
|
- run:
|
||||||
name: Execute migration
|
name: Execute migration
|
||||||
command: |
|
command: |
|
||||||
npm install hasura-cli -g
|
curl -L https://github.com/hasura/graphql-engine/raw/stable/cli/get.sh | bash
|
||||||
hasura migrate apply --endpoint https://db.romeonline.io/ --admin-secret << parameters.secret >>
|
hasura migrate apply --endpoint https://db.romeonline.io/ --admin-secret << parameters.secret >>
|
||||||
hasura metadata apply --endpoint https://db.romeonline.io/ --admin-secret << parameters.secret >>
|
hasura metadata apply --endpoint https://db.romeonline.io/ --admin-secret << parameters.secret >>
|
||||||
hasura metadata reload --endpoint https://db.romeonline.io/ --admin-secret << parameters.secret >>
|
hasura metadata reload --endpoint https://db.romeonline.io/ --admin-secret << parameters.secret >>
|
||||||
|
- jira/notify:
|
||||||
|
environment: Production (Rome) - Hasura
|
||||||
|
environment_type: production
|
||||||
|
pipeline_id: << pipeline.id >>
|
||||||
|
job_type: deployment
|
||||||
|
pipeline_number: << pipeline.number >>
|
||||||
rome-app-build:
|
rome-app-build:
|
||||||
docker:
|
docker:
|
||||||
- image: cimg/node:18.18.2
|
- image: cimg/node:18.18.2
|
||||||
@@ -143,6 +172,12 @@ jobs:
|
|||||||
from: dist
|
from: dist
|
||||||
to: "s3://rome-online-production/"
|
to: "s3://rome-online-production/"
|
||||||
arguments: "--exclude '*.map'"
|
arguments: "--exclude '*.map'"
|
||||||
|
- jira/notify:
|
||||||
|
environment: Production (Rome) - Front End
|
||||||
|
environment_type: production
|
||||||
|
pipeline_id: << pipeline.id >>
|
||||||
|
job_type: deployment
|
||||||
|
pipeline_number: << pipeline.number >>
|
||||||
|
|
||||||
promanager-app-build:
|
promanager-app-build:
|
||||||
docker:
|
docker:
|
||||||
@@ -168,6 +203,12 @@ jobs:
|
|||||||
from: dist
|
from: dist
|
||||||
to: "s3://promanager-production/"
|
to: "s3://promanager-production/"
|
||||||
arguments: "--exclude '*.map'"
|
arguments: "--exclude '*.map'"
|
||||||
|
- jira/notify:
|
||||||
|
environment: Production (ProManager) - Front End
|
||||||
|
environment_type: production
|
||||||
|
pipeline_id: << pipeline.id >>
|
||||||
|
job_type: deployment
|
||||||
|
pipeline_number: << pipeline.number >>
|
||||||
|
|
||||||
test-rome-hasura-migrate:
|
test-rome-hasura-migrate:
|
||||||
docker:
|
docker:
|
||||||
@@ -183,10 +224,18 @@ jobs:
|
|||||||
- run:
|
- run:
|
||||||
name: Execute migration
|
name: Execute migration
|
||||||
command: |
|
command: |
|
||||||
npm install hasura-cli -g
|
curl -L https://github.com/hasura/graphql-engine/raw/stable/cli/get.sh | bash
|
||||||
hasura migrate apply --endpoint https://db.test.romeonline.io/ --admin-secret << parameters.secret >>
|
hasura migrate apply --endpoint https://db.test.romeonline.io/ --admin-secret << parameters.secret >>
|
||||||
|
sleep 5
|
||||||
hasura metadata apply --endpoint https://db.test.romeonline.io/ --admin-secret << parameters.secret >>
|
hasura metadata apply --endpoint https://db.test.romeonline.io/ --admin-secret << parameters.secret >>
|
||||||
|
sleep 10
|
||||||
hasura metadata reload --endpoint https://db.test.romeonline.io/ --admin-secret << parameters.secret >>
|
hasura metadata reload --endpoint https://db.test.romeonline.io/ --admin-secret << parameters.secret >>
|
||||||
|
- jira/notify:
|
||||||
|
environment: Test (Rome) - Hasura
|
||||||
|
environment_type: testing
|
||||||
|
pipeline_id: << pipeline.id >>
|
||||||
|
job_type: deployment
|
||||||
|
pipeline_number: << pipeline.number >>
|
||||||
|
|
||||||
test-rome-app-build:
|
test-rome-app-build:
|
||||||
docker:
|
docker:
|
||||||
@@ -212,6 +261,12 @@ jobs:
|
|||||||
from: dist
|
from: dist
|
||||||
to: "s3://rome-online-test/"
|
to: "s3://rome-online-test/"
|
||||||
arguments: "--exclude '*.map'"
|
arguments: "--exclude '*.map'"
|
||||||
|
- jira/notify:
|
||||||
|
environment: Test (Rome) - Front End
|
||||||
|
environment_type: testing
|
||||||
|
pipeline_id: << pipeline.id >>
|
||||||
|
job_type: deployment
|
||||||
|
pipeline_number: << pipeline.number >>
|
||||||
|
|
||||||
test-promanager-app-build:
|
test-promanager-app-build:
|
||||||
docker:
|
docker:
|
||||||
@@ -237,6 +292,12 @@ jobs:
|
|||||||
from: dist
|
from: dist
|
||||||
to: "s3://promanager-testing/"
|
to: "s3://promanager-testing/"
|
||||||
arguments: "--exclude '*.map'"
|
arguments: "--exclude '*.map'"
|
||||||
|
- jira/notify:
|
||||||
|
environment: Test (ProManager) - Front End
|
||||||
|
environment_type: testing
|
||||||
|
pipeline_id: << pipeline.id >>
|
||||||
|
job_type: deployment
|
||||||
|
pipeline_number: << pipeline.number >>
|
||||||
|
|
||||||
test-hasura-migrate:
|
test-hasura-migrate:
|
||||||
docker:
|
docker:
|
||||||
@@ -252,10 +313,18 @@ jobs:
|
|||||||
- run:
|
- run:
|
||||||
name: Execute migration
|
name: Execute migration
|
||||||
command: |
|
command: |
|
||||||
npm install hasura-cli -g
|
curl -L https://github.com/hasura/graphql-engine/raw/stable/cli/get.sh | bash
|
||||||
hasura migrate apply --endpoint https://db.test.bodyshop.app/ --admin-secret << parameters.secret >>
|
hasura migrate apply --endpoint https://db.test.bodyshop.app/ --admin-secret << parameters.secret >>
|
||||||
|
sleep 15
|
||||||
hasura metadata apply --endpoint https://db.test.bodyshop.app/ --admin-secret << parameters.secret >>
|
hasura metadata apply --endpoint https://db.test.bodyshop.app/ --admin-secret << parameters.secret >>
|
||||||
|
sleep 30
|
||||||
hasura metadata reload --endpoint https://db.test.bodyshop.app/ --admin-secret << parameters.secret >>
|
hasura metadata reload --endpoint https://db.test.bodyshop.app/ --admin-secret << parameters.secret >>
|
||||||
|
- jira/notify:
|
||||||
|
environment: Test (ImEX) - Hasura
|
||||||
|
environment_type: testing
|
||||||
|
pipeline_id: << pipeline.id >>
|
||||||
|
job_type: deployment
|
||||||
|
pipeline_number: << pipeline.number >>
|
||||||
|
|
||||||
imex-test-app-build:
|
imex-test-app-build:
|
||||||
docker:
|
docker:
|
||||||
@@ -302,7 +371,12 @@ jobs:
|
|||||||
from: dist
|
from: dist
|
||||||
to: "s3://imex-online-test-beta/"
|
to: "s3://imex-online-test-beta/"
|
||||||
arguments: "--exclude '*.map'"
|
arguments: "--exclude '*.map'"
|
||||||
|
- jira/notify:
|
||||||
|
environment: Test (ImEX) - Front End
|
||||||
|
environment_type: testing
|
||||||
|
pipeline_id: << pipeline.id >>
|
||||||
|
job_type: deployment
|
||||||
|
pipeline_number: << pipeline.number >>
|
||||||
|
|
||||||
admin-app-build:
|
admin-app-build:
|
||||||
docker:
|
docker:
|
||||||
@@ -353,7 +427,7 @@ workflows:
|
|||||||
secret: ${HASURA_PROD_SECRET}
|
secret: ${HASURA_PROD_SECRET}
|
||||||
filters:
|
filters:
|
||||||
branches:
|
branches:
|
||||||
only: master
|
only: master-AIO
|
||||||
- rome-api-deploy:
|
- rome-api-deploy:
|
||||||
filters:
|
filters:
|
||||||
branches:
|
branches:
|
||||||
@@ -363,7 +437,7 @@ workflows:
|
|||||||
branches:
|
branches:
|
||||||
only: master-AIO
|
only: master-AIO
|
||||||
- rome-hasura-migrate:
|
- rome-hasura-migrate:
|
||||||
secret: ${HASURA_PROD_SECRET}
|
secret: ${HASURA_ROME_PROD_SECRET}
|
||||||
filters:
|
filters:
|
||||||
branches:
|
branches:
|
||||||
only: master-AIO
|
only: master-AIO
|
||||||
|
|||||||
24
.dockerignore
Normal file
24
.dockerignore
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
# Directories to exclude
|
||||||
|
.circleci
|
||||||
|
.idea
|
||||||
|
.platform
|
||||||
|
.vscode
|
||||||
|
_reference
|
||||||
|
client
|
||||||
|
redis/dockerdata
|
||||||
|
hasura
|
||||||
|
node_modules
|
||||||
|
# Files to exclude
|
||||||
|
.ebignore
|
||||||
|
.editorconfig
|
||||||
|
.eslintrc.json
|
||||||
|
.gitignore
|
||||||
|
.prettierrc.js
|
||||||
|
Dockerfile
|
||||||
|
README.MD
|
||||||
|
bodyshop_translations.babel
|
||||||
|
docker-compose.yml
|
||||||
|
ecosystem.config.js
|
||||||
|
|
||||||
|
# Optional: Exclude logs and temporary files
|
||||||
|
*.log
|
||||||
0
.localstack/.gitkeep
Normal file
0
.localstack/.gitkeep
Normal file
@@ -1 +1,2 @@
|
|||||||
client_max_body_size 50M;
|
client_max_body_size 50M;
|
||||||
|
client_body_buffer_size 5M;
|
||||||
|
|||||||
15
.vscode/launch.json
vendored
15
.vscode/launch.json
vendored
@@ -14,6 +14,21 @@
|
|||||||
"request": "launch",
|
"request": "launch",
|
||||||
"url": "http://localhost:3000",
|
"url": "http://localhost:3000",
|
||||||
"webRoot": "${workspaceRoot}/client/src"
|
"webRoot": "${workspaceRoot}/client/src"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Attach to Node.js in Docker",
|
||||||
|
"type": "node",
|
||||||
|
"request": "attach",
|
||||||
|
"address": "localhost",
|
||||||
|
"port": 9229,
|
||||||
|
"localRoot": "${workspaceFolder}",
|
||||||
|
"remoteRoot": "/app",
|
||||||
|
"protocol": "inspector",
|
||||||
|
"restart": true,
|
||||||
|
"sourceMaps": true,
|
||||||
|
"skipFiles": [
|
||||||
|
"<node_internals>/**"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
47
Dockerfile
Normal file
47
Dockerfile
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
# Use Amazon Linux 2023 as the base image
|
||||||
|
FROM amazonlinux:2023
|
||||||
|
|
||||||
|
# Install Git and Node.js (Amazon Linux 2023 uses the DNF package manager)
|
||||||
|
RUN dnf install -y git \
|
||||||
|
&& curl -sL https://rpm.nodesource.com/setup_20.x | bash - \
|
||||||
|
&& dnf install -y nodejs \
|
||||||
|
&& dnf clean all
|
||||||
|
|
||||||
|
|
||||||
|
# Install dependencies required by node-canvas
|
||||||
|
RUN dnf install -y \
|
||||||
|
gcc \
|
||||||
|
gcc-c++ \
|
||||||
|
cairo-devel \
|
||||||
|
pango-devel \
|
||||||
|
libjpeg-turbo-devel \
|
||||||
|
giflib-devel \
|
||||||
|
libpng-devel \
|
||||||
|
make \
|
||||||
|
python3 \
|
||||||
|
python3-pip \
|
||||||
|
&& dnf clean all
|
||||||
|
|
||||||
|
# Set the working directory
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# This is because our test route uses a git commit hash
|
||||||
|
RUN git config --global --add safe.directory /app
|
||||||
|
|
||||||
|
# Copy package.json and package-lock.json
|
||||||
|
COPY package.json ./
|
||||||
|
|
||||||
|
# Install Nodemon
|
||||||
|
RUN npm install -g nodemon
|
||||||
|
|
||||||
|
# Install dependencies
|
||||||
|
RUN npm i --no-package-lock
|
||||||
|
|
||||||
|
# Copy the rest of your application code
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
# Expose the port your app runs on (adjust if necessary)
|
||||||
|
EXPOSE 4000 9229
|
||||||
|
|
||||||
|
# Start the application
|
||||||
|
CMD ["nodemon", "--legacy-watch", "--inspect=0.0.0.0:9229", "server.js"]
|
||||||
@@ -2,7 +2,7 @@ NGROK TEsting:
|
|||||||
./ngrok.exe http http://localhost:4000 -host-header="localhost:4000"
|
./ngrok.exe http http://localhost:4000 -host-header="localhost:4000"
|
||||||
|
|
||||||
Finding deadfiles - run from client directory
|
Finding deadfiles - run from client directory
|
||||||
npx deadfile ./src/index.js --exclude build templates
|
npx deadfile ./src/index.jsx --exclude build templates
|
||||||
|
|
||||||
#Crushing all hasura migrations by creating a new initialization from the server.
|
#Crushing all hasura migrations by creating a new initialization from the server.
|
||||||
hasura migrate create "Init" --from-server --endpoint https://db.imex.online/ --admin-secret 'Production-ImEXOnline!@#'
|
hasura migrate create "Init" --from-server --endpoint https://db.imex.online/ --admin-secret 'Production-ImEXOnline!@#'
|
||||||
@@ -11,4 +11,4 @@ Production-ImEXOnline!@#'
|
|||||||
hasura migrate status --endpoint https://db.imex.online/ --admin-secret 'Production-ImEXOnline!@#'
|
hasura migrate status --endpoint https://db.imex.online/ --admin-secret 'Production-ImEXOnline!@#'
|
||||||
|
|
||||||
Generate the license file:
|
Generate the license file:
|
||||||
$ generate-license-file --input package.json --output third-party-licenses.txt --overwrite
|
$ generate-license-file --input package.json --output third-party-licenses.txt --overwrite
|
||||||
|
|||||||
64
_reference/Documents/dockerreadme.md
Normal file
64
_reference/Documents/dockerreadme.md
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
# Setting up External Networking and Static IP for WSL2 using Hyper-V
|
||||||
|
|
||||||
|
This guide will walk you through the steps to configure your WSL2 (Windows Subsystem for Linux) instance to use an external Hyper-V virtual switch, enabling it to connect directly to your local network. Additionally, you'll learn how to assign a static IP address to your WSL2 instance.
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
|
||||||
|
1. **Windows 11**
|
||||||
|
2. **Docker Desktop For Windows (Latest Version)
|
||||||
|
|
||||||
|
# Docker Setup
|
||||||
|
Inside the root of the project exists the `docker-compose.yaml` file, you can simply run
|
||||||
|
`docker-compose up` to launch the backend.
|
||||||
|
|
||||||
|
Things to note:
|
||||||
|
- When installing NPM packages, you will need to rebuild the `node-app` container
|
||||||
|
- Making changes to the server files will restart the `node-app`
|
||||||
|
|
||||||
|
# Local Stack
|
||||||
|
- LocalStack Front end (Optional) - https://apps.microsoft.com/detail/9ntrnft9zws2?hl=en-us&gl=US
|
||||||
|
- http://localhost:4566/_aws/ses will allow you to see emails sent
|
||||||
|
|
||||||
|
# Docker Commands
|
||||||
|
|
||||||
|
## General `docker-compose` Commands:
|
||||||
|
1. Bring up the services, force a rebuild of all services, and do not use the cache: `docker-compose up --build --no-cache`
|
||||||
|
2. Start Containers in Detached Mode: This will run the containers in the background (detached mode): `docker-compose up -d`
|
||||||
|
3. Stop and Remove Containers: Stops and removes the containers gracefully: `docker-compose down`
|
||||||
|
4. Stop containers without removing them: `docker-compose stop`
|
||||||
|
5. Remove Containers, Volumes, and Networks: `docker-compose down --volumes`
|
||||||
|
6. Force rebuild of containers: `docker-compose build --no-cache`
|
||||||
|
7. View running Containers: `docker-compose ps`
|
||||||
|
8. View a specific containers logs: `docker-compose logs <container-name>`
|
||||||
|
9. Scale services (multiple instances of a service): `docker-compose up --scale <container-name>=<instances number> -d`
|
||||||
|
10. Watch a specific containers logs in realtime with timestamps: `docker-compose logs -f --timestamps <container-name>`
|
||||||
|
|
||||||
|
## Volume Management Commands
|
||||||
|
1. List Docker volumes: `docker volume ls`
|
||||||
|
2. Remove Unused volumes `docker volume prune`
|
||||||
|
3. Remove specific volumes `docker volume rm <volume-name>`
|
||||||
|
4. Inspect a volume: `docker volume inspect <volume-name>`
|
||||||
|
|
||||||
|
## Container Image Management Commands:
|
||||||
|
1. List running containers: `docker ps`
|
||||||
|
2. List all containers: `docker os -a`
|
||||||
|
3. Remove Stopped containers: `docker container prune`
|
||||||
|
4. Remove a specific container: `docker container rm <container-name>`
|
||||||
|
5. Remove a specific image: `docker rmi <image-name>:<version>`
|
||||||
|
6. Remove all unused images: `docker image prune -a`
|
||||||
|
|
||||||
|
## Network Management Commands:
|
||||||
|
1. List networks: `docker network ls`
|
||||||
|
2. Inspect a specific network: `docker network inspect <network-name>`
|
||||||
|
3. Remove a specific network: `docker network rm <network-name>`
|
||||||
|
4. Remove unused networks: `docker network prune`
|
||||||
|
|
||||||
|
## Debugging and maintenance:
|
||||||
|
1. Enter a Running container: `docker exec -it <container name> /bin/bash` (could also be `/bin/sh` or for example `redis-cli` on a redis node)
|
||||||
|
2. View container resource usage: `docker stats`
|
||||||
|
3. Check Disk space used by Docker: `docker system df`
|
||||||
|
4. Remove all unused Data (Nuclear option): `docker system prune`
|
||||||
|
|
||||||
|
## Specific examples
|
||||||
|
1. To simulate a Clean state, one should run `docker system prune` followed by `docker volume prune -a`
|
||||||
|
2. You can run `docker-compose up` without the `-d` option, and you will get what is identical to the experience you were used to, this includes being able to control-c and bring the entire stack down
|
||||||
41
_reference/Documents/productionBoardNotes.md
Normal file
41
_reference/Documents/productionBoardNotes.md
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
# Production Board Notes:
|
||||||
|
|
||||||
|
## General Notes
|
||||||
|
|
||||||
|
- You can single click the lane footer to collapse/un-collapse the lane
|
||||||
|
- You can double click the lane header to collapse/un-collapse the lane
|
||||||
|
- If you need to scroll horizontally, you can hold shift and use the mouse scroll wheel, or press the mouse scroll wheel while scrolling
|
||||||
|
|
||||||
|
## Board Settings
|
||||||
|
|
||||||
|
#### Layout
|
||||||
|
|
||||||
|
- Board Orientation (Vertical or Horizontal)
|
||||||
|
- This determines the orientation of the card layout on the board.
|
||||||
|
- Horizontal is the default setting, and how the prior board was set up.
|
||||||
|
- Vertical is the new setting and allows lanes to be displayed vertically, with a grid of cards
|
||||||
|
- Card Size (Small, Medium, Large)
|
||||||
|
- This determines the size of the cards on the board.
|
||||||
|
- Small is the default setting, and how the prior board was set up.
|
||||||
|
- Medium and Large are new settings and allow for larger cards to be displayed on the board.
|
||||||
|
- Compact Cards (Tall or Wide)
|
||||||
|
- Formally called 'Compact'
|
||||||
|
- When on, data is displayed on the card vertically
|
||||||
|
- when turned off, some fields may share horizontal space, tightening the card layout
|
||||||
|
- Colored Cards (On or Off)
|
||||||
|
- When on, cards are colored based on the Status color
|
||||||
|
- Kiosk Mode (On or Off)
|
||||||
|
- This should be turned on if the shop is using it on a tablet (Ipad)
|
||||||
|
|
||||||
|
#### Information
|
||||||
|
|
||||||
|
These allow users to turn fields on or off, turning them all off will show the card in the most minimal form
|
||||||
|
|
||||||
|
|
||||||
|
### Statistics
|
||||||
|
|
||||||
|
- The statistics section allows users to see accumulations of both jobs on the board, and jobs in production.
|
||||||
|
- you can click a statistic to turn it on and off, and drag and drop the statistics to rearrange them
|
||||||
|
|
||||||
|
### Filters
|
||||||
|
- Allows you to set, and persist filters for estimators and insurance companies
|
||||||
@@ -4,7 +4,7 @@ Clone Repository for:
|
|||||||
{
|
{
|
||||||
"name": "node-webhook-scripts",
|
"name": "node-webhook-scripts",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"main": "index.js",
|
"main": "index.jsx",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"express": "^4.16.4"
|
"express": "^4.16.4"
|
||||||
},
|
},
|
||||||
1
_reference/localEmailViewer/.gitignore
vendored
Normal file
1
_reference/localEmailViewer/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
node_modules
|
||||||
7
_reference/localEmailViewer/README.md
Normal file
7
_reference/localEmailViewer/README.md
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
This will connect to your dockers local stack session and render the email in HTML.
|
||||||
|
|
||||||
|
```shell
|
||||||
|
node index.js
|
||||||
|
```
|
||||||
|
|
||||||
|
http://localhost:3334
|
||||||
116
_reference/localEmailViewer/index.js
Normal file
116
_reference/localEmailViewer/index.js
Normal file
@@ -0,0 +1,116 @@
|
|||||||
|
// index.js
|
||||||
|
|
||||||
|
import express from 'express';
|
||||||
|
import fetch from 'node-fetch';
|
||||||
|
import {simpleParser} from 'mailparser';
|
||||||
|
|
||||||
|
const app = express();
|
||||||
|
const PORT = 3334;
|
||||||
|
|
||||||
|
app.get('/', async (req, res) => {
|
||||||
|
try {
|
||||||
|
const response = await fetch('http://localhost:4566/_aws/ses');
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error('Network response was not ok');
|
||||||
|
}
|
||||||
|
const data = await response.json();
|
||||||
|
const messagesHtml = await parseMessages(data.messages);
|
||||||
|
res.send(renderHtml(messagesHtml));
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error fetching messages:', error);
|
||||||
|
res.status(500).send('Error fetching messages');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
async function parseMessages(messages) {
|
||||||
|
const parsedMessages = await Promise.all(
|
||||||
|
messages.map(async (message, index) => {
|
||||||
|
try {
|
||||||
|
const parsed = await simpleParser(message.RawData);
|
||||||
|
return `
|
||||||
|
<div class="shadow-md rounded-lg p-4 mb-6" style="background-color: lightgray">
|
||||||
|
<div class="shadow-md rounded-lg p-4 mb-6" style="background-color: white">
|
||||||
|
<div class="mb-2">
|
||||||
|
<span class="font-bold text-lg">Message ${index + 1}</span>
|
||||||
|
</div>
|
||||||
|
<div class="mb-2">
|
||||||
|
<span class="font-semibold">From:</span> ${message.Source}
|
||||||
|
</div>
|
||||||
|
<div class="mb-2">
|
||||||
|
<span class="font-semibold">Region:</span> ${message.Region}
|
||||||
|
</div>
|
||||||
|
<div class="mb-2">
|
||||||
|
<span class="font-semibold">Timestamp:</span> ${message.Timestamp}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="prose">
|
||||||
|
${parsed.html || parsed.textAsHtml || 'No HTML content available'}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error parsing email:', error);
|
||||||
|
return `
|
||||||
|
<div class="bg-white shadow-md rounded-lg p-4 mb-6">
|
||||||
|
<div class="mb-2">
|
||||||
|
<span class="font-bold text-lg">Message ${index + 1}</span>
|
||||||
|
</div>
|
||||||
|
<div class="mb-2">
|
||||||
|
<span class="font-semibold">From:</span> ${message.Source}
|
||||||
|
</div>
|
||||||
|
<div class="mb-2">
|
||||||
|
<span class="font-semibold">Region:</span> ${message.Region}
|
||||||
|
</div>
|
||||||
|
<div class="mb-2">
|
||||||
|
<span class="font-semibold">Timestamp:</span> ${message.Timestamp}
|
||||||
|
</div>
|
||||||
|
<div class="text-red-500">
|
||||||
|
Error parsing email content
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
|
return parsedMessages.join('');
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderHtml(messagesHtml) {
|
||||||
|
return `
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Email Messages Viewer</title>
|
||||||
|
<script src="https://cdn.tailwindcss.com"></script>
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
background-color: #f3f4f6;
|
||||||
|
font-family: Arial, sans-serif;
|
||||||
|
}
|
||||||
|
.container {
|
||||||
|
max-width: 800px;
|
||||||
|
margin: 50px auto;
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
.prose {
|
||||||
|
line-height: 1.6;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="container bg-white shadow-lg rounded-lg p-6">
|
||||||
|
<h1 class="text-2xl font-bold text-center mb-6">Email Messages Viewer</h1>
|
||||||
|
<div id="messages-container">
|
||||||
|
${messagesHtml}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
app.listen(PORT, () => {
|
||||||
|
console.log(`Server is running on http://localhost:${PORT}`);
|
||||||
|
});
|
||||||
1214
_reference/localEmailViewer/package-lock.json
generated
Normal file
1214
_reference/localEmailViewer/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
18
_reference/localEmailViewer/package.json
Normal file
18
_reference/localEmailViewer/package.json
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
{
|
||||||
|
"name": "localemailviewer",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"main": "index.js",
|
||||||
|
"type": "module",
|
||||||
|
"scripts": {
|
||||||
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
|
},
|
||||||
|
"keywords": [],
|
||||||
|
"author": "",
|
||||||
|
"license": "ISC",
|
||||||
|
"description": "",
|
||||||
|
"dependencies": {
|
||||||
|
"express": "^4.21.1",
|
||||||
|
"mailparser": "^3.7.1",
|
||||||
|
"node-fetch": "^3.3.2"
|
||||||
|
}
|
||||||
|
}
|
||||||
59
_reference/prHelper/index.html
Normal file
59
_reference/prHelper/index.html
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>IMEX IO Extractor</title>
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
font-family: Arial, sans-serif;
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
textarea {
|
||||||
|
width: 100%;
|
||||||
|
height: 200px;
|
||||||
|
}
|
||||||
|
.output-box {
|
||||||
|
margin-top: 20px;
|
||||||
|
padding: 10px;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
background-color: #f9f9f9;
|
||||||
|
min-height: 40px;
|
||||||
|
}
|
||||||
|
.copy-button {
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>IMEX IO Extractor</h1>
|
||||||
|
<textarea id="inputText" placeholder="Paste your text here..."></textarea>
|
||||||
|
<br>
|
||||||
|
<button onclick="extractIO()">Extract</button>
|
||||||
|
|
||||||
|
<div class="output-box" id="outputBox" contenteditable="true"></div>
|
||||||
|
<button class="copy-button" onclick="copyToClipboard()">Copy to Clipboard</button>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
function extractIO() {
|
||||||
|
const inputText = document.getElementById('inputText').value;
|
||||||
|
const ioNumbers = [...new Set(inputText.match(/IO-\d{4}/g))] // Extract unique IO-#### matches
|
||||||
|
.map(io => ({ io, num: parseInt(io.split('-')[1]) })) // Extract number part for sorting
|
||||||
|
.sort((a, b) => a.num - b.num) // Sort by the number
|
||||||
|
.map(item => item.io); // Extract sorted IO-####
|
||||||
|
|
||||||
|
document.getElementById('outputBox').innerText = ioNumbers.join(', '); // Display horizontally
|
||||||
|
}
|
||||||
|
|
||||||
|
function copyToClipboard() {
|
||||||
|
const outputBox = document.getElementById('outputBox');
|
||||||
|
const range = document.createRange();
|
||||||
|
range.selectNodeContents(outputBox);
|
||||||
|
const selection = window.getSelection();
|
||||||
|
selection.removeAllRanges();
|
||||||
|
selection.addRange(range);
|
||||||
|
document.execCommand('copy');
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -11,7 +11,7 @@ module.exports = {
|
|||||||
|
|
||||||
{
|
{
|
||||||
name: "Bitbucket Webhook",
|
name: "Bitbucket Webhook",
|
||||||
script: "./webhook/index.js",
|
script: "./webhook/index.jsx",
|
||||||
env: {
|
env: {
|
||||||
NODE_ENV: "production"
|
NODE_ENV: "production"
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
20
certs/cert.pem
Normal file
20
certs/cert.pem
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIDWzCCAkOgAwIBAgIUD/QBSAXy/AlJ/cS4DaPWJLpChxgwDQYJKoZIhvcNAQEL
|
||||||
|
BQAwPTELMAkGA1UEBhMCQ0ExCzAJBgNVBAgMAk9OMSEwHwYDVQQKDBhJbnRlcm5l
|
||||||
|
dCBXaWRnaXRzIFB0eSBMdGQwHhcNMjQwOTA5MTU0MjA1WhcNMjUwOTA5MTU0MjA1
|
||||||
|
WjA9MQswCQYDVQQGEwJDQTELMAkGA1UECAwCT04xITAfBgNVBAoMGEludGVybmV0
|
||||||
|
IFdpZGdpdHMgUHR5IEx0ZDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
|
||||||
|
AKSd0l7NJCNBwvtPU+dVPQkteg0AfC3sGqRnZMQteCRVa2oIgC4NoF3A9BK/yHbF
|
||||||
|
ZF25OnXTck5vzc8yb3v73ndfTD9ASKNoiaZE84/GFBsxqlKR8cs0qVwzuAsdijMv
|
||||||
|
vlMPNlMRyE1Rb7nR6HXGkPXNyxgMko03NXPkvIje9zRudm0Lf8L4q/hPyPkS7Mrm
|
||||||
|
/uQfAAJe+xFcupkEX2XY7r0x1C+z6E8lA1UcuhK3SHdW7CWYqp1vU5/dnnUiXwCa
|
||||||
|
GiC6Y1bCJB0pDAVISzy3JUDdINZdiqGR+y8ho3pstChf2mp/76s3N9eG9KA/qaFK
|
||||||
|
BrGk2PvCoZ8/Aj1aMsRYFHECAwEAAaNTMFEwHQYDVR0OBBYEFDLJ2fbWP4VUJgOp
|
||||||
|
PSs+NGHcVgRmMB8GA1UdIwQYMBaAFDLJ2fbWP4VUJgOpPSs+NGHcVgRmMA8GA1Ud
|
||||||
|
EwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBABfv5ut/y03atq0NMB0jeDY4
|
||||||
|
AvW4ukk0k1svyqxFZCw9o7m2lHb/IjmVrZG1Sj4JWrrSv0s02ccb26/t6vazNa5L
|
||||||
|
Powe3eyfHgfjTZJmgs8hyeMwKS0wWk/SPuu9JDhIJakiquqD+UVBGkHpP+XYvhDv
|
||||||
|
vhS2XRlW+aEjpUmr1oCyyrc6WbzrYRNadqEsn/AxwcMyUbht3Ugjkg+OpidcTIQp
|
||||||
|
5lv63waKo6I1vQofzBQ3L7JYsKo8kC0vAP7wkLxvzBii335uZJzzpFYFVOyVNezi
|
||||||
|
dJdazPbRYbXz4LjltdEn/SNfRuKX8ZRiN2OSo7OfSrZaMTS87SfCSFJGgQM8Yrk=
|
||||||
|
-----END CERTIFICATE-----
|
||||||
27
certs/id_rsa
Normal file
27
certs/id_rsa
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
-----BEGIN OPENSSH PRIVATE KEY-----
|
||||||
|
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABFwAAAAdzc2gtcn
|
||||||
|
NhAAAAAwEAAQAAAQEAvNl5fuVmLNv72BZNxnTqX5CHf5Xi8UxjYaYxHITSCx7blnhpVYLd
|
||||||
|
qXvcOWXzbsfjch/den73QiW4n2FYz75oGMhUGlOYzdWKA9I9Sj09Qy1R06RhwDiZGd5qaM
|
||||||
|
swEeXpkNmi2u4Qd2kJeDfUQUigjC09V81O/vrniGtQAJScfiG/itdm+Ufn09Z4MYk0HWjq
|
||||||
|
iDokNEskoEPsibYIrb+Q6vdtuPkZO+wU/smXhPtgw5ST6oQdmm/gVNsRg5XNzxrire+z1G
|
||||||
|
WatnnVL3hPnnfpnf8W589dyms7GGJwhPerSGTN1bn0T4+9C69Cd7LBJtxiuFdRmdlGLLLP
|
||||||
|
RR48Rur71wAAA9AEfVsdBH1bHQAAAAdzc2gtcnNhAAABAQC82Xl+5WYs2/vYFk3GdOpfkI
|
||||||
|
d/leLxTGNhpjEchNILHtuWeGlVgt2pe9w5ZfNux+NyH916fvdCJbifYVjPvmgYyFQaU5jN
|
||||||
|
1YoD0j1KPT1DLVHTpGHAOJkZ3mpoyzAR5emQ2aLa7hB3aQl4N9RBSKCMLT1XzU7++ueIa1
|
||||||
|
AAlJx+Ib+K12b5R+fT1ngxiTQdaOqIOiQ0SySgQ+yJtgitv5Dq9224+Rk77BT+yZeE+2DD
|
||||||
|
lJPqhB2ab+BU2xGDlc3PGuKt77PUZZq2edUveE+ed+md/xbnz13KazsYYnCE96tIZM3Vuf
|
||||||
|
RPj70Lr0J3ssEm3GK4V1GZ2UYsss9FHjxG6vvXAAAAAwEAAQAAAQAQTosSLQbMmtY9S3e9
|
||||||
|
yjyusdExcCTfhyQRu4MEHmfws+JsNMuLqbgwOVTD1AzYJQR7x0qdmDcLjCxL/uDnV16vvS
|
||||||
|
Sd/Vf1dhnryIyoS29tzI0DRG94ZKq7tBvmHp1w/jRT4KcSVnovhW9e5Rs74+SRFhr06PKI
|
||||||
|
S+wQOIv48Nwue9+QUMsMCpWgKXHx7SHNTHvnAfqdhi9O29SWlMA+v+mELZ5Cl+HU0UTt2I
|
||||||
|
A1BxOe1N8FjN7KE2viJexsl3is1PuqMkpLl/wyHBJTVzUadl6DRALJQIm7/YO5goE72YOV
|
||||||
|
Lpo27do3zjhC87dlKdATvZUzfKV0LuUVdxq/PNDZMUbBAAAAgQDShAqDZiDrdTUaGXfUVm
|
||||||
|
QzcnVNbh2/KgZh4uux9QNHST562W6cnN7qxoRwVrM4BCOk1Kl73QQZW4nDvXX3PVC5j038
|
||||||
|
8AXkcBHS9j9f4h72ue7D2jqlbHFa7aGU9zYgk9mbBF+GX3tDntkAIQjLtwOLfj1iiJ/clX
|
||||||
|
mHFUAY1V4L8AAAAIEA3E4t/v0yU5D9AOI0r17UNYqfeyDoKAEDR4QbbFjO1l0kLnEJy7Zx
|
||||||
|
Mhj18GilYg2y0P0v8dSM/oWXS8Hua2t5i9Exlv6gHhGlQ80mwYcVGIxewZ/pPeCPw0U+kt
|
||||||
|
EKUjt09m9Oe7+6xHQsTBj9hY8/vqPmQwRalZFcLdhHiDiVKTcAAACBANtykaPXdVzEFx7D
|
||||||
|
UOlsjVL7zM0EVOFXf9JJQ6BhazhmsEI2PYt3IpgGMo8cXkoUofAOIYjf421AabN1BqSO5J
|
||||||
|
XTMxM0ZV3JmLLi804Mu9h1iFrVTBdLYOMJdc2VCo1EwHWpo9SXOyjxce/znvcIOU04aZhu
|
||||||
|
TaPg816X+E+gw5JhAAAAFGRhdmVARGF2ZVJpY2hlci1JTUVYAQIDBAUG
|
||||||
|
-----END OPENSSH PRIVATE KEY-----
|
||||||
1
certs/id_rsa.pub
Normal file
1
certs/id_rsa.pub
Normal file
@@ -0,0 +1 @@
|
|||||||
|
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC82Xl+5WYs2/vYFk3GdOpfkId/leLxTGNhpjEchNILHtuWeGlVgt2pe9w5ZfNux+NyH916fvdCJbifYVjPvmgYyFQaU5jN1YoD0j1KPT1DLVHTpGHAOJkZ3mpoyzAR5emQ2aLa7hB3aQl4N9RBSKCMLT1XzU7++ueIa1AAlJx+Ib+K12b5R+fT1ngxiTQdaOqIOiQ0SySgQ+yJtgitv5Dq9224+Rk77BT+yZeE+2DDlJPqhB2ab+BU2xGDlc3PGuKt77PUZZq2edUveE+ed+md/xbnz13KazsYYnCE96tIZM3VufRPj70Lr0J3ssEm3GK4V1GZ2UYsss9FHjxG6vvX dave@DaveRicher-IMEX
|
||||||
28
certs/key.pem
Normal file
28
certs/key.pem
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
-----BEGIN PRIVATE KEY-----
|
||||||
|
MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCkndJezSQjQcL7
|
||||||
|
T1PnVT0JLXoNAHwt7BqkZ2TELXgkVWtqCIAuDaBdwPQSv8h2xWRduTp103JOb83P
|
||||||
|
Mm97+953X0w/QEijaImmRPOPxhQbMapSkfHLNKlcM7gLHYozL75TDzZTEchNUW+5
|
||||||
|
0eh1xpD1zcsYDJKNNzVz5LyI3vc0bnZtC3/C+Kv4T8j5EuzK5v7kHwACXvsRXLqZ
|
||||||
|
BF9l2O69MdQvs+hPJQNVHLoSt0h3VuwlmKqdb1Of3Z51Il8AmhogumNWwiQdKQwF
|
||||||
|
SEs8tyVA3SDWXYqhkfsvIaN6bLQoX9pqf++rNzfXhvSgP6mhSgaxpNj7wqGfPwI9
|
||||||
|
WjLEWBRxAgMBAAECggEAUNpHYlLFxh9dokujPUMreF+Cy/IKDBAkQc2au5RNpyLh
|
||||||
|
YDIOqw/8TTAhcTgLQPLQygvZP9f8E7RsVLFD+pSJ/v2qmIJ9au1Edor1Sg+S/oxV
|
||||||
|
SLrwFMunx2aLpcH7iAqSI3+cQg7A3+D4zD7iOz6tIl3Su9wo+v073tFhHKTOrEwv
|
||||||
|
Qgr9Jf3viIiKV1ym+uQEVQndocfsj46FnFpXTQ2qs7kAF6FgAOLDGfQQwzkiqEBD
|
||||||
|
NsqsDmbYIx6foZL+DEz1ZVO2M5B+xxpbNK82KwuQilVpimW8ui4LZHCe+RIFzt9+
|
||||||
|
BK6KGlLpSEwTFliivI3nahy18JzskZsfyah0CPZlQQKBgQDVv+A0qIPGvOP3Sx+9
|
||||||
|
HyeQCV23SkvvSvw8p8pMB0gvwv63YdJ7N/rJzBGS6YUHFWWZZgEeTgkJ6VJvoe0r
|
||||||
|
8JL1el9uSUa7f0eayjmFBOGuzpktNVdIn2Tg7A9MWA4JqPNNC69RMOh86ewGD4J3
|
||||||
|
a8Hz2a1bHxAmy/AZt2ukypY6eQKBgQDFJ7kqeOPkRBz9WbALRgVIXo8YWf5di0sQ
|
||||||
|
r0HC03GAISHQ725A2IFBPHJWeqj0jaMiIZD0y+Obgp7KAskrJaLfsd7Ug775kFfw
|
||||||
|
oUI9UAl6kRuPKvm3BaVAm46SQm+56VsgxTi73YN0NUp75THHZgAJjepF9zSpVJxq
|
||||||
|
VY9DjEGruQKBgQCQCpGIatcCol/tUg69X7VFd0pULhkl1J5OMbQ9r9qRdRI5eg5h
|
||||||
|
QsQaIQ7mtb8TmvOwf/DY/zVQHI+U8sXlCmW+TwzoQTENQSR7xzMj1LpRFqBaustr
|
||||||
|
AR72A537kItFLzll/i3SxOam5uxK2UDOQSuerF4KPdCglGXkrpo3nt3F4QKBgQCa
|
||||||
|
RArPAOjQo7tLQfJN3+wiRFsTYtd1uphx5bA/EdOtvj8HjVFnzADXWsTchf3N3UXY
|
||||||
|
XwtdgGwIMpys1KEz8a8P+c2x26SDAj7NOmDqOMYx8Xju/WGHpBM6Cn30U6e4gK+d
|
||||||
|
ZLSPyzQgqdIuP5hDvbwpvbGiLVw3Ys1BJtGCuSxpgQJ/eHnRiuSi5Zq5jGg+GpA+
|
||||||
|
FEEc9NCy772rR+4uzEOqyIwqewffqzSuVWuIsY/8MP3fh+NDxl/mU6cB5QVeD54Z
|
||||||
|
JZUKwmpM26muiM6WvVnM4ExPdSGA2+l4pZjby/KKd6F/w0tgZ1jb9Pb2/0vN3qVA
|
||||||
|
Y4U4XNTMt2fxUACqiL4SHA==
|
||||||
|
-----END PRIVATE KEY-----
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
VITE_APP_GRAPHQL_ENDPOINT=https://db.dev.bodyshop.app/v1/graphql
|
VITE_APP_GRAPHQL_ENDPOINT=https://db.dev.imex.online/v1/graphql
|
||||||
VITE_APP_GRAPHQL_ENDPOINT_WS=wss://db.dev.bodyshop.app/v1/graphql
|
VITE_APP_GRAPHQL_ENDPOINT_WS=wss://db.dev.imex.online/v1/graphql
|
||||||
VITE_APP_GA_CODE=231099835
|
VITE_APP_GA_CODE=231099835
|
||||||
VITE_APP_FIREBASE_CONFIG={"apiKey":"AIzaSyDPLT8GiDHDR1R4nI66Qi0BY1aYviDPioc","authDomain":"imex-dev.firebaseapp.com","databaseURL":"https://imex-dev.firebaseio.com","projectId":"imex-dev","storageBucket":"imex-dev.appspot.com","messagingSenderId":"759548147434","appId":"1:759548147434:web:e8239868a48ceb36700993","measurementId":"G-K5XRBVVB4S"}
|
VITE_APP_FIREBASE_CONFIG={"apiKey":"AIzaSyDPLT8GiDHDR1R4nI66Qi0BY1aYviDPioc","authDomain":"imex-dev.firebaseapp.com","databaseURL":"https://imex-dev.firebaseio.com","projectId":"imex-dev","storageBucket":"imex-dev.appspot.com","messagingSenderId":"759548147434","appId":"1:759548147434:web:e8239868a48ceb36700993","measurementId":"G-K5XRBVVB4S"}
|
||||||
VITE_APP_CLOUDINARY_ENDPOINT_API=https://api.cloudinary.com/v1_1/io-test
|
VITE_APP_CLOUDINARY_ENDPOINT_API=https://api.cloudinary.com/v1_1/io-test
|
||||||
@@ -8,7 +8,7 @@ VITE_APP_CLOUDINARY_API_KEY=957865933348715
|
|||||||
VITE_APP_CLOUDINARY_THUMB_TRANSFORMATIONS=c_fill,h_250,w_250
|
VITE_APP_CLOUDINARY_THUMB_TRANSFORMATIONS=c_fill,h_250,w_250
|
||||||
VITE_APP_FIREBASE_PUBLIC_VAPID_KEY='BG3tzU7L2BXlGZ_3VLK4PNaRceoEXEnmHfxcVbRMF5o5g05ejslhVPki9kBM9cBBT-08Ad9kN3HSpS6JmrWD6h4'
|
VITE_APP_FIREBASE_PUBLIC_VAPID_KEY='BG3tzU7L2BXlGZ_3VLK4PNaRceoEXEnmHfxcVbRMF5o5g05ejslhVPki9kBM9cBBT-08Ad9kN3HSpS6JmrWD6h4'
|
||||||
VITE_APP_STRIPE_PUBLIC_KEY=pk_test_51GqB4TJl3nQjrZ0wCQWAxAhlNF8jKe0tipIa6ExBaxwJGitwvFsIZUEua4dUzaMIAuXp4qwYHXx7lgjyQSwP0Pe900vzm38C7g
|
VITE_APP_STRIPE_PUBLIC_KEY=pk_test_51GqB4TJl3nQjrZ0wCQWAxAhlNF8jKe0tipIa6ExBaxwJGitwvFsIZUEua4dUzaMIAuXp4qwYHXx7lgjyQSwP0Pe900vzm38C7g
|
||||||
VITE_APP_AXIOS_BASE_API_URL=http://localhost:4000
|
VITE_APP_AXIOS_BASE_API_URL=/api/
|
||||||
VITE_APP_REPORTS_SERVER_URL=https://reports3.test.imex.online
|
VITE_APP_REPORTS_SERVER_URL=https://reports3.test.imex.online
|
||||||
VITE_APP_SPLIT_API=ts615lqgnmk84thn72uk18uu5pgce6e0l4rc
|
VITE_APP_SPLIT_API=ts615lqgnmk84thn72uk18uu5pgce6e0l4rc
|
||||||
VITE_APP_INSTANCE=IMEX
|
VITE_APP_INSTANCE=IMEX
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
VITE_APP_GRAPHQL_ENDPOINT=https://db.dev.bodyshop.app/v1/graphql
|
VITE_APP_GRAPHQL_ENDPOINT=https://db.dev.imex.online/v1/graphql
|
||||||
VITE_APP_GRAPHQL_ENDPOINT_WS=wss://db.dev.bodyshop.app/v1/graphql
|
VITE_APP_GRAPHQL_ENDPOINT_WS=wss://db.dev.imex.online/v1/graphql
|
||||||
VITE_APP_GA_CODE=231099835
|
VITE_APP_GA_CODE=231099835
|
||||||
VITE_APP_FIREBASE_CONFIG={"apiKey":"AIzaSyDPLT8GiDHDR1R4nI66Qi0BY1aYviDPioc","authDomain":"imex-dev.firebaseapp.com","databaseURL":"https://imex-dev.firebaseio.com","projectId":"imex-dev","storageBucket":"imex-dev.appspot.com","messagingSenderId":"759548147434","appId":"1:759548147434:web:e8239868a48ceb36700993","measurementId":"G-K5XRBVVB4S"}
|
VITE_APP_FIREBASE_CONFIG={"apiKey":"AIzaSyDPLT8GiDHDR1R4nI66Qi0BY1aYviDPioc","authDomain":"imex-dev.firebaseapp.com","databaseURL":"https://imex-dev.firebaseio.com","projectId":"imex-dev","storageBucket":"imex-dev.appspot.com","messagingSenderId":"759548147434","appId":"1:759548147434:web:e8239868a48ceb36700993","measurementId":"G-K5XRBVVB4S"}
|
||||||
VITE_APP_CLOUDINARY_ENDPOINT_API=https://api.cloudinary.com/v1_1/io-test
|
VITE_APP_CLOUDINARY_ENDPOINT_API=https://api.cloudinary.com/v1_1/io-test
|
||||||
@@ -8,7 +8,7 @@ VITE_APP_CLOUDINARY_API_KEY=957865933348715
|
|||||||
VITE_APP_CLOUDINARY_THUMB_TRANSFORMATIONS=c_fill,h_250,w_250
|
VITE_APP_CLOUDINARY_THUMB_TRANSFORMATIONS=c_fill,h_250,w_250
|
||||||
VITE_APP_FIREBASE_PUBLIC_VAPID_KEY='BG3tzU7L2BXlGZ_3VLK4PNaRceoEXEnmHfxcVbRMF5o5g05ejslhVPki9kBM9cBBT-08Ad9kN3HSpS6JmrWD6h4'
|
VITE_APP_FIREBASE_PUBLIC_VAPID_KEY='BG3tzU7L2BXlGZ_3VLK4PNaRceoEXEnmHfxcVbRMF5o5g05ejslhVPki9kBM9cBBT-08Ad9kN3HSpS6JmrWD6h4'
|
||||||
VITE_APP_STRIPE_PUBLIC_KEY=pk_test_51GqB4TJl3nQjrZ0wCQWAxAhlNF8jKe0tipIa6ExBaxwJGitwvFsIZUEua4dUzaMIAuXp4qwYHXx7lgjyQSwP0Pe900vzm38C7g
|
VITE_APP_STRIPE_PUBLIC_KEY=pk_test_51GqB4TJl3nQjrZ0wCQWAxAhlNF8jKe0tipIa6ExBaxwJGitwvFsIZUEua4dUzaMIAuXp4qwYHXx7lgjyQSwP0Pe900vzm38C7g
|
||||||
VITE_APP_AXIOS_BASE_API_URL=http://localhost:4000
|
VITE_APP_AXIOS_BASE_API_URL=/api/
|
||||||
VITE_APP_REPORTS_SERVER_URL=https://reports3.test.imex.online
|
VITE_APP_REPORTS_SERVER_URL=https://reports3.test.imex.online
|
||||||
VITE_APP_SPLIT_API=ts615lqgnmk84thn72uk18uu5pgce6e0l4rc
|
VITE_APP_SPLIT_API=ts615lqgnmk84thn72uk18uu5pgce6e0l4rc
|
||||||
VITE_APP_INSTANCE=PROMANAGER
|
VITE_APP_INSTANCE=PROMANAGER
|
||||||
|
|||||||
@@ -1,14 +1,15 @@
|
|||||||
VITE_APP_GRAPHQL_ENDPOINT=https://db.dev.bodyshop.app/v1/graphql
|
VITE_APP_GRAPHQL_ENDPOINT=https://db.dev.imex.online/v1/graphql
|
||||||
VITE_APP_GRAPHQL_ENDPOINT_WS=wss://db.dev.bodyshop.app/v1/graphql
|
VITE_APP_GRAPHQL_ENDPOINT_WS=wss://db.dev.imex.online/v1/graphql
|
||||||
VITE_APP_GA_CODE=231099835
|
VITE_APP_GA_CODE=231099835
|
||||||
VITE_APP_FIREBASE_CONFIG={ "apiKey": "AIzaSyAuLQR9SV5LsVxjU8wh9hvFLdhcAHU6cxE", "authDomain": "rome-prod-1.firebaseapp.com", "projectId": "rome-prod-1", "storageBucket": "rome-prod-1.appspot.com", "messagingSenderId": "147786367145", "appId": "1:147786367145:web:9d4cba68071c3f29a8a9b8", "measurementId": "G-G8Z9DRHTZS"}
|
# VITE_APP_FIREBASE_CONFIG={ "apiKey": "AIzaSyAuLQR9SV5LsVxjU8wh9hvFLdhcAHU6cxE", "authDomain": "rome-prod-1.firebaseapp.com", "projectId": "rome-prod-1", "storageBucket": "rome-prod-1.appspot.com", "messagingSenderId": "147786367145", "appId": "1:147786367145:web:9d4cba68071c3f29a8a9b8", "measurementId": "G-G8Z9DRHTZS"}
|
||||||
|
VITE_APP_FIREBASE_CONFIG={"apiKey":"AIzaSyDPLT8GiDHDR1R4nI66Qi0BY1aYviDPioc","authDomain":"imex-dev.firebaseapp.com","databaseURL":"https://imex-dev.firebaseio.com","projectId":"imex-dev","storageBucket":"imex-dev.appspot.com","messagingSenderId":"759548147434","appId":"1:759548147434:web:e8239868a48ceb36700993","measurementId":"G-K5XRBVVB4S"}
|
||||||
VITE_APP_CLOUDINARY_ENDPOINT_API=https://api.cloudinary.com/v1_1/io-test
|
VITE_APP_CLOUDINARY_ENDPOINT_API=https://api.cloudinary.com/v1_1/io-test
|
||||||
VITE_APP_CLOUDINARY_ENDPOINT=https://res.cloudinary.com/io-test
|
VITE_APP_CLOUDINARY_ENDPOINT=https://res.cloudinary.com/io-test
|
||||||
VITE_APP_CLOUDINARY_API_KEY=957865933348715
|
VITE_APP_CLOUDINARY_API_KEY=957865933348715
|
||||||
VITE_APP_CLOUDINARY_THUMB_TRANSFORMATIONS=c_fill,h_250,w_250
|
VITE_APP_CLOUDINARY_THUMB_TRANSFORMATIONS=c_fill,h_250,w_250
|
||||||
VITE_APP_FIREBASE_PUBLIC_VAPID_KEY='BP1B7ZTYpn-KMt6nOxlld6aS8Skt3Q7ZLEqP0hAvGHxG4UojPYiXZ6kPlzZkUC5jH-EcWXomTLtmadAIxurfcHo'
|
VITE_APP_FIREBASE_PUBLIC_VAPID_KEY='BP1B7ZTYpn-KMt6nOxlld6aS8Skt3Q7ZLEqP0hAvGHxG4UojPYiXZ6kPlzZkUC5jH-EcWXomTLtmadAIxurfcHo'
|
||||||
VITE_APP_STRIPE_PUBLIC_KEY=pk_test_51GqB4TJl3nQjrZ0wCQWAxAhlNF8jKe0tipIa6ExBaxwJGitwvFsIZUEua4dUzaMIAuXp4qwYHXx7lgjyQSwP0Pe900vzm38C7g
|
VITE_APP_STRIPE_PUBLIC_KEY=pk_test_51GqB4TJl3nQjrZ0wCQWAxAhlNF8jKe0tipIa6ExBaxwJGitwvFsIZUEua4dUzaMIAuXp4qwYHXx7lgjyQSwP0Pe900vzm38C7g
|
||||||
VITE_APP_AXIOS_BASE_API_URL=http://localhost:4000
|
VITE_APP_AXIOS_BASE_API_URL=/api/
|
||||||
VITE_APP_REPORTS_SERVER_URL=https://reports3.test.imex.online
|
VITE_APP_REPORTS_SERVER_URL=https://reports3.test.imex.online
|
||||||
VITE_APP_SPLIT_API=ts615lqgnmk84thn72uk18uu5pgce6e0l4rc
|
VITE_APP_SPLIT_API=ts615lqgnmk84thn72uk18uu5pgce6e0l4rc
|
||||||
VITE_APP_COUNTRY=USA
|
VITE_APP_COUNTRY=USA
|
||||||
|
|||||||
1
client/.gitignore
vendored
1
client/.gitignore
vendored
@@ -1,3 +1,4 @@
|
|||||||
|
|
||||||
# Sentry Config File
|
# Sentry Config File
|
||||||
.sentryclirc
|
.sentryclirc
|
||||||
|
/dev-dist
|
||||||
|
|||||||
@@ -1,53 +0,0 @@
|
|||||||
// craco.config.js
|
|
||||||
const TerserPlugin = require("terser-webpack-plugin");
|
|
||||||
const CracoLessPlugin = require("craco-less");
|
|
||||||
const { convertLegacyToken } = require("@ant-design/compatible/lib");
|
|
||||||
const { theme } = require("antd/lib");
|
|
||||||
|
|
||||||
const { defaultAlgorithm, defaultSeed } = theme;
|
|
||||||
|
|
||||||
const mapToken = defaultAlgorithm(defaultSeed);
|
|
||||||
const v4Token = convertLegacyToken(mapToken);
|
|
||||||
|
|
||||||
// TODO, At the moment we are using less in the Dashboard. Once we remove this we can remove the less processor entirely.
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
plugins: [
|
|
||||||
{
|
|
||||||
plugin: CracoLessPlugin,
|
|
||||||
options: {
|
|
||||||
lessLoaderOptions: {
|
|
||||||
lessOptions: {
|
|
||||||
modifyVars: { ...v4Token },
|
|
||||||
javascriptEnabled: true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
webpack: {
|
|
||||||
configure: (webpackConfig) => {
|
|
||||||
return {
|
|
||||||
...webpackConfig,
|
|
||||||
// Required for Dev Server
|
|
||||||
devServer: {
|
|
||||||
...webpackConfig.devServer,
|
|
||||||
allowedHosts: "all"
|
|
||||||
},
|
|
||||||
optimization: {
|
|
||||||
...webpackConfig.optimization,
|
|
||||||
// Workaround for CircleCI bug caused by the number of CPUs shown
|
|
||||||
// https://github.com/facebook/create-react-app/issues/8320
|
|
||||||
minimizer: webpackConfig.optimization.minimizer.map((item) => {
|
|
||||||
if (item instanceof TerserPlugin) {
|
|
||||||
item.options.parallel = 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
return item;
|
|
||||||
})
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
},
|
|
||||||
devtool: "source-map"
|
|
||||||
};
|
|
||||||
@@ -12,6 +12,6 @@ module.exports = defineConfig({
|
|||||||
setupNodeEvents(on, config) {
|
setupNodeEvents(on, config) {
|
||||||
return require("./cypress/plugins/index.js")(on, config);
|
return require("./cypress/plugins/index.js")(on, config);
|
||||||
},
|
},
|
||||||
baseUrl: "http://localhost:3000"
|
baseUrl: "https://localhost:3000"
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/// <reference types="cypress" />
|
/// <reference types="cypress" />
|
||||||
// ***********************************************************
|
// ***********************************************************
|
||||||
// This example plugins/index.js can be used to load plugins
|
// This example plugins/index.jsx can be used to load plugins
|
||||||
//
|
//
|
||||||
// You can change the location of this file or turn off loading
|
// You can change the location of this file or turn off loading
|
||||||
// the plugins file with the 'pluginsFile' configuration option.
|
// the plugins file with the 'pluginsFile' configuration option.
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
// ***********************************************************
|
// ***********************************************************
|
||||||
// This example support/index.js is processed and
|
// This example support/index.jsx is processed and
|
||||||
// loaded automatically before your test files.
|
// loaded automatically before your test files.
|
||||||
//
|
//
|
||||||
// This is a great place to put global configuration and
|
// This is a great place to put global configuration and
|
||||||
|
|||||||
@@ -1,174 +1,126 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8" />
|
<meta charset="utf-8"/>
|
||||||
<% if (env.VITE_APP_INSTANCE === 'IMEX') { %>
|
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate">
|
||||||
<link rel="icon" href="/favicon.png" />
|
<meta http-equiv="Pragma" content="no-cache">
|
||||||
<% } %> <% if (env.VITE_APP_INSTANCE === 'ROME') { %>
|
<meta http-equiv="Expires" content="0">
|
||||||
<link rel="icon" href="/ro-favicon.png" />
|
<% if (env.VITE_APP_INSTANCE === 'IMEX') { %>
|
||||||
<% } %> <% if (env.VITE_APP_INSTANCE === 'PROMANAGER') { %>
|
<link rel="icon" href="/favicon.png"/>
|
||||||
<link rel="icon" href="/pm/pm-favicon.ico" />
|
<% } %> <% if (env.VITE_APP_INSTANCE === 'ROME') { %>
|
||||||
<% } %>
|
<link rel="icon" href="/ro-favicon.png"/>
|
||||||
|
<% } %> <% if (env.VITE_APP_INSTANCE === 'PROMANAGER') { %>
|
||||||
|
<link rel="icon" href="/pm/pm-favicon.ico"/>
|
||||||
|
<% } %>
|
||||||
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
<meta name="viewport" content="width=device-width, initial-scale=1"/>
|
||||||
<meta name="theme-color" content="#1690ff" />
|
<meta name="theme-color" content="#1690ff"/>
|
||||||
<!-- <link rel="apple-touch-icon" href="logo192.png" /> -->
|
<!-- <link rel="apple-touch-icon" href="logo192.png" /> -->
|
||||||
<!-- TODO:AIo Update the individual logos for each.-->
|
<!-- TODO:AIo Update the individual logos for each.-->
|
||||||
<link rel="apple-touch-icon" href="public/logo192.png" />
|
<link rel="apple-touch-icon" href="/logo192.png"/>
|
||||||
<link rel="mask-icon" href="/mask-icon.svg" color="#FFFFFF">
|
<link rel="mask-icon" href="/mask-icon.svg" color="#FFFFFF">
|
||||||
<!--
|
<!--
|
||||||
manifest.json provides metadata used when your web app is installed on a
|
manifest.json provides metadata used when your web app is installed on a
|
||||||
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
|
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
|
||||||
-->
|
-->
|
||||||
<!--
|
<!--
|
||||||
Notice the use of %PUBLIC_URL% in the tags above.
|
Notice the use of %PUBLIC_URL% in the tags above.
|
||||||
It will be replaced with the URL of the `public` folder during the build.
|
It will be replaced with the URL of the `public` folder during the build.
|
||||||
Only files inside the `public` folder can be referenced from the HTML.
|
Only files inside the `public` folder can be referenced from the HTML.
|
||||||
|
|
||||||
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
|
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
|
||||||
work correctly both with client-side routing and a non-root public URL.
|
work correctly both with client-side routing and a non-root public URL.
|
||||||
Learn how to configure a non-root public URL by running `npm run build`.
|
Learn how to configure a non-root public URL by running `npm run build`.
|
||||||
-->
|
-->
|
||||||
<% if (env.VITE_APP_INSTANCE === 'IMEX') { %>
|
<% if (env.VITE_APP_INSTANCE === 'IMEX') { %>
|
||||||
<meta name="description" content="ImEX Online" />
|
<meta name="description" content="ImEX Online"/>
|
||||||
<title>ImEX Online</title>
|
<title>ImEX Online</title>
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
window.$crisp = [];
|
window.$crisp = [];
|
||||||
window.CRISP_WEBSITE_ID = '36724f62-2eb0-4b29-9cdd-9905fb99913e';
|
window.CRISP_WEBSITE_ID = '36724f62-2eb0-4b29-9cdd-9905fb99913e';
|
||||||
(function () {
|
(function () {
|
||||||
d = document;
|
d = document;
|
||||||
s = d.createElement('script');
|
s = d.createElement('script');
|
||||||
s.src = 'https://client.crisp.chat/l.js';
|
s.src = 'https://client.crisp.chat/l.js';
|
||||||
s.async = 1;
|
s.async = 1;
|
||||||
d.getElementsByTagName('head')[0].appendChild(s);
|
d.getElementsByTagName('head')[0].appendChild(s);
|
||||||
})();
|
})();
|
||||||
</script>
|
</script>
|
||||||
<% } %> <% if (env.VITE_APP_INSTANCE === 'ROME') { %>
|
<% } %> <% if (env.VITE_APP_INSTANCE === 'ROME') { %>
|
||||||
<meta name="description" content="Rome Online" />
|
<meta name="description" content="Rome Online"/>
|
||||||
<title>Rome Online</title>
|
<title>Rome Online</title>
|
||||||
|
<script type="text/javascript" id="zsiqchat">
|
||||||
|
var $zoho = $zoho || {};
|
||||||
|
$zoho.salesiq = $zoho.salesiq || {
|
||||||
|
widgetcode: "siq01bb8ac617280bdacddfeb528f07734dadc64ef3f05efef9f769c1ec171af666",
|
||||||
|
values: {},
|
||||||
|
ready: function () {
|
||||||
|
}
|
||||||
|
};
|
||||||
|
var d = document;
|
||||||
|
s = d.createElement("script");
|
||||||
|
s.type = "text/javascript";
|
||||||
|
s.id = "zsiqscript";
|
||||||
|
s.defer = true;
|
||||||
|
s.src = "https://salesiq.zohopublic.com/widget";
|
||||||
|
t = d.getElementsByTagName("script")[0];
|
||||||
|
t.parentNode.insertBefore(s, t);
|
||||||
|
</script>
|
||||||
|
|
||||||
<!--Use the below code snippet to provide real time updates to the live chat plugin without the need of copying and paste each time to your website when changes are made via PBX-->
|
<% } %> <% if (env.VITE_APP_INSTANCE === 'PROMANAGER') { %>
|
||||||
|
<title>ProManager</title>
|
||||||
|
<meta name="description" content="ProManager"/>
|
||||||
|
|
||||||
<call-us-selector phonesystem-url=https://rometech.east.3cx.us:5001 party="LiveChat528346"></call-us-selector>
|
<% } %>
|
||||||
|
<script>
|
||||||
|
!(function () {
|
||||||
|
'use strict';
|
||||||
|
var e = [
|
||||||
|
'debug',
|
||||||
|
'destroy',
|
||||||
|
'do',
|
||||||
|
'help',
|
||||||
|
'identify',
|
||||||
|
'is',
|
||||||
|
'off',
|
||||||
|
'on',
|
||||||
|
'ready',
|
||||||
|
'render',
|
||||||
|
'reset',
|
||||||
|
'safe',
|
||||||
|
'set',
|
||||||
|
];
|
||||||
|
if (window.noticeable) console.warn('Noticeable SDK code snippet loaded more than once');
|
||||||
|
else {
|
||||||
|
var n = (window.noticeable = window.noticeable || []);
|
||||||
|
|
||||||
<!--Incase you don't want real time updates to the live chat plugin when options are changed, use the below code snippet. Please note that each time you change the settings you will need to copy and paste the snippet code to your website-->
|
function t(e) {
|
||||||
|
return function () {
|
||||||
<!--<call-us
|
var t = Array.prototype.slice.call(arguments);
|
||||||
|
return t.unshift(e), n.push(t), n;
|
||||||
phonesystem-url=https://rometech.east.3cx.us:5001
|
};
|
||||||
|
|
||||||
style="position:fixed;font-size:16px;line-height:17px;z-index: 99999;right: 20px; bottom: 20px;"
|
|
||||||
|
|
||||||
id="wp-live-chat-by-3CX"
|
|
||||||
|
|
||||||
minimized="true"
|
|
||||||
|
|
||||||
animation-style="noanimation"
|
|
||||||
|
|
||||||
party="LiveChat528346"
|
|
||||||
|
|
||||||
minimized-style="bubbleright"
|
|
||||||
|
|
||||||
allow-call="true"
|
|
||||||
|
|
||||||
allow-video="false"
|
|
||||||
|
|
||||||
allow-soundnotifications="true"
|
|
||||||
|
|
||||||
enable-mute="true"
|
|
||||||
|
|
||||||
enable-onmobile="true"
|
|
||||||
|
|
||||||
offline-enabled="true"
|
|
||||||
|
|
||||||
enable="true"
|
|
||||||
|
|
||||||
ignore-queueownership="false"
|
|
||||||
|
|
||||||
authentication="both"
|
|
||||||
|
|
||||||
show-operator-actual-name="true"
|
|
||||||
|
|
||||||
aknowledge-received="true"
|
|
||||||
|
|
||||||
gdpr-enabled="false"
|
|
||||||
|
|
||||||
message-userinfo-format="name"
|
|
||||||
|
|
||||||
message-dateformat="both"
|
|
||||||
|
|
||||||
lang="browser"
|
|
||||||
|
|
||||||
button-icon-type="default"
|
|
||||||
|
|
||||||
greeting-visibility="none"
|
|
||||||
|
|
||||||
greeting-offline-visibility="none"
|
|
||||||
|
|
||||||
chat-delay="2000"
|
|
||||||
|
|
||||||
enable-direct-call="true"
|
|
||||||
|
|
||||||
enable-ga="false"
|
|
||||||
|
|
||||||
></call-us>-->
|
|
||||||
|
|
||||||
<script defer src=https://downloads-global.3cx.com/downloads/livechatandtalk/v1/callus.js id="tcx-callus-js" charset="utf-8"></script>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<% } %> <% if (env.VITE_APP_INSTANCE === 'PROMANAGER') { %>
|
|
||||||
<title>ProManager</title>
|
|
||||||
<meta name="description" content="ProManager" />
|
|
||||||
|
|
||||||
<% } %>
|
|
||||||
<script>
|
|
||||||
!(function () {
|
|
||||||
'use strict';
|
|
||||||
var e = [
|
|
||||||
'debug',
|
|
||||||
'destroy',
|
|
||||||
'do',
|
|
||||||
'help',
|
|
||||||
'identify',
|
|
||||||
'is',
|
|
||||||
'off',
|
|
||||||
'on',
|
|
||||||
'ready',
|
|
||||||
'render',
|
|
||||||
'reset',
|
|
||||||
'safe',
|
|
||||||
'set',
|
|
||||||
];
|
|
||||||
if (window.noticeable) console.warn('Noticeable SDK code snippet loaded more than once');
|
|
||||||
else {
|
|
||||||
var n = (window.noticeable = window.noticeable || []);
|
|
||||||
function t(e) {
|
|
||||||
return function () {
|
|
||||||
var t = Array.prototype.slice.call(arguments);
|
|
||||||
return t.unshift(e), n.push(t), n;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
!(function () {
|
|
||||||
for (var o = 0; o < e.length; o++) {
|
|
||||||
var r = e[o];
|
|
||||||
n[r] = t(r);
|
|
||||||
}
|
|
||||||
})(),
|
|
||||||
(function () {
|
|
||||||
var e = document.createElement('script');
|
|
||||||
(e.async = !0), (e.src = 'https://sdk.noticeable.io/l.js');
|
|
||||||
var n = document.head;
|
|
||||||
n.insertBefore(e, n.firstChild);
|
|
||||||
})();
|
|
||||||
}
|
}
|
||||||
})();
|
|
||||||
</script>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<noscript>You need to enable JavaScript to run this app.</noscript>
|
|
||||||
<div id="root"></div>
|
|
||||||
|
|
||||||
<script type="module" src="src/index.jsx"></script>
|
!(function () {
|
||||||
</body>
|
for (var o = 0; o < e.length; o++) {
|
||||||
|
var r = e[o];
|
||||||
|
n[r] = t(r);
|
||||||
|
}
|
||||||
|
})(),
|
||||||
|
(function () {
|
||||||
|
var e = document.createElement('script');
|
||||||
|
(e.async = !0), (e.src = 'https://sdk.noticeable.io/l.js');
|
||||||
|
var n = document.head;
|
||||||
|
n.insertBefore(e, n.firstChild);
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||||
|
<div id="root"></div>
|
||||||
|
|
||||||
|
<script type="module" src="src/index.jsx"></script>
|
||||||
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
22768
client/package-lock.json
generated
22768
client/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -2,93 +2,98 @@
|
|||||||
"name": "bodyshop",
|
"name": "bodyshop",
|
||||||
"version": "0.2.1",
|
"version": "0.2.1",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "18.18.2"
|
"node": ">=18.18.2"
|
||||||
},
|
},
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"private": true,
|
"private": true,
|
||||||
"proxy": "http://localhost:4000",
|
"proxy": "http://localhost:4000",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@ant-design/compatible": "^5.1.2",
|
"@ant-design/pro-layout": "^7.19.12",
|
||||||
"@ant-design/pro-layout": "^7.17.16",
|
"@apollo/client": "^3.11.8",
|
||||||
"@apollo/client": "^3.8.10",
|
"@emotion/is-prop-valid": "^1.3.1",
|
||||||
"@asseinfo/react-kanban": "^2.2.0",
|
"@fingerprintjs/fingerprintjs": "^4.5.0",
|
||||||
"@fingerprintjs/fingerprintjs": "^4.2.2",
|
|
||||||
"@jsreport/browser-client": "^3.1.0",
|
"@jsreport/browser-client": "^3.1.0",
|
||||||
"@reduxjs/toolkit": "^2.2.1",
|
"@reduxjs/toolkit": "^2.2.7",
|
||||||
"@sentry/cli": "^2.28.6",
|
"@sentry/cli": "^2.36.2",
|
||||||
"@sentry/react": "^7.104.0",
|
"@sentry/react": "^7.114.0",
|
||||||
"@splitsoftware/splitio-react": "^1.11.0",
|
"@splitsoftware/splitio-react": "^1.13.0",
|
||||||
"@tanem/react-nprogress": "^5.0.51",
|
"@tanem/react-nprogress": "^5.0.51",
|
||||||
"@vitejs/plugin-react": "^4.2.1",
|
"@vitejs/plugin-react": "^4.3.1",
|
||||||
"antd": "^5.15.3",
|
"antd": "^5.20.1",
|
||||||
"apollo-link-logger": "^2.0.1",
|
"apollo-link-logger": "^2.0.1",
|
||||||
"apollo-link-sentry": "^3.3.0",
|
"apollo-link-sentry": "^3.3.0",
|
||||||
"axios": "^1.6.7",
|
"autosize": "^6.0.1",
|
||||||
"dayjs": "^1.11.10",
|
"axios": "^1.7.7",
|
||||||
|
"classnames": "^2.5.1",
|
||||||
|
"css-box-model": "^1.2.1",
|
||||||
|
"dayjs": "^1.11.13",
|
||||||
"dayjs-business-days2": "^1.2.2",
|
"dayjs-business-days2": "^1.2.2",
|
||||||
"dinero.js": "^1.9.1",
|
"dinero.js": "^1.9.1",
|
||||||
"dotenv": "^16.4.5",
|
"dotenv": "^16.4.5",
|
||||||
"env-cmd": "^10.1.0",
|
"env-cmd": "^10.1.0",
|
||||||
"exifr": "^7.1.3",
|
"exifr": "^7.1.3",
|
||||||
"firebase": "^10.8.1",
|
"firebase": "^10.13.2",
|
||||||
"graphql": "^16.6.0",
|
"graphql": "^16.9.0",
|
||||||
"i18next": "^23.10.0",
|
"i18next": "^23.15.1",
|
||||||
"i18next-browser-languagedetector": "^7.0.2",
|
"i18next-browser-languagedetector": "^8.0.0",
|
||||||
"libphonenumber-js": "^1.10.57",
|
"immutability-helper": "^3.1.1",
|
||||||
"logrocket": "^8.0.1",
|
"libphonenumber-js": "^1.11.9",
|
||||||
"markerjs2": "^2.32.0",
|
"logrocket": "^8.1.2",
|
||||||
"normalize-url": "^8.0.0",
|
"markerjs2": "^2.32.2",
|
||||||
|
"memoize-one": "^6.0.0",
|
||||||
|
"normalize-url": "^8.0.1",
|
||||||
|
"object-hash": "^3.0.0",
|
||||||
"prop-types": "^15.8.1",
|
"prop-types": "^15.8.1",
|
||||||
"query-string": "^9.0.0",
|
"query-string": "^9.1.0",
|
||||||
"react": "^18.2.0",
|
"raf-schd": "^4.0.3",
|
||||||
"react-big-calendar": "^1.11.0",
|
"react": "^18.3.1",
|
||||||
|
"react-big-calendar": "^1.14.1",
|
||||||
"react-color": "^2.19.3",
|
"react-color": "^2.19.3",
|
||||||
"react-cookie": "^7.1.0",
|
"react-cookie": "^7.2.0",
|
||||||
"react-dom": "^18.2.0",
|
"react-dom": "^18.3.1",
|
||||||
"react-drag-listview": "^2.0.0",
|
"react-drag-listview": "^2.0.0",
|
||||||
"react-grid-gallery": "^1.0.0",
|
"react-grid-gallery": "^1.0.1",
|
||||||
"react-grid-layout": "1.3.4",
|
"react-grid-layout": "1.3.4",
|
||||||
"react-i18next": "^14.0.5",
|
"react-i18next": "^14.1.3",
|
||||||
"react-icons": "^5.0.1",
|
"react-icons": "^5.3.0",
|
||||||
"react-image-lightbox": "^5.1.4",
|
"react-image-lightbox": "^5.1.4",
|
||||||
"react-joyride": "^2.7.4",
|
|
||||||
"react-markdown": "^9.0.1",
|
"react-markdown": "^9.0.1",
|
||||||
"react-number-format": "^5.3.3",
|
"react-number-format": "^5.4.2",
|
||||||
"react-product-fruits": "^2.2.6",
|
"react-popopo": "^2.1.9",
|
||||||
"react-redux": "^9.1.0",
|
"react-product-fruits": "^2.2.61",
|
||||||
|
"react-redux": "^9.1.2",
|
||||||
"react-resizable": "^3.0.5",
|
"react-resizable": "^3.0.5",
|
||||||
"react-router-dom": "^6.22.2",
|
"react-router-dom": "^6.26.2",
|
||||||
"react-scripts": "^5.0.1",
|
|
||||||
"react-sticky": "^6.0.3",
|
"react-sticky": "^6.0.3",
|
||||||
"react-virtualized": "^9.22.5",
|
"react-virtualized": "^9.22.5",
|
||||||
"recharts": "^2.12.2",
|
"react-virtuoso": "^4.10.4",
|
||||||
|
"recharts": "^2.12.7",
|
||||||
"redux": "^5.0.1",
|
"redux": "^5.0.1",
|
||||||
|
"redux-actions": "^3.0.3",
|
||||||
"redux-persist": "^6.0.0",
|
"redux-persist": "^6.0.0",
|
||||||
"redux-saga": "^1.3.0",
|
"redux-saga": "^1.3.0",
|
||||||
"redux-state-sync": "^3.1.4",
|
"redux-state-sync": "^3.1.4",
|
||||||
"reselect": "^5.1.0",
|
"reselect": "^5.1.1",
|
||||||
"sass": "^1.71.1",
|
"sass": "^1.79.3",
|
||||||
"socket.io-client": "^4.7.4",
|
"socket.io-client": "^4.8.0",
|
||||||
"styled-components": "^6.1.8",
|
"styled-components": "^6.1.13",
|
||||||
"subscriptions-transport-ws": "^0.11.0",
|
"subscriptions-transport-ws": "^0.11.0",
|
||||||
"terser-webpack-plugin": "^5.3.10",
|
"use-memo-one": "^1.1.3",
|
||||||
"userpilot": "^1.3.1",
|
"userpilot": "^1.3.6",
|
||||||
"vite-plugin-ejs": "^1.7.0",
|
"vite-plugin-ejs": "^1.7.0",
|
||||||
"web-vitals": "^3.5.2",
|
"web-vitals": "^3.5.2"
|
||||||
"workbox-core": "^7.0.0",
|
|
||||||
"workbox-expiration": "^7.0.0",
|
|
||||||
"workbox-navigation-preload": "^7.0.0",
|
|
||||||
"workbox-precaching": "^7.0.0",
|
|
||||||
"workbox-routing": "^7.0.0",
|
|
||||||
"workbox-strategies": "^7.0.0"
|
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
"postinstall": "echo 'when updating react-big-calendar, remember to check to localizer in the calendar wrapper'",
|
||||||
"analyze": "source-map-explorer 'build/static/js/*.js'",
|
"analyze": "source-map-explorer 'build/static/js/*.js'",
|
||||||
"start": "vite",
|
"start": "vite",
|
||||||
"build": "vite build",
|
"build": "dotenvx run --env-file=.env.development.imex -- vite build",
|
||||||
"start:imex": "dotenvx run --env-file=.env.development.imex -- vite",
|
"start:imex": "dotenvx run --env-file=.env.development.imex -- vite",
|
||||||
"start:rome": "dotenvx run --env-file=.env.development.rome -- vite",
|
"start:rome": "dotenvx run --env-file=.env.development.rome -- vite",
|
||||||
"start:promanager": "dotenvx run --env-file=.env.development.promanager -- vite",
|
"start:promanager": "dotenvx run --env-file=.env.development.promanager -- vite",
|
||||||
|
"preview:imex": "dotenvx run --env-file=.env.development.imex -- vite preview",
|
||||||
|
"preview:rome": "dotenvx run --env-file=.env.development.rome -- vite preview",
|
||||||
|
"preview:promanager": "dotenvx run --env-file=.env.development.promanager -- vite preview",
|
||||||
"build:test:imex": "env-cmd -f .env.test.imex npm run build",
|
"build:test:imex": "env-cmd -f .env.test.imex npm run build",
|
||||||
"build:test:rome": "env-cmd -f .env.test.rome npm run build",
|
"build:test:rome": "env-cmd -f .env.test.rome npm run build",
|
||||||
"build:test:promanager": "env-cmd -f .env.test.promanager npm run build",
|
"build:test:promanager": "env-cmd -f .env.test.promanager npm run build",
|
||||||
@@ -128,32 +133,31 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/plugin-proposal-private-property-in-object": "^7.21.11",
|
"@babel/plugin-proposal-private-property-in-object": "^7.21.11",
|
||||||
"@babel/preset-react": "^7.23.3",
|
"@babel/preset-react": "^7.24.7",
|
||||||
"@dotenvx/dotenvx": "^0.15.4",
|
"@dotenvx/dotenvx": "^1.14.1",
|
||||||
"@emotion/babel-plugin": "^11.11.0",
|
"@emotion/babel-plugin": "^11.12.0",
|
||||||
"@emotion/react": "^11.11.3",
|
"@emotion/react": "^11.13.3",
|
||||||
"@sentry/webpack-plugin": "^2.14.2",
|
"@sentry/webpack-plugin": "^2.22.4",
|
||||||
"@swc/core": "^1.3.107",
|
"@testing-library/cypress": "^10.0.2",
|
||||||
"@swc/plugin-styled-components": "^1.5.108",
|
"browserslist": "^4.23.3",
|
||||||
"@testing-library/cypress": "^10.0.1",
|
|
||||||
"browserslist": "^4.22.3",
|
|
||||||
"browserslist-to-esbuild": "^2.1.1",
|
"browserslist-to-esbuild": "^2.1.1",
|
||||||
|
"chalk": "^5.3.0",
|
||||||
"cross-env": "^7.0.3",
|
"cross-env": "^7.0.3",
|
||||||
"cypress": "^13.6.6",
|
"cypress": "^13.14.2",
|
||||||
"eslint": "^8.57.0",
|
"eslint": "^8.57.0",
|
||||||
"eslint-config-react-app": "^7.0.1",
|
"eslint-config-react-app": "^7.0.1",
|
||||||
"eslint-plugin-cypress": "^2.15.1",
|
"eslint-plugin-cypress": "^2.15.1",
|
||||||
"memfs": "^4.6.0",
|
"memfs": "^4.12.0",
|
||||||
"os-browserify": "^0.3.0",
|
"os-browserify": "^0.3.0",
|
||||||
"react-error-overlay": "6.0.11",
|
"react-error-overlay": "6.0.11",
|
||||||
"redux-logger": "^3.0.6",
|
"redux-logger": "^3.0.6",
|
||||||
"source-map-explorer": "^2.5.3",
|
"source-map-explorer": "^2.5.3",
|
||||||
"vite": "^5.0.11",
|
"vite": "^5.4.7",
|
||||||
"vite-plugin-babel": "^1.2.0",
|
"vite-plugin-babel": "^1.2.0",
|
||||||
"vite-plugin-eslint": "^1.8.1",
|
"vite-plugin-eslint": "^1.8.1",
|
||||||
"vite-plugin-legacy": "^2.1.0",
|
"vite-plugin-node-polyfills": "^0.22.0",
|
||||||
"vite-plugin-node-polyfills": "^0.19.0",
|
"vite-plugin-pwa": "^0.20.5",
|
||||||
"vite-plugin-pwa": "^0.19.0",
|
"vite-plugin-style-import": "^2.0.0",
|
||||||
"vite-plugin-style-import": "^2.0.0"
|
"workbox-window": "^7.1.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16422,7 +16422,7 @@ For when you don't want to write the same thing over and over to cache a method
|
|||||||
$ npm install --save-dev stubs
|
$ npm install --save-dev stubs
|
||||||
```
|
```
|
||||||
```js
|
```js
|
||||||
var mylib = require('./lib/index.js')
|
var mylib = require('./lib/index.jsx')
|
||||||
var stubs = require('stubs')
|
var stubs = require('stubs')
|
||||||
|
|
||||||
// make it a noop
|
// make it a noop
|
||||||
|
|||||||
@@ -16567,7 +16567,7 @@ even more slower.
|
|||||||
## Benchmarks
|
## Benchmarks
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
$ node benchmarks/index.js
|
$ node benchmarks/index.jsx
|
||||||
Benchmarking: sign
|
Benchmarking: sign
|
||||||
elliptic#sign x 262 ops/sec ±0.51% (177 runs sampled)
|
elliptic#sign x 262 ops/sec ±0.51% (177 runs sampled)
|
||||||
eccjs#sign x 55.91 ops/sec ±0.90% (144 runs sampled)
|
eccjs#sign x 55.91 ops/sec ±0.90% (144 runs sampled)
|
||||||
|
|||||||
@@ -2,8 +2,6 @@ import { ApolloProvider } from "@apollo/client";
|
|||||||
import { SplitFactoryProvider, SplitSdk } from "@splitsoftware/splitio-react";
|
import { SplitFactoryProvider, SplitSdk } from "@splitsoftware/splitio-react";
|
||||||
import { ConfigProvider } from "antd";
|
import { ConfigProvider } from "antd";
|
||||||
import enLocale from "antd/es/locale/en_US";
|
import enLocale from "antd/es/locale/en_US";
|
||||||
import dayjs from "../utils/day";
|
|
||||||
import "dayjs/locale/en";
|
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import GlobalLoadingBar from "../components/global-loading-bar/global-loading-bar.component";
|
import GlobalLoadingBar from "../components/global-loading-bar/global-loading-bar.component";
|
||||||
@@ -19,8 +17,6 @@ if (import.meta.env.DEV) {
|
|||||||
Userpilot.initialize("NX-69145f08");
|
Userpilot.initialize("NX-69145f08");
|
||||||
}
|
}
|
||||||
|
|
||||||
dayjs.locale("en");
|
|
||||||
|
|
||||||
const config = {
|
const config = {
|
||||||
core: {
|
core: {
|
||||||
authorizationKey: import.meta.env.VITE_APP_SPLIT_API,
|
authorizationKey: import.meta.env.VITE_APP_SPLIT_API,
|
||||||
|
|||||||
@@ -18,10 +18,10 @@ import { checkUserSession } from "../redux/user/user.actions";
|
|||||||
import { selectBodyshop, selectCurrentEula, selectCurrentUser } from "../redux/user/user.selectors";
|
import { selectBodyshop, selectCurrentEula, selectCurrentUser } from "../redux/user/user.selectors";
|
||||||
import PrivateRoute from "../components/PrivateRoute";
|
import PrivateRoute from "../components/PrivateRoute";
|
||||||
import "./App.styles.scss";
|
import "./App.styles.scss";
|
||||||
import handleBeta from "../utils/betaHandler";
|
|
||||||
import Eula from "../components/eula/eula.component";
|
import Eula from "../components/eula/eula.component";
|
||||||
import InstanceRenderMgr from "../utils/instanceRenderMgr";
|
import InstanceRenderMgr from "../utils/instanceRenderMgr";
|
||||||
import ProductFruitsWrapper from "./ProductFruitsWrapper.jsx";
|
import ProductFruitsWrapper from "./ProductFruitsWrapper.jsx";
|
||||||
|
import { SocketProvider } from "../contexts/SocketIO/socketContext.jsx";
|
||||||
|
|
||||||
const ResetPassword = lazy(() => import("../pages/reset-password/reset-password.component"));
|
const ResetPassword = lazy(() => import("../pages/reset-password/reset-password.component"));
|
||||||
const ManagePage = lazy(() => import("../pages/manage/manage.page.container"));
|
const ManagePage = lazy(() => import("../pages/manage/manage.page.container"));
|
||||||
@@ -108,8 +108,6 @@ export function App({ bodyshop, checkUserSession, currentUser, online, setOnline
|
|||||||
return <LoadingSpinner message={t("general.labels.loggingin")} />;
|
return <LoadingSpinner message={t("general.labels.loggingin")} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
handleBeta();
|
|
||||||
|
|
||||||
if (!online) {
|
if (!online) {
|
||||||
return (
|
return (
|
||||||
<Result
|
<Result
|
||||||
@@ -204,7 +202,9 @@ export function App({ bodyshop, checkUserSession, currentUser, online, setOnline
|
|||||||
path="/manage/*"
|
path="/manage/*"
|
||||||
element={
|
element={
|
||||||
<ErrorBoundary>
|
<ErrorBoundary>
|
||||||
<PrivateRoute isAuthorized={currentUser.authorized} />
|
<SocketProvider bodyshop={bodyshop}>
|
||||||
|
<PrivateRoute isAuthorized={currentUser.authorized} />
|
||||||
|
</SocketProvider>
|
||||||
</ErrorBoundary>
|
</ErrorBoundary>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
@@ -214,7 +214,9 @@ export function App({ bodyshop, checkUserSession, currentUser, online, setOnline
|
|||||||
path="/tech/*"
|
path="/tech/*"
|
||||||
element={
|
element={
|
||||||
<ErrorBoundary>
|
<ErrorBoundary>
|
||||||
<PrivateRoute isAuthorized={currentUser.authorized} />
|
<SocketProvider bodyshop={bodyshop}>
|
||||||
|
<PrivateRoute isAuthorized={currentUser.authorized} />
|
||||||
|
</SocketProvider>
|
||||||
</ErrorBoundary>
|
</ErrorBoundary>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -161,3 +161,15 @@
|
|||||||
.rowWithColor > td {
|
.rowWithColor > td {
|
||||||
background-color: var(--bgColor) !important;
|
background-color: var(--bgColor) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.muted-button {
|
||||||
|
color: lightgray;
|
||||||
|
border: none;
|
||||||
|
background: none;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 16px; /* Adjust as needed */
|
||||||
|
}
|
||||||
|
|
||||||
|
.muted-button:hover {
|
||||||
|
color: darkgrey;
|
||||||
|
}
|
||||||
|
|||||||
@@ -27,6 +27,6 @@ ProductFruitsWrapper.propTypes = {
|
|||||||
currentUser: PropTypes.shape({
|
currentUser: PropTypes.shape({
|
||||||
authorized: PropTypes.bool,
|
authorized: PropTypes.bool,
|
||||||
email: PropTypes.string
|
email: PropTypes.string
|
||||||
}).isRequired,
|
}),
|
||||||
workspaceCode: PropTypes.string.isRequired
|
workspaceCode: PropTypes.string
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import { logImEXEvent } from "../../firebase/firebase.utils";
|
|||||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||||
import CurrencyFormatter from "../../utils/CurrencyFormatter";
|
import CurrencyFormatter from "../../utils/CurrencyFormatter";
|
||||||
import { DateFormatter } from "../../utils/DateFormatter";
|
import { DateFormatter } from "../../utils/DateFormatter";
|
||||||
import { pageLimit } from "../../utils/config";
|
import { exportPageLimit } from "../../utils/config";
|
||||||
import { alphaSort, dateSort } from "../../utils/sorters";
|
import { alphaSort, dateSort } from "../../utils/sorters";
|
||||||
import ExportLogsCountDisplay from "../export-logs-count-display/export-logs-count-display.component";
|
import ExportLogsCountDisplay from "../export-logs-count-display/export-logs-count-display.component";
|
||||||
import PayableExportAll from "../payable-export-all-button/payable-export-all-button.component";
|
import PayableExportAll from "../payable-export-all-button/payable-export-all-button.component";
|
||||||
@@ -175,7 +175,7 @@ export function AccountingPayablesTableComponent({ bodyshop, loading, bills, ref
|
|||||||
<Table
|
<Table
|
||||||
loading={loading}
|
loading={loading}
|
||||||
dataSource={dataSource}
|
dataSource={dataSource}
|
||||||
pagination={{ position: "top", pageSize: pageLimit }}
|
pagination={{ position: "top", pageSize: exportPageLimit }}
|
||||||
columns={columns}
|
columns={columns}
|
||||||
rowKey="id"
|
rowKey="id"
|
||||||
onChange={handleTableChange}
|
onChange={handleTableChange}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import { logImEXEvent } from "../../firebase/firebase.utils";
|
|||||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||||
import CurrencyFormatter from "../../utils/CurrencyFormatter";
|
import CurrencyFormatter from "../../utils/CurrencyFormatter";
|
||||||
import { DateFormatter, DateTimeFormatter } from "../../utils/DateFormatter";
|
import { DateFormatter, DateTimeFormatter } from "../../utils/DateFormatter";
|
||||||
import { pageLimit } from "../../utils/config";
|
import { exportPageLimit } from "../../utils/config";
|
||||||
import { alphaSort, dateSort } from "../../utils/sorters";
|
import { alphaSort, dateSort } from "../../utils/sorters";
|
||||||
import ExportLogsCountDisplay from "../export-logs-count-display/export-logs-count-display.component";
|
import ExportLogsCountDisplay from "../export-logs-count-display/export-logs-count-display.component";
|
||||||
import OwnerNameDisplay, { OwnerNameDisplayFunction } from "../owner-name-display/owner-name-display.component";
|
import OwnerNameDisplay, { OwnerNameDisplayFunction } from "../owner-name-display/owner-name-display.component";
|
||||||
@@ -177,7 +177,7 @@ export function AccountingPayablesTableComponent({ bodyshop, loading, payments,
|
|||||||
<Table
|
<Table
|
||||||
loading={loading}
|
loading={loading}
|
||||||
dataSource={dataSource}
|
dataSource={dataSource}
|
||||||
pagination={{ position: "top", pageSize: pageLimit }}
|
pagination={{ position: "top", pageSize: exportPageLimit }}
|
||||||
columns={columns}
|
columns={columns}
|
||||||
rowKey="id"
|
rowKey="id"
|
||||||
onChange={handleTableChange}
|
onChange={handleTableChange}
|
||||||
|
|||||||
@@ -1,18 +1,19 @@
|
|||||||
import { Button, Card, Input, Space, Table } from "antd";
|
import { Button, Card, Input, Space, Table } from "antd";
|
||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
|
import { connect } from "react-redux";
|
||||||
import { Link } from "react-router-dom";
|
import { Link } from "react-router-dom";
|
||||||
|
import { createStructuredSelector } from "reselect";
|
||||||
import { logImEXEvent } from "../../firebase/firebase.utils";
|
import { logImEXEvent } from "../../firebase/firebase.utils";
|
||||||
|
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||||
|
import { exportPageLimit } from "../../utils/config";
|
||||||
import CurrencyFormatter from "../../utils/CurrencyFormatter";
|
import CurrencyFormatter from "../../utils/CurrencyFormatter";
|
||||||
|
import { DateFormatter } from "../../utils/DateFormatter";
|
||||||
import { alphaSort, dateSort, statusSort } from "../../utils/sorters";
|
import { alphaSort, dateSort, statusSort } from "../../utils/sorters";
|
||||||
|
import ExportLogsCountDisplay from "../export-logs-count-display/export-logs-count-display.component";
|
||||||
import JobExportButton from "../jobs-close-export-button/jobs-close-export-button.component";
|
import JobExportButton from "../jobs-close-export-button/jobs-close-export-button.component";
|
||||||
import JobsExportAllButton from "../jobs-export-all-button/jobs-export-all-button.component";
|
import JobsExportAllButton from "../jobs-export-all-button/jobs-export-all-button.component";
|
||||||
|
import JobMarkSelectedExported from "../jobs-mark-selected-exported/jobs-mark-selected-exported";
|
||||||
import { connect } from "react-redux";
|
|
||||||
import { createStructuredSelector } from "reselect";
|
|
||||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
|
||||||
import { DateFormatter } from "../../utils/DateFormatter";
|
|
||||||
import ExportLogsCountDisplay from "../export-logs-count-display/export-logs-count-display.component";
|
|
||||||
import OwnerNameDisplay, { OwnerNameDisplayFunction } from "../owner-name-display/owner-name-display.component";
|
import OwnerNameDisplay, { OwnerNameDisplayFunction } from "../owner-name-display/owner-name-display.component";
|
||||||
import QboAuthorizeComponent from "../qbo-authorize/qbo-authorize.component";
|
import QboAuthorizeComponent from "../qbo-authorize/qbo-authorize.component";
|
||||||
|
|
||||||
@@ -170,13 +171,22 @@ export function AccountingReceivablesTableComponent({ bodyshop, loading, jobs, r
|
|||||||
extra={
|
extra={
|
||||||
<Space wrap>
|
<Space wrap>
|
||||||
{!bodyshop.cdk_dealerid && !bodyshop.pbs_serialnumber && (
|
{!bodyshop.cdk_dealerid && !bodyshop.pbs_serialnumber && (
|
||||||
<JobsExportAllButton
|
<>
|
||||||
jobIds={selectedJobs}
|
<JobMarkSelectedExported
|
||||||
disabled={transInProgress || selectedJobs.length === 0}
|
jobIds={selectedJobs}
|
||||||
loadingCallback={setTransInProgress}
|
disabled={transInProgress || selectedJobs.length === 0}
|
||||||
completedCallback={setSelectedJobs}
|
loadingCallback={setTransInProgress}
|
||||||
refetch={refetch}
|
completedCallback={setSelectedJobs}
|
||||||
/>
|
refetch={refetch}
|
||||||
|
/>
|
||||||
|
<JobsExportAllButton
|
||||||
|
jobIds={selectedJobs}
|
||||||
|
disabled={transInProgress || selectedJobs.length === 0}
|
||||||
|
loadingCallback={setTransInProgress}
|
||||||
|
completedCallback={setSelectedJobs}
|
||||||
|
refetch={refetch}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
)}
|
)}
|
||||||
{bodyshop.accountingconfig && bodyshop.accountingconfig.qbo && <QboAuthorizeComponent />}
|
{bodyshop.accountingconfig && bodyshop.accountingconfig.qbo && <QboAuthorizeComponent />}
|
||||||
<Input.Search
|
<Input.Search
|
||||||
@@ -191,7 +201,7 @@ export function AccountingReceivablesTableComponent({ bodyshop, loading, jobs, r
|
|||||||
<Table
|
<Table
|
||||||
loading={loading}
|
loading={loading}
|
||||||
dataSource={dataSource}
|
dataSource={dataSource}
|
||||||
pagination={{ position: "top" }}
|
pagination={{ position: "top", pageSize: exportPageLimit }}
|
||||||
columns={columns}
|
columns={columns}
|
||||||
rowKey="id"
|
rowKey="id"
|
||||||
onChange={handleTableChange}
|
onChange={handleTableChange}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
|
import { PageHeader } from "@ant-design/pro-layout";
|
||||||
import { useMutation, useQuery } from "@apollo/client";
|
import { useMutation, useQuery } from "@apollo/client";
|
||||||
import { Button, Divider, Form, Popconfirm, Space } from "antd";
|
import { Button, Divider, Form, Popconfirm, Space } from "antd";
|
||||||
import dayjs from "../../utils/day";
|
|
||||||
import queryString from "query-string";
|
import queryString from "query-string";
|
||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
@@ -13,6 +13,7 @@ import { insertAuditTrail } from "../../redux/application/application.actions";
|
|||||||
import { setModalContext } from "../../redux/modals/modals.actions";
|
import { setModalContext } from "../../redux/modals/modals.actions";
|
||||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||||
import AuditTrailMapping from "../../utils/AuditTrailMappings";
|
import AuditTrailMapping from "../../utils/AuditTrailMappings";
|
||||||
|
import dayjs from "../../utils/day";
|
||||||
import AlertComponent from "../alert/alert.component";
|
import AlertComponent from "../alert/alert.component";
|
||||||
import BillFormContainer from "../bill-form/bill-form.container";
|
import BillFormContainer from "../bill-form/bill-form.container";
|
||||||
import BillMarkExportedButton from "../bill-mark-exported-button/bill-mark-exported-button.component";
|
import BillMarkExportedButton from "../bill-mark-exported-button/bill-mark-exported-button.component";
|
||||||
@@ -22,7 +23,6 @@ import JobDocumentsGallery from "../jobs-documents-gallery/jobs-documents-galler
|
|||||||
import JobsDocumentsLocalGallery from "../jobs-documents-local-gallery/jobs-documents-local-gallery.container";
|
import JobsDocumentsLocalGallery from "../jobs-documents-local-gallery/jobs-documents-local-gallery.container";
|
||||||
import LoadingSkeleton from "../loading-skeleton/loading-skeleton.component";
|
import LoadingSkeleton from "../loading-skeleton/loading-skeleton.component";
|
||||||
import BillDetailEditReturn from "./bill-detail-edit-return.component";
|
import BillDetailEditReturn from "./bill-detail-edit-return.component";
|
||||||
import { PageHeader } from "@ant-design/pro-layout";
|
|
||||||
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
bodyshop: selectBodyshop
|
bodyshop: selectBodyshop
|
||||||
@@ -98,7 +98,7 @@ export function BillDetailEditcontainer({ setPartsOrderContext, insertAuditTrail
|
|||||||
});
|
});
|
||||||
|
|
||||||
billlines.forEach((billline) => {
|
billlines.forEach((billline) => {
|
||||||
const { deductedfromlbr, inventories, jobline, ...il } = billline;
|
const { deductedfromlbr, inventories, jobline, original_actual_price, create_ppc, ...il } = billline;
|
||||||
delete il.__typename;
|
delete il.__typename;
|
||||||
|
|
||||||
if (il.id) {
|
if (il.id) {
|
||||||
@@ -153,6 +153,7 @@ export function BillDetailEditcontainer({ setPartsOrderContext, insertAuditTrail
|
|||||||
if (!search.billid) return <></>; //<div>{t("bills.labels.noneselected")}</div>;
|
if (!search.billid) return <></>; //<div>{t("bills.labels.noneselected")}</div>;
|
||||||
|
|
||||||
const exported = data && data.bills_by_pk && data.bills_by_pk.exported;
|
const exported = data && data.bills_by_pk && data.bills_by_pk.exported;
|
||||||
|
const isinhouse = data && data.bills_by_pk && data.bills_by_pk.isinhouse;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@@ -188,7 +189,7 @@ export function BillDetailEditcontainer({ setPartsOrderContext, insertAuditTrail
|
|||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<Form form={form} onFinish={handleFinish} initialValues={transformData(data)} layout="vertical">
|
<Form form={form} onFinish={handleFinish} initialValues={transformData(data)} layout="vertical">
|
||||||
<BillFormContainer form={form} billEdit disabled={exported} />
|
<BillFormContainer form={form} billEdit disabled={exported} disableInHouse={isinhouse} />
|
||||||
<Divider orientation="left">{t("general.labels.media")}</Divider>
|
<Divider orientation="left">{t("general.labels.media")}</Divider>
|
||||||
{bodyshop.uselocalmediaserver ? (
|
{bodyshop.uselocalmediaserver ? (
|
||||||
<JobsDocumentsLocalGallery
|
<JobsDocumentsLocalGallery
|
||||||
|
|||||||
@@ -14,7 +14,6 @@ import dayjs from "../../utils/day";
|
|||||||
import InstanceRenderManager from "../../utils/instanceRenderMgr";
|
import InstanceRenderManager from "../../utils/instanceRenderMgr";
|
||||||
import AlertComponent from "../alert/alert.component";
|
import AlertComponent from "../alert/alert.component";
|
||||||
import BillFormLinesExtended from "../bill-form-lines-extended/bill-form-lines-extended.component";
|
import BillFormLinesExtended from "../bill-form-lines-extended/bill-form-lines-extended.component";
|
||||||
import FormDatePicker from "../form-date-picker/form-date-picker.component";
|
|
||||||
import FormFieldsChanged from "../form-fields-changed-alert/form-fields-changed-alert.component";
|
import FormFieldsChanged from "../form-fields-changed-alert/form-fields-changed-alert.component";
|
||||||
import CurrencyInput from "../form-items-formatted/currency-form-item.component";
|
import CurrencyInput from "../form-items-formatted/currency-form-item.component";
|
||||||
import JobSearchSelect from "../job-search-select/job-search-select.component";
|
import JobSearchSelect from "../job-search-select/job-search-select.component";
|
||||||
@@ -22,6 +21,7 @@ import LayoutFormRow from "../layout-form-row/layout-form-row.component";
|
|||||||
import VendorSearchSelect from "../vendor-search-select/vendor-search-select.component";
|
import VendorSearchSelect from "../vendor-search-select/vendor-search-select.component";
|
||||||
import BillFormLines from "./bill-form.lines.component";
|
import BillFormLines from "./bill-form.lines.component";
|
||||||
import { CalculateBillTotal } from "./bill-form.totals.utility";
|
import { CalculateBillTotal } from "./bill-form.totals.utility";
|
||||||
|
import DateTimePicker from "../form-date-time-picker/form-date-time-picker.component.jsx";
|
||||||
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
bodyshop: selectBodyshop
|
bodyshop: selectBodyshop
|
||||||
@@ -41,7 +41,8 @@ export function BillFormComponent({
|
|||||||
job,
|
job,
|
||||||
loadOutstandingReturns,
|
loadOutstandingReturns,
|
||||||
loadInventory,
|
loadInventory,
|
||||||
preferredMake
|
preferredMake,
|
||||||
|
disableInHouse
|
||||||
}) {
|
}) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const client = useApolloClient();
|
const client = useApolloClient();
|
||||||
@@ -177,7 +178,7 @@ export function BillFormComponent({
|
|||||||
]}
|
]}
|
||||||
>
|
>
|
||||||
<VendorSearchSelect
|
<VendorSearchSelect
|
||||||
disabled={disabled}
|
disabled={disabled || disableInHouse}
|
||||||
options={vendorAutoCompleteOptions}
|
options={vendorAutoCompleteOptions}
|
||||||
preferredMake={preferredMake}
|
preferredMake={preferredMake}
|
||||||
onSelect={handleVendorSelect}
|
onSelect={handleVendorSelect}
|
||||||
@@ -243,7 +244,7 @@ export function BillFormComponent({
|
|||||||
})
|
})
|
||||||
]}
|
]}
|
||||||
>
|
>
|
||||||
<Input disabled={disabled || disableInvNumber} />
|
<Input disabled={disabled || disableInvNumber || disableInHouse} />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
label={t("bills.fields.date")}
|
label={t("bills.fields.date")}
|
||||||
@@ -275,7 +276,7 @@ export function BillFormComponent({
|
|||||||
})
|
})
|
||||||
]}
|
]}
|
||||||
>
|
>
|
||||||
<FormDatePicker disabled={disabled} />
|
<DateTimePicker isDateOnly disabled={disabled} />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
label={t("bills.fields.is_credit_memo")}
|
label={t("bills.fields.is_credit_memo")}
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ const mapStateToProps = createStructuredSelector({
|
|||||||
bodyshop: selectBodyshop
|
bodyshop: selectBodyshop
|
||||||
});
|
});
|
||||||
|
|
||||||
export function BillFormContainer({ bodyshop, form, billEdit, disabled, disableInvNumber }) {
|
export function BillFormContainer({ bodyshop, form, billEdit, disabled, disableInvNumber, disableInHouse }) {
|
||||||
const {
|
const {
|
||||||
treatments: { Simple_Inventory }
|
treatments: { Simple_Inventory }
|
||||||
} = useSplitTreatments({
|
} = useSplitTreatments({
|
||||||
@@ -47,6 +47,7 @@ export function BillFormContainer({ bodyshop, form, billEdit, disabled, disableI
|
|||||||
job={lineData ? lineData.jobs_by_pk : null}
|
job={lineData ? lineData.jobs_by_pk : null}
|
||||||
responsibilityCenters={bodyshop.md_responsibility_centers || null}
|
responsibilityCenters={bodyshop.md_responsibility_centers || null}
|
||||||
disableInvNumber={disableInvNumber}
|
disableInvNumber={disableInvNumber}
|
||||||
|
disableInHouse={disableInHouse}
|
||||||
loadOutstandingReturns={loadOutstandingReturns}
|
loadOutstandingReturns={loadOutstandingReturns}
|
||||||
loadInventory={loadInventory}
|
loadInventory={loadInventory}
|
||||||
preferredMake={lineData ? lineData.jobs_by_pk.v_make_desc : null}
|
preferredMake={lineData ? lineData.jobs_by_pk.v_make_desc : null}
|
||||||
|
|||||||
@@ -7,10 +7,10 @@ import { connect } from "react-redux";
|
|||||||
import { createStructuredSelector } from "reselect";
|
import { createStructuredSelector } from "reselect";
|
||||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||||
import CiecaSelect from "../../utils/Ciecaselect";
|
import CiecaSelect from "../../utils/Ciecaselect";
|
||||||
|
import InstanceRenderManager from "../../utils/instanceRenderMgr";
|
||||||
import BillLineSearchSelect from "../bill-line-search-select/bill-line-search-select.component";
|
import BillLineSearchSelect from "../bill-line-search-select/bill-line-search-select.component";
|
||||||
import BilllineAddInventory from "../billline-add-inventory/billline-add-inventory.component";
|
import BilllineAddInventory from "../billline-add-inventory/billline-add-inventory.component";
|
||||||
import CurrencyInput from "../form-items-formatted/currency-form-item.component";
|
import CurrencyInput from "../form-items-formatted/currency-form-item.component";
|
||||||
import InstanceRenderManager from "../../utils/instanceRenderMgr";
|
|
||||||
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
//currentUser: selectCurrentUser
|
//currentUser: selectCurrentUser
|
||||||
@@ -72,7 +72,14 @@ export function BillEnterModalLinesComponent({
|
|||||||
<BillLineSearchSelect
|
<BillLineSearchSelect
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
options={lineData}
|
options={lineData}
|
||||||
style={{ width: "100%", minWidth: "10rem" }}
|
style={{
|
||||||
|
width: "20rem",
|
||||||
|
maxWidth: "20rem",
|
||||||
|
minWidth: "10rem",
|
||||||
|
whiteSpace: "normal",
|
||||||
|
height: "auto",
|
||||||
|
minHeight: "32px" // default height of Ant Design inputs
|
||||||
|
}}
|
||||||
allowRemoved={form.getFieldValue("is_credit_memo") || false}
|
allowRemoved={form.getFieldValue("is_credit_memo") || false}
|
||||||
onSelect={(value, opt) => {
|
onSelect={(value, opt) => {
|
||||||
setFieldsValue({
|
setFieldsValue({
|
||||||
@@ -105,7 +112,7 @@ export function BillEnterModalLinesComponent({
|
|||||||
title: t("billlines.fields.line_desc"),
|
title: t("billlines.fields.line_desc"),
|
||||||
dataIndex: "line_desc",
|
dataIndex: "line_desc",
|
||||||
editable: true,
|
editable: true,
|
||||||
|
width: "20rem",
|
||||||
formItemProps: (field) => {
|
formItemProps: (field) => {
|
||||||
return {
|
return {
|
||||||
key: `${field.index}line_desc`,
|
key: `${field.index}line_desc`,
|
||||||
@@ -119,7 +126,7 @@ export function BillEnterModalLinesComponent({
|
|||||||
]
|
]
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
formInput: (record, index) => <Input disabled={disabled} />
|
formInput: (record, index) => <Input.TextArea disabled={disabled} autoSize />
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: t("billlines.fields.quantity"),
|
title: t("billlines.fields.quantity"),
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ import React, { forwardRef } from "react";
|
|||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import InstanceRenderMgr from "../../utils/instanceRenderMgr";
|
import InstanceRenderMgr from "../../utils/instanceRenderMgr";
|
||||||
|
|
||||||
//To be used as a form element only.
|
|
||||||
const BillLineSearchSelect = ({ options, disabled, allowRemoved, ...restProps }, ref) => {
|
const BillLineSearchSelect = ({ options, disabled, allowRemoved, ...restProps }, ref) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
@@ -12,7 +11,7 @@ const BillLineSearchSelect = ({ options, disabled, allowRemoved, ...restProps },
|
|||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
ref={ref}
|
ref={ref}
|
||||||
showSearch
|
showSearch
|
||||||
popupMatchSelectWidth={false}
|
popupMatchSelectWidth={true}
|
||||||
optionLabelProp={"name"}
|
optionLabelProp={"name"}
|
||||||
// optionFilterProp="line_desc"
|
// optionFilterProp="line_desc"
|
||||||
filterOption={(inputValue, option) => {
|
filterOption={(inputValue, option) => {
|
||||||
@@ -44,7 +43,7 @@ const BillLineSearchSelect = ({ options, disabled, allowRemoved, ...restProps },
|
|||||||
item.oem_partno ? ` - ${item.oem_partno}` : ""
|
item.oem_partno ? ` - ${item.oem_partno}` : ""
|
||||||
}${item.alt_partno ? ` (${item.alt_partno})` : ""}`.trim(),
|
}${item.alt_partno ? ` (${item.alt_partno})` : ""}`.trim(),
|
||||||
label: (
|
label: (
|
||||||
<>
|
<div style={{ whiteSpace: 'normal', wordBreak: 'break-word' }}>
|
||||||
<span>
|
<span>
|
||||||
{`${item.removed ? `(REMOVED) ` : ""}${item.line_desc}${
|
{`${item.removed ? `(REMOVED) ` : ""}${item.line_desc}${
|
||||||
item.oem_partno ? ` - ${item.oem_partno}` : ""
|
item.oem_partno ? ` - ${item.oem_partno}` : ""
|
||||||
@@ -58,7 +57,7 @@ const BillLineSearchSelect = ({ options, disabled, allowRemoved, ...restProps },
|
|||||||
<span style={{ float: "right", paddingleft: "1rem" }}>
|
<span style={{ float: "right", paddingleft: "1rem" }}>
|
||||||
{item.act_price ? `$${item.act_price && item.act_price.toFixed(2)}` : ``}
|
{item.act_price ? `$${item.act_price && item.act_price.toFixed(2)}` : ``}
|
||||||
</span>
|
</span>
|
||||||
</>
|
</div>
|
||||||
)
|
)
|
||||||
}))
|
}))
|
||||||
]}
|
]}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { DeleteFilled } from "@ant-design/icons";
|
import { DeleteFilled, CopyFilled } from "@ant-design/icons";
|
||||||
import { useLazyQuery, useMutation } from "@apollo/client";
|
import { useLazyQuery, useMutation } from "@apollo/client";
|
||||||
import { Button, Card, Col, Form, Input, Row, Space, Spin, Statistic, notification } from "antd";
|
import { Button, Card, Col, Form, Input, Row, Space, Spin, Statistic, message, notification } from "antd";
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
@@ -14,10 +14,12 @@ import { selectBodyshop } from "../../redux/user/user.selectors";
|
|||||||
import AuditTrailMapping from "../../utils/AuditTrailMappings";
|
import AuditTrailMapping from "../../utils/AuditTrailMappings";
|
||||||
import CurrencyFormItemComponent from "../form-items-formatted/currency-form-item.component";
|
import CurrencyFormItemComponent from "../form-items-formatted/currency-form-item.component";
|
||||||
import JobSearchSelectComponent from "../job-search-select/job-search-select.component";
|
import JobSearchSelectComponent from "../job-search-select/job-search-select.component";
|
||||||
|
import { getCurrentUser } from "../../firebase/firebase.utils";
|
||||||
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
cardPaymentModal: selectCardPayment,
|
cardPaymentModal: selectCardPayment,
|
||||||
bodyshop: selectBodyshop
|
bodyshop: selectBodyshop,
|
||||||
|
currentUser: getCurrentUser
|
||||||
});
|
});
|
||||||
|
|
||||||
const mapDispatchToProps = (dispatch) => ({
|
const mapDispatchToProps = (dispatch) => ({
|
||||||
@@ -25,11 +27,17 @@ const mapDispatchToProps = (dispatch) => ({
|
|||||||
toggleModalVisible: () => dispatch(toggleModalVisible("cardPayment"))
|
toggleModalVisible: () => dispatch(toggleModalVisible("cardPayment"))
|
||||||
});
|
});
|
||||||
|
|
||||||
const CardPaymentModalComponent = ({ bodyshop, cardPaymentModal, toggleModalVisible, insertAuditTrail }) => {
|
const CardPaymentModalComponent = ({
|
||||||
|
bodyshop,
|
||||||
|
currentUser,
|
||||||
|
cardPaymentModal,
|
||||||
|
toggleModalVisible,
|
||||||
|
insertAuditTrail
|
||||||
|
}) => {
|
||||||
const { context, actions } = cardPaymentModal;
|
const { context, actions } = cardPaymentModal;
|
||||||
|
|
||||||
const [form] = Form.useForm();
|
const [form] = Form.useForm();
|
||||||
|
const [paymentLink, setPaymentLink] = useState();
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
// const [insertPayment] = useMutation(INSERT_NEW_PAYMENT);
|
// const [insertPayment] = useMutation(INSERT_NEW_PAYMENT);
|
||||||
const [insertPaymentResponse] = useMutation(INSERT_PAYMENT_RESPONSE);
|
const [insertPaymentResponse] = useMutation(INSERT_PAYMENT_RESPONSE);
|
||||||
@@ -37,7 +45,7 @@ const CardPaymentModalComponent = ({ bodyshop, cardPaymentModal, toggleModalVisi
|
|||||||
|
|
||||||
const [, { data, refetch, queryLoading }] = useLazyQuery(QUERY_RO_AND_OWNER_BY_JOB_PKS, {
|
const [, { data, refetch, queryLoading }] = useLazyQuery(QUERY_RO_AND_OWNER_BY_JOB_PKS, {
|
||||||
variables: { jobids: [context.jobid] },
|
variables: { jobids: [context.jobid] },
|
||||||
skip: true
|
skip: !context?.jobid
|
||||||
});
|
});
|
||||||
|
|
||||||
//Initialize the intellipay window.
|
//Initialize the intellipay window.
|
||||||
@@ -51,8 +59,7 @@ const CardPaymentModalComponent = ({ bodyshop, cardPaymentModal, toggleModalVisi
|
|||||||
//2024-04-25: Nothing is going to happen here anymore. We'll completely rely on the callback.
|
//2024-04-25: Nothing is going to happen here anymore. We'll completely rely on the callback.
|
||||||
//Add a slight delay to allow the refetch to properly get the data.
|
//Add a slight delay to allow the refetch to properly get the data.
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
if (actions && actions.refetch && typeof actions.refetch === "function")
|
if (actions && actions.refetch && typeof actions.refetch === "function") actions.refetch();
|
||||||
actions.refetch();
|
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
toggleModalVisible();
|
toggleModalVisible();
|
||||||
}, 750);
|
}, 750);
|
||||||
@@ -86,7 +93,6 @@ const CardPaymentModalComponent = ({ bodyshop, cardPaymentModal, toggleModalVisi
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
const handleIntelliPayCharge = async () => {
|
const handleIntelliPayCharge = async () => {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
//Validate
|
//Validate
|
||||||
@@ -101,7 +107,7 @@ const CardPaymentModalComponent = ({ bodyshop, cardPaymentModal, toggleModalVisi
|
|||||||
const response = await axios.post("/intellipay/lightbox_credentials", {
|
const response = await axios.post("/intellipay/lightbox_credentials", {
|
||||||
bodyshop,
|
bodyshop,
|
||||||
refresh: !!window.intellipay,
|
refresh: !!window.intellipay,
|
||||||
paymentSplitMeta: form.getFieldsValue(),
|
paymentSplitMeta: form.getFieldsValue()
|
||||||
});
|
});
|
||||||
|
|
||||||
if (window.intellipay) {
|
if (window.intellipay) {
|
||||||
@@ -126,6 +132,42 @@ const CardPaymentModalComponent = ({ bodyshop, cardPaymentModal, toggleModalVisi
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleIntelliPayChargeShortLink = async () => {
|
||||||
|
setLoading(true);
|
||||||
|
//Validate
|
||||||
|
try {
|
||||||
|
await form.validateFields();
|
||||||
|
} catch (error) {
|
||||||
|
setLoading(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const { payments } = form.getFieldsValue();
|
||||||
|
const response = await axios.post("/intellipay/generate_payment_url", {
|
||||||
|
bodyshop,
|
||||||
|
amount: payments?.reduce((acc, val) => {
|
||||||
|
return acc + (val?.amount || 0);
|
||||||
|
}, 0),
|
||||||
|
account: payments && data && data.jobs.length > 0 ? data.jobs.map((j) => j.ro_number).join(", ") : null,
|
||||||
|
comment: btoa(JSON.stringify({ payments, userEmail: currentUser.email })),
|
||||||
|
paymentSplitMeta: form.getFieldsValue()
|
||||||
|
});
|
||||||
|
if (response.data) {
|
||||||
|
setPaymentLink(response.data?.shorUrl);
|
||||||
|
navigator.clipboard.writeText(response.data?.shorUrl);
|
||||||
|
message.success(t("general.actions.copied"));
|
||||||
|
}
|
||||||
|
setLoading(false);
|
||||||
|
} catch (error) {
|
||||||
|
notification.open({
|
||||||
|
type: "error",
|
||||||
|
message: t("job_payments.notifications.error.openingip")
|
||||||
|
});
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Card title="Card Payment">
|
<Card title="Card Payment">
|
||||||
<Spin spinning={loading}>
|
<Spin spinning={loading}>
|
||||||
@@ -202,16 +244,14 @@ const CardPaymentModalComponent = ({ bodyshop, cardPaymentModal, toggleModalVisi
|
|||||||
|
|
||||||
<Form.Item
|
<Form.Item
|
||||||
shouldUpdate={(prevValues, curValues) =>
|
shouldUpdate={(prevValues, curValues) =>
|
||||||
prevValues.payments?.map((p) => p?.jobid).join() !== curValues.payments?.map((p) => p?.jobid).join()
|
prevValues.payments?.map((p) => p?.jobid + p?.amount).join() !==
|
||||||
|
curValues.payments?.map((p) => p?.jobid + p?.amount).join()
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
{() => {
|
{() => {
|
||||||
//If all of the job ids have been fileld in, then query and update the IP field.
|
//If all of the job ids have been fileld in, then query and update the IP field.
|
||||||
const { payments } = form.getFieldsValue();
|
const { payments } = form.getFieldsValue();
|
||||||
if (
|
if (payments?.length > 0 && payments?.filter((p) => p?.jobid).length === payments?.length) {
|
||||||
payments?.length > 0 &&
|
|
||||||
payments?.filter((p) => p?.jobid).length === payments?.length
|
|
||||||
) {
|
|
||||||
refetch({ jobids: payments.map((p) => p.jobid) });
|
refetch({ jobids: payments.map((p) => p.jobid) });
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
@@ -246,7 +286,6 @@ const CardPaymentModalComponent = ({ bodyshop, cardPaymentModal, toggleModalVisi
|
|||||||
const totalAmountToCharge = payments?.reduce((acc, val) => {
|
const totalAmountToCharge = payments?.reduce((acc, val) => {
|
||||||
return acc + (val?.amount || 0);
|
return acc + (val?.amount || 0);
|
||||||
}, 0);
|
}, 0);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Space style={{ float: "right" }}>
|
<Space style={{ float: "right" }}>
|
||||||
<Statistic title="Amount To Charge" value={totalAmountToCharge} precision={2} />
|
<Statistic title="Amount To Charge" value={totalAmountToCharge} precision={2} />
|
||||||
@@ -273,11 +312,36 @@ const CardPaymentModalComponent = ({ bodyshop, cardPaymentModal, toggleModalVisi
|
|||||||
>
|
>
|
||||||
{t("job_payments.buttons.proceedtopayment")}
|
{t("job_payments.buttons.proceedtopayment")}
|
||||||
</Button>
|
</Button>
|
||||||
|
<Space direction="vertical" align="center">
|
||||||
|
<Button
|
||||||
|
type="primary"
|
||||||
|
// data-ipayname="submit"
|
||||||
|
className="ipayfield"
|
||||||
|
loading={queryLoading || loading}
|
||||||
|
disabled={!(totalAmountToCharge > 0)}
|
||||||
|
onClick={handleIntelliPayChargeShortLink}
|
||||||
|
>
|
||||||
|
{t("job_payments.buttons.create_short_link")}
|
||||||
|
</Button>
|
||||||
|
</Space>
|
||||||
</Space>
|
</Space>
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
</Form>
|
</Form>
|
||||||
|
{paymentLink && (
|
||||||
|
<Space
|
||||||
|
style={{ cursor: "pointer", float: "right" }}
|
||||||
|
align="end"
|
||||||
|
onClick={() => {
|
||||||
|
navigator.clipboard.writeText(paymentLink);
|
||||||
|
message.success(t("general.actions.copied"));
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div>{paymentLink}</div>
|
||||||
|
<CopyFilled />
|
||||||
|
</Space>
|
||||||
|
)}
|
||||||
</Spin>
|
</Spin>
|
||||||
</Card>
|
</Card>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,15 +1,17 @@
|
|||||||
import { WarningFilled } from "@ant-design/icons";
|
import { WarningFilled } from "@ant-design/icons";
|
||||||
import { Form, Input, InputNumber, Space } from "antd";
|
import { Form, Input, InputNumber, Space } from "antd";
|
||||||
import dayjs from "../../utils/day";
|
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { DateFormatter } from "../../utils/DateFormatter";
|
import { DateFormatter } from "../../utils/DateFormatter";
|
||||||
|
import dayjs from "../../utils/day";
|
||||||
//import ContractLicenseDecodeButton from "../contract-license-decode-button/contract-license-decode-button.component";
|
//import ContractLicenseDecodeButton from "../contract-license-decode-button/contract-license-decode-button.component";
|
||||||
import ContractStatusSelector from "../contract-status-select/contract-status-select.component";
|
import ContractStatusSelector from "../contract-status-select/contract-status-select.component";
|
||||||
import ContractsRatesChangeButton from "../contracts-rates-change-button/contracts-rates-change-button.component";
|
import ContractsRatesChangeButton from "../contracts-rates-change-button/contracts-rates-change-button.component";
|
||||||
import CourtesyCarFuelSlider from "../courtesy-car-fuel-select/courtesy-car-fuel-select.component";
|
import CourtesyCarFuelSlider from "../courtesy-car-fuel-select/courtesy-car-fuel-select.component";
|
||||||
import FormDatePicker from "../form-date-picker/form-date-picker.component";
|
import {
|
||||||
import FormDateTimePicker from "../form-date-time-picker/form-date-time-picker.component";
|
default as DateTimePicker,
|
||||||
|
default as FormDateTimePicker
|
||||||
|
} from "../form-date-time-picker/form-date-time-picker.component";
|
||||||
import FormFieldsChanged from "../form-fields-changed-alert/form-fields-changed-alert.component";
|
import FormFieldsChanged from "../form-fields-changed-alert/form-fields-changed-alert.component";
|
||||||
import InputPhone, { PhoneItemFormatterValidation } from "../form-items-formatted/phone-form-item.component";
|
import InputPhone, { PhoneItemFormatterValidation } from "../form-items-formatted/phone-form-item.component";
|
||||||
import LayoutFormRow from "../layout-form-row/layout-form-row.component";
|
import LayoutFormRow from "../layout-form-row/layout-form-row.component";
|
||||||
@@ -18,10 +20,10 @@ import ContractFormJobPrefill from "./contract-form-job-prefill.component";
|
|||||||
export default function ContractFormComponent({ form, create = false, selectedJobState, selectedCar }) {
|
export default function ContractFormComponent({ form, create = false, selectedJobState, selectedCar }) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
return (
|
return (
|
||||||
<div>
|
<>
|
||||||
<FormFieldsChanged form={form} />
|
{!create && <FormFieldsChanged form={form} />}
|
||||||
<LayoutFormRow>
|
<LayoutFormRow>
|
||||||
{create ? null : (
|
{!create && (
|
||||||
<Form.Item
|
<Form.Item
|
||||||
label={t("contracts.fields.status")}
|
label={t("contracts.fields.status")}
|
||||||
name="status"
|
name="status"
|
||||||
@@ -50,7 +52,7 @@ export default function ContractFormComponent({ form, create = false, selectedJo
|
|||||||
<Form.Item label={t("contracts.fields.scheduledreturn")} name="scheduledreturn">
|
<Form.Item label={t("contracts.fields.scheduledreturn")} name="scheduledreturn">
|
||||||
<FormDateTimePicker />
|
<FormDateTimePicker />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
{create ? null : (
|
{!create && (
|
||||||
<Form.Item label={t("contracts.fields.actualreturn")} name="actualreturn">
|
<Form.Item label={t("contracts.fields.actualreturn")} name="actualreturn">
|
||||||
<FormDateTimePicker />
|
<FormDateTimePicker />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
@@ -122,7 +124,7 @@ export default function ContractFormComponent({ form, create = false, selectedJo
|
|||||||
}}
|
}}
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
)}
|
)}
|
||||||
{create ? null : (
|
{!create && (
|
||||||
<Form.Item label={t("contracts.fields.kmend")} name="kmend">
|
<Form.Item label={t("contracts.fields.kmend")} name="kmend">
|
||||||
<InputNumber />
|
<InputNumber />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
@@ -145,25 +147,21 @@ export default function ContractFormComponent({ form, create = false, selectedJo
|
|||||||
>
|
>
|
||||||
<CourtesyCarFuelSlider />
|
<CourtesyCarFuelSlider />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
{create ? null : (
|
{!create && (
|
||||||
<Form.Item label={t("contracts.fields.fuelin")} name="fuelin" span={8}>
|
<Form.Item label={t("contracts.fields.fuelin")} name="fuelin" span={8}>
|
||||||
<CourtesyCarFuelSlider />
|
<CourtesyCarFuelSlider />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
)}
|
)}
|
||||||
</LayoutFormRow>
|
</LayoutFormRow>
|
||||||
<div>
|
|
||||||
<Space wrap>
|
|
||||||
{selectedJobState && (
|
|
||||||
<div>
|
|
||||||
<ContractFormJobPrefill jobId={selectedJobState && selectedJobState[0]} form={form} />
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
{
|
|
||||||
//<ContractLicenseDecodeButton form={form} />
|
|
||||||
}
|
|
||||||
</Space>
|
|
||||||
</div>
|
|
||||||
<LayoutFormRow header={t("contracts.labels.driverinformation")}>
|
<LayoutFormRow header={t("contracts.labels.driverinformation")}>
|
||||||
|
<Space wrap>
|
||||||
|
{create && selectedJobState && (
|
||||||
|
<ContractFormJobPrefill jobId={selectedJobState && selectedJobState[0]} form={form} />
|
||||||
|
)}
|
||||||
|
{/* {<ContractLicenseDecodeButton form={form} />} */}
|
||||||
|
</Space>
|
||||||
|
</LayoutFormRow>
|
||||||
|
<LayoutFormRow noDivider={true}>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
label={t("contracts.fields.driver_dlnumber")}
|
label={t("contracts.fields.driver_dlnumber")}
|
||||||
name="driver_dlnumber"
|
name="driver_dlnumber"
|
||||||
@@ -183,9 +181,8 @@ export default function ContractFormComponent({ form, create = false, selectedJo
|
|||||||
const dlExpiresBeforeReturn = dayjs(form.getFieldValue("driver_dlexpiry")).isBefore(
|
const dlExpiresBeforeReturn = dayjs(form.getFieldValue("driver_dlexpiry")).isBefore(
|
||||||
dayjs(form.getFieldValue("scheduledreturn"))
|
dayjs(form.getFieldValue("scheduledreturn"))
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
label={t("contracts.fields.driver_dlexpiry")}
|
label={t("contracts.fields.driver_dlexpiry")}
|
||||||
name="driver_dlexpiry"
|
name="driver_dlexpiry"
|
||||||
@@ -196,7 +193,7 @@ export default function ContractFormComponent({ form, create = false, selectedJo
|
|||||||
}
|
}
|
||||||
]}
|
]}
|
||||||
>
|
>
|
||||||
<FormDatePicker />
|
<DateTimePicker isDateOnly />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
{dlExpiresBeforeReturn && (
|
{dlExpiresBeforeReturn && (
|
||||||
<Space style={{ color: "tomato" }}>
|
<Space style={{ color: "tomato" }}>
|
||||||
@@ -204,11 +201,10 @@ export default function ContractFormComponent({ form, create = false, selectedJo
|
|||||||
<span>{t("contracts.labels.dlexpirebeforereturn")}</span>
|
<span>{t("contracts.labels.dlexpirebeforereturn")}</span>
|
||||||
</Space>
|
</Space>
|
||||||
)}
|
)}
|
||||||
</div>
|
</>
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
|
||||||
<Form.Item label={t("contracts.fields.driver_dlst")} name="driver_dlst">
|
<Form.Item label={t("contracts.fields.driver_dlst")} name="driver_dlst">
|
||||||
<Input />
|
<Input />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
@@ -274,7 +270,7 @@ export default function ContractFormComponent({ form, create = false, selectedJo
|
|||||||
<InputPhone />
|
<InputPhone />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item label={t("contracts.fields.driver_dob")} name="driver_dob">
|
<Form.Item label={t("contracts.fields.driver_dob")} name="driver_dob">
|
||||||
<FormDatePicker />
|
<DateTimePicker isDateOnly />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
</LayoutFormRow>
|
</LayoutFormRow>
|
||||||
<ContractsRatesChangeButton form={form} />
|
<ContractsRatesChangeButton form={form} />
|
||||||
@@ -315,6 +311,6 @@ export default function ContractFormComponent({ form, create = false, selectedJo
|
|||||||
<InputNumber precision={2} />
|
<InputNumber precision={2} />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
</LayoutFormRow>
|
</LayoutFormRow>
|
||||||
</div>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,16 +10,12 @@ import { DateFormatter } from "../../utils/DateFormatter";
|
|||||||
import CourtesyCarFuelSlider from "../courtesy-car-fuel-select/courtesy-car-fuel-select.component";
|
import CourtesyCarFuelSlider from "../courtesy-car-fuel-select/courtesy-car-fuel-select.component";
|
||||||
import CourtesyCarReadiness from "../courtesy-car-readiness-select/courtesy-car-readiness-select.component";
|
import CourtesyCarReadiness from "../courtesy-car-readiness-select/courtesy-car-readiness-select.component";
|
||||||
import CourtesyCarStatus from "../courtesy-car-status-select/courtesy-car-status-select.component";
|
import CourtesyCarStatus from "../courtesy-car-status-select/courtesy-car-status-select.component";
|
||||||
import FormDatePicker from "../form-date-picker/form-date-picker.component";
|
|
||||||
import FormFieldsChanged from "../form-fields-changed-alert/form-fields-changed-alert.component";
|
import FormFieldsChanged from "../form-fields-changed-alert/form-fields-changed-alert.component";
|
||||||
import CurrencyInput from "../form-items-formatted/currency-form-item.component";
|
import CurrencyInput from "../form-items-formatted/currency-form-item.component";
|
||||||
import LayoutFormRow from "../layout-form-row/layout-form-row.component";
|
import LayoutFormRow from "../layout-form-row/layout-form-row.component";
|
||||||
|
import DateTimePicker from "../form-date-time-picker/form-date-time-picker.component.jsx";
|
||||||
|
|
||||||
export default function CourtesyCarCreateFormComponent({
|
export default function CourtesyCarCreateFormComponent({ form, saveLoading, newCC }) {
|
||||||
form,
|
|
||||||
saveLoading,
|
|
||||||
newCC,
|
|
||||||
}) {
|
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const client = useApolloClient();
|
const client = useApolloClient();
|
||||||
|
|
||||||
@@ -161,16 +157,16 @@ export default function CourtesyCarCreateFormComponent({
|
|||||||
<Input />
|
<Input />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item label={t("courtesycars.fields.purchasedate")} name="purchasedate">
|
<Form.Item label={t("courtesycars.fields.purchasedate")} name="purchasedate">
|
||||||
<FormDatePicker />
|
<DateTimePicker isDateOnly />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item label={t("courtesycars.fields.servicestartdate")} name="servicestartdate">
|
<Form.Item label={t("courtesycars.fields.servicestartdate")} name="servicestartdate">
|
||||||
<FormDatePicker />
|
<DateTimePicker isDateOnly />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item label={t("courtesycars.fields.serviceenddate")} name="serviceenddate">
|
<Form.Item label={t("courtesycars.fields.serviceenddate")} name="serviceenddate">
|
||||||
<FormDatePicker />
|
<DateTimePicker isDateOnly />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item label={t("courtesycars.fields.leaseenddate")} name="leaseenddate">
|
<Form.Item label={t("courtesycars.fields.leaseenddate")} name="leaseenddate">
|
||||||
<FormDatePicker />
|
<DateTimePicker isDateOnly />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
</LayoutFormRow>
|
</LayoutFormRow>
|
||||||
|
|
||||||
@@ -228,7 +224,7 @@ export default function CourtesyCarCreateFormComponent({
|
|||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<Form.Item label={t("courtesycars.fields.nextservicedate")} name="nextservicedate">
|
<Form.Item label={t("courtesycars.fields.nextservicedate")} name="nextservicedate">
|
||||||
<FormDatePicker />
|
<DateTimePicker isDateOnly />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item shouldUpdate={(p, c) => p.nextservicedate !== c.nextservicedate}>
|
<Form.Item shouldUpdate={(p, c) => p.nextservicedate !== c.nextservicedate}>
|
||||||
{() => {
|
{() => {
|
||||||
@@ -260,7 +256,7 @@ export default function CourtesyCarCreateFormComponent({
|
|||||||
</Form.Item>
|
</Form.Item>
|
||||||
<div>
|
<div>
|
||||||
<Form.Item label={t("courtesycars.fields.registrationexpires")} name="registrationexpires">
|
<Form.Item label={t("courtesycars.fields.registrationexpires")} name="registrationexpires">
|
||||||
<FormDatePicker />
|
<DateTimePicker isDateOnly />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item shouldUpdate={(p, c) => p.registrationexpires !== c.registrationexpires}>
|
<Form.Item shouldUpdate={(p, c) => p.registrationexpires !== c.registrationexpires}>
|
||||||
{() => {
|
{() => {
|
||||||
@@ -293,7 +289,7 @@ export default function CourtesyCarCreateFormComponent({
|
|||||||
}
|
}
|
||||||
]}
|
]}
|
||||||
>
|
>
|
||||||
<FormDatePicker />
|
<DateTimePicker isDateOnly />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item shouldUpdate={(p, c) => p.insuranceexpires !== c.insuranceexpires}>
|
<Form.Item shouldUpdate={(p, c) => p.insuranceexpires !== c.insuranceexpires}>
|
||||||
{() => {
|
{() => {
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { Form, InputNumber } from "antd";
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import CourtesyCarFuelSlider from "../courtesy-car-fuel-select/courtesy-car-fuel-select.component";
|
import CourtesyCarFuelSlider from "../courtesy-car-fuel-select/courtesy-car-fuel-select.component";
|
||||||
import FormDatePicker from "../form-date-picker/form-date-picker.component";
|
import DateTimePicker from "../form-date-time-picker/form-date-time-picker.component.jsx";
|
||||||
|
|
||||||
export default function CourtesyCarReturnModalComponent() {
|
export default function CourtesyCarReturnModalComponent() {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
@@ -19,7 +19,7 @@ export default function CourtesyCarReturnModalComponent() {
|
|||||||
}
|
}
|
||||||
]}
|
]}
|
||||||
>
|
>
|
||||||
<FormDatePicker />
|
<DateTimePicker isDateOnly />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
label={t("contracts.fields.kmend")}
|
label={t("contracts.fields.kmend")}
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ import axios from "axios";
|
|||||||
const fortyFiveDaysAgo = () => dayjs().subtract(45, "day").toLocaleString();
|
const fortyFiveDaysAgo = () => dayjs().subtract(45, "day").toLocaleString();
|
||||||
|
|
||||||
export default function JobLifecycleDashboardComponent({ data, bodyshop, ...cardProps }) {
|
export default function JobLifecycleDashboardComponent({ data, bodyshop, ...cardProps }) {
|
||||||
console.log("🚀 ~ JobLifecycleDashboardComponent ~ bodyshop:", bodyshop);
|
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const [lifecycleData, setLifecycleData] = useState(null);
|
const [lifecycleData, setLifecycleData] = useState(null);
|
||||||
@@ -143,7 +142,7 @@ export default function JobLifecycleDashboardComponent({ data, bodyshop, ...card
|
|||||||
>
|
>
|
||||||
<div>
|
<div>
|
||||||
{lifecycleData.summations.map((key) => (
|
{lifecycleData.summations.map((key) => (
|
||||||
<Tag color={key.color} style={{ width: "13vh", padding: "4px", margin: "4px" }}>
|
<Tag key={key.status} color={key.color} style={{ width: "13vh", padding: "4px", margin: "4px" }}>
|
||||||
<div
|
<div
|
||||||
aria-label={`${key.status} | ${key.roundedPercentage} | ${key.humanReadable}`}
|
aria-label={`${key.status} | ${key.roundedPercentage} | ${key.humanReadable}`}
|
||||||
title={`${key.status} | ${key.roundedPercentage} | ${key.humanReadable}`}
|
title={`${key.status} | ${key.roundedPercentage} | ${key.humanReadable}`}
|
||||||
@@ -165,6 +164,7 @@ export default function JobLifecycleDashboardComponent({ data, bodyshop, ...card
|
|||||||
size="small"
|
size="small"
|
||||||
pagination={false}
|
pagination={false}
|
||||||
columns={columns}
|
columns={columns}
|
||||||
|
rowKey={(record) => record.status}
|
||||||
dataSource={lifecycleData.summations.sort((a, b) => b.value - a.value).slice(0, 3)}
|
dataSource={lifecycleData.summations.sort((a, b) => b.value - a.value).slice(0, 3)}
|
||||||
/>
|
/>
|
||||||
</Card>
|
</Card>
|
||||||
|
|||||||
@@ -36,9 +36,6 @@ export default function DashboardScheduledOutToday({ data, ...cardProps }) {
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
console.log("Scheduled Out Today");
|
|
||||||
console.dir(scheduledOutToday);
|
|
||||||
|
|
||||||
const tvFontSize = 18;
|
const tvFontSize = 18;
|
||||||
const tvFontWeight = "bold";
|
const tvFontWeight = "bold";
|
||||||
|
|
||||||
@@ -89,8 +86,6 @@ export default function DashboardScheduledOutToday({ data, ...cardProps }) {
|
|||||||
sorter: (a, b) => alphaSort(OwnerNameDisplayFunction(a), OwnerNameDisplayFunction(b)),
|
sorter: (a, b) => alphaSort(OwnerNameDisplayFunction(a), OwnerNameDisplayFunction(b)),
|
||||||
sortOrder: state.sortedInfo.columnKey === "owner" && state.sortedInfo.order,
|
sortOrder: state.sortedInfo.columnKey === "owner" && state.sortedInfo.order,
|
||||||
render: (text, record) => {
|
render: (text, record) => {
|
||||||
console.log("Render record out today");
|
|
||||||
console.dir(record);
|
|
||||||
return record.ownerid ? (
|
return record.ownerid ? (
|
||||||
<Link to={"/manage/owners/" + record.ownerid} onClick={(e) => e.stopPropagation()}>
|
<Link to={"/manage/owners/" + record.ownerid} onClick={(e) => e.stopPropagation()}>
|
||||||
<span style={{ fontSize: tvFontSize, fontWeight: tvFontWeight }}>
|
<span style={{ fontSize: tvFontSize, fontWeight: tvFontWeight }}>
|
||||||
|
|||||||
@@ -40,8 +40,6 @@ export function DmsLogEvents({ socket, logs, bodyshop }) {
|
|||||||
|
|
||||||
function LogLevelHierarchy(level) {
|
function LogLevelHierarchy(level) {
|
||||||
switch (level) {
|
switch (level) {
|
||||||
case "TRACE":
|
|
||||||
return "pink";
|
|
||||||
case "DEBUG":
|
case "DEBUG":
|
||||||
return "orange";
|
return "orange";
|
||||||
case "INFO":
|
case "INFO":
|
||||||
|
|||||||
@@ -24,9 +24,9 @@ import i18n from "../../translations/i18n";
|
|||||||
import dayjs from "../../utils/day";
|
import dayjs from "../../utils/day";
|
||||||
import DmsCdkMakes from "../dms-cdk-makes/dms-cdk-makes.component";
|
import DmsCdkMakes from "../dms-cdk-makes/dms-cdk-makes.component";
|
||||||
import DmsCdkMakesRefetch from "../dms-cdk-makes/dms-cdk-makes.refetch.component";
|
import DmsCdkMakesRefetch from "../dms-cdk-makes/dms-cdk-makes.refetch.component";
|
||||||
import FormDatePicker from "../form-date-picker/form-date-picker.component";
|
|
||||||
import CurrencyInput from "../form-items-formatted/currency-form-item.component";
|
import CurrencyInput from "../form-items-formatted/currency-form-item.component";
|
||||||
import LayoutFormRow from "../layout-form-row/layout-form-row.component";
|
import LayoutFormRow from "../layout-form-row/layout-form-row.component";
|
||||||
|
import DateTimePicker from "../form-date-time-picker/form-date-time-picker.component.jsx";
|
||||||
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
bodyshop: selectBodyshop
|
bodyshop: selectBodyshop
|
||||||
@@ -164,7 +164,7 @@ export function DmsPostForm({ bodyshop, socket, job, logsRef }) {
|
|||||||
<Input disabled />
|
<Input disabled />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item name="inservicedate" label={t("jobs.fields.dms.inservicedate")}>
|
<Form.Item name="inservicedate" label={t("jobs.fields.dms.inservicedate")}>
|
||||||
<FormDatePicker />
|
<DateTimePicker isDateOnly />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
</LayoutFormRow>
|
</LayoutFormRow>
|
||||||
<Space>
|
<Space>
|
||||||
|
|||||||
@@ -4,14 +4,14 @@ import Markdown from "react-markdown";
|
|||||||
import { createStructuredSelector } from "reselect";
|
import { createStructuredSelector } from "reselect";
|
||||||
import { selectCurrentEula, selectCurrentUser } from "../../redux/user/user.selectors";
|
import { selectCurrentEula, selectCurrentUser } from "../../redux/user/user.selectors";
|
||||||
import { connect } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
import { FormDatePicker } from "../form-date-picker/form-date-picker.component";
|
|
||||||
import { INSERT_EULA_ACCEPTANCE } from "../../graphql/user.queries";
|
import { INSERT_EULA_ACCEPTANCE } from "../../graphql/user.queries";
|
||||||
import { useMutation } from "@apollo/client";
|
import { useMutation } from "@apollo/client";
|
||||||
import { acceptEula } from "../../redux/user/user.actions";
|
import { acceptEula } from "../../redux/user/user.actions";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import day from "../../utils/day";
|
import dayjs from "../../utils/day";
|
||||||
|
|
||||||
import "./eula.styles.scss";
|
import "./eula.styles.scss";
|
||||||
|
import DateTimePicker from "../form-date-time-picker/form-date-time-picker.component.jsx";
|
||||||
|
|
||||||
const Eula = ({ currentEula, currentUser, acceptEula }) => {
|
const Eula = ({ currentEula, currentUser, acceptEula }) => {
|
||||||
const [formReady, setFormReady] = useState(false);
|
const [formReady, setFormReady] = useState(false);
|
||||||
@@ -208,7 +208,7 @@ const EulaFormComponent = ({ form, handleChange, onFinish, t }) => (
|
|||||||
{
|
{
|
||||||
required: true,
|
required: true,
|
||||||
validator: (_, value) => {
|
validator: (_, value) => {
|
||||||
if (day(value).isSame(day(), "day")) {
|
if (dayjs(value).isSame(dayjs(), "day")) {
|
||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
}
|
}
|
||||||
return Promise.reject(new Error(t("eula.messages.date_accepted")));
|
return Promise.reject(new Error(t("eula.messages.date_accepted")));
|
||||||
@@ -216,7 +216,7 @@ const EulaFormComponent = ({ form, handleChange, onFinish, t }) => (
|
|||||||
}
|
}
|
||||||
]}
|
]}
|
||||||
>
|
>
|
||||||
<FormDatePicker onChange={handleChange} onlyToday aria-label={t("eula.labels.date_accepted")} />
|
<DateTimePicker isDateOnly onChange={handleChange} onlyToday aria-label={t("eula.labels.date_accepted")} />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
|
|||||||
@@ -1,123 +0,0 @@
|
|||||||
import { DatePicker } from "antd";
|
|
||||||
import dayjs from "../../utils/day";
|
|
||||||
import React, { useRef } from "react";
|
|
||||||
|
|
||||||
import { connect } from "react-redux";
|
|
||||||
import { createStructuredSelector } from "reselect";
|
|
||||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
|
||||||
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
|
||||||
bodyshop: selectBodyshop
|
|
||||||
});
|
|
||||||
const mapDispatchToProps = (dispatch) => ({
|
|
||||||
//setUserLanguage: language => dispatch(setUserLanguage(language))
|
|
||||||
});
|
|
||||||
export default connect(mapStateToProps, mapDispatchToProps)(FormDatePicker);
|
|
||||||
|
|
||||||
const dateFormat = "MM/DD/YYYY";
|
|
||||||
|
|
||||||
export function FormDatePicker({
|
|
||||||
bodyshop,
|
|
||||||
value,
|
|
||||||
onChange,
|
|
||||||
onBlur,
|
|
||||||
onlyFuture,
|
|
||||||
onlyToday,
|
|
||||||
isDateOnly = true,
|
|
||||||
...restProps
|
|
||||||
}) {
|
|
||||||
const ref = useRef();
|
|
||||||
|
|
||||||
const handleChange = (newDate) => {
|
|
||||||
if (value !== newDate && onChange) {
|
|
||||||
onChange(isDateOnly ? newDate && newDate.format("YYYY-MM-DD") : newDate);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleKeyDown = (e) => {
|
|
||||||
if (e.key.toLowerCase() === "t") {
|
|
||||||
if (onChange) {
|
|
||||||
onChange(isDateOnly ? dayjs().format("YYYY-MM-DD") : dayjs());
|
|
||||||
}
|
|
||||||
} else if (e.key.toLowerCase() === "enter") {
|
|
||||||
if (ref.current && ref.current.blur) ref.current.blur();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleBlur = (e) => {
|
|
||||||
const v = e.target.value;
|
|
||||||
if (!v) return;
|
|
||||||
|
|
||||||
const formats = [
|
|
||||||
"MMDDYY",
|
|
||||||
"MMDDYYYY",
|
|
||||||
"MM/DD/YY",
|
|
||||||
"MM/DD/YYYY",
|
|
||||||
"M/DD/YY",
|
|
||||||
"M/DD/YYYY",
|
|
||||||
"MM/D/YY",
|
|
||||||
"MM/D/YYYY",
|
|
||||||
"M/D/YY",
|
|
||||||
"M/D/YYYY",
|
|
||||||
"D/MM/YY",
|
|
||||||
"D/MM/YYYY",
|
|
||||||
"DD/M/YY",
|
|
||||||
"DD/M/YYYY",
|
|
||||||
"D/M/YY",
|
|
||||||
"D/M/YYYY"
|
|
||||||
];
|
|
||||||
|
|
||||||
let _a;
|
|
||||||
|
|
||||||
// Iterate through formats to find the correct one
|
|
||||||
for (let format of formats) {
|
|
||||||
_a = dayjs(v, format);
|
|
||||||
if (v === _a.format(format)) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_a.isValid() && value && value.isValid && value.isValid()) {
|
|
||||||
_a.set({
|
|
||||||
hours: value.hours(),
|
|
||||||
minutes: value.minutes(),
|
|
||||||
seconds: value.seconds(),
|
|
||||||
milliseconds: value.milliseconds()
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_a.isValid() && onChange) {
|
|
||||||
if (onlyFuture) {
|
|
||||||
if (dayjs().subtract(1, "day").isBefore(_a)) {
|
|
||||||
onChange(isDateOnly ? _a.format("YYYY-MM-DD") : _a);
|
|
||||||
} else {
|
|
||||||
onChange(isDateOnly ? dayjs().format("YYYY-MM-DD") : dayjs());
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
onChange(isDateOnly ? _a.format("YYYY-MM-DD") : _a);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div onKeyDown={handleKeyDown}>
|
|
||||||
<DatePicker
|
|
||||||
ref={ref}
|
|
||||||
value={value ? dayjs(value) : null}
|
|
||||||
onChange={handleChange}
|
|
||||||
format={dateFormat}
|
|
||||||
onBlur={onBlur || handleBlur}
|
|
||||||
showToday={false}
|
|
||||||
disabledTime
|
|
||||||
disabledDate={(d) => {
|
|
||||||
if (onlyToday) {
|
|
||||||
return !dayjs().isSame(d, "day");
|
|
||||||
} else if (onlyFuture) {
|
|
||||||
return dayjs().subtract(1, "day").isAfter(d);
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
{...restProps}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,48 +0,0 @@
|
|||||||
import { DatePicker } from "antd";
|
|
||||||
import dayjs from "../../utils/day.js";
|
|
||||||
import React, { useRef } from "react";
|
|
||||||
|
|
||||||
import { connect } from "react-redux";
|
|
||||||
import { createStructuredSelector } from "reselect";
|
|
||||||
import { selectBodyshop } from "../../redux/user/user.selectors.js";
|
|
||||||
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
|
||||||
bodyshop: selectBodyshop
|
|
||||||
});
|
|
||||||
const mapDispatchToProps = (dispatch) => ({
|
|
||||||
//setUserLanguage: language => dispatch(setUserLanguage(language))
|
|
||||||
});
|
|
||||||
export default connect(mapStateToProps, mapDispatchToProps)(FormDateTimePickerEnhanced);
|
|
||||||
|
|
||||||
const dateFormat = "MM/DD/YYYY h:mm a";
|
|
||||||
|
|
||||||
export function FormDateTimePickerEnhanced({
|
|
||||||
bodyshop,
|
|
||||||
value,
|
|
||||||
onBlur,
|
|
||||||
onlyFuture,
|
|
||||||
onlyToday,
|
|
||||||
isDateOnly = true,
|
|
||||||
...restProps
|
|
||||||
}) {
|
|
||||||
const ref = useRef();
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<DatePicker
|
|
||||||
ref={ref}
|
|
||||||
value={value ? dayjs(value) : null}
|
|
||||||
format={dateFormat}
|
|
||||||
onBlur={onBlur}
|
|
||||||
showToday={false}
|
|
||||||
disabledDate={(d) => {
|
|
||||||
if (onlyToday) {
|
|
||||||
return !dayjs().isSame(d, "day");
|
|
||||||
} else if (onlyFuture) {
|
|
||||||
return dayjs().subtract(1, "day").isAfter(d);
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
{...restProps}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,46 +1,123 @@
|
|||||||
import React, { forwardRef } from "react";
|
import { DatePicker } from "antd";
|
||||||
//import DatePicker from "react-datepicker";
|
import PropTypes from "prop-types";
|
||||||
//import "react-datepicker/src/stylesheets/datepicker.scss";
|
import React, { useCallback, useState } from "react";
|
||||||
import { Space, TimePicker } from "antd";
|
import { useTranslation } from "react-i18next";
|
||||||
import dayjs from "../../utils/day";
|
import dayjs from "../../utils/day";
|
||||||
import FormDatePicker from "../form-date-picker/form-date-picker.component";
|
import { fuzzyMatchDate } from "./formats.js";
|
||||||
//To be used as a form element only.
|
import { createStructuredSelector } from "reselect";
|
||||||
|
import { selectBodyshop } from "../../redux/user/user.selectors.js";
|
||||||
|
import { connect } from "react-redux";
|
||||||
|
|
||||||
const DateTimePicker = ({ value, onChange, onBlur, id, onlyFuture, ...restProps }, ref) => {
|
const mapStateToProps = createStructuredSelector({
|
||||||
// const handleChange = (newDate) => {
|
bodyshop: selectBodyshop
|
||||||
// if (value !== newDate && onChange) {
|
});
|
||||||
// onChange(newDate);
|
|
||||||
// }
|
const DateTimePicker = ({
|
||||||
// };
|
value,
|
||||||
|
onChange,
|
||||||
|
onBlur,
|
||||||
|
id,
|
||||||
|
onlyFuture,
|
||||||
|
onlyToday,
|
||||||
|
isDateOnly = false,
|
||||||
|
bodyshop,
|
||||||
|
...restProps
|
||||||
|
}) => {
|
||||||
|
const [isManualInput, setIsManualInput] = useState(false);
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
|
const handleChange = useCallback(
|
||||||
|
(newDate) => {
|
||||||
|
if (!newDate) return;
|
||||||
|
if (onChange) {
|
||||||
|
onChange(bodyshop?.timezone ? dayjs(newDate).tz(bodyshop.timezone, true) : newDate);
|
||||||
|
}
|
||||||
|
setIsManualInput(false);
|
||||||
|
},
|
||||||
|
[onChange, bodyshop?.timezone]
|
||||||
|
);
|
||||||
|
|
||||||
|
const handleBlur = useCallback(
|
||||||
|
(e) => {
|
||||||
|
// Bail if this is not a manual input
|
||||||
|
if (!isManualInput) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Reset manual input flag
|
||||||
|
setIsManualInput(false);
|
||||||
|
|
||||||
|
const v = e?.target?.value;
|
||||||
|
|
||||||
|
if (!v) return;
|
||||||
|
|
||||||
|
let parsedDate = isDateOnly ? fuzzyMatchDate(v)?.startOf("day") : fuzzyMatchDate(v);
|
||||||
|
|
||||||
|
if (parsedDate && onChange) {
|
||||||
|
onChange(parsedDate);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[isManualInput, isDateOnly, onChange]
|
||||||
|
);
|
||||||
|
|
||||||
|
const handleKeyDown = useCallback(
|
||||||
|
(e) => {
|
||||||
|
setIsManualInput(true);
|
||||||
|
|
||||||
|
if (e.key.toLowerCase() === "t" && onChange) {
|
||||||
|
e.preventDefault();
|
||||||
|
setIsManualInput(false);
|
||||||
|
onChange(dayjs());
|
||||||
|
} else if (e.key.toLowerCase() === "enter") {
|
||||||
|
handleBlur(e);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[onChange, handleBlur]
|
||||||
|
);
|
||||||
|
|
||||||
|
const handleDisabledDate = useCallback(
|
||||||
|
(current) => {
|
||||||
|
if (onlyToday) {
|
||||||
|
return !dayjs().isSame(current, "day");
|
||||||
|
} else if (onlyFuture) {
|
||||||
|
return dayjs().subtract(1, "day").isAfter(current);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
[onlyToday, onlyFuture]
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Space direction="vertical" style={{ width: "100%" }} id={id}>
|
<div onKeyDown={handleKeyDown} id={id} style={{ width: "100%" }}>
|
||||||
<FormDatePicker
|
<DatePicker
|
||||||
{...restProps}
|
showTime={
|
||||||
{...(onlyFuture && {
|
isDateOnly
|
||||||
disabledDate: (d) => dayjs().subtract(1, "day").isAfter(d)
|
? false
|
||||||
})}
|
: {
|
||||||
value={value}
|
format: "hh:mm a",
|
||||||
onBlur={onBlur}
|
minuteStep: 15,
|
||||||
onChange={onChange}
|
defaultValue: dayjs(dayjs(), "HH:mm:ss")
|
||||||
onlyFuture={onlyFuture}
|
}
|
||||||
isDateOnly={false}
|
}
|
||||||
/>
|
format={isDateOnly ? "MM/DD/YYYY" : "MM/DD/YYYY hh:mm a"}
|
||||||
|
|
||||||
<TimePicker
|
|
||||||
value={value ? dayjs(value) : null}
|
value={value ? dayjs(value) : null}
|
||||||
{...(onlyFuture && {
|
onChange={handleChange}
|
||||||
disabledDate: (d) => dayjs().isAfter(d)
|
placeholder={isDateOnly ? t("general.labels.date") : t("general.labels.datetime")}
|
||||||
})}
|
onBlur={onBlur || handleBlur}
|
||||||
onChange={onChange}
|
disabledDate={handleDisabledDate}
|
||||||
disableSeconds={true}
|
|
||||||
minuteStep={15}
|
|
||||||
onBlur={onBlur}
|
|
||||||
format="hh:mm a"
|
|
||||||
{...restProps}
|
{...restProps}
|
||||||
/>
|
/>
|
||||||
</Space>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default forwardRef(DateTimePicker);
|
DateTimePicker.propTypes = {
|
||||||
|
value: PropTypes.any,
|
||||||
|
onChange: PropTypes.func,
|
||||||
|
onBlur: PropTypes.func,
|
||||||
|
id: PropTypes.string,
|
||||||
|
onlyFuture: PropTypes.bool,
|
||||||
|
onlyToday: PropTypes.bool,
|
||||||
|
isDateOnly: PropTypes.bool
|
||||||
|
};
|
||||||
|
|
||||||
|
export default connect(mapStateToProps, null)(DateTimePicker);
|
||||||
|
|||||||
63
client/src/components/form-date-time-picker/formats.js
Normal file
63
client/src/components/form-date-time-picker/formats.js
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
import dayjs from "../../utils/day";
|
||||||
|
|
||||||
|
const dateFormats = [
|
||||||
|
"MMDDYYYY",
|
||||||
|
"MMDDYY",
|
||||||
|
"M/D/YYYY",
|
||||||
|
"MM/D/YYYY",
|
||||||
|
"M/DD/YYYY",
|
||||||
|
"MM/DD/YYYY",
|
||||||
|
"M/D/YY",
|
||||||
|
"MM/D/YY",
|
||||||
|
"M/DD/YY",
|
||||||
|
"MM/DD/YY"
|
||||||
|
];
|
||||||
|
|
||||||
|
const timeFormats = ["h:mm A", "h:mmA", "h A", "hA", "hh:mm A", "hh:mm:ss A"];
|
||||||
|
|
||||||
|
const dateTimeFormats = [
|
||||||
|
...["M/D/YYYY", "MM/D/YYYY", "M/DD/YYYY", "MM/DD/YYYY", "M/D/YY", "MM/D/YY", "M/DD/YY", "MM/DD/YY"].flatMap(
|
||||||
|
(dateFormat) => timeFormats.map((timeFormat) => `${dateFormat} ${timeFormat}`)
|
||||||
|
),
|
||||||
|
|
||||||
|
...["MMDDYYYY", "MMDDYY"].flatMap((dateFormat) => timeFormats.map((timeFormat) => `${dateFormat} ${timeFormat}`)),
|
||||||
|
|
||||||
|
"M/D/YYYY",
|
||||||
|
"MM/D/YYYY",
|
||||||
|
"M/DD/YYYY",
|
||||||
|
"MM/DD/YYYY",
|
||||||
|
"M/D/YY",
|
||||||
|
"MM/D/YY",
|
||||||
|
"M/DD/YY",
|
||||||
|
"MM/DD/YY",
|
||||||
|
"MMDDYYYY",
|
||||||
|
"MMDDYY"
|
||||||
|
];
|
||||||
|
|
||||||
|
const sanitizeInput = (input) =>
|
||||||
|
input
|
||||||
|
.trim()
|
||||||
|
.toUpperCase()
|
||||||
|
.replace(/\s*(am|pm)\s*/i, " $1")
|
||||||
|
.replaceAll(".", "/")
|
||||||
|
.replaceAll("-", "/");
|
||||||
|
|
||||||
|
export const fuzzyMatchDate = (dateString) => {
|
||||||
|
const sanitizedInput = sanitizeInput(dateString);
|
||||||
|
|
||||||
|
for (const format of dateFormats) {
|
||||||
|
const parsedDate = dayjs(sanitizedInput, format, true);
|
||||||
|
if (parsedDate.isValid()) {
|
||||||
|
return parsedDate;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const format of dateTimeFormats) {
|
||||||
|
const parsedDateTime = dayjs(sanitizedInput, format, true);
|
||||||
|
if (parsedDateTime.isValid()) {
|
||||||
|
return parsedDateTime; // Return the dayjs object
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null; // If no matching format is found
|
||||||
|
};
|
||||||
@@ -3,13 +3,15 @@ import axios from "axios";
|
|||||||
import _ from "lodash";
|
import _ from "lodash";
|
||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { Link } from "react-router-dom";
|
import { Link, useNavigate } from "react-router-dom";
|
||||||
import PhoneNumberFormatter from "../../utils/PhoneFormatter";
|
import PhoneNumberFormatter from "../../utils/PhoneFormatter";
|
||||||
import OwnerNameDisplay, { OwnerNameDisplayFunction } from "../owner-name-display/owner-name-display.component";
|
import OwnerNameDisplay, { OwnerNameDisplayFunction } from "../owner-name-display/owner-name-display.component";
|
||||||
import VehicleVinDisplay from "../vehicle-vin-display/vehicle-vin-display.component";
|
import VehicleVinDisplay from "../vehicle-vin-display/vehicle-vin-display.component";
|
||||||
|
|
||||||
export default function GlobalSearchOs() {
|
export default function GlobalSearchOs() {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
const navigate = useNavigate();
|
||||||
|
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const [data, setData] = useState(false);
|
const [data, setData] = useState(false);
|
||||||
|
|
||||||
@@ -177,7 +179,18 @@ export default function GlobalSearchOs() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AutoComplete options={data} onSearch={handleSearch} defaultActiveFirstOption onClear={() => setData([])}>
|
<AutoComplete
|
||||||
|
options={data}
|
||||||
|
onSearch={handleSearch}
|
||||||
|
onKeyDown={(e) => {
|
||||||
|
if (e.key !== "Enter") return;
|
||||||
|
const firstUrlForSearch = data?.[0]?.options?.[0]?.label?.props?.to;
|
||||||
|
if (!firstUrlForSearch) return;
|
||||||
|
navigate(firstUrlForSearch);
|
||||||
|
}}
|
||||||
|
defaultActiveFirstOption
|
||||||
|
onClear={() => setData([])}
|
||||||
|
>
|
||||||
<Input.Search
|
<Input.Search
|
||||||
size="large"
|
size="large"
|
||||||
placeholder={t("general.labels.globalsearch")}
|
placeholder={t("general.labels.globalsearch")}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { AutoComplete, Divider, Input, Space } from "antd";
|
|||||||
import _ from "lodash";
|
import _ from "lodash";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { Link } from "react-router-dom";
|
import { Link, useNavigate } from "react-router-dom";
|
||||||
import { GLOBAL_SEARCH_QUERY } from "../../graphql/search.queries";
|
import { GLOBAL_SEARCH_QUERY } from "../../graphql/search.queries";
|
||||||
import PhoneNumberFormatter from "../../utils/PhoneFormatter";
|
import PhoneNumberFormatter from "../../utils/PhoneFormatter";
|
||||||
import AlertComponent from "../alert/alert.component";
|
import AlertComponent from "../alert/alert.component";
|
||||||
@@ -13,6 +13,7 @@ import VehicleVinDisplay from "../vehicle-vin-display/vehicle-vin-display.compon
|
|||||||
export default function GlobalSearch() {
|
export default function GlobalSearch() {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const [callSearch, { loading, error, data }] = useLazyQuery(GLOBAL_SEARCH_QUERY);
|
const [callSearch, { loading, error, data }] = useLazyQuery(GLOBAL_SEARCH_QUERY);
|
||||||
|
const navigate = useNavigate();
|
||||||
|
|
||||||
const executeSearch = (v) => {
|
const executeSearch = (v) => {
|
||||||
if (v && v.variables.search && v.variables.search !== "" && v.variables.search.length >= 3) callSearch(v);
|
if (v && v.variables.search && v.variables.search !== "" && v.variables.search.length >= 3) callSearch(v);
|
||||||
@@ -20,7 +21,6 @@ export default function GlobalSearch() {
|
|||||||
const debouncedExecuteSearch = _.debounce(executeSearch, 750);
|
const debouncedExecuteSearch = _.debounce(executeSearch, 750);
|
||||||
|
|
||||||
const handleSearch = (value) => {
|
const handleSearch = (value) => {
|
||||||
console.log("Handle Search");
|
|
||||||
debouncedExecuteSearch({ variables: { search: value } });
|
debouncedExecuteSearch({ variables: { search: value } });
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -156,7 +156,17 @@ export default function GlobalSearch() {
|
|||||||
if (error) return <AlertComponent message={error.message} type="error" />;
|
if (error) return <AlertComponent message={error.message} type="error" />;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AutoComplete options={options} onSearch={handleSearch} defaultActiveFirstOption>
|
<AutoComplete
|
||||||
|
options={options}
|
||||||
|
onSearch={handleSearch}
|
||||||
|
defaultActiveFirstOption
|
||||||
|
onKeyDown={(e) => {
|
||||||
|
if (e.key !== "Enter") return;
|
||||||
|
const firstUrlForSearch = options?.[0]?.options?.[0]?.label?.props?.to;
|
||||||
|
if (!firstUrlForSearch) return;
|
||||||
|
navigate(firstUrlForSearch);
|
||||||
|
}}
|
||||||
|
>
|
||||||
<Input.Search
|
<Input.Search
|
||||||
size="large"
|
size="large"
|
||||||
placeholder={t("general.labels.globalsearch")}
|
placeholder={t("general.labels.globalsearch")}
|
||||||
|
|||||||
@@ -13,7 +13,6 @@ import Icon, {
|
|||||||
FileFilled,
|
FileFilled,
|
||||||
HomeFilled,
|
HomeFilled,
|
||||||
ImportOutlined,
|
ImportOutlined,
|
||||||
InfoCircleOutlined,
|
|
||||||
LineChartOutlined,
|
LineChartOutlined,
|
||||||
PaperClipOutlined,
|
PaperClipOutlined,
|
||||||
PhoneOutlined,
|
PhoneOutlined,
|
||||||
@@ -27,8 +26,8 @@ import Icon, {
|
|||||||
UserOutlined
|
UserOutlined
|
||||||
} from "@ant-design/icons";
|
} from "@ant-design/icons";
|
||||||
import { useSplitTreatments } from "@splitsoftware/splitio-react";
|
import { useSplitTreatments } from "@splitsoftware/splitio-react";
|
||||||
import { Layout, Menu, Switch, Tooltip } from "antd";
|
import { Layout, Menu } from "antd";
|
||||||
import React, { useEffect, useState } from "react";
|
import React from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { BsKanban } from "react-icons/bs";
|
import { BsKanban } from "react-icons/bs";
|
||||||
import { FaCalendarAlt, FaCarCrash, FaCreditCard, FaFileInvoiceDollar, FaTasks } from "react-icons/fa";
|
import { FaCalendarAlt, FaCarCrash, FaCreditCard, FaFileInvoiceDollar, FaTasks } from "react-icons/fa";
|
||||||
@@ -43,7 +42,6 @@ import { selectRecentItems, selectSelectedHeader } from "../../redux/application
|
|||||||
import { setModalContext } from "../../redux/modals/modals.actions";
|
import { setModalContext } from "../../redux/modals/modals.actions";
|
||||||
import { signOutStart } from "../../redux/user/user.actions";
|
import { signOutStart } from "../../redux/user/user.actions";
|
||||||
import { selectBodyshop, selectCurrentUser } from "../../redux/user/user.selectors";
|
import { selectBodyshop, selectCurrentUser } from "../../redux/user/user.selectors";
|
||||||
import { checkBeta, handleBeta, setBeta } from "../../utils/betaHandler";
|
|
||||||
import InstanceRenderManager from "../../utils/instanceRenderMgr";
|
import InstanceRenderManager from "../../utils/instanceRenderMgr";
|
||||||
import { HasFeatureAccess } from "../feature-wrapper/feature-wrapper.component";
|
import { HasFeatureAccess } from "../feature-wrapper/feature-wrapper.component";
|
||||||
|
|
||||||
@@ -115,19 +113,18 @@ function Header({
|
|||||||
names: ["ImEXPay", "DmsAp", "Simple_Inventory"],
|
names: ["ImEXPay", "DmsAp", "Simple_Inventory"],
|
||||||
splitKey: bodyshop && bodyshop.imexshopid
|
splitKey: bodyshop && bodyshop.imexshopid
|
||||||
});
|
});
|
||||||
const [betaSwitch, setBetaSwitch] = useState(false);
|
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
useEffect(() => {
|
// const deleteBetaCookie = () => {
|
||||||
const isBeta = checkBeta();
|
// const cookieExists = document.cookie.split("; ").some((row) => row.startsWith(`betaSwitchImex=`));
|
||||||
setBetaSwitch(isBeta);
|
// if (cookieExists) {
|
||||||
}, []);
|
// const domain = window.location.hostname.split(".").slice(-2).join(".");
|
||||||
|
// document.cookie = `betaSwitchImex=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/; domain=.${domain}`;
|
||||||
const betaSwitchChange = (checked) => {
|
// }
|
||||||
setBeta(checked);
|
// };
|
||||||
setBetaSwitch(checked);
|
//
|
||||||
handleBeta();
|
// deleteBetaCookie();
|
||||||
};
|
|
||||||
|
|
||||||
const accountingChildren = [];
|
const accountingChildren = [];
|
||||||
|
|
||||||
@@ -695,31 +692,6 @@ function Header({
|
|||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
InstanceRenderManager({
|
|
||||||
executeFunction: true,
|
|
||||||
args: [],
|
|
||||||
imex: () => {
|
|
||||||
menuItems.push({
|
|
||||||
key: "beta-switch",
|
|
||||||
id: "header-beta-switch",
|
|
||||||
style: { marginLeft: "auto" },
|
|
||||||
label: (
|
|
||||||
<Tooltip
|
|
||||||
title={`A more modern ${InstanceRenderManager({
|
|
||||||
imex: t("titles.imexonline"),
|
|
||||||
rome: t("titles.romeonline"),
|
|
||||||
promanager: t("titles.promanager")
|
|
||||||
})} is ready for you to try! You can switch back at any time.`}
|
|
||||||
>
|
|
||||||
<InfoCircleOutlined />
|
|
||||||
<span style={{ marginRight: 8 }}>Try the new app</span>
|
|
||||||
<Switch checked={betaSwitch} onChange={betaSwitchChange} />
|
|
||||||
</Tooltip>
|
|
||||||
)
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Layout.Header>
|
<Layout.Header>
|
||||||
<Menu
|
<Menu
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ import ScheduleEventColor from "./schedule-event.color.component";
|
|||||||
import ScheduleEventNote from "./schedule-event.note.component";
|
import ScheduleEventNote from "./schedule-event.note.component";
|
||||||
import { useMutation } from "@apollo/client";
|
import { useMutation } from "@apollo/client";
|
||||||
import { UPDATE_APPOINTMENT } from "../../graphql/appointments.queries";
|
import { UPDATE_APPOINTMENT } from "../../graphql/appointments.queries";
|
||||||
|
import ProductionListColumnComment from "../production-list-columns/production-list-columns.comment.component";
|
||||||
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
bodyshop: selectBodyshop
|
bodyshop: selectBodyshop
|
||||||
@@ -127,6 +128,9 @@ export function ScheduleEventComponent({
|
|||||||
{(event.job && event.job.alt_transport) || ""}
|
{(event.job && event.job.alt_transport) || ""}
|
||||||
<ScheduleAtChange job={event && event.job} />
|
<ScheduleAtChange job={event && event.job} />
|
||||||
</DataLabel>
|
</DataLabel>
|
||||||
|
<DataLabel label={t("jobs.fields.comment")} valueStyle={{ overflow: "hidden", textOverflow: "ellipsis" }}>
|
||||||
|
<ProductionListColumnComment record={event && event.job} />
|
||||||
|
</DataLabel>
|
||||||
<ScheduleEventNote event={event} />
|
<ScheduleEventNote event={event} />
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
@@ -316,6 +320,7 @@ export function ScheduleEventComponent({
|
|||||||
})`}
|
})`}
|
||||||
|
|
||||||
{event.job && event.job.alt_transport && <div style={{ margin: ".1rem" }}>{event.job.alt_transport}</div>}
|
{event.job && event.job.alt_transport && <div style={{ margin: ".1rem" }}>{event.job.alt_transport}</div>}
|
||||||
|
{event?.job?.comment && `C: ${event.job.comment}`}
|
||||||
</Space>
|
</Space>
|
||||||
) : (
|
) : (
|
||||||
<div
|
<div
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import React from "react";
|
|||||||
import { useQuery } from "@apollo/client";
|
import { useQuery } from "@apollo/client";
|
||||||
import { connect } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
import { createStructuredSelector } from "reselect";
|
import { createStructuredSelector } from "reselect";
|
||||||
import { QUERY_BILLS_BY_JOBID } from "../../graphql/bills.queries";
|
import { QUERY_PARTS_BILLS_BY_JOBID } from "../../graphql/bills.queries";
|
||||||
import { selectJobReadOnly } from "../../redux/application/application.selectors";
|
import { selectJobReadOnly } from "../../redux/application/application.selectors";
|
||||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||||
import AlertComponent from "../alert/alert.component";
|
import AlertComponent from "../alert/alert.component";
|
||||||
@@ -19,7 +19,7 @@ const mapDispatchToProps = (dispatch) => ({
|
|||||||
export default connect(mapStateToProps, mapDispatchToProps)(JobCloseRoGuardBills);
|
export default connect(mapStateToProps, mapDispatchToProps)(JobCloseRoGuardBills);
|
||||||
|
|
||||||
export function JobCloseRoGuardBills({ job, jobRO, bodyshop, form, warningCallback }) {
|
export function JobCloseRoGuardBills({ job, jobRO, bodyshop, form, warningCallback }) {
|
||||||
const { loading, error, data } = useQuery(QUERY_BILLS_BY_JOBID, {
|
const { loading, error, data } = useQuery(QUERY_PARTS_BILLS_BY_JOBID, {
|
||||||
variables: { jobid: job.id },
|
variables: { jobid: job.id },
|
||||||
fetchPolicy: "network-only",
|
fetchPolicy: "network-only",
|
||||||
nextFetchPolicy: "network-only"
|
nextFetchPolicy: "network-only"
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ import JobCloseRoGuardBills from "./job-close-ro-guard.bills";
|
|||||||
import JobCloseRoGuardPpd from "./job-close-ro-guard.ppd";
|
import JobCloseRoGuardPpd from "./job-close-ro-guard.ppd";
|
||||||
import JobCloseRoGuardProfit from "./job-close-ro-guard.profit";
|
import JobCloseRoGuardProfit from "./job-close-ro-guard.profit";
|
||||||
import "./job-close-ro-guard.styles.scss";
|
import "./job-close-ro-guard.styles.scss";
|
||||||
// import JobCloseRoGuardSublet from "./job-close-ro-guard.sublet";
|
|
||||||
import InstanceRenderManager from "../../utils/instanceRenderMgr";
|
import InstanceRenderManager from "../../utils/instanceRenderMgr";
|
||||||
import JobCloseRoGuardTtLifecycle from "./job-close-ro-guard.tt-lifecycle";
|
import JobCloseRoGuardTtLifecycle from "./job-close-ro-guard.tt-lifecycle";
|
||||||
|
|
||||||
|
|||||||
@@ -2,27 +2,30 @@ import { useQuery } from "@apollo/client";
|
|||||||
import { Col, Row, Skeleton, Space, Timeline, Typography } from "antd";
|
import { Col, Row, Skeleton, Space, Timeline, Typography } from "antd";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
|
import { connect } from "react-redux";
|
||||||
import { Link } from "react-router-dom";
|
import { Link } from "react-router-dom";
|
||||||
|
import { createStructuredSelector } from "reselect";
|
||||||
import { GET_JOB_LINE_ORDERS } from "../../graphql/jobs.queries";
|
import { GET_JOB_LINE_ORDERS } from "../../graphql/jobs.queries";
|
||||||
|
import { QUERY_JOBLINE_TASKS_PAGINATED } from "../../graphql/tasks.queries.js";
|
||||||
|
import { selectTechnician } from "../../redux/tech/tech.selectors.js";
|
||||||
|
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||||
import CurrencyFormatter from "../../utils/CurrencyFormatter";
|
import CurrencyFormatter from "../../utils/CurrencyFormatter";
|
||||||
import { DateFormatter } from "../../utils/DateFormatter";
|
import { DateFormatter } from "../../utils/DateFormatter";
|
||||||
import AlertComponent from "../alert/alert.component";
|
import AlertComponent from "../alert/alert.component";
|
||||||
import { connect } from "react-redux";
|
import BillDetailEditcontainer from "../bill-detail-edit/bill-detail-edit.container.jsx";
|
||||||
import { createStructuredSelector } from "reselect";
|
|
||||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
|
||||||
import { QUERY_JOBLINE_TASKS_PAGINATED } from "../../graphql/tasks.queries.js";
|
|
||||||
import TaskListContainer from "../task-list/task-list.container.jsx";
|
|
||||||
import FeatureWrapper from "../feature-wrapper/feature-wrapper.component.jsx";
|
import FeatureWrapper from "../feature-wrapper/feature-wrapper.component.jsx";
|
||||||
|
import TaskListContainer from "../task-list/task-list.container.jsx";
|
||||||
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
bodyshop: selectBodyshop
|
bodyshop: selectBodyshop,
|
||||||
|
technician: selectTechnician
|
||||||
});
|
});
|
||||||
|
|
||||||
const mapDispatchToProps = (dispatch) => ({});
|
const mapDispatchToProps = (dispatch) => ({});
|
||||||
|
|
||||||
export default connect(mapStateToProps, mapDispatchToProps)(JobLinesExpander);
|
export default connect(mapStateToProps, mapDispatchToProps)(JobLinesExpander);
|
||||||
|
|
||||||
export function JobLinesExpander({ jobline, jobid, bodyshop }) {
|
export function JobLinesExpander({ jobline, jobid, bodyshop, technician }) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { loading, error, data } = useQuery(GET_JOB_LINE_ORDERS, {
|
const { loading, error, data } = useQuery(GET_JOB_LINE_ORDERS, {
|
||||||
fetchPolicy: "network-only",
|
fetchPolicy: "network-only",
|
||||||
@@ -47,9 +50,15 @@ export function JobLinesExpander({ jobline, jobid, bodyshop }) {
|
|||||||
children: (
|
children: (
|
||||||
<Row wrap>
|
<Row wrap>
|
||||||
<Col span={4}>
|
<Col span={4}>
|
||||||
<Link to={`/manage/jobs/${jobid}?partsorderid=${line.parts_order.id}`}>
|
{!technician ? (
|
||||||
{line.parts_order.order_number}
|
<>
|
||||||
</Link>
|
<Link to={`/manage/jobs/${jobid}?partsorderid=${line.parts_order.id}`}>
|
||||||
|
{line.parts_order.order_number}
|
||||||
|
</Link>
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
`${line.parts_order.order_number}`
|
||||||
|
)}
|
||||||
</Col>
|
</Col>
|
||||||
<Col span={4}>
|
<Col span={4}>
|
||||||
<DateFormatter>{line.parts_order.order_date}</DateFormatter>
|
<DateFormatter>{line.parts_order.order_date}</DateFormatter>
|
||||||
@@ -84,17 +93,17 @@ export function JobLinesExpander({ jobline, jobid, bodyshop }) {
|
|||||||
key: line.id,
|
key: line.id,
|
||||||
children: (
|
children: (
|
||||||
<Row>
|
<Row>
|
||||||
<Col span={8}>
|
<Col span={8}>{line.parts_dispatch.number}</Col>
|
||||||
<Link to={`/manage/jobs/${jobid}?partsorderid=${line.id}`}>{line.parts_dispatch.number}</Link>
|
|
||||||
</Col>
|
|
||||||
<Col span={8}>
|
<Col span={8}>
|
||||||
{bodyshop.employees.find((e) => e.id === line.parts_dispatch.employeeid)?.first_name}
|
{bodyshop.employees.find((e) => e.id === line.parts_dispatch.employeeid)?.first_name}
|
||||||
</Col>
|
</Col>
|
||||||
<Col span={8}>
|
<Col span={8}>
|
||||||
<Space>
|
{line.accepted_at ? (
|
||||||
{t("parts_dispatch_lines.fields.accepted_at")}
|
<Space>
|
||||||
<DateFormatter>{line.accepted_at}</DateFormatter>
|
{t("parts_dispatch_lines.fields.accepted_at")}
|
||||||
</Space>
|
<DateFormatter>{line.accepted_at}</DateFormatter>
|
||||||
|
</Space>
|
||||||
|
) : null}
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
)
|
)
|
||||||
@@ -111,6 +120,7 @@ export function JobLinesExpander({ jobline, jobid, bodyshop }) {
|
|||||||
<FeatureWrapper featureName="bills" noauth={() => null}>
|
<FeatureWrapper featureName="bills" noauth={() => null}>
|
||||||
<Col md={24} lg={8}>
|
<Col md={24} lg={8}>
|
||||||
<Typography.Title level={4}>{t("bills.labels.bills")}</Typography.Title>
|
<Typography.Title level={4}>{t("bills.labels.bills")}</Typography.Title>
|
||||||
|
<BillDetailEditcontainer />
|
||||||
<Timeline
|
<Timeline
|
||||||
items={
|
items={
|
||||||
data.billlines.length > 0
|
data.billlines.length > 0
|
||||||
@@ -119,9 +129,15 @@ export function JobLinesExpander({ jobline, jobid, bodyshop }) {
|
|||||||
children: (
|
children: (
|
||||||
<Row wrap>
|
<Row wrap>
|
||||||
<Col span={4}>
|
<Col span={4}>
|
||||||
<Link to={`/manage/jobs/${jobid}?tab=partssublet&billid=${line.bill.id}`}>
|
{!technician ? (
|
||||||
{line.bill.invoice_number}
|
<>
|
||||||
</Link>
|
<Link to={`/manage/jobs/${jobid}?tab=partssublet&billid=${line.bill.id}`}>
|
||||||
|
{line.bill.invoice_number}
|
||||||
|
</Link>
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
`${line.bill.invoice_number}`
|
||||||
|
)}
|
||||||
</Col>
|
</Col>
|
||||||
<Col span={4}>
|
<Col span={4}>
|
||||||
<span>
|
<span>
|
||||||
|
|||||||
@@ -3,13 +3,21 @@ import { Button, Form, notification, Popover, Tooltip } from "antd";
|
|||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import { t } from "i18next";
|
import { t } from "i18next";
|
||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
|
import { connect } from "react-redux";
|
||||||
|
import { createStructuredSelector } from "reselect";
|
||||||
import { UPDATE_LINE_PPC } from "../../graphql/jobs-lines.queries";
|
import { UPDATE_LINE_PPC } from "../../graphql/jobs-lines.queries";
|
||||||
|
import { selectTechnician } from "../../redux/tech/tech.selectors";
|
||||||
import CurrencyFormatter from "../../utils/CurrencyFormatter";
|
import CurrencyFormatter from "../../utils/CurrencyFormatter";
|
||||||
import InstanceRenderManager from "../../utils/instanceRenderMgr";
|
import InstanceRenderManager from "../../utils/instanceRenderMgr";
|
||||||
import CurrencyFormItemComponent from "../form-items-formatted/currency-form-item.component";
|
import CurrencyFormItemComponent from "../form-items-formatted/currency-form-item.component";
|
||||||
import JobLineConvertToLabor from "../job-line-convert-to-labor/job-line-convert-to-labor.component";
|
import JobLineConvertToLabor from "../job-line-convert-to-labor/job-line-convert-to-labor.component";
|
||||||
|
|
||||||
export default function JobLinesPartPriceChange({ job, line, refetch }) {
|
const mapStateToProps = createStructuredSelector({
|
||||||
|
technician: selectTechnician
|
||||||
|
});
|
||||||
|
const mapDispatchToProps = (dispatch) => ({});
|
||||||
|
|
||||||
|
export function JobLinesPartPriceChange({ job, line, refetch, technician }) {
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const [updatePartPrice] = useMutation(UPDATE_LINE_PPC);
|
const [updatePartPrice] = useMutation(UPDATE_LINE_PPC);
|
||||||
|
|
||||||
@@ -52,7 +60,7 @@ export default function JobLinesPartPriceChange({ job, line, refetch }) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const popcontent = InstanceRenderManager({
|
const popcontent = !technician && InstanceRenderManager({
|
||||||
imex: null,
|
imex: null,
|
||||||
rome: (
|
rome: (
|
||||||
<Form layout="vertical" onFinish={handleFinish} initialValues={{ act_price: line.act_price }}>
|
<Form layout="vertical" onFinish={handleFinish} initialValues={{ act_price: line.act_price }}>
|
||||||
@@ -95,3 +103,4 @@ export default function JobLinesPartPriceChange({ job, line, refetch }) {
|
|||||||
</JobLineConvertToLabor>
|
</JobLineConvertToLabor>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
export default connect(mapStateToProps, mapDispatchToProps)(JobLinesPartPriceChange);
|
||||||
|
|||||||
@@ -31,19 +31,20 @@ import JobLinesBillRefernece from "../job-lines-bill-reference/job-lines-bill-re
|
|||||||
// import AllocationsEmployeeLabelContainer from "../allocations-employee-label/allocations-employee-label.container";
|
// import AllocationsEmployeeLabelContainer from "../allocations-employee-label/allocations-employee-label.container";
|
||||||
import { useSplitTreatments } from "@splitsoftware/splitio-react";
|
import { useSplitTreatments } from "@splitsoftware/splitio-react";
|
||||||
import _ from "lodash";
|
import _ from "lodash";
|
||||||
|
import { FaTasks } from "react-icons/fa";
|
||||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||||
import dayjs from "../../utils/day";
|
import dayjs from "../../utils/day";
|
||||||
|
import InstanceRenderManager from "../../utils/instanceRenderMgr";
|
||||||
import { HasFeatureAccess } from "../feature-wrapper/feature-wrapper.component";
|
import { HasFeatureAccess } from "../feature-wrapper/feature-wrapper.component";
|
||||||
import JobCreateIOU from "../job-create-iou/job-create-iou.component";
|
import JobCreateIOU from "../job-create-iou/job-create-iou.component";
|
||||||
import JobLineBulkAssignComponent from "../job-line-bulk-assign/job-line-bulk-assign.component";
|
import JobLineBulkAssignComponent from "../job-line-bulk-assign/job-line-bulk-assign.component";
|
||||||
import JobLineDispatchButton from "../job-line-dispatch-button/job-line-dispatch-button.component";
|
import JobLineDispatchButton from "../job-line-dispatch-button/job-line-dispatch-button.component";
|
||||||
import JoblineTeamAssignment from "../job-line-team-assignment/job-line-team-assignmnent.component";
|
import JoblineTeamAssignment from "../job-line-team-assignment/job-line-team-assignmnent.component";
|
||||||
import JobSendPartPriceChangeComponent from "../job-send-parts-price-change/job-send-parts-price-change.component";
|
import JobSendPartPriceChangeComponent from "../job-send-parts-price-change/job-send-parts-price-change.component";
|
||||||
|
import PartsOrderDrawer from "../parts-order-list-table/parts-order-list-table-drawer.component";
|
||||||
import PartsOrderModalContainer from "../parts-order-modal/parts-order-modal.container";
|
import PartsOrderModalContainer from "../parts-order-modal/parts-order-modal.container";
|
||||||
import JobLinesExpander from "./job-lines-expander.component";
|
import JobLinesExpander from "./job-lines-expander.component";
|
||||||
import JobLinesPartPriceChange from "./job-lines-part-price-change.component";
|
import JobLinesPartPriceChange from "./job-lines-part-price-change.component";
|
||||||
import { FaTasks } from "react-icons/fa";
|
|
||||||
import InstanceRenderManager from "../../utils/instanceRenderMgr";
|
|
||||||
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
bodyshop: selectBodyshop,
|
bodyshop: selectBodyshop,
|
||||||
@@ -54,6 +55,7 @@ const mapStateToProps = createStructuredSelector({
|
|||||||
const mapDispatchToProps = (dispatch) => ({
|
const mapDispatchToProps = (dispatch) => ({
|
||||||
setJobLineEditContext: (context) => dispatch(setModalContext({ context: context, modal: "jobLineEdit" })),
|
setJobLineEditContext: (context) => dispatch(setModalContext({ context: context, modal: "jobLineEdit" })),
|
||||||
setPartsOrderContext: (context) => dispatch(setModalContext({ context: context, modal: "partsOrder" })),
|
setPartsOrderContext: (context) => dispatch(setModalContext({ context: context, modal: "partsOrder" })),
|
||||||
|
setPartsReceiveContext: (context) => dispatch(setModalContext({ context: context, modal: "partsReceive" })),
|
||||||
setBillEnterContext: (context) => dispatch(setModalContext({ context: context, modal: "billEnter" })),
|
setBillEnterContext: (context) => dispatch(setModalContext({ context: context, modal: "billEnter" })),
|
||||||
setTaskUpsertContext: (context) => dispatch(setModalContext({ context, modal: "taskUpsert" }))
|
setTaskUpsertContext: (context) => dispatch(setModalContext({ context, modal: "taskUpsert" }))
|
||||||
});
|
});
|
||||||
@@ -63,6 +65,7 @@ export function JobLinesComponent({
|
|||||||
jobRO,
|
jobRO,
|
||||||
technician,
|
technician,
|
||||||
setPartsOrderContext,
|
setPartsOrderContext,
|
||||||
|
setPartsReceiveContext,
|
||||||
loading,
|
loading,
|
||||||
refetch,
|
refetch,
|
||||||
jobLines,
|
jobLines,
|
||||||
@@ -71,7 +74,11 @@ export function JobLinesComponent({
|
|||||||
setJobLineEditContext,
|
setJobLineEditContext,
|
||||||
form,
|
form,
|
||||||
setBillEnterContext,
|
setBillEnterContext,
|
||||||
setTaskUpsertContext
|
setTaskUpsertContext,
|
||||||
|
billsQuery,
|
||||||
|
handleBillOnRowClick,
|
||||||
|
handlePartsOrderOnRowClick,
|
||||||
|
handlePartsDispatchOnRowClick
|
||||||
}) {
|
}) {
|
||||||
const [deleteJobLine] = useMutation(DELETE_JOB_LINE_BY_PK);
|
const [deleteJobLine] = useMutation(DELETE_JOB_LINE_BY_PK);
|
||||||
const {
|
const {
|
||||||
@@ -198,7 +205,6 @@ export function JobLinesComponent({
|
|||||||
onFilter: (value, record) => value.includes(record.part_type),
|
onFilter: (value, record) => value.includes(record.part_type),
|
||||||
render: (text, record) => (record.part_type ? t(`joblines.fields.part_types.${record.part_type}`) : null)
|
render: (text, record) => (record.part_type ? t(`joblines.fields.part_types.${record.part_type}`) : null)
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
title: t("joblines.fields.act_price"),
|
title: t("joblines.fields.act_price"),
|
||||||
dataIndex: "act_price",
|
dataIndex: "act_price",
|
||||||
@@ -213,7 +219,6 @@ export function JobLinesComponent({
|
|||||||
dataIndex: "part_qty",
|
dataIndex: "part_qty",
|
||||||
key: "part_qty"
|
key: "part_qty"
|
||||||
},
|
},
|
||||||
|
|
||||||
// {
|
// {
|
||||||
// title: t('joblines.fields.tax_part'),
|
// title: t('joblines.fields.tax_part'),
|
||||||
// dataIndex: 'tax_part',
|
// dataIndex: 'tax_part',
|
||||||
@@ -322,7 +327,7 @@ export function JobLinesComponent({
|
|||||||
key: "actions",
|
key: "actions",
|
||||||
render: (text, record) => (
|
render: (text, record) => (
|
||||||
<Space>
|
<Space>
|
||||||
{(record.manual_line || jobIsPrivate) && (
|
{(record.manual_line || jobIsPrivate) && !technician && (
|
||||||
<>
|
<>
|
||||||
<Button
|
<Button
|
||||||
disabled={jobRO}
|
disabled={jobRO}
|
||||||
@@ -337,7 +342,6 @@ export function JobLinesComponent({
|
|||||||
</Button>
|
</Button>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
title={t("tasks.buttons.create")}
|
title={t("tasks.buttons.create")}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
@@ -351,7 +355,7 @@ export function JobLinesComponent({
|
|||||||
>
|
>
|
||||||
<FaTasks />
|
<FaTasks />
|
||||||
</Button>
|
</Button>
|
||||||
{(record.manual_line || jobIsPrivate) && (
|
{(record.manual_line || jobIsPrivate) && !technician && (
|
||||||
<>
|
<>
|
||||||
<Button
|
<Button
|
||||||
disabled={jobRO}
|
disabled={jobRO}
|
||||||
@@ -437,6 +441,15 @@ export function JobLinesComponent({
|
|||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<PartsOrderModalContainer />
|
<PartsOrderModalContainer />
|
||||||
|
{!technician && (
|
||||||
|
<PartsOrderDrawer
|
||||||
|
job={job}
|
||||||
|
billsQuery={billsQuery}
|
||||||
|
handleOnRowClick={handlePartsOrderOnRowClick}
|
||||||
|
setPartsReceiveContext={setPartsReceiveContext}
|
||||||
|
setTaskUpsertContext={setTaskUpsertContext}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
<PageHeader
|
<PageHeader
|
||||||
title={t("jobs.labels.estimatelines")}
|
title={t("jobs.labels.estimatelines")}
|
||||||
extra={
|
extra={
|
||||||
@@ -553,7 +566,7 @@ export function JobLinesComponent({
|
|||||||
>
|
>
|
||||||
{t("joblines.actions.new")}
|
{t("joblines.actions.new")}
|
||||||
</Button>
|
</Button>
|
||||||
{InstanceRenderManager({ rome: <JobSendPartPriceChangeComponent job={job} /> })}
|
{InstanceRenderManager({ rome: <JobSendPartPriceChangeComponent job={job} disabled={technician} /> })}
|
||||||
<JobCreateIOU job={job} selectedJobLines={selectedLines} />
|
<JobCreateIOU job={job} selectedJobLines={selectedLines} />
|
||||||
<Input.Search
|
<Input.Search
|
||||||
placeholder={t("general.labels.search")}
|
placeholder={t("general.labels.search")}
|
||||||
|
|||||||
@@ -1,7 +1,17 @@
|
|||||||
import React, { useMemo, useState } from "react";
|
import React, { useMemo, useState } from "react";
|
||||||
import JobLinesComponent from "./job-lines.component";
|
import JobLinesComponent from "./job-lines.component";
|
||||||
|
|
||||||
function JobLinesContainer({ job, joblines, refetch, form, ...rest }) {
|
function JobLinesContainer({
|
||||||
|
job,
|
||||||
|
joblines,
|
||||||
|
billsQuery,
|
||||||
|
handleBillOnRowClick,
|
||||||
|
handlePartsOrderOnRowClick,
|
||||||
|
handlePartsDispatchOnRowClick,
|
||||||
|
refetch,
|
||||||
|
form,
|
||||||
|
...rest
|
||||||
|
}) {
|
||||||
const [searchText, setSearchText] = useState("");
|
const [searchText, setSearchText] = useState("");
|
||||||
|
|
||||||
const jobLines = useMemo(() => {
|
const jobLines = useMemo(() => {
|
||||||
@@ -22,7 +32,19 @@ function JobLinesContainer({ job, joblines, refetch, form, ...rest }) {
|
|||||||
}, [joblines, searchText]);
|
}, [joblines, searchText]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<JobLinesComponent refetch={refetch} jobLines={jobLines} setSearchText={setSearchText} job={job} form={form} />
|
<div>
|
||||||
|
<JobLinesComponent
|
||||||
|
refetch={refetch}
|
||||||
|
jobLines={jobLines}
|
||||||
|
billsQuery={billsQuery}
|
||||||
|
handleBillOnRowClick={handleBillOnRowClick}
|
||||||
|
handlePartsOrderOnRowClick={handlePartsOrderOnRowClick}
|
||||||
|
handlePartsDispatchOnRowClick={handlePartsDispatchOnRowClick}
|
||||||
|
setSearchText={setSearchText}
|
||||||
|
job={job}
|
||||||
|
form={form}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import React, { useCallback, useEffect, useState } from "react";
|
import React, { useCallback, useEffect, useState } from "react";
|
||||||
import day from "../../utils/day";
|
import dayjs from "../../utils/day";
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import { Badge, Card, Space, Table, Tag } from "antd";
|
import { Badge, Card, Space, Table, Tag } from "antd";
|
||||||
import { gql, useQuery } from "@apollo/client";
|
import { gql, useQuery } from "@apollo/client";
|
||||||
@@ -72,7 +72,7 @@ export function JobLifecycleComponent({ job, statuses, ...rest }) {
|
|||||||
dataIndex: "start",
|
dataIndex: "start",
|
||||||
key: "start",
|
key: "start",
|
||||||
render: (text) => DateTimeFormatterFunction(text),
|
render: (text) => DateTimeFormatterFunction(text),
|
||||||
sorter: (a, b) => day(a.start).unix() - day(b.start).unix()
|
sorter: (a, b) => dayjs(a.start).unix() - dayjs(b.start).unix()
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: t("job_lifecycle.columns.relative_start"),
|
title: t("job_lifecycle.columns.relative_start"),
|
||||||
@@ -90,7 +90,7 @@ export function JobLifecycleComponent({ job, statuses, ...rest }) {
|
|||||||
}
|
}
|
||||||
return isEmpty(a.end) ? 1 : -1;
|
return isEmpty(a.end) ? 1 : -1;
|
||||||
}
|
}
|
||||||
return day(a.end).unix() - day(b.end).unix();
|
return dayjs(a.end).unix() - dayjs(b.end).unix();
|
||||||
},
|
},
|
||||||
render: (text) => (isEmpty(text) ? t("job_lifecycle.content.not_available") : DateTimeFormatterFunction(text))
|
render: (text) => (isEmpty(text) ? t("job_lifecycle.content.not_available") : DateTimeFormatterFunction(text))
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -11,17 +11,18 @@ import { connect } from "react-redux";
|
|||||||
import { createStructuredSelector } from "reselect";
|
import { createStructuredSelector } from "reselect";
|
||||||
import { UPDATE_JOB_LINE } from "../../graphql/jobs-lines.queries";
|
import { UPDATE_JOB_LINE } from "../../graphql/jobs-lines.queries";
|
||||||
import { insertAuditTrail } from "../../redux/application/application.actions";
|
import { insertAuditTrail } from "../../redux/application/application.actions";
|
||||||
|
import { selectTechnician } from "../../redux/tech/tech.selectors";
|
||||||
import AuditTrailMapping from "../../utils/AuditTrailMappings";
|
import AuditTrailMapping from "../../utils/AuditTrailMappings";
|
||||||
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
//currentUser: selectCurrentUser
|
technician: selectTechnician
|
||||||
});
|
});
|
||||||
const mapDispatchToProps = (dispatch) => ({
|
const mapDispatchToProps = (dispatch) => ({
|
||||||
insertAuditTrail: ({ jobid, operation, type }) => dispatch(insertAuditTrail({ jobid, operation, type }))
|
insertAuditTrail: ({ jobid, operation, type }) => dispatch(insertAuditTrail({ jobid, operation, type }))
|
||||||
});
|
});
|
||||||
export default connect(mapStateToProps, mapDispatchToProps)(JobLineConvertToLabor);
|
export default connect(mapStateToProps, mapDispatchToProps)(JobLineConvertToLabor);
|
||||||
|
|
||||||
export function JobLineConvertToLabor({ children, jobline, job, insertAuditTrail, ...otherBtnProps }) {
|
export function JobLineConvertToLabor({ children, jobline, job, insertAuditTrail, technician, ...otherBtnProps }) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
@@ -165,7 +166,7 @@ export function JobLineConvertToLabor({ children, jobline, job, insertAuditTrail
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{children}
|
{children}
|
||||||
{jobline.act_price !== 0 && (
|
{jobline.act_price !== 0 && !technician && (
|
||||||
<Popover disabled={jobline.convertedtolbr} content={overlay} open={visibility} placement="bottom">
|
<Popover disabled={jobline.convertedtolbr} content={overlay} open={visibility} placement="bottom">
|
||||||
<Tooltip title={t("joblines.actions.converttolabor")}>
|
<Tooltip title={t("joblines.actions.converttolabor")}>
|
||||||
<Button
|
<Button
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import React, { useState } from "react";
|
|||||||
|
|
||||||
import { useMutation } from "@apollo/client";
|
import { useMutation } from "@apollo/client";
|
||||||
import { Button, Form, notification, Popover, Select, Space } from "antd";
|
import { Button, Form, notification, Popover, Select, Space } from "antd";
|
||||||
import day from "../../utils/day";
|
import dayjs from "../../utils/day";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { connect } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
import { createStructuredSelector } from "reselect";
|
import { createStructuredSelector } from "reselect";
|
||||||
@@ -48,7 +48,7 @@ export function JobLineDispatchButton({
|
|||||||
const result = await dispatchLines({
|
const result = await dispatchLines({
|
||||||
variables: {
|
variables: {
|
||||||
partsDispatch: {
|
partsDispatch: {
|
||||||
dispatched_at: day(),
|
dispatched_at: dayjs(),
|
||||||
employeeid: values.employeeid,
|
employeeid: values.employeeid,
|
||||||
jobid: job.id,
|
jobid: job.id,
|
||||||
dispatched_by: currentUser.email,
|
dispatched_by: currentUser.email,
|
||||||
@@ -138,7 +138,11 @@ export function JobLineDispatchButton({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Popover open={visible} content={popMenu}>
|
<Popover open={visible} content={popMenu}>
|
||||||
<Button disabled={selectedLines.length === 0 || jobRO || disabled} loading={loading} onClick={() => setVisible(true)}>
|
<Button
|
||||||
|
disabled={selectedLines.length === 0 || jobRO || disabled}
|
||||||
|
loading={loading}
|
||||||
|
onClick={() => setVisible(true)}
|
||||||
|
>
|
||||||
{t("joblines.actions.dispatchparts", { count: selectedLines.length })}
|
{t("joblines.actions.dispatchparts", { count: selectedLines.length })}
|
||||||
</Button>
|
</Button>
|
||||||
</Popover>
|
</Popover>
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
import { useMutation } from "@apollo/client";
|
import { useMutation } from "@apollo/client";
|
||||||
|
import { useSplitTreatments } from "@splitsoftware/splitio-react";
|
||||||
import { notification } from "antd";
|
import { notification } from "antd";
|
||||||
|
import Axios from "axios";
|
||||||
|
import Dinero from "dinero.js";
|
||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { connect } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
@@ -7,13 +10,10 @@ import { createStructuredSelector } from "reselect";
|
|||||||
import { INSERT_NEW_JOB_LINE, UPDATE_JOB_LINE } from "../../graphql/jobs-lines.queries";
|
import { INSERT_NEW_JOB_LINE, UPDATE_JOB_LINE } from "../../graphql/jobs-lines.queries";
|
||||||
import { toggleModalVisible } from "../../redux/modals/modals.actions";
|
import { toggleModalVisible } from "../../redux/modals/modals.actions";
|
||||||
import { selectJobLineEditModal } from "../../redux/modals/modals.selectors";
|
import { selectJobLineEditModal } from "../../redux/modals/modals.selectors";
|
||||||
|
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||||
|
import CriticalPartsScan from "../../utils/criticalPartsScan";
|
||||||
import UndefinedToNull from "../../utils/undefinedtonull";
|
import UndefinedToNull from "../../utils/undefinedtonull";
|
||||||
import JobLinesUpdsertModal from "./job-lines-upsert-modal.component";
|
import JobLinesUpdsertModal from "./job-lines-upsert-modal.component";
|
||||||
import Axios from "axios";
|
|
||||||
import Dinero from "dinero.js";
|
|
||||||
import CriticalPartsScan from "../../utils/criticalPartsScan";
|
|
||||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
|
||||||
import { useSplitTreatments } from "@splitsoftware/splitio-react";
|
|
||||||
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
jobLineEditModal: selectJobLineEditModal,
|
jobLineEditModal: selectJobLineEditModal,
|
||||||
@@ -82,13 +82,15 @@ function JobLinesUpsertModalContainer({ jobLineEditModal, toggleModalVisible, bo
|
|||||||
variables: {
|
variables: {
|
||||||
lineId: jobLineEditModal.context.id,
|
lineId: jobLineEditModal.context.id,
|
||||||
line: {
|
line: {
|
||||||
...values,
|
...UndefinedToNull({
|
||||||
prt_dsmk_m: Dinero({
|
...values,
|
||||||
amount: Math.round(values.act_price * 100)
|
prt_dsmk_m: Dinero({
|
||||||
|
amount: Math.round(values.act_price * 100)
|
||||||
|
})
|
||||||
|
.percentage(Math.abs(values.prt_dsmk_p || 0))
|
||||||
|
.multiply(values.prt_dsmk_p >= 0 ? 1 : -1)
|
||||||
|
.toFormat(0.0)
|
||||||
})
|
})
|
||||||
.percentage(Math.abs(values.prt_dsmk_p || 0))
|
|
||||||
.multiply(values.prt_dsmk_p >= 0 ? 1 : -1)
|
|
||||||
.toFormat(0.0)
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
refetchQueries: ["GET_LINE_TICKET_BY_PK"]
|
refetchQueries: ["GET_LINE_TICKET_BY_PK"]
|
||||||
|
|||||||
@@ -10,8 +10,8 @@ import {
|
|||||||
QUERY_SCOREBOARD_ENTRY,
|
QUERY_SCOREBOARD_ENTRY,
|
||||||
UPDATE_SCOREBOARD_ENTRY
|
UPDATE_SCOREBOARD_ENTRY
|
||||||
} from "../../graphql/scoreboard.queries";
|
} from "../../graphql/scoreboard.queries";
|
||||||
import FormDatePicker from "../form-date-picker/form-date-picker.component";
|
|
||||||
import LoadingSpinner from "../loading-spinner/loading-spinner.component";
|
import LoadingSpinner from "../loading-spinner/loading-spinner.component";
|
||||||
|
import DateTimePicker from "../form-date-time-picker/form-date-time-picker.component.jsx";
|
||||||
|
|
||||||
export default function ScoreboardAddButton({ job, disabled, ...otherBtnProps }) {
|
export default function ScoreboardAddButton({ job, disabled, ...otherBtnProps }) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
@@ -86,7 +86,7 @@ export default function ScoreboardAddButton({ job, disabled, ...otherBtnProps })
|
|||||||
}
|
}
|
||||||
]}
|
]}
|
||||||
>
|
>
|
||||||
<FormDatePicker />
|
<DateTimePicker isDateOnly />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
label={t("scoreboard.fields.bodyhrs")}
|
label={t("scoreboard.fields.bodyhrs")}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import axios from "axios";
|
|||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
|
|
||||||
export default function JobSendPartPriceChangeComponent({ job }) {
|
export default function JobSendPartPriceChangeComponent({ job, disabled }) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const handleClick = async () => {
|
const handleClick = async () => {
|
||||||
@@ -24,7 +24,7 @@ export default function JobSendPartPriceChangeComponent({ job }) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Button onClick={handleClick} loading={loading}>
|
<Button onClick={handleClick} loading={loading} disabled={disabled}>
|
||||||
{t("jobs.actions.sendpartspricechange")}
|
{t("jobs.actions.sendpartspricechange")}
|
||||||
</Button>
|
</Button>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -3,8 +3,8 @@ import Dinero from "dinero.js";
|
|||||||
import React, { useMemo, useState } from "react";
|
import React, { useMemo, useState } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import CurrencyFormatter from "../../utils/CurrencyFormatter";
|
import CurrencyFormatter from "../../utils/CurrencyFormatter";
|
||||||
import { alphaSort } from "../../utils/sorters";
|
|
||||||
import InstanceRenderManager from "../../utils/instanceRenderMgr";
|
import InstanceRenderManager from "../../utils/instanceRenderMgr";
|
||||||
|
import { alphaSort } from "../../utils/sorters";
|
||||||
|
|
||||||
export default function JobTotalsTableLabor({ job }) {
|
export default function JobTotalsTableLabor({ job }) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
@@ -56,16 +56,49 @@ export default function JobTotalsTableLabor({ job }) {
|
|||||||
sortOrder: state.sortedInfo.columnKey === "mod_lb_hrs" && state.sortedInfo.order,
|
sortOrder: state.sortedInfo.columnKey === "mod_lb_hrs" && state.sortedInfo.order,
|
||||||
render: (text, record) => record.hours.toFixed(1)
|
render: (text, record) => record.hours.toFixed(1)
|
||||||
},
|
},
|
||||||
{
|
...InstanceRenderManager({
|
||||||
title: t("joblines.fields.total"),
|
imex: [
|
||||||
dataIndex: "total",
|
{
|
||||||
key: "total",
|
title: t("joblines.fields.total"),
|
||||||
align: "right",
|
dataIndex: "total",
|
||||||
sorter: (a, b) => a.total.amount - b.total.amount,
|
key: "total",
|
||||||
sortOrder: state.sortedInfo.columnKey === "total" && state.sortedInfo.order,
|
align: "right",
|
||||||
|
sorter: (a, b) => a.total.amount - b.total.amount,
|
||||||
render: (text, record) => Dinero(record.total).toFormat()
|
sortOrder: state.sortedInfo.columnKey === "total" && state.sortedInfo.order,
|
||||||
}
|
render: (text, record) => Dinero(record.total).toFormat()
|
||||||
|
}
|
||||||
|
],
|
||||||
|
rome: [
|
||||||
|
{
|
||||||
|
title: t("joblines.fields.amount"),
|
||||||
|
dataIndex: "base",
|
||||||
|
key: "base",
|
||||||
|
align: "right",
|
||||||
|
sorter: (a, b) => a.base.amount - b.base.amount,
|
||||||
|
sortOrder: state.sortedInfo.columnKey === "base" && state.sortedInfo.order,
|
||||||
|
render: (text, record) => Dinero(record.base).toFormat()
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t("joblines.fields.adjustment"),
|
||||||
|
dataIndex: "adjustment",
|
||||||
|
key: "adjustment",
|
||||||
|
align: "right",
|
||||||
|
sorter: (a, b) => a.adjustment.amount - b.adjustment.amount,
|
||||||
|
sortOrder: state.sortedInfo.columnKey === "adjustment" && state.sortedInfo.order,
|
||||||
|
render: (text, record) => Dinero(record.adjustment).toFormat()
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t("joblines.fields.total"),
|
||||||
|
dataIndex: "total",
|
||||||
|
key: "total",
|
||||||
|
align: "right",
|
||||||
|
sorter: (a, b) => a.total.amount - b.total.amount,
|
||||||
|
sortOrder: state.sortedInfo.columnKey === "total" && state.sortedInfo.order,
|
||||||
|
render: (text, record) => Dinero(record.total).toFormat()
|
||||||
|
}
|
||||||
|
],
|
||||||
|
promanager: "USE_ROME"
|
||||||
|
})
|
||||||
];
|
];
|
||||||
|
|
||||||
const handleTableChange = (pagination, filters, sorter) => {
|
const handleTableChange = (pagination, filters, sorter) => {
|
||||||
@@ -91,6 +124,16 @@ export default function JobTotalsTableLabor({ job }) {
|
|||||||
<Table.Summary.Cell>
|
<Table.Summary.Cell>
|
||||||
{(job.job_totals.rates.mapa.hours + job.job_totals.rates.mash.hours).toFixed(1)}
|
{(job.job_totals.rates.mapa.hours + job.job_totals.rates.mash.hours).toFixed(1)}
|
||||||
</Table.Summary.Cell>
|
</Table.Summary.Cell>
|
||||||
|
{InstanceRenderManager({
|
||||||
|
imex: null,
|
||||||
|
rome: (
|
||||||
|
<>
|
||||||
|
<Table.Summary.Cell />
|
||||||
|
<Table.Summary.Cell />
|
||||||
|
</>
|
||||||
|
),
|
||||||
|
promanager: "USE_ROME"
|
||||||
|
})}
|
||||||
<Table.Summary.Cell align="right">
|
<Table.Summary.Cell align="right">
|
||||||
<strong>{Dinero(job.job_totals.rates.rates_subtotal).toFormat()}</strong>
|
<strong>{Dinero(job.job_totals.rates.rates_subtotal).toFormat()}</strong>
|
||||||
</Table.Summary.Cell>
|
</Table.Summary.Cell>
|
||||||
@@ -122,7 +165,29 @@ export default function JobTotalsTableLabor({ job }) {
|
|||||||
<CurrencyFormatter>{job.job_totals.rates.mapa.rate}</CurrencyFormatter>
|
<CurrencyFormatter>{job.job_totals.rates.mapa.rate}</CurrencyFormatter>
|
||||||
</Table.Summary.Cell>
|
</Table.Summary.Cell>
|
||||||
<Table.Summary.Cell>{job.job_totals.rates.mapa.hours.toFixed(1)}</Table.Summary.Cell>
|
<Table.Summary.Cell>{job.job_totals.rates.mapa.hours.toFixed(1)}</Table.Summary.Cell>
|
||||||
<Table.Summary.Cell align="right">{Dinero(job.job_totals.rates.mapa.total).toFormat()}</Table.Summary.Cell>
|
{InstanceRenderManager({
|
||||||
|
imex: (
|
||||||
|
<>
|
||||||
|
<Table.Summary.Cell align="right">
|
||||||
|
{Dinero(job.job_totals.rates.mapa.total).toFormat()}
|
||||||
|
</Table.Summary.Cell>
|
||||||
|
</>
|
||||||
|
),
|
||||||
|
rome: (
|
||||||
|
<>
|
||||||
|
<Table.Summary.Cell align="right">
|
||||||
|
{Dinero(job.job_totals.rates.mapa.base).toFormat()}
|
||||||
|
</Table.Summary.Cell>
|
||||||
|
<Table.Summary.Cell align="right">
|
||||||
|
{Dinero(job.job_totals.rates.mapa.adjustment).toFormat()}
|
||||||
|
</Table.Summary.Cell>
|
||||||
|
<Table.Summary.Cell align="right">
|
||||||
|
{Dinero(job.job_totals.rates.mapa.total).toFormat()}
|
||||||
|
</Table.Summary.Cell>
|
||||||
|
</>
|
||||||
|
),
|
||||||
|
promanager: "USE_ROME"
|
||||||
|
})}
|
||||||
</Table.Summary.Row>
|
</Table.Summary.Row>
|
||||||
<Table.Summary.Row>
|
<Table.Summary.Row>
|
||||||
<Table.Summary.Cell>
|
<Table.Summary.Cell>
|
||||||
@@ -151,7 +216,29 @@ export default function JobTotalsTableLabor({ job }) {
|
|||||||
<CurrencyFormatter>{job.job_totals.rates.mash.rate}</CurrencyFormatter>
|
<CurrencyFormatter>{job.job_totals.rates.mash.rate}</CurrencyFormatter>
|
||||||
</Table.Summary.Cell>
|
</Table.Summary.Cell>
|
||||||
<Table.Summary.Cell>{job.job_totals.rates.mash.hours.toFixed(1)}</Table.Summary.Cell>
|
<Table.Summary.Cell>{job.job_totals.rates.mash.hours.toFixed(1)}</Table.Summary.Cell>
|
||||||
<Table.Summary.Cell align="right">{Dinero(job.job_totals.rates.mash.total).toFormat()}</Table.Summary.Cell>
|
{InstanceRenderManager({
|
||||||
|
imex: (
|
||||||
|
<>
|
||||||
|
<Table.Summary.Cell align="right">
|
||||||
|
{Dinero(job.job_totals.rates.mash.total).toFormat()}
|
||||||
|
</Table.Summary.Cell>
|
||||||
|
</>
|
||||||
|
),
|
||||||
|
rome: (
|
||||||
|
<>
|
||||||
|
<Table.Summary.Cell align="right">
|
||||||
|
{Dinero(job.job_totals.rates.mash.base).toFormat()}
|
||||||
|
</Table.Summary.Cell>
|
||||||
|
<Table.Summary.Cell align="right">
|
||||||
|
{Dinero(job.job_totals.rates.mash.adjustment).toFormat()}
|
||||||
|
</Table.Summary.Cell>
|
||||||
|
<Table.Summary.Cell align="right">
|
||||||
|
{Dinero(job.job_totals.rates.mash.total).toFormat()}
|
||||||
|
</Table.Summary.Cell>
|
||||||
|
</>
|
||||||
|
),
|
||||||
|
promanager: "USE_ROME"
|
||||||
|
})}
|
||||||
</Table.Summary.Row>
|
</Table.Summary.Row>
|
||||||
<Table.Summary.Row>
|
<Table.Summary.Row>
|
||||||
<Table.Summary.Cell>
|
<Table.Summary.Cell>
|
||||||
@@ -159,6 +246,16 @@ export default function JobTotalsTableLabor({ job }) {
|
|||||||
</Table.Summary.Cell>
|
</Table.Summary.Cell>
|
||||||
<Table.Summary.Cell />
|
<Table.Summary.Cell />
|
||||||
<Table.Summary.Cell />
|
<Table.Summary.Cell />
|
||||||
|
{InstanceRenderManager({
|
||||||
|
imex: null,
|
||||||
|
rome: (
|
||||||
|
<>
|
||||||
|
<Table.Summary.Cell />
|
||||||
|
<Table.Summary.Cell />
|
||||||
|
</>
|
||||||
|
),
|
||||||
|
promanager: "USE_ROME"
|
||||||
|
})}
|
||||||
<Table.Summary.Cell align="right">
|
<Table.Summary.Cell align="right">
|
||||||
<strong>{Dinero(job.job_totals.rates.subtotal).toFormat()}</strong>
|
<strong>{Dinero(job.job_totals.rates.subtotal).toFormat()}</strong>
|
||||||
</Table.Summary.Cell>
|
</Table.Summary.Cell>
|
||||||
|
|||||||
@@ -141,10 +141,14 @@ export function JobTotalsTableTotals({ bodyshop, job }) {
|
|||||||
key: t("jobs.fields.ded_amt"),
|
key: t("jobs.fields.ded_amt"),
|
||||||
total: job.job_totals.totals.custPayable.deductible
|
total: job.job_totals.totals.custPayable.deductible
|
||||||
},
|
},
|
||||||
// {
|
...(InstanceRenderManager({
|
||||||
// key: t("jobs.fields.federal_tax_payable"),
|
imex: [{
|
||||||
// total: job.job_totals.totals.custPayable.federal_tax,
|
key: t("jobs.fields.federal_tax_payable"),
|
||||||
// },
|
total: job.job_totals.totals.custPayable.federal_tax
|
||||||
|
}],
|
||||||
|
rome: [],
|
||||||
|
promanager: "USE_ROME"
|
||||||
|
})),
|
||||||
{
|
{
|
||||||
key: t("jobs.fields.other_amount_payable"),
|
key: t("jobs.fields.other_amount_payable"),
|
||||||
total: job.job_totals.totals.custPayable.other_customer_amount
|
total: job.job_totals.totals.custPayable.other_customer_amount
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import React, { useEffect, useState } from "react";
|
|||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { UPDATE_JOB } from "../../graphql/jobs.queries";
|
import { UPDATE_JOB } from "../../graphql/jobs.queries";
|
||||||
import AuditTrailMapping from "../../utils/AuditTrailMappings";
|
import AuditTrailMapping from "../../utils/AuditTrailMappings";
|
||||||
import FormDatePicker from "../form-date-picker/form-date-picker.component";
|
|
||||||
import DateTimePicker from "../form-date-time-picker/form-date-time-picker.component";
|
import DateTimePicker from "../form-date-time-picker/form-date-time-picker.component";
|
||||||
import FormFieldsChanged from "../form-fields-changed-alert/form-fields-changed-alert.component";
|
import FormFieldsChanged from "../form-fields-changed-alert/form-fields-changed-alert.component";
|
||||||
import LayoutFormRow from "../layout-form-row/layout-form-row.component";
|
import LayoutFormRow from "../layout-form-row/layout-form-row.component";
|
||||||
@@ -20,7 +19,14 @@ const mapStateToProps = createStructuredSelector({
|
|||||||
});
|
});
|
||||||
|
|
||||||
const mapDispatchToProps = (dispatch) => ({
|
const mapDispatchToProps = (dispatch) => ({
|
||||||
insertAuditTrail: ({ jobid, operation, type }) => dispatch(insertAuditTrail({ jobid, operation, type }))
|
insertAuditTrail: ({ jobid, operation, type }) =>
|
||||||
|
dispatch(
|
||||||
|
insertAuditTrail({
|
||||||
|
jobid,
|
||||||
|
operation,
|
||||||
|
type
|
||||||
|
})
|
||||||
|
)
|
||||||
});
|
});
|
||||||
|
|
||||||
export default connect(mapStateToProps, mapDispatchToProps)(JobsAdminDatesChange);
|
export default connect(mapStateToProps, mapDispatchToProps)(JobsAdminDatesChange);
|
||||||
@@ -87,7 +93,7 @@ export function JobsAdminDatesChange({ insertAuditTrail, job }) {
|
|||||||
<FormFieldsChanged form={form} />
|
<FormFieldsChanged form={form} />
|
||||||
<LayoutFormRow header={t("jobs.forms.estdates")}>
|
<LayoutFormRow header={t("jobs.forms.estdates")}>
|
||||||
<Form.Item label={t("jobs.fields.date_estimated")} name="date_estimated">
|
<Form.Item label={t("jobs.fields.date_estimated")} name="date_estimated">
|
||||||
<FormDatePicker format="MM/DD/YYYY" />
|
<DateTimePicker format="MM/DD/YYYY" isDateOnly />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item label={t("jobs.fields.date_towin")} name="date_towin">
|
<Form.Item label={t("jobs.fields.date_towin")} name="date_towin">
|
||||||
<DateTimePicker />
|
<DateTimePicker />
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ import { useSplitTreatments } from "@splitsoftware/splitio-react";
|
|||||||
import { Col, Row, notification } from "antd";
|
import { Col, Row, notification } from "antd";
|
||||||
import Axios from "axios";
|
import Axios from "axios";
|
||||||
import _ from "lodash";
|
import _ from "lodash";
|
||||||
import dayjs from "../../utils/day";
|
|
||||||
import queryString from "query-string";
|
import queryString from "query-string";
|
||||||
import React, { useCallback, useEffect, useState } from "react";
|
import React, { useCallback, useEffect, useState } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
@@ -24,6 +23,8 @@ import { selectBodyshop, selectCurrentUser } from "../../redux/user/user.selecto
|
|||||||
import AuditTrailMapping from "../../utils/AuditTrailMappings";
|
import AuditTrailMapping from "../../utils/AuditTrailMappings";
|
||||||
import confirmDialog from "../../utils/asyncConfirm";
|
import confirmDialog from "../../utils/asyncConfirm";
|
||||||
import CriticalPartsScan from "../../utils/criticalPartsScan";
|
import CriticalPartsScan from "../../utils/criticalPartsScan";
|
||||||
|
import dayjs from "../../utils/day";
|
||||||
|
import InstanceRenderManager from "../../utils/instanceRenderMgr";
|
||||||
import AlertComponent from "../alert/alert.component";
|
import AlertComponent from "../alert/alert.component";
|
||||||
import JobsAvailableScan from "../jobs-available-scan/jobs-available-scan.component";
|
import JobsAvailableScan from "../jobs-available-scan/jobs-available-scan.component";
|
||||||
import JobsFindModalContainer from "../jobs-find-modal/jobs-find-modal.container";
|
import JobsFindModalContainer from "../jobs-find-modal/jobs-find-modal.container";
|
||||||
@@ -32,7 +33,6 @@ import OwnerFindModalContainer from "../owner-find-modal/owner-find-modal.contai
|
|||||||
import { GetSupplementDelta } from "./jobs-available-supplement.estlines.util";
|
import { GetSupplementDelta } from "./jobs-available-supplement.estlines.util";
|
||||||
import HeaderFields from "./jobs-available-supplement.headerfields";
|
import HeaderFields from "./jobs-available-supplement.headerfields";
|
||||||
import JobsAvailableTableComponent from "./jobs-available-table.component";
|
import JobsAvailableTableComponent from "./jobs-available-table.component";
|
||||||
import InstanceRenderManager from "../../utils/instanceRenderMgr";
|
|
||||||
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
bodyshop: selectBodyshop,
|
bodyshop: selectBodyshop,
|
||||||
@@ -580,12 +580,13 @@ function ResolveCCCLineIssues(estData, bodyshop) {
|
|||||||
InstanceRenderManager({
|
InstanceRenderManager({
|
||||||
executeFunction: true,
|
executeFunction: true,
|
||||||
args: [],
|
args: [],
|
||||||
promanager: () => {
|
rome: () => {
|
||||||
if (line.mod_lbr_ty === "LAET" || line.mod_lbr_ty === "LAUT") {
|
if (line.mod_lbr_ty === "LAET" || line.mod_lbr_ty === "LAUT") {
|
||||||
// line.notes += ` | ET/UT Update (prev = ${line.mod_lbr_ty})`;
|
// line.notes += ` | ET/UT Update (prev = ${line.mod_lbr_ty})`;
|
||||||
line.mod_lbr_ty = "LAR";
|
line.mod_lbr_ty = "LAR";
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
promanager: "USE_ROME"
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1,18 +1,9 @@
|
|||||||
import {
|
import { Collapse, Form, Input, InputNumber, Select, Space, Switch } from "antd";
|
||||||
Collapse,
|
|
||||||
Form,
|
|
||||||
Input,
|
|
||||||
InputNumber,
|
|
||||||
Select,
|
|
||||||
Space,
|
|
||||||
Switch,
|
|
||||||
} from "antd";
|
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { connect } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
import { createStructuredSelector } from "reselect";
|
import { createStructuredSelector } from "reselect";
|
||||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||||
import FormDatePicker from "../form-date-picker/form-date-picker.component";
|
|
||||||
import CurrencyInput from "../form-items-formatted/currency-form-item.component";
|
import CurrencyInput from "../form-items-formatted/currency-form-item.component";
|
||||||
import FormItemEmail from "../form-items-formatted/email-form-item.component";
|
import FormItemEmail from "../form-items-formatted/email-form-item.component";
|
||||||
import FormItemPhone, { PhoneItemFormatterValidation } from "../form-items-formatted/phone-form-item.component";
|
import FormItemPhone, { PhoneItemFormatterValidation } from "../form-items-formatted/phone-form-item.component";
|
||||||
@@ -29,6 +20,7 @@ import JobsDetailRatesTaxes from "../jobs-detail-rates/jobs-detail-rates.taxes.c
|
|||||||
import JobsMarkPstExempt from "../jobs-mark-pst-exempt/jobs-mark-pst-exempt.component";
|
import JobsMarkPstExempt from "../jobs-mark-pst-exempt/jobs-mark-pst-exempt.component";
|
||||||
import LayoutFormRow from "../layout-form-row/layout-form-row.component";
|
import LayoutFormRow from "../layout-form-row/layout-form-row.component";
|
||||||
import InstanceRenderManager from "../../utils/instanceRenderMgr";
|
import InstanceRenderManager from "../../utils/instanceRenderMgr";
|
||||||
|
import DateTimePicker from "../form-date-time-picker/form-date-time-picker.component.jsx";
|
||||||
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
//currentUser: selectCurrentUser
|
//currentUser: selectCurrentUser
|
||||||
@@ -61,10 +53,7 @@ export function JobsCreateJobsInfo({ bodyshop, form, selected }) {
|
|||||||
<Form.Item label={t("jobs.fields.policy_no")} name="policy_no">
|
<Form.Item label={t("jobs.fields.policy_no")} name="policy_no">
|
||||||
<Input />
|
<Input />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item
|
<Form.Item label={t("jobs.fields.regie_number")} name="regie_number">
|
||||||
label={t("jobs.fields.regie_number")}
|
|
||||||
name="regie_number"
|
|
||||||
>
|
|
||||||
<Input />
|
<Input />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item label={t("jobs.fields.ins_co_nm")} name="ins_co_nm">
|
<Form.Item label={t("jobs.fields.ins_co_nm")} name="ins_co_nm">
|
||||||
@@ -116,7 +105,7 @@ export function JobsCreateJobsInfo({ bodyshop, form, selected }) {
|
|||||||
<FormItemEmail email={getFieldValue("ins_ea")} />
|
<FormItemEmail email={getFieldValue("ins_ea")} />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item label={t("jobs.fields.loss_date")} name="loss_date">
|
<Form.Item label={t("jobs.fields.loss_date")} name="loss_date">
|
||||||
<FormDatePicker />
|
<DateTimePicker isDateOnly />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item label={t("jobs.fields.kmin")} name="kmin">
|
<Form.Item label={t("jobs.fields.kmin")} name="kmin">
|
||||||
<Input />
|
<Input />
|
||||||
|
|||||||
@@ -2,9 +2,9 @@ import { Form, Input } from "antd";
|
|||||||
import React, { useContext } from "react";
|
import React, { useContext } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import JobCreateContext from "../../pages/jobs-create/jobs-create.context";
|
import JobCreateContext from "../../pages/jobs-create/jobs-create.context";
|
||||||
import FormDatePicker from "../form-date-picker/form-date-picker.component";
|
|
||||||
import LayoutFormRow from "../layout-form-row/layout-form-row.component";
|
import LayoutFormRow from "../layout-form-row/layout-form-row.component";
|
||||||
import JobsCreateVehicleInfoPredefined from "./jobs-create-vehicle-info.predefined.component";
|
import JobsCreateVehicleInfoPredefined from "./jobs-create-vehicle-info.predefined.component";
|
||||||
|
import DateTimePicker from "../form-date-time-picker/form-date-time-picker.component.jsx";
|
||||||
|
|
||||||
export default function JobsCreateVehicleInfoNewComponent({ form }) {
|
export default function JobsCreateVehicleInfoNewComponent({ form }) {
|
||||||
const [state] = useContext(JobCreateContext);
|
const [state] = useContext(JobCreateContext);
|
||||||
@@ -113,7 +113,7 @@ export default function JobsCreateVehicleInfoNewComponent({ form }) {
|
|||||||
<Input disabled={!state.vehicle.new} />
|
<Input disabled={!state.vehicle.new} />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item label={t("vehicles.fields.v_prod_dt")} name={["vehicle", "data", "v_prod_dt"]}>
|
<Form.Item label={t("vehicles.fields.v_prod_dt")} name={["vehicle", "data", "v_prod_dt"]}>
|
||||||
<FormDatePicker disabled={!state.vehicle.new} />
|
<DateTimePicker isDateOnly disabled={!state.vehicle.new} />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
</LayoutFormRow>
|
</LayoutFormRow>
|
||||||
<LayoutFormRow grow>
|
<LayoutFormRow grow>
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import { connect } from "react-redux";
|
|||||||
import { createStructuredSelector } from "reselect";
|
import { createStructuredSelector } from "reselect";
|
||||||
import { selectJobReadOnly } from "../../redux/application/application.selectors";
|
import { selectJobReadOnly } from "../../redux/application/application.selectors";
|
||||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||||
import FormDatePicker from "../form-date-picker/form-date-picker.component";
|
|
||||||
import DateTimePicker from "../form-date-time-picker/form-date-time-picker.component";
|
import DateTimePicker from "../form-date-time-picker/form-date-time-picker.component";
|
||||||
import FormRow from "../layout-form-row/layout-form-row.component";
|
import FormRow from "../layout-form-row/layout-form-row.component";
|
||||||
|
|
||||||
@@ -30,7 +29,7 @@ export function JobsDetailDatesComponent({ jobRO, job, bodyshop }) {
|
|||||||
<div>
|
<div>
|
||||||
<FormRow header={t("jobs.forms.estdates")}>
|
<FormRow header={t("jobs.forms.estdates")}>
|
||||||
<Form.Item label={t("jobs.fields.date_estimated")} name="date_estimated">
|
<Form.Item label={t("jobs.fields.date_estimated")} name="date_estimated">
|
||||||
<FormDatePicker disabled={jobRO} />
|
<DateTimePicker disabled={jobRO} isDateOnly />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item label={t("jobs.fields.date_open")} name="date_open">
|
<Form.Item label={t("jobs.fields.date_open")} name="date_open">
|
||||||
<DateTimePicker disabled={jobRO} />
|
<DateTimePicker disabled={jobRO} />
|
||||||
@@ -45,7 +44,7 @@ export function JobsDetailDatesComponent({ jobRO, job, bodyshop }) {
|
|||||||
|
|
||||||
<FormRow header={t("jobs.forms.scheddates")}>
|
<FormRow header={t("jobs.forms.scheddates")}>
|
||||||
<Form.Item label={t("jobs.fields.date_scheduled")} name="date_scheduled">
|
<Form.Item label={t("jobs.fields.date_scheduled")} name="date_scheduled">
|
||||||
<FormDatePicker disabled={jobRO} />
|
<DateTimePicker disabled={jobRO} isDateOnly />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Tooltip title={t("jobs.labels.scheduledinchange")}>
|
<Tooltip title={t("jobs.labels.scheduledinchange")}>
|
||||||
<Form.Item label={t("jobs.fields.scheduled_in")} name="scheduled_in">
|
<Form.Item label={t("jobs.fields.scheduled_in")} name="scheduled_in">
|
||||||
@@ -85,7 +84,6 @@ export function JobsDetailDatesComponent({ jobRO, job, bodyshop }) {
|
|||||||
rules={[
|
rules={[
|
||||||
{
|
{
|
||||||
required: jobInPostProduction
|
required: jobInPostProduction
|
||||||
//message: t("general.validation.required"),
|
|
||||||
}
|
}
|
||||||
]}
|
]}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import { connect } from "react-redux";
|
|||||||
import { createStructuredSelector } from "reselect";
|
import { createStructuredSelector } from "reselect";
|
||||||
import { selectJobReadOnly } from "../../redux/application/application.selectors";
|
import { selectJobReadOnly } from "../../redux/application/application.selectors";
|
||||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||||
import FormDatePicker from "../form-date-picker/form-date-picker.component";
|
|
||||||
import CurrencyInput from "../form-items-formatted/currency-form-item.component";
|
import CurrencyInput from "../form-items-formatted/currency-form-item.component";
|
||||||
import FormItemEmail from "../form-items-formatted/email-form-item.component";
|
import FormItemEmail from "../form-items-formatted/email-form-item.component";
|
||||||
import FormItemPhone, { PhoneItemFormatterValidation } from "../form-items-formatted/phone-form-item.component";
|
import FormItemPhone, { PhoneItemFormatterValidation } from "../form-items-formatted/phone-form-item.component";
|
||||||
@@ -13,6 +12,7 @@ import Car from "../job-damage-visual/job-damage-visual.component";
|
|||||||
import JobsDetailChangeEstimator from "../jobs-detail-change-estimator/jobs-detail-change-estimator.component";
|
import JobsDetailChangeEstimator from "../jobs-detail-change-estimator/jobs-detail-change-estimator.component";
|
||||||
import JobsDetailChangeFileHandler from "../jobs-detail-change-filehandler/jobs-detail-change-filehandler.component";
|
import JobsDetailChangeFileHandler from "../jobs-detail-change-filehandler/jobs-detail-change-filehandler.component";
|
||||||
import FormRow from "../layout-form-row/layout-form-row.component";
|
import FormRow from "../layout-form-row/layout-form-row.component";
|
||||||
|
import DateTimePicker from "../form-date-time-picker/form-date-time-picker.component.jsx";
|
||||||
|
|
||||||
const mapStateToProps = createStructuredSelector({
|
const mapStateToProps = createStructuredSelector({
|
||||||
jobRO: selectJobReadOnly,
|
jobRO: selectJobReadOnly,
|
||||||
@@ -152,7 +152,7 @@ export function JobsDetailGeneral({ bodyshop, jobRO, job, form }) {
|
|||||||
<Input disabled={jobRO} />
|
<Input disabled={jobRO} />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item label={t("jobs.fields.loss_date")} name="loss_date">
|
<Form.Item label={t("jobs.fields.loss_date")} name="loss_date">
|
||||||
<FormDatePicker disabled={jobRO} />
|
<DateTimePicker isDateOnly disabled={jobRO} />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item label={t("jobs.fields.loss_of_use")} name="loss_of_use">
|
<Form.Item label={t("jobs.fields.loss_of_use")} name="loss_of_use">
|
||||||
<Input disabled={jobRO} />
|
<Input disabled={jobRO} />
|
||||||
|
|||||||
@@ -1,55 +1,13 @@
|
|||||||
import { useQuery } from "@apollo/client";
|
|
||||||
import queryString from "query-string";
|
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { useLocation, useNavigate } from "react-router-dom";
|
|
||||||
import { QUERY_BILLS_BY_JOBID } from "../../graphql/bills.queries";
|
|
||||||
import JobsDetailPliComponent from "./jobs-detail-pli.component";
|
import JobsDetailPliComponent from "./jobs-detail-pli.component";
|
||||||
|
|
||||||
export default function JobsDetailPliContainer({ job }) {
|
export default function JobsDetailPliContainer({
|
||||||
const billsQuery = useQuery(QUERY_BILLS_BY_JOBID, {
|
job,
|
||||||
variables: { jobid: job.id },
|
billsQuery,
|
||||||
fetchPolicy: "network-only",
|
handleBillOnRowClick,
|
||||||
nextFetchPolicy: "network-only"
|
handlePartsOrderOnRowClick,
|
||||||
});
|
handlePartsDispatchOnRowClick
|
||||||
|
}) {
|
||||||
const search = queryString.parse(useLocation().search);
|
|
||||||
const history = useNavigate();
|
|
||||||
|
|
||||||
const handleBillOnRowClick = (record) => {
|
|
||||||
if (record) {
|
|
||||||
if (record.id) {
|
|
||||||
search.billid = record.id;
|
|
||||||
history({ search: queryString.stringify(search) });
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
delete search.billid;
|
|
||||||
history({ search: queryString.stringify(search) });
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const handlePartsOrderOnRowClick = (record) => {
|
|
||||||
if (record) {
|
|
||||||
if (record.id) {
|
|
||||||
search.partsorderid = record.id;
|
|
||||||
history({ search: queryString.stringify(search) });
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
delete search.partsorderid;
|
|
||||||
history({ search: queryString.stringify(search) });
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const handlePartsDispatchOnRowClick = (record) => {
|
|
||||||
if (record) {
|
|
||||||
if (record.id) {
|
|
||||||
search.partsdispatchid = record.id;
|
|
||||||
history.push({ search: queryString.stringify(search) });
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
delete search.partsdispatchid;
|
|
||||||
history.push({ search: queryString.stringify(search) });
|
|
||||||
}
|
|
||||||
};
|
|
||||||
return (
|
return (
|
||||||
<JobsDetailPliComponent
|
<JobsDetailPliComponent
|
||||||
job={job}
|
job={job}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { Collapse, Form, Switch } from "antd";
|
import { Collapse, Form, InputNumber, Switch } from "antd";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { connect } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
@@ -17,6 +17,9 @@ export function JobsDetailRatesLabor({ jobRO, expanded, required = true, form })
|
|||||||
<Collapse defaultActiveKey={expanded && "rates"}>
|
<Collapse defaultActiveKey={expanded && "rates"}>
|
||||||
<Collapse.Panel forceRender header={t("jobs.labels.cieca_pfl")} key="cieca_pfl">
|
<Collapse.Panel forceRender header={t("jobs.labels.cieca_pfl")} key="cieca_pfl">
|
||||||
<LayoutFormRow header={t("joblines.fields.lbr_types.LAB")}>
|
<LayoutFormRow header={t("joblines.fields.lbr_types.LAB")}>
|
||||||
|
<Form.Item label={t("jobs.fields.cieca_pfl.lbr_adjp")} name={["cieca_pfl", "LAB", "lbr_adjp"]}>
|
||||||
|
<InputNumber min={-100} max={100} precision={4} disabled={jobRO} />
|
||||||
|
</Form.Item>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
label={t("jobs.fields.cieca_pfl.lbr_tax_in")}
|
label={t("jobs.fields.cieca_pfl.lbr_tax_in")}
|
||||||
name={["cieca_pfl", "LAB", "lbr_tax_in"]}
|
name={["cieca_pfl", "LAB", "lbr_tax_in"]}
|
||||||
@@ -24,6 +27,24 @@ export function JobsDetailRatesLabor({ jobRO, expanded, required = true, form })
|
|||||||
>
|
>
|
||||||
<Switch disabled={jobRO} />
|
<Switch disabled={jobRO} />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
<Form.Item shouldUpdate>
|
||||||
|
{() => {
|
||||||
|
return (
|
||||||
|
<Form.Item
|
||||||
|
label={t("jobs.fields.cieca_pfl.lbr_taxp")}
|
||||||
|
name={["cieca_pfl", "LAB", "lbr_taxp"]}
|
||||||
|
rules={[
|
||||||
|
{
|
||||||
|
required: form.getFieldValue(["cieca_pfl", "LAB", "lbr_tax_in"])
|
||||||
|
//message: t("general.validation.required"),
|
||||||
|
}
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<InputNumber min={0} max={100} precision={4} disabled={jobRO} />
|
||||||
|
</Form.Item>
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
</Form.Item>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
label={t("jobs.fields.cieca_pfl.lbr_tx_in1")}
|
label={t("jobs.fields.cieca_pfl.lbr_tx_in1")}
|
||||||
name={["cieca_pfl", "LAB", "lbr_tx_in1"]}
|
name={["cieca_pfl", "LAB", "lbr_tx_in1"]}
|
||||||
@@ -61,6 +82,9 @@ export function JobsDetailRatesLabor({ jobRO, expanded, required = true, form })
|
|||||||
</Form.Item>
|
</Form.Item>
|
||||||
</LayoutFormRow>
|
</LayoutFormRow>
|
||||||
<LayoutFormRow header={t("joblines.fields.lbr_types.LAD")}>
|
<LayoutFormRow header={t("joblines.fields.lbr_types.LAD")}>
|
||||||
|
<Form.Item label={t("jobs.fields.cieca_pfl.lbr_adjp")} name={["cieca_pfl", "LAD", "lbr_adjp"]}>
|
||||||
|
<InputNumber min={-100} max={100} precision={4} disabled={jobRO} />
|
||||||
|
</Form.Item>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
label={t("jobs.fields.cieca_pfl.lbr_tax_in")}
|
label={t("jobs.fields.cieca_pfl.lbr_tax_in")}
|
||||||
name={["cieca_pfl", "LAD", "lbr_tax_in"]}
|
name={["cieca_pfl", "LAD", "lbr_tax_in"]}
|
||||||
@@ -68,6 +92,24 @@ export function JobsDetailRatesLabor({ jobRO, expanded, required = true, form })
|
|||||||
>
|
>
|
||||||
<Switch disabled={jobRO} />
|
<Switch disabled={jobRO} />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
<Form.Item shouldUpdate>
|
||||||
|
{() => {
|
||||||
|
return (
|
||||||
|
<Form.Item
|
||||||
|
label={t("jobs.fields.cieca_pfl.lbr_taxp")}
|
||||||
|
name={["cieca_pfl", "LAD", "lbr_taxp"]}
|
||||||
|
rules={[
|
||||||
|
{
|
||||||
|
required: form.getFieldValue(["cieca_pfl", "LAD", "lbr_tax_in"])
|
||||||
|
//message: t("general.validation.required"),
|
||||||
|
}
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<InputNumber min={0} max={100} precision={4} disabled={jobRO} />
|
||||||
|
</Form.Item>
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
</Form.Item>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
label={t("jobs.fields.cieca_pfl.lbr_tx_in1")}
|
label={t("jobs.fields.cieca_pfl.lbr_tx_in1")}
|
||||||
name={["cieca_pfl", "LAD", "lbr_tx_in1"]}
|
name={["cieca_pfl", "LAD", "lbr_tx_in1"]}
|
||||||
@@ -105,6 +147,9 @@ export function JobsDetailRatesLabor({ jobRO, expanded, required = true, form })
|
|||||||
</Form.Item>
|
</Form.Item>
|
||||||
</LayoutFormRow>
|
</LayoutFormRow>
|
||||||
<LayoutFormRow header={t("joblines.fields.lbr_types.LAE")}>
|
<LayoutFormRow header={t("joblines.fields.lbr_types.LAE")}>
|
||||||
|
<Form.Item label={t("jobs.fields.cieca_pfl.lbr_adjp")} name={["cieca_pfl", "LAE", "lbr_adjp"]}>
|
||||||
|
<InputNumber min={-100} max={100} precision={4} disabled={jobRO} />
|
||||||
|
</Form.Item>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
label={t("jobs.fields.cieca_pfl.lbr_tax_in")}
|
label={t("jobs.fields.cieca_pfl.lbr_tax_in")}
|
||||||
name={["cieca_pfl", "LAE", "lbr_tax_in"]}
|
name={["cieca_pfl", "LAE", "lbr_tax_in"]}
|
||||||
@@ -112,6 +157,24 @@ export function JobsDetailRatesLabor({ jobRO, expanded, required = true, form })
|
|||||||
>
|
>
|
||||||
<Switch disabled={jobRO} />
|
<Switch disabled={jobRO} />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
<Form.Item shouldUpdate>
|
||||||
|
{() => {
|
||||||
|
return (
|
||||||
|
<Form.Item
|
||||||
|
label={t("jobs.fields.cieca_pfl.lbr_taxp")}
|
||||||
|
name={["cieca_pfl", "LAE", "lbr_taxp"]}
|
||||||
|
rules={[
|
||||||
|
{
|
||||||
|
required: form.getFieldValue(["cieca_pfl", "LAE", "lbr_tax_in"])
|
||||||
|
//message: t("general.validation.required"),
|
||||||
|
}
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<InputNumber min={0} max={100} precision={4} disabled={jobRO} />
|
||||||
|
</Form.Item>
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
</Form.Item>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
label={t("jobs.fields.cieca_pfl.lbr_tx_in1")}
|
label={t("jobs.fields.cieca_pfl.lbr_tx_in1")}
|
||||||
name={["cieca_pfl", "LAE", "lbr_tx_in1"]}
|
name={["cieca_pfl", "LAE", "lbr_tx_in1"]}
|
||||||
@@ -149,6 +212,9 @@ export function JobsDetailRatesLabor({ jobRO, expanded, required = true, form })
|
|||||||
</Form.Item>
|
</Form.Item>
|
||||||
</LayoutFormRow>
|
</LayoutFormRow>
|
||||||
<LayoutFormRow header={t("joblines.fields.lbr_types.LAF")}>
|
<LayoutFormRow header={t("joblines.fields.lbr_types.LAF")}>
|
||||||
|
<Form.Item label={t("jobs.fields.cieca_pfl.lbr_adjp")} name={["cieca_pfl", "LAF", "lbr_adjp"]}>
|
||||||
|
<InputNumber min={-100} max={100} precision={4} disabled={jobRO} />
|
||||||
|
</Form.Item>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
label={t("jobs.fields.cieca_pfl.lbr_tax_in")}
|
label={t("jobs.fields.cieca_pfl.lbr_tax_in")}
|
||||||
name={["cieca_pfl", "LAF", "lbr_tax_in"]}
|
name={["cieca_pfl", "LAF", "lbr_tax_in"]}
|
||||||
@@ -156,6 +222,24 @@ export function JobsDetailRatesLabor({ jobRO, expanded, required = true, form })
|
|||||||
>
|
>
|
||||||
<Switch disabled={jobRO} />
|
<Switch disabled={jobRO} />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
<Form.Item shouldUpdate>
|
||||||
|
{() => {
|
||||||
|
return (
|
||||||
|
<Form.Item
|
||||||
|
label={t("jobs.fields.cieca_pfl.lbr_taxp")}
|
||||||
|
name={["cieca_pfl", "LAF", "lbr_taxp"]}
|
||||||
|
rules={[
|
||||||
|
{
|
||||||
|
required: form.getFieldValue(["cieca_pfl", "LAF", "lbr_tax_in"])
|
||||||
|
//message: t("general.validation.required"),
|
||||||
|
}
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<InputNumber min={0} max={100} precision={4} disabled={jobRO} />
|
||||||
|
</Form.Item>
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
</Form.Item>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
label={t("jobs.fields.cieca_pfl.lbr_tx_in1")}
|
label={t("jobs.fields.cieca_pfl.lbr_tx_in1")}
|
||||||
name={["cieca_pfl", "LAF", "lbr_tx_in1"]}
|
name={["cieca_pfl", "LAF", "lbr_tx_in1"]}
|
||||||
@@ -193,6 +277,9 @@ export function JobsDetailRatesLabor({ jobRO, expanded, required = true, form })
|
|||||||
</Form.Item>
|
</Form.Item>
|
||||||
</LayoutFormRow>
|
</LayoutFormRow>
|
||||||
<LayoutFormRow header={t("joblines.fields.lbr_types.LAG")}>
|
<LayoutFormRow header={t("joblines.fields.lbr_types.LAG")}>
|
||||||
|
<Form.Item label={t("jobs.fields.cieca_pfl.lbr_adjp")} name={["cieca_pfl", "LAG", "lbr_adjp"]}>
|
||||||
|
<InputNumber min={-100} max={100} precision={4} disabled={jobRO} />
|
||||||
|
</Form.Item>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
label={t("jobs.fields.cieca_pfl.lbr_tax_in")}
|
label={t("jobs.fields.cieca_pfl.lbr_tax_in")}
|
||||||
name={["cieca_pfl", "LAG", "lbr_tax_in"]}
|
name={["cieca_pfl", "LAG", "lbr_tax_in"]}
|
||||||
@@ -200,6 +287,24 @@ export function JobsDetailRatesLabor({ jobRO, expanded, required = true, form })
|
|||||||
>
|
>
|
||||||
<Switch disabled={jobRO} />
|
<Switch disabled={jobRO} />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
<Form.Item shouldUpdate>
|
||||||
|
{() => {
|
||||||
|
return (
|
||||||
|
<Form.Item
|
||||||
|
label={t("jobs.fields.cieca_pfl.lbr_taxp")}
|
||||||
|
name={["cieca_pfl", "LAG", "lbr_taxp"]}
|
||||||
|
rules={[
|
||||||
|
{
|
||||||
|
required: form.getFieldValue(["cieca_pfl", "LAG", "lbr_tax_in"])
|
||||||
|
//message: t("general.validation.required"),
|
||||||
|
}
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<InputNumber min={0} max={100} precision={4} disabled={jobRO} />
|
||||||
|
</Form.Item>
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
</Form.Item>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
label={t("jobs.fields.cieca_pfl.lbr_tx_in1")}
|
label={t("jobs.fields.cieca_pfl.lbr_tx_in1")}
|
||||||
name={["cieca_pfl", "LAG", "lbr_tx_in1"]}
|
name={["cieca_pfl", "LAG", "lbr_tx_in1"]}
|
||||||
@@ -237,6 +342,9 @@ export function JobsDetailRatesLabor({ jobRO, expanded, required = true, form })
|
|||||||
</Form.Item>
|
</Form.Item>
|
||||||
</LayoutFormRow>
|
</LayoutFormRow>
|
||||||
<LayoutFormRow header={t("joblines.fields.lbr_types.LAM")}>
|
<LayoutFormRow header={t("joblines.fields.lbr_types.LAM")}>
|
||||||
|
<Form.Item label={t("jobs.fields.cieca_pfl.lbr_adjp")} name={["cieca_pfl", "LAM", "lbr_adjp"]}>
|
||||||
|
<InputNumber min={-100} max={100} precision={4} disabled={jobRO} />
|
||||||
|
</Form.Item>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
label={t("jobs.fields.cieca_pfl.lbr_tax_in")}
|
label={t("jobs.fields.cieca_pfl.lbr_tax_in")}
|
||||||
name={["cieca_pfl", "LAM", "lbr_tax_in"]}
|
name={["cieca_pfl", "LAM", "lbr_tax_in"]}
|
||||||
@@ -244,6 +352,24 @@ export function JobsDetailRatesLabor({ jobRO, expanded, required = true, form })
|
|||||||
>
|
>
|
||||||
<Switch disabled={jobRO} />
|
<Switch disabled={jobRO} />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
<Form.Item shouldUpdate>
|
||||||
|
{() => {
|
||||||
|
return (
|
||||||
|
<Form.Item
|
||||||
|
label={t("jobs.fields.cieca_pfl.lbr_taxp")}
|
||||||
|
name={["cieca_pfl", "LAM", "lbr_taxp"]}
|
||||||
|
rules={[
|
||||||
|
{
|
||||||
|
required: form.getFieldValue(["cieca_pfl", "LAM", "lbr_tax_in"])
|
||||||
|
//message: t("general.validation.required"),
|
||||||
|
}
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<InputNumber min={0} max={100} precision={4} disabled={jobRO} />
|
||||||
|
</Form.Item>
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
</Form.Item>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
label={t("jobs.fields.cieca_pfl.lbr_tx_in1")}
|
label={t("jobs.fields.cieca_pfl.lbr_tx_in1")}
|
||||||
name={["cieca_pfl", "LAM", "lbr_tx_in1"]}
|
name={["cieca_pfl", "LAM", "lbr_tx_in1"]}
|
||||||
@@ -281,6 +407,9 @@ export function JobsDetailRatesLabor({ jobRO, expanded, required = true, form })
|
|||||||
</Form.Item>
|
</Form.Item>
|
||||||
</LayoutFormRow>
|
</LayoutFormRow>
|
||||||
<LayoutFormRow header={t("joblines.fields.lbr_types.LAR")}>
|
<LayoutFormRow header={t("joblines.fields.lbr_types.LAR")}>
|
||||||
|
<Form.Item label={t("jobs.fields.cieca_pfl.lbr_adjp")} name={["cieca_pfl", "LAR", "lbr_adjp"]}>
|
||||||
|
<InputNumber min={-100} max={100} precision={4} disabled={jobRO} />
|
||||||
|
</Form.Item>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
label={t("jobs.fields.cieca_pfl.lbr_tax_in")}
|
label={t("jobs.fields.cieca_pfl.lbr_tax_in")}
|
||||||
name={["cieca_pfl", "LAR", "lbr_tax_in"]}
|
name={["cieca_pfl", "LAR", "lbr_tax_in"]}
|
||||||
@@ -288,6 +417,24 @@ export function JobsDetailRatesLabor({ jobRO, expanded, required = true, form })
|
|||||||
>
|
>
|
||||||
<Switch disabled={jobRO} />
|
<Switch disabled={jobRO} />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
<Form.Item shouldUpdate>
|
||||||
|
{() => {
|
||||||
|
return (
|
||||||
|
<Form.Item
|
||||||
|
label={t("jobs.fields.cieca_pfl.lbr_taxp")}
|
||||||
|
name={["cieca_pfl", "LAR", "lbr_taxp"]}
|
||||||
|
rules={[
|
||||||
|
{
|
||||||
|
required: form.getFieldValue(["cieca_pfl", "LAR", "lbr_tax_in"])
|
||||||
|
//message: t("general.validation.required"),
|
||||||
|
}
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<InputNumber min={0} max={100} precision={4} disabled={jobRO} />
|
||||||
|
</Form.Item>
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
</Form.Item>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
label={t("jobs.fields.cieca_pfl.lbr_tx_in1")}
|
label={t("jobs.fields.cieca_pfl.lbr_tx_in1")}
|
||||||
name={["cieca_pfl", "LAR", "lbr_tx_in1"]}
|
name={["cieca_pfl", "LAR", "lbr_tx_in1"]}
|
||||||
@@ -325,6 +472,9 @@ export function JobsDetailRatesLabor({ jobRO, expanded, required = true, form })
|
|||||||
</Form.Item>
|
</Form.Item>
|
||||||
</LayoutFormRow>
|
</LayoutFormRow>
|
||||||
<LayoutFormRow header={t("joblines.fields.lbr_types.LAS")}>
|
<LayoutFormRow header={t("joblines.fields.lbr_types.LAS")}>
|
||||||
|
<Form.Item label={t("jobs.fields.cieca_pfl.lbr_adjp")} name={["cieca_pfl", "LAS", "lbr_adjp"]}>
|
||||||
|
<InputNumber min={-100} max={100} precision={4} disabled={jobRO} />
|
||||||
|
</Form.Item>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
label={t("jobs.fields.cieca_pfl.lbr_tax_in")}
|
label={t("jobs.fields.cieca_pfl.lbr_tax_in")}
|
||||||
name={["cieca_pfl", "LAS", "lbr_tax_in"]}
|
name={["cieca_pfl", "LAS", "lbr_tax_in"]}
|
||||||
@@ -332,6 +482,24 @@ export function JobsDetailRatesLabor({ jobRO, expanded, required = true, form })
|
|||||||
>
|
>
|
||||||
<Switch disabled={jobRO} />
|
<Switch disabled={jobRO} />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
<Form.Item shouldUpdate>
|
||||||
|
{() => {
|
||||||
|
return (
|
||||||
|
<Form.Item
|
||||||
|
label={t("jobs.fields.cieca_pfl.lbr_taxp")}
|
||||||
|
name={["cieca_pfl", "LAS", "lbr_taxp"]}
|
||||||
|
rules={[
|
||||||
|
{
|
||||||
|
required: form.getFieldValue(["cieca_pfl", "LAS", "lbr_tax_in"])
|
||||||
|
//message: t("general.validation.required"),
|
||||||
|
}
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<InputNumber min={0} max={100} precision={4} disabled={jobRO} />
|
||||||
|
</Form.Item>
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
</Form.Item>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
label={t("jobs.fields.cieca_pfl.lbr_tx_in1")}
|
label={t("jobs.fields.cieca_pfl.lbr_tx_in1")}
|
||||||
name={["cieca_pfl", "LAS", "lbr_tx_in1"]}
|
name={["cieca_pfl", "LAS", "lbr_tx_in1"]}
|
||||||
@@ -369,6 +537,9 @@ export function JobsDetailRatesLabor({ jobRO, expanded, required = true, form })
|
|||||||
</Form.Item>
|
</Form.Item>
|
||||||
</LayoutFormRow>
|
</LayoutFormRow>
|
||||||
<LayoutFormRow header={t("joblines.fields.lbr_types.LAU")}>
|
<LayoutFormRow header={t("joblines.fields.lbr_types.LAU")}>
|
||||||
|
<Form.Item label={t("jobs.fields.cieca_pfl.lbr_adjp")} name={["cieca_pfl", "LAU", "lbr_adjp"]}>
|
||||||
|
<InputNumber min={-100} max={100} precision={4} disabled={jobRO} />
|
||||||
|
</Form.Item>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
label={t("jobs.fields.cieca_pfl.lbr_tax_in")}
|
label={t("jobs.fields.cieca_pfl.lbr_tax_in")}
|
||||||
name={["cieca_pfl", "LAU", "lbr_tax_in"]}
|
name={["cieca_pfl", "LAU", "lbr_tax_in"]}
|
||||||
@@ -376,6 +547,24 @@ export function JobsDetailRatesLabor({ jobRO, expanded, required = true, form })
|
|||||||
>
|
>
|
||||||
<Switch disabled={jobRO} />
|
<Switch disabled={jobRO} />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
<Form.Item shouldUpdate>
|
||||||
|
{() => {
|
||||||
|
return (
|
||||||
|
<Form.Item
|
||||||
|
label={t("jobs.fields.cieca_pfl.lbr_taxp")}
|
||||||
|
name={["cieca_pfl", "LAU", "lbr_taxp"]}
|
||||||
|
rules={[
|
||||||
|
{
|
||||||
|
required: form.getFieldValue(["cieca_pfl", "LAU", "lbr_tax_in"])
|
||||||
|
//message: t("general.validation.required"),
|
||||||
|
}
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<InputNumber min={0} max={100} precision={4} disabled={jobRO} />
|
||||||
|
</Form.Item>
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
</Form.Item>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
label={t("jobs.fields.cieca_pfl.lbr_tx_in1")}
|
label={t("jobs.fields.cieca_pfl.lbr_tx_in1")}
|
||||||
name={["cieca_pfl", "LAU", "lbr_tx_in1"]}
|
name={["cieca_pfl", "LAU", "lbr_tx_in1"]}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user