Author SHA1 Message Date
Robert Bond 4cbc674788 Merged PR 2068: Set portal to readonly
Related work items: #21227
2026-01-30 10:24:07 +00:00
robbond 46bc5d1006 pass showlogin vars to pages and components 2026-01-28 13:31:19 +00:00
robbond b790facf56 redirect login attempts to status page 2026-01-28 13:30:27 +00:00
robbond c8f43710d3 service banner annpouncement and display logic 2026-01-28 13:30:05 +00:00
robbond c40d2df1e9 announcement page 2026-01-28 13:29:26 +00:00
632 changed files with 32480 additions and 112490 deletions
-176
View File
@@ -1,176 +0,0 @@
# 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.
-95
View File
@@ -1,95 +0,0 @@
# 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.
-234
View File
@@ -1,234 +0,0 @@
# 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.
-15
View File
@@ -1,15 +0,0 @@
# 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
-17
View File
@@ -1,17 +0,0 @@
# 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
@@ -1,18 +0,0 @@
# 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
-17
View File
@@ -1,17 +0,0 @@
# 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
@@ -1,10 +0,0 @@
# 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
@@ -1,16 +0,0 @@
# 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
-13
View File
@@ -1,13 +0,0 @@
# 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
-16
View File
@@ -1,16 +0,0 @@
# 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
-16
View File
@@ -1,16 +0,0 @@
# 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
@@ -1,15 +0,0 @@
# 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
+65 -72
View File
@@ -18,8 +18,7 @@ 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/ 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" RELAYURI = "ar-ns-lz-pedw-dev-uks-01.servicebus.windows.net"
RELAYPATH = "ar-hc-lz-pedw-dev-uks-01" RELAYPATH = "ar-hc-lz-pedw-dev-uks-01"
CRMURL = "dv-pedw.crm11.dynamics.com" CRMURL = "devcrm2016.llcdt.gov.wales/DVPINS"
CRMURL_VERSION = "v9.2"
# //New Test # //New Test
CLIENT_ID = d40b9373-96c2-4b04-8bd8-c2a2fe6444c1 CLIENT_ID = d40b9373-96c2-4b04-8bd8-c2a2fe6444c1
@@ -27,19 +26,18 @@ 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/ 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" RELAYURI = "ar-ns-lz-pedw-test-uks-01.servicebus.windows.net"
RELAYPATH = "ar-hc-lz-pedw-test-uks-01" RELAYPATH = "ar-hc-lz-pedw-test-uks-01"
# CRMURL = "tscrm2016.llcdt.gov.wales/UATPINS" CRMURL = "tscrm2016.llcdt.gov.wales/UATPINS"
# CRMURL_VERSION = "v8.2"
CRMURL = "ts-pedw.crm11.dynamics.com"
CRMURL_VERSION = "v9.2"
# //New PreProd # # //New PreProd
CLIENT_ID = ab6c4678-b31a-4eb3-b429-e039120e488a # CLIENT_ID = ab6c4678-b31a-4eb3-b429-e039120e488a
CLIENT_SECRET = VWY8Q~9EtRzGXpd8Xs~5OS1fej2IyVJ8JgTMncw3 # 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/ # 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" # RELAYURI = "ar-ns-lz-pedw-ppe-uks-01.servicebus.windows.net"
RELAYPATH = "ar-hc-lz-pedw-ppe-uks-01" # RELAYPATH = "ar-hc-lz-pedw-ppe-uks-01"
CRMURL = "wg-pp-pedw.crm11.dynamics.com" # # RELAY_ROOT = https://ar-ns-lz-pedw-ppe-ukw-01.servicebus.windows.net/ar-hc-lz-pedw-ppe-ukw-01/
CRMURL_VERSION = "v9.2" # # 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"
# //Prod Oauth WGO # //Prod Oauth WGO
@@ -51,27 +49,28 @@ CRMURL_VERSION = "v9.2"
# CRMURL = "crm2016.llc.gov.wales/PEDW" # CRMURL = "crm2016.llc.gov.wales/PEDW"
# //New Prod # //New Prod
# CLIENT_ID = 3e4141a3-1fbd-454e-98f0-7f3a4f14a3cc CLIENT_ID = 3e4141a3-1fbd-454e-98f0-7f3a4f14a3cc
# CLIENT_SECRET = ULC8Q~fZiXm0.teVLlZ_7LjxBOj2vIsWSApu2bAq CLIENT_SECRET = tFk8Q~E.R-HFjROTu1sRKqwb_ONzy05uPYoF6awR
# RELAY_ROOT = https://ar-ns-lz-pedw-prod-uks-01.servicebus.windows.net/ar-hc-lz-pedw-prod-uks-01/ 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" RELAYURI = "ar-ns-lz-pedw-prod-uks-01.servicebus.windows.net"
# RELAYPATH = "ar-hc-lz-pedw-prod-uks-01" RELAYPATH = "ar-hc-lz-pedw-prod-uks-01"
# CRMURL = "crm2016.llc.gov.wales/PEDW" # RELAY_ROOT = https://ar-ns-lz-pedw-ppe-ukw-01.servicebus.windows.net/ar-hc-lz-pedw-prod-ukw-01/
# CRMURL_VERSION = "v8.2" # RELAYURI = "ar-ns-lz-pedw-prod-ukw-01.servicebus.windows.net"
# RELAYPATH = "ar-hc-lz-pedw-prod-ukw-01"
CRMURL = "crm2016.llcdt.gov.wales/PEDW"
//GOOGLE_TAG_MANAGER = GTM-T78CBC3
GOOGLE_TAG_MANAGER = G-GTWW3JT03Z GOOGLE_TAG_MANAGER = G-GTWW3JT03Z
SHOWLOGIN = true SHOWLOGIN = true
SHOWREPRESENTATIONS = true SHOWREPRESENTATIONS = true
SHOWFILEUPLOAD = "false" SHOWFILEUPLOAD = "false"
SHOWMAPS = true SHOWMAPS = false
API_ROOT = "http://localhost:3000" API_ROOT = "http://localhost:3000"
CY_API_ROOT = "http://cymru.local:3000" CY_API_ROOT = "http://cymru.local:3000"
I18N_DOMAIN = "cymru.local" I18N_DOMAIN = "cymru.local"
# DOCAPI_OFFLINE = "07:00:00,16:00:00" # DOCAPI_OFFLINE = "12:00:00,14:00:00"
DOCAPI_OFFLINE = "01:00:00,04:00:00" DOCAPI_OFFLINE = "02:00:00,04:00:00"
SHOWFILTERDOCS = true SHOWFILTERDOCS = true
@@ -80,95 +79,94 @@ NEXTAUTH_URL = $API_ROOT
NEXTAUTH_URL_INTERNAL = $API_ROOT NEXTAUTH_URL_INTERNAL = $API_ROOT
NEXTAUTH_SECRET = SuperSecret NEXTAUTH_SECRET = SuperSecret
# CNR sql server // CNR sql server
# DATABASE_URL = sqlserver://sql-srv-plt-pedw-cnr-uks-01.database.windows.net:1433;database=PEDW;user=PedwSqlAdmin;password=GhWKr62F5sQ69dZx;encrypt=true;trustServerCertificate=true;hostNameInCertificate=*.database.windows.net;loginTimeout=30;authentication=ActiveDirectoryPassword 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 // dev test sql server
DATABASE_URL = sqlserver://sql-srv-plt-pedw-dev-uks-01.database.windows.net:1433;database=PEDW;user=PedwSqlAdmin;password=GhWKr62F5sQ69dZx;encrypt=true;trustServerCertificate=true;hostNameInCertificate=*.database.windows.net;loginTimeout=30;authentication=ActiveDirectoryPassword # 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
# test sql server // test sql server
DATABASE_URL = sqlserver://sql-srv-plt-pedw-test-uks-01.database.windows.net:1433;database=PEDW;user=PedwSqlAdmin;password=GhWKr62F5sQ69dZx;encrypt=true;trustServerCertificate=true;hostNameInCertificate=*.database.windows.net;loginTimeout=30;authentication=ActiveDirectoryPassword 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
# Prod sql server // Pre prod sql server
# DATABASE_URL = sqlserver://sql-srv-plt-pedw-ppe-uks-01.database.windows.net:1433;database=PEDW;user=PedwSqlAdmin;password=GhWKr62F5sQ69dZx;encrypt=true;trustservercertificate=true;hostnameincertificate=*.database.windows.net;logintimeout=30;authentication=SqlPassword
// Prod sql server
# 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 # 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 // 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 DATABASE_URL = sqlserver://sql-srv-plt-pedw-prod-uks-01.database.windows.net:1433;database=PEDW;user=PedwSqlAdmin;password=GhWKr62F5sQ69dZx;encrypt=true;trustServerCertificate=true;hostNameInCertificate=*.database.windows.net;loginTimeout=30;authentication=ActiveDirectoryPassword
SECRET = SuperSecret SECRET = SuperSecret
# Azure Storage Account //Azure Storage Account
AZURE_CLIENT_ID = $CLIENT_ID AZURE_CLIENT_ID = $CLIENT_ID
AZURE_TENANT_ID = $TENANT AZURE_TENANT_ID = $TENANT
AZURE_CLIENT_SECRET = $CLIENT_SECRET AZURE_CLIENT_SECRET = $CLIENT_SECRET
# CNR key // CNR key
AZURE_STORAGE_ACCOUNT_NAME = "sapltpedwcnruks" AZURE_STORAGE_ACCOUNT_NAME = "sapltpedwcnruks"
AZURE_STORAGE_ACCOUNT_KEY = hRffHq4IwctpaTKdS/U33Xq6nyTDF1t++WJgIwsw7gzstktZin/rRwbTIAL9KKqesVsK7EHrTTG6+ASt4+7skw== AZURE_STORAGE_ACCOUNT_KEY = hRffHq4IwctpaTKdS/U33Xq6nyTDF1t++WJgIwsw7gzstktZin/rRwbTIAL9KKqesVsK7EHrTTG6+ASt4+7skw==
AZURE_PEDW_STORAGE_ENDPOINT = https://sapltpedwcnruks.blob.core.windows.net AZURE_PEDW_STORAGE_ENDPOINT = https://sapltpedwcnruks.blob.core.windows.net
# new dev key // new dev key
AZURE_STORAGE_ACCOUNT_NAME = "sapltpedwdevuks" AZURE_STORAGE_ACCOUNT_NAME = "sapltpedwdevuks"
AZURE_STORAGE_ACCOUNT_KEY = MmrsrCjBfop9pI2oImsP/+lJUWU2DrXsAB8nq5bOVROTmPovSGxjCjKw9+TAFr00k8WDUK9r6mVx+AStcMLyAA== AZURE_STORAGE_ACCOUNT_KEY = MmrsrCjBfop9pI2oImsP/+lJUWU2DrXsAB8nq5bOVROTmPovSGxjCjKw9+TAFr00k8WDUK9r6mVx+AStcMLyAA==
AZURE_PEDW_STORAGE_ENDPOINT = https://sapltpedwdevuks.blob.core.windows.net AZURE_PEDW_STORAGE_ENDPOINT = https://sapltpedwdevuks.blob.core.windows.net
# New test key // New test key
AZURE_STORAGE_ACCOUNT_NAME = "sapltpedwtestuks" AZURE_STORAGE_ACCOUNT_NAME = "sapltpedwtestuks"
# AZURE_STORAGE_ACCOUNT_KEY = 5NdDO9GGlbTFLHFOXZRw8H2C0Ow5bFTvHwUHEbStyzg2mbd1uwHSeBSvM/dkN+HfdwrFzqAkwL5P+AStdO6cig==
AZURE_STORAGE_ACCOUNT_KEY = bqJAz5pYQVGee8dnVhlsqW+xHwinNTjgY2AmojNyB+d4uAotMR20WcO4Op13yB+9dFaXAkkjtIA4+AStHT/IYg== AZURE_STORAGE_ACCOUNT_KEY = bqJAz5pYQVGee8dnVhlsqW+xHwinNTjgY2AmojNyB+d4uAotMR20WcO4Op13yB+9dFaXAkkjtIA4+AStHT/IYg==
AZURE_PEDW_STORAGE_ENDPOINT = https://sapltpedwtestuks.blob.core.windows.net AZURE_PEDW_STORAGE_ENDPOINT = https://sapltpedwtestuks.blob.core.windows.net
# New preprod key // New preprod key
AZURE_STORAGE_ACCOUNT_NAME = "sapltpedwppeuks" # AZURE_STORAGE_ACCOUNT_NAME = "sapltpedwppeuks"
AZURE_STORAGE_ACCOUNT_KEY = B4GRKr+cA9b9mNM/GHFivzhzflJIZltG8bMmooXlYvGYySPAspTTHistAT30sHipnR+hh6dqUc9q+ASttAjPRQ== # AZURE_STORAGE_ACCOUNT_KEY = B4GRKr+cA9b9mNM/GHFivzhzflJIZltG8bMmooXlYvGYySPAspTTHistAT30sHipnR+hh6dqUc9q+ASttAjPRQ==
AZURE_PEDW_STORAGE_ENDPOINT = https://sapltpedwppeuks.blob.core.windows.net # AZURE_PEDW_STORAGE_ENDPOINT = https://sapltpedwppeuks.blob.core.windows.net
# PROD key // PROD key
# AZURE_STORAGE_ACCOUNT_NAME = "pedwprod" # AZURE_STORAGE_ACCOUNT_NAME = "pedwprod"
# AZURE_STORAGE_ACCOUNT_KEY = koZ46STRqapSa2Dod8MLL6aju1eYLhhyJ6DXpCLMTnFLJvbDT6CHUv/jwr5U/Ta8a60MWzwToHQy+AStADO7sg== # AZURE_STORAGE_ACCOUNT_KEY = koZ46STRqapSa2Dod8MLL6aju1eYLhhyJ6DXpCLMTnFLJvbDT6CHUv/jwr5U/Ta8a60MWzwToHQy+AStADO7sg==
# AZURE_PEDW_STORAGE_ENDPOINT = https://pedwprod.blob.core.windows.net # AZURE_PEDW_STORAGE_ENDPOINT = https://pedwprod.blob.core.windows.net
# New PROD key # // New PROD key
# AZURE_STORAGE_ACCOUNT_NAME = "sapltpedwproduks" AZURE_STORAGE_ACCOUNT_NAME = "sapltpedwproduks"
# AZURE_STORAGE_ACCOUNT_KEY = OfV9MFqXcLLPam9GhEdMWadIOwIzhc5hd5TUqzIuQoswFdtV4ybaemjatSv+Kht0Ny1qQKjLplwY+AStUTZJrg== AZURE_STORAGE_ACCOUNT_KEY = OfV9MFqXcLLPam9GhEdMWadIOwIzhc5hd5TUqzIuQoswFdtV4ybaemjatSv+Kht0Ny1qQKjLplwY+AStUTZJrg==
# AZURE_PEDW_STORAGE_ENDPOINT = https://sapltpedwproduks.blob.core.windows.net AZURE_PEDW_STORAGE_ENDPOINT = https://sapltpedwproduks.blob.core.windows.net
AZURE_PEDW_CONTAINER = "pedwapplications" AZURE_PEDW_CONTAINER = "pedwapplications"
AZURE_PEDW_QUEUE_ENDPOINT = https://$AZURE_STORAGE_ACCOUNT_NAME.queue.core.windows.net AZURE_PEDW_QUEUE_ENDPOINT = https://$AZURE_STORAGE_ACCOUNT_NAME.queue.core.windows.net
# gov.notify //gov.notify
# NOTIFY_API_KEY = pedwnextauthkey-90f93710-9dae-423e-aea1-11eccd0dc132-0c9469d9-d671-444d-9e9d-3e5a62001043 //NOTIFY_API_KEY = pedwnextauthkey-90f93710-9dae-423e-aea1-11eccd0dc132-0c9469d9-d671-444d-9e9d-3e5a62001043
# NOTIFY_API_KEY = pedwnextauthlivekey-90f93710-9dae-423e-aea1-11eccd0dc132-5c0ed187-754a-4b04-8c99-978e5710c2c1 NOTIFY_API_KEY = pedwnextauthlivekey-90f93710-9dae-423e-aea1-11eccd0dc132-5c0ed187-754a-4b04-8c99-978e5710c2c1
NOTIFY_API_KEY = pedwnextauthlive01key-90f93710-9dae-423e-aea1-11eccd0dc132-72bfb1e1-c0b7-47cb-9887-3d47a4b11ad4
SHOW_DEBUG = true SHOW_DEBUG = true
# DEV Connection string // 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 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
# Preprod Connection string // Test 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=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=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 // 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
# Prod Connection string 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=61f358c2-8075-4164-b897-17bc6dd31fee;IngestionEndpoint=https://ukwest-0.in.applicationinsights.azure.com/;LiveEndpoint=https://ukwest.livediagnostics.monitor.azure.com/;ApplicationId=0c297349-396b-4dc6-8b56-85f5c680adc6
// Prod Connection string
//NEXT_PUBLIC_APP_INSIGHT = InstrumentationKey=61f358c2-8075-4164-b897-17bc6dd31fee;IngestionEndpoint=https://ukwest-0.in.applicationinsights.azure.com/;LiveEndpoint=https://ukwest.livediagnostics.monitor.azure.com/;ApplicationId=0c297349-396b-4dc6-8b56-85f5c680adc6
HIDEERRORLOGS = false HIDEERRORLOGS = false
@@ -176,8 +174,3 @@ HIDEERRORLOGS = false
SHOWSIPS = true SHOWSIPS = true
ALLOWED_IPS=::1,203.0.113.42,198.51.100.17 ALLOWED_IPS=::1,203.0.113.42,198.51.100.17
UPLOAD_BATCH_COUNT = 5
NRWDOMAIN = rdbmedia.co.uk
MAP_TARGET = pedw-dev
-8
View File
@@ -48,11 +48,3 @@ gitclean.sh
pages/admin/logcheck.js pages/admin/logcheck.js
pages/admin/logchecker.js pages/admin/logchecker.js
pages/baracuda.html pages/baracuda.html
pages/holding-min.html
pages/holding.html
# Cline / AI-assistant governance artifacts (keep local-only)
ai-prompts/
pages/baracuda.min.html
+1 -2
View File
@@ -1,6 +1,5 @@
{ {
"tabWidth": 4, "tabWidth": 4,
"useTabs": false, "useTabs": false,
"quoteProps": "preserve", "quoteProps":"preserve"
"trailingComma": "none"
} }
+1 -1
View File
@@ -11,7 +11,7 @@
"command": "npm run dev" "command": "npm run dev"
}, },
{"name": "Launch Chrome against localhost", {"name": "Launch Chrome against localhost",
"type": "chrome", "type": "pwa-chrome",
"request": "launch", "request": "launch",
"url": "http://localhost:3000", "url": "http://localhost:3000",
"webRoot": "${workspaceFolder}" "webRoot": "${workspaceFolder}"
-46
View File
@@ -1,46 +0,0 @@
# 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
View File
@@ -1,25 +0,0 @@
# 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"]
-85
View File
@@ -1,85 +0,0 @@
# PEDW FrontEnd Guardrails
## Purpose
This document is a fast pre-flight checklist to reduce regressions in high-risk areas. Use it before coding, before opening a PR, and before merge.
## Non-Negotiable Guardrails
1. **Auth/session integrity**
- Do not bypass `next-auth` flow in `pages/api/auth/[...nextauth].js`.
- Preserve secure redirect behavior and cookie/session settings.
2. **Security headers and CSP**
- Do not weaken `middleware.js` CSP/header behavior or `next.config.js` security headers without explicit rationale.
3. **Data model safety**
- Treat `prisma/schema.prisma` as source-of-truth for auth/account persistence.
4. **Bilingual parity (EN/CY)**
- Any user-facing route/content change must validate both locales.
- Keep `i18n.js`, `locales/`, and `next.config.js` rewrites aligned.
5. **Public-service reliability**
- Avoid breaking core flows: search, case, account, myportal, admin.
## Sensitive Flow Protection
Apply extra checks for:
- `pages/api/auth/**`
- `pages/api/file/**`
- `pages/api/email/**`
- `pages/api/endpoint/*_api.js` handling account/user data
## Relay Hash Integrity Rules (CRM-bound APIs)
Apply when changing relay-bound portal endpoints and helpers (notably `pages/api/endpoint/**` and `actions/index.js`):
1. Keep relay endpoint configuration sourced from `API_ROOT`.
2. Preserve path-hash generation behavior:
- hash input must be request path/query (excluding domain),
- appended hash parameter must remain compatible with relay expectations.
3. Do not change hash algorithm/key usage contract without coordinated relay change.
4. Treat hash validation failures as security-relevant negative paths; verify graceful rejection handling.
5. Never log hash key material or sensitive request payloads.
Required for sensitive changes:
- Negative-path validation (unauthorized, invalid input, malformed payload).
- Safe logging (no secrets/tokens/personal data in cleartext).
- Explicit rollback steps.
## Relay Policy Change Guardrail (timeouts/retries/logging)
When changing shared relay forwarding policy (for example in `pages/api/middleware/relayForwarding.js`), treat this as an operationally sensitive change even if endpoint contracts are unchanged.
Minimum required before merge:
1. Complete the relay governance gate in `context/runbook.md` (Relay Hardening Rollout Playbook).
2. Attach non-prod smoke evidence for:
- deterministic non-retry classes (`400`, `401`, `403`, `404`)
- transient retry classes (`429`, `503`, timeout/network-transient)
3. Confirm structured redacted logging and duplicate-log suppression behavior.
4. Provide fast mitigation + rollback path (`RELAY_RETRY_MAX=0` and commit-revert path).
## Pre-PR Quick Checklist
- [ ] Ran `npm run lint` (or documented why unavailable)
- [ ] Verified changed routes/APIs manually
- [ ] Verified EN + CY behavior for impacted user-facing flow
- [ ] Performed accessibility smoke checks (keyboard, focus, labels, headings)
- [ ] Added risk notes (auth/data/i18n/a11y)
- [ ] Updated `memory-bank/change-log.md` for non-trivial changes
## If Assumptions Are Unclear
1. Record assumptions in PR notes.
2. Add unresolved items to `memory-bank/open-questions.md`.
3. Choose the safer behavior and clearly mark as temporary.
## Related Docs
- `.clinerules`
- `CONTRIBUTING_AI.md`
- `context/implementation-governance.md`
- `context/maintainability-adoption-programme.md`
- `context/runbook.md`
- `context/integration-map.md`
- `memory-bank/README.md`
Vendored
-50
View File
@@ -1,50 +0,0 @@
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
'
"""
}
}
}
}
}
+249 -284
View File
@@ -1,7 +1,7 @@
import { DefaultAzureCredential } from "@azure/identity"; import { DefaultAzureCredential } from "@azure/identity";
import _ from "lodash"; import _ from "lodash";
import { hashAPIPath, consoleLogger } from "."; import { hashAPIPath, consoleLogger } from ".";
import { getDocumentTypeFromFilename, hasOwn } from "../components/utils"; import { getDocumentTypeFromFilename } from "../components/utils";
const { const {
ContainerClient, ContainerClient,
@@ -11,7 +11,7 @@ const {
ContainerSASPermissions, ContainerSASPermissions,
generateBlobSASQueryParameters, generateBlobSASQueryParameters,
SASProtocol SASProtocol,
} = require("@azure/storage-blob"); } = require("@azure/storage-blob");
const { const {
QueueServiceClient, QueueServiceClient,
@@ -23,7 +23,7 @@ const {
generateAccountSASQueryParameters, generateAccountSASQueryParameters,
generateQueueSASQueryParameters, generateQueueSASQueryParameters,
StorageSharedKeyCredential, StorageSharedKeyCredential,
QueueClient QueueClient,
} = require("@azure/storage-queue"); } = require("@azure/storage-queue");
const STORAGE_PATH = process.env.AZURE_PEDW_STORAGE_ENDPOINT; const STORAGE_PATH = process.env.AZURE_PEDW_STORAGE_ENDPOINT;
const STORAGE_CONTAINER = process.env.AZURE_PEDW_CONTAINER; const STORAGE_CONTAINER = process.env.AZURE_PEDW_CONTAINER;
@@ -31,88 +31,6 @@ const QUEUE_PATH = process.env.AZURE_PEDW_QUEUE_ENDPOINT;
const accountName = process.env.AZURE_STORAGE_ACCOUNT_NAME; 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) => { export const createContainerSas = async (containerName) => {
// Get environment variables // Get environment variables
@@ -149,7 +67,7 @@ export const createContainerSas = async (containerName) => {
permissions: ContainerSASPermissions.parse(containerPermissions), permissions: ContainerSASPermissions.parse(containerPermissions),
protocol: SASProtocol.HttpsAndHttp, protocol: SASProtocol.HttpsAndHttp,
startsOn: TEN_MINUTES_BEFORE_NOW, startsOn: TEN_MINUTES_BEFORE_NOW,
expiresOn: TEN_MINUTES_AFTER_NOW expiresOn: TEN_MINUTES_AFTER_NOW,
}; };
// console.log( // console.log(
@@ -208,7 +126,7 @@ export const createBlobSas = async (containerName, blobName) => {
permissions: BlobSASPermissions.parse(blobPermissionsForAnonymousUser), permissions: BlobSASPermissions.parse(blobPermissionsForAnonymousUser),
protocol: SASProtocol.HttpsAndHttp, protocol: SASProtocol.HttpsAndHttp,
startsOn: TEN_MINUTES_BEFORE_NOW, startsOn: TEN_MINUTES_BEFORE_NOW,
expiresOn: TEN_MINUTES_AFTER_NOW expiresOn: TEN_MINUTES_AFTER_NOW,
}; };
const sasToken = generateBlobSASQueryParameters( const sasToken = generateBlobSASQueryParameters(
@@ -269,38 +187,61 @@ export const getBlobs = async (containerName, casefolderID) => {
const blobObj = []; const blobObj = [];
for await (const blob of containerClient.listBlobsFlat({ for await (const blob of containerClient.listBlobsFlat({
prefix: casefolderID + "/files/" prefix: casefolderID + "/files/",
})) { })) {
const blobPathParts = blob.name.split("/"); let blobDocumentType = blob.name
const fileName = blobPathParts[2]; .split("/")[2]
const contentLength = blob.properties.contentLength; .slice(0, blob.name.split("/")[2].indexOf("_"));
blobObj.push({ blobObj.push({
"name": fileName, "name": blob.name.split("/")[2],
"path": blob.name, "path": blob.name,
"documentType": getDocumentTypeFromFilename(fileName), "documentType": getDocumentTypeFromFilename(
blob.name.split("/")[2]
),
"versionId": blob.versionId, "versionId": blob.versionId,
"caseObj": buildCaseObjectPath(casefolderID), "caseObj": casefolderID + "/" + casefolderID + "_case.json",
"isCurrentVersion": blob.isCurrentVersion, "isCurrentVersion": blob.isCurrentVersion,
"contentLength": contentLength, "contentLength": blob.properties.contentLength,
"size": contentLength, "size": blob.properties.contentLength,
"contentType": blob.contentType, "contentType": blob.contentType,
"lastModified": blob.properties.lastModified, "lastModified": blob.properties.lastModified,
"filepath": buildDownloadBlobQueryPath({ "filepath":
containerName, "/api/file/downloadblob?container=" +
casefolderID, containerName +
blobname: blob.name "&casefolderID=" +
}), encodeURIComponent(casefolderID) +
...buildHashMetadataPaths({ "&blobname=" +
containerName, encodeURIComponent(blob.name),
casefolderID, "hashedfilepath": hashAPIPath(
blobname: fileName "/api/file/downloadblob?container=" +
}), containerName +
"deletepath": buildDeleteBlobQueryPath({ "&casefolderID=" +
containerName, encodeURIComponent(casefolderID) +
casefolderID, "&blobname=" +
blobname: fileName encodeURIComponent(blob.name.split("/")[2])
}) ),
"deletepath":
"/api/file/deleteblob?container=" +
containerName +
"&casefolderID=" +
encodeURIComponent(casefolderID) +
"&blobname=" +
encodeURIComponent(blob.name.split("/")[2]),
"hasheddeletepath": hashAPIPath(
"/api/file/deleteblob?container=" +
containerName +
"&casefolderID=" +
encodeURIComponent(casefolderID) +
"&blobname=" +
encodeURIComponent(blob.name.split("/")[2])
),
"hashgetblobs": hashAPIPath(
"/api/file/getbloblist?container=" +
containerName +
"&casefolderID=" +
casefolderID
),
}); });
} }
//console.log("blobObj:", blobObj); //console.log("blobObj:", blobObj);
@@ -316,7 +257,7 @@ export const createBlob = async (formContent, containerName, caseref) => {
formContent = JSON.parse(formContent); formContent = JSON.parse(formContent);
let caseID = ""; let caseID = "";
caseID = hasOwn(formContent, "pinswg_name") caseID = _.has(formContent, "pinswg_name")
? formContent.pinswg_name ? formContent.pinswg_name
: caseref; : caseref;
@@ -336,7 +277,7 @@ export const createBlob = async (formContent, containerName, caseref) => {
const tags = { const tags = {
containerid: containerName, containerid: containerName,
caseID: caseID, caseID: caseID,
blobType: "Appeal" blobType: "Appeal",
}; };
//console.log("the tags:", tags); //console.log("the tags:", tags);
@@ -368,8 +309,8 @@ export const createRepBlob = async (formContent, containerName, caseref) => {
const tags = { const tags = {
containerid: containerName, containerid: containerName,
caseID: formContent.ticketnumber || formContent.caseRef, caseID: formContent.ticketnumber,
blobType: "Representation" blobType: "Representation",
}; };
//console.log("the tags:", tags); //console.log("the tags:", tags);
@@ -415,14 +356,12 @@ export const createAppealPDFBlob = async (
const uploadOptions = { const uploadOptions = {
blockSize: 4 * 1024 * 1024, // 4 MiB max block size blockSize: 4 * 1024 * 1024, // 4 MiB max block size
concurrency: 2, // maximum number of parallel transfer workers 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); console.log("blobName:", blobName);
const blockBlobClient = containerClient.getBlockBlobClient(blobName); const blockBlobClient = containerClient.getBlockBlobClient(blobName);
const uploadBlobResponse = Buffer.isBuffer(content) const uploadBlobResponse = await blockBlobClient.uploadStream(content);
? await blockBlobClient.uploadData(content)
: await blockBlobClient.uploadStream(content);
console.log(uploadBlobResponse); console.log(uploadBlobResponse);
let whichLocation = "846040000"; // Default value let whichLocation = "846040000"; // Default value
@@ -432,7 +371,7 @@ export const createAppealPDFBlob = async (
caseID: caseID, caseID: caseID,
blobType: "Appeal PDF", blobType: "Appeal PDF",
ishareLocation: whichLocation, ishareLocation: whichLocation,
documentLocationId: whichLocation documentLocationId: whichLocation,
}; };
//console.log("the tags:", tags); //console.log("the tags:", tags);
@@ -466,36 +405,33 @@ export const createRepPDFBlob = async (
const uploadOptions = { const uploadOptions = {
blockSize: 4 * 1024 * 1024, // 4 MiB max block size blockSize: 4 * 1024 * 1024, // 4 MiB max block size
concurrency: 2, // maximum number of parallel transfer workers 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); console.log("blobName:", blobName);
const blockBlobClient = containerClient.getBlockBlobClient(blobName); const blockBlobClient = containerClient.getBlockBlobClient(blobName);
const uploadBlobResponse = Buffer.isBuffer(content) const uploadBlobResponse = await blockBlobClient.uploadStream(content);
? await blockBlobClient.uploadData(content)
: await blockBlobClient.uploadStream(content);
const locationMap = [ let whichLocation =
{ key: "_IP_-_Comments_", value: "846040038" }, // most specific first repName.indexOf("_IP_") > 0
{ key: "_IP_", value: "846040005" }, ? "846040005"
{ key: "_Statement_", value: "846040002" }, : repName.indexOf("_Statement_") > 0
{ key: "_Questionnaire_", value: "846040001" }, ? "846040002"
{ key: "_Comments", value: "846040003" }, : repName.indexOf("_Questionnaire_") > 0
{ key: "_Impact", value: "846040029" }, ? "846040001"
{ key: "_Consultation_Response_", value: "846040036" } : repName.indexOf("_Comments") > 0
]; ? "846040003"
: repName.indexOf("_Impact") > 0
const whichLocation = ? "846040001"
locationMap.find((item) => repName.includes(item.key))?.value || : "846040002";
"846040002";
const tags = { const tags = {
containerid: containerName, containerid: containerName,
caseID: caseID, caseID: caseID,
blobType: "Representation PDF", blobType: "Representation PDF",
ishareLocation: whichLocation, ishareLocation: whichLocation,
documentLocationId: whichLocation documentLocationId: whichLocation,
}; };
//console.log("the tags:", tags); //console.log("the tags:", tags);
@@ -509,7 +445,7 @@ export const deleteBlob = async (containerName, blobName) => {
const creds = new DefaultAzureCredential(); const creds = new DefaultAzureCredential();
const options = { const options = {
deleteSnapshots: "include" // or 'only' deleteSnapshots: "include", // or 'only'
}; };
const containerToken = await createContainerSas(containerName); const containerToken = await createContainerSas(containerName);
@@ -529,7 +465,7 @@ export const deleteBlobCase = async (containerName, blobName) => {
const creds = new DefaultAzureCredential(); const creds = new DefaultAzureCredential();
const options = { const options = {
deleteSnapshots: "include" // or 'only' deleteSnapshots: "include", // or 'only'
}; };
const containerToken = await createContainerSas(containerName); const containerToken = await createContainerSas(containerName);
@@ -541,7 +477,7 @@ export const deleteBlobCase = async (containerName, blobName) => {
console.log("blob to delete:", blobName); console.log("blob to delete:", blobName);
for await (const blob of containerClient.listBlobsFlat({ for await (const blob of containerClient.listBlobsFlat({
prefix: blobName prefix: blobName,
})) { })) {
console.log(" ------ :", blob.name); console.log(" ------ :", blob.name);
containerClient.deleteBlob(blob.name); containerClient.deleteBlob(blob.name);
@@ -559,7 +495,7 @@ export const deleteBlobRep = async (containerName, blobName) => {
const creds = new DefaultAzureCredential(); const creds = new DefaultAzureCredential();
const options = { const options = {
deleteSnapshots: "include" // or 'only' deleteSnapshots: "include", // or 'only'
}; };
const containerToken = await createContainerSas(containerName); const containerToken = await createContainerSas(containerName);
@@ -569,7 +505,7 @@ export const deleteBlobRep = async (containerName, blobName) => {
console.log("blob to delete:", blobName); console.log("blob to delete:", blobName);
for await (const blob of containerClient.listBlobsFlat({ for await (const blob of containerClient.listBlobsFlat({
prefix: blobName prefix: blobName,
})) { })) {
console.log("------ :", blob.name); console.log("------ :", blob.name);
const blockBlobClient = containerClient.getBlockBlobClient(blob.name); const blockBlobClient = containerClient.getBlockBlobClient(blob.name);
@@ -617,46 +553,64 @@ export const uploadFile = async (formContent, containerName, foldername) => {
); );
console.log(data); console.log(data);
const fieldName = files[prop][0].fieldName; let whichLocation =
files[prop][0].fieldName.indexOf("_Statement_of_Case") >
const whichLocation = 0 ||
[ files[prop][0].fieldName.indexOf("_-_Statement_of_Case") >
// 1️⃣ LPA docs (grouped) 0 ||
{ files[prop][0].fieldName.indexOf("_-_Application_Form") >
match: [ 0 ||
"_Statement_of_Case", files[prop][0].fieldName.indexOf(
"_-_Statement_of_Case", "_-_Site_Ownership_Certificate"
"_-_Application_Form", ) > 0 ||
"_-_Site_Ownership_Certificate", files[prop][0].fieldName.indexOf("_-_Decision_Notice") >
"_-_Decision_Notice", 0 ||
"_-_Site_Location_Plan", files[prop][0].fieldName.indexOf("_-_Site_Location_Plan") >
"_-_Plans_Drawing_Documents", 0 ||
"_-_Additional_Plans_Drawings_Documents", files[prop][0].fieldName.indexOf(
"_-_Design_and_Access_Statement", "_-_Plans_Drawing_Documents"
"_-_NSB_LPA_Additional_Documents", ) > 0 ||
"_-_LPA_Correspondence", files[prop][0].fieldName.indexOf(
"_-_LPA_Original_Permission", "_-_Additional_Plans_Drawings_Documents"
"_-_LPA's_Registration_Letter", ) > 0 ||
"_-_Environmental_Statement", files[prop][0].fieldName.indexOf(
"_-_Cost_of_Application", "_-_Design_and_Access_Statement"
"_-_Other_Relevant_Material", ) > 0 ||
"_-_S106_Agreement_or_Unilateral_Undertaking" files[prop][0].fieldName.indexOf(
], "_-_NSB_LPA_Additional_Documents"
value: "846040000" ) > 0 ||
}, files[prop][0].fieldName.indexOf("_-_LPA_Correspondence") >
{ match: ["_IP_-_Comments_"], value: "846040038" }, 0 ||
{ files[prop][0].fieldName.indexOf(
match: ["_Consultation_Response_"], "_-_LPA_Original_Permission"
value: "846040036" ) > 0 ||
}, files[prop][0].fieldName.indexOf(
{ match: ["_Questionnaire_"], value: "846040001" }, "_-_LPA's_Registration_Letter"
{ match: ["_Statement_"], value: "846040002" }, ) > 0 ||
{ match: ["_Comments_"], value: "846040003" }, files[prop][0].fieldName.indexOf(
{ match: ["_Impact_"], value: "846040001" }, +"_-_Environmental_Statement"
{ match: ["_IP_"], value: "846040005" } ) > 0 ||
].find((rule) => files[prop][0].fieldName.indexOf("_-_Cost_of_Application") >
rule.match.some((key) => fieldName.includes(key)) 0 ||
)?.value || "846040000"; files[prop][0].fieldName.indexOf(
"_-_Other_Relevant_Material"
) > 0 ||
files[prop][0].fieldName.indexOf(
"_-_S106_Agreement_or_Unilateral_Undertaking" > 0
)
? "846040000"
: files[prop][0].fieldName.indexOf("_IP_") > 0
? "846040005"
: files[prop][0].fieldName.indexOf("_Statement_") > 0
? "846040002"
: files[prop][0].fieldName.indexOf("_Questionnaire_") >
0
? "846040001"
: files[prop][0].fieldName.indexOf("_Comments_") > 0
? "846040003"
: files[prop][0].fieldName.indexOf("_Impact_") > 0
? "846040001"
: "846040000";
const tags = { const tags = {
containerid: containerName, containerid: containerName,
@@ -664,7 +618,7 @@ export const uploadFile = async (formContent, containerName, foldername) => {
documentType: files[prop][0].fieldName.split(".")[1], documentType: files[prop][0].fieldName.split(".")[1],
blobType: "RepresentationFile", blobType: "RepresentationFile",
ishareLocation: whichLocation, ishareLocation: whichLocation,
documentLocationId: whichLocation documentLocationId: whichLocation,
}; };
const withTags = blockBlobClient.setTags(tags); const withTags = blockBlobClient.setTags(tags);
const withMeta = blockBlobClient.setMetadata(tags); const withMeta = blockBlobClient.setMetadata(tags);
@@ -775,16 +729,13 @@ export const uploadSingleFile = async (
{ {
pattern: 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/, /_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: /_IP_/, value: "846040005" },
{ pattern: /_Statement_/, value: "846040002" }, { pattern: /_Statement_/, value: "846040002" },
{ pattern: /_Questionnaire_/, value: "846040001" }, { pattern: /_Questionnaire_/, value: "846040001" },
{ pattern: /_Comments_/, value: "846040003" }, { pattern: /_Comments_/, value: "846040003" },
{ pattern: /_Impact_/, value: "846040001" }, { pattern: /_Impact_/, value: "846040001" },
{ pattern: /_Consultation_Response_/, value: "846040036" }
]; ];
// Find a matching pattern or fallback to default // Find a matching pattern or fallback to default
@@ -805,7 +756,7 @@ export const uploadSingleFile = async (
documentType: files[prop][0].fieldName.split(".")[1], documentType: files[prop][0].fieldName.split(".")[1],
blobType: "RepresentationFile", blobType: "RepresentationFile",
ishareLocation: whichLocation, ishareLocation: whichLocation,
documentLocationId: whichLocation documentLocationId: whichLocation,
}; };
const withTags = await blockBlobClient.setTags(tags); const withTags = await blockBlobClient.setTags(tags);
const withMeta = await blockBlobClient.setMetadata(tags); const withMeta = await blockBlobClient.setMetadata(tags);
@@ -842,7 +793,7 @@ export const uploadRepFiles = async (
const tags = { const tags = {
containerid: containerName, containerid: containerName,
caseID: formContent.split("tmp/")[0], caseID: formContent.split("tmp/")[0],
documentType: "Rep docs" documentType: "Rep docs",
}; };
console.log(tags); console.log(tags);
const withTags = await blockBlobClient.setTags(tags); const withTags = await blockBlobClient.setTags(tags);
@@ -887,7 +838,7 @@ export const uploadPDFRepFiles = async (
containerid: containerName, containerid: containerName,
caseID: foldername.split("/")[0], caseID: foldername.split("/")[0],
documentType: repType, documentType: repType,
blobType: "RepresentationPDF" blobType: "RepresentationPDF",
}; };
//console.log("the tags:", tags); //console.log("the tags:", tags);
@@ -940,7 +891,7 @@ export const uploadPDFAppealFiles = async (
const tags = { const tags = {
containerid: containerName, containerid: containerName,
caseID: foldername.split("/")[0], caseID: foldername.split("/")[0],
blobType: "AppealPDF" blobType: "AppealPDF",
}; };
//console.log("the tags:", tags); //console.log("the tags:", tags);
@@ -979,7 +930,7 @@ export const uploadPDFCaseFiles = async (
const tags = { const tags = {
containerid: containerName, containerid: containerName,
caseID: foldername.split("/")[0], caseID: foldername.split("/")[0],
blobType: "AppealPDF" blobType: "AppealPDF",
}; };
//console.log("the tags:", tags); //console.log("the tags:", tags);
@@ -1185,7 +1136,7 @@ export const downloadAllRepsFiles = async (containerName, repsBlobObj) => {
return { return {
"@odata.count": blobCount, "@odata.count": blobCount,
"value": downloaded "value": downloaded,
}; };
}; };
@@ -1224,7 +1175,7 @@ export const getCaseBlob = async (
const tags = { const tags = {
containerid: containerName, containerid: containerName,
caseID: caseReference, caseID: caseReference,
blobType: "Case" blobType: "Case",
}; };
//console.log("the tags:", tags); //console.log("the tags:", tags);
@@ -1255,7 +1206,7 @@ export const getProgressBlobs = async (containerName, caseReference) => {
let blobCount = 0; let blobCount = 0;
for await (const blob of containerClient.listBlobsFlat({ for await (const blob of containerClient.listBlobsFlat({
prefix: caseReference prefix: caseReference,
})) { })) {
blobCount++; blobCount++;
} }
@@ -1268,34 +1219,47 @@ export const getProgressBlobs = async (containerName, caseReference) => {
let blobObj = []; let blobObj = [];
for await (const blob of containerClient.listBlobsFlat({ for await (const blob of containerClient.listBlobsFlat({
prefix: caseReference + "/" + caseReference + "_appeal.json" prefix: caseReference + "/" + caseReference + "_appeal.json",
})) { })) {
const blobPathParts = blob.name.split("/"); console.log("getProgressBlobs in here", blob.name.split("/"));
const appealBlobName = blobPathParts[1];
const contentLength = blob.properties.contentLength;
//consoleLogger("getProgressBlobs in here", blobPathParts);
blobObj.push({ blobObj.push({
"name": appealBlobName, "name": blob.name.split("/")[1],
"path": blob.name, "path": blob.name,
"versionId": blob.versionId, "versionId": blob.versionId,
"caseObj": buildCaseObjectPath(caseReference), "caseObj": caseReference + "/" + caseReference + "_case.json",
"isCurrentVersion": blob.isCurrentVersion, "isCurrentVersion": blob.isCurrentVersion,
"contentLength": contentLength, "contentLength": blob.properties.contentLength,
"contentType": blob.contentType, "contentType": blob.contentType,
"lastModified": blob.properties.lastModified, "lastModified": blob.properties.lastModified,
...buildHashMetadataPaths({ "hashedfilepath": hashAPIPath(
containerName, "/api/file/downloadblob?container=" +
casefolderID: caseReference, containerName +
blobname: appealBlobName "&casefolderID=" +
}) encodeURIComponent(caseReference) +
"&blobname=" +
encodeURIComponent(blob.name.split("/")[1])
),
"hasheddeletepath": hashAPIPath(
"/api/file/deleteblob?container=" +
containerName +
"&casefolderID=" +
encodeURIComponent(caseReference) +
"&blobname=" +
encodeURIComponent(blob.name.split("/")[1])
),
"hashgetblobs": hashAPIPath(
"/api/file/getbloblist?container=" +
containerName +
"&casefolderID=" +
caseReference
),
}); });
} }
blobObj = _.sortBy(blobObj, [ blobObj = _.sortBy(blobObj, [
function (o) { function (o) {
return o.lastModified; return o.lastModified;
} },
]).reverse()[0]; ]).reverse()[0];
return blobObj; return blobObj;
@@ -1314,24 +1278,8 @@ export const getAllProgressBlobs = async (containerName) => {
for await (const blob of containerClient.findBlobsByTags( for await (const blob of containerClient.findBlobsByTags(
"blobType='Appeal'" "blobType='Appeal'"
)) { )) {
const namePart = blob.name.split("/")[1] ?? ""; blob.name.split("/")[1].indexOf("_appeal.json") > 0 &&
blob.name.split("/")[1].indexOf("undefined") < 0 &&
// 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({ blobObj.push({
"name": blob.name.split("/")[1], "name": blob.name.split("/")[1],
"path": blob.name, "path": blob.name,
@@ -1340,7 +1288,7 @@ export const getAllProgressBlobs = async (containerName) => {
blob.name.split("/")[0] + blob.name.split("/")[0] +
"/" + "/" +
blob.name.split("/")[0] + blob.name.split("/")[0] +
"_case.json" "_case.json",
// "isCurrentVersion": blob.isCurrentVersion, // "isCurrentVersion": blob.isCurrentVersion,
// "contentLength": blob.properties.contentLength, // "contentLength": blob.properties.contentLength,
// "contentType": blob.contentType, // "contentType": blob.contentType,
@@ -1397,7 +1345,7 @@ export const getRepsBlobs = async (containerName) => {
includeMetadata: true, includeMetadata: true,
includeSnapshots: false, includeSnapshots: false,
includeTags: true, includeTags: true,
includeVersions: true includeVersions: true,
}; };
let blobObj = []; let blobObj = [];
@@ -1406,27 +1354,14 @@ export const getRepsBlobs = async (containerName) => {
listOptions listOptions
)) { )) {
const blobClient = containerClient.getBlobClient(blob.name); const blobClient = containerClient.getBlobClient(blob.name);
//console.log("getreps blob:", blob);
// Filter out soft-deleted/stale tag entries and malformed names. blob.name.split("/")[2].indexOf("_rep.json") > 0 &&
const namePart = blob.name.split("/")[2] ?? ""; blob.name.split("/")[2].indexOf("undefined") < 0 &&
if (
namePart.indexOf("_rep.json") <= 0 ||
namePart.indexOf("undefined") >= 0
)
continue;
try {
const properties = await blobClient.getProperties();
blobObj.push({ blobObj.push({
"name": namePart, "name": blob.name.split("/")[2],
"path": blob.name, "path": blob.name,
"size": properties.contentLength "size": blobClient.getProperties().contentLength,
}); });
} catch (error) {
if (error?.statusCode === 404) continue;
throw error;
}
} }
//console.log("blobObjwwwww:", blobObj); //console.log("blobObjwwwww:", blobObj);
@@ -1449,43 +1384,73 @@ export const getRepsFilesBlobs = async (
const blobObj = []; const blobObj = [];
for await (const blob of containerClient.listBlobsFlat({ for await (const blob of containerClient.listBlobsFlat({
prefix: casefolderID + "/" + filenamePrefix + "/files/" prefix: casefolderID + "/" + filenamePrefix + "/files/",
})) { })) {
const blobPathParts = blob.name.split("/"); let blobDocumentType = blob.name
const casefolderPath = blobPathParts[0] + "/" + blobPathParts[1]; .split("/")[2]
const repFileName = blobPathParts[3]; .slice(0, blob.name.split("/")[2].indexOf("_"));
const contentLength = blob.properties.contentLength;
//consoleLogger(blob.name); console.log(blob.name);
blobObj.push({ blobObj.push({
"name": repFileName, "name": blob.name.split("/")[3],
"path": blob.name, "path": blob.name,
"documentType": getDocumentTypeFromFilename(repFileName), "documentType": getDocumentTypeFromFilename(
blob.name.split("/")[3]
),
"versionId": blob.versionId, "versionId": blob.versionId,
"isCurrentVersion": blob.isCurrentVersion, "isCurrentVersion": blob.isCurrentVersion,
"contentLength": contentLength, "contentLength": blob.properties.contentLength,
"filenameprefix": filenamePrefix, "filenameprefix": filenamePrefix,
"filepath": buildDownloadBlobQueryPath({ "filepath":
containerName, "/api/file/downloadblob?container=" +
casefolderID: casefolderPath, containerName +
blobname: repFileName "&casefolderID=" +
}), encodeURIComponent(
...buildHashMetadataPaths({ blob.name.split("/")[0] + "/" + blob.name.split("/")[1]
containerName, ) +
casefolderID: casefolderPath, "&blobname=" +
blobname: repFileName encodeURIComponent(blob.name.split("/")[3]),
}), "hashedfilepath": hashAPIPath(
"deletepath": buildDeleteBlobQueryPath({ "/api/file/downloadblob?container=" +
containerName, containerName +
casefolderID: casefolderPath, "&casefolderID=" +
blobname: repFileName, encodeURIComponent(
encodeCasefolderID: false, blob.name.split("/")[0] + "/" + blob.name.split("/")[1]
encodeBlobname: false ) +
}) "&blobname=" +
encodeURIComponent(blob.name.split("/")[3])
),
"deletepath":
"/api/file/deleteblob?container=" +
containerName +
"&casefolderID=" +
blob.name.split("/")[0] +
"/" +
blob.name.split("/")[1] +
"&blobname=" +
blob.name.split("/")[3],
"hasheddeletepath": hashAPIPath(
"/api/file/deleteblob?container=" +
containerName +
"&casefolderID=" +
encodeURIComponent(
blob.name.split("/")[0] + "/" + blob.name.split("/")[1]
) +
"&blobname=" +
encodeURIComponent(blob.name.split("/")[3])
),
"hashgetblobs": hashAPIPath(
"/api/file/getbloblist?container=" +
containerName +
"&casefolderID=" +
blob.name.split("/")[0] +
"/" +
blob.name.split("/")[1]
),
}); });
} }
//consoleLogger("blobObj:", blobObj); console.log("blobObj:", blobObj);
return blobObj; return blobObj;
}; };
@@ -1525,7 +1490,7 @@ export const createQueueSas = async (queueName) => {
var sas_signature_val = { var sas_signature_val = {
expiresOn: TEN_MINUTES_AFTER_NOW, expiresOn: TEN_MINUTES_AFTER_NOW,
permissions: permission, permissions: permission,
queueName: queueName queueName: queueName,
}; };
const sasToken = generateQueueSASQueryParameters( const sasToken = generateQueueSASQueryParameters(
@@ -1569,7 +1534,7 @@ export const createCaseCompleteMessage = async (
caseReference + caseReference +
"_case.json", "_case.json",
filespath: filespath:
endpointURL + "/" + containerName + "/" + caseReference + "/files" endpointURL + "/" + containerName + "/" + caseReference + "/files",
// uploadUrl: fileRecord.uploadUrl, // uploadUrl: fileRecord.uploadUrl,
// filename: fileRecord.file.name, // filename: fileRecord.file.name,
@@ -1630,7 +1595,7 @@ export const createRepCompleteMessage = async (
caseReference + caseReference +
"/" + "/" +
filename + filename +
"/files" "/files",
}; };
console.log("======================", message, "====================="); console.log("======================", message, "=====================");
@@ -1656,7 +1621,7 @@ export const listContainers = async (
includeDeleted: false, includeDeleted: false,
includeMetadata: true, includeMetadata: true,
includeSystem: true, includeSystem: true,
prefix: containerNamePrefix prefix: containerNamePrefix,
}; };
console.log( console.log(
"\n\n\n=================================================\n", "\n\n\n=================================================\n",
@@ -1699,7 +1664,7 @@ export const listBlobHierarchical = async (
includeTags: true, // include indexable tags includeTags: true, // include indexable tags
includeUncommitedBlobs: false, // include uncommitted blobs includeUncommitedBlobs: false, // include uncommitted blobs
includeVersions: false, // include all blob version includeVersions: false, // include all blob version
prefix: "" // filter by blob name prefix prefix: "", // filter by blob name prefix
}; };
let i = 1; let i = 1;
@@ -1785,7 +1750,7 @@ export async function listBlobHierarchicalForUser(containerClient) {
? lastModifiedDate.toISOString() ? lastModifiedDate.toISOString()
: null, : null,
createdOn: createdOnDate ? createdOnDate.toISOString() : null, createdOn: createdOnDate ? createdOnDate.toISOString() : null,
displayDate displayDate,
}); });
} }
return blobNames; return blobNames;
@@ -1800,7 +1765,7 @@ export async function listContainersForUser(
includeDeleted: false, includeDeleted: false,
includeMetadata: true, includeMetadata: true,
includeSystem: true, includeSystem: true,
prefix: containerNamePrefix prefix: containerNamePrefix,
}; };
const results = []; const results = [];
@@ -1818,7 +1783,7 @@ export async function listContainersForUser(
if (blobNames && blobNames.length > 0) { if (blobNames && blobNames.length > 0) {
results.push({ results.push({
container: containerItem.name, container: containerItem.name,
blobs: blobNames blobs: blobNames,
}); });
} }
} }
-18
View File
@@ -1,18 +0,0 @@
# 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`.
-11
View File
@@ -1,11 +0,0 @@
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;
};
-22
View File
@@ -1,22 +0,0 @@
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);
};
-37
View File
@@ -1,37 +0,0 @@
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));
};
-5
View File
@@ -1,5 +0,0 @@
export * from "./relayClient";
export * from "./endpointClient";
export * from "./fileClient";
export * from "./fileRouteBuilder";
export * from "./signedRequestClient";
-22
View File
@@ -1,22 +0,0 @@
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;
}
};
-45
View File
@@ -1,45 +0,0 @@
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
});
};
-15
View File
@@ -1,15 +0,0 @@
const port = parseInt(process.env.PORT, 10) || 3000;
export const BASE_URL =
typeof window !== "undefined"
? window.apiRoot
: process.env.API_ROOT || `http://localhost:${port}`;
export const API_PATH = "/api/data/v9.2/";
export const WEBAPI_URL =
process.env.RELAY_ROOT ||
"https://dev-pedw-ns.servicebus.windows.net/dev-pedw-hc/";
export const ACCESS_TOKEN_ENDPOINT = process.env.ACCESS_TOKEN_ENDPOINT;
export const TENANT_ID = process.env.TENANT;
-11
View File
@@ -1,11 +0,0 @@
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, "''");
};
-22
View File
@@ -1,22 +0,0 @@
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);
};
-50
View File
@@ -1,50 +0,0 @@
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
}
};
};
-100
View File
@@ -1,100 +0,0 @@
import { hasOwn } from "../../components/utils";
const MASK = "[REDACTED]";
const redactString = (value) => {
if (typeof value !== "string") return value;
return value
.replace(
/([a-zA-Z0-9._%+-]{1,})@([a-zA-Z0-9.-]+\.[a-zA-Z]{2,})/g,
`${MASK}@${MASK}`
)
.replace(/Bearer\s+[A-Za-z0-9._\-]+/gi, `Bearer ${MASK}`)
.replace(/("client_secret"\s*:\s*")[^"]+("?)/gi, `$1${MASK}$2`)
.replace(/("access_token"\s*:\s*")[^"]+("?)/gi, `$1${MASK}$2`);
};
export const redactSensitive = (value) => {
if (value == null) return value;
if (typeof value === "string") {
return redactString(value);
}
try {
const json = JSON.stringify(value);
return redactString(json);
} catch (_error) {
return MASK;
}
};
export const getIP = (req) => {
const forwarded = req.headers["x-forwarded-for"];
const ip =
typeof forwarded === "string"
? forwarded.split(/, /)[0]
: req.socket.remoteAddress;
console.info(
"\n====================\n Client IP address: " + ip,
"\n=====================\n"
);
};
export const consoleLogger = (err) => {
console.log(
"\n\n/////////////////////////////////////////////////\nRaw Error " +
redactSensitive(err) +
"\n\n/////////////////////////////////////////////////\n"
);
const errStr =
"\n\n/////////////////////////////////////////////////\nServer Error\n" +
(hasOwn(err, "name") ? `Name: ${err.name}\n` : "") +
(hasOwn(err, "code") ? `Code: ${err.code}\n` : "") +
(hasOwn(err, "query") ? `Query: ${err.query}\n` : "") +
(hasOwn(err, "message") ? `Message: ${err.message}\n` : "") +
(err?.request?.url ? `request.url: ${err.request.url}\n` : "") +
(err?.response?.status ? `Status: ${err.response.status}\n` : "") +
(err?.response?.statusText
? `StatusText: ${err.response.statusText}\n`
: "") +
(err?.response?.request?.socket?.remoteAddress
? `Request IP: ${err.response.request.socket.remoteAddress}\n`
: "") +
(err?.response?.data?.error?.message
? `Message: ${redactSensitive(err.response.data.error.message)}\n`
: "") +
(err?.response?.config?.url
? `Request URL: ${redactSensitive(err.response.config.url)}\n`
: "") +
(err?.response?.headers?.date
? `Request Time: ${err.response.headers.date}\n`
: "") +
(err?.config?.url
? `Axios config url: ${redactSensitive(err.config.url)}\n`
: "") +
(err?.message
? `Axios message: ${redactSensitive(err.message)}\n`
: "") +
(err?.config?.data
? `Request payload: ${redactSensitive(err.config.data)}\n`
: "") +
"\n/////////////////////////////////////////////////\n";
console.log(errStr);
};
export const conLog = (err) => {
var errStr =
"\n\n/////////////////////////////////////////////////\nResponse: " +
"\n" +
err +
"\n/////////////////////////////////////////////////\n\n";
console.log(errStr);
return errStr;
};
-41
View File
@@ -1,41 +0,0 @@
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;
}
};
+2196 -8
View File
File diff suppressed because it is too large Load Diff
+21 -32
View File
@@ -1,58 +1,53 @@
export const getSelectQuery = (appealTypeName) => { export const getSelectQuery = (appealTypeName) => {
switch (appealTypeName) { switch (appealTypeName) {
case "pinswg_advertses": case "pinswg_advertses":
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"; return "&$select=pinswg_speacialistcaseprocess,modifiedon,_pinswg_appellant_value,pinswg_name,pinswg_siteaddresscounty,pinswg_siteaddressline1,pinswg_siteaddressline2,pinswg_siteaddresspostcode,pinswg_siteaddresstown,_pinswg_associatedlpa_value,pinswg_casedecisiondate,pinswg_dateeventrequested,pinswg_decision,pinswg_procedure,pinswg_questionnaireduedate,statuscode,pinswg_startdateoftheevent,pinswg_typeofevent,pinswg_startdate,pinswg_otherpartiesstatement,pinswg_finalcommentsduedate,pinswg_proofsofevidencewrittenstatementsofeviden,pinswg_speacialistcaseprocess,pinswg_statementduedate";
break; break;
case "pinswg_callinss77s": 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,pinswg_otherpartiesstatement"; return "&$select=modifiedon,_pinswg_appellant_value,pinswg_name,pinswg_siteaddresscounty,pinswg_siteaddressline1,pinswg_siteaddressline2,pinswg_siteaddresspostcode,pinswg_siteaddresstown,_pinswg_associatedlpa_value,pinswg_casedecisiondate,pinswg_dateeventrequested,pinswg_decision,pinswg_finalcommentsduedate,pinswg_procedure,pinswg_proofsofevidencewrittenstatementsofeviden,pinswg_questionnaireduedate,pinswg_startdate,statuscode,pinswg_dateexportedtoiss,pinswg_startdateofevent,pinswg_typeofevent,pinswg_statementsduedate,pinswg_otherpartiesstatement";
break; break;
case "pinswg_commonlands": 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"; return "&$select=modifiedon,_pinswg_appellant_value,pinswg_name,pinswg_siteaddresscounty,pinswg_siteaddressline1,pinswg_siteaddressline2,pinswg_siteaddresspostcode,pinswg_siteaddresstown,_pinswg_associatedlpa_value,pinswg_casedecisiondate,pinswg_dateeventrequested,pinswg_decision,pinswg_finalcommentsduedate,pinswg_otherpartiesstatement,pinswg_procedure,pinswg_proofsofevidencewrittenstatementsofeviden,pinswg_questionnaireduedate,pinswg_relevantauthorityname,pinswg_startdate,statuscode,pinswg_starttimeoftheevent,pinswg_typeofevent,pinswg_statementsduedate";
break; break;
case "pinswg_environmentalpermittings": case "pinswg_environmentalpermittings":
return "&$select=pinswg_detailedeiascreeningrequired,modifiedon,_pinswg_appellant_value,pinswg_name,pinswg_siteaddresscounty,pinswg_siteaddressline1,pinswg_siteaddressline2,pinswg_siteaddresspostcode,pinswg_siteaddresstown,_pinswg_associatedlpa_value,pinswg_casedecisiondate,pinswg_dateeventrequested,pinswg_decision,pinswg_finalcommentsduedate,pinswg_otherpartiesstatement,pinswg_procedure,pinswg_proofsofevidencewrittenstatementsofeviden,pinswg_questionnaireduedate,pinswg_relevantauthorityname,pinswg_startdate,statuscode,pinswg_startdateofevent,pinswg_typeofevent"; return "&$select=modifiedon,_pinswg_appellant_value,pinswg_name,pinswg_siteaddresscounty,pinswg_siteaddressline1,pinswg_siteaddressline2,pinswg_siteaddresspostcode,pinswg_siteaddresstown,_pinswg_associatedlpa_value,pinswg_casedecisiondate,pinswg_dateeventrequested,pinswg_decision,pinswg_finalcommentsduedate,pinswg_otherpartiesstatement,pinswg_procedure,pinswg_proofsofevidencewrittenstatementsofeviden,pinswg_questionnaireduedate,pinswg_relevantauthorityname,pinswg_startdate,statuscode,pinswg_startdateofevent,pinswg_typeofevent";
break; break;
case "pinswg_hedgeshedgerowstreepreservationreplacems": case "pinswg_hedgeshedgerowstreepreservationreplacems":
return "&$select=pinswg_detailedeiascreening,pinswg_specialistcaseprocess,modifiedon,_pinswg_appellant_value,pinswg_name,pinswg_siteaddresscounty,pinswg_siteaddressline1,pinswg_siteaddressline2,pinswg_siteaddresspostcode,pinswg_siteaddresstown,_pinswg_associatedlpa_value,pinswg_casedecisiondate,pinswg_dateeventrequested,pinswg_decision,pinswg_finalcommentsduedate,pinswg_otherpartiesstatement,pinswg_procedure,pinswg_proofsofevidencewrittenstatementsofeviden,pinswg_questionnaireduedate,pinswg_relevantauthorityname,pinswg_startdate,statuscode,pinswg_startdateoftheevent,pinswg_typeofevent,pinswg_statementduedate,pinswg_specialistcaseprocess"; return "&$select=pinswg_specialistcaseprocess,modifiedon,_pinswg_appellant_value,pinswg_name,pinswg_siteaddresscounty,pinswg_siteaddressline1,pinswg_siteaddressline2,pinswg_siteaddresspostcode,pinswg_siteaddresstown,_pinswg_associatedlpa_value,pinswg_casedecisiondate,pinswg_dateeventrequested,pinswg_decision,pinswg_finalcommentsduedate,pinswg_otherpartiesstatement,pinswg_procedure,pinswg_proofsofevidencewrittenstatementsofeviden,pinswg_questionnaireduedate,pinswg_relevantauthorityname,pinswg_startdate,statuscode,pinswg_startdateoftheevent,pinswg_typeofevent,pinswg_statementduedate,pinswg_specialistcaseprocess";
break; break;
case "pinswg_miscellaneouscaseworks": case "pinswg_miscellaneouscaseworks":
return "&$select=pinswg_eiarequired,modifiedon,_pinswg_appellant_value,pinswg_name,pinswg_siteaddresscounty,pinswg_siteaddressline1,pinswg_siteaddressline2,pinswg_siteaddresspostcode,pinswg_siteaddresstown,_pinswg_associatedlpa_value,pinswg_casedecisiondate,pinswg_dateeventrequested,pinswg_decision,pinswg_finalcommentsduedate,pinswg_otherpartiesstatement,pinswg_procedure,pinswg_proofsofevidencewrittenstatementsofeviden,pinswg_questionnaireduedate,pinswg_relevantauthorityname,pinswg_startdate,statuscode,pinswg_startdateoftheevent,pinswg_typeofevent,pinswg_statementduedate";
break;
case "pinswg_wayleaves": case "pinswg_wayleaves":
return "&$select=pinswg_detailedeiascreening,modifiedon,_pinswg_appellant_value,pinswg_name,pinswg_siteaddresscounty,pinswg_siteaddressline1,pinswg_siteaddressline2,pinswg_siteaddresspostcode,pinswg_siteaddresstown,_pinswg_associatedlpa_value,pinswg_casedecisiondate,pinswg_dateeventrequested,pinswg_decision,pinswg_finalcommentsduedate,pinswg_otherpartiesstatement,pinswg_procedure,pinswg_proofsofevidencewrittenstatementsofeviden,pinswg_questionnaireduedate,pinswg_relevantauthorityname,pinswg_startdate,statuscode,pinswg_startdateoftheevent,pinswg_typeofevent,pinswg_statementduedate"; return "&$select=modifiedon,_pinswg_appellant_value,pinswg_name,pinswg_siteaddresscounty,pinswg_siteaddressline1,pinswg_siteaddressline2,pinswg_siteaddresspostcode,pinswg_siteaddresstown,_pinswg_associatedlpa_value,pinswg_casedecisiondate,pinswg_dateeventrequested,pinswg_decision,pinswg_finalcommentsduedate,pinswg_otherpartiesstatement,pinswg_procedure,pinswg_proofsofevidencewrittenstatementsofeviden,pinswg_questionnaireduedate,pinswg_relevantauthorityname,pinswg_startdate,statuscode,pinswg_startdateoftheevent,pinswg_typeofevent,pinswg_statementduedate";
break; break;
case "pinswg_communityinfrastructurelevys117118119s": case "pinswg_communityinfrastructurelevys117118119s":
return "&$select=pinswg_detailedeiascreeningrequired,modifiedon,_pinswg_appellant_value,pinswg_name,pinswg_siteaddresscounty,pinswg_siteaddressline1,pinswg_siteaddressline2,pinswg_siteaddresspostcode,pinswg_siteaddresstown,_pinswg_associatedlpa_value,pinswg_casedecisiondate,pinswg_dateeventrequested,pinswg_decision,pinswg_finalcommentsduedate,pinswg_procedure,pinswg_startdate,statuscode,pinswg_startdateoftheevent,pinswg_typeofevent,pinswg_questionnaireduedate,pinswg_statementduedate"; return "&$select=modifiedon,_pinswg_appellant_value,pinswg_name,pinswg_siteaddresscounty,pinswg_siteaddressline1,pinswg_siteaddressline2,pinswg_siteaddresspostcode,pinswg_siteaddresstown,_pinswg_associatedlpa_value,pinswg_casedecisiondate,pinswg_dateeventrequested,pinswg_decision,pinswg_finalcommentsduedate,pinswg_procedure,pinswg_startdate,statuscode,pinswg_startdateoftheevent,pinswg_typeofevent,pinswg_questionnaireduedate,pinswg_statementduedate";
break; break;
case "pinswg_compulsorypurchaseorderses": case "pinswg_compulsorypurchaseorderses":
return "&$select=pinswg_detailedeiascreening,modifiedon,_pinswg_appellant_value,pinswg_name,pinswg_siteaddresscounty,pinswg_siteaddressline1,pinswg_siteaddressline2,pinswg_siteaddresspostcode,pinswg_siteaddresstown,pinswg_casedecisiondate,pinswg_dateeventrequested,pinswg_decision,pinswg_finalcommentsduedate,pinswg_otherpartiesstatement,pinswg_procedure,pinswg_proofsofevidencewrittenstatementsofeviden,pinswg_questionnaireduedate,pinswg_relevantauthorityname,pinswg_startdate,statuscode,pinswg_startdateoftheevent,pinswg_typeofevent,pinswg_statementduedate"; return "&$select=modifiedon,_pinswg_appellant_value,pinswg_name,pinswg_siteaddresscounty,pinswg_siteaddressline1,pinswg_siteaddressline2,pinswg_siteaddresspostcode,pinswg_siteaddresstown,pinswg_casedecisiondate,pinswg_dateeventrequested,pinswg_decision,pinswg_finalcommentsduedate,pinswg_otherpartiesstatement,pinswg_procedure,pinswg_proofsofevidencewrittenstatementsofeviden,pinswg_questionnaireduedate,pinswg_relevantauthorityname,pinswg_startdate,statuscode,pinswg_startdateoftheevent,pinswg_typeofevent,pinswg_statementduedate";
break; break;
case "pinswg_dnses": case "pinswg_dnses":
return "&$select=pinswg_eiarequired,pinswg_anticipatedgridreferenceeastingtext,pinswg_anticipatedgridreferencenorthingtext,_pinswg_appellant_value,pinswg_name,pinswg_addressline1,pinswg_addressline2,pinswg_postcode,pinswg_addresstown,_pinswg_associatedlpa_value,pinswg_addresscounty,pinswg_applicationacceptedasvalid,pinswg_applicationrejectedasinvalid,pinswg_choiceofprocedure,pinswg_confirmrequesttovaryapplication,pinswg_dateeventrequested,pinswg_dateofdecision,pinswg_dateofrequesttovarytheapplication,pinswg_dateofsubmissionofapplication,pinswg_dateprojectpublishedonwebsite,pinswg_deadlineforsubmissionofapplication,pinswg_decision,pinswg_endofrepresentationperiod,pinswg_inspectorreportsubmittedtowelshgovernment,pinswg_procedureconfirmed,pinswg_projectdescription,pinswg_projectlocation,pinswg_recommendation,pinswg_rejectrequesttovaryapplication,pinswg_reportdueby,pinswg_suspensiondates,pinswg_suspensionenddates,pinswg_suspensionstartdates,pinswg_validnoticeofintentiontosubmitanapplicati,pinswg_webaddress,pinswg_withdrawndate,pinswg_writtenacceptanceofnotification,statuscode,_pinswg_dnsids_value,pinswg_startdateofevent,pinswg_typeofevent"; 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";
break; break;
case "pinswg_electricityacts": case "pinswg_electricityacts":
return "&$select=pinswg_eiarequired,modifiedon,_pinswg_appellant_value,pinswg_name,pinswg_addressline1,pinswg_addressline2,pinswg_postcode,pinswg_addresstown,_pinswg_associatedlpa_value,pinswg_applicationacceptedasvalid,pinswg_applicationrejectedasinvalid,pinswg_confirmrequesttovaryapplication,pinswg_dateeventrequested,pinswg_dateofrequesttovarytheapplication,pinswg_dateofsubmissionofapplication,pinswg_dateprojectpublishedonwebsite,pinswg_deadlineforsubmissionofapplication,pinswg_decision,pinswg_endofrepresentationperiod,pinswg_inspectorreportsubmittedtowelshgovernment,pinswg_procedureconfirmed,pinswg_projectlocation,pinswg_recommendation,pinswg_rejectrequesttovaryapplication,pinswg_reportdueby,pinswg_suspensiondates,pinswg_validnoticeofintentiontosubmitanapplicati,pinswg_webaddress,pinswg_withdrawndate,pinswg_writtenacceptanceofnotification,statuscode,pinswg_startdateofevent,pinswg_typeofevent"; return "&$select=modifiedon,_pinswg_appellant_value,pinswg_name,pinswg_addressline1,pinswg_addressline2,pinswg_postcode,pinswg_addresstown,_pinswg_associatedlpa_value,pinswg_applicationacceptedasvalid,pinswg_applicationrejectedasinvalid,pinswg_confirmrequesttovaryapplication,pinswg_dateeventrequested,pinswg_dateofrequesttovarytheapplication,pinswg_dateofsubmissionofapplication,pinswg_dateprojectpublishedonwebsite,pinswg_deadlineforsubmissionofapplication,pinswg_decision,pinswg_endofrepresentationperiod,pinswg_inspectorreportsubmittedtowelshgovernment,pinswg_procedureconfirmed,pinswg_projectlocation,pinswg_recommendation,pinswg_rejectrequesttovaryapplication,pinswg_reportdueby,pinswg_suspensiondates,pinswg_validnoticeofintentiontosubmitanapplicati,pinswg_webaddress,pinswg_withdrawndate,pinswg_writtenacceptanceofnotification,statuscode,pinswg_startdateofevent,pinswg_typeofevent";
break;
case "pinswg_harbourrevisionorders":
return "&$select=pinswg_eiarequired,pinswg_anticipatedgridreferenceeastingtext,pinswg_anticipatedgridreferencenorthingtext,_pinswg_appellant_value,pinswg_name,pinswg_addressline1,pinswg_addressline2,pinswg_postcode,pinswg_addresstown,_pinswg_associatedlpa_value,pinswg_addresscounty,pinswg_applicationacceptedasvalid,pinswg_applicationrejectedasinvalid,pinswg_choiceofprocedure,pinswg_confirmrequesttovaryapplication,pinswg_dateeventrequested,pinswg_dateofdecision,pinswg_dateofrequesttovarytheapplication,pinswg_dateofsubmissionofapplication,pinswg_dateprojectpublishedonwebsite,pinswg_deadlineforsubmissionofapplication,pinswg_decision,pinswg_endofrepresentationperiod,pinswg_inspectorreportsubmittedtowelshgovernment,pinswg_procedureconfirmed,pinswg_projectdiscription,pinswg_projectlocation,pinswg_recommendation,pinswg_rejectrequesttovaryapplication,pinswg_reportdueby,pinswg_suspensiondates,pinswg_suspensionenddates,pinswg_suspensionstartdate,pinswg_validnoticeofintentiontosubmitanapplicati,pinswg_webaddress,pinswg_withdrawndate,pinswg_writtenacceptanceofnotification,statuscode,pinswg_startdateofevent,pinswg_typeofevent";
break; break;
case "pinswg_householderappealhases": case "pinswg_householderappealhases":
return "&$select=pinswg_eiarequired,modifiedon,_pinswg_appellant_value,pinswg_name,pinswg_siteaddressline1,pinswg_siteaddressline2,pinswg_siteaddresspostcode,pinswg_siteaddresstown,_pinswg_associatedlpa_value,pinswg_casedecisiondate,pinswg_dateeventrequested,pinswg_decision,pinswg_finalcommentsduedate,pinswg_otherpartiesstmt,pinswg_procedure,pinswg_questionnaireduedate,pinswg_startdate,pinswg_statementduedate,statuscode"; return "&$select=modifiedon,_pinswg_appellant_value,pinswg_name,pinswg_siteaddressline1,pinswg_siteaddressline2,pinswg_siteaddresspostcode,pinswg_siteaddresstown,_pinswg_associatedlpa_value,pinswg_casedecisiondate,pinswg_dateeventrequested,pinswg_decision,pinswg_finalcommentsduedate,pinswg_otherpartiesstmt,pinswg_procedure,pinswg_questionnaireduedate,pinswg_startdate,pinswg_statementduedate,statuscode";
break; break;
case "pinswg_enforcementnoticeappeals174s": case "pinswg_enforcementnoticeappeals174s":
return "&$select=pinswg_eiarequired,modifiedon,_pinswg_appellant_value,pinswg_name,pinswg_siteaddressline1,pinswg_siteaddressline2,pinswg_siteaddresspostcode,pinswg_siteaddresstown,_pinswg_associatedlpa_value,pinswg_casedecisiondate,pinswg_dateeventrequested,pinswg_decision,pinswg_finalcommentsduedate,pinswg_otherpartiesstatement,pinswg_procedure,pinswg_questionnaireduedate,pinswg_startdate,pinswg_statementduedate,statuscode,pinswg_startdateoftheevent,pinswg_typeofevent"; return "&$select=modifiedon,_pinswg_appellant_value,pinswg_name,pinswg_siteaddressline1,pinswg_siteaddressline2,pinswg_siteaddresspostcode,pinswg_siteaddresstown,_pinswg_associatedlpa_value,pinswg_casedecisiondate,pinswg_dateeventrequested,pinswg_decision,pinswg_finalcommentsduedate,pinswg_otherpartiesstatement,pinswg_procedure,pinswg_questionnaireduedate,pinswg_startdate,pinswg_statementduedate,statuscode,pinswg_startdateoftheevent,pinswg_typeofevent";
break; break;
case "pinswg_enforcementlistedbuildingconservationaps": case "pinswg_enforcementlistedbuildingconservationaps":
return "&$select=pinswg_detailedeiascreeningrequired,modifiedon,_pinswg_appellant_value,pinswg_name,pinswg_siteaddressline1,pinswg_siteaddressline2,pinswg_siteaddresspostcode,pinswg_siteaddresstown,_pinswg_associatedlpa_value,pinswg_casedecisiondate,pinswg_dateeventrequested,pinswg_decision,pinswg_finalcommentsduedate,pinswg_otherpartiesstatements,pinswg_procedure,pinswg_questionnaireduedate,pinswg_startdates,pinswg_statementduedate,statuscode,pinswg_startdateofevent,pinswg_typeofevent"; return "&$select=modifiedon,_pinswg_appellant_value,pinswg_name,pinswg_siteaddressline1,pinswg_siteaddressline2,pinswg_siteaddresspostcode,pinswg_siteaddresstown,_pinswg_associatedlpa_value,pinswg_casedecisiondate,pinswg_dateeventrequested,pinswg_decision,pinswg_finalcommentsduedate,pinswg_otherpartiesstatements,pinswg_procedure,pinswg_questionnaireduedate,pinswg_startdates,pinswg_statementduedate,statuscode,pinswg_startdateofevent,pinswg_typeofevent";
break; break;
case "pinswg_maintenanceoflands217s": case "pinswg_maintenanceoflands217s":
return "&$select=pinswg_detailedeiascreeningrequired,modifiedon,_pinswg_appellant_value,pinswg_name,pinswg_siteaddressline1,pinswg_siteaddressline2,pinswg_siteaddresspostcode,pinswg_siteaddresstown,_pinswg_associatedlpa_value,pinswg_casedecisiondate,pinswg_dateeventrequested,pinswg_decision,pinswg_finalcommentsduedate,pinswg_otherpartiesstatement,pinswg_procedure,pinswg_questionnaireduedate,pinswg_startdates,pinswg_statementduedate,statuscode,pinswg_startdateoftheevent,pinswg_typeofevent"; return "&$select=modifiedon,_pinswg_appellant_value,pinswg_name,pinswg_siteaddressline1,pinswg_siteaddressline2,pinswg_siteaddresspostcode,pinswg_siteaddresstown,_pinswg_associatedlpa_value,pinswg_casedecisiondate,pinswg_dateeventrequested,pinswg_decision,pinswg_finalcommentsduedate,pinswg_otherpartiesstatement,pinswg_procedure,pinswg_questionnaireduedate,pinswg_startdates,pinswg_statementduedate,statuscode,pinswg_startdateoftheevent,pinswg_typeofevent";
break; break;
case "pinswg_lawfuldevelopmentcertificates": case "pinswg_lawfuldevelopmentcertificates":
return "&$select=pinswg_detailedeiascreeningrequiered,modifiedon,_pinswg_appellant_value,pinswg_name,pinswg_siteaddressline1,pinswg_siteaddressline2,pinswg_siteaddresspostcode,pinswg_siteaddresstown,_pinswg_associatedlpa_value,pinswg_casedecisiondate,pinswg_dateeventrequested,pinswg_decision,pinswg_finalcommentsduedate,pinswg_otherpartiesstatements,pinswg_procedure,pinswg_questionnaireduedate,pinswg_startdate,pinswg_statementduedate,statuscode,pinswg_startdateoftheevent,pinswg_typeofevent"; return "&$select=modifiedon,_pinswg_appellant_value,pinswg_name,pinswg_siteaddressline1,pinswg_siteaddressline2,pinswg_siteaddresspostcode,pinswg_siteaddresstown,_pinswg_associatedlpa_value,pinswg_casedecisiondate,pinswg_dateeventrequested,pinswg_decision,pinswg_finalcommentsduedate,pinswg_otherpartiesstatements,pinswg_procedure,pinswg_questionnaireduedate,pinswg_startdate,pinswg_statementduedate,statuscode,pinswg_startdateoftheevent,pinswg_typeofevent";
break; break;
case "pinswg_listedbuildingandconservationareaconsens": case "pinswg_listedbuildingandconservationareaconsens":
return "&$select=pinswg_detailedeiascreeningrequiered,modifiedon,_pinswg_appellant_value,pinswg_name,pinswg_siteaddressline1,pinswg_siteaddressline2,pinswg_sitepostcode,pinswg_siteaddresstown,_pinswg_associatedlpa_value,pinswg_casedecisiondate,pinswg_dateeventrequested,pinswg_decision,pinswg_finalcommentsduedate,pinswg_otherpartiesstatement,pinswg_procedure,pinswg_questionnaireduedate,pinswg_startdate,pinswg_statementduedate,statuscode,pinswg_starttimeofevent,pinswg_typeofevent"; return "&$select=modifiedon,_pinswg_appellant_value,pinswg_name,pinswg_siteaddressline1,pinswg_siteaddressline2,pinswg_sitepostcode,pinswg_siteaddresstown,_pinswg_associatedlpa_value,pinswg_casedecisiondate,pinswg_dateeventrequested,pinswg_decision,pinswg_finalcommentsduedate,pinswg_otherpartiesstatement,pinswg_procedure,pinswg_questionnaireduedate,pinswg_startdate,pinswg_statementduedate,statuscode,pinswg_starttimeofevent,pinswg_typeofevent";
break; break;
case "pinswg_planningappeals78s": case "pinswg_planningappeals78s":
//console.log( //console.log(
@@ -60,17 +55,17 @@ export const getSelectQuery = (appealTypeName) => {
// process.env.RELAYPATH == "test-pedw-hc" // process.env.RELAYPATH == "test-pedw-hc"
// ); // );
return process.env.RELAYPATH == "dev-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_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=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_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"; : "&$select=modifiedon,_pinswg_appellant_value,pinswg_name,pinswg_siteaddressline1,pinswg_siteaddressline2,pinswg_siteaddresspostcode,pinswg_siteaddresstown,_pinswg_localplanningauthority_value,pinswg_casedecisiondate,pinswg_dicision,pinswg_dateeventrequested,pinswg_finalcommentsduedate,pinswg_procedure,pinswg_questionnaireduedate,pinswg_startdate,pinswg_statementduedate,statuscode,pinswg_startdatetimeiftheevent,pinswg_typeofevent";
break; break;
case "pinswg_planningconditionss73s79s": 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"; return "&$select=modifiedon,_pinswg_appellant_value,pinswg_name,pinswg_siteaddressline1,pinswg_siteaddressline2,pinswg_siteaddresspostcode,pinswg_siteaddresstown,_pinswg_associatedlpa_value,pinswg_casedecisiondate,pinswg_dateeventrequested,pinswg_decision,pinswg_finalcommentsduedate,pinswg_otherpartiesstatement,pinswg_procedure,pinswg_questionnaireduedate,pinswg_startdate,pinswg_statementduedate,statuscode,pinswg_startdateofevent,pinswg_typeofevent";
break; break;
case "pinswg_planningobligationappeals106s": case "pinswg_planningobligationappeals106s":
return "&$select=pinswg_detailedeiascreeningrequired,modifiedon,_pinswg_appellant_value,pinswg_name,pinswg_siteaddressline1,pinswg_siteaddressline2,pinswg_siteaddresspostcode,pinswg_siteaddresstown,_pinswg_associatedlpa_value,pinswg_casedecisiondate,pinswg_dateeventrequested,pinswg_decision,pinswg_finalcommentsduedate,pinswg_otherpartiesstatements,pinswg_procedure,pinswg_questionnaireduedate,pinswg_startdate,pinswg_statementduedate,statuscode,pinswg_startdateoftheevent,pinswg_typeofevent"; return "&$select=modifiedon,_pinswg_appellant_value,pinswg_name,pinswg_siteaddressline1,pinswg_siteaddressline2,pinswg_siteaddresspostcode,pinswg_siteaddresstown,_pinswg_associatedlpa_value,pinswg_casedecisiondate,pinswg_dateeventrequested,pinswg_decision,pinswg_finalcommentsduedate,pinswg_otherpartiesstatements,pinswg_procedure,pinswg_questionnaireduedate,pinswg_startdate,pinswg_statementduedate,statuscode,pinswg_startdateoftheevent,pinswg_typeofevent";
break; break;
case "pinswg_rows": case "pinswg_rows":
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"; return "&$select=pinswg_specialistcaseprocess,modifiedon,_pinswg_appellant_value,pinswg_name,pinswg_siteaddressline1,pinswg_siteaddressline2,pinswg_siteaddresspostcode,pinswg_siteaddresstown,_pinswg_associatedlpa_value,pinswg_casedecisiondate,pinswg_dateeventrequested,pinswg_decision,pinswg_finalcommentsduedate,pinswg_otherpartiesstatement,pinswg_procedure,pinswg_proofsofevidencewrittenstatementsofeviden,pinswg_questionnaireduedate,pinswg_relevantauthorityname,pinswg_startdate,statuscode,pinswg_startdateoftheevent,pinswg_typeofevent,pinswg_statementduedate,pinswg_specialistcaseprocess";
break; break;
case "pinswg_ldps": case "pinswg_ldps":
return "&$select=modifiedon,pinswg_name"; return "&$select=modifiedon,pinswg_name";
@@ -78,12 +73,6 @@ export const getSelectQuery = (appealTypeName) => {
case "pinswg_nonvalidations": case "pinswg_nonvalidations":
return "&$select=modifiedon,_pinswg_appellant_value,pinswg_name,pinswg_siteaddressline1,pinswg_siteaddressline2,pinswg_siteaddresspostcode,pinswg_siteaddresstown,_pinswg_associatedlpa_value,statuscode"; return "&$select=modifiedon,_pinswg_appellant_value,pinswg_name,pinswg_siteaddressline1,pinswg_siteaddressline2,pinswg_siteaddresspostcode,pinswg_siteaddresstown,_pinswg_associatedlpa_value,statuscode";
break; break;
case "pinswg_transportandworkacts":
return "&$select=pinswg_eiarequired,pinswg_anticipatedgridreferenceeastingtext,pinswg_anticipatedgridreferencenorthingtext,_pinswg_appellant_value,pinswg_name,pinswg_addressline1,pinswg_addressline2,pinswg_postcode,pinswg_addresstown,_pinswg_associatedlpa_value,pinswg_addresscounty,pinswg_applicationacceptedasvalid,pinswg_applicationrejectedasinvalid,pinswg_choiceofprocedure,pinswg_confirmrequesttovaryapplication,pinswg_dateeventrequested,pinswg_dateofdecision,pinswg_dateofrequesttovarytheapplication,pinswg_dateofsubmissionofapplication,pinswg_dateprojectpublishedonwebsite,pinswg_deadlineforsubmissionofapplication,pinswg_endofrepresentationperiod,pinswg_inspectorreportsubmittedtowelshgovernment,pinswg_procedureconfirmed,pinswg_projectdescription,pinswg_projectlocation,pinswg_recommendation,pinswg_rejectrequesttovaryapplication,pinswg_reportdueby,pinswg_suspensiondates,pinswg_suspensionenddates,pinswg_suspensionstartdate,pinswg_validnoticeofintentiontosubmitanapplicati,pinswg_webaddress,pinswg_withdrawndate,pinswg_writtenacceptanceofnotification,statuscode,pinswg_startdateofevent,pinswg_typeofevent";
case "pinswg_sipses":
// return "&$select=pinswg_anticipatedgridreferenceeastingtext,pinswg_anticipatedgridreferencenorthingtext,_pinswg_appellant_value,pinswg_name,pinswg_addressline1,pinswg_addressline2,pinswg_postcode,pinswg_addresstown,_pinswg_associatedlpa_value,pinswg_addresscounty,pinswg_applicationacceptedasvalid,pinswg_applicationrejectedasinvalid,pinswg_choiceofprocedure,pinswg_confirmrequesttovaryapplication,pinswg_dateeventrequested,pinswg_dateofdecision,pinswg_dateofrequesttovarytheapplication,pinswg_dateofsubmissionofapplication,pinswg_dateprojectpublishedonwebsite,pinswg_deadlineforsubmissionofapplication,pinswg_decision,pinswg_endofrepresentationperiod,pinswg_inspectorreportsubmittedtowelshgovernment,pinswg_procedureconfirmed,pinswg_projectdescription,pinswg_projectlocation,pinswg_recommendation,pinswg_rejectrequesttovaryapplication,pinswg_reportdueby,pinswg_suspensiondates,pinswg_suspensionenddates,pinswg_suspensionstartdates,pinswg_validnoticeofintentiontosubmitanapplicati,pinswg_webaddress,pinswg_withdrawndate,pinswg_writtenacceptanceofnotification,statuscode,_pinswg_dnsids_value,pinswg_startdateofevent,pinswg_typeofevent";
return "&$select=pinswg_casedeadline,pinswg_sipseiarequired,pinswg_anticipatedgridrefeasting,pinswg_anticipatedgridrefnorthing,_pinswg_appellant_value,pinswg_name,_pinswg_associatedlpa_value,pinswg_choiceofprocedure,pinswg_decision,pinswg_projectdescription,pinswg_projectlocation,pinswg_recommendation,statuscode,_pinswg_sipscase_value,pinswg_writtenacceptanceofnotification,pinswg_validnoticeofintentiontosubmit,pinswg_deadlineforsubmissionofapplication,pinswg_screeningstartdate,pinswg_eiatargetdate,pinswg_targetextended,pinswg_directionissueddate,pinswg_scopingstartdate,pinswg_scopingtargetdate,pinswg_scopingtargetextended,pinswg_scopingoutcomeissueddate,pinswg_essubmitted,pinswg_deemedmarinelicenseappliedfor,pinswg_validationdeadlineextension,pinswg_consultationopen,pinswg_consultationclose,pinswg_reportissuedtowelshministers,pinswg_decisionissuedtoapplicant,pinswg_decisionoutcome,pinswg_redetermination,pinswg_redeterminationconsultationdeadline,pinswg_reportdeadline,pinswg_casesubmissiondate,pinswg_preexaminationmeetingneeded,pinswg_consultaionpublicitydeadline,pinswg_endofexaminationstartofreporting,pinswg_compulsoryacquisitionvariationsubmitted,pinswg_compulsoryacquisitionvariationaccepted,pinswg_schemeorderamendmentrequestaccepted,pinswg_schemeorderamendmentrequestsubmitted";
break;
default: default:
return ""; return "";
break; break;
-108
View File
@@ -1,108 +0,0 @@
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;
});
};
-23
View File
@@ -1,23 +0,0 @@
import {
getPersonalAccount,
getLogin,
updatePassword,
updateAccount,
createAccount,
getEmailAccountCheck,
getPortalLogin,
getPortalLoginProxy,
getPreferredLanguage
} from "./accountDirectService";
export {
getPersonalAccount,
getLogin,
updatePassword,
updateAccount,
createAccount,
getEmailAccountCheck,
getPortalLogin,
getPortalLoginProxy,
getPreferredLanguage
};
-87
View File
@@ -1,87 +0,0 @@
import { BASE_URL } from "../core/env";
import { logAndReturnResponse } from "./httpServiceUtils";
import { getJson } from "../clients/endpointClient";
export const getNewAppeals = async (searchString) => {
try {
return await getJson(BASE_URL + "/api/admin/getnewappeals_api");
} catch (error) {
return logAndReturnResponse(error);
}
};
export const getNewAppealsPage = async (
searchString,
pageNumber,
orderBy,
fieldSort,
showNumberOfRecords
) => {
try {
return await getJson(
"/api/admin/getnewappeals_api?searchString=" +
searchString +
"&pageNumber=" +
pageNumber +
"&orderby=" +
orderBy +
"&fieldSort=" +
fieldSort +
"&showNumberOfRecords=" +
showNumberOfRecords
);
} catch (error) {
return logAndReturnResponse(error);
}
};
export const getNewDocumentsPaged = async (
pageNumber,
orderBy,
fieldSort,
showNumberOfRecords,
documentType,
documentOrigin,
selectedWeeks
) => {
try {
return await getJson(
"/api/admin/getlatestdocuments_api?pageNumber=" +
pageNumber +
"&orderby=" +
orderBy +
"&fieldSort=" +
fieldSort +
"&showNumberOfRecords=" +
showNumberOfRecords +
"&documentType=" +
documentType +
"&numberWeeks=" +
selectedWeeks +
"&documentOrigin=" +
documentOrigin
);
} catch (error) {
return logAndReturnResponse(error);
}
};
export const getStatusByAppeal = async () => {
try {
return await getJson(
BASE_URL + "/api/admin/getStatusCountsByAppeal_api"
);
} catch (error) {
return logAndReturnResponse(error);
}
};
export const getStatusByAppealLPA = async () => {
try {
return await getJson(
BASE_URL + "/api/admin/getStatusCountsByAppealAndLPA_api"
);
} catch (error) {
return logAndReturnResponse(error);
}
};
-15
View File
@@ -1,15 +0,0 @@
import {
getNewAppeals,
getNewAppealsPage,
getNewDocumentsPaged,
getStatusByAppeal,
getStatusByAppealLPA
} from "./adminDirectService";
export {
getNewAppeals,
getNewAppealsPage,
getNewDocumentsPaged,
getStatusByAppeal,
getStatusByAppealLPA
};
-284
View File
@@ -1,284 +0,0 @@
import { BASE_URL } from "../core/env";
import { consoleLogger } from "../core/logger";
import { logAndReturnResponse } from "./httpServiceUtils";
import { getJson, requestJson } from "../clients/endpointClient";
import { buildFileQuery, withBaseUrl } from "../clients/fileRouteBuilder";
export const getCaseMessage = (searchString) => {
const route = buildFileQuery("/api/cases/get-case-message", {
id: searchString
});
return getJson(withBaseUrl(BASE_URL, route)).catch(logAndReturnResponse);
};
export const getIncidentbyID = (searchString) => {
const route = buildFileQuery("/api/cases/get-incident-by-id", {
searchString
});
return getJson(withBaseUrl(BASE_URL, route)).catch(logAndReturnResponse);
};
export const getIsPublishedbyID = (searchString) => {
const route = buildFileQuery("/api/endpoint/getispublishedbyid_api", {
searchString
});
return getJson(route).catch(logAndReturnResponse);
};
export const getPartSavedAppeal = (searchString) => {
const route = buildFileQuery("/api/endpoint/getpartsavedappeal_api", {
searchString
});
return getJson(withBaseUrl(BASE_URL, route)).catch(logAndReturnResponse);
};
export const getSIPSEvents = async (caseid) => {
const route = buildFileQuery("/api/cases/get-sips-events", {
caseid
});
return getJson(withBaseUrl(BASE_URL, route)).catch(logAndReturnResponse);
};
export const getSIPSMedia = async (caseid) => {
const route = buildFileQuery("/api/cases/get-sips-media", {
caseid
});
return getJson(withBaseUrl(BASE_URL, route)).catch(logAndReturnResponse);
};
export const getAppealID = (
caseReference,
updateFormCollection,
primaryAttribute
) => {
const route = buildFileQuery("/api/endpoint/getappealid_api", {
updateFormCollection,
primaryAttribute,
caseReference
});
return getJson(route)
.then((data) => {
const result = Object.entries(data.value[0]).filter(
([key]) => !key.startsWith("_")
)[0][1];
var appealID = result;
return appealID;
})
.catch((error) => {
consoleLogger(error);
});
};
export const createNewCase = (
appealTypeId,
lpaID,
contactid,
createBody,
containerName
) => {
appealTypeId = parseInt(appealTypeId);
var data = createBody;
var queryUrl = buildFileQuery("/api/endpoint/createcase_api", {
appealTypeId,
lpaID,
contactid,
containername: containerName
});
var config = {
method: "post",
url: withBaseUrl(BASE_URL, queryUrl),
data: data
};
return requestJson(config).catch((error) => {
consoleLogger(error);
});
};
export const createNewCaseBlob = (
appealTypeId,
lpaID,
contactid,
createBody,
containerName,
lpaName
) => {
appealTypeId = parseInt(appealTypeId);
var data = createBody;
data.pinswg_lpaname = lpaName;
data.createdon = new Date();
var queryUrl = buildFileQuery("/api/file/createcase_api", {
appealTypeId,
lpaID,
contactid,
containername: containerName
});
var config = {
method: "post",
url: queryUrl,
data: data
};
return requestJson(config).catch((error) => {
consoleLogger(error);
});
};
export const updateCase = async (
incidentId,
updateBody,
updateFormCollection,
primaryAttribute,
caseReference
) => {
var data = updateBody;
var appealObj = await getAppealID(
caseReference,
updateFormCollection,
primaryAttribute
);
var queryUrl = buildFileQuery("/api/endpoint/updatecase_api", {
updateFormCollection,
appealObj
});
var config = {
method: "post",
url: queryUrl,
data: updateBody
};
return requestJson(config).catch((error) => {
consoleLogger(error);
});
};
export const updateCaseBlob = async (
incidentId,
updateBody,
updateFormCollection,
primaryAttribute,
caseReference
) => {
var data = updateBody;
var appealObj = await getAppealID(
caseReference,
updateFormCollection,
primaryAttribute
);
var queryUrl = buildFileQuery("/api/file/updatecase_api", {
updateFormCollection,
appealObj
});
var config = {
method: "post",
url: queryUrl,
data: updateBody
};
return requestJson(config).catch((error) => {
consoleLogger(error);
});
};
export const patchCase = async (incidentid) => {
var queryUrl = buildFileQuery("/api/endpoint/patchcase_api", {
incidentid
});
return getJson(queryUrl).catch((error) => {
//console.log("this error:", error);
});
};
export const getCase = (incidentID) => {
const route = buildFileQuery("/api/endpoint/getcase_api", {
incidentID
});
return getJson(withBaseUrl(BASE_URL, route)).catch((error) => {
consoleLogger(error);
});
};
export const getCaseByID = (incidentID) => {
const route = buildFileQuery("/api/endpoint/getcasebyid_api", {
incidentID
});
return getJson(withBaseUrl(BASE_URL, route)).catch((error) => {
consoleLogger(error);
});
};
export const getAppealPDFDocs = (incidentID) => {
const route = buildFileQuery("/api/endpoint/getappealpdfdocuments_api", {
incidentid: incidentID
});
return getJson(withBaseUrl(BASE_URL, route)).catch((error) => {
consoleLogger(error);
});
};
export const getAppealPDFDocument = async (incidentid) => {
const route = buildFileQuery("/api/endpoint/getappealpdfdocuments_api", {
incidentid
});
return getJson(withBaseUrl(BASE_URL, route)).catch((error) => {
consoleLogger(error);
return error.response;
});
};
export const getPortalModuleDetails = async (appealType, caseReference) => {
const route = buildFileQuery("/api/myportal/get-portal-module-details", {
appealType,
caseReference: encodeURI(caseReference)
});
return getJson(withBaseUrl(BASE_URL, route)).catch((error) => {
consoleLogger(error);
});
};
export const getPortalModuleDetailsProxy = (appealType, caseReference) => {
const route = buildFileQuery(
"/api/endpoint/getportalmoduledetailsproxy_api",
{
appealType,
caseReference: caseReference.replace(/\'/g, "''")
}
);
return getJson(route).catch((error) => {
consoleLogger(error);
});
};
export const getCaseStatus = async (appealType, caseReference) => {
const route = buildFileQuery("/api/endpoint/getStatusCounts_api", {});
return getJson(withBaseUrl(BASE_URL, route)).catch((error) => {
consoleLogger(error);
});
};
-43
View File
@@ -1,43 +0,0 @@
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
};
-394
View File
@@ -1,394 +0,0 @@
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);
});
};
-43
View File
@@ -1,43 +0,0 @@
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
};
-19
View File
@@ -1,19 +0,0 @@
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);
};
-9
View File
@@ -1,9 +0,0 @@
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";
@@ -1,19 +0,0 @@
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);
}
};
-3
View File
@@ -1,3 +0,0 @@
import { createCRMTask } from "./integrationDirectService";
export { createCRMTask };
-27
View File
@@ -1,27 +0,0 @@
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;
}
};
-3
View File
@@ -1,3 +0,0 @@
import { sendEmail } from "./notifyDirectService";
export { sendEmail };
-313
View File
@@ -1,313 +0,0 @@
import { BASE_URL } from "../core/env";
import { consoleLogger } from "../core/logger";
import { getJson, requestJson } from "../clients/endpointClient";
import {
deleteSignedJson,
buildSignedUrl
} from "../clients/signedRequestClient";
import {
buildFileQuery,
withBaseUrl,
appendQuerySuffix
} from "../clients/fileRouteBuilder";
export const getMyCases = (loggedInUserId) => {
const route = buildFileQuery("/api/myportal/get-my-cases", {
loggedInUserId
});
return getJson(withBaseUrl(BASE_URL, route)).catch((error) => {
consoleLogger(error);
});
};
export const getMyInvolvements = async (loggedInUserId) => {
const route = buildFileQuery("/api/endpoint/getmyinvolvements_api", {
loggedInUserId
});
return getJson(withBaseUrl(BASE_URL, route)).catch((error) => {
consoleLogger(error);
});
};
export const getMyLPACases = (lpaid) => {
const route = buildFileQuery("/api/myportal/get-my-lpa-cases", {
lpaid
});
return getJson(withBaseUrl(BASE_URL, route)).catch((error) => {
consoleLogger(error);
});
};
export const getMyRepresentations = (loggedInUserId) => {
const route = buildFileQuery("/api/endpoint/getmyrepresentations_api", {
loggedInUserId
});
return getJson(withBaseUrl(BASE_URL, route)).catch((error) => {
consoleLogger(error);
});
};
export const getMyRepresentationsProxy = (loggedInUserId) => {
const route = buildFileQuery(
"/api/endpoint/getmyrepresentationsproxy_api",
{
loggedInUserId
}
);
return getJson(route).catch((error) => {
consoleLogger(error);
});
};
export const getRepresentations = (incidentID) => {
const route = buildFileQuery("/api/endpoint/getrepresentations_api", {
incidentID
});
return getJson(route).catch((error) => {
consoleLogger(error);
});
};
export const getRepresentationsProxy = (incidentID) => {
const route = buildFileQuery("/api/endpoint/getrepresentationsproxy_api", {
incidentID
});
return getJson(route).catch((error) => {
consoleLogger(error);
});
};
export const getWatchedCases = (loggedInUserId) => {
const route = buildFileQuery("/api/subscriptions/get-watched-cases", {
loggedInUserId
});
return getJson(withBaseUrl(BASE_URL, route)).catch((error) => {
consoleLogger(error);
});
};
export const getWatchedCasesProxy = (loggedInUserId) => {
const route = buildFileQuery("/api/subscriptions/get-watched-cases-proxy", {
loggedInUserId
});
return getJson(route).catch((error) => {
consoleLogger(error);
});
};
export const getAwaitingSubmissionProxy = (loggedInUserId) => {
const route = buildFileQuery(
"/api/endpoint/getawaitingsubmissionproxy_api",
{
loggedInUserId
}
);
return getJson(route).catch((error) => {
consoleLogger(error);
});
};
export const getAwaitingSubmission = (loggedInUserId) => {
const route = buildFileQuery("/api/endpoint/getawaitingsubmission_api", {
loggedInUserId
});
return getJson(withBaseUrl(BASE_URL, route)).catch((error) => {
consoleLogger(error);
});
};
export const createWatchedCases = async (formValues) => {
var data = formValues;
var queryUrl = buildFileQuery("/api/subscriptions/create-watched-case");
var config = {
method: "post",
url: queryUrl,
data: data
};
try {
return await requestJson(config);
} catch (error) {
consoleLogger(error);
}
};
export const deleteMyRepresentations = (myRepresentationsID) => {
var queryUrl = buildFileQuery("/api/endpoint/deletemyrepresentations_api", {
myRepresentationsID
});
return deleteSignedJson(queryUrl, {
headers: {
"OData-MaxVersion": "4.0",
"OData-Version": "4.0",
"Accept": "application/json;odata.metadata=none",
"Prefer": 'odata.include-annotations="*",return=representation',
"Content-Type": "application/json"
}
}).catch((error) => {
consoleLogger(error);
});
};
export const deleteAwaitingSubmissions = (incidentID) => {
var queryUrl = buildFileQuery(
"/api/endpoint/deleteawaitingsubmissions_api",
{
incidentID
}
);
var config = {
method: "delete",
url: queryUrl
};
return requestJson(config).catch((error) => {
consoleLogger(error);
});
};
export const deleteWatchedCases = async (watchedCaseID) => {
var queryUrl = buildFileQuery("/api/subscriptions/delete-watched-case", {
watchedCaseID
});
return deleteSignedJson(queryUrl).catch((error) => {
consoleLogger(error);
});
};
export const sendCaseCompleteMessage = async (
containerID,
caseReference,
inv
) => {
var hashQueryPath = buildFileQuery(
"/api/file/createappealcompletemessage_api",
{
container: containerID,
tempcaseref: caseReference
}
);
var queryUrl = buildFileQuery("/api/file/createappealcompletemessage_api", {
container: containerID,
tempcaseref: caseReference,
inv
});
var signedQueryUrl = await buildSignedUrl(hashQueryPath);
queryUrl = appendQuerySuffix(
queryUrl,
signedQueryUrl.replace(hashQueryPath, "")
);
var config = {
method: "get",
url: queryUrl
};
return requestJson(config).catch((error) => {
consoleLogger(error);
});
};
export const sendCaseCompleteMessageProxy = async (
containerID,
caseReference
) => {
var queryUrl = buildFileQuery(
"/api/file/createappealcompletemessageproxy_api",
{
container: containerID,
tempcaseref: caseReference
}
);
var config = {
method: "get",
url: queryUrl
};
return requestJson(config).catch((error) => {
consoleLogger(error);
});
};
export const sendRepCompleteMessage = async (
containerID,
caseReference,
fileName
) => {
var hashQueryPath = buildFileQuery(
"/api/file/createrepcompletemessage_api",
{
container: containerID,
tempcaseref: caseReference,
repid: fileName
}
);
var queryUrl = await buildSignedUrl(hashQueryPath);
var config = {
method: "get",
url: queryUrl
};
return requestJson(config).catch((error) => {
consoleLogger(error);
});
};
export const setRepInvolvment = async (caseid, contactid, involvement) => {
var queryUrl = buildFileQuery("/api/file/createrepinvolvement_api");
var data = {
"incidentid": caseid,
"contactid": contactid,
"involvement": involvement
};
var config = {
method: "post",
url: queryUrl,
data: data
};
try {
return await requestJson(config);
} catch (error) {
consoleLogger(error);
}
};
export const setCaseInvolvment = async (caseid, contactid) => {
var queryUrl = buildFileQuery("/api/file/createrepinvolvement_api");
var data = { "incidentid": caseid, "contactid": contactid };
var config = {
method: "post",
url: queryUrl,
data: data
};
try {
return await requestJson(config);
} catch (error) {
consoleLogger(error);
}
};
-45
View File
@@ -1,45 +0,0 @@
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
};
@@ -1,58 +0,0 @@
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);
});
};
-21
View File
@@ -1,21 +0,0 @@
import {
getAppealsTypes,
getProjectTypes,
getAppealsTypesForNewAppeal,
getLPA,
getFormData,
getMandatoryFields,
getPickLists,
getNotice
} from "./referenceDataDirectService";
export {
getAppealsTypes,
getProjectTypes,
getAppealsTypesForNewAppeal,
getLPA,
getFormData,
getMandatoryFields,
getPickLists,
getNotice
};
-261
View File
@@ -1,261 +0,0 @@
import { BASE_URL } from "../core/env";
import { consoleLogger } from "../core/logger";
import { getJson } from "../clients/endpointClient";
import {
logAndReturnResponse,
logAndReturnEmptyValueErrorResponse
} from "./httpServiceUtils";
export const getBasicSearch = (searchString) => {
return getJson(
BASE_URL +
"/api/endpoint/getbasicsearch_api?searchString=" +
searchString
).catch(logAndReturnResponse);
};
export const getBasicDNSURLSearch = (searchString) => {
return getJson(
BASE_URL +
"/api/endpoint/getbasicdnsurlsearch_api?searchString=" +
searchString
).catch(logAndReturnResponse);
};
export const getAddressSearchPaged = (
searchString,
pageNumber,
orderBy,
fieldSort,
showNumberOfRecords
) => {
return getJson(
"/api/endpoint/getbasicsearch_by_address_paged_api?searchString=" +
searchString +
"&pageNumber=" +
pageNumber +
"&orderby=" +
orderBy +
"&fieldSort=" +
fieldSort +
"&showNumberOfRecords=" +
showNumberOfRecords
).catch(logAndReturnResponse);
};
export const getBasicSearchPaged = (
searchString,
pageNumber,
orderBy,
fieldSort,
showNumberOfRecords
) => {
return getJson(
"/api/search/basic-paged?searchString=" +
searchString +
"&pageNumber=" +
pageNumber +
"&orderby=" +
orderBy +
"&fieldSort=" +
fieldSort +
"&showNumberOfRecords=" +
showNumberOfRecords
).catch(logAndReturnResponse);
};
export const getDNSCoords = () => {
return getJson(BASE_URL + "/api/endpoint/getdnscoords_api").catch(
logAndReturnEmptyValueErrorResponse
);
};
export const getDNSList = (searchString) => {
return getJson(BASE_URL + "/api/endpoint/getdnslist_api").catch(
logAndReturnResponse
);
};
export const getBasicDNSSearch = (searchString) => {
return getJson(BASE_URL + "/api/endpoint/getbasicdnssearch_api").catch(
logAndReturnResponse
);
};
export const getBasicDNSSearchPaged = (
pageNumber,
orderBy,
fieldSort,
showNumberOfRecords
) => {
return getJson(
"/api/endpoint/getbasicdnssearchpaged_api?pageNumber=" +
pageNumber +
"&orderby=" +
orderBy +
"&fieldSort=" +
fieldSort +
"&showNumberOfRecords=" +
showNumberOfRecords
).catch(logAndReturnResponse);
};
export const getAdvancedSearch = (searchString) => {
return getJson(
BASE_URL +
"/api/search/advanced?searchstring=" +
JSON.stringify(searchString)
).catch(logAndReturnEmptyValueErrorResponse);
};
export const getAdvancedSearchPaged = (
searchString,
pageNumber,
orderBy,
fieldSort,
showNumberOfRecords
) => {
return getJson(
"/api/search/advanced-paged?searchstring=" +
JSON.stringify(searchString) +
"&pageNumber=" +
pageNumber +
"&orderby=" +
orderBy +
"&fieldSort=" +
fieldSort +
"&showNumberOfRecords=" +
showNumberOfRecords
).catch(logAndReturnEmptyValueErrorResponse);
};
export const getBasicSearchDetails = async (
appealTypeName,
caseReference,
primaryIdAttribute,
incidentID
) => {
return getJson(
BASE_URL +
"/api/endpoint/getbasicsearchdetails_api?appealTypeName=" +
appealTypeName +
"&primaryIdAttribute=" +
primaryIdAttribute +
"&incidentID=" +
incidentID
).catch((error) => {
consoleLogger(error);
});
};
export const getBasicPartSavedDetails = (
appealTypeName,
caseReference,
primaryIdAttribute,
incidentID
) => {
return getJson(
BASE_URL +
"/api/endpoint/getbasicpartsaveddetails_api?appealTypeName=" +
appealTypeName +
"&primaryIdAttribute=" +
primaryIdAttribute +
"&incidentID=" +
incidentID
).catch((error) => {
consoleLogger(error);
});
};
export const getBasicSearchDetailsPaged = async (
appealTypeName,
caseReference,
primaryIdAttribute,
incidentIDs
) => {
if (!incidentIDs || incidentIDs.length === 0) return [];
const filter = incidentIDs
.map((id) => {
const suffix =
primaryIdAttribute === "pinswg_sipscase"
? `_${primaryIdAttribute}_value`
: `_${primaryIdAttribute}s_value`;
return `${suffix} eq ${id}`;
})
.join(" or ");
const groupedUrl = `/api/search/basic-details-paged?appealTypeName=${appealTypeName}&primaryIdAttribute=${primaryIdAttribute}&incidentID=${encodeURIComponent(
filter
)}`;
try {
const data = await getJson(groupedUrl);
return data.value || [];
} catch (error) {
consoleLogger(error);
return [];
}
};
export const getSearchDocumentDetails = (incidentID) => {
return getJson(
"/api/documents/get-search-document-details?incidentid=" + incidentID
).catch((error) => {
consoleLogger(error);
throw error;
});
};
export const getSearchDocumentTypes = (incidentID) => {
return getJson(
"/api/documents/get-search-document-types?incidentid=" + incidentID
).catch((error) => {
consoleLogger(error);
});
};
export const getSearchDocumentDetailsPaged = (
incidentID,
pageNumber,
orderBy,
fieldSort,
showNumberOfRecords,
documentType
) => {
return getJson(
"/api/documents/get-search-document-details-paged?incidentid=" +
incidentID +
"&pageNumber=" +
pageNumber +
"&orderby=" +
orderBy +
"&fieldSort=" +
fieldSort +
"&showNumberOfRecords=" +
showNumberOfRecords +
"&documentType=" +
documentType
).catch((error) => {
consoleLogger(error);
});
};
export const getLinkedCases = (parentIncidentid) => {
return getJson(
"/api/cases/get-linked-cases?parentincidentid=" + parentIncidentid
).catch((error) => {
consoleLogger(error);
});
};
export const getAddressSearch = async (searchString) => {
const params = new URLSearchParams(searchString);
const str = params.toString();
var queryUrl =
BASE_URL + "/api/endpoint/getbasicsearch_by_address_api?" + str;
return getJson(queryUrl).catch(logAndReturnEmptyValueErrorResponse);
};
-41
View File
@@ -1,41 +0,0 @@
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
};
-57
View File
@@ -1,57 +0,0 @@
# 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
-183
View File
@@ -1,183 +0,0 @@
# 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
-104
View File
@@ -1,104 +0,0 @@
import useTranslation from "next-translate/useTranslation";
import { parseCookies, setCookie } from "nookies";
import { useEffect, useRef, useState } from "react";
const COOKIE_NAME = "pedwAiPolicyNoticeHidden";
const COOKIE_DAYS = 7;
export default function AIPolicyNotice() {
let { t } = useTranslation();
const [hasCheckedCookie, setHasCheckedCookie] = useState(false);
const [isOpen, setIsOpen] = useState(false);
const dismissButtonRef = useRef(null);
useEffect(() => {
const cookies = parseCookies();
const isHidden = cookies[COOKIE_NAME] === "true";
setIsOpen(!isHidden);
setHasCheckedCookie(true);
}, []);
useEffect(() => {
if (isOpen && dismissButtonRef.current) {
dismissButtonRef.current.focus();
}
}, [isOpen]);
const dismissNotice = () => {
const now = new Date();
const expDate = new Date(now);
expDate.setDate(now.getDate() + COOKIE_DAYS);
setCookie(null, COOKIE_NAME, "true", {
path: "/",
expires: expDate
});
setIsOpen(false);
};
if (!hasCheckedCookie || !isOpen) {
return null;
}
return (
<div
className="modal aiModal fade show"
style={{
display: "flex",
alignItems: "center",
justifyContent: "center",
padding: "1rem"
}}
aria-hidden={false}
>
<div className="modal-dialog" style={{ margin: 0 }}>
<div
className="modal-content govuk-!-padding-6"
role="dialog"
aria-modal="true"
aria-labelledby="ai-policy-notice-title"
>
<h2
id="ai-policy-notice-title"
className="govuk-heading-m govuk-!-margin-bottom-3"
>
{t("home:ai-policy-notice-title")}
</h2>
<p className="govuk-body">
{t("home:ai-policy-notice-paragraph-one")}
</p>
<p className="govuk-body govuk-!-margin-bottom-4">
{t("home:ai-policy-notice-paragraph-two")}{" "}
<a
target="_blank"
rel="noopener noreferrer"
href={t(
"home:ai-policy-notice-paragraph-two-a-link"
)}
>
{t("home:ai-policy-notice-paragraph-two-a-label")}
</a>{" "}
{t("home:ai-policy-notice-paragraph-two-b")}
</p>
<button
ref={dismissButtonRef}
type="button"
className="govuk-button govuk-!-margin-bottom-0"
data-module="govuk-button"
onClick={dismissNotice}
>
{t("home:ai-policy-notice-dismiss-button")}
</button>
</div>
</div>
<div
className="modal-backdrop fade show"
style={{ opacity: 0.2 }}
></div>
</div>
);
}
+5 -5
View File
@@ -4,7 +4,7 @@ import { useRouter } from "next/router";
import React, { useState } from "react"; import React, { useState } from "react";
import { connect } from "react-redux"; import { connect } from "react-redux";
import { Field, formValueSelector, reduxForm } from "redux-form"; import { Field, formValueSelector, reduxForm } from "redux-form";
import { updatePassword } from "../../actions/services/accountService"; import { updatePassword } from "../../actions";
const RenderTextfield = ({ const RenderTextfield = ({
id, id,
@@ -60,7 +60,7 @@ const ChangePassword = (props) => {
handleSubmit, handleSubmit,
value, value,
setPasswordUpdated, setPasswordUpdated,
passwordUpdated passwordUpdated,
} = props; } = props;
let { t, lang } = useTranslation(); let { t, lang } = useTranslation();
@@ -158,7 +158,7 @@ const mapStateToProps = (state) => {
searchResultsObj: state.searchResultsObj, searchResultsObj: state.searchResultsObj,
formData: state.formData, formData: state.formData,
appealType: state.appealType, appealType: state.appealType,
accountDetails: state.accountDetails accountDetails: state.accountDetails,
//form: state.form, //form: state.form,
}; };
}; };
@@ -167,7 +167,7 @@ const mapDispatchToProps = (dispatch) => {
return { return {
setCurrentSection: (currentSection) => { setCurrentSection: (currentSection) => {
dispatch(setCurrentSection(currentSection)); dispatch(setCurrentSection(currentSection));
} },
}; };
}; };
@@ -179,6 +179,6 @@ export default connect(
)( )(
reduxForm({ reduxForm({
form: "changepasswordForm", form: "changepasswordForm",
destroyOnUnmount: false destroyOnUnmount: false,
})(ChangePassword) })(ChangePassword)
); );
+14 -25
View File
@@ -140,12 +140,12 @@ const RenderPickList = ({
input, input,
optionsArr, optionsArr,
meta: { touched, error }, meta: { touched, error },
errorMsg errorMsg,
}) => { }) => {
let { t, lang } = useTranslation(); let { t, lang } = useTranslation();
optionsArr = [ optionsArr = [
t("account:account-preferred-language-english") + ":846040001", t("account:account-preferred-language-english") + ":846040001",
t("account:account-preferred-language-welsh") + ":846040000" t("account:account-preferred-language-welsh") + ":846040000",
]; ];
return ( return (
<> <>
@@ -202,7 +202,7 @@ let PersonalDetails = (props) => {
load, load,
pristine, pristine,
reset, reset,
submitting submitting,
} = props; } = props;
let { t, lang } = useTranslation(); let { t, lang } = useTranslation();
@@ -246,7 +246,6 @@ let PersonalDetails = (props) => {
return ( return (
<> <>
<div className="govuk-form-group">
{props.accountUpdatedComplete == false ? ( {props.accountUpdatedComplete == false ? (
props.personalDetailsComplete == false ? ( props.personalDetailsComplete == false ? (
<form onSubmit={handleSubmit(onHandleSubmit)}> <form onSubmit={handleSubmit(onHandleSubmit)}>
@@ -287,9 +286,7 @@ let PersonalDetails = (props) => {
type="text" type="text"
className="govuk-input govuk-input--width-20" className="govuk-input govuk-input--width-20"
validate={[required]} validate={[required]}
label={t( label={t("account:account-first-name-label")}
"account:account-first-name-label"
)}
errorMsg={t("account:is-required-label")} errorMsg={t("account:is-required-label")}
/> />
<Field <Field
@@ -309,9 +306,7 @@ let PersonalDetails = (props) => {
type="email" type="email"
className="govuk-input govuk-input--width-20" className="govuk-input govuk-input--width-20"
validate={[required, email]} validate={[required, email]}
label={t( label={t("account:account-email-address-label")}
"account:account-email-address-label"
)}
disabled disabled
/> />
<Field <Field
@@ -324,23 +319,19 @@ let PersonalDetails = (props) => {
label={t("account:account-telephone-label")} label={t("account:account-telephone-label")}
/> />
<Field <Field
name="pinswg_companyname" name="company"
id="pinswg_companyname" id="company"
component={RenderTextfield} component={RenderTextfield}
type="text" type="text"
className="govuk-input govuk-input--width-20" className="govuk-input govuk-input--width-20"
label={t( label={t("account:account-company-group-label")}
"account:account-company-group-label"
)}
errorMsg={t("account:is-required-label")} errorMsg={t("account:is-required-label")}
/> />
</fieldset> </fieldset>
<fieldset className="govuk-fieldset"> <fieldset className="govuk-fieldset">
<legend className="govuk-fieldset__legend govuk-fieldset__legend--m"> <legend className="govuk-fieldset__legend govuk-fieldset__legend--m">
<h2 className="govuk-fieldset__heading"> <h2 className="govuk-fieldset__heading">
{t( {t("account:account-your-address-label")}
"account:account-your-address-label"
)}
</h2> </h2>
</legend> </legend>
@@ -408,8 +399,7 @@ let PersonalDetails = (props) => {
<Link <Link
href={ href={
"/myportal?q=" + "/myportal?q=" +
props.props.accountDetails props.props.accountDetails.loggedinUserId
.loggedinUserId
} }
className="govuk-link" className="govuk-link"
> >
@@ -433,7 +423,6 @@ let PersonalDetails = (props) => {
) : ( ) : (
<PersonalDetailsComplete props={props} /> <PersonalDetailsComplete props={props} />
)} )}
</div>
</> </>
); );
}; };
@@ -444,7 +433,7 @@ const mapStateToProps = (state) => {
searchResultsObj: state.searchResultsObj, searchResultsObj: state.searchResultsObj,
formData: state.formData, formData: state.formData,
appealType: state.appealType, appealType: state.appealType,
accountDetails: state.accountDetails accountDetails: state.accountDetails,
//form: state.form, //form: state.form,
}; };
}; };
@@ -453,7 +442,7 @@ const mapDispatchToProps = (dispatch) => {
return { return {
setCurrentSection: (currentSection) => { setCurrentSection: (currentSection) => {
dispatch(setCurrentSection(currentSection)); dispatch(setCurrentSection(currentSection));
} },
}; };
}; };
@@ -484,12 +473,12 @@ const selector = formValueSelector("personalDetailsForm"); // <-- same as form n
PersonalDetails = reduxForm({ PersonalDetails = reduxForm({
form: "personalDetailsForm", form: "personalDetailsForm",
enableReinitialize: true, // this is needed!! enableReinitialize: true, // this is needed!!
destroyOnUnmount: false destroyOnUnmount: false,
})(PersonalDetails); })(PersonalDetails);
// You have to connect() to any reducers that you wish to connect to yourself // You have to connect() to any reducers that you wish to connect to yourself
PersonalDetails = connect((state) => ({ PersonalDetails = connect((state) => ({
initialValues: state.accountDetails.accountDetails // pull initial values from account reducer initialValues: state.accountDetails.accountDetails, // pull initial values from account reducer
}))(PersonalDetails); }))(PersonalDetails);
export default PersonalDetails; export default PersonalDetails;
+4 -4
View File
@@ -11,7 +11,7 @@ const BuildCheckPersonalDetails = (props) => {
handleSubmit, handleSubmit,
value, value,
setPersonalDetailsComplete, setPersonalDetailsComplete,
setAccountUpdatedComplete setAccountUpdatedComplete,
} = props; } = props;
let { t, lang } = useTranslation(); let { t, lang } = useTranslation();
@@ -142,7 +142,7 @@ const BuildCheckPersonalDetails = (props) => {
<dd className="govuk-summary-list__value"> <dd className="govuk-summary-list__value">
{ {
props.props.props.form.personalDetailsForm.values props.props.props.form.personalDetailsForm.values
.pinswg_companyname .company
} }
</dd> </dd>
<dd className="govuk-summary-list__actions"> <dd className="govuk-summary-list__actions">
@@ -354,7 +354,7 @@ const mapStateToProps = (state) => {
searchResultsObj: state.searchResultsObj, searchResultsObj: state.searchResultsObj,
formData: state.formData, formData: state.formData,
appealType: state.appealType, appealType: state.appealType,
accountDetails: state.accountDetails accountDetails: state.accountDetails,
//form: state.form, //form: state.form,
}; };
}; };
@@ -363,7 +363,7 @@ const mapDispatchToProps = (dispatch) => {
return { return {
setCurrentSection: (currentSection) => { setCurrentSection: (currentSection) => {
dispatch(setCurrentSection(currentSection)); dispatch(setCurrentSection(currentSection));
} },
}; };
}; };
+12 -39
View File
@@ -3,54 +3,28 @@ import Link from "next/link";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
import React, { useEffect } from "react"; import React, { useEffect } from "react";
import { connect } from "react-redux"; import { connect } from "react-redux";
import { updateAccount } from "../../actions/services/accountService"; import { updateAccount } from "../../actions";
import { setCookie } from "nookies";
const PersonalDetailsComplete = (props) => { const PersonalDetailsComplete = (props) => {
const { const {
handleSubmit, handleSubmit,
value, value,
setRegisterFormComplete, setRegisterFormComplete,
setAccountCreatedComplete setAccountCreatedComplete,
} = props; } = props;
let { t, lang } = useTranslation(); let { t, lang } = useTranslation();
const router = useRouter(); const router = useRouter();
const { locale } = router; const { locale } = router;
// let contactid = props.accountDetails.loggedinUserId;
// let updateBody = props.props.props.form.personalDetailsForm.values;
// let prefLang =
// props.props.props.form.personalDetailsForm.values
// .pinswg_preferredlanguage;
const { loggedinUserId } = props.accountDetails || {};
const formValues = props.props?.props?.form?.personalDetailsForm?.values;
const prefLang = formValues?.pinswg_preferredlanguage;
const userLang = prefLang === "846040000" ? "cy" : "en"; // Move this outside useEffect
useEffect(() => { useEffect(() => {
// let contactid = props.accountDetails.loggedinUserId; let contactid = props.accountDetails.loggedinUserId;
// let updateBody = props.props.props.form.personalDetailsForm.values; let updateBody = props.props.props.form.personalDetailsForm.values;
// let prefLang = updateAccount(contactid, updateBody);
// props.props.props.form.personalDetailsForm.values }, [
// .pinswg_preferredlanguage; props.accountDetails.loggedinUserId,
if (!loggedinUserId || !formValues) return; props.props.props.form.personalDetailsForm.values,
]);
console.log("=============== pref lang", prefLang);
setCookie(null, "pedw_locale", userLang, {
path: "/"
});
console.log("Set cookie to:", userLang);
async function doUpdate() {
const response = await updateAccount(loggedinUserId, formValues);
}
doUpdate();
}, [loggedinUserId, formValues, prefLang, userLang]);
return ( return (
<> <>
@@ -60,8 +34,7 @@ const PersonalDetailsComplete = (props) => {
<p className="govuk-body"> <p className="govuk-body">
<Link <Link
locale={userLang} href={"/myportal?q=" + props.accountDetails.loggedinUserId}
href={userLang === "cy" ? "/cy/fymhorth" : "/myportal"}
className="govuk-link" className="govuk-link"
> >
{" "} {" "}
@@ -78,7 +51,7 @@ const mapStateToProps = (state) => {
searchResultsObj: state.searchResultsObj, searchResultsObj: state.searchResultsObj,
formData: state.formData, formData: state.formData,
appealType: state.appealType, appealType: state.appealType,
accountDetails: state.accountDetails accountDetails: state.accountDetails,
//form: state.form, //form: state.form,
}; };
}; };
@@ -87,7 +60,7 @@ const mapDispatchToProps = (dispatch) => {
return { return {
setCurrentSection: (currentSection) => { setCurrentSection: (currentSection) => {
dispatch(setCurrentSection(currentSection)); dispatch(setCurrentSection(currentSection));
} },
}; };
}; };
+7 -10
View File
@@ -8,10 +8,7 @@ import { connect } from "react-redux";
import { setAccCr, setLogout } from "../../store/accountDetails/action"; import { setAccCr, setLogout } from "../../store/accountDetails/action";
import { import { createAccount, getEmailAccountCheck } from "../../actions";
createAccount,
getEmailAccountCheck
} from "../../actions/services/accountService";
const RegisterComplete = (props) => { const RegisterComplete = (props) => {
const { const {
@@ -21,7 +18,7 @@ const RegisterComplete = (props) => {
value, value,
setRegisterFormComplete, setRegisterFormComplete,
setAccountCreatedComplete, setAccountCreatedComplete,
setAccCr setAccCr,
} = props; } = props;
let { t, lang } = useTranslation(); let { t, lang } = useTranslation();
@@ -37,7 +34,7 @@ const RegisterComplete = (props) => {
// was an appellant "pinswg_typeofinvolvement": 846040001, // was an appellant "pinswg_typeofinvolvement": 846040001,
Object.assign(accountBody, { Object.assign(accountBody, {
"pinswg_typeofinvolvement": 846040061 "pinswg_typeofinvolvement": 846040061,
}); });
accountBody = _.omit(accountBody, ["custom_password_check"]); accountBody = _.omit(accountBody, ["custom_password_check"]);
@@ -108,9 +105,9 @@ const RegisterComplete = (props) => {
<p className="govuk-body"> <p className="govuk-body">
<a <a
onClick={() => { onClick={() => {
(setRegisterFormComplete(false), setRegisterFormComplete(false),
setAccountCreatedComplete(false), setAccountCreatedComplete(false),
setAccCr(false)); setAccCr(false);
}} }}
className="govuk-link" className="govuk-link"
> >
@@ -133,7 +130,7 @@ const mapStateToProps = (state) => {
searchResultsObj: state.searchResultsObj, searchResultsObj: state.searchResultsObj,
formData: state.formData, formData: state.formData,
appealType: state.appealType, appealType: state.appealType,
accountDetails: state.accountDetails accountDetails: state.accountDetails,
//form: state.form, //form: state.form,
}; };
}; };
@@ -145,7 +142,7 @@ const mapDispatchToProps = (dispatch) => {
}, },
setLogout: () => { setLogout: () => {
dispatch(setLogout()); dispatch(setLogout());
} },
}; };
}; };
+5 -20
View File
@@ -66,7 +66,7 @@ const RegisterForm = (props) => {
setRegisterFormComplete, setRegisterFormComplete,
setAccountCreatedComplete, setAccountCreatedComplete,
loggedInUserEmail, loggedInUserEmail,
emailaddress1 emailaddress1,
} = props; } = props;
let { t, lang } = useTranslation(); let { t, lang } = useTranslation();
@@ -137,8 +137,6 @@ const RegisterForm = (props) => {
{props.accountCreatedComplete != true ? ( {props.accountCreatedComplete != true ? (
props.registerFormComplete == false ? ( props.registerFormComplete == false ? (
<form onSubmit={handleSubmit(onHandleSubmit)}> <form onSubmit={handleSubmit(onHandleSubmit)}>
<div className="card" id="personalDetailsCard">
<div className="card-body">
<fieldset className="govuk-fieldset"> <fieldset className="govuk-fieldset">
<legend className="govuk-fieldset__legend govuk-fieldset__legend--m"> <legend className="govuk-fieldset__legend govuk-fieldset__legend--m">
<h2 className="govuk-fieldset__heading"> <h2 className="govuk-fieldset__heading">
@@ -199,17 +197,6 @@ const RegisterForm = (props) => {
"account:register-new-account-phone-label" "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>
<fieldset className="govuk-fieldset"> <fieldset className="govuk-fieldset">
<legend className="govuk-fieldset__legend govuk-fieldset__legend--m"> <legend className="govuk-fieldset__legend govuk-fieldset__legend--m">
@@ -294,8 +281,6 @@ const RegisterForm = (props) => {
{t("common:continue-button")} {t("common:continue-button")}
</button> </button>
</div> </div>
</div>
</div>
</form> </form>
) : ( ) : (
<RegisterFormCheck <RegisterFormCheck
@@ -323,8 +308,8 @@ const mapStateToProps = (state, props) => {
appealType: state.appealType, appealType: state.appealType,
//form: state.form, //form: state.form,
initialValues: { initialValues: {
emailaddress1: props.loggedInUserEmail emailaddress1: props.loggedInUserEmail,
} },
}; };
}; };
@@ -332,7 +317,7 @@ const mapDispatchToProps = (dispatch) => {
return { return {
setCurrentSection: (currentSection) => { setCurrentSection: (currentSection) => {
dispatch(setCurrentSection(currentSection)); dispatch(setCurrentSection(currentSection));
} },
}; };
}; };
@@ -345,6 +330,6 @@ export default connect(
reduxForm({ reduxForm({
form: "accountRegisterForm", form: "accountRegisterForm",
enableReinitialize: true, enableReinitialize: true,
destroyOnUnmount: false destroyOnUnmount: false,
})(RegisterForm) })(RegisterForm)
); );
+2 -3
View File
@@ -3,7 +3,6 @@ import Link from "next/link";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
import CRMError from "./crmError"; import CRMError from "./crmError";
import SearchResults from "./search/addresssearchresults"; import SearchResults from "./search/addresssearchresults";
import { hasOwn } from "./utils";
export default function Search(props) { export default function Search(props) {
const { const {
@@ -13,14 +12,14 @@ export default function Search(props) {
myportal, myportal,
watchedCases, watchedCases,
isLinkedCase, isLinkedCase,
showLoginCheck showLoginCheck,
} = props; } = props;
let { t } = useTranslation(); let { t } = useTranslation();
const router = useRouter(); const router = useRouter();
const { locale } = router; const { locale } = router;
var hasError = hasOwn(searchResultsObj.searchResultsObj, "errorCode") var hasError = _.has(searchResultsObj.searchResultsObj, "errorCode")
? true ? true
: false; : false;
+73 -60
View File
@@ -6,20 +6,17 @@ import Link from "next/link";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
import PaginationControl from "../../../components/search/pagination"; import PaginationControl from "../../../components/search/pagination";
import { connect } from "react-redux"; import { connect } from "react-redux";
import transLookup from "../../../data/lookuptranslations.json";
import { import {
setSearchResults, setSearchResults,
setSearchDetails setSearchDetails,
} from "../../../store/searchOutput/action"; } from "../../../store/searchOutput/action";
import { getDetailsProxy, getSearchDetailsPaged, hasOwn } from "../../utils"; import { getDetailsProxy, getSearchDetailsPaged } from "../../utils";
import { getAdvancedSearchPaged } from "../../../actions/services/searchService"; import { getAdvancedSearchPaged, getNewAppealsPage } from "../../../actions";
import { getNewAppealsPage } from "../../../actions/services/adminService";
import resolveCrmDisplayValue from "../../../lib/i18n/crmDisplay/resolveCrmDisplayValue";
import { import {
setCurrentPage, setCurrentPage,
setCurrentReference setCurrentReference,
} from "../../../store/currentView/action"; } from "../../../store/currentView/action";
function AppealsTab(props) { function AppealsTab(props) {
@@ -30,15 +27,9 @@ function AppealsTab(props) {
const [fieldSortState, setfieldSortState] = useState("desc"); const [fieldSortState, setfieldSortState] = useState("desc");
const [loginToWatch, setLoginToWatch] = useState("true"); const [loginToWatch, setLoginToWatch] = useState("true");
const { const searchDetailsObj = props.searchResultsObj.searchDetailsObj || {};
searchResultsObj: searchResultsState, const resultsArr = props.searchResultsObj.searchResultsObj.value || [];
setSearchResults, const searchResultsObj = props.searchResultsObj.searchResultsObj;
setSearchDetails
} = props;
const searchDetailsObj = searchResultsState.searchDetailsObj || {};
const resultsArr = searchResultsState.searchResultsObj.value || [];
const searchResultsObj = searchResultsState.searchResultsObj;
const { t } = useTranslation(); const { t } = useTranslation();
const router = useRouter(); const router = useRouter();
@@ -83,14 +74,20 @@ function AppealsTab(props) {
fieldSort, fieldSort,
selectedOption selectedOption
).then((data) => { ).then((data) => {
setSearchResults(data); props.setSearchResults(data); // ✅ use props, not import
return getSearchDetailsPaged(data).then((details) => { return getSearchDetailsPaged(data).then((details) => {
setSearchDetails(details); props.setSearchDetails(details); // ✅ use props, not import
setShowSpinnerState(false); setShowSpinnerState(false);
}); });
}); });
}, },
[selectedOption, setSearchDetails, setSearchResults] [
advancedSearch,
searchString,
selectedOption,
props.setSearchDetails,
props.setSearchResults,
]
); );
useEffect(() => { useEffect(() => {
@@ -108,7 +105,7 @@ function AppealsTab(props) {
orderByState, orderByState,
searchLoaded, searchLoaded,
getSearchPageResults, getSearchPageResults,
router.query router.query,
]); ]);
const ResultsView = (resultsArr) => { const ResultsView = (resultsArr) => {
@@ -228,7 +225,7 @@ function AppealsTab(props) {
item.ticketnumber + item.ticketnumber +
'")]', '")]',
json: searchDetailsObj, json: searchDetailsObj,
eval: true eval: true,
}); });
detailsObj = detailsObj[0] || {}; detailsObj = detailsObj[0] || {};
@@ -257,8 +254,6 @@ function AppealsTab(props) {
className="govuk-link--no-underline" className="govuk-link--no-underline"
onClick={() => { onClick={() => {
setCurrentReference({ setCurrentReference({
"statuscode":
item.statuscode,
"ticketnumber": "ticketnumber":
item.ticketnumber, item.ticketnumber,
"currentReference": "currentReference":
@@ -280,7 +275,7 @@ function AppealsTab(props) {
"pinswg_specialistcaseprocess" "pinswg_specialistcaseprocess"
) )
? detailsObj.pinswg_specialistcaseprocess ? detailsObj.pinswg_specialistcaseprocess
: "" : "",
}); });
}} }}
> >
@@ -308,7 +303,7 @@ function AppealsTab(props) {
)} )}
: :
</span> </span>
{hasOwn( {_.has(
detailsObj, detailsObj,
"pinswg_projectlocation" "pinswg_projectlocation"
) )
@@ -327,7 +322,7 @@ function AppealsTab(props) {
)[0] )[0]
: "" : ""
: ""} : ""}
{hasOwn( {_.has(
detailsObj, detailsObj,
"pinswg_siteaddressline1" "pinswg_siteaddressline1"
) )
@@ -337,52 +332,52 @@ function AppealsTab(props) {
{/* {detailsObj.pinswg_siteaddressline1 != {/* {detailsObj.pinswg_siteaddressline1 !=
null && <br />} */} null && <br />} */}
{hasOwn( {_.has(
detailsObj, detailsObj,
"pinswg_siteaddressline1" "pinswg_siteaddressline1"
) && ) &&
detailsObj.pinswg_siteaddressline1 != detailsObj.pinswg_siteaddressline1 !=
null && <br />} null && <br />}
{hasOwn( {_.has(
detailsObj, detailsObj,
"pinswg_siteaddressline1" "pinswg_siteaddressline1"
) )
? detailsObj.pinswg_siteaddressline2 ? detailsObj.pinswg_siteaddressline2
: ""} : ""}
{hasOwn( {_.has(
detailsObj, detailsObj,
"pinswg_siteaddressline2" "pinswg_siteaddressline2"
) && ) &&
detailsObj.pinswg_siteaddressline2 != detailsObj.pinswg_siteaddressline2 !=
null && <br />} null && <br />}
{hasOwn( {_.has(
detailsObj, detailsObj,
"pinswg_siteaddresstown" "pinswg_siteaddresstown"
) )
? detailsObj.pinswg_siteaddresstown ? detailsObj.pinswg_siteaddresstown
: ""} : ""}
{hasOwn( {_.has(
detailsObj, detailsObj,
"pinswg_siteaddresstown" "pinswg_siteaddresstown"
) && ) &&
detailsObj.pinswg_siteaddresstown != detailsObj.pinswg_siteaddresstown !=
null && <br />} null && <br />}
{hasOwn( {_.has(
detailsObj, detailsObj,
"pinswg_siteaddresscounty" "pinswg_siteaddresscounty"
) )
? detailsObj.pinswg_siteaddresscounty ? detailsObj.pinswg_siteaddresscounty
: ""} : ""}
{hasOwn( {_.has(
detailsObj, detailsObj,
"pinswg_siteaddresscounty" "pinswg_siteaddresscounty"
) && ) &&
detailsObj.pinswg_siteaddresscounty != detailsObj.pinswg_siteaddresscounty !=
null && <br />} null && <br />}
{hasOwn( {_.has(
detailsObj, detailsObj,
"pinswg_siteaddresspostcode" "pinswg_siteaddresspostcode"
) )
@@ -400,8 +395,8 @@ function AppealsTab(props) {
? item.pinswg_appellantfirstname + ? item.pinswg_appellantfirstname +
" " + " " +
item.pinswg_appellantlastname item.pinswg_appellantlastname
: hasOwn(detailsObj, [ : _.has(detailsObj, [
"_pinswg_appellant_value@OData.Community.Display.V1.FormattedValue" "_pinswg_appellant_value@OData.Community.Display.V1.FormattedValue",
]) ])
? detailsObj[ ? detailsObj[
"_pinswg_appellant_value@OData.Community.Display.V1.FormattedValue" "_pinswg_appellant_value@OData.Community.Display.V1.FormattedValue"
@@ -415,17 +410,23 @@ function AppealsTab(props) {
)} )}
: :
</span> </span>
{hasOwn(item, [ {_.has(item, [
"_pinswg_associatedlpa_value@OData.Community.Display.V1.FormattedValue" "_pinswg_associatedlpa_value@OData.Community.Display.V1.FormattedValue",
]) ])
? resolveCrmDisplayValue({ ? router.locale == "cy"
value: item[ ? jsonpath({
path:
'$..[?(@ && @.value=="' +
item[
"_pinswg_associatedlpa_value@OData.Community.Display.V1.FormattedValue" "_pinswg_associatedlpa_value@OData.Community.Display.V1.FormattedValue"
], ] +
locale: router.locale, '")].value_cy',
translations: transLookup, json: transLookup,
fallbackValue: "N/A" eval: true,
}) })
: item[
"_pinswg_associatedlpa_value@OData.Community.Display.V1.FormattedValue"
] || "N/A"
: ""} : ""}
</dd> </dd>
<dd className="govuk-summary-list__value govuk-!-font-size-16"> <dd className="govuk-summary-list__value govuk-!-font-size-16">
@@ -435,14 +436,20 @@ function AppealsTab(props) {
)} )}
: :
</span> </span>
{resolveCrmDisplayValue({ {router.locale == "cy"
value: item[ ? jsonpath({
path:
'$..[?(@ && @.value=="' +
item[
"pinswg_appealcasetype@OData.Community.Display.V1.FormattedValue" "pinswg_appealcasetype@OData.Community.Display.V1.FormattedValue"
], ] +
locale: router.locale, '")].value_cy',
translations: transLookup, json: transLookup,
fallbackValue: "N/A" eval: true,
})} })
: item[
"pinswg_appealcasetype@OData.Community.Display.V1.FormattedValue"
] || "N/A"}
</dd> </dd>
<dd className="govuk-summary-list__value govuk-!-font-size-16"> <dd className="govuk-summary-list__value govuk-!-font-size-16">
<span className="results-visually-hidden"> <span className="results-visually-hidden">
@@ -452,14 +459,20 @@ function AppealsTab(props) {
: :
</span> </span>
{resolveCrmDisplayValue({ {router.locale == "cy"
value: item[ ? jsonpath({
path:
'$..[?(@ && @.value=="' +
item[
"statuscode@OData.Community.Display.V1.FormattedValue" "statuscode@OData.Community.Display.V1.FormattedValue"
], ] +
locale: router.locale, '")].value_cy',
translations: transLookup, json: transLookup,
fallbackValue: "N/A" eval: true,
})} })
: item[
"statuscode@OData.Community.Display.V1.FormattedValue"
] || "N/A"}
</dd> </dd>
<dd className="govuk-summary-list__value govuk-!-font-size-16"> <dd className="govuk-summary-list__value govuk-!-font-size-16">
{item[ {item[
@@ -542,13 +555,13 @@ const mapDispatchToProps = (dispatch) => {
}, },
setCurrentPage: (currentPage) => { setCurrentPage: (currentPage) => {
dispatch(setCurrentPage(currentPage)); dispatch(setCurrentPage(currentPage));
} },
}; };
}; };
const mapStateToProps = (state) => { const mapStateToProps = (state) => {
return { return {
searchResultsObj: state.searchResultsObj searchResultsObj: state.searchResultsObj,
}; };
}; };
-273
View File
@@ -1,273 +0,0 @@
import { useMemo, useState } from "react";
import Link from "next/link";
export default function AppealStatusDashboard({ statusObj = [] }) {
const [openSections, setOpenSections] = useState({});
const sortedAppeals = useMemo(
() =>
[...statusObj].sort(
(a, b) => (b.caseCount || 0) - (a.caseCount || 0)
),
[statusObj]
);
const percentageOf = (value, total) =>
total ? `${(((value || 0) / total) * 100).toFixed(1)}%` : "0.0%";
const totalCases = sortedAppeals.reduce(
(sum, appeal) => sum + (appeal.caseCount || 0),
0
);
const largestAppeal = sortedAppeals[0];
const allStatuses = sortedAppeals.flatMap((appeal) =>
(appeal.statuses || []).map((status) => ({
...status,
appealType: appeal.value
}))
);
const statusTotals = allStatuses.reduce((acc, status) => {
if (!acc[status.statuscode]) {
acc[status.statuscode] = {
value: status.value,
statuscode: status.statuscode,
caseCount: 0
};
}
acc[status.statuscode].caseCount += status.caseCount || 0;
return acc;
}, {});
const mostCommonStatus = Object.values(statusTotals).sort(
(a, b) => b.caseCount - a.caseCount
)[0];
const maxAppealCount = largestAppeal?.caseCount || 1;
const allExpanded =
sortedAppeals.length > 0 &&
sortedAppeals.every((_, index) => openSections[index]);
const toggleSection = (index) => {
setOpenSections((current) => ({
...current,
[index]: !current[index]
}));
};
const showAll = () => {
const allOpen = {};
sortedAppeals.forEach((_, index) => {
allOpen[index] = true;
});
setOpenSections(allOpen);
};
const hideAll = () => {
setOpenSections({});
};
return (
<div className="govuk-grid-row">
<div className="govuk-grid-column-full">
<h1>Appeal case status dashboard</h1>
<div className="govuk-grid-row">
<DashboardCard title="Total cases" value={totalCases} />
<DashboardCard
title="Appeal types"
value={sortedAppeals.length}
/>
<DashboardCard
title="Largest appeal type"
value={largestAppeal?.caseCount || 0}
caption={largestAppeal?.value}
/>
<DashboardCard
title="Most common status"
value={mostCommonStatus?.caseCount || 0}
caption={mostCommonStatus?.value}
/>
</div>
<section className="govuk-!-margin-top-8">
<h2 className="govuk-heading-m">
Case counts and stage breakdown by appeal type
</h2>
<p className="govuk-body-s">
Select an appeal type row to show the case stage
breakdown.
</p>
<div className="govuk-accordion__controls">
<button
type="button"
className="govuk-accordion__show-all"
onClick={allExpanded ? hideAll : showAll}
>
<span className="govuk-accordion__show-all-text">
{allExpanded
? "Hide all sections"
: "Show all sections"}
</span>
</button>
</div>
<div
className="govuk-accordion appeal-stage-chart"
id="appeals-with-status-accordion"
>
{sortedAppeals.map((appeal, index) => {
const isOpen = !!openSections[index];
const barWidth =
((appeal.caseCount || 0) / maxAppealCount) *
100;
const sortedStatuses = [...(appeal.statuses || [])]
.filter((status) => (status.caseCount || 0) > 0)
.sort(
(a, b) =>
(b.caseCount || 0) - (a.caseCount || 0)
);
return (
<div
className={
isOpen
? "govuk-accordion__section govuk-accordion__section--expanded appeal-stage-chart__accordion-section"
: "govuk-accordion__section appeal-stage-chart__accordion-section"
}
key={appeal.appealType || index}
>
<div className="govuk-accordion__section-header">
<h2 className="govuk-accordion__section-heading">
<button
type="button"
className="govuk-accordion__section-button appeal-stage-chart__button"
id={`appeal-status-heading-${index}`}
aria-expanded={isOpen}
aria-controls={`appeal-status-content-${index}`}
onClick={() =>
toggleSection(index)
}
>
<span className="appeal-stage-chart__row">
<span className="appeal-stage-chart__label">
{appeal.value} (
{percentageOf(
appeal.caseCount,
totalCases
)}
)
</span>
<span className="appeal-stage-chart__bar-wrapper">
<span
className="appeal-stage-chart__bar"
style={{
width: `${barWidth}%`
}}
aria-hidden="true"
>
{sortedStatuses.map(
(
status,
statusIndex
) => (
<span
key={`${status.statuscode}-${statusIndex}`}
className={`appeal-stage-chart__segment appeal-stage-chart__segment--${
statusIndex %
6
}`}
style={{
width: `${
((status.caseCount ||
0) /
(appeal.caseCount ||
1)) *
100
}%`
}}
title={`${status.value}: ${status.caseCount}`}
/>
)
)}
</span>
<span className="appeal-stage-chart__count">
{appeal.caseCount ||
0}{" "}
cases
</span>
</span>
</span>
</button>
</h2>
</div>
<div
id={`appeal-status-content-${index}`}
className="govuk-accordion__section-content"
aria-labelledby={`appeal-status-heading-${index}`}
hidden={!isOpen}
>
<dl className="govuk-summary-list">
{sortedStatuses.map((status) => (
<div
className="govuk-summary-list__row"
key={status.statuscode}
>
<dt className="govuk-summary-list__key">
<Link
target="_blank"
href={`/advancedsearchresults?apt=${appeal.appealType}&statuscode=${status.statuscode}`}
>
{status.value}
</Link>
</dt>
<dd className="govuk-summary-list__value">
{status.caseCount || 0}{" "}
cases (
{percentageOf(
status.caseCount,
appeal.caseCount
)}{" "}
of this appeal type)
</dd>
</div>
))}
</dl>
</div>
</div>
);
})}
</div>
</section>
</div>
</div>
);
}
function DashboardCard({ title, value, caption }) {
return (
<div className="govuk-grid-column-one-quarter">
<div className="dashboard-card">
<p className="govuk-body-s dashboard-card__title">{title}</p>
<p className="govuk-heading-l dashboard-card__value">{value}</p>
{caption && (
<p className="govuk-body-s dashboard-card__caption">
{caption}
</p>
)}
</div>
</div>
);
}
@@ -1,571 +0,0 @@
import { useMemo, useState } from "react";
import Link from "next/link";
export default function AppealLpaStatusDashboard({ statusObj = [] }) {
const [openAppeals, setOpenAppeals] = useState({});
const [openLpaSections, setOpenLpaSections] = useState({});
const [openAppealLpas, setOpenAppealLpas] = useState({});
const [openLpaAppeals, setOpenLpaAppeals] = useState({});
const percentageOf = (value, total) =>
total ? `${(((value || 0) / total) * 100).toFixed(1)}%` : "0.0%";
const totalCases = useMemo(
() =>
statusObj.reduce((total, item) => total + (item.caseCount || 0), 0),
[statusObj]
);
const groupedAppeals = useMemo(() => {
const grouped = statusObj.reduce((acc, item) => {
const appealKey = item.appealType;
if (!acc[appealKey]) {
acc[appealKey] = {
appealType: item.appealType,
appealTypeName: item.appealTypeName,
caseCount: 0,
lpas: {}
};
}
acc[appealKey].caseCount += item.caseCount || 0;
const lpaKey = item.lpaId || "unknown-lpa";
if (!acc[appealKey].lpas[lpaKey]) {
acc[appealKey].lpas[lpaKey] = {
lpaId: item.lpaId,
lpaName: item.lpaName || "Unknown LPA",
caseCount: 0,
statuses: []
};
}
acc[appealKey].lpas[lpaKey].caseCount += item.caseCount || 0;
acc[appealKey].lpas[lpaKey].statuses.push({
statuscode: item.statuscode,
status: item.status,
caseCount: item.caseCount || 0
});
return acc;
}, {});
return Object.values(grouped)
.map((appeal) => ({
...appeal,
lpas: Object.values(appeal.lpas)
.map((lpa) => ({
...lpa,
statuses: lpa.statuses.sort(
(a, b) => (b.caseCount || 0) - (a.caseCount || 0)
)
}))
.sort((a, b) => (b.caseCount || 0) - (a.caseCount || 0))
}))
.sort((a, b) => (b.caseCount || 0) - (a.caseCount || 0));
}, [statusObj]);
const groupedLpas = useMemo(() => {
const grouped = statusObj.reduce((acc, item) => {
const lpaKey = item.lpaId || "unknown-lpa";
if (!acc[lpaKey]) {
acc[lpaKey] = {
lpaId: item.lpaId,
lpaName: item.lpaName || "Unknown LPA",
caseCount: 0,
appeals: {}
};
}
acc[lpaKey].caseCount += item.caseCount || 0;
const appealKey = item.appealType;
if (!acc[lpaKey].appeals[appealKey]) {
acc[lpaKey].appeals[appealKey] = {
appealType: item.appealType,
appealTypeName: item.appealTypeName,
caseCount: 0,
statuses: []
};
}
acc[lpaKey].appeals[appealKey].caseCount += item.caseCount || 0;
acc[lpaKey].appeals[appealKey].statuses.push({
statuscode: item.statuscode,
status: item.status,
caseCount: item.caseCount || 0
});
return acc;
}, {});
return Object.values(grouped)
.map((lpa) => ({
...lpa,
appeals: Object.values(lpa.appeals)
.map((appeal) => ({
...appeal,
statuses: appeal.statuses.sort(
(a, b) => (b.caseCount || 0) - (a.caseCount || 0)
)
}))
.sort((a, b) => (b.caseCount || 0) - (a.caseCount || 0))
}))
.sort((a, b) => (b.caseCount || 0) - (a.caseCount || 0));
}, [statusObj]);
const toggleAppeal = (appealType) => {
setOpenAppeals((current) => ({
...current,
[appealType]: !current[appealType]
}));
};
const toggleLpaSection = (lpaId) => {
setOpenLpaSections((current) => ({
...current,
[lpaId]: !current[lpaId]
}));
};
const toggleAppealLpa = (key) => {
setOpenAppealLpas((current) => ({
...current,
[key]: !current[key]
}));
};
const toggleLpaAppeal = (key) => {
setOpenLpaAppeals((current) => ({
...current,
[key]: !current[key]
}));
};
const sortedAppeals = useMemo(
() => [...statusObj].sort((a, b) => (b.lpaId || 0) - (a.lpaId || 0)),
[statusObj]
);
const allStatuses = sortedAppeals.flatMap((appeal) =>
(appeal.statuses || []).map((status) => ({
...status,
lpaId: appeal.lpaId,
lpaName: appeal.lpaName
}))
);
const statusTotals = allStatuses.reduce((acc, status) => {
if (!acc[status.statuscode]) {
acc[status.statuscode] = {
value: status.value,
statuscode: status.statuscode,
caseCount: 0
};
}
acc[status.statuscode].caseCount += status.caseCount || 0;
return acc;
}, {});
const largestAppeal = groupedLpas[0];
const mostCommonStatus = Object.values(groupedAppeals).sort(
(a, b) => b.caseCount - a.caseCount
)[0];
const maxAppealCount = largestAppeal?.caseCount || 1;
const maxGroupedAppealCount = groupedAppeals[0]?.caseCount || 1;
const allAppealsExpanded =
groupedAppeals.length > 0 &&
groupedAppeals.every((appeal) => openAppeals[appeal.appealType]);
const allLpasExpanded =
groupedLpas.length > 0 &&
groupedLpas.every((lpa) => openLpaSections[lpa.lpaId]);
const showAllAppeals = () => {
const allOpen = {};
groupedAppeals.forEach((appeal) => {
allOpen[appeal.appealType] = true;
});
setOpenAppeals(allOpen);
};
const showAllLpas = () => {
const allOpen = {};
groupedLpas.forEach((lpa) => {
allOpen[lpa.lpaId] = true;
});
setOpenLpaSections(allOpen);
};
const hideAllAppeals = () => {
setOpenAppeals({});
setOpenAppealLpas({});
};
const hideAllLpas = () => {
setOpenLpaSections({});
setOpenLpaAppeals({});
};
return (
<div className="govuk-grid-row">
<div className="govuk-grid-column-full">
<h1 className="">LPA Appeal case status dashboard</h1>
<div className="govuk-grid-row">
<DashboardCard title="Total cases" value={totalCases} />
<DashboardCard title="LPAs" value={groupedLpas.length} />
<DashboardCard
title="Largest number of appeals"
value={largestAppeal?.caseCount || 0}
caption={largestAppeal?.lpaName}
/>
<DashboardCard
title="Most common appeal"
value={mostCommonStatus?.caseCount || 0}
caption={mostCommonStatus?.appealTypeName}
/>
</div>
</div>
<section className="govuk-!-margin-top-8">
<h2 className="govuk-heading-m">
Appeal types and case stages by LPA
</h2>
<div className="govuk-accordion__controls">
<button
type="button"
className="govuk-accordion__show-all"
onClick={allLpasExpanded ? hideAllLpas : showAllLpas}
>
<span className="govuk-accordion__show-all-text">
{allLpasExpanded
? "Hide all sections"
: "Show all sections"}
</span>
</button>
</div>
<div
className="govuk-accordion"
id="lpa-appeal-status-accordion"
>
{groupedLpas.map((lpa) => {
const lpaOpen = !!openLpaSections[lpa.lpaId];
const width =
((lpa.caseCount || 0) / maxAppealCount) * 100;
return (
<div
className={
lpaOpen
? "govuk-accordion__section govuk-accordion__section--expanded"
: "govuk-accordion__section"
}
key={lpa.lpaId}
>
<div className="govuk-accordion__section-header">
<h3 className="govuk-accordion__section-heading">
<button
type="button"
className="govuk-accordion__section-button"
aria-expanded={lpaOpen}
onClick={() =>
toggleLpaSection(lpa.lpaId)
}
>
<div className="appeal-count-chart__row">
<div className="appeal-count-chart__label">
{lpa.lpaName} (
{percentageOf(
lpa.caseCount,
totalCases
)}
)
</div>
<div className="appeal-count-chart__bar-wrapper">
<span
className="appeal-count-chart__bar"
style={{
width: `${width}%`
}}
/>
<span className="appeal-count-chart__count">
{lpa.caseCount}
</span>
</div>
</div>
</button>
</h3>
</div>
<div
className="govuk-accordion__section-content"
hidden={!lpaOpen}
>
{lpa.appeals.map((appeal) => {
const key = `${lpa.lpaId}-${appeal.appealType}`;
const appealOpen =
!!openLpaAppeals[key];
return (
<div
className="lpa-status-block"
key={key}
>
<button
type="button"
className="lpa-status-block__button"
aria-expanded={appealOpen}
onClick={() =>
toggleLpaAppeal(key)
}
>
<span className="govuk-body-m">
{appeal.appealTypeName}
</span>
<span className="govuk-body-m">
{appeal.caseCount} cases
(
{percentageOf(
appeal.caseCount,
lpa.caseCount
)}
)
</span>
</button>
<div hidden={!appealOpen}>
<dl className="govuk-summary-list govuk-!-margin-bottom-4">
{appeal.statuses.map(
(status) => (
<div
className="govuk-summary-list__row"
key={
status.statuscode
}
>
<dt className="govuk-summary-list__key">
<Link
target="_blank"
href={`/advancedsearchresults?apt=${appeal.appealType}&lpa=${lpa.lpaId}&statuscode=${status.statuscode}`}
>
{
status.status
}
</Link>
</dt>
<dd className="govuk-summary-list__value">
{
status.caseCount
}{" "}
(
{percentageOf(
status.caseCount,
appeal.caseCount
)}
)
</dd>
</div>
)
)}
</dl>
</div>
</div>
);
})}
</div>
</div>
);
})}
</div>
</section>
<section className="govuk-!-margin-top-8">
<h2 className="govuk-heading-m">
Case stage by LPA and Appeal Type
</h2>
<p className="govuk-body-s">
Select an appeal type row to show the LPA and then case
stage breakdown.
</p>
<div className="govuk-accordion__controls">
<button
type="button"
className="govuk-accordion__show-all"
onClick={
allAppealsExpanded ? hideAllAppeals : showAllAppeals
}
>
<span className="govuk-accordion__show-all-text">
{allAppealsExpanded
? "Hide all sections"
: "Show all sections"}
</span>
</button>
</div>
<div
className="govuk-accordion"
id="appeal-lpa-status-accordion"
>
{groupedAppeals.map((appeal) => {
const appealOpen = !!openAppeals[appeal.appealType];
const width =
((appeal.caseCount || 0) / maxGroupedAppealCount) *
100;
return (
<div
className={
appealOpen
? "govuk-accordion__section govuk-accordion__section--expanded"
: "govuk-accordion__section"
}
key={appeal.appealType}
>
<div className="govuk-accordion__section-header">
<h2 className="govuk-accordion__section-heading">
<button
type="button"
className="govuk-accordion__section-button"
aria-expanded={appealOpen}
onClick={() =>
toggleAppeal(appeal.appealType)
}
>
<div className="appeal-count-chart__row">
<div className="appeal-count-chart__label">
{appeal.appealTypeName}{" "}
{/* {appeal.caseCount} cases */}
(
{percentageOf(
appeal.caseCount,
totalCases
)}
)
</div>
<div className="appeal-count-chart__bar-wrapper">
<span
className="appeal-count-chart__bar"
style={{
width: `${width}%`
}}
/>
<span className="appeal-count-chart__count">
{appeal.caseCount}
</span>
</div>
</div>
</button>
</h2>
</div>
<div
className="govuk-accordion__section-content"
hidden={!appealOpen}
>
{appeal.lpas.map((lpa) => {
const lpaKey = `${appeal.appealType}-${lpa.lpaId}`;
const lpaOpen =
!!openAppealLpas[lpaKey];
return (
<div
className="lpa-status-block"
key={lpaKey}
>
<button
type="button"
className="lpa-status-block__button"
aria-expanded={lpaOpen}
onClick={() =>
toggleAppealLpa(lpaKey)
}
>
<span className="govuk-body-m">
{lpa.lpaName}
</span>
<span className="govuk-body-m">
{lpa.caseCount} cases (
{percentageOf(
lpa.caseCount,
appeal.caseCount
)}
)
</span>
</button>
<div hidden={!lpaOpen}>
<dl className="govuk-summary-list govuk-!-margin-bottom-4">
{lpa.statuses.map(
(status) => (
<div
className="govuk-summary-list__row"
key={
status.statuscode
}
>
<dt className="govuk-summary-list__key">
<Link
target="_blank"
href={`/advancedsearchresults?apt=${appeal.appealType}&lpa=${lpa.lpaId}&statuscode=${status.statuscode}`}
>
{
status.status
}
</Link>
</dt>
<dd className="govuk-summary-list__value">
{
status.caseCount
}{" "}
(
{percentageOf(
status.caseCount,
lpa.caseCount
)}
)
</dd>
</div>
)
)}
</dl>
</div>
</div>
);
})}
</div>
</div>
);
})}
</div>
</section>
</div>
);
}
function DashboardCard({ title, value, caption }) {
return (
<div className="govuk-grid-column-one-quarter">
<div className="dashboard-card">
<p className="govuk-body-s dashboard-card__title">{title}</p>
<p className="govuk-heading-l dashboard-card__value">{value}</p>
{caption && (
<p className="govuk-body-s dashboard-card__caption">
{caption}
</p>
)}
</div>
</div>
);
}
-294
View File
@@ -1,294 +0,0 @@
// // components/admin/tabs/AccountsTab.js
// import Link from "next/link";
// export default function AppealsWithStatusTab({ statusObj }) {
// return (
// <div>
// <h1>User Accounts</h1>
// <dl className="govuk-summary-list govuk-!-margin-bottom-9 results">
// <div className="govuk-summary-list__row results-headings">
// <dd className="govuk-summary-list__key govuk-!-font-size-16">
// Name
// </dd>
// <dd className="govuk-summary-list__key govuk-!-font-size-16">
// Last accessed
// </dd>
// </div>
// {statusObj.map((appeal) => (
// <div key={appeal.id} className="govuk-summary-list__row">
// <dd className="govuk-summary-list__value govuk-!-font-size-16 ">
// <Link
// target="_blank"
// href={`/auth/signin2?email=${appeal.value}`}
// >
// {appeal.value}
// </Link>
// <br />
// <dl className="govuk-summary-list govuk-!-margin-bottom-9 govuk-!-margin-left-9 results">
// <div className="govuk-summary-list__row results-headings">
// <dd className="govuk-summary-list__key govuk-!-font-size-16">
// Name
// </dd>
// <dd className="govuk-summary-list__key govuk-!-font-size-16">
// Last accessed
// </dd>
// </div>
// {appeal.statuses.map((statuses) => (
// <div
// key={appeal.id}
// className="govuk-summary-list__row"
// >
// <dd className="govuk-summary-list__value govuk-!-font-size-16 ">
// {statuses.value}
// </dd>
// <dd className="govuk-summary-list__value govuk-!-font-size-16 ">
// Total: {statuses.caseCount}
// </dd>
// </div>
// ))}
// </dl>
// </dd>
// <dd className="govuk-summary-list__value govuk-!-font-size-16 ">
// Total: {appeal.caseCount}
// </dd>
// </div>
// ))}
// </dl>
// </div>
// );
// }
import { useState } from "react";
import Link from "next/link";
export default function AppealsWithStatusTab({ statusObj = [] }) {
const [openSections, setOpenSections] = useState({});
const toggleSection = (index) => {
setOpenSections((current) => ({
...current,
[index]: !current[index]
}));
};
const showAll = () => {
const allOpen = {};
statusObj.forEach((_, index) => {
allOpen[index] = true;
});
setOpenSections(allOpen);
};
const hideAll = () => {
setOpenSections({});
};
const allExpanded =
statusObj.length > 0 &&
statusObj.every((_, index) => openSections[index]);
const sortedAppeals = [...statusObj].sort(
(a, b) => (b.caseCount || 0) - (a.caseCount || 0)
);
const maxCount = sortedAppeals[0]?.caseCount || 1;
return (
<div>
<h1 className="govuk-heading-l">Case status by appeal type</h1>
<div className="govuk-!-margin-bottom-6">
<h2 className="govuk-heading-m">Case counts by appeal type</h2>
<dl className="appeal-count-chart">
{sortedAppeals.map((appeal) => {
const maxCount = sortedAppeals[0]?.caseCount || 1;
const width =
((appeal.caseCount || 0) / maxCount) * 100;
return (
<div
className="appeal-count-chart__row"
key={appeal.appealType}
>
<dt className="appeal-count-chart__label">
{appeal.value}
</dt>
<dd className="appeal-count-chart__bar-wrapper">
<span
className="appeal-count-chart__bar"
style={{ width: `${width}%` }}
/>
<span className="appeal-count-chart__count">
{appeal.caseCount || 0}
</span>
</dd>
</div>
);
})}
</dl>
</div>
<div className="govuk-!-margin-bottom-6">
<h2 className="govuk-heading-m">Case stages by appeal type</h2>
<dl className="appeal-stage-chart">
{sortedAppeals.map((appeal) => (
<div
className="appeal-stage-chart__row"
key={appeal.appealType}
>
<dt className="appeal-stage-chart__label">
{appeal.value}
</dt>
<dd className="appeal-stage-chart__bar-wrapper">
<div
className="appeal-stage-chart__bar"
style={{
width: `${((appeal.caseCount || 0) / maxCount) * 100}%`
}}
aria-label={`${appeal.value}, ${appeal.caseCount || 0} cases`}
>
{(appeal.statuses || [])
.filter(
(status) => status.caseCount > 0
)
.sort(
(a, b) => b.caseCount - a.caseCount
)
.map((status, index) => (
<span
key={status.statuscode}
className={`appeal-stage-chart__segment appeal-stage-chart__segment--${index % 6}`}
style={{
width: `${((status.caseCount || 0) / (appeal.caseCount || 1)) * 100}%`
}}
title={`${status.value}: ${status.caseCount}`}
/>
))}
</div>
<span className="appeal-stage-chart__count">
{appeal.caseCount || 0}
</span>
</dd>
</div>
))}
</dl>
</div>
<div className="govuk-accordion__controls">
<button
type="button"
className="govuk-accordion__show-all"
onClick={allExpanded ? hideAll : showAll}
>
<span className="govuk-accordion__show-all-text">
{allExpanded
? "Hide all sections"
: "Show all sections"}
</span>
</button>
</div>
<div className="govuk-accordion" id="appeals-with-status-accordion">
{[...statusObj]
.sort((a, b) => (b.caseCount || 0) - (a.caseCount || 0))
.map((appeal, index) => {
const isOpen = !!openSections[index];
return (
<div
className={
isOpen
? "govuk-accordion__section govuk-accordion__section--expanded"
: "govuk-accordion__section"
}
key={appeal.appealType || index}
>
<div className="govuk-accordion__section-header ">
<h2 className="govuk-accordion__section-heading">
<button
type="button"
className="govuk-accordion__section-button "
id={`appeal-status-heading-${index}`}
aria-expanded={isOpen}
aria-controls={`appeal-status-content-${index}`}
onClick={() => toggleSection(index)}
>
<span
style={{
display: "flex",
justifyContent:
"space-between",
alignItems: "center",
width: "100%",
paddingRight: "20px" // leaves room for accordion icon
}}
>
<span className="govuk-heading-s ">
{appeal.value}
</span>
<span
className="govuk-body-s"
style={{
fontWeight: "normal"
}}
>
{appeal.caseCount || 0}{" "}
cases
</span>
</span>
</button>
</h2>
</div>
<div
id={`appeal-status-content-${index}`}
className="govuk-accordion__section-content"
aria-labelledby={`appeal-status-heading-${index}`}
hidden={!isOpen}
>
<dl className="govuk-summary-list govuk-!-margin-left-9">
{(appeal.statuses || [])
.sort(
(a, b) =>
(b.caseCount || 0) -
(a.caseCount || 0)
)
.map((status) => (
<div
className="govuk-summary-list__row"
key={status.statuscode}
>
<dt className="govuk-summary-list__key">
<Link
target="_blank"
href={`/advancedsearchresults?apt=${appeal.appealType}&statuscode=${status.statuscode}`}
>
{status.value}
</Link>
</dt>
<dd className="govuk-summary-list__value">
{status.caseCount || 0}
</dd>
</div>
))}
</dl>
</div>
</div>
);
})}
</div>
</div>
);
}
+142 -86
View File
@@ -5,7 +5,7 @@ import { useRouter } from "next/router";
import { useCallback, useEffect, useRef, useState } from "react"; import { useCallback, useEffect, useRef, useState } from "react";
import { connect } from "react-redux"; import { connect } from "react-redux";
import transLookup from "../../../data/lookuptranslations.json"; import transLookup from "../../../data/lookuptranslations.json";
import { formatDates, getDocLink, hasOwn } from "../../utils"; import { formatDates } from "../../utils";
import PaginationControl from "../../../components/case/pagination"; import PaginationControl from "../../../components/case/pagination";
import DocumentLink from "../../utils/downloads"; import DocumentLink from "../../utils/downloads";
import { useDownloadQueue } from "../../utils/downloadmanager"; import { useDownloadQueue } from "../../utils/downloadmanager";
@@ -15,179 +15,177 @@ import { sendGAEvent } from "@next/third-parties/google";
import { import {
getSearchDocumentDetails, getSearchDocumentDetails,
getSearchDocumentDetailsPaged, getSearchDocumentDetailsPaged,
getSearchDocumentTypes getSearchDocumentTypes,
} from "../../../actions/services/searchService"; getNewDocumentsPaged,
import { getNewDocumentsPaged } from "../../../actions/services/adminService"; } from "../../../actions";
import { setCurrentPage } from "../../../store/currentView/action"; import { setCurrentPage } from "../../../store/currentView/action";
import { setDocumentDetails } from "../../../store/searchOutput/action"; import { setDocumentDetails } from "../../../store/searchOutput/action";
import resolveCrmDisplayValue from "../../../lib/i18n/crmDisplay/resolveCrmDisplayValue";
const getDocumentTypes = [ const getDocumentTypes = [
{ {
"Value": 846040009, "Value": 846040009,
"Label": "Main Party - Pre-Submission Docs" "Label": "Main Party - Pre-Submission Docs",
}, },
{ {
"Value": 846040000, "Value": 846040000,
"Label": "Main Party - Submission Document" "Label": "Main Party - Submission Document",
}, },
{ {
"Value": 846040001, "Value": 846040001,
"Label": "Main Party - Questionnaire" "Label": "Main Party - Questionnaire",
}, },
{ {
"Value": 846040002, "Value": 846040002,
"Label": "Main Party - Statements" "Label": "Main Party - Statements",
}, },
{ {
"Value": 846040003, "Value": 846040003,
"Label": "Main Party - Comments" "Label": "Main Party - Comments",
}, },
{ {
"Value": 846040004, "Value": 846040004,
"Label": "Main Party - Written Statements of Evidence" "Label": "Main Party - Written Statements of Evidence",
}, },
{ {
"Value": 846040010, "Value": 846040010,
"Label": "Main Party - Environmental Statements" "Label": "Main Party - Environmental Statements",
}, },
{ {
"Value": 846040005, "Value": 846040005,
"Label": "Interested Party Representations" "Label": "Interested Party Representations",
}, },
{ {
"Value": 846040006, "Value": 846040006,
"Label": "Correspondence" "Label": "Correspondence",
}, },
{ {
"Value": 846040008, "Value": 846040008,
"Label": "Inspector Notes" "Label": "Inspector Notes",
}, },
{ {
"Value": 846040007, "Value": 846040007,
"Label": "Final Decision/Report" "Label": "Final Decision/Report",
}, },
{ {
"Value": 846040011, "Value": 846040011,
"Label": "Post Decision Correspondence" "Label": "Post Decision Correspondence",
}, },
{ {
"Value": 846040012, "Value": 846040012,
"Label": "High Court Challenge Correspondence" "Label": "High Court Challenge Correspondence",
}, },
{ {
"Value": 846040013, "Value": 846040013,
"Label": "Event - Correspondence" "Label": "Event - Correspondence",
}, },
{ {
"Value": 846040014, "Value": 846040014,
"Label": "Event - Documents" "Label": "Event - Documents",
}, },
{ {
"Value": 846040015, "Value": 846040015,
"Label": "Pre-Application - General" "Label": "Pre-Application - General",
}, },
{ {
"Value": 846040016, "Value": 846040016,
"Label": "Pre-Application - EIA Screening" "Label": "Pre-Application - EIA Screening",
}, },
{ {
"Value": 846040017, "Value": 846040017,
"Label": "Pre-Application - EIA Scoping" "Label": "Pre-Application - EIA Scoping",
}, },
{ {
"Value": 846040018, "Value": 846040018,
"Label": "EIA Screening" "Label": "EIA Screening",
}, },
{ {
"Value": 846040019, "Value": 846040019,
"Label": "EIA Scoping" "Label": "EIA Scoping",
}, },
{ {
"Value": 846040020, "Value": 846040020,
"Label": "Pre-Application Services Documents" "Label": "Pre-Application Services Documents",
}, },
{ {
"Value": 846040021, "Value": 846040021,
"Label": "Notification" "Label": "Notification",
}, },
{ {
"Value": 846040022, "Value": 846040022,
"Label": "Label":
"Submission - Environmental Statement - written statement and NTS" "Submission - Environmental Statement - written statement and NTS",
}, },
{ {
"Value": 846040023, "Value": 846040023,
"Label": "Submission - Environmental Statement - Appendices" "Label": "Submission - Environmental Statement - Appendices",
}, },
{ {
"Value": 846040024, "Value": 846040024,
"Label": "Submission - Environmental Statement - Figures" "Label": "Submission - Environmental Statement - Figures",
}, },
{ {
"Value": 846040025, "Value": 846040025,
"Label": "Submission - Draft Infrastructure Consent Orders" "Label": "Submission - Draft Infrastructure Consent Orders",
}, },
{ {
"Value": 846040026, "Value": 846040026,
"Label": "Submission - Compulsory Acquisition Information" "Label": "Submission - Compulsory Acquisition Information",
}, },
{ {
"Value": 846040027, "Value": 846040027,
"Label": "Submission - Application Documents" "Label": "Submission - Application Documents",
}, },
{ {
"Value": 846040028, "Value": 846040028,
"Label": "Examination Notices" "Label": "Examination Notices",
}, },
{ {
"Value": 846040029, "Value": 846040029,
"Label": "Local/Marine Impact Reports" "Label": "Local/Marine Impact Reports",
}, },
{ {
"Value": 846040030, "Value": 846040030,
"Label": "Submission - Further Information" "Label": "Submission - Further Information",
}, },
{ {
"Value": 846040031, "Value": 846040031,
"Label": "Formal Variation requests" "Label": "Formal Variation requests",
}, },
{ {
"Value": 846040032, "Value": 846040032,
"Label": "Further Information - Interested Party Representations" "Label": "Further Information - Interested Party Representations",
}, },
{ {
"Value": 846040033, "Value": 846040033,
"Label": "Hearing Statements" "Label": "Hearing Statements",
}, },
{ {
"Value": 846040034, "Value": 846040034,
"Label": "Events - Recordings" "Label": "Events - Recordings",
}, },
{ {
"Value": 846040035, "Value": 846040035,
"Label": "Internal Correspondence" "Label": "Internal Correspondence",
}, },
{ {
"Value": 846040036, "Value": 846040036,
"Label": "Consultation Response" "Label": "Consultation Response",
} },
]; ];
const getOrigin = [ const getOrigin = [
{ {
"Value": 846040000, "Value": 846040000,
"Label": "MDU" "Label": "MDU",
}, },
{ {
"Value": 846040001, "Value": 846040001,
"Label": "Portal" "Label": "Portal",
}, },
{ {
"Value": 846040002, "Value": 846040002,
"Label": "Manual" "Label": "Manual",
} },
]; ];
const DocumentsTab = (props) => { const DocumentsTab = (props) => {
@@ -202,7 +200,7 @@ const DocumentsTab = (props) => {
setDocumentDetails, setDocumentDetails,
setCurrentPage, setCurrentPage,
docsOffline, docsOffline,
showFilteredDocs showFilteredDocs,
} = props; } = props;
const router = useRouter(); const router = useRouter();
@@ -238,7 +236,7 @@ const DocumentsTab = (props) => {
setCheckedItems((prev) => ({ setCheckedItems((prev) => ({
...prev, ...prev,
[name]: checked [name]: checked,
})); }));
setSelectAll(false); setSelectAll(false);
}; };
@@ -248,7 +246,7 @@ const DocumentsTab = (props) => {
setCheckedOriginItems((prev) => ({ setCheckedOriginItems((prev) => ({
...prev, ...prev,
[name]: checked [name]: checked,
})); }));
setSelectOriginAll(false); setSelectOriginAll(false);
}; };
@@ -307,7 +305,37 @@ const DocumentsTab = (props) => {
setSelectedDocumentOrigin("all") setSelectedDocumentOrigin("all")
); );
}; };
let ShowDocLinks = getDocLink(docsOffline); let ShowDocLinks = false;
let checkShowDocLinks = docsOffline != false ? true : false;
const getDocLink = (docsOffline) => {
var startTime = docsOffline.split(",")[0];
var endTime = docsOffline.split(",")[1];
// console.log(startTime);
// console.log(endTime);
var currentDate = new Date();
var startDate = new Date(currentDate.getTime());
startDate.setHours(startTime.split(":")[0]);
startDate.setMinutes(startTime.split(":")[1]);
startDate.setSeconds(startTime.split(":")[2]);
var endDate = new Date(currentDate.getTime());
endDate.setHours(endTime.split(":")[0]);
endDate.setMinutes(endTime.split(":")[1]);
endDate.setSeconds(endTime.split(":")[2]);
// console.log(startDate);
// console.log(endDate);
// console.log(currentDate);
var valid = startDate < currentDate && endDate > currentDate;
ShowDocLinks = valid;
};
checkShowDocLinks && getDocLink(docsOffline);
const FilteredDocumentView = (documentDetailsArr) => { const FilteredDocumentView = (documentDetailsArr) => {
documentDetailsArr = documentDetailsArr.value; documentDetailsArr = documentDetailsArr.value;
@@ -399,11 +427,19 @@ const DocumentsTab = (props) => {
className="govuk-label-s govuk-checkboxes__label" className="govuk-label-s govuk-checkboxes__label"
htmlFor={item.Value} htmlFor={item.Value}
> >
{resolveCrmDisplayValue({ {router.locale == "cy"
value: item.Label, ? jsonpath({
locale, path:
translations: transLookup '$..[?(@ && @.value=="' +
})} item.Label +
'")].value_cy',
json: transLookup,
eval: true,
})
: item.Label ||
t(
"case:summary-no-date-entered-label"
)}{" "}
</label> </label>
</div> </div>
); );
@@ -464,11 +500,19 @@ const DocumentsTab = (props) => {
className="govuk-label-s govuk-checkboxes__label" className="govuk-label-s govuk-checkboxes__label"
htmlFor={"origin_" + item.Value} htmlFor={"origin_" + item.Value}
> >
{resolveCrmDisplayValue({ {router.locale == "cy"
value: item.Label, ? jsonpath({
locale, path:
translations: transLookup '$..[?(@ && @.value=="' +
})} item.Label +
'")].value_cy',
json: transLookup,
eval: true,
})
: item.Label ||
t(
"case:summary-no-date-entered-label"
)}{" "}
</label> </label>
</div> </div>
); );
@@ -482,7 +526,7 @@ const DocumentsTab = (props) => {
const checkedValues = [ const checkedValues = [
...document.querySelectorAll( ...document.querySelectorAll(
".govuk-checkboxes__input:checked" ".govuk-checkboxes__input:checked"
) ),
].map((e) => e.value); ].map((e) => e.value);
const origins = checkedValues const origins = checkedValues
@@ -683,7 +727,7 @@ const DocumentsTab = (props) => {
incidentid + incidentid +
"')]", "')]",
json: item, json: item,
eval: true eval: true,
}); });
detailsObj = item; detailsObj = item;
return ( return (
@@ -740,7 +784,7 @@ const DocumentsTab = (props) => {
// )} // )}
// : // :
// </span> // </span>
// {hasOwn( // {_.has(
// detailsObj, // detailsObj,
// "pinswg_name" // "pinswg_name"
// ) // )
@@ -775,7 +819,7 @@ const DocumentsTab = (props) => {
)} )}
: :
</span> </span>
{hasOwn( {_.has(
detailsObj, detailsObj,
"pinswg_name" "pinswg_name"
) )
@@ -791,7 +835,7 @@ const DocumentsTab = (props) => {
)} )}
: :
</span> </span>
{hasOwn( {_.has(
detailsObj, detailsObj,
"pinswg_name" "pinswg_name"
) )
@@ -808,15 +852,22 @@ const DocumentsTab = (props) => {
: :
</span> </span>
{resolveCrmDisplayValue( {router.locale == "cy"
{ ? jsonpath({
value: detailsObj[ path:
'$..[?(@ && @.value=="' +
detailsObj[
"pinswg_isharedocumentlocations@OData.Community.Display.V1.FormattedValue" "pinswg_isharedocumentlocations@OData.Community.Display.V1.FormattedValue"
], ] +
locale, '")].value_cy',
translations: json: transLookup,
transLookup eval: true,
} })
: detailsObj[
"pinswg_isharedocumentlocations@OData.Community.Display.V1.FormattedValue"
] ||
t(
"case:summary-no-date-entered-label"
)} )}
</dd> </dd>
<dd className="govuk-summary-list__value govuk-!-font-size-14"> <dd className="govuk-summary-list__value govuk-!-font-size-14">
@@ -827,7 +878,7 @@ const DocumentsTab = (props) => {
: :
</span> </span>
{hasOwn( {_.has(
detailsObj, detailsObj,
"createdon" "createdon"
) )
@@ -915,16 +966,17 @@ const DocumentsTab = (props) => {
) )
.then((data) => data) .then((data) => data)
.then((data) => { .then((data) => {
setDocumentDetails(data); props.setDocumentDetails(data);
setShowSpinnerState(false); setShowSpinnerState(false);
}); });
}, },
[ [
props.incidentid,
selectedOption, selectedOption,
selectedDocumentType, selectedDocumentType,
selectedWeeks, selectedWeeks,
selectedDocumentOrigin, selectedDocumentOrigin,
setDocumentDetails props.setDocumentDetails,
] ]
); );
@@ -935,7 +987,7 @@ const DocumentsTab = (props) => {
orderBy, orderBy,
fieldSort fieldSort
).then((data) => { ).then((data) => {
setDocumentDetails(data); props.setDocumentDetails(data);
return data; return data;
}); });
@@ -1038,7 +1090,7 @@ const DocumentsTab = (props) => {
selectedDocumentType, selectedDocumentType,
selectedWeeks selectedWeeks
).then((data) => { ).then((data) => {
setDocumentDetails(data); props.setDocumentDetails(data);
setDocumentSearchState(true); setDocumentSearchState(true);
return data; return data;
@@ -1050,14 +1102,16 @@ const DocumentsTab = (props) => {
//const searchDocumentResultsObj = docDetailsObj(); //const searchDocumentResultsObj = docDetailsObj();
}, [ }, [
incidentid, incidentid,
setDocumentDetails, props.setDocumentDetails,
selectedOption, selectedOption,
selectedDocumentType, selectedDocumentType,
fieldSortState, fieldSortState,
orderByState, orderByState,
getDocumentTypes,
getOrigin,
getDocumentResults, getDocumentResults,
lang, lang,
selectedWeeks selectedWeeks,
]); ]);
function countFieldValue(obj, field, targetValue) { function countFieldValue(obj, field, targetValue) {
@@ -1083,7 +1137,9 @@ const DocumentsTab = (props) => {
return ( return (
<div className="govuk-grid-row"> <div className="govuk-grid-row">
<div className="govuk-grid-column-full"> <div className="govuk-grid-column-full">
<h1 className="">{t("case:documents-heading-label")}</h1> <h2 className="govuk-heading-m ">
{t("case:documents-heading-label")}
</h2>
{/* <div className=""> {/* <div className="">
MDU :{" "} MDU :{" "}
{countFieldValue( {countFieldValue(
@@ -1108,7 +1164,7 @@ const DocumentsTab = (props) => {
<select <select
onChange={(e) => { onChange={(e) => {
setSelectedWeeks(e.target.value); setSelectedWeeks(e.target.value);
setCurrentPage(1); props.setCurrentPage(1);
}} }}
value={selectedWeeks} value={selectedWeeks}
className="govuk-select" className="govuk-select"
@@ -1140,7 +1196,7 @@ const DocumentsTab = (props) => {
const mapStateToProps = (state) => { const mapStateToProps = (state) => {
return { return {
...state ...state,
}; };
}; };
@@ -1151,7 +1207,7 @@ const mapDispatchToProps = (dispatch) => {
}, },
setCurrentPage: (currentPage) => { setCurrentPage: (currentPage) => {
dispatch(setCurrentPage(currentPage)); dispatch(setCurrentPage(currentPage));
} },
}; };
}; };
+7 -37
View File
@@ -5,11 +5,8 @@ import { bytesToSize } from "../../../components/utils";
import { import {
deleteMyRepresentationsFromBlob, deleteMyRepresentationsFromBlob,
deleteAwaitingSubmissionsFromBlob, deleteAwaitingSubmissionsFromBlob,
getRepsFromBlobProxy sendRepCompleteMessage,
} from "../../../actions/services/documentService"; } from "../../../actions";
import { sendRepCompleteMessage } from "../../../actions/services/portalService";
import { parseCookies } from "nookies";
import { consoleLogger } from "../../../actions/core/logger";
import { formatBlobDates } from "../utils/adminHelper"; import { formatBlobDates } from "../utils/adminHelper";
@@ -24,33 +21,6 @@ export default function StorageTab({ data, repCompleteCount }) {
setShowTmpFile(newState); setShowTmpFile(newState);
}; };
const deleteRepItem = (containerID, caseID, repfile) => {
let cookies = parseCookies();
//console.log("sssss", containerID, caseID, repfile);
deleteMyRepresentationsFromBlob(containerID, caseID, repfile)
.then((data) => {
return data;
})
.then(() => {
getRepsFromBlobProxy(containerID)
.then((data) => {
setMyRepresentations(data);
setMyRepresentationsDetails(data);
})
.catch((error) => {
consoleLogger(error);
return null;
})
.then(() => {
setCurrentView({
"viewName": "My Representations",
"viewKey": "myRepresentations"
});
});
});
};
return ( return (
<div> <div>
<h1>Storage Account Contents</h1> <h1>Storage Account Contents</h1>
@@ -180,7 +150,7 @@ export default function StorageTab({ data, repCompleteCount }) {
headers: headers:
{ {
"Content-Type": "Content-Type":
"application/json" "application/json",
}, },
body: JSON.stringify( body: JSON.stringify(
{ {
@@ -189,18 +159,18 @@ export default function StorageTab({ data, repCompleteCount }) {
blobName: blobName:
folder folder
.repJsonBlob .repJsonBlob
.name .name,
} }
) ),
} }
); );
const result = const result =
await response.json(); await response.json();
if (response.ok) { if (response.ok) {
(alert( alert(
"repComplete removed!" "repComplete removed!"
), ),
window.location.reload()); window.location.reload();
// Optionally refresh the page or update UI state here // Optionally refresh the page or update UI state here
} else { } else {
alert( alert(
+9 -17
View File
@@ -5,9 +5,9 @@ import { PrismaClient } from "@prisma/client";
import CryptoJS from "crypto-js"; import CryptoJS from "crypto-js";
import { getUpToLastSlash, streamToString } from "../utils/adminHelper"; import { getUpToLastSlash, streamToString } from "../utils/adminHelper";
import { listContainersForUser } from "../../../actions/azurestorage"; import { listContainersForUser } from "../../../actions/azurestorage";
import pLimit from "p-limit";
const prisma = global.prisma || new PrismaClient(); const prisma = global.prisma || new PrismaClient();
const WORDKEY = process.env.HASHKEY;
/** /**
* Generate HMAC hash for blob API link. * Generate HMAC hash for blob API link.
*/ */
@@ -34,10 +34,8 @@ export async function fetchAdminStorageData() {
const users = await prisma.user.findMany(); const users = await prisma.user.findMany();
const limit = pLimit(5);
let data = await Promise.all( let data = await Promise.all(
users.map(async (user) => { users.map(async (user) => {
return limit(async () => {
const containers = await listContainersForUser( const containers = await listContainersForUser(
blobServiceClient, blobServiceClient,
`${user.id}`, `${user.id}`,
@@ -56,9 +54,7 @@ export async function fetchAdminStorageData() {
`/api/file/downloadblob?container=${ `/api/file/downloadblob?container=${
container.container container.container
}&casefolderID=${folderPath}&blobname=${blob.name }&casefolderID=${folderPath}&blobname=${blob.name
.substring( .substring(blob.name.lastIndexOf("/") + 1)
blob.name.lastIndexOf("/") + 1
)
.trim()}`, .trim()}`,
process.env.HASHKEY process.env.HASHKEY
); );
@@ -66,13 +62,12 @@ export async function fetchAdminStorageData() {
const fileNameOnly = blob.name.substring( const fileNameOnly = blob.name.substring(
blob.name.lastIndexOf("/") + 1 blob.name.lastIndexOf("/") + 1
); );
const isTmpFile = const isTmpFile = fileNameOnly.startsWith("TMP-");
fileNameOnly.startsWith("TMP-");
const blobWithHash = { const blobWithHash = {
...blob, ...blob,
hashedfilepath, hashedfilepath,
isTmpFile isTmpFile,
}; };
let folderGroup = acc.find( let folderGroup = acc.find(
@@ -85,7 +80,7 @@ export async function fetchAdminStorageData() {
hasRepJson: false, hasRepJson: false,
repJsonBlob: null, repJsonBlob: null,
repComplete: false, repComplete: false,
hasTmpFile: false hasTmpFile: false,
}; };
acc.push(folderGroup); acc.push(folderGroup);
} }
@@ -97,9 +92,7 @@ export async function fetchAdminStorageData() {
} }
// rep.json handling // rep.json handling
if ( if (blob.name.toLowerCase().endsWith("rep.json")) {
blob.name.toLowerCase().endsWith("rep.json")
) {
folderGroup.hasRepJson = true; folderGroup.hasRepJson = true;
folderGroup.repJsonBlob = blobWithHash; folderGroup.repJsonBlob = blobWithHash;
@@ -144,10 +137,9 @@ export async function fetchAdminStorageData() {
? { ? {
id: user.id, id: user.id,
email: user.email, email: user.email,
containers: containersWithHashes containers: containersWithHashes,
} }
: null; : null;
});
}) })
); );
@@ -158,7 +150,7 @@ export async function fetchAdminStorageData() {
.map((user) => ({ .map((user) => ({
id: user.id, id: user.id,
email: user.email, email: user.email,
created: user.emailVerified?.toLocaleString("en-GB") || "" created: user.emailVerified?.toLocaleString("en-GB") || "",
})); }));
let repCompleteCount = 0; let repCompleteCount = 0;
+1133 -274
View File
File diff suppressed because it is too large Load Diff
+8 -3
View File
@@ -42,10 +42,15 @@ const Case = (props) => {
documentDetailsObj={props.documentDetailsObj} documentDetailsObj={props.documentDetailsObj}
showFilteredDocs={props.showFilteredDocs} showFilteredDocs={props.showFilteredDocs}
showLoginCheck={props.showLoginCheck} showLoginCheck={props.showLoginCheck}
eventsObj={props.eventsObj}
mediaObj={props.mediaObj}
mapTarget={props.mapTarget}
/> />
{showRepresentations == true && (
<RepresentationList
incidentid={props.incidentid}
caseReference={props.caseReference}
representationsObj={props.representationsObj}
documentDetailsObj={props.documentDetailsObj}
/>
)}
</div> </div>
</div> </div>
</main> </main>
+7 -29
View File
@@ -15,22 +15,12 @@ export default function CaseNoticeBanner(props) {
const bannerOpenCookie = typeof cookie.get("pedwNotice") == "undefined"; const bannerOpenCookie = typeof cookie.get("pedwNotice") == "undefined";
let messagesObjArr = messagesObj.value; let messagesObjArr = messagesObj.value;
let todaysDate = new Date();
return ( return (
<> <>
{messagesObjArr.map((message, index) => ( {messagesObjArr.map((message, index) => (
<div key={index}> <div className="govuk-warning-text noticebanner" key={index}>
{todaysDate.toISOString() >= message.scheduledstart &&
todaysDate.toISOString() <= message.scheduledend && (
<div
className="govuk-warning-text noticebanner"
key={index}
>
<strong className="govuk-warning-text__text"> <strong className="govuk-warning-text__text">
<span className="govuk-visually-hidden"> <span className="govuk-visually-hidden">Warning</span>
{t("case:notice-label")}
</span>
</strong> </strong>
<div> <div>
<div className=" govuk-body-s"> <div className=" govuk-body-s">
@@ -59,9 +49,7 @@ export default function CaseNoticeBanner(props) {
: message.subject : message.subject
.split("Banner ")[1] .split("Banner ")[1]
.split(";")[0] .split(";")[0]
: message.subject.split( : message.subject.split("Banner ")[1]}
"Banner "
)[1]}
</h2> </h2>
</div> </div>
<div className="govuk-body-s"> <div className="govuk-body-s">
@@ -71,24 +59,16 @@ export default function CaseNoticeBanner(props) {
) || [] ) || []
).length > 0 ).length > 0
? router.locale == "cy" ? router.locale == "cy"
? message.description.split( ? message.description.split(">>>")[1]
">>>" : message.description.split(">>>")[0]
)[1]
: message.description.split(
">>>"
)[0]
: ( : (
message.description.match( message.description.match(
new RegExp(";", "g") new RegExp(";", "g")
) || [] ) || []
).length > 0 ).length > 0
? router.locale == "cy" ? router.locale == "cy"
? message.description.split( ? message.description.split(";")[1]
";" : message.description.split(";")[0]
)[1]
: message.description.split(
";"
)[0]
: message.description} : message.description}
</div> </div>
<div className="govuk-body-xs govuk-!-margin-bottom-0 "> <div className="govuk-body-xs govuk-!-margin-bottom-0 ">
@@ -97,8 +77,6 @@ export default function CaseNoticeBanner(props) {
</div> </div>
</div> </div>
</div> </div>
)}
</div>
))} ))}
</> </>
); );
+424 -35
View File
@@ -5,21 +5,20 @@ import { useRouter } from "next/router";
import { useCallback, useEffect, useRef, useState } from "react"; import { useCallback, useEffect, useRef, useState } from "react";
import { connect } from "react-redux"; import { connect } from "react-redux";
import transLookup from "../../data/lookuptranslations.json"; import transLookup from "../../data/lookuptranslations.json";
import { formatDates, getDocLink, hasOwn } from "../utils"; import { formatDates } from "../utils";
import PaginationControl from "./pagination"; import PaginationControl from "./pagination";
import { sendGAEvent } from "@next/third-parties/google"; import { sendGAEvent } from "@next/third-parties/google";
import { import {
getSearchDocumentDetails, getSearchDocumentDetails,
getSearchDocumentDetailsPaged, getSearchDocumentDetailsPaged,
getSearchDocumentTypes getSearchDocumentTypes,
} from "../../actions/services/searchService"; } from "../../actions";
import { setCurrentPage } from "../../store/currentView/action"; import { setCurrentPage } from "../../store/currentView/action";
import { setDocumentDetails } from "../../store/searchOutput/action"; import { setDocumentDetails } from "../../store/searchOutput/action";
import DocumentLink from "../utils/downloads"; import DocumentLink from "../utils/downloads";
import { useDownloadQueue } from "../utils/downloadmanager"; import { useDownloadQueue } from "../utils/downloadmanager";
import resolveCrmDisplayValue from "../../lib/i18n/crmDisplay/resolveCrmDisplayValue";
const DocumentDetails = (props) => { const DocumentDetails = (props) => {
let { t, lang } = useTranslation(); let { t, lang } = useTranslation();
@@ -33,14 +32,12 @@ const DocumentDetails = (props) => {
setDocumentDetails, setDocumentDetails,
setCurrentPage, setCurrentPage,
docsOffline, docsOffline,
showFilteredDocs showFilteredDocs,
} = props; } = props;
const router = useRouter(); const router = useRouter();
const { locale } = router; const { locale } = router;
const appealType = props.currentView?.caseReference?.appealType;
var documentDetailsArr = documentDetailsObj || []; var documentDetailsArr = documentDetailsObj || [];
const { startDownload, getStatus } = useDownloadQueue(3); const { startDownload, getStatus } = useDownloadQueue(3);
const [selectedOption, setSelectedOption] = useState(10); const [selectedOption, setSelectedOption] = useState(10);
@@ -60,7 +57,7 @@ const DocumentDetails = (props) => {
setCheckedItems((prev) => ({ setCheckedItems((prev) => ({
...prev, ...prev,
[name]: checked [name]: checked,
})); }));
setSelectAll(false); setSelectAll(false);
}; };
@@ -93,7 +90,383 @@ const DocumentDetails = (props) => {
setCurrentPage(1) setCurrentPage(1)
); );
}; };
let ShowDocLinks = getDocLink(docsOffline); let ShowDocLinks = false;
let checkShowDocLinks = docsOffline != false ? true : false;
const getDocLink = (docsOffline) => {
var startTime = docsOffline.split(",")[0];
var endTime = docsOffline.split(",")[1];
// console.log(startTime);
// console.log(endTime);
var currentDate = new Date();
var startDate = new Date(currentDate.getTime());
startDate.setHours(startTime.split(":")[0]);
startDate.setMinutes(startTime.split(":")[1]);
startDate.setSeconds(startTime.split(":")[2]);
var endDate = new Date(currentDate.getTime());
endDate.setHours(endTime.split(":")[0]);
endDate.setMinutes(endTime.split(":")[1]);
endDate.setSeconds(endTime.split(":")[2]);
// console.log(startDate);
// console.log(endDate);
// console.log(currentDate);
var valid = startDate < currentDate && endDate > currentDate;
ShowDocLinks = valid;
};
checkShowDocLinks && getDocLink(docsOffline);
const DocumentView = (documentDetailsArr) => {
documentDetailsArr = documentDetailsArr.value;
return (
<>
<p>
{documentDetailsObj["@odata.count"] > 1
? t("case:documents-count-label-1")
: t("case:documents-count-label-1a")}{" "}
{documentDetailsObj["@odata.count"]}{" "}
{documentDetailsObj["@odata.count"] > 1
? t("case:documents-count-label-2")
: t("case:documents-count-label-2a")}
</p>
<div className="documentFilters govuk-!-margin-top-5">
<div
id="recordDocumentTypeSelect"
className="govuk-grid-row govuk-!-margin-left-0"
>
<div className="govuk-form-group">
<label
className="govuk-label-s "
htmlFor="showDocumentType"
>
{t("case:documents-show-label")}
<select
onChange={(e) => {
setSelectedDocumentType(e.target.value);
setCurrentPage(1);
}}
value={selectedDocumentType}
className="govuk-select"
id="showDocumentType"
name="showDocumentType"
>
<option value="all" key="00">
{router.locale == "cy"
? jsonpath({
path: '$..[?(@ && @.value=="All")].value_cy',
json: transLookup,
eval: true,
})
: "All"}
</option>
{documentTypes.map((item, key) => {
return (
<option
key={key}
value={
item.pinswg_isharedocumentlocations
}
>
{router.locale == "cy"
? jsonpath({
path:
'$..[?(@ && @.value=="' +
item.pinswg_isharedocumentlocationsLabel +
'")].value_cy',
json: transLookup,
eval: true,
})
: item.pinswg_isharedocumentlocationsLabel ||
t(
"case:summary-no-date-entered-label"
)}
</option>
);
})}
</select>
{t("case:documents-count-label-2")}
</label>
</div>
</div>
{documentDetailsObj["@odata.count"] > 5 && (
<div
id="recordCountSelect"
className="govuk-grid-row govuk-!-margin-left-0"
>
<div className="govuk-form-group">
<label
className="govuk-label-s "
htmlFor="showNumberOfRecords"
>
{t(
"search:searchresults-show-records-label-a"
)}
<select
onChange={(e) => {
setSelectedOption(e.target.value);
setCurrentPage(1);
}}
value={selectedOption}
className="govuk-select"
id="showNumberOfRecords"
name="showNumberOfRecords"
>
<option value="5">5</option>
<option value="10">10</option>
<option value="20">20</option>
<option value="30">30</option>
<option value="50">50</option>
</select>{" "}
{t(
"search:searchresults-show-records-label-b"
)}
</label>
</div>
</div>
)}
</div>
{ShowDocLinks && (
<div className="govuk-warning-text ">
<span
className="govuk-warning-text__icon"
aria-hidden="true"
>
!
</span>
<strong className="govuk-warning-text__text govuk-!-margin-top-2">
<span className="govuk-visually-hidden">
Notice
</span>
{t("case:documents-not-available-label")}
</strong>
</div>
)}
<dl className="documentList govuk-summary-list govuk-!-margin-bottom-9 results">
<div className="govuk-summary-list__row results-headings">
<dd className="govuk-summary-list__key govuk-!-font-size-16 ">
<button
type="button"
onClick={() => sortDataBy("pinswg_name")}
className={
orderByState == "pinswg_name"
? fieldSortState == "asc"
? `govuk-link govuk-link--no-underline govuk-!-font-weight-bold govuk-!-font-size-16 sortAsc`
: `govuk-link govuk-link--no-underline govuk-!-font-weight-bold govuk-!-font-size-16 sortDesc`
: `govuk-link govuk-link--no-underline govuk-!-font-weight-bold govuk-!-font-size-16`
}
>
{t("case:documents-name-label")}
</button>
</dd>
<dd className="govuk-summary-list__key govuk-!-font-size-16">
{/* {t("case:documents-doc-type-label")} */}
<button
type="button"
onClick={() =>
sortDataBy("pinswg_isharedocumentlocations")
}
className={
orderByState ==
"pinswg_isharedocumentlocations"
? fieldSortState == "asc"
? `govuk-link govuk-link--no-underline govuk-!-font-weight-bold govuk-!-font-size-16 sortAsc`
: `govuk-link govuk-link--no-underline govuk-!-font-weight-bold govuk-!-font-size-16 sortDesc`
: `govuk-link govuk-link--no-underline govuk-!-font-weight-bold govuk-!-font-size-16`
}
>
{t("case:documents-doc-type-label")}
</button>
</dd>
<dd className="govuk-summary-list__key govuk-!-font-size-16">
{/* {t("case:documents-date-published-label")} */}
<button
type="button"
onClick={() => sortDataBy("createdon")}
className={
orderByState == "createdon"
? fieldSortState == "asc"
? `govuk-link govuk-link--no-underline govuk-!-font-weight-bold govuk-!-font-size-16 sortAsc`
: `govuk-link govuk-link--no-underline govuk-!-font-weight-bold govuk-!-font-size-16 sortDesc`
: `govuk-link govuk-link--no-underline govuk-!-font-weight-bold govuk-!-font-size-16`
}
>
{t("case:documents-date-published-label")}
</button>
</dd>
{/* <dd className="govuk-summary-list__key govuk-!-font-size-16">
{t("case:documents-size-label")}
</dd> */}
</div>
{showSpinnerState == true ? (
<div className="govuk-summary-list__row">
<div className="govuk-!-margin-top-4 govuk-!-margin-bottom-4 govuk-!-font-weight-bold govuk-!-font-size-20 ">
{t("common:spinner-fetching-data")}
<img
className="data-loading-icon"
src="/assets/images/loading.gif"
alt={
router.locale == "cy"
? "Nôl data"
: "Fetching data"
}
/>
</div>
</div>
) : (
documentDetailsArr.map((item, key) => {
let detailsObj = jsonpath({
path:
"$..[?(@ && @._pinswg_documentids_value=='" +
incidentid +
"')]",
json: item,
sanbox: {},
});
detailsObj = item;
return (
<div
className="govuk-summary-list__row"
key={key}
>
<dd className="govuk-summary-list__value govuk-!-font-size-16 ">
{showDownloadingState === key && (
<div className="coverLoadingLink downloading">
{/* <img
className="data-loading-icon"
src="/assets/images/loading.gif"
alt={
router.locale ==
"cy"
? "Nôl data"
: "Fetching data"
}
/> */}
</div>
)}
{!ShowDocLinks ? (
<Link
scroll={false}
href={
detailsObj.pinswg_hashlink
}
key={key}
onClick={() => {
toggleDownLoadLink(key),
sendGAEvent(
"event",
"DownloadedFile",
{
caseReference:
props.caseReference,
filename:
detailsObj.pinswg_name,
}
);
}}
>
<span className="results-visually-hidden">
{t(
"case:documents-name-label"
)}
:
</span>
{_.has(
detailsObj,
"pinswg_name"
)
? detailsObj.pinswg_name
: ""}
</Link>
) : (
<>
<span className="results-visually-hidden">
{t(
"case:documents-name-label"
)}
:
</span>
{_.has(
detailsObj,
"pinswg_name"
)
? detailsObj.pinswg_name
: ""}
</>
)}
</dd>
<dd className="govuk-summary-list__value govuk-!-font-size-16">
<span className="results-visually-hidden">
{t("case:documents-doc-type-label")}
:
</span>
{router.locale == "cy"
? jsonpath({
path:
'$..[?(@ && @.value=="' +
detailsObj[
"pinswg_isharedocumentlocations@OData.Community.Display.V1.FormattedValue"
] +
'")].value_cy',
json: transLookup,
eval: true,
})
: detailsObj[
"pinswg_isharedocumentlocations@OData.Community.Display.V1.FormattedValue"
] ||
t(
"case:summary-no-date-entered-label"
)}
</dd>
<dd className="govuk-summary-list__value govuk-!-font-size-16">
<span className="results-visually-hidden">
{t(
"case:documents-date-published-label"
)}
:
</span>
{_.has(
detailsObj,
"pinswg_latestpublisheddate"
)
? formatDates(
detailsObj.pinswg_latestpublisheddate
)
: ""}
</dd>
{/* <dd className="govuk-summary-list__value govuk-!-font-size-16">
<span className="results-visually-hidden">
{t("case:documents-size-label")}:
</span>
92
</dd> */}
</div>
);
})
)}
</dl>
<PaginationControl
showNoOfRecords={selectedOption}
currentPage={currentPage}
searchResultsObj={documentDetailsObj}
spinnerState={spinnerState}
orderBy={orderByState}
fieldSort={fieldSortState}
getDocumentResults={getDocumentResults}
/>
</>
);
};
const FilteredDocumentView = (documentDetailsArr) => { const FilteredDocumentView = (documentDetailsArr) => {
documentDetailsArr = documentDetailsArr.value; documentDetailsArr = documentDetailsArr.value;
@@ -204,11 +577,19 @@ const DocumentDetails = (props) => {
item.pinswg_isharedocumentlocations item.pinswg_isharedocumentlocations
} }
> >
{resolveCrmDisplayValue({ {router.locale == "cy"
value: item.pinswg_isharedocumentlocationsLabel, ? jsonpath({
locale, path:
translations: transLookup '$..[?(@ && @.value=="' +
})}{" "} item.pinswg_isharedocumentlocationsLabel +
'")].value_cy',
json: transLookup,
eval: true,
})
: item.pinswg_isharedocumentlocationsLabel ||
t(
"case:summary-no-date-entered-label"
)}{" "}
- ({item.count}) - ({item.count})
</label> </label>
</div> </div>
@@ -223,7 +604,7 @@ const DocumentDetails = (props) => {
const data = [ const data = [
...document.querySelectorAll( ...document.querySelectorAll(
".govuk-checkboxes__input:checked" ".govuk-checkboxes__input:checked"
) ),
].map((e) => e.value); ].map((e) => e.value);
setSelectedDocumentType(data); setSelectedDocumentType(data);
setCurrentPage(1); setCurrentPage(1);
@@ -359,7 +740,7 @@ const DocumentDetails = (props) => {
incidentid + incidentid +
"')]", "')]",
json: item, json: item,
eval: true eval: true,
}); });
detailsObj = item; detailsObj = item;
return ( return (
@@ -434,7 +815,7 @@ const DocumentDetails = (props) => {
)} )}
: :
</span> </span>
{hasOwn( {_.has(
detailsObj, detailsObj,
"pinswg_name" "pinswg_name"
) )
@@ -450,7 +831,7 @@ const DocumentDetails = (props) => {
)} )}
: :
</span> </span>
{hasOwn( {_.has(
detailsObj, detailsObj,
"pinswg_name" "pinswg_name"
) )
@@ -466,13 +847,24 @@ const DocumentDetails = (props) => {
)} )}
: :
</span> </span>
{resolveCrmDisplayValue({
value: detailsObj[ {router.locale == "cy"
? jsonpath({
path:
'$..[?(@ && @.value=="' +
detailsObj[
"pinswg_isharedocumentlocations@OData.Community.Display.V1.FormattedValue" "pinswg_isharedocumentlocations@OData.Community.Display.V1.FormattedValue"
], ] +
locale, '")].value_cy',
translations: transLookup json: transLookup,
})} eval: true,
})
: detailsObj[
"pinswg_isharedocumentlocations@OData.Community.Display.V1.FormattedValue"
] ||
t(
"case:summary-no-date-entered-label"
)}
</dd> </dd>
<dd className="govuk-summary-list__value govuk-!-font-size-16"> <dd className="govuk-summary-list__value govuk-!-font-size-16">
<span className="results-visually-hidden"> <span className="results-visually-hidden">
@@ -482,7 +874,7 @@ const DocumentDetails = (props) => {
: :
</span> </span>
{hasOwn( {_.has(
detailsObj, detailsObj,
"pinswg_latestpublisheddate" "pinswg_latestpublisheddate"
) )
@@ -543,7 +935,7 @@ const DocumentDetails = (props) => {
props.incidentid, props.incidentid,
selectedOption, selectedOption,
selectedDocumentType, selectedDocumentType,
setDocumentDetails setDocumentDetails,
] ]
); );
@@ -667,7 +1059,7 @@ const DocumentDetails = (props) => {
orderByState, orderByState,
getDocumentTypes, getDocumentTypes,
getDocumentResults, getDocumentResults,
lang lang,
]); ]);
return ( return (
<div className="govuk-grid-row"> <div className="govuk-grid-row">
@@ -681,17 +1073,14 @@ const DocumentDetails = (props) => {
<h3> <h3>
{showDocumentSearchState == false {showDocumentSearchState == false
? t("case:documents-checking-label") ? t("case:documents-checking-label")
: appealType === 846040002 ||
appealType === 846040011
? t(
"case:documents-non-available-app-label"
)
: t("case:documents-non-available-label")} : t("case:documents-non-available-label")}
</h3> </h3>
</div> </div>
</div> </div>
) : ( ) : showFilteredDocs == "true" ? (
FilteredDocumentView(documentDetailsArr) FilteredDocumentView(documentDetailsArr)
) : (
DocumentView(documentDetailsArr)
)} )}
</div> </div>
</div> </div>
@@ -700,7 +1089,7 @@ const DocumentDetails = (props) => {
const mapStateToProps = (state) => { const mapStateToProps = (state) => {
return { return {
...state ...state,
}; };
}; };
@@ -711,7 +1100,7 @@ const mapDispatchToProps = (dispatch) => {
}, },
setCurrentPage: (currentPage) => { setCurrentPage: (currentPage) => {
dispatch(setCurrentPage(currentPage)); dispatch(setCurrentPage(currentPage));
} },
}; };
}; };
-221
View File
@@ -1,221 +0,0 @@
import { setEventDetails } from "../../store/searchOutput/action";
import { setCurrentPage } from "../../store/currentView/action";
import { connect } from "react-redux";
import useTranslation from "next-translate/useTranslation";
import { formatDates } from "../utils";
const EIADetails = (props) => {
let { t } = useTranslation();
const EventView = (eventsArr) => {
eventsArr = eventsArr.value;
return eventsArr.map((item, key) => {
<div>{item.pinswg_name}</div>;
});
};
const eventsArr = props.eventsObj?.value || [];
// event publishiing flag set to true displa
function hasOwnPropertyAndNotNull(obj, property) {
return obj.hasOwnProperty(property) && obj[property] !== null;
}
//console.log(eventsArr.length > 0);
return (
eventsArr.length > 0 && (
<div className="govuk-grid-row">
<div className="card">
<div className="card-body">
<h2 className="govuk-heading-m ">
{t("case:event-title")}
</h2>
{eventsArr.map(
(item, key) =>
item.pinswg_eventpublishflag && (
<>
{" "}
<div className="eventContainer">
<div className="eventColumn">
<div>
<b>
{" "}
{t(
"case:event-name-label"
)}
</b>
: {item.pinswg_name}
</div>
{hasOwnPropertyAndNotNull(
item,
"pinswg_eventname"
) && (
<div>
<b>
{t(
"case:event-event-name-label"
)}
</b>
:{" "}
{item.pinswg_eventname}
</div>
)}
</div>
<div className="eventColumn">
{hasOwnPropertyAndNotNull(
item,
"pinswg_eventaddressline1"
) && (
<>
<div>
<b>
{t(
"case:event-address-label"
)}
</b>
:
</div>
<div>
{
item.pinswg_eventaddressline1
}
</div>
</>
)}
{hasOwnPropertyAndNotNull(
item,
"pinswg_eventaddressline2"
) && (
<div>
{
item.pinswg_eventaddressline2
}
</div>
)}
{hasOwnPropertyAndNotNull(
item,
"pinswg_eventaddresstown"
) && (
<div>
{
item.pinswg_eventaddresstown
}
</div>
)}
{hasOwnPropertyAndNotNull(
item,
"pinswg_eventaddresscounty"
) && (
<div>
{
item.pinswg_eventaddresscounty
}
</div>
)}
{hasOwnPropertyAndNotNull(
item,
"pinswg_eventaddresscounty"
) && (
<div>
{
item.pinswg_eventaddresspostcode
}
</div>
)}
</div>
{/* type of event
start date date of event - end date of event
if virtual event no address showNoOfRecords
show event address */}
<div className="eventColumn">
{hasOwnPropertyAndNotNull(
item,
"pinswg_dateeventrequested"
) && (
<div>
<b>
{t(
"case:event-start-date-label"
)}
</b>
:{" "}
{formatDates(
item.pinswg_dateeventrequested
)}
</div>
)}
{hasOwnPropertyAndNotNull(
item,
"pinswg_enddateoftheevent"
) && (
<div>
<b>
{t(
"case:event-end-date-label"
)}
</b>
:{" "}
{item.pinswg_enddateoftheevent !=
null &&
formatDates(
item.pinswg_enddateoftheevent
)}
</div>
)}
</div>
<div className="eventColumn">
{hasOwnPropertyAndNotNull(
item,
[
"pinswg_typeofevent@OData.Community.Display.V1.FormattedValue",
]
) && (
<div>
<b>
{t(
"case:event-type-of-event-label"
)}
</b>
:{" "}
{
item[
"pinswg_typeofevent@OData.Community.Display.V1.FormattedValue"
]
}
</div>
)}
</div>
</div>
</>
)
)}{" "}
</div>
</div>
</div>
)
);
};
const mapStateToProps = (state) => {
return {
...state,
};
};
const mapDispatchToProps = (dispatch) => {
return {
setEventDetails: (eventsObj) => {
dispatch(setEventDetails(eventsObj));
},
setCurrentPage: (currentPage) => {
dispatch(setCurrentPage(currentPage));
},
};
};
export default connect(mapStateToProps, mapDispatchToProps)(EIADetails);
-264
View File
@@ -1,264 +0,0 @@
import { setEventDetails } from "../../store/searchOutput/action";
import { setCurrentPage } from "../../store/currentView/action";
import { connect } from "react-redux";
import useTranslation from "next-translate/useTranslation";
import { formatDates } from "../utils";
import {
getLivePublishedEvent,
isEventLiveNow
} from "./summary/utils/liveEvent";
import { useRouter } from "next/router";
const EventsDetails = (props) => {
let { t } = useTranslation();
const router = useRouter();
const { locale } = router;
const EventView = (eventsArr) => {
eventsArr = eventsArr.value;
return eventsArr.map((item, key) => {
<div>{item.pinswg_name}</div>;
});
};
const eventsArr = props.eventsObj?.value || [];
// event publishiing flag set to true displa
function hasOwnPropertyAndNotNull(obj, property) {
return obj.hasOwnProperty(property) && obj[property] !== null;
}
return (
eventsArr.length > 0 && (
<div className="govuk-grid-row">
<div className="card">
<div className="card-body">
<h2 className="govuk-heading-m ">
{t("case:event-title")}
</h2>
{eventsArr.map(
(item, key) =>
item.pinswg_eventpublishflag && (
<>
{" "}
<div className="eventContainer">
<div className="eventColumn">
<div>
<b>
{" "}
{t(
"case:event-name-label"
)}
</b>
: {item.pinswg_name}
</div>
{hasOwnPropertyAndNotNull(
item,
"pinswg_eventname"
) && (
<div>
<b>
{t(
"case:event-event-name-label"
)}
</b>
:{" "}
{item.pinswg_eventname}
</div>
)}
{hasOwnPropertyAndNotNull(
item,
[
"pinswg_typeofevent@OData.Community.Display.V1.FormattedValue"
]
) && (
<div>
<b>
{t(
"case:event-type-of-event-label"
)}
</b>
:{" "}
{
item[
"pinswg_typeofevent@OData.Community.Display.V1.FormattedValue"
]
}
</div>
)}
{hasOwnPropertyAndNotNull(
item,
"pinswg_dateeventrequested"
) && (
<div>
<b>
{t(
"case:event-start-date-label"
)}
</b>
:{" "}
{formatDates(
item.pinswg_dateeventrequested
)}
</div>
)}
{hasOwnPropertyAndNotNull(
item,
"pinswg_enddateoftheevent"
) && (
<div>
<b>
{t(
"case:event-end-date-label"
)}
</b>
:{" "}
{item.pinswg_enddateoftheevent !=
null &&
formatDates(
item.pinswg_enddateoftheevent
)}
</div>
)}
</div>
<div className="eventColumn">
{hasOwnPropertyAndNotNull(
item,
"pinswg_eventaddressline1"
) && (
<>
<div
style={{
display: "flex"
}}
>
<b>
{t(
"case:event-address-label"
)}
</b>
:
<div
style={{
display:
"flex",
marginLeft:
"10px",
flexDirection:
"column"
}}
>
{hasOwnPropertyAndNotNull(
item,
"pinswg_eventaddressline1"
) && (
<span>
{
item.pinswg_eventaddressline1
}
</span>
)}
{hasOwnPropertyAndNotNull(
item,
"pinswg_eventaddressline2"
) && (
<span>
{
item.pinswg_eventaddressline2
}
</span>
)}
{hasOwnPropertyAndNotNull(
item,
"pinswg_eventaddresstown"
) && (
<span>
{
item.pinswg_eventaddresstown
}
</span>
)}
{hasOwnPropertyAndNotNull(
item,
"pinswg_eventaddresscounty"
) && (
<span>
{
item.pinswg_eventaddresscounty
}
</span>
)}
{hasOwnPropertyAndNotNull(
item,
"pinswg_eventaddresscounty"
) && (
<span>
{
item.pinswg_eventaddresspostcode
}
</span>
)}
</div>
</div>
</>
)}
</div>
{/* type of event
start date date of event - end date of event
if virtual event no address showNoOfRecords
show event address */}
{hasOwnPropertyAndNotNull(
item,
"pinswg_linktotheevent"
) &&
isEventLiveNow(item) && (
<div className="eventColumn">
<a
href={
locale === "en"
? item.pinswg_linktotheevent
: item.pinswg_linktotheeventstreamwelsh
}
className="govuk-link"
target="_blank"
rel="noopener noreferrer"
>
{t(
"case:live-event-link"
)}
</a>
</div>
)}
</div>
</>
)
)}{" "}
</div>
</div>
</div>
)
);
};
const mapStateToProps = (state) => {
return {
...state
};
};
const mapDispatchToProps = (dispatch) => {
return {
setEventDetails: (eventsObj) => {
dispatch(setEventDetails(eventsObj));
},
setCurrentPage: (currentPage) => {
dispatch(setCurrentPage(currentPage));
}
};
};
export default connect(mapStateToProps, mapDispatchToProps)(EventsDetails);
-260
View File
@@ -1,260 +0,0 @@
import { useEffect, useMemo, useState } from "react";
import useTranslation from "next-translate/useTranslation";
import { useRouter } from "next/router";
import { getBilingualText } from "./summary/utils/helpers";
/**
* MediaDetails
* - Renders a YouTube player + a list of videos from mediaObj.value
* - Loads first item by default (no autoplay)
* - Plays only when user selects an item
* - Stops playback when leaving the "case-media" parent tab (pass whichTab)
* - Shows thumbnail with play overlay
* - Optional duration badge (if you supply v.duration)
* - "Watched" badge once a video has been played (session only)
*/
const extractYouTubeId = (input) => {
if (!input) return null;
// Already looks like a YouTube ID?
if (/^[a-zA-Z0-9_-]{11}$/.test(input)) return input;
try {
const url = new URL(input);
// youtu.be/<id>
if (url.hostname.includes("youtu.be")) {
return url.pathname.replace("/", "") || null;
}
// youtube.com/watch?v=<id>
const v = url.searchParams.get("v");
if (v) return v;
// youtube.com/embed/<id>
const embedMatch = url.pathname.match(/\/embed\/([^/]+)/);
if (embedMatch?.[1]) return embedMatch[1];
// youtube.com/shorts/<id>
const shortsMatch = url.pathname.match(/\/shorts\/([^/]+)/);
if (shortsMatch?.[1]) return shortsMatch[1];
return null;
} catch {
return null;
}
};
const MediaDetails = ({ mediaObj, whichTab, title, useNoCookie = true }) => {
const { t } = useTranslation();
const router = useRouter();
const sourceMedia = mediaObj?.value;
const isActive = whichTab ? whichTab === "case-media" : true;
// Build list of playable items (publishable only)
const videoItems = useMemo(() => {
const isWelsh = router.locale === "cy";
return (sourceMedia || [])
.filter((x) => x?.pinswg_publishtoweb)
.map((item) => {
const link = isWelsh
? item.pinswg_videoplatformurlwelsh
: item.pinswg_videoplatformurl;
const videoId = extractYouTubeId(link);
if (!videoId) return null;
return {
key:
item.pinswg_documentid ||
item.pinswg_mediaid ||
`${item.pinswg_eventrecordingid}-${videoId}`,
videoId,
name: item.pinswg_eventrecordingname || "Video",
description: item.pinswg_description || "",
// If you later store duration in CRM, map it here (e.g. "03:42")
duration: item.pinswg_duration || null,
thumbnailHQ: `https://img.youtube.com/vi/${videoId}/hqdefault.jpg`,
thumbnailMax: `https://img.youtube.com/vi/${videoId}/maxresdefault.jpg`,
raw: item
};
})
.filter(Boolean);
}, [sourceMedia, router.locale]);
const [selectedIndex, setSelectedIndex] = useState(0);
// Default false so first item loads but does not play.
const [autoplay, setAutoplay] = useState(false);
// Bump this to force iframe remount (hard stop playback).
const [playerInstance, setPlayerInstance] = useState(0);
// Track which videos have been played (session only).
const [watchedIds, setWatchedIds] = useState(() => new Set());
// When list or locale changes: reset selection and do not autoplay
useEffect(() => {
setSelectedIndex(0);
setAutoplay(false);
setPlayerInstance((n) => n + 1);
}, [videoItems.length, router.locale]);
// When leaving the media tab: hard stop playback
useEffect(() => {
if (!isActive) {
setAutoplay(false);
setPlayerInstance((n) => n + 1);
}
}, [isActive]);
const selected = videoItems[selectedIndex] || null;
const domain = useNoCookie
? "https://www.youtube-nocookie.com"
: "https://www.youtube.com";
const embedSrc = selected
? `${domain}/embed/${selected.videoId}?rel=0&modestbranding=1&playsinline=1&autoplay=${
autoplay ? "1" : "0"
}`
: "";
if (!videoItems.length) return null;
return (
<div className="govuk-grid-row">
<div className="card">
<div className="card-body">
<h2 className="govuk-heading-m">{t("case:media-title")}</h2>
{/* Player: unmount when not active (guarantees playback stops) */}
{isActive && (
<div className="videoWrapper govuk-!-margin-bottom-4">
<iframe
key={`${selected?.videoId}-${playerInstance}`}
src={embedSrc}
title={selected?.name || "YouTube video"}
frameBorder="0"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
allowFullScreen
/>
</div>
)}
{/* Selected info */}
{selected && (
<div className="govuk-!-margin-bottom-4">
<div className="govuk-body">
<b>{t("case:event-recording-name-label")}</b>:{" "}
{getBilingualText(selected.name, router.locale)}
</div>
{!!selected.description && (
<div className="govuk-body">
<b>
{t(
"case:event-recording-description-label"
)}
</b>
:{" "}
{getBilingualText(
selected.description,
router.locale
)}
</div>
)}
</div>
)}
{/* Video list */}
<h3 className="govuk-heading-s">
{t("case:video-heading")}
</h3>
<ul className="govuk-list govuk-list--spaced">
{videoItems.map((v, idx) => {
const isSelected = idx === selectedIndex;
return (
<li key={v.key}>
<button
type="button"
className={`videoTabButton ${
isSelected ? "active" : ""
}`}
aria-current={
isSelected ? "true" : undefined
}
onClick={() => {
setSelectedIndex(idx);
// Start playback only when user selects
setAutoplay(true);
// Force remount to stop previous + start clean
setPlayerInstance((n) => n + 1);
// Mark watched
setWatchedIds((prev) => {
const next = new Set(prev);
next.add(v.videoId);
return next;
});
}}
>
<div className="videoTabContent">
<div className="thumbnailWrapper">
<img
src={v.thumbnailMax}
onError={(e) => {
// fallback for videos without maxres
e.currentTarget.src =
v.thumbnailHQ;
}}
alt=""
className="videoThumbnail"
loading="lazy"
/>
<span
className="playIcon"
aria-hidden="true"
>
</span>
{!!v.duration && (
<span className="durationBadge">
{v.duration}
</span>
)}
{watchedIds.has(v.videoId) && (
<span className="watchedBadge">
Watched
</span>
)}
</div>
<span className="videoTitle">
{getBilingualText(
v.name,
router.locale
)}
</span>
</div>
</button>
</li>
);
})}
</ul>
</div>
</div>
</div>
);
};
export default MediaDetails;
+12 -13
View File
@@ -13,7 +13,7 @@ const PaginationControl = (props) => {
currentPage, currentPage,
spinnerState, spinnerState,
getDocumentResults, getDocumentResults,
setCurrentPage setCurrentPage,
} = props; } = props;
let { t } = useTranslation(); let { t } = useTranslation();
@@ -45,7 +45,7 @@ const PaginationControl = (props) => {
const range = { const range = {
start: Math.round(currentPage - delta / 2), 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) { if (range.start - 1 === 1 || range.end + 1 === pageCount) {
@@ -89,7 +89,7 @@ const PaginationControl = (props) => {
<span <span
className="govuk-body govuk-link govuk-!-font-weight-bold govuk-link--no-underline activePaginationItem leftTextButton" className="govuk-body govuk-link govuk-!-font-weight-bold govuk-link--no-underline activePaginationItem leftTextButton"
onClick={() => { onClick={() => {
(spinnerState(), spinnerState(),
setCurrentPage( setCurrentPage(
props.currentView.currentPage - props.currentView.currentPage -
1 1
@@ -99,7 +99,7 @@ const PaginationControl = (props) => {
1, 1,
orderBy, orderBy,
fieldSort fieldSort
)); );
}} }}
> >
{t("common:previous-link-button")} {t("common:previous-link-button")}
@@ -132,12 +132,12 @@ const PaginationControl = (props) => {
key={i} key={i}
onClick={() => { onClick={() => {
spinnerState(); spinnerState();
(setCurrentPage(e), setCurrentPage(e),
getDocumentResults( getDocumentResults(
e, e,
orderBy, orderBy,
fieldSort fieldSort
)); );
}} }}
> >
{e} {e}
@@ -150,7 +150,7 @@ const PaginationControl = (props) => {
<span <span
className="govuk-body govuk-link govuk-!-font-weight-bold govuk-link--no-underline activePaginationItem rightTextButton" className="govuk-body govuk-link govuk-!-font-weight-bold govuk-link--no-underline activePaginationItem rightTextButton"
onClick={() => { onClick={() => {
(spinnerState(), spinnerState(),
setCurrentPage( setCurrentPage(
props.currentView.currentPage + props.currentView.currentPage +
1 1
@@ -160,7 +160,7 @@ const PaginationControl = (props) => {
1, 1,
orderBy, orderBy,
fieldSort fieldSort
)); );
}} }}
> >
{t("common:next-link-button")} {t("common:next-link-button")}
@@ -174,9 +174,8 @@ const PaginationControl = (props) => {
</div> </div>
</div> </div>
<div className="govuk-body-s mobilePageCount"> <div className="govuk-body-s mobilePageCount">
{t("common:pages-label")}{" "} {t("common:pages-label")} {currentPage}{" "}
{props.currentView.currentPage} {t("common:of-label")}{" "} {t("common:of-label")} {pagesCount}
{pagesCount}
</div> </div>
</div> </div>
)} )}
@@ -186,7 +185,7 @@ const PaginationControl = (props) => {
const mapStateToProps = (state) => { const mapStateToProps = (state) => {
return { return {
currentView: state.currentView currentView: state.currentView,
}; };
}; };
@@ -194,7 +193,7 @@ const mapDispatchToProps = (dispatch) => {
return { return {
setCurrentPage: (currentPage) => { setCurrentPage: (currentPage) => {
dispatch(setCurrentPage(currentPage)); dispatch(setCurrentPage(currentPage));
} },
}; };
}; };
@@ -1,356 +0,0 @@
import useTranslation from "next-translate/useTranslation";
import { useRouter } from "next/router";
import { connect } from "react-redux";
import { Field, change, reduxForm } from "redux-form";
import { useEffect, useState } from "react";
import { bytesToSize, getThumbnailIconByExtension } from "../../utils";
import {
FileUploadField,
RenderCondtionalRadioList,
RenderRichMultiline,
shouldDisableButton
} from "./representationElements";
import RepresentationTypeSelectorBlock from "./elements/RepresentationTypeSelectorBlock";
import { useDropzone } from "react-dropzone";
import {
setRepresentationCapacity,
setRepresentationSubmit,
setFilesForRepresentations
} from "../../../store/currentView/action";
const ConsultationAgent = (props) => {
let { t } = useTranslation();
const router = useRouter();
const { locale } = router;
const {
formObj,
appellantApplicantRepresentationArr,
setRepresentationCapacity,
setRepresentationSubmit,
currentView,
setRepFileName,
updateRepresentation,
setSavingStatus,
savingStatus,
setFilesForRepresentations,
onRepresentationTypeChange,
onTypeSelectionConfirmed
} = props;
const { acceptedFiles, getRootProps, getInputProps } = useDropzone();
const persistedRepresentationType =
currentView?.caseReference?.repDetails?.representationType;
const [typeSelectionConfirmed, setTypeSelectionConfirmed] = useState(
!!persistedRepresentationType
);
useEffect(() => {
if (persistedRepresentationType) {
setTypeSelectionConfirmed(true);
}
}, [persistedRepresentationType]);
if (JSON.stringify(formObj) != "{}") {
setRepFileName(formObj.representationForm.values);
let filterFilesList = props.currentView.caseReference.hasOwnProperty(
"repDetails"
)
? props.currentView.caseReference.repDetails.hasOwnProperty(
"filesList"
)
? props.currentView.caseReference.repDetails.filesList.filter(
function (el) {
return el != null;
}
)
: []
: [];
const files = acceptedFiles.map((file) => (
<li key={file.path}>
{file.path} - {file.size} bytes
</li>
));
const required = (value) => (value ? undefined : "Required");
const selectedRepresentationType =
formObj?.representationForm?.values?.representationType ||
props.representationType;
const isTypeConfirmed =
!!selectedRepresentationType && typeSelectionConfirmed;
const selectedRepresentationTypeDisplay =
router.locale == "cy"
? selectedRepresentationType == "Questionnaire"
? "Holiadur"
: selectedRepresentationType == "Statement"
? "Datganiad"
: selectedRepresentationType == "Final comments"
? "Sylwadau terfynol"
: selectedRepresentationType
: selectedRepresentationType;
return (
<>
<RepresentationTypeSelectorBlock
t={t}
headingText={t(
"myrepresentations:consultation-from-an-agent-heading"
)}
kindLabelText={t(
"myrepresentations:kind-of-consultation-label"
)}
isTypeSelected={isTypeConfirmed}
selectedTypeDisplay={selectedRepresentationTypeDisplay}
representationType={selectedRepresentationType}
setTypeSelectionConfirmed={setTypeSelectionConfirmed}
onRepresentationTypeChange={onRepresentationTypeChange}
onTypeSelectionConfirmed={onTypeSelectionConfirmed}
optionsArr={appellantApplicantRepresentationArr}
/>
{isTypeConfirmed && (
<>
<div className="govuk-grid-row">
<div className="govuk-form-group">
<Field
name="representationOnBehalfOf"
datafieldname="representationOnBehalfOf"
// label={t("myrepresentations:capacity-select-what-capacity-label")}
options={["Yes", "No"]}
id="representationOnBehalfOf"
className="govuk-radios__input"
errorMsg={t(
"myrepresentations:select-an-option-label"
)}
component={RenderCondtionalRadioList}
validate={[required]}
legend={t("case:representation-onbehalfof")}
hint={t(
"myrepresentations:representation-onbehalfof-hint"
)}
/>
</div>
</div>
<div className="govuk-grid-row">
<div className="govuk-form-group">
<p className="govuk-body">
{selectedRepresentationType ==
"Consultation Response"
? t(
"myrepresentations:enter-comment-label"
)
: t(
"myrepresentations:consultation-comment-label"
)}
</p>
<fieldset
className="govuk-fieldset"
aria-describedby="commentBox-hint"
>
{selectedRepresentationType ==
"Consultation Response" && (
<div className="govuk-form-group">
<Field
name="representationComments"
id="representationComments"
component={RenderRichMultiline}
type="text"
rows="5"
className="govuk-textarea govuk-input--width-30"
aria-describedby={
props.name + "-hint"
}
/>
{formObj.representationForm.values
.appealType == "846040004" ? (
<p className="govuk-hint govuk-!-font-size-14 govuk-!-margin-top-5">
{t(
"myrepresentations:publish-policy-label"
)}{" "}
<a
href={t(
"myrepresentations:publish-policy-link"
)}
>
{t(
"myrepresentations:publish-policy-link-label"
)}
</a>{" "}
{t(
"myrepresentations:publish-policy-label-two"
)}
</p>
) : (
<p className="govuk-hint govuk-!-font-size-14 govuk-!-margin-top-5">
{t(
"myrepresentations:publish-policy-label"
)}{" "}
<a
href={t(
"myrepresentations:publish-policy-link"
)}
>
{t(
"myrepresentations:publish-policy-link-label"
)}
</a>{" "}
{t(
"myrepresentations:publish-policy-label-two"
)}
</p>
)}
</div>
)}
<div className="govuk-form-group govuk-!-margin-bottom-9">
<FileUploadField
name={"representationDocuments"}
id={"representationDocuments"}
label={t(
"myrepresentations:add-files-label"
)}
ticketnumber={
props.currentView.caseReference
.ticketnumber
}
hint={"sdsd"}
fileList={
props.currentView.fileList
// props.currentView.caseReference.hasOwnProperty(
// "repDetails"
// )
// ? props.currentView.caseReference.repDetails.hasOwnProperty(
// "filesList"
// ) &&
// props.currentView
// .caseReference
// .repDetails.filesList
// .length > 0
// ? props.currentView
// .caseReference
// .repDetails
// .filesList
// : []
// : []
}
setFilesForRepresentations={
setFilesForRepresentations
}
containerID={
props.props.props.accountDetails
.containerID
}
filenamePrefix={props.formObj}
props={props.props.props}
setCurrentReference={
props.setCurrentReference
}
/>
</div>
</fieldset>
</div>{" "}
</div>
</>
)}
{isTypeConfirmed && (
<div className="govuk-grid-row">
<div className="govuk-button-group">
<button
type="submit"
className="govuk-button"
data-module="govuk-button"
disabled={shouldDisableButton({
props,
formObj
})}
>
{t("common:continue-button")}
</button>
{/* {router.query.state != "edit" && (
<a
onClick={() => {
setRepresentationCapacity();
props.updateField(
"representationForm",
"representationCapacity",
""
);
}}
className="govuk-link"
>
{t("common:back-link")}
</a>
)} */}
{savingStatus ? (
<span className=" progress-save-active">
{router.locale == "cy"
? "Nôl data"
: "Saving data"}
<img
className="data-loading-icon"
src="/assets/images/loading.gif"
alt={
router.locale == "cy"
? "Nôl data"
: "Saving data"
}
/>
</span>
) : (
<button
className="govuk-button progress-save "
onClick={() => {
let valuesObj =
props.props.props.form[props.form]
.values || {};
//console.log("valuesobj:", valuesObj);
delete valuesObj[
"_pinswg_appellant_value"
];
//console.log("on save:", valuesObj);
updateRepresentation(
valuesObj,
false,
true
);
}}
>
{t("common:save-exit-button")}
</button>
)}
</div>
</div>
)}
</>
);
}
};
const mapDispatchToProps = (dispatch) => ({
updateField: (form, field, newValue) =>
dispatch(change(form, field, newValue)),
setFilesForRepresentations: (fileList) => {
dispatch(setFilesForRepresentations(fileList));
}
});
export default connect(
null,
mapDispatchToProps
)(
reduxForm({
form: "representationForm",
enableReinitialize: true,
destroyOnUnmount: false
})(ConsultationAgent)
);
@@ -1,332 +0,0 @@
import useTranslation from "next-translate/useTranslation";
import { useRouter } from "next/router";
import { connect } from "react-redux";
import { Field, change, reduxForm } from "redux-form";
import { useEffect, useState } from "react";
import { bytesToSize, getThumbnailIconByExtension } from "../../utils";
import {
FileUploadField,
RenderRichMultiline,
shouldDisableButton
} from "./representationElements";
import RepresentationTypeSelectorBlock from "./elements/RepresentationTypeSelectorBlock";
import { useDropzone } from "react-dropzone";
import {
setRepresentationCapacity,
setRepresentationSubmit,
setFilesForRepresentations
} from "../../../store/currentView/action";
const ConsultationAppellant = (props) => {
let { t } = useTranslation();
const router = useRouter();
const { locale } = router;
const {
formObj,
appellantApplicantRepresentationArr,
setRepresentationCapacity,
setRepresentationSubmit,
currentView,
setRepFileName,
updateRepresentation,
setSavingStatus,
savingStatus,
setFilesForRepresentations,
onRepresentationTypeChange,
onTypeSelectionConfirmed
} = props;
const { acceptedFiles, getRootProps, getInputProps } = useDropzone();
const persistedRepresentationType =
currentView?.caseReference?.repDetails?.representationType;
const [typeSelectionConfirmed, setTypeSelectionConfirmed] = useState(
!!persistedRepresentationType
);
useEffect(() => {
if (persistedRepresentationType) {
setTypeSelectionConfirmed(true);
}
}, [persistedRepresentationType]);
console.log(JSON.stringify(formObj) == "{}" ? "empty" : "value");
if (JSON.stringify(formObj) != "{}") {
setRepFileName(formObj.representationForm.values);
let filterFilesList = props.currentView.caseReference.hasOwnProperty(
"repDetails"
)
? props.currentView.caseReference.repDetails.hasOwnProperty(
"filesList"
)
? props.currentView.caseReference.repDetails.filesList.filter(
function (el) {
return el != null;
}
)
: []
: [];
filterFilesList = filterFilesList.filter(
(value, index, self) =>
index === self.findIndex((t) => t.name === value.name)
);
const selectedRepresentationType =
formObj?.representationForm?.values?.representationType ||
props.representationType;
const isTypeConfirmed =
!!selectedRepresentationType && typeSelectionConfirmed;
const selectedRepresentationTypeDisplay =
router.locale == "cy"
? selectedRepresentationType == "Questionnaire"
? "Holiadur"
: selectedRepresentationType == "Statement"
? "Datganiad"
: selectedRepresentationType == "Final comments"
? "Sylwadau terfynol"
: selectedRepresentationType
: selectedRepresentationType;
return (
<>
<RepresentationTypeSelectorBlock
t={t}
headingText={t(
"myrepresentations:consultation-from-an-appellant-heading"
)}
kindLabelText={t(
"myrepresentations:kind-of-consultation-label"
)}
isTypeSelected={isTypeConfirmed}
selectedTypeDisplay={selectedRepresentationTypeDisplay}
representationType={selectedRepresentationType}
setTypeSelectionConfirmed={setTypeSelectionConfirmed}
onRepresentationTypeChange={onRepresentationTypeChange}
onTypeSelectionConfirmed={onTypeSelectionConfirmed}
optionsArr={appellantApplicantRepresentationArr}
/>
{isTypeConfirmed && (
<div className="govuk-grid-row">
<div className="govuk-form-group">
<p className="govuk-body">
{selectedRepresentationType ==
"Consultation Response"
? t("myrepresentations:enter-comment-label")
: t(
"myrepresentations:consultation-comment-label"
)}
</p>
<fieldset
className="govuk-fieldset"
aria-describedby="commentBox-hint"
>
{selectedRepresentationType ==
"Consultation Response" && (
<div className="govuk-form-group">
<Field
name="representationComments"
id="representationComments"
component={RenderRichMultiline}
type="text"
rows="5"
className="govuk-textarea govuk-input--width-30"
aria-describedby={
props.name + "-hint"
}
/>
{formObj.representationForm.values
.appealType == "846040004" ? (
<p className="govuk-hint govuk-!-font-size-14 govuk-!-margin-top-5">
{t(
"myrepresentations:publish-policy-label"
)}{" "}
<a
href={t(
"myrepresentations:publish-policy-link"
)}
>
{t(
"myrepresentations:publish-policy-link-label"
)}
</a>{" "}
{t(
"myrepresentations:publish-policy-label-two"
)}
</p>
) : (
<p className="govuk-hint govuk-!-font-size-14 govuk-!-margin-top-5">
{t(
"myrepresentations:publish-policy-label"
)}{" "}
<a
href={t(
"myrepresentations:publish-policy-link"
)}
>
{t(
"myrepresentations:publish-policy-link-label"
)}
</a>{" "}
{t(
"myrepresentations:publish-policy-label-two"
)}
</p>
)}
</div>
)}
<div className="govuk-form-group govuk-!-margin-bottom-9">
<FileUploadField
name={"representationDocuments"}
id={"representationDocuments"}
label={t(
"myrepresentations:add-files-label"
)}
ticketnumber={
props.currentView.caseReference
.ticketnumber
}
hint={"sdsd"}
fileList={
props.currentView.fileList
// props.currentView.caseReference.hasOwnProperty(
// "repDetails"
// )
// ? props.currentView.caseReference.repDetails.hasOwnProperty(
// "filesList"
// ) &&
// props.currentView
// .caseReference.repDetails
// .filesList.length > 0
// ? props.currentView
// .caseReference
// .repDetails.filesList
// : []
// : []
}
setFilesForRepresentations={
setFilesForRepresentations
}
containerID={
props.props.props.accountDetails
.containerID
}
filenamePrefix={props.formObj}
props={props.props.props}
setCurrentReference={
props.setCurrentReference
}
/>
</div>
</fieldset>
</div>{" "}
</div>
)}
{isTypeConfirmed && (
<div className="govuk-grid-row">
<div className="govuk-button-group">
<button
type="submit"
className="govuk-button"
data-module="govuk-button"
disabled={shouldDisableButton({
props,
formObj
})}
>
{t("common:continue-button")}
</button>
{/* {router.query.state != "edit" && (
<a
onClick={() => {
setRepresentationCapacity();
props.updateField(
"representationType",
""
);
}}
className="govuk-link"
>
{t("common:back-link")}
</a>
)} */}
{savingStatus ? (
<span className=" progress-save-active">
{router.locale == "cy"
? "Nôl data"
: "Saving data"}
<img
className="data-loading-icon"
src="/assets/images/loading.gif"
alt={
router.locale == "cy"
? "Nôl data"
: "Saving data"
}
/>
</span>
) : (
<button
className="govuk-button progress-save "
onClick={() => {
let valuesObj =
props.props.props.form[props.form]
.values || {};
//console.log("valuesobj:", valuesObj);
delete valuesObj[
"_pinswg_appellant_value"
];
//console.log("on save:", valuesObj);
updateRepresentation(
valuesObj,
false,
true
);
}}
>
{t("common:save-exit-button")}
</button>
)}
</div>
</div>
)}
</>
);
}
};
//const mapStateToProps = (state, props) => {};
const mapDispatchToProps = (dispatch) => {
return {
updateField: (form, field, newValue) =>
dispatch(change(form, field, newValue)),
setFilesForRepresentations: (fileList) => {
dispatch(setFilesForRepresentations(fileList));
}
};
};
export default connect(
null,
mapDispatchToProps
)(
reduxForm({
form: "representationForm",
enableReinitialize: true,
destroyOnUnmount: false
})(ConsultationAppellant)
);
@@ -1,369 +0,0 @@
import useTranslation from "next-translate/useTranslation";
import { useRouter } from "next/router";
import { connect } from "react-redux";
import { Field, change, reduxForm } from "redux-form";
import { useEffect, useState } from "react";
import { bytesToSize, getThumbnailIconByExtension } from "../../utils";
import {
FileUploadField,
RenderCondtionalRadioList,
RenderRichMultiline,
shouldDisableButton
} from "./representationElements";
import RepresentationTypeSelectorBlock from "./elements/RepresentationTypeSelectorBlock";
import { useDropzone } from "react-dropzone";
import {
setRepresentationCapacity,
setRepresentationSubmit,
setFilesForRepresentations
} from "../../../store/currentView/action";
const ConsultationInterestedPartyPerson = (props) => {
let { t } = useTranslation();
const router = useRouter();
const { locale } = router;
const {
formObj,
interestedPersonRepresentationArr,
setRepresentationCapacity,
setRepresentationSubmit,
setRepFileName,
updateRepresentation,
setSavingStatus,
savingStatus,
setFilesForRepresentations,
onRepresentationTypeChange,
onTypeSelectionConfirmed
} = props;
const required = (value) => (value ? undefined : "Required");
const { acceptedFiles, getRootProps, getInputProps } = useDropzone();
const persistedRepresentationType =
props.currentView?.caseReference?.repDetails?.representationType;
const [typeSelectionConfirmed, setTypeSelectionConfirmed] = useState(
!!persistedRepresentationType
);
useEffect(() => {
if (persistedRepresentationType) {
setTypeSelectionConfirmed(true);
}
}, [persistedRepresentationType]);
if (JSON.stringify(formObj) != "{}") {
setRepFileName(formObj.representationForm.values);
let filterFilesList = props.currentView.caseReference.hasOwnProperty(
"repDetails"
)
? props.currentView.caseReference.repDetails.hasOwnProperty(
"filesList"
)
? props.currentView.caseReference.repDetails.filesList.filter(
function (el) {
return el != null;
}
)
: []
: [];
const files = acceptedFiles.map((file) => (
<li key={file.path}>
{file.path} - {file.size} bytes
</li>
));
const selectedRepresentationType =
formObj?.representationForm?.values?.representationType ||
props.representationType;
const isTypeConfirmed =
!!selectedRepresentationType && typeSelectionConfirmed;
const selectedRepresentationTypeDisplay =
router.locale == "cy"
? selectedRepresentationType == "Questionnaire"
? "Holiadur"
: selectedRepresentationType == "Statement"
? "Datganiad"
: selectedRepresentationType == "Final comments"
? "Sylwadau terfynol"
: selectedRepresentationType
: selectedRepresentationType;
return (
<>
<RepresentationTypeSelectorBlock
t={t}
headingText={t(
"myrepresentations:consultation-from-an-interested-person-heading"
)}
kindLabelText={t(
"myrepresentations:kind-of-consultation-label"
)}
isTypeSelected={isTypeConfirmed}
selectedTypeDisplay={selectedRepresentationTypeDisplay}
representationType={selectedRepresentationType}
setTypeSelectionConfirmed={setTypeSelectionConfirmed}
onRepresentationTypeChange={onRepresentationTypeChange}
onTypeSelectionConfirmed={onTypeSelectionConfirmed}
optionsArr={interestedPersonRepresentationArr}
validate={[required]}
errorMsg={t("myrepresentations:select-an-option-label")}
/>
{isTypeConfirmed && (
<>
<div className="govuk-grid-row">
<div className="govuk-form-group">
<Field
name="representationOnBehalfOf"
datafieldname="representationOnBehalfOf"
// label="In what capacity do you wish to make representations on this case?"
options={[
t(
"myrepresentations:questionnaire-yes"
),
t("myrepresentations:questionnaire-no")
]}
id="representationOnBehalfOf"
className="govuk-radios__input"
errorMsg={t(
"myrepresentations:select-an-option-label"
)}
component={RenderCondtionalRadioList}
validate={[required]}
legend={t("case:representation-onbehalfof")}
hint={t(
"myrepresentations:representation-onbehalfof-hint"
)}
/>
</div>
</div>
<div className="govuk-grid-row">
<div className="govuk-form-group">
<p className="govuk-body">
{selectedRepresentationType ==
"Consultation Response"
? t(
"myrepresentations:enter-comment-label"
)
: t(
"myrepresentations:consultation-comment-label"
)}
</p>
<fieldset
className="govuk-fieldset"
aria-describedby="commentBox-hint"
>
{" "}
{selectedRepresentationType ==
"Consultation Response" && (
<div className="govuk-form-group">
<Field
name="representationComments"
id="representationComments"
component={RenderRichMultiline}
type="text"
rows="5"
className="govuk-textarea govuk-input--width-30"
aria-describedby={
props.name + "-hint"
}
/>
{formObj.representationForm.values
.appealType == "846040004" ? (
<p className="govuk-hint govuk-!-font-size-14 govuk-!-margin-top-5">
{t(
"myrepresentations:publish-policy-label"
)}{" "}
<a
href={t(
"myrepresentations:publish-policy-link"
)}
>
{t(
"myrepresentations:publish-policy-link-label"
)}
</a>{" "}
{t(
"myrepresentations:publish-policy-label-two"
)}
</p>
) : (
<p className="govuk-hint govuk-!-font-size-14 govuk-!-margin-top-5">
{t(
"myrepresentations:publish-policy-label"
)}{" "}
<a
href={t(
"myrepresentations:publish-policy-link"
)}
>
{t(
"myrepresentations:publish-policy-link-label"
)}
</a>{" "}
{t(
"myrepresentations:publish-policy-label-two"
)}
</p>
)}
</div>
)}
<div className="govuk-form-group govuk-!-margin-bottom-9">
<FileUploadField
name={"representationDocuments"}
id={"representationDocuments"}
label={t(
"myrepresentations:add-files-label"
)}
ticketnumber={
props.currentView.caseReference
.ticketnumber
}
hint={"sdsd"}
fileList={
props.currentView.fileList
// props.currentView.caseReference.hasOwnProperty(
// "repDetails"
// )
// ? props.currentView.caseReference.repDetails.hasOwnProperty(
// "filesList"
// ) &&
// props.currentView
// .caseReference
// .repDetails.filesList
// .length > 0
// ? props.currentView
// .caseReference
// .repDetails
// .filesList
// : []
// : []
}
setFilesForRepresentations={
setFilesForRepresentations
}
containerID={
props.props.props.accountDetails
.containerID
}
filenamePrefix={props.formObj}
props={props.props.props}
setCurrentReference={
props.setCurrentReference
}
/>
</div>
</fieldset>
</div>{" "}
</div>
</>
)}
{isTypeConfirmed && (
<div className="govuk-grid-row">
<div className="govuk-button-group">
<button
type="submit"
className="govuk-button"
data-module="govuk-button"
disabled={shouldDisableButton({
props,
formObj
})}
>
{t("common:continue-button")}
</button>
{/*
<a
onClick={() => {
setRepresentationCapacity();
props.updateField(
"representationForm",
"representationCapacity",
""
);
props.updateField(
"representationForm",
"representationType",
""
);
}}
className="govuk-link"
>
{t("case:summary-back-button-label")}
</a> */}
{savingStatus ? (
<span className=" progress-save-active">
{router.locale == "cy"
? "Nôl data"
: "Saving data"}
<img
className="data-loading-icon"
src="/assets/images/loading.gif"
alt={
router.locale == "cy"
? "Nôl data"
: "Saving data"
}
/>
</span>
) : (
<button
className="govuk-button progress-save "
onClick={() => {
let valuesObj =
props.props.props.form[props.form]
.values || {};
//console.log("valuesobj:", valuesObj);
delete valuesObj[
"_pinswg_appellant_value"
];
//console.log("on save:", valuesObj);
updateRepresentation(
valuesObj,
false,
true
);
}}
>
{t("common:save-exit-button")}
</button>
)}
</div>
</div>
)}
</>
);
}
};
//const mapStateToProps = (state, props) => {};
const mapDispatchToProps = (dispatch) => ({
updateField: (form, field, newValue) =>
dispatch(change(form, field, newValue)),
setFilesForRepresentations: (fileList) => {
dispatch(setFilesForRepresentations(fileList));
}
});
export default connect(
null,
mapDispatchToProps
)(
reduxForm({
form: "representationForm",
enableReinitialize: true,
destroyOnUnmount: false
})(ConsultationInterestedPartyPerson)
);
@@ -1,42 +0,0 @@
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;
@@ -1,205 +0,0 @@
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,23 +2,21 @@ import useTranslation from "next-translate/useTranslation";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
import { connect } from "react-redux"; import { connect } from "react-redux";
import { Field, change, reduxForm } from "redux-form"; import { Field, change, reduxForm } from "redux-form";
import { useEffect, useState } from "react"; import { useState } from "react";
import { bytesToSize, getThumbnailIconByExtension } from "../../utils"; import { bytesToSize, getThumbnailIconByExtension } from "../../utils";
import { import {
FileUploadField, FileUploadField,
RenderCondtionalRadioList, RenderCondtionalRadioList,
RenderPickList,
RenderRichMultiline, RenderRichMultiline,
shouldDisableButton
} from "./representationElements"; } from "./representationElements";
import RepresentationActionButtons from "./elements/RepresentationActionButtons";
import RepresentationTypeSelectorBlock from "./elements/RepresentationTypeSelectorBlock";
import { useDropzone } from "react-dropzone"; import { useDropzone } from "react-dropzone";
import { import {
setRepresentationCapacity, setRepresentationCapacity,
setRepresentationSubmit, setRepresentationSubmit,
setFilesForRepresentations setFilesForRepresentations,
} from "../../../store/currentView/action"; } from "../../../store/currentView/action";
const RepAgent = (props) => { const RepAgent = (props) => {
@@ -37,23 +35,9 @@ const RepAgent = (props) => {
setSavingStatus, setSavingStatus,
savingStatus, savingStatus,
setFilesForRepresentations, setFilesForRepresentations,
onRepresentationTypeChange,
onTypeSelectionConfirmed
} = props; } = props;
const { acceptedFiles, getRootProps, getInputProps } = useDropzone(); 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) != "{}") { if (JSON.stringify(formObj) != "{}") {
setRepFileName(formObj.representationForm.values); setRepFileName(formObj.representationForm.values);
@@ -78,49 +62,61 @@ const RepAgent = (props) => {
)); ));
const required = (value) => (value ? undefined : "Required"); 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 ( return (
<> <>
<RepresentationTypeSelectorBlock <div className="govuk-grid-row">
t={t} <div className="govuk-form-group">
headingText={t( {typeof formObj.representationForm.values
.representationType == "undefined" &&
props.representationType != "Select..." ? (
<>
<h2 className="govuk-heading-m ">
{t(
"myrepresentations:representation-from-an-agent-heading" "myrepresentations:representation-from-an-agent-heading"
)} )}
kindLabelText={t("myrepresentations:kind-of-rep-label")} </h2>
isTypeSelected={isTypeConfirmed}
selectedTypeDisplay={selectedRepresentationTypeDisplay} <label
representationType={selectedRepresentationType} className="govuk-label govuk-body-m"
setTypeSelectionConfirmed={setTypeSelectionConfirmed} htmlFor="representationType"
onRepresentationTypeChange={onRepresentationTypeChange} >
onTypeSelectionConfirmed={onTypeSelectionConfirmed} {t("myrepresentations:kind-of-rep-label")}
optionsArr={appellantApplicantRepresentationArr} </label>
<Field
name="representationType"
component={RenderPickList}
datafieldname="representationType"
optionsArr={
appellantApplicantRepresentationArr
}
/> />
{isTypeConfirmed && ( </>
) : (
<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") && (
<> <>
<div className="govuk-grid-row"> <div className="govuk-grid-row">
<div className="govuk-form-group"> <div className="govuk-form-group">
@@ -243,17 +239,74 @@ const RepAgent = (props) => {
</div> </div>
</> </>
)} )}
{isTypeConfirmed && ( {typeof formObj.representationForm.values.representationType !=
<RepresentationActionButtons "undefined" && (
t={t} <div className="govuk-grid-row">
locale={router.locale} <div className="govuk-button-group">
isSaving={savingStatus} <button
isContinueDisabled={shouldDisableButton({ type="submit"
props, className="govuk-button"
formObj data-module="govuk-button"
})} >
onSaveExit={handleSaveExit} {t("common:continue-button")}
</button>
{/* {router.query.state != "edit" && (
<a
onClick={() => {
setRepresentationCapacity();
props.updateField(
"representationForm",
"representationCapacity",
""
);
}}
className="govuk-link"
>
{t("common:back-link")}
</a>
)} */}
{savingStatus ? (
<span className=" progress-save-active">
{router.locale == "cy"
? "Nôl data"
: "Saving data"}
<img
className="data-loading-icon"
src="/assets/images/loading.gif"
alt={
router.locale == "cy"
? "Nôl data"
: "Saving data"
}
/> />
</span>
) : (
<button
className="govuk-button progress-save "
onClick={() => {
let valuesObj =
props.props.props.form[props.form]
.values || {};
//console.log("valuesobj:", valuesObj);
delete valuesObj[
"_pinswg_appellant_value"
];
//console.log("on save:", valuesObj);
updateRepresentation(
valuesObj,
false,
true
);
}}
>
{t("common:save-exit-button")}
</button>
)}
</div>
</div>
)} )}
</> </>
); );
@@ -266,7 +319,7 @@ const mapDispatchToProps = (dispatch) => ({
setFilesForRepresentations: (fileList) => { setFilesForRepresentations: (fileList) => {
dispatch(setFilesForRepresentations(fileList)); dispatch(setFilesForRepresentations(fileList));
} },
}); });
export default connect( export default connect(
@@ -276,6 +329,6 @@ export default connect(
reduxForm({ reduxForm({
form: "representationForm", form: "representationForm",
enableReinitialize: true, enableReinitialize: true,
destroyOnUnmount: false destroyOnUnmount: false,
})(RepAgent) })(RepAgent)
); );
@@ -2,22 +2,20 @@ import useTranslation from "next-translate/useTranslation";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
import { connect } from "react-redux"; import { connect } from "react-redux";
import { Field, change, reduxForm } from "redux-form"; import { Field, change, reduxForm } from "redux-form";
import { useEffect, useState } from "react"; import { useState } from "react";
import { bytesToSize, getThumbnailIconByExtension } from "../../utils"; import { bytesToSize, getThumbnailIconByExtension } from "../../utils";
import { import {
FileUploadField, FileUploadField,
RenderPickList,
RenderRichMultiline, RenderRichMultiline,
shouldDisableButton
} from "./representationElements"; } from "./representationElements";
import RepresentationActionButtons from "./elements/RepresentationActionButtons";
import RepresentationTypeSelectorBlock from "./elements/RepresentationTypeSelectorBlock";
import { useDropzone } from "react-dropzone"; import { useDropzone } from "react-dropzone";
import { import {
setRepresentationCapacity, setRepresentationCapacity,
setRepresentationSubmit, setRepresentationSubmit,
setFilesForRepresentations setFilesForRepresentations,
} from "../../../store/currentView/action"; } from "../../../store/currentView/action";
const RepAppellant = (props) => { const RepAppellant = (props) => {
@@ -36,23 +34,9 @@ const RepAppellant = (props) => {
setSavingStatus, setSavingStatus,
savingStatus, savingStatus,
setFilesForRepresentations, setFilesForRepresentations,
onRepresentationTypeChange,
onTypeSelectionConfirmed
} = props; } = props;
const { acceptedFiles, getRootProps, getInputProps } = useDropzone(); 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"); console.log(JSON.stringify(formObj) == "{}" ? "empty" : "value");
if (JSON.stringify(formObj) != "{}") { if (JSON.stringify(formObj) != "{}") {
@@ -77,49 +61,59 @@ const RepAppellant = (props) => {
index === self.findIndex((t) => t.name === value.name) 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 ( return (
<> <>
<RepresentationTypeSelectorBlock <div className="govuk-grid-row">
t={t} <div className="govuk-form-group">
headingText={t( {typeof formObj.representationForm.values
.representationType == "undefined" &&
props.representationType != "Select..." ? (
<>
<h2 className="govuk-heading-m ">
{t(
"myrepresentations:representation-from-an-appellant-heading" "myrepresentations:representation-from-an-appellant-heading"
)} )}
kindLabelText={t("myrepresentations:kind-of-rep-label")} </h2>
isTypeSelected={isTypeConfirmed} <label
selectedTypeDisplay={selectedRepresentationTypeDisplay} className="govuk-label govuk-body-m"
representationType={selectedRepresentationType} htmlFor="representationType"
setTypeSelectionConfirmed={setTypeSelectionConfirmed} >
onRepresentationTypeChange={onRepresentationTypeChange} {t("myrepresentations:kind-of-rep-label")}
onTypeSelectionConfirmed={onTypeSelectionConfirmed} </label>
optionsArr={appellantApplicantRepresentationArr} <Field
name="representationType"
component={RenderPickList}
datafieldname="representationType"
optionsArr={
appellantApplicantRepresentationArr
}
/> />
{isTypeConfirmed && ( </>
) : (
<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") && (
<div className="govuk-grid-row"> <div className="govuk-grid-row">
<div className="govuk-form-group"> <div className="govuk-form-group">
<p className="govuk-body"> <p className="govuk-body">
@@ -234,18 +228,75 @@ const RepAppellant = (props) => {
</div>{" "} </div>{" "}
</div> </div>
)} )}
{typeof formObj.representationForm.values.representationType !=
"undefined" && (
<div className="govuk-grid-row">
<div className="govuk-button-group">
<button
type="submit"
className="govuk-button"
data-module="govuk-button"
>
{t("common:continue-button")}
</button>
{/* {router.query.state != "edit" && (
<a
onClick={() => {
setRepresentationCapacity();
props.updateField(
"representationForm",
"representationType",
""
);
}}
className="govuk-link"
>
{t("common:back-link")}
</a>
)} */}
{isTypeConfirmed && ( {savingStatus ? (
<RepresentationActionButtons <span className=" progress-save-active">
t={t} {router.locale == "cy"
locale={router.locale} ? "Nôl data"
isSaving={savingStatus} : "Saving data"}
isContinueDisabled={shouldDisableButton({ <img
props, className="data-loading-icon"
formObj src="/assets/images/loading.gif"
})} alt={
onSaveExit={handleSaveExit} 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>
)} )}
</> </>
); );
@@ -261,7 +312,7 @@ const mapDispatchToProps = (dispatch) => {
setFilesForRepresentations: (fileList) => { setFilesForRepresentations: (fileList) => {
dispatch(setFilesForRepresentations(fileList)); dispatch(setFilesForRepresentations(fileList));
} },
}; };
}; };
@@ -272,6 +323,6 @@ export default connect(
reduxForm({ reduxForm({
form: "representationForm", form: "representationForm",
enableReinitialize: true, enableReinitialize: true,
destroyOnUnmount: false destroyOnUnmount: false,
})(RepAppellant) })(RepAppellant)
); );
@@ -3,7 +3,7 @@ import { useRouter } from "next/router";
import { useDropzone } from "react-dropzone"; import { useDropzone } from "react-dropzone";
import { Field } from "redux-form"; import { Field } from "redux-form";
import RepDetails from "./representationDetails"; import RepDetails from "./representationDetails";
import { RenderRadioList } from "./representationElements"; import { RenderRadioListWithText } from "./representationElements";
let RepCapacitySelection = (props) => { let RepCapacitySelection = (props) => {
let { t } = useTranslation(); let { t } = useTranslation();
@@ -17,7 +17,7 @@ let RepCapacitySelection = (props) => {
casesObj, casesObj,
validate, validate,
handleSubmit, handleSubmit,
setCurrentReference setCurrentReference,
} = props; } = props;
const { acceptedFiles, getRootProps, getInputProps } = useDropzone(); const { acceptedFiles, getRootProps, getInputProps } = useDropzone();
const files = acceptedFiles.map((file) => ( const files = acceptedFiles.map((file) => (
@@ -27,7 +27,6 @@ let RepCapacitySelection = (props) => {
)); ));
const required = (value) => (value ? undefined : "Required"); const required = (value) => (value ? undefined : "Required");
const appealType = props.props.currentView.caseReference.appealType;
return ( return (
<> <>
@@ -43,7 +42,6 @@ let RepCapacitySelection = (props) => {
myRepresentations={props.props.myRepresentations} myRepresentations={props.props.myRepresentations}
props={props} props={props}
setCurrentReference={setCurrentReference} setCurrentReference={setCurrentReference}
appealType={appealType}
/>{" "} />{" "}
<div id="rep-details" className=""> <div id="rep-details" className="">
<div className="govuk-grid-column-full"> <div className="govuk-grid-column-full">
@@ -52,27 +50,21 @@ let RepCapacitySelection = (props) => {
{t( {t(
"myrepresentations:capacity-select-your-details" "myrepresentations:capacity-select-your-details"
)}{" "} )}{" "}
- {props.firstValue}{" "} - {props.firstValue}
</h2> </h2>
<Field <Field
name="representationCapacity" name="representationCapacity"
datafieldname="representationCapacity" datafieldname="representationCapacity"
label={ label={t(
appealType != 846040002
? t(
"myrepresentations:capacity-select-what-capacity-label" "myrepresentations:capacity-select-what-capacity-label"
) )}
: t(
"myrepresentations:sips-capacity-select-what-capacity-label"
)
}
options={capacityOptionsArr} options={capacityOptionsArr}
id="representationCapacity" id="representationCapacity"
className="govuk-radios__input" className="govuk-radios__input"
errorMsg={t( errorMsg={t(
"myrepresentations:select-an-option-label" "myrepresentations:select-an-option-label"
)} )}
component={RenderRadioList} component={RenderRadioListWithText}
validate={[required]} validate={[required]}
/> />
</div> </div>
@@ -7,10 +7,10 @@ import { connect } from "react-redux";
import { useDropzone } from "react-dropzone"; import { useDropzone } from "react-dropzone";
import { import {
createWatchedCases, createWatchedCases,
sendEmail,
sendRepCompleteMessage, sendRepCompleteMessage,
setRepInvolvment setRepInvolvment,
} from "../../../actions/services/portalService"; } from "../../../actions";
import { sendEmail } from "../../../actions/services/notifyService";
import { setRepresentationReset } from "../../../store/currentView/action"; import { setRepresentationReset } from "../../../store/currentView/action";
const RepComplete = (props) => { const RepComplete = (props) => {
@@ -27,7 +27,7 @@ const RepComplete = (props) => {
setSubmitBack, setSubmitBack,
setRepresentationSubmitConfirmation, setRepresentationSubmitConfirmation,
setRepresentationMessageSent, setRepresentationMessageSent,
repFormData repFormData,
} = props; } = props;
const { acceptedFiles, getRootProps, getInputProps } = useDropzone(); const { acceptedFiles, getRootProps, getInputProps } = useDropzone();
const files = acceptedFiles.map((file) => ( const files = acceptedFiles.map((file) => (
@@ -40,16 +40,11 @@ const RepComplete = (props) => {
props.props.currentView.caseReference.appealType === 846040002; props.props.currentView.caseReference.appealType === 846040002;
useEffect(() => { useEffect(() => {
const isWelsh = router.locale === "cy";
const reference = isSIPS const reference = isSIPS
? "PEDW-CONSULTATION-COMPLETE" + isWelsh && "-CY" ? "PEDW-CONSULTATION-COMPLETE"
: "PEDW-REPRESENTATION-COMPLETE" + isWelsh && "-CY"; : "PEDW-REPRESENTATION-COMPLETE";
const templateId = isSIPS const templateId = isSIPS
? isWelsh ? "c3f373ca-df9d-4967-bea0-3ad3a57f8dcc"
? "7d27b968-6f63-4334-b1c4-2e4a69554212"
: "c3f373ca-df9d-4967-bea0-3ad3a57f8dcc"
: isWelsh
? "6e2f0111-b352-4074-91a2-760403cd185b"
: "c49785e7-3217-40b6-b33f-dffc4e58d5c1"; : "c49785e7-3217-40b6-b33f-dffc4e58d5c1";
const emailAddress = const emailAddress =
@@ -60,14 +55,13 @@ const RepComplete = (props) => {
"emailAddress": "emailAddress":
props.props.props.props.accountDetails.accountDetails props.props.props.props.accountDetails.accountDetails
.emailaddress1, .emailaddress1,
"linkExpiry": 10 * 60 "linkExpiry": 10 * 60,
}; };
(props.props.currentView.representationMessageSent != true && props.props.currentView.representationMessageSent != true &&
(setRepInvolvment( (setRepInvolvment(
props.props.currentView.caseReference.incidentid, props.props.currentView.caseReference.incidentid,
props.props.props.props.accountDetails.accountDetails.contactid, props.props.props.props.accountDetails.accountDetails.contactid
props.props.currentView.representationCapacity
), ),
sendRepCompleteMessage( sendRepCompleteMessage(
props.props.props.props.accountDetails.containerID, props.props.props.props.accountDetails.containerID,
@@ -95,10 +89,10 @@ const RepComplete = (props) => {
? props.props.currentView.caseReference.repDetails ? props.props.currentView.caseReference.repDetails
.representationType .representationType
: props.props.currentView.caseReference : props.props.currentView.caseReference
.representationType .representationType,
}), }),
setRepresentationMessageSent(true)), setRepresentationMessageSent(true)),
window.scrollTo({ top: 0, behavior: "smooth" })); window.scrollTo({ top: 0, behavior: "smooth" });
}); });
return ( return (
<div id="rep-appellant"> <div id="rep-appellant">
@@ -110,7 +104,6 @@ const RepComplete = (props) => {
<p>{t("myrepresentations:rep-complete-para-one")}</p> <p>{t("myrepresentations:rep-complete-para-one")}</p>
<p>{t("myrepresentations:rep-complete-para-two")}</p> <p>{t("myrepresentations:rep-complete-para-two")}</p>
<p> {t("myrepresentations:rep-complete-para-three")}</p> <p> {t("myrepresentations:rep-complete-para-three")}</p>
<p> {t("myrepresentations:rep-complete-para-four")}</p>
</div> </div>
<div className="govuk-grid-row"> <div className="govuk-grid-row">
<div className="govuk-button-group"> <div className="govuk-button-group">
@@ -137,7 +130,7 @@ const mapStateToProps = (state) => {
currentView: state.currentView, currentView: state.currentView,
myRepresentations: state.myRepresentations, myRepresentations: state.myRepresentations,
initialValues: state.currentView.caseReference.repDetails, initialValues: state.currentView.caseReference.repDetails,
accountDetails: state.accountDetails accountDetails: state.accountDetails,
//form: state.form, //form: state.form,
}; };
}; };
@@ -1,9 +1,9 @@
import _ from "lodash";
import useTranslation from "next-translate/useTranslation"; import useTranslation from "next-translate/useTranslation";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
import { useState } from "react"; import { useState } from "react";
import { useDropzone } from "react-dropzone"; import { useDropzone } from "react-dropzone";
import { connect } from "react-redux"; import { connect } from "react-redux";
import { generateRepPDF } from "../../../actions/services/documentService";
import RepComplete from "./representationComplete"; import RepComplete from "./representationComplete";
import RepLPAQuestionnaireCheck_enforcement from "./representationQuestionnairesCheck/representationLPAQuestionnaireCheck_enforcement"; import RepLPAQuestionnaireCheck_enforcement from "./representationQuestionnairesCheck/representationLPAQuestionnaireCheck_enforcement";
import RepLPAQuestionnaireCheck_s78 from "./representationQuestionnairesCheck/representationLPAQuestionnaireCheck_s78"; import RepLPAQuestionnaireCheck_s78 from "./representationQuestionnairesCheck/representationLPAQuestionnaireCheck_s78";
@@ -12,21 +12,17 @@ import {
bytesToSize, bytesToSize,
getThumbnailIconByExtension, getThumbnailIconByExtension,
formatDates, formatDates,
hasOwn,
updateLinks, updateLinks,
getDocLink
} from "../../utils"; } from "../../utils";
import { import {
setCurrentReference, setCurrentReference,
setCurrentView setCurrentView,
} from "../../../store/currentView/action"; } from "../../../store/currentView/action";
const RepCompleteSubmit = (props) => { const RepCompleteSubmit = (props) => {
let { t } = useTranslation(); let { t } = useTranslation();
const [confirmSections, setConfirmSections] = useState(false); const [confirmSections, setConfirmSections] = useState(false);
const [downloadQuestionnaire, setDownloadQuestionnaire] = useState(false);
const [downloadInProgress, setDownloadInProgress] = useState(false);
const router = useRouter(); const router = useRouter();
const { locale } = router; const { locale } = router;
@@ -45,11 +41,7 @@ const RepCompleteSubmit = (props) => {
questionnaireCount, questionnaireCount,
finaliseAppealProcess, finaliseAppealProcess,
setCurrentReference, setCurrentReference,
docsOffline
} = props; } = props;
let ShowDocLinks = getDocLink(docsOffline);
const { acceptedFiles, getRootProps, getInputProps } = useDropzone(); const { acceptedFiles, getRootProps, getInputProps } = useDropzone();
const files = acceptedFiles.map((file) => ( const files = acceptedFiles.map((file) => (
<li key={file.path}> <li key={file.path}>
@@ -61,13 +53,6 @@ const RepCompleteSubmit = (props) => {
repFormData = updateLinks(repFormData); 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(); //const repDate = new Date();
// let day = repDate.getDate(); // let day = repDate.getDate();
@@ -179,7 +164,7 @@ const RepCompleteSubmit = (props) => {
typeof filesUploadObj[key].name != "undefined" && typeof filesUploadObj[key].name != "undefined" &&
buildAppealFilesArray.push({ buildAppealFilesArray.push({
"name": filesUploadObj[key].name, "name": filesUploadObj[key].name,
"size": filesUploadObj[key].contentLength "size": filesUploadObj[key].contentLength,
}); });
} }
@@ -195,7 +180,7 @@ const RepCompleteSubmit = (props) => {
// : []; // : [];
let arrUniq = [ 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) { buildAppealFilesArray = buildAppealFilesArray.filter(function (el) {
@@ -227,104 +212,40 @@ const RepCompleteSubmit = (props) => {
arrUniq = removeEmptyObjects(arrUniq); arrUniq = removeEmptyObjects(arrUniq);
Object.assign(formObj.representationForm.values, { Object.assign(formObj.representationForm.values, {
"filesList": arrUniq "filesList": arrUniq,
}); });
let filterFiles = []; let filterFiles = [];
function showRepsEnded(endDate) { function showRepsEnded(endDate) {
if (!endDate) { let date = new Date();
return false; date = new Date(date.toDateString());
} let end = new Date(endDate);
end.setUTCHours(23);
end.setUTCMinutes(59);
end.setUTCSeconds(59);
end.toISOString();
const end = new Date(endDate); return end > date ? false : true;
if (Number.isNaN(end.getTime())) {
return false;
}
const today = new Date();
today.setHours(0, 0, 0, 0);
end.setHours(23, 59, 59, 999);
return end <= today;
} }
const checkRepDatePassed = () => { const checkRepDatePassed = () => {
if (repFormData.representationType === "Questionnaire") { if (repFormData.representationType == "Questionnaire") {
return false; return false;
} else {
if (repFormData.representationType == "Final comments") {
return repFormData.hasOwnProperty(
"pinswg_finalcommentsduedate"
) && showRepsEnded(repFormData.pinswg_finalcommentsduedate)
? true
: false;
} }
if (repFormData.representationType == "Statement") {
if (repFormData.representationType === "Final comments") { return repFormData.hasOwnProperty("pinswg_statementduedate") &&
return showRepsEnded(repFormData.pinswg_finalcommentsduedate); showRepsEnded(repFormData.pinswg_statementduedate)
? true
: false;
} }
if (repFormData.representationType === "Statement") {
return (
showRepsEnded(repFormData.pinswg_statementduedate) ||
showRepsEnded(repFormData.pinswg_endofrepresentationperiod)
);
}
return false;
};
const triggerQuestionnaireDownload = async () => {
if (
repFormData.representationType !== "Questionnaire" ||
!downloadQuestionnaire
) {
return;
}
if (downloadInProgress) {
return;
}
try {
setDownloadInProgress(true);
const containerID =
props.accountDetails?.containerID ||
props.props?.accountDetails?.containerID ||
props.props?.props?.accountDetails?.containerID;
const caseRef =
currentView?.caseReference?.ticketnumber ||
repFormData?.caseRef ||
repFormData?.ticketnumber;
if (!containerID || !caseRef) {
console.error(
"Questionnaire download skipped: missing containerID or case reference",
{ containerID, caseRef }
);
return;
}
repFormData.locale = router.locale == "cy" ? "cy" : "en";
const pdfBlob = await generateRepPDF(
repFormData,
containerID,
caseRef,
{ download: true }
);
if (pdfBlob) {
const blobUrl = window.URL.createObjectURL(pdfBlob);
const anchor = document.createElement("a");
anchor.href = blobUrl;
anchor.download = `${repFormData.repfile_name || "questionnaire"}.pdf`;
document.body.appendChild(anchor);
anchor.click();
anchor.remove();
window.URL.revokeObjectURL(blobUrl);
}
} catch (error) {
console.error("Questionnaire download failed", error);
} finally {
setDownloadInProgress(false);
} }
}; };
@@ -343,31 +264,19 @@ const RepCompleteSubmit = (props) => {
<div className="govuk-grid-row govuk-body"> <div className="govuk-grid-row govuk-body">
<h1 className="govuk-heading-m "> <h1 className="govuk-heading-m ">
{" "} {" "}
{repFormData.appealType == 846040002 {t(
? t(
"myrepresentations:consultation-check-submit-heading"
)
: t(
"myrepresentations:rep-check-submit-heading" "myrepresentations:rep-check-submit-heading"
)} )}
</h1> </h1>
<dl className="govuk-summary-list "> <dl className="govuk-summary-list ">
<h2 className="govuk-heading-m govuk-!-margin-top-9"> <h2 className="govuk-heading-m govuk-!-margin-top-9">
{repFormData.appealType == 846040002 {t(
? t(
"myrepresentations:consultation-check-your-rep-heading"
)
: t(
"myrepresentations:rep-check-your-rep-heading" "myrepresentations:rep-check-your-rep-heading"
)} )}
</h2> </h2>
<div className="govuk-summary-list__row"> <div className="govuk-summary-list__row">
<dt className="govuk-summary-list__key"> <dt className="govuk-summary-list__key">
{repFormData.appealType == 846040002 {t(
? t(
"case:consultation-representation-type"
)
: t(
"case:representation-representation-type" "case:representation-representation-type"
)} )}
</dt> </dt>
@@ -405,7 +314,7 @@ const RepCompleteSubmit = (props) => {
</a> */} </a> */}
</dd> </dd>
</div> </div>
{hasOwn( {_.has(
repFormData, repFormData,
"representationOnBehalfOf" "representationOnBehalfOf"
) && ( ) && (
@@ -419,7 +328,7 @@ const RepCompleteSubmit = (props) => {
<dd className="govuk-summary-list__value"> <dd className="govuk-summary-list__value">
{ {
representationOnBehalfOfDisplay repFormData.representationOnBehalfOf
} }
</dd> </dd>
@@ -441,7 +350,7 @@ const RepCompleteSubmit = (props) => {
"appealType": "appealType":
repFormData.appealType, repFormData.appealType,
"repDetails": "repDetails":
repFormData repFormData,
}); });
setRepresentationSubmit( setRepresentationSubmit(
false false
@@ -494,7 +403,7 @@ const RepCompleteSubmit = (props) => {
"appealType": "appealType":
repFormData.appealType, repFormData.appealType,
"repDetails": "repDetails":
repFormData repFormData,
} }
); );
setRepresentationSubmit( setRepresentationSubmit(
@@ -518,20 +427,17 @@ const RepCompleteSubmit = (props) => {
</> </>
)} )}
{repFormData.representationType != {repFormData.representationType !=
"Questionnaire" && "Questionnaire" && (
repFormData.appealType != 846040002 && (
<div className="govuk-summary-list__row"> <div className="govuk-summary-list__row">
<dt className="govuk-summary-list__key"> <dt className="govuk-summary-list__key">
{t( {t("case:representation-comments")}
"case:representation-comments"
)}
</dt> </dt>
<dd className="govuk-summary-list__value"> <dd className="govuk-summary-list__value">
<span <span
className="multiline-elipsis" className="multiline-elipsis"
dangerouslySetInnerHTML={{ dangerouslySetInnerHTML={{
__html: repFormData.representationComments __html: repFormData.representationComments,
}} }}
/> />
</dd> </dd>
@@ -555,16 +461,14 @@ const RepCompleteSubmit = (props) => {
"appealType": "appealType":
repFormData.appealType, repFormData.appealType,
"repDetails": "repDetails":
repFormData repFormData,
}); });
setRepresentationSubmit( setRepresentationSubmit(
false false
); );
}} }}
> >
{t( {t("common:change-link-label")}
"common:change-link-label"
)}
<span className="govuk-visually-hidden"> <span className="govuk-visually-hidden">
{" "} {" "}
{/* {FieldsTranslations( {/* {FieldsTranslations(
@@ -635,7 +539,7 @@ const RepCompleteSubmit = (props) => {
"appealType": "appealType":
repFormData.appealType, repFormData.appealType,
"repDetails": "repDetails":
repFormData repFormData,
}), }),
setRepresentationSubmit( setRepresentationSubmit(
false false
@@ -682,8 +586,6 @@ const RepCompleteSubmit = (props) => {
"myrepresentations:rep-check-tandc-para-three" "myrepresentations:rep-check-tandc-para-three"
)} )}
</p> </p>
<p></p>
{checkRepDatePassed() ? ( {checkRepDatePassed() ? (
<div className="govuk-warning-text noticebanner"> <div className="govuk-warning-text noticebanner">
<strong className="govuk-warning-text__text"> <strong className="govuk-warning-text__text">
@@ -722,63 +624,8 @@ const RepCompleteSubmit = (props) => {
{t("myrepresentations:rep-wait-label")} {t("myrepresentations:rep-wait-label")}
</p> </p>
</div> </div>
) : ShowDocLinks ? (
<>
{" "}
<div className="govuk-warning-text ">
<span
className="govuk-warning-text__icon"
aria-hidden="true"
>
!
</span>
<strong className="govuk-warning-text__text govuk-!-margin-top-2">
<span className="govuk-visually-hidden">
Notice
</span>
{t(
"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-form-group">
<div className="govuk-checkboxes govuk-checkboxes--small"> <div className="govuk-checkboxes govuk-checkboxes--small">
<div className="govuk-checkboxes__item"> <div className="govuk-checkboxes__item">
@@ -817,11 +664,10 @@ const RepCompleteSubmit = (props) => {
type="submit" type="submit"
className="govuk-button" className="govuk-button"
data-module="govuk-button" data-module="govuk-button"
onClick={async () => { onClick={() => {
// setRepresentationSubmitConfirmation( // setRepresentationSubmitConfirmation(
// true // true
// ); // );
await triggerQuestionnaireDownload();
setRepresentationSubmit( setRepresentationSubmit(
true true
); );
@@ -858,7 +704,7 @@ const mapStateToProps = (state) => {
currentView: state.currentView, currentView: state.currentView,
myRepresentations: state.myRepresentations, myRepresentations: state.myRepresentations,
initialValues: state.currentView.caseReference.repDetails, initialValues: state.currentView.caseReference.repDetails,
accountDetails: state.accountDetails accountDetails: state.accountDetails,
//form: state.form, //form: state.form,
}; };
}; };
@@ -867,7 +713,7 @@ const mapDispatchToProps = (dispatch) => {
return { return {
setCurrentReference: (currentReference) => { setCurrentReference: (currentReference) => {
dispatch(setCurrentReference(currentReference)); dispatch(setCurrentReference(currentReference));
} },
}; };
}; };
@@ -1,7 +1,6 @@
import { JSONPath as jsonpath } from "jsonpath-plus"; import { JSONPath as jsonpath } from "jsonpath-plus";
import useTranslation from "next-translate/useTranslation"; import useTranslation from "next-translate/useTranslation";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
import { hasOwn } from "../../utils";
const RepDetails = (props) => { const RepDetails = (props) => {
let { t } = useTranslation(); let { t } = useTranslation();
@@ -9,7 +8,7 @@ const RepDetails = (props) => {
const router = useRouter(); const router = useRouter();
const { locale } = router; const { locale } = router;
const { currentType, casesObj, appealType } = props; const { currentType, casesObj } = props;
let { caseReference, ticketnumber } = props; let { caseReference, ticketnumber } = props;
@@ -32,7 +31,7 @@ const RepDetails = (props) => {
detailsObj = jsonpath({ detailsObj = jsonpath({
path: '$..[?(@ && @.ticketnumber=="' + ticketnumber + '")]', path: '$..[?(@ && @.ticketnumber=="' + ticketnumber + '")]',
json: setCaseDetailsObj, json: setCaseDetailsObj,
eval: true eval: true,
}); });
detailsObj = detailsObj[0]; detailsObj = detailsObj[0];
@@ -62,43 +61,34 @@ const RepDetails = (props) => {
{t("case:summary-site-address-label")} {t("case:summary-site-address-label")}
</dt> </dt>
<dd className="govuk-summary-list__value"> <dd className="govuk-summary-list__value">
{hasOwn(detailsObj, "pinswg_siteaddressline1") {_.has(detailsObj, "pinswg_siteaddressline1")
? detailsObj.pinswg_siteaddressline1 ? detailsObj.pinswg_siteaddressline1
: ""} : ""}
{hasOwn( {_.has(detailsObj, "pinswg_siteaddressline1") &&
detailsObj,
"pinswg_siteaddressline1"
) &&
detailsObj.pinswg_siteaddressline1 != detailsObj.pinswg_siteaddressline1 !=
null && <br />} null && <br />}
{hasOwn(detailsObj, "pinswg_siteaddressline2") {_.has(detailsObj, "pinswg_siteaddressline2")
? detailsObj.pinswg_siteaddressline2 ? detailsObj.pinswg_siteaddressline2
: ""} : ""}
{hasOwn( {_.has(detailsObj, "pinswg_siteaddressline2") &&
detailsObj,
"pinswg_siteaddressline2"
) &&
detailsObj.pinswg_siteaddressline2 != detailsObj.pinswg_siteaddressline2 !=
null && <br />} null && <br />}
{hasOwn(detailsObj, "pinswg_siteaddresstown") {_.has(detailsObj, "pinswg_siteaddresstown")
? detailsObj.pinswg_siteaddresstown ? detailsObj.pinswg_siteaddresstown
: ""} : ""}
{hasOwn(detailsObj, "pinswg_siteaddresstown") && {_.has(detailsObj, "pinswg_siteaddresstown") &&
detailsObj.pinswg_siteaddresstown != detailsObj.pinswg_siteaddresstown !=
null && <br />} null && <br />}
{hasOwn(detailsObj, "pinswg_siteaddresscounty") {_.has(detailsObj, "pinswg_siteaddresscounty")
? detailsObj.pinswg_siteaddresscounty ? detailsObj.pinswg_siteaddresscounty
: ""} : ""}
{hasOwn( {_.has(
detailsObj, detailsObj,
"pinswg_siteaddresscounty" "pinswg_siteaddresscounty"
) && ) &&
detailsObj.pinswg_siteaddresscounty != detailsObj.pinswg_siteaddresscounty !=
null && <br />} null && <br />}
{hasOwn( {_.has(detailsObj, "pinswg_siteaddresspostcode")
detailsObj,
"pinswg_siteaddresspostcode"
)
? detailsObj.pinswg_siteaddresspostcode ? detailsObj.pinswg_siteaddresspostcode
: ""} : ""}
</dd> </dd>
@@ -107,14 +97,10 @@ const RepDetails = (props) => {
</div> </div>
<div className="govuk-grid-row"> <div className="govuk-grid-row">
<p className="govuk-body"> <p className="govuk-body">
{appealType == 846040002 {t("myrepresentations:capacity-para-one")}
? t("myrepresentations:sips-capacity-para-one")
: t("myrepresentations:capacity-para-one")}
</p> </p>
<p className="govuk-body"> <p className="govuk-body">
{appealType == 846040002 {t("myrepresentations:capacity-para-two")}
? t("myrepresentations:sips-capacity-para-two")
: t("myrepresentations:capacity-para-two")}
</p> </p>
</div> </div>
</div> </div>
@@ -13,8 +13,8 @@ import {
deleteBlob, deleteBlob,
deleteRepBlob, deleteRepBlob,
getFilesFromBlobHashed, getFilesFromBlobHashed,
getFilesFromBlobproxy getFilesFromBlobproxy,
} from "../../../actions/services/documentService"; } from "../../../actions";
const LoadingMessage = () => <div>Loading the editor...</div>; const LoadingMessage = () => <div>Loading the editor...</div>;
@@ -23,7 +23,7 @@ const ReactQuill = dynamic(
() => import("react-quill-new").then((mod) => mod.default), () => import("react-quill-new").then((mod) => mod.default),
{ {
ssr: false, 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 import { useDispatch } from "react-redux"; // Import the useDispatch hook
@@ -35,13 +35,13 @@ import {
parseISO, parseISO,
subDays, subDays,
subMonths, subMonths,
subYears subYears,
} from "date-fns"; } from "date-fns";
import { import {
bytesToSize, bytesToSize,
getThumbnailIconByExtension, getThumbnailIconByExtension,
updateLinks updateLinks,
} from "../../utils"; } from "../../utils";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
@@ -258,26 +258,6 @@ export const RenderCondtionalRadioList = ({
}) => { }) => {
const required = (value) => (value ? undefined : "Required"); const required = (value) => (value ? undefined : "Required");
let { t } = useTranslation(); 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 ( return (
<> <>
<div <div
@@ -324,16 +304,8 @@ export const RenderCondtionalRadioList = ({
{custom.hint} {custom.hint}
</div> </div>
<div className="govuk-radios"> <div className="govuk-radios">
{Object.keys(options).map((key, index) => { {Object.keys(options).map((key, index) => (
const normalizedOptionValue = normalizeYesNo( <div key={key} className="govuk-!-margin-bottom-3">
options[key]
);
return (
<div
key={key}
className="govuk-!-margin-bottom-3"
>
<div <div
className="govuk-radios__item" className="govuk-radios__item"
data-children-count={key} data-children-count={key}
@@ -345,7 +317,7 @@ export const RenderCondtionalRadioList = ({
component="input" component="input"
type="radio" type="radio"
className="govuk-radios__input" className="govuk-radios__input"
value={normalizedOptionValue} value={options[key]}
validate={[required]} validate={[required]}
/> />
<label <label
@@ -361,8 +333,7 @@ export const RenderCondtionalRadioList = ({
)} )}
</label> </label>
</div> </div>
{isYesSelected && {value == "Yes" && options[key] == "Yes" && (
normalizedOptionValue === "Yes" && (
<div <div
className="govuk-radios__conditional " className="govuk-radios__conditional "
id={"conditional-" + id} id={"conditional-" + id}
@@ -373,9 +344,7 @@ export const RenderCondtionalRadioList = ({
> >
<label <label
className="govuk-label" className="govuk-label"
htmlFor={ htmlFor={id + "_details"}
id + "_details"
}
> >
{t( {t(
"myrepresentations:representation-onbehalfof-label" "myrepresentations:representation-onbehalfof-label"
@@ -385,13 +354,9 @@ export const RenderCondtionalRadioList = ({
className="govuk-input govuk-!-width-one-half" className="govuk-input govuk-!-width-one-half"
id={id + "_details"} id={id + "_details"}
name={id + "_details"} name={id + "_details"}
component={ component={RenderTextfield}
RenderTextfield
}
type="text" type="text"
validate={[ validate={[required]}
requiredIfYes
]}
errorMsg={t( errorMsg={t(
"myrepresentations:is-required-label" "myrepresentations:is-required-label"
)} )}
@@ -400,8 +365,7 @@ export const RenderCondtionalRadioList = ({
</div> </div>
)} )}
</div> </div>
); ))}
})}
</div> </div>
</fieldset> </fieldset>
</div> </div>
@@ -582,8 +546,7 @@ export const RenderPickList = ({
? "Sylwadau ysgrifenedig" ? "Sylwadau ysgrifenedig"
: optionsArr[key] == "Inquiry" : optionsArr[key] == "Inquiry"
? "Ymchwiliad" ? "Ymchwiliad"
: optionsArr[key] == : optionsArr[key] == "Hearing"
"Hearing"
? "Gwrandawiad" ? "Gwrandawiad"
: optionsArr[key] : optionsArr[key]
: optionsArr[key]} : optionsArr[key]}
@@ -771,19 +734,13 @@ export const RenderMultiline = ({
input.onChange(valStr); input.onChange(valStr);
}; };
const handleBlur = () => {
const updated = updateLinks(editValue);
setEditValue(updated);
input.onChange(updated);
};
var modules = { var modules = {
toolbar: [ toolbar: [
[{ "header": [1, 2, false] }], [{ "header": [1, 2, false] }],
["bold", "italic", "underline", "blockquote"], ["bold", "italic", "underline", "blockquote"],
[{ "list": "ordered" }, { "list": "bullet" }], [{ "list": "ordered" }, { "list": "bullet" }],
["clean"] ["clean"],
] ],
}; };
return ( return (
@@ -807,7 +764,6 @@ export const RenderMultiline = ({
theme="snow" theme="snow"
value={editValue} value={editValue}
onChange={changeEdit} onChange={changeEdit}
onBlur={handleBlur}
/> />
<textarea <textarea
{...input} {...input}
@@ -839,23 +795,18 @@ export const RenderRichMultiline = ({
); );
const changeEdit = (valStr) => { const changeEdit = (valStr) => {
valStr = updateLinks(valStr);
setEditValue(valStr); setEditValue(valStr);
input.onChange(valStr); input.onChange(valStr);
}; };
const handleBlur = () => {
const updated = updateLinks(editValue);
setEditValue(updated);
input.onChange(updated);
};
var modules = { var modules = {
toolbar: [ toolbar: [
[{ "header": [1, 2, false] }], [{ "header": [1, 2, false] }],
["bold", "italic", "underline", "blockquote"], ["bold", "italic", "underline", "blockquote"],
[{ "list": "ordered" }, { "list": "bullet" }], [{ "list": "ordered" }, { "list": "bullet" }],
["clean"] ["clean"],
] ],
}; };
return ( return (
@@ -868,7 +819,6 @@ export const RenderRichMultiline = ({
theme="snow" theme="snow"
value={editValue} value={editValue}
onChange={changeEdit} onChange={changeEdit}
onBlur={handleBlur}
/> />
<textarea <textarea
{...input} {...input}
@@ -924,19 +874,19 @@ const baseStyle = {
borderStyle: "dashed", borderStyle: "dashed",
backgroundColor: "#fafafa", backgroundColor: "#fafafa",
color: "#bdbdbd", color: "#bdbdbd",
transition: "border .3s ease-in-out" transition: "border .3s ease-in-out",
}; };
const activeStyle = { const activeStyle = {
borderColor: "#2196f3" borderColor: "#2196f3",
}; };
const acceptStyle = { const acceptStyle = {
borderColor: "#00e676" borderColor: "#00e676",
}; };
const rejectStyle = { const rejectStyle = {
borderColor: "#ff1744" borderColor: "#ff1744",
}; };
export const RenderFileUpload = (field) => { export const RenderFileUpload = (field) => {
@@ -947,7 +897,7 @@ export const RenderFileUpload = (field) => {
const style = useMemo( const style = useMemo(
() => ({ () => ({
...baseStyle ...baseStyle,
// ...(isDragActive ? activeStyle : {}), // ...(isDragActive ? activeStyle : {}),
// ...(isDragAccept ? acceptStyle : {}), // ...(isDragAccept ? acceptStyle : {}),
// ...(isDragReject ? rejectStyle : {}), // ...(isDragReject ? rejectStyle : {}),
@@ -1043,7 +993,7 @@ export const RenderFileUpload = (field) => {
typeof filesUploadObj[key].name != "undefined" && typeof filesUploadObj[key].name != "undefined" &&
buildAppealFilesArray.push({ buildAppealFilesArray.push({
"name": filesUploadObj[key].name, "name": filesUploadObj[key].name,
"size": filesUploadObj[key].size "size": filesUploadObj[key].size,
}); });
} }
@@ -1092,12 +1042,9 @@ export const RenderFileUpload = (field) => {
}); });
}; };
const [errorMessage, setErrorMessage] = useState(null);
const [rejectedFiles, setRejectedFiles] = useState([]); // Store rejected files const [rejectedFiles, setRejectedFiles] = useState([]); // Store rejected files
const [completedUploadFiles, setCompletedUploadFiles] = useState(false); const [completedUploadFiles, setCompletedUploadFiles] = useState(false);
const [uploadCountMessage, setUploadCountMessage] = useState(""); const [uploadCountMessage, setUploadCountMessage] = useState("");
const [totalUploadFiles, setTotalUploadFiles] = useState(0);
const handleDropRejected = (fileRejections) => { const handleDropRejected = (fileRejections) => {
const errors = fileRejections const errors = fileRejections
@@ -1113,15 +1060,6 @@ export const RenderFileUpload = (field) => {
"myrepresentations:fileupload-file-error-invalid-type-label" "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( return `${file.name} ${t(
"myrepresentations:fileupload-file-error-invalid-label" "myrepresentations:fileupload-file-error-invalid-label"
)}`; )}`;
@@ -1138,44 +1076,6 @@ export const RenderFileUpload = (field) => {
setRejectedFiles([]); // Clear any previously rejected file errorsss 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 ( return (
<> <>
<Dropzone <Dropzone
@@ -1189,30 +1089,11 @@ export const RenderFileUpload = (field) => {
"image/jpeg": [".jpg", ".jpeg"], "image/jpeg": [".jpg", ".jpeg"],
"image/png": [".png"], "image/png": [".png"],
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet":
[".xlsx"] [".xlsx"],
}} }}
validator={(file) => validateFilename(file, t)} onDrop={(filesToUpload, e) => {
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); setCompletedUploadFiles(false);
const renamedAcceptedFiles = filesToUpload.map(
const renamedAcceptedFiles = acceptedFiles.map(
(file) => (file) =>
new File( new File(
[file], [file],
@@ -1230,22 +1111,12 @@ export const RenderFileUpload = (field) => {
.values.repfile_name .values.repfile_name
}_-_Attachment_-_${file.name}`, }_-_Attachment_-_${file.name}`,
{ {
type: file.type type: file.type,
} }
) )
); );
field.input.onChange(renamedAcceptedFiles); 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( uploadSingleFile(
renamedAcceptedFiles, renamedAcceptedFiles,
@@ -1253,12 +1124,7 @@ export const RenderFileUpload = (field) => {
field.ticketnumber + field.ticketnumber +
"/" + "/" +
field.filenamePrefix.representationForm.values field.filenamePrefix.representationForm.values
.repfile_name, .repfile_name
{
onChunkComplete: ({ cumulativeUploaded }) => {
setUploadCountMessage(cumulativeUploaded);
}
}
).then((data) => { ).then((data) => {
console.log(data); console.log(data);
let buildAppealFilesArray = []; let buildAppealFilesArray = [];
@@ -1269,7 +1135,7 @@ export const RenderFileUpload = (field) => {
typeof filesUploadObj[key].name != "undefined" && typeof filesUploadObj[key].name != "undefined" &&
buildAppealFilesArray.push({ buildAppealFilesArray.push({
"name": filesUploadObj[key].name, "name": filesUploadObj[key].name,
"size": filesUploadObj[key].size "size": filesUploadObj[key].size,
}); });
} }
@@ -1330,6 +1196,8 @@ export const RenderFileUpload = (field) => {
}); });
}); });
}} }}
onDropRejected={handleDropRejected}
onDropAccepted={handleDropAccepted}
> >
{({ getRootProps, getInputProps }) => ( {({ getRootProps, getInputProps }) => (
<> <>
@@ -1356,7 +1224,7 @@ export const RenderFileUpload = (field) => {
</> </>
)} )}
</Dropzone> </Dropzone>
{rejectedFiles.length > 0 && ( {rejectedFiles.length > 0 && completedUploadFiles == true && (
<div <div
style={{ color: "red", marginTop: "10px" }} style={{ color: "red", marginTop: "10px" }}
className="govuk-body govuk-!-font-size-14 " className="govuk-body govuk-!-font-size-14 "
@@ -1368,20 +1236,17 @@ export const RenderFileUpload = (field) => {
</ul> </ul>
</div> </div>
)} )}
{totalUploadFiles > 0 && completedUploadFiles == false && ( {uploadCountMessage > 0 && completedUploadFiles == false && (
<div className="govuk-body govuk-!-font-size-14"> <div className="govuk-body govuk-!-font-size-14">
{t("home:uploading-files-label", { {t("home:uploading-files-label", {
number: number: uploadCountMessage,
totalUploadFiles > 0
? `${uploadCountMessage} of ${totalUploadFiles}`
: uploadCountMessage
})} })}
</div> </div>
)} )}
{completedUploadFiles > 0 && uploadCountMessage >= 0 && ( {completedUploadFiles > 0 && uploadCountMessage >= 0 && (
<div className="govuk-body govuk-!-font-size-14"> <div className="govuk-body govuk-!-font-size-14">
{t("home:completed-uploading-files-label", { {t("home:completed-uploading-files-label", {
number: uploadCountMessage number: uploadCountMessage,
})} })}
</div> </div>
)} )}
@@ -1520,12 +1385,6 @@ export function FileUploadField(props) {
); );
} }
export const shouldDisableButton = ({ props, formObj }) =>
!(
props?.currentView?.fileList?.length > 0 ||
typeof formObj?.representationForm?.values?.representationComments !==
"undefined"
);
// export const RepresentationGuidanceText = (appealType) => { // export const RepresentationGuidanceText = (appealType) => {
// let { t } = useTranslation(); // let { t } = useTranslation();
@@ -2,23 +2,21 @@ import useTranslation from "next-translate/useTranslation";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
import { connect } from "react-redux"; import { connect } from "react-redux";
import { Field, change, reduxForm } from "redux-form"; import { Field, change, reduxForm } from "redux-form";
import { useEffect, useState } from "react"; import { useState } from "react";
import { bytesToSize, getThumbnailIconByExtension } from "../../utils"; import { bytesToSize, getThumbnailIconByExtension } from "../../utils";
import { import {
FileUploadField, FileUploadField,
RenderCondtionalRadioList, RenderCondtionalRadioList,
RenderPickList,
RenderRichMultiline, RenderRichMultiline,
shouldDisableButton
} from "./representationElements"; } from "./representationElements";
import RepresentationActionButtons from "./elements/RepresentationActionButtons";
import RepresentationTypeSelectorBlock from "./elements/RepresentationTypeSelectorBlock";
import { useDropzone } from "react-dropzone"; import { useDropzone } from "react-dropzone";
import { import {
setRepresentationCapacity, setRepresentationCapacity,
setRepresentationSubmit, setRepresentationSubmit,
setFilesForRepresentations setFilesForRepresentations,
} from "../../../store/currentView/action"; } from "../../../store/currentView/action";
const RepInterestedPartyPerson = (props) => { const RepInterestedPartyPerson = (props) => {
@@ -36,25 +34,11 @@ const RepInterestedPartyPerson = (props) => {
setSavingStatus, setSavingStatus,
savingStatus, savingStatus,
setFilesForRepresentations, setFilesForRepresentations,
onRepresentationTypeChange,
onTypeSelectionConfirmed
} = props; } = props;
const required = (value) => (value ? undefined : "Required"); const required = (value) => (value ? undefined : "Required");
const { acceptedFiles, getRootProps, getInputProps } = useDropzone(); 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) != "{}") { if (JSON.stringify(formObj) != "{}") {
setRepFileName(formObj.representationForm.values); setRepFileName(formObj.representationForm.values);
@@ -77,52 +61,65 @@ const RepInterestedPartyPerson = (props) => {
{file.path} - {file.size} bytes {file.path} - {file.size} bytes
</li> </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 ( return (
<> <>
<RepresentationTypeSelectorBlock <div className="govuk-grid-row">
t={t} <div className="govuk-form-group">
headingText={t( {typeof formObj.representationForm.values
.representationType == "undefined" &&
props.representationType != "Select..." ? (
<>
<h2 className="govuk-heading-m ">
{t(
"myrepresentations:representation-from-an-interested-person-heading" "myrepresentations:representation-from-an-interested-person-heading"
)} )}
kindLabelText={t("myrepresentations:kind-of-rep-label")} </h2>
isTypeSelected={isTypeConfirmed}
selectedTypeDisplay={selectedRepresentationTypeDisplay} <label
representationType={selectedRepresentationType} className="govuk-label govuk-body-m"
setTypeSelectionConfirmed={setTypeSelectionConfirmed} htmlFor="representationType"
onRepresentationTypeChange={onRepresentationTypeChange} >
onTypeSelectionConfirmed={onTypeSelectionConfirmed} {t("myrepresentations:kind-of-rep-label")}
optionsArr={interestedPersonRepresentationArr} </label>
<Field
name="representationType"
component={RenderPickList}
datafieldname="representationType"
validate={[required]} validate={[required]}
errorMsg={t("myrepresentations:select-an-option-label")} optionsArr={
interestedPersonRepresentationArr
}
errorMsg={t(
"myrepresentations:select-an-option-label"
)}
/> />
{isTypeConfirmed && ( </>
) : (
<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") && (
<> <>
<div className="govuk-grid-row"> <div className="govuk-grid-row">
<div className="govuk-form-group"> <div className="govuk-form-group">
@@ -130,7 +127,12 @@ const RepInterestedPartyPerson = (props) => {
name="representationOnBehalfOf" name="representationOnBehalfOf"
datafieldname="representationOnBehalfOf" datafieldname="representationOnBehalfOf"
// label="In what capacity do you wish to make representations on this case?" // label="In what capacity do you wish to make representations on this case?"
options={["Yes", "No"]} options={[
t(
"myrepresentations:questionnaire-yes"
),
t("myrepresentations:questionnaire-no"),
]}
id="representationOnBehalfOf" id="representationOnBehalfOf"
className="govuk-radios__input" className="govuk-radios__input"
errorMsg={t( errorMsg={t(
@@ -229,17 +231,78 @@ const RepInterestedPartyPerson = (props) => {
</div> </div>
</> </>
)} )}
{isTypeConfirmed && ( {typeof formObj.representationForm.values.representationType !=
<RepresentationActionButtons "undefined" && (
t={t} <div className="govuk-grid-row">
locale={router.locale} <div className="govuk-button-group">
isSaving={savingStatus} <button
isContinueDisabled={shouldDisableButton({ type="submit"
props, className="govuk-button"
formObj data-module="govuk-button"
})} >
onSaveExit={handleSaveExit} {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>
)} )}
</> </>
); );
@@ -253,7 +316,7 @@ const mapDispatchToProps = (dispatch) => ({
dispatch(change(form, field, newValue)), dispatch(change(form, field, newValue)),
setFilesForRepresentations: (fileList) => { setFilesForRepresentations: (fileList) => {
dispatch(setFilesForRepresentations(fileList)); dispatch(setFilesForRepresentations(fileList));
} },
}); });
export default connect( export default connect(
@@ -263,6 +326,6 @@ export default connect(
reduxForm({ reduxForm({
form: "representationForm", form: "representationForm",
enableReinitialize: true, enableReinitialize: true,
destroyOnUnmount: false destroyOnUnmount: false,
})(RepInterestedPartyPerson) })(RepInterestedPartyPerson)
); );
@@ -10,9 +10,8 @@ import { useState, useEffect } from "react";
import { import {
FileUploadField, FileUploadField,
RenderMultiline, RenderMultiline,
shouldDisableButton RenderPickList,
} from "./representationElements"; } from "./representationElements";
import RepresentationTypeSelectorBlock from "./elements/RepresentationTypeSelectorBlock";
import RepresentationProgress_enforcement from "./representationProgress/representationProgress_enforcement"; import RepresentationProgress_enforcement from "./representationProgress/representationProgress_enforcement";
import RepresentationProgress_s78 from "./representationProgress/representationProgress_s78"; import RepresentationProgress_s78 from "./representationProgress/representationProgress_s78";
import Enforcement_Questionnaire from "./representationQuestionnaires/representationLPAQuestionnaire_enforcement"; import Enforcement_Questionnaire from "./representationQuestionnaires/representationLPAQuestionnaire_enforcement";
@@ -23,7 +22,7 @@ import {
setRepresentationSubmit, setRepresentationSubmit,
setFilesForRepresentations, setFilesForRepresentations,
setCurrentPage, setCurrentPage,
setCurrentReference setCurrentReference,
} from "../../../store/currentView/action"; } from "../../../store/currentView/action";
let RepLPA = (props) => { let RepLPA = (props) => {
@@ -49,8 +48,6 @@ let RepLPA = (props) => {
setSavingStatus, setSavingStatus,
savingStatus, savingStatus,
setFilesForRepresentations, setFilesForRepresentations,
onRepresentationTypeChange,
onTypeSelectionConfirmed
} = props; } = props;
const { acceptedFiles, getRootProps, getInputProps } = useDropzone(); const { acceptedFiles, getRootProps, getInputProps } = useDropzone();
@@ -61,36 +58,6 @@ let RepLPA = (props) => {
)); ));
const required = (value) => (value ? undefined : "Required"); 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 = () => { const whichQuestionnaire = () => {
{ {
switch (currentView.caseReference.appealType) { switch (currentView.caseReference.appealType) {
@@ -215,7 +182,7 @@ let RepLPA = (props) => {
currentView.caseReference.currentReference + currentView.caseReference.currentReference +
'")]', '")]',
json: setCaseDetailsObj, json: setCaseDetailsObj,
eval: true eval: true,
}); });
let setCaseResultssObj = router.query.hasOwnProperty("state") let setCaseResultssObj = router.query.hasOwnProperty("state")
@@ -234,7 +201,7 @@ let RepLPA = (props) => {
currentView.caseReference.currentReference + currentView.caseReference.currentReference +
'")]', '")]',
json: setCaseResultssObj, json: setCaseResultssObj,
eval: true eval: true,
}); });
resultsObj = resultsObj[0]; resultsObj = resultsObj[0];
@@ -257,26 +224,62 @@ let RepLPA = (props) => {
return ( 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-grid-row">
<div className="govuk-form-group"> <div className="govuk-form-group">
{isTypeConfirmed && {!_.has(
(selectedRepresentationType != "Questionnaire" ? ( 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..." ? (
<> <>
<p className="govuk-body"> <p className="govuk-body">
{t("myrepresentations:enter-comment-label")} {t("myrepresentations:enter-comment-label")}
@@ -350,8 +353,7 @@ let RepLPA = (props) => {
"myrepresentations:add-files-label" "myrepresentations:add-files-label"
)} )}
ticketnumber={ ticketnumber={
props.currentView.caseReference props.currentView.caseReference.ticketnumber
.ticketnumber
} }
hint={"sdsd"} hint={"sdsd"}
fileList={ fileList={
@@ -398,8 +400,9 @@ let RepLPA = (props) => {
</div> </div>
<div className="govuk-grid-row"> <div className="govuk-grid-row">
<div className="govuk-button-group"> <div className="govuk-button-group">
{isTypeConfirmed && {(typeof props.representationType != "undefined" ||
selectedRepresentationType == "Questionnaire" && ( _.has(formObj, "values", "representationType")) &&
props.representationType == "Questionnaire" && (
<> <>
{showQuestionnaireSection < {showQuestionnaireSection <
questionnaireCount && ( questionnaireCount && (
@@ -439,14 +442,14 @@ let RepLPA = (props) => {
// top: 0, // top: 0,
// behavior: "smooth", // behavior: "smooth",
// }); // });
(setRepFileName( setRepFileName(
props.formObj[ props.formObj[
"representationForm" "representationForm"
].values ].values
), ),
setShowQuestionnaireSection( setShowQuestionnaireSection(
showQuestionnaireSection - 1 showQuestionnaireSection - 1
)); );
}} }}
className="govuk-link" className="govuk-link"
> >
@@ -499,17 +502,14 @@ let RepLPA = (props) => {
)} )}
</> </>
)}{" "} )}{" "}
{isTypeConfirmed && {(typeof props.representationType != "undefined" ||
selectedRepresentationType != "Questionnaire" && ( _.has(formObj, "values", "representationType")) &&
props.representationType != "Questionnaire" && (
<> <>
<button <button
type="submit" type="submit"
className="govuk-button" className="govuk-button"
data-module="govuk-button" data-module="govuk-button"
disabled={shouldDisableButton({
props,
formObj
})}
onClick={() => { onClick={() => {
let valuesObj = let valuesObj =
props.props.props.form[props.form] props.props.props.form[props.form]
@@ -607,7 +607,7 @@ RepLPA = connect((state) => {
return { return {
procedureType, procedureType,
representationType representationType,
}; };
})(RepLPA); })(RepLPA);
@@ -620,7 +620,7 @@ const mapDispatchToProps = (dispatch) => ({
}, },
setCurrentReference: (currentReference) => { setCurrentReference: (currentReference) => {
dispatch(setCurrentReference(currentReference)); dispatch(setCurrentReference(currentReference));
} },
}); });
const mapStateToProps = (state, props) => { const mapStateToProps = (state, props) => {
@@ -636,7 +636,8 @@ const mapStateToProps = (state, props) => {
], ],
"firstname": "firstname":
props.props.props.accountDetails.accountDetails.firstname, props.props.props.accountDetails.accountDetails.firstname,
"lastname": props.props.props.accountDetails.accountDetails.lastname "lastname":
props.props.props.accountDetails.accountDetails.lastname,
} }
); );
return { return {
@@ -647,7 +648,7 @@ const mapStateToProps = (state, props) => {
currentView: state.currentView, currentView: state.currentView,
myRepresentations: state.myRepresentations, myRepresentations: state.myRepresentations,
watchedCases: state.watchedCases, watchedCases: state.watchedCases,
initialValues: initialValuesTemp initialValues: initialValuesTemp,
}; };
}; };
@@ -658,6 +659,6 @@ export default connect(
reduxForm({ reduxForm({
form: "representationForm", form: "representationForm",
enableReinitialize: true, enableReinitialize: true,
destroyOnUnmount: false destroyOnUnmount: false,
})(RepLPA) })(RepLPA)
); );
@@ -1,7 +1,6 @@
import { JSONPath as jsonpath } from "jsonpath-plus"; import { JSONPath as jsonpath } from "jsonpath-plus";
import useTranslation from "next-translate/useTranslation"; import useTranslation from "next-translate/useTranslation";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
import { hasOwn } from "../../utils";
const RepLPADetails = (props) => { const RepLPADetails = (props) => {
let { t } = useTranslation(); let { t } = useTranslation();
@@ -24,7 +23,7 @@ const RepLPADetails = (props) => {
detailsObj = jsonpath({ detailsObj = jsonpath({
path: '$..[?(@ && @.ticketnumber=="' + ticketnumber + '")]', path: '$..[?(@ && @.ticketnumber=="' + ticketnumber + '")]',
json: setCaseDetailsObj, json: setCaseDetailsObj,
eval: true eval: true,
}); });
detailsObj = detailsObj[0]; detailsObj = detailsObj[0];
@@ -52,43 +51,34 @@ const RepLPADetails = (props) => {
{t("case:summary-site-address-label")} {t("case:summary-site-address-label")}
</dt> </dt>
<dd className="govuk-summary-list__value"> <dd className="govuk-summary-list__value">
{hasOwn(detailsObj, "pinswg_siteaddressline1") {_.has(detailsObj, "pinswg_siteaddressline1")
? detailsObj.pinswg_siteaddressline1 ? detailsObj.pinswg_siteaddressline1
: ""} : ""}
{hasOwn( {_.has(detailsObj, "pinswg_siteaddressline1") &&
detailsObj,
"pinswg_siteaddressline1"
) &&
detailsObj.pinswg_siteaddressline1 != detailsObj.pinswg_siteaddressline1 !=
null && <br />} null && <br />}
{hasOwn(detailsObj, "pinswg_siteaddressline2") {_.has(detailsObj, "pinswg_siteaddressline2")
? detailsObj.pinswg_siteaddressline2 ? detailsObj.pinswg_siteaddressline2
: ""} : ""}
{hasOwn( {_.has(detailsObj, "pinswg_siteaddressline2") &&
detailsObj,
"pinswg_siteaddressline2"
) &&
detailsObj.pinswg_siteaddressline2 != detailsObj.pinswg_siteaddressline2 !=
null && <br />} null && <br />}
{hasOwn(detailsObj, "pinswg_siteaddresstown") {_.has(detailsObj, "pinswg_siteaddresstown")
? detailsObj.pinswg_siteaddresstown ? detailsObj.pinswg_siteaddresstown
: ""} : ""}
{hasOwn(detailsObj, "pinswg_siteaddresstown") && {_.has(detailsObj, "pinswg_siteaddresstown") &&
detailsObj.pinswg_siteaddresstown != detailsObj.pinswg_siteaddresstown !=
null && <br />} null && <br />}
{hasOwn(detailsObj, "pinswg_siteaddresscounty") {_.has(detailsObj, "pinswg_siteaddresscounty")
? detailsObj.pinswg_siteaddresscounty ? detailsObj.pinswg_siteaddresscounty
: ""} : ""}
{hasOwn( {_.has(
detailsObj, detailsObj,
"pinswg_siteaddresscounty" "pinswg_siteaddresscounty"
) && ) &&
detailsObj.pinswg_siteaddresscounty != detailsObj.pinswg_siteaddresscounty !=
null && <br />} null && <br />}
{hasOwn( {_.has(detailsObj, "pinswg_siteaddresspostcode")
detailsObj,
"pinswg_siteaddresspostcode"
)
? detailsObj.pinswg_siteaddresspostcode ? detailsObj.pinswg_siteaddresspostcode
: ""} : ""}
</dd> </dd>
@@ -14,12 +14,12 @@ import {
RenderPickList, RenderPickList,
RenderRadioList, RenderRadioList,
RenderRichMultiline, RenderRichMultiline,
RenderTextfield RenderTextfield,
} from "../representationElements"; } from "../representationElements";
import { import {
setRepresentationCapacity, setRepresentationCapacity,
setRepresentationSubmit, setRepresentationSubmit,
setFilesForRepresentations setFilesForRepresentations,
} from "../../../../store/currentView/action"; } from "../../../../store/currentView/action";
let Enforcement_Questionnaire = (props) => { let Enforcement_Questionnaire = (props) => {
@@ -36,7 +36,7 @@ let Enforcement_Questionnaire = (props) => {
procedureTypeValue, procedureTypeValue,
onBehalfOfLPA, onBehalfOfLPA,
showQuestionnaireSection, showQuestionnaireSection,
setFilesForRepresentations setFilesForRepresentations,
} = props; } = props;
const { acceptedFiles, getRootProps, getInputProps } = useDropzone(); const { acceptedFiles, getRootProps, getInputProps } = useDropzone();
const files = acceptedFiles.map((file) => ( const files = acceptedFiles.map((file) => (
@@ -61,10 +61,10 @@ let Enforcement_Questionnaire = (props) => {
detailsObj = jsonpath({ detailsObj = jsonpath({
path: path:
'$..[?(@ && @.pinswg_name=="' + '$..[?(@ && @.pinswg_name=="' +
currentView.caseReference.ticketnumber + currentView.caseReference.currentReference +
'")]', '")]',
json: setCaseDetailsObj, json: setCaseDetailsObj,
eval: true eval: true,
}); });
let setCaseResultssObj = router.query.hasOwnProperty("state") let setCaseResultssObj = router.query.hasOwnProperty("state")
@@ -84,10 +84,10 @@ let Enforcement_Questionnaire = (props) => {
resultsObj = jsonpath({ resultsObj = jsonpath({
path: path:
'$..[?(@ && @.ticketnumber=="' + '$..[?(@ && @.ticketnumber=="' +
currentView.caseReference.ticketnumber + currentView.caseReference.currentReference +
'")]', '")]',
json: setCaseResultssObj, json: setCaseResultssObj,
eval: true eval: true,
}); });
resultsObj = resultsObj[0]; resultsObj = resultsObj[0];
@@ -118,7 +118,7 @@ let Enforcement_Questionnaire = (props) => {
<div className="govuk-form-group"> <div className="govuk-form-group">
<div className="govuk-label"> <div className="govuk-label">
2. {t("myrepresentations:enf-section-question-2")}:{" "} 2. {t("myrepresentations:enf-section-question-2")}:{" "}
{resultsObj.pinswg_lpareference || ""} {resultsObj.pinswg_lpareference}
</div> </div>
</div> </div>
<div className="govuk-form-group"> <div className="govuk-form-group">
@@ -155,7 +155,7 @@ let Enforcement_Questionnaire = (props) => {
optionsArr={[ optionsArr={[
"Written representations", "Written representations",
"Hearing", "Hearing",
"Inquiry" "Inquiry",
]} ]}
id="procedureType" id="procedureType"
component={RenderPickList} component={RenderPickList}
@@ -190,7 +190,7 @@ let Enforcement_Questionnaire = (props) => {
component={RenderRadioList} component={RenderRadioList}
options={[ options={[
t("myrepresentations:questionnaire-yes"), t("myrepresentations:questionnaire-yes"),
t("myrepresentations:questionnaire-no") t("myrepresentations:questionnaire-no"),
]} ]}
type="text" type="text"
rows="5" rows="5"
@@ -207,7 +207,7 @@ let Enforcement_Questionnaire = (props) => {
datafieldname="enterNeighbouringLandToViewSite" datafieldname="enterNeighbouringLandToViewSite"
options={[ options={[
t("myrepresentations:questionnaire-yes"), t("myrepresentations:questionnaire-yes"),
t("myrepresentations:questionnaire-no") t("myrepresentations:questionnaire-no"),
]} ]}
id="enterNeighbouringLandToViewSite" id="enterNeighbouringLandToViewSite"
className="govuk-radios__input" className="govuk-radios__input"
@@ -236,7 +236,7 @@ let Enforcement_Questionnaire = (props) => {
datafieldname="enterNeighbouringLandAccessRequired" datafieldname="enterNeighbouringLandAccessRequired"
options={[ options={[
t("myrepresentations:questionnaire-yes"), t("myrepresentations:questionnaire-yes"),
t("myrepresentations:questionnaire-no") t("myrepresentations:questionnaire-no"),
]} ]}
id="enterNeighbouringLandAccessRequired" id="enterNeighbouringLandAccessRequired"
className="govuk-radios__input" className="govuk-radios__input"
@@ -265,7 +265,7 @@ let Enforcement_Questionnaire = (props) => {
datafieldname="healthAndSafetyIssues" datafieldname="healthAndSafetyIssues"
options={[ options={[
t("myrepresentations:questionnaire-yes"), t("myrepresentations:questionnaire-yes"),
t("myrepresentations:questionnaire-no") t("myrepresentations:questionnaire-no"),
]} ]}
id="healthAndSafetyIssues" id="healthAndSafetyIssues"
className="govuk-radios__input" className="govuk-radios__input"
@@ -328,7 +328,7 @@ let Enforcement_Questionnaire = (props) => {
component={RenderRadioList} component={RenderRadioList}
options={[ options={[
t("myrepresentations:questionnaire-yes"), t("myrepresentations:questionnaire-yes"),
t("myrepresentations:questionnaire-no") t("myrepresentations:questionnaire-no"),
]} ]}
type="text" type="text"
rows="5" rows="5"
@@ -342,7 +342,7 @@ let Enforcement_Questionnaire = (props) => {
datafieldname="feeExempt" datafieldname="feeExempt"
options={[ options={[
t("myrepresentations:questionnaire-yes"), t("myrepresentations:questionnaire-yes"),
t("myrepresentations:questionnaire-no") t("myrepresentations:questionnaire-no"),
]} ]}
id="feeExempt" id="feeExempt"
className="govuk-radios__input" className="govuk-radios__input"
@@ -379,7 +379,7 @@ let Enforcement_Questionnaire = (props) => {
datafieldname="previousGrantedCerts" datafieldname="previousGrantedCerts"
options={[ options={[
t("myrepresentations:questionnaire-yes"), t("myrepresentations:questionnaire-yes"),
t("myrepresentations:questionnaire-no") t("myrepresentations:questionnaire-no"),
]} ]}
id="previousGrantedCerts" id="previousGrantedCerts"
className="govuk-radios__input" className="govuk-radios__input"
@@ -406,7 +406,7 @@ let Enforcement_Questionnaire = (props) => {
datafieldname="stopNoticeServed" datafieldname="stopNoticeServed"
options={[ options={[
t("myrepresentations:questionnaire-yes"), t("myrepresentations:questionnaire-yes"),
t("myrepresentations:questionnaire-no") t("myrepresentations:questionnaire-no"),
]} ]}
id="stopNoticeServed" id="stopNoticeServed"
className="govuk-radios__input" className="govuk-radios__input"
@@ -433,7 +433,7 @@ let Enforcement_Questionnaire = (props) => {
datafieldname="relatedCases" datafieldname="relatedCases"
options={[ options={[
t("myrepresentations:questionnaire-yes"), t("myrepresentations:questionnaire-yes"),
t("myrepresentations:questionnaire-no") t("myrepresentations:questionnaire-no"),
]} ]}
id="relatedCases" id="relatedCases"
className="govuk-radios__input" className="govuk-radios__input"
@@ -460,7 +460,7 @@ let Enforcement_Questionnaire = (props) => {
datafieldname="previousEnforcement" datafieldname="previousEnforcement"
options={[ options={[
t("myrepresentations:questionnaire-yes"), t("myrepresentations:questionnaire-yes"),
t("myrepresentations:questionnaire-no") t("myrepresentations:questionnaire-no"),
]} ]}
id="previousEnforcement" id="previousEnforcement"
className="govuk-radios__input" className="govuk-radios__input"
@@ -487,7 +487,7 @@ let Enforcement_Questionnaire = (props) => {
datafieldname="subjectArticle4" datafieldname="subjectArticle4"
options={[ options={[
t("myrepresentations:questionnaire-yes"), t("myrepresentations:questionnaire-yes"),
t("myrepresentations:questionnaire-no") t("myrepresentations:questionnaire-no"),
]} ]}
id="subjectArticle4" id="subjectArticle4"
className="govuk-radios__input" className="govuk-radios__input"
@@ -514,7 +514,7 @@ let Enforcement_Questionnaire = (props) => {
datafieldname="previousPDRRestriction" datafieldname="previousPDRRestriction"
options={[ options={[
t("myrepresentations:questionnaire-yes"), t("myrepresentations:questionnaire-yes"),
t("myrepresentations:questionnaire-no") t("myrepresentations:questionnaire-no"),
]} ]}
id="previousPDRRestriction" id="previousPDRRestriction"
className="govuk-radios__input" className="govuk-radios__input"
@@ -594,7 +594,7 @@ let Enforcement_Questionnaire = (props) => {
component={RenderRadioList} component={RenderRadioList}
options={[ options={[
t("myrepresentations:questionnaire-yes"), t("myrepresentations:questionnaire-yes"),
t("myrepresentations:questionnaire-no") t("myrepresentations:questionnaire-no"),
]} ]}
type="text" type="text"
rows="5" rows="5"
@@ -621,7 +621,7 @@ let Enforcement_Questionnaire = (props) => {
component={RenderRadioList} component={RenderRadioList}
options={[ options={[
t("myrepresentations:questionnaire-yes"), t("myrepresentations:questionnaire-yes"),
t("myrepresentations:questionnaire-no") t("myrepresentations:questionnaire-no"),
]} ]}
type="text" type="text"
rows="5" rows="5"
@@ -635,7 +635,7 @@ let Enforcement_Questionnaire = (props) => {
datafieldname="ROW" datafieldname="ROW"
options={[ options={[
t("myrepresentations:questionnaire-yes"), t("myrepresentations:questionnaire-yes"),
t("myrepresentations:questionnaire-no") t("myrepresentations:questionnaire-no"),
]} ]}
id="ROW" id="ROW"
className="govuk-radios__input" className="govuk-radios__input"
@@ -662,7 +662,7 @@ let Enforcement_Questionnaire = (props) => {
datafieldname="conservationArea" datafieldname="conservationArea"
options={[ options={[
t("myrepresentations:questionnaire-yes"), t("myrepresentations:questionnaire-yes"),
t("myrepresentations:questionnaire-no") t("myrepresentations:questionnaire-no"),
]} ]}
id="conservationArea" id="conservationArea"
className="govuk-radios__input" className="govuk-radios__input"
@@ -689,7 +689,7 @@ let Enforcement_Questionnaire = (props) => {
datafieldname="affectListedBuilding" datafieldname="affectListedBuilding"
options={[ options={[
t("myrepresentations:questionnaire-yes"), t("myrepresentations:questionnaire-yes"),
t("myrepresentations:questionnaire-no") t("myrepresentations:questionnaire-no"),
]} ]}
id="affectListedBuilding" id="affectListedBuilding"
className="govuk-radios__input" className="govuk-radios__input"
@@ -716,7 +716,7 @@ let Enforcement_Questionnaire = (props) => {
datafieldname="TPO" datafieldname="TPO"
options={[ options={[
t("myrepresentations:questionnaire-yes"), t("myrepresentations:questionnaire-yes"),
t("myrepresentations:questionnaire-no") t("myrepresentations:questionnaire-no"),
]} ]}
id="TPO" id="TPO"
className="govuk-radios__input" className="govuk-radios__input"
@@ -743,7 +743,7 @@ let Enforcement_Questionnaire = (props) => {
datafieldname="natureConservationSite" datafieldname="natureConservationSite"
options={[ options={[
t("myrepresentations:questionnaire-yes"), t("myrepresentations:questionnaire-yes"),
t("myrepresentations:questionnaire-no") t("myrepresentations:questionnaire-no"),
]} ]}
id="natureConservationSite" id="natureConservationSite"
className="govuk-radios__input" className="govuk-radios__input"
@@ -770,7 +770,7 @@ let Enforcement_Questionnaire = (props) => {
datafieldname="protectedSpecies" datafieldname="protectedSpecies"
options={[ options={[
t("myrepresentations:questionnaire-yes"), t("myrepresentations:questionnaire-yes"),
t("myrepresentations:questionnaire-no") t("myrepresentations:questionnaire-no"),
]} ]}
id="protectedSpecies" id="protectedSpecies"
className="govuk-radios__input" className="govuk-radios__input"
@@ -802,7 +802,7 @@ let Enforcement_Questionnaire = (props) => {
component={RenderRadioList} component={RenderRadioList}
options={[ options={[
t("myrepresentations:questionnaire-yes"), t("myrepresentations:questionnaire-yes"),
t("myrepresentations:questionnaire-no") t("myrepresentations:questionnaire-no"),
]} ]}
type="text" type="text"
rows="5" rows="5"
@@ -816,7 +816,7 @@ let Enforcement_Questionnaire = (props) => {
datafieldname="floodingIssue" datafieldname="floodingIssue"
options={[ options={[
t("myrepresentations:questionnaire-yes"), t("myrepresentations:questionnaire-yes"),
t("myrepresentations:questionnaire-no") t("myrepresentations:questionnaire-no"),
]} ]}
id="floodingIssue" id="floodingIssue"
className="govuk-radios__input" className="govuk-radios__input"
@@ -843,7 +843,7 @@ let Enforcement_Questionnaire = (props) => {
datafieldname="governmentDepartmentComments" datafieldname="governmentDepartmentComments"
options={[ options={[
t("myrepresentations:questionnaire-yes"), t("myrepresentations:questionnaire-yes"),
t("myrepresentations:questionnaire-no") t("myrepresentations:questionnaire-no"),
]} ]}
id="governmentDepartmentComments" id="governmentDepartmentComments"
className="govuk-radios__input" className="govuk-radios__input"
@@ -884,7 +884,7 @@ let Enforcement_Questionnaire = (props) => {
datafieldname="developmentCarriedOutInAccordance" datafieldname="developmentCarriedOutInAccordance"
options={[ options={[
t("myrepresentations:questionnaire-yes"), t("myrepresentations:questionnaire-yes"),
t("myrepresentations:questionnaire-no") t("myrepresentations:questionnaire-no"),
]} ]}
id="developmentCarriedOutInAccordance" id="developmentCarriedOutInAccordance"
className="govuk-radios__input" className="govuk-radios__input"
@@ -915,7 +915,7 @@ let Enforcement_Questionnaire = (props) => {
component={RenderRadioList} component={RenderRadioList}
options={[ options={[
t("myrepresentations:questionnaire-yes"), t("myrepresentations:questionnaire-yes"),
t("myrepresentations:questionnaire-no") t("myrepresentations:questionnaire-no"),
]} ]}
type="text" type="text"
rows="5" rows="5"
@@ -932,7 +932,7 @@ let Enforcement_Questionnaire = (props) => {
component={RenderRadioList} component={RenderRadioList}
options={[ options={[
t("myrepresentations:questionnaire-yes"), t("myrepresentations:questionnaire-yes"),
t("myrepresentations:questionnaire-no") t("myrepresentations:questionnaire-no"),
]} ]}
type="text" type="text"
rows="5" rows="5"
@@ -946,7 +946,7 @@ let Enforcement_Questionnaire = (props) => {
datafieldname="developmentAnyOtherConditions" datafieldname="developmentAnyOtherConditions"
options={[ options={[
t("myrepresentations:questionnaire-yes"), t("myrepresentations:questionnaire-yes"),
t("myrepresentations:questionnaire-no") t("myrepresentations:questionnaire-no"),
]} ]}
id="developmentAnyOtherConditions" id="developmentAnyOtherConditions"
className="govuk-radios__input" className="govuk-radios__input"
@@ -987,7 +987,7 @@ let Enforcement_Questionnaire = (props) => {
datafieldname="copyOfEnforcementNotice" datafieldname="copyOfEnforcementNotice"
options={[ options={[
t("myrepresentations:questionnaire-yes"), t("myrepresentations:questionnaire-yes"),
t("myrepresentations:questionnaire-no") t("myrepresentations:questionnaire-no"),
]} ]}
id="copyOfEnforcementNotice" id="copyOfEnforcementNotice"
className="govuk-radios__input" className="govuk-radios__input"
@@ -1014,7 +1014,7 @@ let Enforcement_Questionnaire = (props) => {
datafieldname="enforcementNoticePlan" datafieldname="enforcementNoticePlan"
options={[ options={[
t("myrepresentations:questionnaire-yes"), t("myrepresentations:questionnaire-yes"),
t("myrepresentations:questionnaire-no") t("myrepresentations:questionnaire-no"),
]} ]}
id="enforcementNoticePlan" id="enforcementNoticePlan"
className="govuk-radios__input" className="govuk-radios__input"
@@ -1041,7 +1041,7 @@ let Enforcement_Questionnaire = (props) => {
datafieldname="listOfNotifiedOfEnforcement" datafieldname="listOfNotifiedOfEnforcement"
options={[ options={[
t("myrepresentations:questionnaire-yes"), t("myrepresentations:questionnaire-yes"),
t("myrepresentations:questionnaire-no") t("myrepresentations:questionnaire-no"),
]} ]}
id="listOfNotifiedOfEnforcement" id="listOfNotifiedOfEnforcement"
className="govuk-radios__input" className="govuk-radios__input"
@@ -1068,7 +1068,7 @@ let Enforcement_Questionnaire = (props) => {
datafieldname="copyOfLetterOfAppealNotification" datafieldname="copyOfLetterOfAppealNotification"
options={[ options={[
t("myrepresentations:questionnaire-yes"), t("myrepresentations:questionnaire-yes"),
t("myrepresentations:questionnaire-no") t("myrepresentations:questionnaire-no"),
]} ]}
id="copyOfLetterOfAppealNotification" id="copyOfLetterOfAppealNotification"
className="govuk-radios__input" className="govuk-radios__input"
@@ -1095,7 +1095,7 @@ let Enforcement_Questionnaire = (props) => {
datafieldname="lpaEIAOS" datafieldname="lpaEIAOS"
options={[ options={[
t("myrepresentations:questionnaire-yes"), t("myrepresentations:questionnaire-yes"),
t("myrepresentations:questionnaire-no") t("myrepresentations:questionnaire-no"),
]} ]}
id="lpaEIAOS" id="lpaEIAOS"
className="govuk-radios__input" className="govuk-radios__input"
@@ -1125,7 +1125,7 @@ let Enforcement_Questionnaire = (props) => {
datafieldname="detailsOfOtherAppeals" datafieldname="detailsOfOtherAppeals"
options={[ options={[
t("myrepresentations:questionnaire-yes"), t("myrepresentations:questionnaire-yes"),
t("myrepresentations:questionnaire-no") t("myrepresentations:questionnaire-no"),
]} ]}
id="detailsOfOtherAppeals" id="detailsOfOtherAppeals"
className="govuk-radios__input" className="govuk-radios__input"
@@ -1152,7 +1152,7 @@ let Enforcement_Questionnaire = (props) => {
datafieldname="detailsOfPreviousAppeals" datafieldname="detailsOfPreviousAppeals"
options={[ options={[
t("myrepresentations:questionnaire-yes"), t("myrepresentations:questionnaire-yes"),
t("myrepresentations:questionnaire-no") t("myrepresentations:questionnaire-no"),
]} ]}
id="detailsOfPreviousAppeals" id="detailsOfPreviousAppeals"
className="govuk-radios__input" className="govuk-radios__input"
@@ -1179,7 +1179,7 @@ let Enforcement_Questionnaire = (props) => {
datafieldname="otherRelevantInformation" datafieldname="otherRelevantInformation"
options={[ options={[
t("myrepresentations:questionnaire-yes"), t("myrepresentations:questionnaire-yes"),
t("myrepresentations:questionnaire-no") t("myrepresentations:questionnaire-no"),
]} ]}
id="otherRelevantInformation" id="otherRelevantInformation"
className="govuk-radios__input" className="govuk-radios__input"
@@ -1312,7 +1312,7 @@ Enforcement_Questionnaire = connect((state) => {
return { return {
procedureTypeValue, procedureTypeValue,
representationTypeValue representationTypeValue,
}; };
})(Enforcement_Questionnaire); })(Enforcement_Questionnaire);
@@ -1323,7 +1323,7 @@ const mapDispatchToProps = (dispatch) => {
setFilesForRepresentations: (fileList) => { setFilesForRepresentations: (fileList) => {
dispatch(setFilesForRepresentations(fileList)); dispatch(setFilesForRepresentations(fileList));
} },
}; };
}; };
@@ -1335,7 +1335,7 @@ const mapStateToProps = (state, props) => {
appealType: state.appealType, appealType: state.appealType,
currentView: state.currentView, currentView: state.currentView,
myRepresentations: state.myRepresentations, myRepresentations: state.myRepresentations,
initialValues: state.currentView.caseReference.repDetails initialValues: state.currentView.caseReference.repDetails,
}; };
}; };
@@ -1346,6 +1346,6 @@ export default connect(
reduxForm({ reduxForm({
form: "representationForm", form: "representationForm",
enableReinitialize: false, enableReinitialize: false,
destroyOnUnmount: false destroyOnUnmount: false,
})(Enforcement_Questionnaire) })(Enforcement_Questionnaire)
); );
@@ -4,7 +4,6 @@ import { useRouter } from "next/router";
import { useDropzone } from "react-dropzone"; import { useDropzone } from "react-dropzone";
import { Field, reduxForm, formValueSelector } from "redux-form"; import { Field, reduxForm, formValueSelector } from "redux-form";
import { getFormCollectionByID } from "../../../../components/utils"; import { getFormCollectionByID } from "../../../../components/utils";
import { import {
FileUploadField, FileUploadField,
RenderDatePicker, RenderDatePicker,
@@ -13,12 +12,12 @@ import {
RenderPickList, RenderPickList,
RenderRadioList, RenderRadioList,
RenderRichMultiline, RenderRichMultiline,
RenderTextfield RenderTextfield,
} from "../representationElements"; } from "../representationElements";
import { import {
setRepresentationCapacity, setRepresentationCapacity,
setRepresentationSubmit, setRepresentationSubmit,
setFilesForRepresentations setFilesForRepresentations,
} from "../../../../store/currentView/action"; } from "../../../../store/currentView/action";
import { connect } from "react-redux"; import { connect } from "react-redux";
@@ -39,7 +38,7 @@ let S78_Questionnaire = (props) => {
procedureTypeValue, procedureTypeValue,
onBehalfOfLPA, onBehalfOfLPA,
showQuestionnaireSection, showQuestionnaireSection,
setFilesForRepresentations setFilesForRepresentations,
} = props; } = props;
const { acceptedFiles, getRootProps, getInputProps } = useDropzone(); const { acceptedFiles, getRootProps, getInputProps } = useDropzone();
const files = acceptedFiles.map((file) => ( const files = acceptedFiles.map((file) => (
@@ -63,11 +62,11 @@ let S78_Questionnaire = (props) => {
detailsObj = jsonpath({ detailsObj = jsonpath({
path: path:
'$..[?(@ && @.ticketnumber=="' + '$..[?(@ && @.pinswg_name=="' +
currentView.caseReference.ticketnumber + currentView.caseReference.currentReference +
'")]', '")]',
json: setCaseDetailsObj, json: setCaseDetailsObj,
eval: true eval: true,
}); });
let setCaseResultssObj = router.query.hasOwnProperty("state") let setCaseResultssObj = router.query.hasOwnProperty("state")
@@ -93,10 +92,10 @@ let S78_Questionnaire = (props) => {
: "ticketnumber" : "ticketnumber"
: "ticketnumber") + : "ticketnumber") +
'=="' + '=="' +
currentView.caseReference.ticketnumber + currentView.caseReference.currentReference +
'")]', '")]',
json: setCaseResultssObj, json: setCaseResultssObj,
eval: true eval: true,
}); });
resultsObj = resultsObj[0]; resultsObj = resultsObj[0];
@@ -137,7 +136,7 @@ let S78_Questionnaire = (props) => {
<div className="govuk-form-group"> <div className="govuk-form-group">
<div className="govuk-label"> <div className="govuk-label">
2. {t("myrepresentations:s78-section-question-2")}:{" "} 2. {t("myrepresentations:s78-section-question-2")}:{" "}
{resultsObj.pinswg_lpareference || ""} {resultsObj.pinswg_lpareference}
</div> </div>
</div> </div>
<div className="govuk-form-group"> <div className="govuk-form-group">
@@ -176,7 +175,7 @@ let S78_Questionnaire = (props) => {
optionsArr={[ optionsArr={[
"Written representations", "Written representations",
"Hearing", "Hearing",
"Inquiry" "Inquiry",
]} ]}
id="procedureType" id="procedureType"
component={RenderPickList} component={RenderPickList}
@@ -210,7 +209,7 @@ let S78_Questionnaire = (props) => {
component={RenderRadioList} component={RenderRadioList}
options={[ options={[
t("myrepresentations:questionnaire-yes"), t("myrepresentations:questionnaire-yes"),
t("myrepresentations:questionnaire-no") t("myrepresentations:questionnaire-no"),
]} ]}
type="text" type="text"
rows="5" rows="5"
@@ -225,7 +224,7 @@ let S78_Questionnaire = (props) => {
datafieldname="enterNeighbouringLandToViewSite" datafieldname="enterNeighbouringLandToViewSite"
options={[ options={[
t("myrepresentations:questionnaire-yes"), t("myrepresentations:questionnaire-yes"),
t("myrepresentations:questionnaire-no") t("myrepresentations:questionnaire-no"),
]} ]}
id="enterNeighbouringLandToViewSite" id="enterNeighbouringLandToViewSite"
className="govuk-radios__input" className="govuk-radios__input"
@@ -254,7 +253,7 @@ let S78_Questionnaire = (props) => {
datafieldname="enterNeighbouringLandAccessRequired" datafieldname="enterNeighbouringLandAccessRequired"
options={[ options={[
t("myrepresentations:questionnaire-yes"), t("myrepresentations:questionnaire-yes"),
t("myrepresentations:questionnaire-no") t("myrepresentations:questionnaire-no"),
]} ]}
id="enterNeighbouringLandAccessRequired" id="enterNeighbouringLandAccessRequired"
className="govuk-radios__input" className="govuk-radios__input"
@@ -283,7 +282,7 @@ let S78_Questionnaire = (props) => {
datafieldname="healthAndSafetyIssues" datafieldname="healthAndSafetyIssues"
options={[ options={[
t("myrepresentations:questionnaire-yes"), t("myrepresentations:questionnaire-yes"),
t("myrepresentations:questionnaire-no") t("myrepresentations:questionnaire-no"),
]} ]}
id="healthAndSafetyIssues" id="healthAndSafetyIssues"
className="govuk-radios__input" className="govuk-radios__input"
@@ -406,7 +405,7 @@ let S78_Questionnaire = (props) => {
component={RenderRadioList} component={RenderRadioList}
options={[ options={[
t("myrepresentations:questionnaire-yes"), t("myrepresentations:questionnaire-yes"),
t("myrepresentations:questionnaire-no") t("myrepresentations:questionnaire-no"),
]} ]}
type="text" type="text"
rows="5" rows="5"
@@ -435,7 +434,7 @@ let S78_Questionnaire = (props) => {
component={RenderRadioList} component={RenderRadioList}
options={[ options={[
t("myrepresentations:questionnaire-yes"), t("myrepresentations:questionnaire-yes"),
t("myrepresentations:questionnaire-no") t("myrepresentations:questionnaire-no"),
]} ]}
type="text" type="text"
rows="5" rows="5"
@@ -451,7 +450,7 @@ let S78_Questionnaire = (props) => {
datafieldname="ROW" datafieldname="ROW"
options={[ options={[
t("myrepresentations:questionnaire-yes"), t("myrepresentations:questionnaire-yes"),
t("myrepresentations:questionnaire-no") t("myrepresentations:questionnaire-no"),
]} ]}
id="ROW" id="ROW"
className="govuk-radios__input" className="govuk-radios__input"
@@ -478,7 +477,7 @@ let S78_Questionnaire = (props) => {
datafieldname="conservationArea" datafieldname="conservationArea"
options={[ options={[
t("myrepresentations:questionnaire-yes"), t("myrepresentations:questionnaire-yes"),
t("myrepresentations:questionnaire-no") t("myrepresentations:questionnaire-no"),
]} ]}
id="conservationArea" id="conservationArea"
className="govuk-radios__input" className="govuk-radios__input"
@@ -505,7 +504,7 @@ let S78_Questionnaire = (props) => {
datafieldname="affectListedBuilding" datafieldname="affectListedBuilding"
options={[ options={[
t("myrepresentations:questionnaire-yes"), t("myrepresentations:questionnaire-yes"),
t("myrepresentations:questionnaire-no") t("myrepresentations:questionnaire-no"),
]} ]}
id="affectListedBuilding" id="affectListedBuilding"
className="govuk-radios__input" className="govuk-radios__input"
@@ -532,7 +531,7 @@ let S78_Questionnaire = (props) => {
datafieldname="TPO" datafieldname="TPO"
options={[ options={[
t("myrepresentations:questionnaire-yes"), t("myrepresentations:questionnaire-yes"),
t("myrepresentations:questionnaire-no") t("myrepresentations:questionnaire-no"),
]} ]}
id="TPO" id="TPO"
className="govuk-radios__input" className="govuk-radios__input"
@@ -559,7 +558,7 @@ let S78_Questionnaire = (props) => {
datafieldname="natureConservationSite" datafieldname="natureConservationSite"
options={[ options={[
t("myrepresentations:questionnaire-yes"), t("myrepresentations:questionnaire-yes"),
t("myrepresentations:questionnaire-no") t("myrepresentations:questionnaire-no"),
]} ]}
id="natureConservationSite" id="natureConservationSite"
className="govuk-radios__input" className="govuk-radios__input"
@@ -586,7 +585,7 @@ let S78_Questionnaire = (props) => {
datafieldname="protectedSpecies" datafieldname="protectedSpecies"
options={[ options={[
t("myrepresentations:questionnaire-yes"), t("myrepresentations:questionnaire-yes"),
t("myrepresentations:questionnaire-no") t("myrepresentations:questionnaire-no"),
]} ]}
id="protectedSpecies" id="protectedSpecies"
className="govuk-radios__input" className="govuk-radios__input"
@@ -617,7 +616,7 @@ let S78_Questionnaire = (props) => {
component={RenderRadioList} component={RenderRadioList}
options={[ options={[
t("myrepresentations:questionnaire-yes"), t("myrepresentations:questionnaire-yes"),
t("myrepresentations:questionnaire-no") t("myrepresentations:questionnaire-no"),
]} ]}
type="text" type="text"
rows="5" rows="5"
@@ -630,7 +629,7 @@ let S78_Questionnaire = (props) => {
datafieldname="governmentDepartmentComments" datafieldname="governmentDepartmentComments"
options={[ options={[
t("myrepresentations:questionnaire-yes"), t("myrepresentations:questionnaire-yes"),
t("myrepresentations:questionnaire-no") t("myrepresentations:questionnaire-no"),
]} ]}
id="governmentDepartmentComments" id="governmentDepartmentComments"
className="govuk-radios__input" className="govuk-radios__input"
@@ -676,7 +675,7 @@ let S78_Questionnaire = (props) => {
component={RenderRadioList} component={RenderRadioList}
options={[ options={[
t("myrepresentations:questionnaire-yes"), t("myrepresentations:questionnaire-yes"),
t("myrepresentations:questionnaire-no") t("myrepresentations:questionnaire-no"),
]} ]}
type="text" type="text"
rows="5" rows="5"
@@ -692,7 +691,7 @@ let S78_Questionnaire = (props) => {
datafieldname="developmentCarriedOutInAccordance" datafieldname="developmentCarriedOutInAccordance"
options={[ options={[
t("myrepresentations:questionnaire-yes"), t("myrepresentations:questionnaire-yes"),
t("myrepresentations:questionnaire-no") t("myrepresentations:questionnaire-no"),
]} ]}
id="developmentCarriedOutInAccordance" id="developmentCarriedOutInAccordance"
className="govuk-radios__input" className="govuk-radios__input"
@@ -723,7 +722,7 @@ let S78_Questionnaire = (props) => {
component={RenderRadioList} component={RenderRadioList}
options={[ options={[
t("myrepresentations:questionnaire-yes"), t("myrepresentations:questionnaire-yes"),
t("myrepresentations:questionnaire-no") t("myrepresentations:questionnaire-no"),
]} ]}
type="text" type="text"
rows="5" rows="5"
@@ -742,7 +741,7 @@ let S78_Questionnaire = (props) => {
component={RenderRadioList} component={RenderRadioList}
options={[ options={[
t("myrepresentations:questionnaire-yes"), t("myrepresentations:questionnaire-yes"),
t("myrepresentations:questionnaire-no") t("myrepresentations:questionnaire-no"),
]} ]}
type="text" type="text"
rows="5" rows="5"
@@ -758,7 +757,7 @@ let S78_Questionnaire = (props) => {
datafieldname="developmentAnyOtherConditions" datafieldname="developmentAnyOtherConditions"
options={[ options={[
t("myrepresentations:questionnaire-yes"), t("myrepresentations:questionnaire-yes"),
t("myrepresentations:questionnaire-no") t("myrepresentations:questionnaire-no"),
]} ]}
id="developmentAnyOtherConditions" id="developmentAnyOtherConditions"
className="govuk-radios__input" className="govuk-radios__input"
@@ -798,7 +797,7 @@ let S78_Questionnaire = (props) => {
datafieldname="copyOfApplicantsCertificate" datafieldname="copyOfApplicantsCertificate"
options={[ options={[
t("myrepresentations:questionnaire-yes"), t("myrepresentations:questionnaire-yes"),
t("myrepresentations:questionnaire-no") t("myrepresentations:questionnaire-no"),
]} ]}
id="copyOfApplicantsCertificate" id="copyOfApplicantsCertificate"
className="govuk-radios__input" className="govuk-radios__input"
@@ -826,7 +825,7 @@ let S78_Questionnaire = (props) => {
datafieldname="advertismentGiven" datafieldname="advertismentGiven"
options={[ options={[
t("myrepresentations:questionnaire-yes"), t("myrepresentations:questionnaire-yes"),
t("myrepresentations:questionnaire-no") t("myrepresentations:questionnaire-no"),
]} ]}
id="advertismentGiven" id="advertismentGiven"
className="govuk-radios__input" className="govuk-radios__input"
@@ -854,7 +853,7 @@ let S78_Questionnaire = (props) => {
datafieldname="copyOfLetterOfAppealNotification" datafieldname="copyOfLetterOfAppealNotification"
options={[ options={[
t("myrepresentations:questionnaire-yes"), t("myrepresentations:questionnaire-yes"),
t("myrepresentations:questionnaire-no") t("myrepresentations:questionnaire-no"),
]} ]}
id="copyOfLetterOfAppealNotification" id="copyOfLetterOfAppealNotification"
className="govuk-radios__input" className="govuk-radios__input"
@@ -881,7 +880,7 @@ let S78_Questionnaire = (props) => {
datafieldname="lpaEIAOS" datafieldname="lpaEIAOS"
options={[ options={[
t("myrepresentations:questionnaire-yes"), t("myrepresentations:questionnaire-yes"),
t("myrepresentations:questionnaire-no") t("myrepresentations:questionnaire-no"),
]} ]}
id="lpaEIAOS" id="lpaEIAOS"
className="govuk-radios__input" className="govuk-radios__input"
@@ -908,7 +907,7 @@ let S78_Questionnaire = (props) => {
datafieldname="advertismentConsentDiscontinuanceNotice" datafieldname="advertismentConsentDiscontinuanceNotice"
options={[ options={[
t("myrepresentations:questionnaire-yes"), t("myrepresentations:questionnaire-yes"),
t("myrepresentations:questionnaire-no") t("myrepresentations:questionnaire-no"),
]} ]}
id="advertismentConsentDiscontinuanceNotice" id="advertismentConsentDiscontinuanceNotice"
className="govuk-radios__input" className="govuk-radios__input"
@@ -935,7 +934,7 @@ let S78_Questionnaire = (props) => {
datafieldname="detailsOfOtherAppeals" datafieldname="detailsOfOtherAppeals"
options={[ options={[
t("myrepresentations:questionnaire-yes"), t("myrepresentations:questionnaire-yes"),
t("myrepresentations:questionnaire-no") t("myrepresentations:questionnaire-no"),
]} ]}
id="detailsOfOtherAppeals" id="detailsOfOtherAppeals"
className="govuk-radios__input" className="govuk-radios__input"
@@ -962,7 +961,7 @@ let S78_Questionnaire = (props) => {
datafieldname="detailsOfPreviousAppeals" datafieldname="detailsOfPreviousAppeals"
options={[ options={[
t("myrepresentations:questionnaire-yes"), t("myrepresentations:questionnaire-yes"),
t("myrepresentations:questionnaire-no") t("myrepresentations:questionnaire-no"),
]} ]}
id="detailsOfPreviousAppeals" id="detailsOfPreviousAppeals"
className="govuk-radios__input" className="govuk-radios__input"
@@ -989,7 +988,7 @@ let S78_Questionnaire = (props) => {
datafieldname="otherRelevantInformation" datafieldname="otherRelevantInformation"
options={[ options={[
t("myrepresentations:questionnaire-yes"), t("myrepresentations:questionnaire-yes"),
t("myrepresentations:questionnaire-no") t("myrepresentations:questionnaire-no"),
]} ]}
id="otherRelevantInformation" id="otherRelevantInformation"
className="govuk-radios__input" className="govuk-radios__input"
@@ -1121,7 +1120,7 @@ S78_Questionnaire = connect((state) => {
return { return {
procedureTypeValue, procedureTypeValue,
representationTypeValue representationTypeValue,
}; };
})(S78_Questionnaire); })(S78_Questionnaire);
@@ -1132,7 +1131,7 @@ const mapDispatchToProps = (dispatch) => {
setFilesForRepresentations: (fileList) => { setFilesForRepresentations: (fileList) => {
dispatch(setFilesForRepresentations(fileList)); dispatch(setFilesForRepresentations(fileList));
} },
}; };
}; };
@@ -1144,7 +1143,7 @@ const mapStateToProps = (state, props) => {
appealType: state.appealType, appealType: state.appealType,
currentView: state.currentView, currentView: state.currentView,
myRepresentations: state.myRepresentations, myRepresentations: state.myRepresentations,
initialValues: state.currentView.caseReference.repDetails initialValues: state.currentView.caseReference.repDetails,
}; };
}; };
@@ -1155,6 +1154,6 @@ export default connect(
reduxForm({ reduxForm({
form: "representationForm", form: "representationForm",
enableReinitialize: false, enableReinitialize: false,
destroyOnUnmount: false destroyOnUnmount: false,
})(S78_Questionnaire) })(S78_Questionnaire)
); );

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