Compare commits
721
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fdeff5b898 | ||
|
|
4e9d585566 | ||
|
|
b95a20a980 | ||
|
|
c9e7743782 | ||
|
|
6bf5918387 | ||
|
|
c2d79cf83f | ||
|
|
6ba1e16f9a | ||
|
|
6cce7d05f1 | ||
|
|
ac4834a2a4 | ||
|
|
850006d917 | ||
|
|
478fa91004 | ||
|
|
5813d409bc | ||
|
|
71035a054f | ||
|
|
c2c4690b9b | ||
|
|
9e2461305f | ||
|
|
db07425788 | ||
|
|
90e8cacf67 | ||
|
|
6462bd5163 | ||
|
|
d190fa8ff7 | ||
|
|
460dfadd1e | ||
|
|
d74e3fd668 | ||
|
|
75e9cf820d | ||
|
|
9a461dee5e | ||
|
|
1258985882 | ||
|
|
02507f298c | ||
|
|
11cdb43da4 | ||
|
|
f5bdf6a7b0 | ||
|
|
f80752ab6a | ||
|
|
b01d789bb8 | ||
|
|
bbf205a45f | ||
|
|
ec046944c0 | ||
|
|
579026b6cc | ||
|
|
2e9f90211c | ||
|
|
b7a644d078 | ||
|
|
7a54f3df71 | ||
|
|
a850399cb1 | ||
|
|
e2897e511f | ||
|
|
95486f0164 | ||
|
|
b00a2c0733 | ||
|
|
d7a73b7b0b | ||
|
|
bab0c26515 | ||
|
|
9ac88bbbde | ||
|
|
79e6dfade9 | ||
|
|
e864049bec | ||
|
|
49aa258fd9 | ||
|
|
ff699735c7 | ||
|
|
7b6af58065 | ||
|
|
001c7ad6fa | ||
|
|
b87c522137 | ||
|
|
3960a357dc | ||
|
|
94b19f9697 | ||
|
|
a1b89d19b8 | ||
|
|
f9f78548b0 | ||
|
|
a266fa5428 | ||
|
|
33dcb6b863 | ||
|
|
153f0d679e | ||
|
|
5483c4cdf2 | ||
|
|
c98bbfc321 | ||
|
|
6d0bc35612 | ||
|
|
d7bb1acb10 | ||
|
|
27fceffbc9 | ||
|
|
0150e243ed | ||
|
|
e195e09429 | ||
|
|
be68b987a1 | ||
|
|
60a2ff4594 | ||
|
|
81a6276f44 | ||
|
|
c84ff3fff9 | ||
|
|
a6941a8a06 | ||
|
|
475aa965b4 | ||
|
|
0b66a0e1d4 | ||
|
|
ca244e5de1 | ||
|
|
3efaafdb72 | ||
|
|
1e14fbc709 | ||
|
|
628b2b71fd | ||
|
|
3297fe4f16 | ||
|
|
7b1faf0bac | ||
|
|
c6e42fc314 | ||
|
|
7e47340326 | ||
|
|
c39e4bcc9a | ||
|
|
9595ad86df | ||
|
|
2262f3ab74 | ||
|
|
d0cae0fff1 | ||
|
|
a9be19b901 | ||
|
|
da07b4873e | ||
|
|
4ced5d0f42 | ||
|
|
18a05d4be8 | ||
|
|
b71a93076b | ||
|
|
3f2b8807e7 | ||
|
|
24cd7000f7 | ||
|
|
905c82f598 | ||
|
|
26e8464d46 | ||
|
|
1df5573fce | ||
|
|
25485d73ed | ||
|
|
6d8d56d745 | ||
|
|
f6bbaa5c1d | ||
|
|
4f3e3f5183 | ||
|
|
a6cc030612 | ||
|
|
2e98be3b65 | ||
|
|
149238dd4e | ||
|
|
b6bd543527 | ||
|
|
5967665138 | ||
|
|
9860f47cbe | ||
|
|
5bf1393020 | ||
|
|
5a8fd73bfd | ||
|
|
c2ae6964f9 | ||
|
|
4fb62a6773 | ||
|
|
d0b2fd077a | ||
|
|
d295a507ac | ||
|
|
4f90c9a058 | ||
|
|
0b02acf035 | ||
|
|
12a28a4be0 | ||
|
|
1a2c3ede3b | ||
|
|
46a0e0b185 | ||
|
|
0ff2d69ba6 | ||
|
|
d2e88b57d8 | ||
|
|
b596374c3c | ||
|
|
9140476a2a | ||
|
|
baf5b1838d | ||
|
|
1fd192b870 | ||
|
|
8b187742af | ||
|
|
421adafca3 | ||
|
|
a25ab433a6 | ||
|
|
843e6adee6 | ||
|
|
b2945790b1 | ||
|
|
138f03912b | ||
|
|
d406d97ddf | ||
|
|
f367f3342c | ||
|
|
d604d4f264 | ||
|
|
43e37dc844 | ||
|
|
7a14b7e8c9 | ||
|
|
b0004381ed | ||
|
|
20782db916 | ||
|
|
f34ac3ba11 | ||
|
|
5bf885933d | ||
|
|
05d83822f2 | ||
|
|
37a81522d5 | ||
|
|
c8b08a04a6 | ||
|
|
bb4c3ee054 | ||
|
|
15c35d201e | ||
|
|
0de9268255 | ||
|
|
bd3d311cfb | ||
|
|
ee2751a642 | ||
|
|
ac74782030 | ||
|
|
7d195ad906 | ||
|
|
61254e3942 | ||
|
|
97cde880c0 | ||
|
|
d3f4dda8af | ||
|
|
7a60e64a84 | ||
|
|
cebd47bf1c | ||
|
|
0b905f9374 | ||
|
|
0cd78e6f46 | ||
|
|
2a84056a76 | ||
|
|
17795f20c7 | ||
|
|
8edd23d621 | ||
|
|
96946ed205 | ||
|
|
c264830934 | ||
|
|
062cd23463 | ||
|
|
5f6dde782a | ||
|
|
78d62c541f | ||
|
|
ee3f3eae74 | ||
|
|
786f906ab8 | ||
|
|
04dc8fd2b9 | ||
|
|
c464fbf13b | ||
|
|
a8ef55c65a | ||
|
|
e24ab89e83 | ||
|
|
dd2ef694f8 | ||
|
|
e3e893ed58 | ||
|
|
30bc729c70 | ||
|
|
d576987fcf | ||
|
|
d75675f059 | ||
|
|
035f0e9adf | ||
|
|
f447aa19ea | ||
|
|
59d3ed287c | ||
|
|
1c06ef1639 | ||
|
|
3cea83b7e1 | ||
|
|
1f5be7c9a2 | ||
|
|
87af9a2c4c | ||
|
|
1b2f8e29c6 | ||
|
|
56e854ca2b | ||
|
|
5d40fab5c4 | ||
|
|
dbebd03cac | ||
|
|
8350e42d02 | ||
|
|
6c387fa6fb | ||
|
|
30bd8c49da | ||
|
|
eccb87e4a1 | ||
|
|
a3b848cfc1 | ||
|
|
497bb4c799 | ||
|
|
5e992507de | ||
|
|
dcdec08f6d | ||
|
|
503a0b5b9a | ||
|
|
52071058d6 | ||
|
|
f886fb8f25 | ||
|
|
f8665ee6b7 | ||
|
|
7ae5f80f26 | ||
|
|
b022c0a0d9 | ||
|
|
5b5a91b33b | ||
|
|
aa4d1fad1e | ||
|
|
5b9498b3ef | ||
|
|
06b7855826 | ||
|
|
02512ec403 | ||
|
|
c754e04034 | ||
|
|
da7e694120 | ||
|
|
786ed43fb2 | ||
|
|
638b51e55d | ||
|
|
bddcd1e964 | ||
|
|
bd13886222 | ||
|
|
69cf5d32b4 | ||
|
|
fd76dfe9bc | ||
|
|
2add85b519 | ||
|
|
82b99ae44f | ||
|
|
3bc3759a48 | ||
|
|
13cd2514c7 | ||
|
|
461ca7dc02 | ||
|
|
536ca11f6b | ||
|
|
2c4d645d56 | ||
|
|
1b145dd90f | ||
|
|
6f8bbd0131 | ||
|
|
830e36d0c4 | ||
|
|
48878e9ebd | ||
|
|
5c62f3088e | ||
|
|
361328c14a | ||
|
|
427e1c4673 | ||
|
|
9791270670 | ||
|
|
58e1eef1f5 | ||
|
|
8744d3dafc | ||
|
|
fcce6a3978 | ||
|
|
1b7e6009aa | ||
|
|
4e964ad1ad | ||
|
|
85cc7d165e | ||
|
|
7470975d0e | ||
|
|
811655c8d2 | ||
|
|
35ff16b2b2 | ||
|
|
30fad8e954 | ||
|
|
e238ec079f | ||
|
|
70d2ee175d | ||
|
|
10f221af38 | ||
|
|
6b66ad6d8f | ||
|
|
05f26ff12c | ||
|
|
ae64ee6c2b | ||
|
|
65003bb08c | ||
|
|
ad855fec88 | ||
|
|
391040b5ac | ||
|
|
e4bd8ab9b6 | ||
|
|
a66d55af80 | ||
|
|
93eb19d028 | ||
|
|
64201a6591 | ||
|
|
7553f992b7 | ||
|
|
d7874686a1 | ||
|
|
342c7ed457 | ||
|
|
a715e5fac7 | ||
|
|
7d2f8a2c27 | ||
|
|
480897bdc0 | ||
|
|
5309ffb8cf | ||
|
|
4a49bbca09 | ||
|
|
ba7d94d83d | ||
|
|
94e2ed5831 | ||
|
|
2f95636c4a | ||
|
|
9d67079fb0 | ||
|
|
ad3b18ac27 | ||
|
|
353378ee45 | ||
|
|
c1f6cc9832 | ||
|
|
f4471c5702 | ||
|
|
13dbb8b2d0 | ||
|
|
17be69323e | ||
|
|
6e6a104dd9 | ||
|
|
f596ad4e98 | ||
|
|
a74f59394e | ||
|
|
eb3b6013b3 | ||
|
|
6fa7cf9375 | ||
|
|
5e51c2eb97 | ||
|
|
fcfb7cf75e | ||
|
|
318f913397 | ||
|
|
0a5819803e | ||
|
|
e0510f9e8f | ||
|
|
bb190946ae | ||
|
|
1ba0cbe8a9 | ||
|
|
0faf79945f | ||
|
|
7903944223 | ||
|
|
ad0d2bf285 | ||
|
|
2ac2f51fc3 | ||
|
|
f12a719a1e | ||
|
|
4e390491c0 | ||
|
|
fad99c93bc | ||
|
|
1b7d9da32c | ||
|
|
51e255f70b | ||
|
|
da29e789c0 | ||
|
|
bf1ba9bc1e | ||
|
|
0f4b8005ba | ||
|
|
e8d4e8563e | ||
|
|
13be069b8b | ||
|
|
bd15fd18e1 | ||
|
|
6da6fdb4d2 | ||
|
|
5797443edc | ||
|
|
ac0253daeb | ||
|
|
44b32a618a | ||
|
|
fdf95dd0b1 | ||
|
|
6edbc431f8 | ||
|
|
312f7415f5 | ||
|
|
dea127912f | ||
|
|
7c0dc30b1a | ||
|
|
fe394f3fa8 | ||
|
|
dfdfd3653c | ||
|
|
c6205bbb39 | ||
|
|
9b0365ffbd | ||
|
|
cc4fb36439 | ||
|
|
411190e403 | ||
|
|
ba9beda65e | ||
|
|
3f2b945172 | ||
|
|
91a0ab82ea | ||
|
|
9f5ec6f50a | ||
|
|
3f5006a744 | ||
|
|
6e02ffe26d | ||
|
|
5c29a82842 | ||
|
|
ab50430493 | ||
|
|
c84287be3c | ||
|
|
f484f87694 | ||
|
|
8e0131d1ce | ||
|
|
bc483c5097 | ||
|
|
bd3bf6834b | ||
|
|
f09f3b75cc | ||
|
|
f8fba6a561 | ||
|
|
78cac2cbb9 | ||
|
|
51eb9b5a4f | ||
|
|
eec59e8e94 | ||
|
|
8b6ed73508 | ||
|
|
134f99c04c | ||
|
|
722ef9846a | ||
|
|
cb69bbe732 | ||
|
|
88e4586541 | ||
|
|
98e159d523 | ||
|
|
e0e91c843b | ||
|
|
bcf03a65f9 | ||
|
|
b59f13a45d | ||
|
|
2959c7d7a4 | ||
|
|
4601d7c15f | ||
|
|
b5a3a62c4b | ||
|
|
a106dea6c9 | ||
|
|
b880364e51 | ||
|
|
9af541ac6b | ||
|
|
b57f3de06f | ||
|
|
2caae7b458 | ||
|
|
a67f84a99f | ||
|
|
26b889d182 | ||
|
|
f9c9687cfe | ||
|
|
54820324f5 | ||
|
|
20b07ec3d5 | ||
|
|
e3bb321eae | ||
|
|
860291e1e6 | ||
|
|
0d23e47bea | ||
|
|
22b70f9081 | ||
|
|
e9cf1cf634 | ||
|
|
d17f3a11d2 | ||
|
|
6610e5c7f3 | ||
|
|
864da9fe23 | ||
|
|
16a5493109 | ||
|
|
0e99d9548b | ||
|
|
991cbf73ba | ||
|
|
25ba88ac34 | ||
|
|
f6c5e7183c | ||
|
|
91890f4d73 | ||
|
|
98184b65df | ||
|
|
3048df3cd9 | ||
|
|
e68319f16c | ||
|
|
3cbd876b77 | ||
|
|
f16161bcee | ||
|
|
9ae8ce7136 | ||
|
|
7d06bc7bfa | ||
|
|
8ff1af00b7 | ||
|
|
bda0af9e5c | ||
|
|
8ecde91bd9 | ||
|
|
51f89320de | ||
|
|
c64c47ca1f | ||
|
|
fcd51b41bd | ||
|
|
605932a640 | ||
|
|
f1775c2a96 | ||
|
|
1e690608fb | ||
|
|
7c84344d5d | ||
|
|
72eafd0a8e | ||
|
|
071fcc0dab | ||
|
|
e9b2753fd9 | ||
|
|
18dfc60754 | ||
|
|
023a8e9e6d | ||
|
|
598e4a6077 | ||
|
|
fffe1d19dd | ||
|
|
daa38d6459 | ||
|
|
36d35f9549 | ||
|
|
c2e14cab31 | ||
|
|
d32d7d016e | ||
|
|
6283786aeb | ||
|
|
e404a6d6db | ||
|
|
49dd99016a | ||
|
|
6a9a257ae8 | ||
|
|
c196edb457 | ||
|
|
1a95cf1098 | ||
|
|
0ca6cd94cc | ||
|
|
43204dfb54 | ||
|
|
b8fa514e3b | ||
|
|
6094874851 | ||
|
|
82f891ada8 | ||
|
|
846cba1645 | ||
|
|
0ca63d0228 | ||
|
|
36260bb405 | ||
|
|
368ef86b74 | ||
|
|
c73313b0fa | ||
|
|
51269db849 | ||
|
|
52202f4e1c | ||
|
|
f28b25cc24 | ||
|
|
e39c9203e3 | ||
|
|
3abebc8093 | ||
|
|
b5ae6c271f | ||
|
|
a35f2990c6 | ||
|
|
0c4a50a9e1 | ||
|
|
13e7e0c1a4 | ||
|
|
cd13453121 | ||
|
|
9a24ba1774 | ||
|
|
906be69648 | ||
|
|
344b6efed1 | ||
|
|
903118e47d | ||
|
|
1d1baec43b | ||
|
|
bef8f2590b | ||
|
|
fa985351ff | ||
|
|
f0202bbd02 | ||
|
|
c4ad9ab7a2 | ||
|
|
a0a633a9ea | ||
|
|
be59237ec9 | ||
|
|
61913f9f80 | ||
|
|
5822930f0a | ||
|
|
2a3c7eac34 | ||
|
|
86f41f81e9 | ||
|
|
79141ac6a9 | ||
|
|
36e41e064d | ||
|
|
d91ceda196 | ||
|
|
8b8742753e | ||
|
|
8141cb2394 | ||
|
|
e7882c9f78 | ||
|
|
7bd5c7d833 | ||
|
|
cf99d8e466 | ||
|
|
1a8a28fe3a | ||
|
|
c33cdf1b28 | ||
|
|
eebcfffd5e | ||
|
|
0da4a4b3b4 | ||
|
|
570bbb2fa1 | ||
|
|
3550faf051 | ||
|
|
72e4655188 | ||
|
|
dacf2511f5 | ||
|
|
5c54220bf8 | ||
|
|
548c85e339 | ||
|
|
562cffdc59 | ||
|
|
cbcb9549be | ||
|
|
694eab8297 | ||
|
|
a0ae6fcba3 | ||
|
|
aeec5e0f59 | ||
|
|
2950ce788a | ||
|
|
0bd6e12877 | ||
|
|
f947821afa | ||
|
|
9c483ec655 | ||
|
|
df311e131a | ||
|
|
93d02697a2 | ||
|
|
3e48f8cd28 | ||
|
|
e6c25d7ef5 | ||
|
|
6e3f7eeec1 | ||
|
|
de5ee86cde | ||
|
|
96e180040d | ||
|
|
95c1492fe0 | ||
|
|
2c6d110d9b | ||
|
|
e2c79d6b0f | ||
|
|
0e9a4da4be | ||
|
|
db184984ca | ||
|
|
610056849d | ||
|
|
92eb0c5a15 | ||
|
|
cfe732f299 | ||
|
|
b39ed0fd8c | ||
|
|
21eceff8df | ||
|
|
43c692a959 | ||
|
|
ab847a62b3 | ||
|
|
292a280f50 | ||
|
|
7da20386dd | ||
|
|
5e46495e79 | ||
|
|
c438a62553 | ||
|
|
5013b967f3 | ||
|
|
85b0a7e4c4 | ||
|
|
5cd3744e52 | ||
|
|
9d355f6f77 | ||
|
|
38a948e9a0 | ||
|
|
53540911cc | ||
|
|
ec067e62a5 | ||
|
|
3bd1e7e7fe | ||
|
|
dc8958f7a1 | ||
|
|
5c6ee2fedd | ||
|
|
1b586da1ae | ||
|
|
49374640e5 | ||
|
|
3569bce8d1 | ||
|
|
6b7403f6c8 | ||
|
|
a65ed04ad7 | ||
|
|
dd12dc99da | ||
|
|
e0392b108c | ||
|
|
e6b0b0763a | ||
|
|
737b74539d | ||
|
|
b9434e07a3 | ||
|
|
cfe6070d57 | ||
|
|
4710d3e420 | ||
|
|
088c93e2cf | ||
|
|
8a0c82f4e0 | ||
|
|
83dc4e12e3 | ||
|
|
9241fe0b84 | ||
|
|
94861846aa | ||
|
|
9b0f9acff9 | ||
|
|
062f64d157 | ||
|
|
dfaa54a6cf | ||
|
|
6978114ce0 | ||
|
|
3a5497fe76 | ||
|
|
5889c4093b | ||
|
|
140d615310 | ||
|
|
1f933b6d17 | ||
|
|
ab1df81745 | ||
|
|
3f4bd8d52e | ||
|
|
dc14e6c9af | ||
|
|
b5b114f455 | ||
|
|
bf2679045e | ||
|
|
92ceacb57b | ||
|
|
8f1aede2e3 | ||
|
|
d0b2fd0996 | ||
|
|
4562e5f092 | ||
|
|
3ccb96abc5 | ||
|
|
ab04761677 | ||
|
|
cb2ade03b4 | ||
|
|
103c548e32 | ||
|
|
28fb2ecbe7 | ||
|
|
8713317404 | ||
|
|
7c1262e4dc | ||
|
|
777d37f8b4 | ||
|
|
a24d68b8c4 | ||
|
|
dcb67e0de3 | ||
|
|
39dc5a349a | ||
|
|
a5dbd52d73 | ||
|
|
53f4b8140a | ||
|
|
9e1d091116 | ||
|
|
7e3c79830c | ||
|
|
4d310fd6c1 | ||
|
|
febfb4e532 | ||
|
|
a92b0af2db | ||
|
|
806952b98d | ||
|
|
412f7d2e90 | ||
|
|
56ad0c4843 | ||
|
|
ffae7df890 | ||
|
|
18ada0f9b1 | ||
|
|
6900d02f8c | ||
|
|
4b92f40018 | ||
|
|
0df0ad5faa | ||
|
|
7eda5ffd37 | ||
|
|
65f6b65613 | ||
|
|
26130d12d4 | ||
|
|
e2df26c935 | ||
|
|
3b65133ea0 | ||
|
|
d31002f0ed | ||
|
|
ffd6943aa1 | ||
|
|
17f516b797 | ||
|
|
46876cdff6 | ||
|
|
b4451dc7ee | ||
|
|
4cea869256 | ||
|
|
89f1691c8f | ||
|
|
5fc3b3867c | ||
|
|
a80fa87ea2 | ||
|
|
19ae9b9f63 | ||
|
|
40f7b92dc6 | ||
|
|
9c42fc64f0 | ||
|
|
1514eef343 | ||
|
|
5561e9f9bf | ||
|
|
e920ea681e | ||
|
|
e97f514c3f | ||
|
|
941e030b57 | ||
|
|
28eb95018a | ||
|
|
d0c56d1741 | ||
|
|
193da6af2f | ||
|
|
5dee64dfec | ||
|
|
f11aa09412 | ||
|
|
3d897e6b26 | ||
|
|
d6fd08a8ff | ||
|
|
f40514b4ea | ||
|
|
408dae0ca3 | ||
|
|
c14b0d0a40 | ||
|
|
cdf48a81a7 | ||
|
|
954e58ee3f | ||
|
|
6e764e9364 | ||
|
|
dedd23dfb1 | ||
|
|
1220131cfd | ||
|
|
3555688e39 | ||
|
|
c38da6c8d8 | ||
|
|
297a5dfc77 | ||
|
|
6c7eca581b | ||
|
|
8b244ffb94 | ||
|
|
089c225e4d | ||
|
|
0e33718c34 | ||
|
|
511713eede | ||
|
|
ff85f525a5 | ||
|
|
2cfb06db2a | ||
|
|
eb020b014d | ||
|
|
6354cabde0 | ||
|
|
f725c811b3 | ||
|
|
8e6b88984f | ||
|
|
e04f87323f | ||
|
|
ea1d530155 | ||
|
|
b72df06349 | ||
|
|
87812a6bf2 | ||
|
|
7aa7e2819a | ||
|
|
26070426e8 | ||
|
|
d85b59a25f | ||
|
|
0cf344ea85 | ||
|
|
deb7b12313 | ||
|
|
29abd0efd0 | ||
|
|
3877323b9b | ||
|
|
b4bec11fa0 | ||
|
|
afa81d8bd6 | ||
|
|
ae25ad4673 | ||
|
|
ae007d18ad | ||
|
|
2fb7895234 | ||
|
|
c738d2bde9 | ||
|
|
bfac0d1ff9 | ||
|
|
f0059eb949 | ||
|
|
50c2feaeba | ||
|
|
72ef0f7f40 | ||
|
|
dd0ed06732 | ||
|
|
48f24a6330 | ||
|
|
4fc0917b78 | ||
|
|
38f7853723 | ||
|
|
9dc135ef66 | ||
|
|
e961a1dff4 | ||
|
|
5ebffe74af | ||
|
|
f498d1a09e | ||
|
|
c0b23fff6c | ||
|
|
7f5fd90a17 | ||
|
|
8f9fd50f36 | ||
|
|
2e454290c7 | ||
|
|
eae42c3622 | ||
|
|
4bd1cf9744 | ||
|
|
0346b57d19 | ||
|
|
a33018d225 | ||
|
|
0f7a9c36df | ||
|
|
372e1bf7ce | ||
|
|
ad5c726b54 | ||
|
|
b6798fbfca | ||
|
|
43a194bf98 | ||
|
|
0433304faf | ||
|
|
0d91e75811 | ||
|
|
f586842b39 | ||
|
|
81fe090ce0 | ||
|
|
2dc8a721ab | ||
|
|
0c8f166410 | ||
|
|
c7c74b6250 | ||
|
|
a26313c798 | ||
|
|
e24fe83d0a | ||
|
|
7c5582f6c2 | ||
|
|
d6206ee2be | ||
|
|
cb8b7938f5 | ||
|
|
13e598c60c | ||
|
|
2af5c712ab | ||
|
|
ed077214bb | ||
|
|
ac1c127548 | ||
|
|
9a44e36ceb | ||
|
|
8a24852961 | ||
|
|
c14c86cdbd | ||
|
|
46bd30cd76 | ||
|
|
7d86ac0ca4 | ||
|
|
479f30b0a4 | ||
|
|
e6498c813d | ||
|
|
a5df22a486 | ||
|
|
b912f9ecb8 | ||
|
|
1a740bd78b | ||
|
|
cc0e830cf8 | ||
|
|
927cd70d75 | ||
|
|
8cca0db6e9 | ||
|
|
a09c458aed | ||
|
|
93f385e0b0 | ||
|
|
5c829f1d26 | ||
|
|
1c65d49110 | ||
|
|
a6cdec43e1 | ||
|
|
b50f94074b | ||
|
|
4d4d1fe995 | ||
|
|
11c9df9483 | ||
|
|
19a377f49f | ||
|
|
cd750a9228 | ||
|
|
98251d5da9 | ||
|
|
d01d83ecc4 | ||
|
|
626b2720ab | ||
|
|
837d7c68f7 | ||
|
|
f7af4d4bcc | ||
|
|
528c3284c6 | ||
|
|
68d03ed93d | ||
|
|
9eace1b626 | ||
|
|
34ce7f73a8 | ||
|
|
07f3769d84 | ||
|
|
f6fdc79ae3 | ||
|
|
ebed61f75f | ||
|
|
d9a18f008d | ||
|
|
c5f893f91c | ||
|
|
373a6c0d27 | ||
|
|
884c62ee46 | ||
|
|
73ebd12cd2 | ||
|
|
05b034c328 | ||
|
|
a458a12c6a | ||
|
|
bbc1e3f0a1 | ||
|
|
83fed387f3 | ||
|
|
1a276be54d | ||
|
|
422b3ce98c | ||
|
|
2c7823f911 | ||
|
|
bef329453a | ||
|
|
8d3d356815 | ||
|
|
baa1f7c4f3 | ||
|
|
804f3a6f66 | ||
|
|
49baec5814 | ||
|
|
ae5c0b4e39 | ||
|
|
e1444887cb | ||
|
|
9d6f9c6c49 | ||
|
|
b699f1d359 | ||
|
|
dec96c0546 | ||
|
|
7fad19452b | ||
|
|
1a102ab6cd | ||
|
|
202e1efd51 | ||
|
|
4d6ed2d38d | ||
|
|
f9df42f361 | ||
|
|
53515afc49 |
@@ -0,0 +1,176 @@
|
||||
# Contributing with AI (Refactor Branch — PEDW FrontEnd)
|
||||
|
||||
## Purpose
|
||||
|
||||
This guide defines how engineers and AI agents should work safely and efficiently in this refactor branch.
|
||||
|
||||
This branch focuses on **safe, behaviour-preserving refactor of the new appeal flow**.
|
||||
|
||||
---
|
||||
|
||||
## Start Here (Required Order)
|
||||
|
||||
1. Read `.clinerules/refactor-branch-rules.md`
|
||||
2. Read `GUARDRAILS.md`
|
||||
3. Read core context:
|
||||
- `context/refactor-branch-charter.md`
|
||||
- `context/newappeal-refactor-guardrails.md`
|
||||
- `context/architecture.md`
|
||||
- `context/domain-flows.md`
|
||||
|
||||
Only read additional files when directly relevant.
|
||||
|
||||
Do **not** load all context, templates, or memory-bank files by default.
|
||||
|
||||
---
|
||||
|
||||
## Core Principle
|
||||
|
||||
This is a **refactor branch**, not a feature branch.
|
||||
|
||||
- Preserve current live S78 behaviour
|
||||
- Do not introduce business-rule changes unless explicitly requested
|
||||
- Prefer small, safe, reversible changes
|
||||
- Focus on structure, not behaviour
|
||||
|
||||
---
|
||||
|
||||
## Standard AI-Assisted Workflow
|
||||
|
||||
### 1. Scope
|
||||
|
||||
- Define requirement
|
||||
- Confirm non-goals
|
||||
- Identify impacted flow areas
|
||||
- Identify risk level
|
||||
|
||||
### 2. Plan
|
||||
|
||||
- Keep plan small and incremental
|
||||
- Identify safe boundaries
|
||||
- Avoid mixing refactor + feature work
|
||||
|
||||
### 3. Implement
|
||||
|
||||
- Make the smallest viable change
|
||||
- Prefer extraction over rewrite
|
||||
- Preserve interfaces and payload shapes
|
||||
|
||||
### 4. Validate
|
||||
|
||||
Minimum required:
|
||||
|
||||
- `npm run lint`
|
||||
- targeted manual checks
|
||||
- EN/CY parity checks (if user-facing)
|
||||
- negative-path checks for sensitive flows
|
||||
|
||||
### 5. Document (only when needed)
|
||||
|
||||
- update `memory-bank/change-log.md` for non-trivial work
|
||||
- record decisions or pitfalls if useful
|
||||
|
||||
---
|
||||
|
||||
## Templates (Use Only When Needed)
|
||||
|
||||
Templates are optional tools, not default context.
|
||||
|
||||
Use **only one** template if needed:
|
||||
|
||||
- feature implementation
|
||||
- bug fix
|
||||
- refactor
|
||||
- debugging
|
||||
- code review
|
||||
|
||||
Do not load all templates.
|
||||
Do not treat templates as baseline context.
|
||||
|
||||
---
|
||||
|
||||
## Context Loading Rule (Critical)
|
||||
|
||||
Always use the **minimum required context**.
|
||||
|
||||
### Default context for this branch:
|
||||
|
||||
- `context/refactor-branch-charter.md`
|
||||
- `context/newappeal-refactor-guardrails.md`
|
||||
- `context/architecture.md`
|
||||
- `context/domain-flows.md`
|
||||
|
||||
### Only load additional files when:
|
||||
|
||||
- working with integrations → `integration-map.md`
|
||||
- reviewing test gaps → `test-coverage-map.md`
|
||||
- performing release work → `runbook.md`
|
||||
- working on specific planned sequence → `context/plans/*`
|
||||
|
||||
Never load:
|
||||
|
||||
- all context files
|
||||
- all templates
|
||||
- onboarding or overview docs
|
||||
|
||||
---
|
||||
|
||||
## Branching Protocol
|
||||
|
||||
This repository currently uses different branch rules depending on the work type.
|
||||
|
||||
### For BAU / normal delivery work
|
||||
|
||||
- create work branches from `SIPS-Development`
|
||||
|
||||
### For new appeal refactor work
|
||||
|
||||
- use the `refactor` branch as the base branch
|
||||
- do refactor implementation either:
|
||||
- directly on `refactor`, if that is the agreed working model, or
|
||||
- on a short-lived feature branch created from `refactor`
|
||||
|
||||
Do not perform refactor implementation directly on `SIPS-Development`.
|
||||
|
||||
If unsure which branch model applies, stop and confirm before making changes.
|
||||
|
||||
---
|
||||
|
||||
## No-Break Rules (Always Enforce)
|
||||
|
||||
- Do not weaken auth/session behaviour
|
||||
- Do not weaken security headers/CSP
|
||||
- Keep EN/CY behaviour aligned
|
||||
- Do not expose secrets or personal data
|
||||
- Protect save/resume/upload/submit journeys
|
||||
|
||||
---
|
||||
|
||||
## PR Minimum (AI-Assisted)
|
||||
|
||||
Every change must include:
|
||||
|
||||
- Scope summary
|
||||
- Files changed
|
||||
- Risk notes (auth/data/i18n/a11y)
|
||||
- Validation evidence
|
||||
- Rollback plan
|
||||
|
||||
---
|
||||
|
||||
## Handling Unknowns
|
||||
|
||||
If unsure:
|
||||
|
||||
1. Choose the safer option
|
||||
2. Do not change behaviour
|
||||
3. call out assumptions clearly
|
||||
4. log open questions if needed
|
||||
|
||||
---
|
||||
|
||||
## Summary Rule
|
||||
|
||||
If in doubt:
|
||||
|
||||
> Preserve behaviour, reduce risk, keep changes small.
|
||||
@@ -0,0 +1,95 @@
|
||||
# Default Rules (Reference Only)
|
||||
|
||||
## Important
|
||||
|
||||
This file is **not the active rule set for this refactor branch**.
|
||||
|
||||
Active working rules are defined in:
|
||||
|
||||
- `.clinerules/refactor-branch-rules.md`
|
||||
- `context/refactor-branch-charter.md`
|
||||
- `context/newappeal-refactor-guardrails.md`
|
||||
|
||||
Do not load this file by default.
|
||||
|
||||
---
|
||||
|
||||
## Purpose
|
||||
|
||||
This file provides general repository-wide guidance and may be referenced when needed for broader context.
|
||||
|
||||
---
|
||||
|
||||
## Repository Mission
|
||||
|
||||
Deliver safe, accessible, bilingual (EN/CY), and reliable public-service functionality without regressing core journeys.
|
||||
|
||||
---
|
||||
|
||||
## General Priorities
|
||||
|
||||
1. Safety and security of user data
|
||||
2. Stability of public-facing journeys
|
||||
3. Accessibility and bilingual parity
|
||||
4. Maintainability of code
|
||||
5. Controlled, safe delivery
|
||||
|
||||
---
|
||||
|
||||
## General Coding Guidance
|
||||
|
||||
- Follow existing repo patterns
|
||||
- Keep page-level logic thin
|
||||
- Move reusable logic into `components/`, `actions/`, or `lib/`
|
||||
- Avoid broad refactors in feature or bugfix work
|
||||
- Prefer small, focused changes
|
||||
|
||||
---
|
||||
|
||||
## Architecture Guardrails (General)
|
||||
|
||||
- Do not bypass auth/session handling
|
||||
- Do not weaken security controls
|
||||
- Preserve relay request integrity
|
||||
- Maintain EN/CY route parity
|
||||
- Keep Redux hydration/persistence stable
|
||||
|
||||
---
|
||||
|
||||
## Validation Expectations (General)
|
||||
|
||||
- linting must pass
|
||||
- user-facing changes must be verified
|
||||
- accessibility and EN/CY checks required
|
||||
- sensitive flows require negative-path checks
|
||||
|
||||
---
|
||||
|
||||
## When To Use This File
|
||||
|
||||
Only reference this file when:
|
||||
|
||||
- broader repository rules are required
|
||||
- behaviour conflicts are unclear
|
||||
- no branch-specific guidance exists
|
||||
|
||||
---
|
||||
|
||||
## Summary
|
||||
|
||||
This file is background guidance only.
|
||||
|
||||
For this refactor branch:
|
||||
|
||||
- follow branch-specific rules first
|
||||
- prioritise behaviour preservation
|
||||
- keep context minimal and focused
|
||||
|
||||
## Branching Guidance (Reference)
|
||||
|
||||
Branching depends on work type:
|
||||
|
||||
- BAU work typically branches from `SIPS-Development`
|
||||
- refactor-stream work for the new appeal flow uses `refactor` as the base branch
|
||||
|
||||
Follow branch-specific rules first.
|
||||
@@ -0,0 +1,234 @@
|
||||
# Refactor Branch Rules (Active)
|
||||
|
||||
## Purpose
|
||||
|
||||
This file defines the active working rules for the **refactor branch**.
|
||||
|
||||
This branch is focused on **safe, behaviour-preserving refactor of portal journeys**, including:
|
||||
|
||||
- New Appeal Flow (completed baseline)
|
||||
- Representations Flow (active refactor stream)
|
||||
|
||||
---
|
||||
|
||||
## Core Rule (Highest Priority)
|
||||
|
||||
Do not change live behaviour unless explicitly instructed.
|
||||
|
||||
Refactor = improve structure, not behaviour.
|
||||
|
||||
---
|
||||
|
||||
## Primary Objectives
|
||||
|
||||
1. Make core portal journeys easier to understand and maintain
|
||||
2. Reduce risk when making future changes
|
||||
3. Improve separation of concerns (UI, workflow, data, integrations)
|
||||
4. Prepare flows for future extensibility (e.g. multiple appeal types, additional journey types)
|
||||
|
||||
---
|
||||
|
||||
## Active Refactor Streams
|
||||
|
||||
### Completed
|
||||
|
||||
- New Appeal Flow (S78)
|
||||
|
||||
### Active
|
||||
|
||||
- Representations Flow
|
||||
|
||||
Each stream must follow **slice-based, behaviour-preserving refactor discipline**.
|
||||
|
||||
---
|
||||
|
||||
## Non-Negotiable Rules
|
||||
|
||||
- Preserve all current user journeys:
|
||||
|
||||
### Appeals
|
||||
|
||||
- start appeal
|
||||
- save and exit
|
||||
- resume appeal
|
||||
- upload documents
|
||||
- check answers
|
||||
- submit appeal
|
||||
- confirmation
|
||||
|
||||
### Representations
|
||||
|
||||
- start from case summary CTA
|
||||
- select capacity
|
||||
- select representation type
|
||||
- enter content / upload files
|
||||
- check answers
|
||||
- submit representation
|
||||
- completion
|
||||
|
||||
---
|
||||
|
||||
Do not:
|
||||
|
||||
- change payload structures
|
||||
- change validation rules
|
||||
- change business logic
|
||||
- change route/query behaviour
|
||||
- change navigation or side-effect sequencing
|
||||
- introduce EN/CY drift
|
||||
- mix refactor with feature work
|
||||
|
||||
---
|
||||
|
||||
## Refactor Approach
|
||||
|
||||
Always:
|
||||
|
||||
1. Understand current behaviour first
|
||||
2. Identify smallest safe change
|
||||
3. Prefer extraction over rewrite
|
||||
4. Keep public interfaces stable
|
||||
5. Make changes easy to review and revert
|
||||
|
||||
---
|
||||
|
||||
## Change Size Guidance
|
||||
|
||||
- Prefer small PRs (<400 LOC where possible)
|
||||
- Avoid large multi-concern changes
|
||||
- Split work into safe slices
|
||||
- One slice = one branch = one commit
|
||||
|
||||
---
|
||||
|
||||
## Branch Model (Critical)
|
||||
|
||||
### Branch Roles
|
||||
|
||||
- `SIPS-Development`
|
||||
- BAU branch
|
||||
- ongoing feature and bugfix work
|
||||
- must remain stable
|
||||
|
||||
- `refactor`
|
||||
- integration branch for refactor work
|
||||
- all refactor slices merge here first
|
||||
|
||||
- feature branches (short-lived)
|
||||
- created from `refactor`
|
||||
- one per slice
|
||||
- merged back into `refactor`
|
||||
|
||||
---
|
||||
|
||||
### Flow
|
||||
|
||||
SIPS-Development
|
||||
↓
|
||||
refactor
|
||||
↓
|
||||
feature/slice-x
|
||||
↓
|
||||
refactor
|
||||
↓ (when stable & validated)
|
||||
SIPS-Development
|
||||
|
||||
---
|
||||
|
||||
## Context Usage Rules (Critical for Efficiency)
|
||||
|
||||
### Default context (only load these):
|
||||
|
||||
- `context/refactor-branch-charter.md`
|
||||
- `context/architecture.md`
|
||||
- `context/domain-flows.md`
|
||||
|
||||
### Only load when needed:
|
||||
|
||||
- appeal work → `newappeal-refactor-guardrails.md`
|
||||
- representation work → `representations-refactor-guardrails.md`
|
||||
- plans → `context/plans/*`
|
||||
|
||||
### Never load by default:
|
||||
|
||||
- all context files
|
||||
- onboarding docs
|
||||
- all templates
|
||||
|
||||
---
|
||||
|
||||
## Templates Usage
|
||||
|
||||
- Use only ONE template when needed
|
||||
- Do not load all templates
|
||||
- Do not treat templates as baseline context
|
||||
|
||||
---
|
||||
|
||||
## Safety Rules
|
||||
|
||||
- Do not weaken authentication or session logic
|
||||
- Do not weaken security headers or middleware
|
||||
- Do not expose secrets or personal data
|
||||
- Preserve EN/CY parity
|
||||
- Maintain accessibility standards
|
||||
|
||||
---
|
||||
|
||||
## Regression Safety Rule (Critical)
|
||||
|
||||
This is a live system. All refactor work must prove behaviour is unchanged.
|
||||
|
||||
Before completing any slice:
|
||||
|
||||
### Appeals
|
||||
|
||||
- start appeal
|
||||
- save and exit
|
||||
- resume
|
||||
- upload
|
||||
- check answers
|
||||
- submit
|
||||
- confirmation
|
||||
|
||||
### Representations
|
||||
|
||||
- navigate from case summary → make representation
|
||||
- complete full journey
|
||||
- submit successfully
|
||||
- confirmation shown
|
||||
|
||||
Also:
|
||||
|
||||
- verify EN/CY parity
|
||||
- verify no navigation or state regressions
|
||||
|
||||
If regression cannot be ruled out:
|
||||
→ do not proceed
|
||||
|
||||
---
|
||||
|
||||
## When Unsure
|
||||
|
||||
1. Choose the safest option
|
||||
2. Do not change behaviour
|
||||
3. Call out assumptions
|
||||
4. Keep the change minimal
|
||||
|
||||
---
|
||||
|
||||
## Definition of Success
|
||||
|
||||
A successful change:
|
||||
|
||||
- preserves behaviour
|
||||
- reduces complexity
|
||||
- improves clarity
|
||||
- is small and safe to merge
|
||||
- introduces no regression risk
|
||||
|
||||
---
|
||||
|
||||
## One-Line Rule
|
||||
|
||||
> Keep behaviour the same, reduce risk, and make the smallest safe change.
|
||||
@@ -0,0 +1,15 @@
|
||||
# Bugfix Workflow
|
||||
|
||||
1. Clarify the bug symptoms and expected behavior.
|
||||
2. Inspect the relevant files and execution path.
|
||||
3. Identify the most likely root cause.
|
||||
4. Implement the smallest safe fix.
|
||||
5. Check for:
|
||||
- side effects
|
||||
- regression risk
|
||||
- validation gaps
|
||||
- missing error handling
|
||||
6. Summarize:
|
||||
- root cause
|
||||
- fix
|
||||
- preventive improvements worth noting
|
||||
@@ -0,0 +1,17 @@
|
||||
# Code Review Workflow
|
||||
|
||||
Review the relevant code or changes for:
|
||||
- correctness
|
||||
- edge cases
|
||||
- data integrity
|
||||
- security concerns
|
||||
- performance concerns
|
||||
- maintainability
|
||||
- readability
|
||||
- consistency with repo conventions
|
||||
|
||||
Return:
|
||||
1. key findings
|
||||
2. impact / severity where useful
|
||||
3. suggested improvements
|
||||
4. strengths worth preserving
|
||||
@@ -0,0 +1,18 @@
|
||||
# Database Migration Workflow
|
||||
|
||||
1. Understand the desired schema or data change.
|
||||
2. Inspect current data model, queries, and dependent code.
|
||||
3. Identify:
|
||||
- forward migration steps
|
||||
- backward compatibility concerns
|
||||
- rollback considerations
|
||||
4. Implement or propose the minimal safe migration path.
|
||||
5. Review for:
|
||||
- data integrity
|
||||
- ordering issues
|
||||
- application compatibility
|
||||
- deployment timing risk
|
||||
6. Summarize:
|
||||
- schema/data changes
|
||||
- impacted code paths
|
||||
- rollout / rollback notes
|
||||
@@ -0,0 +1,17 @@
|
||||
# Debugging Workflow
|
||||
|
||||
1. Capture the symptom, error, or incorrect behavior.
|
||||
2. Inspect the relevant path and recent changes.
|
||||
3. Form the most likely hypotheses.
|
||||
4. Narrow the cause using the smallest practical evidence checks.
|
||||
5. Propose or implement the minimal safe fix.
|
||||
6. Review for:
|
||||
- hidden assumptions
|
||||
- unhandled states
|
||||
- logging or observability gaps
|
||||
- regression risk
|
||||
7. Summarize:
|
||||
- symptom
|
||||
- cause
|
||||
- fix
|
||||
- prevention ideas
|
||||
@@ -0,0 +1,10 @@
|
||||
# Documentation Update Workflow
|
||||
|
||||
1. Identify what changed in the code or workflow.
|
||||
2. Inspect the affected docs and support files.
|
||||
3. Update only the relevant sections.
|
||||
4. Keep the docs concise, factual, and current.
|
||||
5. Summarize:
|
||||
- what changed
|
||||
- which docs were updated
|
||||
- anything still uncertain
|
||||
@@ -0,0 +1,16 @@
|
||||
# Feature Implementation Workflow
|
||||
|
||||
1. Understand the requirement and desired outcome.
|
||||
2. Inspect the relevant files, patterns, and data flows.
|
||||
3. Propose a short implementation plan for non-trivial work.
|
||||
4. Implement the smallest maintainable change that satisfies the requirement.
|
||||
5. Review for:
|
||||
- correctness
|
||||
- edge cases
|
||||
- error handling
|
||||
- compatibility with existing behavior
|
||||
- maintainability
|
||||
6. Summarize:
|
||||
- what changed
|
||||
- why
|
||||
- any follow-up considerations
|
||||
@@ -0,0 +1,13 @@
|
||||
# Planning Workflow
|
||||
|
||||
1. Clarify the objective.
|
||||
2. Inspect the relevant code areas and constraints.
|
||||
3. Identify implementation options.
|
||||
4. Compare trade-offs.
|
||||
5. Recommend the most practical path.
|
||||
6. Return:
|
||||
- objective summary
|
||||
- proposed plan
|
||||
- risks
|
||||
- dependencies
|
||||
- suggested execution order
|
||||
@@ -0,0 +1,16 @@
|
||||
# PR Review Workflow
|
||||
|
||||
Review the pull request or change set for:
|
||||
- correctness
|
||||
- scope discipline
|
||||
- regression risk
|
||||
- compatibility impact
|
||||
- tests or validation gaps
|
||||
- security and performance concerns
|
||||
- maintainability
|
||||
|
||||
Return:
|
||||
1. summary of change intent
|
||||
2. key risks
|
||||
3. requested changes
|
||||
4. optional improvements
|
||||
@@ -0,0 +1,16 @@
|
||||
# Refactor Workflow
|
||||
|
||||
1. Understand the current behavior that must be preserved.
|
||||
2. Inspect the relevant modules and dependencies.
|
||||
3. Identify safe refactor boundaries.
|
||||
4. Propose a scoped plan.
|
||||
5. Refactor incrementally.
|
||||
6. Review for:
|
||||
- preserved behavior
|
||||
- reduced complexity
|
||||
- improved readability
|
||||
- regression risk
|
||||
7. Summarize:
|
||||
- what was simplified
|
||||
- what was preserved
|
||||
- remaining debt
|
||||
@@ -0,0 +1,15 @@
|
||||
# Release Readiness Workflow
|
||||
|
||||
1. Review the scope of changes.
|
||||
2. Check:
|
||||
- build readiness
|
||||
- environment assumptions
|
||||
- configuration changes
|
||||
- database implications
|
||||
- CI/CD impact
|
||||
- rollback expectations
|
||||
3. Identify release risks and missing checks.
|
||||
4. Summarize:
|
||||
- release blockers
|
||||
- risks
|
||||
- final recommended checks
|
||||
+71
-64
@@ -18,7 +18,8 @@ CLIENT_SECRET = .Jf8Q~tKMObCJjhh_hy3J5AIctFrBalU4FS~tdxk
|
||||
RELAY_ROOT = https://ar-ns-lz-pedw-dev-uks-01.servicebus.windows.net/ar-hc-lz-pedw-dev-uks-01/
|
||||
RELAYURI = "ar-ns-lz-pedw-dev-uks-01.servicebus.windows.net"
|
||||
RELAYPATH = "ar-hc-lz-pedw-dev-uks-01"
|
||||
CRMURL = "devcrm2016.llcdt.gov.wales/DVPINS"
|
||||
CRMURL = "dv-pedw.crm11.dynamics.com"
|
||||
CRMURL_VERSION = "v9.2"
|
||||
|
||||
# //New Test
|
||||
CLIENT_ID = d40b9373-96c2-4b04-8bd8-c2a2fe6444c1
|
||||
@@ -26,18 +27,19 @@ CLIENT_SECRET = 6hT8Q~glL~jloWpGmvXw3UY37QFwjUE0r._jobEM
|
||||
RELAY_ROOT = https://ar-ns-lz-pedw-test-uks-01.servicebus.windows.net/ar-hc-lz-pedw-test-uks-01/
|
||||
RELAYURI = "ar-ns-lz-pedw-test-uks-01.servicebus.windows.net"
|
||||
RELAYPATH = "ar-hc-lz-pedw-test-uks-01"
|
||||
CRMURL = "tscrm2016.llcdt.gov.wales/UATPINS"
|
||||
# CRMURL = "tscrm2016.llcdt.gov.wales/UATPINS"
|
||||
# CRMURL_VERSION = "v8.2"
|
||||
CRMURL = "ts-pedw.crm11.dynamics.com"
|
||||
CRMURL_VERSION = "v9.2"
|
||||
|
||||
# # //New PreProd
|
||||
# CLIENT_ID = ab6c4678-b31a-4eb3-b429-e039120e488a
|
||||
# CLIENT_SECRET = V288Q~P1lFMvvX9Xnkx2pLixK~GOREH983Owqc1E
|
||||
# RELAY_ROOT = https://ar-ns-lz-pedw-ppe-uks-01.servicebus.windows.net/ar-hc-lz-pedw-ppe-uks-01/
|
||||
# RELAYURI = "ar-ns-lz-pedw-ppe-uks-01.servicebus.windows.net"
|
||||
# RELAYPATH = "ar-hc-lz-pedw-ppe-uks-01"
|
||||
# # RELAY_ROOT = https://ar-ns-lz-pedw-ppe-ukw-01.servicebus.windows.net/ar-hc-lz-pedw-ppe-ukw-01/
|
||||
# # RELAYURI = "ar-ns-lz-pedw-ppe-ukw-01.servicebus.windows.net"
|
||||
# # RELAYPATH = "ar-hc-lz-pedw-ppe-ukw-01"
|
||||
# CRMURL = "ppcrm2016.llcdt.gov.wales/PPPINSWales"
|
||||
# //New PreProd
|
||||
CLIENT_ID = ab6c4678-b31a-4eb3-b429-e039120e488a
|
||||
CLIENT_SECRET = VWY8Q~9EtRzGXpd8Xs~5OS1fej2IyVJ8JgTMncw3
|
||||
RELAY_ROOT = https://ar-ns-lz-pedw-ppe-uks-01.servicebus.windows.net/ar-hc-lz-pedw-ppe-uks-01/
|
||||
RELAYURI = "ar-ns-lz-pedw-ppe-uks-01.servicebus.windows.net"
|
||||
RELAYPATH = "ar-hc-lz-pedw-ppe-uks-01"
|
||||
CRMURL = "wg-pp-pedw.crm11.dynamics.com"
|
||||
CRMURL_VERSION = "v9.2"
|
||||
|
||||
|
||||
# //Prod Oauth WGO
|
||||
@@ -49,28 +51,27 @@ CRMURL = "tscrm2016.llcdt.gov.wales/UATPINS"
|
||||
# CRMURL = "crm2016.llc.gov.wales/PEDW"
|
||||
|
||||
# //New Prod
|
||||
CLIENT_ID = 3e4141a3-1fbd-454e-98f0-7f3a4f14a3cc
|
||||
CLIENT_SECRET = tFk8Q~E.R-HFjROTu1sRKqwb_ONzy05uPYoF6awR
|
||||
RELAY_ROOT = https://ar-ns-lz-pedw-prod-uks-01.servicebus.windows.net/ar-hc-lz-pedw-prod-uks-01/
|
||||
RELAYURI = "ar-ns-lz-pedw-prod-uks-01.servicebus.windows.net"
|
||||
RELAYPATH = "ar-hc-lz-pedw-prod-uks-01"
|
||||
# RELAY_ROOT = https://ar-ns-lz-pedw-ppe-ukw-01.servicebus.windows.net/ar-hc-lz-pedw-prod-ukw-01/
|
||||
# RELAYURI = "ar-ns-lz-pedw-prod-ukw-01.servicebus.windows.net"
|
||||
# RELAYPATH = "ar-hc-lz-pedw-prod-ukw-01"
|
||||
CRMURL = "crm2016.llcdt.gov.wales/PEDW"
|
||||
# CLIENT_ID = 3e4141a3-1fbd-454e-98f0-7f3a4f14a3cc
|
||||
# CLIENT_SECRET = ULC8Q~fZiXm0.teVLlZ_7LjxBOj2vIsWSApu2bAq
|
||||
# RELAY_ROOT = https://ar-ns-lz-pedw-prod-uks-01.servicebus.windows.net/ar-hc-lz-pedw-prod-uks-01/
|
||||
# RELAYURI = "ar-ns-lz-pedw-prod-uks-01.servicebus.windows.net"
|
||||
# RELAYPATH = "ar-hc-lz-pedw-prod-uks-01"
|
||||
# CRMURL = "crm2016.llc.gov.wales/PEDW"
|
||||
# CRMURL_VERSION = "v8.2"
|
||||
|
||||
|
||||
|
||||
//GOOGLE_TAG_MANAGER = GTM-T78CBC3
|
||||
GOOGLE_TAG_MANAGER = G-GTWW3JT03Z
|
||||
|
||||
SHOWLOGIN = true
|
||||
SHOWREPRESENTATIONS = true
|
||||
SHOWFILEUPLOAD = "false"
|
||||
SHOWMAPS = false
|
||||
SHOWMAPS = true
|
||||
API_ROOT = "http://localhost:3000"
|
||||
CY_API_ROOT = "http://cymru.local:3000"
|
||||
I18N_DOMAIN = "cymru.local"
|
||||
# DOCAPI_OFFLINE = "12:00:00,14:00:00"
|
||||
DOCAPI_OFFLINE = "02:00:00,04:00:00"
|
||||
# DOCAPI_OFFLINE = "07:00:00,16:00:00"
|
||||
DOCAPI_OFFLINE = "01:00:00,04:00:00"
|
||||
SHOWFILTERDOCS = true
|
||||
|
||||
|
||||
@@ -79,94 +80,95 @@ NEXTAUTH_URL = $API_ROOT
|
||||
NEXTAUTH_URL_INTERNAL = $API_ROOT
|
||||
NEXTAUTH_SECRET = SuperSecret
|
||||
|
||||
// CNR sql server
|
||||
DATABASE_URL = sqlserver://sql-srv-plt-pedw-cnr-uks-01.database.windows.net:1433;database=PEDW;user=PedwSqlAdmin;password=GhWKr62F5sQ69dZx;encrypt=true;trustServerCertificate=true;hostNameInCertificate=*.database.windows.net;loginTimeout=30;authentication=ActiveDirectoryPassword
|
||||
# CNR sql server
|
||||
# DATABASE_URL = sqlserver://sql-srv-plt-pedw-cnr-uks-01.database.windows.net:1433;database=PEDW;user=PedwSqlAdmin;password=GhWKr62F5sQ69dZx;encrypt=true;trustServerCertificate=true;hostNameInCertificate=*.database.windows.net;loginTimeout=30;authentication=ActiveDirectoryPassword
|
||||
|
||||
// dev test sql server
|
||||
# DATABASE_URL = sqlserver://pedw-dev-test-sql-svr.database.windows.net:1433;database=PEDWDev;user=RobBondSQL;password=GhWKr62F5sQ69dZx;encrypt=true;trustServerCertificate=true;hostNameInCertificate=*.database.windows.net;loginTimeout=30;authentication=ActiveDirectoryPassword
|
||||
// DATABASE_URL = sqlserver://sql-srv-plt-pedw-dev-uks-01.database.windows.net:1433;database=PEDW;user=PedwSqlAdmin;password=GhWKr62F5sQ69dZx;encrypt=true;trustServerCertificate=true;hostNameInCertificate=*.database.windows.net;loginTimeout=30;authentication=ActiveDirectoryPassword
|
||||
# dev test sql server
|
||||
DATABASE_URL = sqlserver://sql-srv-plt-pedw-dev-uks-01.database.windows.net:1433;database=PEDW;user=PedwSqlAdmin;password=GhWKr62F5sQ69dZx;encrypt=true;trustServerCertificate=true;hostNameInCertificate=*.database.windows.net;loginTimeout=30;authentication=ActiveDirectoryPassword
|
||||
|
||||
// test sql server
|
||||
# test sql server
|
||||
DATABASE_URL = sqlserver://sql-srv-plt-pedw-test-uks-01.database.windows.net:1433;database=PEDW;user=PedwSqlAdmin;password=GhWKr62F5sQ69dZx;encrypt=true;trustServerCertificate=true;hostNameInCertificate=*.database.windows.net;loginTimeout=30;authentication=ActiveDirectoryPassword
|
||||
|
||||
# Pre prod sql server
|
||||
DATABASE_URL = sqlserver://sql-srv-plt-pedw-ppe-uks-01.database.windows.net:1433;database=PEDW;user=PedwSqlAdmin;password=GhWKr62F5sQ69dZx;encrypt=true;trustservercertificate=true;hostnameincertificate=*.database.windows.net;logintimeout=30;authentication=SqlPassword
|
||||
|
||||
// Pre prod sql server
|
||||
# DATABASE_URL = sqlserver://sql-srv-plt-pedw-ppe-uks-01.database.windows.net:1433;database=PEDW;user=PedwSqlAdmin;password=GhWKr62F5sQ69dZx;encrypt=true;trustservercertificate=true;hostnameincertificate=*.database.windows.net;logintimeout=30;authentication=SqlPassword
|
||||
|
||||
// Prod sql server
|
||||
# Prod sql server
|
||||
# DATABASE_URL = sqlserver://pp-pedw-sql.database.windows.net:1433;database=PEDWPreProd;user=RobBondSQL;password=GhWKr62F5sQ69dZx;encrypt=true;trustServerCertificate=true;hostNameInCertificate=*.database.windows.net;loginTimeout=30;authentication=ActiveDirectoryPassword
|
||||
|
||||
// Prod sql server
|
||||
DATABASE_URL = sqlserver://sql-srv-plt-pedw-prod-uks-01.database.windows.net:1433;database=PEDW;user=PedwSqlAdmin;password=GhWKr62F5sQ69dZx;encrypt=true;trustServerCertificate=true;hostNameInCertificate=*.database.windows.net;loginTimeout=30;authentication=ActiveDirectoryPassword
|
||||
# Prod sql server
|
||||
# DATABASE_URL = sqlserver://sql-srv-plt-pedw-prod-uks-01.database.windows.net:1433;database=PEDW;user=PedwSqlAdmin;password=GhWKr62F5sQ69dZx;encrypt=true;trustServerCertificate=true;hostNameInCertificate=*.database.windows.net;loginTimeout=30;authentication=ActiveDirectoryPassword
|
||||
|
||||
|
||||
|
||||
|
||||
SECRET = SuperSecret
|
||||
|
||||
|
||||
|
||||
//Azure Storage Account
|
||||
# Azure Storage Account
|
||||
AZURE_CLIENT_ID = $CLIENT_ID
|
||||
AZURE_TENANT_ID = $TENANT
|
||||
AZURE_CLIENT_SECRET = $CLIENT_SECRET
|
||||
|
||||
// CNR key
|
||||
# CNR key
|
||||
AZURE_STORAGE_ACCOUNT_NAME = "sapltpedwcnruks"
|
||||
AZURE_STORAGE_ACCOUNT_KEY = hRffHq4IwctpaTKdS/U33Xq6nyTDF1t++WJgIwsw7gzstktZin/rRwbTIAL9KKqesVsK7EHrTTG6+ASt4+7skw==
|
||||
AZURE_PEDW_STORAGE_ENDPOINT = https://sapltpedwcnruks.blob.core.windows.net
|
||||
|
||||
// new dev key
|
||||
# new dev key
|
||||
AZURE_STORAGE_ACCOUNT_NAME = "sapltpedwdevuks"
|
||||
AZURE_STORAGE_ACCOUNT_KEY = MmrsrCjBfop9pI2oImsP/+lJUWU2DrXsAB8nq5bOVROTmPovSGxjCjKw9+TAFr00k8WDUK9r6mVx+AStcMLyAA==
|
||||
AZURE_PEDW_STORAGE_ENDPOINT = https://sapltpedwdevuks.blob.core.windows.net
|
||||
|
||||
// New test key
|
||||
# New test key
|
||||
AZURE_STORAGE_ACCOUNT_NAME = "sapltpedwtestuks"
|
||||
# AZURE_STORAGE_ACCOUNT_KEY = 5NdDO9GGlbTFLHFOXZRw8H2C0Ow5bFTvHwUHEbStyzg2mbd1uwHSeBSvM/dkN+HfdwrFzqAkwL5P+AStdO6cig==
|
||||
AZURE_STORAGE_ACCOUNT_KEY = bqJAz5pYQVGee8dnVhlsqW+xHwinNTjgY2AmojNyB+d4uAotMR20WcO4Op13yB+9dFaXAkkjtIA4+AStHT/IYg==
|
||||
AZURE_PEDW_STORAGE_ENDPOINT = https://sapltpedwtestuks.blob.core.windows.net
|
||||
|
||||
// New preprod key
|
||||
# AZURE_STORAGE_ACCOUNT_NAME = "sapltpedwppeuks"
|
||||
# AZURE_STORAGE_ACCOUNT_KEY = B4GRKr+cA9b9mNM/GHFivzhzflJIZltG8bMmooXlYvGYySPAspTTHistAT30sHipnR+hh6dqUc9q+ASttAjPRQ==
|
||||
# AZURE_PEDW_STORAGE_ENDPOINT = https://sapltpedwppeuks.blob.core.windows.net
|
||||
# New preprod key
|
||||
AZURE_STORAGE_ACCOUNT_NAME = "sapltpedwppeuks"
|
||||
AZURE_STORAGE_ACCOUNT_KEY = B4GRKr+cA9b9mNM/GHFivzhzflJIZltG8bMmooXlYvGYySPAspTTHistAT30sHipnR+hh6dqUc9q+ASttAjPRQ==
|
||||
AZURE_PEDW_STORAGE_ENDPOINT = https://sapltpedwppeuks.blob.core.windows.net
|
||||
|
||||
|
||||
// PROD key
|
||||
# PROD key
|
||||
# AZURE_STORAGE_ACCOUNT_NAME = "pedwprod"
|
||||
# AZURE_STORAGE_ACCOUNT_KEY = koZ46STRqapSa2Dod8MLL6aju1eYLhhyJ6DXpCLMTnFLJvbDT6CHUv/jwr5U/Ta8a60MWzwToHQy+AStADO7sg==
|
||||
# AZURE_PEDW_STORAGE_ENDPOINT = https://pedwprod.blob.core.windows.net
|
||||
|
||||
# // New PROD key
|
||||
AZURE_STORAGE_ACCOUNT_NAME = "sapltpedwproduks"
|
||||
AZURE_STORAGE_ACCOUNT_KEY = OfV9MFqXcLLPam9GhEdMWadIOwIzhc5hd5TUqzIuQoswFdtV4ybaemjatSv+Kht0Ny1qQKjLplwY+AStUTZJrg==
|
||||
AZURE_PEDW_STORAGE_ENDPOINT = https://sapltpedwproduks.blob.core.windows.net
|
||||
# New PROD key
|
||||
# AZURE_STORAGE_ACCOUNT_NAME = "sapltpedwproduks"
|
||||
# AZURE_STORAGE_ACCOUNT_KEY = OfV9MFqXcLLPam9GhEdMWadIOwIzhc5hd5TUqzIuQoswFdtV4ybaemjatSv+Kht0Ny1qQKjLplwY+AStUTZJrg==
|
||||
# AZURE_PEDW_STORAGE_ENDPOINT = https://sapltpedwproduks.blob.core.windows.net
|
||||
|
||||
|
||||
AZURE_PEDW_CONTAINER = "pedwapplications"
|
||||
AZURE_PEDW_QUEUE_ENDPOINT = https://$AZURE_STORAGE_ACCOUNT_NAME.queue.core.windows.net
|
||||
|
||||
//gov.notify
|
||||
//NOTIFY_API_KEY = pedwnextauthkey-90f93710-9dae-423e-aea1-11eccd0dc132-0c9469d9-d671-444d-9e9d-3e5a62001043
|
||||
NOTIFY_API_KEY = pedwnextauthlivekey-90f93710-9dae-423e-aea1-11eccd0dc132-5c0ed187-754a-4b04-8c99-978e5710c2c1
|
||||
# gov.notify
|
||||
# NOTIFY_API_KEY = pedwnextauthkey-90f93710-9dae-423e-aea1-11eccd0dc132-0c9469d9-d671-444d-9e9d-3e5a62001043
|
||||
# NOTIFY_API_KEY = pedwnextauthlivekey-90f93710-9dae-423e-aea1-11eccd0dc132-5c0ed187-754a-4b04-8c99-978e5710c2c1
|
||||
NOTIFY_API_KEY = pedwnextauthlive01key-90f93710-9dae-423e-aea1-11eccd0dc132-72bfb1e1-c0b7-47cb-9887-3d47a4b11ad4
|
||||
|
||||
SHOW_DEBUG = true
|
||||
|
||||
|
||||
// DEV Connection string
|
||||
//NEXT_PUBLIC_APP_INSIGHT = InstrumentationKey=4b7568b3-70bd-4591-9dc2-267c0a6501d1;IngestionEndpoint=https://ukwest-0.in.applicationinsights.azure.com/;LiveEndpoint=https://ukwest.livediagnostics.monitor.azure.com/;ApplicationId=447d38b5-5d40-4238-8fb3-0ef4741b3db1
|
||||
|
||||
# DEV Connection string
|
||||
NEXT_PUBLIC_APP_INSIGHT = InstrumentationKey=4b7568b3-70bd-4591-9dc2-267c0a6501d1;IngestionEndpoint=https://ukwest-0.in.applicationinsights.azure.com/;LiveEndpoint=https://ukwest.livediagnostics.monitor.azure.com/;ApplicationId=447d38b5-5d40-4238-8fb3-0ef4741b3db1
|
||||
|
||||
APPLICATIONINSIGHTS_CONNECTIONSTRING = InstrumentationKey=7a06e24a-793c-47bc-8987-ce80f180e035;IngestionEndpoint=https://uksouth-1.in.applicationinsights.azure.com/;LiveEndpoint=https://uksouth.livediagnostics.monitor.azure.com/;ApplicationId=9906b6d0-b791-4add-8d53-c827a534e1d4
|
||||
|
||||
# Test Connection string
|
||||
NEXT_PUBLIC_APP_INSIGHT = InstrumentationKey=cc60e8e7-5b30-4c2b-a176-8b96b21b12df;IngestionEndpoint=https://ukwest-0.in.applicationinsights.azure.com/;LiveEndpoint=https://ukwest.livediagnostics.monitor.azure.com/;ApplicationId=2a4094be-6fd1-46ab-a67d-5f241692b129
|
||||
|
||||
// Test Connection string
|
||||
//NEXT_PUBLIC_APP_INSIGHT = InstrumentationKey=cc60e8e7-5b30-4c2b-a176-8b96b21b12df;IngestionEndpoint=https://ukwest-0.in.applicationinsights.azure.com/;LiveEndpoint=https://ukwest.livediagnostics.monitor.azure.com/;ApplicationId=2a4094be-6fd1-46ab-a67d-5f241692b129
|
||||
# Preprod Connection string
|
||||
# NEXT_PUBLIC_APP_INSIGHT = InstrumentationKey=7370f0f9-834d-4c7a-b3c4-9951fcad5ad2;IngestionEndpoint=https://ukwest-0.in.applicationinsights.azure.com/;LiveEndpoint=https://ukwest.livediagnostics.monitor.azure.com/;ApplicationId=04362cb7-6dfc-469e-8274-12243e8be851
|
||||
|
||||
// Preprod Connection string
|
||||
//NEXT_PUBLIC_APP_INSIGHT = InstrumentationKey=7370f0f9-834d-4c7a-b3c4-9951fcad5ad2;IngestionEndpoint=https://ukwest-0.in.applicationinsights.azure.com/;LiveEndpoint=https://ukwest.livediagnostics.monitor.azure.com/;ApplicationId=04362cb7-6dfc-469e-8274-12243e8be851
|
||||
# NEXT_PUBLIC_APP_INSIGHT = InstrumentationKey=a41b91bf-f7dc-4f44-bb66-a67df4eee435;IngestionEndpoint=https://uksouth-1.in.applicationinsights.azure.com/;LiveEndpoint=https://uksouth.livediagnostics.monitor.azure.com/;ApplicationId=473d0632-16f1-4065-8984-d6bac62402c0
|
||||
|
||||
NEXT_PUBLIC_APP_INSIGHT = InstrumentationKey=a41b91bf-f7dc-4f44-bb66-a67df4eee435;IngestionEndpoint=https://uksouth-1.in.applicationinsights.azure.com/;LiveEndpoint=https://uksouth.livediagnostics.monitor.azure.com/;ApplicationId=473d0632-16f1-4065-8984-d6bac62402c0
|
||||
|
||||
// Prod Connection string
|
||||
//NEXT_PUBLIC_APP_INSIGHT = InstrumentationKey=61f358c2-8075-4164-b897-17bc6dd31fee;IngestionEndpoint=https://ukwest-0.in.applicationinsights.azure.com/;LiveEndpoint=https://ukwest.livediagnostics.monitor.azure.com/;ApplicationId=0c297349-396b-4dc6-8b56-85f5c680adc6
|
||||
# Prod Connection string
|
||||
# NEXT_PUBLIC_APP_INSIGHT = InstrumentationKey=61f358c2-8075-4164-b897-17bc6dd31fee;IngestionEndpoint=https://ukwest-0.in.applicationinsights.azure.com/;LiveEndpoint=https://ukwest.livediagnostics.monitor.azure.com/;ApplicationId=0c297349-396b-4dc6-8b56-85f5c680adc6
|
||||
|
||||
|
||||
HIDEERRORLOGS = false
|
||||
@@ -174,3 +176,8 @@ HIDEERRORLOGS = false
|
||||
SHOWSIPS = true
|
||||
|
||||
ALLOWED_IPS=::1,203.0.113.42,198.51.100.17
|
||||
UPLOAD_BATCH_COUNT = 5
|
||||
|
||||
NRWDOMAIN = rdbmedia.co.uk
|
||||
|
||||
MAP_TARGET = pedw-dev
|
||||
@@ -48,3 +48,11 @@ gitclean.sh
|
||||
pages/admin/logcheck.js
|
||||
pages/admin/logchecker.js
|
||||
pages/baracuda.html
|
||||
pages/holding-min.html
|
||||
pages/holding.html
|
||||
|
||||
# Cline / AI-assistant governance artifacts (keep local-only)
|
||||
|
||||
ai-prompts/
|
||||
|
||||
pages/baracuda.min.html
|
||||
|
||||
+2
-1
@@ -1,5 +1,6 @@
|
||||
{
|
||||
"tabWidth": 4,
|
||||
"useTabs": false,
|
||||
"quoteProps":"preserve"
|
||||
"quoteProps": "preserve",
|
||||
"trailingComma": "none"
|
||||
}
|
||||
Vendored
+1
-1
@@ -11,7 +11,7 @@
|
||||
"command": "npm run dev"
|
||||
},
|
||||
{"name": "Launch Chrome against localhost",
|
||||
"type": "pwa-chrome",
|
||||
"type": "chrome",
|
||||
"request": "launch",
|
||||
"url": "http://localhost:3000",
|
||||
"webRoot": "${workspaceFolder}"
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
# AI Context — PEDW FrontEnd
|
||||
|
||||
## Overview
|
||||
|
||||
PEDW FrontEnd is a Next.js 14 (Pages Router) bilingual (EN/CY) public-service portal for planning case search, case detail/document viewing, and authenticated portal workflows (appeals, representations, watchlists, dashboard views).
|
||||
|
||||
## Architecture
|
||||
|
||||
- Monorepo-style Next.js app with UI routes in `pages/` and API handlers in `pages/api/**`.
|
||||
- Redux (`next-redux-wrapper` + `redux-persist`) for shared client/server state.
|
||||
- `next-auth` for auth/session with Prisma adapter.
|
||||
- Integration-heavy BFF pattern: API routes proxy to relay/CRM and storage/notify services.
|
||||
|
||||
## Key components
|
||||
|
||||
- `components/breadcrumbs.js`: central breadcrumb/back-link behavior.
|
||||
- `components/case/summary.js`: case-detail tabs, representation eligibility logic, watch/email actions.
|
||||
- `actions/index.js`: shared API utilities, token/header/hash helpers, many side-effect wrappers.
|
||||
- `pages/api/endpoint/**`: relay-backed business-data APIs.
|
||||
- `pages/api/file/**`: blob/document/PDF/upload endpoints.
|
||||
|
||||
## Data model boundaries
|
||||
|
||||
- Prisma (`prisma/schema.prisma`) stores auth/session entities only (`User`, `Account`, `Session`, `VerificationToken`) on SQL Server.
|
||||
- Business/case data is external (Dynamics/relay path), not persisted as Prisma domain models here.
|
||||
|
||||
## API/integration patterns
|
||||
|
||||
- Many endpoint handlers compute HMAC hash query params (`hash`) for relay-bound requests.
|
||||
- Token acquisition + OData headers are reused across proxy handlers.
|
||||
- File endpoints often validate request hash for sensitive blob actions.
|
||||
- GOV.UK Notify used for email, including language-specific template selection in some flows.
|
||||
|
||||
## Infrastructure/tooling
|
||||
|
||||
- Scripts: `npm run dev`, `npm run build`, `npm start`, `npm run lint`.
|
||||
- CI/CD artifacts present: `azure-pipelines.yml`, `Jenkinsfile`, `Dockerfile` (active production source-of-truth not explicit in repo).
|
||||
- Security controls: `middleware.js` CSP/runtime headers + `next.config.js` security headers.
|
||||
|
||||
## Development constraints
|
||||
|
||||
- Preserve auth/session behavior in `pages/api/auth/[...nextauth].js`.
|
||||
- Do not weaken CSP/security headers in `middleware.js` or `next.config.js`.
|
||||
- Keep EN/CY parity across routes and locale resources (`i18n.js`, `locales/**`, rewrites).
|
||||
- Treat relay hash behavior as security-sensitive; keep path/hash compatibility stable.
|
||||
- Avoid logging secrets/personal data in auth/email/file/account flows.
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
# Use official Node.js 20 LTS image
|
||||
FROM node:20-alpine
|
||||
|
||||
# Set working directory
|
||||
WORKDIR /app
|
||||
|
||||
# Install dependencies first (better caching)
|
||||
COPY package*.json ./
|
||||
RUN npm ci --production
|
||||
|
||||
# Copy source files (including .next build output if pre-built)
|
||||
COPY . .
|
||||
|
||||
# If you want to build inside container, uncomment:
|
||||
# RUN npm run build
|
||||
|
||||
# Use non-root user (optional, but recommended)
|
||||
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
|
||||
USER appuser
|
||||
|
||||
# Expose port your app listens on
|
||||
EXPOSE 3000
|
||||
|
||||
# Start your Next.js app (adjust if using custom server)
|
||||
CMD ["npm", "start"]
|
||||
@@ -0,0 +1,85 @@
|
||||
# PEDW FrontEnd Guardrails
|
||||
|
||||
## Purpose
|
||||
|
||||
This document is a fast pre-flight checklist to reduce regressions in high-risk areas. Use it before coding, before opening a PR, and before merge.
|
||||
|
||||
## Non-Negotiable Guardrails
|
||||
|
||||
1. **Auth/session integrity**
|
||||
- Do not bypass `next-auth` flow in `pages/api/auth/[...nextauth].js`.
|
||||
- Preserve secure redirect behavior and cookie/session settings.
|
||||
2. **Security headers and CSP**
|
||||
- Do not weaken `middleware.js` CSP/header behavior or `next.config.js` security headers without explicit rationale.
|
||||
3. **Data model safety**
|
||||
- Treat `prisma/schema.prisma` as source-of-truth for auth/account persistence.
|
||||
4. **Bilingual parity (EN/CY)**
|
||||
- Any user-facing route/content change must validate both locales.
|
||||
- Keep `i18n.js`, `locales/`, and `next.config.js` rewrites aligned.
|
||||
5. **Public-service reliability**
|
||||
- Avoid breaking core flows: search, case, account, myportal, admin.
|
||||
|
||||
## Sensitive Flow Protection
|
||||
|
||||
Apply extra checks for:
|
||||
|
||||
- `pages/api/auth/**`
|
||||
- `pages/api/file/**`
|
||||
- `pages/api/email/**`
|
||||
- `pages/api/endpoint/*_api.js` handling account/user data
|
||||
|
||||
## Relay Hash Integrity Rules (CRM-bound APIs)
|
||||
|
||||
Apply when changing relay-bound portal endpoints and helpers (notably `pages/api/endpoint/**` and `actions/index.js`):
|
||||
|
||||
1. Keep relay endpoint configuration sourced from `API_ROOT`.
|
||||
2. Preserve path-hash generation behavior:
|
||||
- hash input must be request path/query (excluding domain),
|
||||
- appended hash parameter must remain compatible with relay expectations.
|
||||
3. Do not change hash algorithm/key usage contract without coordinated relay change.
|
||||
4. Treat hash validation failures as security-relevant negative paths; verify graceful rejection handling.
|
||||
5. Never log hash key material or sensitive request payloads.
|
||||
|
||||
Required for sensitive changes:
|
||||
|
||||
- Negative-path validation (unauthorized, invalid input, malformed payload).
|
||||
- Safe logging (no secrets/tokens/personal data in cleartext).
|
||||
- Explicit rollback steps.
|
||||
|
||||
## Relay Policy Change Guardrail (timeouts/retries/logging)
|
||||
|
||||
When changing shared relay forwarding policy (for example in `pages/api/middleware/relayForwarding.js`), treat this as an operationally sensitive change even if endpoint contracts are unchanged.
|
||||
|
||||
Minimum required before merge:
|
||||
|
||||
1. Complete the relay governance gate in `context/runbook.md` (Relay Hardening Rollout Playbook).
|
||||
2. Attach non-prod smoke evidence for:
|
||||
- deterministic non-retry classes (`400`, `401`, `403`, `404`)
|
||||
- transient retry classes (`429`, `503`, timeout/network-transient)
|
||||
3. Confirm structured redacted logging and duplicate-log suppression behavior.
|
||||
4. Provide fast mitigation + rollback path (`RELAY_RETRY_MAX=0` and commit-revert path).
|
||||
|
||||
## Pre-PR Quick Checklist
|
||||
|
||||
- [ ] Ran `npm run lint` (or documented why unavailable)
|
||||
- [ ] Verified changed routes/APIs manually
|
||||
- [ ] Verified EN + CY behavior for impacted user-facing flow
|
||||
- [ ] Performed accessibility smoke checks (keyboard, focus, labels, headings)
|
||||
- [ ] Added risk notes (auth/data/i18n/a11y)
|
||||
- [ ] Updated `memory-bank/change-log.md` for non-trivial changes
|
||||
|
||||
## If Assumptions Are Unclear
|
||||
|
||||
1. Record assumptions in PR notes.
|
||||
2. Add unresolved items to `memory-bank/open-questions.md`.
|
||||
3. Choose the safer behavior and clearly mark as temporary.
|
||||
|
||||
## Related Docs
|
||||
|
||||
- `.clinerules`
|
||||
- `CONTRIBUTING_AI.md`
|
||||
- `context/implementation-governance.md`
|
||||
- `context/maintainability-adoption-programme.md`
|
||||
- `context/runbook.md`
|
||||
- `context/integration-map.md`
|
||||
- `memory-bank/README.md`
|
||||
Vendored
+50
@@ -0,0 +1,50 @@
|
||||
pipeline {
|
||||
agent {
|
||||
docker {
|
||||
image 'node:20' // ✅ Node.js 20 with npm included
|
||||
}
|
||||
}
|
||||
|
||||
environment {
|
||||
IMAGE = "pedw-app"
|
||||
}
|
||||
|
||||
stages {
|
||||
stage('Install & Build') {
|
||||
steps {
|
||||
sh 'npm ci'
|
||||
sh 'npm run build'
|
||||
}
|
||||
}
|
||||
|
||||
stage('Build Docker Image') {
|
||||
steps {
|
||||
sh "docker build -t $REGISTRY/$IMAGE:latest ."
|
||||
}
|
||||
}
|
||||
|
||||
stage('Push Docker Image') {
|
||||
steps {
|
||||
withCredentials([usernamePassword(credentialsId: 'dockerhub-credentials', usernameVariable: 'DOCKER_USER', passwordVariable: 'DOCKER_PASS')]) {
|
||||
sh "echo $DOCKER_PASS | docker login -u $DOCKER_USER --password-stdin"
|
||||
sh "docker push $REGISTRY/$IMAGE:latest"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
stage('Deploy to Plesk') {
|
||||
steps {
|
||||
sshagent(['plesk-ssh-key']) {
|
||||
sh """
|
||||
ssh root@your-plesk-domain.com '
|
||||
docker pull $REGISTRY/$IMAGE:latest &&
|
||||
docker stop nextjs-app || true &&
|
||||
docker rm nextjs-app || true &&
|
||||
docker run -d --restart=always --name nextjs-app -p 3000:3000 $REGISTRY/$IMAGE:latest
|
||||
'
|
||||
"""
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+284
-249
@@ -1,7 +1,7 @@
|
||||
import { DefaultAzureCredential } from "@azure/identity";
|
||||
import _ from "lodash";
|
||||
import { hashAPIPath, consoleLogger } from ".";
|
||||
import { getDocumentTypeFromFilename } from "../components/utils";
|
||||
import { getDocumentTypeFromFilename, hasOwn } from "../components/utils";
|
||||
|
||||
const {
|
||||
ContainerClient,
|
||||
@@ -11,7 +11,7 @@ const {
|
||||
ContainerSASPermissions,
|
||||
generateBlobSASQueryParameters,
|
||||
|
||||
SASProtocol,
|
||||
SASProtocol
|
||||
} = require("@azure/storage-blob");
|
||||
const {
|
||||
QueueServiceClient,
|
||||
@@ -23,7 +23,7 @@ const {
|
||||
generateAccountSASQueryParameters,
|
||||
generateQueueSASQueryParameters,
|
||||
StorageSharedKeyCredential,
|
||||
QueueClient,
|
||||
QueueClient
|
||||
} = require("@azure/storage-queue");
|
||||
const STORAGE_PATH = process.env.AZURE_PEDW_STORAGE_ENDPOINT;
|
||||
const STORAGE_CONTAINER = process.env.AZURE_PEDW_CONTAINER;
|
||||
@@ -31,6 +31,88 @@ const QUEUE_PATH = process.env.AZURE_PEDW_QUEUE_ENDPOINT;
|
||||
|
||||
const accountName = process.env.AZURE_STORAGE_ACCOUNT_NAME;
|
||||
|
||||
const buildDownloadBlobQueryPath = ({
|
||||
containerName,
|
||||
casefolderID,
|
||||
blobname,
|
||||
encodeCasefolderID = true,
|
||||
encodeBlobname = true
|
||||
}) => {
|
||||
const casefolderPart = encodeCasefolderID
|
||||
? encodeURIComponent(casefolderID)
|
||||
: casefolderID;
|
||||
const blobPart = encodeBlobname ? encodeURIComponent(blobname) : blobname;
|
||||
|
||||
return (
|
||||
"/api/file/downloadblob?container=" +
|
||||
containerName +
|
||||
"&casefolderID=" +
|
||||
casefolderPart +
|
||||
"&blobname=" +
|
||||
blobPart
|
||||
);
|
||||
};
|
||||
|
||||
const buildDeleteBlobQueryPath = ({
|
||||
containerName,
|
||||
casefolderID,
|
||||
blobname,
|
||||
encodeCasefolderID = true,
|
||||
encodeBlobname = true
|
||||
}) => {
|
||||
const casefolderPart = encodeCasefolderID
|
||||
? encodeURIComponent(casefolderID)
|
||||
: casefolderID;
|
||||
const blobPart = encodeBlobname ? encodeURIComponent(blobname) : blobname;
|
||||
|
||||
return (
|
||||
"/api/file/deleteblob?container=" +
|
||||
containerName +
|
||||
"&casefolderID=" +
|
||||
casefolderPart +
|
||||
"&blobname=" +
|
||||
blobPart
|
||||
);
|
||||
};
|
||||
|
||||
const buildGetBlobListQueryPath = ({ containerName, casefolderID }) => {
|
||||
return (
|
||||
"/api/file/getbloblist?container=" +
|
||||
containerName +
|
||||
"&casefolderID=" +
|
||||
casefolderID
|
||||
);
|
||||
};
|
||||
|
||||
const buildCaseObjectPath = (casefolderID) => {
|
||||
return casefolderID + "/" + casefolderID + "_case.json";
|
||||
};
|
||||
|
||||
const buildHashMetadataPaths = ({ containerName, casefolderID, blobname }) => {
|
||||
return {
|
||||
"hashedfilepath": hashAPIPath(
|
||||
buildDownloadBlobQueryPath({
|
||||
containerName,
|
||||
casefolderID,
|
||||
blobname
|
||||
})
|
||||
),
|
||||
"hasheddeletepath": hashAPIPath(
|
||||
buildDeleteBlobQueryPath({
|
||||
containerName,
|
||||
casefolderID,
|
||||
blobname
|
||||
})
|
||||
),
|
||||
"hashgetblobs": hashAPIPath(
|
||||
buildGetBlobListQueryPath({
|
||||
containerName,
|
||||
casefolderID
|
||||
})
|
||||
)
|
||||
};
|
||||
};
|
||||
|
||||
export const createContainerSas = async (containerName) => {
|
||||
// Get environment variables
|
||||
|
||||
@@ -67,7 +149,7 @@ export const createContainerSas = async (containerName) => {
|
||||
permissions: ContainerSASPermissions.parse(containerPermissions),
|
||||
protocol: SASProtocol.HttpsAndHttp,
|
||||
startsOn: TEN_MINUTES_BEFORE_NOW,
|
||||
expiresOn: TEN_MINUTES_AFTER_NOW,
|
||||
expiresOn: TEN_MINUTES_AFTER_NOW
|
||||
};
|
||||
|
||||
// console.log(
|
||||
@@ -126,7 +208,7 @@ export const createBlobSas = async (containerName, blobName) => {
|
||||
permissions: BlobSASPermissions.parse(blobPermissionsForAnonymousUser),
|
||||
protocol: SASProtocol.HttpsAndHttp,
|
||||
startsOn: TEN_MINUTES_BEFORE_NOW,
|
||||
expiresOn: TEN_MINUTES_AFTER_NOW,
|
||||
expiresOn: TEN_MINUTES_AFTER_NOW
|
||||
};
|
||||
|
||||
const sasToken = generateBlobSASQueryParameters(
|
||||
@@ -187,61 +269,38 @@ export const getBlobs = async (containerName, casefolderID) => {
|
||||
|
||||
const blobObj = [];
|
||||
for await (const blob of containerClient.listBlobsFlat({
|
||||
prefix: casefolderID + "/files/",
|
||||
prefix: casefolderID + "/files/"
|
||||
})) {
|
||||
let blobDocumentType = blob.name
|
||||
.split("/")[2]
|
||||
.slice(0, blob.name.split("/")[2].indexOf("_"));
|
||||
const blobPathParts = blob.name.split("/");
|
||||
const fileName = blobPathParts[2];
|
||||
const contentLength = blob.properties.contentLength;
|
||||
|
||||
blobObj.push({
|
||||
"name": blob.name.split("/")[2],
|
||||
"name": fileName,
|
||||
"path": blob.name,
|
||||
"documentType": getDocumentTypeFromFilename(
|
||||
blob.name.split("/")[2]
|
||||
),
|
||||
"documentType": getDocumentTypeFromFilename(fileName),
|
||||
"versionId": blob.versionId,
|
||||
"caseObj": casefolderID + "/" + casefolderID + "_case.json",
|
||||
"caseObj": buildCaseObjectPath(casefolderID),
|
||||
"isCurrentVersion": blob.isCurrentVersion,
|
||||
"contentLength": blob.properties.contentLength,
|
||||
"size": blob.properties.contentLength,
|
||||
"contentLength": contentLength,
|
||||
"size": contentLength,
|
||||
"contentType": blob.contentType,
|
||||
"lastModified": blob.properties.lastModified,
|
||||
"filepath":
|
||||
"/api/file/downloadblob?container=" +
|
||||
containerName +
|
||||
"&casefolderID=" +
|
||||
encodeURIComponent(casefolderID) +
|
||||
"&blobname=" +
|
||||
encodeURIComponent(blob.name),
|
||||
"hashedfilepath": hashAPIPath(
|
||||
"/api/file/downloadblob?container=" +
|
||||
containerName +
|
||||
"&casefolderID=" +
|
||||
encodeURIComponent(casefolderID) +
|
||||
"&blobname=" +
|
||||
encodeURIComponent(blob.name.split("/")[2])
|
||||
),
|
||||
"deletepath":
|
||||
"/api/file/deleteblob?container=" +
|
||||
containerName +
|
||||
"&casefolderID=" +
|
||||
encodeURIComponent(casefolderID) +
|
||||
"&blobname=" +
|
||||
encodeURIComponent(blob.name.split("/")[2]),
|
||||
"hasheddeletepath": hashAPIPath(
|
||||
"/api/file/deleteblob?container=" +
|
||||
containerName +
|
||||
"&casefolderID=" +
|
||||
encodeURIComponent(casefolderID) +
|
||||
"&blobname=" +
|
||||
encodeURIComponent(blob.name.split("/")[2])
|
||||
),
|
||||
"hashgetblobs": hashAPIPath(
|
||||
"/api/file/getbloblist?container=" +
|
||||
containerName +
|
||||
"&casefolderID=" +
|
||||
casefolderID
|
||||
),
|
||||
"filepath": buildDownloadBlobQueryPath({
|
||||
containerName,
|
||||
casefolderID,
|
||||
blobname: blob.name
|
||||
}),
|
||||
...buildHashMetadataPaths({
|
||||
containerName,
|
||||
casefolderID,
|
||||
blobname: fileName
|
||||
}),
|
||||
"deletepath": buildDeleteBlobQueryPath({
|
||||
containerName,
|
||||
casefolderID,
|
||||
blobname: fileName
|
||||
})
|
||||
});
|
||||
}
|
||||
//console.log("blobObj:", blobObj);
|
||||
@@ -257,7 +316,7 @@ export const createBlob = async (formContent, containerName, caseref) => {
|
||||
formContent = JSON.parse(formContent);
|
||||
let caseID = "";
|
||||
|
||||
caseID = _.has(formContent, "pinswg_name")
|
||||
caseID = hasOwn(formContent, "pinswg_name")
|
||||
? formContent.pinswg_name
|
||||
: caseref;
|
||||
|
||||
@@ -277,7 +336,7 @@ export const createBlob = async (formContent, containerName, caseref) => {
|
||||
const tags = {
|
||||
containerid: containerName,
|
||||
caseID: caseID,
|
||||
blobType: "Appeal",
|
||||
blobType: "Appeal"
|
||||
};
|
||||
|
||||
//console.log("the tags:", tags);
|
||||
@@ -309,8 +368,8 @@ export const createRepBlob = async (formContent, containerName, caseref) => {
|
||||
|
||||
const tags = {
|
||||
containerid: containerName,
|
||||
caseID: formContent.ticketnumber,
|
||||
blobType: "Representation",
|
||||
caseID: formContent.ticketnumber || formContent.caseRef,
|
||||
blobType: "Representation"
|
||||
};
|
||||
|
||||
//console.log("the tags:", tags);
|
||||
@@ -356,12 +415,14 @@ export const createAppealPDFBlob = async (
|
||||
const uploadOptions = {
|
||||
blockSize: 4 * 1024 * 1024, // 4 MiB max block size
|
||||
concurrency: 2, // maximum number of parallel transfer workers
|
||||
maxSingleShotSize: 8 * 1024 * 1024, // 8 MiB initial transfer size
|
||||
maxSingleShotSize: 8 * 1024 * 1024 // 8 MiB initial transfer size
|
||||
};
|
||||
console.log("blobName:", blobName);
|
||||
const blockBlobClient = containerClient.getBlockBlobClient(blobName);
|
||||
|
||||
const uploadBlobResponse = await blockBlobClient.uploadStream(content);
|
||||
const uploadBlobResponse = Buffer.isBuffer(content)
|
||||
? await blockBlobClient.uploadData(content)
|
||||
: await blockBlobClient.uploadStream(content);
|
||||
|
||||
console.log(uploadBlobResponse);
|
||||
let whichLocation = "846040000"; // Default value
|
||||
@@ -371,7 +432,7 @@ export const createAppealPDFBlob = async (
|
||||
caseID: caseID,
|
||||
blobType: "Appeal PDF",
|
||||
ishareLocation: whichLocation,
|
||||
documentLocationId: whichLocation,
|
||||
documentLocationId: whichLocation
|
||||
};
|
||||
|
||||
//console.log("the tags:", tags);
|
||||
@@ -405,33 +466,36 @@ export const createRepPDFBlob = async (
|
||||
const uploadOptions = {
|
||||
blockSize: 4 * 1024 * 1024, // 4 MiB max block size
|
||||
concurrency: 2, // maximum number of parallel transfer workers
|
||||
maxSingleShotSize: 8 * 1024 * 1024, // 8 MiB initial transfer size
|
||||
maxSingleShotSize: 8 * 1024 * 1024 // 8 MiB initial transfer size
|
||||
};
|
||||
|
||||
console.log("blobName:", blobName);
|
||||
const blockBlobClient = containerClient.getBlockBlobClient(blobName);
|
||||
|
||||
const uploadBlobResponse = await blockBlobClient.uploadStream(content);
|
||||
const uploadBlobResponse = Buffer.isBuffer(content)
|
||||
? await blockBlobClient.uploadData(content)
|
||||
: await blockBlobClient.uploadStream(content);
|
||||
|
||||
let whichLocation =
|
||||
repName.indexOf("_IP_") > 0
|
||||
? "846040005"
|
||||
: repName.indexOf("_Statement_") > 0
|
||||
? "846040002"
|
||||
: repName.indexOf("_Questionnaire_") > 0
|
||||
? "846040001"
|
||||
: repName.indexOf("_Comments") > 0
|
||||
? "846040003"
|
||||
: repName.indexOf("_Impact") > 0
|
||||
? "846040001"
|
||||
: "846040002";
|
||||
const locationMap = [
|
||||
{ key: "_IP_-_Comments_", value: "846040038" }, // most specific first
|
||||
{ key: "_IP_", value: "846040005" },
|
||||
{ key: "_Statement_", value: "846040002" },
|
||||
{ key: "_Questionnaire_", value: "846040001" },
|
||||
{ key: "_Comments", value: "846040003" },
|
||||
{ key: "_Impact", value: "846040029" },
|
||||
{ key: "_Consultation_Response_", value: "846040036" }
|
||||
];
|
||||
|
||||
const whichLocation =
|
||||
locationMap.find((item) => repName.includes(item.key))?.value ||
|
||||
"846040002";
|
||||
|
||||
const tags = {
|
||||
containerid: containerName,
|
||||
caseID: caseID,
|
||||
blobType: "Representation PDF",
|
||||
ishareLocation: whichLocation,
|
||||
documentLocationId: whichLocation,
|
||||
documentLocationId: whichLocation
|
||||
};
|
||||
|
||||
//console.log("the tags:", tags);
|
||||
@@ -445,7 +509,7 @@ export const deleteBlob = async (containerName, blobName) => {
|
||||
const creds = new DefaultAzureCredential();
|
||||
|
||||
const options = {
|
||||
deleteSnapshots: "include", // or 'only'
|
||||
deleteSnapshots: "include" // or 'only'
|
||||
};
|
||||
|
||||
const containerToken = await createContainerSas(containerName);
|
||||
@@ -465,7 +529,7 @@ export const deleteBlobCase = async (containerName, blobName) => {
|
||||
const creds = new DefaultAzureCredential();
|
||||
|
||||
const options = {
|
||||
deleteSnapshots: "include", // or 'only'
|
||||
deleteSnapshots: "include" // or 'only'
|
||||
};
|
||||
|
||||
const containerToken = await createContainerSas(containerName);
|
||||
@@ -477,7 +541,7 @@ export const deleteBlobCase = async (containerName, blobName) => {
|
||||
console.log("blob to delete:", blobName);
|
||||
|
||||
for await (const blob of containerClient.listBlobsFlat({
|
||||
prefix: blobName,
|
||||
prefix: blobName
|
||||
})) {
|
||||
console.log(" ------ :", blob.name);
|
||||
containerClient.deleteBlob(blob.name);
|
||||
@@ -495,7 +559,7 @@ export const deleteBlobRep = async (containerName, blobName) => {
|
||||
const creds = new DefaultAzureCredential();
|
||||
|
||||
const options = {
|
||||
deleteSnapshots: "include", // or 'only'
|
||||
deleteSnapshots: "include" // or 'only'
|
||||
};
|
||||
|
||||
const containerToken = await createContainerSas(containerName);
|
||||
@@ -505,7 +569,7 @@ export const deleteBlobRep = async (containerName, blobName) => {
|
||||
console.log("blob to delete:", blobName);
|
||||
|
||||
for await (const blob of containerClient.listBlobsFlat({
|
||||
prefix: blobName,
|
||||
prefix: blobName
|
||||
})) {
|
||||
console.log("------ :", blob.name);
|
||||
const blockBlobClient = containerClient.getBlockBlobClient(blob.name);
|
||||
@@ -553,64 +617,46 @@ export const uploadFile = async (formContent, containerName, foldername) => {
|
||||
);
|
||||
console.log(data);
|
||||
|
||||
let whichLocation =
|
||||
files[prop][0].fieldName.indexOf("_Statement_of_Case") >
|
||||
0 ||
|
||||
files[prop][0].fieldName.indexOf("_-_Statement_of_Case") >
|
||||
0 ||
|
||||
files[prop][0].fieldName.indexOf("_-_Application_Form") >
|
||||
0 ||
|
||||
files[prop][0].fieldName.indexOf(
|
||||
"_-_Site_Ownership_Certificate"
|
||||
) > 0 ||
|
||||
files[prop][0].fieldName.indexOf("_-_Decision_Notice") >
|
||||
0 ||
|
||||
files[prop][0].fieldName.indexOf("_-_Site_Location_Plan") >
|
||||
0 ||
|
||||
files[prop][0].fieldName.indexOf(
|
||||
"_-_Plans_Drawing_Documents"
|
||||
) > 0 ||
|
||||
files[prop][0].fieldName.indexOf(
|
||||
"_-_Additional_Plans_Drawings_Documents"
|
||||
) > 0 ||
|
||||
files[prop][0].fieldName.indexOf(
|
||||
"_-_Design_and_Access_Statement"
|
||||
) > 0 ||
|
||||
files[prop][0].fieldName.indexOf(
|
||||
"_-_NSB_LPA_Additional_Documents"
|
||||
) > 0 ||
|
||||
files[prop][0].fieldName.indexOf("_-_LPA_Correspondence") >
|
||||
0 ||
|
||||
files[prop][0].fieldName.indexOf(
|
||||
"_-_LPA_Original_Permission"
|
||||
) > 0 ||
|
||||
files[prop][0].fieldName.indexOf(
|
||||
"_-_LPA's_Registration_Letter"
|
||||
) > 0 ||
|
||||
files[prop][0].fieldName.indexOf(
|
||||
+"_-_Environmental_Statement"
|
||||
) > 0 ||
|
||||
files[prop][0].fieldName.indexOf("_-_Cost_of_Application") >
|
||||
0 ||
|
||||
files[prop][0].fieldName.indexOf(
|
||||
"_-_Other_Relevant_Material"
|
||||
) > 0 ||
|
||||
files[prop][0].fieldName.indexOf(
|
||||
"_-_S106_Agreement_or_Unilateral_Undertaking" > 0
|
||||
)
|
||||
? "846040000"
|
||||
: files[prop][0].fieldName.indexOf("_IP_") > 0
|
||||
? "846040005"
|
||||
: files[prop][0].fieldName.indexOf("_Statement_") > 0
|
||||
? "846040002"
|
||||
: files[prop][0].fieldName.indexOf("_Questionnaire_") >
|
||||
0
|
||||
? "846040001"
|
||||
: files[prop][0].fieldName.indexOf("_Comments_") > 0
|
||||
? "846040003"
|
||||
: files[prop][0].fieldName.indexOf("_Impact_") > 0
|
||||
? "846040001"
|
||||
: "846040000";
|
||||
const fieldName = files[prop][0].fieldName;
|
||||
|
||||
const whichLocation =
|
||||
[
|
||||
// 1️⃣ LPA docs (grouped)
|
||||
{
|
||||
match: [
|
||||
"_Statement_of_Case",
|
||||
"_-_Statement_of_Case",
|
||||
"_-_Application_Form",
|
||||
"_-_Site_Ownership_Certificate",
|
||||
"_-_Decision_Notice",
|
||||
"_-_Site_Location_Plan",
|
||||
"_-_Plans_Drawing_Documents",
|
||||
"_-_Additional_Plans_Drawings_Documents",
|
||||
"_-_Design_and_Access_Statement",
|
||||
"_-_NSB_LPA_Additional_Documents",
|
||||
"_-_LPA_Correspondence",
|
||||
"_-_LPA_Original_Permission",
|
||||
"_-_LPA's_Registration_Letter",
|
||||
"_-_Environmental_Statement",
|
||||
"_-_Cost_of_Application",
|
||||
"_-_Other_Relevant_Material",
|
||||
"_-_S106_Agreement_or_Unilateral_Undertaking"
|
||||
],
|
||||
value: "846040000"
|
||||
},
|
||||
{ match: ["_IP_-_Comments_"], value: "846040038" },
|
||||
{
|
||||
match: ["_Consultation_Response_"],
|
||||
value: "846040036"
|
||||
},
|
||||
{ match: ["_Questionnaire_"], value: "846040001" },
|
||||
{ match: ["_Statement_"], value: "846040002" },
|
||||
{ match: ["_Comments_"], value: "846040003" },
|
||||
{ match: ["_Impact_"], value: "846040001" },
|
||||
{ match: ["_IP_"], value: "846040005" }
|
||||
].find((rule) =>
|
||||
rule.match.some((key) => fieldName.includes(key))
|
||||
)?.value || "846040000";
|
||||
|
||||
const tags = {
|
||||
containerid: containerName,
|
||||
@@ -618,7 +664,7 @@ export const uploadFile = async (formContent, containerName, foldername) => {
|
||||
documentType: files[prop][0].fieldName.split(".")[1],
|
||||
blobType: "RepresentationFile",
|
||||
ishareLocation: whichLocation,
|
||||
documentLocationId: whichLocation,
|
||||
documentLocationId: whichLocation
|
||||
};
|
||||
const withTags = blockBlobClient.setTags(tags);
|
||||
const withMeta = blockBlobClient.setMetadata(tags);
|
||||
@@ -729,13 +775,16 @@ export const uploadSingleFile = async (
|
||||
{
|
||||
pattern:
|
||||
/_Statement_of_Case|_-_Statement_of_Case|_-_Application_Form|_-_Site_Ownership_Certificate|_-_Decision_Notice|_-_Site_Location_Plan|_-_Plans_Drawing_Documents|_-_Additional_Plans_Drawings_Documents|_-_Design_and_Access_Statement|_-_NSB_LPA_Additional_Documents|_-_LPA_Correspondence|_-_LPA_Original_Permission|_-_LPA's_Registration_Letter|_-_Environmental_Statement|_-_Cost_of_Application|_-_Other_Relevant_Material|_-_S106_Agreement_or_Unilateral_Undertaking/,
|
||||
value: "846040000",
|
||||
value: "846040000"
|
||||
},
|
||||
|
||||
{ pattern: /_IP_-_Comments_/, value: "846040038" },
|
||||
{ pattern: /_IP_/, value: "846040005" },
|
||||
{ pattern: /_Statement_/, value: "846040002" },
|
||||
{ pattern: /_Questionnaire_/, value: "846040001" },
|
||||
{ pattern: /_Comments_/, value: "846040003" },
|
||||
{ pattern: /_Impact_/, value: "846040001" },
|
||||
{ pattern: /_Consultation_Response_/, value: "846040036" }
|
||||
];
|
||||
|
||||
// Find a matching pattern or fallback to default
|
||||
@@ -756,7 +805,7 @@ export const uploadSingleFile = async (
|
||||
documentType: files[prop][0].fieldName.split(".")[1],
|
||||
blobType: "RepresentationFile",
|
||||
ishareLocation: whichLocation,
|
||||
documentLocationId: whichLocation,
|
||||
documentLocationId: whichLocation
|
||||
};
|
||||
const withTags = await blockBlobClient.setTags(tags);
|
||||
const withMeta = await blockBlobClient.setMetadata(tags);
|
||||
@@ -793,7 +842,7 @@ export const uploadRepFiles = async (
|
||||
const tags = {
|
||||
containerid: containerName,
|
||||
caseID: formContent.split("tmp/")[0],
|
||||
documentType: "Rep docs",
|
||||
documentType: "Rep docs"
|
||||
};
|
||||
console.log(tags);
|
||||
const withTags = await blockBlobClient.setTags(tags);
|
||||
@@ -838,7 +887,7 @@ export const uploadPDFRepFiles = async (
|
||||
containerid: containerName,
|
||||
caseID: foldername.split("/")[0],
|
||||
documentType: repType,
|
||||
blobType: "RepresentationPDF",
|
||||
blobType: "RepresentationPDF"
|
||||
};
|
||||
|
||||
//console.log("the tags:", tags);
|
||||
@@ -891,7 +940,7 @@ export const uploadPDFAppealFiles = async (
|
||||
const tags = {
|
||||
containerid: containerName,
|
||||
caseID: foldername.split("/")[0],
|
||||
blobType: "AppealPDF",
|
||||
blobType: "AppealPDF"
|
||||
};
|
||||
|
||||
//console.log("the tags:", tags);
|
||||
@@ -930,7 +979,7 @@ export const uploadPDFCaseFiles = async (
|
||||
const tags = {
|
||||
containerid: containerName,
|
||||
caseID: foldername.split("/")[0],
|
||||
blobType: "AppealPDF",
|
||||
blobType: "AppealPDF"
|
||||
};
|
||||
|
||||
//console.log("the tags:", tags);
|
||||
@@ -1136,7 +1185,7 @@ export const downloadAllRepsFiles = async (containerName, repsBlobObj) => {
|
||||
|
||||
return {
|
||||
"@odata.count": blobCount,
|
||||
"value": downloaded,
|
||||
"value": downloaded
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1175,7 +1224,7 @@ export const getCaseBlob = async (
|
||||
const tags = {
|
||||
containerid: containerName,
|
||||
caseID: caseReference,
|
||||
blobType: "Case",
|
||||
blobType: "Case"
|
||||
};
|
||||
|
||||
//console.log("the tags:", tags);
|
||||
@@ -1206,7 +1255,7 @@ export const getProgressBlobs = async (containerName, caseReference) => {
|
||||
|
||||
let blobCount = 0;
|
||||
for await (const blob of containerClient.listBlobsFlat({
|
||||
prefix: caseReference,
|
||||
prefix: caseReference
|
||||
})) {
|
||||
blobCount++;
|
||||
}
|
||||
@@ -1219,47 +1268,34 @@ export const getProgressBlobs = async (containerName, caseReference) => {
|
||||
|
||||
let blobObj = [];
|
||||
for await (const blob of containerClient.listBlobsFlat({
|
||||
prefix: caseReference + "/" + caseReference + "_appeal.json",
|
||||
prefix: caseReference + "/" + caseReference + "_appeal.json"
|
||||
})) {
|
||||
console.log("getProgressBlobs in here", blob.name.split("/"));
|
||||
const blobPathParts = blob.name.split("/");
|
||||
const appealBlobName = blobPathParts[1];
|
||||
const contentLength = blob.properties.contentLength;
|
||||
|
||||
//consoleLogger("getProgressBlobs in here", blobPathParts);
|
||||
blobObj.push({
|
||||
"name": blob.name.split("/")[1],
|
||||
"name": appealBlobName,
|
||||
"path": blob.name,
|
||||
"versionId": blob.versionId,
|
||||
"caseObj": caseReference + "/" + caseReference + "_case.json",
|
||||
"caseObj": buildCaseObjectPath(caseReference),
|
||||
"isCurrentVersion": blob.isCurrentVersion,
|
||||
"contentLength": blob.properties.contentLength,
|
||||
"contentLength": contentLength,
|
||||
"contentType": blob.contentType,
|
||||
"lastModified": blob.properties.lastModified,
|
||||
"hashedfilepath": hashAPIPath(
|
||||
"/api/file/downloadblob?container=" +
|
||||
containerName +
|
||||
"&casefolderID=" +
|
||||
encodeURIComponent(caseReference) +
|
||||
"&blobname=" +
|
||||
encodeURIComponent(blob.name.split("/")[1])
|
||||
),
|
||||
"hasheddeletepath": hashAPIPath(
|
||||
"/api/file/deleteblob?container=" +
|
||||
containerName +
|
||||
"&casefolderID=" +
|
||||
encodeURIComponent(caseReference) +
|
||||
"&blobname=" +
|
||||
encodeURIComponent(blob.name.split("/")[1])
|
||||
),
|
||||
"hashgetblobs": hashAPIPath(
|
||||
"/api/file/getbloblist?container=" +
|
||||
containerName +
|
||||
"&casefolderID=" +
|
||||
caseReference
|
||||
),
|
||||
...buildHashMetadataPaths({
|
||||
containerName,
|
||||
casefolderID: caseReference,
|
||||
blobname: appealBlobName
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
blobObj = _.sortBy(blobObj, [
|
||||
function (o) {
|
||||
return o.lastModified;
|
||||
},
|
||||
}
|
||||
]).reverse()[0];
|
||||
|
||||
return blobObj;
|
||||
@@ -1278,8 +1314,24 @@ export const getAllProgressBlobs = async (containerName) => {
|
||||
for await (const blob of containerClient.findBlobsByTags(
|
||||
"blobType='Appeal'"
|
||||
)) {
|
||||
blob.name.split("/")[1].indexOf("_appeal.json") > 0 &&
|
||||
blob.name.split("/")[1].indexOf("undefined") < 0 &&
|
||||
const namePart = blob.name.split("/")[1] ?? "";
|
||||
|
||||
// keep your existing name filters
|
||||
if (
|
||||
namePart.indexOf("_appeal.json") <= 0 ||
|
||||
namePart.indexOf("undefined") >= 0
|
||||
)
|
||||
continue;
|
||||
|
||||
// existence check (filters out soft-deleted / stale index hits)
|
||||
const blobClient = containerClient.getBlobClient(blob.name);
|
||||
try {
|
||||
await blobClient.getProperties();
|
||||
} catch (e) {
|
||||
// errors usually expose statusCode
|
||||
if (e?.statusCode === 404) continue;
|
||||
throw e;
|
||||
}
|
||||
blobObj.push({
|
||||
"name": blob.name.split("/")[1],
|
||||
"path": blob.name,
|
||||
@@ -1288,7 +1340,7 @@ export const getAllProgressBlobs = async (containerName) => {
|
||||
blob.name.split("/")[0] +
|
||||
"/" +
|
||||
blob.name.split("/")[0] +
|
||||
"_case.json",
|
||||
"_case.json"
|
||||
// "isCurrentVersion": blob.isCurrentVersion,
|
||||
// "contentLength": blob.properties.contentLength,
|
||||
// "contentType": blob.contentType,
|
||||
@@ -1345,7 +1397,7 @@ export const getRepsBlobs = async (containerName) => {
|
||||
includeMetadata: true,
|
||||
includeSnapshots: false,
|
||||
includeTags: true,
|
||||
includeVersions: true,
|
||||
includeVersions: true
|
||||
};
|
||||
|
||||
let blobObj = [];
|
||||
@@ -1354,14 +1406,27 @@ export const getRepsBlobs = async (containerName) => {
|
||||
listOptions
|
||||
)) {
|
||||
const blobClient = containerClient.getBlobClient(blob.name);
|
||||
//console.log("getreps blob:", blob);
|
||||
blob.name.split("/")[2].indexOf("_rep.json") > 0 &&
|
||||
blob.name.split("/")[2].indexOf("undefined") < 0 &&
|
||||
|
||||
// Filter out soft-deleted/stale tag entries and malformed names.
|
||||
const namePart = blob.name.split("/")[2] ?? "";
|
||||
if (
|
||||
namePart.indexOf("_rep.json") <= 0 ||
|
||||
namePart.indexOf("undefined") >= 0
|
||||
)
|
||||
continue;
|
||||
|
||||
try {
|
||||
const properties = await blobClient.getProperties();
|
||||
|
||||
blobObj.push({
|
||||
"name": blob.name.split("/")[2],
|
||||
"name": namePart,
|
||||
"path": blob.name,
|
||||
"size": blobClient.getProperties().contentLength,
|
||||
"size": properties.contentLength
|
||||
});
|
||||
} catch (error) {
|
||||
if (error?.statusCode === 404) continue;
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
//console.log("blobObjwwwww:", blobObj);
|
||||
@@ -1384,73 +1449,43 @@ export const getRepsFilesBlobs = async (
|
||||
|
||||
const blobObj = [];
|
||||
for await (const blob of containerClient.listBlobsFlat({
|
||||
prefix: casefolderID + "/" + filenamePrefix + "/files/",
|
||||
prefix: casefolderID + "/" + filenamePrefix + "/files/"
|
||||
})) {
|
||||
let blobDocumentType = blob.name
|
||||
.split("/")[2]
|
||||
.slice(0, blob.name.split("/")[2].indexOf("_"));
|
||||
const blobPathParts = blob.name.split("/");
|
||||
const casefolderPath = blobPathParts[0] + "/" + blobPathParts[1];
|
||||
const repFileName = blobPathParts[3];
|
||||
const contentLength = blob.properties.contentLength;
|
||||
|
||||
console.log(blob.name);
|
||||
//consoleLogger(blob.name);
|
||||
|
||||
blobObj.push({
|
||||
"name": blob.name.split("/")[3],
|
||||
"name": repFileName,
|
||||
"path": blob.name,
|
||||
"documentType": getDocumentTypeFromFilename(
|
||||
blob.name.split("/")[3]
|
||||
),
|
||||
"documentType": getDocumentTypeFromFilename(repFileName),
|
||||
"versionId": blob.versionId,
|
||||
"isCurrentVersion": blob.isCurrentVersion,
|
||||
"contentLength": blob.properties.contentLength,
|
||||
"contentLength": contentLength,
|
||||
"filenameprefix": filenamePrefix,
|
||||
"filepath":
|
||||
"/api/file/downloadblob?container=" +
|
||||
containerName +
|
||||
"&casefolderID=" +
|
||||
encodeURIComponent(
|
||||
blob.name.split("/")[0] + "/" + blob.name.split("/")[1]
|
||||
) +
|
||||
"&blobname=" +
|
||||
encodeURIComponent(blob.name.split("/")[3]),
|
||||
"hashedfilepath": hashAPIPath(
|
||||
"/api/file/downloadblob?container=" +
|
||||
containerName +
|
||||
"&casefolderID=" +
|
||||
encodeURIComponent(
|
||||
blob.name.split("/")[0] + "/" + blob.name.split("/")[1]
|
||||
) +
|
||||
"&blobname=" +
|
||||
encodeURIComponent(blob.name.split("/")[3])
|
||||
),
|
||||
"deletepath":
|
||||
"/api/file/deleteblob?container=" +
|
||||
containerName +
|
||||
"&casefolderID=" +
|
||||
blob.name.split("/")[0] +
|
||||
"/" +
|
||||
blob.name.split("/")[1] +
|
||||
"&blobname=" +
|
||||
blob.name.split("/")[3],
|
||||
"hasheddeletepath": hashAPIPath(
|
||||
"/api/file/deleteblob?container=" +
|
||||
containerName +
|
||||
"&casefolderID=" +
|
||||
encodeURIComponent(
|
||||
blob.name.split("/")[0] + "/" + blob.name.split("/")[1]
|
||||
) +
|
||||
"&blobname=" +
|
||||
encodeURIComponent(blob.name.split("/")[3])
|
||||
),
|
||||
"hashgetblobs": hashAPIPath(
|
||||
"/api/file/getbloblist?container=" +
|
||||
containerName +
|
||||
"&casefolderID=" +
|
||||
blob.name.split("/")[0] +
|
||||
"/" +
|
||||
blob.name.split("/")[1]
|
||||
),
|
||||
"filepath": buildDownloadBlobQueryPath({
|
||||
containerName,
|
||||
casefolderID: casefolderPath,
|
||||
blobname: repFileName
|
||||
}),
|
||||
...buildHashMetadataPaths({
|
||||
containerName,
|
||||
casefolderID: casefolderPath,
|
||||
blobname: repFileName
|
||||
}),
|
||||
"deletepath": buildDeleteBlobQueryPath({
|
||||
containerName,
|
||||
casefolderID: casefolderPath,
|
||||
blobname: repFileName,
|
||||
encodeCasefolderID: false,
|
||||
encodeBlobname: false
|
||||
})
|
||||
});
|
||||
}
|
||||
console.log("blobObj:", blobObj);
|
||||
//consoleLogger("blobObj:", blobObj);
|
||||
|
||||
return blobObj;
|
||||
};
|
||||
@@ -1490,7 +1525,7 @@ export const createQueueSas = async (queueName) => {
|
||||
var sas_signature_val = {
|
||||
expiresOn: TEN_MINUTES_AFTER_NOW,
|
||||
permissions: permission,
|
||||
queueName: queueName,
|
||||
queueName: queueName
|
||||
};
|
||||
|
||||
const sasToken = generateQueueSASQueryParameters(
|
||||
@@ -1534,7 +1569,7 @@ export const createCaseCompleteMessage = async (
|
||||
caseReference +
|
||||
"_case.json",
|
||||
filespath:
|
||||
endpointURL + "/" + containerName + "/" + caseReference + "/files",
|
||||
endpointURL + "/" + containerName + "/" + caseReference + "/files"
|
||||
|
||||
// uploadUrl: fileRecord.uploadUrl,
|
||||
// filename: fileRecord.file.name,
|
||||
@@ -1595,7 +1630,7 @@ export const createRepCompleteMessage = async (
|
||||
caseReference +
|
||||
"/" +
|
||||
filename +
|
||||
"/files",
|
||||
"/files"
|
||||
};
|
||||
|
||||
console.log("======================", message, "=====================");
|
||||
@@ -1621,7 +1656,7 @@ export const listContainers = async (
|
||||
includeDeleted: false,
|
||||
includeMetadata: true,
|
||||
includeSystem: true,
|
||||
prefix: containerNamePrefix,
|
||||
prefix: containerNamePrefix
|
||||
};
|
||||
console.log(
|
||||
"\n\n\n=================================================\n",
|
||||
@@ -1664,7 +1699,7 @@ export const listBlobHierarchical = async (
|
||||
includeTags: true, // include indexable tags
|
||||
includeUncommitedBlobs: false, // include uncommitted blobs
|
||||
includeVersions: false, // include all blob version
|
||||
prefix: "", // filter by blob name prefix
|
||||
prefix: "" // filter by blob name prefix
|
||||
};
|
||||
|
||||
let i = 1;
|
||||
@@ -1750,7 +1785,7 @@ export async function listBlobHierarchicalForUser(containerClient) {
|
||||
? lastModifiedDate.toISOString()
|
||||
: null,
|
||||
createdOn: createdOnDate ? createdOnDate.toISOString() : null,
|
||||
displayDate,
|
||||
displayDate
|
||||
});
|
||||
}
|
||||
return blobNames;
|
||||
@@ -1765,7 +1800,7 @@ export async function listContainersForUser(
|
||||
includeDeleted: false,
|
||||
includeMetadata: true,
|
||||
includeSystem: true,
|
||||
prefix: containerNamePrefix,
|
||||
prefix: containerNamePrefix
|
||||
};
|
||||
|
||||
const results = [];
|
||||
@@ -1783,7 +1818,7 @@ export async function listContainersForUser(
|
||||
if (blobNames && blobNames.length > 0) {
|
||||
results.push({
|
||||
container: containerItem.name,
|
||||
blobs: blobNames,
|
||||
blobs: blobNames
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
# Actions Clients
|
||||
|
||||
This folder contains extracted client wrappers from `actions/index.js` as part of the Priority 1 refactor plan.
|
||||
|
||||
Current extracted clients:
|
||||
|
||||
- `relayClient` (shared hash-signing helper used by account/portal/document direct services)
|
||||
- `endpointClient` (shared JSON request helpers for GET and generic axios config requests)
|
||||
|
||||
Current usage includes:
|
||||
|
||||
- relay hash-signing helper reuse across account/portal/document direct services
|
||||
- shared endpoint JSON request helpers reused by admin/notify/integration/reference-data direct services
|
||||
|
||||
Notes:
|
||||
|
||||
- Core helper extraction and compatibility barrel support remain in place.
|
||||
- Additional client extraction (`fileClient`, `notifyClient`) can be layered in incrementally without changing public exports from `actions/index.js`.
|
||||
@@ -0,0 +1,11 @@
|
||||
import axios from "axios";
|
||||
|
||||
export const getJson = async (url, config) => {
|
||||
const response = await axios.get(url, config);
|
||||
return response.data;
|
||||
};
|
||||
|
||||
export const requestJson = async (config) => {
|
||||
const response = await axios(config);
|
||||
return response.data;
|
||||
};
|
||||
@@ -0,0 +1,22 @@
|
||||
import { getJson, requestJson } from "./endpointClient";
|
||||
import { getSignedJson, postSignedJson } from "./signedRequestClient";
|
||||
|
||||
export const getFileJson = (url) => {
|
||||
return getJson(url);
|
||||
};
|
||||
|
||||
export const getSignedFileJson = async (queryUrl) => {
|
||||
return getSignedJson(queryUrl);
|
||||
};
|
||||
|
||||
export const downloadFileBlob = (url) => {
|
||||
return requestJson({
|
||||
method: "get",
|
||||
url,
|
||||
responseType: "blob"
|
||||
});
|
||||
};
|
||||
|
||||
export const postSignedFileJson = async (queryUrl, data, config = {}) => {
|
||||
return postSignedJson(queryUrl, data, config);
|
||||
};
|
||||
@@ -0,0 +1,37 @@
|
||||
const encodeRouteParam = (value) => encodeURIComponent(String(value));
|
||||
|
||||
export const buildFileQuery = (path, params = {}, options = {}) => {
|
||||
const { encode = false } = options;
|
||||
|
||||
const entries = Object.entries(params).filter(([, value]) => {
|
||||
return value !== undefined && value !== null;
|
||||
});
|
||||
|
||||
if (entries.length === 0) {
|
||||
return path;
|
||||
}
|
||||
|
||||
const query = entries
|
||||
.map(([key, value]) => {
|
||||
if (!encode) {
|
||||
return `${key}=${String(value)}`;
|
||||
}
|
||||
|
||||
return `${encodeRouteParam(key)}=${encodeRouteParam(value)}`;
|
||||
})
|
||||
.join("&");
|
||||
|
||||
return `${path}?${query}`;
|
||||
};
|
||||
|
||||
export const withBaseUrl = (baseUrl, route) => {
|
||||
return `${baseUrl}${route}`;
|
||||
};
|
||||
|
||||
export const appendQuerySuffix = (route, suffix = "") => {
|
||||
return `${route}${suffix}`;
|
||||
};
|
||||
|
||||
export const appendHashSuffix = (route, hashBuilder) => {
|
||||
return appendQuerySuffix(route, hashBuilder(route));
|
||||
};
|
||||
@@ -0,0 +1,5 @@
|
||||
export * from "./relayClient";
|
||||
export * from "./endpointClient";
|
||||
export * from "./fileClient";
|
||||
export * from "./fileRouteBuilder";
|
||||
export * from "./signedRequestClient";
|
||||
@@ -0,0 +1,22 @@
|
||||
import axios from "axios";
|
||||
import { hashAPIPath } from "../core/hash";
|
||||
|
||||
export const buildHashedQueryUrl = async (queryUrl) => {
|
||||
try {
|
||||
const signRes = await axios.get(
|
||||
"/api/endpoint/gethash_api?path=" + encodeURIComponent(queryUrl)
|
||||
);
|
||||
|
||||
if (!signRes?.data?.hash) {
|
||||
throw new Error("Hash signature unavailable");
|
||||
}
|
||||
|
||||
return queryUrl + signRes.data.hash;
|
||||
} catch (error) {
|
||||
if (typeof window === "undefined" && process.env.HASHKEY) {
|
||||
return queryUrl + hashAPIPath(queryUrl);
|
||||
}
|
||||
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,45 @@
|
||||
import { requestJson } from "./endpointClient";
|
||||
import { buildHashedQueryUrl } from "./relayClient";
|
||||
|
||||
export const buildSignedUrl = async (queryUrl, config = {}) => {
|
||||
const { baseUrl = "" } = config;
|
||||
|
||||
return `${baseUrl}${await buildHashedQueryUrl(queryUrl)}`;
|
||||
};
|
||||
|
||||
const signedRequestJson = async ({ method, queryUrl, data, config = {} }) => {
|
||||
const { baseUrl, ...requestConfig } = config;
|
||||
const signedUrl = await buildSignedUrl(queryUrl, { baseUrl });
|
||||
|
||||
return requestJson({
|
||||
method,
|
||||
url: signedUrl,
|
||||
data,
|
||||
...requestConfig
|
||||
});
|
||||
};
|
||||
|
||||
export const getSignedJson = (queryUrl, config = {}) => {
|
||||
return signedRequestJson({
|
||||
method: "get",
|
||||
queryUrl,
|
||||
config
|
||||
});
|
||||
};
|
||||
|
||||
export const postSignedJson = (queryUrl, data, config = {}) => {
|
||||
return signedRequestJson({
|
||||
method: "post",
|
||||
queryUrl,
|
||||
data,
|
||||
config
|
||||
});
|
||||
};
|
||||
|
||||
export const deleteSignedJson = (queryUrl, config = {}) => {
|
||||
return signedRequestJson({
|
||||
method: "delete",
|
||||
queryUrl,
|
||||
config
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,15 @@
|
||||
const port = parseInt(process.env.PORT, 10) || 3000;
|
||||
|
||||
export const BASE_URL =
|
||||
typeof window !== "undefined"
|
||||
? window.apiRoot
|
||||
: process.env.API_ROOT || `http://localhost:${port}`;
|
||||
|
||||
export const API_PATH = "/api/data/v9.2/";
|
||||
|
||||
export const WEBAPI_URL =
|
||||
process.env.RELAY_ROOT ||
|
||||
"https://dev-pedw-ns.servicebus.windows.net/dev-pedw-hc/";
|
||||
|
||||
export const ACCESS_TOKEN_ENDPOINT = process.env.ACCESS_TOKEN_ENDPOINT;
|
||||
export const TENANT_ID = process.env.TENANT;
|
||||
@@ -0,0 +1,11 @@
|
||||
export const isNonEmptyString = (value) => {
|
||||
return typeof value === "string" && value.trim().length > 0;
|
||||
};
|
||||
|
||||
export const sanitizeString = (value) => {
|
||||
return typeof value === "string" ? value.trim() : "";
|
||||
};
|
||||
|
||||
export const escapeODataString = (value) => {
|
||||
return sanitizeString(value).replace(/'/g, "''");
|
||||
};
|
||||
@@ -0,0 +1,22 @@
|
||||
import CryptoJS from "crypto-js";
|
||||
|
||||
const WORDKEY = process.env.HASHKEY;
|
||||
|
||||
export const hashAPIPath = (queryPath) => {
|
||||
var hashlink = CryptoJS.HmacSHA256(
|
||||
queryPath,
|
||||
CryptoJS.enc.Hex.parse(WORDKEY)
|
||||
);
|
||||
hashlink = hashlink.toString(CryptoJS.enc.Hex);
|
||||
return (queryPath.indexOf("?") > -1 ? "&hash=" : "?hash=") + hashlink;
|
||||
};
|
||||
|
||||
export const hashString = (stringToHash) => {
|
||||
let hashedStr = CryptoJS.AES.encrypt(stringToHash, "pedw");
|
||||
return hashedStr.toString();
|
||||
};
|
||||
|
||||
export const dehashString = (stringToDeHash) => {
|
||||
let dehashedStr = CryptoJS.AES.decrypt(decodeURI(stringToDeHash), "pedw");
|
||||
return dehashedStr.toString(CryptoJS.enc.Utf8);
|
||||
};
|
||||
@@ -0,0 +1,50 @@
|
||||
export const azureHeaders = (access_token) => {
|
||||
return {
|
||||
headers: {
|
||||
"OData-MaxVersion": "4.0",
|
||||
"OData-Version": "4.0",
|
||||
"Accept": "application/json;odata.metadata=none",
|
||||
"Prefer": 'odata.include-annotations="*",return=representation',
|
||||
"Content-Type": "application/json",
|
||||
"Authorization": "Bearer " + access_token
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
export const azureHeadersNoOdata = (access_token) => {
|
||||
return {
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
"Authorization": "Bearer " + access_token
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
export const azureHeadersPaged = (access_token) => {
|
||||
return {
|
||||
headers: {
|
||||
"OData-MaxVersion": "4.0",
|
||||
"OData-Version": "4.0",
|
||||
"Accept": "application/json;odata.metadata=none",
|
||||
"Prefer":
|
||||
'odata.include-annotations="*",return=representation, odata.maxpagesize=10',
|
||||
"Content-Type": "application/json",
|
||||
"Authorization": "Bearer " + access_token
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
export const azureHeadersPagedCustom = (access_token, showNumberOfRecords) => {
|
||||
return {
|
||||
headers: {
|
||||
"OData-MaxVersion": "4.0",
|
||||
"OData-Version": "4.0",
|
||||
"Accept": "application/json;odata.metadata=none",
|
||||
"Prefer":
|
||||
'odata.include-annotations="*",return=representation, odata.maxpagesize=' +
|
||||
showNumberOfRecords,
|
||||
"Content-Type": "application/json",
|
||||
"Authorization": "Bearer " + access_token
|
||||
}
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,100 @@
|
||||
import { hasOwn } from "../../components/utils";
|
||||
|
||||
const MASK = "[REDACTED]";
|
||||
|
||||
const redactString = (value) => {
|
||||
if (typeof value !== "string") return value;
|
||||
|
||||
return value
|
||||
.replace(
|
||||
/([a-zA-Z0-9._%+-]{1,})@([a-zA-Z0-9.-]+\.[a-zA-Z]{2,})/g,
|
||||
`${MASK}@${MASK}`
|
||||
)
|
||||
.replace(/Bearer\s+[A-Za-z0-9._\-]+/gi, `Bearer ${MASK}`)
|
||||
.replace(/("client_secret"\s*:\s*")[^"]+("?)/gi, `$1${MASK}$2`)
|
||||
.replace(/("access_token"\s*:\s*")[^"]+("?)/gi, `$1${MASK}$2`);
|
||||
};
|
||||
|
||||
export const redactSensitive = (value) => {
|
||||
if (value == null) return value;
|
||||
|
||||
if (typeof value === "string") {
|
||||
return redactString(value);
|
||||
}
|
||||
|
||||
try {
|
||||
const json = JSON.stringify(value);
|
||||
return redactString(json);
|
||||
} catch (_error) {
|
||||
return MASK;
|
||||
}
|
||||
};
|
||||
|
||||
export const getIP = (req) => {
|
||||
const forwarded = req.headers["x-forwarded-for"];
|
||||
|
||||
const ip =
|
||||
typeof forwarded === "string"
|
||||
? forwarded.split(/, /)[0]
|
||||
: req.socket.remoteAddress;
|
||||
|
||||
console.info(
|
||||
"\n====================\n Client IP address: " + ip,
|
||||
"\n=====================\n"
|
||||
);
|
||||
};
|
||||
|
||||
export const consoleLogger = (err) => {
|
||||
console.log(
|
||||
"\n\n/////////////////////////////////////////////////\nRaw Error " +
|
||||
redactSensitive(err) +
|
||||
"\n\n/////////////////////////////////////////////////\n"
|
||||
);
|
||||
|
||||
const errStr =
|
||||
"\n\n/////////////////////////////////////////////////\nServer Error\n" +
|
||||
(hasOwn(err, "name") ? `Name: ${err.name}\n` : "") +
|
||||
(hasOwn(err, "code") ? `Code: ${err.code}\n` : "") +
|
||||
(hasOwn(err, "query") ? `Query: ${err.query}\n` : "") +
|
||||
(hasOwn(err, "message") ? `Message: ${err.message}\n` : "") +
|
||||
(err?.request?.url ? `request.url: ${err.request.url}\n` : "") +
|
||||
(err?.response?.status ? `Status: ${err.response.status}\n` : "") +
|
||||
(err?.response?.statusText
|
||||
? `StatusText: ${err.response.statusText}\n`
|
||||
: "") +
|
||||
(err?.response?.request?.socket?.remoteAddress
|
||||
? `Request IP: ${err.response.request.socket.remoteAddress}\n`
|
||||
: "") +
|
||||
(err?.response?.data?.error?.message
|
||||
? `Message: ${redactSensitive(err.response.data.error.message)}\n`
|
||||
: "") +
|
||||
(err?.response?.config?.url
|
||||
? `Request URL: ${redactSensitive(err.response.config.url)}\n`
|
||||
: "") +
|
||||
(err?.response?.headers?.date
|
||||
? `Request Time: ${err.response.headers.date}\n`
|
||||
: "") +
|
||||
(err?.config?.url
|
||||
? `Axios config url: ${redactSensitive(err.config.url)}\n`
|
||||
: "") +
|
||||
(err?.message
|
||||
? `Axios message: ${redactSensitive(err.message)}\n`
|
||||
: "") +
|
||||
(err?.config?.data
|
||||
? `Request payload: ${redactSensitive(err.config.data)}\n`
|
||||
: "") +
|
||||
"\n/////////////////////////////////////////////////\n";
|
||||
|
||||
console.log(errStr);
|
||||
};
|
||||
|
||||
export const conLog = (err) => {
|
||||
var errStr =
|
||||
"\n\n/////////////////////////////////////////////////\nResponse: " +
|
||||
"\n" +
|
||||
err +
|
||||
"\n/////////////////////////////////////////////////\n\n";
|
||||
|
||||
console.log(errStr);
|
||||
return errStr;
|
||||
};
|
||||
@@ -0,0 +1,41 @@
|
||||
import { requestJson } from "../clients/endpointClient";
|
||||
import { ACCESS_TOKEN_ENDPOINT, TENANT_ID } from "./env";
|
||||
import { consoleLogger } from "./logger";
|
||||
|
||||
const cache = {};
|
||||
|
||||
const tokenBody =
|
||||
"grant_type=" +
|
||||
process.env.GRANT_TYPE +
|
||||
"&client_id=" +
|
||||
process.env.CLIENT_ID +
|
||||
"&client_secret=" +
|
||||
process.env.CLIENT_SECRET +
|
||||
"&scope=" +
|
||||
"https://" +
|
||||
process.env.RELAYURI +
|
||||
"/.default";
|
||||
|
||||
const tokenConfig = {
|
||||
headers: {
|
||||
"Content-Type": "application/x-www-form-urlencoded",
|
||||
"Cache-Control": "no-cache"
|
||||
}
|
||||
};
|
||||
|
||||
export const getToken = async () => {
|
||||
try {
|
||||
const data = await requestJson({
|
||||
method: "post",
|
||||
url: `${ACCESS_TOKEN_ENDPOINT}${TENANT_ID}/oauth2/v2.0/token`,
|
||||
data: tokenBody,
|
||||
...tokenConfig
|
||||
});
|
||||
|
||||
cache.tokenResponse = data;
|
||||
return data;
|
||||
} catch (error) {
|
||||
consoleLogger(error);
|
||||
return error;
|
||||
}
|
||||
};
|
||||
+9
-2197
File diff suppressed because it is too large
Load Diff
+32
-21
@@ -1,53 +1,58 @@
|
||||
export const getSelectQuery = (appealTypeName) => {
|
||||
switch (appealTypeName) {
|
||||
case "pinswg_advertses":
|
||||
return "&$select=pinswg_speacialistcaseprocess,modifiedon,_pinswg_appellant_value,pinswg_name,pinswg_siteaddresscounty,pinswg_siteaddressline1,pinswg_siteaddressline2,pinswg_siteaddresspostcode,pinswg_siteaddresstown,_pinswg_associatedlpa_value,pinswg_casedecisiondate,pinswg_dateeventrequested,pinswg_decision,pinswg_procedure,pinswg_questionnaireduedate,statuscode,pinswg_startdateoftheevent,pinswg_typeofevent,pinswg_startdate,pinswg_otherpartiesstatement,pinswg_finalcommentsduedate,pinswg_proofsofevidencewrittenstatementsofeviden,pinswg_speacialistcaseprocess,pinswg_statementduedate";
|
||||
return "&$select=pinswg_detailedeiascreeningrequired,pinswg_speacialistcaseprocess,modifiedon,_pinswg_appellant_value,pinswg_name,pinswg_siteaddresscounty,pinswg_siteaddressline1,pinswg_siteaddressline2,pinswg_siteaddresspostcode,pinswg_siteaddresstown,_pinswg_associatedlpa_value,pinswg_casedecisiondate,pinswg_dateeventrequested,pinswg_decision,pinswg_procedure,pinswg_questionnaireduedate,statuscode,pinswg_startdateoftheevent,pinswg_typeofevent,pinswg_startdate,pinswg_otherpartiesstatement,pinswg_finalcommentsduedate,pinswg_proofsofevidencewrittenstatementsofeviden,pinswg_speacialistcaseprocess,pinswg_statementduedate";
|
||||
break;
|
||||
case "pinswg_callinss77s":
|
||||
return "&$select=modifiedon,_pinswg_appellant_value,pinswg_name,pinswg_siteaddresscounty,pinswg_siteaddressline1,pinswg_siteaddressline2,pinswg_siteaddresspostcode,pinswg_siteaddresstown,_pinswg_associatedlpa_value,pinswg_casedecisiondate,pinswg_dateeventrequested,pinswg_decision,pinswg_finalcommentsduedate,pinswg_procedure,pinswg_proofsofevidencewrittenstatementsofeviden,pinswg_questionnaireduedate,pinswg_startdate,statuscode,pinswg_dateexportedtoiss,pinswg_startdateofevent,pinswg_typeofevent,pinswg_statementsduedate,pinswg_otherpartiesstatement";
|
||||
return "&$select=pinswg_eiarequired,modifiedon,_pinswg_appellant_value,pinswg_name,pinswg_siteaddresscounty,pinswg_siteaddressline1,pinswg_siteaddressline2,pinswg_siteaddresspostcode,pinswg_siteaddresstown,_pinswg_associatedlpa_value,pinswg_casedecisiondate,pinswg_dateeventrequested,pinswg_decision,pinswg_finalcommentsduedate,pinswg_procedure,pinswg_proofsofevidencewrittenstatementsofeviden,pinswg_questionnaireduedate,pinswg_startdate,statuscode,pinswg_dateexportedtoiss,pinswg_startdateofevent,pinswg_typeofevent,pinswg_statementsduedate,pinswg_otherpartiesstatement";
|
||||
break;
|
||||
case "pinswg_commonlands":
|
||||
return "&$select=modifiedon,_pinswg_appellant_value,pinswg_name,pinswg_siteaddresscounty,pinswg_siteaddressline1,pinswg_siteaddressline2,pinswg_siteaddresspostcode,pinswg_siteaddresstown,_pinswg_associatedlpa_value,pinswg_casedecisiondate,pinswg_dateeventrequested,pinswg_decision,pinswg_finalcommentsduedate,pinswg_otherpartiesstatement,pinswg_procedure,pinswg_proofsofevidencewrittenstatementsofeviden,pinswg_questionnaireduedate,pinswg_relevantauthorityname,pinswg_startdate,statuscode,pinswg_starttimeoftheevent,pinswg_typeofevent,pinswg_statementsduedate";
|
||||
return "&$select=pinswg_detailedeiascreeningrequired,modifiedon,_pinswg_appellant_value,pinswg_name,pinswg_siteaddresscounty,pinswg_siteaddressline1,pinswg_siteaddressline2,pinswg_siteaddresspostcode,pinswg_siteaddresstown,_pinswg_associatedlpa_value,pinswg_casedecisiondate,pinswg_dateeventrequested,pinswg_decision,pinswg_finalcommentsduedate,pinswg_otherpartiesstatement,pinswg_procedure,pinswg_proofsofevidencewrittenstatementsofeviden,pinswg_questionnaireduedate,pinswg_relevantauthorityname,pinswg_startdate,statuscode,pinswg_starttimeoftheevent,pinswg_typeofevent,pinswg_statementsduedate";
|
||||
break;
|
||||
case "pinswg_environmentalpermittings":
|
||||
return "&$select=modifiedon,_pinswg_appellant_value,pinswg_name,pinswg_siteaddresscounty,pinswg_siteaddressline1,pinswg_siteaddressline2,pinswg_siteaddresspostcode,pinswg_siteaddresstown,_pinswg_associatedlpa_value,pinswg_casedecisiondate,pinswg_dateeventrequested,pinswg_decision,pinswg_finalcommentsduedate,pinswg_otherpartiesstatement,pinswg_procedure,pinswg_proofsofevidencewrittenstatementsofeviden,pinswg_questionnaireduedate,pinswg_relevantauthorityname,pinswg_startdate,statuscode,pinswg_startdateofevent,pinswg_typeofevent";
|
||||
return "&$select=pinswg_detailedeiascreeningrequired,modifiedon,_pinswg_appellant_value,pinswg_name,pinswg_siteaddresscounty,pinswg_siteaddressline1,pinswg_siteaddressline2,pinswg_siteaddresspostcode,pinswg_siteaddresstown,_pinswg_associatedlpa_value,pinswg_casedecisiondate,pinswg_dateeventrequested,pinswg_decision,pinswg_finalcommentsduedate,pinswg_otherpartiesstatement,pinswg_procedure,pinswg_proofsofevidencewrittenstatementsofeviden,pinswg_questionnaireduedate,pinswg_relevantauthorityname,pinswg_startdate,statuscode,pinswg_startdateofevent,pinswg_typeofevent";
|
||||
break;
|
||||
case "pinswg_hedgeshedgerowstreepreservationreplacems":
|
||||
return "&$select=pinswg_specialistcaseprocess,modifiedon,_pinswg_appellant_value,pinswg_name,pinswg_siteaddresscounty,pinswg_siteaddressline1,pinswg_siteaddressline2,pinswg_siteaddresspostcode,pinswg_siteaddresstown,_pinswg_associatedlpa_value,pinswg_casedecisiondate,pinswg_dateeventrequested,pinswg_decision,pinswg_finalcommentsduedate,pinswg_otherpartiesstatement,pinswg_procedure,pinswg_proofsofevidencewrittenstatementsofeviden,pinswg_questionnaireduedate,pinswg_relevantauthorityname,pinswg_startdate,statuscode,pinswg_startdateoftheevent,pinswg_typeofevent,pinswg_statementduedate,pinswg_specialistcaseprocess";
|
||||
return "&$select=pinswg_detailedeiascreening,pinswg_specialistcaseprocess,modifiedon,_pinswg_appellant_value,pinswg_name,pinswg_siteaddresscounty,pinswg_siteaddressline1,pinswg_siteaddressline2,pinswg_siteaddresspostcode,pinswg_siteaddresstown,_pinswg_associatedlpa_value,pinswg_casedecisiondate,pinswg_dateeventrequested,pinswg_decision,pinswg_finalcommentsduedate,pinswg_otherpartiesstatement,pinswg_procedure,pinswg_proofsofevidencewrittenstatementsofeviden,pinswg_questionnaireduedate,pinswg_relevantauthorityname,pinswg_startdate,statuscode,pinswg_startdateoftheevent,pinswg_typeofevent,pinswg_statementduedate,pinswg_specialistcaseprocess";
|
||||
break;
|
||||
case "pinswg_miscellaneouscaseworks":
|
||||
return "&$select=pinswg_eiarequired,modifiedon,_pinswg_appellant_value,pinswg_name,pinswg_siteaddresscounty,pinswg_siteaddressline1,pinswg_siteaddressline2,pinswg_siteaddresspostcode,pinswg_siteaddresstown,_pinswg_associatedlpa_value,pinswg_casedecisiondate,pinswg_dateeventrequested,pinswg_decision,pinswg_finalcommentsduedate,pinswg_otherpartiesstatement,pinswg_procedure,pinswg_proofsofevidencewrittenstatementsofeviden,pinswg_questionnaireduedate,pinswg_relevantauthorityname,pinswg_startdate,statuscode,pinswg_startdateoftheevent,pinswg_typeofevent,pinswg_statementduedate";
|
||||
break;
|
||||
case "pinswg_wayleaves":
|
||||
return "&$select=modifiedon,_pinswg_appellant_value,pinswg_name,pinswg_siteaddresscounty,pinswg_siteaddressline1,pinswg_siteaddressline2,pinswg_siteaddresspostcode,pinswg_siteaddresstown,_pinswg_associatedlpa_value,pinswg_casedecisiondate,pinswg_dateeventrequested,pinswg_decision,pinswg_finalcommentsduedate,pinswg_otherpartiesstatement,pinswg_procedure,pinswg_proofsofevidencewrittenstatementsofeviden,pinswg_questionnaireduedate,pinswg_relevantauthorityname,pinswg_startdate,statuscode,pinswg_startdateoftheevent,pinswg_typeofevent,pinswg_statementduedate";
|
||||
return "&$select=pinswg_detailedeiascreening,modifiedon,_pinswg_appellant_value,pinswg_name,pinswg_siteaddresscounty,pinswg_siteaddressline1,pinswg_siteaddressline2,pinswg_siteaddresspostcode,pinswg_siteaddresstown,_pinswg_associatedlpa_value,pinswg_casedecisiondate,pinswg_dateeventrequested,pinswg_decision,pinswg_finalcommentsduedate,pinswg_otherpartiesstatement,pinswg_procedure,pinswg_proofsofevidencewrittenstatementsofeviden,pinswg_questionnaireduedate,pinswg_relevantauthorityname,pinswg_startdate,statuscode,pinswg_startdateoftheevent,pinswg_typeofevent,pinswg_statementduedate";
|
||||
break;
|
||||
case "pinswg_communityinfrastructurelevys117118119s":
|
||||
return "&$select=modifiedon,_pinswg_appellant_value,pinswg_name,pinswg_siteaddresscounty,pinswg_siteaddressline1,pinswg_siteaddressline2,pinswg_siteaddresspostcode,pinswg_siteaddresstown,_pinswg_associatedlpa_value,pinswg_casedecisiondate,pinswg_dateeventrequested,pinswg_decision,pinswg_finalcommentsduedate,pinswg_procedure,pinswg_startdate,statuscode,pinswg_startdateoftheevent,pinswg_typeofevent,pinswg_questionnaireduedate,pinswg_statementduedate";
|
||||
return "&$select=pinswg_detailedeiascreeningrequired,modifiedon,_pinswg_appellant_value,pinswg_name,pinswg_siteaddresscounty,pinswg_siteaddressline1,pinswg_siteaddressline2,pinswg_siteaddresspostcode,pinswg_siteaddresstown,_pinswg_associatedlpa_value,pinswg_casedecisiondate,pinswg_dateeventrequested,pinswg_decision,pinswg_finalcommentsduedate,pinswg_procedure,pinswg_startdate,statuscode,pinswg_startdateoftheevent,pinswg_typeofevent,pinswg_questionnaireduedate,pinswg_statementduedate";
|
||||
break;
|
||||
case "pinswg_compulsorypurchaseorderses":
|
||||
return "&$select=modifiedon,_pinswg_appellant_value,pinswg_name,pinswg_siteaddresscounty,pinswg_siteaddressline1,pinswg_siteaddressline2,pinswg_siteaddresspostcode,pinswg_siteaddresstown,pinswg_casedecisiondate,pinswg_dateeventrequested,pinswg_decision,pinswg_finalcommentsduedate,pinswg_otherpartiesstatement,pinswg_procedure,pinswg_proofsofevidencewrittenstatementsofeviden,pinswg_questionnaireduedate,pinswg_relevantauthorityname,pinswg_startdate,statuscode,pinswg_startdateoftheevent,pinswg_typeofevent,pinswg_statementduedate";
|
||||
return "&$select=pinswg_detailedeiascreening,modifiedon,_pinswg_appellant_value,pinswg_name,pinswg_siteaddresscounty,pinswg_siteaddressline1,pinswg_siteaddressline2,pinswg_siteaddresspostcode,pinswg_siteaddresstown,pinswg_casedecisiondate,pinswg_dateeventrequested,pinswg_decision,pinswg_finalcommentsduedate,pinswg_otherpartiesstatement,pinswg_procedure,pinswg_proofsofevidencewrittenstatementsofeviden,pinswg_questionnaireduedate,pinswg_relevantauthorityname,pinswg_startdate,statuscode,pinswg_startdateoftheevent,pinswg_typeofevent,pinswg_statementduedate";
|
||||
break;
|
||||
case "pinswg_dnses":
|
||||
return "&$select=pinswg_anticipatedgridreferenceeastingtext,pinswg_anticipatedgridreferencenorthingtext,_pinswg_appellant_value,pinswg_name,pinswg_addressline1,pinswg_addressline2,pinswg_postcode,pinswg_addresstown,_pinswg_associatedlpa_value,pinswg_addresscounty,pinswg_applicationacceptedasvalid,pinswg_applicationrejectedasinvalid,pinswg_choiceofprocedure,pinswg_confirmrequesttovaryapplication,pinswg_dateeventrequested,pinswg_dateofdecision,pinswg_dateofrequesttovarytheapplication,pinswg_dateofsubmissionofapplication,pinswg_dateprojectpublishedonwebsite,pinswg_deadlineforsubmissionofapplication,pinswg_decision,pinswg_endofrepresentationperiod,pinswg_inspectorreportsubmittedtowelshgovernment,pinswg_procedureconfirmed,pinswg_projectdescription,pinswg_projectlocation,pinswg_recommendation,pinswg_rejectrequesttovaryapplication,pinswg_reportdueby,pinswg_suspensiondates,pinswg_suspensionenddates,pinswg_suspensionstartdates,pinswg_validnoticeofintentiontosubmitanapplicati,pinswg_webaddress,pinswg_withdrawndate,pinswg_writtenacceptanceofnotification,statuscode,pinswg_casestage,_pinswg_dnsids_value,pinswg_startdateofevent,pinswg_typeofevent";
|
||||
return "&$select=pinswg_eiarequired,pinswg_anticipatedgridreferenceeastingtext,pinswg_anticipatedgridreferencenorthingtext,_pinswg_appellant_value,pinswg_name,pinswg_addressline1,pinswg_addressline2,pinswg_postcode,pinswg_addresstown,_pinswg_associatedlpa_value,pinswg_addresscounty,pinswg_applicationacceptedasvalid,pinswg_applicationrejectedasinvalid,pinswg_choiceofprocedure,pinswg_confirmrequesttovaryapplication,pinswg_dateeventrequested,pinswg_dateofdecision,pinswg_dateofrequesttovarytheapplication,pinswg_dateofsubmissionofapplication,pinswg_dateprojectpublishedonwebsite,pinswg_deadlineforsubmissionofapplication,pinswg_decision,pinswg_endofrepresentationperiod,pinswg_inspectorreportsubmittedtowelshgovernment,pinswg_procedureconfirmed,pinswg_projectdescription,pinswg_projectlocation,pinswg_recommendation,pinswg_rejectrequesttovaryapplication,pinswg_reportdueby,pinswg_suspensiondates,pinswg_suspensionenddates,pinswg_suspensionstartdates,pinswg_validnoticeofintentiontosubmitanapplicati,pinswg_webaddress,pinswg_withdrawndate,pinswg_writtenacceptanceofnotification,statuscode,_pinswg_dnsids_value,pinswg_startdateofevent,pinswg_typeofevent";
|
||||
break;
|
||||
case "pinswg_electricityacts":
|
||||
return "&$select=modifiedon,_pinswg_appellant_value,pinswg_name,pinswg_addressline1,pinswg_addressline2,pinswg_postcode,pinswg_addresstown,_pinswg_associatedlpa_value,pinswg_applicationacceptedasvalid,pinswg_applicationrejectedasinvalid,pinswg_confirmrequesttovaryapplication,pinswg_dateeventrequested,pinswg_dateofrequesttovarytheapplication,pinswg_dateofsubmissionofapplication,pinswg_dateprojectpublishedonwebsite,pinswg_deadlineforsubmissionofapplication,pinswg_decision,pinswg_endofrepresentationperiod,pinswg_inspectorreportsubmittedtowelshgovernment,pinswg_procedureconfirmed,pinswg_projectlocation,pinswg_recommendation,pinswg_rejectrequesttovaryapplication,pinswg_reportdueby,pinswg_suspensiondates,pinswg_validnoticeofintentiontosubmitanapplicati,pinswg_webaddress,pinswg_withdrawndate,pinswg_writtenacceptanceofnotification,statuscode,pinswg_startdateofevent,pinswg_typeofevent";
|
||||
return "&$select=pinswg_eiarequired,modifiedon,_pinswg_appellant_value,pinswg_name,pinswg_addressline1,pinswg_addressline2,pinswg_postcode,pinswg_addresstown,_pinswg_associatedlpa_value,pinswg_applicationacceptedasvalid,pinswg_applicationrejectedasinvalid,pinswg_confirmrequesttovaryapplication,pinswg_dateeventrequested,pinswg_dateofrequesttovarytheapplication,pinswg_dateofsubmissionofapplication,pinswg_dateprojectpublishedonwebsite,pinswg_deadlineforsubmissionofapplication,pinswg_decision,pinswg_endofrepresentationperiod,pinswg_inspectorreportsubmittedtowelshgovernment,pinswg_procedureconfirmed,pinswg_projectlocation,pinswg_recommendation,pinswg_rejectrequesttovaryapplication,pinswg_reportdueby,pinswg_suspensiondates,pinswg_validnoticeofintentiontosubmitanapplicati,pinswg_webaddress,pinswg_withdrawndate,pinswg_writtenacceptanceofnotification,statuscode,pinswg_startdateofevent,pinswg_typeofevent";
|
||||
break;
|
||||
case "pinswg_harbourrevisionorders":
|
||||
return "&$select=pinswg_eiarequired,pinswg_anticipatedgridreferenceeastingtext,pinswg_anticipatedgridreferencenorthingtext,_pinswg_appellant_value,pinswg_name,pinswg_addressline1,pinswg_addressline2,pinswg_postcode,pinswg_addresstown,_pinswg_associatedlpa_value,pinswg_addresscounty,pinswg_applicationacceptedasvalid,pinswg_applicationrejectedasinvalid,pinswg_choiceofprocedure,pinswg_confirmrequesttovaryapplication,pinswg_dateeventrequested,pinswg_dateofdecision,pinswg_dateofrequesttovarytheapplication,pinswg_dateofsubmissionofapplication,pinswg_dateprojectpublishedonwebsite,pinswg_deadlineforsubmissionofapplication,pinswg_decision,pinswg_endofrepresentationperiod,pinswg_inspectorreportsubmittedtowelshgovernment,pinswg_procedureconfirmed,pinswg_projectdiscription,pinswg_projectlocation,pinswg_recommendation,pinswg_rejectrequesttovaryapplication,pinswg_reportdueby,pinswg_suspensiondates,pinswg_suspensionenddates,pinswg_suspensionstartdate,pinswg_validnoticeofintentiontosubmitanapplicati,pinswg_webaddress,pinswg_withdrawndate,pinswg_writtenacceptanceofnotification,statuscode,pinswg_startdateofevent,pinswg_typeofevent";
|
||||
break;
|
||||
case "pinswg_householderappealhases":
|
||||
return "&$select=modifiedon,_pinswg_appellant_value,pinswg_name,pinswg_siteaddressline1,pinswg_siteaddressline2,pinswg_siteaddresspostcode,pinswg_siteaddresstown,_pinswg_associatedlpa_value,pinswg_casedecisiondate,pinswg_dateeventrequested,pinswg_decision,pinswg_finalcommentsduedate,pinswg_otherpartiesstmt,pinswg_procedure,pinswg_questionnaireduedate,pinswg_startdate,pinswg_statementduedate,statuscode";
|
||||
return "&$select=pinswg_eiarequired,modifiedon,_pinswg_appellant_value,pinswg_name,pinswg_siteaddressline1,pinswg_siteaddressline2,pinswg_siteaddresspostcode,pinswg_siteaddresstown,_pinswg_associatedlpa_value,pinswg_casedecisiondate,pinswg_dateeventrequested,pinswg_decision,pinswg_finalcommentsduedate,pinswg_otherpartiesstmt,pinswg_procedure,pinswg_questionnaireduedate,pinswg_startdate,pinswg_statementduedate,statuscode";
|
||||
break;
|
||||
case "pinswg_enforcementnoticeappeals174s":
|
||||
return "&$select=modifiedon,_pinswg_appellant_value,pinswg_name,pinswg_siteaddressline1,pinswg_siteaddressline2,pinswg_siteaddresspostcode,pinswg_siteaddresstown,_pinswg_associatedlpa_value,pinswg_casedecisiondate,pinswg_dateeventrequested,pinswg_decision,pinswg_finalcommentsduedate,pinswg_otherpartiesstatement,pinswg_procedure,pinswg_questionnaireduedate,pinswg_startdate,pinswg_statementduedate,statuscode,pinswg_startdateoftheevent,pinswg_typeofevent";
|
||||
return "&$select=pinswg_eiarequired,modifiedon,_pinswg_appellant_value,pinswg_name,pinswg_siteaddressline1,pinswg_siteaddressline2,pinswg_siteaddresspostcode,pinswg_siteaddresstown,_pinswg_associatedlpa_value,pinswg_casedecisiondate,pinswg_dateeventrequested,pinswg_decision,pinswg_finalcommentsduedate,pinswg_otherpartiesstatement,pinswg_procedure,pinswg_questionnaireduedate,pinswg_startdate,pinswg_statementduedate,statuscode,pinswg_startdateoftheevent,pinswg_typeofevent";
|
||||
break;
|
||||
case "pinswg_enforcementlistedbuildingconservationaps":
|
||||
return "&$select=modifiedon,_pinswg_appellant_value,pinswg_name,pinswg_siteaddressline1,pinswg_siteaddressline2,pinswg_siteaddresspostcode,pinswg_siteaddresstown,_pinswg_associatedlpa_value,pinswg_casedecisiondate,pinswg_dateeventrequested,pinswg_decision,pinswg_finalcommentsduedate,pinswg_otherpartiesstatements,pinswg_procedure,pinswg_questionnaireduedate,pinswg_startdates,pinswg_statementduedate,statuscode,pinswg_startdateofevent,pinswg_typeofevent";
|
||||
return "&$select=pinswg_detailedeiascreeningrequired,modifiedon,_pinswg_appellant_value,pinswg_name,pinswg_siteaddressline1,pinswg_siteaddressline2,pinswg_siteaddresspostcode,pinswg_siteaddresstown,_pinswg_associatedlpa_value,pinswg_casedecisiondate,pinswg_dateeventrequested,pinswg_decision,pinswg_finalcommentsduedate,pinswg_otherpartiesstatements,pinswg_procedure,pinswg_questionnaireduedate,pinswg_startdates,pinswg_statementduedate,statuscode,pinswg_startdateofevent,pinswg_typeofevent";
|
||||
break;
|
||||
case "pinswg_maintenanceoflands217s":
|
||||
return "&$select=modifiedon,_pinswg_appellant_value,pinswg_name,pinswg_siteaddressline1,pinswg_siteaddressline2,pinswg_siteaddresspostcode,pinswg_siteaddresstown,_pinswg_associatedlpa_value,pinswg_casedecisiondate,pinswg_dateeventrequested,pinswg_decision,pinswg_finalcommentsduedate,pinswg_otherpartiesstatement,pinswg_procedure,pinswg_questionnaireduedate,pinswg_startdates,pinswg_statementduedate,statuscode,pinswg_startdateoftheevent,pinswg_typeofevent";
|
||||
return "&$select=pinswg_detailedeiascreeningrequired,modifiedon,_pinswg_appellant_value,pinswg_name,pinswg_siteaddressline1,pinswg_siteaddressline2,pinswg_siteaddresspostcode,pinswg_siteaddresstown,_pinswg_associatedlpa_value,pinswg_casedecisiondate,pinswg_dateeventrequested,pinswg_decision,pinswg_finalcommentsduedate,pinswg_otherpartiesstatement,pinswg_procedure,pinswg_questionnaireduedate,pinswg_startdates,pinswg_statementduedate,statuscode,pinswg_startdateoftheevent,pinswg_typeofevent";
|
||||
break;
|
||||
case "pinswg_lawfuldevelopmentcertificates":
|
||||
return "&$select=modifiedon,_pinswg_appellant_value,pinswg_name,pinswg_siteaddressline1,pinswg_siteaddressline2,pinswg_siteaddresspostcode,pinswg_siteaddresstown,_pinswg_associatedlpa_value,pinswg_casedecisiondate,pinswg_dateeventrequested,pinswg_decision,pinswg_finalcommentsduedate,pinswg_otherpartiesstatements,pinswg_procedure,pinswg_questionnaireduedate,pinswg_startdate,pinswg_statementduedate,statuscode,pinswg_startdateoftheevent,pinswg_typeofevent";
|
||||
return "&$select=pinswg_detailedeiascreeningrequiered,modifiedon,_pinswg_appellant_value,pinswg_name,pinswg_siteaddressline1,pinswg_siteaddressline2,pinswg_siteaddresspostcode,pinswg_siteaddresstown,_pinswg_associatedlpa_value,pinswg_casedecisiondate,pinswg_dateeventrequested,pinswg_decision,pinswg_finalcommentsduedate,pinswg_otherpartiesstatements,pinswg_procedure,pinswg_questionnaireduedate,pinswg_startdate,pinswg_statementduedate,statuscode,pinswg_startdateoftheevent,pinswg_typeofevent";
|
||||
break;
|
||||
case "pinswg_listedbuildingandconservationareaconsens":
|
||||
return "&$select=modifiedon,_pinswg_appellant_value,pinswg_name,pinswg_siteaddressline1,pinswg_siteaddressline2,pinswg_sitepostcode,pinswg_siteaddresstown,_pinswg_associatedlpa_value,pinswg_casedecisiondate,pinswg_dateeventrequested,pinswg_decision,pinswg_finalcommentsduedate,pinswg_otherpartiesstatement,pinswg_procedure,pinswg_questionnaireduedate,pinswg_startdate,pinswg_statementduedate,statuscode,pinswg_starttimeofevent,pinswg_typeofevent";
|
||||
return "&$select=pinswg_detailedeiascreeningrequiered,modifiedon,_pinswg_appellant_value,pinswg_name,pinswg_siteaddressline1,pinswg_siteaddressline2,pinswg_sitepostcode,pinswg_siteaddresstown,_pinswg_associatedlpa_value,pinswg_casedecisiondate,pinswg_dateeventrequested,pinswg_decision,pinswg_finalcommentsduedate,pinswg_otherpartiesstatement,pinswg_procedure,pinswg_questionnaireduedate,pinswg_startdate,pinswg_statementduedate,statuscode,pinswg_starttimeofevent,pinswg_typeofevent";
|
||||
break;
|
||||
case "pinswg_planningappeals78s":
|
||||
//console.log(
|
||||
@@ -55,17 +60,17 @@ export const getSelectQuery = (appealTypeName) => {
|
||||
// process.env.RELAYPATH == "test-pedw-hc"
|
||||
// );
|
||||
return process.env.RELAYPATH == "dev-pedw-hc"
|
||||
? "&$select=modifiedon,_pinswg_appellant_value,pinswg_name,pinswg_siteaddressline1,pinswg_siteaddressline2,pinswg_siteaddresspostcode,pinswg_siteaddresstown,_pinswg_localplanningauthority_value,pinswg_casedecisiondate,pinswg_dicision,pinswg_dateeventrequested,pinswg_finalcommentsduedate,pinswg_procedure,pinswg_questionnaireduedate,pinswg_startdate,pinswg_statementduedate,statuscode,pinswg_startdatetimeiftheevent,pinswg_representation_period_end_date,pinswg_extend_representation_date,pinswg_typeofevent"
|
||||
: "&$select=modifiedon,_pinswg_appellant_value,pinswg_name,pinswg_siteaddressline1,pinswg_siteaddressline2,pinswg_siteaddresspostcode,pinswg_siteaddresstown,_pinswg_localplanningauthority_value,pinswg_casedecisiondate,pinswg_dicision,pinswg_dateeventrequested,pinswg_finalcommentsduedate,pinswg_procedure,pinswg_questionnaireduedate,pinswg_startdate,pinswg_statementduedate,statuscode,pinswg_startdatetimeiftheevent,pinswg_typeofevent";
|
||||
? "&$select=pinswg_eiarequired,modifiedon,_pinswg_appellant_value,pinswg_name,pinswg_siteaddressline1,pinswg_siteaddressline2,pinswg_siteaddresspostcode,pinswg_siteaddresstown,pinswg_siteaddresscounty,_pinswg_localplanningauthority_value,pinswg_casedecisiondate,pinswg_dicision,pinswg_dateeventrequested,pinswg_finalcommentsduedate,pinswg_procedure,pinswg_questionnaireduedate,pinswg_startdate,pinswg_statementduedate,statuscode,pinswg_startdatetimeiftheevent,pinswg_representation_period_end_date,pinswg_extend_representation_date,pinswg_typeofevent"
|
||||
: "&$select=pinswg_eiarequired,modifiedon,_pinswg_appellant_value,pinswg_name,pinswg_siteaddressline1,pinswg_siteaddressline2,pinswg_siteaddresspostcode,pinswg_siteaddresstown,pinswg_siteaddresscounty,_pinswg_localplanningauthority_value,pinswg_casedecisiondate,pinswg_dicision,pinswg_dateeventrequested,pinswg_finalcommentsduedate,pinswg_procedure,pinswg_questionnaireduedate,pinswg_startdate,pinswg_statementduedate,statuscode,pinswg_startdatetimeiftheevent,pinswg_typeofevent,pinswg_developmentdescription,pinswg_whyisinspectorneededonsite,pinswg_outlinehealthandsafetyissuesonsite,pinswg_additionalappealsmadedetails,pinswg_chosenprocedureexplanation,pinswg_dateofapplication,pinswg_lpaapplicationreference,pinswg_caseworkreason,pinswg_dateoflpadecision,pinswg_areaofsiteinhectaresdec,pinswg_floorspaceinsquaremeters,pinswg_ownershipcertificate,pinswg_siteviewablefromroad,pinswg_costappliedforindicator,pinswg_s106unilateralsubmitted";
|
||||
break;
|
||||
case "pinswg_planningconditionss73s79s":
|
||||
return "&$select=modifiedon,_pinswg_appellant_value,pinswg_name,pinswg_siteaddressline1,pinswg_siteaddressline2,pinswg_siteaddresspostcode,pinswg_siteaddresstown,_pinswg_associatedlpa_value,pinswg_casedecisiondate,pinswg_dateeventrequested,pinswg_decision,pinswg_finalcommentsduedate,pinswg_otherpartiesstatement,pinswg_procedure,pinswg_questionnaireduedate,pinswg_startdate,pinswg_statementduedate,statuscode,pinswg_startdateofevent,pinswg_typeofevent";
|
||||
return "&$select=pinswg_detailedeiascreeningrequiered,modifiedon,_pinswg_appellant_value,pinswg_name,pinswg_siteaddressline1,pinswg_siteaddressline2,pinswg_siteaddresspostcode,pinswg_siteaddresstown,_pinswg_associatedlpa_value,pinswg_casedecisiondate,pinswg_dateeventrequested,pinswg_decision,pinswg_finalcommentsduedate,pinswg_otherpartiesstatement,pinswg_procedure,pinswg_questionnaireduedate,pinswg_startdate,pinswg_statementduedate,statuscode,pinswg_startdateofevent,pinswg_typeofevent";
|
||||
break;
|
||||
case "pinswg_planningobligationappeals106s":
|
||||
return "&$select=modifiedon,_pinswg_appellant_value,pinswg_name,pinswg_siteaddressline1,pinswg_siteaddressline2,pinswg_siteaddresspostcode,pinswg_siteaddresstown,_pinswg_associatedlpa_value,pinswg_casedecisiondate,pinswg_dateeventrequested,pinswg_decision,pinswg_finalcommentsduedate,pinswg_otherpartiesstatements,pinswg_procedure,pinswg_questionnaireduedate,pinswg_startdate,pinswg_statementduedate,statuscode,pinswg_startdateoftheevent,pinswg_typeofevent";
|
||||
return "&$select=pinswg_detailedeiascreeningrequired,modifiedon,_pinswg_appellant_value,pinswg_name,pinswg_siteaddressline1,pinswg_siteaddressline2,pinswg_siteaddresspostcode,pinswg_siteaddresstown,_pinswg_associatedlpa_value,pinswg_casedecisiondate,pinswg_dateeventrequested,pinswg_decision,pinswg_finalcommentsduedate,pinswg_otherpartiesstatements,pinswg_procedure,pinswg_questionnaireduedate,pinswg_startdate,pinswg_statementduedate,statuscode,pinswg_startdateoftheevent,pinswg_typeofevent";
|
||||
break;
|
||||
case "pinswg_rows":
|
||||
return "&$select=pinswg_specialistcaseprocess,modifiedon,_pinswg_appellant_value,pinswg_name,pinswg_siteaddressline1,pinswg_siteaddressline2,pinswg_siteaddresspostcode,pinswg_siteaddresstown,_pinswg_associatedlpa_value,pinswg_casedecisiondate,pinswg_dateeventrequested,pinswg_decision,pinswg_finalcommentsduedate,pinswg_otherpartiesstatement,pinswg_procedure,pinswg_proofsofevidencewrittenstatementsofeviden,pinswg_questionnaireduedate,pinswg_relevantauthorityname,pinswg_startdate,statuscode,pinswg_startdateoftheevent,pinswg_typeofevent,pinswg_statementduedate,pinswg_specialistcaseprocess";
|
||||
return "&$select=pinswg_detailedeiascreeningrequired,pinswg_specialistcaseprocess,modifiedon,_pinswg_appellant_value,pinswg_name,pinswg_siteaddressline1,pinswg_siteaddressline2,pinswg_siteaddresspostcode,pinswg_siteaddresstown,_pinswg_associatedlpa_value,pinswg_casedecisiondate,pinswg_dateeventrequested,pinswg_decision,pinswg_finalcommentsduedate,pinswg_otherpartiesstatement,pinswg_procedure,pinswg_proofsofevidencewrittenstatementsofeviden,pinswg_questionnaireduedate,pinswg_relevantauthorityname,pinswg_startdate,statuscode,pinswg_startdateoftheevent,pinswg_typeofevent,pinswg_statementduedate,pinswg_specialistcaseprocess";
|
||||
break;
|
||||
case "pinswg_ldps":
|
||||
return "&$select=modifiedon,pinswg_name";
|
||||
@@ -73,6 +78,12 @@ export const getSelectQuery = (appealTypeName) => {
|
||||
case "pinswg_nonvalidations":
|
||||
return "&$select=modifiedon,_pinswg_appellant_value,pinswg_name,pinswg_siteaddressline1,pinswg_siteaddressline2,pinswg_siteaddresspostcode,pinswg_siteaddresstown,_pinswg_associatedlpa_value,statuscode";
|
||||
break;
|
||||
case "pinswg_transportandworkacts":
|
||||
return "&$select=pinswg_eiarequired,pinswg_anticipatedgridreferenceeastingtext,pinswg_anticipatedgridreferencenorthingtext,_pinswg_appellant_value,pinswg_name,pinswg_addressline1,pinswg_addressline2,pinswg_postcode,pinswg_addresstown,_pinswg_associatedlpa_value,pinswg_addresscounty,pinswg_applicationacceptedasvalid,pinswg_applicationrejectedasinvalid,pinswg_choiceofprocedure,pinswg_confirmrequesttovaryapplication,pinswg_dateeventrequested,pinswg_dateofdecision,pinswg_dateofrequesttovarytheapplication,pinswg_dateofsubmissionofapplication,pinswg_dateprojectpublishedonwebsite,pinswg_deadlineforsubmissionofapplication,pinswg_endofrepresentationperiod,pinswg_inspectorreportsubmittedtowelshgovernment,pinswg_procedureconfirmed,pinswg_projectdescription,pinswg_projectlocation,pinswg_recommendation,pinswg_rejectrequesttovaryapplication,pinswg_reportdueby,pinswg_suspensiondates,pinswg_suspensionenddates,pinswg_suspensionstartdate,pinswg_validnoticeofintentiontosubmitanapplicati,pinswg_webaddress,pinswg_withdrawndate,pinswg_writtenacceptanceofnotification,statuscode,pinswg_startdateofevent,pinswg_typeofevent";
|
||||
case "pinswg_sipses":
|
||||
// return "&$select=pinswg_anticipatedgridreferenceeastingtext,pinswg_anticipatedgridreferencenorthingtext,_pinswg_appellant_value,pinswg_name,pinswg_addressline1,pinswg_addressline2,pinswg_postcode,pinswg_addresstown,_pinswg_associatedlpa_value,pinswg_addresscounty,pinswg_applicationacceptedasvalid,pinswg_applicationrejectedasinvalid,pinswg_choiceofprocedure,pinswg_confirmrequesttovaryapplication,pinswg_dateeventrequested,pinswg_dateofdecision,pinswg_dateofrequesttovarytheapplication,pinswg_dateofsubmissionofapplication,pinswg_dateprojectpublishedonwebsite,pinswg_deadlineforsubmissionofapplication,pinswg_decision,pinswg_endofrepresentationperiod,pinswg_inspectorreportsubmittedtowelshgovernment,pinswg_procedureconfirmed,pinswg_projectdescription,pinswg_projectlocation,pinswg_recommendation,pinswg_rejectrequesttovaryapplication,pinswg_reportdueby,pinswg_suspensiondates,pinswg_suspensionenddates,pinswg_suspensionstartdates,pinswg_validnoticeofintentiontosubmitanapplicati,pinswg_webaddress,pinswg_withdrawndate,pinswg_writtenacceptanceofnotification,statuscode,_pinswg_dnsids_value,pinswg_startdateofevent,pinswg_typeofevent";
|
||||
return "&$select=pinswg_casedeadline,pinswg_sipseiarequired,pinswg_anticipatedgridrefeasting,pinswg_anticipatedgridrefnorthing,_pinswg_appellant_value,pinswg_name,_pinswg_associatedlpa_value,pinswg_choiceofprocedure,pinswg_decision,pinswg_projectdescription,pinswg_projectlocation,pinswg_recommendation,statuscode,_pinswg_sipscase_value,pinswg_writtenacceptanceofnotification,pinswg_validnoticeofintentiontosubmit,pinswg_deadlineforsubmissionofapplication,pinswg_screeningstartdate,pinswg_eiatargetdate,pinswg_targetextended,pinswg_directionissueddate,pinswg_scopingstartdate,pinswg_scopingtargetdate,pinswg_scopingtargetextended,pinswg_scopingoutcomeissueddate,pinswg_essubmitted,pinswg_deemedmarinelicenseappliedfor,pinswg_validationdeadlineextension,pinswg_consultationopen,pinswg_consultationclose,pinswg_reportissuedtowelshministers,pinswg_decisionissuedtoapplicant,pinswg_decisionoutcome,pinswg_redetermination,pinswg_redeterminationconsultationdeadline,pinswg_reportdeadline,pinswg_casesubmissiondate,pinswg_preexaminationmeetingneeded,pinswg_consultaionpublicitydeadline,pinswg_endofexaminationstartofreporting,pinswg_compulsoryacquisitionvariationsubmitted,pinswg_compulsoryacquisitionvariationaccepted,pinswg_schemeorderamendmentrequestaccepted,pinswg_schemeorderamendmentrequestsubmitted";
|
||||
break;
|
||||
default:
|
||||
return "";
|
||||
break;
|
||||
|
||||
@@ -0,0 +1,108 @@
|
||||
import { BASE_URL } from "../core/env";
|
||||
import { consoleLogger } from "../core/logger";
|
||||
import { getJson, requestJson } from "../clients/endpointClient";
|
||||
import { getSignedJson } from "../clients/signedRequestClient";
|
||||
|
||||
export const getPersonalAccount = (contactid) => {
|
||||
return getJson(
|
||||
BASE_URL + "/api/endpoint/getpersonalaccount_api?contactid=" + contactid
|
||||
).catch((error) => {
|
||||
consoleLogger(error);
|
||||
});
|
||||
};
|
||||
|
||||
export const getLogin = (emailAddress, pwd) => {
|
||||
return getJson(
|
||||
"/api/endpoint/getlogin_api?emailAddress=" +
|
||||
emailAddress +
|
||||
"&pwd=" +
|
||||
pwd
|
||||
).catch((error) => {
|
||||
consoleLogger(error);
|
||||
});
|
||||
};
|
||||
|
||||
export const updatePassword = (contactId, newpassword) => {
|
||||
var queryUrl = "/api/endpoint/updateaccount_api?contactId=" + contactId;
|
||||
var data = { "pinswg_custom_password": newpassword };
|
||||
var config = {
|
||||
method: "post",
|
||||
url: queryUrl,
|
||||
data: data
|
||||
};
|
||||
|
||||
return requestJson(config).catch((error) => {
|
||||
consoleLogger(error);
|
||||
});
|
||||
};
|
||||
|
||||
export const updateAccount = async (contactId, updateBody, ssr) => {
|
||||
var queryUrl =
|
||||
(ssr ? BASE_URL : "") +
|
||||
"/api/endpoint/updateaccount_api?contactId=" +
|
||||
contactId;
|
||||
var data = updateBody;
|
||||
var config = {
|
||||
method: "post",
|
||||
url: queryUrl,
|
||||
data: data
|
||||
};
|
||||
return requestJson(config).catch((error) => {
|
||||
consoleLogger(error);
|
||||
});
|
||||
};
|
||||
|
||||
export const createAccount = (formValues) => {
|
||||
var data = formValues;
|
||||
var queryUrl = "/api/endpoint/createaccount_api";
|
||||
var config = {
|
||||
method: "post",
|
||||
url: queryUrl,
|
||||
data: data
|
||||
};
|
||||
|
||||
return requestJson(config).catch((error) => {
|
||||
consoleLogger(error);
|
||||
});
|
||||
};
|
||||
|
||||
export const getEmailAccountCheck = (emailAddress) => {
|
||||
return getJson(
|
||||
"/api/endpoint/getemailaccountcheck_api?emailAddress=" + emailAddress
|
||||
).catch((error) => {
|
||||
consoleLogger(error);
|
||||
});
|
||||
};
|
||||
|
||||
export const getPortalLogin = async (emailAddress) => {
|
||||
var queryUrl =
|
||||
"/api/endpoint/getportallogin_api?emailAddress=" + emailAddress;
|
||||
|
||||
return getSignedJson(queryUrl, { baseUrl: BASE_URL }).catch((error) => {
|
||||
consoleLogger(error);
|
||||
|
||||
return JSON.stringify(error);
|
||||
});
|
||||
};
|
||||
|
||||
export const getPortalLoginProxy = async (emailAddress) => {
|
||||
var queryUrl =
|
||||
"/api/endpoint/getportalloginproxy_api?emailAddress=" + emailAddress;
|
||||
|
||||
return getJson(queryUrl).catch((error) => {
|
||||
consoleLogger(error);
|
||||
|
||||
return JSON.stringify(error);
|
||||
});
|
||||
};
|
||||
|
||||
export const getPreferredLanguage = async (email) => {
|
||||
return getJson(
|
||||
BASE_URL +
|
||||
"/api/endpoint/getpreferredlanguage_api?emailAddress=" +
|
||||
email
|
||||
).catch((error) => {
|
||||
consoleLogger(error);
|
||||
return error.response;
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,23 @@
|
||||
import {
|
||||
getPersonalAccount,
|
||||
getLogin,
|
||||
updatePassword,
|
||||
updateAccount,
|
||||
createAccount,
|
||||
getEmailAccountCheck,
|
||||
getPortalLogin,
|
||||
getPortalLoginProxy,
|
||||
getPreferredLanguage
|
||||
} from "./accountDirectService";
|
||||
|
||||
export {
|
||||
getPersonalAccount,
|
||||
getLogin,
|
||||
updatePassword,
|
||||
updateAccount,
|
||||
createAccount,
|
||||
getEmailAccountCheck,
|
||||
getPortalLogin,
|
||||
getPortalLoginProxy,
|
||||
getPreferredLanguage
|
||||
};
|
||||
@@ -0,0 +1,87 @@
|
||||
import { BASE_URL } from "../core/env";
|
||||
import { logAndReturnResponse } from "./httpServiceUtils";
|
||||
import { getJson } from "../clients/endpointClient";
|
||||
|
||||
export const getNewAppeals = async (searchString) => {
|
||||
try {
|
||||
return await getJson(BASE_URL + "/api/admin/getnewappeals_api");
|
||||
} catch (error) {
|
||||
return logAndReturnResponse(error);
|
||||
}
|
||||
};
|
||||
|
||||
export const getNewAppealsPage = async (
|
||||
searchString,
|
||||
pageNumber,
|
||||
orderBy,
|
||||
fieldSort,
|
||||
showNumberOfRecords
|
||||
) => {
|
||||
try {
|
||||
return await getJson(
|
||||
"/api/admin/getnewappeals_api?searchString=" +
|
||||
searchString +
|
||||
"&pageNumber=" +
|
||||
pageNumber +
|
||||
"&orderby=" +
|
||||
orderBy +
|
||||
"&fieldSort=" +
|
||||
fieldSort +
|
||||
"&showNumberOfRecords=" +
|
||||
showNumberOfRecords
|
||||
);
|
||||
} catch (error) {
|
||||
return logAndReturnResponse(error);
|
||||
}
|
||||
};
|
||||
|
||||
export const getNewDocumentsPaged = async (
|
||||
pageNumber,
|
||||
orderBy,
|
||||
fieldSort,
|
||||
showNumberOfRecords,
|
||||
documentType,
|
||||
documentOrigin,
|
||||
selectedWeeks
|
||||
) => {
|
||||
try {
|
||||
return await getJson(
|
||||
"/api/admin/getlatestdocuments_api?pageNumber=" +
|
||||
pageNumber +
|
||||
"&orderby=" +
|
||||
orderBy +
|
||||
"&fieldSort=" +
|
||||
fieldSort +
|
||||
"&showNumberOfRecords=" +
|
||||
showNumberOfRecords +
|
||||
"&documentType=" +
|
||||
documentType +
|
||||
"&numberWeeks=" +
|
||||
selectedWeeks +
|
||||
"&documentOrigin=" +
|
||||
documentOrigin
|
||||
);
|
||||
} catch (error) {
|
||||
return logAndReturnResponse(error);
|
||||
}
|
||||
};
|
||||
|
||||
export const getStatusByAppeal = async () => {
|
||||
try {
|
||||
return await getJson(
|
||||
BASE_URL + "/api/admin/getStatusCountsByAppeal_api"
|
||||
);
|
||||
} catch (error) {
|
||||
return logAndReturnResponse(error);
|
||||
}
|
||||
};
|
||||
|
||||
export const getStatusByAppealLPA = async () => {
|
||||
try {
|
||||
return await getJson(
|
||||
BASE_URL + "/api/admin/getStatusCountsByAppealAndLPA_api"
|
||||
);
|
||||
} catch (error) {
|
||||
return logAndReturnResponse(error);
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,15 @@
|
||||
import {
|
||||
getNewAppeals,
|
||||
getNewAppealsPage,
|
||||
getNewDocumentsPaged,
|
||||
getStatusByAppeal,
|
||||
getStatusByAppealLPA
|
||||
} from "./adminDirectService";
|
||||
|
||||
export {
|
||||
getNewAppeals,
|
||||
getNewAppealsPage,
|
||||
getNewDocumentsPaged,
|
||||
getStatusByAppeal,
|
||||
getStatusByAppealLPA
|
||||
};
|
||||
@@ -0,0 +1,284 @@
|
||||
import { BASE_URL } from "../core/env";
|
||||
import { consoleLogger } from "../core/logger";
|
||||
import { logAndReturnResponse } from "./httpServiceUtils";
|
||||
import { getJson, requestJson } from "../clients/endpointClient";
|
||||
import { buildFileQuery, withBaseUrl } from "../clients/fileRouteBuilder";
|
||||
|
||||
export const getCaseMessage = (searchString) => {
|
||||
const route = buildFileQuery("/api/cases/get-case-message", {
|
||||
id: searchString
|
||||
});
|
||||
|
||||
return getJson(withBaseUrl(BASE_URL, route)).catch(logAndReturnResponse);
|
||||
};
|
||||
|
||||
export const getIncidentbyID = (searchString) => {
|
||||
const route = buildFileQuery("/api/cases/get-incident-by-id", {
|
||||
searchString
|
||||
});
|
||||
|
||||
return getJson(withBaseUrl(BASE_URL, route)).catch(logAndReturnResponse);
|
||||
};
|
||||
|
||||
export const getIsPublishedbyID = (searchString) => {
|
||||
const route = buildFileQuery("/api/endpoint/getispublishedbyid_api", {
|
||||
searchString
|
||||
});
|
||||
|
||||
return getJson(route).catch(logAndReturnResponse);
|
||||
};
|
||||
|
||||
export const getPartSavedAppeal = (searchString) => {
|
||||
const route = buildFileQuery("/api/endpoint/getpartsavedappeal_api", {
|
||||
searchString
|
||||
});
|
||||
|
||||
return getJson(withBaseUrl(BASE_URL, route)).catch(logAndReturnResponse);
|
||||
};
|
||||
|
||||
export const getSIPSEvents = async (caseid) => {
|
||||
const route = buildFileQuery("/api/cases/get-sips-events", {
|
||||
caseid
|
||||
});
|
||||
|
||||
return getJson(withBaseUrl(BASE_URL, route)).catch(logAndReturnResponse);
|
||||
};
|
||||
|
||||
export const getSIPSMedia = async (caseid) => {
|
||||
const route = buildFileQuery("/api/cases/get-sips-media", {
|
||||
caseid
|
||||
});
|
||||
|
||||
return getJson(withBaseUrl(BASE_URL, route)).catch(logAndReturnResponse);
|
||||
};
|
||||
|
||||
export const getAppealID = (
|
||||
caseReference,
|
||||
updateFormCollection,
|
||||
primaryAttribute
|
||||
) => {
|
||||
const route = buildFileQuery("/api/endpoint/getappealid_api", {
|
||||
updateFormCollection,
|
||||
primaryAttribute,
|
||||
caseReference
|
||||
});
|
||||
|
||||
return getJson(route)
|
||||
.then((data) => {
|
||||
const result = Object.entries(data.value[0]).filter(
|
||||
([key]) => !key.startsWith("_")
|
||||
)[0][1];
|
||||
var appealID = result;
|
||||
return appealID;
|
||||
})
|
||||
.catch((error) => {
|
||||
consoleLogger(error);
|
||||
});
|
||||
};
|
||||
|
||||
export const createNewCase = (
|
||||
appealTypeId,
|
||||
lpaID,
|
||||
contactid,
|
||||
createBody,
|
||||
containerName
|
||||
) => {
|
||||
appealTypeId = parseInt(appealTypeId);
|
||||
|
||||
var data = createBody;
|
||||
|
||||
var queryUrl = buildFileQuery("/api/endpoint/createcase_api", {
|
||||
appealTypeId,
|
||||
lpaID,
|
||||
contactid,
|
||||
containername: containerName
|
||||
});
|
||||
|
||||
var config = {
|
||||
method: "post",
|
||||
url: withBaseUrl(BASE_URL, queryUrl),
|
||||
data: data
|
||||
};
|
||||
|
||||
return requestJson(config).catch((error) => {
|
||||
consoleLogger(error);
|
||||
});
|
||||
};
|
||||
|
||||
export const createNewCaseBlob = (
|
||||
appealTypeId,
|
||||
lpaID,
|
||||
contactid,
|
||||
createBody,
|
||||
containerName,
|
||||
lpaName
|
||||
) => {
|
||||
appealTypeId = parseInt(appealTypeId);
|
||||
|
||||
var data = createBody;
|
||||
|
||||
data.pinswg_lpaname = lpaName;
|
||||
data.createdon = new Date();
|
||||
|
||||
var queryUrl = buildFileQuery("/api/file/createcase_api", {
|
||||
appealTypeId,
|
||||
lpaID,
|
||||
contactid,
|
||||
containername: containerName
|
||||
});
|
||||
|
||||
var config = {
|
||||
method: "post",
|
||||
url: queryUrl,
|
||||
data: data
|
||||
};
|
||||
|
||||
return requestJson(config).catch((error) => {
|
||||
consoleLogger(error);
|
||||
});
|
||||
};
|
||||
|
||||
export const updateCase = async (
|
||||
incidentId,
|
||||
updateBody,
|
||||
updateFormCollection,
|
||||
primaryAttribute,
|
||||
caseReference
|
||||
) => {
|
||||
var data = updateBody;
|
||||
|
||||
var appealObj = await getAppealID(
|
||||
caseReference,
|
||||
updateFormCollection,
|
||||
primaryAttribute
|
||||
);
|
||||
|
||||
var queryUrl = buildFileQuery("/api/endpoint/updatecase_api", {
|
||||
updateFormCollection,
|
||||
appealObj
|
||||
});
|
||||
|
||||
var config = {
|
||||
method: "post",
|
||||
url: queryUrl,
|
||||
data: updateBody
|
||||
};
|
||||
|
||||
return requestJson(config).catch((error) => {
|
||||
consoleLogger(error);
|
||||
});
|
||||
};
|
||||
|
||||
export const updateCaseBlob = async (
|
||||
incidentId,
|
||||
updateBody,
|
||||
updateFormCollection,
|
||||
primaryAttribute,
|
||||
caseReference
|
||||
) => {
|
||||
var data = updateBody;
|
||||
|
||||
var appealObj = await getAppealID(
|
||||
caseReference,
|
||||
updateFormCollection,
|
||||
primaryAttribute
|
||||
);
|
||||
|
||||
var queryUrl = buildFileQuery("/api/file/updatecase_api", {
|
||||
updateFormCollection,
|
||||
appealObj
|
||||
});
|
||||
|
||||
var config = {
|
||||
method: "post",
|
||||
url: queryUrl,
|
||||
data: updateBody
|
||||
};
|
||||
|
||||
return requestJson(config).catch((error) => {
|
||||
consoleLogger(error);
|
||||
});
|
||||
};
|
||||
|
||||
export const patchCase = async (incidentid) => {
|
||||
var queryUrl = buildFileQuery("/api/endpoint/patchcase_api", {
|
||||
incidentid
|
||||
});
|
||||
return getJson(queryUrl).catch((error) => {
|
||||
//console.log("this error:", error);
|
||||
});
|
||||
};
|
||||
|
||||
export const getCase = (incidentID) => {
|
||||
const route = buildFileQuery("/api/endpoint/getcase_api", {
|
||||
incidentID
|
||||
});
|
||||
|
||||
return getJson(withBaseUrl(BASE_URL, route)).catch((error) => {
|
||||
consoleLogger(error);
|
||||
});
|
||||
};
|
||||
|
||||
export const getCaseByID = (incidentID) => {
|
||||
const route = buildFileQuery("/api/endpoint/getcasebyid_api", {
|
||||
incidentID
|
||||
});
|
||||
|
||||
return getJson(withBaseUrl(BASE_URL, route)).catch((error) => {
|
||||
consoleLogger(error);
|
||||
});
|
||||
};
|
||||
|
||||
export const getAppealPDFDocs = (incidentID) => {
|
||||
const route = buildFileQuery("/api/endpoint/getappealpdfdocuments_api", {
|
||||
incidentid: incidentID
|
||||
});
|
||||
|
||||
return getJson(withBaseUrl(BASE_URL, route)).catch((error) => {
|
||||
consoleLogger(error);
|
||||
});
|
||||
};
|
||||
|
||||
export const getAppealPDFDocument = async (incidentid) => {
|
||||
const route = buildFileQuery("/api/endpoint/getappealpdfdocuments_api", {
|
||||
incidentid
|
||||
});
|
||||
|
||||
return getJson(withBaseUrl(BASE_URL, route)).catch((error) => {
|
||||
consoleLogger(error);
|
||||
return error.response;
|
||||
});
|
||||
};
|
||||
|
||||
export const getPortalModuleDetails = async (appealType, caseReference) => {
|
||||
const route = buildFileQuery("/api/myportal/get-portal-module-details", {
|
||||
appealType,
|
||||
caseReference: encodeURI(caseReference)
|
||||
});
|
||||
|
||||
return getJson(withBaseUrl(BASE_URL, route)).catch((error) => {
|
||||
consoleLogger(error);
|
||||
});
|
||||
};
|
||||
|
||||
export const getPortalModuleDetailsProxy = (appealType, caseReference) => {
|
||||
const route = buildFileQuery(
|
||||
"/api/endpoint/getportalmoduledetailsproxy_api",
|
||||
{
|
||||
appealType,
|
||||
caseReference: caseReference.replace(/\'/g, "''")
|
||||
}
|
||||
);
|
||||
|
||||
return getJson(route).catch((error) => {
|
||||
consoleLogger(error);
|
||||
});
|
||||
};
|
||||
|
||||
export const getCaseStatus = async (appealType, caseReference) => {
|
||||
const route = buildFileQuery("/api/endpoint/getStatusCounts_api", {});
|
||||
|
||||
return getJson(withBaseUrl(BASE_URL, route)).catch((error) => {
|
||||
consoleLogger(error);
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,43 @@
|
||||
import {
|
||||
getCaseMessage,
|
||||
getIncidentbyID,
|
||||
getSIPSEvents,
|
||||
getSIPSMedia,
|
||||
getAppealID,
|
||||
createNewCase,
|
||||
createNewCaseBlob,
|
||||
updateCase,
|
||||
updateCaseBlob,
|
||||
patchCase,
|
||||
getCase,
|
||||
getCaseByID,
|
||||
getAppealPDFDocs,
|
||||
getAppealPDFDocument,
|
||||
getPartSavedAppeal,
|
||||
getIsPublishedbyID,
|
||||
getPortalModuleDetails,
|
||||
getPortalModuleDetailsProxy,
|
||||
getCaseStatus
|
||||
} from "./caseDirectService";
|
||||
|
||||
export {
|
||||
getCaseMessage,
|
||||
getIncidentbyID,
|
||||
getSIPSEvents,
|
||||
getSIPSMedia,
|
||||
getAppealID,
|
||||
createNewCase,
|
||||
createNewCaseBlob,
|
||||
updateCase,
|
||||
updateCaseBlob,
|
||||
patchCase,
|
||||
getCase,
|
||||
getCaseByID,
|
||||
getAppealPDFDocs,
|
||||
getAppealPDFDocument,
|
||||
getPartSavedAppeal,
|
||||
getIsPublishedbyID,
|
||||
getPortalModuleDetails,
|
||||
getPortalModuleDetailsProxy,
|
||||
getCaseStatus
|
||||
};
|
||||
@@ -0,0 +1,394 @@
|
||||
import { BASE_URL } from "../core/env";
|
||||
import { consoleLogger } from "../core/logger";
|
||||
import { hashAPIPath } from "../core/hash";
|
||||
import {
|
||||
buildFileQuery,
|
||||
withBaseUrl,
|
||||
appendQuerySuffix,
|
||||
appendHashSuffix
|
||||
} from "../clients/fileRouteBuilder";
|
||||
import {
|
||||
getFileJson,
|
||||
getSignedFileJson,
|
||||
downloadFileBlob,
|
||||
postSignedFileJson
|
||||
} from "../clients/fileClient";
|
||||
|
||||
const MAX_FILES_PER_UPLOAD_BATCH = 10;
|
||||
|
||||
export const getAwaitingSubmissionFromBlob = (containerName) => {
|
||||
const route = buildFileQuery("/api/file/getawaitingsubmissionfromblob", {
|
||||
container: containerName
|
||||
});
|
||||
|
||||
return getFileJson(
|
||||
withBaseUrl(BASE_URL, appendHashSuffix(route, hashAPIPath))
|
||||
).catch((error) => {
|
||||
consoleLogger(error);
|
||||
});
|
||||
};
|
||||
|
||||
export const getRepsFromBlob = (containerName) => {
|
||||
const route = buildFileQuery("/api/file/getrepsblob", {
|
||||
container: containerName
|
||||
});
|
||||
|
||||
return getFileJson(
|
||||
withBaseUrl(BASE_URL, appendHashSuffix(route, hashAPIPath))
|
||||
).catch((error) => {
|
||||
consoleLogger(error);
|
||||
});
|
||||
};
|
||||
|
||||
export const getRepsFromBlobProxy = async (containerName) => {
|
||||
const route = buildFileQuery("/api/file/getrepsblobproxy", {
|
||||
container: containerName
|
||||
});
|
||||
|
||||
return getFileJson(route).catch((error) => {
|
||||
consoleLogger(error);
|
||||
});
|
||||
};
|
||||
|
||||
export const getAwaitingSubmissionFromBlobProxy = async (containerName) => {
|
||||
const route = buildFileQuery(
|
||||
"/api/file/getawaitingsubmissionfromblobproxy",
|
||||
{
|
||||
container: containerName
|
||||
}
|
||||
);
|
||||
|
||||
return getFileJson(withBaseUrl(BASE_URL, route)).catch((error) => {
|
||||
consoleLogger(error);
|
||||
});
|
||||
};
|
||||
|
||||
export const getFilesFromBlobproxy = (containerName, casefolderID) => {
|
||||
const route = buildFileQuery("/api/file/getbloblistproxy", {
|
||||
container: containerName,
|
||||
casefolderID
|
||||
});
|
||||
|
||||
return getFileJson(route).catch((error) => {
|
||||
consoleLogger(error);
|
||||
});
|
||||
};
|
||||
|
||||
export const deleteAwaitingSubmissionsFromBlob = (
|
||||
containerID,
|
||||
casefolderID
|
||||
) => {
|
||||
var queryUrl = buildFileQuery("/api/file/deleteblobcase", {
|
||||
container: containerID,
|
||||
casefolderID
|
||||
});
|
||||
|
||||
return getSignedFileJson(queryUrl).catch((error) => {
|
||||
consoleLogger(error);
|
||||
});
|
||||
};
|
||||
|
||||
export const deleteMyRepresentationsFromBlob = (
|
||||
containerID,
|
||||
casefolderID,
|
||||
repfile
|
||||
) => {
|
||||
var queryUrl = buildFileQuery("/api/file/deleteblobrep", {
|
||||
container: containerID,
|
||||
casefolderID,
|
||||
repfile
|
||||
});
|
||||
|
||||
return getSignedFileJson(queryUrl).catch((error) => {
|
||||
consoleLogger(error);
|
||||
});
|
||||
};
|
||||
|
||||
export const uploadFiles = async (
|
||||
formValues,
|
||||
filesObj,
|
||||
containerID,
|
||||
casefolderID
|
||||
) => {
|
||||
let files = filesObj;
|
||||
|
||||
var formData = new FormData();
|
||||
formData.append("appealData", JSON.stringify(formValues));
|
||||
formData.append("containerID", containerID);
|
||||
formData.append("casefolderID", casefolderID);
|
||||
|
||||
for (let i = 0; i < files.length; i++) {
|
||||
for (let j = 0; j < files[i].length; j++) {
|
||||
formData.append(files[i][j].name, files[i][j]);
|
||||
}
|
||||
}
|
||||
|
||||
var queryUrl = "/api/file/upload";
|
||||
|
||||
try {
|
||||
return await postSignedFileJson(queryUrl, formData);
|
||||
} catch (error) {
|
||||
consoleLogger(error);
|
||||
}
|
||||
};
|
||||
|
||||
export const uploadSingleFile = async (
|
||||
filesObj,
|
||||
containerID,
|
||||
casefolderID,
|
||||
options = {}
|
||||
) => {
|
||||
let files = filesObj;
|
||||
try {
|
||||
const queryUrl = "/api/file/uploadsinglefile";
|
||||
const uploadResponse = {
|
||||
data: [],
|
||||
invalidFiles: []
|
||||
};
|
||||
let cumulativeUploaded = 0;
|
||||
let cumulativeInvalid = 0;
|
||||
const totalFiles = files.length;
|
||||
const totalChunks = Math.ceil(totalFiles / MAX_FILES_PER_UPLOAD_BATCH);
|
||||
|
||||
for (
|
||||
let index = 0;
|
||||
index < files.length;
|
||||
index += MAX_FILES_PER_UPLOAD_BATCH
|
||||
) {
|
||||
const chunkIndex =
|
||||
Math.floor(index / MAX_FILES_PER_UPLOAD_BATCH) + 1;
|
||||
const fileChunk = files.slice(
|
||||
index,
|
||||
index + MAX_FILES_PER_UPLOAD_BATCH
|
||||
);
|
||||
const formData = new FormData();
|
||||
|
||||
formData.append("containerID", containerID);
|
||||
formData.append("casefolderID", casefolderID);
|
||||
|
||||
for (let i = 0; i < fileChunk.length; i++) {
|
||||
formData.append(fileChunk[i].name, fileChunk[i]);
|
||||
}
|
||||
|
||||
const chunkResult = await postSignedFileJson(queryUrl, formData);
|
||||
|
||||
if (Array.isArray(chunkResult?.data)) {
|
||||
uploadResponse.data.push(...chunkResult.data);
|
||||
cumulativeUploaded += chunkResult.data.length;
|
||||
}
|
||||
|
||||
if (Array.isArray(chunkResult?.invalidFiles)) {
|
||||
uploadResponse.invalidFiles.push(...chunkResult.invalidFiles);
|
||||
cumulativeInvalid += chunkResult.invalidFiles.length;
|
||||
}
|
||||
|
||||
if (typeof options.onChunkComplete === "function") {
|
||||
options.onChunkComplete({
|
||||
chunkIndex,
|
||||
totalChunks,
|
||||
totalFiles,
|
||||
cumulativeUploaded,
|
||||
cumulativeInvalid,
|
||||
processedFiles: cumulativeUploaded + cumulativeInvalid
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return uploadResponse;
|
||||
} catch (error) {
|
||||
consoleLogger(error);
|
||||
}
|
||||
};
|
||||
|
||||
export const uploadRepFiles = async (
|
||||
formValues,
|
||||
filesObj,
|
||||
containerID,
|
||||
casefolderID
|
||||
) => {
|
||||
var formData = new FormData();
|
||||
formData.append("appealData", JSON.stringify(formValues));
|
||||
formData.append("containerID", containerID);
|
||||
formData.append("casefolderID", casefolderID);
|
||||
formData.append("repOrAppeal", true);
|
||||
|
||||
var queryUrl = "/api/file/upload";
|
||||
|
||||
try {
|
||||
return await postSignedFileJson(queryUrl, formData);
|
||||
} catch (error) {
|
||||
consoleLogger(error);
|
||||
}
|
||||
};
|
||||
|
||||
export const generateRepPDF = async (
|
||||
formValues,
|
||||
containerID,
|
||||
casefolderID,
|
||||
options = {}
|
||||
) => {
|
||||
var queryUrl =
|
||||
"/api/file/generatepdf" + (options.download ? "?download=true" : "");
|
||||
|
||||
formValues.containerID = containerID;
|
||||
try {
|
||||
return await postSignedFileJson(queryUrl, formValues, {
|
||||
...(options.download ? { responseType: "blob" } : {})
|
||||
});
|
||||
} catch (error) {
|
||||
consoleLogger(error);
|
||||
}
|
||||
};
|
||||
|
||||
export const generateAppealPDF = async (
|
||||
formValues,
|
||||
containerID,
|
||||
casefolderID,
|
||||
appealType,
|
||||
fileList,
|
||||
options = {}
|
||||
) => {
|
||||
Object.assign(formValues, {
|
||||
"filesList": fileList
|
||||
});
|
||||
|
||||
var queryUrl =
|
||||
"/api/file/generateappealpdf?appealType=" +
|
||||
appealType +
|
||||
(options.download ? "&download=true" : "");
|
||||
|
||||
try {
|
||||
return await postSignedFileJson(queryUrl, formValues, {
|
||||
...(options.download ? { responseType: "blob" } : {})
|
||||
});
|
||||
} catch (error) {
|
||||
consoleLogger(error);
|
||||
}
|
||||
};
|
||||
|
||||
export const getFilesFromBlob = (containerName, casefolderID) => {
|
||||
const route = buildFileQuery("/api/file/getbloblist", {
|
||||
container: containerName,
|
||||
casefolderID
|
||||
});
|
||||
|
||||
return getFileJson(
|
||||
withBaseUrl(BASE_URL, appendHashSuffix(route, hashAPIPath))
|
||||
).catch((error) => {
|
||||
consoleLogger(error);
|
||||
});
|
||||
};
|
||||
|
||||
export const getFilesFromBlobHashed = (
|
||||
containerName,
|
||||
getblobshash,
|
||||
casefolderID
|
||||
) => {
|
||||
const route = buildFileQuery("/api/file/getbloblist", {
|
||||
container: containerName,
|
||||
casefolderID
|
||||
});
|
||||
|
||||
return getFileJson(appendQuerySuffix(route, getblobshash)).catch(
|
||||
(error) => {
|
||||
consoleLogger(error);
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
export const deleteBlob = async (
|
||||
containerName,
|
||||
blobName,
|
||||
deleteblobhash,
|
||||
casefolderID
|
||||
) => {
|
||||
const route = buildFileQuery(
|
||||
"/api/file/deleteblob",
|
||||
{
|
||||
container: containerName,
|
||||
casefolderID,
|
||||
blobname: blobName
|
||||
},
|
||||
{
|
||||
encode: true
|
||||
}
|
||||
);
|
||||
|
||||
return getFileJson(appendQuerySuffix(route, deleteblobhash)).catch(
|
||||
(error) => {
|
||||
consoleLogger(error);
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
export const deleteRepBlob = async (
|
||||
containerName,
|
||||
blobName,
|
||||
deleteblobhash,
|
||||
casefolderID,
|
||||
filenamePrefix
|
||||
) => {
|
||||
const route = buildFileQuery(
|
||||
"/api/file/deleteblob",
|
||||
{
|
||||
container: containerName,
|
||||
casefolderID: casefolderID + "/" + filenamePrefix,
|
||||
blobname: blobName
|
||||
},
|
||||
{
|
||||
encode: true
|
||||
}
|
||||
);
|
||||
|
||||
return getFileJson(appendQuerySuffix(route, deleteblobhash)).catch(
|
||||
(error) => {
|
||||
consoleLogger(error);
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
export const downloadBlob = (containerName, blobName) => {
|
||||
const queryUrl = withBaseUrl(
|
||||
BASE_URL,
|
||||
buildFileQuery("/api/file/downloadblob", {
|
||||
container: containerName.toLowerCase(),
|
||||
blobname: blobName
|
||||
})
|
||||
);
|
||||
|
||||
return downloadFileBlob(queryUrl).catch((error) => {
|
||||
consoleLogger(error);
|
||||
});
|
||||
};
|
||||
|
||||
export const getProgressFromBlob = async (containerName, casereference) => {
|
||||
const route = buildFileQuery(
|
||||
"/api/file/getprogressobjblob",
|
||||
{
|
||||
container: containerName,
|
||||
casefolderID: casereference
|
||||
},
|
||||
{
|
||||
encode: true
|
||||
}
|
||||
);
|
||||
|
||||
return getFileJson(
|
||||
withBaseUrl(BASE_URL, appendHashSuffix(route, hashAPIPath))
|
||||
).catch((error) => {
|
||||
consoleLogger(error);
|
||||
});
|
||||
};
|
||||
|
||||
export const createContainerProxy = (containerName) => {
|
||||
var route = buildFileQuery("/api/file/setupcontainer", {
|
||||
ident: containerName
|
||||
});
|
||||
var queryUrl = appendHashSuffix(route, hashAPIPath);
|
||||
|
||||
return getFileJson(withBaseUrl(BASE_URL, queryUrl)).catch((error) => {
|
||||
consoleLogger(error);
|
||||
|
||||
return JSON.stringify(error);
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,43 @@
|
||||
import {
|
||||
getAwaitingSubmissionFromBlob,
|
||||
getRepsFromBlob,
|
||||
getRepsFromBlobProxy,
|
||||
getAwaitingSubmissionFromBlobProxy,
|
||||
deleteAwaitingSubmissionsFromBlob,
|
||||
deleteMyRepresentationsFromBlob,
|
||||
uploadFiles,
|
||||
uploadSingleFile,
|
||||
uploadRepFiles,
|
||||
generateRepPDF,
|
||||
generateAppealPDF,
|
||||
getFilesFromBlob,
|
||||
getFilesFromBlobproxy,
|
||||
getFilesFromBlobHashed,
|
||||
deleteBlob,
|
||||
deleteRepBlob,
|
||||
downloadBlob,
|
||||
getProgressFromBlob,
|
||||
createContainerProxy
|
||||
} from "./documentDirectService";
|
||||
|
||||
export {
|
||||
getAwaitingSubmissionFromBlob,
|
||||
getRepsFromBlob,
|
||||
getRepsFromBlobProxy,
|
||||
getAwaitingSubmissionFromBlobProxy,
|
||||
deleteAwaitingSubmissionsFromBlob,
|
||||
deleteMyRepresentationsFromBlob,
|
||||
uploadFiles,
|
||||
uploadSingleFile,
|
||||
uploadRepFiles,
|
||||
generateRepPDF,
|
||||
generateAppealPDF,
|
||||
getFilesFromBlob,
|
||||
getFilesFromBlobproxy,
|
||||
getFilesFromBlobHashed,
|
||||
deleteBlob,
|
||||
deleteRepBlob,
|
||||
downloadBlob,
|
||||
getProgressFromBlob,
|
||||
createContainerProxy
|
||||
};
|
||||
@@ -0,0 +1,19 @@
|
||||
import { consoleLogger } from "../core/logger";
|
||||
|
||||
export const buildEmptyValueErrorResponse = (error) => {
|
||||
return {
|
||||
value: [],
|
||||
errorCode: error.response.status,
|
||||
errorMsg: error.response.statusText
|
||||
};
|
||||
};
|
||||
|
||||
export const logAndReturnResponse = (error) => {
|
||||
consoleLogger(error);
|
||||
return error.response;
|
||||
};
|
||||
|
||||
export const logAndReturnEmptyValueErrorResponse = (error) => {
|
||||
consoleLogger(error);
|
||||
return buildEmptyValueErrorResponse(error);
|
||||
};
|
||||
@@ -0,0 +1,9 @@
|
||||
export * from "./searchService";
|
||||
export * from "./caseService";
|
||||
export * from "./accountService";
|
||||
export * from "./portalService";
|
||||
export * from "./documentService";
|
||||
export * from "./referenceDataService";
|
||||
export * from "./notifyService";
|
||||
export * from "./adminService";
|
||||
export * from "./integrationService";
|
||||
@@ -0,0 +1,19 @@
|
||||
import { consoleLogger } from "../core/logger";
|
||||
import { requestJson } from "../clients/endpointClient";
|
||||
|
||||
export const createCRMTask = async (formValues) => {
|
||||
var queryUrl = "/api/endpoint/createcrmtask_api";
|
||||
|
||||
var data = formValues;
|
||||
var config = {
|
||||
method: "post",
|
||||
url: queryUrl,
|
||||
data: data
|
||||
};
|
||||
|
||||
try {
|
||||
return await requestJson(config);
|
||||
} catch (error) {
|
||||
consoleLogger(error);
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,3 @@
|
||||
import { createCRMTask } from "./integrationDirectService";
|
||||
|
||||
export { createCRMTask };
|
||||
@@ -0,0 +1,27 @@
|
||||
import { consoleLogger } from "../core/logger";
|
||||
import { requestJson } from "../clients/endpointClient";
|
||||
|
||||
export const sendEmail = async (
|
||||
templateId,
|
||||
emailAddress,
|
||||
personalisation,
|
||||
reference
|
||||
) => {
|
||||
var mailData = {
|
||||
"templateId": templateId,
|
||||
"emailAddress": emailAddress,
|
||||
"reference": reference,
|
||||
"personalisation": personalisation
|
||||
};
|
||||
|
||||
try {
|
||||
return await requestJson({
|
||||
method: "post",
|
||||
url: "/api/email/notify",
|
||||
data: mailData
|
||||
});
|
||||
} catch (error) {
|
||||
consoleLogger(error);
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,3 @@
|
||||
import { sendEmail } from "./notifyDirectService";
|
||||
|
||||
export { sendEmail };
|
||||
@@ -0,0 +1,313 @@
|
||||
import { BASE_URL } from "../core/env";
|
||||
import { consoleLogger } from "../core/logger";
|
||||
import { getJson, requestJson } from "../clients/endpointClient";
|
||||
import {
|
||||
deleteSignedJson,
|
||||
buildSignedUrl
|
||||
} from "../clients/signedRequestClient";
|
||||
import {
|
||||
buildFileQuery,
|
||||
withBaseUrl,
|
||||
appendQuerySuffix
|
||||
} from "../clients/fileRouteBuilder";
|
||||
|
||||
export const getMyCases = (loggedInUserId) => {
|
||||
const route = buildFileQuery("/api/myportal/get-my-cases", {
|
||||
loggedInUserId
|
||||
});
|
||||
|
||||
return getJson(withBaseUrl(BASE_URL, route)).catch((error) => {
|
||||
consoleLogger(error);
|
||||
});
|
||||
};
|
||||
|
||||
export const getMyInvolvements = async (loggedInUserId) => {
|
||||
const route = buildFileQuery("/api/endpoint/getmyinvolvements_api", {
|
||||
loggedInUserId
|
||||
});
|
||||
|
||||
return getJson(withBaseUrl(BASE_URL, route)).catch((error) => {
|
||||
consoleLogger(error);
|
||||
});
|
||||
};
|
||||
|
||||
export const getMyLPACases = (lpaid) => {
|
||||
const route = buildFileQuery("/api/myportal/get-my-lpa-cases", {
|
||||
lpaid
|
||||
});
|
||||
|
||||
return getJson(withBaseUrl(BASE_URL, route)).catch((error) => {
|
||||
consoleLogger(error);
|
||||
});
|
||||
};
|
||||
|
||||
export const getMyRepresentations = (loggedInUserId) => {
|
||||
const route = buildFileQuery("/api/endpoint/getmyrepresentations_api", {
|
||||
loggedInUserId
|
||||
});
|
||||
|
||||
return getJson(withBaseUrl(BASE_URL, route)).catch((error) => {
|
||||
consoleLogger(error);
|
||||
});
|
||||
};
|
||||
|
||||
export const getMyRepresentationsProxy = (loggedInUserId) => {
|
||||
const route = buildFileQuery(
|
||||
"/api/endpoint/getmyrepresentationsproxy_api",
|
||||
{
|
||||
loggedInUserId
|
||||
}
|
||||
);
|
||||
|
||||
return getJson(route).catch((error) => {
|
||||
consoleLogger(error);
|
||||
});
|
||||
};
|
||||
|
||||
export const getRepresentations = (incidentID) => {
|
||||
const route = buildFileQuery("/api/endpoint/getrepresentations_api", {
|
||||
incidentID
|
||||
});
|
||||
|
||||
return getJson(route).catch((error) => {
|
||||
consoleLogger(error);
|
||||
});
|
||||
};
|
||||
|
||||
export const getRepresentationsProxy = (incidentID) => {
|
||||
const route = buildFileQuery("/api/endpoint/getrepresentationsproxy_api", {
|
||||
incidentID
|
||||
});
|
||||
|
||||
return getJson(route).catch((error) => {
|
||||
consoleLogger(error);
|
||||
});
|
||||
};
|
||||
|
||||
export const getWatchedCases = (loggedInUserId) => {
|
||||
const route = buildFileQuery("/api/subscriptions/get-watched-cases", {
|
||||
loggedInUserId
|
||||
});
|
||||
|
||||
return getJson(withBaseUrl(BASE_URL, route)).catch((error) => {
|
||||
consoleLogger(error);
|
||||
});
|
||||
};
|
||||
|
||||
export const getWatchedCasesProxy = (loggedInUserId) => {
|
||||
const route = buildFileQuery("/api/subscriptions/get-watched-cases-proxy", {
|
||||
loggedInUserId
|
||||
});
|
||||
|
||||
return getJson(route).catch((error) => {
|
||||
consoleLogger(error);
|
||||
});
|
||||
};
|
||||
|
||||
export const getAwaitingSubmissionProxy = (loggedInUserId) => {
|
||||
const route = buildFileQuery(
|
||||
"/api/endpoint/getawaitingsubmissionproxy_api",
|
||||
{
|
||||
loggedInUserId
|
||||
}
|
||||
);
|
||||
|
||||
return getJson(route).catch((error) => {
|
||||
consoleLogger(error);
|
||||
});
|
||||
};
|
||||
|
||||
export const getAwaitingSubmission = (loggedInUserId) => {
|
||||
const route = buildFileQuery("/api/endpoint/getawaitingsubmission_api", {
|
||||
loggedInUserId
|
||||
});
|
||||
|
||||
return getJson(withBaseUrl(BASE_URL, route)).catch((error) => {
|
||||
consoleLogger(error);
|
||||
});
|
||||
};
|
||||
|
||||
export const createWatchedCases = async (formValues) => {
|
||||
var data = formValues;
|
||||
var queryUrl = buildFileQuery("/api/subscriptions/create-watched-case");
|
||||
|
||||
var config = {
|
||||
method: "post",
|
||||
url: queryUrl,
|
||||
data: data
|
||||
};
|
||||
|
||||
try {
|
||||
return await requestJson(config);
|
||||
} catch (error) {
|
||||
consoleLogger(error);
|
||||
}
|
||||
};
|
||||
|
||||
export const deleteMyRepresentations = (myRepresentationsID) => {
|
||||
var queryUrl = buildFileQuery("/api/endpoint/deletemyrepresentations_api", {
|
||||
myRepresentationsID
|
||||
});
|
||||
|
||||
return deleteSignedJson(queryUrl, {
|
||||
headers: {
|
||||
"OData-MaxVersion": "4.0",
|
||||
"OData-Version": "4.0",
|
||||
"Accept": "application/json;odata.metadata=none",
|
||||
"Prefer": 'odata.include-annotations="*",return=representation',
|
||||
"Content-Type": "application/json"
|
||||
}
|
||||
}).catch((error) => {
|
||||
consoleLogger(error);
|
||||
});
|
||||
};
|
||||
|
||||
export const deleteAwaitingSubmissions = (incidentID) => {
|
||||
var queryUrl = buildFileQuery(
|
||||
"/api/endpoint/deleteawaitingsubmissions_api",
|
||||
{
|
||||
incidentID
|
||||
}
|
||||
);
|
||||
|
||||
var config = {
|
||||
method: "delete",
|
||||
url: queryUrl
|
||||
};
|
||||
|
||||
return requestJson(config).catch((error) => {
|
||||
consoleLogger(error);
|
||||
});
|
||||
};
|
||||
|
||||
export const deleteWatchedCases = async (watchedCaseID) => {
|
||||
var queryUrl = buildFileQuery("/api/subscriptions/delete-watched-case", {
|
||||
watchedCaseID
|
||||
});
|
||||
|
||||
return deleteSignedJson(queryUrl).catch((error) => {
|
||||
consoleLogger(error);
|
||||
});
|
||||
};
|
||||
|
||||
export const sendCaseCompleteMessage = async (
|
||||
containerID,
|
||||
caseReference,
|
||||
inv
|
||||
) => {
|
||||
var hashQueryPath = buildFileQuery(
|
||||
"/api/file/createappealcompletemessage_api",
|
||||
{
|
||||
container: containerID,
|
||||
tempcaseref: caseReference
|
||||
}
|
||||
);
|
||||
|
||||
var queryUrl = buildFileQuery("/api/file/createappealcompletemessage_api", {
|
||||
container: containerID,
|
||||
tempcaseref: caseReference,
|
||||
inv
|
||||
});
|
||||
|
||||
var signedQueryUrl = await buildSignedUrl(hashQueryPath);
|
||||
|
||||
queryUrl = appendQuerySuffix(
|
||||
queryUrl,
|
||||
signedQueryUrl.replace(hashQueryPath, "")
|
||||
);
|
||||
|
||||
var config = {
|
||||
method: "get",
|
||||
url: queryUrl
|
||||
};
|
||||
|
||||
return requestJson(config).catch((error) => {
|
||||
consoleLogger(error);
|
||||
});
|
||||
};
|
||||
|
||||
export const sendCaseCompleteMessageProxy = async (
|
||||
containerID,
|
||||
caseReference
|
||||
) => {
|
||||
var queryUrl = buildFileQuery(
|
||||
"/api/file/createappealcompletemessageproxy_api",
|
||||
{
|
||||
container: containerID,
|
||||
tempcaseref: caseReference
|
||||
}
|
||||
);
|
||||
|
||||
var config = {
|
||||
method: "get",
|
||||
url: queryUrl
|
||||
};
|
||||
|
||||
return requestJson(config).catch((error) => {
|
||||
consoleLogger(error);
|
||||
});
|
||||
};
|
||||
|
||||
export const sendRepCompleteMessage = async (
|
||||
containerID,
|
||||
caseReference,
|
||||
fileName
|
||||
) => {
|
||||
var hashQueryPath = buildFileQuery(
|
||||
"/api/file/createrepcompletemessage_api",
|
||||
{
|
||||
container: containerID,
|
||||
tempcaseref: caseReference,
|
||||
repid: fileName
|
||||
}
|
||||
);
|
||||
|
||||
var queryUrl = await buildSignedUrl(hashQueryPath);
|
||||
|
||||
var config = {
|
||||
method: "get",
|
||||
url: queryUrl
|
||||
};
|
||||
|
||||
return requestJson(config).catch((error) => {
|
||||
consoleLogger(error);
|
||||
});
|
||||
};
|
||||
|
||||
export const setRepInvolvment = async (caseid, contactid, involvement) => {
|
||||
var queryUrl = buildFileQuery("/api/file/createrepinvolvement_api");
|
||||
|
||||
var data = {
|
||||
"incidentid": caseid,
|
||||
"contactid": contactid,
|
||||
"involvement": involvement
|
||||
};
|
||||
var config = {
|
||||
method: "post",
|
||||
url: queryUrl,
|
||||
data: data
|
||||
};
|
||||
|
||||
try {
|
||||
return await requestJson(config);
|
||||
} catch (error) {
|
||||
consoleLogger(error);
|
||||
}
|
||||
};
|
||||
|
||||
export const setCaseInvolvment = async (caseid, contactid) => {
|
||||
var queryUrl = buildFileQuery("/api/file/createrepinvolvement_api");
|
||||
|
||||
var data = { "incidentid": caseid, "contactid": contactid };
|
||||
var config = {
|
||||
method: "post",
|
||||
url: queryUrl,
|
||||
data: data
|
||||
};
|
||||
|
||||
try {
|
||||
return await requestJson(config);
|
||||
} catch (error) {
|
||||
consoleLogger(error);
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,45 @@
|
||||
import {
|
||||
getMyCases,
|
||||
getMyInvolvements,
|
||||
getMyLPACases,
|
||||
getMyRepresentations,
|
||||
getMyRepresentationsProxy,
|
||||
getRepresentations,
|
||||
getRepresentationsProxy,
|
||||
getWatchedCases,
|
||||
getWatchedCasesProxy,
|
||||
getAwaitingSubmission,
|
||||
getAwaitingSubmissionProxy,
|
||||
createWatchedCases,
|
||||
deleteWatchedCases,
|
||||
deleteMyRepresentations,
|
||||
deleteAwaitingSubmissions,
|
||||
sendCaseCompleteMessage,
|
||||
sendCaseCompleteMessageProxy,
|
||||
sendRepCompleteMessage,
|
||||
setRepInvolvment,
|
||||
setCaseInvolvment
|
||||
} from "./portalDirectService";
|
||||
|
||||
export {
|
||||
getMyCases,
|
||||
getMyInvolvements,
|
||||
getMyLPACases,
|
||||
getMyRepresentations,
|
||||
getMyRepresentationsProxy,
|
||||
getRepresentations,
|
||||
getRepresentationsProxy,
|
||||
getWatchedCases,
|
||||
getWatchedCasesProxy,
|
||||
getAwaitingSubmission,
|
||||
getAwaitingSubmissionProxy,
|
||||
createWatchedCases,
|
||||
deleteWatchedCases,
|
||||
deleteMyRepresentations,
|
||||
deleteAwaitingSubmissions,
|
||||
sendCaseCompleteMessage,
|
||||
sendCaseCompleteMessageProxy,
|
||||
sendRepCompleteMessage,
|
||||
setRepInvolvment,
|
||||
setCaseInvolvment
|
||||
};
|
||||
@@ -0,0 +1,58 @@
|
||||
import { BASE_URL } from "../core/env";
|
||||
import { consoleLogger } from "../core/logger";
|
||||
import { logAndReturnEmptyValueErrorResponse } from "./httpServiceUtils";
|
||||
import { getJson } from "../clients/endpointClient";
|
||||
|
||||
export const getAppealsTypes = () => {
|
||||
return getJson(BASE_URL + "/api/endpoint/getappealtypes_api").catch(
|
||||
logAndReturnEmptyValueErrorResponse
|
||||
);
|
||||
};
|
||||
|
||||
export const getProjectTypes = () => {
|
||||
return getJson(BASE_URL + "/api/endpoint/getprojecttypes_api").catch(
|
||||
logAndReturnEmptyValueErrorResponse
|
||||
);
|
||||
};
|
||||
|
||||
export const getAppealsTypesForNewAppeal = () => {
|
||||
return getJson(
|
||||
BASE_URL + "/api/endpoint/getappealtypesfornewappeal_api"
|
||||
).catch(logAndReturnEmptyValueErrorResponse);
|
||||
};
|
||||
|
||||
export const getLPA = () => {
|
||||
return getJson(BASE_URL + "/api/endpoint/getlpa_api").catch(
|
||||
logAndReturnEmptyValueErrorResponse
|
||||
);
|
||||
};
|
||||
|
||||
export const getFormData = (whichForm) => {
|
||||
return getJson(
|
||||
BASE_URL + "/api/endpoint/getformdata_api?whichForm=" + whichForm
|
||||
).catch((error) => {
|
||||
consoleLogger(error);
|
||||
});
|
||||
};
|
||||
|
||||
export const getMandatoryFields = (whichForm) => {
|
||||
return getJson(
|
||||
BASE_URL + "/api/endpoint/getmandatoryfields_api?whichForm=" + whichForm
|
||||
).catch((error) => {
|
||||
consoleLogger(error);
|
||||
});
|
||||
};
|
||||
|
||||
export const getPickLists = (whichForm) => {
|
||||
return getJson(
|
||||
BASE_URL + "/api/endpoint/getpicklists_api?whichForm=" + whichForm
|
||||
).catch((error) => {
|
||||
consoleLogger(error);
|
||||
});
|
||||
};
|
||||
|
||||
export const getNotice = () => {
|
||||
return getJson(BASE_URL + "/api/notices").catch((error) => {
|
||||
consoleLogger(error);
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,21 @@
|
||||
import {
|
||||
getAppealsTypes,
|
||||
getProjectTypes,
|
||||
getAppealsTypesForNewAppeal,
|
||||
getLPA,
|
||||
getFormData,
|
||||
getMandatoryFields,
|
||||
getPickLists,
|
||||
getNotice
|
||||
} from "./referenceDataDirectService";
|
||||
|
||||
export {
|
||||
getAppealsTypes,
|
||||
getProjectTypes,
|
||||
getAppealsTypesForNewAppeal,
|
||||
getLPA,
|
||||
getFormData,
|
||||
getMandatoryFields,
|
||||
getPickLists,
|
||||
getNotice
|
||||
};
|
||||
@@ -0,0 +1,261 @@
|
||||
import { BASE_URL } from "../core/env";
|
||||
import { consoleLogger } from "../core/logger";
|
||||
import { getJson } from "../clients/endpointClient";
|
||||
import {
|
||||
logAndReturnResponse,
|
||||
logAndReturnEmptyValueErrorResponse
|
||||
} from "./httpServiceUtils";
|
||||
|
||||
export const getBasicSearch = (searchString) => {
|
||||
return getJson(
|
||||
BASE_URL +
|
||||
"/api/endpoint/getbasicsearch_api?searchString=" +
|
||||
searchString
|
||||
).catch(logAndReturnResponse);
|
||||
};
|
||||
|
||||
export const getBasicDNSURLSearch = (searchString) => {
|
||||
return getJson(
|
||||
BASE_URL +
|
||||
"/api/endpoint/getbasicdnsurlsearch_api?searchString=" +
|
||||
searchString
|
||||
).catch(logAndReturnResponse);
|
||||
};
|
||||
|
||||
export const getAddressSearchPaged = (
|
||||
searchString,
|
||||
pageNumber,
|
||||
orderBy,
|
||||
fieldSort,
|
||||
showNumberOfRecords
|
||||
) => {
|
||||
return getJson(
|
||||
"/api/endpoint/getbasicsearch_by_address_paged_api?searchString=" +
|
||||
searchString +
|
||||
"&pageNumber=" +
|
||||
pageNumber +
|
||||
"&orderby=" +
|
||||
orderBy +
|
||||
"&fieldSort=" +
|
||||
fieldSort +
|
||||
"&showNumberOfRecords=" +
|
||||
showNumberOfRecords
|
||||
).catch(logAndReturnResponse);
|
||||
};
|
||||
|
||||
export const getBasicSearchPaged = (
|
||||
searchString,
|
||||
pageNumber,
|
||||
orderBy,
|
||||
fieldSort,
|
||||
showNumberOfRecords
|
||||
) => {
|
||||
return getJson(
|
||||
"/api/search/basic-paged?searchString=" +
|
||||
searchString +
|
||||
"&pageNumber=" +
|
||||
pageNumber +
|
||||
"&orderby=" +
|
||||
orderBy +
|
||||
"&fieldSort=" +
|
||||
fieldSort +
|
||||
"&showNumberOfRecords=" +
|
||||
showNumberOfRecords
|
||||
).catch(logAndReturnResponse);
|
||||
};
|
||||
|
||||
export const getDNSCoords = () => {
|
||||
return getJson(BASE_URL + "/api/endpoint/getdnscoords_api").catch(
|
||||
logAndReturnEmptyValueErrorResponse
|
||||
);
|
||||
};
|
||||
|
||||
export const getDNSList = (searchString) => {
|
||||
return getJson(BASE_URL + "/api/endpoint/getdnslist_api").catch(
|
||||
logAndReturnResponse
|
||||
);
|
||||
};
|
||||
|
||||
export const getBasicDNSSearch = (searchString) => {
|
||||
return getJson(BASE_URL + "/api/endpoint/getbasicdnssearch_api").catch(
|
||||
logAndReturnResponse
|
||||
);
|
||||
};
|
||||
|
||||
export const getBasicDNSSearchPaged = (
|
||||
pageNumber,
|
||||
orderBy,
|
||||
fieldSort,
|
||||
showNumberOfRecords
|
||||
) => {
|
||||
return getJson(
|
||||
"/api/endpoint/getbasicdnssearchpaged_api?pageNumber=" +
|
||||
pageNumber +
|
||||
"&orderby=" +
|
||||
orderBy +
|
||||
"&fieldSort=" +
|
||||
fieldSort +
|
||||
"&showNumberOfRecords=" +
|
||||
showNumberOfRecords
|
||||
).catch(logAndReturnResponse);
|
||||
};
|
||||
|
||||
export const getAdvancedSearch = (searchString) => {
|
||||
return getJson(
|
||||
BASE_URL +
|
||||
"/api/search/advanced?searchstring=" +
|
||||
JSON.stringify(searchString)
|
||||
).catch(logAndReturnEmptyValueErrorResponse);
|
||||
};
|
||||
|
||||
export const getAdvancedSearchPaged = (
|
||||
searchString,
|
||||
pageNumber,
|
||||
orderBy,
|
||||
fieldSort,
|
||||
showNumberOfRecords
|
||||
) => {
|
||||
return getJson(
|
||||
"/api/search/advanced-paged?searchstring=" +
|
||||
JSON.stringify(searchString) +
|
||||
"&pageNumber=" +
|
||||
pageNumber +
|
||||
"&orderby=" +
|
||||
orderBy +
|
||||
"&fieldSort=" +
|
||||
fieldSort +
|
||||
"&showNumberOfRecords=" +
|
||||
showNumberOfRecords
|
||||
).catch(logAndReturnEmptyValueErrorResponse);
|
||||
};
|
||||
|
||||
export const getBasicSearchDetails = async (
|
||||
appealTypeName,
|
||||
caseReference,
|
||||
primaryIdAttribute,
|
||||
incidentID
|
||||
) => {
|
||||
return getJson(
|
||||
BASE_URL +
|
||||
"/api/endpoint/getbasicsearchdetails_api?appealTypeName=" +
|
||||
appealTypeName +
|
||||
"&primaryIdAttribute=" +
|
||||
primaryIdAttribute +
|
||||
"&incidentID=" +
|
||||
incidentID
|
||||
).catch((error) => {
|
||||
consoleLogger(error);
|
||||
});
|
||||
};
|
||||
|
||||
export const getBasicPartSavedDetails = (
|
||||
appealTypeName,
|
||||
caseReference,
|
||||
primaryIdAttribute,
|
||||
incidentID
|
||||
) => {
|
||||
return getJson(
|
||||
BASE_URL +
|
||||
"/api/endpoint/getbasicpartsaveddetails_api?appealTypeName=" +
|
||||
appealTypeName +
|
||||
"&primaryIdAttribute=" +
|
||||
primaryIdAttribute +
|
||||
"&incidentID=" +
|
||||
incidentID
|
||||
).catch((error) => {
|
||||
consoleLogger(error);
|
||||
});
|
||||
};
|
||||
|
||||
export const getBasicSearchDetailsPaged = async (
|
||||
appealTypeName,
|
||||
caseReference,
|
||||
primaryIdAttribute,
|
||||
incidentIDs
|
||||
) => {
|
||||
if (!incidentIDs || incidentIDs.length === 0) return [];
|
||||
|
||||
const filter = incidentIDs
|
||||
.map((id) => {
|
||||
const suffix =
|
||||
primaryIdAttribute === "pinswg_sipscase"
|
||||
? `_${primaryIdAttribute}_value`
|
||||
: `_${primaryIdAttribute}s_value`;
|
||||
|
||||
return `${suffix} eq ${id}`;
|
||||
})
|
||||
.join(" or ");
|
||||
|
||||
const groupedUrl = `/api/search/basic-details-paged?appealTypeName=${appealTypeName}&primaryIdAttribute=${primaryIdAttribute}&incidentID=${encodeURIComponent(
|
||||
filter
|
||||
)}`;
|
||||
|
||||
try {
|
||||
const data = await getJson(groupedUrl);
|
||||
return data.value || [];
|
||||
} catch (error) {
|
||||
consoleLogger(error);
|
||||
return [];
|
||||
}
|
||||
};
|
||||
|
||||
export const getSearchDocumentDetails = (incidentID) => {
|
||||
return getJson(
|
||||
"/api/documents/get-search-document-details?incidentid=" + incidentID
|
||||
).catch((error) => {
|
||||
consoleLogger(error);
|
||||
throw error;
|
||||
});
|
||||
};
|
||||
|
||||
export const getSearchDocumentTypes = (incidentID) => {
|
||||
return getJson(
|
||||
"/api/documents/get-search-document-types?incidentid=" + incidentID
|
||||
).catch((error) => {
|
||||
consoleLogger(error);
|
||||
});
|
||||
};
|
||||
|
||||
export const getSearchDocumentDetailsPaged = (
|
||||
incidentID,
|
||||
pageNumber,
|
||||
orderBy,
|
||||
fieldSort,
|
||||
showNumberOfRecords,
|
||||
documentType
|
||||
) => {
|
||||
return getJson(
|
||||
"/api/documents/get-search-document-details-paged?incidentid=" +
|
||||
incidentID +
|
||||
"&pageNumber=" +
|
||||
pageNumber +
|
||||
"&orderby=" +
|
||||
orderBy +
|
||||
"&fieldSort=" +
|
||||
fieldSort +
|
||||
"&showNumberOfRecords=" +
|
||||
showNumberOfRecords +
|
||||
"&documentType=" +
|
||||
documentType
|
||||
).catch((error) => {
|
||||
consoleLogger(error);
|
||||
});
|
||||
};
|
||||
|
||||
export const getLinkedCases = (parentIncidentid) => {
|
||||
return getJson(
|
||||
"/api/cases/get-linked-cases?parentincidentid=" + parentIncidentid
|
||||
).catch((error) => {
|
||||
consoleLogger(error);
|
||||
});
|
||||
};
|
||||
|
||||
export const getAddressSearch = async (searchString) => {
|
||||
const params = new URLSearchParams(searchString);
|
||||
const str = params.toString();
|
||||
|
||||
var queryUrl =
|
||||
BASE_URL + "/api/endpoint/getbasicsearch_by_address_api?" + str;
|
||||
|
||||
return getJson(queryUrl).catch(logAndReturnEmptyValueErrorResponse);
|
||||
};
|
||||
@@ -0,0 +1,41 @@
|
||||
import {
|
||||
getBasicSearch,
|
||||
getAddressSearch,
|
||||
getAddressSearchPaged,
|
||||
getBasicSearchPaged,
|
||||
getAdvancedSearch,
|
||||
getAdvancedSearchPaged,
|
||||
getBasicDNSURLSearch,
|
||||
getBasicDNSSearch,
|
||||
getBasicDNSSearchPaged,
|
||||
getDNSCoords,
|
||||
getDNSList,
|
||||
getBasicSearchDetails,
|
||||
getBasicSearchDetailsPaged,
|
||||
getBasicPartSavedDetails,
|
||||
getSearchDocumentDetails,
|
||||
getSearchDocumentTypes,
|
||||
getSearchDocumentDetailsPaged,
|
||||
getLinkedCases
|
||||
} from "./searchDirectService";
|
||||
|
||||
export {
|
||||
getBasicSearch,
|
||||
getAddressSearch,
|
||||
getAddressSearchPaged,
|
||||
getBasicSearchPaged,
|
||||
getAdvancedSearch,
|
||||
getAdvancedSearchPaged,
|
||||
getBasicDNSURLSearch,
|
||||
getBasicDNSSearch,
|
||||
getBasicDNSSearchPaged,
|
||||
getDNSCoords,
|
||||
getDNSList,
|
||||
getBasicSearchDetails,
|
||||
getBasicSearchDetailsPaged,
|
||||
getBasicPartSavedDetails,
|
||||
getSearchDocumentDetails,
|
||||
getSearchDocumentTypes,
|
||||
getSearchDocumentDetailsPaged,
|
||||
getLinkedCases
|
||||
};
|
||||
@@ -0,0 +1,57 @@
|
||||
# Refactor Session Handoff (Usable Prompt)
|
||||
|
||||
## Purpose
|
||||
|
||||
Copy/paste this directly into a new chat session to continue the current PEDW refactor stream with the right context and next-step planning.
|
||||
|
||||
## Copy/Paste Prompt
|
||||
|
||||
```
|
||||
You are continuing an in-flight refactor stream in the PEDW FrontEnd repository.
|
||||
|
||||
Before any analysis or code changes:
|
||||
1) Ask for the Azure DevOps work item ID (required).
|
||||
2) Create a new branch from `origin/SIPS-Development` prefixed with that ID (e.g. `US12345-progress-update` or `TASK67890-progress-update`).
|
||||
3) Confirm branch name, then continue.
|
||||
|
||||
Follow this order before implementing:
|
||||
1) Read `.clinerules/default-rules.md` and `.clinerules/CONTRIBUTING_AI.md`
|
||||
2) Read `GUARDRAILS.md`
|
||||
3) Read current-state docs:
|
||||
- `context/architecture.md`
|
||||
- `context/current-state-scorecard.md`
|
||||
- `context/next-work-plan-sequence-b.md`
|
||||
- `context/test-coverage-map.md`
|
||||
4) Read memory context:
|
||||
- `memory-bank/change-log.md` (latest entries)
|
||||
- `memory-bank/debt-list.md`
|
||||
- `memory-bank/architect-review.md`
|
||||
- `memory-bank/decisions.md`
|
||||
- `memory-bank/open-questions.md`
|
||||
|
||||
Then provide (based on what you read):
|
||||
1. Current state summary (what is done, what remains)
|
||||
2. Recommended next slice from this exact shortlist (pick one):
|
||||
- Slice B1.1: create shared signed-request helper(s) in `actions/clients/` and migrate one pilot path in `actions/services/portalDirectService.js`
|
||||
- Slice B1.2: migrate remaining signed flows in `actions/services/documentDirectService.js` to the shared signed helper(s)
|
||||
- Slice B2.1: auth logging hardening in `pages/api/auth/[...nextauth].js` (redacted structured logs, no behavior change)
|
||||
- Slice B2.2: file/email logging hardening in selected `pages/api/file/**` and `pages/api/email/**`
|
||||
3. Exact files to change
|
||||
4. Validation plan (lint + targeted tests + EN/CY parity + negative-path checks)
|
||||
5. Rollback plan
|
||||
|
||||
Constraints:
|
||||
- Preserve behavior unless explicitly requested otherwise
|
||||
- Do not weaken auth/session/CSP/security flows
|
||||
- Keep EN/CY parity
|
||||
- Keep scope to one bounded slice per commit
|
||||
- Update `memory-bank/change-log.md` for non-trivial changes
|
||||
|
||||
After proposing the slice, wait for approval before editing files.
|
||||
```
|
||||
|
||||
## Best use
|
||||
|
||||
- Start-of-day continuation
|
||||
- Branch handover between engineers/agents
|
||||
- Recovery after interrupted context window
|
||||
@@ -0,0 +1,183 @@
|
||||
# Refactor Slice Execution (Usable Prompts)
|
||||
|
||||
## Purpose
|
||||
|
||||
Copy/paste one of these prompts directly to execute a specific next slice (not just a template).
|
||||
|
||||
## Prompt A — Slice B1.1 (signed-request helper + pilot migration)
|
||||
|
||||
```
|
||||
Act as a senior architect + senior software engineer working in PEDW FrontEnd.
|
||||
|
||||
Before any analysis or code changes:
|
||||
1) Ask for the Azure DevOps work item ID (required).
|
||||
2) Create a new branch from `origin/SIPS-Development` prefixed with that ID (e.g. `US12345-signed-helper-pilot`).
|
||||
3) Confirm branch name and only then proceed.
|
||||
|
||||
Goal:
|
||||
Implement Slice B1.1 only: introduce shared signed-request helper(s) and migrate one pilot signed path in portal service.
|
||||
|
||||
Exact scope:
|
||||
- Add shared signed-request helper(s) in `actions/clients/` for signed GET/POST/DELETE execution.
|
||||
- Migrate one pilot signed flow in `actions/services/portalDirectService.js` to use the helper.
|
||||
- Do not migrate additional modules in this slice.
|
||||
|
||||
Mandatory context to read before coding:
|
||||
- `.clinerules/default-rules.md`
|
||||
- `GUARDRAILS.md`
|
||||
- `context/architecture.md`
|
||||
- `context/current-state-scorecard.md`
|
||||
- `context/next-work-plan-sequence-b.md`
|
||||
- `memory-bank/debt-list.md`
|
||||
- latest relevant `memory-bank/change-log.md` entries
|
||||
|
||||
Required output before edits:
|
||||
1. Scope and non-goals
|
||||
2. Risks and how they are contained
|
||||
3. Files to touch
|
||||
4. Acceptance criteria
|
||||
5. Validation checklist
|
||||
|
||||
Implementation constraints:
|
||||
- Smallest viable diff
|
||||
- Preserve API/route/public behavior
|
||||
- Preserve auth/session/security and EN/CY parity
|
||||
- No dependency churn unless required by scope
|
||||
- No unrelated cleanup
|
||||
|
||||
Validation minimum:
|
||||
- `npm run lint`
|
||||
- `node tests/phase22/index.test.cjs`
|
||||
- `node tests/phase7/service-behaviour.test.cjs`
|
||||
- explicit negative-path verification for sensitive flows
|
||||
|
||||
Completion output:
|
||||
1. Files changed
|
||||
2. Behavior parity statement
|
||||
3. Validation evidence (commands + pass/fail)
|
||||
4. Rollback steps
|
||||
5. `memory-bank/change-log.md` entry content
|
||||
```
|
||||
|
||||
## Prompt B — Slice B1.2 (document signed-flow migration)
|
||||
|
||||
```
|
||||
Act as a senior architect + senior software engineer working in PEDW FrontEnd.
|
||||
|
||||
Before any analysis or code changes:
|
||||
1) Ask for the Azure DevOps work item ID (required).
|
||||
2) Create a new branch from `origin/SIPS-Development` prefixed with that ID (e.g. `TASK67890-document-signed-migration`).
|
||||
3) Confirm branch name and only then proceed.
|
||||
|
||||
Goal:
|
||||
Implement Slice B1.2 only: migrate remaining signed flows in `documentDirectService` to shared signed-request helper(s) with no behavior change.
|
||||
|
||||
Exact scope:
|
||||
- Update `actions/services/documentDirectService.js` signed GET/POST/DELETE paths to use shared signed helper(s).
|
||||
- Preserve hash generation, headers, methods, and catch-path behavior.
|
||||
- Do not modify unrelated services.
|
||||
|
||||
Mandatory context to read before coding:
|
||||
- `.clinerules/default-rules.md`
|
||||
- `GUARDRAILS.md`
|
||||
- `context/architecture.md`
|
||||
- `context/current-state-scorecard.md`
|
||||
- `context/next-work-plan-sequence-b.md`
|
||||
- `context/test-coverage-map.md`
|
||||
- latest relevant `memory-bank/change-log.md` entries
|
||||
|
||||
Required output before edits:
|
||||
1. Scope and non-goals
|
||||
2. Risks and containment
|
||||
3. Files to touch
|
||||
4. Acceptance criteria
|
||||
5. Validation checklist
|
||||
|
||||
Validation minimum:
|
||||
- `npm run lint`
|
||||
- `node tests/phase22/index.test.cjs`
|
||||
- `node tests/phase7/service-behaviour.test.cjs`
|
||||
|
||||
Completion output:
|
||||
1. Files changed
|
||||
2. Behavior parity statement
|
||||
3. Validation evidence
|
||||
4. Rollback steps
|
||||
5. `memory-bank/change-log.md` entry
|
||||
```
|
||||
|
||||
## Prompt C — Slice B2.1 (auth logging hardening)
|
||||
|
||||
```
|
||||
Act as a senior architect + senior software engineer working in PEDW FrontEnd.
|
||||
|
||||
Before any analysis or code changes:
|
||||
1) Ask for the Azure DevOps work item ID (required).
|
||||
2) Create a new branch from `origin/SIPS-Development` prefixed with that ID (e.g. `US12345-auth-logging-hardening`).
|
||||
3) Confirm branch name and only then proceed.
|
||||
|
||||
Goal:
|
||||
Implement Slice B2.1 only: harden logging in `pages/api/auth/[...nextauth].js` using redacted structured logging with no behavior change.
|
||||
|
||||
Exact scope:
|
||||
- Replace sensitive/verbose direct logs in auth route with structured logger usage.
|
||||
- Do not alter auth/session/redirect functional behavior.
|
||||
|
||||
Mandatory context to read before coding:
|
||||
- `.clinerules/default-rules.md`
|
||||
- `GUARDRAILS.md`
|
||||
- `context/architecture.md`
|
||||
- `context/next-work-plan-sequence-b.md`
|
||||
- `memory-bank/open-questions.md` (Q-001)
|
||||
|
||||
Validation minimum:
|
||||
- `npm run lint`
|
||||
- `node tests/phase22/auth-redirect-safety.test.cjs`
|
||||
- targeted manual negative-path check for auth error logging paths
|
||||
|
||||
Completion output must include:
|
||||
1. Redaction policy applied (fields excluded)
|
||||
2. Files changed
|
||||
3. Behavior parity statement
|
||||
4. Validation evidence
|
||||
5. Rollback plan
|
||||
6. `memory-bank/change-log.md` update text
|
||||
```
|
||||
|
||||
## Prompt D — Slice B2.2 (file/email logging hardening cluster)
|
||||
|
||||
```
|
||||
Act as a senior architect + senior software engineer working in PEDW FrontEnd.
|
||||
|
||||
Before any analysis or code changes:
|
||||
1) Ask for the Azure DevOps work item ID (required).
|
||||
2) Create a new branch from `origin/SIPS-Development` prefixed with that ID (e.g. `TASK67890-file-email-logging-hardening`).
|
||||
3) Confirm branch name and only then proceed.
|
||||
|
||||
Goal:
|
||||
Implement Slice B2.2 only: harden logging in one bounded file/email route cluster using redacted structured logs.
|
||||
|
||||
Exact scope:
|
||||
- Choose a small cluster in `pages/api/file/**` and/or `pages/api/email/**`.
|
||||
- Replace risky direct logs with structured redacted logging.
|
||||
- Preserve endpoint contracts and negative-path semantics.
|
||||
|
||||
Validation minimum:
|
||||
- `npm run lint`
|
||||
- targeted tests for changed handlers
|
||||
- explicit negative-path check(s) for unauthorized/invalid input behavior
|
||||
|
||||
Completion output:
|
||||
1. Cluster chosen and why
|
||||
2. Files changed
|
||||
3. Redaction fields/policy applied
|
||||
4. Validation evidence
|
||||
5. Rollback steps
|
||||
6. `memory-bank/change-log.md` update text
|
||||
```
|
||||
|
||||
## Best use
|
||||
|
||||
- Run Sequence B slices as independent, reviewable commits
|
||||
- Start a fresh chat and execute one prompt at a time
|
||||
- Keep each slice bounded with explicit rollback
|
||||
@@ -0,0 +1,104 @@
|
||||
import useTranslation from "next-translate/useTranslation";
|
||||
import { parseCookies, setCookie } from "nookies";
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
|
||||
const COOKIE_NAME = "pedwAiPolicyNoticeHidden";
|
||||
const COOKIE_DAYS = 7;
|
||||
|
||||
export default function AIPolicyNotice() {
|
||||
let { t } = useTranslation();
|
||||
|
||||
const [hasCheckedCookie, setHasCheckedCookie] = useState(false);
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
const dismissButtonRef = useRef(null);
|
||||
|
||||
useEffect(() => {
|
||||
const cookies = parseCookies();
|
||||
const isHidden = cookies[COOKIE_NAME] === "true";
|
||||
|
||||
setIsOpen(!isHidden);
|
||||
setHasCheckedCookie(true);
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (isOpen && dismissButtonRef.current) {
|
||||
dismissButtonRef.current.focus();
|
||||
}
|
||||
}, [isOpen]);
|
||||
|
||||
const dismissNotice = () => {
|
||||
const now = new Date();
|
||||
const expDate = new Date(now);
|
||||
|
||||
expDate.setDate(now.getDate() + COOKIE_DAYS);
|
||||
|
||||
setCookie(null, COOKIE_NAME, "true", {
|
||||
path: "/",
|
||||
expires: expDate
|
||||
});
|
||||
|
||||
setIsOpen(false);
|
||||
};
|
||||
|
||||
if (!hasCheckedCookie || !isOpen) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
className="modal aiModal fade show"
|
||||
style={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
padding: "1rem"
|
||||
}}
|
||||
aria-hidden={false}
|
||||
>
|
||||
<div className="modal-dialog" style={{ margin: 0 }}>
|
||||
<div
|
||||
className="modal-content govuk-!-padding-6"
|
||||
role="dialog"
|
||||
aria-modal="true"
|
||||
aria-labelledby="ai-policy-notice-title"
|
||||
>
|
||||
<h2
|
||||
id="ai-policy-notice-title"
|
||||
className="govuk-heading-m govuk-!-margin-bottom-3"
|
||||
>
|
||||
{t("home:ai-policy-notice-title")}
|
||||
</h2>
|
||||
<p className="govuk-body">
|
||||
{t("home:ai-policy-notice-paragraph-one")}
|
||||
</p>
|
||||
<p className="govuk-body govuk-!-margin-bottom-4">
|
||||
{t("home:ai-policy-notice-paragraph-two")}{" "}
|
||||
<a
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
href={t(
|
||||
"home:ai-policy-notice-paragraph-two-a-link"
|
||||
)}
|
||||
>
|
||||
{t("home:ai-policy-notice-paragraph-two-a-label")}
|
||||
</a>{" "}
|
||||
{t("home:ai-policy-notice-paragraph-two-b")}
|
||||
</p>
|
||||
<button
|
||||
ref={dismissButtonRef}
|
||||
type="button"
|
||||
className="govuk-button govuk-!-margin-bottom-0"
|
||||
data-module="govuk-button"
|
||||
onClick={dismissNotice}
|
||||
>
|
||||
{t("home:ai-policy-notice-dismiss-button")}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className="modal-backdrop fade show"
|
||||
style={{ opacity: 0.2 }}
|
||||
></div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -4,7 +4,7 @@ import { useRouter } from "next/router";
|
||||
import React, { useState } from "react";
|
||||
import { connect } from "react-redux";
|
||||
import { Field, formValueSelector, reduxForm } from "redux-form";
|
||||
import { updatePassword } from "../../actions";
|
||||
import { updatePassword } from "../../actions/services/accountService";
|
||||
|
||||
const RenderTextfield = ({
|
||||
id,
|
||||
@@ -60,7 +60,7 @@ const ChangePassword = (props) => {
|
||||
handleSubmit,
|
||||
value,
|
||||
setPasswordUpdated,
|
||||
passwordUpdated,
|
||||
passwordUpdated
|
||||
} = props;
|
||||
let { t, lang } = useTranslation();
|
||||
|
||||
@@ -158,7 +158,7 @@ const mapStateToProps = (state) => {
|
||||
searchResultsObj: state.searchResultsObj,
|
||||
formData: state.formData,
|
||||
appealType: state.appealType,
|
||||
accountDetails: state.accountDetails,
|
||||
accountDetails: state.accountDetails
|
||||
//form: state.form,
|
||||
};
|
||||
};
|
||||
@@ -167,7 +167,7 @@ const mapDispatchToProps = (dispatch) => {
|
||||
return {
|
||||
setCurrentSection: (currentSection) => {
|
||||
dispatch(setCurrentSection(currentSection));
|
||||
},
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
@@ -179,6 +179,6 @@ export default connect(
|
||||
)(
|
||||
reduxForm({
|
||||
form: "changepasswordForm",
|
||||
destroyOnUnmount: false,
|
||||
destroyOnUnmount: false
|
||||
})(ChangePassword)
|
||||
);
|
||||
|
||||
@@ -140,12 +140,12 @@ const RenderPickList = ({
|
||||
input,
|
||||
optionsArr,
|
||||
meta: { touched, error },
|
||||
errorMsg,
|
||||
errorMsg
|
||||
}) => {
|
||||
let { t, lang } = useTranslation();
|
||||
optionsArr = [
|
||||
t("account:account-preferred-language-english") + ":846040001",
|
||||
t("account:account-preferred-language-welsh") + ":846040000",
|
||||
t("account:account-preferred-language-welsh") + ":846040000"
|
||||
];
|
||||
return (
|
||||
<>
|
||||
@@ -202,7 +202,7 @@ let PersonalDetails = (props) => {
|
||||
load,
|
||||
pristine,
|
||||
reset,
|
||||
submitting,
|
||||
submitting
|
||||
} = props;
|
||||
let { t, lang } = useTranslation();
|
||||
|
||||
@@ -246,6 +246,7 @@ let PersonalDetails = (props) => {
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="govuk-form-group">
|
||||
{props.accountUpdatedComplete == false ? (
|
||||
props.personalDetailsComplete == false ? (
|
||||
<form onSubmit={handleSubmit(onHandleSubmit)}>
|
||||
@@ -286,7 +287,9 @@ let PersonalDetails = (props) => {
|
||||
type="text"
|
||||
className="govuk-input govuk-input--width-20"
|
||||
validate={[required]}
|
||||
label={t("account:account-first-name-label")}
|
||||
label={t(
|
||||
"account:account-first-name-label"
|
||||
)}
|
||||
errorMsg={t("account:is-required-label")}
|
||||
/>
|
||||
<Field
|
||||
@@ -306,7 +309,9 @@ let PersonalDetails = (props) => {
|
||||
type="email"
|
||||
className="govuk-input govuk-input--width-20"
|
||||
validate={[required, email]}
|
||||
label={t("account:account-email-address-label")}
|
||||
label={t(
|
||||
"account:account-email-address-label"
|
||||
)}
|
||||
disabled
|
||||
/>
|
||||
<Field
|
||||
@@ -319,19 +324,23 @@ let PersonalDetails = (props) => {
|
||||
label={t("account:account-telephone-label")}
|
||||
/>
|
||||
<Field
|
||||
name="company"
|
||||
id="company"
|
||||
name="pinswg_companyname"
|
||||
id="pinswg_companyname"
|
||||
component={RenderTextfield}
|
||||
type="text"
|
||||
className="govuk-input govuk-input--width-20"
|
||||
label={t("account:account-company-group-label")}
|
||||
label={t(
|
||||
"account:account-company-group-label"
|
||||
)}
|
||||
errorMsg={t("account:is-required-label")}
|
||||
/>
|
||||
</fieldset>
|
||||
<fieldset className="govuk-fieldset">
|
||||
<legend className="govuk-fieldset__legend govuk-fieldset__legend--m">
|
||||
<h2 className="govuk-fieldset__heading">
|
||||
{t("account:account-your-address-label")}
|
||||
{t(
|
||||
"account:account-your-address-label"
|
||||
)}
|
||||
</h2>
|
||||
</legend>
|
||||
|
||||
@@ -399,7 +408,8 @@ let PersonalDetails = (props) => {
|
||||
<Link
|
||||
href={
|
||||
"/myportal?q=" +
|
||||
props.props.accountDetails.loggedinUserId
|
||||
props.props.accountDetails
|
||||
.loggedinUserId
|
||||
}
|
||||
className="govuk-link"
|
||||
>
|
||||
@@ -423,6 +433,7 @@ let PersonalDetails = (props) => {
|
||||
) : (
|
||||
<PersonalDetailsComplete props={props} />
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
@@ -433,7 +444,7 @@ const mapStateToProps = (state) => {
|
||||
searchResultsObj: state.searchResultsObj,
|
||||
formData: state.formData,
|
||||
appealType: state.appealType,
|
||||
accountDetails: state.accountDetails,
|
||||
accountDetails: state.accountDetails
|
||||
//form: state.form,
|
||||
};
|
||||
};
|
||||
@@ -442,7 +453,7 @@ const mapDispatchToProps = (dispatch) => {
|
||||
return {
|
||||
setCurrentSection: (currentSection) => {
|
||||
dispatch(setCurrentSection(currentSection));
|
||||
},
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
@@ -473,12 +484,12 @@ const selector = formValueSelector("personalDetailsForm"); // <-- same as form n
|
||||
PersonalDetails = reduxForm({
|
||||
form: "personalDetailsForm",
|
||||
enableReinitialize: true, // this is needed!!
|
||||
destroyOnUnmount: false,
|
||||
destroyOnUnmount: false
|
||||
})(PersonalDetails);
|
||||
|
||||
// You have to connect() to any reducers that you wish to connect to yourself
|
||||
PersonalDetails = connect((state) => ({
|
||||
initialValues: state.accountDetails.accountDetails, // pull initial values from account reducer
|
||||
initialValues: state.accountDetails.accountDetails // pull initial values from account reducer
|
||||
}))(PersonalDetails);
|
||||
|
||||
export default PersonalDetails;
|
||||
|
||||
@@ -11,7 +11,7 @@ const BuildCheckPersonalDetails = (props) => {
|
||||
handleSubmit,
|
||||
value,
|
||||
setPersonalDetailsComplete,
|
||||
setAccountUpdatedComplete,
|
||||
setAccountUpdatedComplete
|
||||
} = props;
|
||||
let { t, lang } = useTranslation();
|
||||
|
||||
@@ -142,7 +142,7 @@ const BuildCheckPersonalDetails = (props) => {
|
||||
<dd className="govuk-summary-list__value">
|
||||
{
|
||||
props.props.props.form.personalDetailsForm.values
|
||||
.company
|
||||
.pinswg_companyname
|
||||
}
|
||||
</dd>
|
||||
<dd className="govuk-summary-list__actions">
|
||||
@@ -354,7 +354,7 @@ const mapStateToProps = (state) => {
|
||||
searchResultsObj: state.searchResultsObj,
|
||||
formData: state.formData,
|
||||
appealType: state.appealType,
|
||||
accountDetails: state.accountDetails,
|
||||
accountDetails: state.accountDetails
|
||||
//form: state.form,
|
||||
};
|
||||
};
|
||||
@@ -363,7 +363,7 @@ const mapDispatchToProps = (dispatch) => {
|
||||
return {
|
||||
setCurrentSection: (currentSection) => {
|
||||
dispatch(setCurrentSection(currentSection));
|
||||
},
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -3,28 +3,54 @@ import Link from "next/link";
|
||||
import { useRouter } from "next/router";
|
||||
import React, { useEffect } from "react";
|
||||
import { connect } from "react-redux";
|
||||
import { updateAccount } from "../../actions";
|
||||
import { updateAccount } from "../../actions/services/accountService";
|
||||
import { setCookie } from "nookies";
|
||||
|
||||
const PersonalDetailsComplete = (props) => {
|
||||
const {
|
||||
handleSubmit,
|
||||
value,
|
||||
setRegisterFormComplete,
|
||||
setAccountCreatedComplete,
|
||||
setAccountCreatedComplete
|
||||
} = props;
|
||||
let { t, lang } = useTranslation();
|
||||
|
||||
const router = useRouter();
|
||||
const { locale } = router;
|
||||
|
||||
// let contactid = props.accountDetails.loggedinUserId;
|
||||
// let updateBody = props.props.props.form.personalDetailsForm.values;
|
||||
// let prefLang =
|
||||
// props.props.props.form.personalDetailsForm.values
|
||||
// .pinswg_preferredlanguage;
|
||||
|
||||
const { loggedinUserId } = props.accountDetails || {};
|
||||
const formValues = props.props?.props?.form?.personalDetailsForm?.values;
|
||||
const prefLang = formValues?.pinswg_preferredlanguage;
|
||||
|
||||
const userLang = prefLang === "846040000" ? "cy" : "en"; // Move this outside useEffect
|
||||
|
||||
useEffect(() => {
|
||||
let contactid = props.accountDetails.loggedinUserId;
|
||||
let updateBody = props.props.props.form.personalDetailsForm.values;
|
||||
updateAccount(contactid, updateBody);
|
||||
}, [
|
||||
props.accountDetails.loggedinUserId,
|
||||
props.props.props.form.personalDetailsForm.values,
|
||||
]);
|
||||
// let contactid = props.accountDetails.loggedinUserId;
|
||||
// let updateBody = props.props.props.form.personalDetailsForm.values;
|
||||
// let prefLang =
|
||||
// props.props.props.form.personalDetailsForm.values
|
||||
// .pinswg_preferredlanguage;
|
||||
if (!loggedinUserId || !formValues) return;
|
||||
|
||||
console.log("=============== pref lang", prefLang);
|
||||
setCookie(null, "pedw_locale", userLang, {
|
||||
path: "/"
|
||||
});
|
||||
|
||||
console.log("Set cookie to:", userLang);
|
||||
|
||||
async function doUpdate() {
|
||||
const response = await updateAccount(loggedinUserId, formValues);
|
||||
}
|
||||
|
||||
doUpdate();
|
||||
}, [loggedinUserId, formValues, prefLang, userLang]);
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -34,7 +60,8 @@ const PersonalDetailsComplete = (props) => {
|
||||
|
||||
<p className="govuk-body">
|
||||
<Link
|
||||
href={"/myportal?q=" + props.accountDetails.loggedinUserId}
|
||||
locale={userLang}
|
||||
href={userLang === "cy" ? "/cy/fymhorth" : "/myportal"}
|
||||
className="govuk-link"
|
||||
>
|
||||
{" "}
|
||||
@@ -51,7 +78,7 @@ const mapStateToProps = (state) => {
|
||||
searchResultsObj: state.searchResultsObj,
|
||||
formData: state.formData,
|
||||
appealType: state.appealType,
|
||||
accountDetails: state.accountDetails,
|
||||
accountDetails: state.accountDetails
|
||||
//form: state.form,
|
||||
};
|
||||
};
|
||||
@@ -60,7 +87,7 @@ const mapDispatchToProps = (dispatch) => {
|
||||
return {
|
||||
setCurrentSection: (currentSection) => {
|
||||
dispatch(setCurrentSection(currentSection));
|
||||
},
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -8,7 +8,10 @@ import { connect } from "react-redux";
|
||||
|
||||
import { setAccCr, setLogout } from "../../store/accountDetails/action";
|
||||
|
||||
import { createAccount, getEmailAccountCheck } from "../../actions";
|
||||
import {
|
||||
createAccount,
|
||||
getEmailAccountCheck
|
||||
} from "../../actions/services/accountService";
|
||||
|
||||
const RegisterComplete = (props) => {
|
||||
const {
|
||||
@@ -18,7 +21,7 @@ const RegisterComplete = (props) => {
|
||||
value,
|
||||
setRegisterFormComplete,
|
||||
setAccountCreatedComplete,
|
||||
setAccCr,
|
||||
setAccCr
|
||||
} = props;
|
||||
let { t, lang } = useTranslation();
|
||||
|
||||
@@ -34,7 +37,7 @@ const RegisterComplete = (props) => {
|
||||
|
||||
// was an appellant "pinswg_typeofinvolvement": 846040001,
|
||||
Object.assign(accountBody, {
|
||||
"pinswg_typeofinvolvement": 846040061,
|
||||
"pinswg_typeofinvolvement": 846040061
|
||||
});
|
||||
|
||||
accountBody = _.omit(accountBody, ["custom_password_check"]);
|
||||
@@ -105,9 +108,9 @@ const RegisterComplete = (props) => {
|
||||
<p className="govuk-body">
|
||||
<a
|
||||
onClick={() => {
|
||||
setRegisterFormComplete(false),
|
||||
(setRegisterFormComplete(false),
|
||||
setAccountCreatedComplete(false),
|
||||
setAccCr(false);
|
||||
setAccCr(false));
|
||||
}}
|
||||
className="govuk-link"
|
||||
>
|
||||
@@ -130,7 +133,7 @@ const mapStateToProps = (state) => {
|
||||
searchResultsObj: state.searchResultsObj,
|
||||
formData: state.formData,
|
||||
appealType: state.appealType,
|
||||
accountDetails: state.accountDetails,
|
||||
accountDetails: state.accountDetails
|
||||
//form: state.form,
|
||||
};
|
||||
};
|
||||
@@ -142,7 +145,7 @@ const mapDispatchToProps = (dispatch) => {
|
||||
},
|
||||
setLogout: () => {
|
||||
dispatch(setLogout());
|
||||
},
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -66,7 +66,7 @@ const RegisterForm = (props) => {
|
||||
setRegisterFormComplete,
|
||||
setAccountCreatedComplete,
|
||||
loggedInUserEmail,
|
||||
emailaddress1,
|
||||
emailaddress1
|
||||
} = props;
|
||||
let { t, lang } = useTranslation();
|
||||
|
||||
@@ -137,6 +137,8 @@ const RegisterForm = (props) => {
|
||||
{props.accountCreatedComplete != true ? (
|
||||
props.registerFormComplete == false ? (
|
||||
<form onSubmit={handleSubmit(onHandleSubmit)}>
|
||||
<div className="card" id="personalDetailsCard">
|
||||
<div className="card-body">
|
||||
<fieldset className="govuk-fieldset">
|
||||
<legend className="govuk-fieldset__legend govuk-fieldset__legend--m">
|
||||
<h2 className="govuk-fieldset__heading">
|
||||
@@ -197,6 +199,17 @@ const RegisterForm = (props) => {
|
||||
"account:register-new-account-phone-label"
|
||||
)}
|
||||
/>
|
||||
<Field
|
||||
name="company"
|
||||
id="company"
|
||||
component={RenderTextfield}
|
||||
type="text"
|
||||
className="govuk-input govuk-input--width-20"
|
||||
validate={[required]}
|
||||
label={t(
|
||||
"account:register-new-account-company-label"
|
||||
)}
|
||||
/>
|
||||
</fieldset>
|
||||
<fieldset className="govuk-fieldset">
|
||||
<legend className="govuk-fieldset__legend govuk-fieldset__legend--m">
|
||||
@@ -281,6 +294,8 @@ const RegisterForm = (props) => {
|
||||
{t("common:continue-button")}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
) : (
|
||||
<RegisterFormCheck
|
||||
@@ -308,8 +323,8 @@ const mapStateToProps = (state, props) => {
|
||||
appealType: state.appealType,
|
||||
//form: state.form,
|
||||
initialValues: {
|
||||
emailaddress1: props.loggedInUserEmail,
|
||||
},
|
||||
emailaddress1: props.loggedInUserEmail
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
@@ -317,7 +332,7 @@ const mapDispatchToProps = (dispatch) => {
|
||||
return {
|
||||
setCurrentSection: (currentSection) => {
|
||||
dispatch(setCurrentSection(currentSection));
|
||||
},
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
@@ -330,6 +345,6 @@ export default connect(
|
||||
reduxForm({
|
||||
form: "accountRegisterForm",
|
||||
enableReinitialize: true,
|
||||
destroyOnUnmount: false,
|
||||
destroyOnUnmount: false
|
||||
})(RegisterForm)
|
||||
);
|
||||
|
||||
@@ -3,6 +3,7 @@ import Link from "next/link";
|
||||
import { useRouter } from "next/router";
|
||||
import CRMError from "./crmError";
|
||||
import SearchResults from "./search/addresssearchresults";
|
||||
import { hasOwn } from "./utils";
|
||||
|
||||
export default function Search(props) {
|
||||
const {
|
||||
@@ -12,14 +13,14 @@ export default function Search(props) {
|
||||
myportal,
|
||||
watchedCases,
|
||||
isLinkedCase,
|
||||
showLoginCheck,
|
||||
showLoginCheck
|
||||
} = props;
|
||||
let { t } = useTranslation();
|
||||
|
||||
const router = useRouter();
|
||||
const { locale } = router;
|
||||
|
||||
var hasError = _.has(searchResultsObj.searchResultsObj, "errorCode")
|
||||
var hasError = hasOwn(searchResultsObj.searchResultsObj, "errorCode")
|
||||
? true
|
||||
: false;
|
||||
|
||||
|
||||
@@ -6,17 +6,20 @@ import Link from "next/link";
|
||||
import { useRouter } from "next/router";
|
||||
import PaginationControl from "../../../components/search/pagination";
|
||||
import { connect } from "react-redux";
|
||||
import transLookup from "../../../data/lookuptranslations.json";
|
||||
|
||||
import {
|
||||
setSearchResults,
|
||||
setSearchDetails,
|
||||
setSearchDetails
|
||||
} from "../../../store/searchOutput/action";
|
||||
|
||||
import { getDetailsProxy, getSearchDetailsPaged } from "../../utils";
|
||||
import { getAdvancedSearchPaged, getNewAppealsPage } from "../../../actions";
|
||||
import { getDetailsProxy, getSearchDetailsPaged, hasOwn } from "../../utils";
|
||||
import { getAdvancedSearchPaged } from "../../../actions/services/searchService";
|
||||
import { getNewAppealsPage } from "../../../actions/services/adminService";
|
||||
import resolveCrmDisplayValue from "../../../lib/i18n/crmDisplay/resolveCrmDisplayValue";
|
||||
import {
|
||||
setCurrentPage,
|
||||
setCurrentReference,
|
||||
setCurrentReference
|
||||
} from "../../../store/currentView/action";
|
||||
|
||||
function AppealsTab(props) {
|
||||
@@ -27,9 +30,15 @@ function AppealsTab(props) {
|
||||
const [fieldSortState, setfieldSortState] = useState("desc");
|
||||
const [loginToWatch, setLoginToWatch] = useState("true");
|
||||
|
||||
const searchDetailsObj = props.searchResultsObj.searchDetailsObj || {};
|
||||
const resultsArr = props.searchResultsObj.searchResultsObj.value || [];
|
||||
const searchResultsObj = props.searchResultsObj.searchResultsObj;
|
||||
const {
|
||||
searchResultsObj: searchResultsState,
|
||||
setSearchResults,
|
||||
setSearchDetails
|
||||
} = props;
|
||||
|
||||
const searchDetailsObj = searchResultsState.searchDetailsObj || {};
|
||||
const resultsArr = searchResultsState.searchResultsObj.value || [];
|
||||
const searchResultsObj = searchResultsState.searchResultsObj;
|
||||
|
||||
const { t } = useTranslation();
|
||||
const router = useRouter();
|
||||
@@ -74,20 +83,14 @@ function AppealsTab(props) {
|
||||
fieldSort,
|
||||
selectedOption
|
||||
).then((data) => {
|
||||
props.setSearchResults(data); // ✅ use props, not import
|
||||
setSearchResults(data);
|
||||
return getSearchDetailsPaged(data).then((details) => {
|
||||
props.setSearchDetails(details); // ✅ use props, not import
|
||||
setSearchDetails(details);
|
||||
setShowSpinnerState(false);
|
||||
});
|
||||
});
|
||||
},
|
||||
[
|
||||
advancedSearch,
|
||||
searchString,
|
||||
selectedOption,
|
||||
props.setSearchDetails,
|
||||
props.setSearchResults,
|
||||
]
|
||||
[selectedOption, setSearchDetails, setSearchResults]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
@@ -105,7 +108,7 @@ function AppealsTab(props) {
|
||||
orderByState,
|
||||
searchLoaded,
|
||||
getSearchPageResults,
|
||||
router.query,
|
||||
router.query
|
||||
]);
|
||||
|
||||
const ResultsView = (resultsArr) => {
|
||||
@@ -225,7 +228,7 @@ function AppealsTab(props) {
|
||||
item.ticketnumber +
|
||||
'")]',
|
||||
json: searchDetailsObj,
|
||||
eval: true,
|
||||
eval: true
|
||||
});
|
||||
|
||||
detailsObj = detailsObj[0] || {};
|
||||
@@ -254,6 +257,8 @@ function AppealsTab(props) {
|
||||
className="govuk-link--no-underline"
|
||||
onClick={() => {
|
||||
setCurrentReference({
|
||||
"statuscode":
|
||||
item.statuscode,
|
||||
"ticketnumber":
|
||||
item.ticketnumber,
|
||||
"currentReference":
|
||||
@@ -275,7 +280,7 @@ function AppealsTab(props) {
|
||||
"pinswg_specialistcaseprocess"
|
||||
)
|
||||
? detailsObj.pinswg_specialistcaseprocess
|
||||
: "",
|
||||
: ""
|
||||
});
|
||||
}}
|
||||
>
|
||||
@@ -303,7 +308,7 @@ function AppealsTab(props) {
|
||||
)}
|
||||
:
|
||||
</span>
|
||||
{_.has(
|
||||
{hasOwn(
|
||||
detailsObj,
|
||||
"pinswg_projectlocation"
|
||||
)
|
||||
@@ -322,7 +327,7 @@ function AppealsTab(props) {
|
||||
)[0]
|
||||
: ""
|
||||
: ""}
|
||||
{_.has(
|
||||
{hasOwn(
|
||||
detailsObj,
|
||||
"pinswg_siteaddressline1"
|
||||
)
|
||||
@@ -332,52 +337,52 @@ function AppealsTab(props) {
|
||||
{/* {detailsObj.pinswg_siteaddressline1 !=
|
||||
null && <br />} */}
|
||||
|
||||
{_.has(
|
||||
{hasOwn(
|
||||
detailsObj,
|
||||
"pinswg_siteaddressline1"
|
||||
) &&
|
||||
detailsObj.pinswg_siteaddressline1 !=
|
||||
null && <br />}
|
||||
|
||||
{_.has(
|
||||
{hasOwn(
|
||||
detailsObj,
|
||||
"pinswg_siteaddressline1"
|
||||
)
|
||||
? detailsObj.pinswg_siteaddressline2
|
||||
: ""}
|
||||
|
||||
{_.has(
|
||||
{hasOwn(
|
||||
detailsObj,
|
||||
"pinswg_siteaddressline2"
|
||||
) &&
|
||||
detailsObj.pinswg_siteaddressline2 !=
|
||||
null && <br />}
|
||||
{_.has(
|
||||
{hasOwn(
|
||||
detailsObj,
|
||||
"pinswg_siteaddresstown"
|
||||
)
|
||||
? detailsObj.pinswg_siteaddresstown
|
||||
: ""}
|
||||
{_.has(
|
||||
{hasOwn(
|
||||
detailsObj,
|
||||
"pinswg_siteaddresstown"
|
||||
) &&
|
||||
detailsObj.pinswg_siteaddresstown !=
|
||||
null && <br />}
|
||||
|
||||
{_.has(
|
||||
{hasOwn(
|
||||
detailsObj,
|
||||
"pinswg_siteaddresscounty"
|
||||
)
|
||||
? detailsObj.pinswg_siteaddresscounty
|
||||
: ""}
|
||||
{_.has(
|
||||
{hasOwn(
|
||||
detailsObj,
|
||||
"pinswg_siteaddresscounty"
|
||||
) &&
|
||||
detailsObj.pinswg_siteaddresscounty !=
|
||||
null && <br />}
|
||||
{_.has(
|
||||
{hasOwn(
|
||||
detailsObj,
|
||||
"pinswg_siteaddresspostcode"
|
||||
)
|
||||
@@ -395,8 +400,8 @@ function AppealsTab(props) {
|
||||
? item.pinswg_appellantfirstname +
|
||||
" " +
|
||||
item.pinswg_appellantlastname
|
||||
: _.has(detailsObj, [
|
||||
"_pinswg_appellant_value@OData.Community.Display.V1.FormattedValue",
|
||||
: hasOwn(detailsObj, [
|
||||
"_pinswg_appellant_value@OData.Community.Display.V1.FormattedValue"
|
||||
])
|
||||
? detailsObj[
|
||||
"_pinswg_appellant_value@OData.Community.Display.V1.FormattedValue"
|
||||
@@ -410,23 +415,17 @@ function AppealsTab(props) {
|
||||
)}
|
||||
:
|
||||
</span>
|
||||
{_.has(item, [
|
||||
"_pinswg_associatedlpa_value@OData.Community.Display.V1.FormattedValue",
|
||||
{hasOwn(item, [
|
||||
"_pinswg_associatedlpa_value@OData.Community.Display.V1.FormattedValue"
|
||||
])
|
||||
? router.locale == "cy"
|
||||
? jsonpath({
|
||||
path:
|
||||
'$..[?(@ && @.value=="' +
|
||||
item[
|
||||
? resolveCrmDisplayValue({
|
||||
value: item[
|
||||
"_pinswg_associatedlpa_value@OData.Community.Display.V1.FormattedValue"
|
||||
] +
|
||||
'")].value_cy',
|
||||
json: transLookup,
|
||||
eval: true,
|
||||
],
|
||||
locale: router.locale,
|
||||
translations: transLookup,
|
||||
fallbackValue: "N/A"
|
||||
})
|
||||
: item[
|
||||
"_pinswg_associatedlpa_value@OData.Community.Display.V1.FormattedValue"
|
||||
] || "N/A"
|
||||
: ""}
|
||||
</dd>
|
||||
<dd className="govuk-summary-list__value govuk-!-font-size-16">
|
||||
@@ -436,20 +435,14 @@ function AppealsTab(props) {
|
||||
)}
|
||||
:
|
||||
</span>
|
||||
{router.locale == "cy"
|
||||
? jsonpath({
|
||||
path:
|
||||
'$..[?(@ && @.value=="' +
|
||||
item[
|
||||
{resolveCrmDisplayValue({
|
||||
value: item[
|
||||
"pinswg_appealcasetype@OData.Community.Display.V1.FormattedValue"
|
||||
] +
|
||||
'")].value_cy',
|
||||
json: transLookup,
|
||||
eval: true,
|
||||
})
|
||||
: item[
|
||||
"pinswg_appealcasetype@OData.Community.Display.V1.FormattedValue"
|
||||
] || "N/A"}
|
||||
],
|
||||
locale: router.locale,
|
||||
translations: transLookup,
|
||||
fallbackValue: "N/A"
|
||||
})}
|
||||
</dd>
|
||||
<dd className="govuk-summary-list__value govuk-!-font-size-16">
|
||||
<span className="results-visually-hidden">
|
||||
@@ -459,20 +452,14 @@ function AppealsTab(props) {
|
||||
:
|
||||
</span>
|
||||
|
||||
{router.locale == "cy"
|
||||
? jsonpath({
|
||||
path:
|
||||
'$..[?(@ && @.value=="' +
|
||||
item[
|
||||
{resolveCrmDisplayValue({
|
||||
value: item[
|
||||
"statuscode@OData.Community.Display.V1.FormattedValue"
|
||||
] +
|
||||
'")].value_cy',
|
||||
json: transLookup,
|
||||
eval: true,
|
||||
})
|
||||
: item[
|
||||
"statuscode@OData.Community.Display.V1.FormattedValue"
|
||||
] || "N/A"}
|
||||
],
|
||||
locale: router.locale,
|
||||
translations: transLookup,
|
||||
fallbackValue: "N/A"
|
||||
})}
|
||||
</dd>
|
||||
<dd className="govuk-summary-list__value govuk-!-font-size-16">
|
||||
{item[
|
||||
@@ -555,13 +542,13 @@ const mapDispatchToProps = (dispatch) => {
|
||||
},
|
||||
setCurrentPage: (currentPage) => {
|
||||
dispatch(setCurrentPage(currentPage));
|
||||
},
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
const mapStateToProps = (state) => {
|
||||
return {
|
||||
searchResultsObj: state.searchResultsObj,
|
||||
searchResultsObj: state.searchResultsObj
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,273 @@
|
||||
import { useMemo, useState } from "react";
|
||||
import Link from "next/link";
|
||||
|
||||
export default function AppealStatusDashboard({ statusObj = [] }) {
|
||||
const [openSections, setOpenSections] = useState({});
|
||||
|
||||
const sortedAppeals = useMemo(
|
||||
() =>
|
||||
[...statusObj].sort(
|
||||
(a, b) => (b.caseCount || 0) - (a.caseCount || 0)
|
||||
),
|
||||
[statusObj]
|
||||
);
|
||||
|
||||
const percentageOf = (value, total) =>
|
||||
total ? `${(((value || 0) / total) * 100).toFixed(1)}%` : "0.0%";
|
||||
|
||||
const totalCases = sortedAppeals.reduce(
|
||||
(sum, appeal) => sum + (appeal.caseCount || 0),
|
||||
0
|
||||
);
|
||||
|
||||
const largestAppeal = sortedAppeals[0];
|
||||
|
||||
const allStatuses = sortedAppeals.flatMap((appeal) =>
|
||||
(appeal.statuses || []).map((status) => ({
|
||||
...status,
|
||||
appealType: appeal.value
|
||||
}))
|
||||
);
|
||||
|
||||
const statusTotals = allStatuses.reduce((acc, status) => {
|
||||
if (!acc[status.statuscode]) {
|
||||
acc[status.statuscode] = {
|
||||
value: status.value,
|
||||
statuscode: status.statuscode,
|
||||
caseCount: 0
|
||||
};
|
||||
}
|
||||
|
||||
acc[status.statuscode].caseCount += status.caseCount || 0;
|
||||
return acc;
|
||||
}, {});
|
||||
|
||||
const mostCommonStatus = Object.values(statusTotals).sort(
|
||||
(a, b) => b.caseCount - a.caseCount
|
||||
)[0];
|
||||
|
||||
const maxAppealCount = largestAppeal?.caseCount || 1;
|
||||
|
||||
const allExpanded =
|
||||
sortedAppeals.length > 0 &&
|
||||
sortedAppeals.every((_, index) => openSections[index]);
|
||||
|
||||
const toggleSection = (index) => {
|
||||
setOpenSections((current) => ({
|
||||
...current,
|
||||
[index]: !current[index]
|
||||
}));
|
||||
};
|
||||
|
||||
const showAll = () => {
|
||||
const allOpen = {};
|
||||
sortedAppeals.forEach((_, index) => {
|
||||
allOpen[index] = true;
|
||||
});
|
||||
setOpenSections(allOpen);
|
||||
};
|
||||
|
||||
const hideAll = () => {
|
||||
setOpenSections({});
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="govuk-grid-row">
|
||||
<div className="govuk-grid-column-full">
|
||||
<h1>Appeal case status dashboard</h1>
|
||||
|
||||
<div className="govuk-grid-row">
|
||||
<DashboardCard title="Total cases" value={totalCases} />
|
||||
<DashboardCard
|
||||
title="Appeal types"
|
||||
value={sortedAppeals.length}
|
||||
/>
|
||||
<DashboardCard
|
||||
title="Largest appeal type"
|
||||
value={largestAppeal?.caseCount || 0}
|
||||
caption={largestAppeal?.value}
|
||||
/>
|
||||
<DashboardCard
|
||||
title="Most common status"
|
||||
value={mostCommonStatus?.caseCount || 0}
|
||||
caption={mostCommonStatus?.value}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<section className="govuk-!-margin-top-8">
|
||||
<h2 className="govuk-heading-m">
|
||||
Case counts and stage breakdown by appeal type
|
||||
</h2>
|
||||
|
||||
<p className="govuk-body-s">
|
||||
Select an appeal type row to show the case stage
|
||||
breakdown.
|
||||
</p>
|
||||
|
||||
<div className="govuk-accordion__controls">
|
||||
<button
|
||||
type="button"
|
||||
className="govuk-accordion__show-all"
|
||||
onClick={allExpanded ? hideAll : showAll}
|
||||
>
|
||||
<span className="govuk-accordion__show-all-text">
|
||||
{allExpanded
|
||||
? "Hide all sections"
|
||||
: "Show all sections"}
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div
|
||||
className="govuk-accordion appeal-stage-chart"
|
||||
id="appeals-with-status-accordion"
|
||||
>
|
||||
{sortedAppeals.map((appeal, index) => {
|
||||
const isOpen = !!openSections[index];
|
||||
|
||||
const barWidth =
|
||||
((appeal.caseCount || 0) / maxAppealCount) *
|
||||
100;
|
||||
|
||||
const sortedStatuses = [...(appeal.statuses || [])]
|
||||
.filter((status) => (status.caseCount || 0) > 0)
|
||||
.sort(
|
||||
(a, b) =>
|
||||
(b.caseCount || 0) - (a.caseCount || 0)
|
||||
);
|
||||
|
||||
return (
|
||||
<div
|
||||
className={
|
||||
isOpen
|
||||
? "govuk-accordion__section govuk-accordion__section--expanded appeal-stage-chart__accordion-section"
|
||||
: "govuk-accordion__section appeal-stage-chart__accordion-section"
|
||||
}
|
||||
key={appeal.appealType || index}
|
||||
>
|
||||
<div className="govuk-accordion__section-header">
|
||||
<h2 className="govuk-accordion__section-heading">
|
||||
<button
|
||||
type="button"
|
||||
className="govuk-accordion__section-button appeal-stage-chart__button"
|
||||
id={`appeal-status-heading-${index}`}
|
||||
aria-expanded={isOpen}
|
||||
aria-controls={`appeal-status-content-${index}`}
|
||||
onClick={() =>
|
||||
toggleSection(index)
|
||||
}
|
||||
>
|
||||
<span className="appeal-stage-chart__row">
|
||||
<span className="appeal-stage-chart__label">
|
||||
{appeal.value} (
|
||||
{percentageOf(
|
||||
appeal.caseCount,
|
||||
totalCases
|
||||
)}
|
||||
)
|
||||
</span>
|
||||
|
||||
<span className="appeal-stage-chart__bar-wrapper">
|
||||
<span
|
||||
className="appeal-stage-chart__bar"
|
||||
style={{
|
||||
width: `${barWidth}%`
|
||||
}}
|
||||
aria-hidden="true"
|
||||
>
|
||||
{sortedStatuses.map(
|
||||
(
|
||||
status,
|
||||
statusIndex
|
||||
) => (
|
||||
<span
|
||||
key={`${status.statuscode}-${statusIndex}`}
|
||||
className={`appeal-stage-chart__segment appeal-stage-chart__segment--${
|
||||
statusIndex %
|
||||
6
|
||||
}`}
|
||||
style={{
|
||||
width: `${
|
||||
((status.caseCount ||
|
||||
0) /
|
||||
(appeal.caseCount ||
|
||||
1)) *
|
||||
100
|
||||
}%`
|
||||
}}
|
||||
title={`${status.value}: ${status.caseCount}`}
|
||||
/>
|
||||
)
|
||||
)}
|
||||
</span>
|
||||
|
||||
<span className="appeal-stage-chart__count">
|
||||
{appeal.caseCount ||
|
||||
0}{" "}
|
||||
cases
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
</button>
|
||||
</h2>
|
||||
</div>
|
||||
|
||||
<div
|
||||
id={`appeal-status-content-${index}`}
|
||||
className="govuk-accordion__section-content"
|
||||
aria-labelledby={`appeal-status-heading-${index}`}
|
||||
hidden={!isOpen}
|
||||
>
|
||||
<dl className="govuk-summary-list">
|
||||
{sortedStatuses.map((status) => (
|
||||
<div
|
||||
className="govuk-summary-list__row"
|
||||
key={status.statuscode}
|
||||
>
|
||||
<dt className="govuk-summary-list__key">
|
||||
<Link
|
||||
target="_blank"
|
||||
href={`/advancedsearchresults?apt=${appeal.appealType}&statuscode=${status.statuscode}`}
|
||||
>
|
||||
{status.value}
|
||||
</Link>
|
||||
</dt>
|
||||
|
||||
<dd className="govuk-summary-list__value">
|
||||
{status.caseCount || 0}{" "}
|
||||
cases (
|
||||
{percentageOf(
|
||||
status.caseCount,
|
||||
appeal.caseCount
|
||||
)}{" "}
|
||||
of this appeal type)
|
||||
</dd>
|
||||
</div>
|
||||
))}
|
||||
</dl>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function DashboardCard({ title, value, caption }) {
|
||||
return (
|
||||
<div className="govuk-grid-column-one-quarter">
|
||||
<div className="dashboard-card">
|
||||
<p className="govuk-body-s dashboard-card__title">{title}</p>
|
||||
<p className="govuk-heading-l dashboard-card__value">{value}</p>
|
||||
{caption && (
|
||||
<p className="govuk-body-s dashboard-card__caption">
|
||||
{caption}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,571 @@
|
||||
import { useMemo, useState } from "react";
|
||||
import Link from "next/link";
|
||||
|
||||
export default function AppealLpaStatusDashboard({ statusObj = [] }) {
|
||||
const [openAppeals, setOpenAppeals] = useState({});
|
||||
const [openLpaSections, setOpenLpaSections] = useState({});
|
||||
const [openAppealLpas, setOpenAppealLpas] = useState({});
|
||||
const [openLpaAppeals, setOpenLpaAppeals] = useState({});
|
||||
|
||||
const percentageOf = (value, total) =>
|
||||
total ? `${(((value || 0) / total) * 100).toFixed(1)}%` : "0.0%";
|
||||
|
||||
const totalCases = useMemo(
|
||||
() =>
|
||||
statusObj.reduce((total, item) => total + (item.caseCount || 0), 0),
|
||||
[statusObj]
|
||||
);
|
||||
|
||||
const groupedAppeals = useMemo(() => {
|
||||
const grouped = statusObj.reduce((acc, item) => {
|
||||
const appealKey = item.appealType;
|
||||
|
||||
if (!acc[appealKey]) {
|
||||
acc[appealKey] = {
|
||||
appealType: item.appealType,
|
||||
appealTypeName: item.appealTypeName,
|
||||
caseCount: 0,
|
||||
lpas: {}
|
||||
};
|
||||
}
|
||||
|
||||
acc[appealKey].caseCount += item.caseCount || 0;
|
||||
|
||||
const lpaKey = item.lpaId || "unknown-lpa";
|
||||
|
||||
if (!acc[appealKey].lpas[lpaKey]) {
|
||||
acc[appealKey].lpas[lpaKey] = {
|
||||
lpaId: item.lpaId,
|
||||
lpaName: item.lpaName || "Unknown LPA",
|
||||
caseCount: 0,
|
||||
statuses: []
|
||||
};
|
||||
}
|
||||
|
||||
acc[appealKey].lpas[lpaKey].caseCount += item.caseCount || 0;
|
||||
acc[appealKey].lpas[lpaKey].statuses.push({
|
||||
statuscode: item.statuscode,
|
||||
status: item.status,
|
||||
caseCount: item.caseCount || 0
|
||||
});
|
||||
|
||||
return acc;
|
||||
}, {});
|
||||
|
||||
return Object.values(grouped)
|
||||
.map((appeal) => ({
|
||||
...appeal,
|
||||
lpas: Object.values(appeal.lpas)
|
||||
.map((lpa) => ({
|
||||
...lpa,
|
||||
statuses: lpa.statuses.sort(
|
||||
(a, b) => (b.caseCount || 0) - (a.caseCount || 0)
|
||||
)
|
||||
}))
|
||||
.sort((a, b) => (b.caseCount || 0) - (a.caseCount || 0))
|
||||
}))
|
||||
.sort((a, b) => (b.caseCount || 0) - (a.caseCount || 0));
|
||||
}, [statusObj]);
|
||||
|
||||
const groupedLpas = useMemo(() => {
|
||||
const grouped = statusObj.reduce((acc, item) => {
|
||||
const lpaKey = item.lpaId || "unknown-lpa";
|
||||
|
||||
if (!acc[lpaKey]) {
|
||||
acc[lpaKey] = {
|
||||
lpaId: item.lpaId,
|
||||
lpaName: item.lpaName || "Unknown LPA",
|
||||
caseCount: 0,
|
||||
appeals: {}
|
||||
};
|
||||
}
|
||||
|
||||
acc[lpaKey].caseCount += item.caseCount || 0;
|
||||
|
||||
const appealKey = item.appealType;
|
||||
|
||||
if (!acc[lpaKey].appeals[appealKey]) {
|
||||
acc[lpaKey].appeals[appealKey] = {
|
||||
appealType: item.appealType,
|
||||
appealTypeName: item.appealTypeName,
|
||||
caseCount: 0,
|
||||
statuses: []
|
||||
};
|
||||
}
|
||||
|
||||
acc[lpaKey].appeals[appealKey].caseCount += item.caseCount || 0;
|
||||
acc[lpaKey].appeals[appealKey].statuses.push({
|
||||
statuscode: item.statuscode,
|
||||
status: item.status,
|
||||
caseCount: item.caseCount || 0
|
||||
});
|
||||
|
||||
return acc;
|
||||
}, {});
|
||||
|
||||
return Object.values(grouped)
|
||||
.map((lpa) => ({
|
||||
...lpa,
|
||||
appeals: Object.values(lpa.appeals)
|
||||
.map((appeal) => ({
|
||||
...appeal,
|
||||
statuses: appeal.statuses.sort(
|
||||
(a, b) => (b.caseCount || 0) - (a.caseCount || 0)
|
||||
)
|
||||
}))
|
||||
.sort((a, b) => (b.caseCount || 0) - (a.caseCount || 0))
|
||||
}))
|
||||
.sort((a, b) => (b.caseCount || 0) - (a.caseCount || 0));
|
||||
}, [statusObj]);
|
||||
|
||||
const toggleAppeal = (appealType) => {
|
||||
setOpenAppeals((current) => ({
|
||||
...current,
|
||||
[appealType]: !current[appealType]
|
||||
}));
|
||||
};
|
||||
|
||||
const toggleLpaSection = (lpaId) => {
|
||||
setOpenLpaSections((current) => ({
|
||||
...current,
|
||||
[lpaId]: !current[lpaId]
|
||||
}));
|
||||
};
|
||||
|
||||
const toggleAppealLpa = (key) => {
|
||||
setOpenAppealLpas((current) => ({
|
||||
...current,
|
||||
[key]: !current[key]
|
||||
}));
|
||||
};
|
||||
|
||||
const toggleLpaAppeal = (key) => {
|
||||
setOpenLpaAppeals((current) => ({
|
||||
...current,
|
||||
[key]: !current[key]
|
||||
}));
|
||||
};
|
||||
|
||||
const sortedAppeals = useMemo(
|
||||
() => [...statusObj].sort((a, b) => (b.lpaId || 0) - (a.lpaId || 0)),
|
||||
[statusObj]
|
||||
);
|
||||
|
||||
const allStatuses = sortedAppeals.flatMap((appeal) =>
|
||||
(appeal.statuses || []).map((status) => ({
|
||||
...status,
|
||||
lpaId: appeal.lpaId,
|
||||
lpaName: appeal.lpaName
|
||||
}))
|
||||
);
|
||||
|
||||
const statusTotals = allStatuses.reduce((acc, status) => {
|
||||
if (!acc[status.statuscode]) {
|
||||
acc[status.statuscode] = {
|
||||
value: status.value,
|
||||
statuscode: status.statuscode,
|
||||
caseCount: 0
|
||||
};
|
||||
}
|
||||
|
||||
acc[status.statuscode].caseCount += status.caseCount || 0;
|
||||
return acc;
|
||||
}, {});
|
||||
const largestAppeal = groupedLpas[0];
|
||||
|
||||
const mostCommonStatus = Object.values(groupedAppeals).sort(
|
||||
(a, b) => b.caseCount - a.caseCount
|
||||
)[0];
|
||||
|
||||
const maxAppealCount = largestAppeal?.caseCount || 1;
|
||||
const maxGroupedAppealCount = groupedAppeals[0]?.caseCount || 1;
|
||||
|
||||
const allAppealsExpanded =
|
||||
groupedAppeals.length > 0 &&
|
||||
groupedAppeals.every((appeal) => openAppeals[appeal.appealType]);
|
||||
|
||||
const allLpasExpanded =
|
||||
groupedLpas.length > 0 &&
|
||||
groupedLpas.every((lpa) => openLpaSections[lpa.lpaId]);
|
||||
|
||||
const showAllAppeals = () => {
|
||||
const allOpen = {};
|
||||
groupedAppeals.forEach((appeal) => {
|
||||
allOpen[appeal.appealType] = true;
|
||||
});
|
||||
setOpenAppeals(allOpen);
|
||||
};
|
||||
|
||||
const showAllLpas = () => {
|
||||
const allOpen = {};
|
||||
groupedLpas.forEach((lpa) => {
|
||||
allOpen[lpa.lpaId] = true;
|
||||
});
|
||||
setOpenLpaSections(allOpen);
|
||||
};
|
||||
|
||||
const hideAllAppeals = () => {
|
||||
setOpenAppeals({});
|
||||
setOpenAppealLpas({});
|
||||
};
|
||||
|
||||
const hideAllLpas = () => {
|
||||
setOpenLpaSections({});
|
||||
setOpenLpaAppeals({});
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="govuk-grid-row">
|
||||
<div className="govuk-grid-column-full">
|
||||
<h1 className="">LPA Appeal case status dashboard</h1>
|
||||
|
||||
<div className="govuk-grid-row">
|
||||
<DashboardCard title="Total cases" value={totalCases} />
|
||||
<DashboardCard title="LPAs" value={groupedLpas.length} />
|
||||
<DashboardCard
|
||||
title="Largest number of appeals"
|
||||
value={largestAppeal?.caseCount || 0}
|
||||
caption={largestAppeal?.lpaName}
|
||||
/>
|
||||
<DashboardCard
|
||||
title="Most common appeal"
|
||||
value={mostCommonStatus?.caseCount || 0}
|
||||
caption={mostCommonStatus?.appealTypeName}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<section className="govuk-!-margin-top-8">
|
||||
<h2 className="govuk-heading-m">
|
||||
Appeal types and case stages by LPA
|
||||
</h2>
|
||||
<div className="govuk-accordion__controls">
|
||||
<button
|
||||
type="button"
|
||||
className="govuk-accordion__show-all"
|
||||
onClick={allLpasExpanded ? hideAllLpas : showAllLpas}
|
||||
>
|
||||
<span className="govuk-accordion__show-all-text">
|
||||
{allLpasExpanded
|
||||
? "Hide all sections"
|
||||
: "Show all sections"}
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
<div
|
||||
className="govuk-accordion"
|
||||
id="lpa-appeal-status-accordion"
|
||||
>
|
||||
{groupedLpas.map((lpa) => {
|
||||
const lpaOpen = !!openLpaSections[lpa.lpaId];
|
||||
|
||||
const width =
|
||||
((lpa.caseCount || 0) / maxAppealCount) * 100;
|
||||
|
||||
return (
|
||||
<div
|
||||
className={
|
||||
lpaOpen
|
||||
? "govuk-accordion__section govuk-accordion__section--expanded"
|
||||
: "govuk-accordion__section"
|
||||
}
|
||||
key={lpa.lpaId}
|
||||
>
|
||||
<div className="govuk-accordion__section-header">
|
||||
<h3 className="govuk-accordion__section-heading">
|
||||
<button
|
||||
type="button"
|
||||
className="govuk-accordion__section-button"
|
||||
aria-expanded={lpaOpen}
|
||||
onClick={() =>
|
||||
toggleLpaSection(lpa.lpaId)
|
||||
}
|
||||
>
|
||||
<div className="appeal-count-chart__row">
|
||||
<div className="appeal-count-chart__label">
|
||||
{lpa.lpaName} (
|
||||
{percentageOf(
|
||||
lpa.caseCount,
|
||||
totalCases
|
||||
)}
|
||||
)
|
||||
</div>
|
||||
|
||||
<div className="appeal-count-chart__bar-wrapper">
|
||||
<span
|
||||
className="appeal-count-chart__bar"
|
||||
style={{
|
||||
width: `${width}%`
|
||||
}}
|
||||
/>
|
||||
<span className="appeal-count-chart__count">
|
||||
{lpa.caseCount}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</button>
|
||||
</h3>
|
||||
</div>
|
||||
|
||||
<div
|
||||
className="govuk-accordion__section-content"
|
||||
hidden={!lpaOpen}
|
||||
>
|
||||
{lpa.appeals.map((appeal) => {
|
||||
const key = `${lpa.lpaId}-${appeal.appealType}`;
|
||||
const appealOpen =
|
||||
!!openLpaAppeals[key];
|
||||
|
||||
return (
|
||||
<div
|
||||
className="lpa-status-block"
|
||||
key={key}
|
||||
>
|
||||
<button
|
||||
type="button"
|
||||
className="lpa-status-block__button"
|
||||
aria-expanded={appealOpen}
|
||||
onClick={() =>
|
||||
toggleLpaAppeal(key)
|
||||
}
|
||||
>
|
||||
<span className="govuk-body-m">
|
||||
{appeal.appealTypeName}
|
||||
</span>
|
||||
<span className="govuk-body-m">
|
||||
{appeal.caseCount} cases
|
||||
(
|
||||
{percentageOf(
|
||||
appeal.caseCount,
|
||||
lpa.caseCount
|
||||
)}
|
||||
)
|
||||
</span>
|
||||
</button>
|
||||
|
||||
<div hidden={!appealOpen}>
|
||||
<dl className="govuk-summary-list govuk-!-margin-bottom-4">
|
||||
{appeal.statuses.map(
|
||||
(status) => (
|
||||
<div
|
||||
className="govuk-summary-list__row"
|
||||
key={
|
||||
status.statuscode
|
||||
}
|
||||
>
|
||||
<dt className="govuk-summary-list__key">
|
||||
<Link
|
||||
target="_blank"
|
||||
href={`/advancedsearchresults?apt=${appeal.appealType}&lpa=${lpa.lpaId}&statuscode=${status.statuscode}`}
|
||||
>
|
||||
{
|
||||
status.status
|
||||
}
|
||||
</Link>
|
||||
</dt>
|
||||
<dd className="govuk-summary-list__value">
|
||||
{
|
||||
status.caseCount
|
||||
}{" "}
|
||||
(
|
||||
{percentageOf(
|
||||
status.caseCount,
|
||||
appeal.caseCount
|
||||
)}
|
||||
)
|
||||
</dd>
|
||||
</div>
|
||||
)
|
||||
)}
|
||||
</dl>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section className="govuk-!-margin-top-8">
|
||||
<h2 className="govuk-heading-m">
|
||||
Case stage by LPA and Appeal Type
|
||||
</h2>
|
||||
<p className="govuk-body-s">
|
||||
Select an appeal type row to show the LPA and then case
|
||||
stage breakdown.
|
||||
</p>
|
||||
|
||||
<div className="govuk-accordion__controls">
|
||||
<button
|
||||
type="button"
|
||||
className="govuk-accordion__show-all"
|
||||
onClick={
|
||||
allAppealsExpanded ? hideAllAppeals : showAllAppeals
|
||||
}
|
||||
>
|
||||
<span className="govuk-accordion__show-all-text">
|
||||
{allAppealsExpanded
|
||||
? "Hide all sections"
|
||||
: "Show all sections"}
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
<div
|
||||
className="govuk-accordion"
|
||||
id="appeal-lpa-status-accordion"
|
||||
>
|
||||
{groupedAppeals.map((appeal) => {
|
||||
const appealOpen = !!openAppeals[appeal.appealType];
|
||||
|
||||
const width =
|
||||
((appeal.caseCount || 0) / maxGroupedAppealCount) *
|
||||
100;
|
||||
|
||||
return (
|
||||
<div
|
||||
className={
|
||||
appealOpen
|
||||
? "govuk-accordion__section govuk-accordion__section--expanded"
|
||||
: "govuk-accordion__section"
|
||||
}
|
||||
key={appeal.appealType}
|
||||
>
|
||||
<div className="govuk-accordion__section-header">
|
||||
<h2 className="govuk-accordion__section-heading">
|
||||
<button
|
||||
type="button"
|
||||
className="govuk-accordion__section-button"
|
||||
aria-expanded={appealOpen}
|
||||
onClick={() =>
|
||||
toggleAppeal(appeal.appealType)
|
||||
}
|
||||
>
|
||||
<div className="appeal-count-chart__row">
|
||||
<div className="appeal-count-chart__label">
|
||||
{appeal.appealTypeName}{" "}
|
||||
{/* {appeal.caseCount} cases */}
|
||||
(
|
||||
{percentageOf(
|
||||
appeal.caseCount,
|
||||
totalCases
|
||||
)}
|
||||
)
|
||||
</div>
|
||||
<div className="appeal-count-chart__bar-wrapper">
|
||||
<span
|
||||
className="appeal-count-chart__bar"
|
||||
style={{
|
||||
width: `${width}%`
|
||||
}}
|
||||
/>
|
||||
<span className="appeal-count-chart__count">
|
||||
{appeal.caseCount}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</button>
|
||||
</h2>
|
||||
</div>
|
||||
|
||||
<div
|
||||
className="govuk-accordion__section-content"
|
||||
hidden={!appealOpen}
|
||||
>
|
||||
{appeal.lpas.map((lpa) => {
|
||||
const lpaKey = `${appeal.appealType}-${lpa.lpaId}`;
|
||||
const lpaOpen =
|
||||
!!openAppealLpas[lpaKey];
|
||||
|
||||
return (
|
||||
<div
|
||||
className="lpa-status-block"
|
||||
key={lpaKey}
|
||||
>
|
||||
<button
|
||||
type="button"
|
||||
className="lpa-status-block__button"
|
||||
aria-expanded={lpaOpen}
|
||||
onClick={() =>
|
||||
toggleAppealLpa(lpaKey)
|
||||
}
|
||||
>
|
||||
<span className="govuk-body-m">
|
||||
{lpa.lpaName}
|
||||
</span>
|
||||
<span className="govuk-body-m">
|
||||
{lpa.caseCount} cases (
|
||||
{percentageOf(
|
||||
lpa.caseCount,
|
||||
appeal.caseCount
|
||||
)}
|
||||
)
|
||||
</span>
|
||||
</button>
|
||||
|
||||
<div hidden={!lpaOpen}>
|
||||
<dl className="govuk-summary-list govuk-!-margin-bottom-4">
|
||||
{lpa.statuses.map(
|
||||
(status) => (
|
||||
<div
|
||||
className="govuk-summary-list__row"
|
||||
key={
|
||||
status.statuscode
|
||||
}
|
||||
>
|
||||
<dt className="govuk-summary-list__key">
|
||||
<Link
|
||||
target="_blank"
|
||||
href={`/advancedsearchresults?apt=${appeal.appealType}&lpa=${lpa.lpaId}&statuscode=${status.statuscode}`}
|
||||
>
|
||||
{
|
||||
status.status
|
||||
}
|
||||
</Link>
|
||||
</dt>
|
||||
<dd className="govuk-summary-list__value">
|
||||
{
|
||||
status.caseCount
|
||||
}{" "}
|
||||
(
|
||||
{percentageOf(
|
||||
status.caseCount,
|
||||
lpa.caseCount
|
||||
)}
|
||||
)
|
||||
</dd>
|
||||
</div>
|
||||
)
|
||||
)}
|
||||
</dl>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function DashboardCard({ title, value, caption }) {
|
||||
return (
|
||||
<div className="govuk-grid-column-one-quarter">
|
||||
<div className="dashboard-card">
|
||||
<p className="govuk-body-s dashboard-card__title">{title}</p>
|
||||
<p className="govuk-heading-l dashboard-card__value">{value}</p>
|
||||
{caption && (
|
||||
<p className="govuk-body-s dashboard-card__caption">
|
||||
{caption}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,294 @@
|
||||
// // components/admin/tabs/AccountsTab.js
|
||||
// import Link from "next/link";
|
||||
|
||||
// export default function AppealsWithStatusTab({ statusObj }) {
|
||||
// return (
|
||||
// <div>
|
||||
// <h1>User Accounts</h1>
|
||||
|
||||
// <dl className="govuk-summary-list govuk-!-margin-bottom-9 results">
|
||||
// <div className="govuk-summary-list__row results-headings">
|
||||
// <dd className="govuk-summary-list__key govuk-!-font-size-16">
|
||||
// Name
|
||||
// </dd>
|
||||
// <dd className="govuk-summary-list__key govuk-!-font-size-16">
|
||||
// Last accessed
|
||||
// </dd>
|
||||
// </div>
|
||||
|
||||
// {statusObj.map((appeal) => (
|
||||
// <div key={appeal.id} className="govuk-summary-list__row">
|
||||
// <dd className="govuk-summary-list__value govuk-!-font-size-16 ">
|
||||
// <Link
|
||||
// target="_blank"
|
||||
// href={`/auth/signin2?email=${appeal.value}`}
|
||||
// >
|
||||
// {appeal.value}
|
||||
// </Link>
|
||||
// <br />
|
||||
|
||||
// <dl className="govuk-summary-list govuk-!-margin-bottom-9 govuk-!-margin-left-9 results">
|
||||
// <div className="govuk-summary-list__row results-headings">
|
||||
// <dd className="govuk-summary-list__key govuk-!-font-size-16">
|
||||
// Name
|
||||
// </dd>
|
||||
// <dd className="govuk-summary-list__key govuk-!-font-size-16">
|
||||
// Last accessed
|
||||
// </dd>
|
||||
// </div>
|
||||
|
||||
// {appeal.statuses.map((statuses) => (
|
||||
// <div
|
||||
// key={appeal.id}
|
||||
// className="govuk-summary-list__row"
|
||||
// >
|
||||
// <dd className="govuk-summary-list__value govuk-!-font-size-16 ">
|
||||
// {statuses.value}
|
||||
// </dd>
|
||||
// <dd className="govuk-summary-list__value govuk-!-font-size-16 ">
|
||||
// Total: {statuses.caseCount}
|
||||
// </dd>
|
||||
// </div>
|
||||
// ))}
|
||||
// </dl>
|
||||
// </dd>
|
||||
// <dd className="govuk-summary-list__value govuk-!-font-size-16 ">
|
||||
// Total: {appeal.caseCount}
|
||||
// </dd>
|
||||
// </div>
|
||||
// ))}
|
||||
// </dl>
|
||||
// </div>
|
||||
// );
|
||||
// }
|
||||
|
||||
import { useState } from "react";
|
||||
import Link from "next/link";
|
||||
|
||||
export default function AppealsWithStatusTab({ statusObj = [] }) {
|
||||
const [openSections, setOpenSections] = useState({});
|
||||
|
||||
const toggleSection = (index) => {
|
||||
setOpenSections((current) => ({
|
||||
...current,
|
||||
[index]: !current[index]
|
||||
}));
|
||||
};
|
||||
|
||||
const showAll = () => {
|
||||
const allOpen = {};
|
||||
|
||||
statusObj.forEach((_, index) => {
|
||||
allOpen[index] = true;
|
||||
});
|
||||
|
||||
setOpenSections(allOpen);
|
||||
};
|
||||
|
||||
const hideAll = () => {
|
||||
setOpenSections({});
|
||||
};
|
||||
|
||||
const allExpanded =
|
||||
statusObj.length > 0 &&
|
||||
statusObj.every((_, index) => openSections[index]);
|
||||
|
||||
const sortedAppeals = [...statusObj].sort(
|
||||
(a, b) => (b.caseCount || 0) - (a.caseCount || 0)
|
||||
);
|
||||
|
||||
const maxCount = sortedAppeals[0]?.caseCount || 1;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<h1 className="govuk-heading-l">Case status by appeal type</h1>
|
||||
|
||||
<div className="govuk-!-margin-bottom-6">
|
||||
<h2 className="govuk-heading-m">Case counts by appeal type</h2>
|
||||
|
||||
<dl className="appeal-count-chart">
|
||||
{sortedAppeals.map((appeal) => {
|
||||
const maxCount = sortedAppeals[0]?.caseCount || 1;
|
||||
const width =
|
||||
((appeal.caseCount || 0) / maxCount) * 100;
|
||||
|
||||
return (
|
||||
<div
|
||||
className="appeal-count-chart__row"
|
||||
key={appeal.appealType}
|
||||
>
|
||||
<dt className="appeal-count-chart__label">
|
||||
{appeal.value}
|
||||
</dt>
|
||||
|
||||
<dd className="appeal-count-chart__bar-wrapper">
|
||||
<span
|
||||
className="appeal-count-chart__bar"
|
||||
style={{ width: `${width}%` }}
|
||||
/>
|
||||
<span className="appeal-count-chart__count">
|
||||
{appeal.caseCount || 0}
|
||||
</span>
|
||||
</dd>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</dl>
|
||||
</div>
|
||||
|
||||
<div className="govuk-!-margin-bottom-6">
|
||||
<h2 className="govuk-heading-m">Case stages by appeal type</h2>
|
||||
|
||||
<dl className="appeal-stage-chart">
|
||||
{sortedAppeals.map((appeal) => (
|
||||
<div
|
||||
className="appeal-stage-chart__row"
|
||||
key={appeal.appealType}
|
||||
>
|
||||
<dt className="appeal-stage-chart__label">
|
||||
{appeal.value}
|
||||
</dt>
|
||||
|
||||
<dd className="appeal-stage-chart__bar-wrapper">
|
||||
<div
|
||||
className="appeal-stage-chart__bar"
|
||||
style={{
|
||||
width: `${((appeal.caseCount || 0) / maxCount) * 100}%`
|
||||
}}
|
||||
aria-label={`${appeal.value}, ${appeal.caseCount || 0} cases`}
|
||||
>
|
||||
{(appeal.statuses || [])
|
||||
.filter(
|
||||
(status) => status.caseCount > 0
|
||||
)
|
||||
.sort(
|
||||
(a, b) => b.caseCount - a.caseCount
|
||||
)
|
||||
.map((status, index) => (
|
||||
<span
|
||||
key={status.statuscode}
|
||||
className={`appeal-stage-chart__segment appeal-stage-chart__segment--${index % 6}`}
|
||||
style={{
|
||||
width: `${((status.caseCount || 0) / (appeal.caseCount || 1)) * 100}%`
|
||||
}}
|
||||
title={`${status.value}: ${status.caseCount}`}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<span className="appeal-stage-chart__count">
|
||||
{appeal.caseCount || 0}
|
||||
</span>
|
||||
</dd>
|
||||
</div>
|
||||
))}
|
||||
</dl>
|
||||
</div>
|
||||
|
||||
<div className="govuk-accordion__controls">
|
||||
<button
|
||||
type="button"
|
||||
className="govuk-accordion__show-all"
|
||||
onClick={allExpanded ? hideAll : showAll}
|
||||
>
|
||||
<span className="govuk-accordion__show-all-text">
|
||||
{allExpanded
|
||||
? "Hide all sections"
|
||||
: "Show all sections"}
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className="govuk-accordion" id="appeals-with-status-accordion">
|
||||
{[...statusObj]
|
||||
.sort((a, b) => (b.caseCount || 0) - (a.caseCount || 0))
|
||||
.map((appeal, index) => {
|
||||
const isOpen = !!openSections[index];
|
||||
|
||||
return (
|
||||
<div
|
||||
className={
|
||||
isOpen
|
||||
? "govuk-accordion__section govuk-accordion__section--expanded"
|
||||
: "govuk-accordion__section"
|
||||
}
|
||||
key={appeal.appealType || index}
|
||||
>
|
||||
<div className="govuk-accordion__section-header ">
|
||||
<h2 className="govuk-accordion__section-heading">
|
||||
<button
|
||||
type="button"
|
||||
className="govuk-accordion__section-button "
|
||||
id={`appeal-status-heading-${index}`}
|
||||
aria-expanded={isOpen}
|
||||
aria-controls={`appeal-status-content-${index}`}
|
||||
onClick={() => toggleSection(index)}
|
||||
>
|
||||
<span
|
||||
style={{
|
||||
display: "flex",
|
||||
justifyContent:
|
||||
"space-between",
|
||||
alignItems: "center",
|
||||
width: "100%",
|
||||
paddingRight: "20px" // leaves room for accordion icon
|
||||
}}
|
||||
>
|
||||
<span className="govuk-heading-s ">
|
||||
{appeal.value}
|
||||
</span>
|
||||
|
||||
<span
|
||||
className="govuk-body-s"
|
||||
style={{
|
||||
fontWeight: "normal"
|
||||
}}
|
||||
>
|
||||
{appeal.caseCount || 0}{" "}
|
||||
cases
|
||||
</span>
|
||||
</span>
|
||||
</button>
|
||||
</h2>
|
||||
</div>
|
||||
|
||||
<div
|
||||
id={`appeal-status-content-${index}`}
|
||||
className="govuk-accordion__section-content"
|
||||
aria-labelledby={`appeal-status-heading-${index}`}
|
||||
hidden={!isOpen}
|
||||
>
|
||||
<dl className="govuk-summary-list govuk-!-margin-left-9">
|
||||
{(appeal.statuses || [])
|
||||
.sort(
|
||||
(a, b) =>
|
||||
(b.caseCount || 0) -
|
||||
(a.caseCount || 0)
|
||||
)
|
||||
.map((status) => (
|
||||
<div
|
||||
className="govuk-summary-list__row"
|
||||
key={status.statuscode}
|
||||
>
|
||||
<dt className="govuk-summary-list__key">
|
||||
<Link
|
||||
target="_blank"
|
||||
href={`/advancedsearchresults?apt=${appeal.appealType}&statuscode=${status.statuscode}`}
|
||||
>
|
||||
{status.value}
|
||||
</Link>
|
||||
</dt>
|
||||
<dd className="govuk-summary-list__value">
|
||||
{status.caseCount || 0}
|
||||
</dd>
|
||||
</div>
|
||||
))}
|
||||
</dl>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -5,7 +5,7 @@ import { useRouter } from "next/router";
|
||||
import { useCallback, useEffect, useRef, useState } from "react";
|
||||
import { connect } from "react-redux";
|
||||
import transLookup from "../../../data/lookuptranslations.json";
|
||||
import { formatDates } from "../../utils";
|
||||
import { formatDates, getDocLink, hasOwn } from "../../utils";
|
||||
import PaginationControl from "../../../components/case/pagination";
|
||||
import DocumentLink from "../../utils/downloads";
|
||||
import { useDownloadQueue } from "../../utils/downloadmanager";
|
||||
@@ -15,177 +15,179 @@ import { sendGAEvent } from "@next/third-parties/google";
|
||||
import {
|
||||
getSearchDocumentDetails,
|
||||
getSearchDocumentDetailsPaged,
|
||||
getSearchDocumentTypes,
|
||||
getNewDocumentsPaged,
|
||||
} from "../../../actions";
|
||||
getSearchDocumentTypes
|
||||
} from "../../../actions/services/searchService";
|
||||
import { getNewDocumentsPaged } from "../../../actions/services/adminService";
|
||||
import { setCurrentPage } from "../../../store/currentView/action";
|
||||
|
||||
import { setDocumentDetails } from "../../../store/searchOutput/action";
|
||||
import resolveCrmDisplayValue from "../../../lib/i18n/crmDisplay/resolveCrmDisplayValue";
|
||||
|
||||
const getDocumentTypes = [
|
||||
{
|
||||
"Value": 846040009,
|
||||
"Label": "Main Party - Pre-Submission Docs",
|
||||
"Label": "Main Party - Pre-Submission Docs"
|
||||
},
|
||||
{
|
||||
"Value": 846040000,
|
||||
"Label": "Main Party - Submission Document",
|
||||
"Label": "Main Party - Submission Document"
|
||||
},
|
||||
{
|
||||
"Value": 846040001,
|
||||
"Label": "Main Party - Questionnaire",
|
||||
"Label": "Main Party - Questionnaire"
|
||||
},
|
||||
{
|
||||
"Value": 846040002,
|
||||
"Label": "Main Party - Statements",
|
||||
"Label": "Main Party - Statements"
|
||||
},
|
||||
{
|
||||
"Value": 846040003,
|
||||
"Label": "Main Party - Comments",
|
||||
"Label": "Main Party - Comments"
|
||||
},
|
||||
{
|
||||
"Value": 846040004,
|
||||
"Label": "Main Party - Written Statements of Evidence",
|
||||
"Label": "Main Party - Written Statements of Evidence"
|
||||
},
|
||||
{
|
||||
"Value": 846040010,
|
||||
"Label": "Main Party - Environmental Statements",
|
||||
"Label": "Main Party - Environmental Statements"
|
||||
},
|
||||
{
|
||||
"Value": 846040005,
|
||||
"Label": "Interested Party Representations",
|
||||
"Label": "Interested Party Representations"
|
||||
},
|
||||
{
|
||||
"Value": 846040006,
|
||||
"Label": "Correspondence",
|
||||
"Label": "Correspondence"
|
||||
},
|
||||
{
|
||||
"Value": 846040008,
|
||||
"Label": "Inspector Notes",
|
||||
"Label": "Inspector Notes"
|
||||
},
|
||||
{
|
||||
"Value": 846040007,
|
||||
"Label": "Final Decision/Report",
|
||||
"Label": "Final Decision/Report"
|
||||
},
|
||||
{
|
||||
"Value": 846040011,
|
||||
"Label": "Post Decision Correspondence",
|
||||
"Label": "Post Decision Correspondence"
|
||||
},
|
||||
{
|
||||
"Value": 846040012,
|
||||
"Label": "High Court Challenge Correspondence",
|
||||
"Label": "High Court Challenge Correspondence"
|
||||
},
|
||||
{
|
||||
"Value": 846040013,
|
||||
"Label": "Event - Correspondence",
|
||||
"Label": "Event - Correspondence"
|
||||
},
|
||||
{
|
||||
"Value": 846040014,
|
||||
"Label": "Event - Documents",
|
||||
"Label": "Event - Documents"
|
||||
},
|
||||
{
|
||||
"Value": 846040015,
|
||||
"Label": "Pre-Application - General",
|
||||
"Label": "Pre-Application - General"
|
||||
},
|
||||
{
|
||||
"Value": 846040016,
|
||||
"Label": "Pre-Application - EIA Screening",
|
||||
"Label": "Pre-Application - EIA Screening"
|
||||
},
|
||||
{
|
||||
"Value": 846040017,
|
||||
"Label": "Pre-Application - EIA Scoping",
|
||||
"Label": "Pre-Application - EIA Scoping"
|
||||
},
|
||||
{
|
||||
"Value": 846040018,
|
||||
"Label": "EIA Screening",
|
||||
"Label": "EIA Screening"
|
||||
},
|
||||
{
|
||||
"Value": 846040019,
|
||||
"Label": "EIA Scoping",
|
||||
"Label": "EIA Scoping"
|
||||
},
|
||||
{
|
||||
"Value": 846040020,
|
||||
"Label": "Pre-Application Services Documents",
|
||||
"Label": "Pre-Application Services Documents"
|
||||
},
|
||||
{
|
||||
"Value": 846040021,
|
||||
"Label": "Notification",
|
||||
"Label": "Notification"
|
||||
},
|
||||
{
|
||||
"Value": 846040022,
|
||||
"Label":
|
||||
"Submission - Environmental Statement - written statement and NTS",
|
||||
"Submission - Environmental Statement - written statement and NTS"
|
||||
},
|
||||
{
|
||||
"Value": 846040023,
|
||||
"Label": "Submission - Environmental Statement - Appendices",
|
||||
"Label": "Submission - Environmental Statement - Appendices"
|
||||
},
|
||||
{
|
||||
"Value": 846040024,
|
||||
"Label": "Submission - Environmental Statement - Figures",
|
||||
"Label": "Submission - Environmental Statement - Figures"
|
||||
},
|
||||
{
|
||||
"Value": 846040025,
|
||||
"Label": "Submission - Draft Infrastructure Consent Orders",
|
||||
"Label": "Submission - Draft Infrastructure Consent Orders"
|
||||
},
|
||||
{
|
||||
"Value": 846040026,
|
||||
"Label": "Submission - Compulsory Acquisition Information",
|
||||
"Label": "Submission - Compulsory Acquisition Information"
|
||||
},
|
||||
{
|
||||
"Value": 846040027,
|
||||
"Label": "Submission - Application Documents",
|
||||
"Label": "Submission - Application Documents"
|
||||
},
|
||||
{
|
||||
"Value": 846040028,
|
||||
"Label": "Examination Notices",
|
||||
"Label": "Examination Notices"
|
||||
},
|
||||
{
|
||||
"Value": 846040029,
|
||||
"Label": "Local/Marine Impact Reports",
|
||||
"Label": "Local/Marine Impact Reports"
|
||||
},
|
||||
{
|
||||
"Value": 846040030,
|
||||
"Label": "Submission - Further Information",
|
||||
"Label": "Submission - Further Information"
|
||||
},
|
||||
{
|
||||
"Value": 846040031,
|
||||
"Label": "Formal Variation requests",
|
||||
"Label": "Formal Variation requests"
|
||||
},
|
||||
{
|
||||
"Value": 846040032,
|
||||
"Label": "Further Information - Interested Party Representations",
|
||||
"Label": "Further Information - Interested Party Representations"
|
||||
},
|
||||
{
|
||||
"Value": 846040033,
|
||||
"Label": "Hearing Statements",
|
||||
"Label": "Hearing Statements"
|
||||
},
|
||||
{
|
||||
"Value": 846040034,
|
||||
"Label": "Events - Recordings",
|
||||
"Label": "Events - Recordings"
|
||||
},
|
||||
{
|
||||
"Value": 846040035,
|
||||
"Label": "Internal Correspondence",
|
||||
"Label": "Internal Correspondence"
|
||||
},
|
||||
{
|
||||
"Value": 846040036,
|
||||
"Label": "Consultation Response",
|
||||
},
|
||||
"Label": "Consultation Response"
|
||||
}
|
||||
];
|
||||
|
||||
const getOrigin = [
|
||||
{
|
||||
"Value": 846040000,
|
||||
"Label": "MDU",
|
||||
"Label": "MDU"
|
||||
},
|
||||
{
|
||||
"Value": 846040001,
|
||||
"Label": "Portal",
|
||||
"Label": "Portal"
|
||||
},
|
||||
{
|
||||
"Value": 846040002,
|
||||
"Label": "Manual",
|
||||
},
|
||||
"Label": "Manual"
|
||||
}
|
||||
];
|
||||
|
||||
const DocumentsTab = (props) => {
|
||||
@@ -200,7 +202,7 @@ const DocumentsTab = (props) => {
|
||||
setDocumentDetails,
|
||||
setCurrentPage,
|
||||
docsOffline,
|
||||
showFilteredDocs,
|
||||
showFilteredDocs
|
||||
} = props;
|
||||
|
||||
const router = useRouter();
|
||||
@@ -236,7 +238,7 @@ const DocumentsTab = (props) => {
|
||||
|
||||
setCheckedItems((prev) => ({
|
||||
...prev,
|
||||
[name]: checked,
|
||||
[name]: checked
|
||||
}));
|
||||
setSelectAll(false);
|
||||
};
|
||||
@@ -246,7 +248,7 @@ const DocumentsTab = (props) => {
|
||||
|
||||
setCheckedOriginItems((prev) => ({
|
||||
...prev,
|
||||
[name]: checked,
|
||||
[name]: checked
|
||||
}));
|
||||
setSelectOriginAll(false);
|
||||
};
|
||||
@@ -305,37 +307,7 @@ const DocumentsTab = (props) => {
|
||||
setSelectedDocumentOrigin("all")
|
||||
);
|
||||
};
|
||||
let ShowDocLinks = false;
|
||||
let checkShowDocLinks = docsOffline != false ? true : false;
|
||||
|
||||
const getDocLink = (docsOffline) => {
|
||||
var startTime = docsOffline.split(",")[0];
|
||||
var endTime = docsOffline.split(",")[1];
|
||||
|
||||
// console.log(startTime);
|
||||
// console.log(endTime);
|
||||
|
||||
var currentDate = new Date();
|
||||
|
||||
var startDate = new Date(currentDate.getTime());
|
||||
startDate.setHours(startTime.split(":")[0]);
|
||||
startDate.setMinutes(startTime.split(":")[1]);
|
||||
startDate.setSeconds(startTime.split(":")[2]);
|
||||
|
||||
var endDate = new Date(currentDate.getTime());
|
||||
endDate.setHours(endTime.split(":")[0]);
|
||||
endDate.setMinutes(endTime.split(":")[1]);
|
||||
endDate.setSeconds(endTime.split(":")[2]);
|
||||
|
||||
// console.log(startDate);
|
||||
// console.log(endDate);
|
||||
// console.log(currentDate);
|
||||
|
||||
var valid = startDate < currentDate && endDate > currentDate;
|
||||
ShowDocLinks = valid;
|
||||
};
|
||||
|
||||
checkShowDocLinks && getDocLink(docsOffline);
|
||||
let ShowDocLinks = getDocLink(docsOffline);
|
||||
|
||||
const FilteredDocumentView = (documentDetailsArr) => {
|
||||
documentDetailsArr = documentDetailsArr.value;
|
||||
@@ -427,19 +399,11 @@ const DocumentsTab = (props) => {
|
||||
className="govuk-label-s govuk-checkboxes__label"
|
||||
htmlFor={item.Value}
|
||||
>
|
||||
{router.locale == "cy"
|
||||
? jsonpath({
|
||||
path:
|
||||
'$..[?(@ && @.value=="' +
|
||||
item.Label +
|
||||
'")].value_cy',
|
||||
json: transLookup,
|
||||
eval: true,
|
||||
})
|
||||
: item.Label ||
|
||||
t(
|
||||
"case:summary-no-date-entered-label"
|
||||
)}{" "}
|
||||
{resolveCrmDisplayValue({
|
||||
value: item.Label,
|
||||
locale,
|
||||
translations: transLookup
|
||||
})}
|
||||
</label>
|
||||
</div>
|
||||
);
|
||||
@@ -500,19 +464,11 @@ const DocumentsTab = (props) => {
|
||||
className="govuk-label-s govuk-checkboxes__label"
|
||||
htmlFor={"origin_" + item.Value}
|
||||
>
|
||||
{router.locale == "cy"
|
||||
? jsonpath({
|
||||
path:
|
||||
'$..[?(@ && @.value=="' +
|
||||
item.Label +
|
||||
'")].value_cy',
|
||||
json: transLookup,
|
||||
eval: true,
|
||||
})
|
||||
: item.Label ||
|
||||
t(
|
||||
"case:summary-no-date-entered-label"
|
||||
)}{" "}
|
||||
{resolveCrmDisplayValue({
|
||||
value: item.Label,
|
||||
locale,
|
||||
translations: transLookup
|
||||
})}
|
||||
</label>
|
||||
</div>
|
||||
);
|
||||
@@ -526,7 +482,7 @@ const DocumentsTab = (props) => {
|
||||
const checkedValues = [
|
||||
...document.querySelectorAll(
|
||||
".govuk-checkboxes__input:checked"
|
||||
),
|
||||
)
|
||||
].map((e) => e.value);
|
||||
|
||||
const origins = checkedValues
|
||||
@@ -727,7 +683,7 @@ const DocumentsTab = (props) => {
|
||||
incidentid +
|
||||
"')]",
|
||||
json: item,
|
||||
eval: true,
|
||||
eval: true
|
||||
});
|
||||
detailsObj = item;
|
||||
return (
|
||||
@@ -784,7 +740,7 @@ const DocumentsTab = (props) => {
|
||||
// )}
|
||||
// :
|
||||
// </span>
|
||||
// {_.has(
|
||||
// {hasOwn(
|
||||
// detailsObj,
|
||||
// "pinswg_name"
|
||||
// )
|
||||
@@ -819,7 +775,7 @@ const DocumentsTab = (props) => {
|
||||
)}
|
||||
:
|
||||
</span>
|
||||
{_.has(
|
||||
{hasOwn(
|
||||
detailsObj,
|
||||
"pinswg_name"
|
||||
)
|
||||
@@ -835,7 +791,7 @@ const DocumentsTab = (props) => {
|
||||
)}
|
||||
:
|
||||
</span>
|
||||
{_.has(
|
||||
{hasOwn(
|
||||
detailsObj,
|
||||
"pinswg_name"
|
||||
)
|
||||
@@ -852,22 +808,15 @@ const DocumentsTab = (props) => {
|
||||
:
|
||||
</span>
|
||||
|
||||
{router.locale == "cy"
|
||||
? jsonpath({
|
||||
path:
|
||||
'$..[?(@ && @.value=="' +
|
||||
detailsObj[
|
||||
{resolveCrmDisplayValue(
|
||||
{
|
||||
value: detailsObj[
|
||||
"pinswg_isharedocumentlocations@OData.Community.Display.V1.FormattedValue"
|
||||
] +
|
||||
'")].value_cy',
|
||||
json: transLookup,
|
||||
eval: true,
|
||||
})
|
||||
: detailsObj[
|
||||
"pinswg_isharedocumentlocations@OData.Community.Display.V1.FormattedValue"
|
||||
] ||
|
||||
t(
|
||||
"case:summary-no-date-entered-label"
|
||||
],
|
||||
locale,
|
||||
translations:
|
||||
transLookup
|
||||
}
|
||||
)}
|
||||
</dd>
|
||||
<dd className="govuk-summary-list__value govuk-!-font-size-14">
|
||||
@@ -878,7 +827,7 @@ const DocumentsTab = (props) => {
|
||||
:
|
||||
</span>
|
||||
|
||||
{_.has(
|
||||
{hasOwn(
|
||||
detailsObj,
|
||||
"createdon"
|
||||
)
|
||||
@@ -966,17 +915,16 @@ const DocumentsTab = (props) => {
|
||||
)
|
||||
.then((data) => data)
|
||||
.then((data) => {
|
||||
props.setDocumentDetails(data);
|
||||
setDocumentDetails(data);
|
||||
setShowSpinnerState(false);
|
||||
});
|
||||
},
|
||||
[
|
||||
props.incidentid,
|
||||
selectedOption,
|
||||
selectedDocumentType,
|
||||
selectedWeeks,
|
||||
selectedDocumentOrigin,
|
||||
props.setDocumentDetails,
|
||||
setDocumentDetails
|
||||
]
|
||||
);
|
||||
|
||||
@@ -987,7 +935,7 @@ const DocumentsTab = (props) => {
|
||||
orderBy,
|
||||
fieldSort
|
||||
).then((data) => {
|
||||
props.setDocumentDetails(data);
|
||||
setDocumentDetails(data);
|
||||
return data;
|
||||
});
|
||||
|
||||
@@ -1090,7 +1038,7 @@ const DocumentsTab = (props) => {
|
||||
selectedDocumentType,
|
||||
selectedWeeks
|
||||
).then((data) => {
|
||||
props.setDocumentDetails(data);
|
||||
setDocumentDetails(data);
|
||||
setDocumentSearchState(true);
|
||||
|
||||
return data;
|
||||
@@ -1102,16 +1050,14 @@ const DocumentsTab = (props) => {
|
||||
//const searchDocumentResultsObj = docDetailsObj();
|
||||
}, [
|
||||
incidentid,
|
||||
props.setDocumentDetails,
|
||||
setDocumentDetails,
|
||||
selectedOption,
|
||||
selectedDocumentType,
|
||||
fieldSortState,
|
||||
orderByState,
|
||||
getDocumentTypes,
|
||||
getOrigin,
|
||||
getDocumentResults,
|
||||
lang,
|
||||
selectedWeeks,
|
||||
selectedWeeks
|
||||
]);
|
||||
|
||||
function countFieldValue(obj, field, targetValue) {
|
||||
@@ -1137,9 +1083,7 @@ const DocumentsTab = (props) => {
|
||||
return (
|
||||
<div className="govuk-grid-row">
|
||||
<div className="govuk-grid-column-full">
|
||||
<h2 className="govuk-heading-m ">
|
||||
{t("case:documents-heading-label")}
|
||||
</h2>
|
||||
<h1 className="">{t("case:documents-heading-label")}</h1>
|
||||
{/* <div className="">
|
||||
MDU :{" "}
|
||||
{countFieldValue(
|
||||
@@ -1164,7 +1108,7 @@ const DocumentsTab = (props) => {
|
||||
<select
|
||||
onChange={(e) => {
|
||||
setSelectedWeeks(e.target.value);
|
||||
props.setCurrentPage(1);
|
||||
setCurrentPage(1);
|
||||
}}
|
||||
value={selectedWeeks}
|
||||
className="govuk-select"
|
||||
@@ -1196,7 +1140,7 @@ const DocumentsTab = (props) => {
|
||||
|
||||
const mapStateToProps = (state) => {
|
||||
return {
|
||||
...state,
|
||||
...state
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1207,7 +1151,7 @@ const mapDispatchToProps = (dispatch) => {
|
||||
},
|
||||
setCurrentPage: (currentPage) => {
|
||||
dispatch(setCurrentPage(currentPage));
|
||||
},
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -5,8 +5,11 @@ import { bytesToSize } from "../../../components/utils";
|
||||
import {
|
||||
deleteMyRepresentationsFromBlob,
|
||||
deleteAwaitingSubmissionsFromBlob,
|
||||
sendRepCompleteMessage,
|
||||
} from "../../../actions";
|
||||
getRepsFromBlobProxy
|
||||
} from "../../../actions/services/documentService";
|
||||
import { sendRepCompleteMessage } from "../../../actions/services/portalService";
|
||||
import { parseCookies } from "nookies";
|
||||
import { consoleLogger } from "../../../actions/core/logger";
|
||||
|
||||
import { formatBlobDates } from "../utils/adminHelper";
|
||||
|
||||
@@ -21,6 +24,33 @@ export default function StorageTab({ data, repCompleteCount }) {
|
||||
setShowTmpFile(newState);
|
||||
};
|
||||
|
||||
const deleteRepItem = (containerID, caseID, repfile) => {
|
||||
let cookies = parseCookies();
|
||||
//console.log("sssss", containerID, caseID, repfile);
|
||||
|
||||
deleteMyRepresentationsFromBlob(containerID, caseID, repfile)
|
||||
.then((data) => {
|
||||
return data;
|
||||
})
|
||||
.then(() => {
|
||||
getRepsFromBlobProxy(containerID)
|
||||
.then((data) => {
|
||||
setMyRepresentations(data);
|
||||
setMyRepresentationsDetails(data);
|
||||
})
|
||||
.catch((error) => {
|
||||
consoleLogger(error);
|
||||
return null;
|
||||
})
|
||||
.then(() => {
|
||||
setCurrentView({
|
||||
"viewName": "My Representations",
|
||||
"viewKey": "myRepresentations"
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
<h1>Storage Account Contents</h1>
|
||||
@@ -150,7 +180,7 @@ export default function StorageTab({ data, repCompleteCount }) {
|
||||
headers:
|
||||
{
|
||||
"Content-Type":
|
||||
"application/json",
|
||||
"application/json"
|
||||
},
|
||||
body: JSON.stringify(
|
||||
{
|
||||
@@ -159,18 +189,18 @@ export default function StorageTab({ data, repCompleteCount }) {
|
||||
blobName:
|
||||
folder
|
||||
.repJsonBlob
|
||||
.name,
|
||||
.name
|
||||
}
|
||||
),
|
||||
)
|
||||
}
|
||||
);
|
||||
const result =
|
||||
await response.json();
|
||||
if (response.ok) {
|
||||
alert(
|
||||
(alert(
|
||||
"repComplete removed!"
|
||||
),
|
||||
window.location.reload();
|
||||
window.location.reload());
|
||||
// Optionally refresh the page or update UI state here
|
||||
} else {
|
||||
alert(
|
||||
|
||||
@@ -5,9 +5,9 @@ import { PrismaClient } from "@prisma/client";
|
||||
import CryptoJS from "crypto-js";
|
||||
import { getUpToLastSlash, streamToString } from "../utils/adminHelper";
|
||||
import { listContainersForUser } from "../../../actions/azurestorage";
|
||||
|
||||
import pLimit from "p-limit";
|
||||
const prisma = global.prisma || new PrismaClient();
|
||||
|
||||
const WORDKEY = process.env.HASHKEY;
|
||||
/**
|
||||
* Generate HMAC hash for blob API link.
|
||||
*/
|
||||
@@ -34,8 +34,10 @@ export async function fetchAdminStorageData() {
|
||||
|
||||
const users = await prisma.user.findMany();
|
||||
|
||||
const limit = pLimit(5);
|
||||
let data = await Promise.all(
|
||||
users.map(async (user) => {
|
||||
return limit(async () => {
|
||||
const containers = await listContainersForUser(
|
||||
blobServiceClient,
|
||||
`${user.id}`,
|
||||
@@ -54,7 +56,9 @@ export async function fetchAdminStorageData() {
|
||||
`/api/file/downloadblob?container=${
|
||||
container.container
|
||||
}&casefolderID=${folderPath}&blobname=${blob.name
|
||||
.substring(blob.name.lastIndexOf("/") + 1)
|
||||
.substring(
|
||||
blob.name.lastIndexOf("/") + 1
|
||||
)
|
||||
.trim()}`,
|
||||
process.env.HASHKEY
|
||||
);
|
||||
@@ -62,12 +66,13 @@ export async function fetchAdminStorageData() {
|
||||
const fileNameOnly = blob.name.substring(
|
||||
blob.name.lastIndexOf("/") + 1
|
||||
);
|
||||
const isTmpFile = fileNameOnly.startsWith("TMP-");
|
||||
const isTmpFile =
|
||||
fileNameOnly.startsWith("TMP-");
|
||||
|
||||
const blobWithHash = {
|
||||
...blob,
|
||||
hashedfilepath,
|
||||
isTmpFile,
|
||||
isTmpFile
|
||||
};
|
||||
|
||||
let folderGroup = acc.find(
|
||||
@@ -80,7 +85,7 @@ export async function fetchAdminStorageData() {
|
||||
hasRepJson: false,
|
||||
repJsonBlob: null,
|
||||
repComplete: false,
|
||||
hasTmpFile: false,
|
||||
hasTmpFile: false
|
||||
};
|
||||
acc.push(folderGroup);
|
||||
}
|
||||
@@ -92,7 +97,9 @@ export async function fetchAdminStorageData() {
|
||||
}
|
||||
|
||||
// rep.json handling
|
||||
if (blob.name.toLowerCase().endsWith("rep.json")) {
|
||||
if (
|
||||
blob.name.toLowerCase().endsWith("rep.json")
|
||||
) {
|
||||
folderGroup.hasRepJson = true;
|
||||
folderGroup.repJsonBlob = blobWithHash;
|
||||
|
||||
@@ -137,9 +144,10 @@ export async function fetchAdminStorageData() {
|
||||
? {
|
||||
id: user.id,
|
||||
email: user.email,
|
||||
containers: containersWithHashes,
|
||||
containers: containersWithHashes
|
||||
}
|
||||
: null;
|
||||
});
|
||||
})
|
||||
);
|
||||
|
||||
@@ -150,7 +158,7 @@ export async function fetchAdminStorageData() {
|
||||
.map((user) => ({
|
||||
id: user.id,
|
||||
email: user.email,
|
||||
created: user.emailVerified?.toLocaleString("en-GB") || "",
|
||||
created: user.emailVerified?.toLocaleString("en-GB") || ""
|
||||
}));
|
||||
|
||||
let repCompleteCount = 0;
|
||||
|
||||
+274
-1133
File diff suppressed because it is too large
Load Diff
+3
-8
@@ -42,15 +42,10 @@ const Case = (props) => {
|
||||
documentDetailsObj={props.documentDetailsObj}
|
||||
showFilteredDocs={props.showFilteredDocs}
|
||||
showLoginCheck={props.showLoginCheck}
|
||||
eventsObj={props.eventsObj}
|
||||
mediaObj={props.mediaObj}
|
||||
mapTarget={props.mapTarget}
|
||||
/>
|
||||
{showRepresentations == true && (
|
||||
<RepresentationList
|
||||
incidentid={props.incidentid}
|
||||
caseReference={props.caseReference}
|
||||
representationsObj={props.representationsObj}
|
||||
documentDetailsObj={props.documentDetailsObj}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
@@ -15,12 +15,22 @@ export default function CaseNoticeBanner(props) {
|
||||
const bannerOpenCookie = typeof cookie.get("pedwNotice") == "undefined";
|
||||
let messagesObjArr = messagesObj.value;
|
||||
|
||||
let todaysDate = new Date();
|
||||
|
||||
return (
|
||||
<>
|
||||
{messagesObjArr.map((message, index) => (
|
||||
<div className="govuk-warning-text noticebanner" key={index}>
|
||||
<div key={index}>
|
||||
{todaysDate.toISOString() >= message.scheduledstart &&
|
||||
todaysDate.toISOString() <= message.scheduledend && (
|
||||
<div
|
||||
className="govuk-warning-text noticebanner"
|
||||
key={index}
|
||||
>
|
||||
<strong className="govuk-warning-text__text">
|
||||
<span className="govuk-visually-hidden">Warning</span>
|
||||
<span className="govuk-visually-hidden">
|
||||
{t("case:notice-label")}
|
||||
</span>
|
||||
</strong>
|
||||
<div>
|
||||
<div className=" govuk-body-s">
|
||||
@@ -49,7 +59,9 @@ export default function CaseNoticeBanner(props) {
|
||||
: message.subject
|
||||
.split("Banner ")[1]
|
||||
.split(";")[0]
|
||||
: message.subject.split("Banner ")[1]}
|
||||
: message.subject.split(
|
||||
"Banner "
|
||||
)[1]}
|
||||
</h2>
|
||||
</div>
|
||||
<div className="govuk-body-s">
|
||||
@@ -59,16 +71,24 @@ export default function CaseNoticeBanner(props) {
|
||||
) || []
|
||||
).length > 0
|
||||
? router.locale == "cy"
|
||||
? message.description.split(">>>")[1]
|
||||
: message.description.split(">>>")[0]
|
||||
? message.description.split(
|
||||
">>>"
|
||||
)[1]
|
||||
: message.description.split(
|
||||
">>>"
|
||||
)[0]
|
||||
: (
|
||||
message.description.match(
|
||||
new RegExp(";", "g")
|
||||
) || []
|
||||
).length > 0
|
||||
? router.locale == "cy"
|
||||
? message.description.split(";")[1]
|
||||
: message.description.split(";")[0]
|
||||
? message.description.split(
|
||||
";"
|
||||
)[1]
|
||||
: message.description.split(
|
||||
";"
|
||||
)[0]
|
||||
: message.description}
|
||||
</div>
|
||||
<div className="govuk-body-xs govuk-!-margin-bottom-0 ">
|
||||
@@ -77,6 +97,8 @@ export default function CaseNoticeBanner(props) {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
</>
|
||||
);
|
||||
|
||||
+35
-424
@@ -5,20 +5,21 @@ import { useRouter } from "next/router";
|
||||
import { useCallback, useEffect, useRef, useState } from "react";
|
||||
import { connect } from "react-redux";
|
||||
import transLookup from "../../data/lookuptranslations.json";
|
||||
import { formatDates } from "../utils";
|
||||
import { formatDates, getDocLink, hasOwn } from "../utils";
|
||||
import PaginationControl from "./pagination";
|
||||
import { sendGAEvent } from "@next/third-parties/google";
|
||||
|
||||
import {
|
||||
getSearchDocumentDetails,
|
||||
getSearchDocumentDetailsPaged,
|
||||
getSearchDocumentTypes,
|
||||
} from "../../actions";
|
||||
getSearchDocumentTypes
|
||||
} from "../../actions/services/searchService";
|
||||
import { setCurrentPage } from "../../store/currentView/action";
|
||||
|
||||
import { setDocumentDetails } from "../../store/searchOutput/action";
|
||||
import DocumentLink from "../utils/downloads";
|
||||
import { useDownloadQueue } from "../utils/downloadmanager";
|
||||
import resolveCrmDisplayValue from "../../lib/i18n/crmDisplay/resolveCrmDisplayValue";
|
||||
|
||||
const DocumentDetails = (props) => {
|
||||
let { t, lang } = useTranslation();
|
||||
@@ -32,12 +33,14 @@ const DocumentDetails = (props) => {
|
||||
setDocumentDetails,
|
||||
setCurrentPage,
|
||||
docsOffline,
|
||||
showFilteredDocs,
|
||||
showFilteredDocs
|
||||
} = props;
|
||||
|
||||
const router = useRouter();
|
||||
const { locale } = router;
|
||||
|
||||
const appealType = props.currentView?.caseReference?.appealType;
|
||||
|
||||
var documentDetailsArr = documentDetailsObj || [];
|
||||
const { startDownload, getStatus } = useDownloadQueue(3);
|
||||
const [selectedOption, setSelectedOption] = useState(10);
|
||||
@@ -57,7 +60,7 @@ const DocumentDetails = (props) => {
|
||||
|
||||
setCheckedItems((prev) => ({
|
||||
...prev,
|
||||
[name]: checked,
|
||||
[name]: checked
|
||||
}));
|
||||
setSelectAll(false);
|
||||
};
|
||||
@@ -90,383 +93,7 @@ const DocumentDetails = (props) => {
|
||||
setCurrentPage(1)
|
||||
);
|
||||
};
|
||||
let ShowDocLinks = false;
|
||||
let checkShowDocLinks = docsOffline != false ? true : false;
|
||||
|
||||
const getDocLink = (docsOffline) => {
|
||||
var startTime = docsOffline.split(",")[0];
|
||||
var endTime = docsOffline.split(",")[1];
|
||||
|
||||
// console.log(startTime);
|
||||
// console.log(endTime);
|
||||
|
||||
var currentDate = new Date();
|
||||
|
||||
var startDate = new Date(currentDate.getTime());
|
||||
startDate.setHours(startTime.split(":")[0]);
|
||||
startDate.setMinutes(startTime.split(":")[1]);
|
||||
startDate.setSeconds(startTime.split(":")[2]);
|
||||
|
||||
var endDate = new Date(currentDate.getTime());
|
||||
endDate.setHours(endTime.split(":")[0]);
|
||||
endDate.setMinutes(endTime.split(":")[1]);
|
||||
endDate.setSeconds(endTime.split(":")[2]);
|
||||
|
||||
// console.log(startDate);
|
||||
// console.log(endDate);
|
||||
// console.log(currentDate);
|
||||
|
||||
var valid = startDate < currentDate && endDate > currentDate;
|
||||
ShowDocLinks = valid;
|
||||
};
|
||||
|
||||
checkShowDocLinks && getDocLink(docsOffline);
|
||||
|
||||
const DocumentView = (documentDetailsArr) => {
|
||||
documentDetailsArr = documentDetailsArr.value;
|
||||
|
||||
return (
|
||||
<>
|
||||
<p>
|
||||
{documentDetailsObj["@odata.count"] > 1
|
||||
? t("case:documents-count-label-1")
|
||||
: t("case:documents-count-label-1a")}{" "}
|
||||
{documentDetailsObj["@odata.count"]}{" "}
|
||||
{documentDetailsObj["@odata.count"] > 1
|
||||
? t("case:documents-count-label-2")
|
||||
: t("case:documents-count-label-2a")}
|
||||
</p>
|
||||
<div className="documentFilters govuk-!-margin-top-5">
|
||||
<div
|
||||
id="recordDocumentTypeSelect"
|
||||
className="govuk-grid-row govuk-!-margin-left-0"
|
||||
>
|
||||
<div className="govuk-form-group">
|
||||
<label
|
||||
className="govuk-label-s "
|
||||
htmlFor="showDocumentType"
|
||||
>
|
||||
{t("case:documents-show-label")}
|
||||
<select
|
||||
onChange={(e) => {
|
||||
setSelectedDocumentType(e.target.value);
|
||||
setCurrentPage(1);
|
||||
}}
|
||||
value={selectedDocumentType}
|
||||
className="govuk-select"
|
||||
id="showDocumentType"
|
||||
name="showDocumentType"
|
||||
>
|
||||
<option value="all" key="00">
|
||||
{router.locale == "cy"
|
||||
? jsonpath({
|
||||
path: '$..[?(@ && @.value=="All")].value_cy',
|
||||
json: transLookup,
|
||||
eval: true,
|
||||
})
|
||||
: "All"}
|
||||
</option>
|
||||
{documentTypes.map((item, key) => {
|
||||
return (
|
||||
<option
|
||||
key={key}
|
||||
value={
|
||||
item.pinswg_isharedocumentlocations
|
||||
}
|
||||
>
|
||||
{router.locale == "cy"
|
||||
? jsonpath({
|
||||
path:
|
||||
'$..[?(@ && @.value=="' +
|
||||
item.pinswg_isharedocumentlocationsLabel +
|
||||
'")].value_cy',
|
||||
json: transLookup,
|
||||
eval: true,
|
||||
})
|
||||
: item.pinswg_isharedocumentlocationsLabel ||
|
||||
t(
|
||||
"case:summary-no-date-entered-label"
|
||||
)}
|
||||
</option>
|
||||
);
|
||||
})}
|
||||
</select>
|
||||
{t("case:documents-count-label-2")}
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
{documentDetailsObj["@odata.count"] > 5 && (
|
||||
<div
|
||||
id="recordCountSelect"
|
||||
className="govuk-grid-row govuk-!-margin-left-0"
|
||||
>
|
||||
<div className="govuk-form-group">
|
||||
<label
|
||||
className="govuk-label-s "
|
||||
htmlFor="showNumberOfRecords"
|
||||
>
|
||||
{t(
|
||||
"search:searchresults-show-records-label-a"
|
||||
)}
|
||||
<select
|
||||
onChange={(e) => {
|
||||
setSelectedOption(e.target.value);
|
||||
setCurrentPage(1);
|
||||
}}
|
||||
value={selectedOption}
|
||||
className="govuk-select"
|
||||
id="showNumberOfRecords"
|
||||
name="showNumberOfRecords"
|
||||
>
|
||||
<option value="5">5</option>
|
||||
<option value="10">10</option>
|
||||
<option value="20">20</option>
|
||||
<option value="30">30</option>
|
||||
<option value="50">50</option>
|
||||
</select>{" "}
|
||||
{t(
|
||||
"search:searchresults-show-records-label-b"
|
||||
)}
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
{ShowDocLinks && (
|
||||
<div className="govuk-warning-text ">
|
||||
<span
|
||||
className="govuk-warning-text__icon"
|
||||
aria-hidden="true"
|
||||
>
|
||||
!
|
||||
</span>
|
||||
<strong className="govuk-warning-text__text govuk-!-margin-top-2">
|
||||
<span className="govuk-visually-hidden">
|
||||
Notice
|
||||
</span>
|
||||
|
||||
{t("case:documents-not-available-label")}
|
||||
</strong>
|
||||
</div>
|
||||
)}
|
||||
<dl className="documentList govuk-summary-list govuk-!-margin-bottom-9 results">
|
||||
<div className="govuk-summary-list__row results-headings">
|
||||
<dd className="govuk-summary-list__key govuk-!-font-size-16 ">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => sortDataBy("pinswg_name")}
|
||||
className={
|
||||
orderByState == "pinswg_name"
|
||||
? fieldSortState == "asc"
|
||||
? `govuk-link govuk-link--no-underline govuk-!-font-weight-bold govuk-!-font-size-16 sortAsc`
|
||||
: `govuk-link govuk-link--no-underline govuk-!-font-weight-bold govuk-!-font-size-16 sortDesc`
|
||||
: `govuk-link govuk-link--no-underline govuk-!-font-weight-bold govuk-!-font-size-16`
|
||||
}
|
||||
>
|
||||
{t("case:documents-name-label")}
|
||||
</button>
|
||||
</dd>
|
||||
<dd className="govuk-summary-list__key govuk-!-font-size-16">
|
||||
{/* {t("case:documents-doc-type-label")} */}
|
||||
<button
|
||||
type="button"
|
||||
onClick={() =>
|
||||
sortDataBy("pinswg_isharedocumentlocations")
|
||||
}
|
||||
className={
|
||||
orderByState ==
|
||||
"pinswg_isharedocumentlocations"
|
||||
? fieldSortState == "asc"
|
||||
? `govuk-link govuk-link--no-underline govuk-!-font-weight-bold govuk-!-font-size-16 sortAsc`
|
||||
: `govuk-link govuk-link--no-underline govuk-!-font-weight-bold govuk-!-font-size-16 sortDesc`
|
||||
: `govuk-link govuk-link--no-underline govuk-!-font-weight-bold govuk-!-font-size-16`
|
||||
}
|
||||
>
|
||||
{t("case:documents-doc-type-label")}
|
||||
</button>
|
||||
</dd>
|
||||
<dd className="govuk-summary-list__key govuk-!-font-size-16">
|
||||
{/* {t("case:documents-date-published-label")} */}
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => sortDataBy("createdon")}
|
||||
className={
|
||||
orderByState == "createdon"
|
||||
? fieldSortState == "asc"
|
||||
? `govuk-link govuk-link--no-underline govuk-!-font-weight-bold govuk-!-font-size-16 sortAsc`
|
||||
: `govuk-link govuk-link--no-underline govuk-!-font-weight-bold govuk-!-font-size-16 sortDesc`
|
||||
: `govuk-link govuk-link--no-underline govuk-!-font-weight-bold govuk-!-font-size-16`
|
||||
}
|
||||
>
|
||||
{t("case:documents-date-published-label")}
|
||||
</button>
|
||||
</dd>
|
||||
{/* <dd className="govuk-summary-list__key govuk-!-font-size-16">
|
||||
{t("case:documents-size-label")}
|
||||
</dd> */}
|
||||
</div>
|
||||
{showSpinnerState == true ? (
|
||||
<div className="govuk-summary-list__row">
|
||||
<div className="govuk-!-margin-top-4 govuk-!-margin-bottom-4 govuk-!-font-weight-bold govuk-!-font-size-20 ">
|
||||
{t("common:spinner-fetching-data")}
|
||||
<img
|
||||
className="data-loading-icon"
|
||||
src="/assets/images/loading.gif"
|
||||
alt={
|
||||
router.locale == "cy"
|
||||
? "Nôl data"
|
||||
: "Fetching data"
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
documentDetailsArr.map((item, key) => {
|
||||
let detailsObj = jsonpath({
|
||||
path:
|
||||
"$..[?(@ && @._pinswg_documentids_value=='" +
|
||||
incidentid +
|
||||
"')]",
|
||||
json: item,
|
||||
sanbox: {},
|
||||
});
|
||||
detailsObj = item;
|
||||
return (
|
||||
<div
|
||||
className="govuk-summary-list__row"
|
||||
key={key}
|
||||
>
|
||||
<dd className="govuk-summary-list__value govuk-!-font-size-16 ">
|
||||
{showDownloadingState === key && (
|
||||
<div className="coverLoadingLink downloading">
|
||||
{/* <img
|
||||
className="data-loading-icon"
|
||||
src="/assets/images/loading.gif"
|
||||
alt={
|
||||
router.locale ==
|
||||
"cy"
|
||||
? "Nôl data"
|
||||
: "Fetching data"
|
||||
}
|
||||
/> */}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{!ShowDocLinks ? (
|
||||
<Link
|
||||
scroll={false}
|
||||
href={
|
||||
detailsObj.pinswg_hashlink
|
||||
}
|
||||
key={key}
|
||||
onClick={() => {
|
||||
toggleDownLoadLink(key),
|
||||
sendGAEvent(
|
||||
"event",
|
||||
"DownloadedFile",
|
||||
{
|
||||
caseReference:
|
||||
props.caseReference,
|
||||
filename:
|
||||
detailsObj.pinswg_name,
|
||||
}
|
||||
);
|
||||
}}
|
||||
>
|
||||
<span className="results-visually-hidden">
|
||||
{t(
|
||||
"case:documents-name-label"
|
||||
)}
|
||||
:
|
||||
</span>
|
||||
{_.has(
|
||||
detailsObj,
|
||||
"pinswg_name"
|
||||
)
|
||||
? detailsObj.pinswg_name
|
||||
: ""}
|
||||
</Link>
|
||||
) : (
|
||||
<>
|
||||
<span className="results-visually-hidden">
|
||||
{t(
|
||||
"case:documents-name-label"
|
||||
)}
|
||||
:
|
||||
</span>
|
||||
{_.has(
|
||||
detailsObj,
|
||||
"pinswg_name"
|
||||
)
|
||||
? detailsObj.pinswg_name
|
||||
: ""}
|
||||
</>
|
||||
)}
|
||||
</dd>
|
||||
<dd className="govuk-summary-list__value govuk-!-font-size-16">
|
||||
<span className="results-visually-hidden">
|
||||
{t("case:documents-doc-type-label")}
|
||||
:
|
||||
</span>
|
||||
|
||||
{router.locale == "cy"
|
||||
? jsonpath({
|
||||
path:
|
||||
'$..[?(@ && @.value=="' +
|
||||
detailsObj[
|
||||
"pinswg_isharedocumentlocations@OData.Community.Display.V1.FormattedValue"
|
||||
] +
|
||||
'")].value_cy',
|
||||
json: transLookup,
|
||||
eval: true,
|
||||
})
|
||||
: detailsObj[
|
||||
"pinswg_isharedocumentlocations@OData.Community.Display.V1.FormattedValue"
|
||||
] ||
|
||||
t(
|
||||
"case:summary-no-date-entered-label"
|
||||
)}
|
||||
</dd>
|
||||
<dd className="govuk-summary-list__value govuk-!-font-size-16">
|
||||
<span className="results-visually-hidden">
|
||||
{t(
|
||||
"case:documents-date-published-label"
|
||||
)}
|
||||
:
|
||||
</span>
|
||||
|
||||
{_.has(
|
||||
detailsObj,
|
||||
"pinswg_latestpublisheddate"
|
||||
)
|
||||
? formatDates(
|
||||
detailsObj.pinswg_latestpublisheddate
|
||||
)
|
||||
: ""}
|
||||
</dd>
|
||||
{/* <dd className="govuk-summary-list__value govuk-!-font-size-16">
|
||||
<span className="results-visually-hidden">
|
||||
{t("case:documents-size-label")}:
|
||||
</span>
|
||||
92
|
||||
</dd> */}
|
||||
</div>
|
||||
);
|
||||
})
|
||||
)}
|
||||
</dl>
|
||||
<PaginationControl
|
||||
showNoOfRecords={selectedOption}
|
||||
currentPage={currentPage}
|
||||
searchResultsObj={documentDetailsObj}
|
||||
spinnerState={spinnerState}
|
||||
orderBy={orderByState}
|
||||
fieldSort={fieldSortState}
|
||||
getDocumentResults={getDocumentResults}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
let ShowDocLinks = getDocLink(docsOffline);
|
||||
|
||||
const FilteredDocumentView = (documentDetailsArr) => {
|
||||
documentDetailsArr = documentDetailsArr.value;
|
||||
@@ -577,19 +204,11 @@ const DocumentDetails = (props) => {
|
||||
item.pinswg_isharedocumentlocations
|
||||
}
|
||||
>
|
||||
{router.locale == "cy"
|
||||
? jsonpath({
|
||||
path:
|
||||
'$..[?(@ && @.value=="' +
|
||||
item.pinswg_isharedocumentlocationsLabel +
|
||||
'")].value_cy',
|
||||
json: transLookup,
|
||||
eval: true,
|
||||
})
|
||||
: item.pinswg_isharedocumentlocationsLabel ||
|
||||
t(
|
||||
"case:summary-no-date-entered-label"
|
||||
)}{" "}
|
||||
{resolveCrmDisplayValue({
|
||||
value: item.pinswg_isharedocumentlocationsLabel,
|
||||
locale,
|
||||
translations: transLookup
|
||||
})}{" "}
|
||||
- ({item.count})
|
||||
</label>
|
||||
</div>
|
||||
@@ -604,7 +223,7 @@ const DocumentDetails = (props) => {
|
||||
const data = [
|
||||
...document.querySelectorAll(
|
||||
".govuk-checkboxes__input:checked"
|
||||
),
|
||||
)
|
||||
].map((e) => e.value);
|
||||
setSelectedDocumentType(data);
|
||||
setCurrentPage(1);
|
||||
@@ -740,7 +359,7 @@ const DocumentDetails = (props) => {
|
||||
incidentid +
|
||||
"')]",
|
||||
json: item,
|
||||
eval: true,
|
||||
eval: true
|
||||
});
|
||||
detailsObj = item;
|
||||
return (
|
||||
@@ -815,7 +434,7 @@ const DocumentDetails = (props) => {
|
||||
)}
|
||||
:
|
||||
</span>
|
||||
{_.has(
|
||||
{hasOwn(
|
||||
detailsObj,
|
||||
"pinswg_name"
|
||||
)
|
||||
@@ -831,7 +450,7 @@ const DocumentDetails = (props) => {
|
||||
)}
|
||||
:
|
||||
</span>
|
||||
{_.has(
|
||||
{hasOwn(
|
||||
detailsObj,
|
||||
"pinswg_name"
|
||||
)
|
||||
@@ -847,24 +466,13 @@ const DocumentDetails = (props) => {
|
||||
)}
|
||||
:
|
||||
</span>
|
||||
|
||||
{router.locale == "cy"
|
||||
? jsonpath({
|
||||
path:
|
||||
'$..[?(@ && @.value=="' +
|
||||
detailsObj[
|
||||
{resolveCrmDisplayValue({
|
||||
value: detailsObj[
|
||||
"pinswg_isharedocumentlocations@OData.Community.Display.V1.FormattedValue"
|
||||
] +
|
||||
'")].value_cy',
|
||||
json: transLookup,
|
||||
eval: true,
|
||||
})
|
||||
: detailsObj[
|
||||
"pinswg_isharedocumentlocations@OData.Community.Display.V1.FormattedValue"
|
||||
] ||
|
||||
t(
|
||||
"case:summary-no-date-entered-label"
|
||||
)}
|
||||
],
|
||||
locale,
|
||||
translations: transLookup
|
||||
})}
|
||||
</dd>
|
||||
<dd className="govuk-summary-list__value govuk-!-font-size-16">
|
||||
<span className="results-visually-hidden">
|
||||
@@ -874,7 +482,7 @@ const DocumentDetails = (props) => {
|
||||
:
|
||||
</span>
|
||||
|
||||
{_.has(
|
||||
{hasOwn(
|
||||
detailsObj,
|
||||
"pinswg_latestpublisheddate"
|
||||
)
|
||||
@@ -935,7 +543,7 @@ const DocumentDetails = (props) => {
|
||||
props.incidentid,
|
||||
selectedOption,
|
||||
selectedDocumentType,
|
||||
setDocumentDetails,
|
||||
setDocumentDetails
|
||||
]
|
||||
);
|
||||
|
||||
@@ -1059,7 +667,7 @@ const DocumentDetails = (props) => {
|
||||
orderByState,
|
||||
getDocumentTypes,
|
||||
getDocumentResults,
|
||||
lang,
|
||||
lang
|
||||
]);
|
||||
return (
|
||||
<div className="govuk-grid-row">
|
||||
@@ -1073,14 +681,17 @@ const DocumentDetails = (props) => {
|
||||
<h3>
|
||||
{showDocumentSearchState == false
|
||||
? t("case:documents-checking-label")
|
||||
: appealType === 846040002 ||
|
||||
appealType === 846040011
|
||||
? t(
|
||||
"case:documents-non-available-app-label"
|
||||
)
|
||||
: t("case:documents-non-available-label")}
|
||||
</h3>
|
||||
</div>
|
||||
</div>
|
||||
) : showFilteredDocs == "true" ? (
|
||||
FilteredDocumentView(documentDetailsArr)
|
||||
) : (
|
||||
DocumentView(documentDetailsArr)
|
||||
FilteredDocumentView(documentDetailsArr)
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
@@ -1089,7 +700,7 @@ const DocumentDetails = (props) => {
|
||||
|
||||
const mapStateToProps = (state) => {
|
||||
return {
|
||||
...state,
|
||||
...state
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1100,7 +711,7 @@ const mapDispatchToProps = (dispatch) => {
|
||||
},
|
||||
setCurrentPage: (currentPage) => {
|
||||
dispatch(setCurrentPage(currentPage));
|
||||
},
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,221 @@
|
||||
import { setEventDetails } from "../../store/searchOutput/action";
|
||||
import { setCurrentPage } from "../../store/currentView/action";
|
||||
import { connect } from "react-redux";
|
||||
import useTranslation from "next-translate/useTranslation";
|
||||
import { formatDates } from "../utils";
|
||||
|
||||
const EIADetails = (props) => {
|
||||
let { t } = useTranslation();
|
||||
|
||||
const EventView = (eventsArr) => {
|
||||
eventsArr = eventsArr.value;
|
||||
|
||||
return eventsArr.map((item, key) => {
|
||||
<div>{item.pinswg_name}</div>;
|
||||
});
|
||||
};
|
||||
|
||||
const eventsArr = props.eventsObj?.value || [];
|
||||
|
||||
// event publishiing flag set to true displa
|
||||
|
||||
function hasOwnPropertyAndNotNull(obj, property) {
|
||||
return obj.hasOwnProperty(property) && obj[property] !== null;
|
||||
}
|
||||
|
||||
//console.log(eventsArr.length > 0);
|
||||
|
||||
return (
|
||||
eventsArr.length > 0 && (
|
||||
<div className="govuk-grid-row">
|
||||
<div className="card">
|
||||
<div className="card-body">
|
||||
<h2 className="govuk-heading-m ">
|
||||
{t("case:event-title")}
|
||||
</h2>
|
||||
{eventsArr.map(
|
||||
(item, key) =>
|
||||
item.pinswg_eventpublishflag && (
|
||||
<>
|
||||
{" "}
|
||||
<div className="eventContainer">
|
||||
<div className="eventColumn">
|
||||
<div>
|
||||
<b>
|
||||
{" "}
|
||||
{t(
|
||||
"case:event-name-label"
|
||||
)}
|
||||
</b>
|
||||
: {item.pinswg_name}
|
||||
</div>
|
||||
{hasOwnPropertyAndNotNull(
|
||||
item,
|
||||
"pinswg_eventname"
|
||||
) && (
|
||||
<div>
|
||||
<b>
|
||||
{t(
|
||||
"case:event-event-name-label"
|
||||
)}
|
||||
</b>
|
||||
:{" "}
|
||||
{item.pinswg_eventname}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<div className="eventColumn">
|
||||
{hasOwnPropertyAndNotNull(
|
||||
item,
|
||||
"pinswg_eventaddressline1"
|
||||
) && (
|
||||
<>
|
||||
<div>
|
||||
<b>
|
||||
{t(
|
||||
"case:event-address-label"
|
||||
)}
|
||||
</b>
|
||||
:
|
||||
</div>
|
||||
<div>
|
||||
{
|
||||
item.pinswg_eventaddressline1
|
||||
}
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
|
||||
{hasOwnPropertyAndNotNull(
|
||||
item,
|
||||
"pinswg_eventaddressline2"
|
||||
) && (
|
||||
<div>
|
||||
{
|
||||
item.pinswg_eventaddressline2
|
||||
}
|
||||
</div>
|
||||
)}
|
||||
{hasOwnPropertyAndNotNull(
|
||||
item,
|
||||
"pinswg_eventaddresstown"
|
||||
) && (
|
||||
<div>
|
||||
{
|
||||
item.pinswg_eventaddresstown
|
||||
}
|
||||
</div>
|
||||
)}
|
||||
{hasOwnPropertyAndNotNull(
|
||||
item,
|
||||
"pinswg_eventaddresscounty"
|
||||
) && (
|
||||
<div>
|
||||
{
|
||||
item.pinswg_eventaddresscounty
|
||||
}
|
||||
</div>
|
||||
)}
|
||||
{hasOwnPropertyAndNotNull(
|
||||
item,
|
||||
"pinswg_eventaddresscounty"
|
||||
) && (
|
||||
<div>
|
||||
{
|
||||
item.pinswg_eventaddresspostcode
|
||||
}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
{/* type of event
|
||||
start date date of event - end date of event
|
||||
|
||||
if virtual event no address showNoOfRecords
|
||||
show event address */}
|
||||
<div className="eventColumn">
|
||||
{hasOwnPropertyAndNotNull(
|
||||
item,
|
||||
"pinswg_dateeventrequested"
|
||||
) && (
|
||||
<div>
|
||||
<b>
|
||||
{t(
|
||||
"case:event-start-date-label"
|
||||
)}
|
||||
</b>
|
||||
:{" "}
|
||||
{formatDates(
|
||||
item.pinswg_dateeventrequested
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
{hasOwnPropertyAndNotNull(
|
||||
item,
|
||||
"pinswg_enddateoftheevent"
|
||||
) && (
|
||||
<div>
|
||||
<b>
|
||||
{t(
|
||||
"case:event-end-date-label"
|
||||
)}
|
||||
</b>
|
||||
:{" "}
|
||||
{item.pinswg_enddateoftheevent !=
|
||||
null &&
|
||||
formatDates(
|
||||
item.pinswg_enddateoftheevent
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<div className="eventColumn">
|
||||
{hasOwnPropertyAndNotNull(
|
||||
item,
|
||||
[
|
||||
"pinswg_typeofevent@OData.Community.Display.V1.FormattedValue",
|
||||
]
|
||||
) && (
|
||||
<div>
|
||||
<b>
|
||||
{t(
|
||||
"case:event-type-of-event-label"
|
||||
)}
|
||||
</b>
|
||||
:{" "}
|
||||
{
|
||||
item[
|
||||
"pinswg_typeofevent@OData.Community.Display.V1.FormattedValue"
|
||||
]
|
||||
}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
)}{" "}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
);
|
||||
};
|
||||
|
||||
const mapStateToProps = (state) => {
|
||||
return {
|
||||
...state,
|
||||
};
|
||||
};
|
||||
|
||||
const mapDispatchToProps = (dispatch) => {
|
||||
return {
|
||||
setEventDetails: (eventsObj) => {
|
||||
dispatch(setEventDetails(eventsObj));
|
||||
},
|
||||
setCurrentPage: (currentPage) => {
|
||||
dispatch(setCurrentPage(currentPage));
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(EIADetails);
|
||||
@@ -0,0 +1,264 @@
|
||||
import { setEventDetails } from "../../store/searchOutput/action";
|
||||
import { setCurrentPage } from "../../store/currentView/action";
|
||||
import { connect } from "react-redux";
|
||||
import useTranslation from "next-translate/useTranslation";
|
||||
import { formatDates } from "../utils";
|
||||
import {
|
||||
getLivePublishedEvent,
|
||||
isEventLiveNow
|
||||
} from "./summary/utils/liveEvent";
|
||||
import { useRouter } from "next/router";
|
||||
|
||||
const EventsDetails = (props) => {
|
||||
let { t } = useTranslation();
|
||||
const router = useRouter();
|
||||
const { locale } = router;
|
||||
|
||||
const EventView = (eventsArr) => {
|
||||
eventsArr = eventsArr.value;
|
||||
|
||||
return eventsArr.map((item, key) => {
|
||||
<div>{item.pinswg_name}</div>;
|
||||
});
|
||||
};
|
||||
|
||||
const eventsArr = props.eventsObj?.value || [];
|
||||
|
||||
// event publishiing flag set to true displa
|
||||
|
||||
function hasOwnPropertyAndNotNull(obj, property) {
|
||||
return obj.hasOwnProperty(property) && obj[property] !== null;
|
||||
}
|
||||
|
||||
return (
|
||||
eventsArr.length > 0 && (
|
||||
<div className="govuk-grid-row">
|
||||
<div className="card">
|
||||
<div className="card-body">
|
||||
<h2 className="govuk-heading-m ">
|
||||
{t("case:event-title")}
|
||||
</h2>
|
||||
{eventsArr.map(
|
||||
(item, key) =>
|
||||
item.pinswg_eventpublishflag && (
|
||||
<>
|
||||
{" "}
|
||||
<div className="eventContainer">
|
||||
<div className="eventColumn">
|
||||
<div>
|
||||
<b>
|
||||
{" "}
|
||||
{t(
|
||||
"case:event-name-label"
|
||||
)}
|
||||
</b>
|
||||
: {item.pinswg_name}
|
||||
</div>
|
||||
{hasOwnPropertyAndNotNull(
|
||||
item,
|
||||
"pinswg_eventname"
|
||||
) && (
|
||||
<div>
|
||||
<b>
|
||||
{t(
|
||||
"case:event-event-name-label"
|
||||
)}
|
||||
</b>
|
||||
:{" "}
|
||||
{item.pinswg_eventname}
|
||||
</div>
|
||||
)}
|
||||
{hasOwnPropertyAndNotNull(
|
||||
item,
|
||||
[
|
||||
"pinswg_typeofevent@OData.Community.Display.V1.FormattedValue"
|
||||
]
|
||||
) && (
|
||||
<div>
|
||||
<b>
|
||||
{t(
|
||||
"case:event-type-of-event-label"
|
||||
)}
|
||||
</b>
|
||||
:{" "}
|
||||
{
|
||||
item[
|
||||
"pinswg_typeofevent@OData.Community.Display.V1.FormattedValue"
|
||||
]
|
||||
}
|
||||
</div>
|
||||
)}
|
||||
{hasOwnPropertyAndNotNull(
|
||||
item,
|
||||
"pinswg_dateeventrequested"
|
||||
) && (
|
||||
<div>
|
||||
<b>
|
||||
{t(
|
||||
"case:event-start-date-label"
|
||||
)}
|
||||
</b>
|
||||
:{" "}
|
||||
{formatDates(
|
||||
item.pinswg_dateeventrequested
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
{hasOwnPropertyAndNotNull(
|
||||
item,
|
||||
"pinswg_enddateoftheevent"
|
||||
) && (
|
||||
<div>
|
||||
<b>
|
||||
{t(
|
||||
"case:event-end-date-label"
|
||||
)}
|
||||
</b>
|
||||
:{" "}
|
||||
{item.pinswg_enddateoftheevent !=
|
||||
null &&
|
||||
formatDates(
|
||||
item.pinswg_enddateoftheevent
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<div className="eventColumn">
|
||||
{hasOwnPropertyAndNotNull(
|
||||
item,
|
||||
"pinswg_eventaddressline1"
|
||||
) && (
|
||||
<>
|
||||
<div
|
||||
style={{
|
||||
display: "flex"
|
||||
}}
|
||||
>
|
||||
<b>
|
||||
{t(
|
||||
"case:event-address-label"
|
||||
)}
|
||||
</b>
|
||||
:
|
||||
<div
|
||||
style={{
|
||||
display:
|
||||
"flex",
|
||||
marginLeft:
|
||||
"10px",
|
||||
flexDirection:
|
||||
"column"
|
||||
}}
|
||||
>
|
||||
{hasOwnPropertyAndNotNull(
|
||||
item,
|
||||
"pinswg_eventaddressline1"
|
||||
) && (
|
||||
<span>
|
||||
{
|
||||
item.pinswg_eventaddressline1
|
||||
}
|
||||
</span>
|
||||
)}
|
||||
{hasOwnPropertyAndNotNull(
|
||||
item,
|
||||
"pinswg_eventaddressline2"
|
||||
) && (
|
||||
<span>
|
||||
{
|
||||
item.pinswg_eventaddressline2
|
||||
}
|
||||
</span>
|
||||
)}
|
||||
{hasOwnPropertyAndNotNull(
|
||||
item,
|
||||
"pinswg_eventaddresstown"
|
||||
) && (
|
||||
<span>
|
||||
{
|
||||
item.pinswg_eventaddresstown
|
||||
}
|
||||
</span>
|
||||
)}
|
||||
{hasOwnPropertyAndNotNull(
|
||||
item,
|
||||
"pinswg_eventaddresscounty"
|
||||
) && (
|
||||
<span>
|
||||
{
|
||||
item.pinswg_eventaddresscounty
|
||||
}
|
||||
</span>
|
||||
)}
|
||||
{hasOwnPropertyAndNotNull(
|
||||
item,
|
||||
"pinswg_eventaddresscounty"
|
||||
) && (
|
||||
<span>
|
||||
{
|
||||
item.pinswg_eventaddresspostcode
|
||||
}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
{/* type of event
|
||||
start date date of event - end date of event
|
||||
|
||||
if virtual event no address showNoOfRecords
|
||||
show event address */}
|
||||
|
||||
{hasOwnPropertyAndNotNull(
|
||||
item,
|
||||
"pinswg_linktotheevent"
|
||||
) &&
|
||||
isEventLiveNow(item) && (
|
||||
<div className="eventColumn">
|
||||
<a
|
||||
href={
|
||||
locale === "en"
|
||||
? item.pinswg_linktotheevent
|
||||
: item.pinswg_linktotheeventstreamwelsh
|
||||
}
|
||||
className="govuk-link"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
{t(
|
||||
"case:live-event-link"
|
||||
)}
|
||||
</a>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
)}{" "}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
);
|
||||
};
|
||||
|
||||
const mapStateToProps = (state) => {
|
||||
return {
|
||||
...state
|
||||
};
|
||||
};
|
||||
|
||||
const mapDispatchToProps = (dispatch) => {
|
||||
return {
|
||||
setEventDetails: (eventsObj) => {
|
||||
dispatch(setEventDetails(eventsObj));
|
||||
},
|
||||
setCurrentPage: (currentPage) => {
|
||||
dispatch(setCurrentPage(currentPage));
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(EventsDetails);
|
||||
@@ -0,0 +1,260 @@
|
||||
import { useEffect, useMemo, useState } from "react";
|
||||
import useTranslation from "next-translate/useTranslation";
|
||||
import { useRouter } from "next/router";
|
||||
import { getBilingualText } from "./summary/utils/helpers";
|
||||
|
||||
/**
|
||||
* MediaDetails
|
||||
* - Renders a YouTube player + a list of videos from mediaObj.value
|
||||
* - Loads first item by default (no autoplay)
|
||||
* - Plays only when user selects an item
|
||||
* - Stops playback when leaving the "case-media" parent tab (pass whichTab)
|
||||
* - Shows thumbnail with play overlay
|
||||
* - Optional duration badge (if you supply v.duration)
|
||||
* - "Watched" badge once a video has been played (session only)
|
||||
*/
|
||||
|
||||
const extractYouTubeId = (input) => {
|
||||
if (!input) return null;
|
||||
|
||||
// Already looks like a YouTube ID?
|
||||
if (/^[a-zA-Z0-9_-]{11}$/.test(input)) return input;
|
||||
|
||||
try {
|
||||
const url = new URL(input);
|
||||
|
||||
// youtu.be/<id>
|
||||
if (url.hostname.includes("youtu.be")) {
|
||||
return url.pathname.replace("/", "") || null;
|
||||
}
|
||||
|
||||
// youtube.com/watch?v=<id>
|
||||
const v = url.searchParams.get("v");
|
||||
if (v) return v;
|
||||
|
||||
// youtube.com/embed/<id>
|
||||
const embedMatch = url.pathname.match(/\/embed\/([^/]+)/);
|
||||
if (embedMatch?.[1]) return embedMatch[1];
|
||||
|
||||
// youtube.com/shorts/<id>
|
||||
const shortsMatch = url.pathname.match(/\/shorts\/([^/]+)/);
|
||||
if (shortsMatch?.[1]) return shortsMatch[1];
|
||||
|
||||
return null;
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
const MediaDetails = ({ mediaObj, whichTab, title, useNoCookie = true }) => {
|
||||
const { t } = useTranslation();
|
||||
const router = useRouter();
|
||||
|
||||
const sourceMedia = mediaObj?.value;
|
||||
const isActive = whichTab ? whichTab === "case-media" : true;
|
||||
|
||||
// Build list of playable items (publishable only)
|
||||
const videoItems = useMemo(() => {
|
||||
const isWelsh = router.locale === "cy";
|
||||
|
||||
return (sourceMedia || [])
|
||||
.filter((x) => x?.pinswg_publishtoweb)
|
||||
.map((item) => {
|
||||
const link = isWelsh
|
||||
? item.pinswg_videoplatformurlwelsh
|
||||
: item.pinswg_videoplatformurl;
|
||||
|
||||
const videoId = extractYouTubeId(link);
|
||||
if (!videoId) return null;
|
||||
|
||||
return {
|
||||
key:
|
||||
item.pinswg_documentid ||
|
||||
item.pinswg_mediaid ||
|
||||
`${item.pinswg_eventrecordingid}-${videoId}`,
|
||||
videoId,
|
||||
name: item.pinswg_eventrecordingname || "Video",
|
||||
description: item.pinswg_description || "",
|
||||
// If you later store duration in CRM, map it here (e.g. "03:42")
|
||||
duration: item.pinswg_duration || null,
|
||||
thumbnailHQ: `https://img.youtube.com/vi/${videoId}/hqdefault.jpg`,
|
||||
thumbnailMax: `https://img.youtube.com/vi/${videoId}/maxresdefault.jpg`,
|
||||
raw: item
|
||||
};
|
||||
})
|
||||
.filter(Boolean);
|
||||
}, [sourceMedia, router.locale]);
|
||||
|
||||
const [selectedIndex, setSelectedIndex] = useState(0);
|
||||
|
||||
// Default false so first item loads but does not play.
|
||||
const [autoplay, setAutoplay] = useState(false);
|
||||
|
||||
// Bump this to force iframe remount (hard stop playback).
|
||||
const [playerInstance, setPlayerInstance] = useState(0);
|
||||
|
||||
// Track which videos have been played (session only).
|
||||
const [watchedIds, setWatchedIds] = useState(() => new Set());
|
||||
|
||||
// When list or locale changes: reset selection and do not autoplay
|
||||
useEffect(() => {
|
||||
setSelectedIndex(0);
|
||||
setAutoplay(false);
|
||||
setPlayerInstance((n) => n + 1);
|
||||
}, [videoItems.length, router.locale]);
|
||||
|
||||
// When leaving the media tab: hard stop playback
|
||||
useEffect(() => {
|
||||
if (!isActive) {
|
||||
setAutoplay(false);
|
||||
setPlayerInstance((n) => n + 1);
|
||||
}
|
||||
}, [isActive]);
|
||||
|
||||
const selected = videoItems[selectedIndex] || null;
|
||||
|
||||
const domain = useNoCookie
|
||||
? "https://www.youtube-nocookie.com"
|
||||
: "https://www.youtube.com";
|
||||
|
||||
const embedSrc = selected
|
||||
? `${domain}/embed/${selected.videoId}?rel=0&modestbranding=1&playsinline=1&autoplay=${
|
||||
autoplay ? "1" : "0"
|
||||
}`
|
||||
: "";
|
||||
|
||||
if (!videoItems.length) return null;
|
||||
|
||||
return (
|
||||
<div className="govuk-grid-row">
|
||||
<div className="card">
|
||||
<div className="card-body">
|
||||
<h2 className="govuk-heading-m">{t("case:media-title")}</h2>
|
||||
|
||||
{/* Player: unmount when not active (guarantees playback stops) */}
|
||||
{isActive && (
|
||||
<div className="videoWrapper govuk-!-margin-bottom-4">
|
||||
<iframe
|
||||
key={`${selected?.videoId}-${playerInstance}`}
|
||||
src={embedSrc}
|
||||
title={selected?.name || "YouTube video"}
|
||||
frameBorder="0"
|
||||
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
|
||||
allowFullScreen
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Selected info */}
|
||||
{selected && (
|
||||
<div className="govuk-!-margin-bottom-4">
|
||||
<div className="govuk-body">
|
||||
<b>{t("case:event-recording-name-label")}</b>:{" "}
|
||||
{getBilingualText(selected.name, router.locale)}
|
||||
</div>
|
||||
|
||||
{!!selected.description && (
|
||||
<div className="govuk-body">
|
||||
<b>
|
||||
{t(
|
||||
"case:event-recording-description-label"
|
||||
)}
|
||||
</b>
|
||||
:{" "}
|
||||
{getBilingualText(
|
||||
selected.description,
|
||||
router.locale
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Video list */}
|
||||
<h3 className="govuk-heading-s">
|
||||
{t("case:video-heading")}
|
||||
</h3>
|
||||
|
||||
<ul className="govuk-list govuk-list--spaced">
|
||||
{videoItems.map((v, idx) => {
|
||||
const isSelected = idx === selectedIndex;
|
||||
|
||||
return (
|
||||
<li key={v.key}>
|
||||
<button
|
||||
type="button"
|
||||
className={`videoTabButton ${
|
||||
isSelected ? "active" : ""
|
||||
}`}
|
||||
aria-current={
|
||||
isSelected ? "true" : undefined
|
||||
}
|
||||
onClick={() => {
|
||||
setSelectedIndex(idx);
|
||||
|
||||
// Start playback only when user selects
|
||||
setAutoplay(true);
|
||||
|
||||
// Force remount to stop previous + start clean
|
||||
setPlayerInstance((n) => n + 1);
|
||||
|
||||
// Mark watched
|
||||
setWatchedIds((prev) => {
|
||||
const next = new Set(prev);
|
||||
next.add(v.videoId);
|
||||
return next;
|
||||
});
|
||||
}}
|
||||
>
|
||||
<div className="videoTabContent">
|
||||
<div className="thumbnailWrapper">
|
||||
<img
|
||||
src={v.thumbnailMax}
|
||||
onError={(e) => {
|
||||
// fallback for videos without maxres
|
||||
e.currentTarget.src =
|
||||
v.thumbnailHQ;
|
||||
}}
|
||||
alt=""
|
||||
className="videoThumbnail"
|
||||
loading="lazy"
|
||||
/>
|
||||
<span
|
||||
className="playIcon"
|
||||
aria-hidden="true"
|
||||
>
|
||||
▶
|
||||
</span>
|
||||
|
||||
{!!v.duration && (
|
||||
<span className="durationBadge">
|
||||
{v.duration}
|
||||
</span>
|
||||
)}
|
||||
|
||||
{watchedIds.has(v.videoId) && (
|
||||
<span className="watchedBadge">
|
||||
Watched
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<span className="videoTitle">
|
||||
{getBilingualText(
|
||||
v.name,
|
||||
router.locale
|
||||
)}
|
||||
</span>
|
||||
</div>
|
||||
</button>
|
||||
</li>
|
||||
);
|
||||
})}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default MediaDetails;
|
||||
@@ -13,7 +13,7 @@ const PaginationControl = (props) => {
|
||||
currentPage,
|
||||
spinnerState,
|
||||
getDocumentResults,
|
||||
setCurrentPage,
|
||||
setCurrentPage
|
||||
} = props;
|
||||
let { t } = useTranslation();
|
||||
|
||||
@@ -45,7 +45,7 @@ const PaginationControl = (props) => {
|
||||
|
||||
const range = {
|
||||
start: Math.round(currentPage - delta / 2),
|
||||
end: Math.round(currentPage + delta / 2),
|
||||
end: Math.round(currentPage + delta / 2)
|
||||
};
|
||||
|
||||
if (range.start - 1 === 1 || range.end + 1 === pageCount) {
|
||||
@@ -89,7 +89,7 @@ const PaginationControl = (props) => {
|
||||
<span
|
||||
className="govuk-body govuk-link govuk-!-font-weight-bold govuk-link--no-underline activePaginationItem leftTextButton"
|
||||
onClick={() => {
|
||||
spinnerState(),
|
||||
(spinnerState(),
|
||||
setCurrentPage(
|
||||
props.currentView.currentPage -
|
||||
1
|
||||
@@ -99,7 +99,7 @@ const PaginationControl = (props) => {
|
||||
1,
|
||||
orderBy,
|
||||
fieldSort
|
||||
);
|
||||
));
|
||||
}}
|
||||
>
|
||||
{t("common:previous-link-button")}
|
||||
@@ -132,12 +132,12 @@ const PaginationControl = (props) => {
|
||||
key={i}
|
||||
onClick={() => {
|
||||
spinnerState();
|
||||
setCurrentPage(e),
|
||||
(setCurrentPage(e),
|
||||
getDocumentResults(
|
||||
e,
|
||||
orderBy,
|
||||
fieldSort
|
||||
);
|
||||
));
|
||||
}}
|
||||
>
|
||||
{e}
|
||||
@@ -150,7 +150,7 @@ const PaginationControl = (props) => {
|
||||
<span
|
||||
className="govuk-body govuk-link govuk-!-font-weight-bold govuk-link--no-underline activePaginationItem rightTextButton"
|
||||
onClick={() => {
|
||||
spinnerState(),
|
||||
(spinnerState(),
|
||||
setCurrentPage(
|
||||
props.currentView.currentPage +
|
||||
1
|
||||
@@ -160,7 +160,7 @@ const PaginationControl = (props) => {
|
||||
1,
|
||||
orderBy,
|
||||
fieldSort
|
||||
);
|
||||
));
|
||||
}}
|
||||
>
|
||||
{t("common:next-link-button")}
|
||||
@@ -174,8 +174,9 @@ const PaginationControl = (props) => {
|
||||
</div>
|
||||
</div>
|
||||
<div className="govuk-body-s mobilePageCount">
|
||||
{t("common:pages-label")} {currentPage}{" "}
|
||||
{t("common:of-label")} {pagesCount}
|
||||
{t("common:pages-label")}{" "}
|
||||
{props.currentView.currentPage} {t("common:of-label")}{" "}
|
||||
{pagesCount}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
@@ -185,7 +186,7 @@ const PaginationControl = (props) => {
|
||||
|
||||
const mapStateToProps = (state) => {
|
||||
return {
|
||||
currentView: state.currentView,
|
||||
currentView: state.currentView
|
||||
};
|
||||
};
|
||||
|
||||
@@ -193,7 +194,7 @@ const mapDispatchToProps = (dispatch) => {
|
||||
return {
|
||||
setCurrentPage: (currentPage) => {
|
||||
dispatch(setCurrentPage(currentPage));
|
||||
},
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,356 @@
|
||||
import useTranslation from "next-translate/useTranslation";
|
||||
import { useRouter } from "next/router";
|
||||
import { connect } from "react-redux";
|
||||
import { Field, change, reduxForm } from "redux-form";
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
import { bytesToSize, getThumbnailIconByExtension } from "../../utils";
|
||||
import {
|
||||
FileUploadField,
|
||||
RenderCondtionalRadioList,
|
||||
RenderRichMultiline,
|
||||
shouldDisableButton
|
||||
} from "./representationElements";
|
||||
import RepresentationTypeSelectorBlock from "./elements/RepresentationTypeSelectorBlock";
|
||||
|
||||
import { useDropzone } from "react-dropzone";
|
||||
import {
|
||||
setRepresentationCapacity,
|
||||
setRepresentationSubmit,
|
||||
setFilesForRepresentations
|
||||
} from "../../../store/currentView/action";
|
||||
|
||||
const ConsultationAgent = (props) => {
|
||||
let { t } = useTranslation();
|
||||
|
||||
const router = useRouter();
|
||||
const { locale } = router;
|
||||
const {
|
||||
formObj,
|
||||
appellantApplicantRepresentationArr,
|
||||
setRepresentationCapacity,
|
||||
setRepresentationSubmit,
|
||||
currentView,
|
||||
setRepFileName,
|
||||
updateRepresentation,
|
||||
setSavingStatus,
|
||||
savingStatus,
|
||||
setFilesForRepresentations,
|
||||
onRepresentationTypeChange,
|
||||
onTypeSelectionConfirmed
|
||||
} = props;
|
||||
const { acceptedFiles, getRootProps, getInputProps } = useDropzone();
|
||||
|
||||
const persistedRepresentationType =
|
||||
currentView?.caseReference?.repDetails?.representationType;
|
||||
const [typeSelectionConfirmed, setTypeSelectionConfirmed] = useState(
|
||||
!!persistedRepresentationType
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (persistedRepresentationType) {
|
||||
setTypeSelectionConfirmed(true);
|
||||
}
|
||||
}, [persistedRepresentationType]);
|
||||
|
||||
if (JSON.stringify(formObj) != "{}") {
|
||||
setRepFileName(formObj.representationForm.values);
|
||||
|
||||
let filterFilesList = props.currentView.caseReference.hasOwnProperty(
|
||||
"repDetails"
|
||||
)
|
||||
? props.currentView.caseReference.repDetails.hasOwnProperty(
|
||||
"filesList"
|
||||
)
|
||||
? props.currentView.caseReference.repDetails.filesList.filter(
|
||||
function (el) {
|
||||
return el != null;
|
||||
}
|
||||
)
|
||||
: []
|
||||
: [];
|
||||
|
||||
const files = acceptedFiles.map((file) => (
|
||||
<li key={file.path}>
|
||||
{file.path} - {file.size} bytes
|
||||
</li>
|
||||
));
|
||||
const required = (value) => (value ? undefined : "Required");
|
||||
|
||||
const selectedRepresentationType =
|
||||
formObj?.representationForm?.values?.representationType ||
|
||||
props.representationType;
|
||||
|
||||
const isTypeConfirmed =
|
||||
!!selectedRepresentationType && typeSelectionConfirmed;
|
||||
|
||||
const selectedRepresentationTypeDisplay =
|
||||
router.locale == "cy"
|
||||
? selectedRepresentationType == "Questionnaire"
|
||||
? "Holiadur"
|
||||
: selectedRepresentationType == "Statement"
|
||||
? "Datganiad"
|
||||
: selectedRepresentationType == "Final comments"
|
||||
? "Sylwadau terfynol"
|
||||
: selectedRepresentationType
|
||||
: selectedRepresentationType;
|
||||
|
||||
return (
|
||||
<>
|
||||
<RepresentationTypeSelectorBlock
|
||||
t={t}
|
||||
headingText={t(
|
||||
"myrepresentations:consultation-from-an-agent-heading"
|
||||
)}
|
||||
kindLabelText={t(
|
||||
"myrepresentations:kind-of-consultation-label"
|
||||
)}
|
||||
isTypeSelected={isTypeConfirmed}
|
||||
selectedTypeDisplay={selectedRepresentationTypeDisplay}
|
||||
representationType={selectedRepresentationType}
|
||||
setTypeSelectionConfirmed={setTypeSelectionConfirmed}
|
||||
onRepresentationTypeChange={onRepresentationTypeChange}
|
||||
onTypeSelectionConfirmed={onTypeSelectionConfirmed}
|
||||
optionsArr={appellantApplicantRepresentationArr}
|
||||
/>
|
||||
{isTypeConfirmed && (
|
||||
<>
|
||||
<div className="govuk-grid-row">
|
||||
<div className="govuk-form-group">
|
||||
<Field
|
||||
name="representationOnBehalfOf"
|
||||
datafieldname="representationOnBehalfOf"
|
||||
// label={t("myrepresentations:capacity-select-what-capacity-label")}
|
||||
options={["Yes", "No"]}
|
||||
id="representationOnBehalfOf"
|
||||
className="govuk-radios__input"
|
||||
errorMsg={t(
|
||||
"myrepresentations:select-an-option-label"
|
||||
)}
|
||||
component={RenderCondtionalRadioList}
|
||||
validate={[required]}
|
||||
legend={t("case:representation-onbehalfof")}
|
||||
hint={t(
|
||||
"myrepresentations:representation-onbehalfof-hint"
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="govuk-grid-row">
|
||||
<div className="govuk-form-group">
|
||||
<p className="govuk-body">
|
||||
{selectedRepresentationType ==
|
||||
"Consultation Response"
|
||||
? t(
|
||||
"myrepresentations:enter-comment-label"
|
||||
)
|
||||
: t(
|
||||
"myrepresentations:consultation-comment-label"
|
||||
)}
|
||||
</p>
|
||||
<fieldset
|
||||
className="govuk-fieldset"
|
||||
aria-describedby="commentBox-hint"
|
||||
>
|
||||
{selectedRepresentationType ==
|
||||
"Consultation Response" && (
|
||||
<div className="govuk-form-group">
|
||||
<Field
|
||||
name="representationComments"
|
||||
id="representationComments"
|
||||
component={RenderRichMultiline}
|
||||
type="text"
|
||||
rows="5"
|
||||
className="govuk-textarea govuk-input--width-30"
|
||||
aria-describedby={
|
||||
props.name + "-hint"
|
||||
}
|
||||
/>
|
||||
{formObj.representationForm.values
|
||||
.appealType == "846040004" ? (
|
||||
<p className="govuk-hint govuk-!-font-size-14 govuk-!-margin-top-5">
|
||||
{t(
|
||||
"myrepresentations:publish-policy-label"
|
||||
)}{" "}
|
||||
<a
|
||||
href={t(
|
||||
"myrepresentations:publish-policy-link"
|
||||
)}
|
||||
>
|
||||
{t(
|
||||
"myrepresentations:publish-policy-link-label"
|
||||
)}
|
||||
</a>{" "}
|
||||
{t(
|
||||
"myrepresentations:publish-policy-label-two"
|
||||
)}
|
||||
</p>
|
||||
) : (
|
||||
<p className="govuk-hint govuk-!-font-size-14 govuk-!-margin-top-5">
|
||||
{t(
|
||||
"myrepresentations:publish-policy-label"
|
||||
)}{" "}
|
||||
<a
|
||||
href={t(
|
||||
"myrepresentations:publish-policy-link"
|
||||
)}
|
||||
>
|
||||
{t(
|
||||
"myrepresentations:publish-policy-link-label"
|
||||
)}
|
||||
</a>{" "}
|
||||
{t(
|
||||
"myrepresentations:publish-policy-label-two"
|
||||
)}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
<div className="govuk-form-group govuk-!-margin-bottom-9">
|
||||
<FileUploadField
|
||||
name={"representationDocuments"}
|
||||
id={"representationDocuments"}
|
||||
label={t(
|
||||
"myrepresentations:add-files-label"
|
||||
)}
|
||||
ticketnumber={
|
||||
props.currentView.caseReference
|
||||
.ticketnumber
|
||||
}
|
||||
hint={"sdsd"}
|
||||
fileList={
|
||||
props.currentView.fileList
|
||||
|
||||
// props.currentView.caseReference.hasOwnProperty(
|
||||
// "repDetails"
|
||||
// )
|
||||
// ? props.currentView.caseReference.repDetails.hasOwnProperty(
|
||||
// "filesList"
|
||||
// ) &&
|
||||
// props.currentView
|
||||
// .caseReference
|
||||
// .repDetails.filesList
|
||||
// .length > 0
|
||||
// ? props.currentView
|
||||
// .caseReference
|
||||
// .repDetails
|
||||
// .filesList
|
||||
// : []
|
||||
// : []
|
||||
}
|
||||
setFilesForRepresentations={
|
||||
setFilesForRepresentations
|
||||
}
|
||||
containerID={
|
||||
props.props.props.accountDetails
|
||||
.containerID
|
||||
}
|
||||
filenamePrefix={props.formObj}
|
||||
props={props.props.props}
|
||||
setCurrentReference={
|
||||
props.setCurrentReference
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
</fieldset>
|
||||
</div>{" "}
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
{isTypeConfirmed && (
|
||||
<div className="govuk-grid-row">
|
||||
<div className="govuk-button-group">
|
||||
<button
|
||||
type="submit"
|
||||
className="govuk-button"
|
||||
data-module="govuk-button"
|
||||
disabled={shouldDisableButton({
|
||||
props,
|
||||
formObj
|
||||
})}
|
||||
>
|
||||
{t("common:continue-button")}
|
||||
</button>
|
||||
{/* {router.query.state != "edit" && (
|
||||
<a
|
||||
onClick={() => {
|
||||
setRepresentationCapacity();
|
||||
props.updateField(
|
||||
"representationForm",
|
||||
"representationCapacity",
|
||||
""
|
||||
);
|
||||
}}
|
||||
className="govuk-link"
|
||||
>
|
||||
{t("common:back-link")}
|
||||
</a>
|
||||
)} */}
|
||||
{savingStatus ? (
|
||||
<span className=" progress-save-active">
|
||||
{router.locale == "cy"
|
||||
? "Nôl data"
|
||||
: "Saving data"}
|
||||
<img
|
||||
className="data-loading-icon"
|
||||
src="/assets/images/loading.gif"
|
||||
alt={
|
||||
router.locale == "cy"
|
||||
? "Nôl data"
|
||||
: "Saving data"
|
||||
}
|
||||
/>
|
||||
</span>
|
||||
) : (
|
||||
<button
|
||||
className="govuk-button progress-save "
|
||||
onClick={() => {
|
||||
let valuesObj =
|
||||
props.props.props.form[props.form]
|
||||
.values || {};
|
||||
|
||||
//console.log("valuesobj:", valuesObj);
|
||||
|
||||
delete valuesObj[
|
||||
"_pinswg_appellant_value"
|
||||
];
|
||||
|
||||
//console.log("on save:", valuesObj);
|
||||
updateRepresentation(
|
||||
valuesObj,
|
||||
false,
|
||||
true
|
||||
);
|
||||
}}
|
||||
>
|
||||
{t("common:save-exit-button")}
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
updateField: (form, field, newValue) =>
|
||||
dispatch(change(form, field, newValue)),
|
||||
|
||||
setFilesForRepresentations: (fileList) => {
|
||||
dispatch(setFilesForRepresentations(fileList));
|
||||
}
|
||||
});
|
||||
|
||||
export default connect(
|
||||
null,
|
||||
mapDispatchToProps
|
||||
)(
|
||||
reduxForm({
|
||||
form: "representationForm",
|
||||
enableReinitialize: true,
|
||||
destroyOnUnmount: false
|
||||
})(ConsultationAgent)
|
||||
);
|
||||
@@ -0,0 +1,332 @@
|
||||
import useTranslation from "next-translate/useTranslation";
|
||||
import { useRouter } from "next/router";
|
||||
import { connect } from "react-redux";
|
||||
import { Field, change, reduxForm } from "redux-form";
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
import { bytesToSize, getThumbnailIconByExtension } from "../../utils";
|
||||
import {
|
||||
FileUploadField,
|
||||
RenderRichMultiline,
|
||||
shouldDisableButton
|
||||
} from "./representationElements";
|
||||
import RepresentationTypeSelectorBlock from "./elements/RepresentationTypeSelectorBlock";
|
||||
|
||||
import { useDropzone } from "react-dropzone";
|
||||
import {
|
||||
setRepresentationCapacity,
|
||||
setRepresentationSubmit,
|
||||
setFilesForRepresentations
|
||||
} from "../../../store/currentView/action";
|
||||
|
||||
const ConsultationAppellant = (props) => {
|
||||
let { t } = useTranslation();
|
||||
|
||||
const router = useRouter();
|
||||
const { locale } = router;
|
||||
const {
|
||||
formObj,
|
||||
appellantApplicantRepresentationArr,
|
||||
setRepresentationCapacity,
|
||||
setRepresentationSubmit,
|
||||
currentView,
|
||||
setRepFileName,
|
||||
updateRepresentation,
|
||||
setSavingStatus,
|
||||
savingStatus,
|
||||
setFilesForRepresentations,
|
||||
onRepresentationTypeChange,
|
||||
onTypeSelectionConfirmed
|
||||
} = props;
|
||||
const { acceptedFiles, getRootProps, getInputProps } = useDropzone();
|
||||
|
||||
const persistedRepresentationType =
|
||||
currentView?.caseReference?.repDetails?.representationType;
|
||||
const [typeSelectionConfirmed, setTypeSelectionConfirmed] = useState(
|
||||
!!persistedRepresentationType
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (persistedRepresentationType) {
|
||||
setTypeSelectionConfirmed(true);
|
||||
}
|
||||
}, [persistedRepresentationType]);
|
||||
|
||||
console.log(JSON.stringify(formObj) == "{}" ? "empty" : "value");
|
||||
|
||||
if (JSON.stringify(formObj) != "{}") {
|
||||
setRepFileName(formObj.representationForm.values);
|
||||
|
||||
let filterFilesList = props.currentView.caseReference.hasOwnProperty(
|
||||
"repDetails"
|
||||
)
|
||||
? props.currentView.caseReference.repDetails.hasOwnProperty(
|
||||
"filesList"
|
||||
)
|
||||
? props.currentView.caseReference.repDetails.filesList.filter(
|
||||
function (el) {
|
||||
return el != null;
|
||||
}
|
||||
)
|
||||
: []
|
||||
: [];
|
||||
|
||||
filterFilesList = filterFilesList.filter(
|
||||
(value, index, self) =>
|
||||
index === self.findIndex((t) => t.name === value.name)
|
||||
);
|
||||
|
||||
const selectedRepresentationType =
|
||||
formObj?.representationForm?.values?.representationType ||
|
||||
props.representationType;
|
||||
|
||||
const isTypeConfirmed =
|
||||
!!selectedRepresentationType && typeSelectionConfirmed;
|
||||
|
||||
const selectedRepresentationTypeDisplay =
|
||||
router.locale == "cy"
|
||||
? selectedRepresentationType == "Questionnaire"
|
||||
? "Holiadur"
|
||||
: selectedRepresentationType == "Statement"
|
||||
? "Datganiad"
|
||||
: selectedRepresentationType == "Final comments"
|
||||
? "Sylwadau terfynol"
|
||||
: selectedRepresentationType
|
||||
: selectedRepresentationType;
|
||||
|
||||
return (
|
||||
<>
|
||||
<RepresentationTypeSelectorBlock
|
||||
t={t}
|
||||
headingText={t(
|
||||
"myrepresentations:consultation-from-an-appellant-heading"
|
||||
)}
|
||||
kindLabelText={t(
|
||||
"myrepresentations:kind-of-consultation-label"
|
||||
)}
|
||||
isTypeSelected={isTypeConfirmed}
|
||||
selectedTypeDisplay={selectedRepresentationTypeDisplay}
|
||||
representationType={selectedRepresentationType}
|
||||
setTypeSelectionConfirmed={setTypeSelectionConfirmed}
|
||||
onRepresentationTypeChange={onRepresentationTypeChange}
|
||||
onTypeSelectionConfirmed={onTypeSelectionConfirmed}
|
||||
optionsArr={appellantApplicantRepresentationArr}
|
||||
/>
|
||||
{isTypeConfirmed && (
|
||||
<div className="govuk-grid-row">
|
||||
<div className="govuk-form-group">
|
||||
<p className="govuk-body">
|
||||
{selectedRepresentationType ==
|
||||
"Consultation Response"
|
||||
? t("myrepresentations:enter-comment-label")
|
||||
: t(
|
||||
"myrepresentations:consultation-comment-label"
|
||||
)}
|
||||
</p>
|
||||
<fieldset
|
||||
className="govuk-fieldset"
|
||||
aria-describedby="commentBox-hint"
|
||||
>
|
||||
{selectedRepresentationType ==
|
||||
"Consultation Response" && (
|
||||
<div className="govuk-form-group">
|
||||
<Field
|
||||
name="representationComments"
|
||||
id="representationComments"
|
||||
component={RenderRichMultiline}
|
||||
type="text"
|
||||
rows="5"
|
||||
className="govuk-textarea govuk-input--width-30"
|
||||
aria-describedby={
|
||||
props.name + "-hint"
|
||||
}
|
||||
/>
|
||||
{formObj.representationForm.values
|
||||
.appealType == "846040004" ? (
|
||||
<p className="govuk-hint govuk-!-font-size-14 govuk-!-margin-top-5">
|
||||
{t(
|
||||
"myrepresentations:publish-policy-label"
|
||||
)}{" "}
|
||||
<a
|
||||
href={t(
|
||||
"myrepresentations:publish-policy-link"
|
||||
)}
|
||||
>
|
||||
{t(
|
||||
"myrepresentations:publish-policy-link-label"
|
||||
)}
|
||||
</a>{" "}
|
||||
{t(
|
||||
"myrepresentations:publish-policy-label-two"
|
||||
)}
|
||||
</p>
|
||||
) : (
|
||||
<p className="govuk-hint govuk-!-font-size-14 govuk-!-margin-top-5">
|
||||
{t(
|
||||
"myrepresentations:publish-policy-label"
|
||||
)}{" "}
|
||||
<a
|
||||
href={t(
|
||||
"myrepresentations:publish-policy-link"
|
||||
)}
|
||||
>
|
||||
{t(
|
||||
"myrepresentations:publish-policy-link-label"
|
||||
)}
|
||||
</a>{" "}
|
||||
{t(
|
||||
"myrepresentations:publish-policy-label-two"
|
||||
)}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="govuk-form-group govuk-!-margin-bottom-9">
|
||||
<FileUploadField
|
||||
name={"representationDocuments"}
|
||||
id={"representationDocuments"}
|
||||
label={t(
|
||||
"myrepresentations:add-files-label"
|
||||
)}
|
||||
ticketnumber={
|
||||
props.currentView.caseReference
|
||||
.ticketnumber
|
||||
}
|
||||
hint={"sdsd"}
|
||||
fileList={
|
||||
props.currentView.fileList
|
||||
// props.currentView.caseReference.hasOwnProperty(
|
||||
// "repDetails"
|
||||
// )
|
||||
// ? props.currentView.caseReference.repDetails.hasOwnProperty(
|
||||
// "filesList"
|
||||
// ) &&
|
||||
// props.currentView
|
||||
// .caseReference.repDetails
|
||||
// .filesList.length > 0
|
||||
// ? props.currentView
|
||||
// .caseReference
|
||||
// .repDetails.filesList
|
||||
// : []
|
||||
// : []
|
||||
}
|
||||
setFilesForRepresentations={
|
||||
setFilesForRepresentations
|
||||
}
|
||||
containerID={
|
||||
props.props.props.accountDetails
|
||||
.containerID
|
||||
}
|
||||
filenamePrefix={props.formObj}
|
||||
props={props.props.props}
|
||||
setCurrentReference={
|
||||
props.setCurrentReference
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
</fieldset>
|
||||
</div>{" "}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{isTypeConfirmed && (
|
||||
<div className="govuk-grid-row">
|
||||
<div className="govuk-button-group">
|
||||
<button
|
||||
type="submit"
|
||||
className="govuk-button"
|
||||
data-module="govuk-button"
|
||||
disabled={shouldDisableButton({
|
||||
props,
|
||||
formObj
|
||||
})}
|
||||
>
|
||||
{t("common:continue-button")}
|
||||
</button>
|
||||
{/* {router.query.state != "edit" && (
|
||||
<a
|
||||
onClick={() => {
|
||||
setRepresentationCapacity();
|
||||
props.updateField(
|
||||
"representationType",
|
||||
""
|
||||
);
|
||||
}}
|
||||
className="govuk-link"
|
||||
>
|
||||
{t("common:back-link")}
|
||||
</a>
|
||||
)} */}
|
||||
|
||||
{savingStatus ? (
|
||||
<span className=" progress-save-active">
|
||||
{router.locale == "cy"
|
||||
? "Nôl data"
|
||||
: "Saving data"}
|
||||
<img
|
||||
className="data-loading-icon"
|
||||
src="/assets/images/loading.gif"
|
||||
alt={
|
||||
router.locale == "cy"
|
||||
? "Nôl data"
|
||||
: "Saving data"
|
||||
}
|
||||
/>
|
||||
</span>
|
||||
) : (
|
||||
<button
|
||||
className="govuk-button progress-save "
|
||||
onClick={() => {
|
||||
let valuesObj =
|
||||
props.props.props.form[props.form]
|
||||
.values || {};
|
||||
|
||||
//console.log("valuesobj:", valuesObj);
|
||||
|
||||
delete valuesObj[
|
||||
"_pinswg_appellant_value"
|
||||
];
|
||||
|
||||
//console.log("on save:", valuesObj);
|
||||
updateRepresentation(
|
||||
valuesObj,
|
||||
false,
|
||||
true
|
||||
);
|
||||
}}
|
||||
>
|
||||
{t("common:save-exit-button")}
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
//const mapStateToProps = (state, props) => {};
|
||||
|
||||
const mapDispatchToProps = (dispatch) => {
|
||||
return {
|
||||
updateField: (form, field, newValue) =>
|
||||
dispatch(change(form, field, newValue)),
|
||||
|
||||
setFilesForRepresentations: (fileList) => {
|
||||
dispatch(setFilesForRepresentations(fileList));
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
export default connect(
|
||||
null,
|
||||
mapDispatchToProps
|
||||
)(
|
||||
reduxForm({
|
||||
form: "representationForm",
|
||||
enableReinitialize: true,
|
||||
destroyOnUnmount: false
|
||||
})(ConsultationAppellant)
|
||||
);
|
||||
@@ -0,0 +1,369 @@
|
||||
import useTranslation from "next-translate/useTranslation";
|
||||
import { useRouter } from "next/router";
|
||||
import { connect } from "react-redux";
|
||||
import { Field, change, reduxForm } from "redux-form";
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
import { bytesToSize, getThumbnailIconByExtension } from "../../utils";
|
||||
import {
|
||||
FileUploadField,
|
||||
RenderCondtionalRadioList,
|
||||
RenderRichMultiline,
|
||||
shouldDisableButton
|
||||
} from "./representationElements";
|
||||
import RepresentationTypeSelectorBlock from "./elements/RepresentationTypeSelectorBlock";
|
||||
|
||||
import { useDropzone } from "react-dropzone";
|
||||
import {
|
||||
setRepresentationCapacity,
|
||||
setRepresentationSubmit,
|
||||
setFilesForRepresentations
|
||||
} from "../../../store/currentView/action";
|
||||
|
||||
const ConsultationInterestedPartyPerson = (props) => {
|
||||
let { t } = useTranslation();
|
||||
|
||||
const router = useRouter();
|
||||
const { locale } = router;
|
||||
const {
|
||||
formObj,
|
||||
interestedPersonRepresentationArr,
|
||||
setRepresentationCapacity,
|
||||
setRepresentationSubmit,
|
||||
setRepFileName,
|
||||
updateRepresentation,
|
||||
setSavingStatus,
|
||||
savingStatus,
|
||||
setFilesForRepresentations,
|
||||
onRepresentationTypeChange,
|
||||
onTypeSelectionConfirmed
|
||||
} = props;
|
||||
const required = (value) => (value ? undefined : "Required");
|
||||
|
||||
const { acceptedFiles, getRootProps, getInputProps } = useDropzone();
|
||||
|
||||
const persistedRepresentationType =
|
||||
props.currentView?.caseReference?.repDetails?.representationType;
|
||||
const [typeSelectionConfirmed, setTypeSelectionConfirmed] = useState(
|
||||
!!persistedRepresentationType
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (persistedRepresentationType) {
|
||||
setTypeSelectionConfirmed(true);
|
||||
}
|
||||
}, [persistedRepresentationType]);
|
||||
|
||||
if (JSON.stringify(formObj) != "{}") {
|
||||
setRepFileName(formObj.representationForm.values);
|
||||
|
||||
let filterFilesList = props.currentView.caseReference.hasOwnProperty(
|
||||
"repDetails"
|
||||
)
|
||||
? props.currentView.caseReference.repDetails.hasOwnProperty(
|
||||
"filesList"
|
||||
)
|
||||
? props.currentView.caseReference.repDetails.filesList.filter(
|
||||
function (el) {
|
||||
return el != null;
|
||||
}
|
||||
)
|
||||
: []
|
||||
: [];
|
||||
|
||||
const files = acceptedFiles.map((file) => (
|
||||
<li key={file.path}>
|
||||
{file.path} - {file.size} bytes
|
||||
</li>
|
||||
));
|
||||
|
||||
const selectedRepresentationType =
|
||||
formObj?.representationForm?.values?.representationType ||
|
||||
props.representationType;
|
||||
|
||||
const isTypeConfirmed =
|
||||
!!selectedRepresentationType && typeSelectionConfirmed;
|
||||
|
||||
const selectedRepresentationTypeDisplay =
|
||||
router.locale == "cy"
|
||||
? selectedRepresentationType == "Questionnaire"
|
||||
? "Holiadur"
|
||||
: selectedRepresentationType == "Statement"
|
||||
? "Datganiad"
|
||||
: selectedRepresentationType == "Final comments"
|
||||
? "Sylwadau terfynol"
|
||||
: selectedRepresentationType
|
||||
: selectedRepresentationType;
|
||||
|
||||
return (
|
||||
<>
|
||||
<RepresentationTypeSelectorBlock
|
||||
t={t}
|
||||
headingText={t(
|
||||
"myrepresentations:consultation-from-an-interested-person-heading"
|
||||
)}
|
||||
kindLabelText={t(
|
||||
"myrepresentations:kind-of-consultation-label"
|
||||
)}
|
||||
isTypeSelected={isTypeConfirmed}
|
||||
selectedTypeDisplay={selectedRepresentationTypeDisplay}
|
||||
representationType={selectedRepresentationType}
|
||||
setTypeSelectionConfirmed={setTypeSelectionConfirmed}
|
||||
onRepresentationTypeChange={onRepresentationTypeChange}
|
||||
onTypeSelectionConfirmed={onTypeSelectionConfirmed}
|
||||
optionsArr={interestedPersonRepresentationArr}
|
||||
validate={[required]}
|
||||
errorMsg={t("myrepresentations:select-an-option-label")}
|
||||
/>
|
||||
{isTypeConfirmed && (
|
||||
<>
|
||||
<div className="govuk-grid-row">
|
||||
<div className="govuk-form-group">
|
||||
<Field
|
||||
name="representationOnBehalfOf"
|
||||
datafieldname="representationOnBehalfOf"
|
||||
// label="In what capacity do you wish to make representations on this case?"
|
||||
options={[
|
||||
t(
|
||||
"myrepresentations:questionnaire-yes"
|
||||
),
|
||||
t("myrepresentations:questionnaire-no")
|
||||
]}
|
||||
id="representationOnBehalfOf"
|
||||
className="govuk-radios__input"
|
||||
errorMsg={t(
|
||||
"myrepresentations:select-an-option-label"
|
||||
)}
|
||||
component={RenderCondtionalRadioList}
|
||||
validate={[required]}
|
||||
legend={t("case:representation-onbehalfof")}
|
||||
hint={t(
|
||||
"myrepresentations:representation-onbehalfof-hint"
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="govuk-grid-row">
|
||||
<div className="govuk-form-group">
|
||||
<p className="govuk-body">
|
||||
{selectedRepresentationType ==
|
||||
"Consultation Response"
|
||||
? t(
|
||||
"myrepresentations:enter-comment-label"
|
||||
)
|
||||
: t(
|
||||
"myrepresentations:consultation-comment-label"
|
||||
)}
|
||||
</p>
|
||||
<fieldset
|
||||
className="govuk-fieldset"
|
||||
aria-describedby="commentBox-hint"
|
||||
>
|
||||
{" "}
|
||||
{selectedRepresentationType ==
|
||||
"Consultation Response" && (
|
||||
<div className="govuk-form-group">
|
||||
<Field
|
||||
name="representationComments"
|
||||
id="representationComments"
|
||||
component={RenderRichMultiline}
|
||||
type="text"
|
||||
rows="5"
|
||||
className="govuk-textarea govuk-input--width-30"
|
||||
aria-describedby={
|
||||
props.name + "-hint"
|
||||
}
|
||||
/>
|
||||
{formObj.representationForm.values
|
||||
.appealType == "846040004" ? (
|
||||
<p className="govuk-hint govuk-!-font-size-14 govuk-!-margin-top-5">
|
||||
{t(
|
||||
"myrepresentations:publish-policy-label"
|
||||
)}{" "}
|
||||
<a
|
||||
href={t(
|
||||
"myrepresentations:publish-policy-link"
|
||||
)}
|
||||
>
|
||||
{t(
|
||||
"myrepresentations:publish-policy-link-label"
|
||||
)}
|
||||
</a>{" "}
|
||||
{t(
|
||||
"myrepresentations:publish-policy-label-two"
|
||||
)}
|
||||
</p>
|
||||
) : (
|
||||
<p className="govuk-hint govuk-!-font-size-14 govuk-!-margin-top-5">
|
||||
{t(
|
||||
"myrepresentations:publish-policy-label"
|
||||
)}{" "}
|
||||
<a
|
||||
href={t(
|
||||
"myrepresentations:publish-policy-link"
|
||||
)}
|
||||
>
|
||||
{t(
|
||||
"myrepresentations:publish-policy-link-label"
|
||||
)}
|
||||
</a>{" "}
|
||||
{t(
|
||||
"myrepresentations:publish-policy-label-two"
|
||||
)}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
<div className="govuk-form-group govuk-!-margin-bottom-9">
|
||||
<FileUploadField
|
||||
name={"representationDocuments"}
|
||||
id={"representationDocuments"}
|
||||
label={t(
|
||||
"myrepresentations:add-files-label"
|
||||
)}
|
||||
ticketnumber={
|
||||
props.currentView.caseReference
|
||||
.ticketnumber
|
||||
}
|
||||
hint={"sdsd"}
|
||||
fileList={
|
||||
props.currentView.fileList
|
||||
|
||||
// props.currentView.caseReference.hasOwnProperty(
|
||||
// "repDetails"
|
||||
// )
|
||||
// ? props.currentView.caseReference.repDetails.hasOwnProperty(
|
||||
// "filesList"
|
||||
// ) &&
|
||||
// props.currentView
|
||||
// .caseReference
|
||||
// .repDetails.filesList
|
||||
// .length > 0
|
||||
// ? props.currentView
|
||||
// .caseReference
|
||||
// .repDetails
|
||||
// .filesList
|
||||
// : []
|
||||
// : []
|
||||
}
|
||||
setFilesForRepresentations={
|
||||
setFilesForRepresentations
|
||||
}
|
||||
containerID={
|
||||
props.props.props.accountDetails
|
||||
.containerID
|
||||
}
|
||||
filenamePrefix={props.formObj}
|
||||
props={props.props.props}
|
||||
setCurrentReference={
|
||||
props.setCurrentReference
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
</fieldset>
|
||||
</div>{" "}
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
{isTypeConfirmed && (
|
||||
<div className="govuk-grid-row">
|
||||
<div className="govuk-button-group">
|
||||
<button
|
||||
type="submit"
|
||||
className="govuk-button"
|
||||
data-module="govuk-button"
|
||||
disabled={shouldDisableButton({
|
||||
props,
|
||||
formObj
|
||||
})}
|
||||
>
|
||||
{t("common:continue-button")}
|
||||
</button>
|
||||
{/*
|
||||
<a
|
||||
onClick={() => {
|
||||
setRepresentationCapacity();
|
||||
props.updateField(
|
||||
"representationForm",
|
||||
"representationCapacity",
|
||||
""
|
||||
);
|
||||
props.updateField(
|
||||
"representationForm",
|
||||
"representationType",
|
||||
""
|
||||
);
|
||||
}}
|
||||
className="govuk-link"
|
||||
>
|
||||
{t("case:summary-back-button-label")}
|
||||
</a> */}
|
||||
{savingStatus ? (
|
||||
<span className=" progress-save-active">
|
||||
{router.locale == "cy"
|
||||
? "Nôl data"
|
||||
: "Saving data"}
|
||||
<img
|
||||
className="data-loading-icon"
|
||||
src="/assets/images/loading.gif"
|
||||
alt={
|
||||
router.locale == "cy"
|
||||
? "Nôl data"
|
||||
: "Saving data"
|
||||
}
|
||||
/>
|
||||
</span>
|
||||
) : (
|
||||
<button
|
||||
className="govuk-button progress-save "
|
||||
onClick={() => {
|
||||
let valuesObj =
|
||||
props.props.props.form[props.form]
|
||||
.values || {};
|
||||
|
||||
//console.log("valuesobj:", valuesObj);
|
||||
|
||||
delete valuesObj[
|
||||
"_pinswg_appellant_value"
|
||||
];
|
||||
|
||||
//console.log("on save:", valuesObj);
|
||||
updateRepresentation(
|
||||
valuesObj,
|
||||
false,
|
||||
true
|
||||
);
|
||||
}}
|
||||
>
|
||||
{t("common:save-exit-button")}
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
//const mapStateToProps = (state, props) => {};
|
||||
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
updateField: (form, field, newValue) =>
|
||||
dispatch(change(form, field, newValue)),
|
||||
setFilesForRepresentations: (fileList) => {
|
||||
dispatch(setFilesForRepresentations(fileList));
|
||||
}
|
||||
});
|
||||
|
||||
export default connect(
|
||||
null,
|
||||
mapDispatchToProps
|
||||
)(
|
||||
reduxForm({
|
||||
form: "representationForm",
|
||||
enableReinitialize: true,
|
||||
destroyOnUnmount: false
|
||||
})(ConsultationInterestedPartyPerson)
|
||||
);
|
||||
@@ -0,0 +1,42 @@
|
||||
const RepresentationActionButtons = ({
|
||||
t,
|
||||
locale,
|
||||
isSaving,
|
||||
isContinueDisabled,
|
||||
onSaveExit
|
||||
}) => {
|
||||
return (
|
||||
<div className="govuk-grid-row">
|
||||
<div className="govuk-button-group">
|
||||
<button
|
||||
type="submit"
|
||||
className="govuk-button"
|
||||
data-module="govuk-button"
|
||||
disabled={isContinueDisabled}
|
||||
>
|
||||
{t("common:continue-button")}
|
||||
</button>
|
||||
|
||||
{isSaving ? (
|
||||
<span className=" progress-save-active">
|
||||
{locale == "cy" ? "Nôl data" : "Saving data"}
|
||||
<img
|
||||
className="data-loading-icon"
|
||||
src="/assets/images/loading.gif"
|
||||
alt={locale == "cy" ? "Nôl data" : "Saving data"}
|
||||
/>
|
||||
</span>
|
||||
) : (
|
||||
<button
|
||||
className="govuk-button progress-save "
|
||||
onClick={onSaveExit}
|
||||
>
|
||||
{t("common:save-exit-button")}
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default RepresentationActionButtons;
|
||||
@@ -0,0 +1,205 @@
|
||||
import { Field } from "redux-form";
|
||||
import router from "next/router";
|
||||
import Link from "next/link";
|
||||
|
||||
const getRepresentationTypeHint = (option, t) => {
|
||||
const map = {
|
||||
"Statement": t("myrepresentations:rep-type-statement-hint"),
|
||||
"Final comments": t("myrepresentations:rep-type-final-comments-hint"),
|
||||
"Questionnaire": t("myrepresentations:rep-type-questionnaire-hint"),
|
||||
"Consultation Response": t(
|
||||
"myrepresentations:rep-type-consultation-hint"
|
||||
),
|
||||
"Local Impact Report": t("myrepresentations:rep-type-lir-hint"),
|
||||
"Marine Impact Report": t("myrepresentations:rep-type-mir-hint")
|
||||
};
|
||||
|
||||
return map[option] || "";
|
||||
};
|
||||
|
||||
const getRepresentationTypeLabel = (option) => {
|
||||
if (router.locale !== "cy") {
|
||||
return option;
|
||||
}
|
||||
|
||||
if (option === "Questionnaire") {
|
||||
return "Holiadur";
|
||||
}
|
||||
|
||||
if (option === "Statement") {
|
||||
return "Datganiad";
|
||||
}
|
||||
|
||||
if (option === "Final comments") {
|
||||
return "Sylwadau terfynol";
|
||||
}
|
||||
|
||||
return option;
|
||||
};
|
||||
|
||||
const RenderRepresentationTypeRadioList = ({
|
||||
name,
|
||||
optionsArr,
|
||||
errorMsg,
|
||||
onRepresentationTypeChange,
|
||||
input,
|
||||
meta: { touched, error }
|
||||
}) => {
|
||||
return (
|
||||
<div
|
||||
className={
|
||||
touched && error
|
||||
? "govuk-form-group govuk-form-group--error"
|
||||
: "govuk-form-group"
|
||||
}
|
||||
>
|
||||
{touched && error && (
|
||||
<span id={`${name}-error`} className="govuk-error-message">
|
||||
<span className="govuk-visually-hidden">Error:</span>{" "}
|
||||
{errorMsg}
|
||||
</span>
|
||||
)}
|
||||
|
||||
<div className="govuk-radios govuk-radios--small">
|
||||
{optionsArr.map((option, index) => {
|
||||
const optionId = `${name}_${index}`;
|
||||
const hintId = `${optionId}-hint`;
|
||||
|
||||
return (
|
||||
<div
|
||||
key={option.value || optionId}
|
||||
className="govuk-radios__item representation-type-option"
|
||||
>
|
||||
<input
|
||||
className="govuk-radios__input"
|
||||
id={optionId}
|
||||
name={input.name}
|
||||
type="radio"
|
||||
value={option.value}
|
||||
checked={input.value === option.value}
|
||||
onChange={() => input.onChange(option.value)}
|
||||
aria-describedby={
|
||||
option.hint ? hintId : undefined
|
||||
}
|
||||
/>
|
||||
|
||||
<label
|
||||
className="govuk-label govuk-radios__label govuk-!-font-weight-bold "
|
||||
htmlFor={optionId}
|
||||
>
|
||||
{option.label}
|
||||
|
||||
{option.hint && (
|
||||
<div
|
||||
id={hintId}
|
||||
className="govuk-hint govuk-!-margin-top-2"
|
||||
>
|
||||
{option.hint}
|
||||
</div>
|
||||
)}
|
||||
</label>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
const RepresentationTypeSelectorBlock = ({
|
||||
t,
|
||||
headingText,
|
||||
kindLabelText,
|
||||
isTypeSelected,
|
||||
selectedTypeDisplay,
|
||||
representationType,
|
||||
setTypeSelectionConfirmed,
|
||||
onRepresentationTypeChange,
|
||||
onTypeSelectionConfirmed,
|
||||
optionsArr,
|
||||
validate,
|
||||
errorMsg
|
||||
}) => {
|
||||
const enhancedOptions = (optionsArr || [])
|
||||
.filter((option) => option && option !== "Select...")
|
||||
.map((option) => ({
|
||||
value: option,
|
||||
label: getRepresentationTypeLabel(option),
|
||||
hint: getRepresentationTypeHint(option, t)
|
||||
}));
|
||||
|
||||
const hasSelectableOptions = enhancedOptions.length > 0;
|
||||
|
||||
return (
|
||||
<div className="govuk-grid-row">
|
||||
<div className="govuk-form-group">
|
||||
{!isTypeSelected ? (
|
||||
<>
|
||||
<h2 className="govuk-heading-m ">{headingText}</h2>
|
||||
|
||||
<label
|
||||
className="govuk-label govuk-body-m govuk-!-margin-bottom-2"
|
||||
htmlFor="representationType"
|
||||
>
|
||||
{kindLabelText}
|
||||
</label>
|
||||
|
||||
{hasSelectableOptions ? (
|
||||
<>
|
||||
<Field
|
||||
name="representationType"
|
||||
component={
|
||||
RenderRepresentationTypeRadioList
|
||||
}
|
||||
onRepresentationTypeChange={
|
||||
onRepresentationTypeChange
|
||||
}
|
||||
validate={validate}
|
||||
optionsArr={enhancedOptions}
|
||||
errorMsg={errorMsg}
|
||||
/>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
className="govuk-button"
|
||||
data-module="govuk-button"
|
||||
disabled={!representationType}
|
||||
onClick={() => {
|
||||
if (representationType) {
|
||||
setTypeSelectionConfirmed(true);
|
||||
onTypeSelectionConfirmed &&
|
||||
onTypeSelectionConfirmed(
|
||||
representationType
|
||||
);
|
||||
}
|
||||
}}
|
||||
>
|
||||
{t("common:continue-button")}
|
||||
</button>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<p className="govuk-body">
|
||||
{t(
|
||||
"myrepresentations:representation-type-unavailable-label"
|
||||
)}
|
||||
</p>
|
||||
<Link className="govuk-link" href="/">
|
||||
{t(
|
||||
"myrepresentations:return-home-link-label"
|
||||
)}
|
||||
</Link>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
) : (
|
||||
<label className="govuk-label govuk-body-m">
|
||||
{t("myrepresentations:representation-type")}:{" "}
|
||||
{selectedTypeDisplay}
|
||||
</label>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default RepresentationTypeSelectorBlock;
|
||||
+722
-1024
File diff suppressed because it is too large
Load Diff
@@ -2,21 +2,23 @@ import useTranslation from "next-translate/useTranslation";
|
||||
import { useRouter } from "next/router";
|
||||
import { connect } from "react-redux";
|
||||
import { Field, change, reduxForm } from "redux-form";
|
||||
import { useState } from "react";
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
import { bytesToSize, getThumbnailIconByExtension } from "../../utils";
|
||||
import {
|
||||
FileUploadField,
|
||||
RenderCondtionalRadioList,
|
||||
RenderPickList,
|
||||
RenderRichMultiline,
|
||||
shouldDisableButton
|
||||
} from "./representationElements";
|
||||
import RepresentationActionButtons from "./elements/RepresentationActionButtons";
|
||||
import RepresentationTypeSelectorBlock from "./elements/RepresentationTypeSelectorBlock";
|
||||
|
||||
import { useDropzone } from "react-dropzone";
|
||||
import {
|
||||
setRepresentationCapacity,
|
||||
setRepresentationSubmit,
|
||||
setFilesForRepresentations,
|
||||
setFilesForRepresentations
|
||||
} from "../../../store/currentView/action";
|
||||
|
||||
const RepAgent = (props) => {
|
||||
@@ -35,9 +37,23 @@ const RepAgent = (props) => {
|
||||
setSavingStatus,
|
||||
savingStatus,
|
||||
setFilesForRepresentations,
|
||||
onRepresentationTypeChange,
|
||||
onTypeSelectionConfirmed
|
||||
} = props;
|
||||
const { acceptedFiles, getRootProps, getInputProps } = useDropzone();
|
||||
|
||||
const persistedRepresentationType =
|
||||
currentView?.caseReference?.repDetails?.representationType;
|
||||
const [typeSelectionConfirmed, setTypeSelectionConfirmed] = useState(
|
||||
!!persistedRepresentationType
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (persistedRepresentationType) {
|
||||
setTypeSelectionConfirmed(true);
|
||||
}
|
||||
}, [persistedRepresentationType]);
|
||||
|
||||
if (JSON.stringify(formObj) != "{}") {
|
||||
setRepFileName(formObj.representationForm.values);
|
||||
|
||||
@@ -62,61 +78,49 @@ const RepAgent = (props) => {
|
||||
));
|
||||
const required = (value) => (value ? undefined : "Required");
|
||||
|
||||
const selectedRepresentationType =
|
||||
formObj?.representationForm?.values?.representationType ||
|
||||
props.representationType;
|
||||
|
||||
const isTypeConfirmed =
|
||||
!!selectedRepresentationType && typeSelectionConfirmed;
|
||||
|
||||
const selectedRepresentationTypeDisplay =
|
||||
router.locale == "cy"
|
||||
? selectedRepresentationType == "Questionnaire"
|
||||
? "Holiadur"
|
||||
: selectedRepresentationType == "Statement"
|
||||
? "Datganiad"
|
||||
: selectedRepresentationType == "Final comments"
|
||||
? "Sylwadau terfynol"
|
||||
: selectedRepresentationType
|
||||
: selectedRepresentationType;
|
||||
|
||||
const handleSaveExit = () => {
|
||||
let valuesObj = props.props.props.form[props.form].values || {};
|
||||
|
||||
delete valuesObj["_pinswg_appellant_value"];
|
||||
|
||||
updateRepresentation(valuesObj, false, true);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="govuk-grid-row">
|
||||
<div className="govuk-form-group">
|
||||
{typeof formObj.representationForm.values
|
||||
.representationType == "undefined" &&
|
||||
props.representationType != "Select..." ? (
|
||||
<>
|
||||
<h2 className="govuk-heading-m ">
|
||||
{t(
|
||||
<RepresentationTypeSelectorBlock
|
||||
t={t}
|
||||
headingText={t(
|
||||
"myrepresentations:representation-from-an-agent-heading"
|
||||
)}
|
||||
</h2>
|
||||
|
||||
<label
|
||||
className="govuk-label govuk-body-m"
|
||||
htmlFor="representationType"
|
||||
>
|
||||
{t("myrepresentations:kind-of-rep-label")}
|
||||
</label>
|
||||
|
||||
<Field
|
||||
name="representationType"
|
||||
component={RenderPickList}
|
||||
datafieldname="representationType"
|
||||
optionsArr={
|
||||
appellantApplicantRepresentationArr
|
||||
}
|
||||
kindLabelText={t("myrepresentations:kind-of-rep-label")}
|
||||
isTypeSelected={isTypeConfirmed}
|
||||
selectedTypeDisplay={selectedRepresentationTypeDisplay}
|
||||
representationType={selectedRepresentationType}
|
||||
setTypeSelectionConfirmed={setTypeSelectionConfirmed}
|
||||
onRepresentationTypeChange={onRepresentationTypeChange}
|
||||
onTypeSelectionConfirmed={onTypeSelectionConfirmed}
|
||||
optionsArr={appellantApplicantRepresentationArr}
|
||||
/>
|
||||
</>
|
||||
) : (
|
||||
<label className="govuk-label govuk-body-m">
|
||||
{t("myrepresentations:representation-type")}:{" "}
|
||||
{router.locale == "cy"
|
||||
? formObj.representationForm.values
|
||||
.representationType == "Questionnaire"
|
||||
? "Holiadur"
|
||||
: formObj.representationForm.values
|
||||
.representationType == "Statement"
|
||||
? "Datganiad"
|
||||
: formObj.representationForm.values
|
||||
.representationType ==
|
||||
"Final comments"
|
||||
? "Sylwadau terfynol"
|
||||
: formObj.representationForm.values
|
||||
.representationType
|
||||
: formObj.representationForm.values
|
||||
.representationType}
|
||||
</label>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
{(typeof props.representationType != "undefined" ||
|
||||
typeof formObj.representationForm.values
|
||||
.representationType != "undefined") && (
|
||||
{isTypeConfirmed && (
|
||||
<>
|
||||
<div className="govuk-grid-row">
|
||||
<div className="govuk-form-group">
|
||||
@@ -239,74 +243,17 @@ const RepAgent = (props) => {
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
{typeof formObj.representationForm.values.representationType !=
|
||||
"undefined" && (
|
||||
<div className="govuk-grid-row">
|
||||
<div className="govuk-button-group">
|
||||
<button
|
||||
type="submit"
|
||||
className="govuk-button"
|
||||
data-module="govuk-button"
|
||||
>
|
||||
{t("common:continue-button")}
|
||||
</button>
|
||||
{/* {router.query.state != "edit" && (
|
||||
<a
|
||||
onClick={() => {
|
||||
setRepresentationCapacity();
|
||||
props.updateField(
|
||||
"representationForm",
|
||||
"representationCapacity",
|
||||
""
|
||||
);
|
||||
}}
|
||||
className="govuk-link"
|
||||
>
|
||||
{t("common:back-link")}
|
||||
</a>
|
||||
)} */}
|
||||
{savingStatus ? (
|
||||
<span className=" progress-save-active">
|
||||
{router.locale == "cy"
|
||||
? "Nôl data"
|
||||
: "Saving data"}
|
||||
<img
|
||||
className="data-loading-icon"
|
||||
src="/assets/images/loading.gif"
|
||||
alt={
|
||||
router.locale == "cy"
|
||||
? "Nôl data"
|
||||
: "Saving data"
|
||||
}
|
||||
{isTypeConfirmed && (
|
||||
<RepresentationActionButtons
|
||||
t={t}
|
||||
locale={router.locale}
|
||||
isSaving={savingStatus}
|
||||
isContinueDisabled={shouldDisableButton({
|
||||
props,
|
||||
formObj
|
||||
})}
|
||||
onSaveExit={handleSaveExit}
|
||||
/>
|
||||
</span>
|
||||
) : (
|
||||
<button
|
||||
className="govuk-button progress-save "
|
||||
onClick={() => {
|
||||
let valuesObj =
|
||||
props.props.props.form[props.form]
|
||||
.values || {};
|
||||
|
||||
//console.log("valuesobj:", valuesObj);
|
||||
|
||||
delete valuesObj[
|
||||
"_pinswg_appellant_value"
|
||||
];
|
||||
|
||||
//console.log("on save:", valuesObj);
|
||||
updateRepresentation(
|
||||
valuesObj,
|
||||
false,
|
||||
true
|
||||
);
|
||||
}}
|
||||
>
|
||||
{t("common:save-exit-button")}
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
@@ -319,7 +266,7 @@ const mapDispatchToProps = (dispatch) => ({
|
||||
|
||||
setFilesForRepresentations: (fileList) => {
|
||||
dispatch(setFilesForRepresentations(fileList));
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
export default connect(
|
||||
@@ -329,6 +276,6 @@ export default connect(
|
||||
reduxForm({
|
||||
form: "representationForm",
|
||||
enableReinitialize: true,
|
||||
destroyOnUnmount: false,
|
||||
destroyOnUnmount: false
|
||||
})(RepAgent)
|
||||
);
|
||||
|
||||
@@ -2,20 +2,22 @@ import useTranslation from "next-translate/useTranslation";
|
||||
import { useRouter } from "next/router";
|
||||
import { connect } from "react-redux";
|
||||
import { Field, change, reduxForm } from "redux-form";
|
||||
import { useState } from "react";
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
import { bytesToSize, getThumbnailIconByExtension } from "../../utils";
|
||||
import {
|
||||
FileUploadField,
|
||||
RenderPickList,
|
||||
RenderRichMultiline,
|
||||
shouldDisableButton
|
||||
} from "./representationElements";
|
||||
import RepresentationActionButtons from "./elements/RepresentationActionButtons";
|
||||
import RepresentationTypeSelectorBlock from "./elements/RepresentationTypeSelectorBlock";
|
||||
|
||||
import { useDropzone } from "react-dropzone";
|
||||
import {
|
||||
setRepresentationCapacity,
|
||||
setRepresentationSubmit,
|
||||
setFilesForRepresentations,
|
||||
setFilesForRepresentations
|
||||
} from "../../../store/currentView/action";
|
||||
|
||||
const RepAppellant = (props) => {
|
||||
@@ -34,9 +36,23 @@ const RepAppellant = (props) => {
|
||||
setSavingStatus,
|
||||
savingStatus,
|
||||
setFilesForRepresentations,
|
||||
onRepresentationTypeChange,
|
||||
onTypeSelectionConfirmed
|
||||
} = props;
|
||||
const { acceptedFiles, getRootProps, getInputProps } = useDropzone();
|
||||
|
||||
const persistedRepresentationType =
|
||||
currentView?.caseReference?.repDetails?.representationType;
|
||||
const [typeSelectionConfirmed, setTypeSelectionConfirmed] = useState(
|
||||
!!persistedRepresentationType
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (persistedRepresentationType) {
|
||||
setTypeSelectionConfirmed(true);
|
||||
}
|
||||
}, [persistedRepresentationType]);
|
||||
|
||||
console.log(JSON.stringify(formObj) == "{}" ? "empty" : "value");
|
||||
|
||||
if (JSON.stringify(formObj) != "{}") {
|
||||
@@ -61,59 +77,49 @@ const RepAppellant = (props) => {
|
||||
index === self.findIndex((t) => t.name === value.name)
|
||||
);
|
||||
|
||||
const selectedRepresentationType =
|
||||
formObj?.representationForm?.values?.representationType ||
|
||||
props.representationType;
|
||||
|
||||
const isTypeConfirmed =
|
||||
!!selectedRepresentationType && typeSelectionConfirmed;
|
||||
|
||||
const selectedRepresentationTypeDisplay =
|
||||
router.locale == "cy"
|
||||
? selectedRepresentationType == "Questionnaire"
|
||||
? "Holiadur"
|
||||
: selectedRepresentationType == "Statement"
|
||||
? "Datganiad"
|
||||
: selectedRepresentationType == "Final comments"
|
||||
? "Sylwadau terfynol"
|
||||
: selectedRepresentationType
|
||||
: selectedRepresentationType;
|
||||
|
||||
const handleSaveExit = () => {
|
||||
let valuesObj = props.props.props.form[props.form].values || {};
|
||||
|
||||
delete valuesObj["_pinswg_appellant_value"];
|
||||
|
||||
updateRepresentation(valuesObj, false, true);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="govuk-grid-row">
|
||||
<div className="govuk-form-group">
|
||||
{typeof formObj.representationForm.values
|
||||
.representationType == "undefined" &&
|
||||
props.representationType != "Select..." ? (
|
||||
<>
|
||||
<h2 className="govuk-heading-m ">
|
||||
{t(
|
||||
<RepresentationTypeSelectorBlock
|
||||
t={t}
|
||||
headingText={t(
|
||||
"myrepresentations:representation-from-an-appellant-heading"
|
||||
)}
|
||||
</h2>
|
||||
<label
|
||||
className="govuk-label govuk-body-m"
|
||||
htmlFor="representationType"
|
||||
>
|
||||
{t("myrepresentations:kind-of-rep-label")}
|
||||
</label>
|
||||
<Field
|
||||
name="representationType"
|
||||
component={RenderPickList}
|
||||
datafieldname="representationType"
|
||||
optionsArr={
|
||||
appellantApplicantRepresentationArr
|
||||
}
|
||||
kindLabelText={t("myrepresentations:kind-of-rep-label")}
|
||||
isTypeSelected={isTypeConfirmed}
|
||||
selectedTypeDisplay={selectedRepresentationTypeDisplay}
|
||||
representationType={selectedRepresentationType}
|
||||
setTypeSelectionConfirmed={setTypeSelectionConfirmed}
|
||||
onRepresentationTypeChange={onRepresentationTypeChange}
|
||||
onTypeSelectionConfirmed={onTypeSelectionConfirmed}
|
||||
optionsArr={appellantApplicantRepresentationArr}
|
||||
/>
|
||||
</>
|
||||
) : (
|
||||
<label className="govuk-label govuk-body-m">
|
||||
{t("myrepresentations:representation-type")}:{" "}
|
||||
{router.locale == "cy"
|
||||
? formObj.representationForm.values
|
||||
.representationType == "Questionnaire"
|
||||
? "Holiadur"
|
||||
: formObj.representationForm.values
|
||||
.representationType == "Statement"
|
||||
? "Datganiad"
|
||||
: formObj.representationForm.values
|
||||
.representationType ==
|
||||
"Final comments"
|
||||
? "Sylwadau terfynol"
|
||||
: formObj.representationForm.values
|
||||
.representationType
|
||||
: formObj.representationForm.values
|
||||
.representationType}
|
||||
</label>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
{(typeof props.representationType != "undefined" ||
|
||||
typeof formObj.representationForm.values
|
||||
.representationType != "undefined") && (
|
||||
{isTypeConfirmed && (
|
||||
<div className="govuk-grid-row">
|
||||
<div className="govuk-form-group">
|
||||
<p className="govuk-body">
|
||||
@@ -228,75 +234,18 @@ const RepAppellant = (props) => {
|
||||
</div>{" "}
|
||||
</div>
|
||||
)}
|
||||
{typeof formObj.representationForm.values.representationType !=
|
||||
"undefined" && (
|
||||
<div className="govuk-grid-row">
|
||||
<div className="govuk-button-group">
|
||||
<button
|
||||
type="submit"
|
||||
className="govuk-button"
|
||||
data-module="govuk-button"
|
||||
>
|
||||
{t("common:continue-button")}
|
||||
</button>
|
||||
{/* {router.query.state != "edit" && (
|
||||
<a
|
||||
onClick={() => {
|
||||
setRepresentationCapacity();
|
||||
props.updateField(
|
||||
"representationForm",
|
||||
"representationType",
|
||||
""
|
||||
);
|
||||
}}
|
||||
className="govuk-link"
|
||||
>
|
||||
{t("common:back-link")}
|
||||
</a>
|
||||
)} */}
|
||||
|
||||
{savingStatus ? (
|
||||
<span className=" progress-save-active">
|
||||
{router.locale == "cy"
|
||||
? "Nôl data"
|
||||
: "Saving data"}
|
||||
<img
|
||||
className="data-loading-icon"
|
||||
src="/assets/images/loading.gif"
|
||||
alt={
|
||||
router.locale == "cy"
|
||||
? "Nôl data"
|
||||
: "Saving data"
|
||||
}
|
||||
{isTypeConfirmed && (
|
||||
<RepresentationActionButtons
|
||||
t={t}
|
||||
locale={router.locale}
|
||||
isSaving={savingStatus}
|
||||
isContinueDisabled={shouldDisableButton({
|
||||
props,
|
||||
formObj
|
||||
})}
|
||||
onSaveExit={handleSaveExit}
|
||||
/>
|
||||
</span>
|
||||
) : (
|
||||
<button
|
||||
className="govuk-button progress-save "
|
||||
onClick={() => {
|
||||
let valuesObj =
|
||||
props.props.props.form[props.form]
|
||||
.values || {};
|
||||
|
||||
//console.log("valuesobj:", valuesObj);
|
||||
|
||||
delete valuesObj[
|
||||
"_pinswg_appellant_value"
|
||||
];
|
||||
|
||||
//console.log("on save:", valuesObj);
|
||||
updateRepresentation(
|
||||
valuesObj,
|
||||
false,
|
||||
true
|
||||
);
|
||||
}}
|
||||
>
|
||||
{t("common:save-exit-button")}
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
@@ -312,7 +261,7 @@ const mapDispatchToProps = (dispatch) => {
|
||||
|
||||
setFilesForRepresentations: (fileList) => {
|
||||
dispatch(setFilesForRepresentations(fileList));
|
||||
},
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
@@ -323,6 +272,6 @@ export default connect(
|
||||
reduxForm({
|
||||
form: "representationForm",
|
||||
enableReinitialize: true,
|
||||
destroyOnUnmount: false,
|
||||
destroyOnUnmount: false
|
||||
})(RepAppellant)
|
||||
);
|
||||
|
||||
@@ -3,7 +3,7 @@ import { useRouter } from "next/router";
|
||||
import { useDropzone } from "react-dropzone";
|
||||
import { Field } from "redux-form";
|
||||
import RepDetails from "./representationDetails";
|
||||
import { RenderRadioListWithText } from "./representationElements";
|
||||
import { RenderRadioList } from "./representationElements";
|
||||
|
||||
let RepCapacitySelection = (props) => {
|
||||
let { t } = useTranslation();
|
||||
@@ -17,7 +17,7 @@ let RepCapacitySelection = (props) => {
|
||||
casesObj,
|
||||
validate,
|
||||
handleSubmit,
|
||||
setCurrentReference,
|
||||
setCurrentReference
|
||||
} = props;
|
||||
const { acceptedFiles, getRootProps, getInputProps } = useDropzone();
|
||||
const files = acceptedFiles.map((file) => (
|
||||
@@ -27,6 +27,7 @@ let RepCapacitySelection = (props) => {
|
||||
));
|
||||
|
||||
const required = (value) => (value ? undefined : "Required");
|
||||
const appealType = props.props.currentView.caseReference.appealType;
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -42,6 +43,7 @@ let RepCapacitySelection = (props) => {
|
||||
myRepresentations={props.props.myRepresentations}
|
||||
props={props}
|
||||
setCurrentReference={setCurrentReference}
|
||||
appealType={appealType}
|
||||
/>{" "}
|
||||
<div id="rep-details" className="">
|
||||
<div className="govuk-grid-column-full">
|
||||
@@ -50,21 +52,27 @@ let RepCapacitySelection = (props) => {
|
||||
{t(
|
||||
"myrepresentations:capacity-select-your-details"
|
||||
)}{" "}
|
||||
- {props.firstValue}
|
||||
- {props.firstValue}{" "}
|
||||
</h2>
|
||||
<Field
|
||||
name="representationCapacity"
|
||||
datafieldname="representationCapacity"
|
||||
label={t(
|
||||
label={
|
||||
appealType != 846040002
|
||||
? t(
|
||||
"myrepresentations:capacity-select-what-capacity-label"
|
||||
)}
|
||||
)
|
||||
: t(
|
||||
"myrepresentations:sips-capacity-select-what-capacity-label"
|
||||
)
|
||||
}
|
||||
options={capacityOptionsArr}
|
||||
id="representationCapacity"
|
||||
className="govuk-radios__input"
|
||||
errorMsg={t(
|
||||
"myrepresentations:select-an-option-label"
|
||||
)}
|
||||
component={RenderRadioListWithText}
|
||||
component={RenderRadioList}
|
||||
validate={[required]}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -7,10 +7,10 @@ import { connect } from "react-redux";
|
||||
import { useDropzone } from "react-dropzone";
|
||||
import {
|
||||
createWatchedCases,
|
||||
sendEmail,
|
||||
sendRepCompleteMessage,
|
||||
setRepInvolvment,
|
||||
} from "../../../actions";
|
||||
setRepInvolvment
|
||||
} from "../../../actions/services/portalService";
|
||||
import { sendEmail } from "../../../actions/services/notifyService";
|
||||
import { setRepresentationReset } from "../../../store/currentView/action";
|
||||
|
||||
const RepComplete = (props) => {
|
||||
@@ -27,7 +27,7 @@ const RepComplete = (props) => {
|
||||
setSubmitBack,
|
||||
setRepresentationSubmitConfirmation,
|
||||
setRepresentationMessageSent,
|
||||
repFormData,
|
||||
repFormData
|
||||
} = props;
|
||||
const { acceptedFiles, getRootProps, getInputProps } = useDropzone();
|
||||
const files = acceptedFiles.map((file) => (
|
||||
@@ -40,11 +40,16 @@ const RepComplete = (props) => {
|
||||
props.props.currentView.caseReference.appealType === 846040002;
|
||||
|
||||
useEffect(() => {
|
||||
const isWelsh = router.locale === "cy";
|
||||
const reference = isSIPS
|
||||
? "PEDW-CONSULTATION-COMPLETE"
|
||||
: "PEDW-REPRESENTATION-COMPLETE";
|
||||
? "PEDW-CONSULTATION-COMPLETE" + isWelsh && "-CY"
|
||||
: "PEDW-REPRESENTATION-COMPLETE" + isWelsh && "-CY";
|
||||
const templateId = isSIPS
|
||||
? "c3f373ca-df9d-4967-bea0-3ad3a57f8dcc"
|
||||
? isWelsh
|
||||
? "7d27b968-6f63-4334-b1c4-2e4a69554212"
|
||||
: "c3f373ca-df9d-4967-bea0-3ad3a57f8dcc"
|
||||
: isWelsh
|
||||
? "6e2f0111-b352-4074-91a2-760403cd185b"
|
||||
: "c49785e7-3217-40b6-b33f-dffc4e58d5c1";
|
||||
|
||||
const emailAddress =
|
||||
@@ -55,13 +60,14 @@ const RepComplete = (props) => {
|
||||
"emailAddress":
|
||||
props.props.props.props.accountDetails.accountDetails
|
||||
.emailaddress1,
|
||||
"linkExpiry": 10 * 60,
|
||||
"linkExpiry": 10 * 60
|
||||
};
|
||||
|
||||
props.props.currentView.representationMessageSent != true &&
|
||||
(props.props.currentView.representationMessageSent != true &&
|
||||
(setRepInvolvment(
|
||||
props.props.currentView.caseReference.incidentid,
|
||||
props.props.props.props.accountDetails.accountDetails.contactid
|
||||
props.props.props.props.accountDetails.accountDetails.contactid,
|
||||
props.props.currentView.representationCapacity
|
||||
),
|
||||
sendRepCompleteMessage(
|
||||
props.props.props.props.accountDetails.containerID,
|
||||
@@ -89,10 +95,10 @@ const RepComplete = (props) => {
|
||||
? props.props.currentView.caseReference.repDetails
|
||||
.representationType
|
||||
: props.props.currentView.caseReference
|
||||
.representationType,
|
||||
.representationType
|
||||
}),
|
||||
setRepresentationMessageSent(true)),
|
||||
window.scrollTo({ top: 0, behavior: "smooth" });
|
||||
window.scrollTo({ top: 0, behavior: "smooth" }));
|
||||
});
|
||||
return (
|
||||
<div id="rep-appellant">
|
||||
@@ -104,6 +110,7 @@ const RepComplete = (props) => {
|
||||
<p>{t("myrepresentations:rep-complete-para-one")}</p>
|
||||
<p>{t("myrepresentations:rep-complete-para-two")}</p>
|
||||
<p> {t("myrepresentations:rep-complete-para-three")}</p>
|
||||
<p> {t("myrepresentations:rep-complete-para-four")}</p>
|
||||
</div>
|
||||
<div className="govuk-grid-row">
|
||||
<div className="govuk-button-group">
|
||||
@@ -130,7 +137,7 @@ const mapStateToProps = (state) => {
|
||||
currentView: state.currentView,
|
||||
myRepresentations: state.myRepresentations,
|
||||
initialValues: state.currentView.caseReference.repDetails,
|
||||
accountDetails: state.accountDetails,
|
||||
accountDetails: state.accountDetails
|
||||
//form: state.form,
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import _ from "lodash";
|
||||
import useTranslation from "next-translate/useTranslation";
|
||||
import { useRouter } from "next/router";
|
||||
import { useState } from "react";
|
||||
import { useDropzone } from "react-dropzone";
|
||||
import { connect } from "react-redux";
|
||||
import { generateRepPDF } from "../../../actions/services/documentService";
|
||||
import RepComplete from "./representationComplete";
|
||||
import RepLPAQuestionnaireCheck_enforcement from "./representationQuestionnairesCheck/representationLPAQuestionnaireCheck_enforcement";
|
||||
import RepLPAQuestionnaireCheck_s78 from "./representationQuestionnairesCheck/representationLPAQuestionnaireCheck_s78";
|
||||
@@ -12,17 +12,21 @@ import {
|
||||
bytesToSize,
|
||||
getThumbnailIconByExtension,
|
||||
formatDates,
|
||||
hasOwn,
|
||||
updateLinks,
|
||||
getDocLink
|
||||
} from "../../utils";
|
||||
|
||||
import {
|
||||
setCurrentReference,
|
||||
setCurrentView,
|
||||
setCurrentView
|
||||
} from "../../../store/currentView/action";
|
||||
|
||||
const RepCompleteSubmit = (props) => {
|
||||
let { t } = useTranslation();
|
||||
const [confirmSections, setConfirmSections] = useState(false);
|
||||
const [downloadQuestionnaire, setDownloadQuestionnaire] = useState(false);
|
||||
const [downloadInProgress, setDownloadInProgress] = useState(false);
|
||||
|
||||
const router = useRouter();
|
||||
const { locale } = router;
|
||||
@@ -41,7 +45,11 @@ const RepCompleteSubmit = (props) => {
|
||||
questionnaireCount,
|
||||
finaliseAppealProcess,
|
||||
setCurrentReference,
|
||||
docsOffline
|
||||
} = props;
|
||||
|
||||
let ShowDocLinks = getDocLink(docsOffline);
|
||||
|
||||
const { acceptedFiles, getRootProps, getInputProps } = useDropzone();
|
||||
const files = acceptedFiles.map((file) => (
|
||||
<li key={file.path}>
|
||||
@@ -53,6 +61,13 @@ const RepCompleteSubmit = (props) => {
|
||||
|
||||
repFormData = updateLinks(repFormData);
|
||||
|
||||
const representationOnBehalfOfDisplay =
|
||||
repFormData.representationOnBehalfOf === "Yes"
|
||||
? t("myrepresentations:questionnaire-yes")
|
||||
: repFormData.representationOnBehalfOf === "No"
|
||||
? t("myrepresentations:questionnaire-no")
|
||||
: repFormData.representationOnBehalfOf;
|
||||
|
||||
//const repDate = new Date();
|
||||
|
||||
// let day = repDate.getDate();
|
||||
@@ -164,7 +179,7 @@ const RepCompleteSubmit = (props) => {
|
||||
typeof filesUploadObj[key].name != "undefined" &&
|
||||
buildAppealFilesArray.push({
|
||||
"name": filesUploadObj[key].name,
|
||||
"size": filesUploadObj[key].contentLength,
|
||||
"size": filesUploadObj[key].contentLength
|
||||
});
|
||||
}
|
||||
|
||||
@@ -180,7 +195,7 @@ const RepCompleteSubmit = (props) => {
|
||||
// : [];
|
||||
|
||||
let arrUniq = [
|
||||
...new Map(buildAppealFilesArray.map((v) => [v.name, v])).values(),
|
||||
...new Map(buildAppealFilesArray.map((v) => [v.name, v])).values()
|
||||
];
|
||||
|
||||
buildAppealFilesArray = buildAppealFilesArray.filter(function (el) {
|
||||
@@ -212,40 +227,104 @@ const RepCompleteSubmit = (props) => {
|
||||
arrUniq = removeEmptyObjects(arrUniq);
|
||||
|
||||
Object.assign(formObj.representationForm.values, {
|
||||
"filesList": arrUniq,
|
||||
"filesList": arrUniq
|
||||
});
|
||||
|
||||
let filterFiles = [];
|
||||
|
||||
function showRepsEnded(endDate) {
|
||||
let date = new Date();
|
||||
date = new Date(date.toDateString());
|
||||
let end = new Date(endDate);
|
||||
end.setUTCHours(23);
|
||||
end.setUTCMinutes(59);
|
||||
end.setUTCSeconds(59);
|
||||
end.toISOString();
|
||||
if (!endDate) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return end > date ? false : true;
|
||||
const end = new Date(endDate);
|
||||
|
||||
if (Number.isNaN(end.getTime())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const today = new Date();
|
||||
today.setHours(0, 0, 0, 0);
|
||||
|
||||
end.setHours(23, 59, 59, 999);
|
||||
|
||||
return end <= today;
|
||||
}
|
||||
|
||||
const checkRepDatePassed = () => {
|
||||
if (repFormData.representationType == "Questionnaire") {
|
||||
if (repFormData.representationType === "Questionnaire") {
|
||||
return false;
|
||||
} else {
|
||||
if (repFormData.representationType == "Final comments") {
|
||||
return repFormData.hasOwnProperty(
|
||||
"pinswg_finalcommentsduedate"
|
||||
) && showRepsEnded(repFormData.pinswg_finalcommentsduedate)
|
||||
? true
|
||||
: false;
|
||||
}
|
||||
if (repFormData.representationType == "Statement") {
|
||||
return repFormData.hasOwnProperty("pinswg_statementduedate") &&
|
||||
showRepsEnded(repFormData.pinswg_statementduedate)
|
||||
? true
|
||||
: false;
|
||||
|
||||
if (repFormData.representationType === "Final comments") {
|
||||
return showRepsEnded(repFormData.pinswg_finalcommentsduedate);
|
||||
}
|
||||
|
||||
if (repFormData.representationType === "Statement") {
|
||||
return (
|
||||
showRepsEnded(repFormData.pinswg_statementduedate) ||
|
||||
showRepsEnded(repFormData.pinswg_endofrepresentationperiod)
|
||||
);
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
const triggerQuestionnaireDownload = async () => {
|
||||
if (
|
||||
repFormData.representationType !== "Questionnaire" ||
|
||||
!downloadQuestionnaire
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (downloadInProgress) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
setDownloadInProgress(true);
|
||||
|
||||
const containerID =
|
||||
props.accountDetails?.containerID ||
|
||||
props.props?.accountDetails?.containerID ||
|
||||
props.props?.props?.accountDetails?.containerID;
|
||||
const caseRef =
|
||||
currentView?.caseReference?.ticketnumber ||
|
||||
repFormData?.caseRef ||
|
||||
repFormData?.ticketnumber;
|
||||
|
||||
if (!containerID || !caseRef) {
|
||||
console.error(
|
||||
"Questionnaire download skipped: missing containerID or case reference",
|
||||
{ containerID, caseRef }
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
repFormData.locale = router.locale == "cy" ? "cy" : "en";
|
||||
|
||||
const pdfBlob = await generateRepPDF(
|
||||
repFormData,
|
||||
containerID,
|
||||
caseRef,
|
||||
{ download: true }
|
||||
);
|
||||
|
||||
if (pdfBlob) {
|
||||
const blobUrl = window.URL.createObjectURL(pdfBlob);
|
||||
const anchor = document.createElement("a");
|
||||
anchor.href = blobUrl;
|
||||
anchor.download = `${repFormData.repfile_name || "questionnaire"}.pdf`;
|
||||
document.body.appendChild(anchor);
|
||||
anchor.click();
|
||||
anchor.remove();
|
||||
window.URL.revokeObjectURL(blobUrl);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Questionnaire download failed", error);
|
||||
} finally {
|
||||
setDownloadInProgress(false);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -264,19 +343,31 @@ const RepCompleteSubmit = (props) => {
|
||||
<div className="govuk-grid-row govuk-body">
|
||||
<h1 className="govuk-heading-m ">
|
||||
{" "}
|
||||
{t(
|
||||
{repFormData.appealType == 846040002
|
||||
? t(
|
||||
"myrepresentations:consultation-check-submit-heading"
|
||||
)
|
||||
: t(
|
||||
"myrepresentations:rep-check-submit-heading"
|
||||
)}
|
||||
</h1>
|
||||
<dl className="govuk-summary-list ">
|
||||
<h2 className="govuk-heading-m govuk-!-margin-top-9">
|
||||
{t(
|
||||
{repFormData.appealType == 846040002
|
||||
? t(
|
||||
"myrepresentations:consultation-check-your-rep-heading"
|
||||
)
|
||||
: t(
|
||||
"myrepresentations:rep-check-your-rep-heading"
|
||||
)}
|
||||
</h2>
|
||||
<div className="govuk-summary-list__row">
|
||||
<dt className="govuk-summary-list__key">
|
||||
{t(
|
||||
{repFormData.appealType == 846040002
|
||||
? t(
|
||||
"case:consultation-representation-type"
|
||||
)
|
||||
: t(
|
||||
"case:representation-representation-type"
|
||||
)}
|
||||
</dt>
|
||||
@@ -314,7 +405,7 @@ const RepCompleteSubmit = (props) => {
|
||||
</a> */}
|
||||
</dd>
|
||||
</div>
|
||||
{_.has(
|
||||
{hasOwn(
|
||||
repFormData,
|
||||
"representationOnBehalfOf"
|
||||
) && (
|
||||
@@ -328,7 +419,7 @@ const RepCompleteSubmit = (props) => {
|
||||
|
||||
<dd className="govuk-summary-list__value">
|
||||
{
|
||||
repFormData.representationOnBehalfOf
|
||||
representationOnBehalfOfDisplay
|
||||
}
|
||||
</dd>
|
||||
|
||||
@@ -350,7 +441,7 @@ const RepCompleteSubmit = (props) => {
|
||||
"appealType":
|
||||
repFormData.appealType,
|
||||
"repDetails":
|
||||
repFormData,
|
||||
repFormData
|
||||
});
|
||||
setRepresentationSubmit(
|
||||
false
|
||||
@@ -403,7 +494,7 @@ const RepCompleteSubmit = (props) => {
|
||||
"appealType":
|
||||
repFormData.appealType,
|
||||
"repDetails":
|
||||
repFormData,
|
||||
repFormData
|
||||
}
|
||||
);
|
||||
setRepresentationSubmit(
|
||||
@@ -427,17 +518,20 @@ const RepCompleteSubmit = (props) => {
|
||||
</>
|
||||
)}
|
||||
{repFormData.representationType !=
|
||||
"Questionnaire" && (
|
||||
"Questionnaire" &&
|
||||
repFormData.appealType != 846040002 && (
|
||||
<div className="govuk-summary-list__row">
|
||||
<dt className="govuk-summary-list__key">
|
||||
{t("case:representation-comments")}
|
||||
{t(
|
||||
"case:representation-comments"
|
||||
)}
|
||||
</dt>
|
||||
|
||||
<dd className="govuk-summary-list__value">
|
||||
<span
|
||||
className="multiline-elipsis"
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: repFormData.representationComments,
|
||||
__html: repFormData.representationComments
|
||||
}}
|
||||
/>
|
||||
</dd>
|
||||
@@ -461,14 +555,16 @@ const RepCompleteSubmit = (props) => {
|
||||
"appealType":
|
||||
repFormData.appealType,
|
||||
"repDetails":
|
||||
repFormData,
|
||||
repFormData
|
||||
});
|
||||
setRepresentationSubmit(
|
||||
false
|
||||
);
|
||||
}}
|
||||
>
|
||||
{t("common:change-link-label")}
|
||||
{t(
|
||||
"common:change-link-label"
|
||||
)}
|
||||
<span className="govuk-visually-hidden">
|
||||
{" "}
|
||||
{/* {FieldsTranslations(
|
||||
@@ -539,7 +635,7 @@ const RepCompleteSubmit = (props) => {
|
||||
"appealType":
|
||||
repFormData.appealType,
|
||||
"repDetails":
|
||||
repFormData,
|
||||
repFormData
|
||||
}),
|
||||
setRepresentationSubmit(
|
||||
false
|
||||
@@ -586,6 +682,8 @@ const RepCompleteSubmit = (props) => {
|
||||
"myrepresentations:rep-check-tandc-para-three"
|
||||
)}
|
||||
</p>
|
||||
<p></p>
|
||||
|
||||
{checkRepDatePassed() ? (
|
||||
<div className="govuk-warning-text noticebanner">
|
||||
<strong className="govuk-warning-text__text">
|
||||
@@ -624,8 +722,63 @@ const RepCompleteSubmit = (props) => {
|
||||
{t("myrepresentations:rep-wait-label")}
|
||||
</p>
|
||||
</div>
|
||||
) : ShowDocLinks ? (
|
||||
<>
|
||||
{" "}
|
||||
<div className="govuk-warning-text ">
|
||||
<span
|
||||
className="govuk-warning-text__icon"
|
||||
aria-hidden="true"
|
||||
>
|
||||
!
|
||||
</span>
|
||||
<strong className="govuk-warning-text__text govuk-!-margin-top-2">
|
||||
<span className="govuk-visually-hidden">
|
||||
Notice
|
||||
</span>
|
||||
{t(
|
||||
"myrepresentations:docsoffline-reps-label"
|
||||
)}
|
||||
{" "}
|
||||
</strong>
|
||||
</div>{" "}
|
||||
<Link className="govuk-link" href="/">
|
||||
{t(
|
||||
"myrepresentations:return-to-myportal-link"
|
||||
)}
|
||||
</Link>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
{repFormData.representationType ==
|
||||
"Questionnaire" && (
|
||||
<div className="govuk-checkboxes govuk-checkboxes--small">
|
||||
<div className="govuk-checkboxes__item">
|
||||
<input
|
||||
name="pinswg_downloadQuestionnaire"
|
||||
id="pinswg_downloadQuestionnaire"
|
||||
type="checkbox"
|
||||
className="govuk-checkboxes__input"
|
||||
checked={
|
||||
downloadQuestionnaire
|
||||
}
|
||||
onChange={(e) => {
|
||||
setDownloadQuestionnaire(
|
||||
e.target.checked
|
||||
);
|
||||
}}
|
||||
/>
|
||||
<label
|
||||
className="govuk-label govuk-checkboxes__label"
|
||||
htmlFor="pinswg_downloadQuestionnaire"
|
||||
>
|
||||
{t(
|
||||
"myrepresentations:rep-check-tandc-para-five"
|
||||
)}
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
<div className="govuk-form-group">
|
||||
<div className="govuk-checkboxes govuk-checkboxes--small">
|
||||
<div className="govuk-checkboxes__item">
|
||||
@@ -664,10 +817,11 @@ const RepCompleteSubmit = (props) => {
|
||||
type="submit"
|
||||
className="govuk-button"
|
||||
data-module="govuk-button"
|
||||
onClick={() => {
|
||||
onClick={async () => {
|
||||
// setRepresentationSubmitConfirmation(
|
||||
// true
|
||||
// );
|
||||
await triggerQuestionnaireDownload();
|
||||
setRepresentationSubmit(
|
||||
true
|
||||
);
|
||||
@@ -704,7 +858,7 @@ const mapStateToProps = (state) => {
|
||||
currentView: state.currentView,
|
||||
myRepresentations: state.myRepresentations,
|
||||
initialValues: state.currentView.caseReference.repDetails,
|
||||
accountDetails: state.accountDetails,
|
||||
accountDetails: state.accountDetails
|
||||
//form: state.form,
|
||||
};
|
||||
};
|
||||
@@ -713,7 +867,7 @@ const mapDispatchToProps = (dispatch) => {
|
||||
return {
|
||||
setCurrentReference: (currentReference) => {
|
||||
dispatch(setCurrentReference(currentReference));
|
||||
},
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { JSONPath as jsonpath } from "jsonpath-plus";
|
||||
import useTranslation from "next-translate/useTranslation";
|
||||
import { useRouter } from "next/router";
|
||||
import { hasOwn } from "../../utils";
|
||||
|
||||
const RepDetails = (props) => {
|
||||
let { t } = useTranslation();
|
||||
@@ -8,7 +9,7 @@ const RepDetails = (props) => {
|
||||
const router = useRouter();
|
||||
const { locale } = router;
|
||||
|
||||
const { currentType, casesObj } = props;
|
||||
const { currentType, casesObj, appealType } = props;
|
||||
|
||||
let { caseReference, ticketnumber } = props;
|
||||
|
||||
@@ -31,7 +32,7 @@ const RepDetails = (props) => {
|
||||
detailsObj = jsonpath({
|
||||
path: '$..[?(@ && @.ticketnumber=="' + ticketnumber + '")]',
|
||||
json: setCaseDetailsObj,
|
||||
eval: true,
|
||||
eval: true
|
||||
});
|
||||
|
||||
detailsObj = detailsObj[0];
|
||||
@@ -61,34 +62,43 @@ const RepDetails = (props) => {
|
||||
{t("case:summary-site-address-label")}
|
||||
</dt>
|
||||
<dd className="govuk-summary-list__value">
|
||||
{_.has(detailsObj, "pinswg_siteaddressline1")
|
||||
{hasOwn(detailsObj, "pinswg_siteaddressline1")
|
||||
? detailsObj.pinswg_siteaddressline1
|
||||
: ""}
|
||||
{_.has(detailsObj, "pinswg_siteaddressline1") &&
|
||||
{hasOwn(
|
||||
detailsObj,
|
||||
"pinswg_siteaddressline1"
|
||||
) &&
|
||||
detailsObj.pinswg_siteaddressline1 !=
|
||||
null && <br />}
|
||||
{_.has(detailsObj, "pinswg_siteaddressline2")
|
||||
{hasOwn(detailsObj, "pinswg_siteaddressline2")
|
||||
? detailsObj.pinswg_siteaddressline2
|
||||
: ""}
|
||||
{_.has(detailsObj, "pinswg_siteaddressline2") &&
|
||||
{hasOwn(
|
||||
detailsObj,
|
||||
"pinswg_siteaddressline2"
|
||||
) &&
|
||||
detailsObj.pinswg_siteaddressline2 !=
|
||||
null && <br />}
|
||||
{_.has(detailsObj, "pinswg_siteaddresstown")
|
||||
{hasOwn(detailsObj, "pinswg_siteaddresstown")
|
||||
? detailsObj.pinswg_siteaddresstown
|
||||
: ""}
|
||||
{_.has(detailsObj, "pinswg_siteaddresstown") &&
|
||||
{hasOwn(detailsObj, "pinswg_siteaddresstown") &&
|
||||
detailsObj.pinswg_siteaddresstown !=
|
||||
null && <br />}
|
||||
{_.has(detailsObj, "pinswg_siteaddresscounty")
|
||||
{hasOwn(detailsObj, "pinswg_siteaddresscounty")
|
||||
? detailsObj.pinswg_siteaddresscounty
|
||||
: ""}
|
||||
{_.has(
|
||||
{hasOwn(
|
||||
detailsObj,
|
||||
"pinswg_siteaddresscounty"
|
||||
) &&
|
||||
detailsObj.pinswg_siteaddresscounty !=
|
||||
null && <br />}
|
||||
{_.has(detailsObj, "pinswg_siteaddresspostcode")
|
||||
{hasOwn(
|
||||
detailsObj,
|
||||
"pinswg_siteaddresspostcode"
|
||||
)
|
||||
? detailsObj.pinswg_siteaddresspostcode
|
||||
: ""}
|
||||
</dd>
|
||||
@@ -97,10 +107,14 @@ const RepDetails = (props) => {
|
||||
</div>
|
||||
<div className="govuk-grid-row">
|
||||
<p className="govuk-body">
|
||||
{t("myrepresentations:capacity-para-one")}
|
||||
{appealType == 846040002
|
||||
? t("myrepresentations:sips-capacity-para-one")
|
||||
: t("myrepresentations:capacity-para-one")}
|
||||
</p>
|
||||
<p className="govuk-body">
|
||||
{t("myrepresentations:capacity-para-two")}
|
||||
{appealType == 846040002
|
||||
? t("myrepresentations:sips-capacity-para-two")
|
||||
: t("myrepresentations:capacity-para-two")}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -13,8 +13,8 @@ import {
|
||||
deleteBlob,
|
||||
deleteRepBlob,
|
||||
getFilesFromBlobHashed,
|
||||
getFilesFromBlobproxy,
|
||||
} from "../../../actions";
|
||||
getFilesFromBlobproxy
|
||||
} from "../../../actions/services/documentService";
|
||||
|
||||
const LoadingMessage = () => <div>Loading the editor...</div>;
|
||||
|
||||
@@ -23,7 +23,7 @@ const ReactQuill = dynamic(
|
||||
() => import("react-quill-new").then((mod) => mod.default),
|
||||
{
|
||||
ssr: false,
|
||||
loading: () => <LoadingMessage />, // This is valid as long as it's a valid React component
|
||||
loading: () => <LoadingMessage /> // This is valid as long as it's a valid React component
|
||||
}
|
||||
);
|
||||
import { useDispatch } from "react-redux"; // Import the useDispatch hook
|
||||
@@ -35,13 +35,13 @@ import {
|
||||
parseISO,
|
||||
subDays,
|
||||
subMonths,
|
||||
subYears,
|
||||
subYears
|
||||
} from "date-fns";
|
||||
|
||||
import {
|
||||
bytesToSize,
|
||||
getThumbnailIconByExtension,
|
||||
updateLinks,
|
||||
updateLinks
|
||||
} from "../../utils";
|
||||
|
||||
import { useRouter } from "next/router";
|
||||
@@ -258,6 +258,26 @@ export const RenderCondtionalRadioList = ({
|
||||
}) => {
|
||||
const required = (value) => (value ? undefined : "Required");
|
||||
let { t } = useTranslation();
|
||||
|
||||
const yesValue = t("myrepresentations:questionnaire-yes");
|
||||
const noValue = t("myrepresentations:questionnaire-no");
|
||||
|
||||
const normalizeYesNo = (rawValue) => {
|
||||
if (rawValue === true) return "Yes";
|
||||
if (rawValue === false) return "No";
|
||||
if (rawValue === "Yes" || rawValue === yesValue) return "Yes";
|
||||
if (rawValue === "No" || rawValue === noValue) return "No";
|
||||
return rawValue;
|
||||
};
|
||||
|
||||
const isYesSelected = normalizeYesNo(value) === "Yes";
|
||||
|
||||
const requiredIfYes = (fieldValue, allValues) => {
|
||||
const selectedValue = normalizeYesNo(allValues?.[id]);
|
||||
return selectedValue === "Yes" && !String(fieldValue || "").trim()
|
||||
? "Required"
|
||||
: undefined;
|
||||
};
|
||||
return (
|
||||
<>
|
||||
<div
|
||||
@@ -304,8 +324,16 @@ export const RenderCondtionalRadioList = ({
|
||||
{custom.hint}
|
||||
</div>
|
||||
<div className="govuk-radios">
|
||||
{Object.keys(options).map((key, index) => (
|
||||
<div key={key} className="govuk-!-margin-bottom-3">
|
||||
{Object.keys(options).map((key, index) => {
|
||||
const normalizedOptionValue = normalizeYesNo(
|
||||
options[key]
|
||||
);
|
||||
|
||||
return (
|
||||
<div
|
||||
key={key}
|
||||
className="govuk-!-margin-bottom-3"
|
||||
>
|
||||
<div
|
||||
className="govuk-radios__item"
|
||||
data-children-count={key}
|
||||
@@ -317,7 +345,7 @@ export const RenderCondtionalRadioList = ({
|
||||
component="input"
|
||||
type="radio"
|
||||
className="govuk-radios__input"
|
||||
value={options[key]}
|
||||
value={normalizedOptionValue}
|
||||
validate={[required]}
|
||||
/>
|
||||
<label
|
||||
@@ -333,7 +361,8 @@ export const RenderCondtionalRadioList = ({
|
||||
)}
|
||||
</label>
|
||||
</div>
|
||||
{value == "Yes" && options[key] == "Yes" && (
|
||||
{isYesSelected &&
|
||||
normalizedOptionValue === "Yes" && (
|
||||
<div
|
||||
className="govuk-radios__conditional "
|
||||
id={"conditional-" + id}
|
||||
@@ -344,7 +373,9 @@ export const RenderCondtionalRadioList = ({
|
||||
>
|
||||
<label
|
||||
className="govuk-label"
|
||||
htmlFor={id + "_details"}
|
||||
htmlFor={
|
||||
id + "_details"
|
||||
}
|
||||
>
|
||||
{t(
|
||||
"myrepresentations:representation-onbehalfof-label"
|
||||
@@ -354,9 +385,13 @@ export const RenderCondtionalRadioList = ({
|
||||
className="govuk-input govuk-!-width-one-half"
|
||||
id={id + "_details"}
|
||||
name={id + "_details"}
|
||||
component={RenderTextfield}
|
||||
component={
|
||||
RenderTextfield
|
||||
}
|
||||
type="text"
|
||||
validate={[required]}
|
||||
validate={[
|
||||
requiredIfYes
|
||||
]}
|
||||
errorMsg={t(
|
||||
"myrepresentations:is-required-label"
|
||||
)}
|
||||
@@ -365,7 +400,8 @@ export const RenderCondtionalRadioList = ({
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</fieldset>
|
||||
</div>
|
||||
@@ -546,7 +582,8 @@ export const RenderPickList = ({
|
||||
? "Sylwadau ysgrifenedig"
|
||||
: optionsArr[key] == "Inquiry"
|
||||
? "Ymchwiliad"
|
||||
: optionsArr[key] == "Hearing"
|
||||
: optionsArr[key] ==
|
||||
"Hearing"
|
||||
? "Gwrandawiad"
|
||||
: optionsArr[key]
|
||||
: optionsArr[key]}
|
||||
@@ -734,13 +771,19 @@ export const RenderMultiline = ({
|
||||
input.onChange(valStr);
|
||||
};
|
||||
|
||||
const handleBlur = () => {
|
||||
const updated = updateLinks(editValue);
|
||||
setEditValue(updated);
|
||||
input.onChange(updated);
|
||||
};
|
||||
|
||||
var modules = {
|
||||
toolbar: [
|
||||
[{ "header": [1, 2, false] }],
|
||||
["bold", "italic", "underline", "blockquote"],
|
||||
[{ "list": "ordered" }, { "list": "bullet" }],
|
||||
["clean"],
|
||||
],
|
||||
["clean"]
|
||||
]
|
||||
};
|
||||
|
||||
return (
|
||||
@@ -764,6 +807,7 @@ export const RenderMultiline = ({
|
||||
theme="snow"
|
||||
value={editValue}
|
||||
onChange={changeEdit}
|
||||
onBlur={handleBlur}
|
||||
/>
|
||||
<textarea
|
||||
{...input}
|
||||
@@ -795,18 +839,23 @@ export const RenderRichMultiline = ({
|
||||
);
|
||||
|
||||
const changeEdit = (valStr) => {
|
||||
valStr = updateLinks(valStr);
|
||||
setEditValue(valStr);
|
||||
input.onChange(valStr);
|
||||
};
|
||||
|
||||
const handleBlur = () => {
|
||||
const updated = updateLinks(editValue);
|
||||
setEditValue(updated);
|
||||
input.onChange(updated);
|
||||
};
|
||||
|
||||
var modules = {
|
||||
toolbar: [
|
||||
[{ "header": [1, 2, false] }],
|
||||
["bold", "italic", "underline", "blockquote"],
|
||||
[{ "list": "ordered" }, { "list": "bullet" }],
|
||||
["clean"],
|
||||
],
|
||||
["clean"]
|
||||
]
|
||||
};
|
||||
|
||||
return (
|
||||
@@ -819,6 +868,7 @@ export const RenderRichMultiline = ({
|
||||
theme="snow"
|
||||
value={editValue}
|
||||
onChange={changeEdit}
|
||||
onBlur={handleBlur}
|
||||
/>
|
||||
<textarea
|
||||
{...input}
|
||||
@@ -874,19 +924,19 @@ const baseStyle = {
|
||||
borderStyle: "dashed",
|
||||
backgroundColor: "#fafafa",
|
||||
color: "#bdbdbd",
|
||||
transition: "border .3s ease-in-out",
|
||||
transition: "border .3s ease-in-out"
|
||||
};
|
||||
|
||||
const activeStyle = {
|
||||
borderColor: "#2196f3",
|
||||
borderColor: "#2196f3"
|
||||
};
|
||||
|
||||
const acceptStyle = {
|
||||
borderColor: "#00e676",
|
||||
borderColor: "#00e676"
|
||||
};
|
||||
|
||||
const rejectStyle = {
|
||||
borderColor: "#ff1744",
|
||||
borderColor: "#ff1744"
|
||||
};
|
||||
|
||||
export const RenderFileUpload = (field) => {
|
||||
@@ -897,7 +947,7 @@ export const RenderFileUpload = (field) => {
|
||||
|
||||
const style = useMemo(
|
||||
() => ({
|
||||
...baseStyle,
|
||||
...baseStyle
|
||||
// ...(isDragActive ? activeStyle : {}),
|
||||
// ...(isDragAccept ? acceptStyle : {}),
|
||||
// ...(isDragReject ? rejectStyle : {}),
|
||||
@@ -993,7 +1043,7 @@ export const RenderFileUpload = (field) => {
|
||||
typeof filesUploadObj[key].name != "undefined" &&
|
||||
buildAppealFilesArray.push({
|
||||
"name": filesUploadObj[key].name,
|
||||
"size": filesUploadObj[key].size,
|
||||
"size": filesUploadObj[key].size
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1042,9 +1092,12 @@ export const RenderFileUpload = (field) => {
|
||||
});
|
||||
};
|
||||
|
||||
const [errorMessage, setErrorMessage] = useState(null);
|
||||
const [rejectedFiles, setRejectedFiles] = useState([]); // Store rejected files
|
||||
|
||||
const [completedUploadFiles, setCompletedUploadFiles] = useState(false);
|
||||
const [uploadCountMessage, setUploadCountMessage] = useState("");
|
||||
const [totalUploadFiles, setTotalUploadFiles] = useState(0);
|
||||
|
||||
const handleDropRejected = (fileRejections) => {
|
||||
const errors = fileRejections
|
||||
@@ -1060,6 +1113,15 @@ export const RenderFileUpload = (field) => {
|
||||
"myrepresentations:fileupload-file-error-invalid-type-label"
|
||||
)}`;
|
||||
}
|
||||
|
||||
if (error.code === "filename-invalid-chars") {
|
||||
return (
|
||||
error.message ||
|
||||
`${file.name} ${t(
|
||||
"newappeal:new-appeal-fileupload-file-error-invalid-filename-label"
|
||||
)}`
|
||||
);
|
||||
}
|
||||
return `${file.name} ${t(
|
||||
"myrepresentations:fileupload-file-error-invalid-label"
|
||||
)}`;
|
||||
@@ -1076,6 +1138,44 @@ export const RenderFileUpload = (field) => {
|
||||
setRejectedFiles([]); // Clear any previously rejected file errorsss
|
||||
};
|
||||
|
||||
const FILENAME_ALLOWED = /^[A-Za-z0-9 ._\-:()—']+$/;
|
||||
|
||||
const validateFilename = (file, t) => {
|
||||
const name = file.name;
|
||||
|
||||
// block #
|
||||
if (name.includes("#")) {
|
||||
return {
|
||||
code: "filename-invalid-chars",
|
||||
message: `${name} ${t(
|
||||
"myrepresentations:fileupload-file-error-invalid-filename-label"
|
||||
)}`
|
||||
};
|
||||
}
|
||||
|
||||
// broader blocklist (optional but recommended)
|
||||
if (!FILENAME_ALLOWED.test(name)) {
|
||||
return {
|
||||
code: "filename-invalid-chars",
|
||||
message: `${name} ${t(
|
||||
"myrepresentations:fileupload-file-error-invalid-filename-label"
|
||||
)}`
|
||||
};
|
||||
}
|
||||
|
||||
// block characters < > " / \ | ? *
|
||||
if (/[<>"/\\|?*]/.test(name)) {
|
||||
return {
|
||||
code: "filename-invalid-chars",
|
||||
message: `${name} ${t(
|
||||
"myrepresentations:fileupload-file-error-invalid-filename-label"
|
||||
)}`
|
||||
};
|
||||
}
|
||||
|
||||
return null; // valid
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<Dropzone
|
||||
@@ -1089,11 +1189,30 @@ export const RenderFileUpload = (field) => {
|
||||
"image/jpeg": [".jpg", ".jpeg"],
|
||||
"image/png": [".png"],
|
||||
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet":
|
||||
[".xlsx"],
|
||||
[".xlsx"]
|
||||
}}
|
||||
onDrop={(filesToUpload, e) => {
|
||||
validator={(file) => validateFilename(file, t)}
|
||||
onDrop={(acceptedFiles, fileRejections, e) => {
|
||||
// build + display rejected messages (ALWAYS, even if some accepted)
|
||||
if (fileRejections?.length) {
|
||||
handleDropRejected(fileRejections);
|
||||
} else {
|
||||
// only clear rejections when nothing was rejected on this drop
|
||||
setRejectedFiles([]);
|
||||
setErrorMessage(null);
|
||||
}
|
||||
|
||||
// if nothing accepted, stop (prevents showing only "uploading" when all invalid)
|
||||
if (!acceptedFiles || acceptedFiles.length === 0) {
|
||||
setCompletedUploadFiles(true); // optional: depends on your UX
|
||||
setUploadCountMessage(0);
|
||||
setTotalUploadFiles(0);
|
||||
return;
|
||||
}
|
||||
|
||||
setCompletedUploadFiles(false);
|
||||
const renamedAcceptedFiles = filesToUpload.map(
|
||||
|
||||
const renamedAcceptedFiles = acceptedFiles.map(
|
||||
(file) =>
|
||||
new File(
|
||||
[file],
|
||||
@@ -1111,12 +1230,22 @@ export const RenderFileUpload = (field) => {
|
||||
.values.repfile_name
|
||||
}_-_Attachment_-_${file.name}`,
|
||||
{
|
||||
type: file.type,
|
||||
type: file.type
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
field.input.onChange(renamedAcceptedFiles);
|
||||
setUploadCountMessage(renamedAcceptedFiles.length);
|
||||
|
||||
if (typeof field.setFileCount === "function") {
|
||||
field.setFileCount(
|
||||
(field.uploadCount || 0) +
|
||||
renamedAcceptedFiles.length
|
||||
);
|
||||
}
|
||||
|
||||
setUploadCountMessage(0);
|
||||
setTotalUploadFiles(renamedAcceptedFiles.length);
|
||||
|
||||
uploadSingleFile(
|
||||
renamedAcceptedFiles,
|
||||
@@ -1124,7 +1253,12 @@ export const RenderFileUpload = (field) => {
|
||||
field.ticketnumber +
|
||||
"/" +
|
||||
field.filenamePrefix.representationForm.values
|
||||
.repfile_name
|
||||
.repfile_name,
|
||||
{
|
||||
onChunkComplete: ({ cumulativeUploaded }) => {
|
||||
setUploadCountMessage(cumulativeUploaded);
|
||||
}
|
||||
}
|
||||
).then((data) => {
|
||||
console.log(data);
|
||||
let buildAppealFilesArray = [];
|
||||
@@ -1135,7 +1269,7 @@ export const RenderFileUpload = (field) => {
|
||||
typeof filesUploadObj[key].name != "undefined" &&
|
||||
buildAppealFilesArray.push({
|
||||
"name": filesUploadObj[key].name,
|
||||
"size": filesUploadObj[key].size,
|
||||
"size": filesUploadObj[key].size
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1196,8 +1330,6 @@ export const RenderFileUpload = (field) => {
|
||||
});
|
||||
});
|
||||
}}
|
||||
onDropRejected={handleDropRejected}
|
||||
onDropAccepted={handleDropAccepted}
|
||||
>
|
||||
{({ getRootProps, getInputProps }) => (
|
||||
<>
|
||||
@@ -1224,7 +1356,7 @@ export const RenderFileUpload = (field) => {
|
||||
</>
|
||||
)}
|
||||
</Dropzone>
|
||||
{rejectedFiles.length > 0 && completedUploadFiles == true && (
|
||||
{rejectedFiles.length > 0 && (
|
||||
<div
|
||||
style={{ color: "red", marginTop: "10px" }}
|
||||
className="govuk-body govuk-!-font-size-14 "
|
||||
@@ -1236,17 +1368,20 @@ export const RenderFileUpload = (field) => {
|
||||
</ul>
|
||||
</div>
|
||||
)}
|
||||
{uploadCountMessage > 0 && completedUploadFiles == false && (
|
||||
{totalUploadFiles > 0 && completedUploadFiles == false && (
|
||||
<div className="govuk-body govuk-!-font-size-14">
|
||||
{t("home:uploading-files-label", {
|
||||
number: uploadCountMessage,
|
||||
number:
|
||||
totalUploadFiles > 0
|
||||
? `${uploadCountMessage} of ${totalUploadFiles}`
|
||||
: uploadCountMessage
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
{completedUploadFiles > 0 && uploadCountMessage >= 0 && (
|
||||
<div className="govuk-body govuk-!-font-size-14">
|
||||
{t("home:completed-uploading-files-label", {
|
||||
number: uploadCountMessage,
|
||||
number: uploadCountMessage
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
@@ -1385,6 +1520,12 @@ export function FileUploadField(props) {
|
||||
);
|
||||
}
|
||||
|
||||
export const shouldDisableButton = ({ props, formObj }) =>
|
||||
!(
|
||||
props?.currentView?.fileList?.length > 0 ||
|
||||
typeof formObj?.representationForm?.values?.representationComments !==
|
||||
"undefined"
|
||||
);
|
||||
// export const RepresentationGuidanceText = (appealType) => {
|
||||
// let { t } = useTranslation();
|
||||
|
||||
|
||||
@@ -2,21 +2,23 @@ import useTranslation from "next-translate/useTranslation";
|
||||
import { useRouter } from "next/router";
|
||||
import { connect } from "react-redux";
|
||||
import { Field, change, reduxForm } from "redux-form";
|
||||
import { useState } from "react";
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
import { bytesToSize, getThumbnailIconByExtension } from "../../utils";
|
||||
import {
|
||||
FileUploadField,
|
||||
RenderCondtionalRadioList,
|
||||
RenderPickList,
|
||||
RenderRichMultiline,
|
||||
shouldDisableButton
|
||||
} from "./representationElements";
|
||||
import RepresentationActionButtons from "./elements/RepresentationActionButtons";
|
||||
import RepresentationTypeSelectorBlock from "./elements/RepresentationTypeSelectorBlock";
|
||||
|
||||
import { useDropzone } from "react-dropzone";
|
||||
import {
|
||||
setRepresentationCapacity,
|
||||
setRepresentationSubmit,
|
||||
setFilesForRepresentations,
|
||||
setFilesForRepresentations
|
||||
} from "../../../store/currentView/action";
|
||||
|
||||
const RepInterestedPartyPerson = (props) => {
|
||||
@@ -34,11 +36,25 @@ const RepInterestedPartyPerson = (props) => {
|
||||
setSavingStatus,
|
||||
savingStatus,
|
||||
setFilesForRepresentations,
|
||||
onRepresentationTypeChange,
|
||||
onTypeSelectionConfirmed
|
||||
} = props;
|
||||
const required = (value) => (value ? undefined : "Required");
|
||||
|
||||
const { acceptedFiles, getRootProps, getInputProps } = useDropzone();
|
||||
|
||||
const persistedRepresentationType =
|
||||
props.currentView?.caseReference?.repDetails?.representationType;
|
||||
const [typeSelectionConfirmed, setTypeSelectionConfirmed] = useState(
|
||||
!!persistedRepresentationType
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (persistedRepresentationType) {
|
||||
setTypeSelectionConfirmed(true);
|
||||
}
|
||||
}, [persistedRepresentationType]);
|
||||
|
||||
if (JSON.stringify(formObj) != "{}") {
|
||||
setRepFileName(formObj.representationForm.values);
|
||||
|
||||
@@ -61,65 +77,52 @@ const RepInterestedPartyPerson = (props) => {
|
||||
{file.path} - {file.size} bytes
|
||||
</li>
|
||||
));
|
||||
|
||||
const selectedRepresentationType =
|
||||
formObj?.representationForm?.values?.representationType ||
|
||||
props.representationType;
|
||||
|
||||
const isTypeConfirmed =
|
||||
!!selectedRepresentationType && typeSelectionConfirmed;
|
||||
|
||||
const selectedRepresentationTypeDisplay =
|
||||
router.locale == "cy"
|
||||
? selectedRepresentationType == "Questionnaire"
|
||||
? "Holiadur"
|
||||
: selectedRepresentationType == "Statement"
|
||||
? "Datganiad"
|
||||
: selectedRepresentationType == "Final comments"
|
||||
? "Sylwadau terfynol"
|
||||
: selectedRepresentationType
|
||||
: selectedRepresentationType;
|
||||
|
||||
const handleSaveExit = () => {
|
||||
let valuesObj = props.props.props.form[props.form].values || {};
|
||||
|
||||
delete valuesObj["_pinswg_appellant_value"];
|
||||
|
||||
updateRepresentation(valuesObj, false, true);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="govuk-grid-row">
|
||||
<div className="govuk-form-group">
|
||||
{typeof formObj.representationForm.values
|
||||
.representationType == "undefined" &&
|
||||
props.representationType != "Select..." ? (
|
||||
<>
|
||||
<h2 className="govuk-heading-m ">
|
||||
{t(
|
||||
<RepresentationTypeSelectorBlock
|
||||
t={t}
|
||||
headingText={t(
|
||||
"myrepresentations:representation-from-an-interested-person-heading"
|
||||
)}
|
||||
</h2>
|
||||
|
||||
<label
|
||||
className="govuk-label govuk-body-m"
|
||||
htmlFor="representationType"
|
||||
>
|
||||
{t("myrepresentations:kind-of-rep-label")}
|
||||
</label>
|
||||
|
||||
<Field
|
||||
name="representationType"
|
||||
component={RenderPickList}
|
||||
datafieldname="representationType"
|
||||
kindLabelText={t("myrepresentations:kind-of-rep-label")}
|
||||
isTypeSelected={isTypeConfirmed}
|
||||
selectedTypeDisplay={selectedRepresentationTypeDisplay}
|
||||
representationType={selectedRepresentationType}
|
||||
setTypeSelectionConfirmed={setTypeSelectionConfirmed}
|
||||
onRepresentationTypeChange={onRepresentationTypeChange}
|
||||
onTypeSelectionConfirmed={onTypeSelectionConfirmed}
|
||||
optionsArr={interestedPersonRepresentationArr}
|
||||
validate={[required]}
|
||||
optionsArr={
|
||||
interestedPersonRepresentationArr
|
||||
}
|
||||
errorMsg={t(
|
||||
"myrepresentations:select-an-option-label"
|
||||
)}
|
||||
errorMsg={t("myrepresentations:select-an-option-label")}
|
||||
/>
|
||||
</>
|
||||
) : (
|
||||
<label className="govuk-label govuk-body-m">
|
||||
{t("myrepresentations:representation-type")}:{" "}
|
||||
{router.locale == "cy"
|
||||
? formObj.representationForm.values
|
||||
.representationType == "Questionnaire"
|
||||
? "Holiadur"
|
||||
: formObj.representationForm.values
|
||||
.representationType == "Statement"
|
||||
? "Datganiad"
|
||||
: formObj.representationForm.values
|
||||
.representationType ==
|
||||
"Final comments"
|
||||
? "Sylwadau terfynol"
|
||||
: formObj.representationForm.values
|
||||
.representationType
|
||||
: formObj.representationForm.values
|
||||
.representationType}
|
||||
</label>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
{(typeof props.representationType != "undefined" ||
|
||||
typeof formObj.representationForm.values
|
||||
.representationType != "undefined") && (
|
||||
{isTypeConfirmed && (
|
||||
<>
|
||||
<div className="govuk-grid-row">
|
||||
<div className="govuk-form-group">
|
||||
@@ -127,12 +130,7 @@ const RepInterestedPartyPerson = (props) => {
|
||||
name="representationOnBehalfOf"
|
||||
datafieldname="representationOnBehalfOf"
|
||||
// label="In what capacity do you wish to make representations on this case?"
|
||||
options={[
|
||||
t(
|
||||
"myrepresentations:questionnaire-yes"
|
||||
),
|
||||
t("myrepresentations:questionnaire-no"),
|
||||
]}
|
||||
options={["Yes", "No"]}
|
||||
id="representationOnBehalfOf"
|
||||
className="govuk-radios__input"
|
||||
errorMsg={t(
|
||||
@@ -231,78 +229,17 @@ const RepInterestedPartyPerson = (props) => {
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
{typeof formObj.representationForm.values.representationType !=
|
||||
"undefined" && (
|
||||
<div className="govuk-grid-row">
|
||||
<div className="govuk-button-group">
|
||||
<button
|
||||
type="submit"
|
||||
className="govuk-button"
|
||||
data-module="govuk-button"
|
||||
>
|
||||
{t("common:continue-button")}
|
||||
</button>
|
||||
{/*
|
||||
<a
|
||||
onClick={() => {
|
||||
setRepresentationCapacity();
|
||||
props.updateField(
|
||||
"representationForm",
|
||||
"representationCapacity",
|
||||
""
|
||||
);
|
||||
props.updateField(
|
||||
"representationForm",
|
||||
"representationType",
|
||||
""
|
||||
);
|
||||
}}
|
||||
className="govuk-link"
|
||||
>
|
||||
{t("case:summary-back-button-label")}
|
||||
</a> */}
|
||||
{savingStatus ? (
|
||||
<span className=" progress-save-active">
|
||||
{router.locale == "cy"
|
||||
? "Nôl data"
|
||||
: "Saving data"}
|
||||
<img
|
||||
className="data-loading-icon"
|
||||
src="/assets/images/loading.gif"
|
||||
alt={
|
||||
router.locale == "cy"
|
||||
? "Nôl data"
|
||||
: "Saving data"
|
||||
}
|
||||
{isTypeConfirmed && (
|
||||
<RepresentationActionButtons
|
||||
t={t}
|
||||
locale={router.locale}
|
||||
isSaving={savingStatus}
|
||||
isContinueDisabled={shouldDisableButton({
|
||||
props,
|
||||
formObj
|
||||
})}
|
||||
onSaveExit={handleSaveExit}
|
||||
/>
|
||||
</span>
|
||||
) : (
|
||||
<button
|
||||
className="govuk-button progress-save "
|
||||
onClick={() => {
|
||||
let valuesObj =
|
||||
props.props.props.form[props.form]
|
||||
.values || {};
|
||||
|
||||
//console.log("valuesobj:", valuesObj);
|
||||
|
||||
delete valuesObj[
|
||||
"_pinswg_appellant_value"
|
||||
];
|
||||
|
||||
//console.log("on save:", valuesObj);
|
||||
updateRepresentation(
|
||||
valuesObj,
|
||||
false,
|
||||
true
|
||||
);
|
||||
}}
|
||||
>
|
||||
{t("common:save-exit-button")}
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
@@ -316,7 +253,7 @@ const mapDispatchToProps = (dispatch) => ({
|
||||
dispatch(change(form, field, newValue)),
|
||||
setFilesForRepresentations: (fileList) => {
|
||||
dispatch(setFilesForRepresentations(fileList));
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
export default connect(
|
||||
@@ -326,6 +263,6 @@ export default connect(
|
||||
reduxForm({
|
||||
form: "representationForm",
|
||||
enableReinitialize: true,
|
||||
destroyOnUnmount: false,
|
||||
destroyOnUnmount: false
|
||||
})(RepInterestedPartyPerson)
|
||||
);
|
||||
|
||||
@@ -10,8 +10,9 @@ import { useState, useEffect } from "react";
|
||||
import {
|
||||
FileUploadField,
|
||||
RenderMultiline,
|
||||
RenderPickList,
|
||||
shouldDisableButton
|
||||
} from "./representationElements";
|
||||
import RepresentationTypeSelectorBlock from "./elements/RepresentationTypeSelectorBlock";
|
||||
import RepresentationProgress_enforcement from "./representationProgress/representationProgress_enforcement";
|
||||
import RepresentationProgress_s78 from "./representationProgress/representationProgress_s78";
|
||||
import Enforcement_Questionnaire from "./representationQuestionnaires/representationLPAQuestionnaire_enforcement";
|
||||
@@ -22,7 +23,7 @@ import {
|
||||
setRepresentationSubmit,
|
||||
setFilesForRepresentations,
|
||||
setCurrentPage,
|
||||
setCurrentReference,
|
||||
setCurrentReference
|
||||
} from "../../../store/currentView/action";
|
||||
|
||||
let RepLPA = (props) => {
|
||||
@@ -48,6 +49,8 @@ let RepLPA = (props) => {
|
||||
setSavingStatus,
|
||||
savingStatus,
|
||||
setFilesForRepresentations,
|
||||
onRepresentationTypeChange,
|
||||
onTypeSelectionConfirmed
|
||||
} = props;
|
||||
const { acceptedFiles, getRootProps, getInputProps } = useDropzone();
|
||||
|
||||
@@ -58,6 +61,36 @@ let RepLPA = (props) => {
|
||||
));
|
||||
const required = (value) => (value ? undefined : "Required");
|
||||
|
||||
const persistedRepresentationType =
|
||||
currentView?.caseReference?.repDetails?.representationType;
|
||||
const [typeSelectionConfirmed, setTypeSelectionConfirmed] = useState(
|
||||
!!persistedRepresentationType
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (persistedRepresentationType) {
|
||||
setTypeSelectionConfirmed(true);
|
||||
}
|
||||
}, [persistedRepresentationType]);
|
||||
|
||||
const selectedRepresentationType =
|
||||
formObj?.representationForm?.values?.representationType ||
|
||||
props.representationType;
|
||||
|
||||
const isTypeConfirmed =
|
||||
!!selectedRepresentationType && typeSelectionConfirmed;
|
||||
|
||||
const selectedRepresentationTypeDisplay =
|
||||
router.locale == "cy"
|
||||
? selectedRepresentationType == "Questionnaire"
|
||||
? "Holiadur"
|
||||
: selectedRepresentationType == "Statement"
|
||||
? "Datganiad"
|
||||
: selectedRepresentationType == "Final comments"
|
||||
? "Sylwadau terfynol"
|
||||
: selectedRepresentationType
|
||||
: selectedRepresentationType;
|
||||
|
||||
const whichQuestionnaire = () => {
|
||||
{
|
||||
switch (currentView.caseReference.appealType) {
|
||||
@@ -182,7 +215,7 @@ let RepLPA = (props) => {
|
||||
currentView.caseReference.currentReference +
|
||||
'")]',
|
||||
json: setCaseDetailsObj,
|
||||
eval: true,
|
||||
eval: true
|
||||
});
|
||||
|
||||
let setCaseResultssObj = router.query.hasOwnProperty("state")
|
||||
@@ -201,7 +234,7 @@ let RepLPA = (props) => {
|
||||
currentView.caseReference.currentReference +
|
||||
'")]',
|
||||
json: setCaseResultssObj,
|
||||
eval: true,
|
||||
eval: true
|
||||
});
|
||||
resultsObj = resultsObj[0];
|
||||
|
||||
@@ -224,62 +257,26 @@ let RepLPA = (props) => {
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="govuk-grid-row">
|
||||
<div className="govuk-form-group">
|
||||
{!_.has(
|
||||
formObj["representationForm"],
|
||||
["values", "representationType"] ||
|
||||
typeof props.currentView.caseReference.repDetails !=
|
||||
"undefined"
|
||||
) ? (
|
||||
<>
|
||||
<label
|
||||
className="govuk-label govuk-body-m"
|
||||
htmlFor="representationType"
|
||||
>
|
||||
{t(
|
||||
<RepresentationTypeSelectorBlock
|
||||
t={t}
|
||||
headingText={t(
|
||||
"myrepresentations:representation-from-an-lpa-heading"
|
||||
)}
|
||||
</label>
|
||||
<Field
|
||||
id="representationType"
|
||||
name="representationType"
|
||||
component={RenderPickList}
|
||||
datafieldname="representationType"
|
||||
kindLabelText={t("myrepresentations:kind-of-rep-label")}
|
||||
isTypeSelected={isTypeConfirmed}
|
||||
selectedTypeDisplay={selectedRepresentationTypeDisplay}
|
||||
representationType={selectedRepresentationType}
|
||||
setTypeSelectionConfirmed={setTypeSelectionConfirmed}
|
||||
onRepresentationTypeChange={onRepresentationTypeChange}
|
||||
onTypeSelectionConfirmed={onTypeSelectionConfirmed}
|
||||
optionsArr={appellantApplicantRepresentationArr}
|
||||
validate={[required]}
|
||||
errorMsg={t("myrepresentations:select-an-option-label")}
|
||||
/>
|
||||
</>
|
||||
) : (
|
||||
<label className="govuk-label govuk-body-m">
|
||||
{t("myrepresentations:representation-type")}:{" "}
|
||||
{router.locale == "cy"
|
||||
? formObj.representationForm.values
|
||||
.representationType == "Questionnaire"
|
||||
? "Holiadur"
|
||||
: formObj.representationForm.values
|
||||
.representationType == "Statement"
|
||||
? "Datganiad"
|
||||
: formObj.representationForm.values
|
||||
.representationType ==
|
||||
"Final comments"
|
||||
? "Sylwadau terfynol"
|
||||
: formObj.representationForm.values
|
||||
.representationType
|
||||
: formObj.representationForm.values
|
||||
.representationType}
|
||||
</label>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<div className="govuk-grid-row">
|
||||
<div className="govuk-form-group">
|
||||
{(_.has(formObj["representationForm"], [
|
||||
"values",
|
||||
"representationType",
|
||||
]) ||
|
||||
typeof props.representationType != "undefined") &&
|
||||
(props.representationType != "Questionnaire" &&
|
||||
props.representationType != "Select..." ? (
|
||||
{isTypeConfirmed &&
|
||||
(selectedRepresentationType != "Questionnaire" ? (
|
||||
<>
|
||||
<p className="govuk-body">
|
||||
{t("myrepresentations:enter-comment-label")}
|
||||
@@ -353,7 +350,8 @@ let RepLPA = (props) => {
|
||||
"myrepresentations:add-files-label"
|
||||
)}
|
||||
ticketnumber={
|
||||
props.currentView.caseReference.ticketnumber
|
||||
props.currentView.caseReference
|
||||
.ticketnumber
|
||||
}
|
||||
hint={"sdsd"}
|
||||
fileList={
|
||||
@@ -400,9 +398,8 @@ let RepLPA = (props) => {
|
||||
</div>
|
||||
<div className="govuk-grid-row">
|
||||
<div className="govuk-button-group">
|
||||
{(typeof props.representationType != "undefined" ||
|
||||
_.has(formObj, "values", "representationType")) &&
|
||||
props.representationType == "Questionnaire" && (
|
||||
{isTypeConfirmed &&
|
||||
selectedRepresentationType == "Questionnaire" && (
|
||||
<>
|
||||
{showQuestionnaireSection <
|
||||
questionnaireCount && (
|
||||
@@ -442,14 +439,14 @@ let RepLPA = (props) => {
|
||||
// top: 0,
|
||||
// behavior: "smooth",
|
||||
// });
|
||||
setRepFileName(
|
||||
(setRepFileName(
|
||||
props.formObj[
|
||||
"representationForm"
|
||||
].values
|
||||
),
|
||||
setShowQuestionnaireSection(
|
||||
showQuestionnaireSection - 1
|
||||
);
|
||||
));
|
||||
}}
|
||||
className="govuk-link"
|
||||
>
|
||||
@@ -502,14 +499,17 @@ let RepLPA = (props) => {
|
||||
)}
|
||||
</>
|
||||
)}{" "}
|
||||
{(typeof props.representationType != "undefined" ||
|
||||
_.has(formObj, "values", "representationType")) &&
|
||||
props.representationType != "Questionnaire" && (
|
||||
{isTypeConfirmed &&
|
||||
selectedRepresentationType != "Questionnaire" && (
|
||||
<>
|
||||
<button
|
||||
type="submit"
|
||||
className="govuk-button"
|
||||
data-module="govuk-button"
|
||||
disabled={shouldDisableButton({
|
||||
props,
|
||||
formObj
|
||||
})}
|
||||
onClick={() => {
|
||||
let valuesObj =
|
||||
props.props.props.form[props.form]
|
||||
@@ -607,7 +607,7 @@ RepLPA = connect((state) => {
|
||||
|
||||
return {
|
||||
procedureType,
|
||||
representationType,
|
||||
representationType
|
||||
};
|
||||
})(RepLPA);
|
||||
|
||||
@@ -620,7 +620,7 @@ const mapDispatchToProps = (dispatch) => ({
|
||||
},
|
||||
setCurrentReference: (currentReference) => {
|
||||
dispatch(setCurrentReference(currentReference));
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
const mapStateToProps = (state, props) => {
|
||||
@@ -636,8 +636,7 @@ const mapStateToProps = (state, props) => {
|
||||
],
|
||||
"firstname":
|
||||
props.props.props.accountDetails.accountDetails.firstname,
|
||||
"lastname":
|
||||
props.props.props.accountDetails.accountDetails.lastname,
|
||||
"lastname": props.props.props.accountDetails.accountDetails.lastname
|
||||
}
|
||||
);
|
||||
return {
|
||||
@@ -648,7 +647,7 @@ const mapStateToProps = (state, props) => {
|
||||
currentView: state.currentView,
|
||||
myRepresentations: state.myRepresentations,
|
||||
watchedCases: state.watchedCases,
|
||||
initialValues: initialValuesTemp,
|
||||
initialValues: initialValuesTemp
|
||||
};
|
||||
};
|
||||
|
||||
@@ -659,6 +658,6 @@ export default connect(
|
||||
reduxForm({
|
||||
form: "representationForm",
|
||||
enableReinitialize: true,
|
||||
destroyOnUnmount: false,
|
||||
destroyOnUnmount: false
|
||||
})(RepLPA)
|
||||
);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { JSONPath as jsonpath } from "jsonpath-plus";
|
||||
import useTranslation from "next-translate/useTranslation";
|
||||
import { useRouter } from "next/router";
|
||||
import { hasOwn } from "../../utils";
|
||||
|
||||
const RepLPADetails = (props) => {
|
||||
let { t } = useTranslation();
|
||||
@@ -23,7 +24,7 @@ const RepLPADetails = (props) => {
|
||||
detailsObj = jsonpath({
|
||||
path: '$..[?(@ && @.ticketnumber=="' + ticketnumber + '")]',
|
||||
json: setCaseDetailsObj,
|
||||
eval: true,
|
||||
eval: true
|
||||
});
|
||||
|
||||
detailsObj = detailsObj[0];
|
||||
@@ -51,34 +52,43 @@ const RepLPADetails = (props) => {
|
||||
{t("case:summary-site-address-label")}
|
||||
</dt>
|
||||
<dd className="govuk-summary-list__value">
|
||||
{_.has(detailsObj, "pinswg_siteaddressline1")
|
||||
{hasOwn(detailsObj, "pinswg_siteaddressline1")
|
||||
? detailsObj.pinswg_siteaddressline1
|
||||
: ""}
|
||||
{_.has(detailsObj, "pinswg_siteaddressline1") &&
|
||||
{hasOwn(
|
||||
detailsObj,
|
||||
"pinswg_siteaddressline1"
|
||||
) &&
|
||||
detailsObj.pinswg_siteaddressline1 !=
|
||||
null && <br />}
|
||||
{_.has(detailsObj, "pinswg_siteaddressline2")
|
||||
{hasOwn(detailsObj, "pinswg_siteaddressline2")
|
||||
? detailsObj.pinswg_siteaddressline2
|
||||
: ""}
|
||||
{_.has(detailsObj, "pinswg_siteaddressline2") &&
|
||||
{hasOwn(
|
||||
detailsObj,
|
||||
"pinswg_siteaddressline2"
|
||||
) &&
|
||||
detailsObj.pinswg_siteaddressline2 !=
|
||||
null && <br />}
|
||||
{_.has(detailsObj, "pinswg_siteaddresstown")
|
||||
{hasOwn(detailsObj, "pinswg_siteaddresstown")
|
||||
? detailsObj.pinswg_siteaddresstown
|
||||
: ""}
|
||||
{_.has(detailsObj, "pinswg_siteaddresstown") &&
|
||||
{hasOwn(detailsObj, "pinswg_siteaddresstown") &&
|
||||
detailsObj.pinswg_siteaddresstown !=
|
||||
null && <br />}
|
||||
{_.has(detailsObj, "pinswg_siteaddresscounty")
|
||||
{hasOwn(detailsObj, "pinswg_siteaddresscounty")
|
||||
? detailsObj.pinswg_siteaddresscounty
|
||||
: ""}
|
||||
{_.has(
|
||||
{hasOwn(
|
||||
detailsObj,
|
||||
"pinswg_siteaddresscounty"
|
||||
) &&
|
||||
detailsObj.pinswg_siteaddresscounty !=
|
||||
null && <br />}
|
||||
{_.has(detailsObj, "pinswg_siteaddresspostcode")
|
||||
{hasOwn(
|
||||
detailsObj,
|
||||
"pinswg_siteaddresspostcode"
|
||||
)
|
||||
? detailsObj.pinswg_siteaddresspostcode
|
||||
: ""}
|
||||
</dd>
|
||||
|
||||
+48
-48
@@ -14,12 +14,12 @@ import {
|
||||
RenderPickList,
|
||||
RenderRadioList,
|
||||
RenderRichMultiline,
|
||||
RenderTextfield,
|
||||
RenderTextfield
|
||||
} from "../representationElements";
|
||||
import {
|
||||
setRepresentationCapacity,
|
||||
setRepresentationSubmit,
|
||||
setFilesForRepresentations,
|
||||
setFilesForRepresentations
|
||||
} from "../../../../store/currentView/action";
|
||||
|
||||
let Enforcement_Questionnaire = (props) => {
|
||||
@@ -36,7 +36,7 @@ let Enforcement_Questionnaire = (props) => {
|
||||
procedureTypeValue,
|
||||
onBehalfOfLPA,
|
||||
showQuestionnaireSection,
|
||||
setFilesForRepresentations,
|
||||
setFilesForRepresentations
|
||||
} = props;
|
||||
const { acceptedFiles, getRootProps, getInputProps } = useDropzone();
|
||||
const files = acceptedFiles.map((file) => (
|
||||
@@ -61,10 +61,10 @@ let Enforcement_Questionnaire = (props) => {
|
||||
detailsObj = jsonpath({
|
||||
path:
|
||||
'$..[?(@ && @.pinswg_name=="' +
|
||||
currentView.caseReference.currentReference +
|
||||
currentView.caseReference.ticketnumber +
|
||||
'")]',
|
||||
json: setCaseDetailsObj,
|
||||
eval: true,
|
||||
eval: true
|
||||
});
|
||||
|
||||
let setCaseResultssObj = router.query.hasOwnProperty("state")
|
||||
@@ -84,10 +84,10 @@ let Enforcement_Questionnaire = (props) => {
|
||||
resultsObj = jsonpath({
|
||||
path:
|
||||
'$..[?(@ && @.ticketnumber=="' +
|
||||
currentView.caseReference.currentReference +
|
||||
currentView.caseReference.ticketnumber +
|
||||
'")]',
|
||||
json: setCaseResultssObj,
|
||||
eval: true,
|
||||
eval: true
|
||||
});
|
||||
resultsObj = resultsObj[0];
|
||||
|
||||
@@ -118,7 +118,7 @@ let Enforcement_Questionnaire = (props) => {
|
||||
<div className="govuk-form-group">
|
||||
<div className="govuk-label">
|
||||
2. {t("myrepresentations:enf-section-question-2")}:{" "}
|
||||
{resultsObj.pinswg_lpareference}
|
||||
{resultsObj.pinswg_lpareference || ""}
|
||||
</div>
|
||||
</div>
|
||||
<div className="govuk-form-group">
|
||||
@@ -155,7 +155,7 @@ let Enforcement_Questionnaire = (props) => {
|
||||
optionsArr={[
|
||||
"Written representations",
|
||||
"Hearing",
|
||||
"Inquiry",
|
||||
"Inquiry"
|
||||
]}
|
||||
id="procedureType"
|
||||
component={RenderPickList}
|
||||
@@ -190,7 +190,7 @@ let Enforcement_Questionnaire = (props) => {
|
||||
component={RenderRadioList}
|
||||
options={[
|
||||
t("myrepresentations:questionnaire-yes"),
|
||||
t("myrepresentations:questionnaire-no"),
|
||||
t("myrepresentations:questionnaire-no")
|
||||
]}
|
||||
type="text"
|
||||
rows="5"
|
||||
@@ -207,7 +207,7 @@ let Enforcement_Questionnaire = (props) => {
|
||||
datafieldname="enterNeighbouringLandToViewSite"
|
||||
options={[
|
||||
t("myrepresentations:questionnaire-yes"),
|
||||
t("myrepresentations:questionnaire-no"),
|
||||
t("myrepresentations:questionnaire-no")
|
||||
]}
|
||||
id="enterNeighbouringLandToViewSite"
|
||||
className="govuk-radios__input"
|
||||
@@ -236,7 +236,7 @@ let Enforcement_Questionnaire = (props) => {
|
||||
datafieldname="enterNeighbouringLandAccessRequired"
|
||||
options={[
|
||||
t("myrepresentations:questionnaire-yes"),
|
||||
t("myrepresentations:questionnaire-no"),
|
||||
t("myrepresentations:questionnaire-no")
|
||||
]}
|
||||
id="enterNeighbouringLandAccessRequired"
|
||||
className="govuk-radios__input"
|
||||
@@ -265,7 +265,7 @@ let Enforcement_Questionnaire = (props) => {
|
||||
datafieldname="healthAndSafetyIssues"
|
||||
options={[
|
||||
t("myrepresentations:questionnaire-yes"),
|
||||
t("myrepresentations:questionnaire-no"),
|
||||
t("myrepresentations:questionnaire-no")
|
||||
]}
|
||||
id="healthAndSafetyIssues"
|
||||
className="govuk-radios__input"
|
||||
@@ -328,7 +328,7 @@ let Enforcement_Questionnaire = (props) => {
|
||||
component={RenderRadioList}
|
||||
options={[
|
||||
t("myrepresentations:questionnaire-yes"),
|
||||
t("myrepresentations:questionnaire-no"),
|
||||
t("myrepresentations:questionnaire-no")
|
||||
]}
|
||||
type="text"
|
||||
rows="5"
|
||||
@@ -342,7 +342,7 @@ let Enforcement_Questionnaire = (props) => {
|
||||
datafieldname="feeExempt"
|
||||
options={[
|
||||
t("myrepresentations:questionnaire-yes"),
|
||||
t("myrepresentations:questionnaire-no"),
|
||||
t("myrepresentations:questionnaire-no")
|
||||
]}
|
||||
id="feeExempt"
|
||||
className="govuk-radios__input"
|
||||
@@ -379,7 +379,7 @@ let Enforcement_Questionnaire = (props) => {
|
||||
datafieldname="previousGrantedCerts"
|
||||
options={[
|
||||
t("myrepresentations:questionnaire-yes"),
|
||||
t("myrepresentations:questionnaire-no"),
|
||||
t("myrepresentations:questionnaire-no")
|
||||
]}
|
||||
id="previousGrantedCerts"
|
||||
className="govuk-radios__input"
|
||||
@@ -406,7 +406,7 @@ let Enforcement_Questionnaire = (props) => {
|
||||
datafieldname="stopNoticeServed"
|
||||
options={[
|
||||
t("myrepresentations:questionnaire-yes"),
|
||||
t("myrepresentations:questionnaire-no"),
|
||||
t("myrepresentations:questionnaire-no")
|
||||
]}
|
||||
id="stopNoticeServed"
|
||||
className="govuk-radios__input"
|
||||
@@ -433,7 +433,7 @@ let Enforcement_Questionnaire = (props) => {
|
||||
datafieldname="relatedCases"
|
||||
options={[
|
||||
t("myrepresentations:questionnaire-yes"),
|
||||
t("myrepresentations:questionnaire-no"),
|
||||
t("myrepresentations:questionnaire-no")
|
||||
]}
|
||||
id="relatedCases"
|
||||
className="govuk-radios__input"
|
||||
@@ -460,7 +460,7 @@ let Enforcement_Questionnaire = (props) => {
|
||||
datafieldname="previousEnforcement"
|
||||
options={[
|
||||
t("myrepresentations:questionnaire-yes"),
|
||||
t("myrepresentations:questionnaire-no"),
|
||||
t("myrepresentations:questionnaire-no")
|
||||
]}
|
||||
id="previousEnforcement"
|
||||
className="govuk-radios__input"
|
||||
@@ -487,7 +487,7 @@ let Enforcement_Questionnaire = (props) => {
|
||||
datafieldname="subjectArticle4"
|
||||
options={[
|
||||
t("myrepresentations:questionnaire-yes"),
|
||||
t("myrepresentations:questionnaire-no"),
|
||||
t("myrepresentations:questionnaire-no")
|
||||
]}
|
||||
id="subjectArticle4"
|
||||
className="govuk-radios__input"
|
||||
@@ -514,7 +514,7 @@ let Enforcement_Questionnaire = (props) => {
|
||||
datafieldname="previousPDRRestriction"
|
||||
options={[
|
||||
t("myrepresentations:questionnaire-yes"),
|
||||
t("myrepresentations:questionnaire-no"),
|
||||
t("myrepresentations:questionnaire-no")
|
||||
]}
|
||||
id="previousPDRRestriction"
|
||||
className="govuk-radios__input"
|
||||
@@ -594,7 +594,7 @@ let Enforcement_Questionnaire = (props) => {
|
||||
component={RenderRadioList}
|
||||
options={[
|
||||
t("myrepresentations:questionnaire-yes"),
|
||||
t("myrepresentations:questionnaire-no"),
|
||||
t("myrepresentations:questionnaire-no")
|
||||
]}
|
||||
type="text"
|
||||
rows="5"
|
||||
@@ -621,7 +621,7 @@ let Enforcement_Questionnaire = (props) => {
|
||||
component={RenderRadioList}
|
||||
options={[
|
||||
t("myrepresentations:questionnaire-yes"),
|
||||
t("myrepresentations:questionnaire-no"),
|
||||
t("myrepresentations:questionnaire-no")
|
||||
]}
|
||||
type="text"
|
||||
rows="5"
|
||||
@@ -635,7 +635,7 @@ let Enforcement_Questionnaire = (props) => {
|
||||
datafieldname="ROW"
|
||||
options={[
|
||||
t("myrepresentations:questionnaire-yes"),
|
||||
t("myrepresentations:questionnaire-no"),
|
||||
t("myrepresentations:questionnaire-no")
|
||||
]}
|
||||
id="ROW"
|
||||
className="govuk-radios__input"
|
||||
@@ -662,7 +662,7 @@ let Enforcement_Questionnaire = (props) => {
|
||||
datafieldname="conservationArea"
|
||||
options={[
|
||||
t("myrepresentations:questionnaire-yes"),
|
||||
t("myrepresentations:questionnaire-no"),
|
||||
t("myrepresentations:questionnaire-no")
|
||||
]}
|
||||
id="conservationArea"
|
||||
className="govuk-radios__input"
|
||||
@@ -689,7 +689,7 @@ let Enforcement_Questionnaire = (props) => {
|
||||
datafieldname="affectListedBuilding"
|
||||
options={[
|
||||
t("myrepresentations:questionnaire-yes"),
|
||||
t("myrepresentations:questionnaire-no"),
|
||||
t("myrepresentations:questionnaire-no")
|
||||
]}
|
||||
id="affectListedBuilding"
|
||||
className="govuk-radios__input"
|
||||
@@ -716,7 +716,7 @@ let Enforcement_Questionnaire = (props) => {
|
||||
datafieldname="TPO"
|
||||
options={[
|
||||
t("myrepresentations:questionnaire-yes"),
|
||||
t("myrepresentations:questionnaire-no"),
|
||||
t("myrepresentations:questionnaire-no")
|
||||
]}
|
||||
id="TPO"
|
||||
className="govuk-radios__input"
|
||||
@@ -743,7 +743,7 @@ let Enforcement_Questionnaire = (props) => {
|
||||
datafieldname="natureConservationSite"
|
||||
options={[
|
||||
t("myrepresentations:questionnaire-yes"),
|
||||
t("myrepresentations:questionnaire-no"),
|
||||
t("myrepresentations:questionnaire-no")
|
||||
]}
|
||||
id="natureConservationSite"
|
||||
className="govuk-radios__input"
|
||||
@@ -770,7 +770,7 @@ let Enforcement_Questionnaire = (props) => {
|
||||
datafieldname="protectedSpecies"
|
||||
options={[
|
||||
t("myrepresentations:questionnaire-yes"),
|
||||
t("myrepresentations:questionnaire-no"),
|
||||
t("myrepresentations:questionnaire-no")
|
||||
]}
|
||||
id="protectedSpecies"
|
||||
className="govuk-radios__input"
|
||||
@@ -802,7 +802,7 @@ let Enforcement_Questionnaire = (props) => {
|
||||
component={RenderRadioList}
|
||||
options={[
|
||||
t("myrepresentations:questionnaire-yes"),
|
||||
t("myrepresentations:questionnaire-no"),
|
||||
t("myrepresentations:questionnaire-no")
|
||||
]}
|
||||
type="text"
|
||||
rows="5"
|
||||
@@ -816,7 +816,7 @@ let Enforcement_Questionnaire = (props) => {
|
||||
datafieldname="floodingIssue"
|
||||
options={[
|
||||
t("myrepresentations:questionnaire-yes"),
|
||||
t("myrepresentations:questionnaire-no"),
|
||||
t("myrepresentations:questionnaire-no")
|
||||
]}
|
||||
id="floodingIssue"
|
||||
className="govuk-radios__input"
|
||||
@@ -843,7 +843,7 @@ let Enforcement_Questionnaire = (props) => {
|
||||
datafieldname="governmentDepartmentComments"
|
||||
options={[
|
||||
t("myrepresentations:questionnaire-yes"),
|
||||
t("myrepresentations:questionnaire-no"),
|
||||
t("myrepresentations:questionnaire-no")
|
||||
]}
|
||||
id="governmentDepartmentComments"
|
||||
className="govuk-radios__input"
|
||||
@@ -884,7 +884,7 @@ let Enforcement_Questionnaire = (props) => {
|
||||
datafieldname="developmentCarriedOutInAccordance"
|
||||
options={[
|
||||
t("myrepresentations:questionnaire-yes"),
|
||||
t("myrepresentations:questionnaire-no"),
|
||||
t("myrepresentations:questionnaire-no")
|
||||
]}
|
||||
id="developmentCarriedOutInAccordance"
|
||||
className="govuk-radios__input"
|
||||
@@ -915,7 +915,7 @@ let Enforcement_Questionnaire = (props) => {
|
||||
component={RenderRadioList}
|
||||
options={[
|
||||
t("myrepresentations:questionnaire-yes"),
|
||||
t("myrepresentations:questionnaire-no"),
|
||||
t("myrepresentations:questionnaire-no")
|
||||
]}
|
||||
type="text"
|
||||
rows="5"
|
||||
@@ -932,7 +932,7 @@ let Enforcement_Questionnaire = (props) => {
|
||||
component={RenderRadioList}
|
||||
options={[
|
||||
t("myrepresentations:questionnaire-yes"),
|
||||
t("myrepresentations:questionnaire-no"),
|
||||
t("myrepresentations:questionnaire-no")
|
||||
]}
|
||||
type="text"
|
||||
rows="5"
|
||||
@@ -946,7 +946,7 @@ let Enforcement_Questionnaire = (props) => {
|
||||
datafieldname="developmentAnyOtherConditions"
|
||||
options={[
|
||||
t("myrepresentations:questionnaire-yes"),
|
||||
t("myrepresentations:questionnaire-no"),
|
||||
t("myrepresentations:questionnaire-no")
|
||||
]}
|
||||
id="developmentAnyOtherConditions"
|
||||
className="govuk-radios__input"
|
||||
@@ -987,7 +987,7 @@ let Enforcement_Questionnaire = (props) => {
|
||||
datafieldname="copyOfEnforcementNotice"
|
||||
options={[
|
||||
t("myrepresentations:questionnaire-yes"),
|
||||
t("myrepresentations:questionnaire-no"),
|
||||
t("myrepresentations:questionnaire-no")
|
||||
]}
|
||||
id="copyOfEnforcementNotice"
|
||||
className="govuk-radios__input"
|
||||
@@ -1014,7 +1014,7 @@ let Enforcement_Questionnaire = (props) => {
|
||||
datafieldname="enforcementNoticePlan"
|
||||
options={[
|
||||
t("myrepresentations:questionnaire-yes"),
|
||||
t("myrepresentations:questionnaire-no"),
|
||||
t("myrepresentations:questionnaire-no")
|
||||
]}
|
||||
id="enforcementNoticePlan"
|
||||
className="govuk-radios__input"
|
||||
@@ -1041,7 +1041,7 @@ let Enforcement_Questionnaire = (props) => {
|
||||
datafieldname="listOfNotifiedOfEnforcement"
|
||||
options={[
|
||||
t("myrepresentations:questionnaire-yes"),
|
||||
t("myrepresentations:questionnaire-no"),
|
||||
t("myrepresentations:questionnaire-no")
|
||||
]}
|
||||
id="listOfNotifiedOfEnforcement"
|
||||
className="govuk-radios__input"
|
||||
@@ -1068,7 +1068,7 @@ let Enforcement_Questionnaire = (props) => {
|
||||
datafieldname="copyOfLetterOfAppealNotification"
|
||||
options={[
|
||||
t("myrepresentations:questionnaire-yes"),
|
||||
t("myrepresentations:questionnaire-no"),
|
||||
t("myrepresentations:questionnaire-no")
|
||||
]}
|
||||
id="copyOfLetterOfAppealNotification"
|
||||
className="govuk-radios__input"
|
||||
@@ -1095,7 +1095,7 @@ let Enforcement_Questionnaire = (props) => {
|
||||
datafieldname="lpaEIAOS"
|
||||
options={[
|
||||
t("myrepresentations:questionnaire-yes"),
|
||||
t("myrepresentations:questionnaire-no"),
|
||||
t("myrepresentations:questionnaire-no")
|
||||
]}
|
||||
id="lpaEIAOS"
|
||||
className="govuk-radios__input"
|
||||
@@ -1125,7 +1125,7 @@ let Enforcement_Questionnaire = (props) => {
|
||||
datafieldname="detailsOfOtherAppeals"
|
||||
options={[
|
||||
t("myrepresentations:questionnaire-yes"),
|
||||
t("myrepresentations:questionnaire-no"),
|
||||
t("myrepresentations:questionnaire-no")
|
||||
]}
|
||||
id="detailsOfOtherAppeals"
|
||||
className="govuk-radios__input"
|
||||
@@ -1152,7 +1152,7 @@ let Enforcement_Questionnaire = (props) => {
|
||||
datafieldname="detailsOfPreviousAppeals"
|
||||
options={[
|
||||
t("myrepresentations:questionnaire-yes"),
|
||||
t("myrepresentations:questionnaire-no"),
|
||||
t("myrepresentations:questionnaire-no")
|
||||
]}
|
||||
id="detailsOfPreviousAppeals"
|
||||
className="govuk-radios__input"
|
||||
@@ -1179,7 +1179,7 @@ let Enforcement_Questionnaire = (props) => {
|
||||
datafieldname="otherRelevantInformation"
|
||||
options={[
|
||||
t("myrepresentations:questionnaire-yes"),
|
||||
t("myrepresentations:questionnaire-no"),
|
||||
t("myrepresentations:questionnaire-no")
|
||||
]}
|
||||
id="otherRelevantInformation"
|
||||
className="govuk-radios__input"
|
||||
@@ -1312,7 +1312,7 @@ Enforcement_Questionnaire = connect((state) => {
|
||||
|
||||
return {
|
||||
procedureTypeValue,
|
||||
representationTypeValue,
|
||||
representationTypeValue
|
||||
};
|
||||
})(Enforcement_Questionnaire);
|
||||
|
||||
@@ -1323,7 +1323,7 @@ const mapDispatchToProps = (dispatch) => {
|
||||
|
||||
setFilesForRepresentations: (fileList) => {
|
||||
dispatch(setFilesForRepresentations(fileList));
|
||||
},
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1335,7 +1335,7 @@ const mapStateToProps = (state, props) => {
|
||||
appealType: state.appealType,
|
||||
currentView: state.currentView,
|
||||
myRepresentations: state.myRepresentations,
|
||||
initialValues: state.currentView.caseReference.repDetails,
|
||||
initialValues: state.currentView.caseReference.repDetails
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1346,6 +1346,6 @@ export default connect(
|
||||
reduxForm({
|
||||
form: "representationForm",
|
||||
enableReinitialize: false,
|
||||
destroyOnUnmount: false,
|
||||
destroyOnUnmount: false
|
||||
})(Enforcement_Questionnaire)
|
||||
);
|
||||
|
||||
+42
-41
@@ -4,6 +4,7 @@ import { useRouter } from "next/router";
|
||||
import { useDropzone } from "react-dropzone";
|
||||
import { Field, reduxForm, formValueSelector } from "redux-form";
|
||||
import { getFormCollectionByID } from "../../../../components/utils";
|
||||
|
||||
import {
|
||||
FileUploadField,
|
||||
RenderDatePicker,
|
||||
@@ -12,12 +13,12 @@ import {
|
||||
RenderPickList,
|
||||
RenderRadioList,
|
||||
RenderRichMultiline,
|
||||
RenderTextfield,
|
||||
RenderTextfield
|
||||
} from "../representationElements";
|
||||
import {
|
||||
setRepresentationCapacity,
|
||||
setRepresentationSubmit,
|
||||
setFilesForRepresentations,
|
||||
setFilesForRepresentations
|
||||
} from "../../../../store/currentView/action";
|
||||
|
||||
import { connect } from "react-redux";
|
||||
@@ -38,7 +39,7 @@ let S78_Questionnaire = (props) => {
|
||||
procedureTypeValue,
|
||||
onBehalfOfLPA,
|
||||
showQuestionnaireSection,
|
||||
setFilesForRepresentations,
|
||||
setFilesForRepresentations
|
||||
} = props;
|
||||
const { acceptedFiles, getRootProps, getInputProps } = useDropzone();
|
||||
const files = acceptedFiles.map((file) => (
|
||||
@@ -62,11 +63,11 @@ let S78_Questionnaire = (props) => {
|
||||
|
||||
detailsObj = jsonpath({
|
||||
path:
|
||||
'$..[?(@ && @.pinswg_name=="' +
|
||||
currentView.caseReference.currentReference +
|
||||
'$..[?(@ && @.ticketnumber=="' +
|
||||
currentView.caseReference.ticketnumber +
|
||||
'")]',
|
||||
json: setCaseDetailsObj,
|
||||
eval: true,
|
||||
eval: true
|
||||
});
|
||||
|
||||
let setCaseResultssObj = router.query.hasOwnProperty("state")
|
||||
@@ -92,10 +93,10 @@ let S78_Questionnaire = (props) => {
|
||||
: "ticketnumber"
|
||||
: "ticketnumber") +
|
||||
'=="' +
|
||||
currentView.caseReference.currentReference +
|
||||
currentView.caseReference.ticketnumber +
|
||||
'")]',
|
||||
json: setCaseResultssObj,
|
||||
eval: true,
|
||||
eval: true
|
||||
});
|
||||
resultsObj = resultsObj[0];
|
||||
|
||||
@@ -136,7 +137,7 @@ let S78_Questionnaire = (props) => {
|
||||
<div className="govuk-form-group">
|
||||
<div className="govuk-label">
|
||||
2. {t("myrepresentations:s78-section-question-2")}:{" "}
|
||||
{resultsObj.pinswg_lpareference}
|
||||
{resultsObj.pinswg_lpareference || ""}
|
||||
</div>
|
||||
</div>
|
||||
<div className="govuk-form-group">
|
||||
@@ -175,7 +176,7 @@ let S78_Questionnaire = (props) => {
|
||||
optionsArr={[
|
||||
"Written representations",
|
||||
"Hearing",
|
||||
"Inquiry",
|
||||
"Inquiry"
|
||||
]}
|
||||
id="procedureType"
|
||||
component={RenderPickList}
|
||||
@@ -209,7 +210,7 @@ let S78_Questionnaire = (props) => {
|
||||
component={RenderRadioList}
|
||||
options={[
|
||||
t("myrepresentations:questionnaire-yes"),
|
||||
t("myrepresentations:questionnaire-no"),
|
||||
t("myrepresentations:questionnaire-no")
|
||||
]}
|
||||
type="text"
|
||||
rows="5"
|
||||
@@ -224,7 +225,7 @@ let S78_Questionnaire = (props) => {
|
||||
datafieldname="enterNeighbouringLandToViewSite"
|
||||
options={[
|
||||
t("myrepresentations:questionnaire-yes"),
|
||||
t("myrepresentations:questionnaire-no"),
|
||||
t("myrepresentations:questionnaire-no")
|
||||
]}
|
||||
id="enterNeighbouringLandToViewSite"
|
||||
className="govuk-radios__input"
|
||||
@@ -253,7 +254,7 @@ let S78_Questionnaire = (props) => {
|
||||
datafieldname="enterNeighbouringLandAccessRequired"
|
||||
options={[
|
||||
t("myrepresentations:questionnaire-yes"),
|
||||
t("myrepresentations:questionnaire-no"),
|
||||
t("myrepresentations:questionnaire-no")
|
||||
]}
|
||||
id="enterNeighbouringLandAccessRequired"
|
||||
className="govuk-radios__input"
|
||||
@@ -282,7 +283,7 @@ let S78_Questionnaire = (props) => {
|
||||
datafieldname="healthAndSafetyIssues"
|
||||
options={[
|
||||
t("myrepresentations:questionnaire-yes"),
|
||||
t("myrepresentations:questionnaire-no"),
|
||||
t("myrepresentations:questionnaire-no")
|
||||
]}
|
||||
id="healthAndSafetyIssues"
|
||||
className="govuk-radios__input"
|
||||
@@ -405,7 +406,7 @@ let S78_Questionnaire = (props) => {
|
||||
component={RenderRadioList}
|
||||
options={[
|
||||
t("myrepresentations:questionnaire-yes"),
|
||||
t("myrepresentations:questionnaire-no"),
|
||||
t("myrepresentations:questionnaire-no")
|
||||
]}
|
||||
type="text"
|
||||
rows="5"
|
||||
@@ -434,7 +435,7 @@ let S78_Questionnaire = (props) => {
|
||||
component={RenderRadioList}
|
||||
options={[
|
||||
t("myrepresentations:questionnaire-yes"),
|
||||
t("myrepresentations:questionnaire-no"),
|
||||
t("myrepresentations:questionnaire-no")
|
||||
]}
|
||||
type="text"
|
||||
rows="5"
|
||||
@@ -450,7 +451,7 @@ let S78_Questionnaire = (props) => {
|
||||
datafieldname="ROW"
|
||||
options={[
|
||||
t("myrepresentations:questionnaire-yes"),
|
||||
t("myrepresentations:questionnaire-no"),
|
||||
t("myrepresentations:questionnaire-no")
|
||||
]}
|
||||
id="ROW"
|
||||
className="govuk-radios__input"
|
||||
@@ -477,7 +478,7 @@ let S78_Questionnaire = (props) => {
|
||||
datafieldname="conservationArea"
|
||||
options={[
|
||||
t("myrepresentations:questionnaire-yes"),
|
||||
t("myrepresentations:questionnaire-no"),
|
||||
t("myrepresentations:questionnaire-no")
|
||||
]}
|
||||
id="conservationArea"
|
||||
className="govuk-radios__input"
|
||||
@@ -504,7 +505,7 @@ let S78_Questionnaire = (props) => {
|
||||
datafieldname="affectListedBuilding"
|
||||
options={[
|
||||
t("myrepresentations:questionnaire-yes"),
|
||||
t("myrepresentations:questionnaire-no"),
|
||||
t("myrepresentations:questionnaire-no")
|
||||
]}
|
||||
id="affectListedBuilding"
|
||||
className="govuk-radios__input"
|
||||
@@ -531,7 +532,7 @@ let S78_Questionnaire = (props) => {
|
||||
datafieldname="TPO"
|
||||
options={[
|
||||
t("myrepresentations:questionnaire-yes"),
|
||||
t("myrepresentations:questionnaire-no"),
|
||||
t("myrepresentations:questionnaire-no")
|
||||
]}
|
||||
id="TPO"
|
||||
className="govuk-radios__input"
|
||||
@@ -558,7 +559,7 @@ let S78_Questionnaire = (props) => {
|
||||
datafieldname="natureConservationSite"
|
||||
options={[
|
||||
t("myrepresentations:questionnaire-yes"),
|
||||
t("myrepresentations:questionnaire-no"),
|
||||
t("myrepresentations:questionnaire-no")
|
||||
]}
|
||||
id="natureConservationSite"
|
||||
className="govuk-radios__input"
|
||||
@@ -585,7 +586,7 @@ let S78_Questionnaire = (props) => {
|
||||
datafieldname="protectedSpecies"
|
||||
options={[
|
||||
t("myrepresentations:questionnaire-yes"),
|
||||
t("myrepresentations:questionnaire-no"),
|
||||
t("myrepresentations:questionnaire-no")
|
||||
]}
|
||||
id="protectedSpecies"
|
||||
className="govuk-radios__input"
|
||||
@@ -616,7 +617,7 @@ let S78_Questionnaire = (props) => {
|
||||
component={RenderRadioList}
|
||||
options={[
|
||||
t("myrepresentations:questionnaire-yes"),
|
||||
t("myrepresentations:questionnaire-no"),
|
||||
t("myrepresentations:questionnaire-no")
|
||||
]}
|
||||
type="text"
|
||||
rows="5"
|
||||
@@ -629,7 +630,7 @@ let S78_Questionnaire = (props) => {
|
||||
datafieldname="governmentDepartmentComments"
|
||||
options={[
|
||||
t("myrepresentations:questionnaire-yes"),
|
||||
t("myrepresentations:questionnaire-no"),
|
||||
t("myrepresentations:questionnaire-no")
|
||||
]}
|
||||
id="governmentDepartmentComments"
|
||||
className="govuk-radios__input"
|
||||
@@ -675,7 +676,7 @@ let S78_Questionnaire = (props) => {
|
||||
component={RenderRadioList}
|
||||
options={[
|
||||
t("myrepresentations:questionnaire-yes"),
|
||||
t("myrepresentations:questionnaire-no"),
|
||||
t("myrepresentations:questionnaire-no")
|
||||
]}
|
||||
type="text"
|
||||
rows="5"
|
||||
@@ -691,7 +692,7 @@ let S78_Questionnaire = (props) => {
|
||||
datafieldname="developmentCarriedOutInAccordance"
|
||||
options={[
|
||||
t("myrepresentations:questionnaire-yes"),
|
||||
t("myrepresentations:questionnaire-no"),
|
||||
t("myrepresentations:questionnaire-no")
|
||||
]}
|
||||
id="developmentCarriedOutInAccordance"
|
||||
className="govuk-radios__input"
|
||||
@@ -722,7 +723,7 @@ let S78_Questionnaire = (props) => {
|
||||
component={RenderRadioList}
|
||||
options={[
|
||||
t("myrepresentations:questionnaire-yes"),
|
||||
t("myrepresentations:questionnaire-no"),
|
||||
t("myrepresentations:questionnaire-no")
|
||||
]}
|
||||
type="text"
|
||||
rows="5"
|
||||
@@ -741,7 +742,7 @@ let S78_Questionnaire = (props) => {
|
||||
component={RenderRadioList}
|
||||
options={[
|
||||
t("myrepresentations:questionnaire-yes"),
|
||||
t("myrepresentations:questionnaire-no"),
|
||||
t("myrepresentations:questionnaire-no")
|
||||
]}
|
||||
type="text"
|
||||
rows="5"
|
||||
@@ -757,7 +758,7 @@ let S78_Questionnaire = (props) => {
|
||||
datafieldname="developmentAnyOtherConditions"
|
||||
options={[
|
||||
t("myrepresentations:questionnaire-yes"),
|
||||
t("myrepresentations:questionnaire-no"),
|
||||
t("myrepresentations:questionnaire-no")
|
||||
]}
|
||||
id="developmentAnyOtherConditions"
|
||||
className="govuk-radios__input"
|
||||
@@ -797,7 +798,7 @@ let S78_Questionnaire = (props) => {
|
||||
datafieldname="copyOfApplicantsCertificate"
|
||||
options={[
|
||||
t("myrepresentations:questionnaire-yes"),
|
||||
t("myrepresentations:questionnaire-no"),
|
||||
t("myrepresentations:questionnaire-no")
|
||||
]}
|
||||
id="copyOfApplicantsCertificate"
|
||||
className="govuk-radios__input"
|
||||
@@ -825,7 +826,7 @@ let S78_Questionnaire = (props) => {
|
||||
datafieldname="advertismentGiven"
|
||||
options={[
|
||||
t("myrepresentations:questionnaire-yes"),
|
||||
t("myrepresentations:questionnaire-no"),
|
||||
t("myrepresentations:questionnaire-no")
|
||||
]}
|
||||
id="advertismentGiven"
|
||||
className="govuk-radios__input"
|
||||
@@ -853,7 +854,7 @@ let S78_Questionnaire = (props) => {
|
||||
datafieldname="copyOfLetterOfAppealNotification"
|
||||
options={[
|
||||
t("myrepresentations:questionnaire-yes"),
|
||||
t("myrepresentations:questionnaire-no"),
|
||||
t("myrepresentations:questionnaire-no")
|
||||
]}
|
||||
id="copyOfLetterOfAppealNotification"
|
||||
className="govuk-radios__input"
|
||||
@@ -880,7 +881,7 @@ let S78_Questionnaire = (props) => {
|
||||
datafieldname="lpaEIAOS"
|
||||
options={[
|
||||
t("myrepresentations:questionnaire-yes"),
|
||||
t("myrepresentations:questionnaire-no"),
|
||||
t("myrepresentations:questionnaire-no")
|
||||
]}
|
||||
id="lpaEIAOS"
|
||||
className="govuk-radios__input"
|
||||
@@ -907,7 +908,7 @@ let S78_Questionnaire = (props) => {
|
||||
datafieldname="advertismentConsentDiscontinuanceNotice"
|
||||
options={[
|
||||
t("myrepresentations:questionnaire-yes"),
|
||||
t("myrepresentations:questionnaire-no"),
|
||||
t("myrepresentations:questionnaire-no")
|
||||
]}
|
||||
id="advertismentConsentDiscontinuanceNotice"
|
||||
className="govuk-radios__input"
|
||||
@@ -934,7 +935,7 @@ let S78_Questionnaire = (props) => {
|
||||
datafieldname="detailsOfOtherAppeals"
|
||||
options={[
|
||||
t("myrepresentations:questionnaire-yes"),
|
||||
t("myrepresentations:questionnaire-no"),
|
||||
t("myrepresentations:questionnaire-no")
|
||||
]}
|
||||
id="detailsOfOtherAppeals"
|
||||
className="govuk-radios__input"
|
||||
@@ -961,7 +962,7 @@ let S78_Questionnaire = (props) => {
|
||||
datafieldname="detailsOfPreviousAppeals"
|
||||
options={[
|
||||
t("myrepresentations:questionnaire-yes"),
|
||||
t("myrepresentations:questionnaire-no"),
|
||||
t("myrepresentations:questionnaire-no")
|
||||
]}
|
||||
id="detailsOfPreviousAppeals"
|
||||
className="govuk-radios__input"
|
||||
@@ -988,7 +989,7 @@ let S78_Questionnaire = (props) => {
|
||||
datafieldname="otherRelevantInformation"
|
||||
options={[
|
||||
t("myrepresentations:questionnaire-yes"),
|
||||
t("myrepresentations:questionnaire-no"),
|
||||
t("myrepresentations:questionnaire-no")
|
||||
]}
|
||||
id="otherRelevantInformation"
|
||||
className="govuk-radios__input"
|
||||
@@ -1120,7 +1121,7 @@ S78_Questionnaire = connect((state) => {
|
||||
|
||||
return {
|
||||
procedureTypeValue,
|
||||
representationTypeValue,
|
||||
representationTypeValue
|
||||
};
|
||||
})(S78_Questionnaire);
|
||||
|
||||
@@ -1131,7 +1132,7 @@ const mapDispatchToProps = (dispatch) => {
|
||||
|
||||
setFilesForRepresentations: (fileList) => {
|
||||
dispatch(setFilesForRepresentations(fileList));
|
||||
},
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1143,7 +1144,7 @@ const mapStateToProps = (state, props) => {
|
||||
appealType: state.appealType,
|
||||
currentView: state.currentView,
|
||||
myRepresentations: state.myRepresentations,
|
||||
initialValues: state.currentView.caseReference.repDetails,
|
||||
initialValues: state.currentView.caseReference.repDetails
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1154,6 +1155,6 @@ export default connect(
|
||||
reduxForm({
|
||||
form: "representationForm",
|
||||
enableReinitialize: false,
|
||||
destroyOnUnmount: false,
|
||||
destroyOnUnmount: false
|
||||
})(S78_Questionnaire)
|
||||
);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user