From cb254296a2490d2e4297cde186e3973693b4d7e9 Mon Sep 17 00:00:00 2001 From: afeescps Date: Fri, 3 Jul 2026 08:44:21 +0000 Subject: [PATCH 01/28] feat(telemetry): Add shared Application Insights client for Materials (#415) * feat(telemetry): Add shared Application Insights client for Materials UI. Initialise the web SDK once at startup from VITE_APPLICATIONINSIGHTS_CONNECTION_STRING and export shared track helpers. * feat(telemetry): sample non-exceptions and tag cloud role * feat(telemetry): fix sonar issue --- materials_ui/.env.example | 4 ++ .../RouteChangeListener.tsx | 2 + materials_ui/src/index.tsx | 3 + materials_ui/src/telemetry/appInsights.ts | 68 +++++++++++++++++++ materials_ui/src/vite-env.d.ts | 3 + 5 files changed, 80 insertions(+) create mode 100644 materials_ui/src/telemetry/appInsights.ts diff --git a/materials_ui/.env.example b/materials_ui/.env.example index 508e7a4e..6a5de5f0 100644 --- a/materials_ui/.env.example +++ b/materials_ui/.env.example @@ -8,6 +8,10 @@ VITE_POLARIS_GATEWAY_SCOPE= VITE_REDACTION_LOG_URL= VITE_REDACTION_LOG_SCOPE= +VITE_APPLICATIONINSIGHTS_CONNECTION_STRING= +VITE_APPLICATIONINSIGHTS_SAMPLING_PERCENTAGE= +VITE_APPLICATIONINSIGHTS_CLOUD_ROLE= + VITE_GLOBAL_SCRIPT_URL= VITE_DISABLE_FEATURE_FLAGS= diff --git a/materials_ui/src/components/RouteChangeListener/RouteChangeListener.tsx b/materials_ui/src/components/RouteChangeListener/RouteChangeListener.tsx index 38ea0fbb..3de6e74b 100644 --- a/materials_ui/src/components/RouteChangeListener/RouteChangeListener.tsx +++ b/materials_ui/src/components/RouteChangeListener/RouteChangeListener.tsx @@ -3,6 +3,7 @@ import { useLocation } from 'react-router-dom'; import { useBanner } from '../../hooks'; import { useMaterialTags, useSelectedItemsStore } from '../../stores'; +import { trackPageView } from '../../telemetry/appInsights'; // this component is a non rendering component to perform actions when the user // changes pages for example resetting banners, selected items, etc @@ -25,6 +26,7 @@ export const RouteChangeListener = () => { clearSelectedItems(); scrollToTop(); + trackPageView(pathname); }, [pathname]); return null; diff --git a/materials_ui/src/index.tsx b/materials_ui/src/index.tsx index a3d12cc1..f293abd8 100644 --- a/materials_ui/src/index.tsx +++ b/materials_ui/src/index.tsx @@ -11,6 +11,9 @@ import './App.scss'; import { AppContextProvider } from './context/AppContext'; import { FilterProvider } from './context/FiltersContext'; import { msalConfig } from './msalInstance'; +import { initTelemetry } from './telemetry/appInsights'; + +initTelemetry(); if (import.meta.env.DEV && !import.meta.env.VITE_E2E) { const { worker } = await import('./mocks/browser'); diff --git a/materials_ui/src/telemetry/appInsights.ts b/materials_ui/src/telemetry/appInsights.ts new file mode 100644 index 00000000..dd95fbd9 --- /dev/null +++ b/materials_ui/src/telemetry/appInsights.ts @@ -0,0 +1,68 @@ +import { + ApplicationInsights, + ICustomProperties +} from '@microsoft/applicationinsights-web'; + +const connectionString = import.meta.env + .VITE_APPLICATIONINSIGHTS_CONNECTION_STRING; +const cloudRole = import.meta.env.VITE_APPLICATIONINSIGHTS_CLOUD_ROLE; +const samplingPercentage = + Number(import.meta.env.VITE_APPLICATIONINSIGHTS_SAMPLING_PERCENTAGE) || 20; + +let appInsights: ApplicationInsights | undefined; + +const normaliseError = (error: unknown): Error => + error instanceof Error ? error : new Error(String(error)); + +export const initTelemetry = () => { + if (appInsights || !connectionString) return; + + appInsights = new ApplicationInsights({ + config: { + connectionString, + enableAutoRouteTracking: false, + enableUnhandledPromiseRejectionTracking: true + } + }); + appInsights.loadAppInsights(); + + // Sample non-exceptions ourselves so we never drop exceptions. One roll per + // load keeps a page's telemetry together. + const retainNonException = Math.random() * 100 < samplingPercentage; + + appInsights.addTelemetryInitializer((item) => { + if (cloudRole) { + item.tags ??= {}; + item.tags['ai.cloud.role'] = cloudRole; + } + + if (item.baseType === 'ExceptionData') { + return true; + } + + return retainNonException; + }); +}; + +export const trackPageView = (pathname: string) => { + if (!appInsights) return; + // Manual SPA tracking doesn't refresh operation name; it stays on the first + // page unless we set it ourselves, so telemetry groups under the wrong route. + appInsights.context.telemetryTrace.name = pathname; + appInsights.trackPageView({ name: pathname }); +}; + +export const trackEvent = (name: string, properties?: ICustomProperties) => + appInsights?.trackEvent({ name }, properties); + +export const trackException = ( + error: unknown, + properties?: ICustomProperties +) => + appInsights?.trackException({ exception: normaliseError(error) }, properties); + +export const trackMetric = ( + name: string, + average: number, + properties?: ICustomProperties +) => appInsights?.trackMetric({ name, average }, properties); diff --git a/materials_ui/src/vite-env.d.ts b/materials_ui/src/vite-env.d.ts index 00df2480..e779b139 100644 --- a/materials_ui/src/vite-env.d.ts +++ b/materials_ui/src/vite-env.d.ts @@ -6,4 +6,7 @@ interface ImportMetaEnv { readonly VITE_POLARIS_GATEWAY_SCOPE: string; readonly VITE_POLARIS_GATEWAY_URL: string; readonly VITE_REDACTION_LOG_URL: string; + readonly VITE_APPLICATIONINSIGHTS_CONNECTION_STRING: string; + readonly VITE_APPLICATIONINSIGHTS_SAMPLING_PERCENTAGE: string; + readonly VITE_APPLICATIONINSIGHTS_CLOUD_ROLE: string; } From 8f40a3fcb8ac40cf7f6a60a366d0453f32a43c48 Mon Sep 17 00:00:00 2001 From: dbarber-cps Date: Tue, 7 Jul 2026 09:37:59 +0100 Subject: [PATCH 02/28] Bugfix/pr pipeline trigger failure (#429) * syntax corrections on PR pipeline * testing parameter options * typo correction * reverting to original parameter structure --- materials_devops_pipelines/Materials-PR.yml | 62 ++++++++++----------- 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/materials_devops_pipelines/Materials-PR.yml b/materials_devops_pipelines/Materials-PR.yml index 1c702af2..6b684348 100644 --- a/materials_devops_pipelines/Materials-PR.yml +++ b/materials_devops_pipelines/Materials-PR.yml @@ -44,7 +44,7 @@ stages: - stage: Wait_For_Running_PRs displayName: Wait for running PRs jobs: - - job: + - job: Query_Status pool: name: $(dev-build-agent) steps: @@ -61,7 +61,7 @@ stages: name: $(dev-build-agent) steps: - checkout: self - fetchDepth: 0 + fetchDepth: '0' - task: PowerShell@2 inputs: @@ -187,10 +187,10 @@ stages: steps: # Setup Node.js - - task: UseNode@1 + - task: NodeTool@0 displayName: "Use Node.js" inputs: - version: "$(nodeVersion)" + versionSpec: "$(nodeVersion)" - task: Npm@1 inputs: @@ -234,19 +234,19 @@ stages: - script: | npx playwright install - displayName: 'Install Playwright browsers' - condition: ne(variables['PLAYWRIGHT_CACHE_RESTORED'], 'true') - workingDirectory: '$(workingDir)' - env: - PLAYWRIGHT_BROWSERS_PATH: '$(Pipeline.Workspace)/.playwright' + displayName: 'Install Playwright browsers' + condition: ne(variables['PLAYWRIGHT_CACHE_RESTORED'], 'true') + workingDirectory: '$(workingDir)' + env: + PLAYWRIGHT_BROWSERS_PATH: '$(Pipeline.Workspace)/.playwright' - - script: | - npx playwright install-deps - displayName: 'Install Playwright OS dependencies' - condition: and(eq(variables['Agent.OS'], 'Linux'), ne(variables['PLAYWRIGHT_CACHE_RESTORED'], 'true')) - workingDirectory: '$(workingDir)' - env: - PLAYWRIGHT_BROWSERS_PATH: '$(Pipeline.Workspace)/.playwright' + - script: | + npx playwright install-deps + displayName: 'Install Playwright OS dependencies' + condition: and(eq(variables['Agent.OS'], 'Linux'), ne(variables['PLAYWRIGHT_CACHE_RESTORED'], 'true')) + workingDirectory: '$(workingDir)' + env: + PLAYWRIGHT_BROWSERS_PATH: '$(Pipeline.Workspace)/.playwright' - script: | npx playwright install msedge @@ -279,19 +279,19 @@ stages: VITE_GLOBAL_SCRIPT_URL: $(GLOBAL_SCRIPT_URL) VITE_E2E: True - - task: PublishPipelineArtifact@1 - displayName: 'Publish E2E Artifact' - inputs: - targetPath: '$(workingDir)/tests/playwright-report' - artifact: 'playwright-report' - publishLocation: 'pipeline' - condition: succeededOrFailed() + - task: PublishPipelineArtifact@1 + displayName: 'Publish E2E Artifact' + inputs: + targetPath: '$(workingDir)/tests/playwright-report' + artifact: 'playwright-report' + publishLocation: 'pipeline' + condition: succeededOrFailed() - - task: PublishTestResults@2 - displayName: 'Publish E2E Test Results (JUnit)' - inputs: - testResultsFormat: 'JUnit' - testResultsFiles: '$(workingDir)/tests/e2e-test-results.xml' - testRunTitle: 'E2E Tests' - publishRunAttachments: false - condition: always() \ No newline at end of file + - task: PublishTestResults@2 + displayName: 'Publish E2E Test Results (JUnit)' + inputs: + testResultsFormat: 'JUnit' + testResultsFiles: '$(workingDir)/tests/e2e-test-results.xml' + testRunTitle: 'E2E Tests' + publishRunAttachments: false + condition: always() \ No newline at end of file From c1140f5c039e77b7450ad2faf91fdf641480c3d8 Mon Sep 17 00:00:00 2001 From: girmacps Date: Tue, 7 Jul 2026 11:52:02 +0100 Subject: [PATCH 03/28] Fixing category list filter (#430) --- materials_ui/src/constants/categoryList.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/materials_ui/src/constants/categoryList.ts b/materials_ui/src/constants/categoryList.ts index 010324fc..e94f29ec 100644 --- a/materials_ui/src/constants/categoryList.ts +++ b/materials_ui/src/constants/categoryList.ts @@ -4,7 +4,7 @@ export const materialsCategoryList = [ 'MG Form', 'Other Material', 'Unused Material', - 'Defendant Pre Conns' + 'Defendant Pre Cons' ]; export const communicationsCategoryList = [ From b860caafe2ce7ba484afaadfd5ec435794505190 Mon Sep 17 00:00:00 2001 From: robmolloy-cps Date: Tue, 7 Jul 2026 15:35:50 +0100 Subject: [PATCH 04/28] FCT2-20144-correct-label-spelling-capitilisation-2 (#431) --- .../Filters/DocumentKeywordSearchFilters.tsx | 12 ------------ materials_ui/src/constants/categoryList.ts | 2 +- .../CaseworkPdfRedactorWrapper.tsx | 9 ++++++--- .../utils/categoriseDocumentHelperUtils.ts | 6 +++--- materials_ui/tests/tests-e2e/review-redact.spec.ts | 2 +- 5 files changed, 11 insertions(+), 20 deletions(-) diff --git a/materials_ui/src/components/Filters/DocumentKeywordSearchFilters.tsx b/materials_ui/src/components/Filters/DocumentKeywordSearchFilters.tsx index be4e3bca..3ea63820 100644 --- a/materials_ui/src/components/Filters/DocumentKeywordSearchFilters.tsx +++ b/materials_ui/src/components/Filters/DocumentKeywordSearchFilters.tsx @@ -60,18 +60,6 @@ export const DocumentKeywordSearchFilters = ({ documents: docsOnDocCategoryNames[category.categoryName] })); - // const docsByDocType = (() => { - // const map: Record = {}; - - // documents?.forEach((doc) => { - // const type = doc.cmsDocType.documentType; - // if (!type) return; // skip nulls - // map[type] = (map[type] ?? 0) + 1; - // }); - - // return map; - // })(); - return ( = { 1040, 1041, 1045, 1046, 1047, 1048, 1049, 1050, 1060, 1061, 1063, 1066, 1203 ], otherDocument: [-2, 1201], - defendant: [1056, 1057], + defendantPreCons: [1056, 1057], unusedMaterial: [1009, 1010, 1011, 1058, 1202, 100239, 226148] }; @@ -33,6 +33,6 @@ export const initDocsOnDocCategoryNamesMap = (): { exhibit: [], mgForm: [], otherDocument: [], - defendant: [], + defendantPreCons: [], unusedMaterial: [] }); diff --git a/materials_ui/tests/tests-e2e/review-redact.spec.ts b/materials_ui/tests/tests-e2e/review-redact.spec.ts index ed3d5a6e..59799069 100644 --- a/materials_ui/tests/tests-e2e/review-redact.spec.ts +++ b/materials_ui/tests/tests-e2e/review-redact.spec.ts @@ -23,7 +23,7 @@ test.describe('Review redact page', () => { await expect(page.getByText('Exhibits')).toBeVisible(); await expect(page.getByText('MG forms')).toBeVisible(); await expect(page.getByText('Other documents')).toBeVisible(); - await expect(page.getByText('Defendant pre cons')).toBeVisible(); + await expect(page.getByText('Defendant pre-cons')).toBeVisible(); await expect(page.getByText('Unused material')).toBeVisible(); }); From dac0f938baa522586d7e26bca443b6d8ff373e7b Mon Sep 17 00:00:00 2001 From: robmolloy-cps Date: Wed, 8 Jul 2026 11:06:19 +0100 Subject: [PATCH 05/28] FCT2-15908-high-contrast-pdf-2 (#433) --- materials_ui/package-lock.json | 777 ++++++------------ materials_ui/package.json | 2 +- .../src/components/PdfViewer/PdfViewer.tsx | 7 +- materials_ui/src/hooks/index.ts | 1 + materials_ui/src/hooks/ui/usePageColors.ts | 30 + .../PdfRedactor/PdfRedactor.tsx | 4 +- .../PdfRedactor/PdfRedactorPage.scss | 23 + .../PdfRedactor/PdfRedactorPage.tsx | 3 + materials_ui/src/pages/ViewDocumentPage.tsx | 4 +- 9 files changed, 339 insertions(+), 512 deletions(-) create mode 100644 materials_ui/src/hooks/ui/usePageColors.ts diff --git a/materials_ui/package-lock.json b/materials_ui/package-lock.json index b2265af1..640fc3e6 100644 --- a/materials_ui/package-lock.json +++ b/materials_ui/package-lock.json @@ -24,7 +24,7 @@ "react": "^18.0.0", "react-dom": "^18.0.0", "react-hook-form": "^7.56.1", - "react-pdf": "^9.1.0", + "react-pdf": "^10.4.1", "react-router-dom": "^6.25.1", "react-use": "^17.6.0", "react-use-pagination": "^2.0.1", @@ -2949,6 +2949,256 @@ "node": ">=18" } }, + "node_modules/@napi-rs/canvas": { + "version": "0.1.100", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas/-/canvas-0.1.100.tgz", + "integrity": "sha512-xglYA6q3XO5P3BNJYxVZ1IV7DLVjp1Py6nwag88YntrS+3vKHyYcMqXVS4ZztJmwz2uGvz1FWhI/4LgbR5uQDA==", + "license": "MIT", + "optional": true, + "workspaces": [ + "e2e/*" + ], + "engines": { + "node": ">= 10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" + }, + "optionalDependencies": { + "@napi-rs/canvas-android-arm64": "0.1.100", + "@napi-rs/canvas-darwin-arm64": "0.1.100", + "@napi-rs/canvas-darwin-x64": "0.1.100", + "@napi-rs/canvas-linux-arm-gnueabihf": "0.1.100", + "@napi-rs/canvas-linux-arm64-gnu": "0.1.100", + "@napi-rs/canvas-linux-arm64-musl": "0.1.100", + "@napi-rs/canvas-linux-riscv64-gnu": "0.1.100", + "@napi-rs/canvas-linux-x64-gnu": "0.1.100", + "@napi-rs/canvas-linux-x64-musl": "0.1.100", + "@napi-rs/canvas-win32-arm64-msvc": "0.1.100", + "@napi-rs/canvas-win32-x64-msvc": "0.1.100" + } + }, + "node_modules/@napi-rs/canvas-android-arm64": { + "version": "0.1.100", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-android-arm64/-/canvas-android-arm64-0.1.100.tgz", + "integrity": "sha512-hjhCKhntPv9+t4ckHymdx0phYNcVW+GKQR6Lzw2zE+pOVjOplSmtx9nNNknTjbEDLcuLZqA1y8ufKg1XfgftzQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" + } + }, + "node_modules/@napi-rs/canvas-darwin-arm64": { + "version": "0.1.100", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-darwin-arm64/-/canvas-darwin-arm64-0.1.100.tgz", + "integrity": "sha512-2PcswRaC7Ly645DGt88///zuFDhJxJYdKAs1uU3mfk1atYkXufgcgLfBpk6Tm12nCQBaNt1wpybuPZ4qOhTo8A==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" + } + }, + "node_modules/@napi-rs/canvas-darwin-x64": { + "version": "0.1.100", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-darwin-x64/-/canvas-darwin-x64-0.1.100.tgz", + "integrity": "sha512-ePNZtj7pNIva/siZMg+HmbeozkIjqUIYdoymH8HaA3qK7LfzFN4WMBM8G6HQ9ZC+H3+Dnn5pqtiXpgLykaPOhw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" + } + }, + "node_modules/@napi-rs/canvas-linux-arm-gnueabihf": { + "version": "0.1.100", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-arm-gnueabihf/-/canvas-linux-arm-gnueabihf-0.1.100.tgz", + "integrity": "sha512-d5cDB48oWFGU8/XPhUOFAlySgb/VAu7D+s8fi55K1Pcfg8aPplHWqMgibhVLU8ky7Pyg/fuiVLz4Nf3JrSTuUA==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" + } + }, + "node_modules/@napi-rs/canvas-linux-arm64-gnu": { + "version": "0.1.100", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-arm64-gnu/-/canvas-linux-arm64-gnu-0.1.100.tgz", + "integrity": "sha512-rDxgxRu69RvDlX/bh9o22DxLsGr8EqsNgotL9+RwQE1S0b0cqeatqsw6aW45mukm0B42DIAaAacKaYQ8cqS1nw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" + } + }, + "node_modules/@napi-rs/canvas-linux-arm64-musl": { + "version": "0.1.100", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-arm64-musl/-/canvas-linux-arm64-musl-0.1.100.tgz", + "integrity": "sha512-K3mDW66N+xT2/V439u1alFANiBUjdEx2gLiNYnCmUsva5jZMxWTjafBYwTzYK+EMFMHrUoabuU+T1BIP5CgbYQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" + } + }, + "node_modules/@napi-rs/canvas-linux-riscv64-gnu": { + "version": "0.1.100", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-riscv64-gnu/-/canvas-linux-riscv64-gnu-0.1.100.tgz", + "integrity": "sha512-mooqUBTIsccZpnoQC4NgrC1v6C1vof39etLNMnBwCY+p0gajWJvAHLGQ6g/gGyS5YrpDW+GefSN4+Cvcr08UWw==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" + } + }, + "node_modules/@napi-rs/canvas-linux-x64-gnu": { + "version": "0.1.100", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-x64-gnu/-/canvas-linux-x64-gnu-0.1.100.tgz", + "integrity": "sha512-1eCvkDCazm7FFhsT7DfGOdSaHgZVK3bt/dSBl5EWHOWmnz+I7j8tPseJqqD81NF+MH21jKUK4wQSDjN0mdhnTg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" + } + }, + "node_modules/@napi-rs/canvas-linux-x64-musl": { + "version": "0.1.100", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-x64-musl/-/canvas-linux-x64-musl-0.1.100.tgz", + "integrity": "sha512-20arT6lnI19S68qNlii73TSEDbECNgzMz2EpldC1V3mZFuRkeujXkcebRk0LRJe9SEUAooYiLokfMViY8IX7yA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" + } + }, + "node_modules/@napi-rs/canvas-win32-arm64-msvc": { + "version": "0.1.100", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-win32-arm64-msvc/-/canvas-win32-arm64-msvc-0.1.100.tgz", + "integrity": "sha512-DZFFT1wIAg37LJw37yhMRFfjATd3vTQzjZ1Yki8u2vhO6Hi5VE6BVaGQ1aaDu7xb4iMErz+9EOwjpS7xcxFeBw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" + } + }, + "node_modules/@napi-rs/canvas-win32-x64-msvc": { + "version": "0.1.100", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-win32-x64-msvc/-/canvas-win32-x64-msvc-0.1.100.tgz", + "integrity": "sha512-MyT1j3mHC2+Lu4pBi9mKyMJhtP6U7k7EldY7sj/uS5gJA65gTXt8MefJQXLJo5d/vZbuWmfxzkEUNc/urV3pHA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" + } + }, "node_modules/@nevware21/ts-async": { "version": "0.5.4", "resolved": "https://registry.npmjs.org/@nevware21/ts-async/-/ts-async-0.5.4.tgz", @@ -4785,27 +5035,6 @@ "dev": true, "license": "MIT" }, - "node_modules/base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT", - "optional": true - }, "node_modules/baseline-browser-mapping": { "version": "2.9.2", "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.9.2.tgz", @@ -4815,18 +5044,6 @@ "baseline-browser-mapping": "dist/cli.js" } }, - "node_modules/bl": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", - "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", - "license": "MIT", - "optional": true, - "dependencies": { - "buffer": "^5.5.0", - "inherits": "^2.0.4", - "readable-stream": "^3.4.0" - } - }, "node_modules/brace-expansion": { "version": "1.1.12", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", @@ -4884,31 +5101,6 @@ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" } }, - "node_modules/buffer": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", - "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT", - "optional": true, - "dependencies": { - "base64-js": "^1.3.1", - "ieee754": "^1.1.13" - } - }, "node_modules/buffer-builder": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/buffer-builder/-/buffer-builder-0.2.0.tgz", @@ -4980,21 +5172,6 @@ ], "license": "CC-BY-4.0" }, - "node_modules/canvas": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/canvas/-/canvas-3.2.0.tgz", - "integrity": "sha512-jk0GxrLtUEmW/TmFsk2WghvgHe8B0pxGilqCL21y8lHkPUGa6FTsnCNtHPOzT8O3y+N+m3espawV80bbBlgfTA==", - "hasInstallScript": true, - "license": "MIT", - "optional": true, - "dependencies": { - "node-addon-api": "^7.0.0", - "prebuild-install": "^7.1.3" - }, - "engines": { - "node": "^18.12.0 || >= 20.9.0" - } - }, "node_modules/chai": { "version": "5.3.3", "resolved": "https://registry.npmjs.org/chai/-/chai-5.3.3.tgz", @@ -5055,13 +5232,6 @@ "url": "https://paulmillr.com/funding/" } }, - "node_modules/chownr": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", - "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", - "license": "ISC", - "optional": true - }, "node_modules/cli-cursor": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-5.0.0.tgz", @@ -5432,22 +5602,6 @@ "dev": true, "license": "MIT" }, - "node_modules/decompress-response": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", - "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", - "license": "MIT", - "optional": true, - "dependencies": { - "mimic-response": "^3.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/deep-eql": { "version": "5.0.2", "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-5.0.2.tgz", @@ -5458,16 +5612,6 @@ "node": ">=6" } }, - "node_modules/deep-extend": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", - "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", - "license": "MIT", - "optional": true, - "engines": { - "node": ">=4.0.0" - } - }, "node_modules/deep-is": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", @@ -5503,16 +5647,6 @@ "node": ">=6" } }, - "node_modules/detect-libc": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", - "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", - "license": "Apache-2.0", - "optional": true, - "engines": { - "node": ">=8" - } - }, "node_modules/diff": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.4.tgz", @@ -5590,16 +5724,6 @@ "dev": true, "license": "MIT" }, - "node_modules/end-of-stream": { - "version": "1.4.5", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz", - "integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==", - "license": "MIT", - "optional": true, - "dependencies": { - "once": "^1.4.0" - } - }, "node_modules/entities": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz", @@ -5949,16 +6073,6 @@ "dev": true, "license": "MIT" }, - "node_modules/expand-template": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", - "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==", - "license": "(MIT OR WTFPL)", - "optional": true, - "engines": { - "node": ">=6" - } - }, "node_modules/expect-type": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.2.2.tgz", @@ -6100,13 +6214,6 @@ "node": ">= 6" } }, - "node_modules/fs-constants": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", - "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", - "license": "MIT", - "optional": true - }, "node_modules/fs-extra": { "version": "10.1.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", @@ -6214,13 +6321,6 @@ "node": ">= 0.4" } }, - "node_modules/github-from-package": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", - "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==", - "license": "MIT", - "optional": true - }, "node_modules/glob-parent": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", @@ -6440,27 +6540,6 @@ "node": ">=0.10.0" } }, - "node_modules/ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "BSD-3-Clause", - "optional": true - }, "node_modules/ignore": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", @@ -6539,20 +6618,6 @@ "node": ">=8" } }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "license": "ISC", - "optional": true - }, - "node_modules/ini": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", - "license": "ISC", - "optional": true - }, "node_modules/inline-style-prefixer": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/inline-style-prefixer/-/inline-style-prefixer-7.0.1.tgz", @@ -6993,9 +7058,9 @@ } }, "node_modules/make-cancellable-promise": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/make-cancellable-promise/-/make-cancellable-promise-1.3.2.tgz", - "integrity": "sha512-GCXh3bq/WuMbS+Ky4JBPW1hYTOU+znU+Q5m9Pu+pI8EoUqIHk9+tviOKC6/qhHh8C4/As3tzJ69IF32kdz85ww==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/make-cancellable-promise/-/make-cancellable-promise-2.0.0.tgz", + "integrity": "sha512-3SEQqTpV9oqVsIWqAcmDuaNeo7yBO3tqPtqGRcKkEo0lrzD3wqbKG9mkxO65KoOgXqj+zH2phJ2LiAsdzlogSw==", "license": "MIT", "funding": { "url": "https://github.com/wojtekmaj/make-cancellable-promise?sponsor=1" @@ -7009,9 +7074,9 @@ "license": "ISC" }, "node_modules/make-event-props": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/make-event-props/-/make-event-props-1.6.2.tgz", - "integrity": "sha512-iDwf7mA03WPiR8QxvcVHmVWEPfMY1RZXerDVNCRYW7dUr2ppH3J58Rwb39/WG39yTZdRSxr3x+2v22tvI0VEvA==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/make-event-props/-/make-event-props-2.0.0.tgz", + "integrity": "sha512-G/hncXrl4Qt7mauJEXSg3AcdYzmpkIITTNl5I+rH9sog5Yw0kK6vseJjCaPfOXqOqQuPUP89Rkhfz5kPS8ijtw==", "license": "MIT", "funding": { "url": "https://github.com/wojtekmaj/make-event-props?sponsor=1" @@ -7033,9 +7098,9 @@ "license": "CC0-1.0" }, "node_modules/merge-refs": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/merge-refs/-/merge-refs-1.3.0.tgz", - "integrity": "sha512-nqXPXbso+1dcKDpPCXvwZyJILz+vSLqGGOnDrYHQYE+B8n9JTCekVLC65AfCpR4ggVyA/45Y0iR9LDyS2iI+zA==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-refs/-/merge-refs-2.0.0.tgz", + "integrity": "sha512-3+B21mYK2IqUWnd2EivABLT7ueDhb0b8/dGK8LoFQPrU61YITeCMn14F7y7qZafWNZhUEKb24cJdiT5Wxs3prg==", "license": "MIT", "funding": { "url": "https://github.com/wojtekmaj/merge-refs?sponsor=1" @@ -7097,19 +7162,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/mimic-response": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", - "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", - "license": "MIT", - "optional": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/min-indent": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", @@ -7133,23 +7185,6 @@ "node": "*" } }, - "node_modules/minimist": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", - "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", - "license": "MIT", - "optional": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/mkdirp-classic": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", - "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==", - "license": "MIT", - "optional": true - }, "node_modules/moment": { "version": "2.30.1", "resolved": "https://registry.npmjs.org/moment/-/moment-2.30.1.tgz", @@ -7305,13 +7340,6 @@ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, - "node_modules/napi-build-utils": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-2.0.0.tgz", - "integrity": "sha512-GEbrYkbfF7MoNaoh2iGG84Mnf/WZfB0GdGEsM8wz7Expx/LlWf5U8t9nvJKXSp3qr5IsEbK04cBGhol/KwOsWA==", - "license": "MIT", - "optional": true - }, "node_modules/natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", @@ -7329,32 +7357,6 @@ "tslib": "^2.0.3" } }, - "node_modules/node-abi": { - "version": "3.85.0", - "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.85.0.tgz", - "integrity": "sha512-zsFhmbkAzwhTft6nd3VxcG0cvJsT70rL+BIGHWVq5fi6MwGrHwzqKaxXE+Hl2GmnGItnDKPPkO5/LQqjVkIdFg==", - "license": "MIT", - "optional": true, - "dependencies": { - "semver": "^7.3.5" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/node-abi/node_modules/semver": { - "version": "7.7.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", - "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", - "license": "ISC", - "optional": true, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/node-addon-api": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz", @@ -7375,16 +7377,6 @@ "dev": true, "license": "MIT" }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "license": "ISC", - "optional": true, - "dependencies": { - "wrappy": "1" - } - }, "node_modules/onetime": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/onetime/-/onetime-7.0.0.tgz", @@ -7562,16 +7554,6 @@ "node": ">=8" } }, - "node_modules/path2d": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/path2d/-/path2d-0.2.2.tgz", - "integrity": "sha512-+vnG6S4dYcYxZd+CZxzXCNKdELYZSKfohrk98yajCo1PtRoDgCTrrwOvK1GT0UoAdVszagDVllQc0U1vaX4NUQ==", - "license": "MIT", - "optional": true, - "engines": { - "node": ">=6" - } - }, "node_modules/pathe": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", @@ -7590,16 +7572,15 @@ } }, "node_modules/pdfjs-dist": { - "version": "4.8.69", - "resolved": "https://registry.npmjs.org/pdfjs-dist/-/pdfjs-dist-4.8.69.tgz", - "integrity": "sha512-IHZsA4T7YElCKNNXtiLgqScw4zPd3pG9do8UrznC757gMd7UPeHSL2qwNNMJo4r79fl8oj1Xx+1nh2YkzdMpLQ==", + "version": "5.4.296", + "resolved": "https://registry.npmjs.org/pdfjs-dist/-/pdfjs-dist-5.4.296.tgz", + "integrity": "sha512-DlOzet0HO7OEnmUmB6wWGJrrdvbyJKftI1bhMitK7O2N8W2gc757yyYBbINy9IDafXAV9wmKr9t7xsTaNKRG5Q==", "license": "Apache-2.0", "engines": { - "node": ">=18" + "node": ">=20.16.0 || >=22.3.0" }, "optionalDependencies": { - "canvas": "^3.0.0-rc2", - "path2d": "^0.2.1" + "@napi-rs/canvas": "^0.1.80" } }, "node_modules/picocolors": { @@ -7694,33 +7675,6 @@ "node": "^10 || ^12 || >=14" } }, - "node_modules/prebuild-install": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.3.tgz", - "integrity": "sha512-8Mf2cbV7x1cXPUILADGI3wuhfqWvtiLA1iclTDbFRZkgRQS0NqsPZphna9V+HyTEadheuPmjaJMsbzKQFOzLug==", - "license": "MIT", - "optional": true, - "dependencies": { - "detect-libc": "^2.0.0", - "expand-template": "^2.0.3", - "github-from-package": "0.0.0", - "minimist": "^1.2.3", - "mkdirp-classic": "^0.5.3", - "napi-build-utils": "^2.0.0", - "node-abi": "^3.3.0", - "pump": "^3.0.0", - "rc": "^1.2.7", - "simple-get": "^4.0.0", - "tar-fs": "^2.0.0", - "tunnel-agent": "^0.6.0" - }, - "bin": { - "prebuild-install": "bin.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", @@ -7800,17 +7754,6 @@ "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", "license": "MIT" }, - "node_modules/pump": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.3.tgz", - "integrity": "sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA==", - "license": "MIT", - "optional": true, - "dependencies": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, "node_modules/punycode": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", @@ -7821,32 +7764,6 @@ "node": ">=6" } }, - "node_modules/rc": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", - "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", - "license": "(BSD-2-Clause OR MIT OR Apache-2.0)", - "optional": true, - "dependencies": { - "deep-extend": "^0.6.0", - "ini": "~1.3.0", - "minimist": "^1.2.0", - "strip-json-comments": "~2.0.1" - }, - "bin": { - "rc": "cli.js" - } - }, - "node_modules/rc/node_modules/strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", - "license": "MIT", - "optional": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/react": { "version": "18.3.1", "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", @@ -7897,17 +7814,17 @@ "peer": true }, "node_modules/react-pdf": { - "version": "9.2.1", - "resolved": "https://registry.npmjs.org/react-pdf/-/react-pdf-9.2.1.tgz", - "integrity": "sha512-AJt0lAIkItWEZRA5d/mO+Om4nPCuTiQ0saA+qItO967DTjmGjnhmF+Bi2tL286mOTfBlF5CyLzJ35KTMaDoH+A==", + "version": "10.4.1", + "resolved": "https://registry.npmjs.org/react-pdf/-/react-pdf-10.4.1.tgz", + "integrity": "sha512-kS/35staVCBqS29verTQJQZXw7RfsRCPO3fdJoW1KXylcv7A9dw6DZ3vJXC2w+bIBgLw5FN4pOFvKSQtkQhPfA==", "license": "MIT", "dependencies": { "clsx": "^2.0.0", "dequal": "^2.0.3", - "make-cancellable-promise": "^1.3.1", - "make-event-props": "^1.6.0", - "merge-refs": "^1.3.0", - "pdfjs-dist": "4.8.69", + "make-cancellable-promise": "^2.0.0", + "make-event-props": "^2.0.0", + "merge-refs": "^2.0.0", + "pdfjs-dist": "5.4.296", "tiny-invariant": "^1.0.0", "warning": "^4.0.0" }, @@ -8011,21 +7928,6 @@ "react": "^16.8.0 || ^17 || ^18" } }, - "node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "license": "MIT", - "optional": true, - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, "node_modules/readdirp": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", @@ -8310,27 +8212,6 @@ "tslib": "^2.1.0" } }, - "node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT", - "optional": true - }, "node_modules/safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", @@ -8801,53 +8682,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/simple-concat": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", - "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT", - "optional": true - }, - "node_modules/simple-get": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz", - "integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT", - "optional": true, - "dependencies": { - "decompress-response": "^6.0.0", - "once": "^1.3.1", - "simple-concat": "^1.0.0" - } - }, "node_modules/slice-ansi": { "version": "7.1.2", "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-7.1.2.tgz", @@ -8982,16 +8816,6 @@ "dev": true, "license": "MIT" }, - "node_modules/string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "license": "MIT", - "optional": true, - "dependencies": { - "safe-buffer": "~5.2.0" - } - }, "node_modules/string-argv": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.2.tgz", @@ -9188,36 +9012,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/tar-fs": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.4.tgz", - "integrity": "sha512-mDAjwmZdh7LTT6pNleZ05Yt65HC3E+NiQzl672vQG38jIrehtJk/J3mNwIg+vShQPcLF/LV7CMnDW6vjj6sfYQ==", - "license": "MIT", - "optional": true, - "dependencies": { - "chownr": "^1.1.1", - "mkdirp-classic": "^0.5.2", - "pump": "^3.0.0", - "tar-stream": "^2.1.4" - } - }, - "node_modules/tar-stream": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", - "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", - "license": "MIT", - "optional": true, - "dependencies": { - "bl": "^4.0.3", - "end-of-stream": "^1.4.1", - "fs-constants": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^3.1.1" - }, - "engines": { - "node": ">=6" - } - }, "node_modules/throttle-debounce": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/throttle-debounce/-/throttle-debounce-3.0.1.tgz", @@ -9466,19 +9260,6 @@ "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", "license": "0BSD" }, - "node_modules/tunnel-agent": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", - "license": "Apache-2.0", - "optional": true, - "dependencies": { - "safe-buffer": "^5.0.1" - }, - "engines": { - "node": "*" - } - }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", @@ -9666,13 +9447,6 @@ "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "license": "MIT", - "optional": true - }, "node_modules/uuid": { "version": "11.1.0", "resolved": "https://registry.npmjs.org/uuid/-/uuid-11.1.0.tgz", @@ -10196,13 +9970,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "license": "ISC", - "optional": true - }, "node_modules/ws": { "version": "8.18.3", "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz", diff --git a/materials_ui/package.json b/materials_ui/package.json index b313c04d..daf5b871 100644 --- a/materials_ui/package.json +++ b/materials_ui/package.json @@ -42,7 +42,7 @@ "react": "^18.0.0", "react-dom": "^18.0.0", "react-hook-form": "^7.56.1", - "react-pdf": "^9.1.0", + "react-pdf": "^10.4.1", "react-router-dom": "^6.25.1", "react-use": "^17.6.0", "react-use-pagination": "^2.0.1", diff --git a/materials_ui/src/components/PdfViewer/PdfViewer.tsx b/materials_ui/src/components/PdfViewer/PdfViewer.tsx index b80ca757..53116bcf 100644 --- a/materials_ui/src/components/PdfViewer/PdfViewer.tsx +++ b/materials_ui/src/components/PdfViewer/PdfViewer.tsx @@ -4,6 +4,7 @@ import { Document, Page, pdfjs } from 'react-pdf'; import 'react-pdf/dist/Page/AnnotationLayer.css'; import 'react-pdf/dist/Page/TextLayer.css'; import { usePagination } from 'react-use-pagination'; +import { usePageColors } from '../../hooks/ui/usePageColors'; import { LoadingSpinner } from '../LoadingSpinner/LoadingSpinner.tsx'; import { Pagination } from '../Pagination/Pagination.tsx'; import './PdfViewer.css'; @@ -18,6 +19,7 @@ export const PdfViewer = ({ file, fileName }: Props) => { const [isLoading, setIsLoading] = useState(true); const { currentPage, setNextPage, setPreviousPage, setPage, totalPages } = usePagination({ initialPageSize: 1, totalItems: numItems }); + const pageColors = usePageColors(); function onDocumentLoadSuccess({ numPages }: { numPages: number }) { setNumItems(numPages); @@ -39,9 +41,7 @@ export const PdfViewer = ({ file, fileName }: Props) => { className="pdf-page-container" file={file} onLoadSuccess={onDocumentLoadSuccess} - loading={ - - } + loading={} aria-label={ isLoading ? `The document preview for ${fileName} is loading. Please wait.` @@ -61,6 +61,7 @@ export const PdfViewer = ({ file, fileName }: Props) => { pageNumber={currentPage + 1} renderTextLayer={true} renderAnnotationLayer={true} + pageColors={pageColors} />
+ Boolean(window.matchMedia?.(FORCED_COLORS_QUERY).matches) + ); + + useEffect(() => { + const mql = window.matchMedia?.(FORCED_COLORS_QUERY); + if (!mql) return; + + const onChange = (e: MediaQueryListEvent) => setIsForcedColors(e.matches); + mql.addEventListener('change', onChange); + return () => mql.removeEventListener('change', onChange); + }, []); + + return isForcedColors ? HIGH_CONTRAST_PAGE_COLORS : undefined; +} diff --git a/materials_ui/src/materials_components/PdfRedactor/PdfRedactor.tsx b/materials_ui/src/materials_components/PdfRedactor/PdfRedactor.tsx index fe06f856..8a2fac7b 100644 --- a/materials_ui/src/materials_components/PdfRedactor/PdfRedactor.tsx +++ b/materials_ui/src/materials_components/PdfRedactor/PdfRedactor.tsx @@ -2,6 +2,8 @@ import type { PDFDocumentProxy } from 'pdfjs-dist'; import pdfWorker from 'pdfjs-dist/build/pdf.worker?url'; import { useEffect, useMemo, useRef, useState } from 'react'; import { Document, pdfjs } from 'react-pdf'; +import 'react-pdf/dist/Page/AnnotationLayer.css'; +import 'react-pdf/dist/Page/TextLayer.css'; import { safeJsonParse } from '../DocumentSelectAccordion/utils/generalUtils'; import { useDocumentFocus } from './hooks/useDocumentFocus'; import { useShiftReleaseRedactTrigger } from './hooks/useShiftReleaseRedactTrigger'; @@ -21,8 +23,6 @@ import type { TSearchHighlight } from './utils/searchHighlightUtils'; import { useTrigger } from './utils/useTriggger'; -import '/node_modules/react-pdf/dist/cjs/Page/AnnotationLayer.css'; -import '/node_modules/react-pdf/dist/cjs/Page/TextLayer.css'; pdfjs.GlobalWorkerOptions.workerSrc = pdfWorker; diff --git a/materials_ui/src/materials_components/PdfRedactor/PdfRedactorPage.scss b/materials_ui/src/materials_components/PdfRedactor/PdfRedactorPage.scss index bc88b8f7..a85a5665 100644 --- a/materials_ui/src/materials_components/PdfRedactor/PdfRedactorPage.scss +++ b/materials_ui/src/materials_components/PdfRedactor/PdfRedactorPage.scss @@ -12,3 +12,26 @@ user-select: none; pointer-events: none; } + +// keep the redaction boxes and highlights visible when the OS is in high-contrast mode. +@media (forced-colors: active) { + .react-pdf-page-wrapper .textLayer { + mix-blend-mode: normal; + } + + .react-pdf-page-wrapper::selection, + .react-pdf-page-wrapper ::selection { + background-color: Highlight; + color: HighlightText; + } + + .react-pdf-page-wrapper .redaction-box { + background: transparent !important; + border: 2px solid CanvasText !important; + } + + .react-pdf-page-wrapper [data-text-highlight-id] { + background: transparent !important; + border-color: Highlight !important; + } +} diff --git a/materials_ui/src/materials_components/PdfRedactor/PdfRedactorPage.tsx b/materials_ui/src/materials_components/PdfRedactor/PdfRedactorPage.tsx index f460dbcf..d4e86b12 100644 --- a/materials_ui/src/materials_components/PdfRedactor/PdfRedactorPage.tsx +++ b/materials_ui/src/materials_components/PdfRedactor/PdfRedactorPage.tsx @@ -5,6 +5,7 @@ import { type MouseEvent as ReactMouseEvent } from 'react'; import { Page } from 'react-pdf'; +import { usePageColors } from '../../hooks/ui/usePageColors'; import { DocumentIcon } from './icons/DocumentIcon'; import { RotateIcon } from './icons/RotateIcon'; import { @@ -362,6 +363,7 @@ export const PdfRedactorPage = (p: { highlightLayers?: THighlightLayer[]; }) => { const { pageNumber, scale, redactions } = p; + const pageColors = usePageColors(); const [pageDimensions, setPageDimensions] = useState<{ width: number; height: number; @@ -513,6 +515,7 @@ export const PdfRedactorPage = (p: { > { const canvas = pdfPageWrapperElmRef.current?.querySelector( '.react-pdf__Page__canvas' diff --git a/materials_ui/src/pages/ViewDocumentPage.tsx b/materials_ui/src/pages/ViewDocumentPage.tsx index ec8d03a8..b2d879a9 100644 --- a/materials_ui/src/pages/ViewDocumentPage.tsx +++ b/materials_ui/src/pages/ViewDocumentPage.tsx @@ -4,6 +4,7 @@ import { Document, Page, pdfjs } from 'react-pdf'; import { useParams } from 'react-router-dom'; import { LoadingSpinner } from '../components'; import { useDocumentPdfUrl } from '../hooks/documents/useDocumentPdfUrl'; +import { usePageColors } from '../hooks/ui/usePageColors'; import { useAxiosInstance } from '../materials_components/DocumentSelectAccordion/getters/getAxiosInstance'; import { safeGetDocumentListFromAxiosInstance, @@ -46,6 +47,7 @@ const LoadAndViewPdf = (p: { const { data: pdfUrl } = useDocumentPdfUrl(p); const { data: documentList } = useDocumentListFromAxiosInstance(p); const [numPages, setNumPages] = useState(); + const pageColors = usePageColors(); useEffect(() => { const cmsStrippedMaterialId = stripCmsPrefix(p.materialId); @@ -86,7 +88,7 @@ const LoadAndViewPdf = (p: { } > {[...Array(numPages)].map((_, j) => ( - + ))} )} From 2d6b9c175e94fc8acc8f65a5896f03cf825acec8 Mon Sep 17 00:00:00 2001 From: dbarber-cps Date: Wed, 8 Jul 2026 13:41:28 +0100 Subject: [PATCH 06/28] added variables into build to support app insights logging (#435) --- materials_devops_pipelines/Materials-UI-Build-Dev.yml | 4 ++++ materials_devops_pipelines/Materials-UI-Build-Prod.yml | 6 +++++- materials_devops_pipelines/Materials-UI-Build-Staging.yml | 4 ++++ 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/materials_devops_pipelines/Materials-UI-Build-Dev.yml b/materials_devops_pipelines/Materials-UI-Build-Dev.yml index aa76b78a..811d3036 100644 --- a/materials_devops_pipelines/Materials-UI-Build-Dev.yml +++ b/materials_devops_pipelines/Materials-UI-Build-Dev.yml @@ -26,6 +26,7 @@ variables: value: "materials_ui" - group: materials-global - group: materials-ui-spa-dev + - group: materials-kv-dev-terraform pool: name: $(dev-build-agent) @@ -94,6 +95,9 @@ stages: VITE_GLOBAL_SCRIPT_URL: $(GLOBAL_SCRIPT_URL) VITE_REDACTION_LOG_URL: $(VITE_REDACTION_LOG_URL) VITE_REDACTION_LOG_SCOPE: $(VITE_REDACTION_LOG_SCOPE) + VITE_APPLICATIONINSIGHTS_CONNECTION_STRING: $(innovation-development-app-insights-instrumentation-key) + VITE_APPLICATIONINSIGHTS_SAMPLING_PERCENTAGE: $(APPLICATIONINSIGHTS_SAMPLING_PERCENTAGE) + VITE_APPLICATIONINSIGHTS_CLOUD_ROLE: $(APPLICATIONINSIGHTS_CLOUD_ROLE) - task: replacetokens@5 displayName: "Set environment specific CSP in serve.json" diff --git a/materials_devops_pipelines/Materials-UI-Build-Prod.yml b/materials_devops_pipelines/Materials-UI-Build-Prod.yml index 305e6f19..0a2bdc95 100644 --- a/materials_devops_pipelines/Materials-UI-Build-Prod.yml +++ b/materials_devops_pipelines/Materials-UI-Build-Prod.yml @@ -26,6 +26,7 @@ variables: value: "materials_ui" - group: materials-global - group: materials-ui-spa-prod + - group: materials-kv-prod-terraform pool: name: $(prod-build-agent) @@ -94,7 +95,10 @@ stages: VITE_GLOBAL_SCRIPT_URL: $(GLOBAL_SCRIPT_URL) VITE_REDACTION_LOG_URL: $(VITE_REDACTION_LOG_URL) VITE_REDACTION_LOG_SCOPE: $(VITE_REDACTION_LOG_SCOPE) - + VITE_APPLICATIONINSIGHTS_CONNECTION_STRING: $(innovation-prod-app-insights-instrumentation-key) + VITE_APPLICATIONINSIGHTS_SAMPLING_PERCENTAGE: $(APPLICATIONINSIGHTS_SAMPLING_PERCENTAGE) + VITE_APPLICATIONINSIGHTS_CLOUD_ROLE: $(APPLICATIONINSIGHTS_CLOUD_ROLE) + - task: replacetokens@5 displayName: "Set environment specific CSP in serve.json" inputs: diff --git a/materials_devops_pipelines/Materials-UI-Build-Staging.yml b/materials_devops_pipelines/Materials-UI-Build-Staging.yml index f4a63349..604a68cc 100644 --- a/materials_devops_pipelines/Materials-UI-Build-Staging.yml +++ b/materials_devops_pipelines/Materials-UI-Build-Staging.yml @@ -26,6 +26,7 @@ variables: value: "materials_ui" - group: materials-global - group: materials-ui-spa-stg + - group: materials-kv-stg-terraform pool: name: $(stg-build-agent) @@ -94,6 +95,9 @@ stages: VITE_GLOBAL_SCRIPT_URL: $(GLOBAL_SCRIPT_URL) VITE_REDACTION_LOG_URL: $(VITE_REDACTION_LOG_URL) VITE_REDACTION_LOG_SCOPE: $(VITE_REDACTION_LOG_SCOPE) + VITE_APPLICATIONINSIGHTS_CONNECTION_STRING: $(innovation-qa-app-insights-instrumentation-key) + VITE_APPLICATIONINSIGHTS_SAMPLING_PERCENTAGE: $(APPLICATIONINSIGHTS_SAMPLING_PERCENTAGE) + VITE_APPLICATIONINSIGHTS_CLOUD_ROLE: $(APPLICATIONINSIGHTS_CLOUD_ROLE) - task: replacetokens@5 displayName: "Set environment specific CSP in serve.json" From dd455a9e1e2b075f6a5ce96373b2149e10ff5edd Mon Sep 17 00:00:00 2001 From: afeescps Date: Thu, 9 Jul 2026 11:18:43 +0100 Subject: [PATCH 07/28] feat(tracking): track user actions, roles and time in telemetry (#432) * feat(tracking): track user actions, roles and time in telemetry - Emit completion-based UserAction events (Reclassified, Updated, Discarded, Renamed, Redacted, UpdatedAutomatically, OpenedInNewWindow) with materialId/category context; View-in-new-window fires on click - Capture page and per-tab dwell time; stamp MSAL user role on all items - Sample non-exceptions (default 20%) while keeping exceptions and actions; set cloud role name from env - Normalise route names to strip case URN/id * fix(tracking): send materialId as string in action telemetry Numeric materialId was routed into customMeasurements by the SDK while the reader/redact screens sent it as a string in customDimensions. Cast to string at all numeric call sites so it's consistently a dimension. * fix(materials-ui): resolve ambiguous JSX spacing in discard caption (S6772) Move the trailing space out of the visually-hidden span into an explicit {' '} so the caption spacing is unambiguous. Output unchanged. * refactor(materials-ui): clarify route-normalisation helper in telemetry Rename normalisePath to stripCaseIdsFromRoute and extract the two regexes into named constants (CASE_URN_AND_ID, NUMERIC_ID_SEGMENT) for readability. No behaviour change. --- materials_ui/src/app.tsx | 8 ++ .../ReviewAndRedactPage.tsx | 10 ++ .../Button/AutoReclassifyButton.tsx | 2 + .../src/components/Drawer/RenameDrawer.tsx | 13 ++- .../CaseworkPdfRedactorWrapper.tsx | 2 + materials_ui/src/pages/Communications.tsx | 5 + materials_ui/src/pages/DiscardMaterial.tsx | 103 +++++++++--------- materials_ui/src/pages/EditMaterial.tsx | 5 + materials_ui/src/pages/Materials.tsx | 5 + materials_ui/src/pages/Reclassification.tsx | 5 + materials_ui/src/telemetry/appInsights.ts | 37 ++++++- 11 files changed, 140 insertions(+), 55 deletions(-) diff --git a/materials_ui/src/app.tsx b/materials_ui/src/app.tsx index 1997d9ec..1e7b509c 100644 --- a/materials_ui/src/app.tsx +++ b/materials_ui/src/app.tsx @@ -3,6 +3,7 @@ import { useEffect } from 'react'; import { RouteChangeListener } from './components'; import { loginRequest } from './msalInstance'; import { Routes } from './routes'; +import { setTelemetryUserRole } from './telemetry/appInsights'; export const App = () => { const { instance, accounts } = useMsal(); @@ -14,6 +15,13 @@ export const App = () => { }, [instance, accounts]); const account = instance.getActiveAccount() || accounts[0]; + const role = (account?.idTokenClaims?.roles as string[] | undefined)?.join( + ',' + ); + + useEffect(() => { + if (role) setTelemetryUserRole(role); + }, [role]); if (!account) { return

Redirecting to login...

; diff --git a/materials_ui/src/caseWorkApp/pages/ReviewAndRedactPage/ReviewAndRedactPage.tsx b/materials_ui/src/caseWorkApp/pages/ReviewAndRedactPage/ReviewAndRedactPage.tsx index a13b814c..7b11bf4d 100644 --- a/materials_ui/src/caseWorkApp/pages/ReviewAndRedactPage/ReviewAndRedactPage.tsx +++ b/materials_ui/src/caseWorkApp/pages/ReviewAndRedactPage/ReviewAndRedactPage.tsx @@ -31,6 +31,7 @@ import { convertMatchesToSearchHighlights } from '../../../materials_components/ import { useTrigger } from '../../../materials_components/PdfRedactor/utils/useTriggger'; import { RedactionLogModal } from '../../../materials_components/RedactionLog/RedactionLogModal'; import type { SearchTermResultType } from '../../../schemas/documents'; +import { trackAction, trackMetric } from '../../../telemetry/appInsights'; import { Tabs } from '../../components/tabs'; import { getLookups, useAxiosInstances } from '../../components/utils/getData'; import { useSwitchContentArea } from '../../hooks/useSwitchContentArea'; @@ -365,6 +366,12 @@ export const ReviewAndRedactPage = () => { const activeTabId = activeParentId || openParentIds[0] || ''; + useEffect(() => { + if (!activeTabId) return; + const start = Date.now(); + return () => trackMetric('TabViewTime', Date.now() - start); + }, [activeTabId]); + const activeDocument = openDocuments.find( (doc) => doc.parentId === activeTabId ); @@ -504,6 +511,9 @@ export const ReviewAndRedactPage = () => { onRedactionLogClick={() => setShowRedactionLogModal(true)} onViewInNewWindowClick={() => { if (!urn || !caseId) return; + trackAction('OpenedInNewWindow', { + materialId: activeTabId + }); navigateToViewDocumentPageInNewTab({ urn, caseId, diff --git a/materials_ui/src/components/Button/AutoReclassifyButton.tsx b/materials_ui/src/components/Button/AutoReclassifyButton.tsx index 7d408447..b01ef3a7 100644 --- a/materials_ui/src/components/Button/AutoReclassifyButton.tsx +++ b/materials_ui/src/components/Button/AutoReclassifyButton.tsx @@ -2,6 +2,7 @@ import { useState } from 'react'; import { useAutoReclassify, useBanner, useCaseMaterials } from '../../hooks'; import { useMaterialTags } from '../../stores'; +import { trackAction } from '../../telemetry/appInsights'; export const AutoReclassifyButton = () => { const [errorCount, setErrorCount] = useState(0); @@ -45,6 +46,7 @@ export const AutoReclassifyButton = () => { }, onSuccess: async (data) => { const totalMaterialsProcessed = data.reclassifiedMaterials.length || 1; + trackAction('UpdatedAutomatically', { count: totalMaterialsProcessed }); setTags( data?.reclassifiedMaterials?.map((material) => ({ diff --git a/materials_ui/src/components/Drawer/RenameDrawer.tsx b/materials_ui/src/components/Drawer/RenameDrawer.tsx index 04386511..57b3717f 100644 --- a/materials_ui/src/components/Drawer/RenameDrawer.tsx +++ b/materials_ui/src/components/Drawer/RenameDrawer.tsx @@ -2,6 +2,7 @@ import { ChangeEvent, FormEvent, useState } from 'react'; import { useRename } from '../../hooks'; import { TDocument } from '../../materials_components/DocumentSelectAccordion/getters/getDocumentList'; import { CaseMaterialsType } from '../../schemas'; +import { trackAction } from '../../telemetry/appInsights'; import { LoadingSpinner } from '../LoadingSpinner/LoadingSpinner'; import Drawer from './Drawer'; @@ -13,7 +14,17 @@ type Props = { export const RenameDrawer = ({ material, onCancel, onSuccess }: Props) => { const { isMutating, trigger: renameMaterial } = useRename(material, { - onSuccess + onSuccess: () => { + trackAction('Renamed', { + materialId: + material && 'materialId' in material + ? material.materialId?.toString() + : undefined, + category: + material && 'category' in material ? material.category : undefined + }); + onSuccess(); + } }); const [error, setError] = useState(''); diff --git a/materials_ui/src/materials_components/CaseworkPdfRedactorWrapper/CaseworkPdfRedactorWrapper.tsx b/materials_ui/src/materials_components/CaseworkPdfRedactorWrapper/CaseworkPdfRedactorWrapper.tsx index bb15340a..e2501bc2 100644 --- a/materials_ui/src/materials_components/CaseworkPdfRedactorWrapper/CaseworkPdfRedactorWrapper.tsx +++ b/materials_ui/src/materials_components/CaseworkPdfRedactorWrapper/CaseworkPdfRedactorWrapper.tsx @@ -1,5 +1,6 @@ import { ComponentProps, useEffect, useState } from 'react'; import { Button } from '../../caseWorkApp/components/button'; +import { trackAction } from '../../telemetry/appInsights'; import { useAxiosInstance } from '../DocumentSelectAccordion/getters/getAxiosInstance'; import { TDocument } from '../DocumentSelectAccordion/getters/getDocumentList'; import { GovUkBanner } from '../DocumentSelectAccordion/templates/GovUkBanner'; @@ -404,6 +405,7 @@ export const CaseworkPdfRedactorWrapper = (p: { redactions }); setRedactions([]); + trackAction('Redacted', { materialId: p.parentId }); p.onRedactionSaveStatusChange('saved'); if (p.document) p.onModification(p.document); await documentCheckOutRequest.checkIn({ diff --git a/materials_ui/src/pages/Communications.tsx b/materials_ui/src/pages/Communications.tsx index c4950e75..185c65ed 100644 --- a/materials_ui/src/pages/Communications.tsx +++ b/materials_ui/src/pages/Communications.tsx @@ -25,6 +25,7 @@ import { useMaterialTags, useSelectedItemsStore } from '../stores'; +import { trackAction } from '../telemetry/appInsights'; export const CommunicationsPage = () => { const [selectedMaterial, setSelectedMaterial] = @@ -95,6 +96,10 @@ export const CommunicationsPage = () => { const caseId = caseInfo?.id; if (!materialId || !urn || !caseId) return; + trackAction('OpenedInNewWindow', { + materialId: row?.materialId?.toString(), + category: row?.category + }); navigateToViewDocumentPageInNewTab({ urn, caseId, materialId }); }; diff --git a/materials_ui/src/pages/DiscardMaterial.tsx b/materials_ui/src/pages/DiscardMaterial.tsx index 261828d6..18a6bce4 100644 --- a/materials_ui/src/pages/DiscardMaterial.tsx +++ b/materials_ui/src/pages/DiscardMaterial.tsx @@ -5,6 +5,7 @@ import { DISCARD_MATERIAL_OPTIONS } from '../constants'; import { Layout, LoadingSpinner, RadioOption, Radios } from '../components'; import { URL } from '../constants/url'; import { useAppRoute, useBanner, useCaseMaterials, useDiscard } from '../hooks'; +import { trackAction } from '../telemetry/appInsights'; export const DiscardMaterialPage = () => { const { getRoute } = useAppRoute(); @@ -24,6 +25,10 @@ export const DiscardMaterialPage = () => { const { isLoading: isDiscarding, trigger } = useDiscard(material, { onSuccess: async () => { + trackAction('Discarded', { + materialId: material?.materialId?.toString(), + category: material?.category + }); setError(''); navigate(returnTo, { state: { persistBanner: true } }); @@ -79,56 +84,56 @@ export const DiscardMaterialPage = () => { <> {!isDiscarding && ( - - { - e.preventDefault(); - navigate(-1); - }} - className="govuk-back-link" - > - Back - - -
-

- This section is Discard - material -

-

Reason for discarding material

- -
- ({ - ...option, - id: option.value - }))} - value={reason?.value as string} - required - /> - -
- - - Cancel - + + { + e.preventDefault(); + navigate(-1); + }} + className="govuk-back-link" + > + Back + + +
+

+ This section is{' '} + Discard material +

+

Reason for discarding material

+ + + ({ + ...option, + id: option.value + }))} + value={reason?.value as string} + required + /> + +
+ + + Cancel + +
+
- -
- + )} ); diff --git a/materials_ui/src/pages/EditMaterial.tsx b/materials_ui/src/pages/EditMaterial.tsx index 5eb34508..177e241c 100644 --- a/materials_ui/src/pages/EditMaterial.tsx +++ b/materials_ui/src/pages/EditMaterial.tsx @@ -19,6 +19,7 @@ import { EditStatementType } from '../schemas/forms/editStatement'; import { useMaterialTags } from '../stores'; +import { trackAction } from '../telemetry/appInsights'; type EditMaterialLocationState = { returnTo: string; row: CaseMaterialsType }; type FormStep = 'form' | 'summary'; @@ -46,6 +47,10 @@ export const EditMaterialPage = () => { }); }, onSuccess: (response) => { + trackAction('Updated', { + materialId: row?.materialId?.toString(), + category: row?.category + }); setTags([{ materialId: response?.materialId, tagName: 'Updated' }]); setBanner( { diff --git a/materials_ui/src/pages/Materials.tsx b/materials_ui/src/pages/Materials.tsx index b8612c0e..14c2c1e2 100644 --- a/materials_ui/src/pages/Materials.tsx +++ b/materials_ui/src/pages/Materials.tsx @@ -28,6 +28,7 @@ import { useNavigate } from 'react-router-dom'; import { URL } from '../constants/url'; import { navigateToViewDocumentPageInNewTab } from '../hooks/ui/navigateToViewDocumentPageInNewTab'; import { CaseMaterialsType } from '../schemas'; +import { trackAction } from '../telemetry/appInsights'; export const MaterialsPage = () => { const { getRoute } = useAppRoute(); @@ -110,6 +111,10 @@ export const MaterialsPage = () => { const urn = caseInfo?.urn; const caseId = caseInfo?.id; if (!urn || !caseId) return; + trackAction('OpenedInNewWindow', { + materialId: materialId.toString(), + category: item.category + }); navigateToViewDocumentPageInNewTab({ urn, caseId, materialId }); } }; diff --git a/materials_ui/src/pages/Reclassification.tsx b/materials_ui/src/pages/Reclassification.tsx index 0aeb1769..2dddd171 100644 --- a/materials_ui/src/pages/Reclassification.tsx +++ b/materials_ui/src/pages/Reclassification.tsx @@ -32,6 +32,7 @@ import { Reclassify_WitnessAndActionPlanType } from '../schemas/forms/reclassify'; import { useMaterialTags } from '../stores'; +import { trackAction } from '../telemetry/appInsights'; import { formatDate } from '../utils/date'; import { getBannerData } from '../utils/reclassify'; @@ -84,6 +85,10 @@ export const ReclassificationPage = () => { }); if (response.data.status !== 'Failed') { + trackAction('Reclassified', { + materialId: material.materialId?.toString(), + category: material.category + }); const documentType = getDocumentTypeById(fieldValues.documentType); const materialReclassifiedId = response?.data?.reclassificationResult?.resultData diff --git a/materials_ui/src/telemetry/appInsights.ts b/materials_ui/src/telemetry/appInsights.ts index dd95fbd9..aeced5cc 100644 --- a/materials_ui/src/telemetry/appInsights.ts +++ b/materials_ui/src/telemetry/appInsights.ts @@ -10,10 +10,23 @@ const samplingPercentage = Number(import.meta.env.VITE_APPLICATIONINSIGHTS_SAMPLING_PERCENTAGE) || 20; let appInsights: ApplicationInsights | undefined; +let userRole: string | undefined; const normaliseError = (error: unknown): Error => error instanceof Error ? error : new Error(String(error)); +// A route looks like ///, sometimes with deeper numeric +// ids (e.g. /materials/8923052). Those identify a specific case/document, so +// we replace them with placeholders before sending telemetry: page views then +// group by route (e.g. /:urn/:caseId/materials) instead of leaking case data. +const CASE_URN_AND_ID = /^\/[^/]+\/[^/]+/; // leading // +const NUMERIC_ID_SEGMENT = /\/\d+/g; // any / segment + +const stripCaseIdsFromRoute = (path: string): string => + path + .replace(CASE_URN_AND_ID, '/:urn/:caseId') + .replace(NUMERIC_ID_SEGMENT, '/:id'); + export const initTelemetry = () => { if (appInsights || !connectionString) return; @@ -21,13 +34,14 @@ export const initTelemetry = () => { config: { connectionString, enableAutoRouteTracking: false, - enableUnhandledPromiseRejectionTracking: true + enableUnhandledPromiseRejectionTracking: true, + autoTrackPageVisitTime: true } }); appInsights.loadAppInsights(); // Sample non-exceptions ourselves so we never drop exceptions. One roll per - // load keeps a page's telemetry together. + // load keeps a page's telemetry together. Actions (events) are kept too. const retainNonException = Math.random() * 100 < samplingPercentage; appInsights.addTelemetryInitializer((item) => { @@ -36,7 +50,12 @@ export const initTelemetry = () => { item.tags['ai.cloud.role'] = cloudRole; } - if (item.baseType === 'ExceptionData') { + if (userRole) { + item.data ??= {}; + item.data.userRole = userRole; + } + + if (item.baseType === 'ExceptionData' || item.baseType === 'EventData') { return true; } @@ -44,14 +63,22 @@ export const initTelemetry = () => { }); }; +export const setTelemetryUserRole = (role: string) => { + userRole = role; +}; + export const trackPageView = (pathname: string) => { if (!appInsights) return; + const name = stripCaseIdsFromRoute(pathname); // Manual SPA tracking doesn't refresh operation name; it stays on the first // page unless we set it ourselves, so telemetry groups under the wrong route. - appInsights.context.telemetryTrace.name = pathname; - appInsights.trackPageView({ name: pathname }); + appInsights.context.telemetryTrace.name = name; + appInsights.trackPageView({ name }); }; +export const trackAction = (action: string, properties?: ICustomProperties) => + appInsights?.trackEvent({ name: 'UserAction' }, { action, ...properties }); + export const trackEvent = (name: string, properties?: ICustomProperties) => appInsights?.trackEvent({ name }, properties); From f5c6cdedbd976d42a127f08f9a6820b42e221bbf Mon Sep 17 00:00:00 2001 From: dbarber-cps Date: Fri, 10 Jul 2026 11:04:26 +0100 Subject: [PATCH 08/28] updating appinsights connection string (#437) --- materials_devops_pipelines/Materials-UI-Build-Dev.yml | 2 +- materials_devops_pipelines/Materials-UI-Build-Prod.yml | 2 +- materials_devops_pipelines/Materials-UI-Build-Staging.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/materials_devops_pipelines/Materials-UI-Build-Dev.yml b/materials_devops_pipelines/Materials-UI-Build-Dev.yml index 811d3036..1f35a08c 100644 --- a/materials_devops_pipelines/Materials-UI-Build-Dev.yml +++ b/materials_devops_pipelines/Materials-UI-Build-Dev.yml @@ -95,7 +95,7 @@ stages: VITE_GLOBAL_SCRIPT_URL: $(GLOBAL_SCRIPT_URL) VITE_REDACTION_LOG_URL: $(VITE_REDACTION_LOG_URL) VITE_REDACTION_LOG_SCOPE: $(VITE_REDACTION_LOG_SCOPE) - VITE_APPLICATIONINSIGHTS_CONNECTION_STRING: $(innovation-development-app-insights-instrumentation-key) + VITE_APPLICATIONINSIGHTS_CONNECTION_STRING: $(innovation-development-app-insights-connection-string) VITE_APPLICATIONINSIGHTS_SAMPLING_PERCENTAGE: $(APPLICATIONINSIGHTS_SAMPLING_PERCENTAGE) VITE_APPLICATIONINSIGHTS_CLOUD_ROLE: $(APPLICATIONINSIGHTS_CLOUD_ROLE) diff --git a/materials_devops_pipelines/Materials-UI-Build-Prod.yml b/materials_devops_pipelines/Materials-UI-Build-Prod.yml index 0a2bdc95..475a5218 100644 --- a/materials_devops_pipelines/Materials-UI-Build-Prod.yml +++ b/materials_devops_pipelines/Materials-UI-Build-Prod.yml @@ -95,7 +95,7 @@ stages: VITE_GLOBAL_SCRIPT_URL: $(GLOBAL_SCRIPT_URL) VITE_REDACTION_LOG_URL: $(VITE_REDACTION_LOG_URL) VITE_REDACTION_LOG_SCOPE: $(VITE_REDACTION_LOG_SCOPE) - VITE_APPLICATIONINSIGHTS_CONNECTION_STRING: $(innovation-prod-app-insights-instrumentation-key) + VITE_APPLICATIONINSIGHTS_CONNECTION_STRING: $(innovation-prod-app-insights-connection-string) VITE_APPLICATIONINSIGHTS_SAMPLING_PERCENTAGE: $(APPLICATIONINSIGHTS_SAMPLING_PERCENTAGE) VITE_APPLICATIONINSIGHTS_CLOUD_ROLE: $(APPLICATIONINSIGHTS_CLOUD_ROLE) diff --git a/materials_devops_pipelines/Materials-UI-Build-Staging.yml b/materials_devops_pipelines/Materials-UI-Build-Staging.yml index 604a68cc..52524469 100644 --- a/materials_devops_pipelines/Materials-UI-Build-Staging.yml +++ b/materials_devops_pipelines/Materials-UI-Build-Staging.yml @@ -95,7 +95,7 @@ stages: VITE_GLOBAL_SCRIPT_URL: $(GLOBAL_SCRIPT_URL) VITE_REDACTION_LOG_URL: $(VITE_REDACTION_LOG_URL) VITE_REDACTION_LOG_SCOPE: $(VITE_REDACTION_LOG_SCOPE) - VITE_APPLICATIONINSIGHTS_CONNECTION_STRING: $(innovation-qa-app-insights-instrumentation-key) + VITE_APPLICATIONINSIGHTS_CONNECTION_STRING: $(innovation-qa-app-insights-connection-string) VITE_APPLICATIONINSIGHTS_SAMPLING_PERCENTAGE: $(APPLICATIONINSIGHTS_SAMPLING_PERCENTAGE) VITE_APPLICATIONINSIGHTS_CLOUD_ROLE: $(APPLICATIONINSIGHTS_CLOUD_ROLE) From 84c34d9fceca9cd07d0ecd22aa77b4dd5a327c27 Mon Sep 17 00:00:00 2001 From: abdul-cps Date: Fri, 10 Jul 2026 11:36:52 +0100 Subject: [PATCH 09/28] fix filtr tests (#438) Co-authored-by: abdul-cps --- materials_ui/tests/tests-e2e/communications.spec.ts | 6 +++--- materials_ui/tests/tests-e2e/materials.spec.ts | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/materials_ui/tests/tests-e2e/communications.spec.ts b/materials_ui/tests/tests-e2e/communications.spec.ts index 8bde02a0..235e0282 100644 --- a/materials_ui/tests/tests-e2e/communications.spec.ts +++ b/materials_ui/tests/tests-e2e/communications.spec.ts @@ -111,10 +111,10 @@ test.describe('Communications page', () => { // hide filter test('T-007: user is able to hide filter', async ({ page }) => { - await page.getByRole('button', { name: 'Hide filter' }).click(); - await expect(page.getByText('FiltersClear filtersSearch')).toBeHidden(); + await page.getByRole('button', { name: 'Hide filters' }).click(); + await expect(page.getByText('Search communications')).toBeHidden(); await page.getByRole('button', { name: 'Show filter' }).click(); - await expect(page.getByText('FiltersClear filtersSearch')).toBeVisible(); + await expect(page.getByText('Search communications')).toBeVisible(); }); // search diff --git a/materials_ui/tests/tests-e2e/materials.spec.ts b/materials_ui/tests/tests-e2e/materials.spec.ts index e6b581c3..c67c4258 100644 --- a/materials_ui/tests/tests-e2e/materials.spec.ts +++ b/materials_ui/tests/tests-e2e/materials.spec.ts @@ -139,10 +139,10 @@ test.describe('Materials page', () => { test('T-008: user is able to hide filter', async ({ page }) => { mockRoute(page, '/case-materials', mockCaseMaterials()); - await page.getByRole('button', { name: 'Hide filter' }).click(); - await expect(page.getByText('FiltersClear filtersSearch')).toBeHidden(); - await page.getByRole('button', { name: 'Show filter' }).click(); - await expect(page.getByText('FiltersClear filtersSearch')).toBeVisible(); + await page.getByRole('button', { name: 'Hide filters' }).click(); + await expect(page.getByText('Search materials')).toBeHidden(); + await page.getByRole('button', { name: 'Show filters' }).click(); + await expect(page.getByText('Search materials')).toBeVisible(); }); // search From 6d7379512c38f63c502686735fb2f3c6d9f4d682 Mon Sep 17 00:00:00 2001 From: afeescps Date: Fri, 10 Jul 2026 12:36:30 +0100 Subject: [PATCH 10/28] feat(relabelling): Re-label Search screen field names in Materials & Comms tabs (#436) * feat(relabelling): Re-label Search screen field names in Materials & Comms tabs * test: use corrector selector value * test: use corrector selector API --- .../src/components/Filters/CommsFilters.tsx | 3 +- .../components/Filters/MaterialsFilters.tsx | 2 +- .../SortableTable/CaseMaterialsTable.tsx | 164 +++++++++--------- .../tests/tests-e2e/communications.spec.ts | 8 +- .../tests/tests-e2e/materials.spec.ts | 6 +- 5 files changed, 88 insertions(+), 95 deletions(-) diff --git a/materials_ui/src/components/Filters/CommsFilters.tsx b/materials_ui/src/components/Filters/CommsFilters.tsx index 00710e16..980b1850 100644 --- a/materials_ui/src/components/Filters/CommsFilters.tsx +++ b/materials_ui/src/components/Filters/CommsFilters.tsx @@ -61,10 +61,9 @@ export const CommsFilters = () => { onSubmit={handleFiltersSubmit} onReset={resetFilters} onSearchChange={handleSearchChange} - searchLabel="Search communications" + searchLabel="Subject" defaultSearchValue={filters?.search || ''} > - {hasAccess([1, 2, 3, 4, 5]) && (
diff --git a/materials_ui/src/components/Filters/MaterialsFilters.tsx b/materials_ui/src/components/Filters/MaterialsFilters.tsx index 4faa1dbd..cd477d96 100644 --- a/materials_ui/src/components/Filters/MaterialsFilters.tsx +++ b/materials_ui/src/components/Filters/MaterialsFilters.tsx @@ -41,7 +41,7 @@ export const MaterialsFilters = () => { onSubmit={handleFiltersSubmit} onReset={resetFilters} onSearchChange={handleSearchChange} - searchLabel="Search materials" + searchLabel="Material name" defaultSearchValue={filters?.search || ''} > {hasAccess([2, 3, 4, 5]) && ( diff --git a/materials_ui/src/components/SortableTable/CaseMaterialsTable.tsx b/materials_ui/src/components/SortableTable/CaseMaterialsTable.tsx index 33152cf6..b8c7c993 100644 --- a/materials_ui/src/components/SortableTable/CaseMaterialsTable.tsx +++ b/materials_ui/src/components/SortableTable/CaseMaterialsTable.tsx @@ -17,12 +17,7 @@ import { DEFAULT_RESULTS_PER_PAGE } from '../../constants/query'; import { READ_STATUS } from '../../constants'; import { formatDate } from '../../utils/date'; -import { - DocumentPreview, - LoadingSpinner, - Pagination, - StatusTag -} from '..'; +import { DocumentPreview, LoadingSpinner, Pagination, StatusTag } from '..'; import { useMaterialTags } from '../../stores'; export const CaseMaterialsTable = () => { @@ -37,57 +32,56 @@ export const CaseMaterialsTable = () => { const columns = useMemo[]>( () => [ - { - key: 'subject', - heading: 'Material', - render: (row) => ( - <> - {row.readStatus == READ_STATUS.UNREAD && } - {row.subject} - {row.statusLabel && } - - ), - isSortable: true - }, - { - key: 'type', - heading: 'Type', - isSortable: true, - sortFn: ({ type: leftType }, { type: rightType }, direction) => { - const compareResult = leftType.localeCompare( - rightType, - undefined, - { numeric: true, sensitivity: 'base' } - ); - return direction === 'ascending' ? compareResult : -compareResult; + { + key: 'subject', + heading: 'Material name', + render: (row) => ( + <> + {row.readStatus == READ_STATUS.UNREAD && } + {row.subject} + {row.statusLabel && } + + ), + isSortable: true + }, + { + key: 'type', + heading: 'Type', + isSortable: true, + sortFn: ({ type: leftType }, { type: rightType }, direction) => { + const compareResult = leftType.localeCompare(rightType, undefined, { + numeric: true, + sensitivity: 'base' + }); + return direction === 'ascending' ? compareResult : -compareResult; + } + }, + { key: 'category', heading: 'Category', isSortable: true }, + { + key: 'date', + heading: 'Date', + render: (row) => ( + + {formatDate(row.date)} + + ), + isSortable: true + }, + { + key: 'status', + heading: 'Status', + render: (row) => , + isSortable: true } - }, - { key: 'category', heading: 'Category', isSortable: true }, - { - key: 'date', - heading: 'Date', - render: (row) => ( - - {formatDate(row.date)} - - ), - isSortable: true - }, - { - key: 'status', - heading: 'Status', - render: (row) => , - isSortable: true - } - ], + ], [] ); const filteredSortedData = useMemo(() => { - const sortFn = getSortFn( - columns, - filters?.sort, - (sortConfig) => defaultSortFn(sortConfig) + const sortFn = getSortFn(columns, filters?.sort, (sortConfig) => + defaultSortFn(sortConfig) ); const sortByStatusFn = defaultSortFn({ column: 'statusLabel', @@ -163,38 +157,40 @@ export const CaseMaterialsTable = () => { textContent="Loading materials..." /> {!caseMaterialsLoading && ( - <> -

- Showing{' '} - - {filteredSortedData?.length === 0 ? 0 : recordsOnCurrentPage} - {' '} - materials out of {filteredSortedData?.length} -

- - -
1 ? 'table-actions-footer' : 'table-actions-footer-end' - } - > - -
- + <> +

+ Showing{' '} + + {filteredSortedData?.length === 0 ? 0 : recordsOnCurrentPage} + {' '} + materials out of {filteredSortedData?.length} +

+ + +
1 + ? 'table-actions-footer' + : 'table-actions-footer-end' + } + > + +
+ )} ); diff --git a/materials_ui/tests/tests-e2e/communications.spec.ts b/materials_ui/tests/tests-e2e/communications.spec.ts index 235e0282..f0f7d891 100644 --- a/materials_ui/tests/tests-e2e/communications.spec.ts +++ b/materials_ui/tests/tests-e2e/communications.spec.ts @@ -112,9 +112,9 @@ test.describe('Communications page', () => { // hide filter test('T-007: user is able to hide filter', async ({ page }) => { await page.getByRole('button', { name: 'Hide filters' }).click(); - await expect(page.getByText('Search communications')).toBeHidden(); + await expect(page.getByLabel('Subject')).toBeHidden(); await page.getByRole('button', { name: 'Show filter' }).click(); - await expect(page.getByText('Search communications')).toBeVisible(); + await expect(page.getByLabel('Subject')).toBeVisible(); }); // search @@ -129,9 +129,7 @@ test.describe('Communications page', () => { method: 'Police' }) ); - await page - .getByRole('searchbox', { name: 'Search communications' }) - .fill('test 1'); + await page.getByRole('searchbox', { name: 'Subject' }).fill('test 1'); await page.getByTestId('applyFiltersButton').click(); await expect(page.getByText('test 1', { exact: true })).toBeVisible(); }); diff --git a/materials_ui/tests/tests-e2e/materials.spec.ts b/materials_ui/tests/tests-e2e/materials.spec.ts index c67c4258..99ce0ee9 100644 --- a/materials_ui/tests/tests-e2e/materials.spec.ts +++ b/materials_ui/tests/tests-e2e/materials.spec.ts @@ -140,9 +140,9 @@ test.describe('Materials page', () => { test('T-008: user is able to hide filter', async ({ page }) => { mockRoute(page, '/case-materials', mockCaseMaterials()); await page.getByRole('button', { name: 'Hide filters' }).click(); - await expect(page.getByText('Search materials')).toBeHidden(); + await expect(page.getByLabel('Material name')).toBeHidden(); await page.getByRole('button', { name: 'Show filters' }).click(); - await expect(page.getByText('Search materials')).toBeVisible(); + await expect(page.getByLabel('Material name')).toBeVisible(); }); // search @@ -158,7 +158,7 @@ test.describe('Materials page', () => { }) ); await page - .getByRole('searchbox', { name: 'Search materials' }) + .getByRole('searchbox', { name: 'Material name' }) .fill('Case Action'); await page.getByTestId('applyFiltersButton').click(); await expect( From b58d728abd69cd4b1df9c63658f185760af6e51f Mon Sep 17 00:00:00 2001 From: girmacps Date: Fri, 10 Jul 2026 16:49:01 +0100 Subject: [PATCH 11/28] fix typo (#440) --- materials_ui/src/constants/categoryList.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/materials_ui/src/constants/categoryList.ts b/materials_ui/src/constants/categoryList.ts index 9ed3a1db..e94f29ec 100644 --- a/materials_ui/src/constants/categoryList.ts +++ b/materials_ui/src/constants/categoryList.ts @@ -4,7 +4,7 @@ export const materialsCategoryList = [ 'MG Form', 'Other Material', 'Unused Material', - 'Defendant Pre-Cons' + 'Defendant Pre Cons' ]; export const communicationsCategoryList = [ From e935594b04084f12631e612ce9020e34d2bd9f00 Mon Sep 17 00:00:00 2001 From: robmolloy-cps Date: Mon, 13 Jul 2026 10:56:05 +0100 Subject: [PATCH 12/28] =?UTF-8?q?FCT2-20521-ensure-that-category-labels-in?= =?UTF-8?q?-the-filters-section-can-be-=E2=80=A6=20(#442)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * FCT2-20521-ensure-that-category-labels-in-the-filters-section-can-be-changed-without-breaking-functionality * FCT2-20521-ensure-that-category-labels-in-the-filters-section-can-be-changed-without-breaking-functionality --- materials_ui/src/components/Filters/MaterialsFilters.tsx | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/materials_ui/src/components/Filters/MaterialsFilters.tsx b/materials_ui/src/components/Filters/MaterialsFilters.tsx index cd477d96..7cd30d88 100644 --- a/materials_ui/src/components/Filters/MaterialsFilters.tsx +++ b/materials_ui/src/components/Filters/MaterialsFilters.tsx @@ -5,6 +5,10 @@ import { useFeatureFlag, useFilters } from '../../hooks'; import Checkbox from '../Checkbox/Checkbox'; import { FilterForm } from './FilterForm'; +const categoryLabelLookup: { [k: string]: string } = { + 'Defendant Pre Cons': 'Defendant Pre-Cons' +}; + export const MaterialsFilters = () => { const { filters, @@ -98,7 +102,10 @@ export const MaterialsFilters = () => { {categories.map((category) => ( { + const lookupLabel = categoryLabelLookup[category]; + return lookupLabel ? lookupLabel : category; + })()} checked={ shallowFilters?.filters?.category?.includes(category) || false } From 2de72e8bfea1225c3b067a352357f8d6026c3344 Mon Sep 17 00:00:00 2001 From: afeescps Date: Mon, 13 Jul 2026 13:17:37 +0100 Subject: [PATCH 13/28] [FCT2-20204] - fix(materials): align category filter labels with Review and Redact (#441) * fix(materials): align category filter labels with Review and Redact * refactor(materials): simplify category filter labels and checked default --- .../components/Filters/MaterialsFilters.tsx | 20 ++++++------------- materials_ui/src/constants/categoryList.ts | 14 ++++++------- 2 files changed, 13 insertions(+), 21 deletions(-) diff --git a/materials_ui/src/components/Filters/MaterialsFilters.tsx b/materials_ui/src/components/Filters/MaterialsFilters.tsx index 7cd30d88..c1facde0 100644 --- a/materials_ui/src/components/Filters/MaterialsFilters.tsx +++ b/materials_ui/src/components/Filters/MaterialsFilters.tsx @@ -5,10 +5,6 @@ import { useFeatureFlag, useFilters } from '../../hooks'; import Checkbox from '../Checkbox/Checkbox'; import { FilterForm } from './FilterForm'; -const categoryLabelLookup: { [k: string]: string } = { - 'Defendant Pre Cons': 'Defendant Pre-Cons' -}; - export const MaterialsFilters = () => { const { filters, @@ -37,7 +33,6 @@ export const MaterialsFilters = () => { setSearch(searchTerm); }; - const categories = materialsCategoryList; const statusList = ['Used', 'Unused']; return ( @@ -99,19 +94,16 @@ export const MaterialsFilters = () => {

Category

- {categories.map((category) => ( + {materialsCategoryList.map(({ value, label }) => ( { - const lookupLabel = categoryLabelLookup[category]; - return lookupLabel ? lookupLabel : category; - })()} + id={`category-${value}`} + label={label} checked={ - shallowFilters?.filters?.category?.includes(category) || false + shallowFilters?.filters?.category?.includes(value) ?? false } onChange={(event) => handleCheckboxChange('category', event)} - value={category} - key={category} + value={value} + key={value} /> ))} diff --git a/materials_ui/src/constants/categoryList.ts b/materials_ui/src/constants/categoryList.ts index e94f29ec..8fcf8e7b 100644 --- a/materials_ui/src/constants/categoryList.ts +++ b/materials_ui/src/constants/categoryList.ts @@ -1,11 +1,11 @@ export const materialsCategoryList = [ - 'Statement', - 'Exhibit', - 'MG Form', - 'Other Material', - 'Unused Material', - 'Defendant Pre Cons' -]; + { value: 'Statement', label: 'Statements' }, + { value: 'Exhibit', label: 'Exhibits' }, + { value: 'MG Form', label: 'MG forms' }, + { value: 'Other Material', label: 'Other material' }, + { value: 'Defendant Pre Cons', label: 'Defendant pre-cons' }, + { value: 'Unused Material', label: 'Unused material' } +] as const; export const communicationsCategoryList = [ 'Bundle', From 1ec056ab295d10292fc19ab7b8fd057628af154a Mon Sep 17 00:00:00 2001 From: afeescps Date: Mon, 13 Jul 2026 14:26:50 +0100 Subject: [PATCH 14/28] fix(review-redact): rename Other documents to Other material for consistency with Materials (#443) --- .../utils/categoriseDocumentHelperUtils.ts | 6 +++--- materials_ui/tests/tests-e2e/review-redact.spec.ts | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/materials_ui/src/materials_components/DocumentSelectAccordion/utils/categoriseDocumentHelperUtils.ts b/materials_ui/src/materials_components/DocumentSelectAccordion/utils/categoriseDocumentHelperUtils.ts index 0e8d7101..f997aad6 100644 --- a/materials_ui/src/materials_components/DocumentSelectAccordion/utils/categoriseDocumentHelperUtils.ts +++ b/materials_ui/src/materials_components/DocumentSelectAccordion/utils/categoriseDocumentHelperUtils.ts @@ -4,7 +4,7 @@ export const categoryDetails = [ { label: 'Statements', categoryName: 'statement' }, { label: 'Exhibits', categoryName: 'exhibit' }, { label: 'MG forms', categoryName: 'mgForm' }, - { label: 'Other documents', categoryName: 'otherDocument' }, + { label: 'Other material', categoryName: 'otherMaterial' }, { label: 'Defendant pre-cons', categoryName: 'defendantPreCons' }, { label: 'Unused material', categoryName: 'unusedMaterial' } ] as const; @@ -21,7 +21,7 @@ export const documentTypeIdsMap: Record = { 1019, 1024, 1025, 1026, 1027, 1033, 1034, 1035, 1036, 1037, 1038, 1039, 1040, 1041, 1045, 1046, 1047, 1048, 1049, 1050, 1060, 1061, 1063, 1066, 1203 ], - otherDocument: [-2, 1201], + otherMaterial: [-2, 1201], defendantPreCons: [1056, 1057], unusedMaterial: [1009, 1010, 1011, 1058, 1202, 100239, 226148] }; @@ -32,7 +32,7 @@ export const initDocsOnDocCategoryNamesMap = (): { statement: [], exhibit: [], mgForm: [], - otherDocument: [], + otherMaterial: [], defendantPreCons: [], unusedMaterial: [] }); diff --git a/materials_ui/tests/tests-e2e/review-redact.spec.ts b/materials_ui/tests/tests-e2e/review-redact.spec.ts index 59799069..5b4005a2 100644 --- a/materials_ui/tests/tests-e2e/review-redact.spec.ts +++ b/materials_ui/tests/tests-e2e/review-redact.spec.ts @@ -22,7 +22,7 @@ test.describe('Review redact page', () => { await expect(page.getByText('Statements')).toBeVisible(); await expect(page.getByText('Exhibits')).toBeVisible(); await expect(page.getByText('MG forms')).toBeVisible(); - await expect(page.getByText('Other documents')).toBeVisible(); + await expect(page.getByText('Other material')).toBeVisible(); await expect(page.getByText('Defendant pre-cons')).toBeVisible(); await expect(page.getByText('Unused material')).toBeVisible(); }); From 6f68e6a6909acbcd685738af917065fd993a076d Mon Sep 17 00:00:00 2001 From: robmolloy-cps Date: Tue, 14 Jul 2026 13:56:24 +0100 Subject: [PATCH 15/28] FCT2-20540-improve-fe-linting-and-agree-with-fe-devs-2 (#445) * FCT2-20540-improve-fe-linting-and-agree-with-fe-devs * FCT2-20540-improve-fe-linting-and-agree-with-fe-devs-2 --- .prettierrc | 3 +- materials_ui/.prettierrc | 3 +- materials_ui/eslint.config.js | 17 +- materials_ui/playwright.config.ts | 24 +- .../public/assets/images/manifest.json | 7 +- materials_ui/public/body-class.js | 5 +- .../global-components-msal-redirect.html | 15 +- materials_ui/public/mockServiceWorker.js | 193 ++++++------- materials_ui/renovate.json | 4 +- materials_ui/serve.json | 7 +- .../__tests__/components/CaseSearch.test.tsx | 20 +- .../src/__tests__/stores/useCaseInfo.test.ts | 4 +- .../__tests__/stores/useMaterialTags.test.ts | 20 +- .../__tests__/stores/useSelectedItems.test.ts | 74 ++--- materials_ui/src/app.tsx | 4 +- .../assetsCWA/svgs/DownArrowIcon.tsx | 6 +- .../LinkButton/LinkButton.module.scss | 2 +- .../components/LinkButton/LinkButton.tsx | 6 +- .../caseWorkApp/components/button/index.tsx | 20 +- .../dropDownButton/DropdownButton.module.scss | 2 - .../dropDownButton/DropdownButton.tsx | 63 +---- .../components/tabs/TabButtons.tsx | 41 +-- .../src/caseWorkApp/components/tabs/Tabs.tsx | 32 +-- .../src/caseWorkApp/components/tabs/index.ts | 2 +- .../caseWorkApp/components/tabs/styles.scss | 18 +- .../components/tooltip/index.module.scss | 8 +- .../caseWorkApp/components/tooltip/index.tsx | 18 +- .../caseWorkApp/components/utils/getData.ts | 36 +-- .../src/caseWorkApp/hooks/useFocusTrap.tsx | 21 +- .../hooks/useGlobalDropdownClose.ts | 26 +- .../src/caseWorkApp/hooks/useLastFocus.tsx | 11 +- .../caseWorkApp/hooks/useSwitchContentArea.ts | 4 +- .../CloseTabUnsavedRedactionsModal.tsx | 8 +- .../pages/ReviewAndRedactPage/Modal.tsx | 10 +- .../ReviewAndRedactPage.tsx | 140 +++------- .../UnsavedRedactionsModal.tsx | 19 +- .../pages/ReviewAndRedactPage/index.tsx | 2 +- .../src/caseWorkApp/types/redaction.ts | 14 +- .../src/caseWorkApp/types/redactionLog.ts | 7 +- .../src/components/Accordion/Accordion.scss | 10 +- .../src/components/Accordion/Accordion.tsx | 22 +- .../src/components/Banner/Banner.scss | 2 +- materials_ui/src/components/Banner/Banner.tsx | 11 +- .../Button/AutoReclassifyButton.tsx | 19 +- .../src/components/ButtonMenu/ButtonMenu.tsx | 39 +-- .../src/components/CaseInfo/CaseInfo.tsx | 12 +- .../src/components/Checkbox/Checkbox.tsx | 8 +- .../src/components/DateField/DateField.tsx | 47 +--- .../DefinitionList/DefinitionList.tsx | 4 +- .../DocumentKeywordSearch.tsx | 147 +++------- .../DocumentPreview/DocumentActions.tsx | 8 +- .../DocumentPreview/DocumentPreview.tsx | 7 +- materials_ui/src/components/Drawer/Drawer.tsx | 5 +- .../src/components/Drawer/RenameDrawer.tsx | 42 +-- .../src/components/Filters/CommsFilters.tsx | 52 +--- .../Filters/DocumentKeywordSearchFilters.tsx | 30 +- .../src/components/Filters/FilterForm.tsx | 2 +- .../components/Filters/MaterialsFilters.tsx | 26 +- materials_ui/src/components/Layout/Layout.tsx | 28 +- .../LoadingSpinner/LoadingSpinner.tsx | 10 +- .../src/components/NavList/NavList.scss | 2 +- .../src/components/NavList/NavList.tsx | 15 +- .../src/components/Pagination/Pagination.tsx | 8 +- .../src/components/PdfViewer/PdfViewer.css | 4 +- .../src/components/PdfViewer/PdfViewer.tsx | 12 +- materials_ui/src/components/Radios/Radios.tsx | 34 +-- .../components/SearchInput/SearchInput.tsx | 2 +- .../components/SectionBreak/SectionBreak.scss | 3 +- .../src/components/SelectList/SelectList.tsx | 28 +- .../SortableTable/CaseMaterialsTable.tsx | 95 ++----- .../SortableTable/CommunicationsTable.tsx | 131 +++------ .../SortableTable/SortableTable.tsx | 263 +++++++++--------- .../components/SortableTable/TableActions.tsx | 10 +- .../components/SummaryCard/SummaryCard.tsx | 14 +- .../src/components/TextArea/TextArea.tsx | 15 +- .../src/components/TextInput/TextInput.tsx | 10 +- .../forms/EditMaterial/EditExhibit.tsx | 41 +-- .../forms/EditMaterial/EditStatement.tsx | 58 +--- .../components/forms/EditMaterial/Summary.tsx | 21 +- .../forms/Reclassify/AddWitness.tsx | 28 +- .../components/forms/Reclassify/Exhibit.tsx | 14 +- .../components/forms/Reclassify/MGForms.tsx | 6 +- .../forms/Reclassify/MaterialName.tsx | 17 +- .../src/components/forms/Reclassify/Other.tsx | 6 +- .../components/forms/Reclassify/Statement.tsx | 29 +- .../components/forms/Reclassify/Summary.tsx | 86 ++---- .../Reclassify/common/DocumentTypeField.tsx | 16 +- .../forms/Reclassify/common/SubjectField.tsx | 10 +- .../forms/Reclassify/common/UsedField.tsx | 8 +- .../forms/Reclassify/constants/options.tsx | 35 +-- .../forms/Reclassify/constants/string.ts | 9 +- .../mappers/mapReclassifyExhibit.ts | 14 +- .../Reclassify/mappers/mapReclassifyMGForm.ts | 6 +- .../Reclassify/mappers/mapReclassifyOther.ts | 6 +- .../mappers/mapReclassifyStatement.ts | 28 +- .../components/forms/Reclassify/utils/form.ts | 2 +- materials_ui/src/constants/categoryList.ts | 8 +- materials_ui/src/constants/chargeStatus.ts | 4 +- materials_ui/src/constants/discard.ts | 2 +- materials_ui/src/constants/enum.ts | 4 +- .../src/constants/featureFlagGroups.ts | 2 +- materials_ui/src/constants/query.ts | 2 +- materials_ui/src/constants/url.ts | 7 +- materials_ui/src/context/AppContext.tsx | 15 +- .../context/FiltersContext/helpers/utils.ts | 22 +- .../src/context/FiltersContext/index.tsx | 39 +-- materials_ui/src/context/GroupContext.tsx | 4 +- .../hooks/case-materials/useAutoReclassify.ts | 6 +- .../hooks/case-materials/useBulkSetUnused.ts | 21 +- .../hooks/case-materials/useCaseMaterial.ts | 4 +- .../hooks/case-materials/useCaseMaterials.ts | 25 +- .../src/hooks/case-materials/useDiscard.ts | 24 +- .../hooks/case-materials/useEditMaterial.tsx | 75 +++-- .../src/hooks/case-materials/useReadStatus.ts | 14 +- .../src/hooks/case-materials/useReclassify.ts | 28 +- .../hooks/case-materials/useReclassifyForm.ts | 9 +- .../src/hooks/case-materials/useRename.ts | 27 +- .../src/hooks/case/useCaseDefendants.ts | 24 +- materials_ui/src/hooks/case/useCaseInfo.ts | 6 +- .../src/hooks/case/useCaseLockCheck.ts | 6 +- .../src/hooks/case/useCaseWitnesses.ts | 24 +- .../src/hooks/case/useWitnessStatements.ts | 27 +- .../src/hooks/documents/useDocumentPdfUrl.ts | 10 +- .../src/hooks/documents/useDocumentPreview.ts | 4 +- .../src/hooks/documents/useDocumentTypes.ts | 42 +-- .../src/hooks/documents/useDocuments.ts | 8 +- .../src/hooks/exhibits/useExhibitProducers.ts | 21 +- .../src/hooks/exhibits/useExhibits.ts | 6 +- materials_ui/src/hooks/index.ts | 10 +- materials_ui/src/hooks/pcd-request/usePCD.ts | 4 +- .../src/hooks/pcd-request/usePCDList.ts | 10 +- .../src/hooks/pcd-review/usePCDReviewCore.ts | 16 +- .../hooks/pcd-review/usePCDReviewDetails.ts | 23 +- .../src/hooks/search/useCaseSearch.ts | 20 +- .../src/hooks/search/useDocumentSearch.ts | 23 +- .../src/hooks/search/useSearchTracker.ts | 14 +- .../ui/navigateToViewDocumentPageInNewTab.ts | 4 +- materials_ui/src/hooks/ui/useAppRoute.ts | 2 +- materials_ui/src/hooks/ui/useBanner.ts | 3 +- materials_ui/src/hooks/ui/useFeatureFlag.ts | 10 +- materials_ui/src/hooks/ui/useFilters.ts | 49 +--- materials_ui/src/hooks/ui/useLogger.ts | 2 +- materials_ui/src/hooks/ui/usePageColors.ts | 7 +- materials_ui/src/hooks/ui/usePager.ts | 15 +- materials_ui/src/hooks/ui/useRequest.ts | 14 +- materials_ui/src/hooks/ui/useTableActions.ts | 34 +-- .../src/hooks/ui/useUserGroupsFeatureFlag.ts | 3 +- materials_ui/src/index.tsx | 12 +- .../BulkRedactionForm.tsx | 42 +-- .../CaseworkPdfRedactorWrapper.tsx | 162 ++++------- .../hooks/useBulkRedactionFlow.ts | 29 +- .../hooks/useBulkSearch.ts | 18 +- .../hooks/useDocumentCheckOutRequest.ts | 37 +-- .../utils/bulkSearchDocumentUtils.ts | 11 +- .../utils/combineRedactionsDeletions.ts | 4 +- .../utils/saveDeletionsUtils.ts | 6 +- .../utils/saveRedactionsUtils.ts | 14 +- .../utils/saveRotationsUtils.ts | 6 +- .../DocumentSidebar.tsx | 9 +- .../DocumentSidebarAccordion.tsx | 45 +-- .../DocumentSidebarAccordionDocument.tsx | 44 +-- .../DocumentSidebarNotes.tsx | 46 +-- .../DocumentSidebarTag.tsx | 5 +- .../DocumentSidebarWrapper.tsx | 6 +- .../getters/getAccessTokenFromMsalInstance.ts | 11 +- .../getters/getAxiosInstance.tsx | 2 +- .../getters/getDocumentList.tsx | 30 +- .../getters/getDocumentNotes.tsx | 17 +- .../templates/GovUkAccordion.scss | 31 +-- .../templates/GovUkAccordion.tsx | 14 +- .../templates/GovUkBanner.tsx | 18 +- .../templates/GovUkButton.scss | 4 +- .../templates/GovUkButton.tsx | 4 +- .../templates/GovUkLink.scss | 4 +- .../templates/GovUkTagTemplate.tsx | 13 +- .../templates/NotesIcon.tsx | 15 +- .../utils/DocumentSidebarLocalStorageUtils.ts | 20 +- .../OpenDocumentTabsLocalStorageUtils.ts | 17 +- .../utils/categoriseDocument.ts | 7 +- .../utils/categoriseDocumentHelperUtils.ts | 20 +- .../utils/dateUtils.ts | 12 +- .../DocumentTabPanel/DocumentTabPanel.tsx | 40 +-- .../PdfRedactor/ManualRedactionForm.tsx | 5 +- .../PdfRedactor/PdfDeletionReasonForm.tsx | 12 +- .../PdfRedactor/PdfRedactor.tsx | 176 +++--------- .../PdfRedactor/PdfRedactorComponents.scss | 1 - .../PdfRedactor/PdfRedactorComponents.tsx | 34 +-- .../PdfRedactor/PdfRedactorPage.tsx | 204 ++++---------- .../PdfRedactor/RedactionTypeSelect.tsx | 6 +- .../PdfRedactor/hooks/useDocumentFocus.ts | 35 +-- .../hooks/useDocumentFocusHelpers.ts | 8 +- .../hooks/useScrollToFocusedHighlight.ts | 12 +- .../PdfRedactor/icons/RotateIcon.tsx | 8 +- .../PdfRedactor/icons/TickCircleIcon.tsx | 6 +- .../modals/PdfRedactorCenteredModal.tsx | 4 +- .../modals/PdfRedactorMiniModal.tsx | 32 +-- .../modals/SaveToProceedToDeletionsModal.tsx | 21 +- .../modals/SaveToProceedToRedactionsModal.tsx | 21 +- .../modals/SaveToProceedToRotationsModal.tsx | 21 +- .../PdfRedactor/templates/CloseIconButton.tsx | 9 +- .../PdfRedactor/templates/GovUkButton.scss | 2 +- .../PdfRedactor/templates/GovUkButton.tsx | 7 +- .../PdfRedactor/utils/bulkRedactionUtils.ts | 14 +- .../PdfRedactor/utils/coordUtils.ts | 11 +- .../PdfRedactor/utils/highlightedTextUtils.ts | 28 +- .../PdfRedactor/utils/rotationUtils.ts | 6 +- .../PdfRedactor/utils/searchHighlightUtils.ts | 15 +- .../PdfRedactor/utils/useTriggger.tsx | 7 +- .../RedactionLog/Modal.tsx | 2 +- .../RedactionLog/Popover.tsx | 2 +- .../RedactionLog/RedactionLogModal.tsx | 46 ++- .../RedactionLog/RedactionLogModalBody.tsx | 72 ++--- .../RedactionLog/RedactionLogModalHeader.tsx | 48 ++-- .../RedactionLog/templates/Checkbox.tsx | 14 +- .../RedactionLog/templates/ErrorSummary.tsx | 11 +- .../RedactionLog/templates/Select.tsx | 6 +- .../utils/getDocumentTypeValueFromMappings.ts | 12 +- .../RedactionLog/utils/transformFormData.ts | 69 ++--- .../DocumentActionsDropdown.tsx | 14 +- .../documenViewportArea/index.module.scss | 2 +- .../documenViewportArea/index.tsx | 43 +-- materials_ui/src/mocks/handlers.ts | 12 +- materials_ui/src/msalInstance.ts | 6 +- materials_ui/src/pages/CaseSearch.tsx | 89 ++---- materials_ui/src/pages/Communications.tsx | 63 ++--- materials_ui/src/pages/DiscardMaterial.tsx | 23 +- materials_ui/src/pages/EditMaterial.tsx | 148 ++++------ materials_ui/src/pages/Materials.tsx | 62 ++--- materials_ui/src/pages/NotAuthorisedPage.tsx | 13 +- materials_ui/src/pages/PcdRequest.tsx | 211 ++++---------- materials_ui/src/pages/PcdReview.tsx | 126 +++------ materials_ui/src/pages/Reclassification.tsx | 132 +++------ materials_ui/src/pages/ReclassifyToUnused.tsx | 39 +-- materials_ui/src/pages/ServerErrorPage.tsx | 8 +- materials_ui/src/pages/ViewDocumentPage.scss | 1 - materials_ui/src/pages/ViewDocumentPage.tsx | 29 +- materials_ui/src/routes.tsx | 62 +---- materials_ui/src/schemas/app.ts | 6 +- materials_ui/src/schemas/banner.ts | 2 +- materials_ui/src/schemas/bulkSetUnused.ts | 21 +- materials_ui/src/schemas/caseDetails.ts | 22 +- materials_ui/src/schemas/caseLockStatus.ts | 6 +- materials_ui/src/schemas/caseMaterials.ts | 47 +--- materials_ui/src/schemas/caseinfo.ts | 2 +- materials_ui/src/schemas/classification.ts | 8 +- materials_ui/src/schemas/defendants.ts | 12 +- materials_ui/src/schemas/documentTypes.ts | 13 +- materials_ui/src/schemas/documents.ts | 25 +- materials_ui/src/schemas/exhibitProducer.ts | 11 +- .../src/schemas/forms/editStatement.ts | 70 +++-- materials_ui/src/schemas/forms/reclassify.ts | 152 ++++------ materials_ui/src/schemas/index.ts | 2 +- materials_ui/src/schemas/pcd.ts | 19 +- materials_ui/src/schemas/pcdReview.ts | 60 ++-- materials_ui/src/schemas/polaris/caseinfo.ts | 7 +- materials_ui/src/schemas/witness.ts | 30 +- materials_ui/src/setupTests.ts | 4 +- materials_ui/src/stores/useCaseInfo.ts | 2 +- materials_ui/src/stores/useMaterialTags.ts | 10 +- materials_ui/src/stores/useSelectedItems.ts | 18 +- materials_ui/src/styles/_accessibility.scss | 1 - materials_ui/src/telemetry/appInsights.ts | 28 +- materials_ui/src/utils/cmsStringTransform.ts | 3 +- materials_ui/src/utils/date.ts | 8 +- materials_ui/src/utils/filtering.ts | 19 +- materials_ui/src/utils/reclassify.ts | 81 +++--- materials_ui/src/utils/string.ts | 5 +- materials_ui/src/utils/url.ts | 11 +- .../tests/global-setup/global.setup.ts | 4 +- materials_ui/tests/helpers.ts | 10 +- materials_ui/tests/mocks/mockCaseDetails.ts | 14 +- materials_ui/tests/mocks/mockCaseMaterials.ts | 9 +- materials_ui/tests/mocks/mockDefendents.ts | 12 +- materials_ui/tests/mocks/mockLockCase.ts | 6 +- .../tests/mocks/mockOchestrationReclassify.ts | 6 +- materials_ui/tests/mocks/mockWitness.ts | 16 +- materials_ui/tests/mocks/pcd/mockPcdCore.ts | 20 +- .../tests/mocks/pcd/mockPcdRequest.ts | 35 +-- .../tests/mocks/pcd/mockPcdReviewCore.ts | 8 +- .../tests/mocks/pcd/mockPcdReviewDetails.ts | 77 ++--- materials_ui/tests/tests-e2e/actions.spec.ts | 44 +-- .../tests/tests-e2e/case-search.spec.ts | 20 +- materials_ui/tests/tests-e2e/casework.spec.ts | 8 +- .../tests/tests-e2e/communications.spec.ts | 38 ++- .../tests/tests-e2e/materials.spec.ts | 72 ++--- .../tests/tests-e2e/pcd-request.spec.ts | 24 +- .../tests/tests-e2e/pcd-review.spec.ts | 54 ++-- .../tests/tests-e2e/reclassify.spec.ts | 127 ++------- .../tests/tests-e2e/review-redact.spec.ts | 23 +- materials_ui/tsconfig.app.json | 1 - materials_ui/tsconfig.json | 5 +- materials_ui/vite.config.ts | 52 ++-- 292 files changed, 2404 insertions(+), 5147 deletions(-) diff --git a/.prettierrc b/.prettierrc index b382ff0a..480073c0 100644 --- a/.prettierrc +++ b/.prettierrc @@ -1,6 +1,7 @@ { "singleQuote": true, - "trailingComma": "none", + "trailingComma": "all", + "printWidth": 100, "objectWrap": "collapse", "semi": true, "useTabs": false, diff --git a/materials_ui/.prettierrc b/materials_ui/.prettierrc index 70ff5d0d..0401b8f0 100644 --- a/materials_ui/.prettierrc +++ b/materials_ui/.prettierrc @@ -1,7 +1,8 @@ { "plugins": ["prettier-plugin-organize-imports"], "singleQuote": true, - "trailingComma": "none", + "trailingComma": "all", + "printWidth": 100, "objectWrap": "collapse", "semi": true, "useTabs": false, diff --git a/materials_ui/eslint.config.js b/materials_ui/eslint.config.js index a06d7cf4..33e47c3e 100644 --- a/materials_ui/eslint.config.js +++ b/materials_ui/eslint.config.js @@ -14,20 +14,13 @@ export default [ plugins: { 'react-hooks': reactHooks, 'react-refresh': reactRefresh }, rules: { ...reactHooks.configs.recommended.rules, - 'react-refresh/only-export-components': [ - 'warn', - { allowConstantExport: true } - ], + 'react-refresh/only-export-components': ['warn', { allowConstantExport: true }], 'react-hooks/exhaustive-deps': 'off', '@typescript-eslint/no-unused-vars': [ 'error', - { - argsIgnorePattern: '^_', - varsIgnorePattern: '^_', - caughtErrorsIgnorePattern: '^_' - } + { argsIgnorePattern: '^_', varsIgnorePattern: '^_', caughtErrorsIgnorePattern: '^_' }, ], - '@typescript-eslint/no-explicit-any': 'warn' - } - } + '@typescript-eslint/no-explicit-any': 'warn', + }, + }, ]; diff --git a/materials_ui/playwright.config.ts b/materials_ui/playwright.config.ts index 79275299..28597aba 100644 --- a/materials_ui/playwright.config.ts +++ b/materials_ui/playwright.config.ts @@ -27,8 +27,8 @@ export default defineConfig({ workers: process.env.CI ? 1 : undefined, /* Reporter to use. See https://playwright.dev/docs/test-reporters */ reporter: [ - ["html", { outputFolder: "./tests/playwright-report" }], - ["junit", { outputFile: "./tests/e2e-test-results.xml" }], + ['html', { outputFolder: './tests/playwright-report' }], + ['junit', { outputFile: './tests/e2e-test-results.xml' }], ], /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */ use: { @@ -38,10 +38,10 @@ export default defineConfig({ screenshot: 'only-on-failure', /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */ trace: 'on-first-retry', - navigationTimeout: 60 * 1000, // 60s for page.goto() - actionTimeout: 30 * 1000, // 30s for clicks/fills + navigationTimeout: 60 * 1000, // 60s for page.goto() + actionTimeout: 30 * 1000, // 30s for clicks/fills }, - + /* Configure projects for major browsers */ projects: [ // { @@ -76,10 +76,10 @@ export default defineConfig({ use: { ...devices['Desktop Edge'], channel: 'msedge', - storageState: 'tests/.auth/globalSetup.json' + storageState: 'tests/.auth/globalSetup.json', }, - dependencies: ['setup'] - } + dependencies: ['setup'], + }, // { // name: 'Google Chrome', // use: { ...devices['Desktop Chrome'], channel: 'chrome' }, @@ -95,7 +95,7 @@ export default defineConfig({ env: { ...process.env, // Keep E2E independent from external script availability in CI. - VITE_GLOBAL_SCRIPT_URL: '' - } - } -}); \ No newline at end of file + VITE_GLOBAL_SCRIPT_URL: '', + }, + }, +}); diff --git a/materials_ui/public/assets/images/manifest.json b/materials_ui/public/assets/images/manifest.json index 6c0dba9d..5eeab57f 100644 --- a/materials_ui/public/assets/images/manifest.json +++ b/materials_ui/public/assets/images/manifest.json @@ -1,12 +1,7 @@ { "icons": [ { "src": "images/favicon.ico", "type": "image/x-icon", "sizes": "48x48" }, - { - "src": "images/favicon.svg", - "type": "image/svg+xml", - "sizes": "150x150", - "purpose": "any" - }, + { "src": "images/favicon.svg", "type": "image/svg+xml", "sizes": "150x150", "purpose": "any" }, { "src": "images/govuk-icon-180.png", "type": "image/png", diff --git a/materials_ui/public/body-class.js b/materials_ui/public/body-class.js index e59a18b2..1bf6e93b 100644 --- a/materials_ui/public/body-class.js +++ b/materials_ui/public/body-class.js @@ -1,5 +1,2 @@ document.body.className += - ' js-enabled' + - ('noModule' in HTMLScriptElement.prototype - ? ' govuk-frontend-supported' - : ''); + ' js-enabled' + ('noModule' in HTMLScriptElement.prototype ? ' govuk-frontend-supported' : ''); diff --git a/materials_ui/public/global-components-msal-redirect.html b/materials_ui/public/global-components-msal-redirect.html index 779770e2..f47748a9 100644 --- a/materials_ui/public/global-components-msal-redirect.html +++ b/materials_ui/public/global-components-msal-redirect.html @@ -1,10 +1,9 @@ - + - - - Global components auth termination - - - - \ No newline at end of file +--> diff --git a/materials_ui/public/mockServiceWorker.js b/materials_ui/public/mockServiceWorker.js index 558540fa..08460145 100644 --- a/materials_ui/public/mockServiceWorker.js +++ b/materials_ui/public/mockServiceWorker.js @@ -7,114 +7,99 @@ * - Please do NOT modify this file. */ -const PACKAGE_VERSION = '2.12.4' -const INTEGRITY_CHECKSUM = '4db4a41e972cec1b64cc569c66952d82' -const IS_MOCKED_RESPONSE = Symbol('isMockedResponse') -const activeClientIds = new Set() +const PACKAGE_VERSION = '2.12.4'; +const INTEGRITY_CHECKSUM = '4db4a41e972cec1b64cc569c66952d82'; +const IS_MOCKED_RESPONSE = Symbol('isMockedResponse'); +const activeClientIds = new Set(); addEventListener('install', function () { - self.skipWaiting() -}) + self.skipWaiting(); +}); addEventListener('activate', function (event) { - event.waitUntil(self.clients.claim()) -}) + event.waitUntil(self.clients.claim()); +}); addEventListener('message', async function (event) { - const clientId = Reflect.get(event.source || {}, 'id') + const clientId = Reflect.get(event.source || {}, 'id'); if (!clientId || !self.clients) { - return + return; } - const client = await self.clients.get(clientId) + const client = await self.clients.get(clientId); if (!client) { - return + return; } - const allClients = await self.clients.matchAll({ - type: 'window', - }) + const allClients = await self.clients.matchAll({ type: 'window' }); switch (event.data) { case 'KEEPALIVE_REQUEST': { - sendToClient(client, { - type: 'KEEPALIVE_RESPONSE', - }) - break + sendToClient(client, { type: 'KEEPALIVE_RESPONSE' }); + break; } case 'INTEGRITY_CHECK_REQUEST': { sendToClient(client, { type: 'INTEGRITY_CHECK_RESPONSE', - payload: { - packageVersion: PACKAGE_VERSION, - checksum: INTEGRITY_CHECKSUM, - }, - }) - break + payload: { packageVersion: PACKAGE_VERSION, checksum: INTEGRITY_CHECKSUM }, + }); + break; } case 'MOCK_ACTIVATE': { - activeClientIds.add(clientId) + activeClientIds.add(clientId); sendToClient(client, { type: 'MOCKING_ENABLED', - payload: { - client: { - id: client.id, - frameType: client.frameType, - }, - }, - }) - break + payload: { client: { id: client.id, frameType: client.frameType } }, + }); + break; } case 'CLIENT_CLOSED': { - activeClientIds.delete(clientId) + activeClientIds.delete(clientId); const remainingClients = allClients.filter((client) => { - return client.id !== clientId - }) + return client.id !== clientId; + }); // Unregister itself when there are no more clients if (remainingClients.length === 0) { - self.registration.unregister() + self.registration.unregister(); } - break + break; } } -}) +}); addEventListener('fetch', function (event) { - const requestInterceptedAt = Date.now() + const requestInterceptedAt = Date.now(); // Bypass navigation requests. if (event.request.mode === 'navigate') { - return + return; } // Opening the DevTools triggers the "only-if-cached" request // that cannot be handled by the worker. Bypass such requests. - if ( - event.request.cache === 'only-if-cached' && - event.request.mode !== 'same-origin' - ) { - return + if (event.request.cache === 'only-if-cached' && event.request.mode !== 'same-origin') { + return; } // Bypass all requests when there are no active clients. // Prevents the self-unregistered worked from handling requests // after it's been terminated (still remains active until the next reload). if (activeClientIds.size === 0) { - return + return; } - const requestId = crypto.randomUUID() - event.respondWith(handleRequest(event, requestId, requestInterceptedAt)) -}) + const requestId = crypto.randomUUID(); + event.respondWith(handleRequest(event, requestId, requestInterceptedAt)); +}); /** * @param {FetchEvent} event @@ -122,23 +107,18 @@ addEventListener('fetch', function (event) { * @param {number} requestInterceptedAt */ async function handleRequest(event, requestId, requestInterceptedAt) { - const client = await resolveMainClient(event) - const requestCloneForEvents = event.request.clone() - const response = await getResponse( - event, - client, - requestId, - requestInterceptedAt, - ) + const client = await resolveMainClient(event); + const requestCloneForEvents = event.request.clone(); + const response = await getResponse(event, client, requestId, requestInterceptedAt); // Send back the response clone for the "response:*" life-cycle events. // Ensure MSW is active and ready to handle the message, otherwise // this message will pend indefinitely. if (client && activeClientIds.has(client.id)) { - const serializedRequest = await serializeRequest(requestCloneForEvents) + const serializedRequest = await serializeRequest(requestCloneForEvents); // Clone the response so both the client and the library could consume it. - const responseClone = response.clone() + const responseClone = response.clone(); sendToClient( client, @@ -146,10 +126,7 @@ async function handleRequest(event, requestId, requestInterceptedAt) { type: 'RESPONSE', payload: { isMockedResponse: IS_MOCKED_RESPONSE in response, - request: { - id: requestId, - ...serializedRequest, - }, + request: { id: requestId, ...serializedRequest }, response: { type: responseClone.type, status: responseClone.status, @@ -160,10 +137,10 @@ async function handleRequest(event, requestId, requestInterceptedAt) { }, }, responseClone.body ? [serializedRequest.body, responseClone.body] : [], - ) + ); } - return response + return response; } /** @@ -175,30 +152,28 @@ async function handleRequest(event, requestId, requestInterceptedAt) { * @returns {Promise} */ async function resolveMainClient(event) { - const client = await self.clients.get(event.clientId) + const client = await self.clients.get(event.clientId); if (activeClientIds.has(event.clientId)) { - return client + return client; } if (client?.frameType === 'top-level') { - return client + return client; } - const allClients = await self.clients.matchAll({ - type: 'window', - }) + const allClients = await self.clients.matchAll({ type: 'window' }); return allClients .filter((client) => { // Get only those clients that are currently visible. - return client.visibilityState === 'visible' + return client.visibilityState === 'visible'; }) .find((client) => { // Find the client ID that's recorded in the // set of clients that have registered the worker. - return activeClientIds.has(client.id) - }) + return activeClientIds.has(client.id); + }); } /** @@ -211,36 +186,34 @@ async function resolveMainClient(event) { async function getResponse(event, client, requestId, requestInterceptedAt) { // Clone the request because it might've been already used // (i.e. its body has been read and sent to the client). - const requestClone = event.request.clone() + const requestClone = event.request.clone(); function passthrough() { // Cast the request headers to a new Headers instance // so the headers can be manipulated with. - const headers = new Headers(requestClone.headers) + const headers = new Headers(requestClone.headers); // Remove the "accept" header value that marked this request as passthrough. // This prevents request alteration and also keeps it compliant with the // user-defined CORS policies. - const acceptHeader = headers.get('accept') + const acceptHeader = headers.get('accept'); if (acceptHeader) { - const values = acceptHeader.split(',').map((value) => value.trim()) - const filteredValues = values.filter( - (value) => value !== 'msw/passthrough', - ) + const values = acceptHeader.split(',').map((value) => value.trim()); + const filteredValues = values.filter((value) => value !== 'msw/passthrough'); if (filteredValues.length > 0) { - headers.set('accept', filteredValues.join(', ')) + headers.set('accept', filteredValues.join(', ')); } else { - headers.delete('accept') + headers.delete('accept'); } } - return fetch(requestClone, { headers }) + return fetch(requestClone, { headers }); } // Bypass mocking when the client is not active. if (!client) { - return passthrough() + return passthrough(); } // Bypass initial page load requests (i.e. static assets). @@ -248,35 +221,31 @@ async function getResponse(event, client, requestId, requestInterceptedAt) { // means that MSW hasn't dispatched the "MOCK_ACTIVATE" event yet // and is not ready to handle requests. if (!activeClientIds.has(client.id)) { - return passthrough() + return passthrough(); } // Notify the client that a request has been intercepted. - const serializedRequest = await serializeRequest(event.request) + const serializedRequest = await serializeRequest(event.request); const clientMessage = await sendToClient( client, { type: 'REQUEST', - payload: { - id: requestId, - interceptedAt: requestInterceptedAt, - ...serializedRequest, - }, + payload: { id: requestId, interceptedAt: requestInterceptedAt, ...serializedRequest }, }, [serializedRequest.body], - ) + ); switch (clientMessage.type) { case 'MOCK_RESPONSE': { - return respondWithMock(clientMessage.data) + return respondWithMock(clientMessage.data); } case 'PASSTHROUGH': { - return passthrough() + return passthrough(); } } - return passthrough() + return passthrough(); } /** @@ -287,21 +256,18 @@ async function getResponse(event, client, requestId, requestInterceptedAt) { */ function sendToClient(client, message, transferrables = []) { return new Promise((resolve, reject) => { - const channel = new MessageChannel() + const channel = new MessageChannel(); channel.port1.onmessage = (event) => { if (event.data && event.data.error) { - return reject(event.data.error) + return reject(event.data.error); } - resolve(event.data) - } + resolve(event.data); + }; - client.postMessage(message, [ - channel.port2, - ...transferrables.filter(Boolean), - ]) - }) + client.postMessage(message, [channel.port2, ...transferrables.filter(Boolean)]); + }); } /** @@ -314,17 +280,14 @@ function respondWithMock(response) { // instance will have status code set to 0. Since it's not possible to create // a Response instance with status code 0, handle that use-case separately. if (response.status === 0) { - return Response.error() + return Response.error(); } - const mockedResponse = new Response(response.body, response) + const mockedResponse = new Response(response.body, response); - Reflect.defineProperty(mockedResponse, IS_MOCKED_RESPONSE, { - value: true, - enumerable: true, - }) + Reflect.defineProperty(mockedResponse, IS_MOCKED_RESPONSE, { value: true, enumerable: true }); - return mockedResponse + return mockedResponse; } /** @@ -345,5 +308,5 @@ async function serializeRequest(request) { referrerPolicy: request.referrerPolicy, body: await request.arrayBuffer(), keepalive: request.keepalive, - } + }; } diff --git a/materials_ui/renovate.json b/materials_ui/renovate.json index 5db72dd6..22a99432 100644 --- a/materials_ui/renovate.json +++ b/materials_ui/renovate.json @@ -1,6 +1,4 @@ { "$schema": "https://docs.renovatebot.com/renovate-schema.json", - "extends": [ - "config:recommended" - ] + "extends": ["config:recommended"] } diff --git a/materials_ui/serve.json b/materials_ui/serve.json index 0d5bccff..f3aa1593 100644 --- a/materials_ui/serve.json +++ b/materials_ui/serve.json @@ -8,11 +8,8 @@ { "key": "Cache-Control", "value": "no-store" }, { "key": "X-Frame-Options", "value": "SAMEORIGIN" }, { "key": "X-Permitted-Cross-Domain-Policies", "value": "none" }, - { - "key": "Content-Security-Policy", - "value": "#{CSP_VALUE_IN_ADO_VARIABLE}#" - } + { "key": "Content-Security-Policy", "value": "#{CSP_VALUE_IN_ADO_VARIABLE}#" } ] } ] -} \ No newline at end of file +} diff --git a/materials_ui/src/__tests__/components/CaseSearch.test.tsx b/materials_ui/src/__tests__/components/CaseSearch.test.tsx index 7c9193e3..60bf89b6 100644 --- a/materials_ui/src/__tests__/components/CaseSearch.test.tsx +++ b/materials_ui/src/__tests__/components/CaseSearch.test.tsx @@ -8,7 +8,7 @@ describe('', () => { render( - + , ); expect(screen.getByText('Find a case')).toBeInTheDocument(); }); @@ -17,7 +17,7 @@ describe('', () => { render( - + , ); expect(screen.getByLabelText('Search for a case URN')).toBeInTheDocument(); }); @@ -26,7 +26,7 @@ describe('', () => { render( - + , ); expect(screen.getByRole('button', { name: 'Search' })).toBeInTheDocument(); }); @@ -35,10 +35,10 @@ describe('', () => { render( - + , ); expect( - screen.getByText('Search and review a CPS case in England and Wales') + screen.getByText('Search and review a CPS case in England and Wales'), ).toBeInTheDocument(); }); @@ -46,7 +46,7 @@ describe('', () => { render( - + , ); expect(screen.getByText('Cancel')).toBeInTheDocument(); }); @@ -55,7 +55,7 @@ describe('', () => { render( - + , ); const input = screen.getByLabelText('Search for a case URN'); @@ -64,8 +64,8 @@ describe('', () => { await userEvent.type(input, '06SC12345711'); await userEvent.click(button); - expect( - (await screen.findAllByText('Enter a URN in the right format')).length - ).toBeGreaterThan(0); + expect((await screen.findAllByText('Enter a URN in the right format')).length).toBeGreaterThan( + 0, + ); }); }); diff --git a/materials_ui/src/__tests__/stores/useCaseInfo.test.ts b/materials_ui/src/__tests__/stores/useCaseInfo.test.ts index c7543c38..eb4ce882 100644 --- a/materials_ui/src/__tests__/stores/useCaseInfo.test.ts +++ b/materials_ui/src/__tests__/stores/useCaseInfo.test.ts @@ -9,7 +9,7 @@ const caseInfoData1: CaseInfoType = { leadDefendantFirstNames: 'Joe', leadDefendantSurname: 'Bloggs', numberOfDefendants: 2, - unitName: 'Unit name 1' + unitName: 'Unit name 1', }; const caseInfoData2: CaseInfoType = { @@ -18,7 +18,7 @@ const caseInfoData2: CaseInfoType = { leadDefendantFirstNames: 'John', leadDefendantSurname: 'Doe', numberOfDefendants: 1, - unitName: 'Unit name 2' + unitName: 'Unit name 2', }; describe('stores > useCaseInfoStore', () => { diff --git a/materials_ui/src/__tests__/stores/useMaterialTags.test.ts b/materials_ui/src/__tests__/stores/useMaterialTags.test.ts index f49d8993..8c2b8c76 100644 --- a/materials_ui/src/__tests__/stores/useMaterialTags.test.ts +++ b/materials_ui/src/__tests__/stores/useMaterialTags.test.ts @@ -10,7 +10,7 @@ describe('useMaterialTags Store', () => { it('should set new tags correctly', () => { const newTags = [ { materialId: 1, tagName: 'tag1' }, - { materialId: 2, tagName: 'tag2' } + { materialId: 2, tagName: 'tag2' }, ]; useMaterialTags.getState().setTags(newTags); @@ -22,14 +22,14 @@ describe('useMaterialTags Store', () => { it('should update existing tags when the same materialId is added with new tagName', () => { const initialTags = [ { materialId: 1, tagName: 'tag1' }, - { materialId: 2, tagName: 'tag2' } + { materialId: 2, tagName: 'tag2' }, ]; useMaterialTags.getState().setTags(initialTags); const updatedTags = [ { materialId: 1, tagName: 'updatedTag1' }, - { materialId: 3, tagName: 'tag3' } + { materialId: 3, tagName: 'tag3' }, ]; useMaterialTags.getState().setTags(updatedTags); @@ -38,21 +38,21 @@ describe('useMaterialTags Store', () => { expect(store.materialTags).toEqual([ { materialId: 1, tagName: 'updatedTag1' }, { materialId: 2, tagName: 'tag2' }, - { materialId: 3, tagName: 'tag3' } + { materialId: 3, tagName: 'tag3' }, ]); }); it('should add new tags and update existing ones with the same materialId', () => { const newTags = [ { materialId: 1, tagName: 'tag1' }, - { materialId: 2, tagName: 'tag2' } + { materialId: 2, tagName: 'tag2' }, ]; useMaterialTags.getState().setTags(newTags); const duplicateTags = [ { materialId: 1, tagName: 'newTag1' }, - { materialId: 3, tagName: 'newTag3' } + { materialId: 3, tagName: 'newTag3' }, ]; useMaterialTags.getState().setTags(duplicateTags); @@ -61,14 +61,14 @@ describe('useMaterialTags Store', () => { expect(store.materialTags).toEqual([ { materialId: 1, tagName: 'newTag1' }, { materialId: 2, tagName: 'tag2' }, - { materialId: 3, tagName: 'newTag3' } + { materialId: 3, tagName: 'newTag3' }, ]); }); it('should clear all tags when clearTags is called with no materialIdsToRemove', () => { const newTags = [ { materialId: 1, tagName: 'tag1' }, - { materialId: 2, tagName: 'tag2' } + { materialId: 2, tagName: 'tag2' }, ]; useMaterialTags.getState().setTags(newTags); @@ -82,7 +82,7 @@ describe('useMaterialTags Store', () => { const newTags = [ { materialId: 1, tagName: 'tag1' }, { materialId: 2, tagName: 'tag2' }, - { materialId: 3, tagName: 'tag3' } + { materialId: 3, tagName: 'tag3' }, ]; useMaterialTags.getState().setTags(newTags); @@ -96,7 +96,7 @@ describe('useMaterialTags Store', () => { it('should not modify tags when clearTags is called with an empty array', () => { const newTags = [ { materialId: 1, tagName: 'tag1' }, - { materialId: 2, tagName: 'tag2' } + { materialId: 2, tagName: 'tag2' }, ]; useMaterialTags.getState().setTags(newTags); diff --git a/materials_ui/src/__tests__/stores/useSelectedItems.test.ts b/materials_ui/src/__tests__/stores/useSelectedItems.test.ts index 3d9620fd..5c48edb0 100644 --- a/materials_ui/src/__tests__/stores/useSelectedItems.test.ts +++ b/materials_ui/src/__tests__/stores/useSelectedItems.test.ts @@ -28,15 +28,13 @@ function getMaterial(override?: Partial): CaseMaterialsType { item: '', existingproducerOrWitnessId: 0, isReclassifiable: false, - ...override + ...override, }; } describe('stores > useSelectedItems', () => { beforeEach(() => { - useSelectedItemsStore.setState({ - items: { communications: [], materials: [] } - }); + useSelectedItemsStore.setState({ items: { communications: [], materials: [] } }); }); it('should initialise as expected', () => { @@ -50,16 +48,12 @@ describe('stores > useSelectedItems', () => { useSelectedItemsStore.getState().addItems([getMaterial()], 'materials'); expect(useSelectedItemsStore.getState().items.materials).toHaveLength(1); - useSelectedItemsStore - .getState() - .addItems([getMaterial({ id: 2 })], 'materials'); + useSelectedItemsStore.getState().addItems([getMaterial({ id: 2 })], 'materials'); expect(useSelectedItemsStore.getState().items.materials).toHaveLength(2); }); it('should add multiple material items to state (addItems())', () => { - useSelectedItemsStore - .getState() - .addItems([getMaterial(), getMaterial({ id: 2 })], 'materials'); + useSelectedItemsStore.getState().addItems([getMaterial(), getMaterial({ id: 2 })], 'materials'); expect(useSelectedItemsStore.getState().items.materials).toHaveLength(2); }); @@ -67,21 +61,15 @@ describe('stores > useSelectedItems', () => { useSelectedItemsStore.getState().addItems([getMaterial()], 'materials'); expect(useSelectedItemsStore.getState().items.materials).toHaveLength(1); - useSelectedItemsStore - .getState() - .addItems([getMaterial(), getMaterial({ id: 2 })], 'materials'); + useSelectedItemsStore.getState().addItems([getMaterial(), getMaterial({ id: 2 })], 'materials'); expect(useSelectedItemsStore.getState().items.materials).toHaveLength(2); }); it('should remove a single material item from state (removeItems())', () => { - useSelectedItemsStore - .getState() - .addItems([getMaterial(), getMaterial({ id: 2 })], 'materials'); + useSelectedItemsStore.getState().addItems([getMaterial(), getMaterial({ id: 2 })], 'materials'); expect(useSelectedItemsStore.getState().items.materials).toHaveLength(2); - useSelectedItemsStore - .getState() - .removeItems([getMaterial({ id: 2 })], 'materials'); + useSelectedItemsStore.getState().removeItems([getMaterial({ id: 2 })], 'materials'); expect(useSelectedItemsStore.getState().items.materials).toHaveLength(1); }); @@ -89,66 +77,40 @@ describe('stores > useSelectedItems', () => { useSelectedItemsStore .getState() .addItems( - [ - getMaterial(), - getMaterial({ id: 2 }), - getMaterial({ id: 3 }), - getMaterial({ id: 4 }) - ], - 'materials' + [getMaterial(), getMaterial({ id: 2 }), getMaterial({ id: 3 }), getMaterial({ id: 4 })], + 'materials', ); expect(useSelectedItemsStore.getState().items.materials).toHaveLength(4); useSelectedItemsStore .getState() - .removeItems( - [getMaterial({ id: 2 }), getMaterial({ id: 4 })], - 'materials' - ); + .removeItems([getMaterial({ id: 2 }), getMaterial({ id: 4 })], 'materials'); expect(useSelectedItemsStore.getState().items.materials).toHaveLength(2); }); it('should clear items from one type (clear(type))', () => { + useSelectedItemsStore.getState().addItems([getMaterial(), getMaterial({ id: 2 })], 'materials'); useSelectedItemsStore .getState() - .addItems([getMaterial(), getMaterial({ id: 2 })], 'materials'); - useSelectedItemsStore - .getState() - .addItems( - [getMaterial({ id: 3 }), getMaterial({ id: 4 })], - 'communications' - ); + .addItems([getMaterial({ id: 3 }), getMaterial({ id: 4 })], 'communications'); expect(useSelectedItemsStore.getState().items.materials).toHaveLength(2); - expect(useSelectedItemsStore.getState().items.communications).toHaveLength( - 2 - ); + expect(useSelectedItemsStore.getState().items.communications).toHaveLength(2); useSelectedItemsStore.getState().clear('communications'); - expect(useSelectedItemsStore.getState().items.communications).toHaveLength( - 0 - ); + expect(useSelectedItemsStore.getState().items.communications).toHaveLength(0); expect(useSelectedItemsStore.getState().items.materials).toHaveLength(2); }); it('should clear all items (clear())', () => { + useSelectedItemsStore.getState().addItems([getMaterial(), getMaterial({ id: 2 })], 'materials'); useSelectedItemsStore .getState() - .addItems([getMaterial(), getMaterial({ id: 2 })], 'materials'); - useSelectedItemsStore - .getState() - .addItems( - [getMaterial({ id: 3 }), getMaterial({ id: 4 })], - 'communications' - ); + .addItems([getMaterial({ id: 3 }), getMaterial({ id: 4 })], 'communications'); expect(useSelectedItemsStore.getState().items.materials).toHaveLength(2); - expect(useSelectedItemsStore.getState().items.communications).toHaveLength( - 2 - ); + expect(useSelectedItemsStore.getState().items.communications).toHaveLength(2); useSelectedItemsStore.getState().clear(); - expect(useSelectedItemsStore.getState().items.communications).toHaveLength( - 0 - ); + expect(useSelectedItemsStore.getState().items.communications).toHaveLength(0); expect(useSelectedItemsStore.getState().items.materials).toHaveLength(0); }); }); diff --git a/materials_ui/src/app.tsx b/materials_ui/src/app.tsx index 1e7b509c..d2a9ff2c 100644 --- a/materials_ui/src/app.tsx +++ b/materials_ui/src/app.tsx @@ -15,9 +15,7 @@ export const App = () => { }, [instance, accounts]); const account = instance.getActiveAccount() || accounts[0]; - const role = (account?.idTokenClaims?.roles as string[] | undefined)?.join( - ',' - ); + const role = (account?.idTokenClaims?.roles as string[] | undefined)?.join(','); useEffect(() => { if (role) setTelemetryUserRole(role); diff --git a/materials_ui/src/caseWorkApp/assetsCWA/svgs/DownArrowIcon.tsx b/materials_ui/src/caseWorkApp/assetsCWA/svgs/DownArrowIcon.tsx index 7780a698..86e770bf 100644 --- a/materials_ui/src/caseWorkApp/assetsCWA/svgs/DownArrowIcon.tsx +++ b/materials_ui/src/caseWorkApp/assetsCWA/svgs/DownArrowIcon.tsx @@ -1,8 +1,4 @@ -export const DownArrowIcon = (p: { - color: string; - rotateDegrees?: number; - scale?: number; -}) => { +export const DownArrowIcon = (p: { color: string; rotateDegrees?: number; scale?: number }) => { const rotateDegrees = p.rotateDegrees ?? 0; const scale = p.scale ?? 1; return ( diff --git a/materials_ui/src/caseWorkApp/components/LinkButton/LinkButton.module.scss b/materials_ui/src/caseWorkApp/components/LinkButton/LinkButton.module.scss index 818feffa..610ad082 100644 --- a/materials_ui/src/caseWorkApp/components/LinkButton/LinkButton.module.scss +++ b/materials_ui/src/caseWorkApp/components/LinkButton/LinkButton.module.scss @@ -7,7 +7,7 @@ font-size: 1.187rem; width: fit-content; color: #1d70b8; - font-family: "NewTransport", "Arial", sans-serif; + font-family: 'NewTransport', 'Arial', sans-serif; &:hover:not(:disabled):not(:focus) { color: #fff; diff --git a/materials_ui/src/caseWorkApp/components/LinkButton/LinkButton.tsx b/materials_ui/src/caseWorkApp/components/LinkButton/LinkButton.tsx index ca81a705..24ba8d33 100644 --- a/materials_ui/src/caseWorkApp/components/LinkButton/LinkButton.tsx +++ b/materials_ui/src/caseWorkApp/components/LinkButton/LinkButton.tsx @@ -26,9 +26,9 @@ export const LinkButton = forwardRef( ariaLabel, ariaExpanded, disabled = false, - type + type, }, - ref + ref, ) => { const resolvedClassName = `${classes.linkButton} ${className}`; return ( @@ -47,5 +47,5 @@ export const LinkButton = forwardRef( {children} ); - } + }, ); diff --git a/materials_ui/src/caseWorkApp/components/button/index.tsx b/materials_ui/src/caseWorkApp/components/button/index.tsx index dc6e8e18..f590149b 100644 --- a/materials_ui/src/caseWorkApp/components/button/index.tsx +++ b/materials_ui/src/caseWorkApp/components/button/index.tsx @@ -14,29 +14,19 @@ const buttonVariantMap: { [k in TButtonVariant]: string } = { inverse: 'govuk-button--inverse', default: 'govuk-button--secondary', secondary: 'govuk-button--secondary', - red: 'govuk-button--red' // custom class to maintain consistency, not required + red: 'govuk-button--red', // custom class to maintain consistency, not required }; const buttonSizeStyleMap: { [k in TButtonSize]: CSSProperties } = { s: { fontSize: '0.875rem' }, - m: {} + m: {}, }; const buttonVariantStyleMap: { [k in TButtonVariant]?: CSSProperties } = { - red: { backgroundColor: '#d4351c', color: 'white' } + red: { backgroundColor: '#d4351c', color: 'white' }, }; export const Button = forwardRef( - ( - { - variant = 'default', - size = 'm', - className, - style, - children, - ...restProps - }, - ref - ) => { + ({ variant = 'default', size = 'm', className, style, children, ...restProps }, ref) => { const variantClass = buttonVariantMap[variant]; const variantStyle = buttonVariantStyleMap[variant]; const sizeStyle = buttonSizeStyleMap[size]; @@ -52,5 +42,5 @@ export const Button = forwardRef( ); - } + }, ); diff --git a/materials_ui/src/caseWorkApp/components/dropDownButton/DropdownButton.module.scss b/materials_ui/src/caseWorkApp/components/dropDownButton/DropdownButton.module.scss index 1fa57966..17b30241 100644 --- a/materials_ui/src/caseWorkApp/components/dropDownButton/DropdownButton.module.scss +++ b/materials_ui/src/caseWorkApp/components/dropDownButton/DropdownButton.module.scss @@ -58,5 +58,3 @@ color: #b1b4b6; } } - - diff --git a/materials_ui/src/caseWorkApp/components/dropDownButton/DropdownButton.tsx b/materials_ui/src/caseWorkApp/components/dropDownButton/DropdownButton.tsx index dc3b86e7..03dc96b9 100644 --- a/materials_ui/src/caseWorkApp/components/dropDownButton/DropdownButton.tsx +++ b/materials_ui/src/caseWorkApp/components/dropDownButton/DropdownButton.tsx @@ -8,23 +8,12 @@ import classes from './DropdownButton.module.scss'; type TButtonProps = React.ComponentPropsWithoutRef; -export const DropdownListItem = ( - initProps: TButtonProps & { borderBottom: boolean } -) => { +export const DropdownListItem = (initProps: TButtonProps & { borderBottom: boolean }) => { const { borderBottom, ...props } = initProps; return ( -
+
@@ -81,36 +70,18 @@ export const DropdownButton2 = (p: { return ( - {p.isOpen && (
-
+
{p.children}
@@ -144,18 +115,13 @@ export const DropdownButton: React.FC = ({ dataTestId = 'dropdown-btn', ariaLabel = 'dropdown', disabled = false, - iconScale = 1 + iconScale = 1, }) => { const dropDownBtnRef = useRef(null); const panelRef = useRef(null); const [buttonOpen, setButtonOpen] = useState(false); - useGlobalDropdownClose( - dropDownBtnRef, - panelRef, - setButtonOpen, - '#dropdown-panel' - ); + useGlobalDropdownClose(dropDownBtnRef, panelRef, setButtonOpen, '#dropdown-panel'); const handleBtnClick = (id: string) => { setButtonOpen(false); @@ -178,18 +144,11 @@ export const DropdownButton: React.FC = ({ >
{name && ( - + {name} )} - +
diff --git a/materials_ui/src/caseWorkApp/components/tabs/TabButtons.tsx b/materials_ui/src/caseWorkApp/components/tabs/TabButtons.tsx index 84d5cf6f..418f606e 100644 --- a/materials_ui/src/caseWorkApp/components/tabs/TabButtons.tsx +++ b/materials_ui/src/caseWorkApp/components/tabs/TabButtons.tsx @@ -16,28 +16,20 @@ const TabButtons: React.FC = ({ items, activeTabIndex, handleTabSelection, - handleCloseTab + handleCloseTab, }) => { const activeTabRef = useRef(null); useEffect(() => { activeTabRef.current?.focus(); - activeTabRef.current?.parentElement?.scrollIntoView({ - behavior: 'smooth', - block: 'nearest' - }); + activeTabRef.current?.parentElement?.scrollIntoView({ behavior: 'smooth', block: 'nearest' }); }, [activeTabIndex, items.length]); type ArrowKeyCodes = 'ArrowLeft' | 'ArrowRight'; - const ARROW_KEY_SHIFTS: Record = { - ArrowLeft: -1, - ArrowRight: 1 - }; + const ARROW_KEY_SHIFTS: Record = { ArrowLeft: -1, ArrowRight: 1 }; - const handleKeyPressOnTab: React.KeyboardEventHandler = ( - ev - ) => { + const handleKeyPressOnTab: React.KeyboardEventHandler = (ev) => { if (ev.code in ARROW_KEY_SHIFTS) { const thisShift = ARROW_KEY_SHIFTS[ev.code as ArrowKeyCodes]; // -1, 1, or undefined moveToNextOrPreviousTab(thisShift); @@ -50,7 +42,7 @@ const TabButtons: React.FC = ({ document.getElementById('tabs-dropdown')?.click(); setTimeout(() => { const firstItem = document.querySelector( - '#dropdown-panel button:not(:disabled)' + '#dropdown-panel button:not(:disabled)', ); firstItem?.focus(); }, 0); @@ -76,10 +68,7 @@ const TabButtons: React.FC = ({ }; const tabDropdownItems = useMemo(() => { - return items.map((item) => ({ - ...item, - disabled: item.id === items[activeTabIndex]?.id - })); + return items.map((item) => ({ ...item, disabled: item.id === items[activeTabIndex]?.id })); }, [items, activeTabIndex]); if (!items.length) { @@ -116,9 +105,7 @@ const TabButtons: React.FC = ({
-
+
    {items.map((item, index) => { const { id, label, ariaLabel } = item; @@ -126,9 +113,7 @@ const TabButtons: React.FC = ({ return (
  • = ({ > @@ -62,12 +53,7 @@ export const Accordion = ({ items = [], plain = false }: AccordionProps) => { data-testid="accordion" > {items.map((item, index) => ( - + ))}
); diff --git a/materials_ui/src/components/Banner/Banner.scss b/materials_ui/src/components/Banner/Banner.scss index fe02bc0d..a46d8f9d 100644 --- a/materials_ui/src/components/Banner/Banner.scss +++ b/materials_ui/src/components/Banner/Banner.scss @@ -12,4 +12,4 @@ max-width: 66.666%; } } -} \ No newline at end of file +} diff --git a/materials_ui/src/components/Banner/Banner.tsx b/materials_ui/src/components/Banner/Banner.tsx index 24eb52c4..fcbad05d 100644 --- a/materials_ui/src/components/Banner/Banner.tsx +++ b/materials_ui/src/components/Banner/Banner.tsx @@ -4,11 +4,7 @@ import './Banner.scss'; type Props = BannerType; -export const Banner = ({ - type = 'success', - header, - content -}: PropsWithChildren) => { +export const Banner = ({ type = 'success', header, content }: PropsWithChildren) => { const bannerRef = useRef(null); useEffect(() => { @@ -49,10 +45,7 @@ export const Banner = ({ tabIndex={-1} >
-

+

{getBannerTitle()}

diff --git a/materials_ui/src/components/Button/AutoReclassifyButton.tsx b/materials_ui/src/components/Button/AutoReclassifyButton.tsx index b01ef3a7..4f44c3ab 100644 --- a/materials_ui/src/components/Button/AutoReclassifyButton.tsx +++ b/materials_ui/src/components/Button/AutoReclassifyButton.tsx @@ -7,9 +7,7 @@ import { trackAction } from '../../telemetry/appInsights'; export const AutoReclassifyButton = () => { const [errorCount, setErrorCount] = useState(0); const { resetBanner, setBanner } = useBanner(); - const { mutate: refreshMaterials } = useCaseMaterials({ - dataType: 'materials' - }); + const { mutate: refreshMaterials } = useCaseMaterials({ dataType: 'materials' }); const { setTags } = useMaterialTags(); const { mutate: submitAutoReclassifyRequest } = useAutoReclassify({ @@ -20,7 +18,7 @@ export const AutoReclassifyButton = () => { setBanner({ type: 'important', header: 'Important', - content: 'No materials were identified for reclassification.' + content: 'No materials were identified for reclassification.', }); } @@ -29,15 +27,14 @@ export const AutoReclassifyButton = () => { setBanner({ type: 'error', header: 'An error occurred', - content: - 'There was a problem reclassifying materials. Please try again.' + content: 'There was a problem reclassifying materials. Please try again.', }); } else { setBanner({ type: 'error', header: 'An error occurred', content: - 'Materials cannot be reclassified automatically. You can still reclassify materials manually.' + 'Materials cannot be reclassified automatically. You can still reclassify materials manually.', }); } } @@ -51,19 +48,19 @@ export const AutoReclassifyButton = () => { setTags( data?.reclassifiedMaterials?.map((material) => ({ materialId: material?.materialId, - tagName: 'Reclassified' - })) + tagName: 'Reclassified', + })), ); setErrorCount(0); setBanner({ type: 'success', header: 'Reclassification successful', - content: `${totalMaterialsProcessed} Unused Material${totalMaterialsProcessed === 1 ? '' : 's'} reclassified successfully.` + content: `${totalMaterialsProcessed} Unused Material${totalMaterialsProcessed === 1 ? '' : 's'} reclassified successfully.`, }); await refreshMaterials(); - } + }, }); const handleClick = async () => { diff --git a/materials_ui/src/components/ButtonMenu/ButtonMenu.tsx b/materials_ui/src/components/ButtonMenu/ButtonMenu.tsx index 49e5a865..91084090 100644 --- a/materials_ui/src/components/ButtonMenu/ButtonMenu.tsx +++ b/materials_ui/src/components/ButtonMenu/ButtonMenu.tsx @@ -1,29 +1,18 @@ import { KeyboardEvent, useEffect, useRef, useState } from 'react'; import './_button-menu.scss'; -type MenuItem = { - label: string; - onClick: () => void; - className?: string; - hide?: boolean; -}; +type MenuItem = { label: string; onClick: () => void; className?: string; hide?: boolean }; type Props = { menuTitle: string; menuItems: MenuItem[]; isDisabled?: boolean }; -export function ButtonMenuComponent({ - menuTitle, - menuItems, - isDisabled = false -}: Props) { +export function ButtonMenuComponent({ menuTitle, menuItems, isDisabled = false }: Props) { const [openMenu, setOpenMenu] = useState(false); const buttonRef = useRef(null); const itemsRef = useRef<(HTMLButtonElement | null)[]>([]); // Focus helper const focusItem = (index: number) => { - const visibleItems = itemsRef.current.filter( - Boolean - ) as HTMLButtonElement[]; + const visibleItems = itemsRef.current.filter(Boolean) as HTMLButtonElement[]; if (!visibleItems.length) return; if (index >= visibleItems.length) index = 0; @@ -33,12 +22,10 @@ export function ButtonMenuComponent({ const currentFocusIndex = () => { const visibleItems = itemsRef.current.filter( - (item): item is HTMLButtonElement => item !== null + (item): item is HTMLButtonElement => item !== null, ); const active = document.activeElement; - return active instanceof HTMLButtonElement - ? visibleItems.indexOf(active) - : -1; + return active instanceof HTMLButtonElement ? visibleItems.indexOf(active) : -1; }; const closeMenu = (moveFocus = true) => { @@ -60,9 +47,7 @@ export function ButtonMenuComponent({ const handleKeyDown = (event: KeyboardEvent) => { const { key } = event; const isToggle = event.target === buttonRef.current; - const isMenuItem = itemsRef.current - .filter(Boolean) - .includes(event.target as HTMLButtonElement); + const isMenuItem = itemsRef.current.filter(Boolean).includes(event.target as HTMLButtonElement); if (isToggle) { if (isDisabled) return; @@ -122,10 +107,7 @@ export function ButtonMenuComponent({ return (
- ) + ), )} )} diff --git a/materials_ui/src/components/CaseInfo/CaseInfo.tsx b/materials_ui/src/components/CaseInfo/CaseInfo.tsx index 1578360b..98b5906b 100644 --- a/materials_ui/src/components/CaseInfo/CaseInfo.tsx +++ b/materials_ui/src/components/CaseInfo/CaseInfo.tsx @@ -17,9 +17,7 @@ export const CaseInfo = ({ caseInfo }: Props) => { return null; } - const handleCaseDefendantsLinkClick = ( - event: MouseEvent - ) => { + const handleCaseDefendantsLinkClick = (event: MouseEvent) => { event.preventDefault(); navigate(getRoute('REVIEW_REDACT'), { state: { docType: 'DAC' } }); @@ -30,9 +28,7 @@ export const CaseInfo = ({ caseInfo }: Props) => { ? `, ${caseInfo?.leadDefendantFirstNames}` : ''; const plusNumber = - caseInfo?.numberOfDefendants > 1 - ? ` +${caseInfo?.numberOfDefendants - 1}` - : ''; + caseInfo?.numberOfDefendants > 1 ? ` +${caseInfo?.numberOfDefendants - 1}` : ''; const caseInfoName = `${surname}${firstNames}${plusNumber}`; @@ -49,9 +45,7 @@ export const CaseInfo = ({ caseInfo }: Props) => {
-

- {caseInfoName} -

+

{caseInfoName}

{caseInfo?.urn}

{caseInfo.numberOfDefendants > 0 && (

diff --git a/materials_ui/src/components/Checkbox/Checkbox.tsx b/materials_ui/src/components/Checkbox/Checkbox.tsx index c7fa330e..0dfa8407 100644 --- a/materials_ui/src/components/Checkbox/Checkbox.tsx +++ b/materials_ui/src/components/Checkbox/Checkbox.tsx @@ -17,7 +17,7 @@ export default function Checkbox({ ariaLabel, labelVisuallyHidden, onChange, - value + value, }: Props) { return (

diff --git a/materials_ui/src/components/DateField/DateField.tsx b/materials_ui/src/components/DateField/DateField.tsx index 6616e6c2..87139192 100644 --- a/materials_ui/src/components/DateField/DateField.tsx +++ b/materials_ui/src/components/DateField/DateField.tsx @@ -1,11 +1,5 @@ import dayjs from 'dayjs'; -import { - forwardRef, - useEffect, - useImperativeHandle, - useRef, - useState -} from 'react'; +import { forwardRef, useEffect, useImperativeHandle, useRef, useState } from 'react'; type Props = { id: string; @@ -20,15 +14,9 @@ export const DateField = forwardRef( ({ error, id, hint, label, onChange, value }, ref) => { const initialDate = value && dayjs(value).isValid() ? dayjs(value) : null; - const [day, setDay] = useState( - initialDate ? String(initialDate.date()) : '' - ); - const [month, setMonth] = useState( - initialDate ? String(initialDate.month() + 1) : '' - ); - const [year, setYear] = useState( - initialDate ? String(initialDate.year()) : '' - ); + const [day, setDay] = useState(initialDate ? String(initialDate.date()) : ''); + const [month, setMonth] = useState(initialDate ? String(initialDate.month() + 1) : ''); + const [year, setYear] = useState(initialDate ? String(initialDate.year()) : ''); // Internal refs const dayRef = useRef(null); @@ -48,14 +36,8 @@ export const DateField = forwardRef( }, [day, month, year, onChange]); return ( -
-
+
+
(
-
-
-
); - } + }, ); diff --git a/materials_ui/src/components/DefinitionList/DefinitionList.tsx b/materials_ui/src/components/DefinitionList/DefinitionList.tsx index 5391d456..05ac15ee 100644 --- a/materials_ui/src/components/DefinitionList/DefinitionList.tsx +++ b/materials_ui/src/components/DefinitionList/DefinitionList.tsx @@ -8,9 +8,7 @@ export const DefinitionList = ({ items, fixedWidth }: Props) => { if (!items.length) return null; return ( -
+
{items.map((item, index) => (
{item.title}
diff --git a/materials_ui/src/components/DocumentKeywordSearch/DocumentKeywordSearch.tsx b/materials_ui/src/components/DocumentKeywordSearch/DocumentKeywordSearch.tsx index 8b28341b..939cf5ff 100644 --- a/materials_ui/src/components/DocumentKeywordSearch/DocumentKeywordSearch.tsx +++ b/materials_ui/src/components/DocumentKeywordSearch/DocumentKeywordSearch.tsx @@ -7,18 +7,10 @@ import { useDocumentSearchResults, useFilters, usePager, - useSearchTracker + useSearchTracker, } from '../../hooks'; -import { - Banner, - LoadingSpinner, - Modal, - Pagination, - SearchInput, - SectionBreak, - TwoCol -} from '..'; +import { Banner, LoadingSpinner, Modal, Pagination, SearchInput, SectionBreak, TwoCol } from '..'; import { categoriseDocument } from '../../materials_components/DocumentSelectAccordion/utils/categoriseDocument'; import { SearchTermResultType } from '../../schemas/documents'; @@ -29,36 +21,21 @@ import { DocumentKeywordSearchFilters } from '../Filters/DocumentKeywordSearchFi import { DEFAULT_RESULTS_PER_PAGE } from '../../constants/query'; import './DocumentKeywordSearch.scss'; -type DocumentKeywordSearchProps = { - modalOpen: boolean; - setModalOpen: (open: boolean) => void; -}; +type DocumentKeywordSearchProps = { modalOpen: boolean; setModalOpen: (open: boolean) => void }; -export const DocumentKeywordSearch = ({ - modalOpen, - setModalOpen -}: DocumentKeywordSearchProps) => { +export const DocumentKeywordSearch = ({ modalOpen, setModalOpen }: DocumentKeywordSearchProps) => { const { getRoute } = useAppRoute(); const [searchTerm, setSearchTerm] = useState(null); - const [expandedDocuments, setExpandedDocuments] = useState< - Record - >({}); + const [expandedDocuments, setExpandedDocuments] = useState>({}); const [selectedSort, setSelectedSort] = useState('date'); - const { isComplete: trackerComplete, failedToConvert } = - useSearchTracker(searchTerm); + const { isComplete: trackerComplete, failedToConvert } = useSearchTracker(searchTerm); - const { searchResults, loading } = useDocumentSearch( - searchTerm, - trackerComplete - ); + const { searchResults, loading } = useDocumentSearch(searchTerm, trackerComplete); const { documents } = useDocuments(); - const combinedSearchResults = useDocumentSearchResults( - documents ?? [], - searchResults ?? [] - ); + const combinedSearchResults = useDocumentSearchResults(documents ?? [], searchResults ?? []); const { filters, resetFilters } = useFilters('documents'); @@ -84,14 +61,11 @@ export const DocumentKeywordSearch = ({ const newStatus = selectedStatus.includes('New'); - const sortColumn = - selectedSort === 'date' - ? 'cmsFileCreatedDate' - : 'resultsPerDocumentCount'; + const sortColumn = selectedSort === 'date' ? 'cmsFileCreatedDate' : 'resultsPerDocumentCount'; const sortFn = defaultSortFn({ column: sortColumn, - direction: 'descending' + direction: 'descending', }); return combinedSearchResults @@ -107,31 +81,19 @@ export const DocumentKeywordSearch = ({ (category !== null && selectedCategories.includes(category)) ); }) - .map((item) => ({ - ...item, - [sortColumn]: String(item[sortColumn] ?? '') - })) + .map((item) => ({ ...item, [sortColumn]: String(item[sortColumn] ?? '') })) .sort(sortFn); - }, [ - combinedSearchResults, - filters?.filters?.category, - filters?.filters?.status, - selectedSort - ]); + }, [combinedSearchResults, filters?.filters?.category, filters?.filters?.status, selectedSort]); const highlightExactMatches = ( text: string, - words: { boundingBox: number[] | null; text: string; matchType: string[] }[] + words: { boundingBox: number[] | null; text: string; matchType: string[] }[], ) => { - const exactWords = words - .filter((w) => w.matchType.includes('Exact')) - .map((w) => w.text); + const exactWords = words.filter((w) => w.matchType.includes('Exact')).map((w) => w.text); if (!text || exactWords.length === 0) return text; - const escaped = exactWords.map((w) => - w.replace(/[.*+?^${}()|[\]\\]/g, '\\$&') - ); + const escaped = exactWords.map((w) => w.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')); const regex = new RegExp(`(${escaped.join('|')})`, 'gi'); @@ -142,23 +104,16 @@ export const DocumentKeywordSearch = ({ {part} ) : ( {part} - ) + ), ); }; - const { - currentPage, - totalPages, - startIndex, - endIndex, - setNextPage, - setPage, - setPreviousPage - } = usePager({ - totalItems: filteredResults ? filteredResults.length : 0, - initialPageSize: DEFAULT_RESULTS_PER_PAGE, - initialPage: 0 - }); + const { currentPage, totalPages, startIndex, endIndex, setNextPage, setPage, setPreviousPage } = + usePager({ + totalItems: filteredResults ? filteredResults.length : 0, + initialPageSize: DEFAULT_RESULTS_PER_PAGE, + initialPage: 0, + }); return (
@@ -171,16 +126,11 @@ export const DocumentKeywordSearch = ({ /> - + {trackerComplete && ( setSearchTerm(term)} - /> + setSearchTerm(term)} /> } > {loading &&

Searching…

} @@ -193,16 +143,12 @@ export const DocumentKeywordSearch = ({ {documents?.length} documents in this case

- Search may not have found all instances of "{searchTerm}" in - this case + Search may not have found all instances of "{searchTerm}" in this case

-
@@ -228,10 +172,7 @@ export const DocumentKeywordSearch = ({ type="important" header="Technical problems stopped us from searching these documents:" content={failedToConvert.map((doc: SearchTermResultType) => ( -

+

{doc.presentationTitle}

))} @@ -244,22 +185,15 @@ export const DocumentKeywordSearch = ({ const isExpanded = expandedDocuments[doc.parentId] ?? false; const first = doc.matches[0]; const firstLineMatchCount = - first?.words.filter((word) => - word.matchType?.includes('Exact') - ).length ?? 0; - const remainingCount = - (doc.resultsPerDocumentCount ?? 0) - firstLineMatchCount; + first?.words.filter((word) => word.matchType?.includes('Exact')).length ?? 0; + const remainingCount = (doc.resultsPerDocumentCount ?? 0) - firstLineMatchCount; return (

{doc.documentTitle} @@ -270,24 +204,17 @@ export const DocumentKeywordSearch = ({ Uploaded: {formatDateLong(doc.cmsFileCreatedDate)}

{doc.cmsDocType.documentType && ( -

- Type: {doc.cmsDocType.documentType} -

+

Type: {doc.cmsDocType.documentType}

)}
-

- {first && - highlightExactMatches(first.text, first.words)} -

+

{first && highlightExactMatches(first.text, first.words)}

{isExpanded && remainingCount > 0 && ( <> {doc.matches.slice(1).map((match, index) => (
-

- {highlightExactMatches(match.text, match.words)} -

+

{highlightExactMatches(match.text, match.words)}

))} @@ -299,13 +226,11 @@ export const DocumentKeywordSearch = ({ cursor: 'pointer', textDecoration: 'underline', display: 'inline-block', - marginTop: 8 + marginTop: 8, }} onClick={() => toggleDocumentExpand(doc.parentId)} > - {isExpanded - ? 'Hide additional results' - : `View ${remainingCount} more`} + {isExpanded ? 'Hide additional results' : `View ${remainingCount} more`} )}
diff --git a/materials_ui/src/components/DocumentPreview/DocumentActions.tsx b/materials_ui/src/components/DocumentPreview/DocumentActions.tsx index 99c2de4d..786fbf20 100644 --- a/materials_ui/src/components/DocumentPreview/DocumentActions.tsx +++ b/materials_ui/src/components/DocumentPreview/DocumentActions.tsx @@ -1,10 +1,6 @@ type Props = { label: string; isOpen: boolean; onDocumentOpen: () => void }; -export default function DocumentActions({ - label, - isOpen = false, - onDocumentOpen -}: Props) { +export default function DocumentActions({ label, isOpen = false, onDocumentOpen }: Props) { return ( diff --git a/materials_ui/src/components/DocumentPreview/DocumentPreview.tsx b/materials_ui/src/components/DocumentPreview/DocumentPreview.tsx index 3c4cf482..b35c80d9 100644 --- a/materials_ui/src/components/DocumentPreview/DocumentPreview.tsx +++ b/materials_ui/src/components/DocumentPreview/DocumentPreview.tsx @@ -11,7 +11,7 @@ export default function DocumentPreview({ row }: Props) { const { data: caseDocumentData, loading: caseDocumentLoading, - error: caseDocumentError + error: caseDocumentError, } = useDocumentPreview({ materialId: row.materialId }); const errorTitle = caseDocumentError?.toString().includes('403') @@ -38,10 +38,7 @@ export default function DocumentPreview({ row }: Props) { return ( <> - + {content} ); diff --git a/materials_ui/src/components/Drawer/Drawer.tsx b/materials_ui/src/components/Drawer/Drawer.tsx index ae896fbb..fcaae86c 100644 --- a/materials_ui/src/components/Drawer/Drawer.tsx +++ b/materials_ui/src/components/Drawer/Drawer.tsx @@ -3,10 +3,7 @@ import './Drawer.scss'; type Props = { heading: string }; -export default function Drawer({ - heading, - children -}: PropsWithChildren) { +export default function Drawer({ heading, children }: PropsWithChildren) { return (
diff --git a/materials_ui/src/components/Drawer/RenameDrawer.tsx b/materials_ui/src/components/Drawer/RenameDrawer.tsx index 57b3717f..383696d6 100644 --- a/materials_ui/src/components/Drawer/RenameDrawer.tsx +++ b/materials_ui/src/components/Drawer/RenameDrawer.tsx @@ -17,36 +17,26 @@ export const RenameDrawer = ({ material, onCancel, onSuccess }: Props) => { onSuccess: () => { trackAction('Renamed', { materialId: - material && 'materialId' in material - ? material.materialId?.toString() - : undefined, - category: - material && 'category' in material ? material.category : undefined + material && 'materialId' in material ? material.materialId?.toString() : undefined, + category: material && 'category' in material ? material.category : undefined, }); onSuccess(); - } + }, }); const [error, setError] = useState(''); - const getDefaultMaterialName = ( - material: CaseMaterialsType | TDocument | null - ) => { + const getDefaultMaterialName = (material: CaseMaterialsType | TDocument | null) => { if (!material) return ''; if ('subject' in material && typeof material.subject === 'string') { return material.subject; } - if ( - 'presentationTitle' in material && - typeof material.presentationTitle === 'string' - ) { + if ('presentationTitle' in material && typeof material.presentationTitle === 'string') { return material.presentationTitle; } return ''; }; - const [inputValue, setInputValue] = useState( - getDefaultMaterialName(material) - ); + const [inputValue, setInputValue] = useState(getDefaultMaterialName(material)); if (!material) return null; @@ -85,23 +75,13 @@ export const RenameDrawer = ({ material, onCancel, onSuccess }: Props) => { return ( - + {!isMutating && (
-
+

-

@@ -114,9 +94,7 @@ export const RenameDrawer = ({ material, onCancel, onSuccess }: Props) => { )} { shallowFilters, setCheckboxFilter, setSearch, - saveFiltersToContext + saveFiltersToContext, } = useFilters('communications'); const hasAccess = useFeatureFlag(); - const handleCheckboxChange = ( - filterGroup: string, - event: ChangeEvent - ) => { + const handleCheckboxChange = (filterGroup: string, event: ChangeEvent) => { const { checked, value } = event.target; setCheckboxFilter(filterGroup, value, checked); @@ -38,22 +35,10 @@ export const CommsFilters = () => { }; const formGroups = [ - { - heading: 'In/Out', - data: ['Incoming', 'Outgoing'], - filterGroup: 'direction' - }, - { - heading: 'Comms type', - data: communicationsCategoryList, - filterGroup: 'method' - }, - { - heading: 'Comms with', - data: communicationsWithList, - filterGroup: 'party' - }, - { heading: 'Type', data: typeList, filterGroup: 'type' } + { heading: 'In/Out', data: ['Incoming', 'Outgoing'], filterGroup: 'direction' }, + { heading: 'Comms type', data: communicationsCategoryList, filterGroup: 'method' }, + { heading: 'Comms with', data: communicationsWithList, filterGroup: 'party' }, + { heading: 'Type', data: typeList, filterGroup: 'type' }, ]; return ( @@ -69,18 +54,12 @@ export const CommsFilters = () => {
-

- New communication -

+

New communication

handleCheckboxChange('readStatus', event)} value={READ_STATUS.UNREAD} /> @@ -93,21 +72,14 @@ export const CommsFilters = () => {
-

- {heading} -

+

{heading}

{data.map((value) => ( - handleCheckboxChange(`${filterGroup}`, event) - } + checked={shallowFilters?.filters?.[filterGroup]?.includes(value) || false} + onChange={(event) => handleCheckboxChange(`${filterGroup}`, event)} value={value} key={value} /> diff --git a/materials_ui/src/components/Filters/DocumentKeywordSearchFilters.tsx b/materials_ui/src/components/Filters/DocumentKeywordSearchFilters.tsx index 3ea63820..a1e4f11e 100644 --- a/materials_ui/src/components/Filters/DocumentKeywordSearchFilters.tsx +++ b/materials_ui/src/components/Filters/DocumentKeywordSearchFilters.tsx @@ -3,17 +3,15 @@ import { useDocuments, useFilters } from '../../hooks'; import { categoriseDocument } from '../../materials_components/DocumentSelectAccordion/utils/categoriseDocument'; import { categoryDetails, - initDocsOnDocCategoryNamesMap + initDocsOnDocCategoryNamesMap, } from '../../materials_components/DocumentSelectAccordion/utils/categoriseDocumentHelperUtils'; import Checkbox from '../Checkbox/Checkbox'; import { FilterForm } from './FilterForm'; -type DocumentKeywordSearchFiltersProps = { - onSearchSubmit?: (term: string) => void; -}; +type DocumentKeywordSearchFiltersProps = { onSearchSubmit?: (term: string) => void }; export const DocumentKeywordSearchFilters = ({ - onSearchSubmit + onSearchSubmit, }: DocumentKeywordSearchFiltersProps) => { const { filters, @@ -21,15 +19,12 @@ export const DocumentKeywordSearchFilters = ({ shallowFilters, setCheckboxFilter, saveFiltersToContext, - setSearch + setSearch, } = useFilters('documents'); const { documents } = useDocuments(); - const handleCheckboxChange = ( - filterGroup: string, - event: ChangeEvent - ) => { + const handleCheckboxChange = (filterGroup: string, event: ChangeEvent) => { const { checked, value } = event.target; setCheckboxFilter(filterGroup, value, checked); @@ -57,7 +52,7 @@ export const DocumentKeywordSearchFilters = ({ const categoriesList = categoryDetails.map((category) => ({ key: category.categoryName, label: category.label, - documents: docsOnDocCategoryNames[category.categoryName] + documents: docsOnDocCategoryNames[category.categoryName], })); return ( @@ -72,16 +67,12 @@ export const DocumentKeywordSearchFilters = ({
-

- New materials -

+

New materials

handleCheckboxChange('status', event)} value={'New'} /> @@ -99,10 +90,7 @@ export const DocumentKeywordSearchFilters = ({ handleCheckboxChange('category', event)} value={category.key} key={category.key} diff --git a/materials_ui/src/components/Filters/FilterForm.tsx b/materials_ui/src/components/Filters/FilterForm.tsx index 363647fa..1be96cc2 100644 --- a/materials_ui/src/components/Filters/FilterForm.tsx +++ b/materials_ui/src/components/Filters/FilterForm.tsx @@ -17,7 +17,7 @@ export const FilterForm = ({ onSearchChange, searchLabel, defaultSearchValue, - children + children, }: FilterFormProps) => { return ( { shallowFilters, setCheckboxFilter, setSearch, - saveFiltersToContext + saveFiltersToContext, } = useFilters('materials'); const hasAccess = useFeatureFlag(); - const handleCheckboxChange = ( - filterGroup: string, - event: ChangeEvent - ) => { + const handleCheckboxChange = (filterGroup: string, event: ChangeEvent) => { const { checked, value } = event.target; setCheckboxFilter(filterGroup, value, checked); @@ -48,18 +45,12 @@ export const MaterialsFilters = () => {
-

- New material -

+

New material

handleCheckboxChange('readStatus', event)} value={READ_STATUS.UNREAD} /> @@ -73,13 +64,12 @@ export const MaterialsFilters = () => {

Status

+ {statusList.map((status) => ( handleCheckboxChange('status', event)} value={status} key={status} @@ -98,9 +88,7 @@ export const MaterialsFilters = () => { handleCheckboxChange('category', event)} value={value} key={value} diff --git a/materials_ui/src/components/Layout/Layout.tsx b/materials_ui/src/components/Layout/Layout.tsx index f4eb44d1..0dc82863 100644 --- a/materials_ui/src/components/Layout/Layout.tsx +++ b/materials_ui/src/components/Layout/Layout.tsx @@ -19,7 +19,7 @@ export const Layout = ({ children, plain = false, title, - shouldBlockNavigationCheck + shouldBlockNavigationCheck, }: PropsWithChildren) => { const { banners } = useBanner(); const { caseInfo, isLoading: caseInfoLoading } = useCaseInfoStore(); @@ -31,36 +31,32 @@ export const Layout = ({ id: 'pcd-request', name: 'PCD Request', href: getRoute('PCD_REQUEST'), - active: - location.pathname === '/' || - location.pathname.includes(getRoute('PCD_REQUEST')) + active: location.pathname === '/' || location.pathname.includes(getRoute('PCD_REQUEST')), }, { id: 'materials', name: 'Materials', href: getRoute('MATERIALS'), - active: location.pathname === getRoute('MATERIALS') + active: location.pathname === getRoute('MATERIALS'), }, { id: 'review-redact', name: 'Review and Redact', href: getRoute('REVIEW_REDACT'), - active: location.pathname === getRoute('REVIEW_REDACT') + active: location.pathname === getRoute('REVIEW_REDACT'), }, { id: 'communications', name: 'Communications', href: getRoute('COMMUNICATIONS'), - active: location.pathname === getRoute('COMMUNICATIONS') + active: location.pathname === getRoute('COMMUNICATIONS'), }, { id: 'pcd-review', name: 'Reviews', href: getRoute('PCD_REVIEW'), - active: - location.pathname === '/' || - location.pathname.includes(getRoute('PCD_REVIEW')) - } + active: location.pathname === '/' || location.pathname.includes(getRoute('PCD_REVIEW')), + }, ]; const tabs = initTabs.map((tab) => ({ ...tab, shouldBlockNavigationCheck })); @@ -74,17 +70,11 @@ export const Layout = ({ return ( <>
-
- {banners && - banners.map((banner, index) => )} -
+
{banners && banners.map((banner, index) => )}
{!plain ? ( <> - + {!caseInfoLoading && caseInfo && ( <> diff --git a/materials_ui/src/components/LoadingSpinner/LoadingSpinner.tsx b/materials_ui/src/components/LoadingSpinner/LoadingSpinner.tsx index 9ff60805..4210964e 100644 --- a/materials_ui/src/components/LoadingSpinner/LoadingSpinner.tsx +++ b/materials_ui/src/components/LoadingSpinner/LoadingSpinner.tsx @@ -1,14 +1,8 @@ import { useRef } from 'react'; -type Props = { - isLoading: boolean; - textContent?: string; -}; +type Props = { isLoading: boolean; textContent?: string }; -export const LoadingSpinner = ({ - isLoading, - textContent = 'Loading...', -}: Props) => { +export const LoadingSpinner = ({ isLoading, textContent = 'Loading...' }: Props) => { const wasLoading = useRef(false); const completeMessage = 'Loading complete.'; diff --git a/materials_ui/src/components/NavList/NavList.scss b/materials_ui/src/components/NavList/NavList.scss index 43efca0a..5314afa5 100644 --- a/materials_ui/src/components/NavList/NavList.scss +++ b/materials_ui/src/components/NavList/NavList.scss @@ -14,4 +14,4 @@ .nav-list-section__heading:first-child { margin-top: 0; -} \ No newline at end of file +} diff --git a/materials_ui/src/components/NavList/NavList.tsx b/materials_ui/src/components/NavList/NavList.tsx index 2c48f30c..98ad076d 100644 --- a/materials_ui/src/components/NavList/NavList.tsx +++ b/materials_ui/src/components/NavList/NavList.tsx @@ -8,11 +8,7 @@ import './NavList.scss'; export type NavListItem = { href: string; name: string }; export type NavListSection = { headerLabel?: string; items: NavListItem[] }; -type Props = { - items?: NavListItem[]; - headerLabel?: string; - sections?: NavListSection[]; -}; +type Props = { items?: NavListItem[]; headerLabel?: string; sections?: NavListSection[] }; export const NavList = ({ items = [], headerLabel, sections }: Props) => { const { pathname } = useLocation(); @@ -23,10 +19,7 @@ export const NavList = ({ items = [], headerLabel, sections }: Props) => { } return ( -
); - } + }, ); diff --git a/materials_ui/src/components/SearchInput/SearchInput.tsx b/materials_ui/src/components/SearchInput/SearchInput.tsx index af8618d7..1ae79a1f 100644 --- a/materials_ui/src/components/SearchInput/SearchInput.tsx +++ b/materials_ui/src/components/SearchInput/SearchInput.tsx @@ -17,7 +17,7 @@ export const SearchInput = ({ onSearch, hideButton = true, label, - placeholder + placeholder, }: Props) => { const [searchTerm, setSearchTerm] = useState(''); diff --git a/materials_ui/src/components/SectionBreak/SectionBreak.scss b/materials_ui/src/components/SectionBreak/SectionBreak.scss index 47ef0c0c..8c64a4a2 100644 --- a/materials_ui/src/components/SectionBreak/SectionBreak.scss +++ b/materials_ui/src/components/SectionBreak/SectionBreak.scss @@ -13,5 +13,4 @@ margin-bottom: 30px; margin-top: 30px; } - -} \ No newline at end of file +} diff --git a/materials_ui/src/components/SelectList/SelectList.tsx b/materials_ui/src/components/SelectList/SelectList.tsx index eee2ae2c..73bfc7ef 100644 --- a/materials_ui/src/components/SelectList/SelectList.tsx +++ b/materials_ui/src/components/SelectList/SelectList.tsx @@ -22,26 +22,13 @@ type Props = { export const SelectList = forwardRef( ( - { - id, - defaultValue, - disabled = false, - label, - hint, - error, - options, - onChange, - required, - value - }, - ref + { id, defaultValue, disabled = false, label, hint, error, options, onChange, required, value }, + ref, ) => { const hasError = !!error; return ( -
+
@@ -73,17 +60,12 @@ export const SelectList = forwardRef( required={required} > {options.map(({ value, label, id, disabled = false }) => ( - ))}
); - } + }, ); diff --git a/materials_ui/src/components/SortableTable/CaseMaterialsTable.tsx b/materials_ui/src/components/SortableTable/CaseMaterialsTable.tsx index b8c7c993..ed049225 100644 --- a/materials_ui/src/components/SortableTable/CaseMaterialsTable.tsx +++ b/materials_ui/src/components/SortableTable/CaseMaterialsTable.tsx @@ -4,12 +4,7 @@ import { useSearchParams } from 'react-router-dom'; import { useCaseMaterials, useFilters, usePager } from '../../hooks'; import { CaseMaterialsType } from '../../schemas'; -import { - defaultFilterFn, - defaultSearchFn, - defaultSortFn, - getSortFn -} from '../../utils/filtering'; +import { defaultFilterFn, defaultSearchFn, defaultSortFn, getSortFn } from '../../utils/filtering'; import SortableTable, { Column } from './SortableTable'; import { DEFAULT_RESULTS_PER_PAGE } from '../../constants/query'; @@ -25,7 +20,7 @@ export const CaseMaterialsTable = () => { const { filteredData, loading: caseMaterialsLoading, - error + error, } = useCaseMaterials({ dataType: 'materials' }); const { filters } = useFilters('materials'); const { materialTags } = useMaterialTags(); @@ -42,7 +37,7 @@ export const CaseMaterialsTable = () => { {row.statusLabel && } ), - isSortable: true + isSortable: true, }, { key: 'type', @@ -51,71 +46,58 @@ export const CaseMaterialsTable = () => { sortFn: ({ type: leftType }, { type: rightType }, direction) => { const compareResult = leftType.localeCompare(rightType, undefined, { numeric: true, - sensitivity: 'base' + sensitivity: 'base', }); return direction === 'ascending' ? compareResult : -compareResult; - } + }, }, { key: 'category', heading: 'Category', isSortable: true }, { key: 'date', heading: 'Date', render: (row) => ( - + {formatDate(row.date)} ), - isSortable: true + isSortable: true, }, { key: 'status', heading: 'Status', render: (row) => , - isSortable: true - } + isSortable: true, + }, ], - [] + [], ); const filteredSortedData = useMemo(() => { const sortFn = getSortFn(columns, filters?.sort, (sortConfig) => - defaultSortFn(sortConfig) + defaultSortFn(sortConfig), ); const sortByStatusFn = defaultSortFn({ column: 'statusLabel', - direction: 'descending' + direction: 'descending', }); const filterFn = defaultFilterFn(filters?.filters); - const searchFn = defaultSearchFn( - 'subject', - filters?.search - ); + const searchFn = defaultSearchFn('subject', filters?.search); return filteredData ?.map((material) => { const materialTag = materialTags.find( - (materialTag) => materialTag.materialId === material.materialId + (materialTag) => materialTag.materialId === material.materialId, ); - return materialTag - ? { ...material, statusLabel: materialTag.tagName } - : material; + return materialTag ? { ...material, statusLabel: materialTag.tagName } : material; }) ?.filter(searchFn) ?.filter(filterFn) ?.sort((a, b) => { - if ( - a.readStatus === READ_STATUS.UNREAD && - b.readStatus !== READ_STATUS.UNREAD - ) { + if (a.readStatus === READ_STATUS.UNREAD && b.readStatus !== READ_STATUS.UNREAD) { return -1; } - if ( - a.readStatus !== READ_STATUS.READ && - b.readStatus === READ_STATUS.READ - ) { + if (a.readStatus !== READ_STATUS.READ && b.readStatus === READ_STATUS.READ) { return 1; } return 0; @@ -126,23 +108,14 @@ export const CaseMaterialsTable = () => { const currentPageParam = queryParams?.get('page'); - const { - currentPage, - totalPages, - startIndex, - endIndex, - setNextPage, - setPage, - setPreviousPage - } = usePager({ - totalItems: filteredSortedData?.length, - initialPageSize: DEFAULT_RESULTS_PER_PAGE, - initialPage: currentPageParam ? +currentPageParam - 1 : 0 - }); - - const expandableRow = (row: CaseMaterialsType) => ( - - ); + const { currentPage, totalPages, startIndex, endIndex, setNextPage, setPage, setPreviousPage } = + usePager({ + totalItems: filteredSortedData?.length, + initialPageSize: DEFAULT_RESULTS_PER_PAGE, + initialPage: currentPageParam ? +currentPageParam - 1 : 0, + }); + + const expandableRow = (row: CaseMaterialsType) => ; const recordsOnCurrentPage = endIndex + 1 - startIndex; @@ -152,17 +125,11 @@ export const CaseMaterialsTable = () => { return ( <> - + {!caseMaterialsLoading && ( <>

- Showing{' '} - - {filteredSortedData?.length === 0 ? 0 : recordsOnCurrentPage} - {' '} + Showing {filteredSortedData?.length === 0 ? 0 : recordsOnCurrentPage}{' '} materials out of {filteredSortedData?.length}

{ error={error} /> -
1 - ? 'table-actions-footer' - : 'table-actions-footer-end' - } - > +
1 ? 'table-actions-footer' : 'table-actions-footer-end'}> { const { filteredData, loading: caseMaterialsLoading, - error + error, } = useCaseMaterials({ dataType: 'communications' }); const { filters } = useFilters('communications'); @@ -38,37 +29,26 @@ export const CommunicationsTable = () => { const sortFn = defaultSortFn(filters?.sort); const sortByStatusFn = defaultSortFn({ column: 'statusLabel', - direction: 'descending' + direction: 'descending', }); const filterFn = defaultFilterFn(filters?.filters); - const searchFn = defaultSearchFn( - 'subject', - filters?.search - ); + const searchFn = defaultSearchFn('subject', filters?.search); return filteredData ?.map((material) => { const materialTag = materialTags.find( - (materialTag) => materialTag.materialId === material.materialId + (materialTag) => materialTag.materialId === material.materialId, ); - return materialTag - ? { ...material, statusLabel: materialTag.tagName } - : material; + return materialTag ? { ...material, statusLabel: materialTag.tagName } : material; }) ?.filter(searchFn) ?.filter(filterFn) ?.sort((a, b) => { - if ( - a.readStatus === READ_STATUS.UNREAD && - b.readStatus !== READ_STATUS.UNREAD - ) { + if (a.readStatus === READ_STATUS.UNREAD && b.readStatus !== READ_STATUS.UNREAD) { return -1; } - if ( - a.readStatus !== READ_STATUS.READ && - b.readStatus === READ_STATUS.READ - ) { + if (a.readStatus !== READ_STATUS.READ && b.readStatus === READ_STATUS.READ) { return 1; } return 0; @@ -79,19 +59,12 @@ export const CommunicationsTable = () => { const currentPageParam = queryParams?.get('page'); - const { - currentPage, - totalPages, - startIndex, - endIndex, - setNextPage, - setPage, - setPreviousPage - } = usePager({ - totalItems: filteredSortedData?.length, - initialPageSize: DEFAULT_RESULTS_PER_PAGE, - initialPage: currentPageParam ? +currentPageParam - 1 : 0 - }); + const { currentPage, totalPages, startIndex, endIndex, setNextPage, setPage, setPreviousPage } = + usePager({ + totalItems: filteredSortedData?.length, + initialPageSize: DEFAULT_RESULTS_PER_PAGE, + initialPage: currentPageParam ? +currentPageParam - 1 : 0, + }); const columns: Column[] = [ { @@ -104,7 +77,7 @@ export const CommunicationsTable = () => { {row.statusLabel && } ), - isSortable: true + isSortable: true, }, { key: 'direction', heading: 'In/Out', isSortable: true }, { key: 'party', heading: 'Comms with', isSortable: true }, @@ -118,13 +91,11 @@ export const CommunicationsTable = () => { {formatDate(row.date)} ), - isSortable: true - } + isSortable: true, + }, ]; - const expandableRow = (row: CaseMaterialsType) => ( - - ); + const expandableRow = (row: CaseMaterialsType) => ; const recordsOnCurrentPage = endIndex + 1 - startIndex; @@ -134,44 +105,34 @@ export const CommunicationsTable = () => { return ( <> - + {!caseMaterialsLoading && ( - <> -

- Showing{' '} - - {filteredSortedData?.length === 0 ? 0 : recordsOnCurrentPage} - {' '} - {filteredSortedData?.length === 1 ? `communication` : `communications`}{' '} - out of {filteredSortedData?.length} -

- -
1 ? 'table-actions-footer' : 'table-actions-footer-end' - } - > - -
- + <> +

+ Showing {filteredSortedData?.length === 0 ? 0 : recordsOnCurrentPage}{' '} + {filteredSortedData?.length === 1 ? `communication` : `communications`} out of{' '} + {filteredSortedData?.length} +

+ +
1 ? 'table-actions-footer' : 'table-actions-footer-end'}> + +
+ )} ); diff --git a/materials_ui/src/components/SortableTable/SortableTable.tsx b/materials_ui/src/components/SortableTable/SortableTable.tsx index 46704162..d4d6f5ae 100644 --- a/materials_ui/src/components/SortableTable/SortableTable.tsx +++ b/materials_ui/src/components/SortableTable/SortableTable.tsx @@ -36,24 +36,23 @@ const SortableTable = ({ dataName, checkboxes = true, error, - isCommunications = false + isCommunications = false, }: SortableTableProps) => { const { items: selectedItems, addItems: addSelectedItems, removeItems: removeSelectedItems, - clear: clearSelectedItems + clear: clearSelectedItems, } = useSelectedItemsStore(); const { isPending: isAutoReclassifyPending } = useAutoReclassify(); const { setSort } = useFilters(dataName); - const { selectedMaterialId, selectMaterial, deselectMaterial } = - useCaseMaterial(); + const { selectedMaterialId, selectMaterial, deselectMaterial } = useCaseMaterial(); const materialType = isCommunications ? 'communications' : 'materials'; const handleSelectItem = (material: CaseMaterialsType) => { const isSelected = selectedItems[materialType]?.some( - (m) => m.materialId === material.materialId + (m) => m.materialId === material.materialId, ); if (isSelected) { @@ -86,145 +85,131 @@ const SortableTable = ({ textContent={`Reclassifying ${dataName}...`} /> {!isAutoReclassifyPending && ( -
- - - - - {checkboxes && ( - - )} - {columns.length && - columns.map(({ key, heading, isSortable }) => { - const isSortedColumn = - filters?.sort?.column === key && !!filters?.sort?.direction; - const ariaSortValue = isSortable - ? isSortedColumn && filters?.sort?.direction - ? filters.sort.direction - : 'none' - : undefined; +
+
{caption}
- 0 - } - /> -
+ + + + {checkboxes && ( + + )} + {columns.length && + columns.map(({ key, heading, isSortable }) => { + const isSortedColumn = + filters?.sort?.column === key && !!filters?.sort?.direction; + const ariaSortValue = isSortable + ? isSortedColumn && filters?.sort?.direction + ? filters.sort.direction + : 'none' + : undefined; - return ( - - ); - })} - - - + {isSortable ? ( + + ) : ( + heading + )} + + ); + })} + + + - - {data.length > 0 ? ( - data.map((row, index) => { - const isCurrentMaterial = - selectedMaterialId !== null && - +selectedMaterialId === row.materialId; + + {data.length > 0 ? ( + data.map((row, index) => { + const isCurrentMaterial = + selectedMaterialId !== null && +selectedMaterialId === row.materialId; - return ( - - - {checkboxes && ( - - )} - {columns.map((col, colIndex) => ( - - ))} - - + return ( + + + {checkboxes && ( + + )} + {columns.map((col, colIndex) => ( + + ))} + + - {expandableRow && isCurrentMaterial && ( - - - - )} - - ); - }) - ) : error ? ( - - - - ) : ( - - - - )} - -
{caption}
+ 0 + } + /> + - {isSortable ? ( - - {heading} - - ) : ( - heading - )} -
- m.id === row.id - )} - onChange={() => handleSelectItem(row)} - labelVisuallyHidden={true} - /> - - {/* @ts-expect-error generic type mismatch with CaseMaterialsType */} - {col.render ? col.render(row) : row[col.key]} - - - handleActionsClick( - isCurrentMaterial ? null : row.materialId - ) - } - /> -
+ m.id === row.id)} + onChange={() => handleSelectItem(row)} + labelVisuallyHidden={true} + /> + + {/* @ts-expect-error generic type mismatch with CaseMaterialsType */} + {col.render ? col.render(row) : row[col.key]} + + + handleActionsClick(isCurrentMaterial ? null : row.materialId) + } + /> +
- {expandableRow(row as any)} -
-

- Unable to fetch {dataName} for this case -

-
-

- There are no {dataName} that match your selection for this - case -

-
-
+ {expandableRow && isCurrentMaterial && ( + + + {expandableRow(row as any)} + + + )} + + ); + }) + ) : error ? ( + + +

+ Unable to fetch {dataName} for this case +

+ + + ) : ( + + +

+ There are no {dataName} that match your selection for this case +

+ + + )} + + +
)} ); diff --git a/materials_ui/src/components/SortableTable/TableActions.tsx b/materials_ui/src/components/SortableTable/TableActions.tsx index eb18c8d1..d3202b0f 100644 --- a/materials_ui/src/components/SortableTable/TableActions.tsx +++ b/materials_ui/src/components/SortableTable/TableActions.tsx @@ -17,7 +17,7 @@ export function TableActions({ showFilter, onSetShowFilter, menuItems = [], - selectedItems + selectedItems, }: Props) { const { caseInfo } = useCaseInfoStore(); const [isSticky, setIsSticky] = useState(false); @@ -29,7 +29,7 @@ export function TableActions({ ([entry]) => { if (entry) setIsSticky(!entry.isIntersecting); }, - { threshold: 0 } + { threshold: 0 }, ); if (ref.current) { @@ -44,9 +44,7 @@ export function TableActions({ return ( <>
-
+
{!isSticky && (
@@ -58,7 +56,7 @@ export function TableActions({ onSetShowFilter(!showFilter); log({ logLevel: 1, - message: `HK-UI-FE: caseId [${caseInfo?.id}] - filter panel is now ${filterStatus}.` + message: `HK-UI-FE: caseId [${caseInfo?.id}] - filter panel is now ${filterStatus}.`, }); }} > diff --git a/materials_ui/src/components/SummaryCard/SummaryCard.tsx b/materials_ui/src/components/SummaryCard/SummaryCard.tsx index 08746bba..e3c7be7f 100644 --- a/materials_ui/src/components/SummaryCard/SummaryCard.tsx +++ b/materials_ui/src/components/SummaryCard/SummaryCard.tsx @@ -1,18 +1,8 @@ export type ContentItem = { key: string; value: unknown }; -type Props = { - title: string; - content: ContentItem[]; - actionName?: string; - action?: () => void; -}; +type Props = { title: string; content: ContentItem[]; actionName?: string; action?: () => void }; -export const SummaryCard = ({ - title, - content, - actionName = 'Change', - action -}: Props) => { +export const SummaryCard = ({ title, content, actionName = 'Change', action }: Props) => { return (
diff --git a/materials_ui/src/components/TextArea/TextArea.tsx b/materials_ui/src/components/TextArea/TextArea.tsx index 2cbf31a2..d00b9e38 100644 --- a/materials_ui/src/components/TextArea/TextArea.tsx +++ b/materials_ui/src/components/TextArea/TextArea.tsx @@ -25,9 +25,9 @@ export const TextArea = forwardRef( onChange, required, rows = 5, - maxCharacters = 0 + maxCharacters = 0, }, - ref + ref, ) => { const [text, setText] = useState(''); const hasError = !!error; @@ -38,9 +38,7 @@ export const TextArea = forwardRef( }; return ( -
+
@@ -74,14 +72,11 @@ export const TextArea = forwardRef( /> {!!maxCharacters && ( -
+
You can enter up to {maxCharacters - text.length} characters
)}
); - } + }, ); diff --git a/materials_ui/src/components/TextInput/TextInput.tsx b/materials_ui/src/components/TextInput/TextInput.tsx index e928e8d2..fba692cb 100644 --- a/materials_ui/src/components/TextInput/TextInput.tsx +++ b/materials_ui/src/components/TextInput/TextInput.tsx @@ -35,16 +35,14 @@ export const TextInput = forwardRef( type = 'text', autocomplete, spellCheck, - readonly = false + readonly = false, }, - ref + ref, ) => { const hasError = !!error; return ( -
+
@@ -82,5 +80,5 @@ export const TextInput = forwardRef( />
); - } + }, ); diff --git a/materials_ui/src/components/forms/EditMaterial/EditExhibit.tsx b/materials_ui/src/components/forms/EditMaterial/EditExhibit.tsx index 362fffd1..bde49177 100644 --- a/materials_ui/src/components/forms/EditMaterial/EditExhibit.tsx +++ b/materials_ui/src/components/forms/EditMaterial/EditExhibit.tsx @@ -3,10 +3,7 @@ import { Controller, useForm } from 'react-hook-form'; import { Link } from 'react-router-dom'; import { useExhibitProducers } from '../../../hooks/index.ts'; -import { - EditExhibitSchema, - EditExhibitType -} from '../../../schemas/forms/editStatement.ts'; +import { EditExhibitSchema, EditExhibitType } from '../../../schemas/forms/editStatement.ts'; import { CaseMaterialsType } from '../../../schemas/index.ts'; import { SelectList } from '../../SelectList/SelectList.tsx'; @@ -21,22 +18,15 @@ type Props = { onSuccess: (data: EditExhibitType) => void; }; -export const EditExhibitForm = ({ - cancelUrl, - formState, - material, - onSuccess -}: Props) => { - const { - selectOptions: exhibitProducers, - loading: isExhibitProducersLoading - } = useExhibitProducers(); +export const EditExhibitForm = ({ cancelUrl, formState, material, onSuccess }: Props) => { + const { selectOptions: exhibitProducers, loading: isExhibitProducersLoading } = + useExhibitProducers(); const { control, handleSubmit, formState: { errors }, - watch + watch, } = useForm({ // @ts-expect-error fix type resolver: zodResolver(EditExhibitSchema), @@ -48,14 +38,11 @@ export const EditExhibitForm = ({ subject: formState?.item || material?.subject || '', used: formState?.used || material?.status === 'Used', existingproducerOrWitnessId: - formState?.existingproducerOrWitnessId || - material?.existingproducerOrWitnessId, + formState?.existingproducerOrWitnessId || material?.existingproducerOrWitnessId, producedBy: formState?.producedBy || - (!material?.existingproducerOrWitnessId - ? material?.producer?.trim() - : undefined) - } + (!material?.existingproducerOrWitnessId ? material?.producer?.trim() : undefined), + }, }); const fieldValues = watch(); @@ -126,10 +113,8 @@ export const EditExhibitForm = ({ options={[ ...(isExhibitProducersLoading ? [{ label: 'Loading...', value: '', id: '' }] - : [ - { label: 'Select producer or witness', value: '', id: '' } - ]), - ...exhibitProducers + : [{ label: 'Select producer or witness', value: '', id: '' }]), + ...exhibitProducers, ]} /> )} @@ -154,11 +139,7 @@ export const EditExhibitForm = ({
- diff --git a/materials_ui/src/components/forms/EditMaterial/EditStatement.tsx b/materials_ui/src/components/forms/EditMaterial/EditStatement.tsx index 172b75dc..f5a0df57 100644 --- a/materials_ui/src/components/forms/EditMaterial/EditStatement.tsx +++ b/materials_ui/src/components/forms/EditMaterial/EditStatement.tsx @@ -3,14 +3,8 @@ import { useEffect } from 'react'; import { Controller, useForm } from 'react-hook-form'; import { Link } from 'react-router-dom'; -import { - useCaseWitnesses, - useWitnessStatements -} from '../../../hooks/index.ts'; -import { - EditStatementSchema, - EditStatementType -} from '../../../schemas/forms/editStatement.ts'; +import { useCaseWitnesses, useWitnessStatements } from '../../../hooks/index.ts'; +import { EditStatementSchema, EditStatementType } from '../../../schemas/forms/editStatement.ts'; import { CaseMaterialsType } from '../../../schemas/index.ts'; import { SelectList } from '../../SelectList/SelectList.tsx'; @@ -26,21 +20,16 @@ type Props = { cancelUrl: string; }; -export const EditStatementForm = ({ - formState, - material, - onSuccess, - cancelUrl -}: Props) => { +export const EditStatementForm = ({ formState, material, onSuccess, cancelUrl }: Props) => { const { selectOptions, loading: isWitnessesLoading } = useCaseWitnesses(); const { data: witnessStatements, loading: isWitnessStatementsLoading, - setWitnessId + setWitnessId, } = useWitnessStatements(); const matchedStatement = witnessStatements.find( - (statement) => statement.id === material.materialId + (statement) => statement.id === material.materialId, ); const defaultStatementNumber = matchedStatement @@ -51,21 +40,18 @@ export const EditStatementForm = ({ control, handleSubmit, formState: { errors }, - watch + watch, } = useForm({ // @ts-expect-error fix type here resolver: zodResolver(EditStatementSchema), defaultValues: { - hasStatementDate: formState - ? formState?.hasStatementDate - : !!material?.recordedDate, + hasStatementDate: formState ? formState?.hasStatementDate : !!material?.recordedDate, materialId: material?.materialId, - statementDate: - formState?.statementDate || material?.recordedDate || undefined, + statementDate: formState?.statementDate || material?.recordedDate || undefined, statementNumber: formState?.statementNumber || undefined, used: formState ? formState.used : material?.status === 'Used', - witnessId: formState?.witnessId || material?.witnessId || undefined - } + witnessId: formState?.witnessId || material?.witnessId || undefined, + }, }); const fieldValues = watch(); @@ -122,12 +108,8 @@ export const EditStatementForm = ({ label="Who is the witness?" error={errors?.witnessId?.message as string} options={[ - { - label: isWitnessesLoading ? 'Loading...' : 'Select witness', - value: '', - id: '' - }, - ...selectOptions + { label: isWitnessesLoading ? 'Loading...' : 'Select witness', value: '', id: '' }, + ...selectOptions, ]} /> )} @@ -139,18 +121,12 @@ export const EditStatementForm = ({ render={({ field }) => (
- diff --git a/materials_ui/src/components/forms/EditMaterial/Summary.tsx b/materials_ui/src/components/forms/EditMaterial/Summary.tsx index e004e10b..416f1138 100644 --- a/materials_ui/src/components/forms/EditMaterial/Summary.tsx +++ b/materials_ui/src/components/forms/EditMaterial/Summary.tsx @@ -1,6 +1,6 @@ -import { type ContentItem, SummaryCard } from '../../SummaryCard/SummaryCard.tsx'; import { Link } from 'react-router-dom'; import { URL } from '../../../constants/url.ts'; +import { type ContentItem, SummaryCard } from '../../SummaryCard/SummaryCard.tsx'; type Props = { onChange: () => void; @@ -9,12 +9,7 @@ type Props = { title: string; }; -export const Summary = ({ - onChange, - onSave, - summaryCardData, - title -}: Props) => { +export const Summary = ({ onChange, onSave, summaryCardData, title }: Props) => { const handleChangeClick = () => { onChange(); }; @@ -27,18 +22,10 @@ export const Summary = ({ <>

Check your answers

- +
- diff --git a/materials_ui/src/components/forms/Reclassify/AddWitness.tsx b/materials_ui/src/components/forms/Reclassify/AddWitness.tsx index 5bbe563e..8f7aa2c9 100644 --- a/materials_ui/src/components/forms/Reclassify/AddWitness.tsx +++ b/materials_ui/src/components/forms/Reclassify/AddWitness.tsx @@ -3,15 +3,15 @@ import dayjs from 'dayjs'; import { Controller, useForm } from 'react-hook-form'; import { Link } from 'react-router-dom'; -import { ErrorSummary, Radios, SelectList, TextArea, TextInput } from '../../index.ts'; import { URL } from '../../../constants/url.ts'; import { useCaseDefendants } from '../../../hooks/index.ts'; import { Reclassify_WitnessAndActionPlanSchema, - type Reclassify_WitnessAndActionPlanType + type Reclassify_WitnessAndActionPlanType, } from '../../../schemas/forms/reclassify.ts'; import { formatDateInputValue } from '../../../utils/date.ts'; import type { ErrorSummaryItem } from '../../ErrorSummary/ErrorSummary.tsx'; +import { ErrorSummary, Radios, SelectList, TextArea, TextInput } from '../../index.ts'; type Props = { data: Reclassify_WitnessAndActionPlanType; @@ -24,11 +24,11 @@ export const AddWitness = ({ data, onSave }: Props) => { control, formState: { errors }, handleSubmit, - watch + watch, } = useForm({ defaultValues: data, // @ts-expect-error fix type - resolver: zodResolver(Reclassify_WitnessAndActionPlanSchema) + resolver: zodResolver(Reclassify_WitnessAndActionPlanSchema), }); // format react-hook-form error object into array to be rendered by ErrorSummary @@ -104,7 +104,7 @@ export const AddWitness = ({ data, onSave }: Props) => { legend="What do you want to request?" options={[ { id: 'KWD', value: 'KWD', label: 'Key witness details' }, - { id: 'NKWD', value: 'NKWD', label: 'Non-key witness details' } + { id: 'NKWD', value: 'NKWD', label: 'Non-key witness details' }, ]} required error={errors?.requestType?.message as string} @@ -128,7 +128,7 @@ export const AddWitness = ({ data, onSave }: Props) => { ...defendantSelectOptions, ...(defendantSelectOptions?.length > 1 ? [{ label: 'All defendants', value: 0, id: 0 }] - : []) + : []), ]} /> )} @@ -174,18 +174,12 @@ export const AddWitness = ({ data, onSave }: Props) => { render={({ field }) => ( { )}
- diff --git a/materials_ui/src/components/forms/Reclassify/Exhibit.tsx b/materials_ui/src/components/forms/Reclassify/Exhibit.tsx index 5df8db94..3533ae05 100644 --- a/materials_ui/src/components/forms/Reclassify/Exhibit.tsx +++ b/materials_ui/src/components/forms/Reclassify/Exhibit.tsx @@ -15,10 +15,8 @@ type Props = { }; export const Exhibit = ({ control, data, errors, currentMaterial }: Props) => { - const { - selectOptions: exhibitProducerOptions, - loading: isExhibitProducersLoading - } = useExhibitProducers(); + const { selectOptions: exhibitProducerOptions, loading: isExhibitProducersLoading } = + useExhibitProducers(); return ( <> @@ -43,11 +41,7 @@ export const Exhibit = ({ control, data, errors, currentMaterial }: Props) => { )} /> - + { ...(isExhibitProducersLoading ? [{ label: 'Loading...', value: '', id: '' }] : [{ label: 'Select producer or witness', value: '', id: '' }]), - ...exhibitProducerOptions + ...exhibitProducerOptions, ]} /> )} diff --git a/materials_ui/src/components/forms/Reclassify/MGForms.tsx b/materials_ui/src/components/forms/Reclassify/MGForms.tsx index 24a4d713..a2632efe 100644 --- a/materials_ui/src/components/forms/Reclassify/MGForms.tsx +++ b/materials_ui/src/components/forms/Reclassify/MGForms.tsx @@ -5,11 +5,7 @@ import { DocumentTypeField } from './common/DocumentTypeField'; import { SubjectField } from './common/SubjectField'; import { UsedField } from './common/UsedField'; -type Props = { - control: Control; - errors?: FieldErrors; - currentMaterial: CaseMaterialsType; -}; +type Props = { control: Control; errors?: FieldErrors; currentMaterial: CaseMaterialsType }; export const MGForms = ({ control, errors, currentMaterial }: Props) => { return ( diff --git a/materials_ui/src/components/forms/Reclassify/MaterialName.tsx b/materials_ui/src/components/forms/Reclassify/MaterialName.tsx index ec679bfc..16a3c8ef 100644 --- a/materials_ui/src/components/forms/Reclassify/MaterialName.tsx +++ b/materials_ui/src/components/forms/Reclassify/MaterialName.tsx @@ -6,24 +6,21 @@ import { ErrorSummary } from '../..'; import { URL } from '../../../constants/url'; import { Reclassify_MaterialNameFormSchema, - Reclassify_MaterialNameFormType + Reclassify_MaterialNameFormType, } from '../../../schemas/forms/reclassify'; import type { ErrorSummaryItem } from '../../ErrorSummary/ErrorSummary'; import { SubjectField } from './common/SubjectField'; -type Props = { - data: Record; - onSave: (data: Record) => void; -}; +type Props = { data: Record; onSave: (data: Record) => void }; export const MaterialName = ({ data, onSave }: Props) => { const { control, formState: { errors }, - handleSubmit + handleSubmit, } = useForm({ defaultValues: data, - resolver: zodResolver(Reclassify_MaterialNameFormSchema) + resolver: zodResolver(Reclassify_MaterialNameFormSchema), }); // format react-hook-form error object into array to be rendered by ErrorSummary @@ -52,11 +49,7 @@ export const MaterialName = ({ data, onSave }: Props) => {
- diff --git a/materials_ui/src/components/forms/Reclassify/Other.tsx b/materials_ui/src/components/forms/Reclassify/Other.tsx index ecf3bd28..6cbc9cc6 100644 --- a/materials_ui/src/components/forms/Reclassify/Other.tsx +++ b/materials_ui/src/components/forms/Reclassify/Other.tsx @@ -5,11 +5,7 @@ import { DocumentTypeField } from './common/DocumentTypeField'; import { SubjectField } from './common/SubjectField'; import { UsedField } from './common/UsedField'; -type Props = { - control: Control; - errors?: FieldErrors; - currentMaterial: CaseMaterialsType; -}; +type Props = { control: Control; errors?: FieldErrors; currentMaterial: CaseMaterialsType }; export const Other = ({ control, errors, currentMaterial }: Props) => { return ( diff --git a/materials_ui/src/components/forms/Reclassify/Statement.tsx b/materials_ui/src/components/forms/Reclassify/Statement.tsx index a382b0eb..ed1aa851 100644 --- a/materials_ui/src/components/forms/Reclassify/Statement.tsx +++ b/materials_ui/src/components/forms/Reclassify/Statement.tsx @@ -5,15 +5,10 @@ import type { ReclassifyFormData } from '../../../hooks'; import { useCaseWitnesses, useWitnessStatements } from '../../../hooks'; import { UsedField } from './common/UsedField'; -type Props = { - control: Control; - errors?: FieldErrors; - data?: ReclassifyFormData; -}; +type Props = { control: Control; errors?: FieldErrors; data?: ReclassifyFormData }; export const Statement = ({ control, data, errors }: Props) => { - const { selectOptions: witnessOptions, loading: isWitnessesLoading } = - useCaseWitnesses(); + const { selectOptions: witnessOptions, loading: isWitnessesLoading } = useCaseWitnesses(); const { data: witnessStatements, setWitnessId } = useWitnessStatements(); if (data?.classification !== 'STATEMENT') { @@ -65,20 +60,14 @@ export const Statement = ({ control, data, errors }: Props) => { ? [{ label: 'Loading...', value: '', id: '' }] : [{ label: 'Select witness', value: '', id: '' }]), ...witnessOptions, - { - label: 'Witness not on the list - add witness', - value: '0', - id: '0' - } + { label: 'Witness not on the list - add witness', value: '0', id: '0' }, ]} /> )} /> {data?.witnessId === 0 && (

- - You will be asked to add a new witness on the next page. - + You will be asked to add a new witness on the next page.

)} @@ -88,18 +77,12 @@ export const Statement = ({ control, data, errors }: Props) => { render={({ field }) => ( { const documentType = getDocumentTypeById(data?.documentType as number); const usedStatus = data?.used ? 'Used' : 'Unused'; const classification = mapBEClassificationToFE( - data?.classification as Reclassify_ClassificationForm['classification'] + data?.classification as Reclassify_ClassificationForm['classification'], ); const witnessName = data?.classification === 'STATEMENT' @@ -53,15 +53,11 @@ export const Summary = ({ data, onChange, onSave }: Props) => { data?.classification === 'STATEMENT' ? data?.witnessActionPlan?.defendantId === 0 ? 'All defendants' - : formatDefendantName( - getDefendantById(data?.witnessActionPlan?.defendantId as number) - ) + : formatDefendantName(getDefendantById(data?.witnessActionPlan?.defendantId as number)) : null; const exhibitProducer = - data?.classification === 'EXHIBIT' - ? getExhibitProducerById(data?.producerId) - : false; + data?.classification === 'EXHIBIT' ? getExhibitProducerById(data?.producerId) : false; return ( <> @@ -77,8 +73,8 @@ export const Summary = ({ data, onChange, onSave }: Props) => {
{documentType?.name} - ) - } + ), + }, ]} /> @@ -88,29 +84,21 @@ export const Summary = ({ data, onChange, onSave }: Props) => { action={() => handleChangeClick('classification')} title={`${documentType?.name} details`} content={[ - { - key: 'Who is the Witness', - value: witnessName || 'New witness (see below)' - }, + { key: 'Who is the Witness', value: witnessName || 'New witness (see below)' }, { key: 'Does the statement have a date?', - value: data?.hasStatementDate ? 'Yes' : 'No' + value: data?.hasStatementDate ? 'Yes' : 'No', }, ...(data?.hasStatementDate ? [ { key: 'What is the statement date?', - value: data?.statementDate - ? formatDate(data?.statementDate) - : '' - } + value: data?.statementDate ? formatDate(data?.statementDate) : '', + }, ] : []), - { - key: 'Statement number', - value: data?.statementNumber as number - }, - { key: 'What is the material status?', value: usedStatus } + { key: 'Statement number', value: data?.statementNumber as number }, + { key: 'What is the material status?', value: usedStatus }, ]} /> @@ -121,41 +109,29 @@ export const Summary = ({ data, onChange, onSave }: Props) => { content={[ { key: 'Name', value: data?.witnessActionPlan?.firstName }, { key: 'Surname', value: data?.witnessActionPlan?.surname }, - { - key: 'Contested issue', - value: data?.witnessActionPlan?.actionPointText - }, + { key: 'Contested issue', value: data?.witnessActionPlan?.actionPointText }, { key: 'What do you want to request', value: data?.witnessActionPlan?.requestType === 'KWD' ? 'Key witness details' - : 'Non-key witness details' - }, - { - key: 'Select the defendant the action plan relates to', - value: defendantName - }, - { - key: 'Describe the action plan', - value: data?.witnessActionPlan?.actionPlan - }, - { - key: 'Date needed', - value: formatDate(data?.witnessActionPlan?.dateNeeded) + : 'Non-key witness details', }, + { key: 'Select the defendant the action plan relates to', value: defendantName }, + { key: 'Describe the action plan', value: data?.witnessActionPlan?.actionPlan }, + { key: 'Date needed', value: formatDate(data?.witnessActionPlan?.dateNeeded) }, { key: 'Do you want to add a follow up?', - value: data?.witnessActionPlan?.followUp ? 'Yes' : 'No' + value: data?.witnessActionPlan?.followUp ? 'Yes' : 'No', }, ...(data?.witnessActionPlan?.followUp ? [ { key: 'Follow up date', - value: formatDate(data?.witnessActionPlan?.followUpDate) - } + value: formatDate(data?.witnessActionPlan?.followUpDate), + }, ] - : []) + : []), ]} /> )} @@ -177,13 +153,11 @@ export const Summary = ({ data, onChange, onSave }: Props) => { ? [ { key: 'Exhibit producer', - value: exhibitProducer - ? exhibitProducer?.producer - : data?.producedBy - } + value: exhibitProducer ? exhibitProducer?.producer : data?.producedBy, + }, ] : []), - { key: 'What is the material status?', value: usedStatus } + { key: 'What is the material status?', value: usedStatus }, ]} /> @@ -192,24 +166,18 @@ export const Summary = ({ data, onChange, onSave }: Props) => { {['MG Form', 'OTHER'].includes(data.classification as string) && ( - handleChangeClick( - data.classification === 'STATEMENT' ? 'subject' : 'classification' - ) + handleChangeClick(data.classification === 'STATEMENT' ? 'subject' : 'classification') } title={`${documentType?.name} details`} content={[ { key: 'Material name', value: data?.subject }, - { key: 'What is the material status?', value: usedStatus } + { key: 'What is the material status?', value: usedStatus }, ]} /> )}
- diff --git a/materials_ui/src/components/forms/Reclassify/common/DocumentTypeField.tsx b/materials_ui/src/components/forms/Reclassify/common/DocumentTypeField.tsx index a0681486..0a0e0cc6 100644 --- a/materials_ui/src/components/forms/Reclassify/common/DocumentTypeField.tsx +++ b/materials_ui/src/components/forms/Reclassify/common/DocumentTypeField.tsx @@ -12,21 +12,16 @@ type Props = { excludedTypeIds: (string | number)[]; }; -export const DocumentTypeField = ({ - control, - errors, - type, - excludedTypeIds = [] -}: Props) => { +export const DocumentTypeField = ({ control, errors, type, excludedTypeIds = [] }: Props) => { const { selectOptions } = useDocumentTypes(); const filteredOptions = useMemo( () => selectOptions(type).map((option) => ({ ...option, - disabled: excludedTypeIds?.includes(option?.id) + disabled: excludedTypeIds?.includes(option?.id), })), - [excludedTypeIds, selectOptions, type] + [excludedTypeIds, selectOptions, type], ); return ( @@ -40,10 +35,7 @@ export const DocumentTypeField = ({ label="What is the material classification type?" error={errors?.documentType?.message as string} defaultValue={field?.value?.toString()} - options={[ - { label: 'Select type', value: '', id: '' }, - ...filteredOptions - ]} + options={[{ label: 'Select type', value: '', id: '' }, ...filteredOptions]} onChange={(value) => { field.onChange(value || undefined); }} diff --git a/materials_ui/src/components/forms/Reclassify/common/SubjectField.tsx b/materials_ui/src/components/forms/Reclassify/common/SubjectField.tsx index e88f5ed0..acb8b9a2 100644 --- a/materials_ui/src/components/forms/Reclassify/common/SubjectField.tsx +++ b/materials_ui/src/components/forms/Reclassify/common/SubjectField.tsx @@ -1,10 +1,4 @@ -import { - Control, - Controller, - FieldErrors, - FieldValues, - Path -} from 'react-hook-form'; +import { Control, Controller, FieldErrors, FieldValues, Path } from 'react-hook-form'; import { TextInput } from '../../..'; type Props = { @@ -18,7 +12,7 @@ export const SubjectField = ({ control, defaultValue, errors, - label + label, }: Props) => { return ( { render={({ field }) => ( , errors: FieldErrors, - caseMaterial: CaseMaterialsType + caseMaterial: CaseMaterialsType, ): RadioOption[] => [ { label: 'Statement (MG11)', @@ -18,49 +18,32 @@ export const categoryOptions = ( // prevent user trying to reclassify a statement to a statement disabled: caseMaterial.category === 'Statement', conditionalField: ( - - ) + + ), }, { label: 'Exhibit', value: 'EXHIBIT', id: 'exhibit', conditionalField: ( - - ) + + ), }, { label: 'MG Forms', value: 'MG Form', id: 'mgForm', - conditionalField: ( - - ) + conditionalField: , }, { label: 'Other', value: 'OTHER', id: 'other', - conditionalField: ( - - ) - } + conditionalField: , + }, ]; export const usedOptions: RadioOption[] = [ { label: 'Used', value: 'true', id: 'used' }, - { label: 'Unused', value: 'false', id: 'unused' } + { label: 'Unused', value: 'false', id: 'unused' }, ]; diff --git a/materials_ui/src/components/forms/Reclassify/constants/string.ts b/materials_ui/src/components/forms/Reclassify/constants/string.ts index fbb37008..469b9dc2 100644 --- a/materials_ui/src/components/forms/Reclassify/constants/string.ts +++ b/materials_ui/src/components/forms/Reclassify/constants/string.ts @@ -3,15 +3,10 @@ import { Reclassify_ClassificationForm } from '../../../../schemas/forms/reclass const BE_TO_FE_CLASSIFICATIONS_MAP: Record< Reclassify_ClassificationForm['classification'], string -> = { - STATEMENT: 'Statement', - EXHIBIT: 'Exhibit', - 'MG Form': 'MG Forms', - OTHER: 'Other' -}; +> = { STATEMENT: 'Statement', EXHIBIT: 'Exhibit', 'MG Form': 'MG Forms', OTHER: 'Other' }; export const mapBEClassificationToFE = ( - classification: Reclassify_ClassificationForm['classification'] + classification: Reclassify_ClassificationForm['classification'], ) => { return BE_TO_FE_CLASSIFICATIONS_MAP[classification]; }; diff --git a/materials_ui/src/components/forms/Reclassify/mappers/mapReclassifyExhibit.ts b/materials_ui/src/components/forms/Reclassify/mappers/mapReclassifyExhibit.ts index aebb9c8c..6282cb2b 100644 --- a/materials_ui/src/components/forms/Reclassify/mappers/mapReclassifyExhibit.ts +++ b/materials_ui/src/components/forms/Reclassify/mappers/mapReclassifyExhibit.ts @@ -3,7 +3,7 @@ import type { Reclassify_Orchestrated_Request_Type } from '../../../../schemas/f export const mapReclassifyExhibit = ( data: ReclassifyFormData, - urn: string + urn: string, ): Reclassify_Orchestrated_Request_Type => { if (data.classification !== 'EXHIBIT') { throw new Error('Not a valid classification'); @@ -19,13 +19,9 @@ export const mapReclassifyExhibit = ( exhibit: { item: data?.item, reference: data?.referenceNumber, - ...(data?.producerId - ? { existingproducerOrWitnessId: data?.producerId as number } - : {}), - ...(data?.producedBy - ? { Producer: data?.producedBy, newProducer: data?.producedBy } - : {}) - } - } + ...(data?.producerId ? { existingproducerOrWitnessId: data?.producerId as number } : {}), + ...(data?.producedBy ? { Producer: data?.producedBy, newProducer: data?.producedBy } : {}), + }, + }, }; }; diff --git a/materials_ui/src/components/forms/Reclassify/mappers/mapReclassifyMGForm.ts b/materials_ui/src/components/forms/Reclassify/mappers/mapReclassifyMGForm.ts index ffc87fbb..8b802178 100644 --- a/materials_ui/src/components/forms/Reclassify/mappers/mapReclassifyMGForm.ts +++ b/materials_ui/src/components/forms/Reclassify/mappers/mapReclassifyMGForm.ts @@ -3,7 +3,7 @@ import type { Reclassify_Orchestrated_Request_Type } from '../../../../schemas/f export const mapReclassifyMGForm = ( data: ReclassifyFormData, - urn: string + urn: string, ): Reclassify_Orchestrated_Request_Type => { if (data.classification !== 'MG Form') { throw new Error('Not a valid classification'); @@ -15,7 +15,7 @@ export const mapReclassifyMGForm = ( classification: 'OTHER', documentTypeId: data?.documentType, subject: data?.subject, - used: data?.used - } + used: data?.used, + }, }; }; diff --git a/materials_ui/src/components/forms/Reclassify/mappers/mapReclassifyOther.ts b/materials_ui/src/components/forms/Reclassify/mappers/mapReclassifyOther.ts index 99510ed9..35d40b64 100644 --- a/materials_ui/src/components/forms/Reclassify/mappers/mapReclassifyOther.ts +++ b/materials_ui/src/components/forms/Reclassify/mappers/mapReclassifyOther.ts @@ -3,7 +3,7 @@ import type { Reclassify_Orchestrated_Request_Type } from '../../../../schemas/f export const mapReclassifyOther = ( data: ReclassifyFormData, - urn: string + urn: string, ): Reclassify_Orchestrated_Request_Type => { if (data.classification !== 'OTHER') { throw new Error('Not a valid classification'); @@ -15,7 +15,7 @@ export const mapReclassifyOther = ( classification: 'OTHER', documentTypeId: data?.documentType, subject: data?.subject, - used: data?.used - } + used: data?.used, + }, }; }; diff --git a/materials_ui/src/components/forms/Reclassify/mappers/mapReclassifyStatement.ts b/materials_ui/src/components/forms/Reclassify/mappers/mapReclassifyStatement.ts index b195ef89..a716b261 100644 --- a/materials_ui/src/components/forms/Reclassify/mappers/mapReclassifyStatement.ts +++ b/materials_ui/src/components/forms/Reclassify/mappers/mapReclassifyStatement.ts @@ -3,7 +3,7 @@ import dayjs from 'dayjs'; import type { ReclassifyFormData } from '../../../../hooks'; import { type Reclassify_Orchestrated_Request_Type, - Reclassify_RequestTypeEnum + Reclassify_RequestTypeEnum, } from '../../../../schemas/forms/reclassify'; import { formatDateInputValue } from '../../../../utils/date'; @@ -11,7 +11,7 @@ const dateFormat = 'YYYY-MM-DD'; export const mapReclassifyStatement = ( data: ReclassifyFormData, - urn: string + urn: string, ): Reclassify_Orchestrated_Request_Type => { if (data.classification !== 'STATEMENT') { throw new Error('Not a valid classification'); @@ -46,8 +46,8 @@ export const mapReclassifyStatement = ( description: 'Key Witness Details', text: '', hidden: false, - hiddenDraft: false - } + hiddenDraft: false, + }, ] : [ { @@ -55,10 +55,10 @@ export const mapReclassifyStatement = ( description: 'Non-Key Witness Details', text: '', hidden: false, - hiddenDraft: false - } - ]) - ] + hiddenDraft: false, + }, + ]), + ], }; const witness: Reclassify_Orchestrated_Request_Type['witness'] = { @@ -66,8 +66,8 @@ export const mapReclassifyStatement = ( ? { witnessId: data?.witnessId } : { firstName: witnessActionPlan?.firstName || '', - surname: witnessActionPlan?.surname || '' - }) + surname: witnessActionPlan?.surname || '', + }), }; return { @@ -79,12 +79,10 @@ export const mapReclassifyStatement = ( used: data?.used, statement: { statementNo: data?.statementNumber, - ...(data?.hasStatementDate - ? { date: formatDateInputValue(data?.statementDate) } - : {}) - } + ...(data?.hasStatementDate ? { date: formatDateInputValue(data?.statementDate) } : {}), + }, }, witness, - ...(hasActionPlan ? { actionPlan: actionPlanData } : {}) + ...(hasActionPlan ? { actionPlan: actionPlanData } : {}), }; }; diff --git a/materials_ui/src/components/forms/Reclassify/utils/form.ts b/materials_ui/src/components/forms/Reclassify/utils/form.ts index 9f669502..74c9f75d 100644 --- a/materials_ui/src/components/forms/Reclassify/utils/form.ts +++ b/materials_ui/src/components/forms/Reclassify/utils/form.ts @@ -2,7 +2,7 @@ export const generateMaterialName = ( documentType: string, firstName: string, surname: string, - date?: string + date?: string, ) => { return `${documentType} ${surname.toUpperCase()} ${firstName}${date ? ' ' + date : ''}`; }; diff --git a/materials_ui/src/constants/categoryList.ts b/materials_ui/src/constants/categoryList.ts index 8fcf8e7b..e366639a 100644 --- a/materials_ui/src/constants/categoryList.ts +++ b/materials_ui/src/constants/categoryList.ts @@ -4,7 +4,7 @@ export const materialsCategoryList = [ { value: 'MG Form', label: 'MG forms' }, { value: 'Other Material', label: 'Other material' }, { value: 'Defendant Pre Cons', label: 'Defendant pre-cons' }, - { value: 'Unused Material', label: 'Unused material' } + { value: 'Unused Material', label: 'Unused material' }, ] as const; export const communicationsCategoryList = [ @@ -13,7 +13,7 @@ export const communicationsCategoryList = [ 'Email', 'Item', 'Meeting', - 'Telephone call' + 'Telephone call', ]; export const communicationsWithList = [ @@ -23,7 +23,7 @@ export const communicationsWithList = [ 'Defence', 'Police', 'WCU', - 'Other' + 'Other', ]; export const typeList = [ @@ -36,5 +36,5 @@ export const typeList = [ 'Forwarded Internal Email', 'Correspondence', 'Other Communication', - 'Service of ABE' + 'Service of ABE', ]; diff --git a/materials_ui/src/constants/chargeStatus.ts b/materials_ui/src/constants/chargeStatus.ts index dca7e6d2..201b641c 100644 --- a/materials_ui/src/constants/chargeStatus.ts +++ b/materials_ui/src/constants/chargeStatus.ts @@ -1,9 +1,9 @@ export enum ChargeStatusCode { PreCharge = 1, - PostCharge = 2 + PostCharge = 2, } export const CHARGE_STATUS_SELECT_OPTIONS = [ { id: String(ChargeStatusCode.PreCharge), name: 'Pre-charge' }, - { id: String(ChargeStatusCode.PostCharge), name: 'Post-charge' } + { id: String(ChargeStatusCode.PostCharge), name: 'Post-charge' }, ]; diff --git a/materials_ui/src/constants/discard.ts b/materials_ui/src/constants/discard.ts index f7ddb643..3d42a892 100644 --- a/materials_ui/src/constants/discard.ts +++ b/materials_ui/src/constants/discard.ts @@ -4,5 +4,5 @@ export const DISCARD_MATERIAL_OPTIONS = [ { label: 'Duplicate', value: 'DUP' }, { label: 'Illegible', value: 'ILG' }, { label: 'Replaced', value: 'REP' }, - { label: 'Superfluous', value: 'SUP' } + { label: 'Superfluous', value: 'SUP' }, ]; diff --git a/materials_ui/src/constants/enum.ts b/materials_ui/src/constants/enum.ts index 7123bed8..2b994b8c 100644 --- a/materials_ui/src/constants/enum.ts +++ b/materials_ui/src/constants/enum.ts @@ -1,11 +1,11 @@ export enum PcdReviewCoreType { EarlyAdvice = 0, InitialReview = 1, - PreChargeDecisionAnalysis = 2 + PreChargeDecisionAnalysis = 2, } export const PcdReviewTypeLabel: Record = { [PcdReviewCoreType.EarlyAdvice]: 'Early Advice', [PcdReviewCoreType.InitialReview]: 'Initial Review', - [PcdReviewCoreType.PreChargeDecisionAnalysis]: 'Further Review' + [PcdReviewCoreType.PreChargeDecisionAnalysis]: 'Further Review', }; diff --git a/materials_ui/src/constants/featureFlagGroups.ts b/materials_ui/src/constants/featureFlagGroups.ts index bf5269ca..0bf22be7 100644 --- a/materials_ui/src/constants/featureFlagGroups.ts +++ b/materials_ui/src/constants/featureFlagGroups.ts @@ -3,5 +3,5 @@ export const PRIVATE_BETA_FEATURE_USER_GROUPS: Record = { 2: '1663cea9-062e-4f6e-a7ac-26f0942724f3', // group 2 3: '870b7ef9-5937-4eb6-9ea0-98158f522ed7', // group 3 (stale) 4: '4e8b4cd0-5794-4dd8-a5a9-3bf6c19efb17', // group 4 (stale) - 5: 'bc71fb89-46f2-4b85-8cfc-9aaea49e0e5a' // group 5 (stale) + 5: 'bc71fb89-46f2-4b85-8cfc-9aaea49e0e5a', // group 5 (stale) }; diff --git a/materials_ui/src/constants/query.ts b/materials_ui/src/constants/query.ts index 5ebcf983..9be4111c 100644 --- a/materials_ui/src/constants/query.ts +++ b/materials_ui/src/constants/query.ts @@ -26,7 +26,7 @@ export const QUERY_KEYS = { DOCUMENT_SEARCH: 'documentSearch', GET_ALL_DOCUMENTS: 'getAllDocuments', UPDATE_STATEMENT: 'updateStatement', - UPDATE_EXHIBIT: 'updateExhibit' + UPDATE_EXHIBIT: 'updateExhibit', }; export const DEFAULT_RESULTS_PER_PAGE = 20; diff --git a/materials_ui/src/constants/url.ts b/materials_ui/src/constants/url.ts index 2d025998..0faca3a0 100644 --- a/materials_ui/src/constants/url.ts +++ b/materials_ui/src/constants/url.ts @@ -15,7 +15,7 @@ export const URL = { COMMUNICATIONS: '/communications', ERROR: '/error', PCD_REVIEW: '/pcd-review', - PCD_REVIEW_DETAILS: '/pcd-review:pcdId' + PCD_REVIEW_DETAILS: '/pcd-review:pcdId', }; export const APP_DEFAULT_PAGE = URL.ROOT; @@ -50,8 +50,7 @@ export const API_ENDPOINTS = { RECLASSIFY: '/material/{materialId}/reclassify-complete', EXHIBIT_PRODUCERS: '/exhibit-producers', CREATE_WITNESS: '/case-witnesses', - CREATE_ACTION_PLAN: '/action-plan' + CREATE_ACTION_PLAN: '/action-plan', }; -export const AUTH_REDIRECT_URL = - '{apiUrl}/init?caseId={caseId}&screen={screenPath}'; +export const AUTH_REDIRECT_URL = '{apiUrl}/init?caseId={caseId}&screen={screenPath}'; diff --git a/materials_ui/src/context/AppContext.tsx b/materials_ui/src/context/AppContext.tsx index e3cba2cf..b7a7d0fb 100644 --- a/materials_ui/src/context/AppContext.tsx +++ b/materials_ui/src/context/AppContext.tsx @@ -16,7 +16,7 @@ export const AppContext = createContext({ wmReturnUrl: null, removeBanner: () => null, setBannerState: () => null, - setWmTriageUrl: () => null + setWmTriageUrl: () => null, }); export const AppContextProvider = ({ children }: PropsWithChildren) => { @@ -36,9 +36,7 @@ export const AppContextProvider = ({ children }: PropsWithChildren) => { }; const removeBanner = (bannerIdentifier: string) => { - setBanner( - banners.filter((banner) => banner.identifier !== bannerIdentifier) - ); + setBanner(banners.filter((banner) => banner.identifier !== bannerIdentifier)); }; const setWmTriageUrl = (url?: string | null) => { @@ -47,14 +45,7 @@ export const AppContextProvider = ({ children }: PropsWithChildren) => { return ( {children} diff --git a/materials_ui/src/context/FiltersContext/helpers/utils.ts b/materials_ui/src/context/FiltersContext/helpers/utils.ts index 4eed3107..e9ae0734 100644 --- a/materials_ui/src/context/FiltersContext/helpers/utils.ts +++ b/materials_ui/src/context/FiltersContext/helpers/utils.ts @@ -4,36 +4,32 @@ export const getDefaultState = (defaultFilters?: FilterItem): FilterItem => { return { filters: { ...(defaultFilters ? defaultFilters?.filters : {}) }, search: '', - sort: { ...(defaultFilters?.sort || { column: null, direction: null }) } + sort: { ...(defaultFilters?.sort || { column: null, direction: null }) }, }; }; // updates a FilterItem with new sort criteria -export const setSort = ( - column: string | null, - direction: SortBy -): FilterItem['sort'] => ({ column, direction }); +export const setSort = (column: string | null, direction: SortBy): FilterItem['sort'] => ({ + column, + direction, +}); // updates a FilterItem with new filter criteria export const setFilter = ( currentFilters: FilterItem['filters'], fieldGroup: string, name: string, - checked: boolean + checked: boolean, ): FilterItem['filters'] => { // if this filter hasn't been checked, create it if checked - if ( - !Object.prototype.hasOwnProperty.call(currentFilters, fieldGroup) && - checked - ) { + if (!Object.prototype.hasOwnProperty.call(currentFilters, fieldGroup) && checked) { return { ...currentFilters, [fieldGroup]: [name] }; } const newFilterValues = checked ? [...(currentFilters?.[fieldGroup] || []), name] - : currentFilters?.[fieldGroup]?.filter( - (existingFilterName) => existingFilterName !== name - ) || []; + : currentFilters?.[fieldGroup]?.filter((existingFilterName) => existingFilterName !== name) || + []; if (!newFilterValues?.length) { delete currentFilters?.[fieldGroup]; diff --git a/materials_ui/src/context/FiltersContext/index.tsx b/materials_ui/src/context/FiltersContext/index.tsx index 8c196e89..26a4a58b 100644 --- a/materials_ui/src/context/FiltersContext/index.tsx +++ b/materials_ui/src/context/FiltersContext/index.tsx @@ -1,10 +1,6 @@ import { createContext, PropsWithChildren, useState } from 'react'; -import type { - FilterItem, - FilterKeys, - FiltersContextState -} from './helpers/types'; +import type { FilterItem, FilterKeys, FiltersContextState } from './helpers/types'; import { getDefaultState } from './helpers/utils'; // DATA STRUCTURE @@ -18,14 +14,8 @@ import { getDefaultState } from './helpers/utils'; export type FiltersContext = { filters: FiltersContextState; - createFilterContext: ( - filterSet: FilterKeys, - defaultState?: FilterItem - ) => void; - updateFilterContext: ( - filterSet: FilterKeys, - newFilterSet: FilterItem - ) => void; + createFilterContext: (filterSet: FilterKeys, defaultState?: FilterItem) => void; + updateFilterContext: (filterSet: FilterKeys, newFilterSet: FilterItem) => void; resetFilterContext: (filterSet: FilterKeys) => void; resetAllFilters: () => void; }; @@ -41,34 +31,25 @@ export const FilterContext = createContext({ export const FilterProvider = ({ children }: PropsWithChildren) => { const [filters, setFilters] = useState({}); - const createFilterContext = ( - filterSet: string, - defaultState?: FilterItem - ) => { - setFilters((prev) => ({ - ...prev, - [filterSet]: getDefaultState(defaultState) - })); + const createFilterContext = (filterSet: string, defaultState?: FilterItem) => { + setFilters((prev) => ({ ...prev, [filterSet]: getDefaultState(defaultState) })); }; - const updateFilterContext = ( - filterSet: FilterKeys, - newFilterSet: FilterItem - ) => { + const updateFilterContext = (filterSet: FilterKeys, newFilterSet: FilterItem) => { setFilters((prev) => ({ ...prev, [filterSet]: { filters: { ...(newFilterSet.filters ?? {}) }, search: newFilterSet.search ?? '', - sort: newFilterSet.sort ?? prev[filterSet]?.sort - } + sort: newFilterSet.sort ?? prev[filterSet]?.sort, + }, })); }; const resetFilterContext = (filterSet: FilterKeys) => { setFilters((prev) => ({ ...prev, - [filterSet]: { sort: prev[filterSet]?.sort, filters: {}, search: '' } + [filterSet]: { sort: prev[filterSet]?.sort, filters: {}, search: '' }, })); }; @@ -81,7 +62,7 @@ export const FilterProvider = ({ children }: PropsWithChildren) => { resetAllFilters, createFilterContext, resetFilterContext, - updateFilterContext + updateFilterContext, }} > {children} diff --git a/materials_ui/src/context/GroupContext.tsx b/materials_ui/src/context/GroupContext.tsx index 852706cb..023c58a6 100644 --- a/materials_ui/src/context/GroupContext.tsx +++ b/materials_ui/src/context/GroupContext.tsx @@ -11,9 +11,7 @@ export type GroupContextType = { hasAppAccess: () => boolean; }; -export const GroupDataContext = createContext( - {} as GroupContextType -); +export const GroupDataContext = createContext({} as GroupContextType); export const GroupDataProvider = ({ children }: PropsWithChildren) => { const [groups, setGroups] = useState(() => { diff --git a/materials_ui/src/hooks/case-materials/useAutoReclassify.ts b/materials_ui/src/hooks/case-materials/useAutoReclassify.ts index 4ff4a5e8..d82fef14 100644 --- a/materials_ui/src/hooks/case-materials/useAutoReclassify.ts +++ b/materials_ui/src/hooks/case-materials/useAutoReclassify.ts @@ -17,7 +17,7 @@ export const useAutoReclassify = (options?: UseAutoReclassifyProps) => { const postAutoReclassify = () => request.post( - `urns/${caseInfo?.urn}/cases/${caseInfo?.id}/uma-reclassify` + `urns/${caseInfo?.urn}/cases/${caseInfo?.id}/uma-reclassify`, ); const { trigger, isMutating, error } = useSWRMutation( @@ -33,8 +33,8 @@ export const useAutoReclassify = (options?: UseAutoReclassifyProps) => { if (options?.onError) { options.onError(error); } - } - } + }, + }, ); return { isPending: isMutating, error, mutate: trigger }; diff --git a/materials_ui/src/hooks/case-materials/useBulkSetUnused.ts b/materials_ui/src/hooks/case-materials/useBulkSetUnused.ts index b8aaa3e2..2c0da72c 100644 --- a/materials_ui/src/hooks/case-materials/useBulkSetUnused.ts +++ b/materials_ui/src/hooks/case-materials/useBulkSetUnused.ts @@ -3,10 +3,7 @@ import useSWRMutation from 'swr/mutation'; import { useBanner, useLogger, useRequest } from '..'; import { QUERY_KEYS } from '../../constants/query'; import { SwrPayload } from '../../schemas'; -import { - BulkSetUnusedRequestType, - BulkSetUnusedResponseType -} from '../../schemas/bulkSetUnused'; +import { BulkSetUnusedRequestType, BulkSetUnusedResponseType } from '../../schemas/bulkSetUnused'; import { useCaseInfoStore } from '../../stores'; type UseBulkSetUnusedOptions = { @@ -14,10 +11,7 @@ type UseBulkSetUnusedOptions = { onSuccess?: (response: { data: BulkSetUnusedResponseType }) => void; }; -export const useBulkSetUnused = ({ - onError, - onSuccess -}: UseBulkSetUnusedOptions) => { +export const useBulkSetUnused = ({ onError, onSuccess }: UseBulkSetUnusedOptions) => { const request = useRequest(); const { resetBanner } = useBanner(); const { log } = useLogger(); @@ -25,14 +19,14 @@ export const useBulkSetUnused = ({ const postBulkSetUnused = async ( _url: string, - { arg: data }: SwrPayload + { arg: data }: SwrPayload, ) => { resetBanner(); return request .post( `urns/${caseInfo?.urn}/cases/${caseInfo?.id}/bulk-set-unused`, - data + data, ) .then((response) => response); }; @@ -49,11 +43,10 @@ export const useBulkSetUnused = ({ log({ logLevel: 3, - message: - 'HK-UI-FE: Failed to update status to Unused for selected materials.' + message: 'HK-UI-FE: Failed to update status to Unused for selected materials.', }); - } - } + }, + }, ); return { trigger, isMutating, error, data }; diff --git a/materials_ui/src/hooks/case-materials/useCaseMaterial.ts b/materials_ui/src/hooks/case-materials/useCaseMaterial.ts index cd613b21..d688a79f 100644 --- a/materials_ui/src/hooks/case-materials/useCaseMaterial.ts +++ b/materials_ui/src/hooks/case-materials/useCaseMaterial.ts @@ -4,9 +4,7 @@ import { SELECTED_MATERIAL_QUERY_PARAM } from '../../constants/materials'; export const useCaseMaterial = () => { const [searchParams, setSearchParams] = useSearchParams(); const newQueryCommands = new URLSearchParams(searchParams); - const selectedMaterialId = newQueryCommands.get( - SELECTED_MATERIAL_QUERY_PARAM - ); + const selectedMaterialId = newQueryCommands.get(SELECTED_MATERIAL_QUERY_PARAM); const selectMaterial = (materialId: number) => { newQueryCommands.set(SELECTED_MATERIAL_QUERY_PARAM, materialId.toString()); diff --git a/materials_ui/src/hooks/case-materials/useCaseMaterials.ts b/materials_ui/src/hooks/case-materials/useCaseMaterials.ts index a87b900f..d986c43b 100644 --- a/materials_ui/src/hooks/case-materials/useCaseMaterials.ts +++ b/materials_ui/src/hooks/case-materials/useCaseMaterials.ts @@ -15,39 +15,28 @@ export const useCaseMaterials = ({ dataType }: UseCaseMaterialsProps) => { const getCaseMaterials = async () => { const response = await request.get( - `/urns/${urn}/cases/${id}/case-materials` + `/urns/${urn}/cases/${id}/case-materials`, ); if (response.status === 422 || response.status !== 200) { - throw new Error( - `Validation error: Unable to process ${dataType} request` - ); + throw new Error(`Validation error: Unable to process ${dataType} request`); } return response.data; }; - const { data, error, isLoading, isValidating, mutate } = useSWR( - materialsKey, - getCaseMaterials, - { keepPreviousData: true } - ); + const { data, error, isLoading, isValidating, mutate } = useSWR(materialsKey, getCaseMaterials, { + keepPreviousData: true, + }); const filteredData = (data ?? []).filter((material) => dataType === 'communications' ? material.category === 'Communication' - : material.category !== 'Communication' + : material.category !== 'Communication', ); const isInitialLoading = !data && isLoading; const isRefreshing = !!data && isValidating; - return { - data, - loading: isInitialLoading, - refreshing: isRefreshing, - error, - filteredData, - mutate - }; + return { data, loading: isInitialLoading, refreshing: isRefreshing, error, filteredData, mutate }; }; diff --git a/materials_ui/src/hooks/case-materials/useDiscard.ts b/materials_ui/src/hooks/case-materials/useDiscard.ts index 6525fcc6..a1ecd1e6 100644 --- a/materials_ui/src/hooks/case-materials/useDiscard.ts +++ b/materials_ui/src/hooks/case-materials/useDiscard.ts @@ -7,29 +7,23 @@ import { SwrPayload } from '../../schemas'; import { CaseMaterialDiscardRequestType, CaseMaterialDiscardResponseType, - CaseMaterialsType + CaseMaterialsType, } from '../../schemas/caseMaterials'; -export type UseDiscardOptions = { - onError?: () => void; - onSuccess?: () => void; -}; +export type UseDiscardOptions = { onError?: () => void; onSuccess?: () => void }; -export const useDiscard = ( - material?: CaseMaterialsType, - options?: UseDiscardOptions -) => { +export const useDiscard = (material?: CaseMaterialsType, options?: UseDiscardOptions) => { const request = useRequest(); const { caseInfo } = useCaseInfoStore(); const { log } = useLogger(); const discardMaterialRequest = async ( _url: string, - { arg: data }: SwrPayload + { arg: data }: SwrPayload, ) => { return await request.patch( `urns/${caseInfo?.urn}/cases/${caseInfo?.id}/materials/${material?.materialId}/discard`, - data + data, ); }; @@ -46,7 +40,7 @@ export const useDiscard = ( log({ logLevel: 1, message: `HK-UI-FE: caseId ${caseInfo?.id} - Material [${material?.materialId}] discarded`, - errorMessage: '' + errorMessage: '', }); }, onError: (error: AxiosError) => { @@ -58,10 +52,10 @@ export const useDiscard = ( log({ logLevel: 3, message: `HK-UI-FE: Error discarding material ${material?.materialId}`, - errorMessage: `HK-UI-FE: Error discarding material ${material?.materialId}` + errorMessage: `HK-UI-FE: Error discarding material ${material?.materialId}`, }); - } - } + }, + }, ); return { isLoading: isMutating, trigger, error }; diff --git a/materials_ui/src/hooks/case-materials/useEditMaterial.tsx b/materials_ui/src/hooks/case-materials/useEditMaterial.tsx index cde189ca..3922f89e 100644 --- a/materials_ui/src/hooks/case-materials/useEditMaterial.tsx +++ b/materials_ui/src/hooks/case-materials/useEditMaterial.tsx @@ -8,7 +8,7 @@ import { EditExhibitType, EditStatementRequestType, EditStatementResponseType, - EditStatementType + EditStatementType, } from '../../schemas/forms/editStatement.ts'; import { SwrPayload } from '../../schemas/index.ts'; @@ -17,20 +17,17 @@ type UseEditMaterialOptions = { onSuccess?: (response: { materialId: number }) => void; }; -export const useEditMaterial = ({ - onError, - onSuccess - }: UseEditMaterialOptions) => { +export const useEditMaterial = ({ onError, onSuccess }: UseEditMaterialOptions) => { const request = useRequest(); const { caseInfo } = useCaseInfoStore(); const postUpdateStatement = async ( _url: string, - { arg: data }: SwrPayload + { arg: data }: SwrPayload, ): Promise => { const response = await request.patch( `urns/${caseInfo?.urn}/cases/${caseInfo?.id}/materials/${data?.materialId}/statement`, - data + data, ); return response.data; @@ -38,58 +35,54 @@ export const useEditMaterial = ({ const postUpdateExhibit = async ( _url: string, - { arg: data }: SwrPayload + { arg: data }: SwrPayload, ): Promise => { const response = await request.patch( `urns/${caseInfo?.urn}/cases/${caseInfo?.id}/materials/${data?.materialId}/exhibit`, { ...data, - newProducer: data?.existingproducerOrWitnessId - ? undefined - : data?.producedBy, + newProducer: data?.existingproducerOrWitnessId ? undefined : data?.producedBy, existingProducerOrWitnessId: !data?.existingproducerOrWitnessId ? undefined - : data?.existingproducerOrWitnessId - } + : data?.existingproducerOrWitnessId, + }, ); return response.data; }; - const { trigger: submitUpdateStatement, isMutating: isStatementUpdating } = - useSWRMutation( - caseInfo ? QUERY_KEYS.UPDATE_STATEMENT : null, - postUpdateStatement, - { - onError, - onSuccess: (response) => { - if (onSuccess) { - onSuccess({ materialId: response.updateStatement.id }); - } + const { trigger: submitUpdateStatement, isMutating: isStatementUpdating } = useSWRMutation( + caseInfo ? QUERY_KEYS.UPDATE_STATEMENT : null, + postUpdateStatement, + { + onError, + onSuccess: (response) => { + if (onSuccess) { + onSuccess({ materialId: response.updateStatement.id }); } - } - ); + }, + }, + ); - const { trigger: submitUpdateExhibit, isMutating: isExhibitUpdating } = - useSWRMutation( - caseInfo ? QUERY_KEYS.UPDATE_EXHIBIT : null, - postUpdateExhibit, - { - onError, - onSuccess: (response) => { - if (onSuccess) { - onSuccess({ materialId: response.updateExhibit.id }); - } + const { trigger: submitUpdateExhibit, isMutating: isExhibitUpdating } = useSWRMutation( + caseInfo ? QUERY_KEYS.UPDATE_EXHIBIT : null, + postUpdateExhibit, + { + onError, + onSuccess: (response) => { + if (onSuccess) { + onSuccess({ materialId: response.updateExhibit.id }); } - } - ); + }, + }, + ); const updateStatement = async (data: EditStatementType) => { await submitUpdateStatement({ ...data, statementDate: data?.hasStatementDate ? dayjs(data?.statementDate).format('YYYY-MM-DD') - : null + : null, }); }; @@ -97,9 +90,5 @@ export const useEditMaterial = ({ await submitUpdateExhibit(data); }; - return { - loading: isStatementUpdating || isExhibitUpdating, - updateExhibit, - updateStatement - }; + return { loading: isStatementUpdating || isExhibitUpdating, updateExhibit, updateStatement }; }; diff --git a/materials_ui/src/hooks/case-materials/useReadStatus.ts b/materials_ui/src/hooks/case-materials/useReadStatus.ts index f910d500..eaba9852 100644 --- a/materials_ui/src/hooks/case-materials/useReadStatus.ts +++ b/materials_ui/src/hooks/case-materials/useReadStatus.ts @@ -2,7 +2,7 @@ import { QUERY_KEYS } from '../../constants/query'; import { SwrPayload } from '../../schemas'; import { CaseMaterialReadStatusRequestType, - CaseMaterialReadStatusResponseType + CaseMaterialReadStatusResponseType, } from '../../schemas/caseMaterials'; import useSWRMutation from 'swr/mutation'; @@ -16,11 +16,11 @@ export const useReadStatus = () => { const updateReadStatus = async ( _url: string, - { arg: data }: SwrPayload + { arg: data }: SwrPayload, ) => { return await request.patch( `urns/${caseInfo?.urn}/cases/${caseInfo?.id}/materials/${data?.materialId}/read-status`, - data + data, ); }; @@ -31,7 +31,7 @@ export const useReadStatus = () => { onSuccess: () => { log({ logLevel: 1, - message: `HK-UI-FE: caseId ${caseInfo?.id} - Material [id] read status updated` + message: `HK-UI-FE: caseId ${caseInfo?.id} - Material [id] read status updated`, }); }, onError: (error) => { @@ -39,10 +39,10 @@ export const useReadStatus = () => { log({ logLevel: 3, message: 'HK-UI-FE: Error updating material read status', - errorMessage: 'HK-UI-FE: Error updating material read status' + errorMessage: 'HK-UI-FE: Error updating material read status', }); - } - } + }, + }, ); return { trigger, isMutating, error }; diff --git a/materials_ui/src/hooks/case-materials/useReclassify.ts b/materials_ui/src/hooks/case-materials/useReclassify.ts index bb9aa73f..67ac62ac 100644 --- a/materials_ui/src/hooks/case-materials/useReclassify.ts +++ b/materials_ui/src/hooks/case-materials/useReclassify.ts @@ -4,13 +4,13 @@ import { mapReclassifyExhibit, mapReclassifyMGForm, mapReclassifyOther, - mapReclassifyStatement + mapReclassifyStatement, } from '../../components/forms/Reclassify/mappers'; import { SwrPayload } from '../../schemas'; import { Reclassify_ClassificationEnumType, Reclassify_Orchestrated_Request_Type, - Reclassify_Orchestrated_Response_Type + Reclassify_Orchestrated_Response_Type, } from '../../schemas/forms/reclassify'; import { ReclassifyFormData } from './useReclassifyForm'; @@ -36,34 +36,28 @@ const getDataMapper = (classification: Reclassify_ClassificationEnumType) => { export type UseReclassifyOptions = { materialId: number; onError?: (error: Error) => void; - onSuccess?: (response: { - data: Reclassify_Orchestrated_Response_Type; - }) => void; + onSuccess?: (response: { data: Reclassify_Orchestrated_Response_Type }) => void; }; -export const useReclassify = ({ - materialId, - onError, - onSuccess -}: UseReclassifyOptions) => { +export const useReclassify = ({ materialId, onError, onSuccess }: UseReclassifyOptions) => { const request = useRequest(); const { caseInfo } = useCaseInfoStore(); const postReclassification = async ( _url: string, - { arg: data }: SwrPayload + { arg: data }: SwrPayload, ) => { return await request.post( `/urns/${caseInfo?.urn}/cases/${caseInfo?.id}/materials/${materialId}/reclassify-complete`, - data + data, ); }; - const { trigger: submitReclassify, isMutating: isReclassifyLoading } = - useSWRMutation(QUERY_KEYS.RECLASSIFY_MATERIAL, postReclassification, { - onError, - onSuccess - }); + const { trigger: submitReclassify, isMutating: isReclassifyLoading } = useSWRMutation( + QUERY_KEYS.RECLASSIFY_MATERIAL, + postReclassification, + { onError, onSuccess }, + ); const submitReclassification = async (data: ReclassifyFormData) => { const mapper = getDataMapper(data?.classification); diff --git a/materials_ui/src/hooks/case-materials/useReclassifyForm.ts b/materials_ui/src/hooks/case-materials/useReclassifyForm.ts index 72229a34..55b118fc 100644 --- a/materials_ui/src/hooks/case-materials/useReclassifyForm.ts +++ b/materials_ui/src/hooks/case-materials/useReclassifyForm.ts @@ -5,7 +5,7 @@ import { Reclassify_TypeMGFormType, Reclassify_TypeOtherType, Reclassify_TypeStatementType, - Reclassify_WitnessAndActionPlanType + Reclassify_WitnessAndActionPlanType, } from '../../schemas/forms/reclassify'; export type FormStep = 'classification' | 'summary' | 'addWitness' | 'subject'; @@ -15,10 +15,7 @@ type Reclassify_Statement_With_ActionPlan = { witnessActionPlan: Reclassify_WitnessAndActionPlanType; }; -type Reclassify_Statement_Without_ActionPlan = { - witnessId: number; - witnessActionPlan?: undefined; -}; +type Reclassify_Statement_Without_ActionPlan = { witnessId: number; witnessActionPlan?: undefined }; type Reclassify_Statement_Data = ( | Reclassify_Statement_With_ActionPlan @@ -37,7 +34,7 @@ export const useReclassifyForm = (material: CaseMaterialsType) => { const [formData, setFormData] = useState>({ materialId: material?.materialId, subject: material?.subject, - used: true + used: true, }); const changeFormStep = (step: FormStep) => { diff --git a/materials_ui/src/hooks/case-materials/useRename.ts b/materials_ui/src/hooks/case-materials/useRename.ts index 39e1a734..1ec0bf7c 100644 --- a/materials_ui/src/hooks/case-materials/useRename.ts +++ b/materials_ui/src/hooks/case-materials/useRename.ts @@ -1,34 +1,25 @@ import useSWRMutation from 'swr/mutation'; import { QUERY_KEYS } from '../../constants/query.ts'; import { TDocument } from '../../materials_components/DocumentSelectAccordion/getters/getDocumentList.tsx'; -import { - CaseMaterialRenameResponseType, - CaseMaterialsType -} from '../../schemas/caseMaterials.ts'; +import { CaseMaterialRenameResponseType, CaseMaterialsType } from '../../schemas/caseMaterials.ts'; import { SwrPayload } from '../../schemas/index.ts'; import { useCaseInfoStore } from '../../stores/index.ts'; import { useLogger, useRequest } from '../index.ts'; -type UseRenameOptions = { - onError?: (error: Error) => void; - onSuccess?: () => void; -}; +type UseRenameOptions = { onError?: (error: Error) => void; onSuccess?: () => void }; export const useRename = ( material: CaseMaterialsType | (TDocument & { materialId?: number }) | null, - options?: UseRenameOptions + options?: UseRenameOptions, ) => { const request = useRequest(); const { caseInfo } = useCaseInfoStore(); const { log } = useLogger(); - const renameMaterialRequest = ( - _url: string, - { arg: newSubject }: SwrPayload - ) => { + const renameMaterialRequest = (_url: string, { arg: newSubject }: SwrPayload) => { return request.patch( `/urns/${caseInfo?.urn}/cases/${caseInfo?.id}/materials/${material?.materialId}/rename`, - { materialId: material?.materialId, subject: newSubject } + { materialId: material?.materialId, subject: newSubject }, ); }; const { trigger, isMutating } = useSWRMutation( @@ -42,7 +33,7 @@ export const useRename = ( console.error('Error renaming material:', error); log({ logLevel: 1, - message: `HK-UI-FE: caseId [${caseInfo?.id}] - materialID [${material?.materialId}] has not been renamed.` + message: `HK-UI-FE: caseId [${caseInfo?.id}] - materialID [${material?.materialId}] has not been renamed.`, }); }, onSuccess: () => { @@ -51,10 +42,10 @@ export const useRename = ( log({ logLevel: 1, - message: `HK-UI-FE: caseId [${caseInfo?.id}] - materialID [${material?.materialId}] has been renamed.` + message: `HK-UI-FE: caseId [${caseInfo?.id}] - materialID [${material?.materialId}] has been renamed.`, }); - } - } + }, + }, ); return { trigger, isMutating }; diff --git a/materials_ui/src/hooks/case/useCaseDefendants.ts b/materials_ui/src/hooks/case/useCaseDefendants.ts index 84c04e51..c73bc6ec 100644 --- a/materials_ui/src/hooks/case/useCaseDefendants.ts +++ b/materials_ui/src/hooks/case/useCaseDefendants.ts @@ -3,10 +3,7 @@ import useSWR from 'swr'; import { useRequest } from '../'; import type { SelectOption } from '../../components/SelectList/SelectList'; import { QUERY_KEYS } from '../../constants/query'; -import { - DefendantsResponseType, - DefendantType -} from '../../schemas/defendants'; +import { DefendantsResponseType, DefendantType } from '../../schemas/defendants'; import { useCaseInfoStore } from '../../stores'; export const useCaseDefendants = () => { @@ -15,15 +12,14 @@ export const useCaseDefendants = () => { const getCaseDefendants = async () => await request - .get( - `/urns/${caseInfo?.urn}/cases/${caseInfo?.id}/case-defendants`, - { params: { caseId: caseInfo?.id } } - ) + .get(`/urns/${caseInfo?.urn}/cases/${caseInfo?.id}/case-defendants`, { + params: { caseId: caseInfo?.id }, + }) .then((response) => response.data); const { data: caseDefendants, isLoading } = useSWR( caseInfo?.id ? QUERY_KEYS.CASE_DEFENDANTS : null, - getCaseDefendants + getCaseDefendants, ); const formatDefendantName = (defendant?: DefendantType | null): string => { @@ -34,15 +30,13 @@ export const useCaseDefendants = () => { return `${defendant?.firstNames} ${defendant?.surname}`; }; - const getDefendantById = ( - defendantId?: number | string - ): DefendantType | null => { + const getDefendantById = (defendantId?: number | string): DefendantType | null => { if (!defendantId) { return null; } const defendant = caseDefendants?.defendants?.find( - (def) => def.id.toString() === defendantId?.toString() + (def) => def.id.toString() === defendantId?.toString(), ); return defendant || null; @@ -52,7 +46,7 @@ export const useCaseDefendants = () => { caseDefendants?.defendants?.map((defendant) => ({ id: defendant?.id, label: formatDefendantName(defendant) || '', - value: defendant?.id + value: defendant?.id, })) || []; return { @@ -60,6 +54,6 @@ export const useCaseDefendants = () => { loading: isLoading, getDefendantById, formatDefendantName, - selectOptions + selectOptions, }; }; diff --git a/materials_ui/src/hooks/case/useCaseInfo.ts b/materials_ui/src/hooks/case/useCaseInfo.ts index 6d9dc82b..a4215943 100644 --- a/materials_ui/src/hooks/case/useCaseInfo.ts +++ b/materials_ui/src/hooks/case/useCaseInfo.ts @@ -18,9 +18,5 @@ export const useCaseInfo = ({ caseId, urn }: UseCaseInfoProps) => { const { data, isLoading, isValidating, mutate } = useSWR(key, getCaseInfo); - return { - caseInfo: data || null, - loading: isLoading || isValidating, - refresh: mutate - }; + return { caseInfo: data || null, loading: isLoading || isValidating, refresh: mutate }; }; diff --git a/materials_ui/src/hooks/case/useCaseLockCheck.ts b/materials_ui/src/hooks/case/useCaseLockCheck.ts index 6dff97dc..835896af 100644 --- a/materials_ui/src/hooks/case/useCaseLockCheck.ts +++ b/materials_ui/src/hooks/case/useCaseLockCheck.ts @@ -17,7 +17,7 @@ export const useCaseLockCheck = (): UseCaseLockStatus => { const getCaseLockStatus = async () => { const response = await request.get( - `/urns/${caseInfo?.urn}/cases/${caseInfo?.id}/case-lock-info` + `/urns/${caseInfo?.urn}/cases/${caseInfo?.id}/case-lock-info`, ); return response.data; @@ -25,12 +25,12 @@ export const useCaseLockCheck = (): UseCaseLockStatus => { const { data, mutate: refreshCaseLockStatus } = useSWR( caseInfo ? QUERY_KEYS.CASE_LOCK_STATUS : null, - getCaseLockStatus + getCaseLockStatus, ); return { isLocked: data?.isLocked || false, name: data?.lockedByUser || null, - refreshCaseLockStatus + refreshCaseLockStatus, }; }; diff --git a/materials_ui/src/hooks/case/useCaseWitnesses.ts b/materials_ui/src/hooks/case/useCaseWitnesses.ts index 997e8282..93684a78 100644 --- a/materials_ui/src/hooks/case/useCaseWitnesses.ts +++ b/materials_ui/src/hooks/case/useCaseWitnesses.ts @@ -3,10 +3,7 @@ import useSWR from 'swr'; import { useRequest } from '../'; import type { SelectOption } from '../../components/SelectList/SelectList'; import { QUERY_KEYS } from '../../constants/query'; -import type { - WitnessListItemType, - WitnessListResponseType -} from '../../schemas/witness'; +import type { WitnessListItemType, WitnessListResponseType } from '../../schemas/witness'; import { useCaseInfoStore } from '../../stores'; export const useCaseWitnesses = () => { @@ -15,15 +12,14 @@ export const useCaseWitnesses = () => { const getCaseWitnesses = async () => await request - .get( - `urns/${caseInfo?.urn}/cases/${caseInfo?.id}/case-witnesses`, - { params: { caseId: caseInfo?.id } } - ) + .get(`urns/${caseInfo?.urn}/cases/${caseInfo?.id}/case-witnesses`, { + params: { caseId: caseInfo?.id }, + }) .then((response) => response.data); const { data: caseWitnesses, isLoading } = useSWR( caseInfo ? QUERY_KEYS.CASE_WITNESSES : null, - getCaseWitnesses + getCaseWitnesses, ); const formatWitnessName = (witness?: WitnessListItemType | null): string => { @@ -33,15 +29,13 @@ export const useCaseWitnesses = () => { return `${witness?.firstName} ${witness?.surname}`; }; - const getWitnessById = ( - witnessId?: number | string - ): WitnessListItemType | null => { + const getWitnessById = (witnessId?: number | string): WitnessListItemType | null => { if (!witnessId) { return null; } const witness = caseWitnesses?.witnesses?.find( - (witness) => witness.witnessId.toString() === witnessId?.toString() + (witness) => witness.witnessId.toString() === witnessId?.toString(), ); return witness || null; @@ -51,7 +45,7 @@ export const useCaseWitnesses = () => { caseWitnesses?.witnesses?.map((witness) => ({ id: witness?.witnessId, label: formatWitnessName(witness) || '', - value: witness?.witnessId + value: witness?.witnessId, })) || []; return { @@ -59,6 +53,6 @@ export const useCaseWitnesses = () => { loading: isLoading, data: caseWitnesses?.witnesses || [], selectOptions, - formatWitnessName + formatWitnessName, }; }; diff --git a/materials_ui/src/hooks/case/useWitnessStatements.ts b/materials_ui/src/hooks/case/useWitnessStatements.ts index 329817ab..16bc5586 100644 --- a/materials_ui/src/hooks/case/useWitnessStatements.ts +++ b/materials_ui/src/hooks/case/useWitnessStatements.ts @@ -3,10 +3,7 @@ import useSWR from 'swr'; import { useRequest } from '..'; import { QUERY_KEYS } from '../../constants/query'; -import type { - WitnessStatementResponseType, - WitnessStatementType -} from '../../schemas/witness'; +import type { WitnessStatementResponseType, WitnessStatementType } from '../../schemas/witness'; import { useCaseInfoStore } from '../../stores'; export const useWitnessStatements = () => { @@ -17,38 +14,28 @@ export const useWitnessStatements = () => { const getWitnessStatements = async () => await request .get( - `/urns/${caseInfo?.urn}/cases/${caseInfo?.id}/witnesses/${witnessId}/witness-statements` + `/urns/${caseInfo?.urn}/cases/${caseInfo?.id}/witnesses/${witnessId}/witness-statements`, ) .then((response) => response.data); const { data, isLoading } = useSWR( witnessId && caseInfo ? [QUERY_KEYS.WITNESS_STATEMENTS, witnessId] : null, - getWitnessStatements + getWitnessStatements, ); const setWitnessId = (id: number | null) => { setWitness(id); }; - const [witnessStatements, lastStatementId] = useMemo((): [ - WitnessStatementType[], - number - ] => { - const statements = (data?.statementsForWitness || []).sort( - (a, b) => a.title - b.title - ); + const [witnessStatements, lastStatementId] = useMemo((): [WitnessStatementType[], number] => { + const statements = (data?.statementsForWitness || []).sort((a, b) => a.title - b.title); const statementIds: number = Math.max( - ...(statements || []).map((item: WitnessStatementType) => item.title) + ...(statements || []).map((item: WitnessStatementType) => item.title), ); return [statements, statementIds]; }, [data]); - return { - data: witnessStatements, - loading: isLoading, - setWitnessId, - lastStatementId - }; + return { data: witnessStatements, loading: isLoading, setWitnessId, lastStatementId }; }; diff --git a/materials_ui/src/hooks/documents/useDocumentPdfUrl.ts b/materials_ui/src/hooks/documents/useDocumentPdfUrl.ts index d5912b62..5a57ed6e 100644 --- a/materials_ui/src/hooks/documents/useDocumentPdfUrl.ts +++ b/materials_ui/src/hooks/documents/useDocumentPdfUrl.ts @@ -12,7 +12,7 @@ const getDocumentBlobFromAxiosInstance = async (p: { try { const response = await p.axiosInstance.get( `/urns/${p.urn}/cases/${p.caseId}/materials/${p.materialId}/document`, - { responseType: 'blob' } + { responseType: 'blob' }, ); const blob = response.data; @@ -26,11 +26,7 @@ const getDocumentBlobFromAxiosInstance = async (p: { } }; -export const useDocumentPdfUrl = (p: { - urn: string; - caseId: number; - materialId: string; -}) => { +export const useDocumentPdfUrl = (p: { urn: string; caseId: number; materialId: string }) => { const [pdfUrl, setPdfUrl] = useState(); const axiosInstance = useAxiosInstance(); @@ -40,7 +36,7 @@ export const useDocumentPdfUrl = (p: { axiosInstance, urn: p.urn, caseId: p.caseId, - materialId: stripCmsPrefix(p.materialId) + materialId: stripCmsPrefix(p.materialId), }); if (!resp.success) return setPdfUrl(null); diff --git a/materials_ui/src/hooks/documents/useDocumentPreview.ts b/materials_ui/src/hooks/documents/useDocumentPreview.ts index e5c0f2d8..403461d5 100644 --- a/materials_ui/src/hooks/documents/useDocumentPreview.ts +++ b/materials_ui/src/hooks/documents/useDocumentPreview.ts @@ -14,13 +14,13 @@ export const useDocumentPreview = ({ materialId }: Props) => { await request .get( `/urns/${caseInfo?.urn}/cases/${caseInfo?.id}/materials/${materialId}/document`, - { responseType: 'blob' } + { responseType: 'blob' }, ) .then((response) => response.data); const { data, error, isLoading } = useSWR( caseInfo ? `${QUERY_KEYS.CASE_MATERIAL_FULL_DOCUMENT}/${materialId}` : null, - getDocumentPreview + getDocumentPreview, ); return { data, loading: isLoading, error }; diff --git a/materials_ui/src/hooks/documents/useDocumentTypes.ts b/materials_ui/src/hooks/documents/useDocumentTypes.ts index 57126653..0b8633ba 100644 --- a/materials_ui/src/hooks/documents/useDocumentTypes.ts +++ b/materials_ui/src/hooks/documents/useDocumentTypes.ts @@ -2,10 +2,7 @@ import useSWR from 'swr'; import { useRequest } from '../'; import type { SelectOption } from '../../components/SelectList/SelectList'; import { QUERY_KEYS } from '../../constants/query'; -import { - DocumentType, - DocumentTypeResponseType -} from '../../schemas/documentTypes'; +import { DocumentType, DocumentTypeResponseType } from '../../schemas/documentTypes'; import { useCaseInfoStore } from '../../stores'; export const useDocumentTypes = () => { @@ -14,35 +11,26 @@ export const useDocumentTypes = () => { const getDocumentTypes = async () => await request - .get( - `/urns/${caseInfo?.urn}/cases/${caseInfo?.id}/document-types` - ) + .get(`/urns/${caseInfo?.urn}/cases/${caseInfo?.id}/document-types`) .then((response) => response.data); const { data: documentTypes, isLoading } = useSWR( caseInfo ? QUERY_KEYS.DOCUMENT_TYPES : null, - getDocumentTypes + getDocumentTypes, ); - const getDocumentTypeById = ( - documentId: number | string - ): DocumentType | undefined => { - return documentTypes?.find( - (type) => type.id.toString() === documentId.toString() - ); + const getDocumentTypeById = (documentId: number | string): DocumentType | undefined => { + return documentTypes?.find((type) => type.id.toString() === documentId.toString()); }; // Step 1: Group by `group` - const types = documentTypes?.reduce>( - (acc, item) => { - if (!acc[item.group]) { - acc[item.group] = []; - } - acc[item.group]?.push(item); - return acc; - }, - {} - ); + const types = documentTypes?.reduce>((acc, item) => { + if (!acc[item.group]) { + acc[item.group] = []; + } + acc[item.group]?.push(item); + return acc; + }, {}); // Step 2: Sort each group by `name` for (const group in types) { @@ -54,11 +42,7 @@ export const useDocumentTypes = () => { return []; } - return types[group].map((type) => ({ - id: type.id, - label: type.name, - value: type.id - })); + return types[group].map((type) => ({ id: type.id, label: type.name, value: type.id })); }; return { getDocumentTypeById, loading: isLoading, selectOptions, types }; diff --git a/materials_ui/src/hooks/documents/useDocuments.ts b/materials_ui/src/hooks/documents/useDocuments.ts index c5689c13..f6de9cd8 100644 --- a/materials_ui/src/hooks/documents/useDocuments.ts +++ b/materials_ui/src/hooks/documents/useDocuments.ts @@ -17,16 +17,14 @@ export const useDocuments = () => { const { data, isLoading } = useSWR( urn && caseId ? [QUERY_KEYS.GET_ALL_DOCUMENTS, urn, caseId] : null, - getDocuments + getDocuments, ); const docTypes = data ? Array.from( new Set( - data - .map((doc) => doc.cmsDocType.documentType) - .filter((t) => t != null && t !== '') - ) + data.map((doc) => doc.cmsDocType.documentType).filter((t) => t != null && t !== ''), + ), ) : []; diff --git a/materials_ui/src/hooks/exhibits/useExhibitProducers.ts b/materials_ui/src/hooks/exhibits/useExhibitProducers.ts index dc6a924e..d600629e 100644 --- a/materials_ui/src/hooks/exhibits/useExhibitProducers.ts +++ b/materials_ui/src/hooks/exhibits/useExhibitProducers.ts @@ -3,10 +3,7 @@ import useSWR from 'swr'; import { useRequest } from '../'; import type { SelectOption } from '../../components/SelectList/SelectList'; import { QUERY_KEYS } from '../../constants/query'; -import { - ExhibitProducerResponseType, - ExhibitProducerType -} from '../../schemas/exhibitProducer'; +import { ExhibitProducerResponseType, ExhibitProducerType } from '../../schemas/exhibitProducer'; import { useCaseInfoStore } from '../../stores'; export const useExhibitProducers = () => { @@ -16,32 +13,28 @@ export const useExhibitProducers = () => { const getExhibitProducers = async () => await request .get( - `urns/${caseInfo?.urn}/cases/${caseInfo?.id}/case-exhibit-producers` + `urns/${caseInfo?.urn}/cases/${caseInfo?.id}/case-exhibit-producers`, ) .then((response) => response.data); const { data, isLoading, isValidating } = useSWR( caseInfo ? QUERY_KEYS.EXHIBIT_PRODUCERS : null, - getExhibitProducers + getExhibitProducers, ); const selectOptions: SelectOption[] = data?.exhibitProducers?.map((item) => ({ id: item?.id, label: item.producer, - value: item?.id + value: item?.id, })) || []; - const getExhibitProducerById = ( - id?: number | string - ): ExhibitProducerType | null => { + const getExhibitProducerById = (id?: number | string): ExhibitProducerType | null => { if (!id) { return null; } - const producer = data?.exhibitProducers?.find( - (item) => item.id.toString() === id?.toString() - ); + const producer = data?.exhibitProducers?.find((item) => item.id.toString() === id?.toString()); return producer || null; }; @@ -50,6 +43,6 @@ export const useExhibitProducers = () => { data: data?.exhibitProducers || [], getExhibitProducerById, loading: isLoading || isValidating, - selectOptions + selectOptions, }; }; diff --git a/materials_ui/src/hooks/exhibits/useExhibits.ts b/materials_ui/src/hooks/exhibits/useExhibits.ts index e8132cfd..8a86364a 100644 --- a/materials_ui/src/hooks/exhibits/useExhibits.ts +++ b/materials_ui/src/hooks/exhibits/useExhibits.ts @@ -4,14 +4,12 @@ export const useExhibits = () => { const { data: materials, loading: isLoading, - error + error, } = useCaseMaterials({ dataType: 'materials' }); const references = materials?.length ? materials - ?.map((material) => - (material.reference || '').trim().toLocaleLowerCase() - ) + ?.map((material) => (material.reference || '').trim().toLocaleLowerCase()) .filter((ref) => !!ref) : []; diff --git a/materials_ui/src/hooks/index.ts b/materials_ui/src/hooks/index.ts index 82a68a59..ce8f23cd 100644 --- a/materials_ui/src/hooks/index.ts +++ b/materials_ui/src/hooks/index.ts @@ -8,10 +8,7 @@ export { useEditMaterial } from './case-materials/useEditMaterial'; export { useReadStatus } from './case-materials/useReadStatus'; export { useReclassify } from './case-materials/useReclassify'; export { useReclassifyForm } from './case-materials/useReclassifyForm'; -export type { - FormStep, - ReclassifyFormData -} from './case-materials/useReclassifyForm'; +export type { FormStep, ReclassifyFormData } from './case-materials/useReclassifyForm'; export { useRename } from './case-materials/useRename'; export { useCaseDefendants } from './case/useCaseDefendants'; export { useCaseInfo } from './case/useCaseInfo'; @@ -26,10 +23,7 @@ export { useExhibits } from './exhibits/useExhibits'; export { usePCD } from './pcd-request/usePCD'; export { usePCDList } from './pcd-request/usePCDList'; export { useCaseSearch } from './search/useCaseSearch'; -export { - useDocumentSearch, - useDocumentSearchResults -} from './search/useDocumentSearch'; +export { useDocumentSearch, useDocumentSearchResults } from './search/useDocumentSearch'; export { useSearchTracker } from './search/useSearchTracker'; export { useAppRoute } from './ui/useAppRoute'; export { useBanner } from './ui/useBanner'; diff --git a/materials_ui/src/hooks/pcd-request/usePCD.ts b/materials_ui/src/hooks/pcd-request/usePCD.ts index cfe090c3..60440d3b 100644 --- a/materials_ui/src/hooks/pcd-request/usePCD.ts +++ b/materials_ui/src/hooks/pcd-request/usePCD.ts @@ -13,13 +13,13 @@ export const usePCD = ({ pcdId }: UsePCDProps) => { const getPCDDetails = async () => await request .get( - `urns/${caseInfo?.urn}/cases/${caseInfo?.id}/pcds/${pcdId}/pcd-request` + `urns/${caseInfo?.urn}/cases/${caseInfo?.id}/pcds/${pcdId}/pcd-request`, ) .then((response) => response.data); const { data, error, isLoading, isValidating } = useSWR( caseInfo && pcdId ? `${QUERY_KEYS.PCD_REQUEST}/${pcdId}` : null, - getPCDDetails + getPCDDetails, ); return { data, error, isLoading: isLoading || isValidating }; diff --git a/materials_ui/src/hooks/pcd-request/usePCDList.ts b/materials_ui/src/hooks/pcd-request/usePCDList.ts index 9f564e92..4f2cfe1e 100644 --- a/materials_ui/src/hooks/pcd-request/usePCDList.ts +++ b/materials_ui/src/hooks/pcd-request/usePCDList.ts @@ -10,21 +10,17 @@ export const usePCDList = () => { const getPCDList = async () => await request .get( - `urns/${caseInfo?.urn}/cases/${caseInfo?.id}/pcds/${caseInfo?.id}/pcd-request-core` + `urns/${caseInfo?.urn}/cases/${caseInfo?.id}/pcds/${caseInfo?.id}/pcd-request-core`, ) .then((response) => response.data); const { data, error, isLoading, isValidating } = useSWR( caseInfo ? QUERY_KEYS.PCD_REQUESTS : null, - getPCDList + getPCDList, ); const sortByDate = (a: PCDListingType, b: PCDListingType) => Date.parse(b.decisionRequested) - Date.parse(a.decisionRequested); - return { - data: data?.sort(sortByDate) || undefined, - error, - isLoading: isLoading || isValidating - }; + return { data: data?.sort(sortByDate) || undefined, error, isLoading: isLoading || isValidating }; }; diff --git a/materials_ui/src/hooks/pcd-review/usePCDReviewCore.ts b/materials_ui/src/hooks/pcd-review/usePCDReviewCore.ts index aef00405..6af77aca 100644 --- a/materials_ui/src/hooks/pcd-review/usePCDReviewCore.ts +++ b/materials_ui/src/hooks/pcd-review/usePCDReviewCore.ts @@ -2,10 +2,7 @@ import useSWR from 'swr'; import { useCaseInfoStore, useRequest } from '..'; import { QUERY_KEYS } from '../../constants/query'; -import { - PCDReviewCoreResponseType, - PCDReviewCoreSchema -} from '../../schemas/pcdReview'; +import { PCDReviewCoreResponseType, PCDReviewCoreSchema } from '../../schemas/pcdReview'; export const usePCDReviewCore = () => { const request = useRequest(); @@ -14,7 +11,7 @@ export const usePCDReviewCore = () => { const getPCDReviewCore = async () => { try { const response = await request.get( - `urns/${caseInfo?.urn}/cases/${caseInfo?.id}/pcd-review-core` + `urns/${caseInfo?.urn}/cases/${caseInfo?.id}/pcd-review-core`, ); const parsedResponse = PCDReviewCoreSchema.safeParse(response.data); @@ -30,11 +27,10 @@ export const usePCDReviewCore = () => { } }; - const { data, error, isLoading, isValidating } = - useSWR( - caseInfo ? QUERY_KEYS.PCD_REVIEW_CORE : null, - getPCDReviewCore - ); + const { data, error, isLoading, isValidating } = useSWR( + caseInfo ? QUERY_KEYS.PCD_REVIEW_CORE : null, + getPCDReviewCore, + ); return { data, error, isLoading: isLoading || isValidating }; }; diff --git a/materials_ui/src/hooks/pcd-review/usePCDReviewDetails.ts b/materials_ui/src/hooks/pcd-review/usePCDReviewDetails.ts index e0449e99..45577eea 100644 --- a/materials_ui/src/hooks/pcd-review/usePCDReviewDetails.ts +++ b/materials_ui/src/hooks/pcd-review/usePCDReviewDetails.ts @@ -2,22 +2,16 @@ import useSWR from 'swr'; import { useCaseInfoStore, useRequest } from '..'; import { QUERY_KEYS } from '../../constants/query'; -import { - PCDReviewDetailsResponseType, - PCDReviewDetailsSchema -} from '../../schemas/pcdReview'; +import { PCDReviewDetailsResponseType, PCDReviewDetailsSchema } from '../../schemas/pcdReview'; export const usePCDReviewDetails = (historyId: number | undefined) => { const request = useRequest(); const { caseInfo } = useCaseInfoStore(); - const getPCDReviewDetails = async ([, requestedHistoryId]: readonly [ - string, - number - ]) => { + const getPCDReviewDetails = async ([, requestedHistoryId]: readonly [string, number]) => { try { const response = await request.get( - `urns/${caseInfo?.urn}/cases/${caseInfo?.id}/history/${requestedHistoryId}/pcd-review-details` + `urns/${caseInfo?.urn}/cases/${caseInfo?.id}/history/${requestedHistoryId}/pcd-review-details`, ); const parsedResponse = PCDReviewDetailsSchema.safeParse(response.data); @@ -32,13 +26,10 @@ export const usePCDReviewDetails = (historyId: number | undefined) => { } }; - const { data, error, isLoading, isValidating } = - useSWR( - caseInfo && historyId !== undefined - ? [QUERY_KEYS.PCD_REVIEW_REVIEW_DETAILS, historyId] - : null, - getPCDReviewDetails - ); + const { data, error, isLoading, isValidating } = useSWR( + caseInfo && historyId !== undefined ? [QUERY_KEYS.PCD_REVIEW_REVIEW_DETAILS, historyId] : null, + getPCDReviewDetails, + ); return { data, error, isLoading: isLoading || isValidating }; }; diff --git a/materials_ui/src/hooks/search/useCaseSearch.ts b/materials_ui/src/hooks/search/useCaseSearch.ts index 5b3a8786..48953ee6 100644 --- a/materials_ui/src/hooks/search/useCaseSearch.ts +++ b/materials_ui/src/hooks/search/useCaseSearch.ts @@ -27,25 +27,17 @@ export const useCaseSearch = (urn: string | undefined) => { setBanner({ type: 'error', header: 'Something went wrong', - content: - 'There was a problem with the server when searching for a case.' + content: 'There was a problem with the server when searching for a case.', }); } - } - } + }, + }, ); - return { - caseDetails: data ?? null, - loading: isLoading || isValidating, - refresh: mutate - }; + return { caseDetails: data ?? null, loading: isLoading || isValidating, refresh: mutate }; }; -export const getCaseDetails = async (p: { - axiosInstance: AxiosInstance; - urn: string; -}) => { +export const getCaseDetails = async (p: { axiosInstance: AxiosInstance; urn: string }) => { return p.axiosInstance.get(`/urns/${p.urn}/cases`); }; @@ -57,7 +49,7 @@ export const useCaseDetails = (p: { urn: string }) => { () => { if (!p.urn) return; return getCaseDetails({ axiosInstance, urn: p.urn }); - } + }, ); return rtn; diff --git a/materials_ui/src/hooks/search/useDocumentSearch.ts b/materials_ui/src/hooks/search/useDocumentSearch.ts index ac1d849b..4e1dfa72 100644 --- a/materials_ui/src/hooks/search/useDocumentSearch.ts +++ b/materials_ui/src/hooks/search/useDocumentSearch.ts @@ -4,13 +4,10 @@ import { QUERY_KEYS } from '../../constants/query'; import { DocumentResultType, SearchResultType, - SearchTermResultType + SearchTermResultType, } from '../../schemas/documents'; -export const useDocumentSearch = ( - searchTerm: string | null, - trackerComplete: boolean -) => { +export const useDocumentSearch = (searchTerm: string | null, trackerComplete: boolean) => { const request = useRequest(); const { caseInfo } = useCaseInfoStore(); @@ -25,10 +22,8 @@ export const useDocumentSearch = ( .then((res) => res.data); const { data, isLoading } = useSWR( - searchTerm && trackerComplete - ? [QUERY_KEYS.DOCUMENT_SEARCH, urn, caseId, searchTerm] - : null, - getSearch + searchTerm && trackerComplete ? [QUERY_KEYS.DOCUMENT_SEARCH, urn, caseId, searchTerm] : null, + getSearch, ); return { searchResults: data ?? null, loading: isLoading }; @@ -36,7 +31,7 @@ export const useDocumentSearch = ( export const useDocumentSearchResults = ( documents: DocumentResultType = [], - searchResults: SearchResultType[] = [] + searchResults: SearchResultType[] = [], ) => { if (!documents || !searchResults) return []; @@ -46,9 +41,7 @@ export const useDocumentSearchResults = ( const matches = searchResults.filter((sr) => sr.parentId === doc.parentId); const resultsPerDocumentCount = matches.reduce((acc, curr) => { - const count = curr.words.filter((w) => - w.matchType?.includes('Exact') - ).length; + const count = curr.words.filter((w) => w.matchType?.includes('Exact')).length; return acc + count; }, 0); @@ -70,9 +63,9 @@ export const useDocumentSearchResults = ( lineIndex: match.lineIndex, pageHeight: match.pageHeight, pageWidth: match.pageWidth, - words: match.words + words: match.words, })), - resultsPerDocumentCount + resultsPerDocumentCount, }); } } diff --git a/materials_ui/src/hooks/search/useSearchTracker.ts b/materials_ui/src/hooks/search/useSearchTracker.ts index 6816be2e..9764cbe7 100644 --- a/materials_ui/src/hooks/search/useSearchTracker.ts +++ b/materials_ui/src/hooks/search/useSearchTracker.ts @@ -15,11 +15,9 @@ export const useSearchTracker = (trigger: unknown) => { const getTracker = () => request.get(`/urns/${urn}/cases/${caseId}/tracker`); // Start pipeline once per case when first search is triggered - const { data: postData } = useSWR( - trigger ? ['tracker-init', urn, caseId] : null, - postInit, - { revalidateOnFocus: false } - ); + const { data: postData } = useSWR(trigger ? ['tracker-init', urn, caseId] : null, postInit, { + revalidateOnFocus: false, + }); // Poll until Completed const { data: trackerData, isLoading: trackerLoading } = useSWR( @@ -33,8 +31,8 @@ export const useSearchTracker = (trigger: unknown) => { ? 1000 : 0, dedupingInterval: 0, - revalidateOnFocus: false - } + revalidateOnFocus: false, + }, ); const failedToConvert = @@ -42,7 +40,7 @@ export const useSearchTracker = (trigger: unknown) => { (doc: SearchTermResultType) => doc.status === 'UnableToConvertToPdf' || doc.conversionStatus === 'UnexpectedError' || - doc.status === 'OcrAndIndexFailure' + doc.status === 'OcrAndIndexFailure', ) ?? []; const isComplete = trackerData?.data.status === 'Completed'; diff --git a/materials_ui/src/hooks/ui/navigateToViewDocumentPageInNewTab.ts b/materials_ui/src/hooks/ui/navigateToViewDocumentPageInNewTab.ts index 1fab1028..9dbec7a9 100644 --- a/materials_ui/src/hooks/ui/navigateToViewDocumentPageInNewTab.ts +++ b/materials_ui/src/hooks/ui/navigateToViewDocumentPageInNewTab.ts @@ -3,7 +3,5 @@ export const navigateToViewDocumentPageInNewTab = (p: { caseId: number; materialId: string | number; }) => { - window.open( - `${import.meta.env.BASE_URL}${p.urn}/${p.caseId}/view-document/${p.materialId}` - ); + window.open(`${import.meta.env.BASE_URL}${p.urn}/${p.caseId}/view-document/${p.materialId}`); }; diff --git a/materials_ui/src/hooks/ui/useAppRoute.ts b/materials_ui/src/hooks/ui/useAppRoute.ts index d1d89bbf..3abaf17b 100644 --- a/materials_ui/src/hooks/ui/useAppRoute.ts +++ b/materials_ui/src/hooks/ui/useAppRoute.ts @@ -15,7 +15,7 @@ export const APP_ROUTES = { SERVER_ERROR: 'service-down', UNAUTHORISED: 'unauthorized', CASE_SEARCH: 'case-search', - UPDATE_MATERIAL: 'update-material' + UPDATE_MATERIAL: 'update-material', } as const; type AppRouteKey = keyof typeof APP_ROUTES; diff --git a/materials_ui/src/hooks/ui/useBanner.ts b/materials_ui/src/hooks/ui/useBanner.ts index 34ca6154..3a2922cb 100644 --- a/materials_ui/src/hooks/ui/useBanner.ts +++ b/materials_ui/src/hooks/ui/useBanner.ts @@ -3,8 +3,7 @@ import { AppContext } from '../../context/AppContext'; import { BannerType } from '../../schemas'; export const useBanner = () => { - const { banners, clearBanners, removeBanner, setBannerState } = - useContext(AppContext); + const { banners, clearBanners, removeBanner, setBannerState } = useContext(AppContext); const setBanner = (banner: BannerType, persistBanners?: boolean) => { setBannerState(banner, persistBanners); diff --git a/materials_ui/src/hooks/ui/useFeatureFlag.ts b/materials_ui/src/hooks/ui/useFeatureFlag.ts index cf888ffc..cf073f24 100644 --- a/materials_ui/src/hooks/ui/useFeatureFlag.ts +++ b/materials_ui/src/hooks/ui/useFeatureFlag.ts @@ -3,13 +3,9 @@ import { PRIVATE_BETA_FEATURE_USER_GROUPS } from '../../constants'; import { GroupDataContext } from '../../context'; import { UserGroupType } from '../../schemas/user'; -type UseFeatureFlag = ( - allowedGroups: number[], - groupsOverride?: UserGroupType[] -) => boolean; +type UseFeatureFlag = (allowedGroups: number[], groupsOverride?: UserGroupType[]) => boolean; -const featureFlagsDisabled = - import.meta.env.VITE_DISABLE_FEATURE_FLAGS === 'true'; +const featureFlagsDisabled = import.meta.env.VITE_DISABLE_FEATURE_FLAGS === 'true'; export const useFeatureFlag = (): UseFeatureFlag => { const { groups = [] } = useContext(GroupDataContext); @@ -28,7 +24,7 @@ export const useFeatureFlag = (): UseFeatureFlag => { .map((groupId) => { return PRIVATE_BETA_FEATURE_USER_GROUPS[groupId]; }) - .includes(group?.id) + .includes(group?.id), ); }; }; diff --git a/materials_ui/src/hooks/ui/useFilters.ts b/materials_ui/src/hooks/ui/useFilters.ts index f8a23848..289d7226 100644 --- a/materials_ui/src/hooks/ui/useFilters.ts +++ b/materials_ui/src/hooks/ui/useFilters.ts @@ -1,46 +1,31 @@ import { useContext, useEffect, useState } from 'react'; import { FilterContext } from '../../context/FiltersContext'; -import type { - FilterItem, - FilterKeys -} from '../../context/FiltersContext/helpers/types'; +import type { FilterItem, FilterKeys } from '../../context/FiltersContext/helpers/types'; import { getDefaultState, setFilter as setFilterState, - setSort as setSortState + setSort as setSortState, } from '../../context/FiltersContext/helpers/utils'; -export const useFilters = ( - filterSetName: FilterKeys, - defaultState?: FilterItem -) => { - const { - createFilterContext, - filters, - resetFilterContext, - updateFilterContext - } = useContext(FilterContext); +export const useFilters = (filterSetName: FilterKeys, defaultState?: FilterItem) => { + const { createFilterContext, filters, resetFilterContext, updateFilterContext } = + useContext(FilterContext); const [shallowFilters, setShallowFilters] = useState( - () => filters[filterSetName] ?? getDefaultState(defaultState) + () => filters[filterSetName] ?? getDefaultState(defaultState), ); const setSort = (column: string | null) => { setShallowFilters((prev) => { const newSortDirection = - !prev.sort?.direction || prev.sort?.direction === 'descending' - ? 'ascending' - : 'descending'; + !prev.sort?.direction || prev.sort?.direction === 'descending' ? 'ascending' : 'descending'; const hasSortColumnChanged = prev.sort?.column !== column; const newSortState: FilterItem = { filters: filters[filterSetName]?.filters ?? {}, // if someone clicks on a new sort column, we want to change to ascending no matter what - sort: setSortState( - column, - hasSortColumnChanged ? 'ascending' : newSortDirection - ) + sort: setSortState(column, hasSortColumnChanged ? 'ascending' : newSortDirection), }; // we want to update context immediately for sorting @@ -52,18 +37,14 @@ export const useFilters = ( const setFilter = (filterGroup: string, name: string, value: boolean) => { setShallowFilters((prev) => ({ ...prev, - filters: setFilterState(prev.filters, filterGroup, name, value) + filters: setFilterState(prev.filters, filterGroup, name, value), })); }; - const setCheckboxFilter = ( - filterGroup: string, - name: string, - checked: boolean - ) => { + const setCheckboxFilter = (filterGroup: string, name: string, checked: boolean) => { setShallowFilters((prev) => ({ ...prev, - filters: setFilterState(prev.filters, filterGroup, name, checked) + filters: setFilterState(prev.filters, filterGroup, name, checked), })); }; @@ -76,11 +57,7 @@ export const useFilters = ( }; const resetFilters = () => { - setShallowFilters((prev) => ({ - ...prev, - filters: defaultState?.filters || {}, - search: '' - })); + setShallowFilters((prev) => ({ ...prev, filters: defaultState?.filters || {}, search: '' })); resetFilterContext(filterSetName); }; @@ -102,6 +79,6 @@ export const useFilters = ( setFilter, setCheckboxFilter, setSearch, - setSort + setSort, }; }; diff --git a/materials_ui/src/hooks/ui/useLogger.ts b/materials_ui/src/hooks/ui/useLogger.ts index e06c0c25..35106ff9 100644 --- a/materials_ui/src/hooks/ui/useLogger.ts +++ b/materials_ui/src/hooks/ui/useLogger.ts @@ -21,7 +21,7 @@ export const useLogger = () => { console.error('Failed to send log:', error); } }, - [request] + [request], ); return { log }; diff --git a/materials_ui/src/hooks/ui/usePageColors.ts b/materials_ui/src/hooks/ui/usePageColors.ts index 988d9467..e8fd7d20 100644 --- a/materials_ui/src/hooks/ui/usePageColors.ts +++ b/materials_ui/src/hooks/ui/usePageColors.ts @@ -7,14 +7,11 @@ import { useEffect, useState } from 'react'; const FORCED_COLORS_QUERY = '(forced-colors: active)'; type PdfPageColors = { background: string; foreground: string }; -const HIGH_CONTRAST_PAGE_COLORS: PdfPageColors = { - background: 'Canvas', - foreground: 'CanvasText' -}; +const HIGH_CONTRAST_PAGE_COLORS: PdfPageColors = { background: 'Canvas', foreground: 'CanvasText' }; export function usePageColors(): PdfPageColors | undefined { const [isForcedColors, setIsForcedColors] = useState(() => - Boolean(window.matchMedia?.(FORCED_COLORS_QUERY).matches) + Boolean(window.matchMedia?.(FORCED_COLORS_QUERY).matches), ); useEffect(() => { diff --git a/materials_ui/src/hooks/ui/usePager.ts b/materials_ui/src/hooks/ui/usePager.ts index c6205b42..bb450f50 100644 --- a/materials_ui/src/hooks/ui/usePager.ts +++ b/materials_ui/src/hooks/ui/usePager.ts @@ -1,12 +1,8 @@ -import { usePagination } from 'react-use-pagination'; -import { useSearchParams } from 'react-router-dom'; import { useEffect } from 'react'; +import { useSearchParams } from 'react-router-dom'; +import { usePagination } from 'react-use-pagination'; -type UsePagerOptions = { - totalItems?: number; - initialPage?: number; - initialPageSize?: number; -}; +type UsePagerOptions = { totalItems?: number; initialPage?: number; initialPageSize?: number }; export const usePager = (options?: UsePagerOptions) => { const usePaginationData = usePagination(options); @@ -17,10 +13,7 @@ export const usePager = (options?: UsePagerOptions) => { if (usePaginationData.currentPage === 0) { newQueryCommands.delete('page'); } else { - newQueryCommands.set( - 'page', - (usePaginationData.currentPage + 1 || '').toString() - ); + newQueryCommands.set('page', (usePaginationData.currentPage + 1 || '').toString()); } setQueryParams(newQueryCommands); }, [usePaginationData.currentPage]); diff --git a/materials_ui/src/hooks/ui/useRequest.ts b/materials_ui/src/hooks/ui/useRequest.ts index 7589b929..34be55fd 100644 --- a/materials_ui/src/hooks/ui/useRequest.ts +++ b/materials_ui/src/hooks/ui/useRequest.ts @@ -13,13 +13,13 @@ export const useRequest = () => { const axiosInstance = axios.create({ baseURL: `${POLARIS_GATEWAY_URL}/api/`, - withCredentials: true + withCredentials: true, }); axiosInstance.interceptors.request.use(async (config) => { const tokenResponse = await msalInstance.acquireTokenSilent({ ...loginRequest, - account: msalInstance.getActiveAccount()! + account: msalInstance.getActiveAccount()!, }); config.headers['Authorization'] = `Bearer ${tokenResponse.accessToken}`; @@ -47,16 +47,14 @@ export const useRequest = () => { if ( !error.request.responseURL.includes('/uma-reclassify') && - !/^\/api\/urns\/[^/]+\/cases$/.test( - new URL(error.request.responseURL).pathname - ) + !/^\/api\/urns\/[^/]+\/cases$/.test(new URL(error.request.responseURL).pathname) ) { return navigate(`/${getRoute('SERVER_ERROR', false)}`); } } return Promise.reject(error); - } + }, ); return axiosInstance; @@ -67,13 +65,13 @@ export const useAxiosInstance = () => { const axiosInstance = axios.create({ baseURL: `${POLARIS_GATEWAY_URL}/api/`, - withCredentials: true + withCredentials: true, }); axiosInstance.interceptors.request.use(async (config) => { const tokenResponse = await msalInstance.acquireTokenSilent({ ...loginRequest, - account: msalInstance.getActiveAccount()! + account: msalInstance.getActiveAccount()!, }); config.headers['Authorization'] = `Bearer ${tokenResponse.accessToken}`; diff --git a/materials_ui/src/hooks/ui/useTableActions.ts b/materials_ui/src/hooks/ui/useTableActions.ts index dd7ae84b..a213536c 100644 --- a/materials_ui/src/hooks/ui/useTableActions.ts +++ b/materials_ui/src/hooks/ui/useTableActions.ts @@ -23,7 +23,7 @@ export const useTableActions = ({ refreshData, setBanner, deselectItem, - resetBanner + resetBanner, }: TableActionsProps) => { const { getRoute } = useAppRoute(); const navigate = useNavigate(); @@ -32,37 +32,26 @@ export const useTableActions = ({ const [isReadStatusUpdating, setIsReadStatusUpdating] = useState(false); const handleReclassifyClick = () => { - navigate(getRoute('RECLASSIFICATION'), { - state: { row: selectedItems[0] } - }); + navigate(getRoute('RECLASSIFICATION'), { state: { row: selectedItems[0] } }); }; const handleDiscardClick = (returnToUrl: string) => { navigate(getRoute('DISCARD'), { - state: { selectedMaterial: selectedItems[0], returnTo: returnToUrl } + state: { selectedMaterial: selectedItems[0], returnTo: returnToUrl }, }); }; const handleEditClick = (material: CaseMaterialsType, returnTo: string) => { - navigate(getRoute('UPDATE_MATERIAL'), { - state: { returnTo, row: material } - }); + navigate(getRoute('UPDATE_MATERIAL'), { state: { returnTo, row: material } }); }; const handleRedactClick = (materialId: number) => { - navigate(getRoute('REVIEW_REDACT'), { - state: { materialId: `CMS-${materialId}` } - }); + navigate(getRoute('REVIEW_REDACT'), { state: { materialId: `CMS-${materialId}` } }); }; - const handleUnusedClick = ( - materials: CaseMaterialsType[], - returnTo: string - ) => { + const handleUnusedClick = (materials: CaseMaterialsType[], returnTo: string) => { resetBanner(); - navigate(getRoute('RECLASSIFY_TO_UNUSED'), { - state: { materials, returnTo } - }); + navigate(getRoute('RECLASSIFY_TO_UNUSED'), { state: { materials, returnTo } }); }; const determineReadStatusLabel = (items: CaseMaterialsType[]) => { @@ -83,7 +72,7 @@ export const useTableActions = ({ await trigger({ materialId: row.materialId, state: row.readStatus === READ_STATUS.READ ? 'unread' : 'read', - correspondenceId: uuidv4() + correspondenceId: uuidv4(), }); } @@ -93,15 +82,14 @@ export const useTableActions = ({ setBanner({ type: 'success', header: 'Read status updated', - content: 'Selected items have been updated.' + content: 'Selected items have been updated.', }); } catch (error) { console.error('Error updating read status:', error); setBanner({ type: 'error', header: 'Error updating read status', - content: - 'There was an error updating the read status of the selected items.' + content: 'There was an error updating the read status of the selected items.', }); } finally { setIsReadStatusUpdating(false); @@ -116,6 +104,6 @@ export const useTableActions = ({ handleUnusedClick, determineReadStatusLabel, handleReadStatusClick, - isReadStatusUpdating + isReadStatusUpdating, }; }; diff --git a/materials_ui/src/hooks/ui/useUserGroupsFeatureFlag.ts b/materials_ui/src/hooks/ui/useUserGroupsFeatureFlag.ts index 936cba76..94ce6554 100644 --- a/materials_ui/src/hooks/ui/useUserGroupsFeatureFlag.ts +++ b/materials_ui/src/hooks/ui/useUserGroupsFeatureFlag.ts @@ -3,8 +3,7 @@ import { PRIVATE_BETA_FEATURE_USER_GROUPS } from '../../constants'; export type UserGroupsFeatureFlags = { bulkRedaction: boolean }; -const featureFlagsDisabled = - import.meta.env.VITE_DISABLE_FEATURE_FLAGS === 'true'; +const featureFlagsDisabled = import.meta.env.VITE_DISABLE_FEATURE_FLAGS === 'true'; export const useUserGroupsFeatureFlag = (): UserGroupsFeatureFlags => { const { instance } = useMsal(); diff --git a/materials_ui/src/index.tsx b/materials_ui/src/index.tsx index f293abd8..fd856d2d 100644 --- a/materials_ui/src/index.tsx +++ b/materials_ui/src/index.tsx @@ -19,7 +19,7 @@ if (import.meta.env.DEV && !import.meta.env.VITE_E2E) { const { worker } = await import('./mocks/browser'); await worker.start({ onUnhandledRequest: 'bypass', - serviceWorker: { url: `${import.meta.env.BASE_URL}mockServiceWorker.js` } + serviceWorker: { url: `${import.meta.env.BASE_URL}mockServiceWorker.js` }, }); } @@ -34,13 +34,7 @@ if (redirectResult?.account) { ReactDOM.createRoot(document.getElementById('root')!).render( - + - + , ); diff --git a/materials_ui/src/materials_components/CaseworkPdfRedactorWrapper/BulkRedactionForm.tsx b/materials_ui/src/materials_components/CaseworkPdfRedactorWrapper/BulkRedactionForm.tsx index ed9913b3..8e070601 100644 --- a/materials_ui/src/materials_components/CaseworkPdfRedactorWrapper/BulkRedactionForm.tsx +++ b/materials_ui/src/materials_components/CaseworkPdfRedactorWrapper/BulkRedactionForm.tsx @@ -1,8 +1,5 @@ import { useState } from 'react'; -import { - RedactionTypeSelect, - TRedactionType -} from '../PdfRedactor/RedactionTypeSelect'; +import { RedactionTypeSelect, TRedactionType } from '../PdfRedactor/RedactionTypeSelect'; import { GovUkButton } from '../PdfRedactor/templates/GovUkButton'; export type TBulkSearchSummary = @@ -23,10 +20,8 @@ export type TBulkProps = { const BulkSearchStatusText = (p: { search: TBulkSearchSummary }) => { if (p.search.status === 'idle') return null; if (p.search.status === 'loading') return Searching…; - if (p.search.status === 'error') - return Couldn’t search this document.; - if (p.search.count === 0) - return No other matches found in the document.; + if (p.search.status === 'error') return Couldn’t search this document.; + if (p.search.count === 0) return No other matches found in the document.; return ( This phrase appears {p.search.count} time @@ -41,8 +36,7 @@ export const BulkRedactionForm = (p: { }) => { const [redactionType, setRedactionType] = useState(); - const completedSearch = - p.bulkProps.search.status === 'done' ? p.bulkProps.search : undefined; + const completedSearch = p.bulkProps.search.status === 'done' ? p.bulkProps.search : undefined; const matchCount = completedSearch?.count ?? 0; const hasMatches = matchCount >= 1; const hasMultipleMatches = matchCount >= 2; @@ -58,11 +52,7 @@ export const BulkRedactionForm = (p: { return (
- + {p.bulkProps.search.status !== 'idle' && (
@@ -72,11 +62,7 @@ export const BulkRedactionForm = (p: { {!completedSearch && (
- + Redact this text - {p.bulkProps.search.status === 'error' - ? 'Try again' - : 'Find matching text'} + {p.bulkProps.search.status === 'error' ? 'Try again' : 'Find matching text'}
)} @@ -101,11 +85,7 @@ export const BulkRedactionForm = (p: { > View previous - + View next
@@ -113,11 +93,7 @@ export const BulkRedactionForm = (p: { {completedSearch && (
- + Redact this {hasMultipleMatches && ( diff --git a/materials_ui/src/materials_components/CaseworkPdfRedactorWrapper/CaseworkPdfRedactorWrapper.tsx b/materials_ui/src/materials_components/CaseworkPdfRedactorWrapper/CaseworkPdfRedactorWrapper.tsx index e2501bc2..d13738b7 100644 --- a/materials_ui/src/materials_components/CaseworkPdfRedactorWrapper/CaseworkPdfRedactorWrapper.tsx +++ b/materials_ui/src/materials_components/CaseworkPdfRedactorWrapper/CaseworkPdfRedactorWrapper.tsx @@ -16,59 +16,39 @@ import { GovUkButton } from '../PdfRedactor/templates/GovUkButton'; import { TCoord, TRedaction } from '../PdfRedactor/utils/coordUtils'; import { TIndexedDeletion } from '../PdfRedactor/utils/deletionUtils'; import { TMode } from '../PdfRedactor/utils/modeUtils'; -import { - TIndexedRotation, - TRotation -} from '../PdfRedactor/utils/rotationUtils'; -import type { - THighlightLayer, - TSearchHighlight -} from '../PdfRedactor/utils/searchHighlightUtils'; -import { - TTriggerData, - useTriggerListener -} from '../PdfRedactor/utils/useTriggger'; +import { TIndexedRotation, TRotation } from '../PdfRedactor/utils/rotationUtils'; +import type { THighlightLayer, TSearchHighlight } from '../PdfRedactor/utils/searchHighlightUtils'; +import { TTriggerData, useTriggerListener } from '../PdfRedactor/utils/useTriggger'; import { useWindowMouseListener } from '../PdfRedactor/utils/useWindowMouseListener'; import { useBulkRedactionFlow } from './hooks/useBulkRedactionFlow'; import { useDocumentCheckOutRequest } from './hooks/useDocumentCheckOutRequest'; import { RedactionPopover } from './RedactionPopover'; import { combineDeletionsWithDeletionDetails, - TDeletionDetail + TDeletionDetail, } from './utils/combineRedactionsDeletions'; import { saveDeletions } from './utils/saveDeletionsUtils'; import { saveRedactions } from './utils/saveRedactionsUtils'; import { saveRotations } from './utils/saveRotationsUtils'; -const presentationWriteFlagToRedactionDisabledMessageMap: { - [k: string]: string; -} = { - IsRedactionServiceOffline: - 'Redaction is currently unavailable and undergoing maintenance.', +const presentationWriteFlagToRedactionDisabledMessageMap: { [k: string]: string } = { + IsRedactionServiceOffline: 'Redaction is currently unavailable and undergoing maintenance.', OnlyAvailableInCms: 'This document can only be redacted in CMS.', DocTypeNotAllowed: 'Redaction is not supported for this document type.', OriginalFileTypeNotAllowed: 'Redaction is not supported for this file type.', IsDispatched: 'This is a dispatched document.', IsPageRotationModeOn: - 'Redaction is unavailable in page rotation mode, please turn off page rotation to continue with redaction.' + 'Redaction is unavailable in page rotation mode, please turn off page rotation to continue with redaction.', }; -const getDocumentRedactionDisabledMessage = ( - doc: TDocument | null | undefined -) => { +const getDocumentRedactionDisabledMessage = (doc: TDocument | null | undefined) => { const writePresentationFlag = doc?.presentationFlags?.write; if (!writePresentationFlag) return null; - const value = - presentationWriteFlagToRedactionDisabledMessageMap[ - `${writePresentationFlag}` - ]; + const value = presentationWriteFlagToRedactionDisabledMessageMap[`${writePresentationFlag}`]; return value ? value : null; }; -const createCheckoutMessageFromCheckoutResponse = (p: { - action?: string; - message?: string; -}) => +const createCheckoutMessageFromCheckoutResponse = (p: { action?: string; message?: string }) => p.message ? `It is not possible to ${p.action} as ${p.message}. Please try again later.` : 'Something has gone wrong, please try again later'; @@ -97,26 +77,18 @@ export const CaseworkPdfRedactorWrapper = (p: { checkInDocumentTriggerData: TTriggerData; }) => { const [isDocumentCheckedOut, setIsDocumentCheckedOut] = useState(false); - const [selectedRedactionTypes, setSelectedRedactionTypes] = useState< - TRedactionType[] - >([]); + const [selectedRedactionTypes, setSelectedRedactionTypes] = useState([]); - const documentCheckOutRequest = useDocumentCheckOutRequest({ - caseId: p.caseId, - urn: p.urn - }); + const documentCheckOutRequest = useDocumentCheckOutRequest({ caseId: p.caseId, urn: p.urn }); const checkInDocument = async () => { if (!isDocumentCheckedOut) return; const resp = await documentCheckOutRequest.checkIn({ parentId: p.parentId, - childId: p.childId + childId: p.childId, }); if (resp.success) setIsDocumentCheckedOut(false); }; - useTriggerListener({ - triggerData: p.checkInDocumentTriggerData, - fn: () => checkInDocument() - }); + useTriggerListener({ triggerData: p.checkInDocumentTriggerData, fn: () => checkInDocument() }); useEffect(() => { return () => { @@ -130,24 +102,17 @@ export const CaseworkPdfRedactorWrapper = (p: { const [deletionDetails, setDeletionDetails] = useState([]); - const documentCategory = p.document - ? categoriseDocument(p.document) - : undefined; + const documentCategory = p.document ? categoriseDocument(p.document) : undefined; const isUnredactableDocumentCategory = documentCategory && - (['review', 'defendantPreCons'] as TCategoryName[]).includes( - documentCategory - ); - const isDocumentDispatched = - p.document?.presentationFlags?.write === 'IsDispatched'; + (['review', 'defendantPreCons'] as TCategoryName[]).includes(documentCategory); + const isDocumentDispatched = p.document?.presentationFlags?.write === 'IsDispatched'; const cleanupDeletionDetails = () => { const deletionIds = Object.values(indexedDeletion) .filter((del) => del.isDeleted) .map((del) => del.id); - setDeletionDetails((prev) => - prev.filter((detail) => deletionIds.includes(detail.deletionId)) - ); + setDeletionDetails((prev) => prev.filter((detail) => deletionIds.includes(detail.deletionId))); }; useEffect(() => cleanupDeletionDetails(), [indexedDeletion]); @@ -166,7 +131,7 @@ export const CaseworkPdfRedactorWrapper = (p: { childId: p.childId, parentId: p.parentId, setRedactions, - setSelectedRedactionTypes + setSelectedRedactionTypes, }); const searchLayer: THighlightLayer = { @@ -174,17 +139,18 @@ export const CaseworkPdfRedactorWrapper = (p: { focusedId: p.focusedSearchIndex !== undefined ? p.searchHighlights?.[p.focusedSearchIndex]?.id - : undefined + : undefined, }; - const [documentIsCheckedOutPopupProps, setDocumentIsCheckedOutPopupProps] = - useState<{ action: string; message: string } | null>(null); - const [ - documentIsUnableToBeRedactedPopupProps, - setDocumentIsUnableToBeRedactedPopupProps - ] = useState<{ message: string } | null>(null); - const [redactionDisabledModalProps, setRedactionDisabledModalProps] = + const [documentIsCheckedOutPopupProps, setDocumentIsCheckedOutPopupProps] = useState<{ + action: string; + message: string; + } | null>(null); + const [documentIsUnableToBeRedactedPopupProps, setDocumentIsUnableToBeRedactedPopupProps] = useState<{ message: string } | null>(null); + const [redactionDisabledModalProps, setRedactionDisabledModalProps] = useState<{ + message: string; + } | null>(null); const [deleteReasonPopupProps, setDeleteReasonPopupProps] = useState & TCoord, @@ -201,11 +167,7 @@ export const CaseworkPdfRedactorWrapper = (p: { }; const unrotatePage = (pageNumber: number) => { setIndexedRotation((prev) => { - const noRotation: TRotation = { - id: crypto.randomUUID(), - pageNumber, - rotationDegrees: 0 - }; + const noRotation: TRotation = { id: crypto.randomUUID(), pageNumber, rotationDegrees: 0 }; return { ...prev, [pageNumber]: noRotation }; }); }; @@ -214,7 +176,7 @@ export const CaseworkPdfRedactorWrapper = (p: { if (isDocumentCheckedOut) return { success: true } as const; const checkoutResponse = await documentCheckOutRequest.checkOut({ parentId: p.parentId, - childId: p.childId + childId: p.childId, }); setIsDocumentCheckedOut(checkoutResponse.success); return checkoutResponse; @@ -271,8 +233,7 @@ export const CaseworkPdfRedactorWrapper = (p: { })()} {documentIsUnableToBeRedactedPopupProps && (() => { - const closeModal = () => - setDocumentIsUnableToBeRedactedPopupProps(null); + const closeModal = () => setDocumentIsUnableToBeRedactedPopupProps(null); return ( + )} {deleteReasonPopupProps && (() => { @@ -352,10 +310,7 @@ export const CaseworkPdfRedactorWrapper = (p: { const popoverAnchor = (() => { if (highlightedText) { - const rect = window - .getSelection() - ?.getRangeAt(0) - ?.getBoundingClientRect(); + const rect = window.getSelection()?.getRangeAt(0)?.getBoundingClientRect(); if (rect && rect.width > 0) { return { x: (rect.left + rect.right) / 2, y: rect.top }; } @@ -364,14 +319,10 @@ export const CaseworkPdfRedactorWrapper = (p: { })(); const checkoutResponsePromise = checkCheckoutStatus(); - const redactionDisabledMessage = getDocumentRedactionDisabledMessage( - p.document - ); + const redactionDisabledMessage = getDocumentRedactionDisabledMessage(p.document); if (redactionDisabledMessage) { removeRedactions(add.map((x) => x.id)); - setRedactionDisabledModalProps({ - message: redactionDisabledMessage - }); + setRedactionDisabledModalProps({ message: redactionDisabledMessage }); return; } const checkoutResponse = await checkoutResponsePromise; @@ -379,7 +330,7 @@ export const CaseworkPdfRedactorWrapper = (p: { removeRedactions(add.map((x) => x.id)); const message = createCheckoutMessageFromCheckoutResponse({ action: 'redact', - message: checkoutResponse.message + message: checkoutResponse.message, }); setDocumentIsCheckedOutPopupProps({ action: 'redact', message }); return; @@ -389,7 +340,7 @@ export const CaseworkPdfRedactorWrapper = (p: { x: popoverAnchor.x, y: popoverAnchor.y, redactionIds: add.map((x) => x.id), - highlightedText + highlightedText, }); }} onRemoveRedactions={() => {}} @@ -402,16 +353,13 @@ export const CaseworkPdfRedactorWrapper = (p: { caseId: p.caseId, childId: p.childId, parentId: p.parentId, - redactions + redactions, }); setRedactions([]); trackAction('Redacted', { materialId: p.parentId }); p.onRedactionSaveStatusChange('saved'); if (p.document) p.onModification(p.document); - await documentCheckOutRequest.checkIn({ - parentId: p.parentId, - childId: p.childId - }); + await documentCheckOutRequest.checkIn({ parentId: p.parentId, childId: p.childId }); } catch (error) { console.error('Failed to save redactions:', error); setRedactions([]); @@ -420,11 +368,7 @@ export const CaseworkPdfRedactorWrapper = (p: { } }} onShowRedactionLogModal={(redactions) => { - p.onShowRedactionLogModal({ - mode: 'list', - redactions, - selectedRedactionTypes - }); + p.onShowRedactionLogModal({ mode: 'list', redactions, selectedRedactionTypes }); }} indexedRotation={indexedRotation} onRotationsChange={(newRotations) => setIndexedRotation(newRotations)} @@ -437,7 +381,7 @@ export const CaseworkPdfRedactorWrapper = (p: { const message = createCheckoutMessageFromCheckoutResponse({ action: 'rotate', - message: checkoutResponse.message + message: checkoutResponse.message, }); setDocumentIsCheckedOutPopupProps({ action: 'rotate', message }); }} @@ -452,7 +396,7 @@ export const CaseworkPdfRedactorWrapper = (p: { const message = createCheckoutMessageFromCheckoutResponse({ action: 'delete', - message: checkoutResponse.message + message: checkoutResponse.message, }); setDocumentIsCheckedOutPopupProps({ action: 'delete', message }); return; @@ -460,7 +404,7 @@ export const CaseworkPdfRedactorWrapper = (p: { const newDeletionDetails = { deletionId: add.id, - randomId: `This deletion does ${crypto.randomUUID()}` + randomId: `This deletion does ${crypto.randomUUID()}`, }; setDeletionDetails((prev) => [...prev, newDeletionDetails]); setDeleteReasonPopupProps(() => ({ @@ -469,14 +413,14 @@ export const CaseworkPdfRedactorWrapper = (p: { pageNumber: add.pageNumber, documentId: 'This document does not exist', urn: 'This URN does not exist', - caseId: 'This case does not exist' + caseId: 'This case does not exist', })); }} onDeletionRemove={() => {}} onSaveDeletions={async () => { combineDeletionsWithDeletionDetails({ deletions: Object.values(indexedDeletion), - deletionDetails + deletionDetails, }); await saveDeletions({ @@ -485,13 +429,10 @@ export const CaseworkPdfRedactorWrapper = (p: { caseId: p.caseId, childId: p.childId, parentId: p.parentId, - deletions: Object.values(indexedDeletion) + deletions: Object.values(indexedDeletion), }); if (p.document) p.onModification(p.document); - await documentCheckOutRequest.checkIn({ - parentId: p.parentId, - childId: p.childId - }); + await documentCheckOutRequest.checkIn({ parentId: p.parentId, childId: p.childId }); }} onSaveRotations={async () => { const checkoutResponse = await checkCheckoutStatus(); @@ -499,7 +440,7 @@ export const CaseworkPdfRedactorWrapper = (p: { if (!checkoutResponse.success) { const message = createCheckoutMessageFromCheckoutResponse({ action: 'rotate', - message: checkoutResponse.message + message: checkoutResponse.message, }); setDocumentIsCheckedOutPopupProps({ action: 'rotate', message }); @@ -511,13 +452,10 @@ export const CaseworkPdfRedactorWrapper = (p: { caseId: p.caseId, childId: p.childId, parentId: p.parentId, - rotations: Object.values(indexedRotation) + rotations: Object.values(indexedRotation), }); if (p.document) p.onModification(p.document); - await documentCheckOutRequest.checkIn({ - parentId: p.parentId, - childId: p.childId - }); + await documentCheckOutRequest.checkIn({ parentId: p.parentId, childId: p.childId }); }} initRedactions={p.initRedactions} onNumOfDocPagesChanged={p.onNumOfPagesDocumentChange} diff --git a/materials_ui/src/materials_components/CaseworkPdfRedactorWrapper/hooks/useBulkRedactionFlow.ts b/materials_ui/src/materials_components/CaseworkPdfRedactorWrapper/hooks/useBulkRedactionFlow.ts index d8923f53..4d9cb658 100644 --- a/materials_ui/src/materials_components/CaseworkPdfRedactorWrapper/hooks/useBulkRedactionFlow.ts +++ b/materials_ui/src/materials_components/CaseworkPdfRedactorWrapper/hooks/useBulkRedactionFlow.ts @@ -20,9 +20,7 @@ export const useBulkRedactionFlow = (p: { }) => { const featureFlags = useUserGroupsFeatureFlag(); - const [popupProps, setPopupProps] = useState( - null - ); + const [popupProps, setPopupProps] = useState(null); const removeRedactions = (ids: string[]) => p.setRedactions((prev) => prev.filter((r) => !ids.includes(r.id))); @@ -32,7 +30,7 @@ export const useBulkRedactionFlow = (p: { urn: p.urn, caseId: p.caseId, versionId: p.childId, - documentId: p.parentId + documentId: p.parentId, }); // pin the popover above whichever match is currently focused @@ -40,14 +38,10 @@ export const useBulkRedactionFlow = (p: { const focusedId = bulkSearch.focusedCandidate?.id; if (!focusedId) return; - const elm = document.querySelector( - `[data-text-highlight-id="${focusedId}"]` - ); + const elm = document.querySelector(`[data-text-highlight-id="${focusedId}"]`); if (!elm) return; const matchTop = elm.getBoundingClientRect().top; - setPopupProps((prev) => - prev ? { ...prev, x: window.innerWidth / 2, y: matchTop } : prev - ); + setPopupProps((prev) => (prev ? { ...prev, x: window.innerWidth / 2, y: matchTop } : prev)); }, [bulkSearch.focusedCandidate?.id]); const trimmedSearchText = popupProps?.highlightedText?.trim() ?? ''; @@ -65,7 +59,7 @@ export const useBulkRedactionFlow = (p: { const onSaveSingle = (currentType: TRedactionType) => { p.setSelectedRedactionTypes((prev) => [ ...prev, - { id: currentType.id, name: currentType.name } + { id: currentType.id, name: currentType.name }, ]); closePopover(); }; @@ -85,7 +79,7 @@ export const useBulkRedactionFlow = (p: { p.setRedactions((prev) => [...prev, focused]); p.setSelectedRedactionTypes((prev) => [ ...prev, - { id: currentType.id, name: currentType.name } + { id: currentType.id, name: currentType.name }, ]); const willBeEmpty = bulkSearch.candidates.length === 1; bulkSearch.removeFocused(); @@ -97,10 +91,7 @@ export const useBulkRedactionFlow = (p: { p.setRedactions((prev) => [...prev, ...bulkSearch.candidates]); p.setSelectedRedactionTypes((prev) => [ ...prev, - ...Array(bulkSearch.candidates.length).fill({ - id: currentType.id, - name: currentType.name - }) + ...Array(bulkSearch.candidates.length).fill({ id: currentType.id, name: currentType.name }), ]); closePopover(); }; @@ -116,19 +107,19 @@ export const useBulkRedactionFlow = (p: { onViewPrevious: bulkSearch.goPrev, onViewNext: bulkSearch.goNext, onRedactFocused: acceptFocusedMatch, - onRedactAll: acceptAllMatches + onRedactAll: acceptAllMatches, } : undefined; const highlightLayer: THighlightLayer = { highlights: convertCandidatesToSearchHighlights(bulkSearch.candidates), - focusedId: bulkSearch.focusedCandidate?.id + focusedId: bulkSearch.focusedCandidate?.id, }; return { highlightLayer, popupProps, openPopover: (props: TRedactionPopupProps) => setPopupProps(props), - popoverProps: { onClose, onSaveSingle, bulkProps } + popoverProps: { onClose, onSaveSingle, bulkProps }, }; }; diff --git a/materials_ui/src/materials_components/CaseworkPdfRedactorWrapper/hooks/useBulkSearch.ts b/materials_ui/src/materials_components/CaseworkPdfRedactorWrapper/hooks/useBulkSearch.ts index fa8ff839..10b11bba 100644 --- a/materials_ui/src/materials_components/CaseworkPdfRedactorWrapper/hooks/useBulkSearch.ts +++ b/materials_ui/src/materials_components/CaseworkPdfRedactorWrapper/hooks/useBulkSearch.ts @@ -22,7 +22,7 @@ const wait = (ms: number, signal: AbortSignal) => clearTimeout(timeoutId); resolve(); }, - { once: true } + { once: true }, ); }); @@ -33,9 +33,7 @@ export const useBulkSearch = (p: { versionId: number; documentId: string; }) => { - const [state, setState] = useState({ - status: 'idle' - }); + const [state, setState] = useState({ status: 'idle' }); const abortRef = useRef(null); const clear = useCallback(() => { @@ -60,7 +58,7 @@ export const useBulkSearch = (p: { versionId: p.versionId, documentId: p.documentId, searchText, - signal: controller.signal + signal: controller.signal, }); if (controller.signal.aborted) return undefined; @@ -94,7 +92,7 @@ export const useBulkSearch = (p: { return undefined; } }, - [p.axiosInstance, p.urn, p.caseId, p.versionId, p.documentId] + [p.axiosInstance, p.urn, p.caseId, p.versionId, p.documentId], ); const nudge = (delta: number) => @@ -110,14 +108,12 @@ export const useBulkSearch = (p: { const removeFocused = useCallback(() => { setState((prev) => { if (prev.status !== 'done' || prev.candidates.length === 0) return prev; - const remaining = prev.candidates.filter( - (_, i) => i !== prev.focusedIndex - ); + const remaining = prev.candidates.filter((_, i) => i !== prev.focusedIndex); if (remaining.length === 0) return { status: 'idle' }; return { status: 'done', candidates: remaining, - focusedIndex: Math.min(prev.focusedIndex, remaining.length - 1) + focusedIndex: Math.min(prev.focusedIndex, remaining.length - 1), }; }); }, []); @@ -136,6 +132,6 @@ export const useBulkSearch = (p: { clear, goNext, goPrev, - removeFocused + removeFocused, }; }; diff --git a/materials_ui/src/materials_components/CaseworkPdfRedactorWrapper/hooks/useDocumentCheckOutRequest.ts b/materials_ui/src/materials_components/CaseworkPdfRedactorWrapper/hooks/useDocumentCheckOutRequest.ts index e12d09a6..131043fe 100644 --- a/materials_ui/src/materials_components/CaseworkPdfRedactorWrapper/hooks/useDocumentCheckOutRequest.ts +++ b/materials_ui/src/materials_components/CaseworkPdfRedactorWrapper/hooks/useDocumentCheckOutRequest.ts @@ -7,9 +7,7 @@ import { useAxiosInstance } from '../../../caseWorkApp/components/utils/getData' type UseDocumentCheckoutOptions = { caseId?: number; urn?: string }; const extractReadableMessageFromError = (error: unknown) => { - const errorSchema = z.object({ - response: z.object({ data: z.object({ Error: z.string() }) }) - }); + const errorSchema = z.object({ response: z.object({ data: z.object({ Error: z.string() }) }) }); const parsed = errorSchema.safeParse(error); if (!parsed.success) return null; @@ -27,7 +25,7 @@ const checkOutDocumentFromAxiosInstance = async (p: { }) => { try { const response = await p.axiosInstance.post( - `/api/urns/${p.urn}/cases/${p.caseId}/documents/${p.parentId}/versions/${p.childId}/checkout` + `/api/urns/${p.urn}/cases/${p.caseId}/documents/${p.parentId}/versions/${p.childId}/checkout`, ); return { success: true, data: { response } } as const; @@ -41,11 +39,7 @@ const checkOutDocumentFromAxiosInstance = async (p: { return { success: false, status: 'locked', message } as const; } - return { - success: false, - status: 'generic error', - message: defaultMessage - } as const; + return { success: false, status: 'generic error', message: defaultMessage } as const; } }; @@ -59,32 +53,24 @@ export const checkInDocumentFromAxiosInstance = async (p: { try { await p.axiosInstance.delete( `/api/urns/${p.urn}/cases/${p.caseId}/documents/${p.parentId}/versions/${p.childId}/checkout`, - { fetchOptions: { keepalive: true } } + { fetchOptions: { keepalive: true } }, ); return { success: true } as const; } catch (error: unknown) { - if (!!error && typeof error === 'object' && 'message' in error) - console.error(error?.message); + if (!!error && typeof error === 'object' && 'message' in error) console.error(error?.message); return { success: false } as const; } }; -export const useDocumentCheckOutRequest = ({ - caseId, - urn -}: UseDocumentCheckoutOptions) => { +export const useDocumentCheckOutRequest = ({ caseId, urn }: UseDocumentCheckoutOptions) => { const [isLoading, setIsLoading] = useState(false); const axiosInstance = useAxiosInstance(); - const checkOut = async (fnProps: { - parentId: string; - childId: number | string; - }) => { + const checkOut = async (fnProps: { parentId: string; childId: number | string }) => { if (!urn) return { success: false, message: 'no urn provided' } as const; - if (!caseId) - return { success: false, message: 'no caseId provided' } as const; + if (!caseId) return { success: false, message: 'no caseId provided' } as const; setIsLoading(true); const resp = await checkOutDocumentFromAxiosInstance({ @@ -92,7 +78,7 @@ export const useDocumentCheckOutRequest = ({ urn, caseId, parentId: fnProps.parentId, - childId: fnProps.childId + childId: fnProps.childId, }); setIsLoading(false); @@ -101,8 +87,7 @@ export const useDocumentCheckOutRequest = ({ const checkIn = async (fnProps: { parentId: string; childId: number }) => { if (!urn) return { success: false, message: 'no urn provided' } as const; - if (!caseId) - return { success: false, message: 'no caseId provided' } as const; + if (!caseId) return { success: false, message: 'no caseId provided' } as const; setIsLoading(true); const resp = await checkInDocumentFromAxiosInstance({ @@ -110,7 +95,7 @@ export const useDocumentCheckOutRequest = ({ urn, caseId, parentId: fnProps.parentId, - childId: fnProps.childId + childId: fnProps.childId, }); setIsLoading(false); diff --git a/materials_ui/src/materials_components/CaseworkPdfRedactorWrapper/utils/bulkSearchDocumentUtils.ts b/materials_ui/src/materials_components/CaseworkPdfRedactorWrapper/utils/bulkSearchDocumentUtils.ts index 94d1faf3..f82787bd 100644 --- a/materials_ui/src/materials_components/CaseworkPdfRedactorWrapper/utils/bulkSearchDocumentUtils.ts +++ b/materials_ui/src/materials_components/CaseworkPdfRedactorWrapper/utils/bulkSearchDocumentUtils.ts @@ -19,10 +19,7 @@ export type TBulkSearchResponse = { isNotFound: boolean; }; -export type TBulkSearchResult = { - status: number; - data: TBulkSearchResponse | null; -}; +export type TBulkSearchResult = { status: number; data: TBulkSearchResponse | null }; export const bulkSearchDocument = async (p: { axiosInstance: AxiosInstance; @@ -35,11 +32,7 @@ export const bulkSearchDocument = async (p: { }): Promise => { const response = await p.axiosInstance.get( `/api/urns/${p.urn}/cases/${p.caseId}/documents/${p.documentId}/versions/${p.versionId}/search`, - { - params: { SearchText: p.searchText }, - signal: p.signal, - validateStatus: () => true - } + { params: { SearchText: p.searchText }, signal: p.signal, validateStatus: () => true }, ); return { status: response.status, data: response.data ?? null }; }; diff --git a/materials_ui/src/materials_components/CaseworkPdfRedactorWrapper/utils/combineRedactionsDeletions.ts b/materials_ui/src/materials_components/CaseworkPdfRedactorWrapper/utils/combineRedactionsDeletions.ts index 02ca2351..e8608200 100644 --- a/materials_ui/src/materials_components/CaseworkPdfRedactorWrapper/utils/combineRedactionsDeletions.ts +++ b/materials_ui/src/materials_components/CaseworkPdfRedactorWrapper/utils/combineRedactionsDeletions.ts @@ -10,9 +10,7 @@ export const combineRedactionsWithRedactionDetails = (p: { }) => { const redactionsWithDetails = p.redactions .map((x) => { - const thisDetails = p.redactionDetails.find( - (y) => y.redactionId === x.id - ); + const thisDetails = p.redactionDetails.find((y) => y.redactionId === x.id); if (!thisDetails) return undefined; return { ...x, ...thisDetails }; }) diff --git a/materials_ui/src/materials_components/CaseworkPdfRedactorWrapper/utils/saveDeletionsUtils.ts b/materials_ui/src/materials_components/CaseworkPdfRedactorWrapper/utils/saveDeletionsUtils.ts index f9dcef29..f1f54746 100644 --- a/materials_ui/src/materials_components/CaseworkPdfRedactorWrapper/utils/saveDeletionsUtils.ts +++ b/materials_ui/src/materials_components/CaseworkPdfRedactorWrapper/utils/saveDeletionsUtils.ts @@ -13,13 +13,13 @@ export const saveDeletions = async (p: { redactions: [], documentModifications: p.deletions.map((red) => ({ pageIndex: red.pageNumber, - operation: 'delete' - })) + operation: 'delete', + })), }; const response = await p.axiosInstance.put( `/api/urns/${p.urn}/cases/${p.caseId}/documents/${p.parentId}/versions/${p.childId}/redact`, - payload + payload, ); return response.data; diff --git a/materials_ui/src/materials_components/CaseworkPdfRedactorWrapper/utils/saveRedactionsUtils.ts b/materials_ui/src/materials_components/CaseworkPdfRedactorWrapper/utils/saveRedactionsUtils.ts index 8d4e5e0f..f88daf7a 100644 --- a/materials_ui/src/materials_components/CaseworkPdfRedactorWrapper/utils/saveRedactionsUtils.ts +++ b/materials_ui/src/materials_components/CaseworkPdfRedactorWrapper/utils/saveRedactionsUtils.ts @@ -10,12 +10,8 @@ export const saveRedactions = async (p: { redactions: TRedaction[]; }) => { const redactionsIndexedOnPageNumber: { [k: number]: TRedaction[] } = {}; - p.redactions.forEach( - (red) => (redactionsIndexedOnPageNumber[red.pageNumber] = []) - ); - p.redactions.forEach((red) => - redactionsIndexedOnPageNumber[red.pageNumber]!.push(red) - ); + p.redactions.forEach((red) => (redactionsIndexedOnPageNumber[red.pageNumber] = [])); + p.redactions.forEach((red) => redactionsIndexedOnPageNumber[red.pageNumber]!.push(red)); const payload = { redactions: Object.values(redactionsIndexedOnPageNumber).map((reds) => { const first = reds[0]!; @@ -26,13 +22,13 @@ export const saveRedactions = async (p: { width: first.pageWidth, redactionCoordinates: reds.map((red) => { return { x1: red.x1, y1: red.y1, x2: red.x2, y2: red.y2 }; - }) + }), }; - }) + }), }; const response = await p.axiosInstance.put( `/api/urns/${p.urn}/cases/${p.caseId}/documents/${p.parentId}/versions/${p.childId}/redact`, - payload + payload, ); return response.data; diff --git a/materials_ui/src/materials_components/CaseworkPdfRedactorWrapper/utils/saveRotationsUtils.ts b/materials_ui/src/materials_components/CaseworkPdfRedactorWrapper/utils/saveRotationsUtils.ts index 9c9be17b..c46de2e8 100644 --- a/materials_ui/src/materials_components/CaseworkPdfRedactorWrapper/utils/saveRotationsUtils.ts +++ b/materials_ui/src/materials_components/CaseworkPdfRedactorWrapper/utils/saveRotationsUtils.ts @@ -13,13 +13,13 @@ export const saveRotations = async (p: { documentModifications: p.rotations.map((rotation) => ({ pageIndex: rotation.pageNumber, operation: 'rotate', - arg: rotation.rotationDegrees - })) + arg: rotation.rotationDegrees, + })), }; const response = await p.axiosInstance.post( `/api/urns/${p.urn}/cases/${p.caseId}/documents/${p.parentId}/versions/${p.childId}/modify`, - payload + payload, ); return response.data; diff --git a/materials_ui/src/materials_components/DocumentSelectAccordion/DocumentSidebar.tsx b/materials_ui/src/materials_components/DocumentSelectAccordion/DocumentSidebar.tsx index 0235ad08..26d29972 100644 --- a/materials_ui/src/materials_components/DocumentSelectAccordion/DocumentSidebar.tsx +++ b/materials_ui/src/materials_components/DocumentSelectAccordion/DocumentSidebar.tsx @@ -21,10 +21,7 @@ export const DocumentSidebar = (p: { { mode: 'accordion' } | { mode: 'notes'; documentId: string } >({ mode: 'accordion' }); - useTriggerListener({ - triggerData: p.reloadTriggerData, - fn: () => documentList.load() - }); + useTriggerListener({ triggerData: p.reloadTriggerData, fn: () => documentList.load() }); const documentList = useGetDocumentList({ urn, caseId }); useEffect(() => { @@ -49,9 +46,7 @@ export const DocumentSidebar = (p: { openDocumentIds={p.openDocumentIds} onSetActiveDocumentIds={(docIds) => p.onSetDocumentOpenIds(docIds)} onDocumentClick={p.onDocumentClick} - onNotesClick={(docId: string) => - setStatus({ mode: 'notes', documentId: docId }) - } + onNotesClick={(docId: string) => setStatus({ mode: 'notes', documentId: docId })} ActionComponent={p.ActionComponent} />
diff --git a/materials_ui/src/materials_components/DocumentSelectAccordion/DocumentSidebarAccordion.tsx b/materials_ui/src/materials_components/DocumentSelectAccordion/DocumentSidebarAccordion.tsx index 88367763..f0690620 100644 --- a/materials_ui/src/materials_components/DocumentSelectAccordion/DocumentSidebarAccordion.tsx +++ b/materials_ui/src/materials_components/DocumentSelectAccordion/DocumentSidebarAccordion.tsx @@ -1,30 +1,28 @@ import React, { useEffect, useState } from 'react'; import { DocumentSidebarAccordionDocument, - DocumentSidebarAccordionNoDocumentsAvailable + DocumentSidebarAccordionNoDocumentsAvailable, } from './DocumentSidebarAccordionDocument'; import { DocumentSidebarWrapper } from './DocumentSidebarWrapper'; import { TDocument, TDocumentList } from './getters/getDocumentList'; import { GovUkAccordionOpenCloseLinkTemplate, GovUkAccordionSectionTemplate, - GovUkAccordionTemplate + GovUkAccordionTemplate, } from './templates/GovUkAccordion'; import { categoriseDocument } from './utils/categoriseDocument'; import { categoryDetails, - initDocsOnDocCategoryNamesMap + initDocsOnDocCategoryNamesMap, } from './utils/categoriseDocumentHelperUtils'; import { safeGetDocumentSidebarReadDocIdsFromLocalStorage, - safeSetDocumentSidebarReadDocIdsFromLocalStorage + safeSetDocumentSidebarReadDocIdsFromLocalStorage, } from './utils/DocumentSidebarLocalStorageUtils'; import { areSetsEqual } from './utils/generalUtils'; -const createOpenDocumentAccordionSectionKey = (p: { - caseId: number; - sectionTitle: string; -}) => `openDocumentAccordionSection-${p.caseId}-${p.sectionTitle}`; +const createOpenDocumentAccordionSectionKey = (p: { caseId: number; sectionTitle: string }) => + `openDocumentAccordionSection-${p.caseId}-${p.sectionTitle}`; export const DocumentSidebarAccordion = (p: { caseId: number; @@ -40,9 +38,7 @@ export const DocumentSidebarAccordion = (p: { }) => { const { caseId } = p; - const [openDocumentIds, setOpenDocumentIds] = useState( - p.openDocumentIds - ); + const [openDocumentIds, setOpenDocumentIds] = useState(p.openDocumentIds); const isNoChangeInActiveDocIds = () => areSetsEqual(new Set(openDocumentIds), new Set(p.openDocumentIds)); @@ -57,13 +53,11 @@ export const DocumentSidebarAccordion = (p: { }, [openDocumentIds]); const [readDocumentIds, setReadDocumentIds] = useState( - safeGetDocumentSidebarReadDocIdsFromLocalStorage(p.caseId) + safeGetDocumentSidebarReadDocIdsFromLocalStorage(p.caseId), ); useEffect(() => { - const newReadDocIds = [ - ...new Set([...readDocumentIds, ...p.openDocumentIds]) - ]; + const newReadDocIds = [...new Set([...readDocumentIds, ...p.openDocumentIds])]; safeSetDocumentSidebarReadDocIdsFromLocalStorage({ caseId, newReadDocIds }); }, [readDocumentIds]); @@ -77,13 +71,11 @@ export const DocumentSidebarAccordion = (p: { key: x.label, label: x.label, categoryName: x.categoryName, - documents: docsOnDocCategoryNames[x.categoryName] + documents: docsOnDocCategoryNames[x.categoryName], })); const [isExpandedController, setIsExpandedController] = useState(false); - const [isExpandedSectionsTracker, setIsExpandedSectionsTracker] = useState< - boolean[] - >([]); + const [isExpandedSectionsTracker, setIsExpandedSectionsTracker] = useState([]); useEffect(() => { if (isExpandedSectionsTracker.length === 0) return; const allSectionsExpanded = isExpandedSectionsTracker.every((x) => x); @@ -115,7 +107,7 @@ export const DocumentSidebarAccordion = (p: { }} localStorageKey={createOpenDocumentAccordionSectionKey({ caseId: p.caseId, - sectionTitle: item.label + sectionTitle: item.label, })} > {item.documents.length === 0 ? ( @@ -131,20 +123,13 @@ export const DocumentSidebarAccordion = (p: { readDocumentIds={readDocumentIds} onDocumentClick={() => { p.onDocumentClick?.(document.parentId); - setReadDocumentIds((docIds) => [ - ...new Set([...docIds, document.parentId]) - ]); - const docSet = new Set([ - ...openDocumentIds, - document.parentId - ]); + setReadDocumentIds((docIds) => [...new Set([...docIds, document.parentId])]); + const docSet = new Set([...openDocumentIds, document.parentId]); setOpenDocumentIds([...docSet]); }} onNotesClick={() => p.onNotesClick(document.parentId)} ActionComponent={ - p.ActionComponent ? ( - - ) : null + p.ActionComponent ? : null } urn={p.urn} caseId={p.caseId} diff --git a/materials_ui/src/materials_components/DocumentSelectAccordion/DocumentSidebarAccordionDocument.tsx b/materials_ui/src/materials_components/DocumentSelectAccordion/DocumentSidebarAccordionDocument.tsx index 42ee9d8c..e4d41f3d 100644 --- a/materials_ui/src/materials_components/DocumentSelectAccordion/DocumentSidebarAccordionDocument.tsx +++ b/materials_ui/src/materials_components/DocumentSelectAccordion/DocumentSidebarAccordionDocument.tsx @@ -3,12 +3,7 @@ import { DocumentSidebarTag } from './DocumentSidebarTag'; import { TDocument } from './getters/getDocumentList'; import { useGetDocumentNotes } from './getters/getDocumentNotes'; import './templates/GovUkAccordion.scss'; -import { - NOTES_ARIA_LABELS, - NOTES_STATUS, - NotesIcon, - NotesStatus -} from './templates/NotesIcon'; +import { NOTES_ARIA_LABELS, NOTES_STATUS, NotesIcon, NotesStatus } from './templates/NotesIcon'; import { formatShortDate } from './utils/dateUtils'; export const DocumentSidebarAccordionNoDocumentsAvailable = () => { @@ -18,7 +13,7 @@ export const DocumentSidebarAccordionNoDocumentsAvailable = () => { borderTop: 'solid 1px #b1b4b6', background: '#ffffff', height: '60px', - padding: '12px' + padding: '12px', }} > There are no documents available. @@ -36,7 +31,7 @@ const Tooltip = (p: { text: string }) => { padding: '8px 14px', borderRadius: '6px', whiteSpace: 'nowrap', - boxShadow: '0 2px 8px rgba(0, 0, 0, 0.2)' + boxShadow: '0 2px 8px rgba(0, 0, 0, 0.2)', }} > {p.text} @@ -48,7 +43,7 @@ const Tooltip = (p: { text: string }) => { height: '0', borderLeft: '6px solid transparent', borderRight: '6px solid transparent', - borderTop: '6px solid #3d3d3d' + borderTop: '6px solid #3d3d3d', }} />
@@ -72,7 +67,7 @@ export const DocumentSidebarAccordionDocument = (p: { urn: p.urn, caseId: p.caseId, documentId: p.document.parentId, - revalidateOnMount: false + revalidateOnMount: false, }); const tooltipText = (() => { @@ -82,9 +77,7 @@ export const DocumentSidebarAccordionDocument = (p: { const firstNote = documentNotes.data[0]; - return firstNote - ? `${firstNote.text} (+${documentNotes.data.length - 1} more)` - : ''; + return firstNote ? `${firstNote.text} (+${documentNotes.data.length - 1} more)` : ''; })(); return ( @@ -96,9 +89,7 @@ export const DocumentSidebarAccordionDocument = (p: { NewVersionTag={p.newVersionDocumentId === p.document.parentId} showLeftBorder={p.activeDocumentId === p.document.parentId} showRightBorder={p.openDocumentIds.includes(p.document.parentId)} - backgroundColor={ - p.readDocumentIds.includes(p.document.parentId) ? 'white' : 'blue' - } + backgroundColor={p.readDocumentIds.includes(p.document.parentId) ? 'white' : 'blue'} // backgroundColor="blue" notesStatus={(() => { if ( @@ -143,24 +134,11 @@ export const DocumentSidebarAccordionDocumentTemplate = (p: { className={`document-select-accordion-document ${p.backgroundColor === 'blue' ? 'bg-blue' : 'bg-white'} ${p.showLeftBorder ? 'show-left-border' : ''} ${p.showRightBorder ? 'show-right-border' : ''}`} >
-
+
- {p.ActiveDocumentTag && ( - - )} + {p.ActiveDocumentTag && } {p.NewTag && } {p.NewVersionTag && } {p.ReclassifiedTag && } @@ -195,7 +173,7 @@ export const DocumentSidebarAccordionDocumentTemplate = (p: { top: '0', left: '50%', transform: 'translate(-50%, -100%)', - zIndex: 850 + zIndex: 850, }} > diff --git a/materials_ui/src/materials_components/DocumentSelectAccordion/DocumentSidebarNotes.tsx b/materials_ui/src/materials_components/DocumentSelectAccordion/DocumentSidebarNotes.tsx index cdcb7278..3387f883 100644 --- a/materials_ui/src/materials_components/DocumentSelectAccordion/DocumentSidebarNotes.tsx +++ b/materials_ui/src/materials_components/DocumentSelectAccordion/DocumentSidebarNotes.tsx @@ -4,7 +4,7 @@ import { DocumentSidebarWrapper } from './DocumentSidebarWrapper'; import { useAxiosInstance } from './getters/getAxiosInstance'; import { postDocumentNotesFromAxiosInstance, - useGetDocumentNotes + useGetDocumentNotes, } from './getters/getDocumentNotes'; import { CloseIconButton } from './templates/CloseIconButton'; import { GovUkBanner } from './templates/GovUkBanner'; @@ -30,7 +30,7 @@ export const DocumentSidebarNotes = (p: { const documentNotes = useGetDocumentNotes({ urn: p.urn, caseId: p.caseId, - documentId: p.documentId + documentId: p.documentId, }); return ( @@ -39,12 +39,10 @@ export const DocumentSidebarNotes = (p: { style={{ borderBottom: 'solid 1px #b1b4b6', display: 'flex', - justifyContent: 'space-between' + justifyContent: 'space-between', }} > -
- Notes -
+
Notes
p.onBackButtonClick()} />
{savedSuccessfully && ( @@ -56,11 +54,7 @@ export const DocumentSidebarNotes = (p: { )}
-