From 4cd28138a74b58ad86f28a558687a8c531e63db1 Mon Sep 17 00:00:00 2001 From: Morten Stulen Date: Wed, 4 Oct 2023 16:01:33 +0200 Subject: [PATCH] Run prettier --- .eslintrc.json | 35 +- .github/dependabot.yml | 28 +- .github/workflows/alert-deploy.yml | 4 +- .github/workflows/auto-deployment.yml | 18 +- .github/workflows/build-push.yml | 93 +- .github/workflows/main.yml | 54 +- .github/workflows/manual-deployment.yml | 52 +- .github/workflows/preprod-alt.yml | 54 +- .github/workflows/preprod.yml | 70 +- .github/workflows/test.yml | 65 +- .nais/alerts-preprod.yml | 16 +- .nais/alerts.yml | 16 +- .nais/nais-preprod-alt.yml | 107 +- .nais/nais-preprod.yml | 106 +- .nais/nais.yml | 106 +- assets/locales/en/backend.json | 50 +- assets/locales/en/translation.json | 378 ++++--- assets/locales/nb/backend.json | 50 +- assets/locales/nb/translation.json | 376 ++++--- assets/locales/nn/backend.json | 50 +- assets/locales/nn/translation.json | 376 ++++--- auth/getTokenXToken.ts | 123 +-- auth/verifyIdPortenToken.ts | 78 +- components/AuthenticationProvider.tsx | 20 +- components/AutomatiskInnsending.tsx | 28 +- components/AxiosInterceptor.tsx | 62 +- components/EndreVedlegg.tsx | 205 ++-- components/ErrorMessageProvider.tsx | 91 +- components/FellesModal.tsx | 150 +-- components/Fil.tsx | 935 ++++++++---------- components/FilUploadIcon.tsx | 185 ++-- components/Filvelger.tsx | 194 ++-- components/Kvittering.tsx | 338 +++---- components/LagringsProsessProvider.tsx | 138 ++- components/LastOppVedlegg.tsx | 316 +++--- components/Layout.tsx | 20 +- components/OpprettAnnetVedlegg.tsx | 244 ++--- components/SideValideringProvider.tsx | 236 ++--- components/SkjemaNedlasting.tsx | 127 ++- components/SkjemaOpplasting.tsx | 143 ++- components/SoknadHeader.tsx | 67 +- components/SoknadModalProvider.tsx | 350 +++---- components/ValideringsRamme.tsx | 62 +- components/Vedlegg.tsx | 751 ++++++-------- components/VedleggRadio.tsx | 272 +++-- components/VedleggsListe.tsx | 494 ++++----- components/common/ButtonContainer.tsx | 24 +- components/common/LastNedKnapp.tsx | 44 +- components/common/Linje.tsx | 6 +- .../skjemaSpesifikt/KvitteringsTillegg.tsx | 37 +- components/textStyle.tsx | 31 +- cypress/e2e/accessibility/axeTest.cy.js | 60 +- cypress/e2e/unauthenticated.cy.js | 27 +- cypress/fixtures/file.json | 2 +- cypress/fixtures/form.json | 2 +- cypress/fixtures/user.json | 2 +- hooks/useErrorMessage.tsx | 113 ++- hooks/useSoknadLanguage.tsx | 45 +- hooks/useUser.tsx | 54 +- hooks/useValidation.tsx | 54 +- i18n.ts | 74 +- i18next.d.ts | 10 +- metrics.ts | 12 +- mocks/data/annetVedlegg.json | 32 +- mocks/data/fil.json | 14 +- mocks/data/filFeil.json | 8 +- mocks/data/filer.json | 54 +- mocks/data/kvittering.json | 34 +- .../soknad/dokumentinnsending-default.json | 184 ++-- mocks/data/soknad/ettersending-default.json | 148 +-- mocks/data/soknad/fyll-ut-default.json | 220 ++--- .../fyll-ut-uten-vedlegg-med-annet.json | 112 +-- .../fyll-ut-uten-vedlegg-uten-annet.json | 112 +-- mocks/data/soknad/index.js | 16 +- mocks/handlers.js | 34 +- mocks/handlers/endreSoknad.js | 9 +- mocks/handlers/endreVedlegg.js | 23 +- mocks/handlers/hentFiler.js | 9 +- mocks/handlers/hentSoknad.js | 17 +- mocks/handlers/opprettEttersending.js | 13 +- mocks/handlers/opprettFil.js | 12 +- mocks/handlers/opprettSoknad.js | 14 +- mocks/handlers/opprettVedlegg.js | 11 +- mocks/handlers/sendInn.js | 12 +- mocks/handlers/slettFil.js | 19 +- mocks/handlers/slettVedlegg.js | 23 +- mocks/index.js | 12 +- mocks/utils/importJSON.js | 10 +- next.config.js | 103 +- package.json | 5 +- pages/404.tsx | 128 ++- pages/500.tsx | 128 ++- pages/[innsendingsId].tsx | 94 +- pages/_app.tsx | 70 +- pages/_document.tsx | 124 +-- pages/_error.js | 18 +- pages/api/backend/[[...all]].ts | 235 ++--- pages/api/internal/prometheus.ts | 9 +- pages/api/isAlive.ts | 7 +- pages/api/isReady.ts | 7 +- pages/api/mock/frontend/v1/soknad.ts | 63 +- pages/api/user.ts | 50 +- pages/dev/index.tsx | 185 ++-- pages/feilside/soknad-sendt-inn.tsx | 124 +-- pages/opprettSoknadResource.tsx | 110 +-- sentry.client.config.js | 21 +- sentry.server.config.js | 21 +- tsconfig.json | 17 +- types/enums.tsx | 16 +- types/types.tsx | 111 +-- utils/backendLogger.ts | 34 +- utils/dato.ts | 10 +- utils/fetchJson.ts | 77 +- utils/navigerTilMinSide.ts | 4 +- 114 files changed, 5128 insertions(+), 6125 deletions(-) diff --git a/.eslintrc.json b/.eslintrc.json index 96a993c0..76afe43d 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -1,20 +1,17 @@ { - "root": true, - "parser": "@typescript-eslint/parser", - "plugins": ["@typescript-eslint"], - "extends": [ - "eslint:recommended", - "plugin:@typescript-eslint/eslint-recommended", - "plugin:@typescript-eslint/recommended", - "next/core-web-vitals", - "prettier", - "plugin:cypress/recommended" - ], - "rules": { - "@typescript-eslint/no-unused-vars": [ - "warn", - { "ignoreRestSiblings": true } - ], - "cypress/no-unnecessary-waiting": "warn" - } - } + "root": true, + "parser": "@typescript-eslint/parser", + "plugins": ["@typescript-eslint"], + "extends": [ + "eslint:recommended", + "plugin:@typescript-eslint/eslint-recommended", + "plugin:@typescript-eslint/recommended", + "next/core-web-vitals", + "prettier", + "plugin:cypress/recommended" + ], + "rules": { + "@typescript-eslint/no-unused-vars": ["warn", { "ignoreRestSiblings": true }], + "cypress/no-unnecessary-waiting": "warn" + } +} diff --git a/.github/dependabot.yml b/.github/dependabot.yml index df83e8e7..56133fc5 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -1,28 +1,28 @@ version: 2 updates: - - package-ecosystem: "npm" - directory: "/" + - package-ecosystem: 'npm' + directory: '/' schedule: - interval: "monthly" + interval: 'monthly' open-pull-requests-limit: 20 groups: all-minor-patch: patterns: - - "*" + - '*' update-types: - - "minor" - - "patch" + - 'minor' + - 'patch' - - package-ecosystem: "github-actions" - directory: "/" + - package-ecosystem: 'github-actions' + directory: '/' schedule: - interval: "monthly" + interval: 'monthly' groups: all: patterns: - - "*" - - - package-ecosystem: "docker" - directory: "/" + - '*' + + - package-ecosystem: 'docker' + directory: '/' schedule: - interval: "monthly" + interval: 'monthly' diff --git a/.github/workflows/alert-deploy.yml b/.github/workflows/alert-deploy.yml index 0f1458f2..c7f52fea 100644 --- a/.github/workflows/alert-deploy.yml +++ b/.github/workflows/alert-deploy.yml @@ -17,7 +17,7 @@ on: paths: - '.nais/alerts.yml' - '.github/workflows/alert-deploy.yml' - + jobs: apply-alerts-prod: name: Apply alerts to prod @@ -45,4 +45,4 @@ jobs: env: APIKEY: ${{ secrets.NAIS_DEPLOY_APIKEY }} CLUSTER: dev-gcp - RESOURCE: .nais/alerts-preprod.yml \ No newline at end of file + RESOURCE: .nais/alerts-preprod.yml diff --git a/.github/workflows/auto-deployment.yml b/.github/workflows/auto-deployment.yml index b08bd08c..05a0cde1 100644 --- a/.github/workflows/auto-deployment.yml +++ b/.github/workflows/auto-deployment.yml @@ -1,14 +1,14 @@ name: Autodeployment run-name: Autodeploy til prod (hver mandag) on: - schedule: - - cron: '0 08 * * 1' # kl 09 hver mandag + schedule: + - cron: '0 08 * * 1' # kl 09 hver mandag jobs: - build-push-deploy-main: - uses: ./.github/workflows/main.yml - secrets: inherit - permissions: - contents: "read" - id-token: "write" - packages: "read" \ No newline at end of file + build-push-deploy-main: + uses: ./.github/workflows/main.yml + secrets: inherit + permissions: + contents: 'read' + id-token: 'write' + packages: 'read' diff --git a/.github/workflows/build-push.yml b/.github/workflows/build-push.yml index 4b4a9505..76cd58f4 100644 --- a/.github/workflows/build-push.yml +++ b/.github/workflows/build-push.yml @@ -1,51 +1,48 @@ name: Build and push Docker container -on: - workflow_call: - outputs: - image: - description: "The docker image" - value: ${{ jobs.build-and-push.outputs.image }} - inputs: - environment: - required: true - type: string +on: + workflow_call: + outputs: + image: + description: 'The docker image' + value: ${{ jobs.build-and-push.outputs.image }} + inputs: + environment: + required: true + type: string jobs: - build-and-push: - name: Build and push Docker container - runs-on: ubuntu-latest - permissions: - contents: "read" - id-token: "write" - packages: "read" - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v3 - with: - node-version: '20.8.0' - registry-url: https://npm.pkg.github.com - scope: "@navikt" - cache: "npm" - - name: Install dependencies - run: npm ci - env: - NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - name: Set environment variables - run: cp environments/${{ inputs.environment }}.env .env - - name: Build - env: - SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }} - run: npm run build - - name: Build and push Docker image - uses: nais/docker-build-push@v0 - id: docker-build-push - with: - team: team-soknad - identity_provider: ${{ secrets.NAIS_WORKLOAD_IDENTITY_PROVIDER }} - project_id: ${{ vars.NAIS_MANAGEMENT_PROJECT_ID }} - image_suffix: ${{ inputs.environment }} - outputs: - image: ${{ steps.docker-build-push.outputs.image }} - - - + build-and-push: + name: Build and push Docker container + runs-on: ubuntu-latest + permissions: + contents: 'read' + id-token: 'write' + packages: 'read' + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v3 + with: + node-version: '20.8.0' + registry-url: https://npm.pkg.github.com + scope: '@navikt' + cache: 'npm' + - name: Install dependencies + run: npm ci + env: + NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + - name: Set environment variables + run: cp environments/${{ inputs.environment }}.env .env + - name: Build + env: + SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }} + run: npm run build + - name: Build and push Docker image + uses: nais/docker-build-push@v0 + id: docker-build-push + with: + team: team-soknad + identity_provider: ${{ secrets.NAIS_WORKLOAD_IDENTITY_PROVIDER }} + project_id: ${{ vars.NAIS_MANAGEMENT_PROJECT_ID }} + image_suffix: ${{ inputs.environment }} + outputs: + image: ${{ steps.docker-build-push.outputs.image }} diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 953be7e5..4361b356 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -9,32 +9,32 @@ on: workflow_call: jobs: - build-and-test: - name: Test frontend - uses: ./.github/workflows/test.yml + build-and-test: + name: Test frontend + uses: ./.github/workflows/test.yml - build-and-push: - name: Build and push Docker container for prod - uses: ./.github/workflows/build-push.yml - with: - environment: prod - secrets: inherit - permissions: - contents: "read" - id-token: "write" - packages: "read" + build-and-push: + name: Build and push Docker container for prod + uses: ./.github/workflows/build-push.yml + with: + environment: prod + secrets: inherit + permissions: + contents: 'read' + id-token: 'write' + packages: 'read' - deploy-prod: - name: Deploy to prod - needs: [build-and-test, build-and-push] - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: nais/deploy/actions/deploy@v1 - env: - APIKEY: ${{ secrets.NAIS_DEPLOY_APIKEY }} - DRY_RUN: false - PRINT_PAYLOAD: true - CLUSTER: prod-gcp - RESOURCE: .nais/nais.yml - VAR: app_version=${{ github.sha }},image=${{ needs.build-and-push.outputs.image }} + deploy-prod: + name: Deploy to prod + needs: [build-and-test, build-and-push] + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: nais/deploy/actions/deploy@v1 + env: + APIKEY: ${{ secrets.NAIS_DEPLOY_APIKEY }} + DRY_RUN: false + PRINT_PAYLOAD: true + CLUSTER: prod-gcp + RESOURCE: .nais/nais.yml + VAR: app_version=${{ github.sha }},image=${{ needs.build-and-push.outputs.image }} diff --git a/.github/workflows/manual-deployment.yml b/.github/workflows/manual-deployment.yml index 445d87fe..45e26b2f 100644 --- a/.github/workflows/manual-deployment.yml +++ b/.github/workflows/manual-deployment.yml @@ -1,34 +1,34 @@ name: Manually triggered deployment run-name: Manual deploy to ${{ inputs.environment }} [${{ github.ref_name }}] on: - workflow_dispatch: - inputs: - environment: - description: 'Environment to deploy' - required: true - default: 'preprod' - type: choice - options: - - preprod - - preprod-alt - - prod + workflow_dispatch: + inputs: + environment: + description: 'Environment to deploy' + required: true + default: 'preprod' + type: choice + options: + - preprod + - preprod-alt + - prod permissions: - contents: "read" - id-token: "write" - packages: "read" + contents: 'read' + id-token: 'write' + packages: 'read' jobs: - preprod: - if: inputs.environment == 'preprod' - uses: ./.github/workflows/preprod.yml - secrets: inherit + preprod: + if: inputs.environment == 'preprod' + uses: ./.github/workflows/preprod.yml + secrets: inherit - preprod-alt: - if: inputs.environment == 'preprod-alt' - uses: ./.github/workflows/preprod-alt.yml - secrets: inherit + preprod-alt: + if: inputs.environment == 'preprod-alt' + uses: ./.github/workflows/preprod-alt.yml + secrets: inherit - prod: - if: inputs.environment == 'prod' - uses: ./.github/workflows/main.yml - secrets: inherit + prod: + if: inputs.environment == 'prod' + uses: ./.github/workflows/main.yml + secrets: inherit diff --git a/.github/workflows/preprod-alt.yml b/.github/workflows/preprod-alt.yml index 734bd1eb..e0116fe0 100644 --- a/.github/workflows/preprod-alt.yml +++ b/.github/workflows/preprod-alt.yml @@ -2,32 +2,32 @@ name: Build, push, and deploy (preprod-alt) on: workflow_call jobs: - build-and-test: - name: Test frontend - uses: ./.github/workflows/test.yml + build-and-test: + name: Test frontend + uses: ./.github/workflows/test.yml - build-and-push: - name: Build and push Docker container for preprod - uses: ./.github/workflows/build-push.yml - with: - environment: preprod-alt - secrets: inherit - permissions: - contents: "read" - id-token: "write" - packages: "read" + build-and-push: + name: Build and push Docker container for preprod + uses: ./.github/workflows/build-push.yml + with: + environment: preprod-alt + secrets: inherit + permissions: + contents: 'read' + id-token: 'write' + packages: 'read' - deploy-preprod: - name: Deploy to preprod-alt - needs: [build-and-test, build-and-push] - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: nais/deploy/actions/deploy@v1 - env: - APIKEY: ${{ secrets.NAIS_DEPLOY_APIKEY }} - DRY_RUN: false - PRINT_PAYLOAD: true - CLUSTER: dev-gcp - RESOURCE: .nais/nais-preprod-alt.yml - VAR: app_version=${{ github.sha }},image=${{ needs.build-and-push.outputs.image }} + deploy-preprod: + name: Deploy to preprod-alt + needs: [build-and-test, build-and-push] + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: nais/deploy/actions/deploy@v1 + env: + APIKEY: ${{ secrets.NAIS_DEPLOY_APIKEY }} + DRY_RUN: false + PRINT_PAYLOAD: true + CLUSTER: dev-gcp + RESOURCE: .nais/nais-preprod-alt.yml + VAR: app_version=${{ github.sha }},image=${{ needs.build-and-push.outputs.image }} diff --git a/.github/workflows/preprod.yml b/.github/workflows/preprod.yml index 350428bc..fda8ab90 100644 --- a/.github/workflows/preprod.yml +++ b/.github/workflows/preprod.yml @@ -1,42 +1,40 @@ name: Build, push, and deploy (preprod) on: - push: - branches: - - 'main' - paths-ignore: - - '**.md' - - '**/**.md' - workflow_call: + push: + branches: + - 'main' + paths-ignore: + - '**.md' + - '**/**.md' + workflow_call: jobs: - build-and-test: - name: Test frontend - uses: ./.github/workflows/test.yml - - build-and-push: - name: Build and push Docker container for preprod - uses: ./.github/workflows/build-push.yml - with: - environment: preprod - secrets: inherit - permissions: - contents: "read" - id-token: "write" - packages: "read" - - deploy-preprod: - name: Deploy to preprod - needs: [build-and-test, build-and-push] - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: nais/deploy/actions/deploy@v1 - env: - APIKEY: ${{ secrets.NAIS_DEPLOY_APIKEY }} - DRY_RUN: false - PRINT_PAYLOAD: true - CLUSTER: dev-gcp - RESOURCE: .nais/nais-preprod.yml - VAR: app_version=${{ github.sha }},image=${{ needs.build-and-push.outputs.image }} + build-and-test: + name: Test frontend + uses: ./.github/workflows/test.yml + build-and-push: + name: Build and push Docker container for preprod + uses: ./.github/workflows/build-push.yml + with: + environment: preprod + secrets: inherit + permissions: + contents: 'read' + id-token: 'write' + packages: 'read' + deploy-preprod: + name: Deploy to preprod + needs: [build-and-test, build-and-push] + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: nais/deploy/actions/deploy@v1 + env: + APIKEY: ${{ secrets.NAIS_DEPLOY_APIKEY }} + DRY_RUN: false + PRINT_PAYLOAD: true + CLUSTER: dev-gcp + RESOURCE: .nais/nais-preprod.yml + VAR: app_version=${{ github.sha }},image=${{ needs.build-and-push.outputs.image }} diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 2dc6051c..c08df966 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -1,40 +1,37 @@ name: Build and test run-name: Build and test from trigger ${{ github.event_name }} on: [workflow_call, push, pull_request] - + env: - CI: true - TZ: Europe/Oslo + CI: true + TZ: Europe/Oslo jobs: - build-and-test: - name: Build and Test - runs-on: ubuntu-latest - permissions: - contents: "read" - packages: "read" - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v3 - with: - node-version: '20.8.0' - cache: 'npm' - registry-url: 'https://npm.pkg.github.com' - scope: '@navikt' - - name: Install dependencies - run: npm ci - env: - NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - name: Build with mock - run: npm run build:mock - - uses: cypress-io/github-action@v6.5.0 - with: - install: false - spec: cypress/e2e/*.cy.js - start: npm run start:with:test - wait-on: 'http://localhost:3100/sendinn/api/isAlive' - config: video=false - config-file: cypress.config.ts - - - + build-and-test: + name: Build and Test + runs-on: ubuntu-latest + permissions: + contents: 'read' + packages: 'read' + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v3 + with: + node-version: '20.8.0' + cache: 'npm' + registry-url: 'https://npm.pkg.github.com' + scope: '@navikt' + - name: Install dependencies + run: npm ci + env: + NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + - name: Build with mock + run: npm run build:mock + - uses: cypress-io/github-action@v6.5.0 + with: + install: false + spec: cypress/e2e/*.cy.js + start: npm run start:with:test + wait-on: 'http://localhost:3100/sendinn/api/isAlive' + config: video=false + config-file: cypress.config.ts diff --git a/.nais/alerts-preprod.yml b/.nais/alerts-preprod.yml index 593dd235..6c7f9558 100644 --- a/.nais/alerts-preprod.yml +++ b/.nais/alerts-preprod.yml @@ -1,4 +1,4 @@ -apiVersion: "monitoring.coreos.com/v1" +apiVersion: 'monitoring.coreos.com/v1' kind: PrometheusRule metadata: name: alert-send-inn-frontend @@ -14,13 +14,13 @@ spec: expr: (100 * sum by (app, namespace) (rate(log_messages_errors{app="send-inn-frontend",level="Error"}[3m])) / sum by (app, namespace) (rate(log_messages_total{app="send-inn-frontend"}[3m]))) > 10 for: 3m annotations: - title: "Høy feilrate i logger" - consequence: "Det kan være mange forskjellige årsaker til feilmeldingene. Se i loggene og undersøk hvorfor det er flere feilmeldinger enn normalt." + title: 'Høy feilrate i logger' + consequence: 'Det kan være mange forskjellige årsaker til feilmeldingene. Se i loggene og undersøk hvorfor det er flere feilmeldinger enn normalt.' action: https://logs.adeo.no/app/discover#/view/68589dd0-0e73-11ee-b29f-0f158c56b75a labels: service: send-inn-frontend namespace: fyllut-sendinn - special_type_to_use_in_alertmanager_config: "fyllut-sendinn-alerts-dev" + special_type_to_use_in_alertmanager_config: 'fyllut-sendinn-alerts-dev' alert_type: custom severity: warning @@ -28,13 +28,13 @@ spec: expr: kube_deployment_status_replicas_available{deployment="send-inn-frontend"} == 0 for: 1m annotations: - title: "send-inn-frontend er nede" - consequence: "Tjenesten er utilgjengelig. Undersøk hvorfor poddene er nede." + title: 'send-inn-frontend er nede' + consequence: 'Tjenesten er utilgjengelig. Undersøk hvorfor poddene er nede.' action: https://logs.adeo.no/app/discover#/view/68589dd0-0e73-11ee-b29f-0f158c56b75a sla: respond within 1h, during office hours labels: service: send-inn-frontend namespace: fyllut-sendinn - special_type_to_use_in_alertmanager_config: "fyllut-sendinn-alerts-dev" + special_type_to_use_in_alertmanager_config: 'fyllut-sendinn-alerts-dev' alert_type: custom - severity: critical \ No newline at end of file + severity: critical diff --git a/.nais/alerts.yml b/.nais/alerts.yml index 08695fcc..f2e34535 100644 --- a/.nais/alerts.yml +++ b/.nais/alerts.yml @@ -1,4 +1,4 @@ -apiVersion: "monitoring.coreos.com/v1" +apiVersion: 'monitoring.coreos.com/v1' kind: PrometheusRule metadata: name: alert-send-inn-frontend @@ -14,13 +14,13 @@ spec: expr: (100 * sum by (app, namespace) (rate(log_messages_errors{app="send-inn-frontend",level="Error"}[3m])) / sum by (app, namespace) (rate(log_messages_total{app="send-inn-frontend"}[3m]))) > 10 for: 3m annotations: - title: "Høy feilrate i logger" - consequence: "Det kan være mange forskjellige årsaker til feilmeldingene. Se i loggene og undersøk hvorfor det er flere feilmeldinger enn normalt." + title: 'Høy feilrate i logger' + consequence: 'Det kan være mange forskjellige årsaker til feilmeldingene. Se i loggene og undersøk hvorfor det er flere feilmeldinger enn normalt.' action: https://logs.adeo.no/app/discover#/view/332450f0-0e73-11ee-b29f-0f158c56b75a labels: service: send-inn-frontend namespace: fyllut-sendinn - special_type_to_use_in_alertmanager_config: "fyllut-sendinn-alerts" + special_type_to_use_in_alertmanager_config: 'fyllut-sendinn-alerts' alert_type: custom severity: warning @@ -28,13 +28,13 @@ spec: expr: kube_deployment_status_replicas_available{deployment="send-inn-frontend"} == 0 for: 1m annotations: - title: "send-inn-frontend er nede" - consequence: "Tjenesten er utilgjengelig. Undersøk hvorfor poddene er nede." + title: 'send-inn-frontend er nede' + consequence: 'Tjenesten er utilgjengelig. Undersøk hvorfor poddene er nede.' action: https://logs.adeo.no/app/discover#/view/332450f0-0e73-11ee-b29f-0f158c56b75a sla: respond within 1h, during office hours labels: service: send-inn-frontend namespace: fyllut-sendinn - special_type_to_use_in_alertmanager_config: "fyllut-sendinn-alerts" + special_type_to_use_in_alertmanager_config: 'fyllut-sendinn-alerts' alert_type: custom - severity: critical \ No newline at end of file + severity: critical diff --git a/.nais/nais-preprod-alt.yml b/.nais/nais-preprod-alt.yml index 3fa02c72..d8c7ccc0 100644 --- a/.nais/nais-preprod-alt.yml +++ b/.nais/nais-preprod-alt.yml @@ -1,58 +1,57 @@ apiVersion: 'nais.io/v1alpha1' kind: 'Application' metadata: - name: send-inn-frontend-alt - namespace: team-soknad - labels: - team: team-soknad - annotations: - nginx.ingress.kubernetes.io/proxy-body-size: "50M" - nginx.ingress.kubernetes.io/proxy-read-timeout: "300" + name: send-inn-frontend-alt + namespace: team-soknad + labels: + team: team-soknad + annotations: + nginx.ingress.kubernetes.io/proxy-body-size: '50M' + nginx.ingress.kubernetes.io/proxy-read-timeout: '300' spec: - image: '{{ image }}' - port: 3100 - liveness: - path: /sendinn-alt/api/isAlive - initialDelay: 20 - timeout: 10 - periodSeconds: 5 - failureThreshold: 10 - readiness: - path: /sendinn-alt/api/isReady - initialDelay: 20 - timeout: 10 - replicas: - min: 1 - max: 2 - cpuThresholdPercentage: 50 - prometheus: - enabled: true - path: /sendinn-alt/api/internal/prometheus - resources: - limits: - memory: 786Mi - requests: - memory: 512Mi - idporten: - enabled: true - sidecar: - enabled: true - level: Level4 - tokenx: - enabled: true - accessPolicy: - outbound: - rules: - - application: innsending-api - - application: nav-dekoratoren - namespace: personbruker - ingresses: - - 'https://www.intern.dev.nav.no/sendinn-alt' - env: - - name: APP_VERSION - value: {{ app_version }} - - name: INNSENDING_API_AUDIENCE - value: "dev-gcp:team-soknad:innsending-api" - - name: REMOTE_API_URL - value: "http://innsending-api" - + image: '{{ image }}' + port: 3100 + liveness: + path: /sendinn-alt/api/isAlive + initialDelay: 20 + timeout: 10 + periodSeconds: 5 + failureThreshold: 10 + readiness: + path: /sendinn-alt/api/isReady + initialDelay: 20 + timeout: 10 + replicas: + min: 1 + max: 2 + cpuThresholdPercentage: 50 + prometheus: + enabled: true + path: /sendinn-alt/api/internal/prometheus + resources: + limits: + memory: 786Mi + requests: + memory: 512Mi + idporten: + enabled: true + sidecar: + enabled: true + level: Level4 + tokenx: + enabled: true + accessPolicy: + outbound: + rules: + - application: innsending-api + - application: nav-dekoratoren + namespace: personbruker + ingresses: + - 'https://www.intern.dev.nav.no/sendinn-alt' + env: + - name: APP_VERSION + value: { { app_version } } + - name: INNSENDING_API_AUDIENCE + value: 'dev-gcp:team-soknad:innsending-api' + - name: REMOTE_API_URL + value: 'http://innsending-api' diff --git a/.nais/nais-preprod.yml b/.nais/nais-preprod.yml index 5f6d6d24..bbd3f209 100644 --- a/.nais/nais-preprod.yml +++ b/.nais/nais-preprod.yml @@ -1,57 +1,57 @@ apiVersion: 'nais.io/v1alpha1' kind: 'Application' metadata: - name: send-inn-frontend - namespace: team-soknad - labels: - team: team-soknad - annotations: - nginx.ingress.kubernetes.io/proxy-body-size: "50M" - nginx.ingress.kubernetes.io/proxy-read-timeout: "300" + name: send-inn-frontend + namespace: team-soknad + labels: + team: team-soknad + annotations: + nginx.ingress.kubernetes.io/proxy-body-size: '50M' + nginx.ingress.kubernetes.io/proxy-read-timeout: '300' spec: - image: '{{ image }}' - port: 3100 - liveness: - path: /sendinn/api/isAlive - initialDelay: 20 - timeout: 10 - periodSeconds: 5 - failureThreshold: 10 - readiness: - path: /sendinn/api/isReady - initialDelay: 20 - timeout: 10 - replicas: - min: 1 - max: 2 - cpuThresholdPercentage: 50 - prometheus: - enabled: true - path: /sendinn/api/internal/prometheus - resources: - limits: - memory: 786Mi - requests: - memory: 512Mi - idporten: - enabled: true - sidecar: - enabled: true - level: Level4 - tokenx: - enabled: true - accessPolicy: - outbound: - rules: - - application: innsending-api - - application: nav-dekoratoren - namespace: personbruker - ingresses: - - 'https://www.intern.dev.nav.no/sendinn' - env: - - name: APP_VERSION - value: {{ app_version }} - - name: INNSENDING_API_AUDIENCE - value: "dev-gcp:team-soknad:innsending-api" - - name: REMOTE_API_URL - value: "http://innsending-api" + image: '{{ image }}' + port: 3100 + liveness: + path: /sendinn/api/isAlive + initialDelay: 20 + timeout: 10 + periodSeconds: 5 + failureThreshold: 10 + readiness: + path: /sendinn/api/isReady + initialDelay: 20 + timeout: 10 + replicas: + min: 1 + max: 2 + cpuThresholdPercentage: 50 + prometheus: + enabled: true + path: /sendinn/api/internal/prometheus + resources: + limits: + memory: 786Mi + requests: + memory: 512Mi + idporten: + enabled: true + sidecar: + enabled: true + level: Level4 + tokenx: + enabled: true + accessPolicy: + outbound: + rules: + - application: innsending-api + - application: nav-dekoratoren + namespace: personbruker + ingresses: + - 'https://www.intern.dev.nav.no/sendinn' + env: + - name: APP_VERSION + value: { { app_version } } + - name: INNSENDING_API_AUDIENCE + value: 'dev-gcp:team-soknad:innsending-api' + - name: REMOTE_API_URL + value: 'http://innsending-api' diff --git a/.nais/nais.yml b/.nais/nais.yml index 96f54e3a..45b31464 100644 --- a/.nais/nais.yml +++ b/.nais/nais.yml @@ -1,57 +1,57 @@ apiVersion: 'nais.io/v1alpha1' kind: 'Application' metadata: - name: send-inn-frontend - namespace: team-soknad - labels: - team: team-soknad - annotations: - nginx.ingress.kubernetes.io/proxy-body-size: "50M" - nginx.ingress.kubernetes.io/proxy-read-timeout: "300" + name: send-inn-frontend + namespace: team-soknad + labels: + team: team-soknad + annotations: + nginx.ingress.kubernetes.io/proxy-body-size: '50M' + nginx.ingress.kubernetes.io/proxy-read-timeout: '300' spec: - image: "{{ image }}" - port: 3100 - liveness: - path: /sendinn/api/isAlive - initialDelay: 20 - timeout: 10 - periodSeconds: 5 - failureThreshold: 10 - readiness: - path: /sendinn/api/isReady - initialDelay: 20 - timeout: 10 - replicas: - min: 2 - max: 6 - cpuThresholdPercentage: 50 - prometheus: - enabled: true - path: /sendinn/api/internal/prometheus - resources: - limits: - memory: 786Mi - requests: - memory: 512Mi - idporten: - enabled: true - sidecar: - enabled: true - level: Level4 - tokenx: - enabled: true - accessPolicy: - outbound: - rules: - - application: innsending-api - - application: nav-dekoratoren - namespace: personbruker - ingresses: - - "https://www.nav.no/sendinn" - env: - - name: APP_VERSION - value: {{ app_version }} - - name: INNSENDING_API_AUDIENCE - value: "prod-gcp:team-soknad:innsending-api" - - name: REMOTE_API_URL - value: "http://innsending-api" + image: '{{ image }}' + port: 3100 + liveness: + path: /sendinn/api/isAlive + initialDelay: 20 + timeout: 10 + periodSeconds: 5 + failureThreshold: 10 + readiness: + path: /sendinn/api/isReady + initialDelay: 20 + timeout: 10 + replicas: + min: 2 + max: 6 + cpuThresholdPercentage: 50 + prometheus: + enabled: true + path: /sendinn/api/internal/prometheus + resources: + limits: + memory: 786Mi + requests: + memory: 512Mi + idporten: + enabled: true + sidecar: + enabled: true + level: Level4 + tokenx: + enabled: true + accessPolicy: + outbound: + rules: + - application: innsending-api + - application: nav-dekoratoren + namespace: personbruker + ingresses: + - 'https://www.nav.no/sendinn' + env: + - name: APP_VERSION + value: { { app_version } } + - name: INNSENDING_API_AUDIENCE + value: 'prod-gcp:team-soknad:innsending-api' + - name: REMOTE_API_URL + value: 'http://innsending-api' diff --git a/assets/locales/en/backend.json b/assets/locales/en/backend.json index 4362e785..4e7bb531 100644 --- a/assets/locales/en/backend.json +++ b/assets/locales/en/backend.json @@ -1,27 +1,27 @@ { - "illegalAction.applicationSentInOrDeleted": { - "message": "The application cannot be displayed or changed because it has been deleted or submitted to NAV" - }, - "illegalAction.fileCannotBeRead": { - "message": "File upload failed because the file cannot be read. Check that it is not encrypted or password protected and try again" - }, - "illegalAction.sendInErrorNoApplication": { - "message": "Submission failed because no application document has been uploaded" - }, - "illegalAction.sendInErrorNoChange": { - "message": "You must upload at least one new attachment that you want to send to NAV.", - "title": "You have not uploaded any new attachments" - }, - "illegalAction.notSupportedFileFormat": { - "message": "Wrong file format. It is only allowed to upload files of type PDF, JPEG/JPG and PNG" - }, - "illegalAction.fileSizeSumTooLarge": { - "message": "The sum of the size of uploaded files for the entire application exceeds the maximum allowed size. The maximum size allowed is 150MB in total." - }, - "illegalAction.vedleggFileSizeSumTooLarge": { - "message": "The sum of the size of uploaded files for this attachment exceeds the maximum allowed size. The maximum size allowed is 50MB in total." - }, - "illegalAction.virusScanFailed": { - "message": "The uploaded file contains a virus. Try again with another file" - } + "illegalAction.applicationSentInOrDeleted": { + "message": "The application cannot be displayed or changed because it has been deleted or submitted to NAV" + }, + "illegalAction.fileCannotBeRead": { + "message": "File upload failed because the file cannot be read. Check that it is not encrypted or password protected and try again" + }, + "illegalAction.sendInErrorNoApplication": { + "message": "Submission failed because no application document has been uploaded" + }, + "illegalAction.sendInErrorNoChange": { + "message": "You must upload at least one new attachment that you want to send to NAV.", + "title": "You have not uploaded any new attachments" + }, + "illegalAction.notSupportedFileFormat": { + "message": "Wrong file format. It is only allowed to upload files of type PDF, JPEG/JPG and PNG" + }, + "illegalAction.fileSizeSumTooLarge": { + "message": "The sum of the size of uploaded files for the entire application exceeds the maximum allowed size. The maximum size allowed is 150MB in total." + }, + "illegalAction.vedleggFileSizeSumTooLarge": { + "message": "The sum of the size of uploaded files for this attachment exceeds the maximum allowed size. The maximum size allowed is 50MB in total." + }, + "illegalAction.virusScanFailed": { + "message": "The uploaded file contains a virus. Try again with another file" + } } diff --git a/assets/locales/en/translation.json b/assets/locales/en/translation.json index db38eeed..cdbf5dba 100644 --- a/assets/locales/en/translation.json +++ b/assets/locales/en/translation.json @@ -1,202 +1,198 @@ { - "test": "this is english", - "soknad": { - "visningsSteg": { - "fraFyllutUtenVedlegg": { - "laster": "Loading... Please wait" - }, - "steg0": { - "tittel": "Download and fill in the form" - }, - "steg1": { - "tittel": "Upload the completed form" - }, - "lastOppVedlegg": { - "tittel": "Upload attachments", - "ingress": "You can upload attachments to your case here. You must upload all the attachments before NAV can process the case.", - "infoFrist": "Deadline for uploading attachments: {{dato}}", - "advarselHovedskjema": "UTGÅR!! Du får ikke sendt inn før du har lastet opp ferdig utfylt skjema på forrige side." - } - }, - "skjemaNedlasting": { - "listeTittel": "Instructions:", - "liste": [ - "Click “Download form”.", - "Open and fill in the downloaded pdf form.", - "Save the form on your device after filling it out.", - "Click “Next step”." - ], - "lastNedKnapp": "Download form" - }, - "hovedSkjema": { - "listeTittel": "Instructions:", - "liste": [ - "Click “Upload completed form”.", - "Find and upload the completed form.", - "Click “Next step”.", - "You can upload any attachments in the next step." - ], - "filvelgerKnapp": "Upload completed form", - "feilmelding": { - "manglerFil": "Upload completed form: {{label}}" - } - }, - "vedlegg": { - "tidligereSendtInn": "Previously submitted documents:", - "sendtInnNaa": "Documents you have uploaded now:", - "mottatt": "Recieved", - "ettersendingFilvelgerKnapp": "Upload new files", - "feilmelding": { - "manglerFil": "Upload {{label}}" - }, - "annet": { - "tittel": "Describe the document", - "beskrivelse": "Give a descriptive name to the document you wish to upload.", - "rediger": "Edit", - "slett": "Delete attachment", - "bekreft": "Confirm", - "avbryt": "Cancel", - "feilmelding": { - "fullforOpprettelse": "Complete or cancel attachment description", - "fullforRedigering": "Complete and confirm the attachment description", - "manglerFil": "Upload or delete attachment: {{label}}", - "manglerNavn": "Describe the attachment", - "navnForLangt": "The attachment description is too long. Max {{maxLength}} characters." - } - }, - "radio": { - "tittel": "Select submission", - "lasterOppNaa": "I will upload this now", - "sendSenere": "I will upload this later", - "sendesAvAndre": "Will be submitted by others (e.g. doctor, employer)" - }, - "fil": { - "provIgjen": "Try again", - "avbryt": "Cancel", - "slett": "Remove", - "progress": "Progress", - "alt": { - "opplastet": "Successfully uploaded “{{filnavn}}”", - "tidligereLastetOpp": "Previously submitted “{{filnavn}}”", - "lasterOpp": "Uploading “{{filnavn}}”", - "feil": "Error while uploading “{{filnavn}}”" - }, - "feilmelding": { - "provIgjenEllerFjern": "Finish uploading “{{filnavn}}”, or remove file.", - "ikkeFerdigOpplastet": "Wait until the file has finished uploading" - } - } - }, - "knapper": { - "annenVedleggKnapp": "Add other documentation", - "sendInn": "Submit to NAV", - "fortsettSenere": "Save and continue later", - "neste": "Next step", - "forrige": "Previous step", - "avbryt": "Cancel", - "slett": "Delete form" - }, - "beskjedOmAvvik": "Have you experienced problems submitting attachments? Please upload the attachment again and press Submit." + "test": "this is english", + "soknad": { + "visningsSteg": { + "fraFyllutUtenVedlegg": { + "laster": "Loading... Please wait" + }, + "steg0": { + "tittel": "Download and fill in the form" + }, + "steg1": { + "tittel": "Upload the completed form" + }, + "lastOppVedlegg": { + "tittel": "Upload attachments", + "ingress": "You can upload attachments to your case here. You must upload all the attachments before NAV can process the case.", + "infoFrist": "Deadline for uploading attachments: {{dato}}", + "advarselHovedskjema": "UTGÅR!! Du får ikke sendt inn før du har lastet opp ferdig utfylt skjema på forrige side." + } }, - "filvelger": { - "defaultText": "Select your files" + "skjemaNedlasting": { + "listeTittel": "Instructions:", + "liste": [ + "Click “Download form”.", + "Open and fill in the downloaded pdf form.", + "Save the form on your device after filling it out.", + "Click “Next step”." + ], + "lastNedKnapp": "Download form" }, - "link": { - "nyFane": "{{tekst}} (opens in a new tab)" + "hovedSkjema": { + "listeTittel": "Instructions:", + "liste": [ + "Click “Upload completed form”.", + "Find and upload the completed form.", + "Click “Next step”.", + "You can upload any attachments in the next step." + ], + "filvelgerKnapp": "Upload completed form", + "feilmelding": { + "manglerFil": "Upload completed form: {{label}}" + } }, - "modal": { - "fortsettSenere": { - "tittel": "Are you sure you want to save the form and continue later?", - "liste": [ - "The form will NOT be sent to the case manager in NAV now, but only saved so that you can continue later.", - "If you want to set today's date as the start date for the application, you must click “Cancel” and select “Send to NAV”.", - "We have created a task at nav.no/minside (my page) with a link to the application." - ], - "accept": "Yes, save and continue later", - "cancel": "Cancel" - }, - "slett": { - "tittel": "Are you sure you want to delete the application?", - "liste": [ - "The application and all documents you have uploaded will be deleted." - ], - "accept": "Yes, delete the application", - "cancel": "Cancel" - }, - "sendInnUferdig": { - "tittel": "Are you sure you want to send the application now, even though some documents have not been uploaded?", - "liste": [ - "Today's date will be set as the date of receipt of the application.", - "You have not uploaded all the documents required to process the application.", - "You must send the missing documents by {{dato}}.", - "We have created a task at nav.no/minside (my page) with a link to the application. There you will find the list of attachments you must send." - ], - "accept": "Yes, send the application", - "cancel": "Cancel" + "vedlegg": { + "tidligereSendtInn": "Previously submitted documents:", + "sendtInnNaa": "Documents you have uploaded now:", + "mottatt": "Recieved", + "ettersendingFilvelgerKnapp": "Upload new files", + "feilmelding": { + "manglerFil": "Upload {{label}}" + }, + "annet": { + "tittel": "Describe the document", + "beskrivelse": "Give a descriptive name to the document you wish to upload.", + "rediger": "Edit", + "slett": "Delete attachment", + "bekreft": "Confirm", + "avbryt": "Cancel", + "feilmelding": { + "fullforOpprettelse": "Complete or cancel attachment description", + "fullforRedigering": "Complete and confirm the attachment description", + "manglerFil": "Upload or delete attachment: {{label}}", + "manglerNavn": "Describe the attachment", + "navnForLangt": "The attachment description is too long. Max {{maxLength}} characters." + } + }, + "radio": { + "tittel": "Select submission", + "lasterOppNaa": "I will upload this now", + "sendSenere": "I will upload this later", + "sendesAvAndre": "Will be submitted by others (e.g. doctor, employer)" + }, + "fil": { + "provIgjen": "Try again", + "avbryt": "Cancel", + "slett": "Remove", + "progress": "Progress", + "alt": { + "opplastet": "Successfully uploaded “{{filnavn}}”", + "tidligereLastetOpp": "Previously submitted “{{filnavn}}”", + "lasterOpp": "Uploading “{{filnavn}}”", + "feil": "Error while uploading “{{filnavn}}”" }, - "sendInnKomplett": { - "tittel": "The application is ready for submission. Do you want to send it now?", - "liste": [ - "Today's date will be set as the date of receipt of the application." - ], - "accept": "Yes, send the application", - "cancel": "Cancel" + "feilmelding": { + "provIgjenEllerFjern": "Finish uploading “{{filnavn}}”, or remove file.", + "ikkeFerdigOpplastet": "Wait until the file has finished uploading" } + } }, - "kvittering": { - "tittel": "Thank you!", - "mottattDokumenter": "We received the following documents on {{dato}}:", - "skjema": "Form", - "vedlegg": "Attachments", - "skjemaLenke": "Download a copy", - "maaEttersendes": "Documents that must be sent later:", - "sendesAvAndre": "Documents to be sent by others:", - "fristEttersending": "Deadline for sending the missing documents: {{dato}}", - "ettersendingsInfo": "We cannot process your case until we have received all the required documents. The task for sending the remaining documents can be found at nav.no/minside (my page).", - "altMottatInfo": "All necessary documents have been received. You can find them under Dine saker (Your cases) at nav.no/minside (my page).", - "minSideKnapp": "Go to My page" + "knapper": { + "annenVedleggKnapp": "Add other documentation", + "sendInn": "Submit to NAV", + "fortsettSenere": "Save and continue later", + "neste": "Next step", + "forrige": "Previous step", + "avbryt": "Cancel", + "slett": "Delete form" }, - "feil": { - "fraBackend": "We are experiencing technical difficulties. We apologize for the inconvenience. Please try again later. If the problem persists, you can get help from NAV Service Centre at (+47) 55 55 33 33 or at your local NAV office.", - "medTilkobling": "Check your network connection and try again.", - "ukjent": "We are experiencing technical difficulties. We apologize for the inconvenience. Please try again later. If the problem persists, you can get help from NAV Service Centre at (+47) 55 55 33 33 or at your local NAV office.", - "advarselOverskrift": "An error has occurred", - "advarselBrukerBekreftelse": "OK", - "manglerHovedskjema": "You must upload the completed form. Go back to the previous step", - "filForStor": "The size of the selected file exceeds the maximum size limit. The maximum size allowed is 50MB.", - "filIkkeValgt": "An error occurred during file selection, please retry" + "beskjedOmAvvik": "Have you experienced problems submitting attachments? Please upload the attachment again and press Submit." + }, + "filvelger": { + "defaultText": "Select your files" + }, + "link": { + "nyFane": "{{tekst}} (opens in a new tab)" + }, + "modal": { + "fortsettSenere": { + "tittel": "Are you sure you want to save the form and continue later?", + "liste": [ + "The form will NOT be sent to the case manager in NAV now, but only saved so that you can continue later.", + "If you want to set today's date as the start date for the application, you must click “Cancel” and select “Send to NAV”.", + "We have created a task at nav.no/minside (my page) with a link to the application." + ], + "accept": "Yes, save and continue later", + "cancel": "Cancel" }, - "feilside": { - "404": { - "tittel": "We did not find that page", - "overskrift": "We did not find that page", - "p1": "The page you requested cannot be found. It may have been deleted, moved, or there may be an error in the link that led you here. We apologize for the inconvenience.", - "p2": "We would appreciate it if you report the error via the link below.", - "lenkeTekst": { - "forside": "Return to nav.no front page", - "meldFra": "Report this error" - } - }, - "500": { - "tittel": "Oops, something went wrong", - "overskrift": "Oops, something went wrong", - "p1": "The page or service is currently unavailable due to a technical error.", - "p2": "We apologize. Try again later.", - "lenkeTekst": { - "forside": "Return to nav.no front page", - "meldFra": "Report this error" - } - }, - "soknadSendtInn": { - "tittel": "Error page: Application already submitted", - "overskrift": "You have tried to reopen an application that has already been sent to NAV", - "melding": "If you want to submit additional documentation to this application, it must be submitted on paper.", - "lenkeTekst": { - "minSide": "You will find the application you previously submitted on my page on nav.no (Norwegian)", - "ettersende": "Forward documentation" - } - } + "slett": { + "tittel": "Are you sure you want to delete the application?", + "liste": ["The application and all documents you have uploaded will be deleted."], + "accept": "Yes, delete the application", + "cancel": "Cancel" + }, + "sendInnUferdig": { + "tittel": "Are you sure you want to send the application now, even though some documents have not been uploaded?", + "liste": [ + "Today's date will be set as the date of receipt of the application.", + "You have not uploaded all the documents required to process the application.", + "You must send the missing documents by {{dato}}.", + "We have created a task at nav.no/minside (my page) with a link to the application. There you will find the list of attachments you must send." + ], + "accept": "Yes, send the application", + "cancel": "Cancel" + }, + "sendInnKomplett": { + "tittel": "The application is ready for submission. Do you want to send it now?", + "liste": ["Today's date will be set as the date of receipt of the application."], + "accept": "Yes, send the application", + "cancel": "Cancel" + } + }, + "kvittering": { + "tittel": "Thank you!", + "mottattDokumenter": "We received the following documents on {{dato}}:", + "skjema": "Form", + "vedlegg": "Attachments", + "skjemaLenke": "Download a copy", + "maaEttersendes": "Documents that must be sent later:", + "sendesAvAndre": "Documents to be sent by others:", + "fristEttersending": "Deadline for sending the missing documents: {{dato}}", + "ettersendingsInfo": "We cannot process your case until we have received all the required documents. The task for sending the remaining documents can be found at nav.no/minside (my page).", + "altMottatInfo": "All necessary documents have been received. You can find them under Dine saker (Your cases) at nav.no/minside (my page).", + "minSideKnapp": "Go to My page" + }, + "feil": { + "fraBackend": "We are experiencing technical difficulties. We apologize for the inconvenience. Please try again later. If the problem persists, you can get help from NAV Service Centre at (+47) 55 55 33 33 or at your local NAV office.", + "medTilkobling": "Check your network connection and try again.", + "ukjent": "We are experiencing technical difficulties. We apologize for the inconvenience. Please try again later. If the problem persists, you can get help from NAV Service Centre at (+47) 55 55 33 33 or at your local NAV office.", + "advarselOverskrift": "An error has occurred", + "advarselBrukerBekreftelse": "OK", + "manglerHovedskjema": "You must upload the completed form. Go back to the previous step", + "filForStor": "The size of the selected file exceeds the maximum size limit. The maximum size allowed is 50MB.", + "filIkkeValgt": "An error occurred during file selection, please retry" + }, + "feilside": { + "404": { + "tittel": "We did not find that page", + "overskrift": "We did not find that page", + "p1": "The page you requested cannot be found. It may have been deleted, moved, or there may be an error in the link that led you here. We apologize for the inconvenience.", + "p2": "We would appreciate it if you report the error via the link below.", + "lenkeTekst": { + "forside": "Return to nav.no front page", + "meldFra": "Report this error" + } + }, + "500": { + "tittel": "Oops, something went wrong", + "overskrift": "Oops, something went wrong", + "p1": "The page or service is currently unavailable due to a technical error.", + "p2": "We apologize. Try again later.", + "lenkeTekst": { + "forside": "Return to nav.no front page", + "meldFra": "Report this error" + } }, - "statuskode": "Status code", - "for": "for" + "soknadSendtInn": { + "tittel": "Error page: Application already submitted", + "overskrift": "You have tried to reopen an application that has already been sent to NAV", + "melding": "If you want to submit additional documentation to this application, it must be submitted on paper.", + "lenkeTekst": { + "minSide": "You will find the application you previously submitted on my page on nav.no (Norwegian)", + "ettersende": "Forward documentation" + } + } + }, + "statuskode": "Status code", + "for": "for" } diff --git a/assets/locales/nb/backend.json b/assets/locales/nb/backend.json index 594d2d45..50b8d816 100644 --- a/assets/locales/nb/backend.json +++ b/assets/locales/nb/backend.json @@ -1,27 +1,27 @@ { - "illegalAction.applicationSentInOrDeleted": { - "message": "Søknaden kan ikke vises eller endres fordi den er slettet eller sendt inn til NAV" - }, - "illegalAction.fileCannotBeRead": { - "message": "Opplasting av fil feilet fordi den ikke kan leses. Sjekk at den ikke er kryptert eller passordbeskyttet og prøv igjen" - }, - "illegalAction.sendInErrorNoApplication": { - "message": "Innsending feilet fordi det ikke er lastet opp søknad" - }, - "illegalAction.sendInErrorNoChange": { - "message": "Du må laste opp minst ett nytt vedlegg som du vil sende til NAV.", - "title": "Du har ikke lastet opp noen nye vedlegg" - }, - "illegalAction.notSupportedFileFormat": { - "message": "Feil filformat, det er kun lov å laste opp filer av type PDF, JPEG/JPG og PNG" - }, - "illegalAction.fileSizeSumTooLarge": { - "message": "Summen av størrelsen på opplastede filer for hele søknaden overskrider maksimal tillatt størrelse. Den maksimale størrelsen er 150MB totalt." - }, - "illegalAction.vedleggFileSizeSumTooLarge": { - "message": "Summen av størrelsen på opplastede filer for dette vedlegget overskrider maksimal tillatt størrelse. Den maksimale størrelsen er 50MB totalt." - }, - "illegalAction.virusScanFailed": { - "message": "Filen du har lastet opp inneholder virus. Prøv igjen med en annen fil" - } + "illegalAction.applicationSentInOrDeleted": { + "message": "Søknaden kan ikke vises eller endres fordi den er slettet eller sendt inn til NAV" + }, + "illegalAction.fileCannotBeRead": { + "message": "Opplasting av fil feilet fordi den ikke kan leses. Sjekk at den ikke er kryptert eller passordbeskyttet og prøv igjen" + }, + "illegalAction.sendInErrorNoApplication": { + "message": "Innsending feilet fordi det ikke er lastet opp søknad" + }, + "illegalAction.sendInErrorNoChange": { + "message": "Du må laste opp minst ett nytt vedlegg som du vil sende til NAV.", + "title": "Du har ikke lastet opp noen nye vedlegg" + }, + "illegalAction.notSupportedFileFormat": { + "message": "Feil filformat, det er kun lov å laste opp filer av type PDF, JPEG/JPG og PNG" + }, + "illegalAction.fileSizeSumTooLarge": { + "message": "Summen av størrelsen på opplastede filer for hele søknaden overskrider maksimal tillatt størrelse. Den maksimale størrelsen er 150MB totalt." + }, + "illegalAction.vedleggFileSizeSumTooLarge": { + "message": "Summen av størrelsen på opplastede filer for dette vedlegget overskrider maksimal tillatt størrelse. Den maksimale størrelsen er 50MB totalt." + }, + "illegalAction.virusScanFailed": { + "message": "Filen du har lastet opp inneholder virus. Prøv igjen med en annen fil" + } } diff --git a/assets/locales/nb/translation.json b/assets/locales/nb/translation.json index 8064c247..2f93d407 100644 --- a/assets/locales/nb/translation.json +++ b/assets/locales/nb/translation.json @@ -1,200 +1,198 @@ { - "test": "det er bokmål", - "soknad": { - "visningsSteg": { - "fraFyllutUtenVedlegg": { - "laster": "Laster... Vennligst vent" - }, - "steg0": { - "tittel": "Last ned og fyll ut skjema" - }, - "steg1": { - "tittel": "Last opp ferdig utfylt skjema" - }, - "lastOppVedlegg": { - "tittel": "Last opp vedlegg", - "ingress": "Her kan du laste opp vedlegg til saken din. Du må laste opp alle vedleggene før NAV kan behandle saken.", - "infoFrist": "Frist for opplasting av vedlegg: {{dato}}", - "advarselHovedskjema": "Du får ikke sendt inn før du har lastet opp ferdig utfylt skjema på forrige side." - } - }, - "skjemaNedlasting": { - "listeTittel": "Slik gjør du:", - "liste": [ - "Klikk på “Last ned skjema”.", - "Åpne og fyll ut pdf-skjemaet som lastes ned.", - "Lagre skjemaet på enheten din etter utfylling.", - "Klikk på “Neste steg”." - ], - "lastNedKnapp": "Last ned skjema" - }, - "hovedSkjema": { - "listeTittel": "Slik gjør du:", - "liste": [ - "Klikk på “Last opp utfylt skjema”.", - "Finn og last opp det ferdig utfylte skjemaet.", - "Klikk på “Neste steg”.", - "Hvis du skal sende inn vedlegg gjør du det i neste steg." - ], - "filvelgerKnapp": "Last opp utfylt skjema", - "feilmelding": { - "manglerFil": "Last opp utfylt skjema: {{label}}" - } - }, - "vedlegg": { - "tidligereSendtInn": "Dokumenter du har sendt inn tidligere:", - "sendtInnNaa": "Dokumenter du har lastet opp nå:", - "mottatt": "Mottatt", - "ettersendingFilvelgerKnapp": "Last opp nye filer", - "feilmelding": { - "manglerFil": "Last opp {{label}}" - }, - "annet": { - "tittel": "Beskriv vedlegget", - "beskrivelse": "Gi et beskrivende navn på dokumentet du ønsker å laste opp.", - "rediger": "Rediger", - "slett": "Slett vedlegg", - "bekreft": "Bekreft", - "avbryt": "Avbryt", - "feilmelding": { - "fullforOpprettelse": "Fullfør eller avbryt vedleggsbeskrivelse", - "fullforRedigering": "Fullfør og bekreft redigering av vedleggsbeskrivelse", - "manglerFil": "Last opp eller slett vedlegget: {{label}}", - "manglerNavn": "Gi en vedleggsbeskrivelse", - "navnForLangt": "Vedleggsbeskrivelsen er for lang. Maks {{maxLength}} tegn" - } - }, - "radio": { - "tittel": "Velg innsending", - "lasterOppNaa": "Jeg laster opp dette nå", - "sendSenere": "Jeg laster opp dette senere", - "sendesAvAndre": "Sendes inn av andre (for eksempel lege eller arbeidsgiver)" - }, - "fil": { - "provIgjen": "Prøv igjen", - "avbryt": "Avbryt", - "slett": "Fjern", - "progress": "Framgang", - "alt": { - "opplastet": "Fullført opplasting av “{{filnavn}}”", - "tidligereLastetOpp": "Tidligere sendt inn “{{filnavn}}”", - "lasterOpp": "Laster opp “{{filnavn}}”", - "feil": "Feil ved opplasting av “{{filnavn}}”" - }, - "feilmelding": { - "provIgjenEllerFjern": "Fullfør opplasting av “{{filnavn}}”, eller fjern feil", - "ikkeFerdigOpplastet": "Vent til fil er ferdig opplastet" - } - } - }, - "knapper": { - "annenVedleggKnapp": "Legg til annen dokumentasjon", - "sendInn": "Send til NAV", - "fortsettSenere": "Lagre og fortsett senere", - "neste": "Neste steg", - "forrige": "Forrige steg", - "avbryt": "Avbryt", - "slett": "Slett søknad" - }, - "beskjedOmAvvik": "Får du ikke ettersendt vedlegg? Da må du laste opp vedlegget på nytt og trykke Send inn." + "test": "det er bokmål", + "soknad": { + "visningsSteg": { + "fraFyllutUtenVedlegg": { + "laster": "Laster... Vennligst vent" + }, + "steg0": { + "tittel": "Last ned og fyll ut skjema" + }, + "steg1": { + "tittel": "Last opp ferdig utfylt skjema" + }, + "lastOppVedlegg": { + "tittel": "Last opp vedlegg", + "ingress": "Her kan du laste opp vedlegg til saken din. Du må laste opp alle vedleggene før NAV kan behandle saken.", + "infoFrist": "Frist for opplasting av vedlegg: {{dato}}", + "advarselHovedskjema": "Du får ikke sendt inn før du har lastet opp ferdig utfylt skjema på forrige side." + } }, - "filvelger": { - "defaultText": "Velg dine filer" + "skjemaNedlasting": { + "listeTittel": "Slik gjør du:", + "liste": [ + "Klikk på “Last ned skjema”.", + "Åpne og fyll ut pdf-skjemaet som lastes ned.", + "Lagre skjemaet på enheten din etter utfylling.", + "Klikk på “Neste steg”." + ], + "lastNedKnapp": "Last ned skjema" }, - "link": { - "nyFane": "{{tekst}} (åpnes i ny fane)" + "hovedSkjema": { + "listeTittel": "Slik gjør du:", + "liste": [ + "Klikk på “Last opp utfylt skjema”.", + "Finn og last opp det ferdig utfylte skjemaet.", + "Klikk på “Neste steg”.", + "Hvis du skal sende inn vedlegg gjør du det i neste steg." + ], + "filvelgerKnapp": "Last opp utfylt skjema", + "feilmelding": { + "manglerFil": "Last opp utfylt skjema: {{label}}" + } }, - "modal": { - "fortsettSenere": { - "tittel": "Er du sikker på at du vil lagre søknaden og fortsette senere?", - "liste": [ - "Søknaden blir IKKE sendt til saksbehandler i NAV nå, men bare lagret slik at du kan fortsette senere.", - "Hvis du ønsker å sette dagens dato som startdato for søknaden må du klikke “Avbryt” og velge “Send til NAV”.", - "Vi har opprettet en oppgave på nav.no/minside med en lenke til søknaden." - ], - "accept": "Ja, lagre og fortsett senere", - "cancel": "Avbryt" - }, - "slett": { - "tittel": "Er du sikker på at du vil slette søknaden?", - "liste": [ - "Søknaden og all dokumentasjon du har lastet opp vil bli slettet." - ], - "accept": "Ja, slett søknaden", - "cancel": "Avbryt" - }, - "sendInnUferdig": { - "tittel": "Er du sikker på at du vil sende søknaden nå, selv om ikke alle dokumenter er lastet opp?", - "liste": [ - "Dagens dato vil bli satt som mottaksdato for søknaden.", - "Du har ikke lastet opp alle dokumenter som er påkrevd for å behandle søknaden.", - "Du må ettersende dokumentene som mangler innen {{dato}}.", - "Vi har opprettet en oppgave på nav.no/minside med en lenke til søknaden. Der finner du en liste med vedleggene du må ettersende." - ], - "accept": "Ja, send søknaden", - "cancel": "Avbryt" + "vedlegg": { + "tidligereSendtInn": "Dokumenter du har sendt inn tidligere:", + "sendtInnNaa": "Dokumenter du har lastet opp nå:", + "mottatt": "Mottatt", + "ettersendingFilvelgerKnapp": "Last opp nye filer", + "feilmelding": { + "manglerFil": "Last opp {{label}}" + }, + "annet": { + "tittel": "Beskriv vedlegget", + "beskrivelse": "Gi et beskrivende navn på dokumentet du ønsker å laste opp.", + "rediger": "Rediger", + "slett": "Slett vedlegg", + "bekreft": "Bekreft", + "avbryt": "Avbryt", + "feilmelding": { + "fullforOpprettelse": "Fullfør eller avbryt vedleggsbeskrivelse", + "fullforRedigering": "Fullfør og bekreft redigering av vedleggsbeskrivelse", + "manglerFil": "Last opp eller slett vedlegget: {{label}}", + "manglerNavn": "Gi en vedleggsbeskrivelse", + "navnForLangt": "Vedleggsbeskrivelsen er for lang. Maks {{maxLength}} tegn" + } + }, + "radio": { + "tittel": "Velg innsending", + "lasterOppNaa": "Jeg laster opp dette nå", + "sendSenere": "Jeg laster opp dette senere", + "sendesAvAndre": "Sendes inn av andre (for eksempel lege eller arbeidsgiver)" + }, + "fil": { + "provIgjen": "Prøv igjen", + "avbryt": "Avbryt", + "slett": "Fjern", + "progress": "Framgang", + "alt": { + "opplastet": "Fullført opplasting av “{{filnavn}}”", + "tidligereLastetOpp": "Tidligere sendt inn “{{filnavn}}”", + "lasterOpp": "Laster opp “{{filnavn}}”", + "feil": "Feil ved opplasting av “{{filnavn}}”" }, - "sendInnKomplett": { - "tittel": "Søknaden er klar til å sendes inn. Vil du sende den nå?", - "liste": ["Dagens dato vil bli satt som mottaksdato."], - "accept": "Ja, send søknaden", - "cancel": "Avbryt" + "feilmelding": { + "provIgjenEllerFjern": "Fullfør opplasting av “{{filnavn}}”, eller fjern feil", + "ikkeFerdigOpplastet": "Vent til fil er ferdig opplastet" } + } }, - "kvittering": { - "tittel": "Takk!", - "mottattDokumenter": "Vi mottok disse dokumentene {{dato}}:", - "skjema": "Skjema", - "vedlegg": "Vedlegg", - "skjemaLenke": "Last ned kopi", - "maaEttersendes": "Dokumenter som må ettersendes:", - "sendesAvAndre": "Dokumenter som skal sendes av andre:", - "fristEttersending": "Frist for å ettersende dokumentene: {{dato}}", - "ettersendingsInfo": "Vi kan ikke behandle saken din før vi har mottatt disse dokumentene. Oppgaven for å ettersende dokumentene finner du på nav.no/minside.", - "altMottatInfo": "Alle nødvendige dokumenter er mottatt. Du finner dem under Dine saker på nav.no/minside.", - "minSideKnapp": "Gå til Min side" + "knapper": { + "annenVedleggKnapp": "Legg til annen dokumentasjon", + "sendInn": "Send til NAV", + "fortsettSenere": "Lagre og fortsett senere", + "neste": "Neste steg", + "forrige": "Forrige steg", + "avbryt": "Avbryt", + "slett": "Slett søknad" }, - "feil": { - "fraBackend": "Beklager, vi har tekniske problemer. Prøv igjen senere. Om problemet vedvarer ta kontakt med NAV for å få hjelp på telefon (+47) 55 55 33 33 eller på ditt lokale NAV kontor.", - "medTilkobling": "Sjekk nettverksforbindelsen din og prøv igjen.", - "ukjent": "Beklager, vi har tekniske problemer. Prøv igjen senere. Om problemet vedvarer ta kontakt med NAV for å få hjelp på telefon (+47) 55 55 33 33 eller på ditt lokale NAV kontor. ", - "advarselOverskrift": "Det har skjedd en feil", - "advarselBrukerBekreftelse": "OK", - "manglerHovedskjema": "Du må laste opp ferdig utfylt skjema. Gå tilbake til forrige steg", - "filForStor": "Størrelsen på filen overskrider maksimal tillatt størrelse. Den maksimale størrelsen er 50MB.", - "filIkkeValgt": "En feil oppsto under valg av fil. Prøv på nytt" + "beskjedOmAvvik": "Får du ikke ettersendt vedlegg? Da må du laste opp vedlegget på nytt og trykke Send inn." + }, + "filvelger": { + "defaultText": "Velg dine filer" + }, + "link": { + "nyFane": "{{tekst}} (åpnes i ny fane)" + }, + "modal": { + "fortsettSenere": { + "tittel": "Er du sikker på at du vil lagre søknaden og fortsette senere?", + "liste": [ + "Søknaden blir IKKE sendt til saksbehandler i NAV nå, men bare lagret slik at du kan fortsette senere.", + "Hvis du ønsker å sette dagens dato som startdato for søknaden må du klikke “Avbryt” og velge “Send til NAV”.", + "Vi har opprettet en oppgave på nav.no/minside med en lenke til søknaden." + ], + "accept": "Ja, lagre og fortsett senere", + "cancel": "Avbryt" }, - "feilside": { - "404": { - "tittel": "Vi fant ikke den siden", - "overskrift": "Vi fant ikke den siden", - "p1": "Beklager, siden kan være slettet eller flyttet, eller det var en feil i lenken som førte deg hit.", - "p2": "Vi setter pris på om du melder fra om feilen via lenken nedenfor.", - "lenkeTekst": { - "forside": "Gå til forsiden på nav.no", - "meldFra": "Meld fra om denne feilen" - } - }, - "500": { - "tittel": "Oops, noe gikk galt", - "overskrift": "Oops, noe gikk galt", - "p1": "Siden eller tjenesten er for tiden utilgjengelig på grunn av teknisk feil.", - "p2": "Vi beklager dette. Prøv igjen senere.", - "lenkeTekst": { - "forside": "Gå til forsiden på nav.no", - "meldFra": "Meld fra om denne feilen" - } - }, - "soknadSendtInn": { - "tittel": "Feilside: Søknad er sendt inn", - "overskrift": "Du har forsøkt å gå tilbake til en søknad som allerede er sendt til NAV", - "melding": "Hvis du skal ettersende dokumentasjon til denne søknaden må det sendes inn på papir.", - "lenkeTekst": { - "minSide": "Du finner søknaden du sendte inn på Min side på nav.no", - "ettersende": "Gå til ettersendelse" - } - }, - "statuskode": "Statuskode" + "slett": { + "tittel": "Er du sikker på at du vil slette søknaden?", + "liste": ["Søknaden og all dokumentasjon du har lastet opp vil bli slettet."], + "accept": "Ja, slett søknaden", + "cancel": "Avbryt" + }, + "sendInnUferdig": { + "tittel": "Er du sikker på at du vil sende søknaden nå, selv om ikke alle dokumenter er lastet opp?", + "liste": [ + "Dagens dato vil bli satt som mottaksdato for søknaden.", + "Du har ikke lastet opp alle dokumenter som er påkrevd for å behandle søknaden.", + "Du må ettersende dokumentene som mangler innen {{dato}}.", + "Vi har opprettet en oppgave på nav.no/minside med en lenke til søknaden. Der finner du en liste med vedleggene du må ettersende." + ], + "accept": "Ja, send søknaden", + "cancel": "Avbryt" + }, + "sendInnKomplett": { + "tittel": "Søknaden er klar til å sendes inn. Vil du sende den nå?", + "liste": ["Dagens dato vil bli satt som mottaksdato."], + "accept": "Ja, send søknaden", + "cancel": "Avbryt" + } + }, + "kvittering": { + "tittel": "Takk!", + "mottattDokumenter": "Vi mottok disse dokumentene {{dato}}:", + "skjema": "Skjema", + "vedlegg": "Vedlegg", + "skjemaLenke": "Last ned kopi", + "maaEttersendes": "Dokumenter som må ettersendes:", + "sendesAvAndre": "Dokumenter som skal sendes av andre:", + "fristEttersending": "Frist for å ettersende dokumentene: {{dato}}", + "ettersendingsInfo": "Vi kan ikke behandle saken din før vi har mottatt disse dokumentene. Oppgaven for å ettersende dokumentene finner du på nav.no/minside.", + "altMottatInfo": "Alle nødvendige dokumenter er mottatt. Du finner dem under Dine saker på nav.no/minside.", + "minSideKnapp": "Gå til Min side" + }, + "feil": { + "fraBackend": "Beklager, vi har tekniske problemer. Prøv igjen senere. Om problemet vedvarer ta kontakt med NAV for å få hjelp på telefon (+47) 55 55 33 33 eller på ditt lokale NAV kontor.", + "medTilkobling": "Sjekk nettverksforbindelsen din og prøv igjen.", + "ukjent": "Beklager, vi har tekniske problemer. Prøv igjen senere. Om problemet vedvarer ta kontakt med NAV for å få hjelp på telefon (+47) 55 55 33 33 eller på ditt lokale NAV kontor. ", + "advarselOverskrift": "Det har skjedd en feil", + "advarselBrukerBekreftelse": "OK", + "manglerHovedskjema": "Du må laste opp ferdig utfylt skjema. Gå tilbake til forrige steg", + "filForStor": "Størrelsen på filen overskrider maksimal tillatt størrelse. Den maksimale størrelsen er 50MB.", + "filIkkeValgt": "En feil oppsto under valg av fil. Prøv på nytt" + }, + "feilside": { + "404": { + "tittel": "Vi fant ikke den siden", + "overskrift": "Vi fant ikke den siden", + "p1": "Beklager, siden kan være slettet eller flyttet, eller det var en feil i lenken som førte deg hit.", + "p2": "Vi setter pris på om du melder fra om feilen via lenken nedenfor.", + "lenkeTekst": { + "forside": "Gå til forsiden på nav.no", + "meldFra": "Meld fra om denne feilen" + } + }, + "500": { + "tittel": "Oops, noe gikk galt", + "overskrift": "Oops, noe gikk galt", + "p1": "Siden eller tjenesten er for tiden utilgjengelig på grunn av teknisk feil.", + "p2": "Vi beklager dette. Prøv igjen senere.", + "lenkeTekst": { + "forside": "Gå til forsiden på nav.no", + "meldFra": "Meld fra om denne feilen" + } + }, + "soknadSendtInn": { + "tittel": "Feilside: Søknad er sendt inn", + "overskrift": "Du har forsøkt å gå tilbake til en søknad som allerede er sendt til NAV", + "melding": "Hvis du skal ettersende dokumentasjon til denne søknaden må det sendes inn på papir.", + "lenkeTekst": { + "minSide": "Du finner søknaden du sendte inn på Min side på nav.no", + "ettersende": "Gå til ettersendelse" + } }, - "for": "for" + "statuskode": "Statuskode" + }, + "for": "for" } diff --git a/assets/locales/nn/backend.json b/assets/locales/nn/backend.json index b0151a1a..5fab5acc 100644 --- a/assets/locales/nn/backend.json +++ b/assets/locales/nn/backend.json @@ -1,27 +1,27 @@ { - "illegalAction.applicationSentInOrDeleted": { - "message": "Søknaden kan ikkje visast eller bli endra fordi han er sletta eller sendt inn til NAV" - }, - "illegalAction.fileCannotBeRead": { - "message": "Opplastinga av fil feila fordi ho ikkje kan lesast. Sjekk at ho ikkje er kryptert eller verna med passord og prøv igjen " - }, - "illegalAction.sendInErrorNoApplication": { - "message": "Innsendinga feila fordi det ikkje er lasta opp søknad " - }, - "illegalAction.sendInErrorNoChange": { - "message": "Du må lasta opp minst eitt nytt vedlegg som du vil senda til NAV.", - "title": "Du har ikkje lasta opp nokon nye vedlegg" - }, - "illegalAction.notSupportedFileFormat": { - "message": "Feil filformat, det er berre lov å laste opp filer av typen PDF, JPEG/JPG og PNG" - }, - "illegalAction.fileSizeSumTooLarge": { - "message": "Summen av storleiken på opplasta filer for heile søknaden overskrid maksimal tillaten storleik. Den maksimale storleiken er 150MB totalt." - }, - "illegalAction.vedleggFileSizeSumTooLarge": { - "message": "Summen av storleiken på opplasta filer for dette vedlegget overskrid maksimal tillaten storleik. Den maksimale storleiken er 50MB totalt." - }, - "illegalAction.virusScanFailed": { - "message": "Fila du har lasta opp inneheld virus. Prøv igjen med ei anna fil" - } + "illegalAction.applicationSentInOrDeleted": { + "message": "Søknaden kan ikkje visast eller bli endra fordi han er sletta eller sendt inn til NAV" + }, + "illegalAction.fileCannotBeRead": { + "message": "Opplastinga av fil feila fordi ho ikkje kan lesast. Sjekk at ho ikkje er kryptert eller verna med passord og prøv igjen " + }, + "illegalAction.sendInErrorNoApplication": { + "message": "Innsendinga feila fordi det ikkje er lasta opp søknad " + }, + "illegalAction.sendInErrorNoChange": { + "message": "Du må lasta opp minst eitt nytt vedlegg som du vil senda til NAV.", + "title": "Du har ikkje lasta opp nokon nye vedlegg" + }, + "illegalAction.notSupportedFileFormat": { + "message": "Feil filformat, det er berre lov å laste opp filer av typen PDF, JPEG/JPG og PNG" + }, + "illegalAction.fileSizeSumTooLarge": { + "message": "Summen av storleiken på opplasta filer for heile søknaden overskrid maksimal tillaten storleik. Den maksimale storleiken er 150MB totalt." + }, + "illegalAction.vedleggFileSizeSumTooLarge": { + "message": "Summen av storleiken på opplasta filer for dette vedlegget overskrid maksimal tillaten storleik. Den maksimale storleiken er 50MB totalt." + }, + "illegalAction.virusScanFailed": { + "message": "Fila du har lasta opp inneheld virus. Prøv igjen med ei anna fil" + } } diff --git a/assets/locales/nn/translation.json b/assets/locales/nn/translation.json index 26e05300..8a73d578 100644 --- a/assets/locales/nn/translation.json +++ b/assets/locales/nn/translation.json @@ -1,200 +1,198 @@ { - "test": "det er nynorsk", - "soknad": { - "visningsSteg": { - "fraFyllutUtenVedlegg": { - "laster": "Lastar... Ver venleg og vent" - }, - "steg0": { - "tittel": "Last ned og fyll ut skjema" - }, - "steg1": { - "tittel": "Last opp ferdig utfylt skjema" - }, - "lastOppVedlegg": { - "tittel": "Last opp vedlegg", - "ingress": "Her kan du lasta opp vedlegg til saka di. Du må lasta opp alle vedlegga før NAV kan behandla saka.", - "infoFrist": "Frist for opplasting av vedlegg: {{dato}}", - "advarselHovedskjema": "UTGÅR!! Du får ikkje sendt inn før du har lasta opp ferdig utfylt skjema på førre side." - } - }, - "skjemaNedlasting": { - "listeTittel": "Slik gjer du:", - "liste": [ - "Klikk på “Last ned skjema”.", - "Åpne og fyll ut pdf-skjemaet som blir lasta ned.", - " Lagre skjemaet på di eining etter at du har fylt det ut.", - "Klikk på “Neste steg”." - ], - "lastNedKnapp": "Last ned skjema" - }, - "hovedSkjema": { - "listeTittel": "Slik gjer du:", - "liste": [ - "Klikk på “Last opp utfylt skjema”.", - "Finn og last opp det ferdig utfylte skjemaet.", - "Klikk på “Neste steg”.", - "Viss du skal senda inn vedlegg gjer du det i neste steg." - ], - "filvelgerKnapp": "Last opp utfylt skjema", - "feilmelding": { - "manglerFil": "Last opp utfylt skjema: {{label}}" - } - }, - "vedlegg": { - "tidligereSendtInn": "Dokument du har sendt inn tidlegare:", - "sendtInnNaa": "Dokument du har lasta opp nå:", - "mottatt": "Tatt imot", - "ettersendingFilvelgerKnapp": "Last opp nye filer", - "feilmelding": { - "manglerFil": "Last opp {{label}}" - }, - "annet": { - "tittel": "Beskriv vedlegget", - "beskrivelse": "Gi eit beskrivande namn på dokumenta du ønsker å laste opp.", - "rediger": "Rediger", - "slett": "Slett vedlegg", - "bekreft": "Bekreft", - "avbryt": "Avbryt", - "feilmelding": { - "fullforOpprettelse": "Fullfør eller avbryt for å gi vedlegget namn", - "fullforRedigering": "Fullfør og bekreft redigering av namngiving av vedlegg", - "manglerFil": "Last opp eller slett vedlegget: {{label}}", - "manglerNavn": "Gi eit namn til vedlegget", - "navnForLangt": "Namnet på vedlegget er for langt. Maks {{maxLength}} tegn" - } - }, - "radio": { - "tittel": "Velg innsending", - "lasterOppNaa": "Eg lastar opp dette nå", - "sendSenere": "Eg lastar opp dette seinare", - "sendesAvAndre": "Sendes inn av andre (til dømes lege eller arbeidsgjevar)" - }, - "fil": { - "provIgjen": "Prøv igjen", - "avbryt": "Avbryt", - "slett": "Fjern", - "progress": "Framgang", - "alt": { - "opplastet": "Fullført opplasting av “{{filnavn}}”", - "tidligereLastetOpp": "Tidlegare sendt inn “{{filnavn}}”", - "lasterOpp": "Lastar opp “{{filnavn}}”", - "feil": "Feil ved opplasting av “{{filnavn}}”" - }, - "feilmelding": { - "provIgjenEllerFjern": "Fullfør opplasting av “{{filnavn}}”, eller fjern feil", - "ikkeFerdigOpplastet": "Vent til fil er ferdig lasta" - } - } - }, - "knapper": { - "annenVedleggKnapp": "Legg til anna dokumentasjon", - "sendInn": "Send til NAV", - "fortsettSenere": "Lagre og fortsett seinare", - "neste": "Neste steg", - "forrige": "Forrige steg", - "avbryt": "Avbryt", - "slett": "Slett søknad" - }, - "beskjedOmAvvik": "Får du ikkje ettersendt vedlegg? Då må du lasta opp vedlegget på nytt og trykkja Send inn." + "test": "det er nynorsk", + "soknad": { + "visningsSteg": { + "fraFyllutUtenVedlegg": { + "laster": "Lastar... Ver venleg og vent" + }, + "steg0": { + "tittel": "Last ned og fyll ut skjema" + }, + "steg1": { + "tittel": "Last opp ferdig utfylt skjema" + }, + "lastOppVedlegg": { + "tittel": "Last opp vedlegg", + "ingress": "Her kan du lasta opp vedlegg til saka di. Du må lasta opp alle vedlegga før NAV kan behandla saka.", + "infoFrist": "Frist for opplasting av vedlegg: {{dato}}", + "advarselHovedskjema": "UTGÅR!! Du får ikkje sendt inn før du har lasta opp ferdig utfylt skjema på førre side." + } }, - "filvelger": { - "defaultText": "Velg dine filer" + "skjemaNedlasting": { + "listeTittel": "Slik gjer du:", + "liste": [ + "Klikk på “Last ned skjema”.", + "Åpne og fyll ut pdf-skjemaet som blir lasta ned.", + " Lagre skjemaet på di eining etter at du har fylt det ut.", + "Klikk på “Neste steg”." + ], + "lastNedKnapp": "Last ned skjema" }, - "link": { - "nyFane": "{{tekst}} (åpnes i ny fane)" + "hovedSkjema": { + "listeTittel": "Slik gjer du:", + "liste": [ + "Klikk på “Last opp utfylt skjema”.", + "Finn og last opp det ferdig utfylte skjemaet.", + "Klikk på “Neste steg”.", + "Viss du skal senda inn vedlegg gjer du det i neste steg." + ], + "filvelgerKnapp": "Last opp utfylt skjema", + "feilmelding": { + "manglerFil": "Last opp utfylt skjema: {{label}}" + } }, - "modal": { - "fortsettSenere": { - "tittel": "Er du sikker på at du vil lagre søknaden og fortsette seinare?", - "liste": [ - "Søknaden blir IKKJE send til saksbehandlar i NAV no, men berre lagra slik at du kan fortsetja seinare.", - "Viss du ønsker å setja dagens dato som startdato for søknaden må du klikke “Avbryt” og velja “Send til NAV”.", - "Vi har oppretta ei oppgåve på nav.no/minside med ei lenke til søknaden." - ], - "accept": "Ja, lagre og fortsett seinare", - "cancel": "Avbryt" - }, - "slett": { - "tittel": "Er du sikker på at du vil slette søknaden?", - "liste": [ - "Søknaden og alle dokumenta du har lastet opp vil bli slettet." - ], - "accept": "Ja, slett søknaden", - "cancel": "Avbryt" - }, - "sendInnUferdig": { - "tittel": " Er du sikker på at du vil senda søknaden no, sjølv om ikkje alle dokumenta er lasta opp?", - "liste": [ - "Dagens dato vil bli sett som mottaksdato for søknaden.", - "Du har ikkje lasta opp alle dokumenta som er nødvendig for å behandle søknaden.", - "Du må ettersenda dokumenta som manglar innan {{dato}}.", - "Vi har oppretta ei oppgåve på nav.no/minside med ei lenke til søknaden. Der finn du vedlegga du må ettersenda." - ], - "accept": "Ja, send søknaden", - "cancel": "Avbryt" + "vedlegg": { + "tidligereSendtInn": "Dokument du har sendt inn tidlegare:", + "sendtInnNaa": "Dokument du har lasta opp nå:", + "mottatt": "Tatt imot", + "ettersendingFilvelgerKnapp": "Last opp nye filer", + "feilmelding": { + "manglerFil": "Last opp {{label}}" + }, + "annet": { + "tittel": "Beskriv vedlegget", + "beskrivelse": "Gi eit beskrivande namn på dokumenta du ønsker å laste opp.", + "rediger": "Rediger", + "slett": "Slett vedlegg", + "bekreft": "Bekreft", + "avbryt": "Avbryt", + "feilmelding": { + "fullforOpprettelse": "Fullfør eller avbryt for å gi vedlegget namn", + "fullforRedigering": "Fullfør og bekreft redigering av namngiving av vedlegg", + "manglerFil": "Last opp eller slett vedlegget: {{label}}", + "manglerNavn": "Gi eit namn til vedlegget", + "navnForLangt": "Namnet på vedlegget er for langt. Maks {{maxLength}} tegn" + } + }, + "radio": { + "tittel": "Velg innsending", + "lasterOppNaa": "Eg lastar opp dette nå", + "sendSenere": "Eg lastar opp dette seinare", + "sendesAvAndre": "Sendes inn av andre (til dømes lege eller arbeidsgjevar)" + }, + "fil": { + "provIgjen": "Prøv igjen", + "avbryt": "Avbryt", + "slett": "Fjern", + "progress": "Framgang", + "alt": { + "opplastet": "Fullført opplasting av “{{filnavn}}”", + "tidligereLastetOpp": "Tidlegare sendt inn “{{filnavn}}”", + "lasterOpp": "Lastar opp “{{filnavn}}”", + "feil": "Feil ved opplasting av “{{filnavn}}”" }, - "sendInnKomplett": { - "tittel": "Søknaden er klar til å sendast inn. Vil du senda han no?", - "liste": ["Dagens dato vil bli satt som mottaksdato."], - "accept": "Ja, send søknaden", - "cancel": "Avbryt" + "feilmelding": { + "provIgjenEllerFjern": "Fullfør opplasting av “{{filnavn}}”, eller fjern feil", + "ikkeFerdigOpplastet": "Vent til fil er ferdig lasta" } + } }, - "kvittering": { - "tittel": "Takk!", - "mottattDokumenter": "Vi mottok desse dokumenta {{dato}}:", - "skjema": "Skjema", - "vedlegg": "Vedlegg", - "skjemaLenke": "Last ned kopi", - "maaEttersendes": " Dokument som må ettersendast:", - "sendesAvAndre": " Dokument som skal sendast av andre:", - "fristEttersending": "Frist for å ettersenda dokumenta: {{dato}}", - "ettersendingsInfo": "Vi kan ikkje behandla saka di før vi har tatt imot desse. Oppgåva for å ettersenda dokumentasjonen finn du på nav.no/minside.", - "altMottatInfo": "Alle nødvendige dokument er tatt imot. Du finn dei under Dine saker på nav.no/minside.", - "minSideKnapp": "Gå til Min side" + "knapper": { + "annenVedleggKnapp": "Legg til anna dokumentasjon", + "sendInn": "Send til NAV", + "fortsettSenere": "Lagre og fortsett seinare", + "neste": "Neste steg", + "forrige": "Forrige steg", + "avbryt": "Avbryt", + "slett": "Slett søknad" }, - "feil": { - "fraBackend": "Beklagar, vi har tekniske problem. Prøv igjen seinare. Om problemet held fram ta kontakt med NAV for å få hjelp på telefon (+47) 55 55 33 33 eller på ditt lokale NAV kontor.", - "medTilkobling": "Sjekk nettverkstilkoplinga di og prøv igjen.", - "ukjent": "Beklagar, vi har tekniske problem. Prøv igjen seinare. Om problemet held fram ta kontakt med NAV for å få hjelp på telefon (+47) 55 55 33 33 eller på ditt lokale NAV kontor.", - "advarselOverskrift": "Det har skjedd ein feil", - "advarselBrukerBekreftelse": "OK", - "manglerHovedskjema": "Du må lasta opp ferdig utfylt skjema. Gå tilbake til forrige steg", - "filForStor": "Storleiken på fila overskrid maksimal tillaten storleik. Den maksimale storleiken er 50MB.", - "filIkkeValgt": "Ein feil oppstod under val av fil. Prøv på nytt" + "beskjedOmAvvik": "Får du ikkje ettersendt vedlegg? Då må du lasta opp vedlegget på nytt og trykkja Send inn." + }, + "filvelger": { + "defaultText": "Velg dine filer" + }, + "link": { + "nyFane": "{{tekst}} (åpnes i ny fane)" + }, + "modal": { + "fortsettSenere": { + "tittel": "Er du sikker på at du vil lagre søknaden og fortsette seinare?", + "liste": [ + "Søknaden blir IKKJE send til saksbehandlar i NAV no, men berre lagra slik at du kan fortsetja seinare.", + "Viss du ønsker å setja dagens dato som startdato for søknaden må du klikke “Avbryt” og velja “Send til NAV”.", + "Vi har oppretta ei oppgåve på nav.no/minside med ei lenke til søknaden." + ], + "accept": "Ja, lagre og fortsett seinare", + "cancel": "Avbryt" }, - "feilside": { - "404": { - "tittel": "Me fann ikkje den sida", - "overskrift": "Me fann ikkje den sida", - "p1": "Beklagar, sida kan vera sletta eller flytta, eller det var ein feil i lenkja som førte deg hit.", - "p2": "Me set pris på om du melder frå om feilen via lenkja nedanfor.", - "lenkeTekst": { - "forside": "Gå til framsida på nav.no", - "meldFra": "Meld frå om denne feilen" - } - }, - "500": { - "tittel": "Oops, noko gjekk gale", - "overskrift": "Oops, noko gjekk gale", - "p1": "Sida eller tenesta er for tida utilgjengeleg på grunn av teknisk feil.", - "p2": "Me beklagar dette. Prøv igjen seinare.", - "lenkeTekst": { - "forside": "Gå til framsida på nav.no", - "meldFra": "Meld frå om denne feilen" - } - }, - "soknadSendtInn": { - "tittel": "Feilside: Søknad er sendt inn", - "overskrift": "Du har prøvd å gå tilbake til ein søknad som allereie er send til NAV", - "melding": "Viss du skal ettersende dokumentasjon til denne søknaden må det sendast inn på papir.", - "lenkeTekst": { - "minSide": "Du finn søknaden du sendte inn på Mi side på(bokmål)", - "ettersende": "Gå til ettersending" - } - }, - "statuskode": "Statuskode" + "slett": { + "tittel": "Er du sikker på at du vil slette søknaden?", + "liste": ["Søknaden og alle dokumenta du har lastet opp vil bli slettet."], + "accept": "Ja, slett søknaden", + "cancel": "Avbryt" + }, + "sendInnUferdig": { + "tittel": " Er du sikker på at du vil senda søknaden no, sjølv om ikkje alle dokumenta er lasta opp?", + "liste": [ + "Dagens dato vil bli sett som mottaksdato for søknaden.", + "Du har ikkje lasta opp alle dokumenta som er nødvendig for å behandle søknaden.", + "Du må ettersenda dokumenta som manglar innan {{dato}}.", + "Vi har oppretta ei oppgåve på nav.no/minside med ei lenke til søknaden. Der finn du vedlegga du må ettersenda." + ], + "accept": "Ja, send søknaden", + "cancel": "Avbryt" + }, + "sendInnKomplett": { + "tittel": "Søknaden er klar til å sendast inn. Vil du senda han no?", + "liste": ["Dagens dato vil bli satt som mottaksdato."], + "accept": "Ja, send søknaden", + "cancel": "Avbryt" + } + }, + "kvittering": { + "tittel": "Takk!", + "mottattDokumenter": "Vi mottok desse dokumenta {{dato}}:", + "skjema": "Skjema", + "vedlegg": "Vedlegg", + "skjemaLenke": "Last ned kopi", + "maaEttersendes": " Dokument som må ettersendast:", + "sendesAvAndre": " Dokument som skal sendast av andre:", + "fristEttersending": "Frist for å ettersenda dokumenta: {{dato}}", + "ettersendingsInfo": "Vi kan ikkje behandla saka di før vi har tatt imot desse. Oppgåva for å ettersenda dokumentasjonen finn du på nav.no/minside.", + "altMottatInfo": "Alle nødvendige dokument er tatt imot. Du finn dei under Dine saker på nav.no/minside.", + "minSideKnapp": "Gå til Min side" + }, + "feil": { + "fraBackend": "Beklagar, vi har tekniske problem. Prøv igjen seinare. Om problemet held fram ta kontakt med NAV for å få hjelp på telefon (+47) 55 55 33 33 eller på ditt lokale NAV kontor.", + "medTilkobling": "Sjekk nettverkstilkoplinga di og prøv igjen.", + "ukjent": "Beklagar, vi har tekniske problem. Prøv igjen seinare. Om problemet held fram ta kontakt med NAV for å få hjelp på telefon (+47) 55 55 33 33 eller på ditt lokale NAV kontor.", + "advarselOverskrift": "Det har skjedd ein feil", + "advarselBrukerBekreftelse": "OK", + "manglerHovedskjema": "Du må lasta opp ferdig utfylt skjema. Gå tilbake til forrige steg", + "filForStor": "Storleiken på fila overskrid maksimal tillaten storleik. Den maksimale storleiken er 50MB.", + "filIkkeValgt": "Ein feil oppstod under val av fil. Prøv på nytt" + }, + "feilside": { + "404": { + "tittel": "Me fann ikkje den sida", + "overskrift": "Me fann ikkje den sida", + "p1": "Beklagar, sida kan vera sletta eller flytta, eller det var ein feil i lenkja som førte deg hit.", + "p2": "Me set pris på om du melder frå om feilen via lenkja nedanfor.", + "lenkeTekst": { + "forside": "Gå til framsida på nav.no", + "meldFra": "Meld frå om denne feilen" + } + }, + "500": { + "tittel": "Oops, noko gjekk gale", + "overskrift": "Oops, noko gjekk gale", + "p1": "Sida eller tenesta er for tida utilgjengeleg på grunn av teknisk feil.", + "p2": "Me beklagar dette. Prøv igjen seinare.", + "lenkeTekst": { + "forside": "Gå til framsida på nav.no", + "meldFra": "Meld frå om denne feilen" + } + }, + "soknadSendtInn": { + "tittel": "Feilside: Søknad er sendt inn", + "overskrift": "Du har prøvd å gå tilbake til ein søknad som allereie er send til NAV", + "melding": "Viss du skal ettersende dokumentasjon til denne søknaden må det sendast inn på papir.", + "lenkeTekst": { + "minSide": "Du finn søknaden du sendte inn på Mi side på(bokmål)", + "ettersende": "Gå til ettersending" + } }, - "for": "for" + "statuskode": "Statuskode" + }, + "for": "for" } diff --git a/auth/getTokenXToken.ts b/auth/getTokenXToken.ts index 3e859788..35a1b9e9 100644 --- a/auth/getTokenXToken.ts +++ b/auth/getTokenXToken.ts @@ -7,88 +7,69 @@ let _issuer: Issuer; let _client: Client; async function issuer() { - if (typeof _issuer === 'undefined') { - if (!process.env.TOKEN_X_WELL_KNOWN_URL) - throw new TypeError( - 'Miljøvariabelen "TOKEN_X_WELL_KNOWN_URL må være satt', - ); - _issuer = await Issuer.discover( - process.env.TOKEN_X_WELL_KNOWN_URL, - ); - } - return _issuer; + if (typeof _issuer === 'undefined') { + if (!process.env.TOKEN_X_WELL_KNOWN_URL) + throw new TypeError('Miljøvariabelen "TOKEN_X_WELL_KNOWN_URL må være satt'); + _issuer = await Issuer.discover(process.env.TOKEN_X_WELL_KNOWN_URL); + } + return _issuer; } function jwk() { - if (!process.env.TOKEN_X_PRIVATE_JWK) - throw new TypeError( - 'Miljøvariabelen "TOKEN_X_PRIVATE_JWK må være satt', - ); - return JSON.parse(process.env.TOKEN_X_PRIVATE_JWK); + if (!process.env.TOKEN_X_PRIVATE_JWK) throw new TypeError('Miljøvariabelen "TOKEN_X_PRIVATE_JWK må være satt'); + return JSON.parse(process.env.TOKEN_X_PRIVATE_JWK); } async function client() { - if (typeof _client === 'undefined') { - if (!process.env.TOKEN_X_CLIENT_ID) - throw new TypeError( - 'Miljøvariabelen "TOKEN_X_CLIENT_ID må være satt', - ); + if (typeof _client === 'undefined') { + if (!process.env.TOKEN_X_CLIENT_ID) throw new TypeError('Miljøvariabelen "TOKEN_X_CLIENT_ID må være satt'); - const _jwk = jwk(); - const _issuer = await issuer(); - _client = new _issuer.Client( - { - client_id: process.env.TOKEN_X_CLIENT_ID, - token_endpoint_auth_method: 'private_key_jwt', - }, - { keys: [_jwk] }, - ); - } - return _client; + const _jwk = jwk(); + const _issuer = await issuer(); + _client = new _issuer.Client( + { + client_id: process.env.TOKEN_X_CLIENT_ID, + token_endpoint_auth_method: 'private_key_jwt', + }, + { keys: [_jwk] }, + ); + } + return _client; } -export async function getTokenxToken( - subject_token: string, - audience: string, -) { - const _client = await client(); +export async function getTokenxToken(subject_token: string, audience: string) { + const _client = await client(); - const now = Math.floor(Date.now() / 1000); - const additionalClaims = { - clientAssertionPayload: { - nbf: now, - aud: _client.issuer.metadata.token_endpoint, - }, - }; + const now = Math.floor(Date.now() / 1000); + const additionalClaims = { + clientAssertionPayload: { + nbf: now, + aud: _client.issuer.metadata.token_endpoint, + }, + }; - const grantBody: GrantBody = { - grant_type: 'urn:ietf:params:oauth:grant-type:token-exchange', - client_assertion_type: - 'urn:ietf:params:oauth:client-assertion-type:jwt-bearer', - subject_token_type: 'urn:ietf:params:oauth:token-type:jwt', - audience, - subject_token, - }; + const grantBody: GrantBody = { + grant_type: 'urn:ietf:params:oauth:grant-type:token-exchange', + client_assertion_type: 'urn:ietf:params:oauth:client-assertion-type:jwt-bearer', + subject_token_type: 'urn:ietf:params:oauth:token-type:jwt', + audience, + subject_token, + }; - try { - const grant = await _client.grant( - grantBody, - additionalClaims, - ); - if (!grant.access_token) { - throw new Error( - 'TokenX: Mangler accessToken etter token exchange', - ); - } - return grant.access_token; - } catch (err) { - if (err instanceof OPError) { - rawLogger.error({ - statusCode: err.response?.statusCode, - statusMessage: err.response?.statusMessage, - message: `Noe gikk galt med token exchange mot TokenX: ${err.error}`, - }); - } - throw err; + try { + const grant = await _client.grant(grantBody, additionalClaims); + if (!grant.access_token) { + throw new Error('TokenX: Mangler accessToken etter token exchange'); + } + return grant.access_token; + } catch (err) { + if (err instanceof OPError) { + rawLogger.error({ + statusCode: err.response?.statusCode, + statusMessage: err.response?.statusMessage, + message: `Noe gikk galt med token exchange mot TokenX: ${err.error}`, + }); } + throw err; + } } diff --git a/auth/verifyIdPortenToken.ts b/auth/verifyIdPortenToken.ts index 8f7ae59f..292ae1ee 100644 --- a/auth/verifyIdPortenToken.ts +++ b/auth/verifyIdPortenToken.ts @@ -1,70 +1,54 @@ -import { - createRemoteJWKSet, - FlattenedJWSInput, - JWSHeaderParameters, - jwtVerify, - JWTPayload, -} from 'jose'; +import { FlattenedJWSInput, JWSHeaderParameters, JWTPayload, createRemoteJWKSet, jwtVerify } from 'jose'; import { GetKeyFunction } from 'jose/dist/types/types'; import { Client, Issuer } from 'openid-client'; let _issuer: Issuer; -let _remoteJWKSet: GetKeyFunction< - JWSHeaderParameters, - FlattenedJWSInput ->; +let _remoteJWKSet: GetKeyFunction; async function validerToken(token: string | Uint8Array) { - return jwtVerify(token, await jwks(), { - issuer: (await issuer()).metadata.issuer, - }); + return jwtVerify(token, await jwks(), { + issuer: (await issuer()).metadata.issuer, + }); } async function jwks() { - if (typeof _remoteJWKSet === 'undefined') { - const iss = await issuer(); - _remoteJWKSet = createRemoteJWKSet( - new URL(iss.metadata.jwks_uri), - ); - } + if (typeof _remoteJWKSet === 'undefined') { + const iss = await issuer(); + _remoteJWKSet = createRemoteJWKSet(new URL(iss.metadata.jwks_uri)); + } - return _remoteJWKSet; + return _remoteJWKSet; } async function issuer() { - if (typeof _issuer === 'undefined') { - if (!process.env.IDPORTEN_WELL_KNOWN_URL) - throw new Error( - 'Miljøvariabelen "IDPORTEN_WELL_KNOWN_URL" må være satt', - ); - _issuer = await Issuer.discover( - process.env.IDPORTEN_WELL_KNOWN_URL, - ); - } - return _issuer; + if (typeof _issuer === 'undefined') { + if (!process.env.IDPORTEN_WELL_KNOWN_URL) throw new Error('Miljøvariabelen "IDPORTEN_WELL_KNOWN_URL" må være satt'); + _issuer = await Issuer.discover(process.env.IDPORTEN_WELL_KNOWN_URL); + } + return _issuer; } export const isExpired = (payload: JWTPayload) => { - if (payload?.exp && payload.exp * 1000 <= Date.now()) { - return true; - } - return false; + if (payload?.exp && payload.exp * 1000 <= Date.now()) { + return true; + } + return false; }; export async function verifyIdportenAccessToken(token: string) { - const verified = await validerToken(token); - if (isExpired(verified.payload)) { - throw new Error('IdPortenToken is expired'); - } + const verified = await validerToken(token); + if (isExpired(verified.payload)) { + throw new Error('IdPortenToken is expired'); + } - const { client_id, acr } = verified.payload; + const { client_id, acr } = verified.payload; - if (client_id !== process.env.IDPORTEN_CLIENT_ID) { - throw new Error('client_id matcher ikke min client ID'); - } + if (client_id !== process.env.IDPORTEN_CLIENT_ID) { + throw new Error('client_id matcher ikke min client ID'); + } - if (acr !== 'Level4' && acr !== 'idporten-loa-high') { - throw new Error('For lavt sikkerhetsnivå - acr: ' + acr); - } - return verified; + if (acr !== 'Level4' && acr !== 'idporten-loa-high') { + throw new Error('For lavt sikkerhetsnivå - acr: ' + acr); + } + return verified; } diff --git a/components/AuthenticationProvider.tsx b/components/AuthenticationProvider.tsx index ab469bf4..3cd6d71f 100644 --- a/components/AuthenticationProvider.tsx +++ b/components/AuthenticationProvider.tsx @@ -1,19 +1,17 @@ +import { useRouter } from 'next/router'; import React from 'react'; import useUser from '../hooks/useUser'; -import { useRouter } from 'next/router'; interface AuthenticationProviderProps { - children?: React.ReactNode; + children?: React.ReactNode; } -export function AuthenticationProvider({ - children, -}: AuthenticationProviderProps) { - const router = useRouter(); - const { user } = useUser({ - redirectTo: '/redirect/login', - redirectedFrom: router.basePath + router.asPath, - }); +export function AuthenticationProvider({ children }: AuthenticationProviderProps) { + const router = useRouter(); + const { user } = useUser({ + redirectTo: '/redirect/login', + redirectedFrom: router.basePath + router.asPath, + }); - return <>{user?.isLoggedIn ? children : null}; + return <>{user?.isLoggedIn ? children : null}; } diff --git a/components/AutomatiskInnsending.tsx b/components/AutomatiskInnsending.tsx index 64b6c6b9..959d6d86 100644 --- a/components/AutomatiskInnsending.tsx +++ b/components/AutomatiskInnsending.tsx @@ -1,23 +1,19 @@ -import { useEffect, useState } from 'react'; -import { useVedleggslisteContext } from './VedleggsListe'; import { BodyLong } from '@navikt/ds-react'; +import { useEffect, useState } from 'react'; import { useTranslation } from 'react-i18next'; +import { useVedleggslisteContext } from './VedleggsListe'; export const AutomatiskInnsending = () => { - const { onSendInn } = useVedleggslisteContext(); - const { t } = useTranslation(); - const [skalSendeInn, setSkalSendeInn] = useState(true); + const { onSendInn } = useVedleggslisteContext(); + const { t } = useTranslation(); + const [skalSendeInn, setSkalSendeInn] = useState(true); - useEffect(() => { - if (skalSendeInn) { - setSkalSendeInn(false); - onSendInn(); - } - }, [onSendInn, skalSendeInn]); + useEffect(() => { + if (skalSendeInn) { + setSkalSendeInn(false); + onSendInn(); + } + }, [onSendInn, skalSendeInn]); - return ( - - {t('soknad.visningsSteg.fraFyllutUtenVedlegg.laster')} - - ); + return {t('soknad.visningsSteg.fraFyllutUtenVedlegg.laster')}; }; diff --git a/components/AxiosInterceptor.tsx b/components/AxiosInterceptor.tsx index 713dca9d..d45eb73d 100644 --- a/components/AxiosInterceptor.tsx +++ b/components/AxiosInterceptor.tsx @@ -3,42 +3,32 @@ import { useRouter } from 'next/router'; import React, { useEffect, useState } from 'react'; interface PropsAxiosInterceptor { - children: React.ReactNode; + children: React.ReactNode; } -export const AxiosInterceptor = ({ - children, -}: PropsAxiosInterceptor) => { - const [isSet, setIsSet] = useState(false); - - const router = useRouter(); - - useEffect(() => { - const responseInterceptor = (response: AxiosResponse) => { - return response; - }; - - const errorInterceptor = (error: AxiosError) => { - if (error.response?.status === 401) { - router.push( - 'redirect/login?redirect=' + - encodeURIComponent( - router.basePath + router.asPath, - ), - ); - } - return Promise.reject(error); - }; - - const interceptor = axios.interceptors.response.use( - responseInterceptor, - errorInterceptor, - ); - - setIsSet(true); - - return () => axios.interceptors.response.eject(interceptor); - }, [router]); - - return <>{isSet && children}; +export const AxiosInterceptor = ({ children }: PropsAxiosInterceptor) => { + const [isSet, setIsSet] = useState(false); + + const router = useRouter(); + + useEffect(() => { + const responseInterceptor = (response: AxiosResponse) => { + return response; + }; + + const errorInterceptor = (error: AxiosError) => { + if (error.response?.status === 401) { + router.push('redirect/login?redirect=' + encodeURIComponent(router.basePath + router.asPath)); + } + return Promise.reject(error); + }; + + const interceptor = axios.interceptors.response.use(responseInterceptor, errorInterceptor); + + setIsSet(true); + + return () => axios.interceptors.response.eject(interceptor); + }, [router]); + + return <>{isSet && children}; }; diff --git a/components/EndreVedlegg.tsx b/components/EndreVedlegg.tsx index f882c2cc..f13673de 100644 --- a/components/EndreVedlegg.tsx +++ b/components/EndreVedlegg.tsx @@ -1,143 +1,112 @@ -import React, { useState } from 'react'; -import { useForm, SubmitHandler } from 'react-hook-form'; -import axios from 'axios'; import { Button, TextField } from '@navikt/ds-react'; -import { VedleggType } from '../types/types'; +import axios from 'axios'; import getConfig from 'next/config'; -import styled from 'styled-components'; +import { useState } from 'react'; +import { SubmitHandler, useForm } from 'react-hook-form'; import { useTranslation } from 'react-i18next'; -import { useValidation } from '../hooks/useValidation'; +import styled from 'styled-components'; import { useErrorMessage } from '../hooks/useErrorMessage'; -import { VedleggPanel } from './Vedlegg'; +import { useValidation } from '../hooks/useValidation'; +import { VedleggType } from '../types/types'; import { ValideringsRamme } from './ValideringsRamme'; +import { VedleggPanel } from './Vedlegg'; const { publicRuntimeConfig } = getConfig(); const ButtonRow = styled.div` - margin-top: 24px; + margin-top: 24px; `; export interface EndreVedleggProps { - tittel: string; - setEndrer: (arg: boolean) => void; - vedlegg: VedleggType; - innsendingsId: string; - setTittel: (arg: string) => void; + tittel: string; + setEndrer: (arg: boolean) => void; + vedlegg: VedleggType; + innsendingsId: string; + setTittel: (arg: string) => void; } type FormValues = { - tittel: string; + tittel: string; }; -export function EndreVedlegg({ - tittel, - setEndrer, - vedlegg, - innsendingsId, - setTittel, -}: EndreVedleggProps) { - const { t } = useTranslation(); - const [isLoading, setIsLoading] = useState(false); - const { - register, - handleSubmit, - formState: { errors }, - } = useForm(); - const { showError } = useErrorMessage(); +export function EndreVedlegg({ tittel, setEndrer, vedlegg, innsendingsId, setTittel }: EndreVedleggProps) { + const { t } = useTranslation(); + const [isLoading, setIsLoading] = useState(false); + const { + register, + handleSubmit, + formState: { errors }, + } = useForm(); + const { showError } = useErrorMessage(); - const feilId = `vedlegg-endrer-feil-${vedlegg.id}`; + const feilId = `vedlegg-endrer-feil-${vedlegg.id}`; - const harVailderingfeil = errors.tittel?.message != undefined; + const harVailderingfeil = errors.tittel?.message != undefined; - const [visFeil, valideringsMelding] = useValidation({ - komponentId: feilId, - melding: t( - 'soknad.vedlegg.annet.feilmelding.fullforRedigering', - ), - harFeil: !harVailderingfeil, - }); + const [visFeil, valideringsMelding] = useValidation({ + komponentId: feilId, + melding: t('soknad.vedlegg.annet.feilmelding.fullforRedigering'), + harFeil: !harVailderingfeil, + }); - useValidation({ - komponentId: feilId + '-validering', - melding: errors.tittel?.message || '', - harFeil: harVailderingfeil, - }); + useValidation({ + komponentId: feilId + '-validering', + melding: errors.tittel?.message || '', + harFeil: harVailderingfeil, + }); - const onSubmit: SubmitHandler = (data) => { - setIsLoading(true); + const onSubmit: SubmitHandler = (data) => { + setIsLoading(true); - axios - .patch( - `${publicRuntimeConfig.apiUrl}/frontend/v1/soknad/${innsendingsId}/vedlegg/${vedlegg.id}`, - { - tittel: data.tittel, - }, - ) - .then(() => { - setTittel(data.tittel); - }) - .catch((error) => { - showError(error); - }) - .finally(() => { - setIsLoading(false); - setEndrer(false); - }); - }; - const maxLength = 250; + axios + .patch(`${publicRuntimeConfig.apiUrl}/frontend/v1/soknad/${innsendingsId}/vedlegg/${vedlegg.id}`, { + tittel: data.tittel, + }) + .then(() => { + setTittel(data.tittel); + }) + .catch((error) => { + showError(error); + }) + .finally(() => { + setIsLoading(false); + setEndrer(false); + }); + }; + const maxLength = 250; - return ( - - -
- - - - - - -
-
- ); + return ( + + +
+ + + + + + +
+
+ ); } diff --git a/components/ErrorMessageProvider.tsx b/components/ErrorMessageProvider.tsx index a4005c6a..378efb0d 100644 --- a/components/ErrorMessageProvider.tsx +++ b/components/ErrorMessageProvider.tsx @@ -1,69 +1,64 @@ import { BodyLong, Heading } from '@navikt/ds-react'; -import { useState, createContext, useContext } from 'react'; +import { createContext, useContext, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { FellesModal } from './FellesModal'; interface ErrorMessageProviderProps { - children?: React.ReactNode; + children?: React.ReactNode; } export type ErrorMessageType = { - message: string; - title?: string; + message: string; + title?: string; }; interface ErrorMessageContextType { - open: boolean; - setOpen: React.Dispatch>; - error: ErrorMessageType; - setError: React.Dispatch>; + open: boolean; + setOpen: React.Dispatch>; + error: ErrorMessageType; + setError: React.Dispatch>; } -const ErrorMessageContext = - createContext(null); +const ErrorMessageContext = createContext(null); export const useErrorMessageContext = () => { - const errorMessageContext = useContext(ErrorMessageContext); - if (!errorMessageContext) { - throw new Error( - 'Mangler ErrorMessageProvider, når useErrorMessageContext kalles', - ); - } - return errorMessageContext; + const errorMessageContext = useContext(ErrorMessageContext); + if (!errorMessageContext) { + throw new Error('Mangler ErrorMessageProvider, når useErrorMessageContext kalles'); + } + return errorMessageContext; }; -export const ErrorMessageProvider = ({ - children, -}: ErrorMessageProviderProps) => { - const { t } = useTranslation(); - const defaultTitle = t('feil.advarselOverskrift'); - const [open, setOpen] = useState(false); - const [error, setError] = useState({ - message: '', - }); +export const ErrorMessageProvider = ({ children }: ErrorMessageProviderProps) => { + const { t } = useTranslation(); + const defaultTitle = t('feil.advarselOverskrift'); + const [open, setOpen] = useState(false); + const [error, setError] = useState({ + message: '', + }); - const value = { - open, - setOpen, - error, - setError, - }; + const value = { + open, + setOpen, + error, + setError, + }; - return ( - - {children} + return ( + + {children} - - - {error.title || defaultTitle} - + + + {error.title || defaultTitle} + - {error.message} - - - ); + {error.message} + + + ); }; diff --git a/components/FellesModal.tsx b/components/FellesModal.tsx index 25948a2a..b4472db7 100644 --- a/components/FellesModal.tsx +++ b/components/FellesModal.tsx @@ -1,98 +1,98 @@ +import { Button, ButtonProps, Modal } from '@navikt/ds-react'; import React, { useEffect } from 'react'; -import { Modal, Button, ButtonProps } from '@navikt/ds-react'; import styled from 'styled-components'; const StyledModal = styled(Modal)` - max-width: 700px; + max-width: 700px; `; const ButtonRow = styled.div` - padding-top: 37px; - display: flex; - justify-content: right; - button { - margin: 0 12px; - } + padding-top: 37px; + display: flex; + justify-content: right; + button { + margin: 0 12px; + } `; const StyledContent = styled(Modal.Content)` - > *:first-child { - margin-right: 36px; - } + > *:first-child { + margin-right: 36px; + } + ol, + ul { + padding-left: 1.75rem; + } + @media only screen and (max-width: 600px) { ol, ul { - padding-left: 1.75rem; - } - @media only screen and (max-width: 600px) { - ol, - ul { - padding-left: 1.5rem; - } + padding-left: 1.5rem; } + } `; type FellesModalProps = { - open: boolean; - setOpen(isOpen: boolean): void; - children?: React.ReactNode; - onAccept?: () => void; - acceptButtonText?: string; - cancelButtonText?: string; - acceptButtonVariant?: ButtonProps['variant']; - cancelButtonVariant?: ButtonProps['variant']; - isLoading?: boolean; + open: boolean; + setOpen(isOpen: boolean): void; + children?: React.ReactNode; + onAccept?: () => void; + acceptButtonText?: string; + cancelButtonText?: string; + acceptButtonVariant?: ButtonProps['variant']; + cancelButtonVariant?: ButtonProps['variant']; + isLoading?: boolean; }; export const FellesModal = (props: FellesModalProps) => { - const { - open, - setOpen, - onAccept, - children, - acceptButtonText = null, - cancelButtonText = null, - acceptButtonVariant = 'primary', - cancelButtonVariant = 'tertiary', - isLoading = false, - } = props; + const { + open, + setOpen, + onAccept, + children, + acceptButtonText = null, + cancelButtonText = null, + acceptButtonVariant = 'primary', + cancelButtonVariant = 'tertiary', + isLoading = false, + } = props; - useEffect(() => { - Modal.setAppElement('#__next'); - }, []); + useEffect(() => { + Modal.setAppElement('#__next'); + }, []); - return ( - <> - setOpen(false)}> - - {children} - {(acceptButtonText || cancelButtonText) && ( - - {cancelButtonText && ( - - )} - {acceptButtonText && ( - - )} - - )} - - - - ); + return ( + <> + setOpen(false)}> + + {children} + {(acceptButtonText || cancelButtonText) && ( + + {cancelButtonText && ( + + )} + {acceptButtonText && ( + + )} + + )} + + + + ); }; diff --git a/components/Fil.tsx b/components/Fil.tsx index 727f0877..c3ebea86 100644 --- a/components/Fil.tsx +++ b/components/Fil.tsx @@ -1,592 +1,503 @@ -import React, { useState, useEffect, useReducer } from 'react'; -import axios, { - AxiosError, - AxiosProgressEvent, - AxiosResponse, -} from 'axios'; -import { useErrorMessage } from '../hooks/useErrorMessage'; -import { ACTIONS, ActionType } from './Vedlegg'; -import { - ErrorResponsDto, - OpplastetFil, - VedleggType, -} from '../types/types'; -import { - Button, - Panel, - BodyShort, - Link as NavLink, -} from '@navikt/ds-react'; -import styled from 'styled-components'; +import { BodyShort, Button, Link as NavLink, Panel } from '@navikt/ds-react'; +import axios, { AxiosError, AxiosProgressEvent, AxiosResponse } from 'axios'; +import getConfig from 'next/config'; +import React, { useEffect, useReducer, useState } from 'react'; import { useTranslation } from 'react-i18next'; +import styled from 'styled-components'; +import { useErrorMessage } from '../hooks/useErrorMessage'; +import { useValidation } from '../hooks/useValidation'; import { FIL_STATUS } from '../types/enums'; +import { ErrorResponsDto, OpplastetFil, VedleggType } from '../types/types'; import { FilUploadIcon } from './FilUploadIcon'; -import getConfig from 'next/config'; import { Filvelger } from './Filvelger'; -import { useValidation } from '../hooks/useValidation'; -import { ErrorMessageWithDot, ScreenReaderOnly } from './textStyle'; +import { ACTIONS, ActionType } from './Vedlegg'; import { useVedleggslisteContext } from './VedleggsListe'; +import { ErrorMessageWithDot, ScreenReaderOnly } from './textStyle'; const { publicRuntimeConfig } = getConfig(); const API_URL = publicRuntimeConfig.apiUrl; -const MAX_FILE_SIZE_IN_MB = parseInt( - process.env.NEXT_PUBLIC_MAX_FILE_SIZE_IN_MB!, -); +const MAX_FILE_SIZE_IN_MB = parseInt(process.env.NEXT_PUBLIC_MAX_FILE_SIZE_IN_MB!); const MAX_FILE_SIZE = MAX_FILE_SIZE_IN_MB * 1024 * 1024; export const FilePanel = styled(Panel)` - border-width: 2px; - border-radius: 8px; - - .icon { - grid-area: icon; - display: flex; - justify-content: flex-start; - align-items: center; - } - .filename { - grid-area: filename; - color: var(--a-text-subtle); - justify-items: left; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - a { - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - display: block; - } + border-width: 2px; + border-radius: 8px; + + .icon { + grid-area: icon; + display: flex; + justify-content: flex-start; + align-items: center; + } + .filename { + grid-area: filename; + color: var(--a-text-subtle); + justify-items: left; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + a { + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + display: block; } - .fileinfo { - grid-area: fileinfo; - justify-items: left; - } - .hoyreHalvdel { - grid-area: hoyreHalvdel; - display: flex; - flex-flow: row wrap; - justify-content: flex-end; - @media only screen and (max-width: 600px) { - justify-content: center; - margin-top: 16px; - width: 100%; - } + } + .fileinfo { + grid-area: fileinfo; + justify-items: left; + } + .hoyreHalvdel { + grid-area: hoyreHalvdel; + display: flex; + flex-flow: row wrap; + justify-content: flex-end; + @media only screen and (max-width: 600px) { + justify-content: center; + margin-top: 16px; + width: 100%; } + } - display: grid; + display: grid; - grid-template-columns: 53px auto auto; - grid-template-areas: - 'icon filename hoyreHalvdel hoyreHalvdel' - 'icon fileinfo hoyreHalvdel hoyreHalvdel'; + grid-template-columns: 53px auto auto; + grid-template-areas: + 'icon filename hoyreHalvdel hoyreHalvdel' + 'icon fileinfo hoyreHalvdel hoyreHalvdel'; - padding: 12px 8px; + padding: 12px 8px; - ${(props) => - props.type === FIL_STATUS.FEIL && - 'border-color: var(--a-surface-danger)'}; + ${(props) => props.type === FIL_STATUS.FEIL && 'border-color: var(--a-surface-danger)'}; - @media only screen and (max-width: 600px) { - grid-template-areas: - 'icon filename filename' - 'icon fileinfo fileinfo' - 'hoyreHalvdel hoyreHalvdel hoyreHalvdel'; - - button, - label { - width: 100%; - } + @media only screen and (max-width: 600px) { + grid-template-areas: + 'icon filename filename' + 'icon fileinfo fileinfo' + 'hoyreHalvdel hoyreHalvdel hoyreHalvdel'; + + button, + label { + width: 100%; } + } `; const StyledButton = styled.div` - /* button, + /* button, label { border-radius: 4px; } */ - @media only screen and (max-width: 600px) { - width: 100%; - } + @media only screen and (max-width: 600px) { + width: 100%; + } `; const StyledProvIgjenButton = styled(StyledButton)` - label { - background-color: var(--a-surface-action-subtle-hover); - } - label:hover { - background-color: var(--a-surface-action-hover); - color: var(--a-text-on-inverted); - } + label { + background-color: var(--a-surface-action-subtle-hover); + } + label:hover { + background-color: var(--a-surface-action-hover); + color: var(--a-text-on-inverted); + } `; const StyledTertiaryButton = styled(StyledButton)` - @media only screen and (max-width: 600px) { - :first-child { - border-top: 1px solid var(--a-border-divider); - } - :first-child:last-child { - margin-bottom: -0.75rem; - } + @media only screen and (max-width: 600px) { + :first-child { + border-top: 1px solid var(--a-border-divider); } + :first-child:last-child { + margin-bottom: -0.75rem; + } + } `; export interface FilProps { - komponentID: string; - vedlegg: VedleggType; - innsendingsId: string; - lokalFil?: File; - opplastetFil?: OpplastetFil; - filListeDispatch: React.Dispatch; + komponentID: string; + vedlegg: VedleggType; + innsendingsId: string; + lokalFil?: File; + opplastetFil?: OpplastetFil; + filListeDispatch: React.Dispatch; } export interface FilData { - komponentID?: string; - lokalFil?: File; - opplastetFil?: OpplastetFil; + komponentID?: string; + lokalFil?: File; + opplastetFil?: OpplastetFil; } export const FIL_ACTIONS = { - START_OPPLASTNING: 'START_OPPLASTNING', - OPPDATER_PROGRESS: 'OPPDATER_PROGRESS', - SETT_STATUS: 'SETT_STATUS', - OPPLASTET: 'OPPLASTET', - LAST_OPP_NY_FIL: 'LAST_OPP_NY_FIL', - AVBRYT: 'AVBRYT', - FEIL: 'FEIL', + START_OPPLASTNING: 'START_OPPLASTNING', + OPPDATER_PROGRESS: 'OPPDATER_PROGRESS', + SETT_STATUS: 'SETT_STATUS', + OPPLASTET: 'OPPLASTET', + LAST_OPP_NY_FIL: 'LAST_OPP_NY_FIL', + AVBRYT: 'AVBRYT', + FEIL: 'FEIL', } as const; export interface FilState { - filData?: FilData; - progress?: number; - status?: (typeof FIL_STATUS)[keyof typeof FIL_STATUS]; + filData?: FilData; + progress?: number; + status?: (typeof FIL_STATUS)[keyof typeof FIL_STATUS]; } export interface FilActionType { - type: (typeof FIL_ACTIONS)[keyof typeof FIL_ACTIONS]; - filState?: FilState; + type: (typeof FIL_ACTIONS)[keyof typeof FIL_ACTIONS]; + filState?: FilState; } -const filValidering = ( - fil?: File, -): { harFeil: boolean; melding?: 'filForStor' | 'filIkkeValgt' } => { - if (!fil) { - return { harFeil: true, melding: 'filIkkeValgt' }; - } - if (fil.size > MAX_FILE_SIZE) { - return { harFeil: true, melding: 'filForStor' }; - } - return { harFeil: false }; +const filValidering = (fil?: File): { harFeil: boolean; melding?: 'filForStor' | 'filIkkeValgt' } => { + if (!fil) { + return { harFeil: true, melding: 'filIkkeValgt' }; + } + if (fil.size > MAX_FILE_SIZE) { + return { harFeil: true, melding: 'filForStor' }; + } + return { harFeil: false }; }; const filStorrelseVisning = (bytes: number): string => { - const enheter = ['B', 'KB', 'MB', 'GB', 'TB']; - if (bytes == 0) return '0 B'; - const indeksIEnheter = Math.floor( - Math.log(bytes) / Math.log(1024), - ); - const enhet = enheter[indeksIEnheter]; - const storrelserIEnhet = Math.round( - bytes / Math.pow(1024, indeksIEnheter), - ); - - return `${storrelserIEnhet} ${enhet}`; + const enheter = ['B', 'KB', 'MB', 'GB', 'TB']; + if (bytes == 0) return '0 B'; + const indeksIEnheter = Math.floor(Math.log(bytes) / Math.log(1024)); + const enhet = enheter[indeksIEnheter]; + const storrelserIEnhet = Math.round(bytes / Math.pow(1024, indeksIEnheter)); + + return `${storrelserIEnhet} ${enhet}`; }; -const filReducer = ( - filState: FilState, - action: FilActionType, -): FilState => { - console.debug('Dispatcher:', action.type); - switch (action.type) { - case FIL_ACTIONS.START_OPPLASTNING: { - return { - ...filState, - status: FIL_STATUS.STARTER_OPPLASTNING, - filData: action.filState?.filData, - }; - } - case FIL_ACTIONS.LAST_OPP_NY_FIL: { - return { - ...filState, - status: FIL_STATUS.STARTER_OPPLASTNING, - filData: action.filState?.filData, - }; - } - case FIL_ACTIONS.OPPLASTET: { - return { - ...filState, - status: FIL_STATUS.OPPLASTET, - filData: action.filState?.filData, - }; - } - case FIL_ACTIONS.OPPDATER_PROGRESS: { - return { - ...filState, - progress: action.filState?.progress, - }; - } - case FIL_ACTIONS.AVBRYT: { - return { - ...filState, - status: FIL_STATUS.FEIL, - }; - } - case FIL_ACTIONS.FEIL: { - return { - ...filState, - status: FIL_STATUS.FEIL, - }; - } - case FIL_ACTIONS.SETT_STATUS: { - console.debug('Status:', action.filState?.status); - return { - ...filState, - status: action.filState?.status, - }; - } +const filReducer = (filState: FilState, action: FilActionType): FilState => { + console.debug('Dispatcher:', action.type); + switch (action.type) { + case FIL_ACTIONS.START_OPPLASTNING: { + return { + ...filState, + status: FIL_STATUS.STARTER_OPPLASTNING, + filData: action.filState?.filData, + }; + } + case FIL_ACTIONS.LAST_OPP_NY_FIL: { + return { + ...filState, + status: FIL_STATUS.STARTER_OPPLASTNING, + filData: action.filState?.filData, + }; } + case FIL_ACTIONS.OPPLASTET: { + return { + ...filState, + status: FIL_STATUS.OPPLASTET, + filData: action.filState?.filData, + }; + } + case FIL_ACTIONS.OPPDATER_PROGRESS: { + return { + ...filState, + progress: action.filState?.progress, + }; + } + case FIL_ACTIONS.AVBRYT: { + return { + ...filState, + status: FIL_STATUS.FEIL, + }; + } + case FIL_ACTIONS.FEIL: { + return { + ...filState, + status: FIL_STATUS.FEIL, + }; + } + case FIL_ACTIONS.SETT_STATUS: { + console.debug('Status:', action.filState?.status); + return { + ...filState, + status: action.filState?.status, + }; + } + } }; const initialState: FilState = { - progress: 0, - status: FIL_STATUS.OPPRETTET, - filData: {}, + progress: 0, + status: FIL_STATUS.OPPRETTET, + filData: {}, }; export function Fil({ - komponentID, - opplastetFil: opplastetFilProp, - lokalFil: lokalFilProp, - innsendingsId, - vedlegg, - filListeDispatch, + komponentID, + opplastetFil: opplastetFilProp, + lokalFil: lokalFilProp, + innsendingsId, + vedlegg, + filListeDispatch, }: FilProps) { - const [filState, dispatch] = useReducer(filReducer, initialState); - const { status } = filState; - const [controller] = useState(new AbortController()); - const { t } = useTranslation(); - const { t: tB } = useTranslation('backend'); - const [feilmelding, setFeilmelding] = useState( - null, - ); - const { showError } = useErrorMessage(); - - const { oppdaterLokalOpplastingStatus } = - useVedleggslisteContext(); - - const filnavn = - filState.filData?.opplastetFil?.filnavn || - filState.filData?.lokalFil?.name; - - useValidation({ - komponentId: komponentID, - melding: t( - 'soknad.vedlegg.fil.feilmelding.provIgjenEllerFjern', - { filnavn }, - ), - harFeil: - status !== FIL_STATUS.OPPLASTET && - status !== FIL_STATUS.TIDLIGERE_LASTET_OPP && - status !== FIL_STATUS.LASTER_OPP, + const [filState, dispatch] = useReducer(filReducer, initialState); + const { status } = filState; + const [controller] = useState(new AbortController()); + const { t } = useTranslation(); + const { t: tB } = useTranslation('backend'); + const [feilmelding, setFeilmelding] = useState(null); + const { showError } = useErrorMessage(); + + const { oppdaterLokalOpplastingStatus } = useVedleggslisteContext(); + + const filnavn = filState.filData?.opplastetFil?.filnavn || filState.filData?.lokalFil?.name; + + useValidation({ + komponentId: komponentID, + melding: t('soknad.vedlegg.fil.feilmelding.provIgjenEllerFjern', { filnavn }), + harFeil: + status !== FIL_STATUS.OPPLASTET && status !== FIL_STATUS.TIDLIGERE_LASTET_OPP && status !== FIL_STATUS.LASTER_OPP, + }); + + useValidation({ + komponentId: komponentID, + melding: t('soknad.vedlegg.fil.feilmelding.ikkeFerdigOpplastet'), + harFeil: status === FIL_STATUS.LASTER_OPP, + }); + + const slettFil = () => { + dispatch({ + type: FIL_ACTIONS.SETT_STATUS, + filState: { status: FIL_STATUS.SLETTER }, }); + if (!filState.filData?.opplastetFil) { + filListeDispatch({ + type: ACTIONS.SLETT_FIL, + filData: { komponentID }, + }); + return; + } + axios + .delete( + `${API_URL}/frontend/v1/soknad/${innsendingsId}/vedlegg/${vedlegg.id}/fil/${filState.filData.opplastetFil.id}`, + ) + .then((response) => { + filListeDispatch({ + type: ACTIONS.SLETT_FIL, + filData: { komponentID }, + }); + oppdaterLokalOpplastingStatus(vedlegg.id, response.data.opplastingsStatus); + }) + .catch((error) => { + dispatch({ + type: FIL_ACTIONS.FEIL, + }); + showError(error); + }); + }; + + useEffect(() => { + if (status === FIL_STATUS.OPPRETTET) { + dispatch({ + type: opplastetFilProp ? FIL_ACTIONS.OPPLASTET : FIL_ACTIONS.START_OPPLASTNING, + filState: { + filData: { + opplastetFil: opplastetFilProp, + lokalFil: lokalFilProp, + }, + }, + }); + } + if (status !== FIL_STATUS.STARTER_OPPLASTNING) return; + + const lokalFil = filState.filData?.lokalFil; + const { harFeil, melding } = filValidering(lokalFil); + if (harFeil) { + dispatch({ + type: FIL_ACTIONS.FEIL, + }); + setFeilmelding(t(`feil.${melding!}`)); + return; + } - useValidation({ - komponentId: komponentID, - melding: t( - 'soknad.vedlegg.fil.feilmelding.ikkeFerdigOpplastet', - ), - harFeil: status === FIL_STATUS.LASTER_OPP, + const formData = new FormData(); + formData.append('file', lokalFil!); + const config = { + headers: { + 'Content-Type': 'multipart/form-data', + }, + signal: controller.signal, + onUploadProgress: (progressEvent: AxiosProgressEvent) => { + const totalSize = progressEvent.total; + const progress = totalSize ? Math.round((progressEvent.loaded * 100) / totalSize) : 0; + dispatch({ + type: FIL_ACTIONS.OPPDATER_PROGRESS, + filState: { progress }, + }); + console.debug({ progress }); + }, + }; + dispatch({ + type: FIL_ACTIONS.SETT_STATUS, + filState: { status: FIL_STATUS.LASTER_OPP }, }); - const slettFil = () => { + axios + .post(`${API_URL}/frontend/v1/soknad/${innsendingsId}/vedlegg/${vedlegg.id}/fil`, formData, config) + .then((response: AxiosResponse) => { + const filData = { + opplastetFil: { + id: response.data.id, + filnavn: lokalFil!.name, + storrelse: response.data.storrelse, + }, + }; dispatch({ - type: FIL_ACTIONS.SETT_STATUS, - filState: { status: FIL_STATUS.SLETTER }, + type: FIL_ACTIONS.OPPLASTET, + filState: { + filData, + }, + }); + filListeDispatch({ + type: ACTIONS.ENDRE_FIL, + filData: { + ...filData, + komponentID, + }, }); - if (!filState.filData?.opplastetFil) { - filListeDispatch({ - type: ACTIONS.SLETT_FIL, - filData: { komponentID }, - }); - return; + oppdaterLokalOpplastingStatus(vedlegg.id, 'LastetOpp'); + }) + .catch((error: AxiosError) => { + if (axios.isCancel(error) as boolean) { + // avbrutt av bruker + return; } - axios - .delete( - `${API_URL}/frontend/v1/soknad/${innsendingsId}/vedlegg/${vedlegg.id}/fil/${filState.filData.opplastetFil.id}`, - ) - .then((response) => { - filListeDispatch({ - type: ACTIONS.SLETT_FIL, - filData: { komponentID }, - }); - oppdaterLokalOpplastingStatus( - vedlegg.id, - response.data.opplastingsStatus, - ); - }) - .catch((error) => { - dispatch({ - type: FIL_ACTIONS.FEIL, - }); - showError(error); - }); - }; + dispatch({ + type: FIL_ACTIONS.FEIL, + }); - useEffect(() => { - if (status === FIL_STATUS.OPPRETTET) { - dispatch({ - type: opplastetFilProp - ? FIL_ACTIONS.OPPLASTET - : FIL_ACTIONS.START_OPPLASTNING, - filState: { - filData: { - opplastetFil: opplastetFilProp, - lokalFil: lokalFilProp, - }, - }, - }); + const { errorCode } = error?.response?.data || {}; + if (error.response?.status === 413) { + return setFeilmelding(t('feil.filForStor')); } - if (status !== FIL_STATUS.STARTER_OPPLASTNING) return; - - const lokalFil = filState.filData?.lokalFil; - const { harFeil, melding } = filValidering(lokalFil); - if (harFeil) { - dispatch({ - type: FIL_ACTIONS.FEIL, - }); - setFeilmelding(t(`feil.${melding!}`)); - return; + if ( + errorCode === 'illegalAction.notSupportedFileFormat' || + errorCode === 'illegalAction.fileCannotBeRead' || + errorCode === 'illegalAction.virusScanFailed' + ) { + return setFeilmelding(tB(`${errorCode}.message`)); + } else if (errorCode === 'illegalAction.fileSizeSumTooLarge') { + setFeilmelding(tB(`${errorCode}.message`)); } - - const formData = new FormData(); - formData.append('file', lokalFil!); - const config = { - headers: { - 'Content-Type': 'multipart/form-data', - }, - signal: controller.signal, - onUploadProgress: (progressEvent: AxiosProgressEvent) => { - const totalSize = progressEvent.total; - const progress = totalSize - ? Math.round( - (progressEvent.loaded * 100) / totalSize, - ) - : 0; - dispatch({ - type: FIL_ACTIONS.OPPDATER_PROGRESS, - filState: { progress }, - }); - console.debug({ progress }); - }, - }; + showError(error); + }) + .finally(() => { dispatch({ - type: FIL_ACTIONS.SETT_STATUS, - filState: { status: FIL_STATUS.LASTER_OPP }, + type: FIL_ACTIONS.OPPDATER_PROGRESS, + filState: { + progress: 0, + }, }); - - axios - .post( - `${API_URL}/frontend/v1/soknad/${innsendingsId}/vedlegg/${vedlegg.id}/fil`, - formData, - config, - ) - .then((response: AxiosResponse) => { - const filData = { - opplastetFil: { - id: response.data.id, - filnavn: lokalFil!.name, - storrelse: response.data.storrelse, - }, - }; - dispatch({ - type: FIL_ACTIONS.OPPLASTET, + }); + }, [ + filState, + innsendingsId, + lokalFilProp, + opplastetFilProp, + oppdaterLokalOpplastingStatus, + vedlegg, + controller.signal, + status, + filListeDispatch, + komponentID, + t, + tB, + showError, + ]); + + return ( +
  • + {/* TODO why does one status work but not the other styled div vs panel?*/} + +
    + +
    +
    + {status === FIL_STATUS.OPPLASTET ? ( + + {filnavn} + {t('link.nyFane', { tekst: '' })} + + ) : ( + filnavn + )} +
    +
    + {status === FIL_STATUS.LASTER_OPP && ( + + {t('soknad.vedlegg.fil.progress')}: {filState.progress} + + )} + {status === FIL_STATUS.OPPLASTET && ( + {filStorrelseVisning(filState.filData?.opplastetFil?.storrelse || 0)} + )} +
    + +
    + {status === FIL_STATUS.FEIL && !filState.filData?.opplastetFil && ( + + + dispatch({ + type: FIL_ACTIONS.LAST_OPP_NY_FIL, filState: { - filData, - }, - }); - filListeDispatch({ - type: ACTIONS.ENDRE_FIL, - filData: { - ...filData, - komponentID, + filData: { + lokalFil: fil, + }, }, - }); - oppdaterLokalOpplastingStatus( - vedlegg.id, - 'LastetOpp', - ); - }) - .catch((error: AxiosError) => { - if (axios.isCancel(error) as boolean) { - // avbrutt av bruker - return; - } - dispatch({ - type: FIL_ACTIONS.FEIL, - }); - - const { errorCode } = error?.response?.data || {}; - if (error.response?.status === 413) { - return setFeilmelding(t('feil.filForStor')); + }) } - if ( - errorCode === - 'illegalAction.notSupportedFileFormat' || - errorCode === 'illegalAction.fileCannotBeRead' || - errorCode === 'illegalAction.virusScanFailed' - ) { - return setFeilmelding(tB(`${errorCode}.message`)); - } else if ( - errorCode === 'illegalAction.fileSizeSumTooLarge' - ) { - setFeilmelding(tB(`${errorCode}.message`)); + CustomButton={ + } - showError(error); - }) - .finally(() => { - dispatch({ - type: FIL_ACTIONS.OPPDATER_PROGRESS, - filState: { - progress: 0, - }, - }); - }); - }, [ - filState, - innsendingsId, - lokalFilProp, - opplastetFilProp, - oppdaterLokalOpplastingStatus, - vedlegg, - controller.signal, - status, - filListeDispatch, - komponentID, - t, - tB, - showError, - ]); - - return ( -
  • - {/* TODO why does one status work but not the other styled div vs panel?*/} - -
    - -
    -
    - {status === FIL_STATUS.OPPLASTET ? ( - - {filnavn} - - {t('link.nyFane', { tekst: '' })} - - - ) : ( - filnavn - )} -
    -
    - {status === FIL_STATUS.LASTER_OPP && ( - - {t('soknad.vedlegg.fil.progress')}:{' '} - {filState.progress} - - )} - {status === FIL_STATUS.OPPLASTET && ( - - {filStorrelseVisning( - filState.filData?.opplastetFil - ?.storrelse || 0, - )} - - )} -
    - -
    - {status === FIL_STATUS.FEIL && - !filState.filData?.opplastetFil && ( - - - dispatch({ - type: FIL_ACTIONS.LAST_OPP_NY_FIL, - filState: { - filData: { - lokalFil: fil, - }, - }, - }) - } - CustomButton={ - - } - allowMultiple={false} - /> - - )} - - {status === FIL_STATUS.LASTER_OPP && ( - - - - )} - - {status !== FIL_STATUS.LASTER_OPP && ( - - - - )} -
    -
    - {status === FIL_STATUS.FEIL && ( - - {feilmelding} - - )} -
  • - ); + allowMultiple={false} + /> + + )} + + {status === FIL_STATUS.LASTER_OPP && ( + + + + )} + + {status !== FIL_STATUS.LASTER_OPP && ( + + + + )} + + + {status === FIL_STATUS.FEIL && {feilmelding}} + + ); } diff --git a/components/FilUploadIcon.tsx b/components/FilUploadIcon.tsx index 079117e9..b5edda6e 100644 --- a/components/FilUploadIcon.tsx +++ b/components/FilUploadIcon.tsx @@ -1,139 +1,124 @@ +import { FileCheckmarkIcon, FileLoadingIcon, FileXMarkIcon } from '@navikt/aksel-icons'; +import { useTranslation } from 'react-i18next'; import styled from 'styled-components'; import { FIL_STATUS } from '../types/enums'; -import { useTranslation } from 'react-i18next'; -import { - FileLoadingIcon, - FileCheckmarkIcon, - FileXMarkIcon, -} from '@navikt/aksel-icons'; // https://stackoverflow.com/a/63620855 interface FileUploadIconProps { - filstatus?: (typeof FIL_STATUS)[keyof typeof FIL_STATUS]; - filnavn: string; + filstatus?: (typeof FIL_STATUS)[keyof typeof FIL_STATUS]; + filnavn: string; } const StyledDiv = styled.div` - border-radius: 4px; - width: 40px; - height: 40px; - display: flex; - align-items: center; - justify-content: center; - font-size: 1.875rem; - > * { - line-height: 0px; - } + border-radius: 4px; + width: 40px; + height: 40px; + display: flex; + align-items: center; + justify-content: center; + font-size: 1.875rem; + > * { + line-height: 0px; + } `; const ErrorStyled = styled(StyledDiv)` - background-color: var(--a-surface-danger-subtle); + background-color: var(--a-surface-danger-subtle); - > * { - color: var(--a-surface-danger); - } + > * { + color: var(--a-surface-danger); + } `; function ErrorFileIcon({ filnavn }: { filnavn: string }) { - const { t } = useTranslation(); - return ( - -
    - -
    -
    - ); + const { t } = useTranslation(); + return ( + +
    + +
    +
    + ); } const AlreadyUploadedStyled = styled(StyledDiv)` - background-color: var(--a-bg-subtle); + background-color: var(--a-bg-subtle); - > * { - color: var(--a-text-subtle); - } + > * { + color: var(--a-text-subtle); + } `; function AlreadyUploadedFileIcon({ filnavn }: { filnavn: string }) { - const { t } = useTranslation(); - return ( - -
    - -
    -
    - ); + const { t } = useTranslation(); + return ( + +
    + +
    +
    + ); } const UploadingStyled = styled(StyledDiv)` - background-color: var(--a-surface-info-subtle); + background-color: var(--a-surface-info-subtle); - > * { - color: var(--a-icon-info); - } + > * { + color: var(--a-icon-info); + } `; function UploadingFileIcon({ filnavn }: { filnavn: string }) { - const { t } = useTranslation(); - return ( - -
    - -
    -
    - ); + const { t } = useTranslation(); + return ( + +
    + +
    +
    + ); } const SuccessStyled = styled(StyledDiv)` - background-color: var(--a-surface-success-subtle); - > * { - color: var(--a-icon-success); - } + background-color: var(--a-surface-success-subtle); + > * { + color: var(--a-icon-success); + } `; function SuccessFileIcon({ filnavn }: { filnavn: string }) { - const { t } = useTranslation(); - return ( - - - - ); + const { t } = useTranslation(); + return ( + + + + ); } export function FilUploadIcon(props: FileUploadIconProps) { - return ( - <> - {props.filstatus === FIL_STATUS.FEIL && ( - - )} - {props.filstatus === FIL_STATUS.OPPLASTET && ( - - )} - {props.filstatus === FIL_STATUS.LASTER_OPP && ( - - )} - {props.filstatus === FIL_STATUS.TIDLIGERE_LASTET_OPP && ( - - )} - - ); + return ( + <> + {props.filstatus === FIL_STATUS.FEIL && } + {props.filstatus === FIL_STATUS.OPPLASTET && } + {props.filstatus === FIL_STATUS.LASTER_OPP && } + {props.filstatus === FIL_STATUS.TIDLIGERE_LASTET_OPP && } + + ); } diff --git a/components/Filvelger.tsx b/components/Filvelger.tsx index fbe75a8c..8eb5e8f5 100644 --- a/components/Filvelger.tsx +++ b/components/Filvelger.tsx @@ -1,134 +1,112 @@ -import React, { - useCallback, - useEffect, - useRef, - cloneElement, - useMemo, -} from 'react'; -import { useForm, SubmitHandler } from 'react-hook-form'; -import { Button } from '@navikt/ds-react'; import { UploadIcon } from '@navikt/aksel-icons'; +import { Button } from '@navikt/ds-react'; +import { cloneElement, useCallback, useEffect, useMemo, useRef } from 'react'; +import { SubmitHandler, useForm } from 'react-hook-form'; +import { useTranslation } from 'react-i18next'; import styled from 'styled-components'; import { v4 as uuidv4 } from 'uuid'; -import { useTranslation } from 'react-i18next'; type FormValues = { - file: FileList | null; + file: FileList | null; }; const StyledUpload = styled.input` - clip: rect(0 0 0 0); - clip-path: inset(50%); - height: 1px; - overflow: hidden; - position: absolute; - white-space: nowrap; - width: 1px; + clip: rect(0 0 0 0); + clip-path: inset(50%); + height: 1px; + overflow: hidden; + position: absolute; + white-space: nowrap; + width: 1px; `; const FilvelgerForm = styled.form` - input[type='file']:focus + label { - box-shadow: - inset 0 0 0 2px var(--a-border-action), - var(--a-shadow-focus); - } + input[type='file']:focus + label { + box-shadow: + inset 0 0 0 2px var(--a-border-action), + var(--a-shadow-focus); + } `; interface FilvelgerProps { - autoFocus?: boolean; - onFileSelected: (fil: File) => void; - CustomButton?: JSX.Element; - allowMultiple?: boolean; - buttonText?: string | null; + autoFocus?: boolean; + onFileSelected: (fil: File) => void; + CustomButton?: JSX.Element; + allowMultiple?: boolean; + buttonText?: string | null; } export function Filvelger(props: FilvelgerProps) { - const { - autoFocus, - onFileSelected, - CustomButton, - allowMultiple = true, - buttonText, - } = props; - const { t } = useTranslation(); - const { register, handleSubmit, setValue, watch } = - useForm(); - - const fileRef = useRef(null); - const { ref, ...rest } = register('file'); + const { autoFocus, onFileSelected, CustomButton, allowMultiple = true, buttonText } = props; + const { t } = useTranslation(); + const { register, handleSubmit, setValue, watch } = useForm(); - const inputId = useMemo(uuidv4, []); + const fileRef = useRef(null); + const { ref, ...rest } = register('file'); - const onSubmit: SubmitHandler = useCallback( - (data) => { - if (!data.file?.length) { - console.debug('Fil ikke valgt!'); - } else { - const fileListArray = Array.from(data.file); - fileListArray.forEach((fil, index) => { - console.debug( - `Legger til fil ${index + 1} av ${ - fileListArray.length - }`, - ); - onFileSelected(fil); - }); + const inputId = useMemo(uuidv4, []); - setValue('file', null); + const onSubmit: SubmitHandler = useCallback( + (data) => { + if (!data.file?.length) { + console.debug('Fil ikke valgt!'); + } else { + const fileListArray = Array.from(data.file); + fileListArray.forEach((fil, index) => { + console.debug(`Legger til fil ${index + 1} av ${fileListArray.length}`); + onFileSelected(fil); + }); - if (fileRef.current) { - fileRef.current.value = ''; - } - } - }, - [setValue, onFileSelected], - ); + setValue('file', null); - useEffect(() => { - const subscription = watch((value, { name }) => { - if (name === 'file') { - console.debug('Fil endret', value); - if (value?.file) { - console.debug('Starter filopplasting...'); - handleSubmit(onSubmit)(); - } - } - }); - return () => subscription.unsubscribe(); - }, [handleSubmit, onSubmit, watch]); + if (fileRef.current) { + fileRef.current.value = ''; + } + } + }, + [setValue, onFileSelected], + ); - const CurrentButton = useCallback(() => { - const DefaultButton = ( - - ); - return cloneElement(CustomButton || DefaultButton, { - htmlFor: inputId, - }); - }, [CustomButton, inputId, buttonText, t]); + useEffect(() => { + const subscription = watch((value, { name }) => { + if (name === 'file') { + console.debug('Fil endret', value); + if (value?.file) { + console.debug('Starter filopplasting...'); + handleSubmit(onSubmit)(); + } + } + }); + return () => subscription.unsubscribe(); + }, [handleSubmit, onSubmit, watch]); - return ( - - { - ref(e); - fileRef.current = e; // you can still assign to ref - }} - /> - - + const CurrentButton = useCallback(() => { + const DefaultButton = ( + ); + return cloneElement(CustomButton || DefaultButton, { + htmlFor: inputId, + }); + }, [CustomButton, inputId, buttonText, t]); + + return ( + + { + ref(e); + fileRef.current = e; // you can still assign to ref + }} + /> + + + ); } diff --git a/components/Kvittering.tsx b/components/Kvittering.tsx index 5e49f6f3..a9b7a1be 100644 --- a/components/Kvittering.tsx +++ b/components/Kvittering.tsx @@ -1,236 +1,164 @@ -import React from 'react'; -import { - Alert, - Heading, - BodyLong, - Button, - BodyShort, -} from '@navikt/ds-react'; -import styled from 'styled-components'; +import { Alert, BodyLong, BodyShort, Button, Heading } from '@navikt/ds-react'; import getConfig from 'next/config'; import { useTranslation } from 'react-i18next'; -import { Bold } from './textStyle'; +import styled from 'styled-components'; import { formatertDato } from '../utils/dato'; -import { KvitteringsTillegg } from './skjemaSpesifikt/KvitteringsTillegg'; import { useVedleggslisteContext } from './VedleggsListe'; import { LastNedKnapp } from './common/LastNedKnapp'; +import { KvitteringsTillegg } from './skjemaSpesifikt/KvitteringsTillegg'; +import { Bold } from './textStyle'; const { publicRuntimeConfig } = getConfig(); export interface KvitteringsProps { - kvprops: KvitteringsDto; + kvprops: KvitteringsDto; } export interface KvitteringsDto { - innsendingsId: string; - label: string; - mottattdato: string; - hoveddokumentRef: string; - innsendteVedlegg: { - vedleggsnr: string; - tittel: string; - }[]; - skalEttersendes: { - vedleggsnr: string; - tittel: string; - }[]; - skalSendesAvAndre: { - vedleggsnr: string; - tittel: string; - }[]; - ettersendingsfrist: string; + innsendingsId: string; + label: string; + mottattdato: string; + hoveddokumentRef: string; + innsendteVedlegg: { + vedleggsnr: string; + tittel: string; + }[]; + skalEttersendes: { + vedleggsnr: string; + tittel: string; + }[]; + skalSendesAvAndre: { + vedleggsnr: string; + tittel: string; + }[]; + ettersendingsfrist: string; } const SjekkBoksListe = styled.ul` - list-style: none; - margin: 0; - padding-left: 0; + list-style: none; + margin: 0; + padding-left: 0; - li:not(:last-child) { - padding-bottom: var(--a-spacing-4); - } + li:not(:last-child) { + padding-bottom: var(--a-spacing-4); + } `; const StyledSection = styled.section` - margin-bottom: var(--a-spacing-8); + margin-bottom: var(--a-spacing-8); `; const BoksMedMargin = styled.div` - margin-top: var(--a-spacing-4); - margin-bottom: var(--a-spacing-4); + margin-top: var(--a-spacing-4); + margin-bottom: var(--a-spacing-4); `; const StyledAlert = styled(Alert)` - margin-bottom: var(--a-spacing-11); + margin-bottom: var(--a-spacing-11); `; export function Kvittering({ kvprops }: KvitteringsProps) { - const { t } = useTranslation(); - - const { soknad } = useVedleggslisteContext(); - - return ( -
    - - {t('kvittering.tittel')} + const { t } = useTranslation(); + + const { soknad } = useVedleggslisteContext(); + + return ( +
    + + {t('kvittering.tittel')} + + + + {t( + 'kvittering.mottattDokumenter', + + { + dato: formatertDato(new Date(kvprops.mottattdato)), + }, + )} + + + {kvprops && kvprops.hoveddokumentRef && ( +
  • + + + {t('kvittering.skjema')} + {': '} + + {kvprops.label} + + + + {t('kvittering.skjemaLenke')} + + +
  • + )} + {kvprops && + kvprops.innsendteVedlegg && + kvprops.innsendteVedlegg.length > 0 && + kvprops.innsendteVedlegg.map((vedlegg) => { + return ( +
  • + + + {t('kvittering.vedlegg')} + {': '} + + {vedlegg.tittel} + +
  • + ); + })} +
    +
    + + {kvprops.skalEttersendes && kvprops.skalEttersendes.length > 0 && ( + + + {t('kvittering.maaEttersendes')} + + + + {kvprops.skalEttersendes.map((vedlegg) => { + return
  • {vedlegg.tittel}
  • ; + })} +
    +
    + )} + + {kvprops.skalSendesAvAndre && kvprops.skalSendesAvAndre.length > 0 && ( + + + {t('kvittering.sendesAvAndre')} + + + + {kvprops.skalSendesAvAndre.map((vedlegg) => { + return
  • {vedlegg.tittel}
  • ; + })} +
    +
    + )} + + {kvprops.skalEttersendes && kvprops.skalEttersendes.length > 0 && ( + <> + + + {t('kvittering.fristEttersending', { + dato: formatertDato(new Date(kvprops.ettersendingsfrist)), + })} - - - {t( - 'kvittering.mottattDokumenter', - - { - dato: formatertDato( - new Date(kvprops.mottattdato), - ), - }, - )} - - - {kvprops && kvprops.hoveddokumentRef && ( -
  • - - - {t('kvittering.skjema')} - {': '} - - {kvprops.label} - - - - {t('kvittering.skjemaLenke')} - - -
  • - )} - {kvprops && - kvprops.innsendteVedlegg && - kvprops.innsendteVedlegg.length > 0 && - kvprops.innsendteVedlegg.map((vedlegg) => { - return ( -
  • - - - {t('kvittering.vedlegg')} - {': '} - - {vedlegg.tittel} - -
  • - ); - })} -
    -
    - - {kvprops.skalEttersendes && - kvprops.skalEttersendes.length > 0 && ( - - - {t('kvittering.maaEttersendes')} - - - - {kvprops.skalEttersendes.map( - (vedlegg) => { - return ( -
  • - {' '} - {vedlegg.tittel} -
  • - ); - }, - )} -
    -
    - )} - - {kvprops.skalSendesAvAndre && - kvprops.skalSendesAvAndre.length > 0 && ( - - - {t('kvittering.sendesAvAndre')} - - - - {kvprops.skalSendesAvAndre.map( - (vedlegg) => { - return ( -
  • - {' '} - {vedlegg.tittel} -
  • - ); - }, - )} -
    -
    - )} - - {kvprops.skalEttersendes && - kvprops.skalEttersendes.length > 0 && ( - <> - - - {t('kvittering.fristEttersending', { - dato: formatertDato( - new Date( - kvprops.ettersendingsfrist, - ), - ), - })} - - - {t('kvittering.ettersendingsInfo')} - - - - )} - {!kvprops.skalEttersendes.length && ( - - {t('kvittering.altMottatInfo')} - - )} - - -
    - ); + {t('kvittering.ettersendingsInfo')} + + + )} + {!kvprops.skalEttersendes.length && {t('kvittering.altMottatInfo')}} + + +
    + ); } export default Kvittering; diff --git a/components/LagringsProsessProvider.tsx b/components/LagringsProsessProvider.tsx index d6dbe014..54d34651 100644 --- a/components/LagringsProsessProvider.tsx +++ b/components/LagringsProsessProvider.tsx @@ -1,97 +1,79 @@ -import React, { - createContext, - useCallback, - useContext, - useRef, -} from 'react'; -import { useState } from 'react'; +import React, { createContext, useCallback, useContext, useRef, useState } from 'react'; interface LagringsProsessProviderProps { - children?: React.ReactNode; + children?: React.ReactNode; } interface LagringsProsessContextType { - lagrer: boolean; - lagrerNaa: () => boolean; - ventPaaLagring: () => Promise; - nyLagringsProsess: (promise: Promise) => Promise; + lagrer: boolean; + lagrerNaa: () => boolean; + ventPaaLagring: () => Promise; + nyLagringsProsess: (promise: Promise) => Promise; } -const LagringsProsessContext = - createContext(null); +const LagringsProsessContext = createContext(null); export const useLagringsProsessContext = () => { - const lagringsProsessContext = useContext(LagringsProsessContext); - if (!lagringsProsessContext) { - throw new Error( - 'Mangler LagringsProsessProvider, når useLagringsProsessContext kalles', - ); - } - return lagringsProsessContext; + const lagringsProsessContext = useContext(LagringsProsessContext); + if (!lagringsProsessContext) { + throw new Error('Mangler LagringsProsessProvider, når useLagringsProsessContext kalles'); + } + return lagringsProsessContext; }; -export const LagringsProsessProvider = ({ - children, -}: LagringsProsessProviderProps) => { - const [aktiveLagringsProsesser, setAktiveLagringsProsesser] = - useState[]>([]); - const aktiveLagringsProsesserRef = useRef[]>([]); +export const LagringsProsessProvider = ({ children }: LagringsProsessProviderProps) => { + const [aktiveLagringsProsesser, setAktiveLagringsProsesser] = useState[]>([]); + const aktiveLagringsProsesserRef = useRef[]>([]); - const leggTilLagringsProsess = useCallback( - (promise: Promise) => { - setAktiveLagringsProsesser((a) => { - const nyListe = [...a, promise]; - aktiveLagringsProsesserRef.current = nyListe; - return nyListe; - }); - }, - [], - ); - const fjernLagringsProsess = useCallback( - (promise: Promise) => { - setAktiveLagringsProsesser((a) => { - const nyListe = a.filter((p) => p !== promise); - aktiveLagringsProsesserRef.current = nyListe; - return nyListe; - }); - }, - [], - ); + const leggTilLagringsProsess = useCallback((promise: Promise) => { + setAktiveLagringsProsesser((a) => { + const nyListe = [...a, promise]; + aktiveLagringsProsesserRef.current = nyListe; + return nyListe; + }); + }, []); + const fjernLagringsProsess = useCallback((promise: Promise) => { + setAktiveLagringsProsesser((a) => { + const nyListe = a.filter((p) => p !== promise); + aktiveLagringsProsesserRef.current = nyListe; + return nyListe; + }); + }, []); - const nyLagringsProsess = useCallback( - (promise: Promise) => { - leggTilLagringsProsess(promise); + const nyLagringsProsess = useCallback( + (promise: Promise) => { + leggTilLagringsProsess(promise); - return promise.finally(() => { - fjernLagringsProsess(promise); - }); - }, - [leggTilLagringsProsess, fjernLagringsProsess], - ); + return promise.finally(() => { + fjernLagringsProsess(promise); + }); + }, + [leggTilLagringsProsess, fjernLagringsProsess], + ); - const ventPaaLagring = useCallback(async () => { - while (aktiveLagringsProsesserRef.current.length) { - await Promise.all(aktiveLagringsProsesserRef.current); - } - return; - }, []); + const ventPaaLagring = useCallback(async () => { + while (aktiveLagringsProsesserRef.current.length) { + await Promise.all(aktiveLagringsProsesserRef.current); + } + return; + }, []); - const lagrerNaa = useCallback(() => { - return aktiveLagringsProsesserRef.current.length !== 0; - }, []); + const lagrerNaa = useCallback(() => { + return aktiveLagringsProsesserRef.current.length !== 0; + }, []); - const lagrer = aktiveLagringsProsesser.length !== 0; + const lagrer = aktiveLagringsProsesser.length !== 0; - return ( - - {children} - - ); + return ( + + {children} + + ); }; diff --git a/components/LastOppVedlegg.tsx b/components/LastOppVedlegg.tsx index 33b97afd..e11a07ce 100644 --- a/components/LastOppVedlegg.tsx +++ b/components/LastOppVedlegg.tsx @@ -1,211 +1,171 @@ -import React, { useState } from 'react'; -import { Heading, Button, Ingress, Alert } from '@navikt/ds-react'; -import styled from 'styled-components'; +import { Alert, Button, Heading, Ingress } from '@navikt/ds-react'; +import { useState } from 'react'; import { useTranslation } from 'react-i18next'; +import styled from 'styled-components'; import { VedleggType } from '../types/types'; import { SideValideringProvider } from './SideValideringProvider'; import Vedlegg from './Vedlegg'; import { useVedleggslisteContext } from './VedleggsListe'; import { ButtonContainer } from './common/ButtonContainer'; -import { OpprettAnnetVedlegg } from './OpprettAnnetVedlegg'; +import { useErrorMessage } from '../hooks/useErrorMessage'; import { formatertDato } from '../utils/dato'; +import { useLagringsProsessContext } from './LagringsProsessProvider'; +import { OpprettAnnetVedlegg } from './OpprettAnnetVedlegg'; import { useModalContext } from './SoknadModalProvider'; import { Linje } from './common/Linje'; -import { useErrorMessage } from '../hooks/useErrorMessage'; -import { useLagringsProsessContext } from './LagringsProsessProvider'; const FristForOpplastingInfo = styled(Alert)` - border: 0; - border-bottom: 1px solid var(--a-border-strong); - padding-bottom: 4px; - border-radius: 0px; - margin-bottom: 24px; - text-transform: uppercase; + border: 0; + border-bottom: 1px solid var(--a-border-strong); + padding-bottom: 4px; + border-radius: 0px; + margin-bottom: 24px; + text-transform: uppercase; `; const PaddedVedlegg = styled.div` - > * { - margin-top: 16px; - } + > * { + margin-top: 16px; + } `; export interface LastOppVedleggdProps { - vedleggsliste: VedleggType[]; - oppdaterVisningsSteg: (nr: number) => void; + vedleggsliste: VedleggType[]; + oppdaterVisningsSteg: (nr: number) => void; } function LastOppVedlegg(props: LastOppVedleggdProps) { - const { vedleggsliste, oppdaterVisningsSteg } = props; + const { vedleggsliste, oppdaterVisningsSteg } = props; - const { t } = useTranslation(); + const { t } = useTranslation(); - const { soknad, soknadKlar, soknadDelvisKlar } = - useVedleggslisteContext(); - const { - openForstettSenereSoknadModal, - openSendInnKomplettSoknadModal, - openSendInnUferdigSoknadModal, - openSlettSoknadModal, - } = useModalContext(); - const { ventPaaLagring } = useLagringsProsessContext(); + const { soknad, soknadKlar, soknadDelvisKlar } = useVedleggslisteContext(); + const { + openForstettSenereSoknadModal, + openSendInnKomplettSoknadModal, + openSendInnUferdigSoknadModal, + openSlettSoknadModal, + } = useModalContext(); + const { ventPaaLagring } = useLagringsProsessContext(); - const [lastOppVedleggHarFeil, setLastOppVedleggHarFeil] = - useState(false); - const [visLastOppVedleggFeil, setVisLastOppVedleggFeil] = - useState(false); - const [ - lastOppVedleggValideringfokus, - setLastOppVedleggValideringfokus, - ] = useState(false); - const [isLoading, setIsLoading] = useState(false); - const { customErrorMessage } = useErrorMessage(); + const [lastOppVedleggHarFeil, setLastOppVedleggHarFeil] = useState(false); + const [visLastOppVedleggFeil, setVisLastOppVedleggFeil] = useState(false); + const [lastOppVedleggValideringfokus, setLastOppVedleggValideringfokus] = useState(false); + const [isLoading, setIsLoading] = useState(false); + const { customErrorMessage } = useErrorMessage(); - return ( - <> - - {t('soknad.visningsSteg.lastOppVedlegg.tittel')} - - - {t('soknad.visningsSteg.lastOppVedlegg.ingress')} - + return ( + <> + + {t('soknad.visningsSteg.lastOppVedlegg.tittel')} + + {t('soknad.visningsSteg.lastOppVedlegg.ingress')} - {soknad.visningsType === 'ettersending' ? ( - - {t( - 'soknad.visningsSteg.lastOppVedlegg.infoFrist', - { - dato: formatertDato( - new Date(soknad.innsendingsFristDato), - ), - }, - )} - - ) : ( - - )} - - {soknad.visningsType === 'dokumentinnsending' && - soknad.visningsType === 'dokumentinnsending' && - vedleggsliste.some((element) => { - return ( - element.erHoveddokument === true && - element.opplastingsStatus !== 'LastetOpp' - ); - }) && ( - - {t( - 'soknad.visningsSteg.lastOppVedlegg.advarselHovedskjema', - )} - - )} + {soknad.visningsType === 'ettersending' ? ( + + {t('soknad.visningsSteg.lastOppVedlegg.infoFrist', { + dato: formatertDato(new Date(soknad.innsendingsFristDato)), + })} + + ) : ( + + )} + + {soknad.visningsType === 'dokumentinnsending' && + soknad.visningsType === 'dokumentinnsending' && + vedleggsliste.some((element) => { + return element.erHoveddokument === true && element.opplastingsStatus !== 'LastetOpp'; + }) && ( + + {t('soknad.visningsSteg.lastOppVedlegg.advarselHovedskjema')} + + )} - - {vedleggsliste - .filter((x) => !x.erHoveddokument) - .map((vedlegg) => { - return ( - - ); - })} + + {vedleggsliste + .filter((x) => !x.erHoveddokument) + .map((vedlegg) => { + return ; + })} - {soknad.kanLasteOppAnnet && ( - - )} - - + {soknad.kanLasteOppAnnet && } + + - - + + - {/* lagre og fortsett senere */} - + {/* lagre og fortsett senere */} + - {/* gå tilbake et steg */} - {soknad.visningsType === 'dokumentinnsending' && ( - - )} + {/* gå tilbake et steg */} + {soknad.visningsType === 'dokumentinnsending' && ( + + )} - - - {/* end */} - - ); + + + {/* end */} + + ); } export default LastOppVedlegg; diff --git a/components/Layout.tsx b/components/Layout.tsx index c6c30edb..506af963 100644 --- a/components/Layout.tsx +++ b/components/Layout.tsx @@ -1,21 +1,21 @@ import styled from 'styled-components'; const Style = styled.main` - max-width: 60rem; - min-height: 100vh; - padding-top: 16px; - margin: 0 auto; - padding-left: 16px; - padding-right: 16px; + max-width: 60rem; + min-height: 100vh; + padding-top: 16px; + margin: 0 auto; + padding-left: 16px; + padding-right: 16px; - // Overskriver bakgrunnsfarge på secondary button i ds-css - --ac-button-secondary-bg: var(--a-surface-default); + // Overskriver bakgrunnsfarge på secondary button i ds-css + --ac-button-secondary-bg: var(--a-surface-default); `; interface LayoutProps { - children: React.ReactNode; + children: React.ReactNode; } export const Layout = ({ children }: LayoutProps) => { - return ; + return ; }; diff --git a/components/OpprettAnnetVedlegg.tsx b/components/OpprettAnnetVedlegg.tsx index 239c0c7d..7d51c111 100644 --- a/components/OpprettAnnetVedlegg.tsx +++ b/components/OpprettAnnetVedlegg.tsx @@ -1,164 +1,138 @@ -import React, { useState } from 'react'; -import { useForm, SubmitHandler } from 'react-hook-form'; -import axios from 'axios'; -import { useErrorMessage } from '../hooks/useErrorMessage'; -import { Button, TextField } from '@navikt/ds-react'; import { PlusIcon } from '@navikt/aksel-icons'; +import { Button, TextField } from '@navikt/ds-react'; +import axios from 'axios'; import getConfig from 'next/config'; -import styled from 'styled-components'; +import { useState } from 'react'; +import { SubmitHandler, useForm } from 'react-hook-form'; import { useTranslation } from 'react-i18next'; -import { VedleggPanel } from './Vedlegg'; +import styled from 'styled-components'; +import { useErrorMessage } from '../hooks/useErrorMessage'; import { useValidation } from '../hooks/useValidation'; import { ValideringsRamme } from './ValideringsRamme'; +import { VedleggPanel } from './Vedlegg'; import { useVedleggslisteContext } from './VedleggsListe'; const { publicRuntimeConfig } = getConfig(); const ButtomRow = styled.div` - margin-top: 24px; + margin-top: 24px; `; export interface EndreVedleggProps { - innsendingsId: string; + innsendingsId: string; } type FormValues = { - tittel: string; + tittel: string; }; -export function OpprettAnnetVedlegg({ - innsendingsId, -}: EndreVedleggProps) { - const { t } = useTranslation(); - const [isLoading, setIsLoading] = useState(false); - const [visOpprett, setVisOpprett] = useState(false); - const [giFokusPaaLeggTil, setGiFokusPaaLeggTil] = useState(false); - const { - register, - handleSubmit, - reset, - formState: { errors }, - } = useForm(); - const { showError } = useErrorMessage(); +export function OpprettAnnetVedlegg({ innsendingsId }: EndreVedleggProps) { + const { t } = useTranslation(); + const [isLoading, setIsLoading] = useState(false); + const [visOpprett, setVisOpprett] = useState(false); + const [giFokusPaaLeggTil, setGiFokusPaaLeggTil] = useState(false); + const { + register, + handleSubmit, + reset, + formState: { errors }, + } = useForm(); + const { showError } = useErrorMessage(); - const feilId = 'opprett-vedlegg-feil'; - const harVailderingfeil = errors.tittel?.message != undefined; + const feilId = 'opprett-vedlegg-feil'; + const harVailderingfeil = errors.tittel?.message != undefined; - const [visFeil, valideringsMelding] = useValidation({ - komponentId: feilId, - melding: t( - 'soknad.vedlegg.annet.feilmelding.fullforOpprettelse', - ), - harFeil: !harVailderingfeil && visOpprett, - }); + const [visFeil, valideringsMelding] = useValidation({ + komponentId: feilId, + melding: t('soknad.vedlegg.annet.feilmelding.fullforOpprettelse'), + harFeil: !harVailderingfeil && visOpprett, + }); - const { leggTilVedlegg } = useVedleggslisteContext(); + const { leggTilVedlegg } = useVedleggslisteContext(); - useValidation({ - komponentId: feilId + '-validering', - melding: errors.tittel?.message || '', - harFeil: harVailderingfeil && visOpprett, - }); + useValidation({ + komponentId: feilId + '-validering', + melding: errors.tittel?.message || '', + harFeil: harVailderingfeil && visOpprett, + }); - const onSubmit: SubmitHandler = (data) => { - setIsLoading(true); + const onSubmit: SubmitHandler = (data) => { + setIsLoading(true); - axios - .post( - `${publicRuntimeConfig.apiUrl}/frontend/v1/soknad/${innsendingsId}/vedlegg`, - { - tittel: data.tittel, - }, - ) - .then((response) => { - leggTilVedlegg({ ...response.data, autoFocus: true }); - }) - .catch((error) => { - showError(error); - }) - .finally(() => { - setIsLoading(false); - setGiFokusPaaLeggTil(false); - setVisOpprett(false); - reset(); - }); - }; - const maxLength = 250; + axios + .post(`${publicRuntimeConfig.apiUrl}/frontend/v1/soknad/${innsendingsId}/vedlegg`, { + tittel: data.tittel, + }) + .then((response) => { + leggTilVedlegg({ ...response.data, autoFocus: true }); + }) + .catch((error) => { + showError(error); + }) + .finally(() => { + setIsLoading(false); + setGiFokusPaaLeggTil(false); + setVisOpprett(false); + reset(); + }); + }; + const maxLength = 250; - return ( - <> - {visOpprett && ( - - -
    - - - - - - -
    -
    - )} - {!visOpprett && ( + return ( + <> + {visOpprett && ( + + +
    + + + - )} - - ); + + +
    +
    + )} + {!visOpprett && ( + + )} + + ); } diff --git a/components/SideValideringProvider.tsx b/components/SideValideringProvider.tsx index 8ce8319e..01de5563 100644 --- a/components/SideValideringProvider.tsx +++ b/components/SideValideringProvider.tsx @@ -1,173 +1,123 @@ -import React, { - createContext, - useCallback, - useContext, - useEffect, - useReducer, - useRef, -} from 'react'; +import React, { createContext, useCallback, useContext, useEffect, useReducer, useRef } from 'react'; import { ErrorSummary } from '@navikt/ds-react'; export interface SideValideringProps { - setHarValideringsfeil: React.Dispatch< - React.SetStateAction - >; - visValideringsfeil: boolean; - setVisValideringsfeil: React.Dispatch< - React.SetStateAction - >; - fokus: boolean; - setFokus: React.Dispatch>; - children: React.ReactNode; + setHarValideringsfeil: React.Dispatch>; + visValideringsfeil: boolean; + setVisValideringsfeil: React.Dispatch>; + fokus: boolean; + setFokus: React.Dispatch>; + children: React.ReactNode; } export interface ValideringsType { - valideringsId: string; - komponentId: string; - harFeil: boolean; - melding: string; + valideringsId: string; + komponentId: string; + harFeil: boolean; + melding: string; } export const ACTIONS = { - LAGRE: 'LAGRE', - SLETT: 'SLETT', + LAGRE: 'LAGRE', + SLETT: 'SLETT', } as const; export interface ActionType { - type: (typeof ACTIONS)[keyof typeof ACTIONS]; - validering: ValideringsType; + type: (typeof ACTIONS)[keyof typeof ACTIONS]; + validering: ValideringsType; } -const vedleggReducer = ( - valideringer: ValideringsType[], - action: ActionType, -) => { - switch (action.type) { - case ACTIONS.LAGRE: { - const finnes = valideringer.some( - (validering) => - validering.valideringsId === - action.validering.valideringsId, - ); - - if (finnes) { - return valideringer.map((validering) => - validering.valideringsId === - action.validering.valideringsId - ? action.validering - : validering, - ); - } - return [...valideringer, action.validering]; - } - case ACTIONS.SLETT: { - return valideringer.filter( - (validering) => - validering.valideringsId !== - action.validering.valideringsId, - ); - } +const vedleggReducer = (valideringer: ValideringsType[], action: ActionType) => { + switch (action.type) { + case ACTIONS.LAGRE: { + const finnes = valideringer.some((validering) => validering.valideringsId === action.validering.valideringsId); + + if (finnes) { + return valideringer.map((validering) => + validering.valideringsId === action.validering.valideringsId ? action.validering : validering, + ); + } + return [...valideringer, action.validering]; + } + case ACTIONS.SLETT: { + return valideringer.filter((validering) => validering.valideringsId !== action.validering.valideringsId); } + } }; const initialState: ValideringsType[] = []; interface ValideringsContextType { - lagreValidering: (validering: ValideringsType) => void; - slettValidering: (validering: ValideringsType) => void; - visValideringsfeil: boolean; + lagreValidering: (validering: ValideringsType) => void; + slettValidering: (validering: ValideringsType) => void; + visValideringsfeil: boolean; } -const ValideringsContext = - createContext(null); +const ValideringsContext = createContext(null); export const useValideringsContext = () => { - const valideringsContext = useContext(ValideringsContext); - if (!valideringsContext) { - throw new Error( - 'Mangler SideValideringProvider, når useValideringsContext kalles', - ); - } - return valideringsContext; + const valideringsContext = useContext(ValideringsContext); + if (!valideringsContext) { + throw new Error('Mangler SideValideringProvider, når useValideringsContext kalles'); + } + return valideringsContext; }; export const SideValideringProvider = ({ - setHarValideringsfeil, - visValideringsfeil, - setVisValideringsfeil, - fokus, - setFokus, - children, + setHarValideringsfeil, + visValideringsfeil, + setVisValideringsfeil, + fokus, + setFokus, + children, }: SideValideringProps) => { - const [valideringer, dispatch] = useReducer( - vedleggReducer, - initialState, - ); - - const errorRef = useRef(null); - - const valideringsFeil = valideringer.filter( - (validering) => validering.harFeil, - ); - - const harFeil = valideringsFeil.length !== 0; - - useEffect(() => { - if (fokus) { - errorRef?.current && errorRef.current.focus(); - setFokus(false); - } - }, [fokus, setFokus]); - - useEffect(() => { - setHarValideringsfeil(harFeil); - if (!harFeil) { - setVisValideringsfeil(false); - } - }, [ - harFeil, - setHarValideringsfeil, - setVisValideringsfeil, - setFokus, - ]); - - const lagreValidering = useCallback( - (validering: ValideringsType) => { - dispatch({ type: ACTIONS.LAGRE, validering }); - }, - [], - ); - const slettValidering = useCallback( - (validering: ValideringsType) => { - dispatch({ type: ACTIONS.SLETT, validering }); - }, - [], - ); - return ( - - {harFeil && visValideringsfeil && ( - - {valideringsFeil.map((validering) => ( - - {validering.melding} - - ))} - - )} - {children} - - ); + const [valideringer, dispatch] = useReducer(vedleggReducer, initialState); + + const errorRef = useRef(null); + + const valideringsFeil = valideringer.filter((validering) => validering.harFeil); + + const harFeil = valideringsFeil.length !== 0; + + useEffect(() => { + if (fokus) { + errorRef?.current && errorRef.current.focus(); + setFokus(false); + } + }, [fokus, setFokus]); + + useEffect(() => { + setHarValideringsfeil(harFeil); + if (!harFeil) { + setVisValideringsfeil(false); + } + }, [harFeil, setHarValideringsfeil, setVisValideringsfeil, setFokus]); + + const lagreValidering = useCallback((validering: ValideringsType) => { + dispatch({ type: ACTIONS.LAGRE, validering }); + }, []); + const slettValidering = useCallback((validering: ValideringsType) => { + dispatch({ type: ACTIONS.SLETT, validering }); + }, []); + return ( + + {harFeil && visValideringsfeil && ( + + {valideringsFeil.map((validering) => ( + + {validering.melding} + + ))} + + )} + {children} + + ); }; diff --git a/components/SkjemaNedlasting.tsx b/components/SkjemaNedlasting.tsx index 6d2083ec..e172acfb 100644 --- a/components/SkjemaNedlasting.tsx +++ b/components/SkjemaNedlasting.tsx @@ -1,88 +1,83 @@ -import React from 'react'; -import { Heading, Button, BodyShort } from '@navikt/ds-react'; +import { BodyShort, Button, Heading } from '@navikt/ds-react'; import { useTranslation } from 'react-i18next'; import { ButtonContainer } from './common/ButtonContainer'; +import styled from 'styled-components'; import { VedleggType } from '../types/types'; -import { VedleggPanel } from './Vedlegg'; import { useModalContext } from './SoknadModalProvider'; -import styled from 'styled-components'; -import { Linje } from './common/Linje'; +import { VedleggPanel } from './Vedlegg'; import { LastNedKnapp } from './common/LastNedKnapp'; +import { Linje } from './common/Linje'; const BeskrivelsesGruppe = styled.div` - padding-bottom: 1.5rem; - @media only screen and (max-width: 600px) { - ol { - padding-left: 1.5rem; - } + padding-bottom: 1.5rem; + @media only screen and (max-width: 600px) { + ol { + padding-left: 1.5rem; } + } `; export interface SkjemanedlastingdProps { - vedlegg: VedleggType; - oppdaterVisningsSteg: (nr: number) => void; + vedlegg: VedleggType; + oppdaterVisningsSteg: (nr: number) => void; } function SkjemaNedlasting(props: SkjemanedlastingdProps) { - const { vedlegg, oppdaterVisningsSteg } = props; + const { vedlegg, oppdaterVisningsSteg } = props; - const { t } = useTranslation(); - const { openSlettSoknadModal } = useModalContext(); + const { t } = useTranslation(); + const { openSlettSoknadModal } = useModalContext(); - return ( - <> - - {t('soknad.visningsSteg.steg0.tittel')} - - - - - {vedlegg.label} - - - - {t('soknad.skjemaNedlasting.listeTittel')} - - - {( - t('soknad.skjemaNedlasting.liste', { - returnObjects: true, - }) as string[] - ).map((element, key) => ( -
  • {element}
  • - ))} -
    -
    + return ( + <> + + {t('soknad.visningsSteg.steg0.tittel')} + + + + + {vedlegg.label} + + + {t('soknad.skjemaNedlasting.listeTittel')} + + {( + t('soknad.skjemaNedlasting.liste', { + returnObjects: true, + }) as string[] + ).map((element, key) => ( +
  • {element}
  • + ))} +
    +
    - {vedlegg.skjemaurl && ( - - {t('soknad.skjemaNedlasting.lastNedKnapp')} - - )} -
    + {vedlegg.skjemaurl && ( + {t('soknad.skjemaNedlasting.lastNedKnapp')} + )} +
    - - + + - - - - ); + + + + ); } export default SkjemaNedlasting; diff --git a/components/SkjemaOpplasting.tsx b/components/SkjemaOpplasting.tsx index ebc98b86..9f388f31 100644 --- a/components/SkjemaOpplasting.tsx +++ b/components/SkjemaOpplasting.tsx @@ -1,94 +1,89 @@ -import React, { useState } from 'react'; -import { Heading, Button } from '@navikt/ds-react'; -import styled from 'styled-components'; +import { Button, Heading } from '@navikt/ds-react'; +import { useState } from 'react'; import { useTranslation } from 'react-i18next'; -import { VedleggType } from '../types/types'; +import styled from 'styled-components'; +import { SoknadType, VedleggType } from '../types/types'; import { SideValideringProvider } from './SideValideringProvider'; -import { SoknadType } from '../types/types'; +import { useModalContext } from './SoknadModalProvider'; import Vedlegg from './Vedlegg'; import { ButtonContainer } from './common/ButtonContainer'; -import { useModalContext } from './SoknadModalProvider'; import { Linje } from './common/Linje'; const PaddedVedlegg = styled.div` - > * { - margin-top: 16px; - } + > * { + margin-top: 16px; + } `; export interface SkjemaOpplastingdProps { - vedlegg: VedleggType; - soknad: SoknadType; - oppdaterVisningsSteg: (nr: number) => void; + vedlegg: VedleggType; + soknad: SoknadType; + oppdaterVisningsSteg: (nr: number) => void; } function SkjemaOpplasting(props: SkjemaOpplastingdProps) { - const { vedlegg, soknad, oppdaterVisningsSteg } = props; + const { vedlegg, soknad, oppdaterVisningsSteg } = props; - const { t } = useTranslation(); + const { t } = useTranslation(); - const { openSlettSoknadModal } = useModalContext(); + const { openSlettSoknadModal } = useModalContext(); - const [side1HarFeil, setSide1HarFeil] = useState(false); - const [visSide1Feil, setVisSide1Feil] = useState(false); - const [side1Valideringfokus, setSide1Valideringfokus] = - useState(false); + const [side1HarFeil, setSide1HarFeil] = useState(false); + const [visSide1Feil, setVisSide1Feil] = useState(false); + const [side1Valideringfokus, setSide1Valideringfokus] = useState(false); - return ( - <> - - {t('soknad.visningsSteg.steg1.tittel')} - - + return ( + <> + + {t('soknad.visningsSteg.steg1.tittel')} + + - - - - - - - - - - - - ); + + + + + + + + + + + + ); } export default SkjemaOpplasting; diff --git a/components/SoknadHeader.tsx b/components/SoknadHeader.tsx index 898e2e17..3b1121a7 100644 --- a/components/SoknadHeader.tsx +++ b/components/SoknadHeader.tsx @@ -1,49 +1,46 @@ +import '@navikt/ds-css'; import { Detail, Heading } from '@navikt/ds-react'; import styled from 'styled-components'; -import '@navikt/ds-css'; export interface SoknadHeaderProps { - soknadoverskrift: string; - skjemanr: string; + soknadoverskrift: string; + skjemanr: string; } export const StyledDetail = styled(Detail)` - color: var(--a-gray-900); + color: var(--a-gray-900); `; export const Style = styled.div` - & > * { - max-width: 60rem; - padding-left: 16px; - padding-right: 16px; - } + & > * { + max-width: 60rem; + padding-left: 16px; + padding-right: 16px; + } - align-items: center; - display: flex; - flex-direction: column; - border-bottom: 0.3rem solid var(--a-deepblue-200); - padding-top: 24px; - padding-bottom: 24px; - margin-left: -16px; - margin-right: -16px; - width: 100vw; - margin-left: calc(50% - 50vw); + align-items: center; + display: flex; + flex-direction: column; + border-bottom: 0.3rem solid var(--a-deepblue-200); + padding-top: 24px; + padding-bottom: 24px; + margin-left: -16px; + margin-right: -16px; + width: 100vw; + margin-left: calc(50% - 50vw); `; -export function SoknadHeader({ - soknadoverskrift, - skjemanr, -}: SoknadHeaderProps) { - return ( - - ); +export function SoknadHeader({ soknadoverskrift, skjemanr }: SoknadHeaderProps) { + return ( + + ); } diff --git a/components/SoknadModalProvider.tsx b/components/SoknadModalProvider.tsx index 49abc3c6..603dc6d5 100644 --- a/components/SoknadModalProvider.tsx +++ b/components/SoknadModalProvider.tsx @@ -1,203 +1,181 @@ import { BodyLong, Heading } from '@navikt/ds-react'; -import { - useState, - createContext, - useCallback, - useContext, -} from 'react'; +import { createContext, useCallback, useContext, useState } from 'react'; import { useTranslation } from 'react-i18next'; -import { FellesModal } from './FellesModal'; -import { formatertDato, datoOmXDager } from '../utils/dato'; -import { useVedleggslisteContext } from './VedleggsListe'; -import { useErrorMessageContext } from './ErrorMessageProvider'; +import { datoOmXDager, formatertDato } from '../utils/dato'; import { navigerTilMinSide } from '../utils/navigerTilMinSide'; +import { useErrorMessageContext } from './ErrorMessageProvider'; +import { FellesModal } from './FellesModal'; import { useLagringsProsessContext } from './LagringsProsessProvider'; +import { useVedleggslisteContext } from './VedleggsListe'; interface SoknadModalProviderProps { - children?: React.ReactNode; + children?: React.ReactNode; } interface ModalContextType { - openForstettSenereSoknadModal: () => void; - openSlettSoknadModal: () => void; - openSendInnUferdigSoknadModal: () => void; - openSendInnKomplettSoknadModal: () => void; + openForstettSenereSoknadModal: () => void; + openSlettSoknadModal: () => void; + openSendInnUferdigSoknadModal: () => void; + openSendInnKomplettSoknadModal: () => void; } const ModalContext = createContext(null); export const useModalContext = () => { - const modalContext = useContext(ModalContext); - if (!modalContext) { - throw new Error( - 'Mangler ErrorMessageProvider, når useModalContext kalles', - ); - } - return modalContext; + const modalContext = useContext(ModalContext); + if (!modalContext) { + throw new Error('Mangler ErrorMessageProvider, når useModalContext kalles'); + } + return modalContext; }; -export const SoknadModalProvider = ({ - children, -}: SoknadModalProviderProps) => { - const { t } = useTranslation(); - - const { soknad, onSendInn, slettSoknad } = - useVedleggslisteContext(); - const { lagrer } = useLagringsProsessContext(); - const { open: hasError } = useErrorMessageContext(); - - const [fortsettSenereSoknadModal, setForstettSenereSoknadModal] = - useState(false); - const [slettSoknadModal, setSlettSoknadModal] = useState(false); - const [sendInnUferdigSoknadModal, setSendInnUferdigSoknadModal] = - useState(false); - const [ - sendInnKomplettSoknadModal, - setSendInnKomplettSoknadModal, - ] = useState(false); - - if ( - hasError && - (fortsettSenereSoknadModal || - slettSoknadModal || - sendInnUferdigSoknadModal || - sendInnKomplettSoknadModal) - ) { - setForstettSenereSoknadModal(false); - setSlettSoknadModal(false); - setSendInnUferdigSoknadModal(false); - setSendInnKomplettSoknadModal(false); - } - - const openForstettSenereSoknadModal = useCallback(() => { - setForstettSenereSoknadModal(true); - }, [setForstettSenereSoknadModal]); - - const openSlettSoknadModal = useCallback(() => { - setSlettSoknadModal(true); - }, [setSlettSoknadModal]); - - const openSendInnUferdigSoknadModal = useCallback(() => { - setSendInnUferdigSoknadModal(true); - }, [setSendInnUferdigSoknadModal]); - - const openSendInnKomplettSoknadModal = useCallback(() => { - setSendInnKomplettSoknadModal(true); - }, [setSendInnKomplettSoknadModal]); - - return ( - - {children} - - - - {t('modal.fortsettSenere.tittel')} - - - {( - t('modal.fortsettSenere.liste', { - returnObjects: true, - }) as string[] - ).map((element, key) => ( -
  • {element}
  • - ))} -
    -
    - - - - {t('modal.slett.tittel')} - - - {( - t('modal.slett.liste', { - returnObjects: true, - }) as string[] - ).map((element, key) => ( -
  • {element}
  • - ))} -
    -
    - - { - await onSendInn(); - setSendInnUferdigSoknadModal(false); - }} - acceptButtonText={t('modal.sendInnUferdig.accept')} - cancelButtonText={t('modal.sendInnUferdig.cancel')} - isLoading={lagrer} - > - - {t('modal.sendInnUferdig.tittel')} - - - {( - t('modal.sendInnUferdig.liste', { - dato: formatertDato( - soknad.visningsType === 'ettersending' - ? new Date( - soknad.innsendingsFristDato, - ) - : datoOmXDager( - soknad.fristForEttersendelse, - ), - ), - - returnObjects: true, - }) as string[] - ).map((element, key) => ( -
  • {element}
  • - ))} -
    -
    - - { - await onSendInn(); - setSendInnKomplettSoknadModal(false); - }} - acceptButtonText={t('modal.sendInnKomplett.accept')} - cancelButtonText={t('modal.sendInnKomplett.cancel')} - isLoading={lagrer} - > - - {t('modal.sendInnKomplett.tittel')} - - - {( - t('modal.sendInnKomplett.liste', { - returnObjects: true, - }) as string[] - ).map((element, key) => ( -
  • {element}
  • - ))} -
    -
    -
    - ); +export const SoknadModalProvider = ({ children }: SoknadModalProviderProps) => { + const { t } = useTranslation(); + + const { soknad, onSendInn, slettSoknad } = useVedleggslisteContext(); + const { lagrer } = useLagringsProsessContext(); + const { open: hasError } = useErrorMessageContext(); + + const [fortsettSenereSoknadModal, setForstettSenereSoknadModal] = useState(false); + const [slettSoknadModal, setSlettSoknadModal] = useState(false); + const [sendInnUferdigSoknadModal, setSendInnUferdigSoknadModal] = useState(false); + const [sendInnKomplettSoknadModal, setSendInnKomplettSoknadModal] = useState(false); + + if ( + hasError && + (fortsettSenereSoknadModal || slettSoknadModal || sendInnUferdigSoknadModal || sendInnKomplettSoknadModal) + ) { + setForstettSenereSoknadModal(false); + setSlettSoknadModal(false); + setSendInnUferdigSoknadModal(false); + setSendInnKomplettSoknadModal(false); + } + + const openForstettSenereSoknadModal = useCallback(() => { + setForstettSenereSoknadModal(true); + }, [setForstettSenereSoknadModal]); + + const openSlettSoknadModal = useCallback(() => { + setSlettSoknadModal(true); + }, [setSlettSoknadModal]); + + const openSendInnUferdigSoknadModal = useCallback(() => { + setSendInnUferdigSoknadModal(true); + }, [setSendInnUferdigSoknadModal]); + + const openSendInnKomplettSoknadModal = useCallback(() => { + setSendInnKomplettSoknadModal(true); + }, [setSendInnKomplettSoknadModal]); + + return ( + + {children} + + + + {t('modal.fortsettSenere.tittel')} + + + {( + t('modal.fortsettSenere.liste', { + returnObjects: true, + }) as string[] + ).map((element, key) => ( +
  • {element}
  • + ))} +
    +
    + + + + {t('modal.slett.tittel')} + + + {( + t('modal.slett.liste', { + returnObjects: true, + }) as string[] + ).map((element, key) => ( +
  • {element}
  • + ))} +
    +
    + + { + await onSendInn(); + setSendInnUferdigSoknadModal(false); + }} + acceptButtonText={t('modal.sendInnUferdig.accept')} + cancelButtonText={t('modal.sendInnUferdig.cancel')} + isLoading={lagrer} + > + + {t('modal.sendInnUferdig.tittel')} + + + {( + t('modal.sendInnUferdig.liste', { + dato: formatertDato( + soknad.visningsType === 'ettersending' + ? new Date(soknad.innsendingsFristDato) + : datoOmXDager(soknad.fristForEttersendelse), + ), + + returnObjects: true, + }) as string[] + ).map((element, key) => ( +
  • {element}
  • + ))} +
    +
    + + { + await onSendInn(); + setSendInnKomplettSoknadModal(false); + }} + acceptButtonText={t('modal.sendInnKomplett.accept')} + cancelButtonText={t('modal.sendInnKomplett.cancel')} + isLoading={lagrer} + > + + {t('modal.sendInnKomplett.tittel')} + + + {( + t('modal.sendInnKomplett.liste', { + returnObjects: true, + }) as string[] + ).map((element, key) => ( +
  • {element}
  • + ))} +
    +
    +
    + ); }; diff --git a/components/ValideringsRamme.tsx b/components/ValideringsRamme.tsx index 27b5de7b..c690320f 100644 --- a/components/ValideringsRamme.tsx +++ b/components/ValideringsRamme.tsx @@ -3,47 +3,37 @@ import styled from 'styled-components'; import { ErrorMessageWithDot } from './textStyle'; interface ValideringsRammeProps { - id: string; - visFeil: boolean; - melding: string; - children?: React.ReactNode; + id: string; + visFeil: boolean; + melding: string; + children?: React.ReactNode; } const FeilRamme = styled.div` - &.visFeil { - border: 1px solid var(--a-border-danger); - box-shadow: 0 0 0 1px var(--a-border-danger); - border-radius: 8px; + &.visFeil { + border: 1px solid var(--a-border-danger); + box-shadow: 0 0 0 1px var(--a-border-danger); + border-radius: 8px; - :hover { - border-color: var(--a-border-action); - } - :focus { - box-shadow: 0 0 0 1px var(--a-border-danger), - var(--a-shadow-focus); - } - margin-bottom: 0.5rem; + :hover { + border-color: var(--a-border-action); } + :focus { + box-shadow: + 0 0 0 1px var(--a-border-danger), + var(--a-shadow-focus); + } + margin-bottom: 0.5rem; + } `; -export const ValideringsRamme = ({ - id, - visFeil, - melding, - children, -}: ValideringsRammeProps) => { - return ( - <> - - {children} - - {visFeil && ( - {melding} - )} - - ); +export const ValideringsRamme = ({ id, visFeil, melding, children }: ValideringsRammeProps) => { + return ( + <> + + {children} + + {visFeil && {melding}} + + ); }; diff --git a/components/Vedlegg.tsx b/components/Vedlegg.tsx index 6b84ceab..557182a7 100644 --- a/components/Vedlegg.tsx +++ b/components/Vedlegg.tsx @@ -1,520 +1,385 @@ -import React, { useEffect, useReducer } from 'react'; -import { useState } from 'react'; import axios from 'axios'; +import { useEffect, useReducer, useState } from 'react'; import { useErrorMessage } from '../hooks/useErrorMessage'; -import { - Panel, - Heading, - Link as NavLink, - Button, - BodyShort, -} from '@navikt/ds-react'; -import { Filvelger } from './Filvelger'; +import { BodyShort, Button, Heading, Link as NavLink, Panel } from '@navikt/ds-react'; +import { useTranslation } from 'react-i18next'; import styled from 'styled-components'; import { v4 as uuidv4 } from 'uuid'; -import { useTranslation } from 'react-i18next'; import VedleggRadio from '../components/VedleggRadio'; +import { Filvelger } from './Filvelger'; +import getConfig from 'next/config'; +import { useValidation } from '../hooks/useValidation'; +import { FIL_STATUS } from '../types/enums'; import { OpplastetFil, VedleggType } from '../types/types'; import { EndreVedlegg } from './EndreVedlegg'; import { Fil, FilePanel } from './Fil'; -import getConfig from 'next/config'; import { FilUploadIcon } from './FilUploadIcon'; -import { FIL_STATUS } from '../types/enums'; -import { useValidation } from '../hooks/useValidation'; import { ValideringsRamme } from './ValideringsRamme'; -import { useVedleggslisteContext } from './VedleggsListe'; -import sanitizeHtml from 'sanitize-html'; import parse from 'html-react-parser'; +import sanitizeHtml from 'sanitize-html'; +import { useVedleggslisteContext } from './VedleggsListe'; const { publicRuntimeConfig } = getConfig(); export interface ExtendedVedleggType extends VedleggType { - autoFocus?: boolean; + autoFocus?: boolean; } export interface VedleggProps { - vedlegg: ExtendedVedleggType; - innsendingsId: string; - erAnnetVedlegg?: boolean; + vedlegg: ExtendedVedleggType; + innsendingsId: string; + erAnnetVedlegg?: boolean; } export interface FilData { - komponentID?: string; - lokalFil?: File; - opplastetFil?: OpplastetFil; + komponentID?: string; + lokalFil?: File; + opplastetFil?: OpplastetFil; } export const ACTIONS = { - NY_FIL: 'NY_FIL', - SLETT_FIL: 'SLETT_FIL', - ENDRE_FIL: 'ENDRE_FIL', - RESET_LISTE: 'RESET_LISTE', + NY_FIL: 'NY_FIL', + SLETT_FIL: 'SLETT_FIL', + ENDRE_FIL: 'ENDRE_FIL', + RESET_LISTE: 'RESET_LISTE', } as const; export type ActionType = - | { - type: Exclude< - (typeof ACTIONS)[keyof typeof ACTIONS], - typeof ACTIONS.RESET_LISTE - >; - filData: FilData; - } - | { type: typeof ACTIONS.RESET_LISTE }; + | { + type: Exclude<(typeof ACTIONS)[keyof typeof ACTIONS], typeof ACTIONS.RESET_LISTE>; + filData: FilData; + } + | { type: typeof ACTIONS.RESET_LISTE }; const filListeReducer = (filListe: FilData[], action: ActionType) => { - switch (action.type) { - case ACTIONS.NY_FIL: { - return [ - ...filListe, - { komponentID: uuidv4(), ...action.filData }, - ]; - } - case ACTIONS.SLETT_FIL: { - return filListe.filter( - (fil) => - fil.komponentID !== action.filData.komponentID, - ); - } - case ACTIONS.ENDRE_FIL: { - return filListe.map((fil) => - fil.komponentID === action.filData.komponentID - ? action.filData - : fil, - ); - } - case ACTIONS.RESET_LISTE: { - return initialState; - } + switch (action.type) { + case ACTIONS.NY_FIL: { + return [...filListe, { komponentID: uuidv4(), ...action.filData }]; + } + case ACTIONS.SLETT_FIL: { + return filListe.filter((fil) => fil.komponentID !== action.filData.komponentID); + } + case ACTIONS.ENDRE_FIL: { + return filListe.map((fil) => (fil.komponentID === action.filData.komponentID ? action.filData : fil)); + } + case ACTIONS.RESET_LISTE: { + return initialState; } + } }; const initialState: FilData[] = []; export const VedleggContainer = styled.section<{ - $extraMargin?: boolean; + $extraMargin?: boolean; }>` - ${(props) => props.$extraMargin && 'margin-bottom: 60px'}; + ${(props) => props.$extraMargin && 'margin-bottom: 60px'}; `; export const VedleggPanel = styled(Panel)` - background-color: var(--a-bg-subtle); - border-radius: 8px; - padding: 24px; - @media only screen and (max-width: 600px) { - padding: 12px; - } + background-color: var(--a-bg-subtle); + border-radius: 8px; + padding: 24px; + @media only screen and (max-width: 600px) { + padding: 12px; + } `; const ListeGruppe = styled.div` - padding-bottom: 1.5rem; - @media only screen and (max-width: 600px) { - ol { - padding-left: 1.5rem; - } + padding-bottom: 1.5rem; + @media only screen and (max-width: 600px) { + ol { + padding-left: 1.5rem; } + } `; const VedleggBeskrivelse = styled(BodyShort)` - margin-bottom: 24px; + margin-bottom: 24px; `; const VedleggButtons = styled.div` - display: flex; - gap: 20px; - @media only screen and (max-width: 475px) { - flex-direction: column; - button, - label { - width: 100%; - } + display: flex; + gap: 20px; + @media only screen and (max-width: 475px) { + flex-direction: column; + button, + label { + width: 100%; } + } `; const SendtInnTidligereGruppe = styled.div` - margin-bottom: 24px; + margin-bottom: 24px; `; const FilListeGruppe = styled.div` - margin-top: 24px; - li:not(:last-child) { - margin-bottom: 8px; - } + margin-top: 24px; + li:not(:last-child) { + margin-bottom: 8px; + } `; const FilMottattFelt = styled.div` - display: flex; - flex-direction: column; - @media only screen and (max-width: 600px) { - flex-direction: row; - p:first-child { - padding-right: 0.5rem; - } + display: flex; + flex-direction: column; + @media only screen and (max-width: 600px) { + flex-direction: row; + p:first-child { + padding-right: 0.5rem; } + } `; const List = styled.ul` - padding: 0; - margin: 0; - list-style: none; + padding: 0; + margin: 0; + list-style: none; `; function Vedlegg(props: VedleggProps) { - const { innsendingsId, vedlegg } = props; - const { opplastingsStatus } = vedlegg; - - const { slettAnnetVedlegg } = useVedleggslisteContext(); - - const { t } = useTranslation(); - - const [filListe, dispatch] = useReducer( - filListeReducer, - initialState, - ); - const [hasFetched, setHasFetched] = useState(false); - const [endrer, setEndrer] = useState(false); - const [tittel, setTittel] = useState(vedlegg.label); - const [valgtOpplastingStatus, setValgtOpplastingStatus] = - useState(opplastingsStatus); - const [prevOpplastingStatus, setPrevOpplastingStatus] = - useState(opplastingsStatus); - const [autoFocus, setAutoFocus] = useState(vedlegg.autoFocus); - const { showError } = useErrorMessage(); - - if (opplastingsStatus !== prevOpplastingStatus) { - setPrevOpplastingStatus(opplastingsStatus); - if (valgtOpplastingStatus !== opplastingsStatus) { - setValgtOpplastingStatus(opplastingsStatus); - } + const { innsendingsId, vedlegg } = props; + const { opplastingsStatus } = vedlegg; + + const { slettAnnetVedlegg } = useVedleggslisteContext(); + + const { t } = useTranslation(); + + const [filListe, dispatch] = useReducer(filListeReducer, initialState); + const [hasFetched, setHasFetched] = useState(false); + const [endrer, setEndrer] = useState(false); + const [tittel, setTittel] = useState(vedlegg.label); + const [valgtOpplastingStatus, setValgtOpplastingStatus] = useState(opplastingsStatus); + const [prevOpplastingStatus, setPrevOpplastingStatus] = useState(opplastingsStatus); + const [autoFocus, setAutoFocus] = useState(vedlegg.autoFocus); + const { showError } = useErrorMessage(); + + if (opplastingsStatus !== prevOpplastingStatus) { + setPrevOpplastingStatus(opplastingsStatus); + if (valgtOpplastingStatus !== opplastingsStatus) { + setValgtOpplastingStatus(opplastingsStatus); } - - const harOpplastetFil = - opplastingsStatus === 'LastetOpp' || - filListe.some((fil) => fil.opplastetFil); - - const erAnnetVedlegg = - vedlegg.vedleggsnr?.toUpperCase() === 'N6' && - !vedlegg.erPakrevd; - const erSendtInnTidligere = vedlegg.innsendtdato !== null; - const skjulFiler = - valgtOpplastingStatus === 'SendSenere' || - valgtOpplastingStatus === 'SendesAvAndre'; - - const manglerFilTekst = () => { - if (vedlegg.erHoveddokument) - return t('soknad.hovedSkjema.feilmelding.manglerFil', { - label: vedlegg.label, - }); - if (erAnnetVedlegg) - return t('soknad.vedlegg.annet.feilmelding.manglerFil', { - label: vedlegg.label, + } + + const harOpplastetFil = opplastingsStatus === 'LastetOpp' || filListe.some((fil) => fil.opplastetFil); + + const erAnnetVedlegg = vedlegg.vedleggsnr?.toUpperCase() === 'N6' && !vedlegg.erPakrevd; + const erSendtInnTidligere = vedlegg.innsendtdato !== null; + const skjulFiler = valgtOpplastingStatus === 'SendSenere' || valgtOpplastingStatus === 'SendesAvAndre'; + + const manglerFilTekst = () => { + if (vedlegg.erHoveddokument) + return t('soknad.hovedSkjema.feilmelding.manglerFil', { + label: vedlegg.label, + }); + if (erAnnetVedlegg) + return t('soknad.vedlegg.annet.feilmelding.manglerFil', { + label: vedlegg.label, + }); + return t('soknad.vedlegg.feilmelding.manglerFil', { + label: vedlegg.label, + }); + }; + + const feilId = `vedlegg-feil-${vedlegg.id}`; + + const [visFeil, valideringsMelding] = useValidation({ + komponentId: feilId, + melding: manglerFilTekst(), + harFeil: !filListe.length && valgtOpplastingStatus === 'IkkeValgt' && !endrer, + }); + + useEffect(() => { + if (!hasFetched && innsendingsId && vedlegg.id) { + setHasFetched(true); + axios + .get(`${publicRuntimeConfig.apiUrl}/frontend/v1/soknad/${innsendingsId}/vedlegg/${vedlegg.id}/fil`) + .then((response) => { + const responseJSON = response.data; + for (const item in responseJSON) { + const jsonitem = responseJSON[item]; + const nyFil: FilData = { + opplastetFil: { + id: jsonitem.id, + filnavn: jsonitem.filnavn, + storrelse: jsonitem.storrelse, + }, + }; + dispatch({ + type: ACTIONS.NY_FIL, + filData: nyFil, }); - return t('soknad.vedlegg.feilmelding.manglerFil', { - label: vedlegg.label, + } + }) + .catch((error) => { + showError(error); }); - }; - - const feilId = `vedlegg-feil-${vedlegg.id}`; + } - const [visFeil, valideringsMelding] = useValidation({ - komponentId: feilId, - melding: manglerFilTekst(), - harFeil: - !filListe.length && - valgtOpplastingStatus === 'IkkeValgt' && - !endrer, - }); + return () => + dispatch({ + type: ACTIONS.RESET_LISTE, + }); + }, [innsendingsId, vedlegg.id, showError, hasFetched]); - useEffect(() => { - if (!hasFetched && innsendingsId && vedlegg.id) { - setHasFetched(true); - axios - .get( - `${publicRuntimeConfig.apiUrl}/frontend/v1/soknad/${innsendingsId}/vedlegg/${vedlegg.id}/fil`, - ) - .then((response) => { - const responseJSON = response.data; - for (const item in responseJSON) { - const jsonitem = responseJSON[item]; - const nyFil: FilData = { - opplastetFil: { - id: jsonitem.id, - filnavn: jsonitem.filnavn, - storrelse: jsonitem.storrelse, - }, - }; - dispatch({ - type: ACTIONS.NY_FIL, - filData: nyFil, - }); - } - }) - .catch((error) => { - showError(error); - }); - } - - return () => - dispatch({ - type: ACTIONS.RESET_LISTE, - }); - }, [innsendingsId, vedlegg.id, showError, hasFetched]); - - const getFilvelgerButtonText = () => { - if (vedlegg.erHoveddokument) { - return t('soknad.hovedSkjema.filvelgerKnapp'); - } - if (erSendtInnTidligere) { - return t('soknad.vedlegg.ettersendingFilvelgerKnapp'); - } - return null; // default text - }; - - return ( - - - {endrer ? ( - { + if (vedlegg.erHoveddokument) { + return t('soknad.hovedSkjema.filvelgerKnapp'); + } + if (erSendtInnTidligere) { + return t('soknad.vedlegg.ettersendingFilvelgerKnapp'); + } + return null; // default text + }; + + return ( + + + {endrer ? ( + + ) : ( + +
    + {(vedlegg.erHoveddokument || !vedlegg.skjemaurl) && ( + + {tittel} + + )} + {!vedlegg.erHoveddokument && vedlegg.skjemaurl && ( + + + {t('link.nyFane', { + tekst: tittel, + })} + + + )} + + {vedlegg.erHoveddokument && ( + + {t('soknad.hovedSkjema.listeTittel')} + + {( + t('soknad.hovedSkjema.liste', { + returnObjects: true, + }) as string[] + ).map((element, key) => ( +
  • {element}
  • + ))} +
    +
    + )} + {/* beskrivelse ligger i mange søknader fra fyll ut, men finnes ikke for dokumentinnsending */} + {vedlegg.beskrivelse && ( + {parse(sanitizeHtml(vedlegg.beskrivelse))} + )} +
    + + {vedlegg.erPakrevd && !vedlegg.erHoveddokument && !erSendtInnTidligere && ( + + )} + + {erSendtInnTidligere && ( + + + {t('soknad.vedlegg.tidligereSendtInn')} + + +
    + +
    + + {vedlegg.label} +
    + + {t('soknad.vedlegg.mottatt')} + + {new Date(vedlegg.innsendtdato!).toLocaleString('no', { + dateStyle: 'short', + })} + + +
    +
    +
    + )} + + {!skjulFiler && ( + + + dispatch({ + type: ACTIONS.NY_FIL, + filData: { + lokalFil: fil, + }, + }) + } + /> + + {erAnnetVedlegg && !erSendtInnTidligere && ( + <> + + + + + )} + + )} + + {!skjulFiler && filListe.length > 0 && ( + + + {t('soknad.vedlegg.sendtInnNaa')} + + + {filListe.map((fil) => { + return ( + - ) : ( - -
    - {(vedlegg.erHoveddokument || - !vedlegg.skjemaurl) && ( - - {tittel} - - )} - {!vedlegg.erHoveddokument && - vedlegg.skjemaurl && ( - - - {t('link.nyFane', { - tekst: tittel, - })} - - - )} - - {vedlegg.erHoveddokument && ( - - - {t( - 'soknad.hovedSkjema.listeTittel', - )} - - - {( - t( - 'soknad.hovedSkjema.liste', - { - returnObjects: - true, - }, - ) as string[] - ).map((element, key) => ( -
  • - {element} -
  • - ))} -
    -
    - )} - {/* beskrivelse ligger i mange søknader fra fyll ut, men finnes ikke for dokumentinnsending */} - {vedlegg.beskrivelse && ( - - {parse( - sanitizeHtml( - vedlegg.beskrivelse, - ), - )} - - )} -
    - - {vedlegg.erPakrevd && - !vedlegg.erHoveddokument && - !erSendtInnTidligere && ( - - )} - - {erSendtInnTidligere && ( - - - {t( - 'soknad.vedlegg.tidligereSendtInn', - )} - - -
    - -
    - - - {vedlegg.label} - -
    - - - {t( - 'soknad.vedlegg.mottatt', - )} - - - {new Date( - vedlegg.innsendtdato!, - ).toLocaleString( - 'no', - { - dateStyle: - 'short', - }, - )} - - -
    -
    -
    - )} - - {!skjulFiler && ( - - - dispatch({ - type: ACTIONS.NY_FIL, - filData: { - lokalFil: fil, - }, - }) - } - /> - - {erAnnetVedlegg && - !erSendtInnTidligere && ( - <> - - - - - )} - - )} - - {!skjulFiler && filListe.length > 0 && ( - - - {t('soknad.vedlegg.sendtInnNaa')} - - - {filListe.map((fil) => { - return ( - - ); - })} - - - )} -
    - )} -
    -
    - ); + lokalFil={fil.lokalFil} + opplastetFil={fil.opplastetFil} + filListeDispatch={dispatch} + /> + ); + })} + + + )} + + )} +
    +
    + ); } export default Vedlegg; diff --git a/components/VedleggRadio.tsx b/components/VedleggRadio.tsx index 6c57e85a..530eb038 100644 --- a/components/VedleggRadio.tsx +++ b/components/VedleggRadio.tsx @@ -1,175 +1,149 @@ -import React, { - useCallback, - useEffect, - useRef, - useState, -} from 'react'; -import { RadioGroup, Radio } from '@navikt/ds-react'; -import { OpplastingsStatus, VedleggType } from '../types/types'; -import styled from 'styled-components'; +import { Radio, RadioGroup } from '@navikt/ds-react'; +import axios, { AxiosResponse } from 'axios'; +import getConfig from 'next/config'; +import React, { useCallback, useEffect, useRef, useState } from 'react'; import { useTranslation } from 'react-i18next'; -import { useVedleggslisteContext } from './VedleggsListe'; +import styled from 'styled-components'; import { useDebouncedCallback } from 'use-debounce'; -import getConfig from 'next/config'; -import axios, { AxiosResponse } from 'axios'; import { useErrorMessage } from '../hooks/useErrorMessage'; +import { OpplastingsStatus, VedleggType } from '../types/types'; import { useLagringsProsessContext } from './LagringsProsessProvider'; +import { useVedleggslisteContext } from './VedleggsListe'; import { ScreenReaderOnly } from './textStyle'; const { publicRuntimeConfig } = getConfig(); interface VedleggRadioProp { - id: number; - vedlegg: VedleggType; - harOpplastetFil: boolean; - valgtOpplastingStatus: OpplastingsStatus; - setValgtOpplastingStatus: React.Dispatch< - React.SetStateAction - >; + id: number; + vedlegg: VedleggType; + harOpplastetFil: boolean; + valgtOpplastingStatus: OpplastingsStatus; + setValgtOpplastingStatus: React.Dispatch>; } const StyledRadioGroup = styled(RadioGroup)` - &:not(:last-child) { - padding-bottom: 24px; - } + &:not(:last-child) { + padding-bottom: 24px; + } `; function VedleggRadio({ - id, - vedlegg, - harOpplastetFil, - valgtOpplastingStatus, - setValgtOpplastingStatus, + id, + vedlegg, + harOpplastetFil, + valgtOpplastingStatus, + setValgtOpplastingStatus, }: VedleggRadioProp) { - const { t } = useTranslation(); - const { showError } = useErrorMessage(); - const controller = useRef(new AbortController()); + const { t } = useTranslation(); + const { showError } = useErrorMessage(); + const controller = useRef(new AbortController()); - const [harKjortFix, setHarKjortFix] = useState(false); + const [harKjortFix, setHarKjortFix] = useState(false); - const { soknad, oppdaterLokalOpplastingStatus } = - useVedleggslisteContext(); - const { nyLagringsProsess } = useLagringsProsessContext(); + const { soknad, oppdaterLokalOpplastingStatus } = useVedleggslisteContext(); + const { nyLagringsProsess } = useLagringsProsessContext(); - const oppdaterOpplastingStatus = useCallback( - (nyOpplastingsStatus: OpplastingsStatus) => { - nyLagringsProsess( - axios.patch( - `${publicRuntimeConfig.apiUrl}/frontend/v1/soknad/${soknad.innsendingsId}/vedlegg/${id}`, - { - opplastingsStatus: nyOpplastingsStatus, - }, - { - timeout: 10000, - signal: controller.current.signal, - }, - ), - ) - .then((response: AxiosResponse) => { - oppdaterLokalOpplastingStatus( - id, - response.data.opplastingsStatus, - ); - }) - .catch((error) => { - if (axios.isCancel(error)) { - // avbrutt - return; - } - setValgtOpplastingStatus( - vedlegg.opplastingsStatus, - ); - showError(error); - }); - }, - [ - soknad.innsendingsId, - id, - vedlegg.opplastingsStatus, - setValgtOpplastingStatus, - nyLagringsProsess, - oppdaterLokalOpplastingStatus, - showError, - ], - ); + const oppdaterOpplastingStatus = useCallback( + (nyOpplastingsStatus: OpplastingsStatus) => { + nyLagringsProsess( + axios.patch( + `${publicRuntimeConfig.apiUrl}/frontend/v1/soknad/${soknad.innsendingsId}/vedlegg/${id}`, + { + opplastingsStatus: nyOpplastingsStatus, + }, + { + timeout: 10000, + signal: controller.current.signal, + }, + ), + ) + .then((response: AxiosResponse) => { + oppdaterLokalOpplastingStatus(id, response.data.opplastingsStatus); + }) + .catch((error) => { + if (axios.isCancel(error)) { + // avbrutt + return; + } + setValgtOpplastingStatus(vedlegg.opplastingsStatus); + showError(error); + }); + }, + [ + soknad.innsendingsId, + id, + vedlegg.opplastingsStatus, + setValgtOpplastingStatus, + nyLagringsProsess, + oppdaterLokalOpplastingStatus, + showError, + ], + ); - const debounced = useDebouncedCallback( - (debouncedLokalOpplastingsStatus) => { - if ( - debouncedLokalOpplastingsStatus === - vedlegg.opplastingsStatus - ) - return; + const debounced = useDebouncedCallback( + (debouncedLokalOpplastingsStatus) => { + if (debouncedLokalOpplastingsStatus === vedlegg.opplastingsStatus) return; - oppdaterOpplastingStatus(debouncedLokalOpplastingsStatus); - }, - 500, - { leading: true }, - ); + oppdaterOpplastingStatus(debouncedLokalOpplastingsStatus); + }, + 500, + { leading: true }, + ); - // TODO: useEffect kan fjernes etter 4. april - // Fikser opp i problem som satt opplastingsStatus til IkkeValgt, etter opplasting av fil - useEffect(() => { - if ( - !harKjortFix && - vedlegg.opplastingsStatus === 'IkkeValgt' && - harOpplastetFil - ) { - oppdaterOpplastingStatus('LastetOpp'); - setHarKjortFix(true); - } - }, [ - harKjortFix, - harOpplastetFil, - vedlegg.opplastingsStatus, - oppdaterOpplastingStatus, - ]); + // TODO: useEffect kan fjernes etter 4. april + // Fikser opp i problem som satt opplastingsStatus til IkkeValgt, etter opplasting av fil + useEffect(() => { + if (!harKjortFix && vedlegg.opplastingsStatus === 'IkkeValgt' && harOpplastetFil) { + oppdaterOpplastingStatus('LastetOpp'); + setHarKjortFix(true); + } + }, [harKjortFix, harOpplastetFil, vedlegg.opplastingsStatus, oppdaterOpplastingStatus]); - const handleChange = (val: OpplastingsStatus) => { - controller.current.abort(); - const newController = new AbortController(); - controller.current = newController; - debounced(val); - setValgtOpplastingStatus(val); - }; + const handleChange = (val: OpplastingsStatus) => { + controller.current.abort(); + const newController = new AbortController(); + controller.current = newController; + debounced(val); + setValgtOpplastingStatus(val); + }; - return ( - - {t('soknad.vedlegg.radio.tittel')} - - {t('for')} {vedlegg.label} - - - } - size="medium" - onChange={(val: OpplastingsStatus) => handleChange(val)} - onBlur={(e) => { - if (!e.currentTarget.contains(e.relatedTarget)) { - // Trigger når radioGroup mister fokus - debounced.flush(); - } - }} - value={valgtOpplastingStatus} - > - {!harOpplastetFil && ( - - {t('soknad.vedlegg.radio.lasterOppNaa')} - - )} - {harOpplastetFil && ( - - {t('soknad.vedlegg.radio.lasterOppNaa')} - - )} - - {t('soknad.vedlegg.radio.sendSenere')} - - - {t('soknad.vedlegg.radio.sendesAvAndre')} - - - ); + return ( + + {t('soknad.vedlegg.radio.tittel')} + + {t('for')} {vedlegg.label} + + + } + size="medium" + onChange={(val: OpplastingsStatus) => handleChange(val)} + onBlur={(e) => { + if (!e.currentTarget.contains(e.relatedTarget)) { + // Trigger når radioGroup mister fokus + debounced.flush(); + } + }} + value={valgtOpplastingStatus} + > + {!harOpplastetFil && ( + + {t('soknad.vedlegg.radio.lasterOppNaa')} + + )} + {harOpplastetFil && ( + + {t('soknad.vedlegg.radio.lasterOppNaa')} + + )} + + {t('soknad.vedlegg.radio.sendSenere')} + + + {t('soknad.vedlegg.radio.sendesAvAndre')} + + + ); } export default VedleggRadio; diff --git a/components/VedleggsListe.tsx b/components/VedleggsListe.tsx index 0ca14e97..d06bb1e8 100644 --- a/components/VedleggsListe.tsx +++ b/components/VedleggsListe.tsx @@ -1,319 +1,239 @@ -import React, { - createContext, - useCallback, - useContext, - useMemo, - useRef, -} from 'react'; -import { useState } from 'react'; import axios from 'axios'; -import { useErrorMessage } from '../hooks/useErrorMessage'; -import { - VedleggType, - SoknadType, - OpplastingsStatus, -} from '../types/types'; -import { ExtendedVedleggType } from '../components/Vedlegg'; -import SkjemaNedlasting from '../components/SkjemaNedlasting'; -import SkjemaOpplasting from './SkjemaOpplasting'; -import Kvittering, { KvitteringsDto } from '../components/Kvittering'; import getConfig from 'next/config'; +import React, { createContext, useCallback, useContext, useMemo, useRef, useState } from 'react'; import styled from 'styled-components'; -import LastOppVedlegg from './LastOppVedlegg'; -import { SoknadModalProvider } from './SoknadModalProvider'; +import Kvittering, { KvitteringsDto } from '../components/Kvittering'; +import SkjemaNedlasting from '../components/SkjemaNedlasting'; +import { ExtendedVedleggType } from '../components/Vedlegg'; +import { useErrorMessage } from '../hooks/useErrorMessage'; +import { OpplastingsStatus, SoknadType, VedleggType } from '../types/types'; import { navigerTilMinSide } from '../utils/navigerTilMinSide'; import { AutomatiskInnsending } from './AutomatiskInnsending'; import { useLagringsProsessContext } from './LagringsProsessProvider'; +import LastOppVedlegg from './LastOppVedlegg'; +import SkjemaOpplasting from './SkjemaOpplasting'; +import { SoknadModalProvider } from './SoknadModalProvider'; const { publicRuntimeConfig } = getConfig(); const initialVedleggsliste: VedleggType[] = []; const Style = styled.div` - padding-top: 44px; - margin-bottom: 44px; - outline: none; - max-width: 50rem; + padding-top: 44px; + margin-bottom: 44px; + outline: none; + max-width: 50rem; `; export interface VedleggsListeProps { - soknad: SoknadType; - setSoknad: React.Dispatch< - React.SetStateAction - >; - erEttersending: boolean; - visningsSteg?: number; - visningsType?: string; + soknad: SoknadType; + setSoknad: React.Dispatch>; + erEttersending: boolean; + visningsSteg?: number; + visningsType?: string; } const soknadErKomplett = (vedleggsliste: VedleggType[]): boolean => - vedleggsliste - .filter((element) => element.erPakrevd === true) - .every((element) => { - return ( - element.opplastingsStatus === 'LastetOpp' || - element.opplastingsStatus === 'SendesAvAndre' || - element.opplastingsStatus === 'Innsendt' - ); - }); + vedleggsliste + .filter((element) => element.erPakrevd === true) + .every((element) => { + return ( + element.opplastingsStatus === 'LastetOpp' || + element.opplastingsStatus === 'SendesAvAndre' || + element.opplastingsStatus === 'Innsendt' + ); + }); const soknadKanSendesInn = (vedleggsliste: VedleggType[]): boolean => - vedleggsliste - .filter((element) => element.erHoveddokument === true) - .every( - (element) => element.opplastingsStatus === 'LastetOpp', - ); + vedleggsliste + .filter((element) => element.erHoveddokument === true) + .every((element) => element.opplastingsStatus === 'LastetOpp'); interface VedleggslisteContextType { - soknad: SoknadType; - soknadKlar: boolean; - soknadDelvisKlar: boolean; - onSendInn: () => Promise; - slettSoknad: () => void; - oppdaterLokalOpplastingStatus: ( - id: number, - opplastingsStatus: OpplastingsStatus, - ) => void; - leggTilVedlegg: (vedlegg: ExtendedVedleggType) => void; - slettAnnetVedlegg: (vedleggId: number) => void; + soknad: SoknadType; + soknadKlar: boolean; + soknadDelvisKlar: boolean; + onSendInn: () => Promise; + slettSoknad: () => void; + oppdaterLokalOpplastingStatus: (id: number, opplastingsStatus: OpplastingsStatus) => void; + leggTilVedlegg: (vedlegg: ExtendedVedleggType) => void; + slettAnnetVedlegg: (vedleggId: number) => void; } -export const VedleggslisteContext = - createContext(null); +export const VedleggslisteContext = createContext(null); export const useVedleggslisteContext = () => { - const vedleggslisteContext = useContext(VedleggslisteContext); - if (!vedleggslisteContext) { - throw new Error( - 'Mangler VedleggsListe -provider, når useVedleggslisteContext kalles', - ); - } - return vedleggslisteContext; + const vedleggslisteContext = useContext(VedleggslisteContext); + if (!vedleggslisteContext) { + throw new Error('Mangler VedleggsListe -provider, når useVedleggslisteContext kalles'); + } + return vedleggslisteContext; }; function VedleggsListe({ soknad, setSoknad }: VedleggsListeProps) { - const { showError } = useErrorMessage(); - const { lagrerNaa, nyLagringsProsess } = - useLagringsProsessContext(); - - const [vedleggsliste, setVedleggsListe] = useState( - soknad.vedleggsListe, - ); - - const soknadKlar = useMemo( - () => soknadErKomplett(vedleggsliste), - [vedleggsliste], - ); - const soknadDelvisKlar = useMemo( - () => soknadKanSendesInn(vedleggsliste), - [vedleggsliste], - ); - - const [visningsSteg, setVisningsSteg] = useState( - soknad.visningsSteg, - ); - - const [visKvittering, setVisKvittering] = useState(false); - const [soknadsInnsendingsRespons, setSoknadsInnsendingsRespons] = - useState(null); - - const { visningsType, kanLasteOppAnnet } = soknad; - - const vedleggsListeContainer = useRef(null); - - const erFraFyllutUtenVedlegg = - !visKvittering && - visningsType === 'fyllUt' && - vedleggsliste.every((vedlegg) => vedlegg.erHoveddokument) && - !kanLasteOppAnnet; - - const visSteg0 = - !visKvittering && - visningsType === 'dokumentinnsending' && - visningsSteg === 0 && - vedleggsliste.some((x) => x.erHoveddokument); - - const visSteg1 = - !visKvittering && - visningsType === 'dokumentinnsending' && - visningsSteg === 1 && - vedleggsliste.some((x) => x.erHoveddokument); - - const visLastOppVedlegg = - !visKvittering && - !erFraFyllutUtenVedlegg && - (visningsType !== 'dokumentinnsending' || - (visningsType === 'dokumentinnsending' && - visningsSteg === 2)); - - const onSendInn = async () => { - if (lagrerNaa()) return; - - await nyLagringsProsess( - axios.post( - `${publicRuntimeConfig.apiUrl}/frontend/v1/sendInn/${soknad?.innsendingsId}`, - ), - ) - .then((response) => { - const kv: KvitteringsDto = response.data; - setSoknadsInnsendingsRespons(kv); - setVisKvittering(true); - resettFokus(); - }) - .catch((error) => { - showError(error); - }); - }; - - const slettSoknad = () => { - if (lagrerNaa()) return; - - nyLagringsProsess( - axios.delete( - `${publicRuntimeConfig.apiUrl}/frontend/v1/soknad/${soknad?.innsendingsId}`, - ), - ) - .then(() => { - resetState(); - navigerTilMinSide(); - }) - .catch((error) => { - showError(error); - }); - }; - - const resettFokus = () => { - if (vedleggsListeContainer.current) { - vedleggsListeContainer.current.focus(); - if (window.scrollY !== 0) { - vedleggsListeContainer.current.scrollIntoView(true); - } else { - window.scrollTo(0, 0); - } - } - }; - - const oppdaterVisningsSteg = (nr: number) => { - const nyttVisningsSteg = visningsSteg + nr; - setVisningsSteg(nyttVisningsSteg); - resettFokus(); + const { showError } = useErrorMessage(); + const { lagrerNaa, nyLagringsProsess } = useLagringsProsessContext(); + + const [vedleggsliste, setVedleggsListe] = useState(soknad.vedleggsListe); + + const soknadKlar = useMemo(() => soknadErKomplett(vedleggsliste), [vedleggsliste]); + const soknadDelvisKlar = useMemo(() => soknadKanSendesInn(vedleggsliste), [vedleggsliste]); + + const [visningsSteg, setVisningsSteg] = useState(soknad.visningsSteg); + + const [visKvittering, setVisKvittering] = useState(false); + const [soknadsInnsendingsRespons, setSoknadsInnsendingsRespons] = useState(null); + + const { visningsType, kanLasteOppAnnet } = soknad; + + const vedleggsListeContainer = useRef(null); - axios - .patch( - `${publicRuntimeConfig.apiUrl}/frontend/v1/soknad/${soknad.innsendingsId}`, - { - visningsSteg: nyttVisningsSteg, - }, - ) - .catch((error) => { - showError(error); - }); - }; - - const oppdaterLokalOpplastingStatus = useCallback( - (id: number, opplastingsStatus: OpplastingsStatus) => { - setVedleggsListe((forrigeVedleggsliste) => - forrigeVedleggsliste.map((el) => - el.id === id ? { ...el, opplastingsStatus } : el, - ), - ); - }, - [setVedleggsListe], - ); - - const leggTilVedlegg = (vedlegg: ExtendedVedleggType) => { - setVedleggsListe((forrigeVedleggsliste) => [ - ...forrigeVedleggsliste, - vedlegg, - ]); - }; - const slettAnnetVedlegg = (vedleggsId: number) => { - axios - .delete( - `${publicRuntimeConfig.apiUrl}/frontend/v1/soknad/${soknad.innsendingsId}/vedlegg/${vedleggsId}`, - ) - .then(() => { - setVedleggsListe((forrigeVedleggsliste) => - forrigeVedleggsliste.filter( - (el) => el.id !== vedleggsId, - ), - ); - }) - .catch((error) => { - showError(error); - }); - }; - - const resetState = () => { - setVedleggsListe(initialVedleggsliste); - setSoknad(null); - }; - return ( - - - - - - ); + const erFraFyllutUtenVedlegg = + !visKvittering && + visningsType === 'fyllUt' && + vedleggsliste.every((vedlegg) => vedlegg.erHoveddokument) && + !kanLasteOppAnnet; + + const visSteg0 = + !visKvittering && + visningsType === 'dokumentinnsending' && + visningsSteg === 0 && + vedleggsliste.some((x) => x.erHoveddokument); + + const visSteg1 = + !visKvittering && + visningsType === 'dokumentinnsending' && + visningsSteg === 1 && + vedleggsliste.some((x) => x.erHoveddokument); + + const visLastOppVedlegg = + !visKvittering && + !erFraFyllutUtenVedlegg && + (visningsType !== 'dokumentinnsending' || (visningsType === 'dokumentinnsending' && visningsSteg === 2)); + + const onSendInn = async () => { + if (lagrerNaa()) return; + + await nyLagringsProsess(axios.post(`${publicRuntimeConfig.apiUrl}/frontend/v1/sendInn/${soknad?.innsendingsId}`)) + .then((response) => { + const kv: KvitteringsDto = response.data; + setSoknadsInnsendingsRespons(kv); + setVisKvittering(true); + resettFokus(); + }) + .catch((error) => { + showError(error); + }); + }; + + const slettSoknad = () => { + if (lagrerNaa()) return; + + nyLagringsProsess(axios.delete(`${publicRuntimeConfig.apiUrl}/frontend/v1/soknad/${soknad?.innsendingsId}`)) + .then(() => { + resetState(); + navigerTilMinSide(); + }) + .catch((error) => { + showError(error); + }); + }; + + const resettFokus = () => { + if (vedleggsListeContainer.current) { + vedleggsListeContainer.current.focus(); + if (window.scrollY !== 0) { + vedleggsListeContainer.current.scrollIntoView(true); + } else { + window.scrollTo(0, 0); + } + } + }; + + const oppdaterVisningsSteg = (nr: number) => { + const nyttVisningsSteg = visningsSteg + nr; + setVisningsSteg(nyttVisningsSteg); + resettFokus(); + + axios + .patch(`${publicRuntimeConfig.apiUrl}/frontend/v1/soknad/${soknad.innsendingsId}`, { + visningsSteg: nyttVisningsSteg, + }) + .catch((error) => { + showError(error); + }); + }; + + const oppdaterLokalOpplastingStatus = useCallback( + (id: number, opplastingsStatus: OpplastingsStatus) => { + setVedleggsListe((forrigeVedleggsliste) => + forrigeVedleggsliste.map((el) => (el.id === id ? { ...el, opplastingsStatus } : el)), + ); + }, + [setVedleggsListe], + ); + + const leggTilVedlegg = (vedlegg: ExtendedVedleggType) => { + setVedleggsListe((forrigeVedleggsliste) => [...forrigeVedleggsliste, vedlegg]); + }; + const slettAnnetVedlegg = (vedleggsId: number) => { + axios + .delete(`${publicRuntimeConfig.apiUrl}/frontend/v1/soknad/${soknad.innsendingsId}/vedlegg/${vedleggsId}`) + .then(() => { + setVedleggsListe((forrigeVedleggsliste) => forrigeVedleggsliste.filter((el) => el.id !== vedleggsId)); + }) + .catch((error) => { + showError(error); + }); + }; + + const resetState = () => { + setVedleggsListe(initialVedleggsliste); + setSoknad(null); + }; + return ( + + + + + + ); } export default VedleggsListe; diff --git a/components/common/ButtonContainer.tsx b/components/common/ButtonContainer.tsx index c8f6186f..0594d242 100644 --- a/components/common/ButtonContainer.tsx +++ b/components/common/ButtonContainer.tsx @@ -1,18 +1,18 @@ import styled from 'styled-components'; export const ButtonContainer = styled.div` - margin-right: auto; - margin-top: 60px; - width: fit-content; - min-width: 207px; - button { - margin-bottom: 24px; - } - display: flex; + margin-right: auto; + margin-top: 60px; + width: fit-content; + min-width: 207px; + button { + margin-bottom: 24px; + } + display: flex; - flex-direction: column; + flex-direction: column; - @media only screen and (max-width: 600px) { - width: 100%; - } + @media only screen and (max-width: 600px) { + width: 100%; + } `; diff --git a/components/common/LastNedKnapp.tsx b/components/common/LastNedKnapp.tsx index 59ca59ce..65c26fa8 100644 --- a/components/common/LastNedKnapp.tsx +++ b/components/common/LastNedKnapp.tsx @@ -4,31 +4,25 @@ import { useTranslation } from 'react-i18next'; import { ScreenReaderOnly } from '../textStyle'; interface LastNedKnappProps { - children: string; - url: string; - variant?: ButtonProps['variant']; + children: string; + url: string; + variant?: ButtonProps['variant']; } -export const LastNedKnapp = ({ - children, - url, - variant = 'secondary', -}: LastNedKnappProps) => { - const { t } = useTranslation(); - return ( - - ); +export const LastNedKnapp = ({ children, url, variant = 'secondary' }: LastNedKnappProps) => { + const { t } = useTranslation(); + return ( + + ); }; diff --git a/components/common/Linje.tsx b/components/common/Linje.tsx index aced744e..46e910a7 100644 --- a/components/common/Linje.tsx +++ b/components/common/Linje.tsx @@ -1,7 +1,7 @@ import styled from 'styled-components'; export const Linje = styled.div` - border-bottom: 1px solid var(--a-border-strong); - margin-top: 1.5rem; - margin-bottom: 1.5rem; + border-bottom: 1px solid var(--a-border-strong); + margin-top: 1.5rem; + margin-bottom: 1.5rem; `; diff --git a/components/skjemaSpesifikt/KvitteringsTillegg.tsx b/components/skjemaSpesifikt/KvitteringsTillegg.tsx index 36e1d123..c1f4f034 100644 --- a/components/skjemaSpesifikt/KvitteringsTillegg.tsx +++ b/components/skjemaSpesifikt/KvitteringsTillegg.tsx @@ -2,32 +2,23 @@ import Script from 'next/script'; import { ReactNode } from 'react'; const Skjemaer: Record = { - 'NAV 08-09.06': ( - <> -