Compare commits
564
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e5ada29cdb | ||
|
|
64dc4e78d2 | ||
|
|
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 | ||
|
|
ff394882a5 | ||
|
|
6a7806f5ea | ||
|
|
c622cb2f74 | ||
|
|
02a83700ba | ||
|
|
eebe30a232 | ||
|
|
e54a0b2253 | ||
|
|
df199cff53 | ||
|
|
d0d2b5d7a9 | ||
|
|
84aed438f8 | ||
|
|
8be971f0b9 | ||
|
|
118d8a56c7 | ||
|
|
0b3cb9778b | ||
|
|
cb948a160b | ||
|
|
c5d3792048 | ||
|
|
17042d9836 | ||
|
|
e9fc8816c1 | ||
|
|
f8769d0bf1 | ||
|
|
c0dbaa2c3f | ||
|
|
dc14e6c9af | ||
|
|
b5b114f455 | ||
|
|
16010f177a | ||
|
|
7ec709581f | ||
|
|
2c3c3f1cdf | ||
|
|
ac17e2058b | ||
|
|
75bab2af0b | ||
|
|
60a9081ead | ||
|
|
2d18a5a2b3 | ||
|
|
bf2679045e | ||
|
|
92ceacb57b | ||
|
|
6f58e7ad63 | ||
|
|
9a3201792c | ||
|
|
0b070de9f7 | ||
|
|
7cc9469b2b | ||
|
|
a4ce38511d | ||
|
|
95d5164b2f | ||
|
|
6df20eb960 | ||
|
|
a9c3a1368f | ||
|
|
92aee7e23e | ||
|
|
5cf5a64ad5 | ||
|
|
1d1adf017a | ||
|
|
fcba17c81f | ||
|
|
0e91dfe8a2 | ||
|
|
38ebd522a8 | ||
|
|
b86712efb8 | ||
|
|
8e9d89a2af | ||
|
|
fabcb3ee5a | ||
|
|
ec3a591126 | ||
|
|
ad2dddc9a4 | ||
|
|
68a34d03ae | ||
|
|
fc1f63f388 | ||
|
|
664d0dd787 | ||
|
|
c55242fd90 | ||
|
|
21bba4a131 | ||
|
|
82f96493ce | ||
|
|
2347a104c8 | ||
|
|
fbfd21df41 | ||
|
|
f6bfc4b5d0 | ||
|
|
8d8ae89ae6 | ||
|
|
6fa2418b19 | ||
|
|
b808a34b14 | ||
|
|
8a2ee508c0 | ||
|
|
5fb944e90f | ||
|
|
5a4670dda3 | ||
|
|
75436837a2 | ||
|
|
58b5c71a64 | ||
|
|
f9524638a7 | ||
|
|
f696b20671 | ||
|
|
8895d5a328 | ||
|
|
f9831b9aa4 | ||
|
|
986d5a382f | ||
|
|
9845af7046 | ||
|
|
14a24616d0 | ||
|
|
e990feddbc | ||
|
|
8f1aede2e3 | ||
|
|
d0b2fd0996 | ||
|
|
9744ab93a4 | ||
|
|
9971f8be4d | ||
|
|
4562e5f092 | ||
|
|
3ccb96abc5 | ||
|
|
b2e8eae518 | ||
|
|
f6cd76ed38 | ||
|
|
ab97d28a1c | ||
|
|
7f2ed69972 | ||
|
|
0d24e3ee12 | ||
|
|
42866765c2 | ||
|
|
a156cc5dda | ||
|
|
9710301b8d | ||
|
|
79538f5f5c | ||
|
|
8c07850486 | ||
|
|
ab04761677 | ||
|
|
cb2ade03b4 | ||
|
|
103c548e32 | ||
|
|
28fb2ecbe7 | ||
|
|
8713317404 | ||
|
|
7c1262e4dc | ||
|
|
777d37f8b4 | ||
|
|
a24d68b8c4 | ||
|
|
5fbd07bb1f | ||
|
|
ac21337d4d | ||
|
|
67d6db3b05 | ||
|
|
f705cc41c3 | ||
|
|
8edc905a8c | ||
|
|
527decda43 | ||
|
|
7742558f17 | ||
|
|
a1b821521d | ||
|
|
b736239bf3 | ||
|
|
12a6e15a40 | ||
|
|
dcb67e0de3 | ||
|
|
39dc5a349a | ||
|
|
d59290364d | ||
|
|
0a25358860 | ||
|
|
9935f65e73 | ||
|
|
5ecaa58bdf | ||
|
|
dbc0345197 | ||
|
|
4bf2a129de | ||
|
|
75a15948e4 | ||
|
|
91dcf6c5c3 | ||
|
|
e0988de47b | ||
|
|
dfd76757ae | ||
|
|
84fc916c7f | ||
|
|
a5dbd52d73 | ||
|
|
53f4b8140a | ||
|
|
9e1d091116 | ||
|
|
7e3c79830c | ||
|
|
4d310fd6c1 | ||
|
|
febfb4e532 | ||
|
|
a92b0af2db | ||
|
|
806952b98d | ||
|
|
412f7d2e90 | ||
|
|
56ad0c4843 | ||
|
|
f39bdee1ee | ||
|
|
cc3c70024f | ||
|
|
2ac542e6c2 | ||
|
|
e3546e29a7 |
@@ -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
|
||||
+173
-46
@@ -13,31 +13,38 @@ HASHKEY = 028ffbae928d7191c0017f298260995f901d78eabde1436c0af0423459cc3715832136
|
||||
# CRMURL = "devcrm2016.llcdt.gov.wales/DVPINS"
|
||||
|
||||
# //New Dev oauth ESNR
|
||||
# CLIENT_ID = 9b834097-03d7-409b-b038-ecfec31a394a
|
||||
# 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"
|
||||
CLIENT_ID = 9b834097-03d7-409b-b038-ecfec31a394a
|
||||
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 = "dv-pedw.crm11.dynamics.com"
|
||||
CRMURL_VERSION = "v9.2"
|
||||
|
||||
# //New Test
|
||||
# CLIENT_ID = d40b9373-96c2-4b04-8bd8-c2a2fe6444c1
|
||||
# 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"
|
||||
CLIENT_ID = d40b9373-96c2-4b04-8bd8-c2a2fe6444c1
|
||||
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_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"
|
||||
# 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"
|
||||
# # 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"
|
||||
# # CRMURL_VERSION = "v8.2"
|
||||
# CRMURL = "wg-pp-pedw.crm11.dynamics.com"
|
||||
# CRMURL_VERSION = "v9.2"
|
||||
|
||||
|
||||
# //Prod Oauth WGO
|
||||
@@ -48,18 +55,79 @@ CRMURL = "ppcrm2016.llcdt.gov.wales/PPPINSWales"
|
||||
# RELAYPATH = "prod-pedw-hc"
|
||||
# CRMURL = "crm2016.llc.gov.wales/PEDW"
|
||||
|
||||
# //New Prod
|
||||
# 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"
|
||||
# # 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.llc.gov.wales/PEDW"
|
||||
# CRMURL_VERSION = "v8.2"
|
||||
|
||||
|
||||
|
||||
# D365 cnr WGO
|
||||
# CLIENT_ID = 3125ac03-91ac-46a7-a166-0086f0ed90b3
|
||||
# CLIENT_SECRET = bFq8Q~9VX5Ra3lKnGGIXsB.G6-ZGMx7LqyqXjdr4
|
||||
# RELAY_ROOT = https://ar-ns-lz-pedw-d365cnr-uks-01.servicebus.windows.net/ar-hc-lz-pedw-d365cnr-uks-01/
|
||||
# RELAYURI = "ar-ns-lz-pedw-d365cnr-uks-01.servicebus.windows.net"
|
||||
# RELAYPATH = "ar-hc-lz-pedw-d365cnr-uks-01"
|
||||
# CRMURL = "dv-pedw.crm11.dynamics.com"
|
||||
# CRMURL_VERSION = "v9.2"
|
||||
|
||||
# D365 Dev WGO
|
||||
# CLIENT_ID = 9b834097-03d7-409b-b038-ecfec31a394a
|
||||
# CLIENT_SECRET = .Jf8Q~tKMObCJjhh_hy3J5AIctFrBalU4FS~tdxk
|
||||
# RELAY_ROOT = https://ar-ns-lz-pedw-d365dev-uks-01.servicebus.windows.net/ar-hc-lz-pedw-d365dev-uks-01/
|
||||
# RELAYURI = "ar-ns-lz-pedw-d365dev-uks-01.servicebus.windows.net"
|
||||
# RELAYPATH = "ar-hc-lz-pedw-d365dev-uks-01"
|
||||
# CRMURL = "dv-pedw.crm11.dynamics.com"
|
||||
# CRMURL_VERSION = "v9.2"
|
||||
|
||||
# D365 Test WGO
|
||||
# CLIENT_ID = d40b9373-96c2-4b04-8bd8-c2a2fe6444c1
|
||||
# CLIENT_SECRET = 6hT8Q~glL~jloWpGmvXw3UY37QFwjUE0r._jobEM
|
||||
# RELAY_ROOT = https://ar-ns-lz-pedw-d365test-uks-01.servicebus.windows.net/ar-hc-lz-pedw-d365test-uks-01/
|
||||
# RELAYURI = "ar-ns-lz-pedw-d365test-uks-01.servicebus.windows.net"
|
||||
# RELAYPATH = "ar-hc-lz-pedw-d365test-uks-01"
|
||||
# CRMURL = "ts-pedw.crm11.dynamics.com"
|
||||
# CRMURL_VERSION = "v9.2"
|
||||
|
||||
# D365 PP WGO
|
||||
# CLIENT_ID = ab6c4678-b31a-4eb3-b429-e039120e488a
|
||||
# CLIENT_SECRET = V288Q~P1lFMvvX9Xnkx2pLixK~GOREH983Owqc1E
|
||||
# RELAY_ROOT = https://ar-ns-lz-pedw-d365ppe-uks-01.servicebus.windows.net/ar-hc-lz-pedw-d365ppe-uks-01/
|
||||
# RELAYURI = "ar-ns-lz-pedw-d365ppe-uks-01.servicebus.windows.net"
|
||||
# RELAYPATH = "ar-hc-lz-pedw-d365ppe-uks-01"
|
||||
# CRMURL = "wg-pp-pedw.crm11.dynamics.com"
|
||||
# CRMURL_VERSION = "v9.2"
|
||||
|
||||
# D365 Prod WGO
|
||||
# CLIENT_ID = 3e4141a3-1fbd-454e-98f0-7f3a4f14a3cc
|
||||
# CLIENT_SECRET = ULC8Q~fZiXm0.teVLlZ_7LjxBOj2vIsWSApu2bAq
|
||||
# RELAY_ROOT = https://ar-ns-lz-pedw-d365prod-uks-01.servicebus.windows.net/ar-hc-lz-pedw-d365prod-uks-01/
|
||||
# RELAYURI = "ar-ns-lz-pedw-d365prod-uks-01.servicebus.windows.net"
|
||||
# RELAYPATH = "ar-hc-lz-pedw-d365prod-uks-01"
|
||||
# CRMURL = "wg-prod-pedw.crm11.dynamics.com"
|
||||
# CRMURL_VERSION = "v9.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"
|
||||
SHOWFILTERDOCS = false
|
||||
# DOCAPI_OFFLINE = "07:00:00,16:00:00"
|
||||
DOCAPI_OFFLINE = "01:00:00,04:00:00"
|
||||
SHOWFILTERDOCS = true
|
||||
|
||||
|
||||
// Next Auth vars
|
||||
@@ -71,15 +139,36 @@ NEXTAUTH_SECRET = SuperSecret
|
||||
# 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
|
||||
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
|
||||
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
|
||||
# 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
|
||||
# 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
|
||||
|
||||
// D365 CNR sql server
|
||||
# DATABASE_URL = sqlserver://sql-srv-plt-pedw-d365cnr-uks-01.database.windows.net:1433;database=PEDW;user=PedwSqlAdmin;password=GhWKr62F5sQ69dZx;encrypt=true;trustServerCertificate=true;hostNameInCertificate=*.database.windows.net;loginTimeout=30;authentication=ActiveDirectoryPassword
|
||||
|
||||
// D365 Dev sql server
|
||||
# DATABASE_URL = sqlserver://sql-srv-plt-pedw-d365dev-uks-01.database.windows.net:1433;database=PEDW;user=PedwSqlAdmin;password=GhWKr62F5sQ69dZx;encrypt=true;trustServerCertificate=true;hostNameInCertificate=*.database.windows.net;loginTimeout=30;authentication=ActiveDirectoryPassword
|
||||
|
||||
// D365 Test sql server
|
||||
# DATABASE_URL = sqlserver://sql-srv-plt-pedw-d365test-uks-01.database.windows.net:1433;database=PEDW;user=PedwSqlAdmin;password=GhWKr62F5sQ69dZx;encrypt=true;trustServerCertificate=true;hostNameInCertificate=*.database.windows.net;loginTimeout=30;authentication=ActiveDirectoryPassword
|
||||
|
||||
// D365 PPE sql server
|
||||
# DATABASE_URL = sqlserver://sql-srv-plt-pedw-d365ppe-uks-01.database.windows.net:1433;database=PEDW;user=PedwSqlAdmin;password=GhWKr62F5sQ69dZx;encrypt=true;trustServerCertificate=true;hostNameInCertificate=*.database.windows.net;loginTimeout=30;authentication=ActiveDirectoryPassword
|
||||
|
||||
// D365 Prod sql server
|
||||
# DATABASE_URL = sqlserver://sql-srv-plt-pedw-d365prod-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
|
||||
|
||||
@@ -91,31 +180,62 @@ AZURE_TENANT_ID = $TENANT
|
||||
AZURE_CLIENT_SECRET = $CLIENT_SECRET
|
||||
|
||||
// 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
|
||||
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
|
||||
# AZURE_STORAGE_ACCOUNT_NAME = "sapltpedwdevuks"
|
||||
# AZURE_STORAGE_ACCOUNT_KEY = MmrsrCjBfop9pI2oImsP/+lJUWU2DrXsAB8nq5bOVROTmPovSGxjCjKw9+TAFr00k8WDUK9r6mVx+AStcMLyAA==
|
||||
# AZURE_PEDW_STORAGE_ENDPOINT = https://sapltpedwdevuks.blob.core.windows.net
|
||||
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
|
||||
# AZURE_STORAGE_ACCOUNT_NAME = "sapltpedwtestuks"
|
||||
# AZURE_STORAGE_ACCOUNT_KEY = bqJAz5pYQVGee8dnVhlsqW+xHwinNTjgY2AmojNyB+d4uAotMR20WcO4Op13yB+9dFaXAkkjtIA4+AStHT/IYg==
|
||||
# AZURE_PEDW_STORAGE_ENDPOINT = https://sapltpedwtestuks.blob.core.windows.net
|
||||
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
|
||||
# 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
|
||||
|
||||
# D365 CNR key
|
||||
# AZURE_STORAGE_ACCOUNT_NAME = "sapltpedwd365cnruks"
|
||||
# AZURE_STORAGE_ACCOUNT_KEY = nEwCp+4FuVf/9a4DOyKuQO2yRRV4Ypigg20ch1YaiL09YmEhWMEO5pNLpYtI3WnQCkIqeu1CUqwM+AStCLW01g==
|
||||
# AZURE_PEDW_STORAGE_ENDPOINT = https://sapltpedwd365cnruks.blob.core.windows.net
|
||||
|
||||
# D365 DEV key
|
||||
# AZURE_STORAGE_ACCOUNT_NAME = "sapltpedwd365devuks"
|
||||
# AZURE_STORAGE_ACCOUNT_KEY = XzwQxuZXSwYrVgemDUD2ymTpYTIfWqhypbmEALw1ZEEP0M4D3b3Gh28clSymxwFu7Gu9mhwkW4/V+AStZ6RF8Q==
|
||||
# AZURE_PEDW_STORAGE_ENDPOINT = https://sapltpedwd365devuks.blob.core.windows.net
|
||||
|
||||
# D365 TEST key
|
||||
# AZURE_STORAGE_ACCOUNT_NAME = "sapltpedwd365testuks"
|
||||
# AZURE_STORAGE_ACCOUNT_KEY = 5NdDO9GGlbTFLHFOXZRw8H2C0Ow5bFTvHwUHEbStyzg2mbd1uwHSeBSvM/dkN+HfdwrFzqAkwL5P+AStdO6cig==
|
||||
# AZURE_PEDW_STORAGE_ENDPOINT = https://sapltpedwd365testuks.blob.core.windows.net
|
||||
|
||||
# D365 PP key
|
||||
# AZURE_STORAGE_ACCOUNT_NAME = "sapltpedwd365ppeuks"
|
||||
# AZURE_STORAGE_ACCOUNT_KEY = xQz4FWDnQDE09uPOCj1t7axRiquvZG9vbxL88ywzVsJnTsAgewrHnuAGkxGPBCp2xGE53ffYOme6+AStSr8OoQ==
|
||||
# AZURE_PEDW_STORAGE_ENDPOINT = https://sapltpedwd365ppeuks.blob.core.windows.net
|
||||
|
||||
# D365 Prod key
|
||||
# AZURE_STORAGE_ACCOUNT_NAME = "sapltpedwd365produks"
|
||||
# AZURE_STORAGE_ACCOUNT_KEY = DvKcWhDpFKMFdVXFF2SqDG0sYQ3AkNCmJUBG0cvgzi5NBHS4Ahd2hPAlfA3hGi2EbohUag3vCucK+ASt1IdBhA==
|
||||
# AZURE_PEDW_STORAGE_ENDPOINT = https://sapltpedwd365produks.blob.core.windows.net
|
||||
|
||||
|
||||
AZURE_PEDW_CONTAINER = "pedwapplications"
|
||||
AZURE_PEDW_QUEUE_ENDPOINT = https://$AZURE_STORAGE_ACCOUNT_NAME.queue.core.windows.net
|
||||
@@ -126,24 +246,31 @@ NOTIFY_API_KEY = pedwnextauthlivekey-90f93710-9dae-423e-aea1-11eccd0dc132-5c0ed1
|
||||
|
||||
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
|
||||
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
|
||||
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
|
||||
# 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
|
||||
# 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
|
||||
HIDEERRORLOGS = false
|
||||
|
||||
SHOWSIPS = true
|
||||
|
||||
ALLOWED_IPS=::1,203.0.113.42,198.51.100.17
|
||||
UPLOAD_BATCH_COUNT = 5
|
||||
|
||||
NRWDOMAIN = rdbmedia.co.uk
|
||||
+19
-2
@@ -37,5 +37,22 @@ pages/polling.js
|
||||
|
||||
pages/api/endpoint/getaccounts_api.js
|
||||
|
||||
# certs
|
||||
certificates/*
|
||||
# remove swagger api docs
|
||||
|
||||
next-swagger-doc.json
|
||||
pages/api-doc.js
|
||||
public/swagger.json
|
||||
certificates/cert-key.pem
|
||||
certificates/cert.pem
|
||||
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
+2
-2
@@ -8,10 +8,10 @@
|
||||
"name": "Next.js: debug server-side",
|
||||
"type": "node-terminal",
|
||||
"request": "launch",
|
||||
"command": "yarn run dev"
|
||||
"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,83 @@
|
||||
# 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/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
|
||||
'
|
||||
"""
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+392
-266
@@ -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=" +
|
||||
casefolderID +
|
||||
"&blobname=" +
|
||||
blob.name,
|
||||
"hashedfilepath": hashAPIPath(
|
||||
"/api/file/downloadblob?container=" +
|
||||
containerName +
|
||||
"&casefolderID=" +
|
||||
casefolderID +
|
||||
"&blobname=" +
|
||||
blob.name.split("/")[2]
|
||||
),
|
||||
"deletepath":
|
||||
"/api/file/deleteblob?container=" +
|
||||
containerName +
|
||||
"&casefolderID=" +
|
||||
casefolderID +
|
||||
"&blobname=" +
|
||||
blob.name.split("/")[2],
|
||||
"hasheddeletepath": hashAPIPath(
|
||||
"/api/file/deleteblob?container=" +
|
||||
containerName +
|
||||
"&casefolderID=" +
|
||||
casefolderID +
|
||||
"&blobname=" +
|
||||
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);
|
||||
@@ -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,15 +368,15 @@ export const createRepBlob = async (formContent, containerName, caseref) => {
|
||||
|
||||
const tags = {
|
||||
containerid: containerName,
|
||||
caseID: formContent.caseRef,
|
||||
blobType: "Representation",
|
||||
caseID: formContent.ticketnumber || formContent.caseRef,
|
||||
blobType: "Representation"
|
||||
};
|
||||
|
||||
//console.log("the tags:", tags);
|
||||
const withTags = await blockBlobClient.setTags(tags);
|
||||
const withMeta = await blockBlobClient.setMetadata(tags);
|
||||
|
||||
return formContent.pinswg_name;
|
||||
return formContent.ticketnumber;
|
||||
};
|
||||
|
||||
export const createAppealPDFBlob = async (
|
||||
@@ -356,21 +415,24 @@ 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
|
||||
|
||||
const tags = {
|
||||
containerid: containerName,
|
||||
caseID: caseID,
|
||||
blobType: "Appeal PDF",
|
||||
documentLocationId: "846040000",
|
||||
ishareLocation: "846040000",
|
||||
ishareLocation: whichLocation,
|
||||
documentLocationId: whichLocation
|
||||
};
|
||||
|
||||
//console.log("the tags:", tags);
|
||||
@@ -404,35 +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
|
||||
? "846040029"
|
||||
: repName.indexOf("_Consultation_Response_") > 0
|
||||
? "846040036"
|
||||
: "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",
|
||||
documentLocationId: whichLocation,
|
||||
ishareLocation: whichLocation,
|
||||
documentLocationId: whichLocation
|
||||
};
|
||||
|
||||
//console.log("the tags:", tags);
|
||||
@@ -446,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);
|
||||
@@ -466,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);
|
||||
@@ -478,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);
|
||||
@@ -496,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);
|
||||
@@ -506,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);
|
||||
@@ -554,76 +617,54 @@ 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"
|
||||
: files[prop][0].fieldName.indexOf(
|
||||
"_Consultation_Response_"
|
||||
) > 0
|
||||
? "846040036"
|
||||
: "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,
|
||||
caseID: foldername.split("/")[0],
|
||||
documentType: files[prop][0].fieldName.split(".")[1],
|
||||
blobType: "RepresentationFile",
|
||||
documentLocationId: whichLocation,
|
||||
ishareLocation: whichLocation,
|
||||
documentLocationId: whichLocation
|
||||
};
|
||||
const withTags = blockBlobClient.setTags(tags);
|
||||
const withMeta = blockBlobClient.setMetadata(tags);
|
||||
@@ -734,14 +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" },
|
||||
{ pattern: /_Consultation_Response_/, value: "846040036" }
|
||||
];
|
||||
|
||||
// Find a matching pattern or fallback to default
|
||||
@@ -762,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);
|
||||
@@ -799,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);
|
||||
@@ -844,7 +887,7 @@ export const uploadPDFRepFiles = async (
|
||||
containerid: containerName,
|
||||
caseID: foldername.split("/")[0],
|
||||
documentType: repType,
|
||||
blobType: "RepresentationPDF",
|
||||
blobType: "RepresentationPDF"
|
||||
};
|
||||
|
||||
//console.log("the tags:", tags);
|
||||
@@ -897,7 +940,7 @@ export const uploadPDFAppealFiles = async (
|
||||
const tags = {
|
||||
containerid: containerName,
|
||||
caseID: foldername.split("/")[0],
|
||||
blobType: "AppealPDF",
|
||||
blobType: "AppealPDF"
|
||||
};
|
||||
|
||||
//console.log("the tags:", tags);
|
||||
@@ -936,7 +979,7 @@ export const uploadPDFCaseFiles = async (
|
||||
const tags = {
|
||||
containerid: containerName,
|
||||
caseID: foldername.split("/")[0],
|
||||
blobType: "AppealPDF",
|
||||
blobType: "AppealPDF"
|
||||
};
|
||||
|
||||
//console.log("the tags:", tags);
|
||||
@@ -1142,7 +1185,7 @@ export const downloadAllRepsFiles = async (containerName, repsBlobObj) => {
|
||||
|
||||
return {
|
||||
"@odata.count": blobCount,
|
||||
"value": downloaded,
|
||||
"value": downloaded
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1181,7 +1224,7 @@ export const getCaseBlob = async (
|
||||
const tags = {
|
||||
containerid: containerName,
|
||||
caseID: caseReference,
|
||||
blobType: "Case",
|
||||
blobType: "Case"
|
||||
};
|
||||
|
||||
//console.log("the tags:", tags);
|
||||
@@ -1212,7 +1255,7 @@ export const getProgressBlobs = async (containerName, caseReference) => {
|
||||
|
||||
let blobCount = 0;
|
||||
for await (const blob of containerClient.listBlobsFlat({
|
||||
prefix: caseReference,
|
||||
prefix: caseReference
|
||||
})) {
|
||||
blobCount++;
|
||||
}
|
||||
@@ -1225,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=" +
|
||||
caseReference +
|
||||
"&blobname=" +
|
||||
blob.name.split("/")[1]
|
||||
),
|
||||
"hasheddeletepath": hashAPIPath(
|
||||
"/api/file/deleteblob?container=" +
|
||||
containerName +
|
||||
"&casefolderID=" +
|
||||
caseReference +
|
||||
"&blobname=" +
|
||||
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;
|
||||
@@ -1284,22 +1314,38 @@ 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 &&
|
||||
blobObj.push({
|
||||
"name": blob.name.split("/")[1],
|
||||
"path": blob.name,
|
||||
//"versionId": blob.versionId,
|
||||
"caseObj":
|
||||
blob.name.split("/")[0] +
|
||||
"/" +
|
||||
blob.name.split("/")[0] +
|
||||
"_case.json",
|
||||
// "isCurrentVersion": blob.isCurrentVersion,
|
||||
// "contentLength": blob.properties.contentLength,
|
||||
// "contentType": blob.contentType,
|
||||
// "lastModified": blob.properties.lastModified,
|
||||
});
|
||||
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,
|
||||
//"versionId": blob.versionId,
|
||||
"caseObj":
|
||||
blob.name.split("/")[0] +
|
||||
"/" +
|
||||
blob.name.split("/")[0] +
|
||||
"_case.json"
|
||||
// "isCurrentVersion": blob.isCurrentVersion,
|
||||
// "contentLength": blob.properties.contentLength,
|
||||
// "contentType": blob.contentType,
|
||||
// "lastModified": blob.properties.lastModified,
|
||||
});
|
||||
}
|
||||
|
||||
// console.log(
|
||||
@@ -1351,7 +1397,7 @@ export const getRepsBlobs = async (containerName) => {
|
||||
includeMetadata: true,
|
||||
includeSnapshots: false,
|
||||
includeTags: true,
|
||||
includeVersions: true,
|
||||
includeVersions: true
|
||||
};
|
||||
|
||||
let blobObj = [];
|
||||
@@ -1360,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);
|
||||
@@ -1390,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=" +
|
||||
blob.name.split("/")[0] +
|
||||
"/" +
|
||||
blob.name.split("/")[1] +
|
||||
"&blobname=" +
|
||||
blob.name.split("/")[3],
|
||||
"hashedfilepath": hashAPIPath(
|
||||
"/api/file/downloadblob?container=" +
|
||||
containerName +
|
||||
"&casefolderID=" +
|
||||
blob.name.split("/")[0] +
|
||||
"/" +
|
||||
blob.name.split("/")[1] +
|
||||
"&blobname=" +
|
||||
blob.name
|
||||
),
|
||||
"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=" +
|
||||
blob.name.split("/")[0] +
|
||||
"/" +
|
||||
blob.name.split("/")[1] +
|
||||
"&blobname=" +
|
||||
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;
|
||||
};
|
||||
@@ -1496,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(
|
||||
@@ -1540,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,
|
||||
@@ -1601,7 +1630,7 @@ export const createRepCompleteMessage = async (
|
||||
caseReference +
|
||||
"/" +
|
||||
filename +
|
||||
"/files",
|
||||
"/files"
|
||||
};
|
||||
|
||||
console.log("======================", message, "=====================");
|
||||
@@ -1627,7 +1656,7 @@ export const listContainers = async (
|
||||
includeDeleted: false,
|
||||
includeMetadata: true,
|
||||
includeSystem: true,
|
||||
prefix: containerNamePrefix,
|
||||
prefix: containerNamePrefix
|
||||
};
|
||||
console.log(
|
||||
"\n\n\n=================================================\n",
|
||||
@@ -1670,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;
|
||||
@@ -1699,3 +1728,100 @@ export const listBlobHierarchical = async (
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
function formatTimeSince(date) {
|
||||
if (!date) return "Unknown date";
|
||||
|
||||
const now = new Date();
|
||||
const diffMs = now - date;
|
||||
const diffDays = Math.floor(diffMs / (1000 * 60 * 60 * 24));
|
||||
|
||||
if (diffDays < 7) {
|
||||
return `${diffDays} day${diffDays !== 1 ? "s" : ""} ago`;
|
||||
} else {
|
||||
const diffWeeks = Math.floor(diffDays / 7);
|
||||
return `${diffWeeks} week${diffWeeks !== 1 ? "s" : ""} ago`;
|
||||
}
|
||||
}
|
||||
|
||||
function formatDateDisplay(date) {
|
||||
return date
|
||||
? `${date.toLocaleString("en-GB")} (${formatTimeSince(date)})`
|
||||
: "Unknown";
|
||||
}
|
||||
|
||||
export async function listBlobHierarchicalForUser(containerClient) {
|
||||
const blobNames = [];
|
||||
for await (const blob of containerClient.listBlobsFlat()) {
|
||||
const lastModifiedDate = blob.properties?.lastModified || null;
|
||||
const createdOnDate = blob.properties?.createdOn || null;
|
||||
|
||||
let displayDate = "";
|
||||
|
||||
if (createdOnDate && lastModifiedDate) {
|
||||
if (
|
||||
createdOnDate.toDateString() === lastModifiedDate.toDateString()
|
||||
) {
|
||||
// Same day — show just one
|
||||
displayDate = `Date: ${formatDateDisplay(lastModifiedDate)}`;
|
||||
} else {
|
||||
// Different days — show both
|
||||
displayDate = `Created: ${formatDateDisplay(
|
||||
createdOnDate
|
||||
)}, Modified: ${formatDateDisplay(lastModifiedDate)}`;
|
||||
}
|
||||
} else if (lastModifiedDate) {
|
||||
displayDate = `Modified: ${formatDateDisplay(lastModifiedDate)}`;
|
||||
} else if (createdOnDate) {
|
||||
displayDate = `Created: ${formatDateDisplay(createdOnDate)}`;
|
||||
} else {
|
||||
displayDate = "Unknown date";
|
||||
}
|
||||
|
||||
blobNames.push({
|
||||
name: blob.name,
|
||||
size: blob.properties.contentLength || 0,
|
||||
lastModified: lastModifiedDate
|
||||
? lastModifiedDate.toISOString()
|
||||
: null,
|
||||
createdOn: createdOnDate ? createdOnDate.toISOString() : null,
|
||||
displayDate
|
||||
});
|
||||
}
|
||||
return blobNames;
|
||||
}
|
||||
|
||||
export async function listContainersForUser(
|
||||
blobServiceClient,
|
||||
containerNamePrefix,
|
||||
emailAddress
|
||||
) {
|
||||
const options = {
|
||||
includeDeleted: false,
|
||||
includeMetadata: true,
|
||||
includeSystem: true,
|
||||
prefix: containerNamePrefix
|
||||
};
|
||||
|
||||
const results = [];
|
||||
|
||||
for await (const containerItem of blobServiceClient.listContainers(
|
||||
options
|
||||
)) {
|
||||
const containerClient = blobServiceClient.getContainerClient(
|
||||
containerItem.name
|
||||
);
|
||||
const blobNames = await listBlobHierarchicalForUser(
|
||||
containerClient
|
||||
).catch(console.error);
|
||||
|
||||
if (blobNames && blobNames.length > 0) {
|
||||
results.push({
|
||||
container: containerItem.name,
|
||||
blobs: blobNames
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return results; // array of non-empty containers
|
||||
}
|
||||
|
||||
@@ -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/v8.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,106 @@
|
||||
import _ from "lodash";
|
||||
|
||||
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"
|
||||
);
|
||||
var errStr =
|
||||
"\n\n/////////////////////////////////////////////////\nServer Error " +
|
||||
"\n" +
|
||||
(_.has(err, "name") ? "Name: " + err.name + "\n" : "") +
|
||||
(_.has(err, "code") ? "Code: " + err.code + "\n" : "") +
|
||||
(_.has(err, "query") ? "Query: " + err.query + "\n" : "") +
|
||||
(_.has(err, "message") ? "Message: " + err.message + "\n" : "") +
|
||||
(_.has(err, "request.url")
|
||||
? "request.url: " + err.request.url + "\n"
|
||||
: "") +
|
||||
(_.has(err, "response.status") ? "Status: " + err.code + "\n" : "") +
|
||||
(_.has(err, "response.statusText")
|
||||
? "\nStatusText: " + err.response.status + "\n"
|
||||
: "") +
|
||||
(_.has(err, "response.request.socket.remoteAddress")
|
||||
? "\nRequest IP: " +
|
||||
err.response.request.socket.remoteAddress +
|
||||
"\n"
|
||||
: "") +
|
||||
(_.has(err, "response.data.error.message")
|
||||
? "\nMessage: " +
|
||||
redactSensitive(err.response.data.error.message) +
|
||||
"\n"
|
||||
: "") +
|
||||
(_.has(err, "response.config.url")
|
||||
? "\nRequest URL: " + redactSensitive(err.config.url) + "\n"
|
||||
: "") +
|
||||
(_.has(err, "response.headers.date")
|
||||
? "\nRequest Time: " + err.response.headers.date + "\n"
|
||||
: "") +
|
||||
(_.has(err, "config.url")
|
||||
? "\nAxios config url: " + redactSensitive(err.config.url) + "\n"
|
||||
: "") +
|
||||
(_.has(err, "config.url")
|
||||
? "\nAxios message url: " + redactSensitive(err.message) + "\n"
|
||||
: "") +
|
||||
(_.has(err, "config.data")
|
||||
? "\nRequest 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
-2162
File diff suppressed because it is too large
Load Diff
@@ -4,7 +4,7 @@ export const getSelectQuery = (appealTypeName) => {
|
||||
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=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";
|
||||
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=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";
|
||||
@@ -60,8 +60,8 @@ export const getSelectQuery = (appealTypeName) => {
|
||||
// process.env.RELAYPATH == "test-pedw-hc"
|
||||
// );
|
||||
return process.env.RELAYPATH == "dev-pedw-hc"
|
||||
? "&$select=pinswg_eiarequired,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=pinswg_eiarequired,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=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";
|
||||
@@ -73,7 +73,7 @@ export const getSelectQuery = (appealTypeName) => {
|
||||
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=pinswg_eiarequired,modifiedon,pinswg_name";
|
||||
return "&$select=modifiedon,pinswg_name";
|
||||
break;
|
||||
case "pinswg_nonvalidations":
|
||||
return "&$select=modifiedon,_pinswg_appellant_value,pinswg_name,pinswg_siteaddressline1,pinswg_siteaddressline2,pinswg_siteaddresspostcode,pinswg_siteaddresstown,_pinswg_associatedlpa_value,statuscode";
|
||||
@@ -82,7 +82,7 @@ export const getSelectQuery = (appealTypeName) => {
|
||||
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_casestage,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_casestage,_pinswg_dnsids_value,pinswg_startdateofevent,pinswg_typeofevent";
|
||||
return "&$select=_pinswg_projecttype_value,pinswg_eiarequired,pinswg_anticipatedgridrefeasting,pinswg_anticipatedgridrefnorthing,_pinswg_appellant_value,pinswg_name,_pinswg_associatedlpa_value,pinswg_choiceofprocedure,pinswg_decision,pinswg_projectdescription,pinswg_projectlocation,pinswg_recommendation,statuscode,pinswg_casestage,_pinswg_sipscase_value,pinswg_writtenacceptanceofnotification,pinswg_validnoticeofintentiontosubmit,pinswg_deadlineforsubmissionofapplication,pinswg_screeningstartdate,pinswg_eiatargetdate,pinswg_targetextended,pinswg_directionissueddate,pinswg_eiarequired,pinswg_scopingstartdate,pinswg_scopingtargetdate,pinswg_scopingtargetextended,pinswg_scopingoutcomeissueddate,pinswg_essubmitted,pinswg_deemedmarinelicenseappliedfor,pinswg_validationdeadlineextension,pinswg_casesuspensionstartdate,pinswg_casesuspensionenddate,pinswg_consultationopen,pinswg_consultationclose,pinswg_reportissuedtowelshministers,pinswg_decisionissuedtoapplicant,pinswg_decisionoutcome";
|
||||
return "&$select=pinswg_casedeadline,_pinswg_projecttype_value,pinswg_eiarequired,pinswg_anticipatedgridrefeasting,pinswg_anticipatedgridrefnorthing,_pinswg_appellant_value,pinswg_name,_pinswg_associatedlpa_value,pinswg_choiceofprocedure,pinswg_decision,pinswg_projectdescription,pinswg_projectlocation,pinswg_recommendation,statuscode,pinswg_casestage,_pinswg_sipscase_value,pinswg_writtenacceptanceofnotification,pinswg_validnoticeofintentiontosubmit,pinswg_deadlineforsubmissionofapplication,pinswg_screeningstartdate,pinswg_eiatargetdate,pinswg_targetextended,pinswg_directionissueddate,pinswg_eiarequired,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";
|
||||
break;
|
||||
default:
|
||||
return "";
|
||||
|
||||
@@ -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,67 @@
|
||||
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);
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,7 @@
|
||||
import {
|
||||
getNewAppeals,
|
||||
getNewAppealsPage,
|
||||
getNewDocumentsPaged
|
||||
} from "./adminDirectService";
|
||||
|
||||
export { getNewAppeals, getNewAppealsPage, getNewDocumentsPaged };
|
||||
@@ -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/endpoint/getcasemessage_api", {
|
||||
id: searchString
|
||||
});
|
||||
|
||||
return getJson(withBaseUrl(BASE_URL, route)).catch(logAndReturnResponse);
|
||||
};
|
||||
|
||||
export const getIncidentbyID = (searchString) => {
|
||||
const route = buildFileQuery("/api/endpoint/getincidentbyid_api", {
|
||||
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/endpoint/getsipsevents_api", {
|
||||
caseid
|
||||
});
|
||||
|
||||
return getJson(withBaseUrl(BASE_URL, route)).catch(logAndReturnResponse);
|
||||
};
|
||||
|
||||
export const getSIPSMedia = async (caseid) => {
|
||||
const route = buildFileQuery("/api/endpoint/getsipsmedia_api", {
|
||||
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/endpoint/getportalmoduledetails_api", {
|
||||
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/endpoint/getmycases_api", {
|
||||
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/endpoint/getmylpacases_api", {
|
||||
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/endpoint/getwatchedcases_api", {
|
||||
loggedInUserId
|
||||
});
|
||||
|
||||
return getJson(withBaseUrl(BASE_URL, route)).catch((error) => {
|
||||
consoleLogger(error);
|
||||
});
|
||||
};
|
||||
|
||||
export const getWatchedCasesProxy = (loggedInUserId) => {
|
||||
const route = buildFileQuery("/api/endpoint/getwatchedcasesproxy_api", {
|
||||
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/endpoint/createwatchedcases_api");
|
||||
|
||||
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/endpoint/deletewatchedcases_api", {
|
||||
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/endpoint/getbasicsearchpaged_api?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/endpoint/getadvancedsearch_api?searchstring=" +
|
||||
JSON.stringify(searchString)
|
||||
).catch(logAndReturnEmptyValueErrorResponse);
|
||||
};
|
||||
|
||||
export const getAdvancedSearchPaged = (
|
||||
searchString,
|
||||
pageNumber,
|
||||
orderBy,
|
||||
fieldSort,
|
||||
showNumberOfRecords
|
||||
) => {
|
||||
return getJson(
|
||||
"/api/endpoint/getadvancedsearchpaged_api?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 url = `/api/endpoint/getbasicsearchdetailspaged_api?appealTypeName=${appealTypeName}&primaryIdAttribute=${primaryIdAttribute}&incidentID=${encodeURIComponent(
|
||||
filter
|
||||
)}`;
|
||||
|
||||
try {
|
||||
const data = await getJson(url);
|
||||
return data.value || [];
|
||||
} catch (error) {
|
||||
consoleLogger(error);
|
||||
return [];
|
||||
}
|
||||
};
|
||||
|
||||
export const getSearchDocumentDetails = (incidentID) => {
|
||||
return getJson(
|
||||
"/api/endpoint/getsearchdocumentdetails_api?incidentid=" + incidentID
|
||||
).catch((error) => {
|
||||
consoleLogger(error);
|
||||
throw error;
|
||||
});
|
||||
};
|
||||
|
||||
export const getSearchDocumentTypes = (incidentID) => {
|
||||
return getJson(
|
||||
"/api/endpoint/getsearchdocumentTypes_api?incidentid=" + incidentID
|
||||
).catch((error) => {
|
||||
consoleLogger(error);
|
||||
});
|
||||
};
|
||||
|
||||
export const getSearchDocumentDetailsPaged = (
|
||||
incidentID,
|
||||
pageNumber,
|
||||
orderBy,
|
||||
fieldSort,
|
||||
showNumberOfRecords,
|
||||
documentType
|
||||
) => {
|
||||
return getJson(
|
||||
"/api/endpoint/getsearchdocumentdetailspaged_api?incidentid=" +
|
||||
incidentID +
|
||||
"&pageNumber=" +
|
||||
pageNumber +
|
||||
"&orderby=" +
|
||||
orderBy +
|
||||
"&fieldSort=" +
|
||||
fieldSort +
|
||||
"&showNumberOfRecords=" +
|
||||
showNumberOfRecords +
|
||||
"&documentType=" +
|
||||
documentType
|
||||
).catch((error) => {
|
||||
consoleLogger(error);
|
||||
});
|
||||
};
|
||||
|
||||
export const getLinkedCases = (parentIncidentid) => {
|
||||
return getJson(
|
||||
"/api/endpoint/getlinkedcases_api?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,94 @@
|
||||
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")}
|
||||
</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();
|
||||
|
||||
@@ -324,8 +324,8 @@ 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"
|
||||
@@ -444,7 +444,7 @@ const mapStateToProps = (state) => {
|
||||
searchResultsObj: state.searchResultsObj,
|
||||
formData: state.formData,
|
||||
appealType: state.appealType,
|
||||
accountDetails: state.accountDetails,
|
||||
accountDetails: state.accountDetails
|
||||
//form: state.form,
|
||||
};
|
||||
};
|
||||
@@ -453,7 +453,7 @@ const mapDispatchToProps = (dispatch) => {
|
||||
return {
|
||||
setCurrentSection: (currentSection) => {
|
||||
dispatch(setCurrentSection(currentSection));
|
||||
},
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
@@ -484,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,7 +3,7 @@ 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) => {
|
||||
@@ -11,7 +11,7 @@ const PersonalDetailsComplete = (props) => {
|
||||
handleSubmit,
|
||||
value,
|
||||
setRegisterFormComplete,
|
||||
setAccountCreatedComplete,
|
||||
setAccountCreatedComplete
|
||||
} = props;
|
||||
let { t, lang } = useTranslation();
|
||||
|
||||
@@ -28,6 +28,8 @@ const PersonalDetailsComplete = (props) => {
|
||||
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;
|
||||
@@ -37,10 +39,8 @@ const PersonalDetailsComplete = (props) => {
|
||||
if (!loggedinUserId || !formValues) return;
|
||||
|
||||
console.log("=============== pref lang", prefLang);
|
||||
const userLang = prefLang == "846040000" ? "cy" : "en";
|
||||
setCookie(null, "pedw_locale", userLang, {
|
||||
path: "/",
|
||||
maxAge: 60 * 60 * 24 * 365,
|
||||
path: "/"
|
||||
});
|
||||
|
||||
console.log("Set cookie to:", userLang);
|
||||
@@ -50,7 +50,7 @@ const PersonalDetailsComplete = (props) => {
|
||||
}
|
||||
|
||||
doUpdate();
|
||||
}, [loggedinUserId, formValues, prefLang]);
|
||||
}, [loggedinUserId, formValues, prefLang, userLang]);
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -59,7 +59,11 @@ const PersonalDetailsComplete = (props) => {
|
||||
{/* <p className="govuk-body">{t("account:account-complete-para-2")}</p> */}
|
||||
|
||||
<p className="govuk-body">
|
||||
<Link href={"/"} className="govuk-link">
|
||||
<Link
|
||||
locale={userLang}
|
||||
href={userLang === "cy" ? "/cy/fymhorth" : "/myportal"}
|
||||
className="govuk-link"
|
||||
>
|
||||
{" "}
|
||||
{t("account:account-complete-return-to-portal-link")}
|
||||
</Link>
|
||||
@@ -74,7 +78,7 @@ const mapStateToProps = (state) => {
|
||||
searchResultsObj: state.searchResultsObj,
|
||||
formData: state.formData,
|
||||
appealType: state.appealType,
|
||||
accountDetails: state.accountDetails,
|
||||
accountDetails: state.accountDetails
|
||||
//form: state.form,
|
||||
};
|
||||
};
|
||||
@@ -83,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();
|
||||
|
||||
@@ -199,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">
|
||||
@@ -312,8 +323,8 @@ const mapStateToProps = (state, props) => {
|
||||
appealType: state.appealType,
|
||||
//form: state.form,
|
||||
initialValues: {
|
||||
emailaddress1: props.loggedInUserEmail,
|
||||
},
|
||||
emailaddress1: props.loggedInUserEmail
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
@@ -321,7 +332,7 @@ const mapDispatchToProps = (dispatch) => {
|
||||
return {
|
||||
setCurrentSection: (currentSection) => {
|
||||
dispatch(setCurrentSection(currentSection));
|
||||
},
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
@@ -334,6 +345,6 @@ export default connect(
|
||||
reduxForm({
|
||||
form: "accountRegisterForm",
|
||||
enableReinitialize: true,
|
||||
destroyOnUnmount: false,
|
||||
destroyOnUnmount: false
|
||||
})(RegisterForm)
|
||||
);
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
// components/admin/tabs/AccountsTab.js
|
||||
import Link from "next/link";
|
||||
|
||||
export default function AccountsTab({ userData }) {
|
||||
return (
|
||||
<div>
|
||||
<h1>User Accounts</h1>
|
||||
<p>Number of accounts created: {userData.length}</p>
|
||||
|
||||
<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>
|
||||
|
||||
{userData.map((user) => (
|
||||
<div key={user.id} className="govuk-summary-list__row">
|
||||
<dd className="govuk-summary-list__value govuk-!-font-size-16 ">
|
||||
<Link
|
||||
target="_blank"
|
||||
href={`/auth/signin2?email=${user.email}`}
|
||||
>
|
||||
{user.email}
|
||||
</Link>
|
||||
<br />
|
||||
{user.id}
|
||||
</dd>
|
||||
<dd className="govuk-summary-list__value govuk-!-font-size-16 ">
|
||||
Last accessed: {user.created}
|
||||
</dd>
|
||||
</div>
|
||||
))}
|
||||
</dl>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,571 @@
|
||||
// components/admin/tabs/AppealsTab.js
|
||||
import useTranslation from "next-translate/useTranslation";
|
||||
import { useCallback, useState, useEffect } from "react";
|
||||
import { JSONPath as jsonpath } from "jsonpath-plus";
|
||||
import Link from "next/link";
|
||||
import { useRouter } from "next/router";
|
||||
import PaginationControl from "../../../components/search/pagination";
|
||||
import { connect } from "react-redux";
|
||||
|
||||
import {
|
||||
setSearchResults,
|
||||
setSearchDetails
|
||||
} from "../../../store/searchOutput/action";
|
||||
|
||||
import { getDetailsProxy, getSearchDetailsPaged } from "../../utils";
|
||||
import { getAdvancedSearchPaged } from "../../../actions/services/searchService";
|
||||
import { getNewAppealsPage } from "../../../actions/services/adminService";
|
||||
import {
|
||||
setCurrentPage,
|
||||
setCurrentReference
|
||||
} from "../../../store/currentView/action";
|
||||
|
||||
function AppealsTab(props) {
|
||||
const [searchLoaded, setSearchLoaded] = useState(false);
|
||||
const [showSpinnerState, setShowSpinnerState] = useState(false);
|
||||
const [selectedOption, setSelectedOption] = useState(10);
|
||||
const [orderByState, setOrderbyState] = useState("createdon");
|
||||
const [fieldSortState, setfieldSortState] = useState("desc");
|
||||
const [loginToWatch, setLoginToWatch] = useState("true");
|
||||
|
||||
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();
|
||||
const myportal = false;
|
||||
const advancedSearch = false;
|
||||
const searchString = "";
|
||||
|
||||
const spinnerState = () => {
|
||||
setShowSpinnerState((prev) => !prev);
|
||||
};
|
||||
|
||||
const pagesCount = Math.ceil(searchResultsObj["@odata.count"] / 10);
|
||||
|
||||
let currentPage = 0;
|
||||
try {
|
||||
currentPage = decodeURI(searchResultsObj["@odata.nextLink"]).split(
|
||||
"skiptoken="
|
||||
)[1];
|
||||
currentPage =
|
||||
typeof currentPage !== "undefined"
|
||||
? parseInt(
|
||||
decodeURI(currentPage)
|
||||
.split('pagenumber="')[1]
|
||||
.slice(
|
||||
0,
|
||||
decodeURI(currentPage)
|
||||
.split('pagenumber="')[1]
|
||||
.indexOf('"')
|
||||
) - 1
|
||||
)
|
||||
: pagesCount;
|
||||
} catch (e) {
|
||||
currentPage = pagesCount;
|
||||
}
|
||||
|
||||
const getSearchPageResults = useCallback(
|
||||
(pageNumber, orderBy, fieldSort) => {
|
||||
getNewAppealsPage(
|
||||
searchString,
|
||||
pageNumber,
|
||||
orderBy,
|
||||
fieldSort,
|
||||
selectedOption
|
||||
).then((data) => {
|
||||
setSearchResults(data);
|
||||
return getSearchDetailsPaged(data).then((details) => {
|
||||
setSearchDetails(details);
|
||||
setShowSpinnerState(false);
|
||||
});
|
||||
});
|
||||
},
|
||||
[selectedOption, setSearchDetails, setSearchResults]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (searchLoaded) {
|
||||
if (selectedOption) {
|
||||
setShowSpinnerState(true);
|
||||
getSearchPageResults(1, orderByState, fieldSortState);
|
||||
}
|
||||
} else {
|
||||
setSearchLoaded(true);
|
||||
}
|
||||
}, [
|
||||
selectedOption,
|
||||
fieldSortState,
|
||||
orderByState,
|
||||
searchLoaded,
|
||||
getSearchPageResults,
|
||||
router.query
|
||||
]);
|
||||
|
||||
const ResultsView = (resultsArr) => {
|
||||
return (
|
||||
<>
|
||||
<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 results_wider ">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => sortDataBy("title")}
|
||||
className={
|
||||
orderByState == "title"
|
||||
? 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("search:searchresults-case-reference-label")}
|
||||
</button>
|
||||
</dd>
|
||||
<dd className="govuk-summary-list__key govuk-!-font-size-16">
|
||||
{t("search:searchresults-site-address-label")}
|
||||
</dd>
|
||||
<dd className="govuk-summary-list__key govuk-!-font-size-16">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => sortDataBy("_customerid_value")}
|
||||
className={
|
||||
orderByState == "_customerid_value"
|
||||
? 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("search:searchresults-applicant-label")}
|
||||
</button>
|
||||
</dd>
|
||||
<dd className="govuk-summary-list__key govuk-!-font-size-16">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() =>
|
||||
sortDataBy("_pinswg_associatedlpa_value")
|
||||
}
|
||||
className={
|
||||
orderByState ==
|
||||
"_pinswg_associatedlpa_value"
|
||||
? 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("search:searchresults-authority-label")}
|
||||
</button>
|
||||
</dd>
|
||||
<dd className="govuk-summary-list__key govuk-!-font-size-16">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() =>
|
||||
sortDataBy("pinswg_appealcasetype")
|
||||
}
|
||||
className={
|
||||
orderByState == "pinswg_appealcasetype"
|
||||
? 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("search:searchresults-case-type-label")}
|
||||
</button>
|
||||
</dd>
|
||||
<dd className="govuk-summary-list__key govuk-!-font-size-16">
|
||||
{/* {t("search:searchresults-status-label")} */}
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => sortDataBy("statuscode")}
|
||||
className={
|
||||
orderByState == "statuscode"
|
||||
? 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("search:searchresults-status-label")}
|
||||
</button>
|
||||
</dd>
|
||||
|
||||
<dd className="govuk-summary-list__key govuk-!-font-size-16 govuk-summary-list__action">
|
||||
Origin
|
||||
</dd>
|
||||
</div>
|
||||
{showSpinnerState == true ? (
|
||||
<div className="govuk-summary-list__row">
|
||||
<div className="govuk-!-margin-top-9 govuk-!-margin-bottom-9 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>
|
||||
) : (
|
||||
resultsArr.map((item, key) => {
|
||||
let detailsObj = jsonpath({
|
||||
path:
|
||||
'$..[?(@ && @.ticketnumber=="' +
|
||||
item.ticketnumber +
|
||||
'")]',
|
||||
json: searchDetailsObj,
|
||||
eval: true
|
||||
});
|
||||
|
||||
detailsObj = detailsObj[0] || {};
|
||||
return (
|
||||
<div
|
||||
className="govuk-summary-list__row"
|
||||
key={key}
|
||||
>
|
||||
<dd className="govuk-summary-list__value govuk-!-font-size-16 ">
|
||||
<div></div>
|
||||
{item.pinswg_publishtoweb == true ? (
|
||||
<Link
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
href={
|
||||
(router.locale == "cy"
|
||||
? myportal == true
|
||||
? "/fymhorth/achos"
|
||||
: "/achos"
|
||||
: myportal == true
|
||||
? "/myportal/case"
|
||||
: "/case") +
|
||||
"/" +
|
||||
item.ticketnumber
|
||||
}
|
||||
className="govuk-link--no-underline"
|
||||
onClick={() => {
|
||||
setCurrentReference({
|
||||
"statuscode":
|
||||
item.statuscode,
|
||||
"ticketnumber":
|
||||
item.ticketnumber,
|
||||
"currentReference":
|
||||
item.title,
|
||||
"currentType":
|
||||
"searchResultsObj",
|
||||
"incidentid":
|
||||
item.incidentid,
|
||||
"appealType":
|
||||
item.pinswg_appealcasetype,
|
||||
"showLoginCheck":
|
||||
props.showLoginCheck,
|
||||
"specialistProcess":
|
||||
detailsObj.hasOwnProperty(
|
||||
"pinswg_speacialistcaseprocess"
|
||||
)
|
||||
? detailsObj.pinswg_speacialistcaseprocess
|
||||
: detailsObj.hasOwnProperty(
|
||||
"pinswg_specialistcaseprocess"
|
||||
)
|
||||
? detailsObj.pinswg_specialistcaseprocess
|
||||
: ""
|
||||
});
|
||||
}}
|
||||
>
|
||||
<span className="results-visually-hidden">
|
||||
{t(
|
||||
"search:searchresults-case-reference-label"
|
||||
)}
|
||||
:
|
||||
</span>
|
||||
{item.title}
|
||||
</Link>
|
||||
) : (
|
||||
item.title
|
||||
)}
|
||||
|
||||
<br />
|
||||
{new Date(
|
||||
item.createdon
|
||||
).toLocaleString()}
|
||||
</dd>
|
||||
<dd className="govuk-summary-list__value govuk-!-font-size-16">
|
||||
<span className="results-visually-hidden">
|
||||
{t(
|
||||
"search:searchresults-site-address-label"
|
||||
)}
|
||||
:
|
||||
</span>
|
||||
{_.has(
|
||||
detailsObj,
|
||||
"pinswg_projectlocation"
|
||||
)
|
||||
? detailsObj.pinswg_projectlocation !=
|
||||
null
|
||||
? detailsObj.pinswg_projectlocation.indexOf(
|
||||
";"
|
||||
) < 0
|
||||
? detailsObj.pinswg_projectlocation
|
||||
: router.locale == "cy"
|
||||
? detailsObj.pinswg_projectlocation.split(
|
||||
";"
|
||||
)[1]
|
||||
: detailsObj.pinswg_projectlocation.split(
|
||||
";"
|
||||
)[0]
|
||||
: ""
|
||||
: ""}
|
||||
{_.has(
|
||||
detailsObj,
|
||||
"pinswg_siteaddressline1"
|
||||
)
|
||||
? detailsObj.pinswg_siteaddressline1
|
||||
: ""}
|
||||
|
||||
{/* {detailsObj.pinswg_siteaddressline1 !=
|
||||
null && <br />} */}
|
||||
|
||||
{_.has(
|
||||
detailsObj,
|
||||
"pinswg_siteaddressline1"
|
||||
) &&
|
||||
detailsObj.pinswg_siteaddressline1 !=
|
||||
null && <br />}
|
||||
|
||||
{_.has(
|
||||
detailsObj,
|
||||
"pinswg_siteaddressline1"
|
||||
)
|
||||
? detailsObj.pinswg_siteaddressline2
|
||||
: ""}
|
||||
|
||||
{_.has(
|
||||
detailsObj,
|
||||
"pinswg_siteaddressline2"
|
||||
) &&
|
||||
detailsObj.pinswg_siteaddressline2 !=
|
||||
null && <br />}
|
||||
{_.has(
|
||||
detailsObj,
|
||||
"pinswg_siteaddresstown"
|
||||
)
|
||||
? detailsObj.pinswg_siteaddresstown
|
||||
: ""}
|
||||
{_.has(
|
||||
detailsObj,
|
||||
"pinswg_siteaddresstown"
|
||||
) &&
|
||||
detailsObj.pinswg_siteaddresstown !=
|
||||
null && <br />}
|
||||
|
||||
{_.has(
|
||||
detailsObj,
|
||||
"pinswg_siteaddresscounty"
|
||||
)
|
||||
? detailsObj.pinswg_siteaddresscounty
|
||||
: ""}
|
||||
{_.has(
|
||||
detailsObj,
|
||||
"pinswg_siteaddresscounty"
|
||||
) &&
|
||||
detailsObj.pinswg_siteaddresscounty !=
|
||||
null && <br />}
|
||||
{_.has(
|
||||
detailsObj,
|
||||
"pinswg_siteaddresspostcode"
|
||||
)
|
||||
? detailsObj.pinswg_siteaddresspostcode
|
||||
: ""}
|
||||
</dd>
|
||||
<dd className="govuk-summary-list__value govuk-!-font-size-16">
|
||||
<span className="results-visually-hidden">
|
||||
{t(
|
||||
"search:searchresults-applicant-label"
|
||||
)}
|
||||
:
|
||||
</span>
|
||||
{item.pinswg_appellantagent == 846040001
|
||||
? item.pinswg_appellantfirstname +
|
||||
" " +
|
||||
item.pinswg_appellantlastname
|
||||
: _.has(detailsObj, [
|
||||
"_pinswg_appellant_value@OData.Community.Display.V1.FormattedValue"
|
||||
])
|
||||
? detailsObj[
|
||||
"_pinswg_appellant_value@OData.Community.Display.V1.FormattedValue"
|
||||
]
|
||||
: ""}
|
||||
</dd>
|
||||
<dd className="govuk-summary-list__value govuk-!-font-size-16">
|
||||
<span className="results-visually-hidden">
|
||||
{t(
|
||||
"search:searchresults-authority-label"
|
||||
)}
|
||||
:
|
||||
</span>
|
||||
{_.has(item, [
|
||||
"_pinswg_associatedlpa_value@OData.Community.Display.V1.FormattedValue"
|
||||
])
|
||||
? router.locale == "cy"
|
||||
? jsonpath({
|
||||
path:
|
||||
'$..[?(@ && @.value=="' +
|
||||
item[
|
||||
"_pinswg_associatedlpa_value@OData.Community.Display.V1.FormattedValue"
|
||||
] +
|
||||
'")].value_cy',
|
||||
json: transLookup,
|
||||
eval: true
|
||||
})
|
||||
: item[
|
||||
"_pinswg_associatedlpa_value@OData.Community.Display.V1.FormattedValue"
|
||||
] || "N/A"
|
||||
: ""}
|
||||
</dd>
|
||||
<dd className="govuk-summary-list__value govuk-!-font-size-16">
|
||||
<span className="results-visually-hidden">
|
||||
{t(
|
||||
"search:searchresults-case-type-label"
|
||||
)}
|
||||
:
|
||||
</span>
|
||||
{router.locale == "cy"
|
||||
? jsonpath({
|
||||
path:
|
||||
'$..[?(@ && @.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"}
|
||||
</dd>
|
||||
<dd className="govuk-summary-list__value govuk-!-font-size-16">
|
||||
<span className="results-visually-hidden">
|
||||
{t(
|
||||
"search:searchresults-status-label"
|
||||
)}
|
||||
:
|
||||
</span>
|
||||
|
||||
{router.locale == "cy"
|
||||
? jsonpath({
|
||||
path:
|
||||
'$..[?(@ && @.value=="' +
|
||||
item[
|
||||
"statuscode@OData.Community.Display.V1.FormattedValue"
|
||||
] +
|
||||
'")].value_cy',
|
||||
json: transLookup,
|
||||
eval: true
|
||||
})
|
||||
: item[
|
||||
"statuscode@OData.Community.Display.V1.FormattedValue"
|
||||
] || "N/A"}
|
||||
</dd>
|
||||
<dd className="govuk-summary-list__value govuk-!-font-size-16">
|
||||
{item[
|
||||
"caseorigincode@OData.Community.Display.V1.FormattedValue"
|
||||
] || "N/A"}
|
||||
</dd>
|
||||
</div>
|
||||
);
|
||||
})
|
||||
)}
|
||||
</dl>
|
||||
<PaginationControl
|
||||
showNoOfRecords={selectedOption}
|
||||
currentPage={currentPage}
|
||||
searchResultsObj={props.searchResultsObj.searchResultsObj}
|
||||
orderBy={orderByState}
|
||||
fieldSort={fieldSortState}
|
||||
spinnerState={spinnerState}
|
||||
getSearchPageResults={getSearchPageResults}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
<h1>Appeals</h1>
|
||||
{searchResultsObj["@odata.count"] > 5 && (
|
||||
<div id="recordCountSelect" className="">
|
||||
<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);
|
||||
props.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>
|
||||
)}
|
||||
{resultsArr.length > 0 ? (
|
||||
ResultsView(resultsArr)
|
||||
) : (
|
||||
<div className="govuk-grid-row">
|
||||
<div className="govuk-grid-column-two-thirds">
|
||||
<h3>{t("search:searchresults-no-records-label")}</h3>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
const mapDispatchToProps = (dispatch) => {
|
||||
return {
|
||||
setCurrentReference: (currentReference) => {
|
||||
dispatch(setCurrentReference(currentReference));
|
||||
},
|
||||
setSearchResults: (searchResultsObj) => {
|
||||
dispatch(setSearchResults(searchResultsObj));
|
||||
},
|
||||
setSearchDetails: (searchDetailsObj) => {
|
||||
dispatch(setSearchDetails(searchDetailsObj));
|
||||
},
|
||||
setCurrentPage: (currentPage) => {
|
||||
dispatch(setCurrentPage(currentPage));
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
const mapStateToProps = (state) => {
|
||||
return {
|
||||
searchResultsObj: state.searchResultsObj
|
||||
};
|
||||
};
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(AppealsTab);
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,266 @@
|
||||
// components/admin/tabs/StorageTab.js
|
||||
import { useState } from "react";
|
||||
import Link from "next/link";
|
||||
import { bytesToSize } from "../../../components/utils";
|
||||
import {
|
||||
deleteMyRepresentationsFromBlob,
|
||||
deleteAwaitingSubmissionsFromBlob
|
||||
} from "../../../actions/services/documentService";
|
||||
import { sendRepCompleteMessage } from "../../../actions/services/portalService";
|
||||
|
||||
import { formatBlobDates } from "../utils/adminHelper";
|
||||
|
||||
export default function StorageTab({ data, repCompleteCount }) {
|
||||
const [showRepJson, setShowRepJson] = useState(true);
|
||||
const [showTmpFile, setShowTmpFile] = useState(true);
|
||||
const [listData, setListData] = useState(data);
|
||||
|
||||
const toggleAll = () => {
|
||||
const newState = !(showRepJson || showTmpFile);
|
||||
setShowRepJson(newState);
|
||||
setShowTmpFile(newState);
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
<h1>Storage Account Contents</h1>
|
||||
{repCompleteCount > 0 && (
|
||||
<p>Number of Orphaned Reps: {repCompleteCount}</p>
|
||||
)}
|
||||
|
||||
{/* Toggle buttons */}
|
||||
<div style={{ marginBottom: "0.2rem" }}>
|
||||
<button
|
||||
className="govuk-button govuk-button--secondary"
|
||||
onClick={() => setShowRepJson(!showRepJson)}
|
||||
>
|
||||
{showRepJson ? "Hide Reps" : "Show Reps"}
|
||||
</button>
|
||||
<button
|
||||
className="govuk-button govuk-button--secondary"
|
||||
onClick={() => setShowTmpFile(!showTmpFile)}
|
||||
style={{ marginLeft: "0.5rem" }}
|
||||
>
|
||||
{showTmpFile ? "Hide Temp Appeal" : "Show Temp Appeal"}
|
||||
</button>
|
||||
<button
|
||||
className="govuk-button govuk-button--secondary"
|
||||
onClick={toggleAll}
|
||||
style={{ marginLeft: "0.5rem" }}
|
||||
>
|
||||
Show/Hide All
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Render users & containers */}
|
||||
{listData.map((user) => (
|
||||
<div key={user.id} className="govuk-grid-row">
|
||||
{user.containers.map((c) => (
|
||||
<div key={c.container} className="card">
|
||||
<div className="card-body">
|
||||
<h3>
|
||||
{c.container} -{" "}
|
||||
<Link
|
||||
href={`/auth/signin2?email=${user.email}`}
|
||||
>
|
||||
{user.email}
|
||||
</Link>
|
||||
</h3>
|
||||
{/* folders */}
|
||||
{c.folders.map((folder) => (
|
||||
<div
|
||||
key={folder.folderPath}
|
||||
style={
|
||||
showRepJson && folder.hasRepJson
|
||||
? { display: "block" }
|
||||
: showTmpFile &&
|
||||
folder.hasTmpFile
|
||||
? { display: "block" }
|
||||
: { display: "none" }
|
||||
}
|
||||
>
|
||||
<h4>{folder.folderPath || "Root"}</h4>
|
||||
|
||||
{/* Buttons for TMP + Rep actions go here (same logic as before) */}
|
||||
|
||||
{folder.hasTmpFile && (
|
||||
<>
|
||||
<button
|
||||
onClick={() => {
|
||||
confirm(
|
||||
"Do you want to remove this unsubmitted appeal " +
|
||||
folder.folderPath +
|
||||
"?\n"
|
||||
) &&
|
||||
(deleteCaseItem(
|
||||
c.container,
|
||||
folder.folderPath,
|
||||
setData
|
||||
),
|
||||
alert(
|
||||
"Temp case Deleted!"
|
||||
));
|
||||
}}
|
||||
>
|
||||
Delete this TMP appeal
|
||||
</button>
|
||||
</>
|
||||
)}
|
||||
{folder.hasRepJson && (
|
||||
<div>
|
||||
{" "}
|
||||
<button
|
||||
title={
|
||||
"Do you want to delete rep"
|
||||
}
|
||||
className=" cardModuleRemoveCase govuk-link govuk-link--no-underline govuk-link--inverse "
|
||||
onClick={() => {
|
||||
confirm(
|
||||
"Do you want tyo delete rep " +
|
||||
folder.repJsonBlob.name.split(
|
||||
"/"
|
||||
)[0] +
|
||||
"?\n"
|
||||
) &&
|
||||
(deleteRepItem(
|
||||
c.container,
|
||||
folder.repJsonBlob.name.split(
|
||||
"/"
|
||||
)[0],
|
||||
folder.repJsonBlob.name.split(
|
||||
"/"
|
||||
)[1]
|
||||
),
|
||||
alert(
|
||||
"Rep Deleted!"
|
||||
),
|
||||
window.location.reload());
|
||||
}}
|
||||
>
|
||||
Delete Rep
|
||||
</button>
|
||||
{folder.repComplete && (
|
||||
<button
|
||||
onClick={async () => {
|
||||
const response =
|
||||
await fetch(
|
||||
"/api/file/editRepJson",
|
||||
{
|
||||
method: "POST",
|
||||
headers:
|
||||
{
|
||||
"Content-Type":
|
||||
"application/json"
|
||||
},
|
||||
body: JSON.stringify(
|
||||
{
|
||||
container:
|
||||
c.container,
|
||||
blobName:
|
||||
folder
|
||||
.repJsonBlob
|
||||
.name
|
||||
}
|
||||
)
|
||||
}
|
||||
);
|
||||
const result =
|
||||
await response.json();
|
||||
if (response.ok) {
|
||||
(alert(
|
||||
"repComplete removed!"
|
||||
),
|
||||
window.location.reload());
|
||||
// Optionally refresh the page or update UI state here
|
||||
} else {
|
||||
alert(
|
||||
"Error: " +
|
||||
result.error
|
||||
);
|
||||
}
|
||||
}}
|
||||
>
|
||||
Remove repComplete
|
||||
</button>
|
||||
)}
|
||||
{folder.repComplete && (
|
||||
<button
|
||||
onClick={async () => {
|
||||
confirm(
|
||||
"Do you want resend the rep queue message " +
|
||||
folder.repJsonBlob.name.split(
|
||||
"/"
|
||||
)[0] +
|
||||
" --- " +
|
||||
folder.repJsonBlob.name.split(
|
||||
"/"
|
||||
)[1]
|
||||
) &&
|
||||
(sendRepCompleteMessage(
|
||||
c.container,
|
||||
folder.repJsonBlob.name.split(
|
||||
"/"
|
||||
)[0],
|
||||
folder.repJsonBlob.name.split(
|
||||
"/"
|
||||
)[1]
|
||||
),
|
||||
alert(
|
||||
"rep queue message sent!"
|
||||
),
|
||||
window.location.reload());
|
||||
}}
|
||||
>
|
||||
Recreate Queue Message
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
<ul>
|
||||
{folder.blobs.map((blob) => (
|
||||
<li key={blob.name}>
|
||||
<Link
|
||||
scroll={false}
|
||||
href={`/api/file/downloadblob?container=${
|
||||
c.container
|
||||
}&casefolderID=${
|
||||
folder.folderPath
|
||||
}&blobname=${blob.name.substring(
|
||||
blob.name.lastIndexOf(
|
||||
"/"
|
||||
) + 1
|
||||
)}&hash=${
|
||||
blob.hashedfilepath
|
||||
}`}
|
||||
className="govuk-body govuk-!-font-size-14 govuk-link"
|
||||
>
|
||||
{blob.name} (
|
||||
{bytesToSize(
|
||||
blob.contentLength ||
|
||||
blob.size
|
||||
)}
|
||||
)
|
||||
</Link>{" "}
|
||||
{blob.lastModified && (
|
||||
<span className="govuk-!-font-size-14">
|
||||
{/* {
|
||||
blob.displayDate
|
||||
} */}
|
||||
{formatBlobDates(
|
||||
blob
|
||||
)}
|
||||
</span>
|
||||
)}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
// components/admin/utils/adminStorage.js
|
||||
|
||||
/**
|
||||
* Get the folder path up to the last slash.
|
||||
* Used for grouping blobs by "case folder".
|
||||
*/
|
||||
export function getUpToLastSlash(url) {
|
||||
let lastSlash = url.lastIndexOf("/");
|
||||
|
||||
url = url.substring(0, lastSlash);
|
||||
|
||||
url =
|
||||
url.lastIndexOf("/files") > 0
|
||||
? url.substring(0, url.lastIndexOf("/files"))
|
||||
: url;
|
||||
return url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a stream (Azure blob download) to a string.
|
||||
*/
|
||||
export async function streamToString(readableStream) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const chunks = [];
|
||||
readableStream.on("data", (data) => {
|
||||
chunks.push(data.toString());
|
||||
});
|
||||
readableStream.on("end", () => {
|
||||
resolve(chunks.join(""));
|
||||
});
|
||||
readableStream.on("error", reject);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Format how long ago a date occurred.
|
||||
*/
|
||||
export function formatTimeSince(date) {
|
||||
if (!date) return "Unknown date";
|
||||
|
||||
const now = new Date();
|
||||
const diffMs = now - date;
|
||||
const diffDays = Math.floor(diffMs / (1000 * 60 * 60 * 24));
|
||||
|
||||
if (diffDays < 7) {
|
||||
return `${diffDays} day${diffDays !== 1 ? "s" : ""} ago`;
|
||||
} else {
|
||||
const diffWeeks = Math.floor(diffDays / 7);
|
||||
return `${diffWeeks} week${diffWeeks !== 1 ? "s" : ""} ago`;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Format Azure blob created/modified dates into a readable string.
|
||||
*/
|
||||
export function formatBlobDates(blob) {
|
||||
const created = blob.createdOn ? new Date(blob.createdOn) : null;
|
||||
const modified = blob.lastModified ? new Date(blob.lastModified) : null;
|
||||
|
||||
if (!created && !modified) return "Unknown";
|
||||
|
||||
// If both exist and are the same
|
||||
if (created && modified && created.getTime() === modified.getTime()) {
|
||||
return `${created.toLocaleString("en-GB")} (${formatTimeSince(
|
||||
created
|
||||
)})`;
|
||||
}
|
||||
|
||||
// If modified exists and is newer than created
|
||||
if (created && modified && modified.getTime() > created.getTime()) {
|
||||
return `Created: ${created.toLocaleString("en-GB")} (${formatTimeSince(
|
||||
created
|
||||
)}), Modified: ${modified.toLocaleString("en-GB")} (${formatTimeSince(
|
||||
modified
|
||||
)})`;
|
||||
}
|
||||
|
||||
// Only one date exists
|
||||
const date = modified || created;
|
||||
return `${date.toLocaleString("en-GB")} (${formatTimeSince(date)})`;
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
// lib/prisma.js
|
||||
import { PrismaClient } from "@prisma/client";
|
||||
|
||||
const globalForPrisma = globalThis;
|
||||
|
||||
export const prisma =
|
||||
globalForPrisma.prisma ||
|
||||
new PrismaClient({
|
||||
log: ["query", "error", "warn"],
|
||||
});
|
||||
|
||||
if (process.env.NODE_ENV !== "production") {
|
||||
globalForPrisma.prisma = prisma;
|
||||
}
|
||||
@@ -0,0 +1,174 @@
|
||||
// components/admin/utils/serverStorage.js
|
||||
import { DefaultAzureCredential } from "@azure/identity";
|
||||
import { BlobServiceClient } from "@azure/storage-blob";
|
||||
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.
|
||||
*/
|
||||
function hashAPIPath(queryPath, WORDKEY) {
|
||||
let hashlink = CryptoJS.HmacSHA256(
|
||||
queryPath,
|
||||
CryptoJS.enc.Hex.parse(WORDKEY)
|
||||
);
|
||||
return hashlink.toString(CryptoJS.enc.Hex);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch blob structure + users for admin storage page.
|
||||
*/
|
||||
export async function fetchAdminStorageData() {
|
||||
const accountName = process.env.AZURE_STORAGE_ACCOUNT_NAME;
|
||||
const creds = new DefaultAzureCredential();
|
||||
const blobServiceClient = new BlobServiceClient(
|
||||
`https://${accountName}.blob.core.windows.net`,
|
||||
creds
|
||||
);
|
||||
|
||||
const prisma = global.prisma || new PrismaClient();
|
||||
|
||||
const users = await prisma.user.findMany();
|
||||
|
||||
const limit = pLimit(5);
|
||||
let data = await Promise.all(
|
||||
users.map(async (user) => {
|
||||
limit(async () => {
|
||||
const containers = await listContainersForUser(
|
||||
blobServiceClient,
|
||||
`${user.id}`,
|
||||
user.email
|
||||
);
|
||||
|
||||
const containersWithHashes = await Promise.all(
|
||||
containers.map(async (container) => {
|
||||
const groupedByFolder = await container.blobs.reduce(
|
||||
async (accP, blob) => {
|
||||
const acc = await accP;
|
||||
const folderPath =
|
||||
getUpToLastSlash(blob.name.trim()) || "";
|
||||
|
||||
const hashedfilepath = hashAPIPath(
|
||||
`/api/file/downloadblob?container=${
|
||||
container.container
|
||||
}&casefolderID=${folderPath}&blobname=${blob.name
|
||||
.substring(
|
||||
blob.name.lastIndexOf("/") + 1
|
||||
)
|
||||
.trim()}`,
|
||||
process.env.HASHKEY
|
||||
);
|
||||
|
||||
const fileNameOnly = blob.name.substring(
|
||||
blob.name.lastIndexOf("/") + 1
|
||||
);
|
||||
const isTmpFile =
|
||||
fileNameOnly.startsWith("TMP-");
|
||||
|
||||
const blobWithHash = {
|
||||
...blob,
|
||||
hashedfilepath,
|
||||
isTmpFile
|
||||
};
|
||||
|
||||
let folderGroup = acc.find(
|
||||
(f) => f.folderPath === folderPath
|
||||
);
|
||||
if (!folderGroup) {
|
||||
folderGroup = {
|
||||
folderPath,
|
||||
blobs: [],
|
||||
hasRepJson: false,
|
||||
repJsonBlob: null,
|
||||
repComplete: false,
|
||||
hasTmpFile: false
|
||||
};
|
||||
acc.push(folderGroup);
|
||||
}
|
||||
|
||||
folderGroup.blobs.push(blobWithHash);
|
||||
|
||||
if (isTmpFile) {
|
||||
folderGroup.hasTmpFile = true;
|
||||
}
|
||||
|
||||
// rep.json handling
|
||||
if (
|
||||
blob.name.toLowerCase().endsWith("rep.json")
|
||||
) {
|
||||
folderGroup.hasRepJson = true;
|
||||
folderGroup.repJsonBlob = blobWithHash;
|
||||
|
||||
const containerClient =
|
||||
blobServiceClient.getContainerClient(
|
||||
container.container
|
||||
);
|
||||
const blockBlobClient =
|
||||
containerClient.getBlockBlobClient(
|
||||
blob.name
|
||||
);
|
||||
|
||||
try {
|
||||
const downloadResponse =
|
||||
await blockBlobClient.download(0);
|
||||
const downloaded = await streamToString(
|
||||
downloadResponse.readableStreamBody
|
||||
);
|
||||
const json = JSON.parse(downloaded);
|
||||
folderGroup.repComplete = Boolean(
|
||||
json.repComplete
|
||||
);
|
||||
} catch (err) {
|
||||
console.error(
|
||||
"Error reading rep.json",
|
||||
err
|
||||
);
|
||||
folderGroup.repComplete = false;
|
||||
}
|
||||
}
|
||||
|
||||
return acc;
|
||||
},
|
||||
Promise.resolve([])
|
||||
);
|
||||
|
||||
return { ...container, folders: groupedByFolder };
|
||||
})
|
||||
);
|
||||
|
||||
return containersWithHashes.length > 0
|
||||
? {
|
||||
id: user.id,
|
||||
email: user.email,
|
||||
containers: containersWithHashes
|
||||
}
|
||||
: null;
|
||||
});
|
||||
})
|
||||
);
|
||||
|
||||
data = data.filter(Boolean);
|
||||
|
||||
let userData = users
|
||||
.filter((user) => user.email && user.email.trim() !== "")
|
||||
.map((user) => ({
|
||||
id: user.id,
|
||||
email: user.email,
|
||||
created: user.emailVerified?.toLocaleString("en-GB") || ""
|
||||
}));
|
||||
|
||||
let repCompleteCount = 0;
|
||||
data.forEach((user) => {
|
||||
user.containers.forEach((container) => {
|
||||
container.folders.forEach((folder) => {
|
||||
if (folder.repComplete === true) repCompleteCount++;
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
return { data, userData, repCompleteCount };
|
||||
}
|
||||
+276
-1156
File diff suppressed because it is too large
Load Diff
@@ -27,6 +27,7 @@ const Case = (props) => {
|
||||
watchedCasesDetails={props.watchedCasesDetails}
|
||||
awaitingSubmission={props.awaitingSubmission}
|
||||
caseReference={props.caseReference}
|
||||
ticketnumber={props.ticketnumber}
|
||||
currentType={props.currentType}
|
||||
appealTypeID={props.appealTypeID}
|
||||
searchResultsObj={props.searchResultsObj}
|
||||
@@ -40,7 +41,9 @@ const Case = (props) => {
|
||||
docsOffline={props.props.docsOffline}
|
||||
documentDetailsObj={props.documentDetailsObj}
|
||||
showFilteredDocs={props.showFilteredDocs}
|
||||
showLoginCheck={props.showLoginCheck}
|
||||
eventsObj={props.eventsObj}
|
||||
mediaObj={props.mediaObj}
|
||||
/>
|
||||
{showRepresentations == true && (
|
||||
<RepresentationList
|
||||
|
||||
+101
-139
@@ -5,21 +5,23 @@ 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 } 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";
|
||||
|
||||
const DocumentDetails = (props) => {
|
||||
let { t } = useTranslation();
|
||||
let { t, lang } = useTranslation();
|
||||
const firstRender = useRef(false);
|
||||
const {
|
||||
incidentid,
|
||||
@@ -30,14 +32,14 @@ const DocumentDetails = (props) => {
|
||||
setDocumentDetails,
|
||||
setCurrentPage,
|
||||
docsOffline,
|
||||
showFilteredDocs,
|
||||
showFilteredDocs
|
||||
} = props;
|
||||
|
||||
const router = useRouter();
|
||||
const { locale } = router;
|
||||
|
||||
var documentDetailsArr = documentDetailsObj || [];
|
||||
|
||||
const { startDownload, getStatus } = useDownloadQueue(3);
|
||||
const [selectedOption, setSelectedOption] = useState(10);
|
||||
const [documentTypes, setDocumentTypes] = useState([{}]);
|
||||
const [selectedDocumentType, setSelectedDocumentType] = useState("all");
|
||||
@@ -55,7 +57,7 @@ const DocumentDetails = (props) => {
|
||||
|
||||
setCheckedItems((prev) => ({
|
||||
...prev,
|
||||
[name]: checked,
|
||||
[name]: checked
|
||||
}));
|
||||
setSelectAll(false);
|
||||
};
|
||||
@@ -88,37 +90,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);
|
||||
let ShowDocLinks = getDocLink(docsOffline);
|
||||
|
||||
const DocumentView = (documentDetailsArr) => {
|
||||
documentDetailsArr = documentDetailsArr.value;
|
||||
@@ -160,7 +132,7 @@ const DocumentDetails = (props) => {
|
||||
? jsonpath({
|
||||
path: '$..[?(@ && @.value=="All")].value_cy',
|
||||
json: transLookup,
|
||||
eval: true,
|
||||
eval: true
|
||||
})
|
||||
: "All"}
|
||||
</option>
|
||||
@@ -179,7 +151,7 @@ const DocumentDetails = (props) => {
|
||||
item.pinswg_isharedocumentlocationsLabel +
|
||||
'")].value_cy',
|
||||
json: transLookup,
|
||||
eval: true,
|
||||
eval: true
|
||||
})
|
||||
: item.pinswg_isharedocumentlocationsLabel ||
|
||||
t(
|
||||
@@ -287,12 +259,9 @@ const DocumentDetails = (props) => {
|
||||
{/* {t("case:documents-date-published-label")} */}
|
||||
<button
|
||||
type="button"
|
||||
onClick={() =>
|
||||
sortDataBy("pinswg_documentpublisheddate")
|
||||
}
|
||||
onClick={() => sortDataBy("createdon")}
|
||||
className={
|
||||
orderByState ==
|
||||
"pinswg_documentpublisheddate"
|
||||
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`
|
||||
@@ -329,7 +298,7 @@ const DocumentDetails = (props) => {
|
||||
incidentid +
|
||||
"')]",
|
||||
json: item,
|
||||
sanbox: {},
|
||||
sanbox: {}
|
||||
});
|
||||
detailsObj = item;
|
||||
return (
|
||||
@@ -361,7 +330,7 @@ const DocumentDetails = (props) => {
|
||||
}
|
||||
key={key}
|
||||
onClick={() => {
|
||||
toggleDownLoadLink(key),
|
||||
(toggleDownLoadLink(key),
|
||||
sendGAEvent(
|
||||
"event",
|
||||
"DownloadedFile",
|
||||
@@ -369,9 +338,9 @@ const DocumentDetails = (props) => {
|
||||
caseReference:
|
||||
props.caseReference,
|
||||
filename:
|
||||
detailsObj.pinswg_name,
|
||||
detailsObj.pinswg_name
|
||||
}
|
||||
);
|
||||
));
|
||||
}}
|
||||
>
|
||||
<span className="results-visually-hidden">
|
||||
@@ -419,7 +388,7 @@ const DocumentDetails = (props) => {
|
||||
] +
|
||||
'")].value_cy',
|
||||
json: transLookup,
|
||||
sanbox: {},
|
||||
eval: true
|
||||
})
|
||||
: detailsObj[
|
||||
"pinswg_isharedocumentlocations@OData.Community.Display.V1.FormattedValue"
|
||||
@@ -507,7 +476,7 @@ const DocumentDetails = (props) => {
|
||||
</p>
|
||||
<div>
|
||||
<button onClick={clearCheckboxes}>
|
||||
{t("case:documents-clear-filter-label")}
|
||||
{t("search:clear-filter-button-label")}
|
||||
</button>
|
||||
</div>
|
||||
<div className="govuk-checkboxes govuk-checkboxes--small">
|
||||
@@ -584,8 +553,8 @@ const DocumentDetails = (props) => {
|
||||
'$..[?(@ && @.value=="' +
|
||||
item.pinswg_isharedocumentlocationsLabel +
|
||||
'")].value_cy',
|
||||
jsonL: transLookup,
|
||||
sanbox: {},
|
||||
json: transLookup,
|
||||
eval: true
|
||||
})
|
||||
: item.pinswg_isharedocumentlocationsLabel ||
|
||||
t(
|
||||
@@ -605,13 +574,13 @@ const DocumentDetails = (props) => {
|
||||
const data = [
|
||||
...document.querySelectorAll(
|
||||
".govuk-checkboxes__input:checked"
|
||||
),
|
||||
)
|
||||
].map((e) => e.value);
|
||||
setSelectedDocumentType(data);
|
||||
setCurrentPage(1);
|
||||
}}
|
||||
>
|
||||
{t("case:documents-filter-button")}
|
||||
{t("search:filter-documents-label")}
|
||||
</button>
|
||||
</div>
|
||||
{documentDetailsObj["@odata.count"] > 5 && (
|
||||
@@ -700,14 +669,9 @@ const DocumentDetails = (props) => {
|
||||
{/* {t("case:documents-date-published-label")} */}
|
||||
<button
|
||||
type="button"
|
||||
onClick={() =>
|
||||
sortDataBy(
|
||||
"pinswg_documentpublisheddate"
|
||||
)
|
||||
}
|
||||
onClick={() => sortDataBy("createdon")}
|
||||
className={
|
||||
orderByState ==
|
||||
"pinswg_documentpublisheddate"
|
||||
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`
|
||||
@@ -746,7 +710,7 @@ const DocumentDetails = (props) => {
|
||||
incidentid +
|
||||
"')]",
|
||||
json: item,
|
||||
eval: true,
|
||||
eval: true
|
||||
});
|
||||
detailsObj = item;
|
||||
return (
|
||||
@@ -772,41 +736,63 @@ const DocumentDetails = (props) => {
|
||||
)}
|
||||
|
||||
{!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>
|
||||
<>
|
||||
<DocumentLink
|
||||
key={
|
||||
detailsObj.pinswg_documentid
|
||||
}
|
||||
id={
|
||||
detailsObj.pinswg_documentid
|
||||
}
|
||||
detailsObj={
|
||||
detailsObj
|
||||
}
|
||||
caseReference={
|
||||
caseReference
|
||||
}
|
||||
startDownload={
|
||||
startDownload
|
||||
}
|
||||
getStatus={
|
||||
getStatus
|
||||
}
|
||||
/>
|
||||
{/* <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">
|
||||
@@ -841,7 +827,7 @@ const DocumentDetails = (props) => {
|
||||
] +
|
||||
'")].value_cy',
|
||||
json: transLookup,
|
||||
eval: true,
|
||||
eval: true
|
||||
})
|
||||
: detailsObj[
|
||||
"pinswg_isharedocumentlocations@OData.Community.Display.V1.FormattedValue"
|
||||
@@ -858,36 +844,14 @@ const DocumentDetails = (props) => {
|
||||
:
|
||||
</span>
|
||||
|
||||
{/* {
|
||||
detailsObj.pinswg_documentpublisheddate
|
||||
}
|
||||
{
|
||||
detailsObj.pinswg_latestpublisheddate
|
||||
} */}
|
||||
|
||||
{detailsObj.pinswg_documentpublisheddate !=
|
||||
null
|
||||
? formatDates(
|
||||
detailsObj.pinswg_documentpublisheddate
|
||||
)
|
||||
: formatDates(
|
||||
detailsObj.pinswg_latestpublisheddate
|
||||
)}
|
||||
{/* {_.has(
|
||||
{_.has(
|
||||
detailsObj,
|
||||
"pinswg_documentpublisheddate"
|
||||
"pinswg_latestpublisheddate"
|
||||
)
|
||||
? formatDates(
|
||||
detailsObj.pinswg_documentpublisheddate
|
||||
)
|
||||
: _.has(
|
||||
detailsObj,
|
||||
"pinswg_latestpublisheddate"
|
||||
)
|
||||
? formatDates(
|
||||
detailsObj.pinswg_latestpublisheddate
|
||||
)
|
||||
: ""} */}
|
||||
: ""}
|
||||
</dd>
|
||||
{/* <dd className="govuk-summary-list__value govuk-!-font-size-16">
|
||||
<span className="results-visually-hidden">
|
||||
@@ -931,9 +895,8 @@ const DocumentDetails = (props) => {
|
||||
selectedOption,
|
||||
selectedDocumentType
|
||||
)
|
||||
// .then((data) => data)
|
||||
.then((data) => data)
|
||||
.then((data) => {
|
||||
setDocumentSearchState(true);
|
||||
setDocumentDetails(data);
|
||||
setShowSpinnerState(false);
|
||||
});
|
||||
@@ -942,7 +905,7 @@ const DocumentDetails = (props) => {
|
||||
props.incidentid,
|
||||
selectedOption,
|
||||
selectedDocumentType,
|
||||
setDocumentDetails,
|
||||
setDocumentDetails
|
||||
]
|
||||
);
|
||||
|
||||
@@ -1003,10 +966,8 @@ const DocumentDetails = (props) => {
|
||||
};
|
||||
|
||||
const [showDocumentSearchState, setDocumentSearchState] = useState(false);
|
||||
const [orderByState, setOrderbyState] = useState(
|
||||
"pinswg_documentpublisheddate"
|
||||
);
|
||||
const [fieldSortState, setfieldSortState] = useState("desc");
|
||||
const [orderByState, setOrderbyState] = useState("createdon");
|
||||
const [fieldSortState, setfieldSortState] = useState("asc");
|
||||
|
||||
let documentSearchState = () => {
|
||||
showDocumentSearchState == true
|
||||
@@ -1016,14 +977,14 @@ const DocumentDetails = (props) => {
|
||||
|
||||
const sortDataBy = (whichField) => {
|
||||
setOrderbyState(whichField);
|
||||
setfieldSortState("desc");
|
||||
setfieldSortState("asc");
|
||||
|
||||
getDocumentResults(1, whichField, fieldSortState);
|
||||
whichField == orderByState
|
||||
? fieldSortState == "asc"
|
||||
? setfieldSortState("desc")
|
||||
: setfieldSortState("asc")
|
||||
: setfieldSortState("desc");
|
||||
? fieldSortState == "desc"
|
||||
? setfieldSortState("asc")
|
||||
: setfieldSortState("desc")
|
||||
: setfieldSortState("asc");
|
||||
setCurrentPage(1);
|
||||
setShowSpinnerState(true);
|
||||
};
|
||||
@@ -1058,7 +1019,7 @@ const DocumentDetails = (props) => {
|
||||
return docObj;
|
||||
};
|
||||
|
||||
//const searchDocumentResultsObj = docDetailsObj();
|
||||
const searchDocumentResultsObj = docDetailsObj();
|
||||
}, [
|
||||
incidentid,
|
||||
setDocumentDetails,
|
||||
@@ -1068,6 +1029,7 @@ const DocumentDetails = (props) => {
|
||||
orderByState,
|
||||
getDocumentTypes,
|
||||
getDocumentResults,
|
||||
lang
|
||||
]);
|
||||
return (
|
||||
<div className="govuk-grid-row">
|
||||
@@ -1097,7 +1059,7 @@ const DocumentDetails = (props) => {
|
||||
|
||||
const mapStateToProps = (state) => {
|
||||
return {
|
||||
...state,
|
||||
...state
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1108,7 +1070,7 @@ const mapDispatchToProps = (dispatch) => {
|
||||
},
|
||||
setCurrentPage: (currentPage) => {
|
||||
dispatch(setCurrentPage(currentPage));
|
||||
},
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
+125
-82
@@ -3,9 +3,16 @@ 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;
|
||||
@@ -23,8 +30,6 @@ const EventsDetails = (props) => {
|
||||
return obj.hasOwnProperty(property) && obj[property] !== null;
|
||||
}
|
||||
|
||||
//console.log(eventsArr.length > 0);
|
||||
|
||||
return (
|
||||
eventsArr.length > 0 && (
|
||||
<div className="govuk-grid-row">
|
||||
@@ -63,76 +68,26 @@ const EventsDetails = (props) => {
|
||||
{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"
|
||||
[
|
||||
"pinswg_typeofevent@OData.Community.Display.V1.FormattedValue"
|
||||
]
|
||||
) && (
|
||||
<div>
|
||||
<b>
|
||||
{t(
|
||||
"case:event-type-of-event-label"
|
||||
)}
|
||||
</b>
|
||||
:{" "}
|
||||
{
|
||||
item.pinswg_eventaddressline2
|
||||
item[
|
||||
"pinswg_typeofevent@OData.Community.Display.V1.FormattedValue"
|
||||
]
|
||||
}
|
||||
</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"
|
||||
@@ -171,25 +126,113 @@ const EventsDetails = (props) => {
|
||||
<div className="eventColumn">
|
||||
{hasOwnPropertyAndNotNull(
|
||||
item,
|
||||
[
|
||||
"pinswg_typeofevent@OData.Community.Display.V1.FormattedValue",
|
||||
]
|
||||
"pinswg_eventaddressline1"
|
||||
) && (
|
||||
<div>
|
||||
<b>
|
||||
{t(
|
||||
"case:event-type-of-event-label"
|
||||
)}
|
||||
</b>
|
||||
:{" "}
|
||||
{
|
||||
item[
|
||||
"pinswg_typeofevent@OData.Community.Display.V1.FormattedValue"
|
||||
]
|
||||
}
|
||||
</div>
|
||||
<>
|
||||
<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>
|
||||
</>
|
||||
)
|
||||
@@ -203,7 +246,7 @@ const EventsDetails = (props) => {
|
||||
|
||||
const mapStateToProps = (state) => {
|
||||
return {
|
||||
...state,
|
||||
...state
|
||||
};
|
||||
};
|
||||
|
||||
@@ -214,7 +257,7 @@ const mapDispatchToProps = (dispatch) => {
|
||||
},
|
||||
setCurrentPage: (currentPage) => {
|
||||
dispatch(setCurrentPage(currentPage));
|
||||
},
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,646 @@
|
||||
// // 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 MediaDetails = (props) => {
|
||||
// // let { t } = useTranslation();
|
||||
|
||||
// // const MediaView = (mediaArr) => {
|
||||
// // mediaArr = mediaArr.value;
|
||||
|
||||
// // return mediaArr.map((item, key) => {
|
||||
// // <div>{item.pinswg_name}</div>;
|
||||
// // });
|
||||
// // };
|
||||
|
||||
// // const mediaArr = props.mediaObj?.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 (
|
||||
// // mediaArr.length > 0 && (
|
||||
// // <div className="govuk-grid-row">
|
||||
// // <div className="card">
|
||||
// // <div className="card-body">
|
||||
// // <h2 className="govuk-heading-m ">
|
||||
// // {t("case:event-title")}Media
|
||||
// // </h2>
|
||||
// // {mediaArr.map(
|
||||
// // (item, key) =>
|
||||
// // item.pinswg_publishtoweb && (
|
||||
// // <>
|
||||
// // {" "}
|
||||
// // <div className="">
|
||||
// // <div className="">
|
||||
// // <div>
|
||||
// // <b>
|
||||
// // {" "}
|
||||
// // {t(
|
||||
// // "case:event-name-label",
|
||||
// // )}
|
||||
// // </b>
|
||||
// // : {item.pinswg_name}
|
||||
// // </div>
|
||||
// // {hasOwnPropertyAndNotNull(
|
||||
// // item,
|
||||
// // "pinswg_description",
|
||||
// // ) && (
|
||||
// // <div>
|
||||
// // <b>
|
||||
// // {t(
|
||||
// // "case:event-event-name-label",
|
||||
// // )}
|
||||
// // </b>
|
||||
// // :{" "}
|
||||
// // {
|
||||
// // item.pinswg_description
|
||||
// // }
|
||||
// // </div>
|
||||
// // )}
|
||||
// // </div>
|
||||
// // </div>
|
||||
// // </>
|
||||
// // ),
|
||||
// // )}{" "}
|
||||
// // </div>
|
||||
// // </div>
|
||||
// // </div>
|
||||
// // )
|
||||
// // );
|
||||
// // };
|
||||
|
||||
// // const mapStateToProps = (state) => {
|
||||
// // return {
|
||||
// // ...state,
|
||||
// // };
|
||||
// // };
|
||||
|
||||
// // const mapDispatchToProps = (dispatch) => {
|
||||
// // return {
|
||||
// // setEventDetails: (mediaObj) => {
|
||||
// // dispatch(setEventDetails(mediaObj));
|
||||
// // },
|
||||
// // setCurrentPage: (currentPage) => {
|
||||
// // dispatch(setCurrentPage(currentPage));
|
||||
// // },
|
||||
// // };
|
||||
// // };
|
||||
|
||||
// // export default connect(mapStateToProps, mapDispatchToProps)(MediaDetails);
|
||||
// import { useEffect, useMemo, useState } from "react";
|
||||
// import { connect } from "react-redux";
|
||||
// import useTranslation from "next-translate/useTranslation";
|
||||
// import { useRouter } from "next/router";
|
||||
|
||||
// const extractYouTubeId = (input) => {
|
||||
// if (!input) return null;
|
||||
// if (/^[a-zA-Z0-9_-]{11}$/.test(input)) return input;
|
||||
|
||||
// try {
|
||||
// const url = new URL(input);
|
||||
// if (url.hostname.includes("youtu.be"))
|
||||
// return url.pathname.slice(1) || null;
|
||||
|
||||
// const v = url.searchParams.get("v");
|
||||
// if (v) return v;
|
||||
|
||||
// const embedMatch = url.pathname.match(/\/embed\/([^/]+)/);
|
||||
// if (embedMatch?.[1]) return embedMatch[1];
|
||||
|
||||
// const shortsMatch = url.pathname.match(/\/shorts\/([^/]+)/);
|
||||
// if (shortsMatch?.[1]) return shortsMatch[1];
|
||||
|
||||
// return null;
|
||||
// } catch {
|
||||
// return null;
|
||||
// }
|
||||
// };
|
||||
|
||||
// export default function MediaDetails({ mediaObj, whichTab }) {
|
||||
// const router = useRouter();
|
||||
// const mediaArr = mediaObj?.value || [];
|
||||
|
||||
// const videoItems = useMemo(() => {
|
||||
// const isWelsh = router.locale === "cy";
|
||||
|
||||
// return (mediaArr || [])
|
||||
// .filter((x) => x?.pinswg_publishtoweb)
|
||||
// .map((item) => {
|
||||
// const url = isWelsh
|
||||
// ? item.pinswg_mediaLinkCY
|
||||
// : item.pinswg_mediaLinkEN;
|
||||
// const videoId = extractYouTubeId(url);
|
||||
// if (!videoId) return null;
|
||||
|
||||
// return {
|
||||
// key:
|
||||
// item.pinswg_documentid ||
|
||||
// `${item.pinswg_name}-${videoId}`,
|
||||
// videoId,
|
||||
// name: item.pinswg_name || "Video",
|
||||
// description: item.pinswg_description || "",
|
||||
// thumbnail: `https://img.youtube.com/vi/${videoId}/hqdefault.jpg`,
|
||||
// };
|
||||
// })
|
||||
// .filter(Boolean);
|
||||
// }, [mediaArr, router.locale]);
|
||||
|
||||
// const [watchedIds, setWatchedIds] = useState(new Set());
|
||||
// const [selectedIndex, setSelectedIndex] = useState(0);
|
||||
|
||||
// // Forces a fresh iframe instance whenever we need to hard-stop playback
|
||||
// const [playerInstance, setPlayerInstance] = useState(0);
|
||||
|
||||
// const isActive = whichTab === "case-media";
|
||||
// const selected = videoItems[selectedIndex] || null;
|
||||
|
||||
// // When leaving the media tab, hard-stop playback by unmounting (and bumping instance)
|
||||
// useEffect(() => {
|
||||
// if (!isActive) {
|
||||
// setPlayerInstance((n) => n + 1);
|
||||
// }
|
||||
// }, [isActive]);
|
||||
|
||||
// // When list/locale changes, reset to first (no autoplay)
|
||||
// useEffect(() => {
|
||||
// setSelectedIndex(0);
|
||||
// setPlayerInstance((n) => n + 1);
|
||||
// }, [videoItems.length, router.locale]);
|
||||
|
||||
// if (!videoItems.length) return null;
|
||||
|
||||
// const embedBase = "https://www.youtube-nocookie.com/embed";
|
||||
|
||||
// // IMPORTANT:
|
||||
// // - autoplay=0 for initial load
|
||||
// // - autoplay=1 only when user clicks an item
|
||||
// const [autoplay, setAutoplay] = useState(false);
|
||||
|
||||
// useEffect(() => {
|
||||
// // whenever we leave tab or reset player, don't autoplay next time
|
||||
// if (!isActive) setAutoplay(false);
|
||||
// }, [isActive]);
|
||||
|
||||
// const embedSrc = selected
|
||||
// ? `${embedBase}/${selected.videoId}?rel=0&modestbranding=1&playsinline=1&autoplay=${autoplay ? "1" : "0"}`
|
||||
// : "";
|
||||
|
||||
// return (
|
||||
// <div className="govuk-grid-row">
|
||||
// <div className="card">
|
||||
// <div className="card-body">
|
||||
// <h2 className="govuk-heading-m">Media</h2>
|
||||
|
||||
// {/* Player: only render when tab is active */}
|
||||
// {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>
|
||||
// )}
|
||||
|
||||
// <h3 className="govuk-heading-s">Videos</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" : ""}`}
|
||||
// onClick={() => {
|
||||
// setSelectedIndex(idx);
|
||||
// setAutoplay(true); // play only on user action
|
||||
// setPlayerInstance((n) => n + 1); // ensure clean switch / stop previous
|
||||
// setWatchedIds((prev) =>
|
||||
// new Set(prev).add(v.videoId),
|
||||
// );
|
||||
// }}
|
||||
// >
|
||||
// <div className="videoTabContent">
|
||||
// <div className="thumbnailWrapper">
|
||||
// <img
|
||||
// src={v.thumbnail}
|
||||
// alt=""
|
||||
// className="videoThumbnail"
|
||||
// loading="lazy"
|
||||
// />
|
||||
// <span
|
||||
// className="playIcon"
|
||||
// aria-hidden="true"
|
||||
// >
|
||||
// ▶
|
||||
// </span>
|
||||
|
||||
// {/* Duration badge (see section 2) */}
|
||||
// {v.duration && (
|
||||
// <span className="durationBadge">
|
||||
// {v.duration}
|
||||
// </span>
|
||||
// )}
|
||||
|
||||
// {/* Watched indicator (see section 3) */}
|
||||
// {watchedIds.has(v.videoId) && (
|
||||
// <span className="watchedBadge">
|
||||
// Watched
|
||||
// </span>
|
||||
// )}
|
||||
// </div>
|
||||
|
||||
// <span className="videoTitle">
|
||||
// {v.name}
|
||||
// </span>
|
||||
// </div>
|
||||
// </button>
|
||||
// </li>
|
||||
// );
|
||||
// })}
|
||||
// </ul>
|
||||
// </div>
|
||||
// </div>
|
||||
|
||||
// <style jsx>{`
|
||||
// .videoWrapper {
|
||||
// position: relative;
|
||||
// padding-bottom: 56.25%;
|
||||
// height: 0;
|
||||
// overflow: hidden;
|
||||
// border: 1px solid #b1b4b6;
|
||||
// border-radius: 4px;
|
||||
// }
|
||||
// .videoWrapper iframe {
|
||||
// position: absolute;
|
||||
// top: 0;
|
||||
// left: 0;
|
||||
// width: 100%;
|
||||
// height: 100%;
|
||||
// }
|
||||
// .videoTabButton {
|
||||
// width: 100%;
|
||||
// text-align: left;
|
||||
// background: transparent;
|
||||
// border: 1px solid #b1b4b6;
|
||||
// border-radius: 4px;
|
||||
// padding: 10px 12px;
|
||||
// cursor: pointer;
|
||||
// }
|
||||
// .videoTabButton:hover {
|
||||
// background: #f3f2f1;
|
||||
// }
|
||||
// .videoTabButton.active {
|
||||
// border-color: #1d70b8;
|
||||
// box-shadow: inset 0 0 0 1px #1d70b8;
|
||||
// background: #eef4ff;
|
||||
// }
|
||||
// .videoTabContent {
|
||||
// display: flex;
|
||||
// gap: 12px;
|
||||
// align-items: center;
|
||||
// }
|
||||
|
||||
// .videoThumbnail {
|
||||
// width: 120px;
|
||||
// aspect-ratio: 16 / 9;
|
||||
// object-fit: cover;
|
||||
// border-radius: 4px;
|
||||
// border: 1px solid #b1b4b6;
|
||||
// background: #000;
|
||||
// }
|
||||
|
||||
// .videoTitle {
|
||||
// font-weight: 600;
|
||||
// }
|
||||
|
||||
// @media (max-width: 40.0625em) {
|
||||
// .videoThumbnail {
|
||||
// width: 90px;
|
||||
// }
|
||||
// }
|
||||
// .thumbnailWrapper {
|
||||
// position: relative;
|
||||
// width: 120px;
|
||||
// flex-shrink: 0;
|
||||
// }
|
||||
|
||||
// .videoThumbnail {
|
||||
// width: 100%;
|
||||
// aspect-ratio: 16 / 9;
|
||||
// object-fit: cover;
|
||||
// border-radius: 4px;
|
||||
// border: 1px solid #b1b4b6;
|
||||
// background: #000;
|
||||
// }
|
||||
|
||||
// /* ▶ Play icon */
|
||||
// .playIcon {
|
||||
// position: absolute;
|
||||
// inset: 0;
|
||||
// display: flex;
|
||||
// align-items: center;
|
||||
// justify-content: center;
|
||||
// font-size: 32px;
|
||||
// color: white;
|
||||
// text-shadow: 0 0 6px rgba(0, 0, 0, 0.7);
|
||||
// pointer-events: none;
|
||||
// }
|
||||
|
||||
// /* ⏱ Duration badge */
|
||||
// .durationBadge {
|
||||
// position: absolute;
|
||||
// bottom: 6px;
|
||||
// right: 6px;
|
||||
// background: rgba(0, 0, 0, 0.8);
|
||||
// color: white;
|
||||
// font-size: 12px;
|
||||
// padding: 2px 6px;
|
||||
// border-radius: 3px;
|
||||
// }
|
||||
|
||||
// /* 👁 Watched badge */
|
||||
// .watchedBadge {
|
||||
// position: absolute;
|
||||
// top: 6px;
|
||||
// left: 6px;
|
||||
// background: #00703c; /* GOV green */
|
||||
// color: white;
|
||||
// font-size: 11px;
|
||||
// padding: 2px 6px;
|
||||
// border-radius: 3px;
|
||||
// }
|
||||
|
||||
// .videoTabContent {
|
||||
// display: flex;
|
||||
// gap: 12px;
|
||||
// align-items: center;
|
||||
// }
|
||||
|
||||
// .videoTitle {
|
||||
// font-weight: 600;
|
||||
// }
|
||||
// `}</style>
|
||||
// </div>
|
||||
// );
|
||||
// }
|
||||
|
||||
import { useEffect, useMemo, useState } from "react";
|
||||
import useTranslation from "next-translate/useTranslation";
|
||||
import { useRouter } from "next/router";
|
||||
|
||||
/**
|
||||
* 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-name-label")}</b>:{" "}
|
||||
{selected.name}
|
||||
</div>
|
||||
|
||||
{!!selected.description && (
|
||||
<div className="govuk-body">
|
||||
<b>{t("case:event-event-name-label")}</b>:{" "}
|
||||
{selected.description}
|
||||
</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">
|
||||
{v.name}
|
||||
</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));
|
||||
},
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -2,22 +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,
|
||||
RenderCondtionalRadioList,
|
||||
RenderPickList,
|
||||
RenderRichMultiline,
|
||||
shouldDisableButton,
|
||||
shouldDisableButton
|
||||
} from "./representationElements";
|
||||
import RepresentationTypeSelectorBlock from "./elements/RepresentationTypeSelectorBlock";
|
||||
|
||||
import { useDropzone } from "react-dropzone";
|
||||
import {
|
||||
setRepresentationCapacity,
|
||||
setRepresentationSubmit,
|
||||
setFilesForRepresentations,
|
||||
setFilesForRepresentations
|
||||
} from "../../../store/currentView/action";
|
||||
|
||||
const ConsultationAgent = (props) => {
|
||||
@@ -36,9 +36,23 @@ const ConsultationAgent = (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);
|
||||
|
||||
@@ -63,63 +77,43 @@ const ConsultationAgent = (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;
|
||||
|
||||
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(
|
||||
"myrepresentations:consultation-from-an-agent-heading"
|
||||
)}
|
||||
</h2>
|
||||
|
||||
<label
|
||||
className="govuk-label govuk-body-m"
|
||||
htmlFor="representationType"
|
||||
>
|
||||
{t(
|
||||
"myrepresentations:kind-of-consultation-label"
|
||||
)}
|
||||
</label>
|
||||
|
||||
<Field
|
||||
name="representationType"
|
||||
component={RenderPickList}
|
||||
datafieldname="representationType"
|
||||
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") && (
|
||||
<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">
|
||||
@@ -146,8 +140,7 @@ const ConsultationAgent = (props) => {
|
||||
<div className="govuk-grid-row">
|
||||
<div className="govuk-form-group">
|
||||
<p className="govuk-body">
|
||||
{formObj.representationForm.values
|
||||
.representationType ==
|
||||
{selectedRepresentationType ==
|
||||
"Consultation Response"
|
||||
? t(
|
||||
"myrepresentations:enter-comment-label"
|
||||
@@ -160,8 +153,7 @@ const ConsultationAgent = (props) => {
|
||||
className="govuk-fieldset"
|
||||
aria-describedby="commentBox-hint"
|
||||
>
|
||||
{formObj.representationForm.values
|
||||
.representationType ==
|
||||
{selectedRepresentationType ==
|
||||
"Consultation Response" && (
|
||||
<div className="govuk-form-group">
|
||||
<Field
|
||||
@@ -265,8 +257,7 @@ const ConsultationAgent = (props) => {
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
{typeof formObj.representationForm.values.representationType !=
|
||||
"undefined" && (
|
||||
{isTypeConfirmed && (
|
||||
<div className="govuk-grid-row">
|
||||
<div className="govuk-button-group">
|
||||
<button
|
||||
@@ -275,7 +266,7 @@ const ConsultationAgent = (props) => {
|
||||
data-module="govuk-button"
|
||||
disabled={shouldDisableButton({
|
||||
props,
|
||||
formObj,
|
||||
formObj
|
||||
})}
|
||||
>
|
||||
{t("common:continue-button")}
|
||||
@@ -349,7 +340,7 @@ const mapDispatchToProps = (dispatch) => ({
|
||||
|
||||
setFilesForRepresentations: (fileList) => {
|
||||
dispatch(setFilesForRepresentations(fileList));
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
export default connect(
|
||||
@@ -359,6 +350,6 @@ export default connect(
|
||||
reduxForm({
|
||||
form: "representationForm",
|
||||
enableReinitialize: true,
|
||||
destroyOnUnmount: false,
|
||||
destroyOnUnmount: false
|
||||
})(ConsultationAgent)
|
||||
);
|
||||
|
||||
@@ -2,21 +2,21 @@ 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,
|
||||
shouldDisableButton
|
||||
} from "./representationElements";
|
||||
import RepresentationTypeSelectorBlock from "./elements/RepresentationTypeSelectorBlock";
|
||||
|
||||
import { useDropzone } from "react-dropzone";
|
||||
import {
|
||||
setRepresentationCapacity,
|
||||
setRepresentationSubmit,
|
||||
setFilesForRepresentations,
|
||||
setFilesForRepresentations
|
||||
} from "../../../store/currentView/action";
|
||||
|
||||
const ConsultationAppellant = (props) => {
|
||||
@@ -35,9 +35,23 @@ const ConsultationAppellant = (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) != "{}") {
|
||||
@@ -62,66 +76,47 @@ const ConsultationAppellant = (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;
|
||||
|
||||
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(
|
||||
"myrepresentations:consultation-from-an-appellant-heading"
|
||||
)}
|
||||
</h2>
|
||||
<label
|
||||
className="govuk-label govuk-body-m"
|
||||
htmlFor="representationType"
|
||||
>
|
||||
{t(
|
||||
"myrepresentations:kind-of-consultation-label"
|
||||
)}
|
||||
</label>
|
||||
<Field
|
||||
name="representationType"
|
||||
component={RenderPickList}
|
||||
datafieldname="representationType"
|
||||
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") && (
|
||||
<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">
|
||||
{formObj.representationForm.values
|
||||
.representationType ==
|
||||
{selectedRepresentationType ==
|
||||
"Consultation Response"
|
||||
? t("myrepresentations:enter-comment-label")
|
||||
: t(
|
||||
@@ -132,8 +127,7 @@ const ConsultationAppellant = (props) => {
|
||||
className="govuk-fieldset"
|
||||
aria-describedby="commentBox-hint"
|
||||
>
|
||||
{formObj.representationForm.values
|
||||
.representationType ==
|
||||
{selectedRepresentationType ==
|
||||
"Consultation Response" && (
|
||||
<div className="govuk-form-group">
|
||||
<Field
|
||||
@@ -233,8 +227,7 @@ const ConsultationAppellant = (props) => {
|
||||
</div>
|
||||
)}
|
||||
|
||||
{typeof formObj.representationForm.values.representationType !=
|
||||
"undefined" && (
|
||||
{isTypeConfirmed && (
|
||||
<div className="govuk-grid-row">
|
||||
<div className="govuk-button-group">
|
||||
<button
|
||||
@@ -243,7 +236,7 @@ const ConsultationAppellant = (props) => {
|
||||
data-module="govuk-button"
|
||||
disabled={shouldDisableButton({
|
||||
props,
|
||||
formObj,
|
||||
formObj
|
||||
})}
|
||||
>
|
||||
{t("common:continue-button")}
|
||||
@@ -253,7 +246,6 @@ const ConsultationAppellant = (props) => {
|
||||
onClick={() => {
|
||||
setRepresentationCapacity();
|
||||
props.updateField(
|
||||
"representationForm",
|
||||
"representationType",
|
||||
""
|
||||
);
|
||||
@@ -321,7 +313,7 @@ const mapDispatchToProps = (dispatch) => {
|
||||
|
||||
setFilesForRepresentations: (fileList) => {
|
||||
dispatch(setFilesForRepresentations(fileList));
|
||||
},
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
@@ -332,6 +324,6 @@ export default connect(
|
||||
reduxForm({
|
||||
form: "representationForm",
|
||||
enableReinitialize: true,
|
||||
destroyOnUnmount: false,
|
||||
destroyOnUnmount: false
|
||||
})(ConsultationAppellant)
|
||||
);
|
||||
|
||||
@@ -2,22 +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,
|
||||
RenderCondtionalRadioList,
|
||||
RenderPickList,
|
||||
RenderRichMultiline,
|
||||
shouldDisableButton,
|
||||
shouldDisableButton
|
||||
} from "./representationElements";
|
||||
import RepresentationTypeSelectorBlock from "./elements/RepresentationTypeSelectorBlock";
|
||||
|
||||
import { useDropzone } from "react-dropzone";
|
||||
import {
|
||||
setRepresentationCapacity,
|
||||
setRepresentationSubmit,
|
||||
setFilesForRepresentations,
|
||||
setFilesForRepresentations
|
||||
} from "../../../store/currentView/action";
|
||||
|
||||
const ConsultationInterestedPartyPerson = (props) => {
|
||||
@@ -35,11 +35,25 @@ const ConsultationInterestedPartyPerson = (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);
|
||||
|
||||
@@ -62,67 +76,46 @@ const ConsultationInterestedPartyPerson = (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;
|
||||
|
||||
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(
|
||||
"myrepresentations:consultation-from-an-interested-person-heading"
|
||||
)}
|
||||
</h2>
|
||||
|
||||
<label
|
||||
className="govuk-label govuk-body-m"
|
||||
htmlFor="representationType"
|
||||
>
|
||||
{t(
|
||||
"myrepresentations:kind-of-consultation-label"
|
||||
)}
|
||||
</label>
|
||||
|
||||
<Field
|
||||
name="representationType"
|
||||
component={RenderPickList}
|
||||
datafieldname="representationType"
|
||||
validate={[required]}
|
||||
optionsArr={
|
||||
interestedPersonRepresentationArr
|
||||
}
|
||||
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") && (
|
||||
<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">
|
||||
@@ -134,7 +127,7 @@ const ConsultationInterestedPartyPerson = (props) => {
|
||||
t(
|
||||
"myrepresentations:questionnaire-yes"
|
||||
),
|
||||
t("myrepresentations:questionnaire-no"),
|
||||
t("myrepresentations:questionnaire-no")
|
||||
]}
|
||||
id="representationOnBehalfOf"
|
||||
className="govuk-radios__input"
|
||||
@@ -154,8 +147,7 @@ const ConsultationInterestedPartyPerson = (props) => {
|
||||
<div className="govuk-grid-row">
|
||||
<div className="govuk-form-group">
|
||||
<p className="govuk-body">
|
||||
{formObj.representationForm.values
|
||||
.representationType ==
|
||||
{selectedRepresentationType ==
|
||||
"Consultation Response"
|
||||
? t(
|
||||
"myrepresentations:enter-comment-label"
|
||||
@@ -169,8 +161,7 @@ const ConsultationInterestedPartyPerson = (props) => {
|
||||
aria-describedby="commentBox-hint"
|
||||
>
|
||||
{" "}
|
||||
{formObj.representationForm.values
|
||||
.representationType ==
|
||||
{selectedRepresentationType ==
|
||||
"Consultation Response" && (
|
||||
<div className="govuk-form-group">
|
||||
<Field
|
||||
@@ -274,8 +265,7 @@ const ConsultationInterestedPartyPerson = (props) => {
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
{typeof formObj.representationForm.values.representationType !=
|
||||
"undefined" && (
|
||||
{isTypeConfirmed && (
|
||||
<div className="govuk-grid-row">
|
||||
<div className="govuk-button-group">
|
||||
<button
|
||||
@@ -284,7 +274,7 @@ const ConsultationInterestedPartyPerson = (props) => {
|
||||
data-module="govuk-button"
|
||||
disabled={shouldDisableButton({
|
||||
props,
|
||||
formObj,
|
||||
formObj
|
||||
})}
|
||||
>
|
||||
{t("common:continue-button")}
|
||||
@@ -363,7 +353,7 @@ const mapDispatchToProps = (dispatch) => ({
|
||||
dispatch(change(form, field, newValue)),
|
||||
setFilesForRepresentations: (fileList) => {
|
||||
dispatch(setFilesForRepresentations(fileList));
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
export default connect(
|
||||
@@ -373,6 +363,6 @@ export default connect(
|
||||
reduxForm({
|
||||
form: "representationForm",
|
||||
enableReinitialize: true,
|
||||
destroyOnUnmount: false,
|
||||
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;
|
||||
File diff suppressed because it is too large
Load Diff
@@ -2,22 +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,
|
||||
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) => {
|
||||
@@ -36,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);
|
||||
|
||||
@@ -63,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(
|
||||
"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
|
||||
}
|
||||
/>
|
||||
</>
|
||||
) : (
|
||||
<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") && (
|
||||
<RepresentationTypeSelectorBlock
|
||||
t={t}
|
||||
headingText={t(
|
||||
"myrepresentations:representation-from-an-agent-heading"
|
||||
)}
|
||||
kindLabelText={t("myrepresentations:kind-of-rep-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">
|
||||
@@ -197,7 +200,8 @@ const RepAgent = (props) => {
|
||||
"myrepresentations:add-files-label"
|
||||
)}
|
||||
ticketnumber={
|
||||
props.props.caseReference
|
||||
props.currentView.caseReference
|
||||
.ticketnumber
|
||||
}
|
||||
hint={"sdsd"}
|
||||
fileList={
|
||||
@@ -239,64 +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"
|
||||
disabled={shouldDisableButton({
|
||||
props,
|
||||
formObj,
|
||||
})}
|
||||
>
|
||||
{t("common:continue-button")}
|
||||
</button>
|
||||
|
||||
{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>
|
||||
{isTypeConfirmed && (
|
||||
<RepresentationActionButtons
|
||||
t={t}
|
||||
locale={router.locale}
|
||||
isSaving={savingStatus}
|
||||
isContinueDisabled={shouldDisableButton({
|
||||
props,
|
||||
formObj
|
||||
})}
|
||||
onSaveExit={handleSaveExit}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
@@ -309,7 +266,7 @@ const mapDispatchToProps = (dispatch) => ({
|
||||
|
||||
setFilesForRepresentations: (fileList) => {
|
||||
dispatch(setFilesForRepresentations(fileList));
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
export default connect(
|
||||
@@ -319,6 +276,6 @@ export default connect(
|
||||
reduxForm({
|
||||
form: "representationForm",
|
||||
enableReinitialize: true,
|
||||
destroyOnUnmount: false,
|
||||
destroyOnUnmount: false
|
||||
})(RepAgent)
|
||||
);
|
||||
|
||||
@@ -2,21 +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,
|
||||
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) => {
|
||||
@@ -35,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) != "{}") {
|
||||
@@ -62,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(
|
||||
"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
|
||||
}
|
||||
/>
|
||||
</>
|
||||
) : (
|
||||
<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") && (
|
||||
<RepresentationTypeSelectorBlock
|
||||
t={t}
|
||||
headingText={t(
|
||||
"myrepresentations:representation-from-an-appellant-heading"
|
||||
)}
|
||||
kindLabelText={t("myrepresentations:kind-of-rep-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">
|
||||
@@ -189,7 +194,10 @@ const RepAppellant = (props) => {
|
||||
label={t(
|
||||
"myrepresentations:add-files-label"
|
||||
)}
|
||||
ticketnumber={props.props.caseReference}
|
||||
ticketnumber={
|
||||
props.currentView.caseReference
|
||||
.ticketnumber
|
||||
}
|
||||
hint={"sdsd"}
|
||||
fileList={
|
||||
props.currentView.fileList
|
||||
@@ -227,64 +235,17 @@ const RepAppellant = (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"
|
||||
disabled={shouldDisableButton({
|
||||
props,
|
||||
formObj,
|
||||
})}
|
||||
>
|
||||
{t("common:continue-button")}
|
||||
</button>
|
||||
|
||||
{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>
|
||||
{isTypeConfirmed && (
|
||||
<RepresentationActionButtons
|
||||
t={t}
|
||||
locale={router.locale}
|
||||
isSaving={savingStatus}
|
||||
isContinueDisabled={shouldDisableButton({
|
||||
props,
|
||||
formObj
|
||||
})}
|
||||
onSaveExit={handleSaveExit}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
@@ -300,7 +261,7 @@ const mapDispatchToProps = (dispatch) => {
|
||||
|
||||
setFilesForRepresentations: (fileList) => {
|
||||
dispatch(setFilesForRepresentations(fileList));
|
||||
},
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
@@ -311,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) => (
|
||||
@@ -36,6 +36,9 @@ let RepCapacitySelection = (props) => {
|
||||
currentType={currentType}
|
||||
casesObj={casesObj}
|
||||
caseReference={props.props.caseReference}
|
||||
ticketnumber={
|
||||
props.props.currentView.caseReference.ticketnumber
|
||||
}
|
||||
searchResultsObj={props.props.searchResultsObj}
|
||||
myRepresentations={props.props.myRepresentations}
|
||||
props={props}
|
||||
@@ -49,7 +52,7 @@ let RepCapacitySelection = (props) => {
|
||||
{t(
|
||||
"myrepresentations:capacity-select-your-details"
|
||||
)}{" "}
|
||||
- {props.firstValue}
|
||||
- {props.firstValue}{" "}
|
||||
</h2>
|
||||
<Field
|
||||
name="representationCapacity"
|
||||
@@ -69,7 +72,7 @@ let RepCapacitySelection = (props) => {
|
||||
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) => (
|
||||
@@ -36,9 +36,22 @@ const RepComplete = (props) => {
|
||||
</li>
|
||||
));
|
||||
|
||||
const isSIPS =
|
||||
props.props.currentView.caseReference.appealType === 846040002;
|
||||
|
||||
useEffect(() => {
|
||||
const reference = "PEDW-REPRESENTATION-COMPLETE";
|
||||
const templateId = "c49785e7-3217-40b6-b33f-dffc4e58d5c1";
|
||||
const isWelsh = router.locale === "cy";
|
||||
const reference = isSIPS
|
||||
? "PEDW-CONSULTATION-COMPLETE" + isWelsh && "-CY"
|
||||
: "PEDW-REPRESENTATION-COMPLETE" + isWelsh && "-CY";
|
||||
const templateId = isSIPS
|
||||
? isWelsh
|
||||
? "7d27b968-6f63-4334-b1c4-2e4a69554212"
|
||||
: "c3f373ca-df9d-4967-bea0-3ad3a57f8dcc"
|
||||
: isWelsh
|
||||
? "6e2f0111-b352-4074-91a2-760403cd185b"
|
||||
: "c49785e7-3217-40b6-b33f-dffc4e58d5c1";
|
||||
|
||||
const emailAddress =
|
||||
props.props.props.props.accountDetails.accountDetails.emailaddress1;
|
||||
const personalisation = {
|
||||
@@ -47,17 +60,18 @@ 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,
|
||||
props.props.currentView.caseReference.currentReference,
|
||||
props.props.currentView.caseReference.ticketnumber,
|
||||
props.repFormData.repfile_name
|
||||
),
|
||||
sendEmail(templateId, emailAddress, personalisation, reference),
|
||||
@@ -81,9 +95,10 @@ const RepComplete = (props) => {
|
||||
? props.props.currentView.caseReference.repDetails
|
||||
.representationType
|
||||
: props.props.currentView.caseReference
|
||||
.representationType,
|
||||
.representationType
|
||||
}),
|
||||
setRepresentationMessageSent(true));
|
||||
setRepresentationMessageSent(true)),
|
||||
window.scrollTo({ top: 0, behavior: "smooth" }));
|
||||
});
|
||||
return (
|
||||
<div id="rep-appellant">
|
||||
@@ -95,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">
|
||||
@@ -121,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,
|
||||
};
|
||||
};
|
||||
|
||||
@@ -4,6 +4,7 @@ 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";
|
||||
@@ -13,16 +14,19 @@ import {
|
||||
getThumbnailIconByExtension,
|
||||
formatDates,
|
||||
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,7 +227,7 @@ const RepCompleteSubmit = (props) => {
|
||||
arrUniq = removeEmptyObjects(arrUniq);
|
||||
|
||||
Object.assign(formObj.representationForm.values, {
|
||||
"filesList": arrUniq,
|
||||
"filesList": arrUniq
|
||||
});
|
||||
|
||||
let filterFiles = [];
|
||||
@@ -249,6 +264,64 @@ const RepCompleteSubmit = (props) => {
|
||||
}
|
||||
};
|
||||
|
||||
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);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
{currentView.representationSubmitConfirmation == true ? (
|
||||
@@ -299,12 +372,12 @@ const RepCompleteSubmit = (props) => {
|
||||
"Questionnaire"
|
||||
? "Holiadur"
|
||||
: repFormData.representationType ==
|
||||
"Statement"
|
||||
? "Datganiad"
|
||||
: repFormData.representationType ==
|
||||
"Final comments"
|
||||
? "Sylwadau terfynol"
|
||||
: repFormData.representationType
|
||||
"Statement"
|
||||
? "Datganiad"
|
||||
: repFormData.representationType ==
|
||||
"Final comments"
|
||||
? "Sylwadau terfynol"
|
||||
: repFormData.representationType
|
||||
: repFormData.representationType}
|
||||
</dd>
|
||||
|
||||
@@ -340,7 +413,7 @@ const RepCompleteSubmit = (props) => {
|
||||
|
||||
<dd className="govuk-summary-list__value">
|
||||
{
|
||||
repFormData.representationOnBehalfOf
|
||||
representationOnBehalfOfDisplay
|
||||
}
|
||||
</dd>
|
||||
|
||||
@@ -362,7 +435,7 @@ const RepCompleteSubmit = (props) => {
|
||||
"appealType":
|
||||
repFormData.appealType,
|
||||
"repDetails":
|
||||
repFormData,
|
||||
repFormData
|
||||
});
|
||||
setRepresentationSubmit(
|
||||
false
|
||||
@@ -415,7 +488,7 @@ const RepCompleteSubmit = (props) => {
|
||||
"appealType":
|
||||
repFormData.appealType,
|
||||
"repDetails":
|
||||
repFormData,
|
||||
repFormData
|
||||
}
|
||||
);
|
||||
setRepresentationSubmit(
|
||||
@@ -452,7 +525,7 @@ const RepCompleteSubmit = (props) => {
|
||||
<span
|
||||
className="multiline-elipsis"
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: repFormData.representationComments,
|
||||
__html: repFormData.representationComments
|
||||
}}
|
||||
/>
|
||||
</dd>
|
||||
@@ -476,7 +549,7 @@ const RepCompleteSubmit = (props) => {
|
||||
"appealType":
|
||||
repFormData.appealType,
|
||||
"repDetails":
|
||||
repFormData,
|
||||
repFormData
|
||||
});
|
||||
setRepresentationSubmit(
|
||||
false
|
||||
@@ -556,7 +629,7 @@ const RepCompleteSubmit = (props) => {
|
||||
"appealType":
|
||||
repFormData.appealType,
|
||||
"repDetails":
|
||||
repFormData,
|
||||
repFormData
|
||||
}),
|
||||
setRepresentationSubmit(
|
||||
false
|
||||
@@ -603,6 +676,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">
|
||||
@@ -641,8 +716,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">
|
||||
@@ -681,10 +811,11 @@ const RepCompleteSubmit = (props) => {
|
||||
type="submit"
|
||||
className="govuk-button"
|
||||
data-module="govuk-button"
|
||||
onClick={() => {
|
||||
onClick={async () => {
|
||||
// setRepresentationSubmitConfirmation(
|
||||
// true
|
||||
// );
|
||||
await triggerQuestionnaireDownload();
|
||||
setRepresentationSubmit(
|
||||
true
|
||||
);
|
||||
@@ -721,7 +852,7 @@ const mapStateToProps = (state) => {
|
||||
currentView: state.currentView,
|
||||
myRepresentations: state.myRepresentations,
|
||||
initialValues: state.currentView.caseReference.repDetails,
|
||||
accountDetails: state.accountDetails,
|
||||
accountDetails: state.accountDetails
|
||||
//form: state.form,
|
||||
};
|
||||
};
|
||||
@@ -730,7 +861,7 @@ const mapDispatchToProps = (dispatch) => {
|
||||
return {
|
||||
setCurrentReference: (currentReference) => {
|
||||
dispatch(setCurrentReference(currentReference));
|
||||
},
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ const RepDetails = (props) => {
|
||||
|
||||
const { currentType, casesObj, appealType } = props;
|
||||
|
||||
let { caseReference } = props;
|
||||
let { caseReference, ticketnumber } = props;
|
||||
|
||||
let setCaseDetailsObj = router.query.hasOwnProperty("state")
|
||||
? router.query.state == "edit"
|
||||
@@ -29,7 +29,7 @@ const RepDetails = (props) => {
|
||||
: caseReference;
|
||||
|
||||
detailsObj = jsonpath({
|
||||
path: '$..[?(@ && @.pinswg_name=="' + caseReference + '")]',
|
||||
path: '$..[?(@ && @.ticketnumber=="' + ticketnumber + '")]',
|
||||
json: setCaseDetailsObj,
|
||||
eval: true,
|
||||
});
|
||||
|
||||
@@ -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,68 +324,84 @@ 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
|
||||
className="govuk-radios__item"
|
||||
data-children-count={key}
|
||||
key={key}
|
||||
className="govuk-!-margin-bottom-3"
|
||||
>
|
||||
<Field
|
||||
id={id + "_" + index}
|
||||
name={id}
|
||||
component="input"
|
||||
type="radio"
|
||||
className="govuk-radios__input"
|
||||
value={options[key]}
|
||||
validate={[required]}
|
||||
/>
|
||||
<label
|
||||
className="govuk-label govuk-radios__label"
|
||||
htmlFor={id + "_" + index}
|
||||
>
|
||||
{options[key] == "Yes"
|
||||
? t(
|
||||
"myrepresentations:questionnaire-yes"
|
||||
)
|
||||
: t(
|
||||
"myrepresentations:questionnaire-no"
|
||||
)}
|
||||
</label>
|
||||
</div>
|
||||
{value == "Yes" && options[key] == "Yes" && (
|
||||
<div
|
||||
className="govuk-radios__conditional "
|
||||
id={"conditional-" + id}
|
||||
className="govuk-radios__item"
|
||||
data-children-count={key}
|
||||
key={key}
|
||||
>
|
||||
<div
|
||||
className="govuk-form-group"
|
||||
key={"yes_group_" + key}
|
||||
<Field
|
||||
id={id + "_" + index}
|
||||
name={id}
|
||||
component="input"
|
||||
type="radio"
|
||||
className="govuk-radios__input"
|
||||
value={normalizedOptionValue}
|
||||
validate={[required]}
|
||||
/>
|
||||
<label
|
||||
className="govuk-label govuk-radios__label"
|
||||
htmlFor={id + "_" + index}
|
||||
>
|
||||
<label
|
||||
className="govuk-label"
|
||||
htmlFor={id + "_details"}
|
||||
>
|
||||
{t(
|
||||
"myrepresentations:representation-onbehalfof-label"
|
||||
)}
|
||||
</label>
|
||||
<Field
|
||||
className="govuk-input govuk-!-width-one-half"
|
||||
id={id + "_details"}
|
||||
name={id + "_details"}
|
||||
component={RenderTextfield}
|
||||
type="text"
|
||||
validate={[required]}
|
||||
errorMsg={t(
|
||||
"myrepresentations:is-required-label"
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
{options[key] == "Yes"
|
||||
? t(
|
||||
"myrepresentations:questionnaire-yes"
|
||||
)
|
||||
: t(
|
||||
"myrepresentations:questionnaire-no"
|
||||
)}
|
||||
</label>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
{isYesSelected &&
|
||||
normalizedOptionValue === "Yes" && (
|
||||
<div
|
||||
className="govuk-radios__conditional "
|
||||
id={"conditional-" + id}
|
||||
>
|
||||
<div
|
||||
className="govuk-form-group"
|
||||
key={"yes_group_" + key}
|
||||
>
|
||||
<label
|
||||
className="govuk-label"
|
||||
htmlFor={
|
||||
id + "_details"
|
||||
}
|
||||
>
|
||||
{t(
|
||||
"myrepresentations:representation-onbehalfof-label"
|
||||
)}
|
||||
</label>
|
||||
<Field
|
||||
className="govuk-input govuk-!-width-one-half"
|
||||
id={id + "_details"}
|
||||
name={id + "_details"}
|
||||
component={
|
||||
RenderTextfield
|
||||
}
|
||||
type="text"
|
||||
validate={[
|
||||
requiredIfYes
|
||||
]}
|
||||
errorMsg={t(
|
||||
"myrepresentations:is-required-label"
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</fieldset>
|
||||
</div>
|
||||
@@ -537,18 +573,19 @@ export const RenderPickList = ({
|
||||
? optionsArr[key] == "Questionnaire"
|
||||
? "Holiadur"
|
||||
: optionsArr[key] == "Statement"
|
||||
? "Datganiad"
|
||||
: optionsArr[key] ==
|
||||
"Final comments"
|
||||
? "Sylwadau terfynol"
|
||||
: optionsArr[key] ==
|
||||
"Written representations"
|
||||
? "Sylwadau ysgrifenedig"
|
||||
: optionsArr[key] == "Inquiry"
|
||||
? "Ymchwiliad"
|
||||
: optionsArr[key] == "Hearing"
|
||||
? "Gwrandawiad"
|
||||
: optionsArr[key]
|
||||
? "Datganiad"
|
||||
: optionsArr[key] ==
|
||||
"Final comments"
|
||||
? "Sylwadau terfynol"
|
||||
: optionsArr[key] ==
|
||||
"Written representations"
|
||||
? "Sylwadau ysgrifenedig"
|
||||
: optionsArr[key] == "Inquiry"
|
||||
? "Ymchwiliad"
|
||||
: optionsArr[key] ==
|
||||
"Hearing"
|
||||
? "Gwrandawiad"
|
||||
: optionsArr[key]
|
||||
: optionsArr[key]}
|
||||
</option>
|
||||
);
|
||||
@@ -627,31 +664,31 @@ export const RenderDatePicker = ({
|
||||
startDateArr == 0
|
||||
? new Date()
|
||||
: startDateArr[0] == "-"
|
||||
? startDateArr[2] == "y"
|
||||
? subYears(new Date(), startDateArr[1])
|
||||
? startDateArr[2] == "y"
|
||||
? subYears(new Date(), startDateArr[1])
|
||||
: startDateArr[2] == "m"
|
||||
? subMonths(new Date(), startDateArr[1])
|
||||
: subDays(new Date(), startDateArr[1])
|
||||
: startDateArr[2] == "y"
|
||||
? addYears(new Date(), startDateArr[1])
|
||||
: startDateArr[2] == "m"
|
||||
? subMonths(new Date(), startDateArr[1])
|
||||
: subDays(new Date(), startDateArr[1])
|
||||
: startDateArr[2] == "y"
|
||||
? addYears(new Date(), startDateArr[1])
|
||||
: startDateArr[2] == "m"
|
||||
? addMonths(new Date(), startDateArr[1])
|
||||
: addDays(new Date(), startDateArr[1]);
|
||||
? addMonths(new Date(), startDateArr[1])
|
||||
: addDays(new Date(), startDateArr[1]);
|
||||
|
||||
var maxDate =
|
||||
endDateArr == 0
|
||||
? new Date()
|
||||
: startDateArr[0] == "-"
|
||||
? startDateArr[2] == "y"
|
||||
? subYears(new Date(), startDateArr[1])
|
||||
? startDateArr[2] == "y"
|
||||
? subYears(new Date(), startDateArr[1])
|
||||
: startDateArr[2] == "m"
|
||||
? subMonths(new Date(), startDateArr[1])
|
||||
: subDays(new Date(), startDateArr[1])
|
||||
: startDateArr[2] == "y"
|
||||
? addYears(new Date(), startDateArr[1])
|
||||
: startDateArr[2] == "m"
|
||||
? subMonths(new Date(), startDateArr[1])
|
||||
: subDays(new Date(), startDateArr[1])
|
||||
: startDateArr[2] == "y"
|
||||
? addYears(new Date(), startDateArr[1])
|
||||
: startDateArr[2] == "m"
|
||||
? addMonths(new Date(), startDateArr[1])
|
||||
: addDays(new Date(), startDateArr[1]);
|
||||
? addMonths(new Date(), startDateArr[1])
|
||||
: addDays(new Date(), startDateArr[1]);
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -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 : {}),
|
||||
@@ -939,10 +989,6 @@ export const RenderFileUpload = (field) => {
|
||||
case "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet":
|
||||
return "/assets/images/documenttypes/xlsx.png";
|
||||
break;
|
||||
|
||||
case "application/zip":
|
||||
return "/assets/images/documenttypes/zip.png";
|
||||
break;
|
||||
case "image/jpeg":
|
||||
return "/assets/images/documenttypes/jpg.png";
|
||||
case "image/png":
|
||||
@@ -997,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
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1046,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
|
||||
@@ -1064,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"
|
||||
)}`;
|
||||
@@ -1080,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
|
||||
@@ -1091,14 +1187,32 @@ export const RenderFileUpload = (field) => {
|
||||
[".docx"],
|
||||
"image/tiff": [".tif", ".tiff"],
|
||||
"image/jpeg": [".jpg", ".jpeg"],
|
||||
"application/zip": [".zip"],
|
||||
"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],
|
||||
@@ -1116,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,
|
||||
@@ -1129,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 = [];
|
||||
@@ -1140,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
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1201,8 +1330,6 @@ export const RenderFileUpload = (field) => {
|
||||
});
|
||||
});
|
||||
}}
|
||||
onDropRejected={handleDropRejected}
|
||||
onDropAccepted={handleDropAccepted}
|
||||
>
|
||||
{({ getRootProps, getInputProps }) => (
|
||||
<>
|
||||
@@ -1229,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 "
|
||||
@@ -1241,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>
|
||||
)}
|
||||
@@ -1338,7 +1468,7 @@ export const RenderFileUpload = (field) => {
|
||||
?.values?.repfile_name
|
||||
) +
|
||||
"&blobname=" +
|
||||
blob.name +
|
||||
encodeURIComponent(blob.name) +
|
||||
blob.hashedfilepath
|
||||
}
|
||||
className="govuk-body govuk-!-font-size-14 govuk-!-padding-left-5 govuk-link"
|
||||
@@ -1380,9 +1510,9 @@ export function FileUploadField(props) {
|
||||
? props.filenamePrefix.representationForm.values
|
||||
.repfile_name
|
||||
: props.filenamePrefix.hasOwnProperty("formObj")
|
||||
? props.filenamePrefix.formObj["representationForm"]
|
||||
.values.repfile_name
|
||||
: ""
|
||||
? props.filenamePrefix.formObj["representationForm"]
|
||||
.values.repfile_name
|
||||
: ""
|
||||
}
|
||||
props={props}
|
||||
/>
|
||||
|
||||
@@ -2,22 +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,
|
||||
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) => {
|
||||
@@ -35,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);
|
||||
|
||||
@@ -62,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(
|
||||
"myrepresentations:consultation-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"
|
||||
validate={[required]}
|
||||
optionsArr={
|
||||
interestedPersonRepresentationArr
|
||||
}
|
||||
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") && (
|
||||
<RepresentationTypeSelectorBlock
|
||||
t={t}
|
||||
headingText={t(
|
||||
"myrepresentations:consultation-from-an-interested-person-heading"
|
||||
)}
|
||||
kindLabelText={t("myrepresentations:kind-of-rep-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">
|
||||
@@ -128,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(
|
||||
@@ -189,7 +186,8 @@ const RepInterestedPartyPerson = (props) => {
|
||||
"myrepresentations:add-files-label"
|
||||
)}
|
||||
ticketnumber={
|
||||
props.props.caseReference
|
||||
props.currentView.caseReference
|
||||
.ticketnumber
|
||||
}
|
||||
hint={"sdsd"}
|
||||
fileList={
|
||||
@@ -231,82 +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"
|
||||
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>
|
||||
{isTypeConfirmed && (
|
||||
<RepresentationActionButtons
|
||||
t={t}
|
||||
locale={router.locale}
|
||||
isSaving={savingStatus}
|
||||
isContinueDisabled={shouldDisableButton({
|
||||
props,
|
||||
formObj
|
||||
})}
|
||||
onSaveExit={handleSaveExit}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
@@ -320,7 +253,7 @@ const mapDispatchToProps = (dispatch) => ({
|
||||
dispatch(change(form, field, newValue)),
|
||||
setFilesForRepresentations: (fileList) => {
|
||||
dispatch(setFilesForRepresentations(fileList));
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
export default connect(
|
||||
@@ -330,6 +263,6 @@ export default connect(
|
||||
reduxForm({
|
||||
form: "representationForm",
|
||||
enableReinitialize: true,
|
||||
destroyOnUnmount: false,
|
||||
destroyOnUnmount: false
|
||||
})(RepInterestedPartyPerson)
|
||||
);
|
||||
|
||||
@@ -10,9 +10,9 @@ import { useState, useEffect } from "react";
|
||||
import {
|
||||
FileUploadField,
|
||||
RenderMultiline,
|
||||
RenderPickList,
|
||||
shouldDisableButton,
|
||||
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";
|
||||
@@ -23,7 +23,7 @@ import {
|
||||
setRepresentationSubmit,
|
||||
setFilesForRepresentations,
|
||||
setCurrentPage,
|
||||
setCurrentReference,
|
||||
setCurrentReference
|
||||
} from "../../../store/currentView/action";
|
||||
|
||||
let RepLPA = (props) => {
|
||||
@@ -49,6 +49,8 @@ let RepLPA = (props) => {
|
||||
setSavingStatus,
|
||||
savingStatus,
|
||||
setFilesForRepresentations,
|
||||
onRepresentationTypeChange,
|
||||
onTypeSelectionConfirmed
|
||||
} = props;
|
||||
const { acceptedFiles, getRootProps, getInputProps } = useDropzone();
|
||||
|
||||
@@ -59,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) {
|
||||
@@ -183,7 +215,7 @@ let RepLPA = (props) => {
|
||||
currentView.caseReference.currentReference +
|
||||
'")]',
|
||||
json: setCaseDetailsObj,
|
||||
eval: true,
|
||||
eval: true
|
||||
});
|
||||
|
||||
let setCaseResultssObj = router.query.hasOwnProperty("state")
|
||||
@@ -202,7 +234,7 @@ let RepLPA = (props) => {
|
||||
currentView.caseReference.currentReference +
|
||||
'")]',
|
||||
json: setCaseResultssObj,
|
||||
eval: true,
|
||||
eval: true
|
||||
});
|
||||
resultsObj = resultsObj[0];
|
||||
|
||||
@@ -225,62 +257,26 @@ let RepLPA = (props) => {
|
||||
|
||||
return (
|
||||
<>
|
||||
<RepresentationTypeSelectorBlock
|
||||
t={t}
|
||||
headingText={t(
|
||||
"myrepresentations:representation-from-an-lpa-heading"
|
||||
)}
|
||||
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")}
|
||||
/>
|
||||
<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(
|
||||
"myrepresentations:representation-from-an-lpa-heading"
|
||||
)}
|
||||
</label>
|
||||
<Field
|
||||
id="representationType"
|
||||
name="representationType"
|
||||
component={RenderPickList}
|
||||
datafieldname="representationType"
|
||||
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>
|
||||
<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")}
|
||||
@@ -354,7 +350,8 @@ let RepLPA = (props) => {
|
||||
"myrepresentations:add-files-label"
|
||||
)}
|
||||
ticketnumber={
|
||||
props.props.caseReference
|
||||
props.currentView.caseReference
|
||||
.ticketnumber
|
||||
}
|
||||
hint={"sdsd"}
|
||||
fileList={
|
||||
@@ -401,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 && (
|
||||
@@ -443,14 +439,14 @@ let RepLPA = (props) => {
|
||||
// top: 0,
|
||||
// behavior: "smooth",
|
||||
// });
|
||||
setRepFileName(
|
||||
(setRepFileName(
|
||||
props.formObj[
|
||||
"representationForm"
|
||||
].values
|
||||
),
|
||||
setShowQuestionnaireSection(
|
||||
showQuestionnaireSection - 1
|
||||
);
|
||||
));
|
||||
}}
|
||||
className="govuk-link"
|
||||
>
|
||||
@@ -503,9 +499,8 @@ let RepLPA = (props) => {
|
||||
)}
|
||||
</>
|
||||
)}{" "}
|
||||
{(typeof props.representationType != "undefined" ||
|
||||
_.has(formObj, "values", "representationType")) &&
|
||||
props.representationType != "Questionnaire" && (
|
||||
{isTypeConfirmed &&
|
||||
selectedRepresentationType != "Questionnaire" && (
|
||||
<>
|
||||
<button
|
||||
type="submit"
|
||||
@@ -513,7 +508,7 @@ let RepLPA = (props) => {
|
||||
data-module="govuk-button"
|
||||
disabled={shouldDisableButton({
|
||||
props,
|
||||
formObj,
|
||||
formObj
|
||||
})}
|
||||
onClick={() => {
|
||||
let valuesObj =
|
||||
@@ -612,7 +607,7 @@ RepLPA = connect((state) => {
|
||||
|
||||
return {
|
||||
procedureType,
|
||||
representationType,
|
||||
representationType
|
||||
};
|
||||
})(RepLPA);
|
||||
|
||||
@@ -625,7 +620,7 @@ const mapDispatchToProps = (dispatch) => ({
|
||||
},
|
||||
setCurrentReference: (currentReference) => {
|
||||
dispatch(setCurrentReference(currentReference));
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
const mapStateToProps = (state, props) => {
|
||||
@@ -641,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 {
|
||||
@@ -653,7 +647,7 @@ const mapStateToProps = (state, props) => {
|
||||
currentView: state.currentView,
|
||||
myRepresentations: state.myRepresentations,
|
||||
watchedCases: state.watchedCases,
|
||||
initialValues: initialValuesTemp,
|
||||
initialValues: initialValuesTemp
|
||||
};
|
||||
};
|
||||
|
||||
@@ -664,6 +658,6 @@ export default connect(
|
||||
reduxForm({
|
||||
form: "representationForm",
|
||||
enableReinitialize: true,
|
||||
destroyOnUnmount: false,
|
||||
destroyOnUnmount: false
|
||||
})(RepLPA)
|
||||
);
|
||||
|
||||
@@ -34,6 +34,7 @@ let RepLPACapacitySelection = (props) => {
|
||||
casesObj={casesObj}
|
||||
detailsObj={detailsObj}
|
||||
caseReference={props.props.caseReference}
|
||||
ticketnumber={props.props.ticketnumber}
|
||||
searchResultsObj={props.props.searchResultsObj}
|
||||
props={props.props}
|
||||
/>{" "}
|
||||
|
||||
@@ -8,7 +8,7 @@ const RepLPADetails = (props) => {
|
||||
const router = useRouter();
|
||||
const { locale } = router;
|
||||
|
||||
const { currentType, casesObj, caseReference } = props;
|
||||
const { currentType, casesObj, caseReference, ticketnumber } = props;
|
||||
|
||||
let setCaseDetailsObj = router.query.hasOwnProperty("state")
|
||||
? router.query.state == "edit"
|
||||
@@ -21,7 +21,7 @@ const RepLPADetails = (props) => {
|
||||
var detailsObj = {};
|
||||
|
||||
detailsObj = jsonpath({
|
||||
path: '$..[?(@ && @.pinswg_name=="' + caseReference + '")]',
|
||||
path: '$..[?(@ && @.ticketnumber=="' + ticketnumber + '")]',
|
||||
json: setCaseDetailsObj,
|
||||
eval: true,
|
||||
});
|
||||
|
||||
@@ -84,7 +84,10 @@ const RepLandOwner = (props) => {
|
||||
label={t(
|
||||
"myrepresentations:add-files-label"
|
||||
)}
|
||||
ticketnumber={props.props.caseReference}
|
||||
ticketnumber={
|
||||
props.currentView.caseReference
|
||||
.ticketnumber
|
||||
}
|
||||
hint={"sdsd"}
|
||||
fileList={[]}
|
||||
setFilesForRepresentation={[]}
|
||||
|
||||
+60
-57
@@ -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) => (
|
||||
@@ -50,32 +50,32 @@ let Enforcement_Questionnaire = (props) => {
|
||||
? router.query.state == "edit"
|
||||
? props.props.myRepresentations.myRepresentations
|
||||
: currentView.caseReference.currentType == "watchedCases"
|
||||
? props.props.watchedCases.watchedCasesDetails
|
||||
: props.props.searchResultsObj.searchDetailsObj
|
||||
? props.props.watchedCases.watchedCasesDetails
|
||||
: props.props.searchResultsObj.searchDetailsObj
|
||||
: currentView.caseReference.currentType == "watchedCases"
|
||||
? props.props.watchedCases.watchedCasesDetails
|
||||
: props.props.searchResultsObj.searchDetailsObj;
|
||||
? props.props.watchedCases.watchedCasesDetails
|
||||
: props.props.searchResultsObj.searchDetailsObj;
|
||||
|
||||
var detailsObj = {};
|
||||
|
||||
detailsObj = jsonpath({
|
||||
path:
|
||||
'$..[?(@ && @.pinswg_name=="' +
|
||||
currentView.caseReference.currentReference +
|
||||
currentView.caseReference.ticketnumber +
|
||||
'")]',
|
||||
json: setCaseDetailsObj,
|
||||
eval: true,
|
||||
eval: true
|
||||
});
|
||||
|
||||
let setCaseResultssObj = router.query.hasOwnProperty("state")
|
||||
? router.query.state == "edit"
|
||||
? props.props.myRepresentations.myRepresentations
|
||||
: currentView.caseReference.currentType == "watchedCases"
|
||||
? props.props.watchedCases.watchedCases
|
||||
: props.props.searchResultsObj.searchResultsObj
|
||||
? props.props.watchedCases.watchedCases
|
||||
: props.props.searchResultsObj.searchResultsObj
|
||||
: currentView.caseReference.currentType == "watchedCases"
|
||||
? props.props.watchedCases.watchedCases
|
||||
: props.props.searchResultsObj.searchResultsObj;
|
||||
? props.props.watchedCases.watchedCases
|
||||
: props.props.searchResultsObj.searchResultsObj;
|
||||
|
||||
detailsObj = detailsObj[0];
|
||||
|
||||
@@ -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"
|
||||
@@ -1213,7 +1213,10 @@ let Enforcement_Questionnaire = (props) => {
|
||||
name={"representationDocuments"}
|
||||
id={"representationDocuments"}
|
||||
label={t("myrepresentations:add-files-label")}
|
||||
ticketnumber={props.props.props.caseReference}
|
||||
ticketnumber={
|
||||
props.props.currentView.caseReference
|
||||
.ticketnumber
|
||||
}
|
||||
hint={"sdsd"}
|
||||
fileList={
|
||||
props.currentView.fileList
|
||||
@@ -1309,7 +1312,7 @@ Enforcement_Questionnaire = connect((state) => {
|
||||
|
||||
return {
|
||||
procedureTypeValue,
|
||||
representationTypeValue,
|
||||
representationTypeValue
|
||||
};
|
||||
})(Enforcement_Questionnaire);
|
||||
|
||||
@@ -1320,7 +1323,7 @@ const mapDispatchToProps = (dispatch) => {
|
||||
|
||||
setFilesForRepresentations: (fileList) => {
|
||||
dispatch(setFilesForRepresentations(fileList));
|
||||
},
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1332,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
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1343,6 +1346,6 @@ export default connect(
|
||||
reduxForm({
|
||||
form: "representationForm",
|
||||
enableReinitialize: false,
|
||||
destroyOnUnmount: false,
|
||||
destroyOnUnmount: false
|
||||
})(Enforcement_Questionnaire)
|
||||
);
|
||||
|
||||
+54
-50
@@ -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) => (
|
||||
@@ -52,32 +53,32 @@ let S78_Questionnaire = (props) => {
|
||||
? router.query.state == "edit"
|
||||
? props.props.myRepresentations.myRepresentations
|
||||
: currentView.caseReference.currentType == "watchedCases"
|
||||
? props.props.watchedCases.watchedCasesDetails
|
||||
: props.props.searchResultsObj.searchDetailsObj
|
||||
? props.props.watchedCases.watchedCasesDetails
|
||||
: props.props.searchResultsObj.searchDetailsObj
|
||||
: currentView.caseReference.currentType == "watchedCases"
|
||||
? props.props.watchedCases.watchedCasesDetails
|
||||
: props.props.searchResultsObj.searchDetailsObj;
|
||||
? props.props.watchedCases.watchedCasesDetails
|
||||
: props.props.searchResultsObj.searchDetailsObj;
|
||||
|
||||
var detailsObj = {};
|
||||
|
||||
detailsObj = jsonpath({
|
||||
path:
|
||||
'$..[?(@ && @.pinswg_name=="' +
|
||||
currentView.caseReference.currentReference +
|
||||
'$..[?(@ && @.ticketnumber=="' +
|
||||
currentView.caseReference.ticketnumber +
|
||||
'")]',
|
||||
json: setCaseDetailsObj,
|
||||
eval: true,
|
||||
eval: true
|
||||
});
|
||||
|
||||
let setCaseResultssObj = router.query.hasOwnProperty("state")
|
||||
? router.query.state == "edit"
|
||||
? props.props.myRepresentations.myRepresentations
|
||||
: currentView.caseReference.currentType == "watchedCases"
|
||||
? props.props.watchedCases.watchedCases
|
||||
: props.props.searchResultsObj.searchResultsObj
|
||||
? props.props.watchedCases.watchedCases
|
||||
: props.props.searchResultsObj.searchResultsObj
|
||||
: currentView.caseReference.currentType == "watchedCases"
|
||||
? props.props.watchedCases.watchedCases
|
||||
: props.props.searchResultsObj.searchResultsObj;
|
||||
? props.props.watchedCases.watchedCases
|
||||
: props.props.searchResultsObj.searchResultsObj;
|
||||
|
||||
detailsObj = detailsObj[0];
|
||||
|
||||
@@ -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"
|
||||
@@ -1022,7 +1023,10 @@ let S78_Questionnaire = (props) => {
|
||||
name={"representationDocuments"}
|
||||
id={"representationDocuments"}
|
||||
label={t("myrepresentations:add-files-label")}
|
||||
ticketnumber={props.props.props.caseReference}
|
||||
ticketnumber={
|
||||
props.props.currentView.caseReference
|
||||
.ticketnumber
|
||||
}
|
||||
hint={"sdsd"}
|
||||
fileList={
|
||||
props.currentView.fileList
|
||||
@@ -1117,7 +1121,7 @@ S78_Questionnaire = connect((state) => {
|
||||
|
||||
return {
|
||||
procedureTypeValue,
|
||||
representationTypeValue,
|
||||
representationTypeValue
|
||||
};
|
||||
})(S78_Questionnaire);
|
||||
|
||||
@@ -1128,7 +1132,7 @@ const mapDispatchToProps = (dispatch) => {
|
||||
|
||||
setFilesForRepresentations: (fileList) => {
|
||||
dispatch(setFilesForRepresentations(fileList));
|
||||
},
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1140,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
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1151,6 +1155,6 @@ export default connect(
|
||||
reduxForm({
|
||||
form: "representationForm",
|
||||
enableReinitialize: false,
|
||||
destroyOnUnmount: false,
|
||||
destroyOnUnmount: false
|
||||
})(S78_Questionnaire)
|
||||
);
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
import RepresentationTimetablePanel from "./RepresentationTimetablePanel";
|
||||
|
||||
const RepresentationFlowFormStage = ({
|
||||
t,
|
||||
appealIsConsultation,
|
||||
currentReference,
|
||||
whichControl,
|
||||
appealIsLocalImpact,
|
||||
renderDueDate,
|
||||
renderStatementsDue,
|
||||
renderMarineImpact,
|
||||
renderConsultationClose,
|
||||
renderFinalCommentsDue,
|
||||
isQuestionnaire,
|
||||
whichProgress
|
||||
}) => {
|
||||
return (
|
||||
<>
|
||||
<h1 className="govuk-heading-l">
|
||||
{appealIsConsultation
|
||||
? t("myrepresentations:make-a-consultation-on-label")
|
||||
: t(
|
||||
"myrepresentations:make-a-representation-on-label"
|
||||
)}{" "}
|
||||
{currentReference}{" "}
|
||||
</h1>
|
||||
|
||||
<div id="rep-form">
|
||||
<div className="govuk-grid-column-three-quarters wgForm">
|
||||
{whichControl()}
|
||||
</div>
|
||||
|
||||
<RepresentationTimetablePanel
|
||||
t={t}
|
||||
appealIsConsultation={appealIsConsultation}
|
||||
appealIsLocalImpact={appealIsLocalImpact}
|
||||
renderDueDate={renderDueDate}
|
||||
renderStatementsDue={renderStatementsDue}
|
||||
renderMarineImpact={renderMarineImpact}
|
||||
renderConsultationClose={renderConsultationClose}
|
||||
renderFinalCommentsDue={renderFinalCommentsDue}
|
||||
isQuestionnaire={isQuestionnaire}
|
||||
whichProgress={whichProgress}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default RepresentationFlowFormStage;
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user