diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index d9d7ad29b0f6..fab199409190 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -6,401 +6,408 @@ # Organisation name is @island-is, not @island.is # Fallback. If there is no owner, assign to core maintainers. -* @island-is/core +* @island-is/core # Top level project ownership. When a project contains, for example, templates or modules # that are developed by others teams, we first list down the team working on the core and # further below the other team working on other part of the project. -/apps/application-system/ @island-is/norda-applications -/apps/web*/ @island-is/juni @island-is/stefna -/libs/application/ @island-is/norda-applications -/libs/portals/my-pages/ @island-is/hugsmidjan -/libs/portals/admin/ @island-is/aranja -/libs/portals/core/ @island-is/aranja @island-is/hugsmidjan -/libs/shared/connected/ @island-is/stefna - -/* @island-is/core -/libs/api/domains/identity/ @island-is/core +/apps/application-system/ @island-is/norda-applications +/apps/web*/ @island-is/juni @island-is/stefna +/libs/application/ @island-is/norda-applications +/libs/portals/my-pages/ @island-is/hugsmidjan +/libs/portals/admin/ @island-is/aranja +/libs/portals/core/ @island-is/aranja @island-is/hugsmidjan +/libs/shared/connected/ @island-is/stefna + +/* @island-is/core +/libs/api/domains/identity/ @island-is/core # Edge case escaping the /infra/ and **/infra/ devops patterns below -/libs/infra-nest-server/src/lib/infra/ @island-is/core -/libs/testing/ @island-is/core -/libs/nest/swagger/ @island-is/core - -/apps/services/endorsements/ @island-is/juni -/apps/icelandic-names-registry*/ @island-is/juni -/apps/web/screens/PetitionView/ @island-is/juni -/libs/cms/ @island-is/juni @island-is/stefna -/libs/clients/cms/ @island-is/juni @island-is/aranja -/libs/residence-history @island-is/juni -/libs/api/domains/endorsement-system @island-is/juni -/libs/api/domains/icelandic-names-registry/ @island-is/juni -/libs/clients/rsk/ @island-is/juni -/libs/clients/zendesk/ @island-is/juni -/libs/icelandic-names-registry/ @island-is/juni -/libs/portals/my-pages/petitions/ @island-is/juni -/libs/portals/my-pages/signature-collection/ @island-is/juni -/libs/portals/my-pages/education/ @island-is/juni @island-is/hugsmidjan -/libs/portals/my-pages/education-career/ @island-is/juni @island-is/hugsmidjan -/libs/portals/my-pages/education-degree/ @island-is/juni @island-is/hugsmidjan -/libs/portals/my-pages/education-license/ @island-is/juni @island-is/hugsmidjan -/libs/portals/my-pages/education-student-assessment/ @island-is/juni @island-is/norda @island-is/hugsmidjan -/libs/clients/driving-license/ @island-is/juni -/libs/clients/judicial-administration/ @island-is/juni -/libs/application/templates/announcement-of-death/ @island-is/juni -/libs/application/template-api-modules/src/lib/modules/templates/announcement-of-death @island-is/juni -/libs/application/templates/driving-license/ @island-is/juni -/libs/application/templates/driving-assessment-approval/ @island-is/juni -/libs/application/templates/driving-learners-permit/ @island-is/juni -/libs/application/template-api-modules/src/lib/modules/templates/driving-learners-permit/ @island-is/juni -/libs/application/template-api-modules/src/lib/modules/templates/driving-license-submission @island-is/juni -/libs/api/domains/driving-license/ @island-is/juni -/libs/api/domains/education/ @island-is/juni @island-is/hugsmidjan @island-is/deloitte -/libs/application/templates/estate/ @island-is/juni -/libs/application/template-api-modules/src/lib/modules/templates/estate @island-is/juni -/libs/application/templates/general-petition/ @island-is/juni -/libs/shared/connected/src/lib/generalPetition/GeneralPetitionLists/ @island-is/juni -/libs/shared/connected/src/lib/SignatureLists/ @island-is/juni -/libs/api/domains/communications/ @island-is/juni @island-is/stefna -/apps/services/user-notification/ @island-is/juni @island-is/aranja -/apps/air-discount-scheme/ @island-is/hugsmidjan -/libs/air-discount-scheme/ @island-is/hugsmidjan -/libs/application/templates/p-sign/ @island-is/juni -/libs/application/template-api-modules/src/lib/modules/templates/p-sign-submission @island-is/juni -/libs/application/templates/marriage-conditions/ @island-is/juni -/libs/application/template-api-modules/src/lib/modules/templates/marriage-conditions-submission @island-is/juni -/libs/message-queue/ @island-is/juni -/libs/application/templates/example-payment/ @island-is/juni -/libs/application/template-api-modules/src/lib/modules/templates/example-payment-actions @island-is/juni -/libs/application/templates/driving-school-confirmation/ @island-is/juni -/libs/application/templates/driving-instructor-registrations/ @island-is/juni -/libs/api/domains/driving-license-book/ @island-is/juni -/libs/clients/driving-license-book/ @island-is/juni -/libs/application/template-api-modules/src/lib/modules/templates/passport @island-is/juni -/libs/application/templates/passport/ @island-is/juni -/libs/application/template-api-modules/src/lib/modules/templates/passport-annulment @island-is/juni -/libs/application/templates/passport-annulment/ @island-is/juni -/libs/application/template-api-modules/src/lib/modules/templates/driving-school-confirmation/ @island-is/juni -/libs/application/templates/operating-license/ @island-is/juni -/libs/application/template-api-modules/src/lib/modules/templates/operating-license/ @island-is/juni -/libs/application/templates/driving-license-duplicate/ @island-is/juni -/libs/application/template-api-modules/src/lib/modules/templates/driving-license-duplicate/ @island-is/juni -/libs/application/templates/inheritance-report/ @island-is/juni -/libs/application/template-api-modules/src/lib/modules/templates/inheritance-report @island-is/juni -/libs/application/templates/signature-collection @island-is/juni -/libs/api/domains/disability-license @island-is/juni -/libs/portals/admin/petition @island-is/juni -/libs/portals/admin/signature-collection @island-is/juni -/libs/portals/admin/icelandic-names-registry @island-is/juni -/libs/api/domains/signature-collection @island-is/juni -/libs/clients/signature-collection @island-is/juni -/libs/application/template-api-modules/src/lib/modules/templates/signature-collection @island-is/juni -/libs/application/template-api-modules/src/lib/modules/templates/general-petition @island-is/juni - -/apps/portals/admin/ @island-is/aranja -/libs/api/domains/auth-admin/ @island-is/aranja -/libs/api/domains/sessions/ @island-is/aranja -/libs/clients/auth/ @island-is/aranja -/libs/clients/middlewares/ @island-is/aranja -libs/clients/rsk/relationships/ @island-is/aranja -/libs/clients/sessions @island-is/aranja -/libs/portals/shared-modules/delegations @island-is/aranja -/libs/portals/admin/ids-admin @island-is/aranja -/libs/portals/my-pages/consent @island-is/aranja -/libs/portals/my-pages/restrictions @island-is/aranja -/libs/portals/my-pages/sessions @island-is/aranja -/apps/native/app/ @island-is/aranja-app -codemagic.yaml @island-is/aranja-app -/apps/web/public/.well-known/ @island-is/aranja-app - -/apps/judicial-system/ @island-is/kolibri-justice-league -/libs/judicial-system/ @island-is/kolibri-justice-league -/libs/nova-sms/ @island-is/kolibri-justice-league -/libs/dokobit-signing/ @island-is/kolibri-justice-league -/libs/email-service/ @island-is/kolibri-justice-league - -/apps/financial-aid/ @island-is/kolibri-robin-hood -/libs/financial-aid/ @island-is/kolibri-robin-hood -/libs/next-ids-auth/ @island-is/kolibri-robin-hood -/libs/clients/rsk/personal-tax-return @island-is/kolibri-robin-hood -/libs/application/templates/financial-aid/ @island-is/kolibri-robin-hood -/libs/api/domains/municipalities-financial-aid @island-is/kolibri-robin-hood -/libs/clients/municipalities-financial-aid @island-is/kolibri-robin-hood -/libs/application/template-api-modules/src/lib/modules/templates/financial-aid @island-is/kolibri-robin-hood - -/apps/download-service/ @island-is/hugsmidjan -/apps/portals/my-pages*/ @island-is/hugsmidjan -/apps/services/regulations-admin-backend/ @island-is/hugsmidjan -/apps/services/user-profile/ @island-is/hugsmidjan @island-is/juni @island-is/aranja -/apps/web/components/Grant/ @island-is/hugsmidjan -/apps/web/components/PlazaCard/ @island-is/hugsmidjan -/apps/web/screens/Grants/ @island-is/hugsmidjan -/apps/web/screens/Regulations/ @island-is/hugsmidjan -/apps/web/components/Regulations/ @island-is/hugsmidjan -/apps/web/screens/OfficialJournalOfIceland/ @island-is/hugsmidjan -/apps/web/components/OfficialJournalOfIceland/ @island-is/hugsmidjan -/libs/api/domains/air-discount-scheme @island-is/hugsmidjan -/libs/api/domains/documents/ @island-is/hugsmidjan -/libs/api/domains/finance/ @island-is/hugsmidjan -/libs/api/domains/assets/ @island-is/hugsmidjan -/libs/api/domains/health-directorate/ @island-is/hugsmidjan -/libs/api/domains/hms-loans/ @island-is/hugsmidjan -/libs/api/domains/license-service/ @island-is/hugsmidjan @island-is/aranja -/libs/api/domains/work-machines/ @island-is/hugsmidjan @island-is/origo -/libs/api/domains/national-registry/ @island-is/hugsmidjan -/libs/api/domains/notifications/ @island-is/hugsmidjan -/libs/api/domains/user-profile/ @island-is/hugsmidjan @island-is/juni @island-is/aranja -/libs/api/domains/passport/ @island-is/hugsmidjan -/libs/api/domains/vehicles/ @island-is/hugsmidjan -/libs/api/domains/university-careers/ @island-is/hugsmidjan -/libs/api/domains/regulations/ @island-is/hugsmidjan -/libs/api/domains/regulations-admin/ @island-is/hugsmidjan -/libs/api/domains/rights-portal @island-is/hugsmidjan -/libs/api/domains/social-insurance @island-is/hugsmidjan @island-is/stefna -/libs/api/domains/occupational-licenses/ @island-is/hugsmidjan -/libs/api/domains/occupational-licenses-v2/ @island-is/hugsmidjan -/libs/api/domains/intellectual-properties/ @island-is/hugsmidjan -/libs/api/domains/official-journal-of-iceland/ @island-is/hugsmidjan -/libs/api/domains/official-journal-of-iceland-application/ @island-is/hugsmidjan -/libs/api/domains/document-provider/ @island-is/hugsmidjan @island-is/core -/libs/api/domains/housing-benefits/ @island-is/hugsmidjan -/libs/api/domains/law-and-order/ @island-is/hugsmidjan -/libs/clients/documents/ @island-is/hugsmidjan -/libs/clients/documents-v2/ @island-is/hugsmidjan -/libs/clients/finance/ @island-is/hugsmidjan -/libs/clients/finance-v2/ @island-is/hugsmidjan -/libs/clients/adr-and-machine-license/ @island-is/hugsmidjan -/libs/clients/work-machines/ @island-is/hugsmidjan @island-is/origo -/libs/clients/disability-license/ @island-is/hugsmidjan -/libs/clients/firearm-license/ @island-is/hugsmidjan -/libs/clients/hunting-license/ @island-is/hugsmidjan -/libs/clients/smartsolutions/ @island-is/hugsmidjan -/libs/clients/smart-solutions-v2/ @island-is/hugsmidjan -/libs/clients/license-client/ @island-is/hugsmidjan @island-is/aranja -/libs/clients/intellectual-properties/ @island-is/hugsmidjan -/libs/clients/islykill/ @island-is/hugsmidjan -/libs/clients/national-registry/v3/ @island-is/hugsmidjan -/libs/clients/district-commissioners-licenses/ @island-is/hugsmidjan -/libs/clients/regulations/ @island-is/hugsmidjan -/libs/clients/vehicles/ @island-is/hugsmidjan @island-is/stefna -/libs/clients/vehicles-mileage/ @island-is/hugsmidjan -/libs/clients/user-notification/ @island-is/hugsmidjan -/libs/clients/passports/ @island-is/hugsmidjan -/libs/clients/p-card/ @island-is/hugsmidjan -/libs/clients/assets/ @island-is/hugsmidjan -/libs/clients/university-careers/ @island-is/hugsmidjan -/libs/clients/regulations-admin/ @island-is/hugsmidjan -/libs/clients/inna/ @island-is/hugsmidjan -/libs/clients/hms-loans/ @island-is/hugsmidjan -/libs/clients/official-journal-of-iceland/ @island-is/hugsmidjan -/libs/clients/hms-housing-benefits/ @island-is/hugsmidjan -/apps/services/license-api/ @island-is/hugsmidjan -/libs/regulations/ @island-is/hugsmidjan -/libs/portals/admin/regulations-admin/ @island-is/hugsmidjan -/libs/portals/admin/document-provider/ @island-is/hugsmidjan @island-is/core -/libs/clients/icelandic-health-insurance/rights-portal/ @island-is/hugsmidjan -/libs/clients/health-directorate @island-is/hugsmidjan -/libs/clients/health-directorate/src/lib/clients/occupational-license @island-is/hugsmidjan @island-is/origo -/libs/clients/mms/grade @island-is/hugsmidjan -/libs/portals/admin/air-discount-scheme @island-is/hugsmidjan -/libs/application/templates/official-journal-of-iceland/ @island-is/hugsmidjan -/libs/application/template-api-modules/src/lib/modules/templates/official-journal-of-iceland/ @island-is/hugsmidjan -/libs/clients/judicial-system-sp/ @island-is/hugsmidjan -/libs/application/templates/data-protection-complaint/ @island-is/norda -/libs/application/templates/institution-collaboration/ @island-is/norda @island-is/fuglar -/libs/application/templates/login-service/ @island-is/norda -/libs/application/template-api-modules/src/lib/modules/templates/login-service/ @island-is/norda -/libs/clients/payment-schedule/ @island-is/norda -/libs/api/domains/payment-schedule/ @island-is/norda -/libs/application/templates/funding-government-projects/ @island-is/norda -/libs/application/template-api-modules/src/lib/modules/templates/funding-government-projects/ @island-is/norda -/libs/application/template-api-modules/src/lib/modules/templates/institution-collaboration/ @island-is/norda -/libs/application/templates/public-debt-payment-plan/ @island-is/norda -/libs/application/templates/complaints-to-althingi-ombudsman/ @island-is/norda -/libs/application/template-api-modules/src/lib/modules/templates/complaints-to-althingi-ombudsman/ @island-is/norda -/libs/application/templates/accident-notification/ @island-is/norda -/libs/application/template-api-modules/src/lib/modules/templates/accident-notification/ @island-is/norda -/libs/application/template-api-modules/src/lib/modules/templates/health-insurance/ @island-is/norda -/libs/application/template-api-modules/src/lib/modules/templates/public-debt-payment-plan @island-is/norda -/libs/api/domains/health-insurance/ @island-is/norda -/libs/application/templates/health-insurance/ @island-is/norda -/libs/clients/rsk/company-registry @island-is/norda -/libs/clients/althingi-ombudsman/ @island-is/norda -/libs/api/domains/company-registry @island-is/norda -/libs/clients/icelandic-health-insurance/health-insurance/ @island-is/norda -/libs/clients/data-protection-complaint/ @island-is/norda -/libs/clients/fishing-license/ @island-is/norda -/libs/api/domains/fishing-license/ @island-is/norda -/libs/application/templates/general-fishing-license/ @island-is/norda -/libs/application/template-api-modules/src/lib/modules/templates/general-fishing-license/ @island-is/norda -/libs/application/template-api-modules/src/lib/modules/templates/data-protection-complaint/ @island-is/norda -/libs/shared/form-fields/ @island-is/norda @island-is/island-ui -/libs/clients/financial-statements-inao @island-is/norda -/libs/api/domains/financial-statements-inao/ @island-is/norda -/libs/application/templates/financial-statements-inao/ @island-is/norda -/libs/application/template-api-modules/src/lib/modules/templates/financial-statements-inao @island-is/norda - -/libs/portals/my-pages/applications/ @island-is/norda-applications -/libs/portals/admin/application-system/ @island-is/norda-applications -/libs/api/domains/application/ @island-is/norda-applications -/libs/api/domains/payment/ @island-is/norda-applications - -/apps/contentful-apps/ @island-is/stefna -/apps/services/search-indexer/ @island-is/stefna @island-is/juni -/apps/services/contentful-entry-tagger/ @island-is/stefna -/apps/tools/contentful-role-permissions/ @island-is/stefna -/apps/web/screens/Organization/ @island-is/stefna -/apps/web/screens/Project/ @island-is/stefna -/apps/web/components/Organization/ @island-is/stefna -/apps/web/components/ChatPanel/ @island-is/stefna -/apps/web/components/Form/ @island-is/stefna -/apps/web/components/Stepper/ @island-is/stefna -/libs/content-search-toolkit/ @island-is/stefna @island-is/juni -/libs/content-search-index-manager/ @island-is/stefna @island-is/juni -/libs/content-search-metrics/ @island-is/stefna @island-is/juni -/libs/content-search-indexer/ @island-is/stefna @island-is/juni -/libs/api/domains/content-search/ @island-is/stefna @island-is/juni -/libs/api/domains/syslumenn/ @island-is/stefna -/libs/api/domains/email-signup/ @island-is/stefna -/libs/api/domains/electronic-registration-statistics/ @island-is/stefna -/libs/clients/electronic-registration-statistics/ @island-is/stefna -/libs/api/domains/fiskistofa/ @island-is/stefna -/libs/clients/fiskistofa/ @island-is/stefna -/libs/clients/syslumenn/ @island-is/stefna @island-is/juni -/libs/api/domains/watson-assistant-chat/ @island-is/stefna -/libs/clients/icelandic-government-institution-vacancies/ @island-is/stefna -/libs/api/domains/icelandic-government-institution-vacancies/ @island-is/stefna -/libs/clients/aircraft-registry/ @island-is/stefna -/libs/api/domains/aircraft-registry/ @island-is/stefna -/libs/api/domains/housing-benefit-calculator/ @island-is/stefna -/libs/clients/housing-benefit-calculator/ @island-is/stefna -/libs/clients/ship-registry/ @island-is/stefna -/libs/api/domains/ship-registry/ @island-is/stefna -/libs/clients/administration-of-occupational-safety-and-health/ @island-is/stefna -/libs/api/domains/administration-of-occupational-safety-and-health/ @island-is/stefna -/libs/clients/ultraviolet-radiation/ @island-is/stefna -/libs/clients/ums-cost-of-living-calculator/ @island-is/stefna -/libs/api/domains/umbodsmadur-skuldara/ @island-is/stefna - -/libs/island-ui/ @island-is/island-ui - -/apps/consultation-portal/ @island-is/advania -/apps/services/form-system/ @island-is/advania -/libs/clients/consultation-portal/ @island-is/advania -/libs/api/domains/consultation-portal/ @island-is/advania - -/apps/skilavottord/ @island-is/deloitte -/libs/skilavottord/ @island-is/deloitte -/libs/application/templates/parental-leave/ @island-is/deloitte -/libs/application/template-api-modules/src/lib/modules/templates/parental-leave/ @island-is/deloitte -/libs/clients/vmst/ @island-is/deloitte -/libs/api/domains/directorate-of-labour/ @island-is/deloitte -/libs/application/template-api-modules/src/lib/modules/templates/social-insurance-administration @island-is/deloitte -/libs/application/templates/social-insurance-administration/ @island-is/deloitte -/libs/clients/social-insurance-administration/ @island-is/deloitte @island-is/stefna @island-is/hugsmidjan -/libs/application/templates/car-recycling/ @island-is/deloitte -/libs/application/template-api-modules/src/lib/modules/templates/car-recycling/ @island-is/deloitte -/libs/clients/car-recycling/ @island-is/deloitte -/libs/application/templates/new-primary-school/ @island-is/deloitte -/libs/application/template-api-modules/src/lib/modules/templates/new-primary-school/ @island-is/deloitte -/libs/clients/mms/frigg @island-is/deloitte - -/apps/services/auth/ids-api/ @island-is/fuglar @island-is/aranja -/apps/services/auth/admin-api/ @island-is/fuglar @island-is/aranja -/apps/services/auth/public-api/ @island-is/fuglar @island-is/aranja -/apps/services/auth/delegation-api/ @island-is/fuglar @island-is/aranja -/apps/services/sessions/ @island-is/fuglar @island-is/aranja -/apps/auth-admin-web/ @island-is/fuglar @island-is/aranja -/libs/auth-api-lib/ @island-is/fuglar @island-is/aranja -/libs/auth-api-lib/seeders/ @island-is/fuglar @island-is/aranja @island-is/origo-auth -/libs/auth-nest-tools/ @island-is/fuglar @island-is/aranja -/libs/application/templates/european-health-insurance-card/ @island-is/fuglar -/libs/application/template-api-modules/src/lib/modules/templates/european-health-insurance-card/ @island-is/fuglar -/libs/clients/ehic-client-v1 @island-is/fuglar - -/apps/services/auth/personal-representative/ @island-is/programm @island-is/aranja -/apps/services/auth/personal-representative-public/ @island-is/programm @island-is/aranja - -/libs/application/templates/criminal-record/ @island-is/origo -/libs/application/template-api-modules/src/lib/modules/templates/criminal-record-submission/ @island-is/origo -/libs/api/domains/criminal-record/ @island-is/origo -/libs/clients/criminal-record/ @island-is/origo - -/libs/application/templates/mortgage-certificate/ @island-is/origo -/libs/application/template-api-modules/src/lib/modules/templates/mortgage-certificate-submission/ @island-is/origo -/libs/api/domains/mortgage-certificate/ @island-is/origo - -/libs/application/templates/no-debt-certificate/ @island-is/origo -/libs/application/template-api-modules/src/lib/modules/templates/no-debt-certificate/ @island-is/origo - -/libs/application/templates/id-card/ @island-is/origo -/libs/application/template-api-modules/src/lib/modules/templates/id-card/ @island-is/origo - -/libs/clients/charge-fjs-v2/ @island-is/origo -/libs/clients/vehicle-service-fjs-v1/ @island-is/origo - -/libs/application/templates/transport-authority/ @island-is/origo -/libs/application/template-api-modules/src/lib/modules/templates/transport-authority/ @island-is/origo -/libs/api/domains/transport-authority/ @island-is/origo -/libs/clients/transport-authority/ @island-is/origo - -/libs/application/templates/driving-license-book-update-instructor/ @island-is/origo -/libs/application/template-api-modules/src/lib/modules/templates/driving-license-book-update-instructor/ @island-is/origo - -/apps/services/university-gateway/ @island-is/origo -/libs/clients/university-application/ @island-is/origo -/libs/clients/university-gateway-api/ @island-is/origo -/libs/api/domains/university-gateway/ @island-is/origo -/libs/university-gateway/ @island-is/origo -/apps/web/screens/UniversitySearch/ @island-is/origo -/apps/web/screens/queries/UniversityGateway.ts @island-is/origo -/apps/web/components/ListViewCard/ @island-is/origo - -/libs/application/templates/directorate-of-immigration/ @island-is/origo -/libs/application/template-api-modules/src/lib/modules/templates/directorate-of-immigration/ @island-is/origo -/libs/clients/directorate-of-immigration/ @island-is/origo - -/libs/application/templates/aosh/ @island-is/origo -/libs/application/template-api-modules/src/lib/modules/templates/aosh @island-is/origo - -/libs/application/templates/healthcare-license-certificate/ @island-is/origo -/libs/application/template-api-modules/src/lib/modules/templates/healthcare-license-certificate/ @island-is/origo - - -/libs/application/templates/healthcare-work-permit/ @island-is/origo -/libs/application/template-api-modules/src/lib/modules/templates/healthcare-work-permit/ @island-is/origo - -/libs/application/templates/energy-funds/ @island-is/origo -/libs/application/template-api-modules/src/lib/modules/templates/energy-funds/ @island-is/origo -/libs/api/domains/energy-funds/ @island-is/origo -/libs/clients/energy-funds/ @island-is/origo - -/libs/application/templates/university/ @island-is/origo -/libs/application/template-api-modules/src/lib/modules/templates/university/ @island-is/origo +/libs/infra-nest-server/src/lib/infra/ @island-is/core +/libs/testing/ @island-is/core +/libs/nest/swagger/ @island-is/core + +/apps/services/endorsements/ @island-is/juni +/apps/icelandic-names-registry*/ @island-is/juni +/apps/web/screens/PetitionView/ @island-is/juni +/libs/cms/ @island-is/juni @island-is/stefna +/libs/clients/cms/ @island-is/juni @island-is/aranja +/libs/residence-history @island-is/juni +/libs/api/domains/endorsement-system @island-is/juni +/libs/api/domains/icelandic-names-registry/ @island-is/juni +/libs/clients/rsk/ @island-is/juni +/libs/clients/zendesk/ @island-is/juni +/libs/icelandic-names-registry/ @island-is/juni +/libs/portals/my-pages/petitions/ @island-is/juni +/libs/portals/my-pages/signature-collection/ @island-is/juni +/libs/portals/my-pages/education/ @island-is/juni @island-is/hugsmidjan +/libs/portals/my-pages/education-career/ @island-is/juni @island-is/hugsmidjan +/libs/portals/my-pages/education-degree/ @island-is/juni @island-is/hugsmidjan +/libs/portals/my-pages/education-license/ @island-is/juni @island-is/hugsmidjan +/libs/portals/my-pages/education-student-assessment/ @island-is/juni @island-is/norda @island-is/hugsmidjan +/libs/clients/driving-license/ @island-is/juni +/libs/clients/judicial-administration/ @island-is/juni +/libs/application/templates/announcement-of-death/ @island-is/juni +/libs/application/template-api-modules/src/lib/modules/templates/announcement-of-death @island-is/juni +/libs/application/templates/driving-license/ @island-is/juni +/libs/application/templates/driving-assessment-approval/ @island-is/juni +/libs/application/templates/driving-learners-permit/ @island-is/juni +/libs/application/template-api-modules/src/lib/modules/templates/driving-learners-permit/ @island-is/juni +/libs/application/template-api-modules/src/lib/modules/templates/driving-license-submission @island-is/juni +/libs/api/domains/driving-license/ @island-is/juni +/libs/api/domains/education/ @island-is/juni @island-is/hugsmidjan @island-is/deloitte +/libs/application/templates/estate/ @island-is/juni +/libs/application/template-api-modules/src/lib/modules/templates/estate @island-is/juni +/libs/application/templates/general-petition/ @island-is/juni +/libs/shared/connected/src/lib/generalPetition/GeneralPetitionLists/ @island-is/juni +/libs/shared/connected/src/lib/SignatureLists/ @island-is/juni +/libs/api/domains/communications/ @island-is/juni @island-is/stefna +/apps/services/user-notification/ @island-is/juni @island-is/aranja +/apps/air-discount-scheme/ @island-is/hugsmidjan +/libs/air-discount-scheme/ @island-is/hugsmidjan +/libs/application/templates/p-sign/ @island-is/juni +/libs/application/template-api-modules/src/lib/modules/templates/p-sign-submission @island-is/juni +/libs/application/templates/marriage-conditions/ @island-is/juni +/libs/application/template-api-modules/src/lib/modules/templates/marriage-conditions-submission @island-is/juni +/libs/message-queue/ @island-is/juni +/libs/application/templates/example-payment/ @island-is/juni +/libs/application/template-api-modules/src/lib/modules/templates/example-payment-actions @island-is/juni +/libs/application/templates/driving-school-confirmation/ @island-is/juni +/libs/application/templates/driving-instructor-registrations/ @island-is/juni +/libs/api/domains/driving-license-book/ @island-is/juni +/libs/clients/driving-license-book/ @island-is/juni +/libs/application/template-api-modules/src/lib/modules/templates/passport @island-is/juni +/libs/application/templates/passport/ @island-is/juni +/libs/application/template-api-modules/src/lib/modules/templates/passport-annulment @island-is/juni +/libs/application/templates/passport-annulment/ @island-is/juni +/libs/application/template-api-modules/src/lib/modules/templates/driving-school-confirmation/ @island-is/juni +/libs/application/templates/operating-license/ @island-is/juni +/libs/application/template-api-modules/src/lib/modules/templates/operating-license/ @island-is/juni +/libs/application/templates/driving-license-duplicate/ @island-is/juni +/libs/application/template-api-modules/src/lib/modules/templates/driving-license-duplicate/ @island-is/juni +/libs/application/templates/inheritance-report/ @island-is/juni +/libs/application/template-api-modules/src/lib/modules/templates/inheritance-report @island-is/juni +/libs/application/templates/signature-collection @island-is/juni +/libs/api/domains/disability-license @island-is/juni +/libs/portals/admin/petition @island-is/juni +/libs/portals/admin/signature-collection @island-is/juni +/libs/portals/admin/icelandic-names-registry @island-is/juni +/libs/api/domains/signature-collection @island-is/juni +/libs/clients/signature-collection @island-is/juni +/libs/application/template-api-modules/src/lib/modules/templates/signature-collection @island-is/juni +/libs/application/template-api-modules/src/lib/modules/templates/general-petition @island-is/juni + +/apps/portals/admin/ @island-is/aranja +/libs/api/domains/auth-admin/ @island-is/aranja +/libs/api/domains/sessions/ @island-is/aranja +/libs/clients/auth/ @island-is/aranja +/libs/clients/middlewares/ @island-is/aranja +libs/clients/rsk/relationships/ @island-is/aranja +/libs/clients/sessions @island-is/aranja +/libs/portals/shared-modules/delegations @island-is/aranja +/libs/portals/admin/ids-admin @island-is/aranja +/libs/portals/my-pages/consent @island-is/aranja +/libs/portals/my-pages/restrictions @island-is/aranja +/libs/portals/my-pages/sessions @island-is/aranja +/apps/native/app/ @island-is/aranja-app +codemagic.yaml @island-is/aranja-app +/apps/web/public/.well-known/ @island-is/aranja-app + +/apps/judicial-system/ @island-is/kolibri-justice-league +/libs/judicial-system/ @island-is/kolibri-justice-league +/libs/nova-sms/ @island-is/kolibri-justice-league +/libs/dokobit-signing/ @island-is/kolibri-justice-league +/libs/email-service/ @island-is/kolibri-justice-league + +/apps/financial-aid/ @island-is/kolibri-robin-hood +/libs/financial-aid/ @island-is/kolibri-robin-hood +/libs/next-ids-auth/ @island-is/kolibri-robin-hood +/libs/clients/rsk/personal-tax-return @island-is/kolibri-robin-hood +/libs/application/templates/financial-aid/ @island-is/kolibri-robin-hood +/libs/api/domains/municipalities-financial-aid @island-is/kolibri-robin-hood +/libs/clients/municipalities-financial-aid @island-is/kolibri-robin-hood +/libs/application/template-api-modules/src/lib/modules/templates/financial-aid @island-is/kolibri-robin-hood + +/apps/download-service/ @island-is/hugsmidjan +/apps/portals/my-pages*/ @island-is/hugsmidjan +/apps/services/regulations-admin-backend/ @island-is/hugsmidjan +/apps/services/user-profile/ @island-is/hugsmidjan @island-is/juni @island-is/aranja +/apps/web/components/Grant/ @island-is/hugsmidjan +/apps/web/screens/Grants/ @island-is/hugsmidjan +/apps/web/screens/Regulations/ @island-is/hugsmidjan +/apps/web/components/Regulations/ @island-is/hugsmidjan +/apps/web/screens/OfficialJournalOfIceland/ @island-is/hugsmidjan +/apps/web/components/OfficialJournalOfIceland/ @island-is/hugsmidjan +/libs/api/domains/air-discount-scheme @island-is/hugsmidjan +/libs/api/domains/documents/ @island-is/hugsmidjan +/libs/api/domains/finance/ @island-is/hugsmidjan +/libs/api/domains/assets/ @island-is/hugsmidjan +/libs/api/domains/health-directorate/ @island-is/hugsmidjan +/libs/api/domains/hms-loans/ @island-is/hugsmidjan +/libs/api/domains/license-service/ @island-is/hugsmidjan @island-is/aranja +/libs/api/domains/work-machines/ @island-is/hugsmidjan @island-is/origo +/libs/api/domains/national-registry/ @island-is/hugsmidjan +/libs/api/domains/notifications/ @island-is/hugsmidjan +/libs/api/domains/user-profile/ @island-is/hugsmidjan @island-is/juni @island-is/aranja +/libs/api/domains/passport/ @island-is/hugsmidjan +/libs/api/domains/vehicles/ @island-is/hugsmidjan +/libs/api/domains/university-careers/ @island-is/hugsmidjan +/libs/api/domains/regulations/ @island-is/hugsmidjan +/libs/api/domains/regulations-admin/ @island-is/hugsmidjan +/libs/api/domains/rights-portal @island-is/hugsmidjan +/libs/api/domains/social-insurance @island-is/hugsmidjan @island-is/stefna +/libs/api/domains/occupational-licenses/ @island-is/hugsmidjan +/libs/api/domains/occupational-licenses-v2/ @island-is/hugsmidjan +/libs/api/domains/intellectual-properties/ @island-is/hugsmidjan +/libs/api/domains/official-journal-of-iceland/ @island-is/hugsmidjan +/libs/api/domains/official-journal-of-iceland-application/ @island-is/hugsmidjan +/libs/api/domains/document-provider/ @island-is/hugsmidjan @island-is/core +/libs/api/domains/housing-benefits/ @island-is/hugsmidjan +/libs/api/domains/law-and-order/ @island-is/hugsmidjan +/libs/clients/documents/ @island-is/hugsmidjan +/libs/clients/documents-v2/ @island-is/hugsmidjan +/libs/clients/finance/ @island-is/hugsmidjan +/libs/clients/finance-v2/ @island-is/hugsmidjan +/libs/clients/adr-and-machine-license/ @island-is/hugsmidjan +/libs/clients/work-machines/ @island-is/hugsmidjan @island-is/origo +/libs/clients/disability-license/ @island-is/hugsmidjan +/libs/clients/firearm-license/ @island-is/hugsmidjan +/libs/clients/hunting-license/ @island-is/hugsmidjan +/libs/clients/smartsolutions/ @island-is/hugsmidjan +/libs/clients/smart-solutions-v2/ @island-is/hugsmidjan +/libs/clients/license-client/ @island-is/hugsmidjan @island-is/aranja +/libs/clients/intellectual-properties/ @island-is/hugsmidjan +/libs/clients/islykill/ @island-is/hugsmidjan +/libs/clients/national-registry/v3/ @island-is/hugsmidjan +/libs/clients/district-commissioners-licenses/ @island-is/hugsmidjan +/libs/clients/regulations/ @island-is/hugsmidjan +/libs/clients/vehicles/ @island-is/hugsmidjan @island-is/stefna +/libs/clients/vehicles-mileage/ @island-is/hugsmidjan +/libs/clients/user-notification/ @island-is/hugsmidjan +/libs/clients/passports/ @island-is/hugsmidjan +/libs/clients/p-card/ @island-is/hugsmidjan +/libs/clients/assets/ @island-is/hugsmidjan +/libs/clients/university-careers/ @island-is/hugsmidjan +/libs/clients/regulations-admin/ @island-is/hugsmidjan +/libs/clients/inna/ @island-is/hugsmidjan +/libs/clients/hms-loans/ @island-is/hugsmidjan +/libs/clients/official-journal-of-iceland/ @island-is/hugsmidjan +/libs/clients/hms-housing-benefits/ @island-is/hugsmidjan +/apps/services/license-api/ @island-is/hugsmidjan +/libs/regulations/ @island-is/hugsmidjan +/libs/portals/admin/regulations-admin/ @island-is/hugsmidjan +/libs/portals/admin/document-provider/ @island-is/hugsmidjan @island-is/core +/libs/clients/icelandic-health-insurance/rights-portal/ @island-is/hugsmidjan +/libs/clients/health-directorate @island-is/hugsmidjan +/libs/clients/health-directorate/src/lib/clients/occupational-license @island-is/hugsmidjan @island-is/origo +/libs/clients/mms/grade @island-is/hugsmidjan +/libs/portals/admin/air-discount-scheme @island-is/hugsmidjan +/libs/application/templates/official-journal-of-iceland/ @island-is/hugsmidjan +/libs/application/template-api-modules/src/lib/modules/templates/official-journal-of-iceland/ @island-is/hugsmidjan +/libs/clients/judicial-system-sp/ @island-is/hugsmidjan +/libs/application/templates/data-protection-complaint/ @island-is/norda +/libs/application/templates/institution-collaboration/ @island-is/norda @island-is/fuglar +/libs/application/templates/login-service/ @island-is/norda +/libs/application/template-api-modules/src/lib/modules/templates/login-service/ @island-is/norda +/libs/clients/payment-schedule/ @island-is/norda +/libs/api/domains/payment-schedule/ @island-is/norda +/libs/application/templates/funding-government-projects/ @island-is/norda +/libs/application/template-api-modules/src/lib/modules/templates/funding-government-projects/ @island-is/norda +/libs/application/template-api-modules/src/lib/modules/templates/institution-collaboration/ @island-is/norda +/libs/application/templates/public-debt-payment-plan/ @island-is/norda +/libs/application/templates/complaints-to-althingi-ombudsman/ @island-is/norda +/libs/application/template-api-modules/src/lib/modules/templates/complaints-to-althingi-ombudsman/ @island-is/norda +/libs/application/templates/accident-notification/ @island-is/norda +/libs/application/template-api-modules/src/lib/modules/templates/accident-notification/ @island-is/norda +/libs/application/template-api-modules/src/lib/modules/templates/health-insurance/ @island-is/norda +/libs/application/template-api-modules/src/lib/modules/templates/public-debt-payment-plan @island-is/norda +/libs/api/domains/health-insurance/ @island-is/norda +/libs/application/templates/health-insurance/ @island-is/norda +/libs/clients/rsk/company-registry @island-is/norda +/libs/clients/althingi-ombudsman/ @island-is/norda +/libs/api/domains/company-registry @island-is/norda +/libs/clients/icelandic-health-insurance/health-insurance/ @island-is/norda +/libs/clients/data-protection-complaint/ @island-is/norda +/libs/clients/fishing-license/ @island-is/norda +/libs/api/domains/fishing-license/ @island-is/norda +/libs/application/templates/general-fishing-license/ @island-is/norda +/libs/application/template-api-modules/src/lib/modules/templates/general-fishing-license/ @island-is/norda +/libs/application/template-api-modules/src/lib/modules/templates/data-protection-complaint/ @island-is/norda +/libs/shared/form-fields/ @island-is/norda @island-is/island-ui +/libs/clients/financial-statements-inao @island-is/norda +/libs/api/domains/financial-statements-inao/ @island-is/norda +/libs/application/templates/financial-statements-inao/ @island-is/norda +/libs/application/template-api-modules/src/lib/modules/templates/financial-statements-inao @island-is/norda +/libs/application/templates/inao/ @island-is/norda +/libs/application/templates/inao/financial-statement-cemetery/ @island-is/norda +/libs/application/templates/inao/financial-statement-individual-election/ @island-is/norda +/libs/application/templates/inao/financial-statement-political-party/ @island-is/norda +/libs/application/template-api-modules/src/lib/modules/templates/financial-statement-cemetery/ @island-is/norda +/libs/application/template-api-modules/src/lib/modules/templates/financial-statement-individual-election/ @island-is/norda +/libs/application/template-api-modules/src/lib/modules/templates/financial-statement-political-party/ @island-is/norda + + +/libs/portals/my-pages/applications/ @island-is/norda-applications +/libs/portals/admin/application-system/ @island-is/norda-applications +/libs/api/domains/application/ @island-is/norda-applications +/libs/api/domains/payment/ @island-is/norda-applications + +/apps/contentful-apps/ @island-is/stefna +/apps/services/search-indexer/ @island-is/stefna @island-is/juni +/apps/services/contentful-entry-tagger/ @island-is/stefna +/apps/tools/contentful-role-permissions/ @island-is/stefna +/apps/web/screens/Organization/ @island-is/stefna +/apps/web/screens/Project/ @island-is/stefna +/apps/web/components/Organization/ @island-is/stefna +/apps/web/components/ChatPanel/ @island-is/stefna +/apps/web/components/Form/ @island-is/stefna +/apps/web/components/Stepper/ @island-is/stefna +/libs/content-search-toolkit/ @island-is/stefna @island-is/juni +/libs/content-search-index-manager/ @island-is/stefna @island-is/juni +/libs/content-search-metrics/ @island-is/stefna @island-is/juni +/libs/content-search-indexer/ @island-is/stefna @island-is/juni +/libs/api/domains/content-search/ @island-is/stefna @island-is/juni +/libs/api/domains/syslumenn/ @island-is/stefna +/libs/api/domains/email-signup/ @island-is/stefna +/libs/api/domains/electronic-registration-statistics/ @island-is/stefna +/libs/clients/electronic-registration-statistics/ @island-is/stefna +/libs/api/domains/fiskistofa/ @island-is/stefna +/libs/clients/fiskistofa/ @island-is/stefna +/libs/clients/syslumenn/ @island-is/stefna @island-is/juni +/libs/api/domains/watson-assistant-chat/ @island-is/stefna +/libs/clients/icelandic-government-institution-vacancies/ @island-is/stefna +/libs/api/domains/icelandic-government-institution-vacancies/ @island-is/stefna +/libs/clients/aircraft-registry/ @island-is/stefna +/libs/api/domains/aircraft-registry/ @island-is/stefna +/libs/api/domains/housing-benefit-calculator/ @island-is/stefna +/libs/clients/housing-benefit-calculator/ @island-is/stefna +/libs/clients/ship-registry/ @island-is/stefna +/libs/api/domains/ship-registry/ @island-is/stefna +/libs/clients/administration-of-occupational-safety-and-health/ @island-is/stefna +/libs/api/domains/administration-of-occupational-safety-and-health/ @island-is/stefna +/libs/clients/ultraviolet-radiation/ @island-is/stefna +/libs/clients/ums-cost-of-living-calculator/ @island-is/stefna +/libs/api/domains/umbodsmadur-skuldara/ @island-is/stefna + +/libs/island-ui/ @island-is/island-ui + +/apps/consultation-portal/ @island-is/advania +/apps/services/form-system/ @island-is/advania +/libs/clients/consultation-portal/ @island-is/advania +/libs/api/domains/consultation-portal/ @island-is/advania + +/apps/skilavottord/ @island-is/deloitte +/libs/skilavottord/ @island-is/deloitte +/libs/application/templates/parental-leave/ @island-is/deloitte +/libs/application/template-api-modules/src/lib/modules/templates/parental-leave/ @island-is/deloitte +/libs/clients/vmst/ @island-is/deloitte +/libs/api/domains/directorate-of-labour/ @island-is/deloitte +/libs/application/template-api-modules/src/lib/modules/templates/social-insurance-administration @island-is/deloitte +/libs/application/templates/social-insurance-administration/ @island-is/deloitte +/libs/clients/social-insurance-administration/ @island-is/deloitte @island-is/stefna @island-is/hugsmidjan +/libs/application/templates/car-recycling/ @island-is/deloitte +/libs/application/template-api-modules/src/lib/modules/templates/car-recycling/ @island-is/deloitte +/libs/clients/car-recycling/ @island-is/deloitte +/libs/application/templates/new-primary-school/ @island-is/deloitte +/libs/application/template-api-modules/src/lib/modules/templates/new-primary-school/ @island-is/deloitte +/libs/clients/mms/frigg @island-is/deloitte + +/apps/services/auth/ids-api/ @island-is/fuglar @island-is/aranja +/apps/services/auth/admin-api/ @island-is/fuglar @island-is/aranja +/apps/services/auth/public-api/ @island-is/fuglar @island-is/aranja +/apps/services/auth/delegation-api/ @island-is/fuglar @island-is/aranja +/apps/services/sessions/ @island-is/fuglar @island-is/aranja +/apps/auth-admin-web/ @island-is/fuglar @island-is/aranja +/libs/auth-api-lib/ @island-is/fuglar @island-is/aranja +/libs/auth-api-lib/seeders/ @island-is/fuglar @island-is/aranja @island-is/origo-auth +/libs/auth-nest-tools/ @island-is/fuglar @island-is/aranja +/libs/application/templates/european-health-insurance-card/ @island-is/fuglar +/libs/application/template-api-modules/src/lib/modules/templates/european-health-insurance-card/ @island-is/fuglar +/libs/clients/ehic-client-v1 @island-is/fuglar + +/apps/services/auth/personal-representative/ @island-is/programm @island-is/aranja +/apps/services/auth/personal-representative-public/ @island-is/programm @island-is/aranja + +/libs/application/templates/criminal-record/ @island-is/origo +/libs/application/template-api-modules/src/lib/modules/templates/criminal-record-submission/ @island-is/origo +/libs/api/domains/criminal-record/ @island-is/origo +/libs/clients/criminal-record/ @island-is/origo + +/libs/application/templates/mortgage-certificate/ @island-is/origo +/libs/application/template-api-modules/src/lib/modules/templates/mortgage-certificate-submission/ @island-is/origo +/libs/api/domains/mortgage-certificate/ @island-is/origo + +/libs/application/templates/no-debt-certificate/ @island-is/origo +/libs/application/template-api-modules/src/lib/modules/templates/no-debt-certificate/ @island-is/origo + +/libs/application/templates/id-card/ @island-is/origo +/libs/application/template-api-modules/src/lib/modules/templates/id-card/ @island-is/origo + +/libs/clients/charge-fjs-v2/ @island-is/origo +/libs/clients/vehicle-service-fjs-v1/ @island-is/origo + +/libs/application/templates/transport-authority/ @island-is/origo +/libs/application/template-api-modules/src/lib/modules/templates/transport-authority/ @island-is/origo +/libs/api/domains/transport-authority/ @island-is/origo +/libs/clients/transport-authority/ @island-is/origo + +/libs/application/templates/driving-license-book-update-instructor/ @island-is/origo +/libs/application/template-api-modules/src/lib/modules/templates/driving-license-book-update-instructor/ @island-is/origo + +/apps/services/university-gateway/ @island-is/origo +/libs/clients/university-application/ @island-is/origo +/libs/clients/university-gateway-api/ @island-is/origo +/libs/api/domains/university-gateway/ @island-is/origo +/libs/university-gateway/ @island-is/origo +/apps/web/screens/UniversitySearch/ @island-is/origo +/apps/web/screens/queries/UniversityGateway.ts @island-is/origo +/apps/web/components/ListViewCard/ @island-is/origo + +/libs/application/templates/directorate-of-immigration/ @island-is/origo +/libs/application/template-api-modules/src/lib/modules/templates/directorate-of-immigration/ @island-is/origo +/libs/clients/directorate-of-immigration/ @island-is/origo + +/libs/application/templates/aosh/ @island-is/origo +/libs/application/template-api-modules/src/lib/modules/templates/aosh @island-is/origo + +/libs/application/templates/healthcare-license-certificate/ @island-is/origo +/libs/application/template-api-modules/src/lib/modules/templates/healthcare-license-certificate/ @island-is/origo + + +/libs/application/templates/healthcare-work-permit/ @island-is/origo +/libs/application/template-api-modules/src/lib/modules/templates/healthcare-work-permit/ @island-is/origo + +/libs/application/templates/energy-funds/ @island-is/origo +/libs/application/template-api-modules/src/lib/modules/templates/energy-funds/ @island-is/origo +/libs/api/domains/energy-funds/ @island-is/origo +/libs/clients/energy-funds/ @island-is/origo + +/libs/application/templates/university/ @island-is/origo +/libs/application/template-api-modules/src/lib/modules/templates/university/ @island-is/origo # DevOps -/.github/ @island-is/devops -/.githooks/ @island-is/devops -/apps/reference-backend/ @island-is/devops -/apps/github-actions-cache/ @island-is/devops -/infra/ @island-is/devops -**/infra/ @island-is/devops -/libs/logging/ @island-is/devops -/scripts/ @island-is/devops -/scripts/postinstall.js @island-is/devops @island-is/core -/scripts/codegen.js @island-is/devops @island-is/core -/charts/ @island-is/devops -.dockerignore @island-is/devops +/.github/ @island-is/devops +/.githooks/ @island-is/devops +/apps/reference-backend/ @island-is/devops +/apps/github-actions-cache/ @island-is/devops +/infra/ @island-is/devops +**/infra/ @island-is/devops +/libs/logging/ @island-is/devops +/scripts/ @island-is/devops +/scripts/postinstall.js @island-is/devops @island-is/core +/scripts/codegen.js @island-is/devops @island-is/core +/charts/ @island-is/devops +.dockerignore @island-is/devops # QA -/apps/system-e2e/ @island-is/qa -/libs/testing/e2e @island-is/qa +/apps/system-e2e/ @island-is/qa +/libs/testing/e2e @island-is/qa # Islandis -/apps/system-e2e/src/tests/islandis/admin-portal/ @island-is/aranja -/apps/system-e2e/src/tests/islandis/application-system/ @island-is/norda-applications -/apps/system-e2e/src/tests/islandis/application-system/acceptance/parental-leave.spec.ts @island-is/deloitte -/apps/system-e2e/src/tests/islandis/consultation-portal/ @island-is/advania -/apps/system-e2e/src/tests/islandis/service-portal/ @island-is/hugsmidjan @island-is/juni @island-is/norda-applications -/apps/system-e2e/src/tests/islandis/web/ @island-is/hugsmidjan @island-is/juni @island-is/stefna +/apps/system-e2e/src/tests/islandis/admin-portal/ @island-is/aranja +/apps/system-e2e/src/tests/islandis/application-system/ @island-is/norda-applications +/apps/system-e2e/src/tests/islandis/application-system/acceptance/parental-leave.spec.ts @island-is/deloitte +/apps/system-e2e/src/tests/islandis/consultation-portal/ @island-is/advania +/apps/system-e2e/src/tests/islandis/service-portal/ @island-is/hugsmidjan @island-is/juni @island-is/norda-applications +/apps/system-e2e/src/tests/islandis/web/ @island-is/hugsmidjan @island-is/juni @island-is/stefna # Judicial system -/apps/system-e2e/src/tests/judicial-system/ @island-is/kolibri-justice-league +/apps/system-e2e/src/tests/judicial-system/ @island-is/kolibri-justice-league diff --git a/apps/download-service/src/app/app.module.ts b/apps/download-service/src/app/app.module.ts index 2c3b3a9b69a6..994224f5e721 100644 --- a/apps/download-service/src/app/app.module.ts +++ b/apps/download-service/src/app/app.module.ts @@ -51,7 +51,6 @@ import { WorkMachinesClientConfig, WorkMachinesClientModule, } from '@island.is/clients/work-machines' -import { HealthPaymentsOverviewController } from './modules/health/payment-overview-documents.controller' import { RightsPortalClientConfig, RightsPortalClientModule, @@ -70,7 +69,6 @@ import { RegulationDocumentsController, WorkMachinesController, OccupationalLicensesController, - HealthPaymentsOverviewController, ], imports: [ AuditModule.forRoot(environment.audit), diff --git a/apps/download-service/src/app/modules/health/payment-overview-documents.controller.ts b/apps/download-service/src/app/modules/health/payment-overview-documents.controller.ts deleted file mode 100644 index 1bb2aa7e9701..000000000000 --- a/apps/download-service/src/app/modules/health/payment-overview-documents.controller.ts +++ /dev/null @@ -1,73 +0,0 @@ -import type { User } from '@island.is/auth-nest-tools' -import { - AuthMiddleware, - CurrentUser, - IdsUserGuard, - Scopes, - ScopesGuard, -} from '@island.is/auth-nest-tools' -import { ApiScope } from '@island.is/auth/scopes' -import { PaymentsOverviewApi } from '@island.is/clients/icelandic-health-insurance/rights-portal' -import { AuditService } from '@island.is/nest/audit' -import { Controller, Header, Param, Post, Res, UseGuards } from '@nestjs/common' -import { ApiOkResponse } from '@nestjs/swagger' -import { Response } from 'express' - -@UseGuards(IdsUserGuard, ScopesGuard) -@Scopes(ApiScope.healthPayments) -@Controller('health') -export class HealthPaymentsOverviewController { - constructor( - private readonly paymentApi: PaymentsOverviewApi, - private readonly auditService: AuditService, - ) {} - - @Post('/payments/:documentId') - @Header('Content-Type', 'application/pdf') - @ApiOkResponse({ - content: { 'application/pdf': {} }, - description: - 'Gets payment overview document for specific bill with documentId', - }) - async getHealthPaymentOverviewPdf( - @Param('documentId') documentId: string, - @CurrentUser() user: User, - @Res() res: Response, - ) { - const documentResponse = await this.paymentApi - .withMiddleware(new AuthMiddleware(user)) - .getPaymentsOverviewDocument({ - documentId: parseInt(documentId), - }) - - if (documentResponse) { - this.auditService.audit({ - action: 'getHealthPaymentOverviewPdf', - auth: user, - resources: documentId, - }) - - if (!documentResponse.data) - return res.status(404).end( - JSON.stringify({ - statusCode: 404, - message: 'Document not found', - }), - ) - - const buffer = Buffer.from(documentResponse.data, 'base64') - - res.header('Content-length', buffer.length.toString()) - res.header( - 'Content-Disposition', - `inline; filename=${user.nationalId}-health-payment-overview-${documentResponse.fileName}.pdf`, - ) - res.header('Content-Type', 'application/pdf') - res.header('Pragma', 'no-cache') - res.header('Cache-Control', 'no-cache') - res.header('Cache-Control', 'nmax-age=0') - return res.status(200).end(buffer) - } - return res.end() - } -} diff --git a/apps/judicial-system/api/src/app/modules/backend/backend.service.ts b/apps/judicial-system/api/src/app/modules/backend/backend.service.ts index 8069fc52faac..12377fb8d096 100644 --- a/apps/judicial-system/api/src/app/modules/backend/backend.service.ts +++ b/apps/judicial-system/api/src/app/modules/backend/backend.service.ts @@ -355,6 +355,17 @@ export class BackendService extends DataSource<{ req: Request }> { ) } + limitedAccessUpdateDefendant( + caseId: string, + defendantId: string, + updateDefendant: unknown, + ): Promise { + return this.patch( + `case/${caseId}/limitedAccess/defendant/${defendantId}`, + updateDefendant, + ) + } + deleteDefendant( caseId: string, defendantId: string, diff --git a/apps/judicial-system/api/src/app/modules/defendant/defendant.module.ts b/apps/judicial-system/api/src/app/modules/defendant/defendant.module.ts index 245771d1f74e..069954e5695f 100644 --- a/apps/judicial-system/api/src/app/modules/defendant/defendant.module.ts +++ b/apps/judicial-system/api/src/app/modules/defendant/defendant.module.ts @@ -2,8 +2,13 @@ import { Module } from '@nestjs/common' import { CivilClaimantResolver } from './civilClaimant.resolver' import { DefendantResolver } from './defendant.resolver' +import { LimitedAccessDefendantResolver } from './limitedAccessDefendant.resolver' @Module({ - providers: [DefendantResolver, CivilClaimantResolver], + providers: [ + DefendantResolver, + CivilClaimantResolver, + LimitedAccessDefendantResolver, + ], }) export class DefendantModule {} diff --git a/apps/judicial-system/api/src/app/modules/defendant/dto/updateDefendant.input.ts b/apps/judicial-system/api/src/app/modules/defendant/dto/updateDefendant.input.ts index d25bad9175cb..185906750683 100644 --- a/apps/judicial-system/api/src/app/modules/defendant/dto/updateDefendant.input.ts +++ b/apps/judicial-system/api/src/app/modules/defendant/dto/updateDefendant.input.ts @@ -6,6 +6,7 @@ import { DefendantPlea, DefenderChoice, Gender, + PunishmentType, ServiceRequirement, SubpoenaType, } from '@island.is/judicial-system/types' @@ -114,4 +115,9 @@ export class UpdateDefendantInput { @IsOptional() @Field(() => Boolean, { nullable: true }) readonly isSentToPrisonAdmin?: boolean + + @Allow() + @IsOptional() + @Field(() => PunishmentType, { nullable: true }) + readonly punishmentType?: PunishmentType } diff --git a/apps/judicial-system/api/src/app/modules/defendant/limitedAccessDefendant.resolver.ts b/apps/judicial-system/api/src/app/modules/defendant/limitedAccessDefendant.resolver.ts new file mode 100644 index 000000000000..ab84737de74c --- /dev/null +++ b/apps/judicial-system/api/src/app/modules/defendant/limitedAccessDefendant.resolver.ts @@ -0,0 +1,54 @@ +import { Inject, UseGuards } from '@nestjs/common' +import { Args, Context, Mutation, Resolver } from '@nestjs/graphql' + +import type { Logger } from '@island.is/logging' +import { LOGGER_PROVIDER } from '@island.is/logging' + +import { + AuditedAction, + AuditTrailService, +} from '@island.is/judicial-system/audit-trail' +import { + CurrentGraphQlUser, + JwtGraphQlAuthGuard, +} from '@island.is/judicial-system/auth' +import type { User } from '@island.is/judicial-system/types' + +import { BackendService } from '../backend' +import { UpdateDefendantInput } from './dto/updateDefendant.input' +import { Defendant } from './models/defendant.model' + +@UseGuards(JwtGraphQlAuthGuard) +@Resolver() +export class LimitedAccessDefendantResolver { + constructor( + private readonly auditTrailService: AuditTrailService, + @Inject(LOGGER_PROVIDER) + private readonly logger: Logger, + ) {} + + @Mutation(() => Defendant, { nullable: true }) + limitedAccessUpdateDefendant( + @Args('input', { type: () => UpdateDefendantInput }) + input: UpdateDefendantInput, + @CurrentGraphQlUser() user: User, + @Context('dataSources') + { backendService }: { backendService: BackendService }, + ): Promise { + const { caseId, defendantId, ...updateDefendant } = input + this.logger.debug( + `Updating limitedAccess defendant ${defendantId} for case ${caseId}`, + ) + + return this.auditTrailService.audit( + user.id, + AuditedAction.UPDATE_DEFENDANT, + backendService.limitedAccessUpdateDefendant( + caseId, + defendantId, + updateDefendant, + ), + defendantId, + ) + } +} diff --git a/apps/judicial-system/api/src/app/modules/defendant/models/defendant.model.ts b/apps/judicial-system/api/src/app/modules/defendant/models/defendant.model.ts index 8a692f3a9ade..589709247bd9 100644 --- a/apps/judicial-system/api/src/app/modules/defendant/models/defendant.model.ts +++ b/apps/judicial-system/api/src/app/modules/defendant/models/defendant.model.ts @@ -4,6 +4,7 @@ import { DefendantPlea, DefenderChoice, Gender, + PunishmentType, ServiceRequirement, SubpoenaType, } from '@island.is/judicial-system/types' @@ -15,6 +16,7 @@ registerEnumType(DefendantPlea, { name: 'DefendantPlea' }) registerEnumType(ServiceRequirement, { name: 'ServiceRequirement' }) registerEnumType(DefenderChoice, { name: 'DefenderChoice' }) registerEnumType(SubpoenaType, { name: 'SubpoenaType' }) +registerEnumType(PunishmentType, { name: 'PunishmentType' }) @ObjectType() export class Defendant { @@ -107,4 +109,7 @@ export class Defendant { @Field(() => String, { nullable: true }) readonly sentToPrisonAdminDate?: string + + @Field(() => PunishmentType, { nullable: true }) + readonly punishmentType?: PunishmentType } diff --git a/apps/judicial-system/backend/migrations/20241211095654-update-defendant.js b/apps/judicial-system/backend/migrations/20241211095654-update-defendant.js new file mode 100644 index 000000000000..f8d0249598cc --- /dev/null +++ b/apps/judicial-system/backend/migrations/20241211095654-update-defendant.js @@ -0,0 +1,26 @@ +'use strict' + +module.exports = { + async up(queryInterface, Sequelize) { + return queryInterface.sequelize.transaction((t) => + Promise.all([ + queryInterface.addColumn( + 'defendant', + 'punishment_type', + { + type: Sequelize.STRING, + allowNull: true, + }, + { transaction: t }, + ), + ]), + ) + }, + async down(queryInterface, Sequelize) { + return queryInterface.sequelize.transaction((t) => + queryInterface.removeColumn('defendant', 'punishment_type', { + transaction: t, + }), + ) + }, +} diff --git a/apps/judicial-system/backend/src/app/messages/notifications.ts b/apps/judicial-system/backend/src/app/messages/notifications.ts index 43bda5af9fb3..ed00262e39d9 100644 --- a/apps/judicial-system/backend/src/app/messages/notifications.ts +++ b/apps/judicial-system/backend/src/app/messages/notifications.ts @@ -856,4 +856,19 @@ export const notifications = { description: 'Texti í pósti til aðila máls þegar ný gögn eru send', }, }), + courtOfficialAssignedEmail: defineMessages({ + subject: { + id: 'judicial.system.backend:notifications.court_official_assigned_email.subject', + defaultMessage: 'Úthlutun máls {courtCaseNumber}', + description: + 'Fyrirsögn í pósti til dómara og dómritara þegar máli er úthlutað á þau', + }, + body: { + id: 'judicial.system.backend:notifications.court_official_assigned_email.body', + defaultMessage: + 'Héraðsdómur hefur skráð þig sem {role, select, DISTRICT_COURT_JUDGE {dómara} DISTRICT_COURT_REGISTRAR {dómritara} other {óþekkt}} í máli {courtCaseNumber}. Hægt er að nálgast gögn málsins á {linkStart}yfirlitssíðu málsins í Réttarvörslugátt{linkEnd}', + description: + 'Texti í pósti til dómara og dómritara þegar máli er úthlutað á þau', + }, + }), } diff --git a/apps/judicial-system/backend/src/app/modules/case/case.service.ts b/apps/judicial-system/backend/src/app/modules/case/case.service.ts index c89bbc8c0e0c..75fe945637d3 100644 --- a/apps/judicial-system/backend/src/app/modules/case/case.service.ts +++ b/apps/judicial-system/backend/src/app/modules/case/case.service.ts @@ -45,6 +45,7 @@ import { eventTypes, isCompletedCase, isIndictmentCase, + isInvestigationCase, isRequestCase, isTrafficViolationCase, notificationTypes, @@ -686,6 +687,34 @@ export class CaseService { ]) } + private addMessagesForDistrictCourtJudgeAssignedToQueue( + theCase: Case, + user: TUser, + ): Promise { + return this.messageService.sendMessagesToQueue([ + { + type: MessageType.NOTIFICATION, + user, + caseId: theCase.id, + body: { type: CaseNotificationType.DISTRICT_COURT_JUDGE_ASSIGNED }, + }, + ]) + } + + private addMessagesForDistrictCourtRegistrarAssignedToQueue( + theCase: Case, + user: TUser, + ): Promise { + return this.messageService.sendMessagesToQueue([ + { + type: MessageType.NOTIFICATION, + user, + caseId: theCase.id, + body: { type: CaseNotificationType.DISTRICT_COURT_REGISTRAR_ASSIGNED }, + }, + ]) + } + private addMessagesForReceivedCaseToQueue( theCase: Case, user: TUser, @@ -845,7 +874,25 @@ export class CaseService { this.getDeliverProsecutorToCourtMessages(theCase, user), ) } + private addMessagesForSignedCourtRecordToQueue( + theCase: Case, + user: TUser, + ): Promise { + const messages = [] + if ( + theCase.origin === CaseOrigin.LOKE && + isInvestigationCase(theCase.type) + ) { + messages.push({ + type: MessageType.DELIVERY_TO_POLICE_SIGNED_COURT_RECORD, + user, + caseId: theCase.id, + }) + } + + return this.messageService.sendMessagesToQueue(messages) + } private addMessagesForSignedRulingToQueue( theCase: Case, user: TUser, @@ -1384,6 +1431,30 @@ export class CaseService { } } + if ( + isIndictment && + [CaseState.SUBMITTED, CaseState.RECEIVED].includes(updatedCase.state) + ) { + const isJudgeChanged = + updatedCase.judge?.nationalId !== theCase.judge?.nationalId + const isRegistrarChanged = + updatedCase.registrar?.nationalId !== theCase.registrar?.nationalId + + if (isJudgeChanged) { + await this.addMessagesForDistrictCourtJudgeAssignedToQueue( + updatedCase, + user, + ) + } + + if (isRegistrarChanged) { + await this.addMessagesForDistrictCourtRegistrarAssignedToQueue( + updatedCase, + user, + ) + } + } + if ( isIndictment && ![ @@ -1899,6 +1970,8 @@ export class CaseService { false, ) + await this.addMessagesForSignedCourtRecordToQueue(theCase, user) + return { documentSigned: true } } catch (error) { this.eventService.postErrorEvent( diff --git a/apps/judicial-system/backend/src/app/modules/case/internalCase.controller.ts b/apps/judicial-system/backend/src/app/modules/case/internalCase.controller.ts index 60991a38b33f..d48a86633f14 100644 --- a/apps/judicial-system/backend/src/app/modules/case/internalCase.controller.ts +++ b/apps/judicial-system/backend/src/app/modules/case/internalCase.controller.ts @@ -571,6 +571,35 @@ export class InternalCaseController { ) } + @UseGuards( + CaseExistsGuard, + new CaseTypeGuard([...restrictionCases, ...investigationCases]), + CaseCompletedGuard, + ) + @Post( + `case/:caseId/${ + messageEndpoint[MessageType.DELIVERY_TO_POLICE_SIGNED_COURT_RECORD] + }`, + ) + @ApiOkResponse({ + type: DeliverResponse, + description: 'Delivers a signed court record to police', + }) + deliverSignedCourtRecordToPolice( + @Param('caseId') caseId: string, + @CurrentCase() theCase: Case, + @Body() deliverDto: DeliverDto, + ): Promise { + this.logger.debug( + `Delivering the signed court record for case ${caseId} to police`, + ) + + return this.internalCaseService.deliverSignedCourtRecordToPolice( + theCase, + deliverDto.user, + ) + } + @UseGuards( CaseExistsGuard, new CaseTypeGuard([...restrictionCases, ...investigationCases]), diff --git a/apps/judicial-system/backend/src/app/modules/case/internalCase.service.ts b/apps/judicial-system/backend/src/app/modules/case/internalCase.service.ts index a969cf40351b..8a06a7825db3 100644 --- a/apps/judicial-system/backend/src/app/modules/case/internalCase.service.ts +++ b/apps/judicial-system/backend/src/app/modules/case/internalCase.service.ts @@ -307,6 +307,13 @@ export class InternalCaseService { ) } + private getSignedCourtRecordPdf(theCase: Case) { + return this.awsS3Service.getGeneratedRequestCaseObject( + theCase.type, + `${theCase.id}/courtRecord.pdf`, + ) + } + private async deliverSignedRulingPdfToCourt( theCase: Case, user: TUser, @@ -606,6 +613,7 @@ export class InternalCaseService { ? { name: theCase.prosecutor.name, nationalId: theCase.prosecutor.nationalId, + email: theCase.prosecutor.email, } : undefined, ) @@ -1099,6 +1107,32 @@ export class InternalCaseService { return { delivered } } + async deliverSignedCourtRecordToPolice( + theCase: Case, + user: TUser, + ): Promise { + const delivered = await this.getSignedCourtRecordPdf(theCase) + .then((pdf) => + this.deliverCaseToPoliceWithFiles(theCase, user, [ + { + type: PoliceDocumentType.RVTB, + courtDocument: Base64.btoa(pdf.toString('binary')), + }, + ]), + ) + .catch((reason) => { + // Tolerate failure, but log error + this.logger.error( + `Failed to deliver signed court record for case ${theCase.id} to police`, + { reason }, + ) + + return false + }) + + return { delivered } + } + async deliverSignedRulingToPolice( theCase: Case, user: TUser, @@ -1115,7 +1149,7 @@ export class InternalCaseService { .catch((reason) => { // Tolerate failure, but log error this.logger.error( - `Failed to deliver sigend ruling for case ${theCase.id} to police`, + `Failed to deliver signed ruling for case ${theCase.id} to police`, { reason }, ) diff --git a/apps/judicial-system/backend/src/app/modules/case/limitedAccessCase.service.ts b/apps/judicial-system/backend/src/app/modules/case/limitedAccessCase.service.ts index 14e595b23ff0..a837de8c2089 100644 --- a/apps/judicial-system/backend/src/app/modules/case/limitedAccessCase.service.ts +++ b/apps/judicial-system/backend/src/app/modules/case/limitedAccessCase.service.ts @@ -234,6 +234,7 @@ export const include: Includeable[] = [ CaseFileCategory.PROSECUTOR_CASE_FILE, CaseFileCategory.DEFENDANT_CASE_FILE, CaseFileCategory.CIVIL_CLAIM, + CaseFileCategory.SENT_TO_PRISON_ADMIN_FILE, ], }, separate: true, diff --git a/apps/judicial-system/backend/src/app/modules/case/test/internalCaseController/deliverIndictmentInfoToCourt.spec.ts b/apps/judicial-system/backend/src/app/modules/case/test/internalCaseController/deliverIndictmentInfoToCourt.spec.ts index 3236f05eb4de..c7b01baee552 100644 --- a/apps/judicial-system/backend/src/app/modules/case/test/internalCaseController/deliverIndictmentInfoToCourt.spec.ts +++ b/apps/judicial-system/backend/src/app/modules/case/test/internalCaseController/deliverIndictmentInfoToCourt.spec.ts @@ -54,7 +54,11 @@ describe('InternalCaseController - Deliver indictment info to court', () => { { eventType: EventType.INDICTMENT_CONFIRMED, created: indictmentDate }, ], defendants: [{ name: 'Test Ákærði', nationalId: '1234567890' }], - prosecutor: { name: 'Test Sækjandi', nationalId: '0101010101' }, + prosecutor: { + name: 'Test Sækjandi', + nationalId: '0101010101', + email: 'prosecutor@omnitrix.is', + }, } as Case let mockCourtService: CourtService diff --git a/apps/judicial-system/backend/src/app/modules/case/test/internalCaseController/deliverSignedCourtRecordToPolice.spec.ts b/apps/judicial-system/backend/src/app/modules/case/test/internalCaseController/deliverSignedCourtRecordToPolice.spec.ts new file mode 100644 index 000000000000..dabef1f9f88d --- /dev/null +++ b/apps/judicial-system/backend/src/app/modules/case/test/internalCaseController/deliverSignedCourtRecordToPolice.spec.ts @@ -0,0 +1,124 @@ +import { Base64 } from 'js-base64' +import { uuid } from 'uuidv4' + +import { + CaseOrigin, + CaseState, + CaseType, + User, +} from '@island.is/judicial-system/types' + +import { createTestingCaseModule } from '../createTestingCaseModule' + +import { nowFactory } from '../../../../factories' +import { randomDate } from '../../../../test' +import { AwsS3Service } from '../../../aws-s3' +import { PoliceDocumentType, PoliceService } from '../../../police' +import { Case } from '../../models/case.model' +import { DeliverResponse } from '../../models/deliver.response' + +jest.mock('../../../../factories') + +interface Then { + result: DeliverResponse + error: Error +} + +type GivenWhenThen = (caseId: string, theCase: Case) => Promise + +describe('InternalCaseController - Deliver signed court record to police', () => { + const userId = uuid() + const user = { id: userId } as User + + let mockAwsS3Service: AwsS3Service + let mockPoliceService: PoliceService + let givenWhenThen: GivenWhenThen + + beforeEach(async () => { + const { awsS3Service, policeService, internalCaseController } = + await createTestingCaseModule() + + mockAwsS3Service = awsS3Service + mockPoliceService = policeService + + const mockGetGeneratedObject = + awsS3Service.getGeneratedRequestCaseObject as jest.Mock + mockGetGeneratedObject.mockRejectedValue(new Error('Some error')) + const mockUpdatePoliceCase = mockPoliceService.updatePoliceCase as jest.Mock + mockUpdatePoliceCase.mockRejectedValue(new Error('Some error')) + + givenWhenThen = async (caseId: string, theCase: Case) => { + const then = {} as Then + + await internalCaseController + .deliverSignedCourtRecordToPolice(caseId, theCase, { user }) + .then((result) => (then.result = result)) + .catch((error) => (then.error = error)) + + return then + } + }) + + describe('deliver case to police', () => { + const caseId = uuid() + const caseType = CaseType.PHONE_TAPPING + const caseState = CaseState.ACCEPTED + const policeCaseNumber = uuid() + const courtCaseNumber = uuid() + const defendantNationalId = '0123456789' + const validToDate = randomDate() + const caseConclusion = 'test conclusion' + const theCase = { + id: caseId, + origin: CaseOrigin.LOKE, + type: caseType, + state: caseState, + policeCaseNumbers: [policeCaseNumber], + courtCaseNumber, + defendants: [{ nationalId: defendantNationalId }], + validToDate, + conclusion: caseConclusion, + } as Case + const courtRecordPdf = 'test court record' + + let then: Then + + beforeEach(async () => { + const mockToday = nowFactory as jest.Mock + mockToday.mockReturnValueOnce(validToDate) + + const mockGetGeneratedObject = + mockAwsS3Service.getGeneratedRequestCaseObject as jest.Mock + mockGetGeneratedObject.mockResolvedValueOnce(courtRecordPdf) + const mockUpdatePoliceCase = + mockPoliceService.updatePoliceCase as jest.Mock + mockUpdatePoliceCase.mockResolvedValueOnce(true) + + then = await givenWhenThen(caseId, theCase) + }) + + it('should update the police case with a signed court record', async () => { + expect( + mockAwsS3Service.getGeneratedRequestCaseObject, + ).toHaveBeenCalledWith(caseType, `${caseId}/courtRecord.pdf`) + expect(mockPoliceService.updatePoliceCase).toHaveBeenCalledWith( + user, + caseId, + caseType, + caseState, + policeCaseNumber, + courtCaseNumber, + defendantNationalId, + validToDate, + caseConclusion, + [ + { + type: PoliceDocumentType.RVTB, + courtDocument: Base64.btoa(courtRecordPdf), + }, + ], + ) + expect(then.result.delivered).toEqual(true) + }) + }) +}) diff --git a/apps/judicial-system/backend/src/app/modules/case/test/internalCaseController/deliverSignedCourtRecordToPoliceGuards.spec.ts b/apps/judicial-system/backend/src/app/modules/case/test/internalCaseController/deliverSignedCourtRecordToPoliceGuards.spec.ts new file mode 100644 index 000000000000..38394cc82fd3 --- /dev/null +++ b/apps/judicial-system/backend/src/app/modules/case/test/internalCaseController/deliverSignedCourtRecordToPoliceGuards.spec.ts @@ -0,0 +1,66 @@ +import { CanActivate } from '@nestjs/common' + +import { + investigationCases, + restrictionCases, +} from '@island.is/judicial-system/types' + +import { CaseCompletedGuard } from '../../guards/caseCompleted.guard' +import { CaseExistsGuard } from '../../guards/caseExists.guard' +import { CaseTypeGuard } from '../../guards/caseType.guard' +import { InternalCaseController } from '../../internalCase.controller' + +describe('InternalCaseController - Deliver signed court record to police guards', () => { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + let guards: any[] + + beforeEach(() => { + guards = Reflect.getMetadata( + '__guards__', + InternalCaseController.prototype.deliverSignedCourtRecordToPolice, + ) + }) + + it('should have three guards', () => { + expect(guards).toHaveLength(3) + }) + + describe('CaseExistsGuard', () => { + let guard: CanActivate + + beforeEach(() => { + guard = new guards[0]() + }) + + it('should have CaseExistsGuard as guard 1', () => { + expect(guard).toBeInstanceOf(CaseExistsGuard) + }) + }) + + describe('CaseTypeGuard', () => { + let guard: CanActivate + + beforeEach(() => { + guard = guards[1] + }) + + it('should have CaseTypeGuard as guard 2', () => { + expect(guard).toBeInstanceOf(CaseTypeGuard) + expect(guard).toEqual({ + allowedCaseTypes: [...restrictionCases, ...investigationCases], + }) + }) + }) + + describe('CaseCompletedGuard', () => { + let guard: CanActivate + + beforeEach(() => { + guard = new guards[2]() + }) + + it('should have CaseCompletedGuard as guard 3', () => { + expect(guard).toBeInstanceOf(CaseCompletedGuard) + }) + }) +}) diff --git a/apps/judicial-system/backend/src/app/modules/court/court.service.ts b/apps/judicial-system/backend/src/app/modules/court/court.service.ts index 7113dd6769b0..33f9c74c7c83 100644 --- a/apps/judicial-system/backend/src/app/modules/court/court.service.ts +++ b/apps/judicial-system/backend/src/app/modules/court/court.service.ts @@ -336,6 +336,9 @@ export class CourtService { ) const isIndictment = isIndictmentCase(type) + const policeCaseNumber = policeCaseNumbers[0] + ? policeCaseNumbers[0].replace(/-/g, '') + : '' return await this.courtClientService.createCase(courtId, { caseType: isIndictment ? 'S - Ákærumál' : 'R - Rannsóknarmál', @@ -344,7 +347,7 @@ export class CourtService { receivalDate: formatISO(receivalDate, { representation: 'date' }), basedOn: isIndictment ? 'Sakamál' : 'Rannsóknarhagsmunir', // TODO: pass in all policeCaseNumbers when CourtService supports it - sourceNumber: policeCaseNumbers[0] ? policeCaseNumbers[0] : '', + sourceNumber: policeCaseNumber, }) } catch (reason) { if (reason instanceof ServiceUnavailableException) { @@ -569,10 +572,13 @@ export class CourtService { policeCaseNumber?: string, subtypes?: string[], defendants?: { name?: string; nationalId?: string }[], - prosecutor?: { name?: string; nationalId?: string }, + prosecutor?: { name?: string; nationalId?: string; email?: string }, ): Promise { try { const subject = `${courtName} - ${courtCaseNumber} - upplýsingar` + + policeCaseNumber = policeCaseNumber?.replace(/-/g, '') + const content = JSON.stringify({ receivedByCourtDate, indictmentDate, diff --git a/apps/judicial-system/backend/src/app/modules/court/test/createCourtCase.spec.ts b/apps/judicial-system/backend/src/app/modules/court/test/createCourtCase.spec.ts index a32798d80b4e..5b98cb354570 100644 --- a/apps/judicial-system/backend/src/app/modules/court/test/createCourtCase.spec.ts +++ b/apps/judicial-system/backend/src/app/modules/court/test/createCourtCase.spec.ts @@ -105,7 +105,7 @@ describe('CourtService - Create court case', () => { status: 'Skráð', receivalDate: formatISO(receivalDate, { representation: 'date' }), basedOn: 'Rannsóknarhagsmunir', - sourceNumber: policeCaseNumbers[0], + sourceNumber: policeCaseNumbers[0].replace(/-/g, ''), }, ) }) @@ -146,7 +146,7 @@ describe('CourtService - Create court case', () => { status: 'Skráð', receivalDate: formatISO(receivalDate, { representation: 'date' }), basedOn: 'Sakamál', - sourceNumber: policeCaseNumbers[0], + sourceNumber: policeCaseNumbers[0].replace(/-/g, ''), }, ) }) @@ -183,7 +183,7 @@ describe('CourtService - Create court case', () => { status: 'Skráð', receivalDate: formatISO(receivalDate, { representation: 'date' }), basedOn: 'Rannsóknarhagsmunir', - sourceNumber: policeCaseNumbers[0], + sourceNumber: policeCaseNumbers[0].replace(/-/g, ''), }) }) }) @@ -218,7 +218,7 @@ describe('CourtService - Create court case', () => { status: 'Skráð', receivalDate: formatISO(receivalDate, { representation: 'date' }), basedOn: 'Rannsóknarhagsmunir', - sourceNumber: policeCaseNumbers[0], + sourceNumber: policeCaseNumbers[0].replace(/-/g, ''), }) }) }) diff --git a/apps/judicial-system/backend/src/app/modules/defendant/defendant.module.ts b/apps/judicial-system/backend/src/app/modules/defendant/defendant.module.ts index 3aa77ff57b8f..3ac9e2543e23 100644 --- a/apps/judicial-system/backend/src/app/modules/defendant/defendant.module.ts +++ b/apps/judicial-system/backend/src/app/modules/defendant/defendant.module.ts @@ -13,6 +13,7 @@ import { CivilClaimantService } from './civilClaimant.service' import { DefendantController } from './defendant.controller' import { DefendantService } from './defendant.service' import { InternalDefendantController } from './internalDefendant.controller' +import { LimitedAccessDefendantController } from './limitedAccessDefendant.controller' @Module({ imports: [ @@ -25,6 +26,7 @@ import { InternalDefendantController } from './internalDefendant.controller' DefendantController, InternalDefendantController, CivilClaimantController, + LimitedAccessDefendantController, ], providers: [DefendantService, CivilClaimantService], exports: [DefendantService, CivilClaimantService], diff --git a/apps/judicial-system/backend/src/app/modules/defendant/dto/updateDefendant.dto.ts b/apps/judicial-system/backend/src/app/modules/defendant/dto/updateDefendant.dto.ts index 611604fb8c5d..50cad98ba07e 100644 --- a/apps/judicial-system/backend/src/app/modules/defendant/dto/updateDefendant.dto.ts +++ b/apps/judicial-system/backend/src/app/modules/defendant/dto/updateDefendant.dto.ts @@ -15,6 +15,7 @@ import { DefendantPlea, DefenderChoice, Gender, + PunishmentType, ServiceRequirement, SubpoenaType, } from '@island.is/judicial-system/types' @@ -149,4 +150,9 @@ export class UpdateDefendantDto { @IsBoolean() @ApiPropertyOptional({ type: Boolean }) readonly isSentToPrisonAdmin?: boolean + + @IsOptional() + @IsEnum(PunishmentType) + @ApiPropertyOptional({ enum: PunishmentType }) + readonly punishmentType?: PunishmentType } diff --git a/apps/judicial-system/backend/src/app/modules/defendant/guards/rolesRules.ts b/apps/judicial-system/backend/src/app/modules/defendant/guards/rolesRules.ts new file mode 100644 index 000000000000..94577db1a405 --- /dev/null +++ b/apps/judicial-system/backend/src/app/modules/defendant/guards/rolesRules.ts @@ -0,0 +1,13 @@ +import { RolesRule, RulesType } from '@island.is/judicial-system/auth' +import { UserRole } from '@island.is/judicial-system/types' + +import { UpdateDefendantDto } from '../dto/updateDefendant.dto' + +const limitedAccessFields: (keyof UpdateDefendantDto)[] = ['punishmentType'] + +// Allows prison staff to update a specific set of fields for defendant +export const prisonSystemStaffUpdateRule: RolesRule = { + role: UserRole.PRISON_SYSTEM_STAFF, + type: RulesType.FIELD, + dtoFields: limitedAccessFields, +} diff --git a/apps/judicial-system/backend/src/app/modules/defendant/limitedAccessDefendant.controller.ts b/apps/judicial-system/backend/src/app/modules/defendant/limitedAccessDefendant.controller.ts new file mode 100644 index 000000000000..f68b9dabf06c --- /dev/null +++ b/apps/judicial-system/backend/src/app/modules/defendant/limitedAccessDefendant.controller.ts @@ -0,0 +1,64 @@ +import { + Body, + Controller, + Inject, + Param, + Patch, + UseGuards, +} from '@nestjs/common' +import { ApiOkResponse, ApiTags } from '@nestjs/swagger' + +import type { Logger } from '@island.is/logging' +import { LOGGER_PROVIDER } from '@island.is/logging' + +import { + CurrentHttpUser, + JwtAuthGuard, + RolesGuard, + RolesRules, +} from '@island.is/judicial-system/auth' +import { type User } from '@island.is/judicial-system/types' + +import { Case, CaseExistsGuard, CurrentCase } from '../case' +import { UpdateDefendantDto } from './dto/updateDefendant.dto' +import { CurrentDefendant } from './guards/defendant.decorator' +import { DefendantExistsGuard } from './guards/defendantExists.guard' +import { prisonSystemStaffUpdateRule } from './guards/rolesRules' +import { Defendant } from './models/defendant.model' +import { DefendantService } from './defendant.service' + +@Controller('api/case/:caseId/limitedAccess/defendant') +@ApiTags('limited access defendant') +@UseGuards(JwtAuthGuard, RolesGuard) +export class LimitedAccessDefendantController { + constructor( + private readonly defendantService: DefendantService, + @Inject(LOGGER_PROVIDER) private readonly logger: Logger, + ) {} + + @UseGuards(CaseExistsGuard, DefendantExistsGuard) + @RolesRules(prisonSystemStaffUpdateRule) + @Patch(':defendantId') + @ApiOkResponse({ + type: Defendant, + description: 'Updates a defendant', + }) + updateDefendant( + @Param('caseId') caseId: string, + @Param('defendantId') defendantId: string, + @CurrentHttpUser() user: User, + @CurrentCase() theCase: Case, + @CurrentDefendant() defendant: Defendant, + @Body() updateDto: Pick, + ): Promise { + this.logger.debug( + `Updating limitedAccess defendant ${defendantId} of case ${caseId}`, + ) + return this.defendantService.updateRequestCaseDefendant( + theCase, + defendant, + updateDto, + user, + ) + } +} diff --git a/apps/judicial-system/backend/src/app/modules/defendant/models/defendant.model.ts b/apps/judicial-system/backend/src/app/modules/defendant/models/defendant.model.ts index f795a4980c13..8c3f12c78c73 100644 --- a/apps/judicial-system/backend/src/app/modules/defendant/models/defendant.model.ts +++ b/apps/judicial-system/backend/src/app/modules/defendant/models/defendant.model.ts @@ -17,6 +17,7 @@ import { DefendantPlea, DefenderChoice, Gender, + PunishmentType, ServiceRequirement, SubpoenaType, } from '@island.is/judicial-system/types' @@ -201,6 +202,14 @@ export class Defendant extends Model { @ApiPropertyOptional({ type: Boolean }) isSentToPrisonAdmin?: boolean + @Column({ + type: DataType.ENUM, + allowNull: true, + values: Object.values(PunishmentType), + }) + @ApiPropertyOptional({ enum: PunishmentType }) + punishmentType?: PunishmentType + @HasMany(() => DefendantEventLog, { foreignKey: 'defendantId' }) @ApiPropertyOptional({ type: () => DefendantEventLog, isArray: true }) eventLogs?: DefendantEventLog[] diff --git a/apps/judicial-system/backend/src/app/modules/defendant/test/createTestingDefendantModule.ts b/apps/judicial-system/backend/src/app/modules/defendant/test/createTestingDefendantModule.ts index e6ef10b79545..fe83d08485fc 100644 --- a/apps/judicial-system/backend/src/app/modules/defendant/test/createTestingDefendantModule.ts +++ b/apps/judicial-system/backend/src/app/modules/defendant/test/createTestingDefendantModule.ts @@ -18,6 +18,7 @@ import { CivilClaimantService } from '../civilClaimant.service' import { DefendantController } from '../defendant.controller' import { DefendantService } from '../defendant.service' import { InternalDefendantController } from '../internalDefendant.controller' +import { LimitedAccessDefendantController } from '../limitedAccessDefendant.controller' import { CivilClaimant } from '../models/civilClaimant.model' import { Defendant } from '../models/defendant.model' import { DefendantEventLog } from '../models/defendantEventLog.model' @@ -32,6 +33,7 @@ export const createTestingDefendantModule = async () => { imports: [ConfigModule.forRoot({ load: [sharedAuthModuleConfig] })], controllers: [ DefendantController, + LimitedAccessDefendantController, InternalDefendantController, CivilClaimantController, ], @@ -108,6 +110,11 @@ export const createTestingDefendantModule = async () => { InternalDefendantController, ) + const limitedAccessDefendantController = + defendantModule.get( + LimitedAccessDefendantController, + ) + const civilClaimantModel = await defendantModule.resolve< typeof CivilClaimant >(getModelToken(CivilClaimant)) @@ -129,6 +136,7 @@ export const createTestingDefendantModule = async () => { defendantService, defendantController, internalDefendantController, + limitedAccessDefendantController, civilClaimantService, civilClaimantController, civilClaimantModel, diff --git a/apps/judicial-system/backend/src/app/modules/defendant/test/limitedAccessDefendantController/updateDefendant.spec.ts b/apps/judicial-system/backend/src/app/modules/defendant/test/limitedAccessDefendantController/updateDefendant.spec.ts new file mode 100644 index 000000000000..6ce093954315 --- /dev/null +++ b/apps/judicial-system/backend/src/app/modules/defendant/test/limitedAccessDefendantController/updateDefendant.spec.ts @@ -0,0 +1,95 @@ +import { uuid } from 'uuidv4' + +import { MessageService } from '@island.is/judicial-system/message' +import { + CaseType, + PunishmentType, + User, +} from '@island.is/judicial-system/types' + +import { createTestingDefendantModule } from '../createTestingDefendantModule' + +import { Case } from '../../../case' +import { UpdateDefendantDto } from '../../dto/updateDefendant.dto' +import { Defendant } from '../../models/defendant.model' + +interface Then { + result: Defendant + error: Error +} + +type GivenWhenThen = ( + defendantUpdate: UpdateDefendantDto, + type: CaseType, + courtCaseNumber?: string, +) => Promise + +describe('LimitedAccessDefendantController - UpdateDefendant', () => { + const user = { id: uuid() } as User + const caseId = uuid() + const defendantId = uuid() + const defendant = { + id: defendantId, + caseId, + nationalId: uuid(), + defenderEmail: uuid(), + } as Defendant + + let mockMessageService: MessageService + let mockDefendantModel: typeof Defendant + let givenWhenThen: GivenWhenThen + + beforeEach(async () => { + const { messageService, defendantModel, limitedAccessDefendantController } = + await createTestingDefendantModule() + + mockMessageService = messageService + mockDefendantModel = defendantModel + + const mockUpdate = mockDefendantModel.update as jest.Mock + mockUpdate.mockRejectedValue(new Error('Some error')) + + givenWhenThen = async ( + defendantUpdate: UpdateDefendantDto, + type: CaseType, + ) => { + const then = {} as Then + + await limitedAccessDefendantController + .updateDefendant( + caseId, + defendantId, + user, + { id: caseId, type } as Case, + defendant, + defendantUpdate, + ) + .then((result) => (then.result = result)) + .catch((error) => (then.error = error)) + + return then + } + }) + + describe('defendant limited updated', () => { + const defendantUpdate = { punishmentType: PunishmentType.IMPRISONMENT } + const updatedDefendant = { ...defendant, ...defendantUpdate } + let then: Then + + beforeEach(async () => { + const mockUpdate = mockDefendantModel.update as jest.Mock + mockUpdate.mockResolvedValueOnce([1, [updatedDefendant]]) + + then = await givenWhenThen(defendantUpdate, CaseType.INDICTMENT) + }) + + it('should update the defendant without queuing', () => { + expect(mockDefendantModel.update).toHaveBeenCalledWith(defendantUpdate, { + where: { id: defendantId, caseId }, + returning: true, + }) + expect(then.result).toBe(updatedDefendant) + expect(mockMessageService.sendMessagesToQueue).not.toHaveBeenCalled() + }) + }) +}) diff --git a/apps/judicial-system/backend/src/app/modules/defendant/test/limitedAccessDefendantController/updateDefendantRolesRules.spec.ts b/apps/judicial-system/backend/src/app/modules/defendant/test/limitedAccessDefendantController/updateDefendantRolesRules.spec.ts new file mode 100644 index 000000000000..d53607986ffc --- /dev/null +++ b/apps/judicial-system/backend/src/app/modules/defendant/test/limitedAccessDefendantController/updateDefendantRolesRules.spec.ts @@ -0,0 +1,19 @@ +import { prisonSystemStaffUpdateRule } from '../../guards/rolesRules' +import { LimitedAccessDefendantController } from '../../limitedAccessDefendant.controller' + +describe('LimitedAccessDefendantController - Update defendant roles rules', () => { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + let rules: any[] + + beforeEach(() => { + rules = Reflect.getMetadata( + 'roles-rules', + LimitedAccessDefendantController.prototype.updateDefendant, + ) + }) + + it('should give permission to roles', () => { + expect(rules).toHaveLength(1) + expect(rules).toContain(prisonSystemStaffUpdateRule) + }) +}) diff --git a/apps/judicial-system/backend/src/app/modules/file/guards/caseFileCategory.ts b/apps/judicial-system/backend/src/app/modules/file/guards/caseFileCategory.ts index 0c873991e68e..b6656ac08470 100644 --- a/apps/judicial-system/backend/src/app/modules/file/guards/caseFileCategory.ts +++ b/apps/judicial-system/backend/src/app/modules/file/guards/caseFileCategory.ts @@ -44,6 +44,7 @@ const defenderCaseFileCategoriesForIndictmentCases = const prisonAdminCaseFileCategories = [ CaseFileCategory.APPEAL_RULING, CaseFileCategory.RULING, + CaseFileCategory.SENT_TO_PRISON_ADMIN_FILE, ] const prisonStaffCaseFileCategories = [CaseFileCategory.APPEAL_RULING] diff --git a/apps/judicial-system/backend/src/app/modules/file/guards/test/limitedAccessViewCaseFileGuard.spec.ts b/apps/judicial-system/backend/src/app/modules/file/guards/test/limitedAccessViewCaseFileGuard.spec.ts index 2c83715462f4..f333b338737f 100644 --- a/apps/judicial-system/backend/src/app/modules/file/guards/test/limitedAccessViewCaseFileGuard.spec.ts +++ b/apps/judicial-system/backend/src/app/modules/file/guards/test/limitedAccessViewCaseFileGuard.spec.ts @@ -434,6 +434,7 @@ describe('Limited Access View Case File Guard', () => { const allowedCaseFileCategories = [ CaseFileCategory.APPEAL_RULING, CaseFileCategory.RULING, + CaseFileCategory.SENT_TO_PRISON_ADMIN_FILE, ] describe.each(allowedCaseFileCategories)( diff --git a/apps/judicial-system/backend/src/app/modules/notification/guards/rolesRules.ts b/apps/judicial-system/backend/src/app/modules/notification/guards/rolesRules.ts index 04cccc5de218..567e17620945 100644 --- a/apps/judicial-system/backend/src/app/modules/notification/guards/rolesRules.ts +++ b/apps/judicial-system/backend/src/app/modules/notification/guards/rolesRules.ts @@ -28,7 +28,7 @@ export const defenderNotificationRule: RolesRule = { ], } as RolesRule -// Allows district court judges to send notifiications +// Allows district court judges to send notifications export const districtCourtJudgeNotificationRule: RolesRule = { role: UserRole.DISTRICT_COURT_JUDGE, type: RulesType.FIELD_VALUES, diff --git a/apps/judicial-system/backend/src/app/modules/notification/services/caseNotification/caseNotification.service.ts b/apps/judicial-system/backend/src/app/modules/notification/services/caseNotification/caseNotification.service.ts index 0c4cbba076cb..fe2aa576b272 100644 --- a/apps/judicial-system/backend/src/app/modules/notification/services/caseNotification/caseNotification.service.ts +++ b/apps/judicial-system/backend/src/app/modules/notification/services/caseNotification/caseNotification.service.ts @@ -21,6 +21,7 @@ import { INDICTMENTS_OVERVIEW_ROUTE, INVESTIGATION_CASE_POLICE_CONFIRMATION_ROUTE, RESTRICTION_CASE_OVERVIEW_ROUTE, + ROUTE_HANDLER_ROUTE, SIGNED_VERDICT_OVERVIEW_ROUTE, } from '@island.is/judicial-system/consts' import { @@ -46,6 +47,7 @@ import { RequestSharedWithDefender, SessionArrangements, type User, + UserRole, } from '@island.is/judicial-system/types' import { @@ -689,6 +691,28 @@ export class CaseNotificationService extends BaseNotificationService { }) } + private sendCourtOfficialAssignedEmailNotificationForIndictmentCase( + theCase: Case, + role: UserRole.DISTRICT_COURT_JUDGE | UserRole.DISTRICT_COURT_REGISTRAR, + ): Promise { + const official = + role === UserRole.DISTRICT_COURT_JUDGE ? theCase.judge : theCase.registrar + + return this.sendEmail( + this.formatMessage(notifications.courtOfficialAssignedEmail.subject, { + courtCaseNumber: theCase.courtCaseNumber, + }), + this.formatMessage(notifications.courtOfficialAssignedEmail.body, { + courtCaseNumber: theCase.courtCaseNumber, + role, + linkStart: ``, + linkEnd: '', + }), + official?.name, + official?.email, + ) + } + private sendCourtDateEmailNotificationForIndictmentCase( theCase: Case, user: User, @@ -810,6 +834,25 @@ export class CaseNotificationService extends BaseNotificationService { return result } + + private async sendDistrictCourtUserAssignedNotifications( + theCase: Case, + userRole: UserRole.DISTRICT_COURT_JUDGE | UserRole.DISTRICT_COURT_REGISTRAR, + ): Promise { + const recipient = + await this.sendCourtOfficialAssignedEmailNotificationForIndictmentCase( + theCase, + userRole, + ) + + return await this.recordNotification( + theCase.id, + userRole === UserRole.DISTRICT_COURT_JUDGE + ? CaseNotificationType.DISTRICT_COURT_JUDGE_ASSIGNED + : CaseNotificationType.DISTRICT_COURT_REGISTRAR_ASSIGNED, + [recipient], + ) + } //#endregion //#region RULING notifications @@ -2552,6 +2595,16 @@ export class CaseNotificationService extends BaseNotificationService { return this.sendReceivedByCourtNotifications(theCase) case CaseNotificationType.COURT_DATE: return this.sendCourtDateNotifications(theCase, user) + case CaseNotificationType.DISTRICT_COURT_JUDGE_ASSIGNED: + return this.sendDistrictCourtUserAssignedNotifications( + theCase, + UserRole.DISTRICT_COURT_JUDGE, + ) + case CaseNotificationType.DISTRICT_COURT_REGISTRAR_ASSIGNED: + return this.sendDistrictCourtUserAssignedNotifications( + theCase, + UserRole.DISTRICT_COURT_REGISTRAR, + ) case CaseNotificationType.RULING: return this.sendRulingNotifications(theCase) case CaseNotificationType.MODIFIED: diff --git a/apps/judicial-system/digital-mailbox-api/src/app/modules/cases/case.service.ts b/apps/judicial-system/digital-mailbox-api/src/app/modules/cases/case.service.ts index 6f4274fcbe56..0fc03e1d0632 100644 --- a/apps/judicial-system/digital-mailbox-api/src/app/modules/cases/case.service.ts +++ b/apps/judicial-system/digital-mailbox-api/src/app/modules/cases/case.service.ts @@ -173,7 +173,6 @@ export class CaseService { 'Content-Type': 'application/json', authorization: `Bearer ${this.config.secretToken}`, }, - body: JSON.stringify({ nationalId }), }, ) diff --git a/apps/judicial-system/web/messages/Core/errors.ts b/apps/judicial-system/web/messages/Core/errors.ts index b2388cfda63e..02927f00f07f 100644 --- a/apps/judicial-system/web/messages/Core/errors.ts +++ b/apps/judicial-system/web/messages/Core/errors.ts @@ -43,8 +43,8 @@ export const errors = defineMessages({ 'Notaður sem villuskilaboð þegar ekki gengur að eyða kröfuhafa', }, createCase: { - id: 'judicial.system.core:errors.create_case', - defaultMessage: 'Upp kom villa við að stofnun máls', + id: 'judicial.system.core:errors.create_case_v1', + defaultMessage: 'Upp kom villa við stofnun máls', description: 'Notaður sem villuskilaboð þegar ekki gengur að stofna mál', }, updateCase: { diff --git a/apps/judicial-system/web/src/components/FormProvider/case.graphql b/apps/judicial-system/web/src/components/FormProvider/case.graphql index 00c390081d4a..4aec6d983d4b 100644 --- a/apps/judicial-system/web/src/components/FormProvider/case.graphql +++ b/apps/judicial-system/web/src/components/FormProvider/case.graphql @@ -35,6 +35,7 @@ query Case($input: CaseQueryInput!) { subpoenaType isSentToPrisonAdmin sentToPrisonAdminDate + punishmentType subpoenas { id created @@ -343,6 +344,7 @@ query Case($input: CaseQueryInput!) { verdictAppealDate isVerdictAppealDeadlineExpired subpoenaType + punishmentType subpoenas { id created diff --git a/apps/judicial-system/web/src/components/FormProvider/limitedAccessCase.graphql b/apps/judicial-system/web/src/components/FormProvider/limitedAccessCase.graphql index b61738d433a9..dea05680c538 100644 --- a/apps/judicial-system/web/src/components/FormProvider/limitedAccessCase.graphql +++ b/apps/judicial-system/web/src/components/FormProvider/limitedAccessCase.graphql @@ -47,6 +47,7 @@ query LimitedAccessCase($input: CaseQueryInput!) { subpoenaType isSentToPrisonAdmin sentToPrisonAdminDate + punishmentType subpoenas { id created diff --git a/apps/judicial-system/web/src/components/IndictmentCaseFilesList/IndictmentCaseFilesList.strings.ts b/apps/judicial-system/web/src/components/IndictmentCaseFilesList/IndictmentCaseFilesList.strings.ts index ab0f020ba135..5a4b7ecb6bb6 100644 --- a/apps/judicial-system/web/src/components/IndictmentCaseFilesList/IndictmentCaseFilesList.strings.ts +++ b/apps/judicial-system/web/src/components/IndictmentCaseFilesList/IndictmentCaseFilesList.strings.ts @@ -51,4 +51,10 @@ export const strings = defineMessages({ description: 'Notaður sem texti á PDF takka til að sækja birtingarvottorð í ákærum.', }, + sentToPrisonAdmin: { + id: 'judicial.system.core:indictment_case_files_list.sent_to_prison_admin', + defaultMessage: 'Fullnusta', + description: + 'Notaður sem titill á fullnusta hluta á dómskjalaskjá í ákærum.', + }, }) diff --git a/apps/judicial-system/web/src/components/IndictmentCaseFilesList/IndictmentCaseFilesList.tsx b/apps/judicial-system/web/src/components/IndictmentCaseFilesList/IndictmentCaseFilesList.tsx index b9646bc28671..752011aac971 100644 --- a/apps/judicial-system/web/src/components/IndictmentCaseFilesList/IndictmentCaseFilesList.tsx +++ b/apps/judicial-system/web/src/components/IndictmentCaseFilesList/IndictmentCaseFilesList.tsx @@ -1,4 +1,4 @@ -import { FC, useContext } from 'react' +import { FC, useContext, useMemo } from 'react' import { useIntl } from 'react-intl' import { AnimatePresence } from 'framer-motion' @@ -9,6 +9,7 @@ import { isCompletedCase, isDefenceUser, isDistrictCourtUser, + isPrisonAdminUser, isProsecutionUser, isPublicProsecutor, isPublicProsecutorUser, @@ -25,6 +26,7 @@ import { import { CaseFile, CaseFileCategory, + User, } from '@island.is/judicial-system-web/src/graphql/schema' import { TempCase as Case } from '@island.is/judicial-system-web/src/types' import { useFileList } from '@island.is/judicial-system-web/src/utils/hooks' @@ -45,6 +47,13 @@ interface RenderFilesProps { onOpenFile: (fileId: string) => void } +interface FileSection { + title: string + onOpenFile: (fileId: string) => void + files?: CaseFile[] + shouldRender?: boolean +} + export const RenderFiles: FC = ({ caseFiles, onOpenFile, @@ -65,6 +74,82 @@ export const RenderFiles: FC = ({ ) } +const FileSection: FC = (props: FileSection) => { + const { title, files, onOpenFile, shouldRender = true } = props + + if (!files?.length || !shouldRender) { + return null + } + + return ( + + + {title} + + + + ) +} + +const useFilteredCaseFiles = (caseFiles?: CaseFile[] | null) => { + return useMemo(() => { + const filterByCategories = ( + categories: CaseFileCategory | CaseFileCategory[], + ) => { + const categoryArray = Array.isArray(categories) + ? categories + : [categories] + + return ( + caseFiles?.filter( + (file) => file.category && categoryArray.includes(file.category), + ) ?? [] + ) + } + + return { + indictments: filterByCategories(CaseFileCategory.INDICTMENT), + criminalRecords: filterByCategories(CaseFileCategory.CRIMINAL_RECORD), + costBreakdowns: filterByCategories(CaseFileCategory.COST_BREAKDOWN), + others: filterByCategories(CaseFileCategory.CASE_FILE), + rulings: filterByCategories(CaseFileCategory.RULING), + courtRecords: filterByCategories(CaseFileCategory.COURT_RECORD), + criminalRecordUpdate: filterByCategories( + CaseFileCategory.CRIMINAL_RECORD_UPDATE, + ), + uploadedCaseFiles: filterByCategories([ + CaseFileCategory.PROSECUTOR_CASE_FILE, + CaseFileCategory.DEFENDANT_CASE_FILE, + ]), + civilClaims: filterByCategories(CaseFileCategory.CIVIL_CLAIM), + sentToPrisonAdminFiles: filterByCategories( + CaseFileCategory.SENT_TO_PRISON_ADMIN_FILE, + ), + } + }, [caseFiles]) +} + +const useFilePermissions = (workingCase: Case, user?: User) => { + return useMemo( + () => ({ + canViewCriminalRecordUpdate: + isDistrictCourtUser(user) || + isPublicProsecutor(user) || + isPublicProsecutorUser(user), + canViewCivilClaims: + Boolean(workingCase.hasCivilClaims) && + (isDistrictCourtUser(user) || + isProsecutionUser(user) || + isDefenceUser(user)), + canViewSentToPrisonAdminFiles: + isPrisonAdminUser(user) || isPublicProsecutorUser(user), + canViewRulings: + isDistrictCourtUser(user) || isCompletedCase(workingCase.state), + }), + [user, workingCase.hasCivilClaims, workingCase.state], + ) +} + const IndictmentCaseFilesList: FC = ({ workingCase, displayGeneratedPDFs = true, @@ -89,51 +174,19 @@ const IndictmentCaseFilesList: FC = ({ (defendant) => defendant.subpoenas && defendant.subpoenas.length > 0, ) - const cf = workingCase.caseFiles - - const indictments = cf?.filter( - (file) => file.category === CaseFileCategory.INDICTMENT, - ) - const criminalRecords = cf?.filter( - (file) => file.category === CaseFileCategory.CRIMINAL_RECORD, - ) - const costBreakdowns = cf?.filter( - (file) => file.category === CaseFileCategory.COST_BREAKDOWN, - ) - const others = cf?.filter( - (file) => file.category === CaseFileCategory.CASE_FILE, - ) - const rulings = cf?.filter( - (file) => file.category === CaseFileCategory.RULING, - ) - const courtRecords = cf?.filter( - (file) => file.category === CaseFileCategory.COURT_RECORD, - ) - const criminalRecordUpdate = cf?.filter( - (file) => file.category === CaseFileCategory.CRIMINAL_RECORD_UPDATE, - ) - const uploadedCaseFiles = cf?.filter( - (file) => - file.category === CaseFileCategory.PROSECUTOR_CASE_FILE || - file.category === CaseFileCategory.DEFENDANT_CASE_FILE, - ) - const civilClaims = cf?.filter( - (file) => file.category === CaseFileCategory.CIVIL_CLAIM, - ) + const filteredFiles = useFilteredCaseFiles(workingCase.caseFiles) + const permissions = useFilePermissions(workingCase, user) return ( <> {displayHeading && ( )} - {indictments && indictments.length > 0 && ( - - - {formatMessage(caseFiles.indictmentSection)} - - - - )} + {showTrafficViolationCaseFiles && displayGeneratedPDFs && ( @@ -150,42 +203,27 @@ const IndictmentCaseFilesList: FC = ({ )} - {criminalRecords && criminalRecords.length > 0 && ( - - - {formatMessage(caseFiles.criminalRecordSection)} - - - - )} - {criminalRecordUpdate && - criminalRecordUpdate.length > 0 && - (isDistrictCourtUser(user) || - isPublicProsecutor(user) || - isPublicProsecutorUser(user)) && ( - - - {formatMessage(caseFiles.criminalRecordUpdateSection)} - - - - )} - {costBreakdowns && costBreakdowns.length > 0 && ( - - - {formatMessage(caseFiles.costBreakdownSection)} - - - - )} - {others && others.length > 0 && ( - - - {formatMessage(caseFiles.otherDocumentsSection)} - - - - )} + + + + {displayGeneratedPDFs && ( @@ -207,34 +245,34 @@ const IndictmentCaseFilesList: FC = ({ ))} )} - {courtRecords?.length || rulings?.length ? ( + {filteredFiles.courtRecords?.length || filteredFiles.rulings?.length ? ( {formatMessage(strings.rulingAndCourtRecordsTitle)} - {courtRecords && courtRecords.length > 0 && ( - - )} - {(isDistrictCourtUser(user) || isCompletedCase(workingCase.state)) && - rulings && - rulings.length > 0 && ( - + {filteredFiles.courtRecords && + filteredFiles.courtRecords.length > 0 && ( + + )} + {permissions.canViewRulings && + filteredFiles.rulings && + filteredFiles.rulings.length > 0 && ( + )} ) : null} - {workingCase.hasCivilClaims && - civilClaims && - civilClaims.length > 0 && - (isDistrictCourtUser(user) || - isProsecutionUser(user) || - isDefenceUser(user)) && ( - - - {formatMessage(strings.civilClaimsTitle)} - - - - )} + {showSubpoenaPdf && ( @@ -273,14 +311,24 @@ const IndictmentCaseFilesList: FC = ({ )} )} - {uploadedCaseFiles && uploadedCaseFiles.length > 0 && ( - - - {formatMessage(strings.uploadedCaseFiles)} - - - - )} + {filteredFiles.uploadedCaseFiles && + filteredFiles.uploadedCaseFiles.length > 0 && ( + + + {formatMessage(strings.uploadedCaseFiles)} + + + + )} + {fileNotFound && } diff --git a/apps/judicial-system/web/src/routes/Court/Indictments/Completed/Completed.strings.ts b/apps/judicial-system/web/src/routes/Court/Indictments/Completed/Completed.strings.ts index 884252537f62..d231db70e78f 100644 --- a/apps/judicial-system/web/src/routes/Court/Indictments/Completed/Completed.strings.ts +++ b/apps/judicial-system/web/src/routes/Court/Indictments/Completed/Completed.strings.ts @@ -36,6 +36,13 @@ const strings = defineMessages({ description: 'Notaður sem texti í valmöguleika fyrir það þegar ekki skal birta dómdfellda dóminn.', }, + serviceRequirementNotRequiredTooltip: { + id: 'judicial.system.core:court.indictments.completed.service_requirement_not_required_tooltip', + defaultMessage: + 'Ekki þarf að birta dóm þar sem sektarfjárhæð er lægri en sem nemur áfrýjunarfjárhæð í einkamáli kr. 1.355.762. Gildir frá 01.01.2024', + description: + 'Notað sem tooltip í valmöguleika fyrir það þegar ekki skal birta dómdfellda dóminn.', + }, serviceRequirementNotApplicable: { id: 'judicial.system.core:court.indictments.completed.service_requirement_not_applicable', defaultMessage: 'Dómfelldi var viðstaddur dómsuppkvaðningu', diff --git a/apps/judicial-system/web/src/routes/Court/Indictments/Completed/Completed.tsx b/apps/judicial-system/web/src/routes/Court/Indictments/Completed/Completed.tsx index d988fde76856..88ac21c155da 100644 --- a/apps/judicial-system/web/src/routes/Court/Indictments/Completed/Completed.tsx +++ b/apps/judicial-system/web/src/routes/Court/Indictments/Completed/Completed.tsx @@ -291,6 +291,9 @@ const Completed: FC = () => { large backgroundColor="white" label={formatMessage(strings.serviceRequirementNotRequired)} + tooltip={formatMessage( + strings.serviceRequirementNotRequiredTooltip, + )} /> diff --git a/apps/judicial-system/web/src/routes/Prison/IndictmentOverview/IndictmentOverview.strings.ts b/apps/judicial-system/web/src/routes/Prison/IndictmentOverview/IndictmentOverview.strings.ts index 3762e47532c0..d574238883e5 100644 --- a/apps/judicial-system/web/src/routes/Prison/IndictmentOverview/IndictmentOverview.strings.ts +++ b/apps/judicial-system/web/src/routes/Prison/IndictmentOverview/IndictmentOverview.strings.ts @@ -26,4 +26,41 @@ export const strings = defineMessages({ defaultMessage: 'Dómur', description: 'Titill á Dómur hluta', }, + punishmentTypeTitle: { + id: 'judicial.system.core:indictment_overview.punishment_type_title', + defaultMessage: 'Refsitegund', + description: 'Titill á Refsitegund', + }, + punishmentTypeImprisonment: { + id: 'judicial.system.core:indictment_overview.punishment_type_imprisonment', + defaultMessage: 'Óskilorðsbundið', + description: + 'Notaður sem texti í óskilorðsbundið valmöguleika í Refsitegund', + }, + punishmentTypeProbation: { + id: 'judicial.system.core:indictment_overview.punishment_type_probation', + defaultMessage: 'Skilorðsbundið', + description: + 'Notaður sem texti í skilorðsbundið valmöguleika í Refsitegund', + }, + punishmentTypeFine: { + id: 'judicial.system.core:indictment_overview.punishment_type_fine', + defaultMessage: 'Sekt', + description: 'Notaður sem texti í sekt valmöguleika í Refsitegund', + }, + punishmentTypeIndictmentRulingDecisionFine: { + id: 'judicial.system.core:indictment_overview.punishment_type_indictment_ruling_decision_fine', + defaultMessage: 'Viðurlagaákvörðun', + description: 'Notaður sem texti í viðurlagaákvörðun í Refsitegund', + }, + punishmentTypeSignedFineInvitation: { + id: 'judicial.system.core:indictment_overview.punishment_type_signed_fine_invitation', + defaultMessage: 'Áritað sektarboð', + description: 'Notaður sem texti í sektarboð í Refsitegund', + }, + sentToPrisonAdminFileTitle: { + id: 'judicial.system.core:indictment_overview.sent_to_prison_admin_file_title', + defaultMessage: 'Fullnusta', + description: 'Titill á til fullnustu skjali', + }, }) diff --git a/apps/judicial-system/web/src/routes/Prison/IndictmentOverview/IndictmentOverview.tsx b/apps/judicial-system/web/src/routes/Prison/IndictmentOverview/IndictmentOverview.tsx index fa2d92993205..beab42f136a8 100644 --- a/apps/judicial-system/web/src/routes/Prison/IndictmentOverview/IndictmentOverview.tsx +++ b/apps/judicial-system/web/src/routes/Prison/IndictmentOverview/IndictmentOverview.tsx @@ -1,11 +1,13 @@ import { useContext } from 'react' import { useIntl } from 'react-intl' -import { Box, Text } from '@island.is/island-ui/core' +import { Box, RadioButton, Text } from '@island.is/island-ui/core' import * as constants from '@island.is/judicial-system/consts' import { formatDate } from '@island.is/judicial-system/formatters' +import { PunishmentType } from '@island.is/judicial-system/types' import { core } from '@island.is/judicial-system-web/messages' import { + BlueBox, FormContentContainer, FormContext, FormFooter, @@ -16,18 +18,45 @@ import { RenderFiles, } from '@island.is/judicial-system-web/src/components' import { CaseFileCategory } from '@island.is/judicial-system-web/src/graphql/schema' -import { useFileList } from '@island.is/judicial-system-web/src/utils/hooks' +import { + useDefendants, + useFileList, +} from '@island.is/judicial-system-web/src/utils/hooks' import { strings } from './IndictmentOverview.strings' const IndictmentOverview = () => { - const { workingCase } = useContext(FormContext) + const { workingCase, setWorkingCase } = useContext(FormContext) const { formatMessage } = useIntl() + const { limitedAccessUpdateDefendant, updateDefendantState } = useDefendants() const { onOpen } = useFileList({ caseId: workingCase.id, }) + const { defendants } = workingCase + const defendant = + defendants && defendants?.length > 0 ? defendants[0] : undefined + + const onChange = (updatedPunishmentType: PunishmentType) => { + if (!defendant) return + + const defendantUpdate = { + defendantId: defendant.id, + caseId: workingCase.id, + punishmentType: updatedPunishmentType, + } + updateDefendantState(defendantUpdate, setWorkingCase) + limitedAccessUpdateDefendant(defendantUpdate) + } + + const sentToPrisonAdminFiles = workingCase.caseFiles?.filter( + (file) => file.category === CaseFileCategory.SENT_TO_PRISON_ADMIN_FILE, + ) + + const hasPunishmentType = (punishmentType: PunishmentType) => + defendant?.punishmentType === punishmentType + return ( @@ -56,7 +85,7 @@ const IndictmentOverview = () => { - + {formatMessage(strings.verdictTitle)} @@ -69,6 +98,98 @@ const IndictmentOverview = () => { } /> + + {sentToPrisonAdminFiles && sentToPrisonAdminFiles.length > 0 && ( + + + {formatMessage(strings.sentToPrisonAdminFileTitle)} + + + + )} + + + {formatMessage(strings.punishmentTypeTitle)} + + + + { + onChange(PunishmentType.IMPRISONMENT) + }} + large + backgroundColor="white" + label={formatMessage(strings.punishmentTypeImprisonment)} + /> + + + { + onChange(PunishmentType.PROBATION) + }} + large + backgroundColor="white" + label={formatMessage(strings.punishmentTypeProbation)} + /> + + + { + onChange(PunishmentType.FINE) + }} + large + backgroundColor="white" + label={formatMessage(strings.punishmentTypeFine)} + /> + + + { + onChange(PunishmentType.INDICTMENT_RULING_DECISION_FINE) + }} + large + backgroundColor="white" + label={formatMessage( + strings.punishmentTypeIndictmentRulingDecisionFine, + )} + /> + + + { + onChange(PunishmentType.SIGNED_FINE_INVITATION) + }} + large + backgroundColor="white" + label={formatMessage( + strings.punishmentTypeSignedFineInvitation, + )} + /> + + + diff --git a/apps/judicial-system/web/src/routes/Shared/Cases/PrisonCases.tsx b/apps/judicial-system/web/src/routes/Shared/Cases/PrisonCases.tsx index ad91229428cb..3027b2e998f6 100644 --- a/apps/judicial-system/web/src/routes/Shared/Cases/PrisonCases.tsx +++ b/apps/judicial-system/web/src/routes/Shared/Cases/PrisonCases.tsx @@ -3,7 +3,10 @@ import { useIntl } from 'react-intl' import partition from 'lodash/partition' import { AlertMessage, Box, Tag, Text } from '@island.is/island-ui/core' -import { capitalize } from '@island.is/judicial-system/formatters' +import { + capitalize, + districtCourtAbbreviation, +} from '@island.is/judicial-system/formatters' import { core, errors, @@ -166,6 +169,10 @@ export const PrisonCases: FC = () => { thead={[ { title: formatMessage(tables.caseNumber), + sortable: { + isSortable: true, + key: 'courtCaseNumber', + }, }, { title: capitalize(formatMessage(core.defendant, { suffix: 'i' })), @@ -182,13 +189,21 @@ export const PrisonCases: FC = () => { data={cases} columns={[ { - cell: (row) => ( - - ), + cell: (row) => { + const courtAbbreviation = districtCourtAbbreviation( + row.court?.name, + ) + + return ( + + ) + }, }, { cell: (row) => , diff --git a/apps/judicial-system/web/src/routes/Shared/Cases/prisonCases.graphql b/apps/judicial-system/web/src/routes/Shared/Cases/prisonCases.graphql index 23b25b22538c..04f635815e1e 100644 --- a/apps/judicial-system/web/src/routes/Shared/Cases/prisonCases.graphql +++ b/apps/judicial-system/web/src/routes/Shared/Cases/prisonCases.graphql @@ -44,6 +44,10 @@ query PrisonCases { role active } + court { + id + name + } prosecutor { id created diff --git a/apps/judicial-system/web/src/utils/hooks/useDefendants/index.ts b/apps/judicial-system/web/src/utils/hooks/useDefendants/index.ts index 49da94987d47..fad7f5a7efae 100644 --- a/apps/judicial-system/web/src/utils/hooks/useDefendants/index.ts +++ b/apps/judicial-system/web/src/utils/hooks/useDefendants/index.ts @@ -12,6 +12,7 @@ import { TempCase as Case } from '@island.is/judicial-system-web/src/types' import { useCreateDefendantMutation } from './createDefendant.generated' import { useDeleteDefendantMutation } from './deleteDefendant.generated' +import { useLimitedAccessUpdateDefendantMutation } from './limitedAccessUpdateDefendant.generated' import { useUpdateDefendantMutation } from './updateDefendant.generated' const useDefendants = () => { @@ -19,10 +20,15 @@ const useDefendants = () => { const [createDefendantMutation, { loading: isCreatingDefendant }] = useCreateDefendantMutation() + const [deleteDefendantMutation] = useDeleteDefendantMutation() + const [updateDefendantMutation, { loading: isUpdatingDefendant }] = useUpdateDefendantMutation() + const [limitedAccessUpdateDefendantMutation] = + useLimitedAccessUpdateDefendantMutation() + const createDefendant = useCallback( async (defendant: CreateDefendantInput) => { try { @@ -78,6 +84,24 @@ const useDefendants = () => { [formatMessage, updateDefendantMutation], ) + const limitedAccessUpdateDefendant = useCallback( + async (updateDefendant: UpdateDefendantInput) => { + try { + const { data } = await limitedAccessUpdateDefendantMutation({ + variables: { + input: updateDefendant, + }, + }) + + return Boolean(data) + } catch (error) { + toast.error(formatMessage(errors.updateDefendant)) + return false + } + }, + [formatMessage, limitedAccessUpdateDefendantMutation], + ) + const updateDefendantState = useCallback( ( update: UpdateDefendantInput, @@ -119,6 +143,7 @@ const useDefendants = () => { createDefendant, deleteDefendant, updateDefendant, + limitedAccessUpdateDefendant, isUpdatingDefendant, updateDefendantState, setAndSendDefendantToServer, diff --git a/apps/judicial-system/web/src/utils/hooks/useDefendants/limitedAccessUpdateDefendant.graphql b/apps/judicial-system/web/src/utils/hooks/useDefendants/limitedAccessUpdateDefendant.graphql new file mode 100644 index 000000000000..a2fe721993a5 --- /dev/null +++ b/apps/judicial-system/web/src/utils/hooks/useDefendants/limitedAccessUpdateDefendant.graphql @@ -0,0 +1,5 @@ +mutation LimitedAccessUpdateDefendant($input: UpdateDefendantInput!) { + limitedAccessUpdateDefendant(input: $input) { + id + } +} diff --git a/apps/native/app/android/app/build.gradle b/apps/native/app/android/app/build.gradle index a32464e07a8f..997472187673 100644 --- a/apps/native/app/android/app/build.gradle +++ b/apps/native/app/android/app/build.gradle @@ -16,11 +16,11 @@ react { // The root of your project, i.e. where "package.json" lives. Default is '..' // root = file("../") // The folder where the react-native NPM package is. Default is ../node_modules/react-native - // reactNativeDir = file("../node_modules/react-native") + reactNativeDir = file("../../../../../node_modules/react-native") // The folder where the react-native Codegen package is. Default is ../node_modules/@react-native/codegen - // codegenDir = file("../node_modules/@react-native/codegen") + codegenDir = file("../../../../../node_modules/@react-native/codegen") // The cli.js file which is the React Native CLI entrypoint. Default is ../node_modules/react-native/cli.js - // cliFile = file("../node_modules/react-native/cli.js") + cliFile = file("../../../../../node_modules/react-native/cli.js") /* Variants */ // The list of variants to that are debuggable. For those we're going to diff --git a/apps/native/app/android/build.gradle b/apps/native/app/android/build.gradle index 46f7b30a85d0..06110e23ae99 100644 --- a/apps/native/app/android/build.gradle +++ b/apps/native/app/android/build.gradle @@ -33,11 +33,11 @@ allprojects { repositories { maven { // All of React Native (JS, Obj-C sources, Android binaries) is installed from npm - url("$rootDir/../node_modules/react-native/android") + url("$rootDir/../../../../../node_modules/react-native/android") } maven { // Android JSC is installed from npm - url("$rootDir/../node_modules/jsc-android/dist") + url("$rootDir/../../../../../node_modules/jsc-android/dist") } mavenCentral { // We don't want to fetch react-native from Maven Central as there are diff --git a/apps/native/app/android/settings.gradle b/apps/native/app/android/settings.gradle index 12979ce6cda2..d9655025ec45 100644 --- a/apps/native/app/android/settings.gradle +++ b/apps/native/app/android/settings.gradle @@ -6,11 +6,8 @@ applyNativeModulesSettingsGradle(settings) include ':app', ':react-native-code-push' project(':react-native-code-push').projectDir = new File(rootProject.projectDir, '../../../../node_modules/react-native-code-push/android/app') -include ':react-native-clipboard' -project(':react-native-clipboard').projectDir = new File(rootProject.projectDir, '../../node_modules/@react-native-clipboard/clipboard/android') - include ':app' -includeBuild('../node_modules/@react-native/gradle-plugin') +includeBuild('../../../../node_modules/@react-native/gradle-plugin') apply from: new File(["node", "--print", "require.resolve('expo/package.json')"].execute(null, rootDir).text.trim(), "../scripts/autolinking.gradle") useExpoModules() diff --git a/apps/native/app/ios/Podfile.lock b/apps/native/app/ios/Podfile.lock index 4a489728f683..8223c8bef141 100644 --- a/apps/native/app/ios/Podfile.lock +++ b/apps/native/app/ios/Podfile.lock @@ -1531,7 +1531,73 @@ PODS: - React-Core - RNQuickAction (0.3.13): - React - - RNReanimated (3.12.1): + - RNReanimated (3.16.5): + - DoubleConversion + - glog + - hermes-engine + - RCT-Folly (= 2024.01.01.00) + - RCTRequired + - RCTTypeSafety + - React-Codegen + - React-Core + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-ImageManager + - React-NativeModulesApple + - React-RCTFabric + - React-rendererdebug + - React-utils + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core + - RNReanimated/reanimated (= 3.16.5) + - RNReanimated/worklets (= 3.16.5) + - Yoga + - RNReanimated/reanimated (3.16.5): + - DoubleConversion + - glog + - hermes-engine + - RCT-Folly (= 2024.01.01.00) + - RCTRequired + - RCTTypeSafety + - React-Codegen + - React-Core + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-ImageManager + - React-NativeModulesApple + - React-RCTFabric + - React-rendererdebug + - React-utils + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core + - RNReanimated/reanimated/apple (= 3.16.5) + - Yoga + - RNReanimated/reanimated/apple (3.16.5): + - DoubleConversion + - glog + - hermes-engine + - RCT-Folly (= 2024.01.01.00) + - RCTRequired + - RCTTypeSafety + - React-Codegen + - React-Core + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-ImageManager + - React-NativeModulesApple + - React-RCTFabric + - React-rendererdebug + - React-utils + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core + - Yoga + - RNReanimated/worklets (3.16.5): - DoubleConversion - glog - hermes-engine @@ -2030,7 +2096,7 @@ SPEC CHECKSUMS: RNInAppBrowser: e36d6935517101ccba0e875bac8ad7b0cb655364 RNKeychain: ff836453cba46938e0e9e4c22e43d43fa2c90333 RNQuickAction: 6d404a869dc872cde841ad3147416a670d13fa93 - RNReanimated: d093daf3973a7ee9f77c10a9337e10390b2969e2 + RNReanimated: 73acffa7201bc9caee34b6f26878342cc9d8ab47 RNShare: 0fad69ae2d71de9d1f7b9a43acf876886a6cb99c RNSVG: 43b64ed39c14ce830d840903774154ca0c1f27ec SocketRocket: abac6f5de4d4d62d24e11868d7a2f427e0ef940d diff --git a/apps/native/app/package.json b/apps/native/app/package.json index 3ebb950c5cba..f742ee2bb587 100644 --- a/apps/native/app/package.json +++ b/apps/native/app/package.json @@ -90,7 +90,7 @@ "react-native-pdf": "6.7.5", "react-native-quick-actions": "0.3.13", "react-native-quick-base64": "2.1.2", - "react-native-reanimated": "3.12.1", + "react-native-reanimated": "3.16.5", "react-native-share": "10.2.1", "react-native-spotlight-search": "2.0.0", "react-native-svg": "15.2.0", diff --git a/apps/native/app/src/screens/passkey/passkey.tsx b/apps/native/app/src/screens/passkey/passkey.tsx index a6ba79951324..ead1271ebc47 100644 --- a/apps/native/app/src/screens/passkey/passkey.tsx +++ b/apps/native/app/src/screens/passkey/passkey.tsx @@ -150,7 +150,10 @@ export const PasskeyScreen: NavigationFunctionComponent<{ - openBrowser('https://island.is/adgangslyklar', componentId) + openBrowser( + 'https://island.is/innskraning-umbod-og-adgangsstyring-a-island-is#innskraning-med-adgangslykli-i-island-is-appinu', + componentId, + ) } > diff --git a/apps/portals/my-pages/src/components/Loaders/AuthOverlay/AuthOverlay.tsx b/apps/portals/my-pages/src/components/Loaders/AuthOverlay/AuthOverlay.tsx index 79e6410f2d8f..f186fe7a5d17 100644 --- a/apps/portals/my-pages/src/components/Loaders/AuthOverlay/AuthOverlay.tsx +++ b/apps/portals/my-pages/src/components/Loaders/AuthOverlay/AuthOverlay.tsx @@ -2,11 +2,11 @@ import { Text } from '@island.is/island-ui/core' import { useLocale } from '@island.is/localization' import { m } from '@island.is/portals/my-pages/core' -import { useBff } from '@island.is/react-spa/bff' +import { useAuth } from '@island.is/react-spa/bff' import * as styles from './AuthOverlay.css' const AuthOverlay = () => { - const { authState } = useBff() + const { authState } = useAuth() const { formatMessage } = useLocale() if (authState === 'switching') diff --git a/apps/services/auth/ids-api/infra/ids-api.ts b/apps/services/auth/ids-api/infra/ids-api.ts index 1afda547b717..b4f06d72ee64 100644 --- a/apps/services/auth/ids-api/infra/ids-api.ts +++ b/apps/services/auth/ids-api/infra/ids-api.ts @@ -100,6 +100,11 @@ export const serviceSetup = (): ServiceBuilder<'services-auth-ids-api'> => { staging: 'digitaliceland', dev: 'digitaliceland', }, + ALSO_USE_FAKE_USER_API: { + dev: 'true', + staging: 'false', + prod: 'false', + }, }) .secrets({ ZENDESK_CONTACT_FORM_EMAIL: '/k8s/api/ZENDESK_CONTACT_FORM_EMAIL', diff --git a/apps/services/auth/ids-api/src/app/app.module.ts b/apps/services/auth/ids-api/src/app/app.module.ts index b1cfb1b1506c..16198e21f08d 100644 --- a/apps/services/auth/ids-api/src/app/app.module.ts +++ b/apps/services/auth/ids-api/src/app/app.module.ts @@ -13,6 +13,7 @@ import { NationalRegistryV3ClientConfig } from '@island.is/clients/national-regi import { CompanyRegistryConfig } from '@island.is/clients/rsk/company-registry' import { SyslumennClientConfig } from '@island.is/clients/syslumenn' import { UserProfileClientConfig } from '@island.is/clients/user-profile' +import { ZendeskServiceConfig } from '@island.is/clients/zendesk' import { AuditModule } from '@island.is/nest/audit' import { ConfigModule, @@ -35,7 +36,6 @@ import { ResourcesModule } from './resources/resources.module' import { TranslationModule } from './translation/translation.module' import { UserProfileModule } from './user-profile/user-profile.module' import { UsersModule } from './users/users.module' -import { ZendeskServiceConfig } from '@island.is/clients/zendesk' @Module({ imports: [ diff --git a/apps/services/auth/ids-api/src/app/user-profile/user-profile.service.ts b/apps/services/auth/ids-api/src/app/user-profile/user-profile.service.ts index 626b782bb437..9479bd021332 100644 --- a/apps/services/auth/ids-api/src/app/user-profile/user-profile.service.ts +++ b/apps/services/auth/ids-api/src/app/user-profile/user-profile.service.ts @@ -1,4 +1,5 @@ -import { Inject, Injectable } from '@nestjs/common' +import { Inject, Injectable, Optional } from '@nestjs/common' +import { ConfigService } from '@nestjs/config' import { AuthMiddleware } from '@island.is/auth-nest-tools' import { FetchError } from '@island.is/clients/middlewares' @@ -30,6 +31,7 @@ type CountryFormatter = { of: (countryCode: string) => string } @Injectable() export class UserProfileService { + alsoUseFakeApi: boolean // REMOVE these ignores after upgrading to TypeScript 4.5 // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore @@ -45,7 +47,12 @@ export class UserProfileService { private companyRegistryApi: CompanyRegistryClientService, @Inject(LOGGER_PROVIDER) private logger: Logger, - ) {} + @Optional() + readonly configService?: ConfigService, + ) { + this.alsoUseFakeApi = + configService?.get('ALSO_USE_FAKE_USER_API') ?? false + } userProfileApiWithAuth(auth: Auth) { return this.userProfileApi.withMiddleware(new AuthMiddleware(auth)) @@ -123,6 +130,7 @@ export class UserProfileService { const individual = await this.nationalRegistryV3.getAllDataIndividual( auth.nationalId, false, + this.alsoUseFakeApi, ) if (!individual) { diff --git a/apps/services/bff/src/app/modules/auth/auth.service.ts b/apps/services/bff/src/app/modules/auth/auth.service.ts index 4c8ee5b5b02b..282cbf868f7b 100644 --- a/apps/services/bff/src/app/modules/auth/auth.service.ts +++ b/apps/services/bff/src/app/modules/auth/auth.service.ts @@ -277,14 +277,24 @@ export class AuthService { }) } - let loginAttemptData: LoginAttemptData | undefined + const loginAttemptCacheKey = this.cacheService.createSessionKeyType( + 'attempt', + query.state, + ) + // Get login attempt data from the cache + const loginAttemptData = await this.cacheService.get( + loginAttemptCacheKey, + // Do not throw an error if the key is not found + false, + ) - try { - // Get login attempt from cache - loginAttemptData = await this.cacheService.get( - this.cacheService.createSessionKeyType('attempt', query.state), - ) + if (!loginAttemptData) { + this.logger.warn(this.cacheService.createKeyError(loginAttemptCacheKey)) + return this.redirectWithError(res) + } + + try { // Get tokens and user information from the authorization code const tokenResponse = await this.idsService.getTokens({ code: query.code, diff --git a/apps/services/bff/src/app/modules/user/user.controller.spec.ts b/apps/services/bff/src/app/modules/user/user.controller.spec.ts index dba1a6918e0a..a6dfc9d72ef6 100644 --- a/apps/services/bff/src/app/modules/user/user.controller.spec.ts +++ b/apps/services/bff/src/app/modules/user/user.controller.spec.ts @@ -230,5 +230,117 @@ describe('UserController', () => { profile: expiredTokenResponse.userProfile, }) }) + + it('should not refresh token when token exists but is not expired', async () => { + // Arrange - Set up login attempt in cache + mockCacheStore.set( + `attempt::${mockConfig.name}::${SID_VALUE}`, + createLoginAttempt(mockConfig), + ) + + // Initialize session + await server.get('/login') + await server + .get('/callbacks/login') + .set('Cookie', [`${SESSION_COOKIE_NAME}=${SID_VALUE}`]) + .query({ code: 'some_code', state: SID_VALUE }) + + // Set valid (not expired) token in cache + const validTokenResponse = { + ...mockCachedTokenResponse, + accessTokenExp: Date.now() + 1000, // Future expiration + } + mockCacheStore.set( + `current::${mockConfig.name}::${SID_VALUE}`, + validTokenResponse, + ) + + // Act + const res = await server + .get('/user') + .query({ refresh: 'true' }) + .set('Cookie', [`${SESSION_COOKIE_NAME}=${SID_VALUE}`]) + + // Assert + expect(mockTokenRefreshService.refreshToken).not.toHaveBeenCalled() + expect(res.status).toEqual(HttpStatus.OK) + expect(res.body).toEqual({ + scopes: validTokenResponse.scopes, + profile: validTokenResponse.userProfile, + }) + }) + + it('should refresh token only when all conditions are met (token exists, is expired, and refresh=true)', async () => { + // Arrange - Set up login attempt in cache + mockCacheStore.set( + `attempt::${mockConfig.name}::${SID_VALUE}`, + createLoginAttempt(mockConfig), + ) + + const testCases = [ + { + exists: true, + expired: true, + refresh: true, + shouldCallRefresh: true, + }, + { + exists: true, + expired: true, + refresh: false, + shouldCallRefresh: false, + }, + { + exists: true, + expired: false, + refresh: true, + shouldCallRefresh: false, + }, + { + exists: false, + expired: true, + refresh: true, + shouldCallRefresh: false, + }, + ] + + for (const testCase of testCases) { + // Reset mocks + jest.clearAllMocks() + mockCacheStore.clear() + + if (testCase.exists) { + const tokenResponse = { + ...mockCachedTokenResponse, + accessTokenExp: testCase.expired + ? Date.now() - 1000 // Expired + : Date.now() + 1000, // Not expired + } + mockCacheStore.set( + `current::${mockConfig.name}::${SID_VALUE}`, + tokenResponse, + ) + } + + // Act + const res = await server + .get('/user') + .query({ refresh: testCase.refresh.toString() }) + .set('Cookie', [`${SESSION_COOKIE_NAME}=${SID_VALUE}`]) + + // Assert + if (testCase.shouldCallRefresh) { + expect(mockTokenRefreshService.refreshToken).toHaveBeenCalled() + } else { + expect(mockTokenRefreshService.refreshToken).not.toHaveBeenCalled() + } + + if (testCase.exists) { + expect(res.status).toEqual(HttpStatus.OK) + } else { + expect(res.status).toEqual(HttpStatus.UNAUTHORIZED) + } + } + }) }) }) diff --git a/apps/services/bff/src/app/modules/user/user.service.ts b/apps/services/bff/src/app/modules/user/user.service.ts index 4babb4df7a4e..74f576a5d8aa 100644 --- a/apps/services/bff/src/app/modules/user/user.service.ts +++ b/apps/services/bff/src/app/modules/user/user.service.ts @@ -5,6 +5,7 @@ import { BffUser } from '@island.is/shared/types' import { SESSION_COOKIE_NAME } from '../../constants/cookies' import { ErrorService } from '../../services/error.service' +import { hasTimestampExpiredInMS } from '../../utils/has-timestamp-expired-in-ms' import { CachedTokenResponse } from '../auth/auth.types' import { TokenRefreshService } from '../auth/token-refresh.service' import { CacheService } from '../cache/cache.service' @@ -58,7 +59,11 @@ export class UserService { false, ) - if (cachedTokenResponse && refresh) { + if ( + cachedTokenResponse && + hasTimestampExpiredInMS(cachedTokenResponse.accessTokenExp) && + refresh + ) { cachedTokenResponse = await this.tokenRefreshService.refreshToken({ sid, encryptedRefreshToken: cachedTokenResponse.encryptedRefreshToken, diff --git a/apps/services/endorsements/api/migrations/20241216113500-add-ownerName-column.js b/apps/services/endorsements/api/migrations/20241216113500-add-ownerName-column.js new file mode 100644 index 000000000000..7afadcf304a4 --- /dev/null +++ b/apps/services/endorsements/api/migrations/20241216113500-add-ownerName-column.js @@ -0,0 +1,12 @@ +module.exports = { + up: async (queryInterface, Sequelize) => { + await queryInterface.addColumn('endorsement_list', 'owner_name', { + type: Sequelize.STRING, + allowNull: true, + }) + }, + + down: async (queryInterface, Sequelize) => { + await queryInterface.removeColumn('endorsement_list', 'owner_name') + }, +} diff --git a/apps/services/endorsements/api/src/app/modules/endorsementList/endorsementList.model.ts b/apps/services/endorsements/api/src/app/modules/endorsementList/endorsementList.model.ts index 82b4c591cea8..8f00e8d7ee57 100644 --- a/apps/services/endorsements/api/src/app/modules/endorsementList/endorsementList.model.ts +++ b/apps/services/endorsements/api/src/app/modules/endorsementList/endorsementList.model.ts @@ -85,6 +85,13 @@ export class EndorsementList extends Model { }) owner!: string + @ApiProperty() + @Column({ + type: DataType.STRING, + allowNull: true, + }) + ownerName?: string + @ApiProperty() @Column({ type: DataType.BOOLEAN, diff --git a/apps/services/endorsements/api/src/app/modules/endorsementList/endorsementList.service.ts b/apps/services/endorsements/api/src/app/modules/endorsementList/endorsementList.service.ts index 3624f7b1b88f..5f5b4bb71cb6 100644 --- a/apps/services/endorsements/api/src/app/modules/endorsementList/endorsementList.service.ts +++ b/apps/services/endorsements/api/src/app/modules/endorsementList/endorsementList.service.ts @@ -247,7 +247,11 @@ export class EndorsementListService { ]) } this.logger.info(`Creating endorsement list: ${list.title}`) - const endorsementList = await this.endorsementListModel.create({ ...list }) + const ownerName = await this.fetchOwnerNameFromRegistry(list.owner) + const endorsementList = await this.endorsementListModel.create({ + ...list, + ownerName, + }) if (process.env.NODE_ENV === 'production') { await this.emailCreated(endorsementList) @@ -305,6 +309,10 @@ export class EndorsementListService { throw new NotFoundException(['This endorsement list does not exist.']) } owner = endorsementList.owner + // Use stored ownerName if available + if (endorsementList.ownerName) { + return endorsementList.ownerName + } } try { @@ -953,4 +961,19 @@ export class EndorsementListService { ) } } + + private async fetchOwnerNameFromRegistry( + nationalId: string, + ): Promise { + try { + const person = await this.nationalRegistryApiV3.getName(nationalId) + return person?.fulltNafn ? person.fulltNafn : '' + } catch (error) { + this.logger.error('Failed to fetch owner name from NationalRegistry', { + error: error.message, + nationalId, + }) + return '' + } + } } diff --git a/apps/services/user-notification/src/assets/images/en-button-open.png b/apps/services/user-notification/src/assets/images/en-button-open.png index ab0144dc9ec9..b5ce25afbdbc 100644 Binary files a/apps/services/user-notification/src/assets/images/en-button-open.png and b/apps/services/user-notification/src/assets/images/en-button-open.png differ diff --git a/apps/services/user-notification/src/assets/images/is-button-open.png b/apps/services/user-notification/src/assets/images/is-button-open.png index 5d2a07e9db64..0d800da8faf6 100644 Binary files a/apps/services/user-notification/src/assets/images/is-button-open.png and b/apps/services/user-notification/src/assets/images/is-button-open.png differ diff --git a/apps/skilavottord/web/graphql/errorLink.ts b/apps/skilavottord/web/graphql/errorLink.ts index 59cdc715ed61..15c86f40a958 100644 --- a/apps/skilavottord/web/graphql/errorLink.ts +++ b/apps/skilavottord/web/graphql/errorLink.ts @@ -1,5 +1,5 @@ import { onError, ErrorResponse } from '@apollo/client/link/error' -import { signIn, signOut } from 'next-auth/client' +import { signIn } from 'next-auth/client' import { toast } from '@island.is/island-ui/core' @@ -22,7 +22,10 @@ export default onError(({ graphQLErrors, networkError }: ErrorResponse) => { }) } return - } else if (errorCodes.includes('FORBIDDEN')) { + } else if ( + errorCodes.includes('FORBIDDEN') || + (graphQLErrors[0]?.extensions as any)?.response?.error === 'NOT_FOUND' + ) { return } diff --git a/apps/skilavottord/web/screens/DeregisterVehicle/Confirm/Confirm.tsx b/apps/skilavottord/web/screens/DeregisterVehicle/Confirm/Confirm.tsx index a8b25824b009..c102ea78bf04 100644 --- a/apps/skilavottord/web/screens/DeregisterVehicle/Confirm/Confirm.tsx +++ b/apps/skilavottord/web/screens/DeregisterVehicle/Confirm/Confirm.tsx @@ -133,6 +133,9 @@ const Confirm: FC> = () => { SkilavottordVehicleReadyToDeregisteredQuery, { variables: { permno: id }, + onError: (_err) => { + // Do nothing error handled in ErrorLink + }, }, ) diff --git a/apps/skilavottord/web/screens/DeregisterVehicle/Overview/Overview.tsx b/apps/skilavottord/web/screens/DeregisterVehicle/Overview/Overview.tsx index 859ecd9b4dbf..ae383ea2a2f9 100644 --- a/apps/skilavottord/web/screens/DeregisterVehicle/Overview/Overview.tsx +++ b/apps/skilavottord/web/screens/DeregisterVehicle/Overview/Overview.tsx @@ -1,34 +1,32 @@ -import React, { FC, useContext, useEffect, useRef } from 'react' -import Link from 'next/link' -import { useRouter } from 'next/router' import { useQuery } from '@apollo/client' import gql from 'graphql-tag' +import Link from 'next/link' +import { useRouter } from 'next/router' +import React, { FC, useContext, useEffect, useRef } from 'react' import { Box, - Stack, - Text, BreadcrumbsDeprecated as Breadcrumbs, Button, GridColumn, LoadingDots, + Stack, + Text, } from '@island.is/island-ui/core' -import { useI18n } from '@island.is/skilavottord-web/i18n' -import { UserContext } from '@island.is/skilavottord-web/context' import { hasPermission } from '@island.is/skilavottord-web/auth/utils' import { - Sidenav, NotFound, PartnerPageLayout, + Sidenav, } from '@island.is/skilavottord-web/components' +import { UserContext } from '@island.is/skilavottord-web/context' import { - RecyclingPartner, - RecyclingRequest, - Vehicle, Query, Role, + Vehicle, } from '@island.is/skilavottord-web/graphql/schema' +import { useI18n } from '@island.is/skilavottord-web/i18n' import { BASE_PATH } from '@island.is/skilavottord/consts' import { CarsTable } from './components/CarsTable' diff --git a/apps/skilavottord/web/utils/roleUtils.ts b/apps/skilavottord/web/utils/roleUtils.ts index 2cf4bb6cfe9b..793c56126f3f 100644 --- a/apps/skilavottord/web/utils/roleUtils.ts +++ b/apps/skilavottord/web/utils/roleUtils.ts @@ -12,7 +12,9 @@ export const getRoleTranslation = (role: Role, locale: Locale): string => { case 'recyclingFund': return locale === 'is' ? 'Úrvinnslusjóður' : 'Recycling Fund' case 'recyclingCompanyAdmin': - return locale === 'is' ? 'Mótökuaðili umsýsla' : 'Recycling Company Admin' + return locale === 'is' + ? 'Móttökuaðili umsýsla' + : 'Recycling Company Admin' default: return startCase(role) } diff --git a/apps/skilavottord/ws/src/app/modules/recyclingRequest/recyclingRequest.service.ts b/apps/skilavottord/ws/src/app/modules/recyclingRequest/recyclingRequest.service.ts index b84bedcff8ea..afb5ea568a87 100644 --- a/apps/skilavottord/ws/src/app/modules/recyclingRequest/recyclingRequest.service.ts +++ b/apps/skilavottord/ws/src/app/modules/recyclingRequest/recyclingRequest.service.ts @@ -1,4 +1,9 @@ -import { Inject, Injectable, forwardRef } from '@nestjs/common' +import { + Inject, + Injectable, + NotFoundException, + forwardRef, +} from '@nestjs/common' import { HttpService } from '@nestjs/axios' import { InjectModel } from '@nestjs/sequelize' import format from 'date-fns/format' @@ -159,8 +164,12 @@ export class RecyclingRequestService { ) } } else { - throw new Error( - `Could not find any requestType for vehicle's number: ${loggedPermno} in database`, + this.logger.warn( + `car-recycling: Could not find any requestType for vehicle's number: ${loggedPermno} in database from partner ${user.partnerId}`, + ) + throw new NotFoundException( + `Could not find any requestType for vehicle's number: ${loggedPermno} in database from partner ${user.partnerId}`, + 'NOT_FOUND', ) } @@ -173,6 +182,10 @@ export class RecyclingRequestService { } return res } catch (err) { + if (err instanceof NotFoundException) { + throw err + } + throw new Error( `Failed on getVehicleInfoToDeregistered request from partner ${user.partnerId} with error: ${err}`, ) diff --git a/apps/web/components/ChatPanel/LiveChatIncChatPanel/LiveChatIncChatPanel.tsx b/apps/web/components/ChatPanel/LiveChatIncChatPanel/LiveChatIncChatPanel.tsx index 303b4036f181..116fec059775 100644 --- a/apps/web/components/ChatPanel/LiveChatIncChatPanel/LiveChatIncChatPanel.tsx +++ b/apps/web/components/ChatPanel/LiveChatIncChatPanel/LiveChatIncChatPanel.tsx @@ -38,7 +38,12 @@ export const LiveChatIncChatPanel = ({ const n = useNamespace(namespace) useEffect(() => { - if (!hasButtonBeenClicked && !showLauncher) { + const queryParam = new URLSearchParams(window.location.search).get('wa_lid') + if ( + !hasButtonBeenClicked && + !showLauncher && + !(queryParam && ['t10', 't11'].includes(queryParam)) + ) { return () => { // No need for cleanup if we don't initialize widget } diff --git a/apps/web/components/Organization/Wrapper/OrganizationWrapper.tsx b/apps/web/components/Organization/Wrapper/OrganizationWrapper.tsx index 9c68d0398745..02e5d0341ada 100644 --- a/apps/web/components/Organization/Wrapper/OrganizationWrapper.tsx +++ b/apps/web/components/Organization/Wrapper/OrganizationWrapper.tsx @@ -618,6 +618,13 @@ export const OrganizationHeader: React.FC< logoImageClassName={styles.logoLarge} /> ) + case 'rannis': + return ( + + ) default: return } diff --git a/apps/web/components/PlazaCard/PlazaCard.css.ts b/apps/web/components/PlazaCard/PlazaCard.css.ts deleted file mode 100644 index bb5b75f34928..000000000000 --- a/apps/web/components/PlazaCard/PlazaCard.css.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { style } from '@vanilla-extract/css' - -export const container = style({ - maxWidth: '476px', -}) diff --git a/apps/web/components/ServiceWeb/Forms/StandardForm/StandardForm.tsx b/apps/web/components/ServiceWeb/Forms/StandardForm/StandardForm.tsx index 3f469edd3828..3054bbc88e70 100644 --- a/apps/web/components/ServiceWeb/Forms/StandardForm/StandardForm.tsx +++ b/apps/web/components/ServiceWeb/Forms/StandardForm/StandardForm.tsx @@ -26,7 +26,10 @@ import { Stack, Text, } from '@island.is/island-ui/core' -import { InputController } from '@island.is/shared/form-fields' +import { + CheckboxController, + InputController, +} from '@island.is/shared/form-fields' import { sortAlpha } from '@island.is/shared/utils' import { ContentLanguage, @@ -42,6 +45,7 @@ import { GET_SUPPORT_SEARCH_RESULTS_QUERY } from '@island.is/web/screens/queries import { FiskistofaCategories, SjukratryggingarCategories, + VinnueftirlitidCategories, } from '@island.is/web/screens/ServiceWeb/Forms/utils' import { getServiceWebSearchTagQuery } from '@island.is/web/screens/ServiceWeb/utils' @@ -93,6 +97,14 @@ const labels: Record = { malsnumer_ef_til_stadar: 'Málsnúmer (ef til staðar)', faedingardagur_eda_kennitala_malsadila: 'Fæðingardagur/Kennitala málsaðila', skipaskrarnumer: 'Skipaskrárnúmer', + vinnuvelanumer_kaupanda: 'Vinnuvélanúmer kaupanda', + vinnuvelanumer_seljanda: 'Vinnuvélanúmer seljanda', + vinnuvelanumer_vegna_skodunar: 'Vinnuvélanúmer vegna skoðunar', + stadsetning_taekis: 'Staðsetning tækis', + stadsetning_verkstadar: 'Staðsetning verkstaðar', + nafn_fyrirtaekis: 'Nafn fyrirtækis', + starfsstod: 'Starfsstöð', + oska_eftir_vernd_uppljostrara: 'Óska eftir vernd uppljóstrara', } // these should be skipped in the message itself @@ -154,6 +166,35 @@ const BasicInput = ({ ) } +interface BasicCheckboxProps { + name: keyof typeof labels + label: string +} + +const BasicCheckbox = ({ name, label }: BasicCheckboxProps) => { + const { + formState: { errors }, + register, + } = useFormContext() + + return ( + + ) +} + const MIN_SEARCH_QUERY_LENGTH = 1 export const StandardForm = ({ @@ -482,6 +523,129 @@ export const StandardForm = ({ ) break + case VinnueftirlitidCategories.NAMSKEID: + case VinnueftirlitidCategories.VINNUSLYS: + case VinnueftirlitidCategories.VINNUVELARETTINDI: + case VinnueftirlitidCategories.VINNUVERND: + case VinnueftirlitidCategories.MARKADSEFTIRLIT: + case VinnueftirlitidCategories.EKKO_OG_SAMSKIPTI: + case VinnueftirlitidCategories.LOG_OG_REGLUGERDIR: + case VinnueftirlitidCategories.LEYFI_OG_UMSAGNIR: + case VinnueftirlitidCategories.ONNUR_THJONUSTA: + fields = ( + + + + ) + break + case VinnueftirlitidCategories.SKRANING_OG_SKODUN_VINNUVELA: + fields = ( + <> + + + + + + + + + + + + + + + + + ) + break + case VinnueftirlitidCategories.MANNVIRKJAGERD: + fields = ( + <> + + + + + + + + ) + break + case VinnueftirlitidCategories.VINNUADSTADA: + fields = ( + <> + + + + + + + + ) + break default: break } @@ -571,7 +735,11 @@ export const StandardForm = ({ const label = labels[k] const value = values[k] - if (label && value) { + if ( + label && + ((Array.isArray(value) && value.length > 0) || + (!Array.isArray(value) && Boolean(value))) + ) { message += `${label}:\n${value}\n\n` } diff --git a/apps/web/components/ServiceWeb/Forms/StandardForm/types.ts b/apps/web/components/ServiceWeb/Forms/StandardForm/types.ts index 26ca5c2e89a1..0934e1dc2baf 100644 --- a/apps/web/components/ServiceWeb/Forms/StandardForm/types.ts +++ b/apps/web/components/ServiceWeb/Forms/StandardForm/types.ts @@ -1,12 +1,14 @@ import type { FiskistofaCategories, SjukratryggingarCategories, + VinnueftirlitidCategories, } from '@island.is/web/screens/ServiceWeb/Forms/utils' export type CategoryId = | SyslumennCategories | SjukratryggingarCategories | FiskistofaCategories + | VinnueftirlitidCategories export enum SyslumennCategories { FJOLSKYLDUMAL = '4vQ4htPOAZvzcXBcjx06SH', diff --git a/apps/web/components/real.ts b/apps/web/components/real.ts index e03cf0f7843f..bcf7523b139d 100644 --- a/apps/web/components/real.ts +++ b/apps/web/components/real.ts @@ -12,7 +12,6 @@ */ export * from './Card/Card' -export * from './PlazaCard/PlazaCard' export * from './Header/Header' export * from './SearchInput/SearchInput' export * from './LanguageToggler/LanguageToggler' diff --git a/apps/web/pages/en/grants-plaza/grant/[id].ts b/apps/web/pages/en/grants-plaza/grant/[id].ts new file mode 100644 index 000000000000..bc85b78454d8 --- /dev/null +++ b/apps/web/pages/en/grants-plaza/grant/[id].ts @@ -0,0 +1,12 @@ +import withApollo from '@island.is/web/graphql/withApollo' +import { withLocale } from '@island.is/web/i18n' +import GrantSinglePage from '@island.is/web/screens/Grants/Grant/Grant' +import { getServerSidePropsWrapper } from '@island.is/web/utils/getServerSidePropsWrapper' +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore make web strict +// +const Screen = withApollo(withLocale('en')(GrantSinglePage)) + +export default Screen + +export const getServerSideProps = getServerSidePropsWrapper(Screen) diff --git a/apps/web/pages/en/grants-plaza/grants/index.ts b/apps/web/pages/en/grants-plaza/grants/index.ts new file mode 100644 index 000000000000..15cf49a9aa93 --- /dev/null +++ b/apps/web/pages/en/grants-plaza/grants/index.ts @@ -0,0 +1,12 @@ +import withApollo from '@island.is/web/graphql/withApollo' +import { withLocale } from '@island.is/web/i18n' +import GrantsSearchResults from '@island.is/web/screens/Grants/SearchResults/SearchResults' +import { getServerSidePropsWrapper } from '@island.is/web/utils/getServerSidePropsWrapper' +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore make web strict +// +const Screen = withApollo(withLocale('en')(GrantsSearchResults)) + +export default Screen + +export const getServerSideProps = getServerSidePropsWrapper(Screen) diff --git a/apps/web/pages/en/grants-plaza/index.ts b/apps/web/pages/en/grants-plaza/index.ts new file mode 100644 index 000000000000..a95dff22d022 --- /dev/null +++ b/apps/web/pages/en/grants-plaza/index.ts @@ -0,0 +1,11 @@ +import withApollo from '@island.is/web/graphql/withApollo' +import { withLocale } from '@island.is/web/i18n' +import GrantsHome from '@island.is/web/screens/Grants/Home/GrantsHome' +import { getServerSidePropsWrapper } from '@island.is/web/utils/getServerSidePropsWrapper' +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore make web strict +const Screen = withApollo(withLocale('en')(GrantsHome)) + +export default Screen + +export const getServerSideProps = getServerSidePropsWrapper(Screen) diff --git a/apps/web/screens/Grants/Grant/Grant.tsx b/apps/web/screens/Grants/Grant/Grant.tsx index 1a5f16e475fe..03184ecdfccc 100644 --- a/apps/web/screens/Grants/Grant/Grant.tsx +++ b/apps/web/screens/Grants/Grant/Grant.tsx @@ -105,7 +105,8 @@ const GrantSinglePage: CustomScreen = ({ grant, locale }) => { backgroundColor="blue" cta={{ disabled: !grant.applicationUrl?.slug, - label: formatMessage(m.single.apply), + label: + grant.applicationButtonLabel ?? formatMessage(m.single.apply), onClick: () => router.push(grant.applicationUrl?.slug ?? ''), icon: 'open', iconType: 'outline', @@ -139,26 +140,21 @@ const GrantSinglePage: CustomScreen = ({ grant, locale }) => { ) : undefined} {grant.howToApply?.length ? ( - - {formatMessage(m.single.howToApply)} - - {webRichText( - grant.howToApply as SliceType[], - undefined, - locale, - )} + <> + + {formatMessage(m.single.howToApply)} + + {webRichText( + grant.howToApply as SliceType[], + undefined, + locale, + )} + - - ) : undefined} - {grant.applicationDeadline?.length ? ( - - {webRichText( - grant.applicationDeadline as SliceType[], - undefined, - locale, - )} - + + ) : undefined} + {grant.applicationHints?.length ? ( {webRichText( diff --git a/apps/web/screens/Grants/Grant/GrantSidebar.tsx b/apps/web/screens/Grants/Grant/GrantSidebar.tsx index c785d595a2b1..5a1941ee5b2a 100644 --- a/apps/web/screens/Grants/Grant/GrantSidebar.tsx +++ b/apps/web/screens/Grants/Grant/GrantSidebar.tsx @@ -1,6 +1,14 @@ import { useMemo } from 'react' +import { useIntl } from 'react-intl' -import { Box, Button, LinkV2, Stack, Text } from '@island.is/island-ui/core' +import { + Box, + BoxProps, + Button, + LinkV2, + Stack, + Text, +} from '@island.is/island-ui/core' import { Locale } from '@island.is/shared/types' import { isDefined } from '@island.is/shared/utils' import { InstitutionPanel } from '@island.is/web/components' @@ -8,8 +16,7 @@ import { Grant } from '@island.is/web/graphql/schema' import { LinkType, useLinkResolver } from '@island.is/web/hooks' import { m } from '../messages' -import { useLocale } from '@island.is/localization' -import { generateStatusTag } from '../utils' +import { generateStatusTag, parseStatus } from '../utils' interface Props { grant: Grant @@ -30,9 +37,28 @@ const generateLine = (heading: string, content?: React.ReactNode) => { ) } +const generateSidebarPanel = ( + data: Array, + background: BoxProps['background'], +) => { + if (!data.length) { + return undefined + } + return ( + + {data} + + ) +} + export const GrantSidebar = ({ grant, locale }: Props) => { const { linkResolver } = useLinkResolver() - const { formatMessage } = useLocale() + const { formatMessage } = useIntl() + + const status = useMemo( + () => parseStatus(grant, formatMessage, locale), + [grant, formatMessage, locale], + ) const detailPanelData = useMemo( () => @@ -72,22 +98,19 @@ export const GrantSidebar = ({ grant, locale }: Props) => { {grant.typeTag?.title} ) : undefined, ), - generateLine( - formatMessage(m.single.deadline), - grant?.applicationDeadlineStatus ? ( - {grant.applicationDeadlineStatus} - ) : undefined, - ), generateLine( formatMessage(m.single.status), grant?.status ? ( - {generateStatusTag(grant.status, formatMessage)?.label} + { + generateStatusTag(status.applicationStatus, formatMessage) + ?.label + } ) : undefined, ), ].filter(isDefined) ?? [], - [grant, formatMessage, linkResolver], + [grant, formatMessage, linkResolver, status], ) const filesPanelData = useMemo( @@ -100,6 +123,7 @@ export const GrantSidebar = ({ grant, locale }: Props) => { return ( @@ -113,6 +137,35 @@ export const GrantSidebar = ({ grant, locale }: Props) => { [grant.files], ) + const supportLinksPanelData = useMemo( + () => + grant.supportLinks + ?.map((link) => { + if (!link.url || !link.text || !link.id) { + return null + } + return ( + + + + ) + }) + .filter(isDefined) ?? [], + [grant.supportLinks], + ) + return ( { img={grant.fund?.parentOrganization.logo?.url} locale={locale} /> - {detailPanelData.length ? ( - - {detailPanelData} - - ) : undefined} - {filesPanelData.length ? ( - - {filesPanelData} - - ) : undefined} + {generateSidebarPanel(detailPanelData, 'blue100')} + {generateSidebarPanel(filesPanelData, 'red100')} + {generateSidebarPanel(supportLinksPanelData, 'purple100')} ) } diff --git a/apps/web/screens/Grants/Home/GrantsHome.tsx b/apps/web/screens/Grants/Home/GrantsHome.tsx index 83ed0453f013..0b75b23ec399 100644 --- a/apps/web/screens/Grants/Home/GrantsHome.tsx +++ b/apps/web/screens/Grants/Home/GrantsHome.tsx @@ -42,8 +42,9 @@ const GrantsHomePage: CustomScreen = ({ locale, customPageData, }) => { - const { formatMessage } = useIntl() + const intl = useIntl() const { linkResolver } = useLinkResolver() + const { formatMessage } = intl const baseUrl = linkResolver('styrkjatorg', [], locale).href const searchUrl = linkResolver('styrkjatorgsearch', [], locale).href diff --git a/apps/web/screens/Grants/SearchResults/SearchResults.tsx b/apps/web/screens/Grants/SearchResults/SearchResults.tsx index 1dbb89da54d9..4902b1229a2b 100644 --- a/apps/web/screens/Grants/SearchResults/SearchResults.tsx +++ b/apps/web/screens/Grants/SearchResults/SearchResults.tsx @@ -1,4 +1,4 @@ -import { useCallback, useEffect, useMemo, useState } from 'react' +import { ReactNode, useCallback, useEffect, useMemo, useState } from 'react' import { useIntl } from 'react-intl' import { useWindowSize } from 'react-use' import debounce from 'lodash/debounce' @@ -16,6 +16,7 @@ import { BreadCrumbItem, Breadcrumbs, FilterInput, + Pagination, Text, } from '@island.is/island-ui/core' import { theme } from '@island.is/island-ui/theme' @@ -55,9 +56,11 @@ export interface SearchState { organization?: Array } +const PAGE_SIZE = 8 + const GrantsSearchResultsPage: CustomScreen = ({ locale, - initialGrants, + initialGrantList, tags, }) => { const { formatMessage } = useIntl() @@ -67,7 +70,12 @@ const GrantsSearchResultsPage: CustomScreen = ({ const parentUrl = linkResolver('styrkjatorg', [], locale).href const currentUrl = linkResolver('styrkjatorgsearch', [], locale).href - const [grants, setGrants] = useState>(initialGrants ?? []) + const [grants, setGrants] = useState>( + initialGrantList?.items ?? [], + ) + const [totalHits, setTotalHits] = useState( + initialGrantList?.total ?? 0, + ) const [searchState, setSearchState] = useState() const [initialRender, setInitialRender] = useState(true) @@ -89,7 +97,7 @@ const GrantsSearchResultsPage: CustomScreen = ({ const organizations = searchParams.getAll('organization') setSearchState({ - page: page ? Number.parseInt(page) : undefined, + page: page ? Number.parseInt(page) : 1, query: searchParams.get('query') ?? undefined, status: statuses.length ? statuses : undefined, category: categories.length ? categories : undefined, @@ -98,6 +106,13 @@ const GrantsSearchResultsPage: CustomScreen = ({ }) }, []) + const totalPages = useMemo(() => { + if (!totalHits) { + return + } + return totalHits > PAGE_SIZE ? Math.ceil(totalHits / PAGE_SIZE) : 1 + }, [totalHits]) + const updateUrl = useCallback(() => { if (!searchState) { return @@ -134,7 +149,7 @@ const GrantsSearchResultsPage: CustomScreen = ({ organizations: searchState?.organization, page: searchState?.page, search: searchState?.query, - size: 8, + size: PAGE_SIZE, statuses: searchState?.status, types: searchState?.type, }, @@ -143,6 +158,7 @@ const GrantsSearchResultsPage: CustomScreen = ({ .then((res) => { if (res.data) { setGrants(res.data.getGrants.items) + setTotalHits(res.data.getGrants.total) } else if (res.error) { setGrants([]) console.error('Error fetching grants', res.error) @@ -199,7 +215,7 @@ const GrantsSearchResultsPage: CustomScreen = ({ const onResetFilter = () => { setSearchState({ - page: undefined, + page: 1, query: undefined, status: undefined, category: undefined, @@ -210,18 +226,18 @@ const GrantsSearchResultsPage: CustomScreen = ({ } const hitsMessage = useMemo(() => { - if (!grants) { + if (!totalHits) { return } - if (grants.length === 1) { + if (totalHits === 1) { return formatMessage(m.search.resultFound, { - arg: {grants.length}, + arg: {totalHits}, }) } return formatMessage(m.search.resultsFound, { - arg: {grants.length}, + arg: {totalHits}, }) - }, [formatMessage, grants]) + }, [formatMessage, totalHits]) return ( = ({ locale={locale} /> + {totalPages && totalPages > 1 ? ( + + ( + { + updateSearchStateValue('page', page) + }} + > + {children} + + )} + /> + + ) : undefined} )} {isMobile && ( @@ -335,19 +373,19 @@ const GrantsSearchResultsPage: CustomScreen = ({ interface GrantsHomeProps { locale: Locale - initialGrants?: Array + initialGrantList?: GrantList tags?: Array } const GrantsSearchResults: CustomScreen = ({ - initialGrants, + initialGrantList, tags, customPageData, locale, }) => { return ( { }, }), ]) + return { - initialGrants: getGrants.items, + initialGrantList: getGrants, tags: getGenericTagsInTagGroups ?? undefined, locale: locale as Locale, themeConfig: { diff --git a/apps/web/screens/Grants/SearchResults/SearchResultsContent.tsx b/apps/web/screens/Grants/SearchResults/SearchResultsContent.tsx index 071b7f063483..b95daf770f97 100644 --- a/apps/web/screens/Grants/SearchResults/SearchResultsContent.tsx +++ b/apps/web/screens/Grants/SearchResults/SearchResultsContent.tsx @@ -1,19 +1,17 @@ +import { useState } from 'react' import { useIntl } from 'react-intl' import { useWindowSize } from 'react-use' import format from 'date-fns/format' -import { useRouter } from 'next/router' -import { Box, Inline, Text } from '@island.is/island-ui/core' +import { Box, Button, InfoCardGrid, Text } from '@island.is/island-ui/core' import { theme } from '@island.is/island-ui/theme' -import { useLocale } from '@island.is/localization' import { Locale } from '@island.is/shared/types' import { isDefined } from '@island.is/shared/utils' -import { PlazaCard } from '@island.is/web/components' import { Grant } from '@island.is/web/graphql/schema' import { useLinkResolver } from '@island.is/web/hooks' import { m } from '../messages' -import { generateStatusTag } from '../utils' +import { generateStatusTag, parseStatus } from '../utils' interface Props { grants?: Array @@ -22,90 +20,111 @@ interface Props { } export const SearchResultsContent = ({ grants, subheader, locale }: Props) => { - const { formatMessage } = useLocale() - const router = useRouter() + const { formatMessage } = useIntl() const { linkResolver } = useLinkResolver() const { width } = useWindowSize() const isMobile = width <= theme.breakpoints.md const isTablet = width <= theme.breakpoints.lg && width > theme.breakpoints.md + const [isGridLayout, setIsGridLayout] = useState(true) + return ( <> {!isMobile && ( - + {subheader} + )} {grants?.length ? ( - - {grants?.map((grant) => { - if (!grant) { - return null - } + { + if (!grant || !grant.applicationId) { + return null + } + + const status = parseStatus(grant, formatMessage, locale) - return ( - - {grant.applicationId && ( - { - router.push( - linkResolver( - 'styrkjatorggrant', - [grant?.applicationId ?? ''], - locale, - ).href, - ) - }, - icon: 'arrowForward', - }} - detailLines={[ - grant.dateFrom && grant.dateTo - ? { - icon: 'calendar' as const, - text: `${format( - new Date(grant.dateFrom), - 'dd.MM.', - )}-${format(new Date(grant.dateTo), 'dd.MM.yyyy')}`, - } - : null, - grant.applicationDeadlineStatus - ? { - icon: 'time' as const, - //todo: fix when the text is ready - text: grant.applicationDeadlineStatus, - } - : undefined, - grant.categoryTags - ? { - icon: 'informationCircle' as const, - text: grant.categoryTags - .map((ct) => ct.title) - .filter(isDefined) - .join(', '), - } - : undefined, - ].filter(isDefined)} - /> - )} - - ) - })} - + return { + id: grant.id, + eyebrow: grant.fund?.title ?? grant.name ?? '', + subEyebrow: grant.fund?.parentOrganization?.title, + title: grant.name ?? '', + description: grant.description ?? '', + logo: + grant.fund?.featuredImage?.url ?? + grant.fund?.parentOrganization?.logo?.url ?? + '', + logoAlt: + grant.fund?.featuredImage?.title ?? + grant.fund?.parentOrganization?.logo?.title ?? + '', + tags: status.applicationStatus + ? [ + generateStatusTag( + status.applicationStatus, + formatMessage, + ), + ].filter(isDefined) + : undefined, + link: { + label: formatMessage(m.general.seeMore), + href: linkResolver( + 'styrkjatorggrant', + [grant?.applicationId ?? ''], + locale, + ).href, + }, + detailLines: [ + grant.dateFrom && grant.dateTo + ? { + icon: 'calendar' as const, + text: `${format( + new Date(grant.dateFrom), + 'dd.MM.yyyy', + )} - ${format(new Date(grant.dateTo), 'dd.MM.yyyy')}`, + } + : null, + { + icon: 'time' as const, + text: status.deadlineStatus, + }, + grant.categoryTags + ? { + icon: 'informationCircle' as const, + text: grant.categoryTags + .map((ct) => ct.title) + .filter(isDefined) + .join(', '), + } + : undefined, + ].filter(isDefined), + } + }) + .filter(isDefined) ?? [] + } + /> ) : undefined} {!grants?.length && ( { - switch (status) { - case GrantStatus.Open: +interface Status { + applicationStatus: 'open' | 'closed' | 'unknown' + deadlineStatus: string + note?: string +} + +const formatDate = ( + date: Date, + locale: Locale, + stringFormat = 'dd.MMMM yyyy', +): string | undefined => { + try { + return format(date, stringFormat, { + locale: locale === 'is' ? localeIS : localeEn, + }) + } catch (e) { + console.warn('Error formatting date') + return + } +} + +export const containsTimePart = (date: string) => date.includes('T') + +export const parseStatus = ( + grant: Grant, + formatMessage: IntlShape['formatMessage'], + locale: Locale, +): Status => { + switch (grant.status) { + case GrantStatus.Closed: { + const date = grant.dateTo + ? formatDate(new Date(grant.dateTo), locale) + : undefined + return { + applicationStatus: 'closed', + deadlineStatus: date + ? formatMessage( + containsTimePart(date) + ? m.search.applicationWasOpenToAndWith + : m.search.applicationWasOpenTo, + { + arg: date, + }, + ) + : formatMessage(m.search.applicationClosed), + note: grant.statusText ?? undefined, + } + } + case GrantStatus.ClosedOpeningSoon: { + const date = grant.dateFrom + ? formatDate(new Date(grant.dateFrom), locale) + : undefined return { - label: formatMessage(m.search.applicationOpen), - variant: 'mint', + applicationStatus: 'closed', + deadlineStatus: date + ? formatMessage(m.search.applicationOpensAt, { + arg: date, + }) + : formatMessage(m.search.applicationClosed), + note: grant.statusText ?? undefined, } - case GrantStatus.Closed: + } + case GrantStatus.ClosedOpeningSoonWithEstimation: { + const date = grant.dateFrom + ? formatDate(new Date(grant.dateFrom), locale, 'MMMM yyyy') + : undefined return { - label: formatMessage(m.search.applicationClosed), - variant: 'rose', + applicationStatus: 'closed', + deadlineStatus: date + ? formatMessage(m.search.applicationEstimatedOpensAt, { + arg: date, + }) + : formatMessage(m.search.applicationClosed), + note: grant.statusText ?? undefined, } - case GrantStatus.SeeDescription: + } + case GrantStatus.ClosedWithNote: { return { - label: formatMessage(m.search.applicationSeeDescription), - variant: 'purple', + applicationStatus: 'closed', + deadlineStatus: formatMessage(m.search.applicationSeeDescription), + note: grant.statusText ?? undefined, } - default: - return + } + case GrantStatus.AlwaysOpen: { + return { + applicationStatus: 'open', + deadlineStatus: formatMessage(m.search.applicationAlwaysOpen), + note: grant.statusText ?? undefined, + } + } + case GrantStatus.Open: { + const date = grant.dateTo + ? formatDate(new Date(grant.dateTo), locale, 'dd.MMMM.') + : undefined + return { + applicationStatus: 'open', + deadlineStatus: date + ? formatMessage( + containsTimePart(date) + ? m.search.applicationOpensToWithDay + : m.search.applicationOpensTo, + { + arg: date, + }, + ) + : formatMessage(m.search.applicationOpen), + note: grant.statusText ?? undefined, + } + } + case GrantStatus.OpenWithNote: { + return { + applicationStatus: 'open', + deadlineStatus: formatMessage(m.search.applicationSeeDescription), + note: grant.statusText ?? undefined, + } + } + default: { + return { + applicationStatus: 'unknown', + deadlineStatus: '', + } + } } } + +export const generateStatusTag = ( + status: Status['applicationStatus'], + formatMessage: IntlShape['formatMessage'], +) => + status !== 'unknown' + ? { + label: + status === 'open' + ? formatMessage(m.search.applicationOpen) + : formatMessage(m.search.applicationClosed), + variant: status === 'open' ? ('mint' as const) : ('rose' as const), + } + : undefined diff --git a/apps/web/screens/Organization/SocialInsuranceAdministration/PensionCalculator.css.ts b/apps/web/screens/Organization/SocialInsuranceAdministration/PensionCalculator.css.ts index 66a268028923..8550d211f92b 100644 --- a/apps/web/screens/Organization/SocialInsuranceAdministration/PensionCalculator.css.ts +++ b/apps/web/screens/Organization/SocialInsuranceAdministration/PensionCalculator.css.ts @@ -46,3 +46,7 @@ export const yearSelectContainer = style({ md: { width: '204px' }, }), }) + +export const noWrap = style({ + flexWrap: 'nowrap', +}) diff --git a/apps/web/screens/Organization/SocialInsuranceAdministration/PensionCalculator.tsx b/apps/web/screens/Organization/SocialInsuranceAdministration/PensionCalculator.tsx index af85afcd89db..2dfab0c78d4e 100644 --- a/apps/web/screens/Organization/SocialInsuranceAdministration/PensionCalculator.tsx +++ b/apps/web/screens/Organization/SocialInsuranceAdministration/PensionCalculator.tsx @@ -1,4 +1,4 @@ -import { PropsWithChildren, useMemo, useState } from 'react' +import { PropsWithChildren, useEffect, useMemo, useState } from 'react' import { Controller, FormProvider, useForm } from 'react-hook-form' import { useIntl } from 'react-intl' import add from 'date-fns/add' @@ -50,6 +50,7 @@ import { GET_ORGANIZATION_PAGE_QUERY, GET_ORGANIZATION_QUERY, } from '../../queries' +import { PensionCalculatorTitle } from './PensionCalculatorTitle' import { PensionCalculatorWrapper } from './PensionCalculatorWrapper' import { translationStrings } from './translationStrings' import { @@ -57,6 +58,8 @@ import { convertToQueryParams, extractSlug, getDateOfCalculationsOptions, + is2025FormPreviewActive, + NEW_SYSTEM_TAKES_PLACE_DATE, } from './utils' import * as styles from './PensionCalculator.css' @@ -70,7 +73,10 @@ const hasDisabilityAssessment = ( ) => { return ( typeOfBasePension === BasePensionType.Disability || - typeOfBasePension === BasePensionType.Rehabilitation + typeOfBasePension === BasePensionType.Rehabilitation || + typeOfBasePension === BasePensionType.NewSystemDisability || + typeOfBasePension === BasePensionType.NewSystemPartialDisability || + typeOfBasePension === BasePensionType.NewSystemMedicalAndRehabilitation ) } @@ -131,6 +137,15 @@ const PensionCalculator: CustomScreen = ({ defaultValues, }) + const [dateOfCalculations, setDateOfCalculations] = useQueryState( + 'dateOfCalculations', + { + defaultValue: + methods.formState.defaultValues?.dateOfCalculations ?? + dateOfCalculationsOptions[0].value, + }, + ) + const currencyInputMaxLength = customPageData?.configJson?.currencyInputMaxLength ?? 14 @@ -165,7 +180,47 @@ const PensionCalculator: CustomScreen = ({ ? maxMonthPensionDelayIfBorn1951OrEarlier : maxMonthPensionDelayIfBornAfter1951 + const allCalculatorsOptions = useMemo(() => { + const options = [...dateOfCalculationsOptions] + + if (is2025FormPreviewActive(customPageData)) { + options.unshift({ + label: formatMessage(translationStrings.form2025PreviewLabel), + value: NEW_SYSTEM_TAKES_PLACE_DATE.toISOString(), + }) + } + + return options + }, [customPageData, dateOfCalculationsOptions, formatMessage]) + + const isNewSystemActive = + is2025FormPreviewActive(customPageData) && + dateOfCalculations === NEW_SYSTEM_TAKES_PLACE_DATE.toISOString() + const basePensionTypeOptions = useMemo[]>(() => { + if (isNewSystemActive) { + const options = [ + { + label: formatMessage( + translationStrings.basePensionNewSystemDisabilityLabel, + ), + value: BasePensionType.NewSystemDisability, + }, + { + label: formatMessage( + translationStrings.basePensionNewSystemPartialDisabilityLabel, + ), + value: BasePensionType.NewSystemPartialDisability, + }, + { + label: formatMessage( + translationStrings.basePensionNewSystemMedicalAndRehabilitation, + ), + value: BasePensionType.NewSystemMedicalAndRehabilitation, + }, + ] + return options + } const options = [ { label: formatMessage(translationStrings.basePensionRetirementLabel), @@ -190,9 +245,10 @@ const PensionCalculator: CustomScreen = ({ value: BasePensionType.HalfRetirement, }, ] + options.sort(sortAlpha('label')) return options - }, [formatMessage]) + }, [formatMessage, isNewSystemActive]) const hasSpouseOptions = useMemo[]>(() => { return [ @@ -265,15 +321,6 @@ const PensionCalculator: CustomScreen = ({ ] }, [formatMessage]) - const [dateOfCalculations, setDateOfCalculations] = useQueryState( - 'dateOfCalculations', - { - defaultValue: - methods.formState.defaultValues?.dateOfCalculations ?? - dateOfCalculationsOptions[0].value, - }, - ) - const { linkResolver } = useLinkResolver() const router = useRouter() @@ -355,6 +402,30 @@ const PensionCalculator: CustomScreen = ({ ] }, [formatMessage]) + // Make sure we never enter an invalid state + useEffect(() => { + if (isNewSystemActive) { + if ( + typeOfBasePension !== BasePensionType.NewSystemDisability && + typeOfBasePension !== BasePensionType.NewSystemPartialDisability && + typeOfBasePension !== BasePensionType.NewSystemMedicalAndRehabilitation + ) { + methods.setValue( + 'typeOfBasePension', + BasePensionType.NewSystemDisability, + ) + } + } else { + if ( + typeOfBasePension === BasePensionType.NewSystemDisability || + typeOfBasePension === BasePensionType.NewSystemPartialDisability || + typeOfBasePension === BasePensionType.NewSystemMedicalAndRehabilitation + ) { + methods.setValue('typeOfBasePension', BasePensionType.Retirement) + } + } + }, [isNewSystemActive, methods, typeOfBasePension]) + const birthYearOptions = useMemo[]>(() => { const today = new Date() const options: Option[] = [] @@ -411,10 +482,17 @@ const PensionCalculator: CustomScreen = ({ return options }, [defaultPensionDate, maxMonthPensionDelay, maxMonthPensionHurry]) - const title = `${formatMessage(translationStrings.mainTitle)} ${ - dateOfCalculationsOptions.find((o) => o.value === dateOfCalculations) - ?.label ?? dateOfCalculationsOptions[0].label - }` + const title = `${formatMessage( + isNewSystemActive + ? translationStrings.form2025PreviewMainTitle + : translationStrings.mainTitle, + )}` + const titlePostfix = `${( + allCalculatorsOptions.find((o) => o.value === dateOfCalculations)?.label ?? + dateOfCalculationsOptions[0].label + ).toLowerCase()}` + + const titleVariant = isNewSystemActive ? 'h2' : 'h1' const startMonthOptions = useMemo(() => { if (!defaultPensionDate) { @@ -477,9 +555,12 @@ const PensionCalculator: CustomScreen = ({ > - - {title} - + {formatMessage(translationStrings.isTurnedOff)} @@ -500,9 +581,12 @@ const PensionCalculator: CustomScreen = ({ - - {title} - + = ({ translationStrings.dateOfCalculationsPlaceholder, )} size="sm" - options={dateOfCalculationsOptions} + options={allCalculatorsOptions} onSelect={(option) => { if (option) { setDateOfCalculations(option.value) + if (isNewSystemActive) { + if ( + option.value === + NEW_SYSTEM_TAKES_PLACE_DATE.toISOString() + ) { + // Date is being moved to the new system date + methods.setValue( + 'typeOfBasePension', + BasePensionType.NewSystemDisability, + ) + } else if ( + dateOfCalculations === + NEW_SYSTEM_TAKES_PLACE_DATE.toISOString() + ) { + // Date is being moved from new system date + methods.setValue( + 'typeOfBasePension', + BasePensionType.Retirement, + ) + } + } } }} /> @@ -827,6 +932,10 @@ const PensionCalculator: CustomScreen = ({ {(typeOfBasePension === BasePensionType.Disability || + typeOfBasePension === + BasePensionType.NewSystemDisability || + typeOfBasePension === + BasePensionType.NewSystemPartialDisability || typeOfBasePension === BasePensionType.Rehabilitation) && ( @@ -839,7 +948,11 @@ const PensionCalculator: CustomScreen = ({ } label={formatMessage( typeOfBasePension === - BasePensionType.Disability + BasePensionType.Disability || + typeOfBasePension === + BasePensionType.NewSystemDisability || + typeOfBasePension === + BasePensionType.NewSystemPartialDisability ? translationStrings.ageOfFirst75DisabilityAssessment : translationStrings.ageOfFirst75RehabilitationAssessment, )} diff --git a/apps/web/screens/Organization/SocialInsuranceAdministration/PensionCalculatorResults.tsx b/apps/web/screens/Organization/SocialInsuranceAdministration/PensionCalculatorResults.tsx index 8d0d36910b4a..a1f0dfe86979 100644 --- a/apps/web/screens/Organization/SocialInsuranceAdministration/PensionCalculatorResults.tsx +++ b/apps/web/screens/Organization/SocialInsuranceAdministration/PensionCalculatorResults.tsx @@ -1,4 +1,4 @@ -import { Fragment, useState } from 'react' +import { Fragment, useMemo, useState } from 'react' import { useIntl } from 'react-intl' import { @@ -51,6 +51,7 @@ import { GET_ORGANIZATION_QUERY, } from '../../queries' import { GET_PENSION_CALCULATION } from '../../queries/PensionCalculator' +import { PensionCalculatorTitle } from './PensionCalculatorTitle' import { PensionCalculatorWrapper } from './PensionCalculatorWrapper' import { translationStrings } from './translationStrings' import { @@ -58,7 +59,9 @@ import { convertToQueryParams, extractSlug, getDateOfCalculationsOptions, + is2025FormPreviewActive, is2025PreviewActive, + NEW_SYSTEM_TAKES_PLACE_DATE, } from './utils' import * as styles from './PensionCalculatorResults.css' @@ -285,11 +288,36 @@ const PensionCalculatorResults: CustomScreen = ({ const highlightedItems2025 = calculation2025.highlightedItems ?? [] - const title = `${formatMessage(translationStrings.mainTitle)} ${ - dateOfCalculationsOptions.find( + const allCalculatorsOptions = useMemo(() => { + const options = [...dateOfCalculationsOptions] + + if (is2025FormPreviewActive(customPageData)) { + options.unshift({ + label: formatMessage(translationStrings.form2025PreviewLabel), + value: NEW_SYSTEM_TAKES_PLACE_DATE.toISOString(), + }) + } + + return options + }, [customPageData, dateOfCalculationsOptions, formatMessage]) + + const isNewSystemActive = + is2025FormPreviewActive(customPageData) && + calculationInput.dateOfCalculations === + NEW_SYSTEM_TAKES_PLACE_DATE.toISOString() + + const title = `${formatMessage( + isNewSystemActive + ? translationStrings.form2025PreviewMainTitle + : translationStrings.mainTitle, + )}` + const titlePostfix = `${( + allCalculatorsOptions.find( (o) => o.value === calculationInput.dateOfCalculations, - )?.label ?? '' - }` + )?.label ?? dateOfCalculationsOptions[0].label + ).toLowerCase()}` + + const titleVariant = isNewSystemActive ? 'h2' : 'h1' const calculationIsPresent = typeof calculation.groups?.length === 'number' && @@ -334,9 +362,12 @@ const PensionCalculatorResults: CustomScreen = ({ > - - {title} - + {formatMessage(translationStrings.isTurnedOff)} @@ -357,9 +388,12 @@ const PensionCalculatorResults: CustomScreen = ({ - - {title} - + {formatMessage( diff --git a/apps/web/screens/Organization/SocialInsuranceAdministration/PensionCalculatorTitle.tsx b/apps/web/screens/Organization/SocialInsuranceAdministration/PensionCalculatorTitle.tsx new file mode 100644 index 000000000000..4a61eb3b61fb --- /dev/null +++ b/apps/web/screens/Organization/SocialInsuranceAdministration/PensionCalculatorTitle.tsx @@ -0,0 +1,45 @@ +import { useIntl } from 'react-intl' + +import { GridColumn, GridRow, Text } from '@island.is/island-ui/core' + +import { translationStrings } from './translationStrings' +import * as styles from './PensionCalculator.css' + +interface PensionCalculatorTitleProps { + isNewSystemActive: boolean + title: string + titlePostfix: string + titleVariant: 'h1' | 'h2' +} + +export const PensionCalculatorTitle = ({ + isNewSystemActive, + title, + titlePostfix, + titleVariant, +}: PensionCalculatorTitleProps) => { + const { formatMessage } = useIntl() + if (isNewSystemActive) + return ( + + + + + + + {title}
{titlePostfix}
+
+
+
+ ) + return ( + + {title} {titlePostfix} + + ) +} diff --git a/apps/web/screens/Organization/SocialInsuranceAdministration/translationStrings.ts b/apps/web/screens/Organization/SocialInsuranceAdministration/translationStrings.ts index 4c5373609c9f..89f5b13b9202 100644 --- a/apps/web/screens/Organization/SocialInsuranceAdministration/translationStrings.ts +++ b/apps/web/screens/Organization/SocialInsuranceAdministration/translationStrings.ts @@ -17,6 +17,12 @@ export const translationStrings = defineMessages({ defaultMessage: 'Þú vilt hefja töku eftir 67 ára aldur', description: 'Upplýsingar sem birtast ef þú vilt seinka töku ellilífeyris', }, + form2025PreviewLabel: { + id: 'web.pensionCalculator:form2025PreviewLabel', + defaultMessage: 'Eftir 1. september 2025', + description: + 'Valmöguleiki í dropdown fyrir "Allar reiknivélar" ef það á að leyfa eftir 1. sept 2025 preview', + }, results2025ImageUrl: { id: 'web.pensionCalculator:results2025ImageUrl', defaultMessage: @@ -54,6 +60,24 @@ export const translationStrings = defineMessages({ defaultMessage: 'Ellilífeyrir', description: 'Tegund lífeyris, Ellilífeyrir', }, + basePensionNewSystemDisabilityLabel: { + id: 'web.pensionCalculator:basePensionNewSystemDisabilityLabel', + defaultMessage: 'Örorkulífeyrir', + description: + 'Tegund lífeyris fyrir nýtt kerfi þann 1. sept 2025, Örorkulífeyrir', + }, + basePensionNewSystemPartialDisabilityLabel: { + id: 'web.pensionCalculator:basePensionNewSystemPartialDisabilityLabel', + defaultMessage: 'Hlutaörorkulífeyrir', + description: + 'Tegund lífeyris fyrir nýtt kerfi þann 1. sept 2025, Hlutaörorkulífeyrir', + }, + basePensionNewSystemMedicalAndRehabilitation: { + id: 'web.pensionCalculator:basePensionNewSystemMedicalAndRehabilitation', + defaultMessage: 'Sjúkra- og endurhæfing', + description: + 'Tegund lífeyris fyrir nýtt kerfi þann 1. sept 2025, Sjúkra- og endurhæfing', + }, basePensionFishermanRetirementLabel: { id: 'web.pensionCalculator:basePensionFishermanRetirementLabel', defaultMessage: 'Ellilífeyrir sjómanna', @@ -429,6 +453,11 @@ export const translationStrings = defineMessages({ defaultMessage: 'Reiknivél lífeyris', description: 'Aðal titill', }, + form2025PreviewMainTitle: { + id: 'web.pensionCalculator:form2025PreviewMainTitle', + defaultMessage: 'Reiknivél örorku- og endurhæfingargreiðslna', + description: 'Aðal titill fyrir nýju eftir 1. sept 2025 reiknivél', + }, resultDisclaimer: { id: 'web.pensionCalculator:resultDisclaimer', defaultMessage: @@ -596,6 +625,13 @@ export const translationStrings = defineMessages({ defaultMessage: 'Eftir 1. september 2025', description: 'Eftir 1. september 2025', }, + after1stSeptember2025IconUrl: { + id: 'web.pensionCalculator:after1stSeptember2025IconUrl', + defaultMessage: + 'https://images.ctfassets.net/8k0h54kbe6bj/5RIwKVet87Nm4ycltkzjnX/9c594855a9b2f90dde63766ee87a09ca/58dd40fbf365769d984be22a9b64bc29.png', + description: + 'Mynd vinstra megin við titil "Reiknivél örorku- og endurhæfingargreiðslna eftir 1. september 2025"', + }, after1stSeptember2025Calculate: { id: 'web.pensionCalculator:after1stSeptember2025Calculate', defaultMessage: 'Reikna', @@ -948,6 +984,38 @@ export const translationStrings = defineMessages({ defaultMessage: 'Örorkulífeyrir', description: 'Niðurstöðuskjár, Örorkulífeyrir 2025', }, + 'REIKNH.SJUKRAOGENDURH_HUPPBOT_2025': { + id: 'web.pensionCalculator:REIKNH.SJUKRAOGENDURH_HUPPBOT_2025', + defaultMessage: 'Sjúkra- og endurhæfingargreiðslur og heimilisuppbót', + description: + 'Niðurstöðuskjár, Sjúkra- og endurhæfingargreiðslur og heimilisuppbót', + }, + 'REIKNH.SJUKRAOGENDURH_2025': { + id: 'web.pensionCalculator:REIKNH.SJUKRAOGENDURH_2025', + defaultMessage: 'Sjúkra- og endurhæfingargreiðslur', + description: 'Niðurstöðuskjár, Sjúkra- og endurhæfingargreiðslur', + }, + 'REIKNH.HLUTAORORKA_ALDURSV_HUPPBOT_2025': { + id: 'web.pensionCalculator:REIKNH.HLUTAORORKA_ALDURSV_HUPPBOT_2025', + defaultMessage: 'Hlutaörorkulífeyrir, aldursviðbót og heimilisuppbót', + description: + 'Niðurstöðuskjár, Hlutaörorkulífeyrir, aldursviðbót og heimilisuppbót', + }, + 'REIKNH.HLUTAORORKA_ALDURSV_2025': { + id: 'web.pensionCalculator:REIKNH.HLUTAORORKA_ALDURSV_2025', + defaultMessage: 'Hlutaörorkulífeyrir og aldursviðbót', + description: 'Niðurstöðuskjár, Hlutaörorkulífeyrir og aldursviðbót', + }, + 'REIKNH.HLUTAORORKA_HUPPBOT_2025': { + id: 'web.pensionCalculator:REIKNH.HLUTAORORKA_HUPPBOT_2025', + defaultMessage: 'Hlutaörorkulífeyrir og heimilisuppbót', + description: 'Niðurstöðuskjár, Hlutaörorkulífeyrir og heimilisuppbót', + }, + 'REIKNH.HLUTAORORKA': { + id: 'web.pensionCalculator:REIKNH.HLUTAORORKA', + defaultMessage: 'Hlutaörorkulífeyrir', + description: 'Niðurstöðuskjár, Hlutaörorkulífeyrir', + }, highlighedResultItemHeadingForTotalAfterTaxFromTR: { id: 'web.pensionCalculator:REIKNH.highlighedResultItemHeadingForTotalAfterTaxFromTR', defaultMessage: 'Þar af greiðslur frá TR', diff --git a/apps/web/screens/Organization/SocialInsuranceAdministration/utils.ts b/apps/web/screens/Organization/SocialInsuranceAdministration/utils.ts index 722370dda5ab..fb8cad0b51dc 100644 --- a/apps/web/screens/Organization/SocialInsuranceAdministration/utils.ts +++ b/apps/web/screens/Organization/SocialInsuranceAdministration/utils.ts @@ -153,3 +153,9 @@ export const extractSlug = ( export const is2025PreviewActive = (customPageData?: CustomPage | null) => { return Boolean(customPageData?.configJson?.show2025Preview) } + +export const is2025FormPreviewActive = (customPageData?: CustomPage | null) => { + return Boolean(customPageData?.configJson?.show2025FormPreview) +} + +export const NEW_SYSTEM_TAKES_PLACE_DATE = new Date(2025, 8, 2) diff --git a/apps/web/screens/ServiceWeb/Forms/utils.ts b/apps/web/screens/ServiceWeb/Forms/utils.ts index e84d8a93ed75..4a0b84c7c836 100644 --- a/apps/web/screens/ServiceWeb/Forms/utils.ts +++ b/apps/web/screens/ServiceWeb/Forms/utils.ts @@ -97,6 +97,21 @@ export enum FiskistofaCategories { VEIDIHEIMILDIR = '1agbWJCHTDVfVR4yQZPaEK', } +export enum VinnueftirlitidCategories { + NAMSKEID = '41SeTRazu0qKIixRhWpDLA', + SKRANING_OG_SKODUN_VINNUVELA = '1ulMblBQwDkfSNgh2NyKpw', + VINNUSLYS = '3VY4skpcXo7XyniStyxrVc', + VINNUVELARETTINDI = '1AkjZQc1CO6hMPXYaLSqTw', + VINNUVERND = '4Wmxb25h9R7L0kuYsz19jG', + MARKADSEFTIRLIT = '61OI7gY23wC80mRRA4yrbA', + MANNVIRKJAGERD = '7fLoJqpyojUHgdDofIpqlU', + EKKO_OG_SAMSKIPTI = '3SAlg8Xt7AKBQFrGUCTkG1', + VINNUADSTADA = '7FPsjPxRHA2aIOUXY3Xr3V', + LOG_OG_REGLUGERDIR = '7vb5yId3HMigcXEDMYN9uN', + LEYFI_OG_UMSAGNIR = '7nLIjBeO5EovoPYwINWoyv', + ONNUR_THJONUSTA = 'fdkCIdREoNlYmgkr37DTl', +} + export const filterSupportCategories = ( supportCategories: SupportCategory[] | undefined, slug: string, diff --git a/apps/web/screens/queries/Grants.ts b/apps/web/screens/queries/Grants.ts index 22b40ec4d2cf..c62a073a363b 100644 --- a/apps/web/screens/queries/Grants.ts +++ b/apps/web/screens/queries/Grants.ts @@ -1,23 +1,24 @@ import gql from 'graphql-tag' + import { nestedFields, slices } from './fragments' export const GET_GRANTS_QUERY = gql` query GetGrants($input: GetGrantsInput!) { getGrants(input: $input) { + total items { id name description applicationId - applicationDeadlineStatus applicationUrl { slug type } dateFrom dateTo - isOpen status + statusText categoryTags { id title @@ -67,8 +68,11 @@ export const GET_GRANT_QUERY = gql` slug type } - applicationDeadlineStatus + applicationButtonLabel status + statusText + dateFrom + dateTo categoryTags { id title @@ -77,6 +81,12 @@ export const GET_GRANT_QUERY = gql` id title } + supportLinks { + id + text + url + date + } files { ...AssetFields } @@ -111,10 +121,6 @@ export const GET_GRANT_QUERY = gql` ...AllSlices ${nestedFields} } - applicationDeadline { - ...AllSlices - ${nestedFields} - } applicationHints { ...AllSlices ${nestedFields} diff --git a/charts/identity-server/values.dev.yaml b/charts/identity-server/values.dev.yaml index a5d5ce51e239..47834b587715 100644 --- a/charts/identity-server/values.dev.yaml +++ b/charts/identity-server/values.dev.yaml @@ -414,6 +414,7 @@ services-auth-delegation-api: services-auth-ids-api: enabled: true env: + ALSO_USE_FAKE_USER_API: 'true' CODE_OWNER: 'aranja' COMPANY_REGISTRY_REDIS_NODES: '["clustercfg.general-redis-cluster-group.5fzau3.euw1.cache.amazonaws.com:6379"]' COMPANY_REGISTRY_XROAD_PROVIDER_ID: 'IS-DEV/GOV/10006/Skatturinn/ft-v1' diff --git a/charts/identity-server/values.prod.yaml b/charts/identity-server/values.prod.yaml index 2f51a29e6326..a350ead4e04b 100644 --- a/charts/identity-server/values.prod.yaml +++ b/charts/identity-server/values.prod.yaml @@ -411,6 +411,7 @@ services-auth-delegation-api: services-auth-ids-api: enabled: true env: + ALSO_USE_FAKE_USER_API: 'false' CODE_OWNER: 'aranja' COMPANY_REGISTRY_REDIS_NODES: '["clustercfg.general-redis-cluster-group.dnugi2.euw1.cache.amazonaws.com:6379"]' COMPANY_REGISTRY_XROAD_PROVIDER_ID: 'IS/GOV/5402696029/Skatturinn/ft-v1' diff --git a/charts/identity-server/values.staging.yaml b/charts/identity-server/values.staging.yaml index 00cbc00e4a90..7f6ac4dcf3fb 100644 --- a/charts/identity-server/values.staging.yaml +++ b/charts/identity-server/values.staging.yaml @@ -36,8 +36,8 @@ auth-admin-web: cpuAverageUtilization: 90 nginxRequestsIrate: 5 replicas: - max: 10 - min: 2 + max: 3 + min: 1 image: repository: '821090935708.dkr.ecr.eu-west-1.amazonaws.com/auth-admin-web' ingress: @@ -59,9 +59,9 @@ auth-admin-web: progressDeadlineSeconds: 1200 pvcs: [] replicaCount: - default: 2 - max: 10 - min: 2 + default: 1 + max: 3 + min: 1 resources: limits: cpu: '400m' @@ -270,8 +270,8 @@ services-auth-admin-api: cpuAverageUtilization: 90 nginxRequestsIrate: 5 replicas: - max: 10 - min: 2 + max: 3 + min: 1 image: repository: '821090935708.dkr.ecr.eu-west-1.amazonaws.com/services-auth-admin-api' ingress: @@ -289,9 +289,9 @@ services-auth-admin-api: maxUnavailable: 1 pvcs: [] replicaCount: - default: 2 - max: 10 - min: 2 + default: 1 + max: 3 + min: 1 resources: limits: cpu: '400m' @@ -369,8 +369,8 @@ services-auth-delegation-api: cpuAverageUtilization: 90 nginxRequestsIrate: 5 replicas: - max: 10 - min: 2 + max: 3 + min: 1 image: repository: '821090935708.dkr.ecr.eu-west-1.amazonaws.com/services-auth-delegation-api' ingress: @@ -387,9 +387,9 @@ services-auth-delegation-api: maxUnavailable: 1 pvcs: [] replicaCount: - default: 2 - max: 10 - min: 2 + default: 1 + max: 3 + min: 1 resources: limits: cpu: '400m' @@ -414,6 +414,7 @@ services-auth-delegation-api: services-auth-ids-api: enabled: true env: + ALSO_USE_FAKE_USER_API: 'false' CODE_OWNER: 'aranja' COMPANY_REGISTRY_REDIS_NODES: '["clustercfg.general-redis-cluster-group.ab9ckb.euw1.cache.amazonaws.com:6379"]' COMPANY_REGISTRY_XROAD_PROVIDER_ID: 'IS-TEST/GOV/5402696029/Skatturinn/ft-v1' @@ -475,8 +476,8 @@ services-auth-ids-api: cpuAverageUtilization: 90 nginxRequestsIrate: 5 replicas: - max: 15 - min: 2 + max: 3 + min: 1 image: repository: '821090935708.dkr.ecr.eu-west-1.amazonaws.com/services-auth-ids-api' initContainer: @@ -521,9 +522,9 @@ services-auth-ids-api: maxUnavailable: 1 pvcs: [] replicaCount: - default: 2 - max: 15 - min: 2 + default: 1 + max: 3 + min: 1 resources: limits: cpu: '800m' @@ -659,8 +660,8 @@ services-auth-personal-representative: cpuAverageUtilization: 90 nginxRequestsIrate: 5 replicas: - max: 10 - min: 2 + max: 3 + min: 1 image: repository: '821090935708.dkr.ecr.eu-west-1.amazonaws.com/services-auth-personal-representative' ingress: @@ -677,9 +678,9 @@ services-auth-personal-representative: maxUnavailable: 1 pvcs: [] replicaCount: - default: 2 - max: 10 - min: 2 + default: 1 + max: 3 + min: 1 resources: limits: cpu: '400m' @@ -728,8 +729,8 @@ services-auth-personal-representative-public: cpuAverageUtilization: 90 nginxRequestsIrate: 5 replicas: - max: 10 - min: 2 + max: 3 + min: 1 image: repository: '821090935708.dkr.ecr.eu-west-1.amazonaws.com/services-auth-personal-representative-public' ingress: @@ -746,9 +747,9 @@ services-auth-personal-representative-public: maxUnavailable: 1 pvcs: [] replicaCount: - default: 2 - max: 10 - min: 2 + default: 1 + max: 3 + min: 1 resources: limits: cpu: '400m' @@ -823,8 +824,8 @@ services-auth-public-api: cpuAverageUtilization: 90 nginxRequestsIrate: 5 replicas: - max: 10 - min: 2 + max: 3 + min: 1 image: repository: '821090935708.dkr.ecr.eu-west-1.amazonaws.com/services-auth-public-api' ingress: @@ -845,9 +846,9 @@ services-auth-public-api: maxUnavailable: 1 pvcs: [] replicaCount: - default: 2 - max: 10 - min: 2 + default: 1 + max: 3 + min: 1 resources: limits: cpu: '400m' diff --git a/charts/islandis/values.staging.yaml b/charts/islandis/values.staging.yaml index 2cd78ddb6714..541ee602df90 100644 --- a/charts/islandis/values.staging.yaml +++ b/charts/islandis/values.staging.yaml @@ -35,8 +35,8 @@ air-discount-scheme-api: cpuAverageUtilization: 90 nginxRequestsIrate: 20 replicas: - max: 10 - min: 2 + max: 3 + min: 1 image: repository: '821090935708.dkr.ecr.eu-west-1.amazonaws.com/air-discount-scheme-api' ingress: @@ -58,9 +58,9 @@ air-discount-scheme-api: fsGroup: 65534 pvcs: [] replicaCount: - default: 2 - max: 10 - min: 2 + default: 1 + max: 3 + min: 1 resources: limits: cpu: '400m' @@ -123,8 +123,8 @@ air-discount-scheme-backend: cpuAverageUtilization: 90 nginxRequestsIrate: 20 replicas: - max: 10 - min: 2 + max: 3 + min: 1 image: repository: '821090935708.dkr.ecr.eu-west-1.amazonaws.com/air-discount-scheme-backend' ingress: @@ -170,9 +170,9 @@ air-discount-scheme-backend: maxUnavailable: 1 pvcs: [] replicaCount: - default: 2 - max: 10 - min: 2 + default: 1 + max: 3 + min: 1 resources: limits: cpu: '400m' @@ -223,8 +223,8 @@ air-discount-scheme-web: cpuAverageUtilization: 90 nginxRequestsIrate: 20 replicas: - max: 10 - min: 2 + max: 3 + min: 1 image: repository: '821090935708.dkr.ecr.eu-west-1.amazonaws.com/air-discount-scheme-web' ingress: @@ -249,9 +249,9 @@ air-discount-scheme-web: maxUnavailable: 1 pvcs: [] replicaCount: - default: 2 - max: 10 - min: 2 + default: 1 + max: 3 + min: 1 resources: limits: cpu: '200m' @@ -440,8 +440,8 @@ api: cpuAverageUtilization: 90 nginxRequestsIrate: 5 replicas: - max: 50 - min: 2 + max: 3 + min: 1 image: repository: '821090935708.dkr.ecr.eu-west-1.amazonaws.com/api' ingress: @@ -460,9 +460,9 @@ api: fsGroup: 65534 pvcs: [] replicaCount: - default: 2 - max: 50 - min: 2 + default: 1 + max: 3 + min: 1 resources: limits: cpu: '1200m' @@ -713,8 +713,8 @@ application-system-api: cpuAverageUtilization: 90 nginxRequestsIrate: 5 replicas: - max: 60 - min: 2 + max: 3 + min: 1 image: repository: '821090935708.dkr.ecr.eu-west-1.amazonaws.com/application-system-api' ingress: @@ -763,9 +763,9 @@ application-system-api: fsGroup: 65534 pvcs: [] replicaCount: - default: 2 - max: 60 - min: 2 + default: 1 + max: 3 + min: 1 resources: limits: cpu: '600m' @@ -1023,8 +1023,8 @@ consultation-portal: cpuAverageUtilization: 90 nginxRequestsIrate: 5 replicas: - max: 30 - min: 2 + max: 3 + min: 1 image: repository: '821090935708.dkr.ecr.eu-west-1.amazonaws.com/consultation-portal' ingress: @@ -1043,9 +1043,9 @@ consultation-portal: maxUnavailable: 1 pvcs: [] replicaCount: - default: 2 - max: 30 - min: 2 + default: 1 + max: 3 + min: 1 resources: limits: cpu: '400m' @@ -1471,8 +1471,8 @@ license-api: cpuAverageUtilization: 90 nginxRequestsIrate: 5 replicas: - max: 10 - min: 2 + max: 3 + min: 1 image: repository: '821090935708.dkr.ecr.eu-west-1.amazonaws.com/license-api' ingress: @@ -1489,9 +1489,9 @@ license-api: maxUnavailable: 1 pvcs: [] replicaCount: - default: 2 - max: 10 - min: 2 + default: 1 + max: 3 + min: 1 resources: limits: cpu: '400m' @@ -1576,8 +1576,8 @@ portals-admin: cpuAverageUtilization: 90 nginxRequestsIrate: 8 replicas: - max: 30 - min: 2 + max: 3 + min: 1 image: repository: '821090935708.dkr.ecr.eu-west-1.amazonaws.com/portals-admin' ingress: @@ -1596,9 +1596,9 @@ portals-admin: maxUnavailable: 1 pvcs: [] replicaCount: - default: 2 - max: 30 - min: 2 + default: 1 + max: 3 + min: 1 resources: limits: cpu: '400m' @@ -1742,7 +1742,7 @@ search-indexer-service: cpuAverageUtilization: 90 nginxRequestsIrate: 5 replicas: - max: 1 + max: 3 min: 1 image: repository: '821090935708.dkr.ecr.eu-west-1.amazonaws.com/services-search-indexer' @@ -1820,7 +1820,7 @@ search-indexer-service: pvcs: [] replicaCount: default: 1 - max: 1 + max: 3 min: 1 resources: limits: @@ -1873,8 +1873,8 @@ service-portal: cpuAverageUtilization: 90 nginxRequestsIrate: 5 replicas: - max: 30 - min: 2 + max: 3 + min: 1 image: repository: '821090935708.dkr.ecr.eu-west-1.amazonaws.com/service-portal' ingress: @@ -1893,9 +1893,9 @@ service-portal: maxUnavailable: 1 pvcs: [] replicaCount: - default: 2 - max: 30 - min: 2 + default: 1 + max: 3 + min: 1 resources: limits: cpu: '300m' @@ -1962,8 +1962,8 @@ service-portal-api: cpuAverageUtilization: 90 nginxRequestsIrate: 5 replicas: - max: 30 - min: 2 + max: 3 + min: 1 image: repository: '821090935708.dkr.ecr.eu-west-1.amazonaws.com/services-user-profile' ingress: @@ -2005,9 +2005,9 @@ service-portal-api: fsGroup: 65534 pvcs: [] replicaCount: - default: 2 - max: 30 - min: 2 + default: 1 + max: 3 + min: 1 resources: limits: cpu: '800m' @@ -2080,8 +2080,8 @@ services-bff-portals-admin: cpuAverageUtilization: 90 nginxRequestsIrate: 5 replicas: - max: 10 - min: 2 + max: 3 + min: 1 image: repository: '821090935708.dkr.ecr.eu-west-1.amazonaws.com/services-bff' ingress: @@ -2103,9 +2103,9 @@ services-bff-portals-admin: fsGroup: 65534 pvcs: [] replicaCount: - default: 2 - max: 10 - min: 2 + default: 1 + max: 3 + min: 1 resources: limits: cpu: '400m' @@ -2166,8 +2166,8 @@ services-bff-portals-my-pages: cpuAverageUtilization: 90 nginxRequestsIrate: 5 replicas: - max: 10 - min: 2 + max: 3 + min: 1 image: repository: '821090935708.dkr.ecr.eu-west-1.amazonaws.com/services-bff' ingress: @@ -2189,9 +2189,9 @@ services-bff-portals-my-pages: fsGroup: 65534 pvcs: [] replicaCount: - default: 2 - max: 10 - min: 2 + default: 1 + max: 3 + min: 1 resources: limits: cpu: '400m' @@ -2323,7 +2323,7 @@ services-sessions: cpuAverageUtilization: 90 nginxRequestsIrate: 5 replicas: - max: 10 + max: 3 min: 1 image: repository: '821090935708.dkr.ecr.eu-west-1.amazonaws.com/services-sessions' @@ -2342,7 +2342,7 @@ services-sessions: pvcs: [] replicaCount: default: 1 - max: 10 + max: 3 min: 1 resources: limits: @@ -2565,8 +2565,8 @@ services-university-gateway: cpuAverageUtilization: 90 nginxRequestsIrate: 5 replicas: - max: 10 - min: 2 + max: 3 + min: 1 image: repository: '821090935708.dkr.ecr.eu-west-1.amazonaws.com/services-university-gateway' ingress: @@ -2621,9 +2621,9 @@ services-university-gateway: fsGroup: 65534 pvcs: [] replicaCount: - default: 2 - max: 10 - min: 2 + default: 1 + max: 3 + min: 1 resources: limits: cpu: '200m' @@ -2755,8 +2755,8 @@ skilavottord-web: cpuAverageUtilization: 90 nginxRequestsIrate: 8 replicas: - max: 10 - min: 2 + max: 3 + min: 1 image: repository: '821090935708.dkr.ecr.eu-west-1.amazonaws.com/skilavottord-web' ingress: @@ -2775,9 +2775,9 @@ skilavottord-web: maxUnavailable: 1 pvcs: [] replicaCount: - default: 2 - max: 10 - min: 2 + default: 1 + max: 3 + min: 1 resources: limits: cpu: '400m' @@ -3155,7 +3155,7 @@ user-notification-worker: cpuAverageUtilization: 90 nginxRequestsIrate: 5 replicas: - max: 2 + max: 3 min: 1 image: repository: '821090935708.dkr.ecr.eu-west-1.amazonaws.com/services-user-notification' @@ -3190,7 +3190,7 @@ user-notification-worker: pvcs: [] replicaCount: default: 1 - max: 2 + max: 3 min: 1 resources: limits: @@ -3251,8 +3251,8 @@ web: cpuAverageUtilization: 90 nginxRequestsIrate: 5 replicas: - max: 50 - min: 2 + max: 3 + min: 1 image: repository: '821090935708.dkr.ecr.eu-west-1.amazonaws.com/web' ingress: @@ -3271,9 +3271,9 @@ web: maxUnavailable: 1 pvcs: [] replicaCount: - default: 2 - max: 50 - min: 2 + default: 1 + max: 3 + min: 1 resources: limits: cpu: '1000m' diff --git a/charts/judicial-system/values.staging.yaml b/charts/judicial-system/values.staging.yaml index e6b543a61ce6..6939b5a9fae4 100644 --- a/charts/judicial-system/values.staging.yaml +++ b/charts/judicial-system/values.staging.yaml @@ -53,8 +53,8 @@ judicial-system-api: cpuAverageUtilization: 90 nginxRequestsIrate: 8 replicas: - max: 10 - min: 2 + max: 3 + min: 1 image: repository: '821090935708.dkr.ecr.eu-west-1.amazonaws.com/judicial-system-api' ingress: @@ -78,9 +78,9 @@ judicial-system-api: fsGroup: 65534 pvcs: [] replicaCount: - default: 2 - max: 10 - min: 2 + default: 1 + max: 3 + min: 1 resources: limits: cpu: '350m' @@ -155,8 +155,8 @@ judicial-system-backend: cpuAverageUtilization: 90 nginxRequestsIrate: 5 replicas: - max: 10 - min: 2 + max: 3 + min: 1 image: repository: '821090935708.dkr.ecr.eu-west-1.amazonaws.com/judicial-system-backend' initContainer: @@ -189,9 +189,9 @@ judicial-system-backend: fsGroup: 65534 pvcs: [] replicaCount: - default: 2 - max: 10 - min: 2 + default: 1 + max: 3 + min: 1 resources: limits: cpu: '400m' @@ -413,7 +413,7 @@ judicial-system-scheduler: cpuAverageUtilization: 90 nginxRequestsIrate: 5 replicas: - max: 1 + max: 3 min: 1 image: repository: '821090935708.dkr.ecr.eu-west-1.amazonaws.com/judicial-system-scheduler' @@ -425,7 +425,7 @@ judicial-system-scheduler: pvcs: [] replicaCount: default: 1 - max: 1 + max: 3 min: 1 resources: limits: diff --git a/charts/services/air-discount-scheme-api/values.staging.yaml b/charts/services/air-discount-scheme-api/values.staging.yaml index 03dae66f38f1..b3ffdaf667ff 100644 --- a/charts/services/air-discount-scheme-api/values.staging.yaml +++ b/charts/services/air-discount-scheme-api/values.staging.yaml @@ -46,8 +46,8 @@ hpa: cpuAverageUtilization: 90 nginxRequestsIrate: 20 replicas: - max: 10 - min: 2 + max: 3 + min: 1 image: repository: '821090935708.dkr.ecr.eu-west-1.amazonaws.com/air-discount-scheme-api' ingress: @@ -69,9 +69,9 @@ podSecurityContext: fsGroup: 65534 pvcs: [] replicaCount: - default: 2 - max: 10 - min: 2 + default: 1 + max: 3 + min: 1 resources: limits: cpu: '400m' diff --git a/charts/services/air-discount-scheme-backend/values.staging.yaml b/charts/services/air-discount-scheme-backend/values.staging.yaml index 2e45fbac3401..503a736d94f1 100644 --- a/charts/services/air-discount-scheme-backend/values.staging.yaml +++ b/charts/services/air-discount-scheme-backend/values.staging.yaml @@ -57,8 +57,8 @@ hpa: cpuAverageUtilization: 90 nginxRequestsIrate: 20 replicas: - max: 10 - min: 2 + max: 3 + min: 1 image: repository: '821090935708.dkr.ecr.eu-west-1.amazonaws.com/air-discount-scheme-backend' ingress: @@ -104,9 +104,9 @@ podDisruptionBudget: maxUnavailable: 1 pvcs: [] replicaCount: - default: 2 - max: 10 - min: 2 + default: 1 + max: 3 + min: 1 resources: limits: cpu: '400m' diff --git a/charts/services/air-discount-scheme-web/values.staging.yaml b/charts/services/air-discount-scheme-web/values.staging.yaml index d160667b9dd5..7185fc6bcd41 100644 --- a/charts/services/air-discount-scheme-web/values.staging.yaml +++ b/charts/services/air-discount-scheme-web/values.staging.yaml @@ -45,8 +45,8 @@ hpa: cpuAverageUtilization: 90 nginxRequestsIrate: 20 replicas: - max: 10 - min: 2 + max: 3 + min: 1 image: repository: '821090935708.dkr.ecr.eu-west-1.amazonaws.com/air-discount-scheme-web' ingress: @@ -71,9 +71,9 @@ podDisruptionBudget: maxUnavailable: 1 pvcs: [] replicaCount: - default: 2 - max: 10 - min: 2 + default: 1 + max: 3 + min: 1 resources: limits: cpu: '200m' diff --git a/charts/services/api/values.staging.yaml b/charts/services/api/values.staging.yaml index d200690c8557..53c6e7b18726 100644 --- a/charts/services/api/values.staging.yaml +++ b/charts/services/api/values.staging.yaml @@ -189,8 +189,8 @@ hpa: cpuAverageUtilization: 90 nginxRequestsIrate: 5 replicas: - max: 50 - min: 2 + max: 3 + min: 1 image: repository: '821090935708.dkr.ecr.eu-west-1.amazonaws.com/api' ingress: @@ -209,9 +209,9 @@ podSecurityContext: fsGroup: 65534 pvcs: [] replicaCount: - default: 2 - max: 50 - min: 2 + default: 1 + max: 3 + min: 1 resources: limits: cpu: '1200m' diff --git a/charts/services/application-system-api/values.staging.yaml b/charts/services/application-system-api/values.staging.yaml index c47d9cd07c30..4b37d4cb9945 100644 --- a/charts/services/application-system-api/values.staging.yaml +++ b/charts/services/application-system-api/values.staging.yaml @@ -156,8 +156,8 @@ hpa: cpuAverageUtilization: 90 nginxRequestsIrate: 5 replicas: - max: 60 - min: 2 + max: 3 + min: 1 image: repository: '821090935708.dkr.ecr.eu-west-1.amazonaws.com/application-system-api' ingress: @@ -206,9 +206,9 @@ podSecurityContext: fsGroup: 65534 pvcs: [] replicaCount: - default: 2 - max: 60 - min: 2 + default: 1 + max: 3 + min: 1 resources: limits: cpu: '600m' diff --git a/charts/services/auth-admin-web/values.staging.yaml b/charts/services/auth-admin-web/values.staging.yaml index 846c0af6c998..44ac2b27f2d8 100644 --- a/charts/services/auth-admin-web/values.staging.yaml +++ b/charts/services/auth-admin-web/values.staging.yaml @@ -47,8 +47,8 @@ hpa: cpuAverageUtilization: 90 nginxRequestsIrate: 5 replicas: - max: 10 - min: 2 + max: 3 + min: 1 image: repository: '821090935708.dkr.ecr.eu-west-1.amazonaws.com/auth-admin-web' ingress: @@ -70,9 +70,9 @@ podDisruptionBudget: progressDeadlineSeconds: 1200 pvcs: [] replicaCount: - default: 2 - max: 10 - min: 2 + default: 1 + max: 3 + min: 1 resources: limits: cpu: '400m' diff --git a/charts/services/consultation-portal/values.staging.yaml b/charts/services/consultation-portal/values.staging.yaml index e3547fb54d2e..198c3aefabfb 100644 --- a/charts/services/consultation-portal/values.staging.yaml +++ b/charts/services/consultation-portal/values.staging.yaml @@ -46,8 +46,8 @@ hpa: cpuAverageUtilization: 90 nginxRequestsIrate: 5 replicas: - max: 30 - min: 2 + max: 3 + min: 1 image: repository: '821090935708.dkr.ecr.eu-west-1.amazonaws.com/consultation-portal' ingress: @@ -66,9 +66,9 @@ podDisruptionBudget: maxUnavailable: 1 pvcs: [] replicaCount: - default: 2 - max: 30 - min: 2 + default: 1 + max: 3 + min: 1 resources: limits: cpu: '400m' diff --git a/charts/services/judicial-system-api/values.staging.yaml b/charts/services/judicial-system-api/values.staging.yaml index 7533d12090a6..8ec818a14e50 100644 --- a/charts/services/judicial-system-api/values.staging.yaml +++ b/charts/services/judicial-system-api/values.staging.yaml @@ -53,8 +53,8 @@ hpa: cpuAverageUtilization: 90 nginxRequestsIrate: 8 replicas: - max: 10 - min: 2 + max: 3 + min: 1 image: repository: '821090935708.dkr.ecr.eu-west-1.amazonaws.com/judicial-system-api' ingress: @@ -78,9 +78,9 @@ podSecurityContext: fsGroup: 65534 pvcs: [] replicaCount: - default: 2 - max: 10 - min: 2 + default: 1 + max: 3 + min: 1 resources: limits: cpu: '350m' diff --git a/charts/services/judicial-system-backend/values.staging.yaml b/charts/services/judicial-system-backend/values.staging.yaml index 30787a83c52d..a4c0268de4d4 100644 --- a/charts/services/judicial-system-backend/values.staging.yaml +++ b/charts/services/judicial-system-backend/values.staging.yaml @@ -68,8 +68,8 @@ hpa: cpuAverageUtilization: 90 nginxRequestsIrate: 5 replicas: - max: 10 - min: 2 + max: 3 + min: 1 image: repository: '821090935708.dkr.ecr.eu-west-1.amazonaws.com/judicial-system-backend' initContainer: @@ -102,9 +102,9 @@ podSecurityContext: fsGroup: 65534 pvcs: [] replicaCount: - default: 2 - max: 10 - min: 2 + default: 1 + max: 3 + min: 1 resources: limits: cpu: '400m' diff --git a/charts/services/judicial-system-scheduler/values.staging.yaml b/charts/services/judicial-system-scheduler/values.staging.yaml index b62035e69488..c05114e58282 100644 --- a/charts/services/judicial-system-scheduler/values.staging.yaml +++ b/charts/services/judicial-system-scheduler/values.staging.yaml @@ -50,7 +50,7 @@ hpa: cpuAverageUtilization: 90 nginxRequestsIrate: 5 replicas: - max: 1 + max: 3 min: 1 image: repository: '821090935708.dkr.ecr.eu-west-1.amazonaws.com/judicial-system-scheduler' @@ -62,7 +62,7 @@ podSecurityContext: pvcs: [] replicaCount: default: 1 - max: 1 + max: 3 min: 1 resources: limits: diff --git a/charts/services/license-api/values.staging.yaml b/charts/services/license-api/values.staging.yaml index 6e7db7b9814d..81577da0aa8e 100644 --- a/charts/services/license-api/values.staging.yaml +++ b/charts/services/license-api/values.staging.yaml @@ -56,8 +56,8 @@ hpa: cpuAverageUtilization: 90 nginxRequestsIrate: 5 replicas: - max: 10 - min: 2 + max: 3 + min: 1 image: repository: '821090935708.dkr.ecr.eu-west-1.amazonaws.com/license-api' ingress: @@ -74,9 +74,9 @@ podDisruptionBudget: maxUnavailable: 1 pvcs: [] replicaCount: - default: 2 - max: 10 - min: 2 + default: 1 + max: 3 + min: 1 resources: limits: cpu: '400m' diff --git a/charts/services/portals-admin/values.staging.yaml b/charts/services/portals-admin/values.staging.yaml index 7db3b0717c80..e993af124894 100644 --- a/charts/services/portals-admin/values.staging.yaml +++ b/charts/services/portals-admin/values.staging.yaml @@ -43,8 +43,8 @@ hpa: cpuAverageUtilization: 90 nginxRequestsIrate: 8 replicas: - max: 30 - min: 2 + max: 3 + min: 1 image: repository: '821090935708.dkr.ecr.eu-west-1.amazonaws.com/portals-admin' ingress: @@ -63,9 +63,9 @@ podDisruptionBudget: maxUnavailable: 1 pvcs: [] replicaCount: - default: 2 - max: 30 - min: 2 + default: 1 + max: 3 + min: 1 resources: limits: cpu: '400m' diff --git a/charts/services/search-indexer-service/values.staging.yaml b/charts/services/search-indexer-service/values.staging.yaml index 39cebc125692..ba80482ce963 100644 --- a/charts/services/search-indexer-service/values.staging.yaml +++ b/charts/services/search-indexer-service/values.staging.yaml @@ -49,7 +49,7 @@ hpa: cpuAverageUtilization: 90 nginxRequestsIrate: 5 replicas: - max: 1 + max: 3 min: 1 image: repository: '821090935708.dkr.ecr.eu-west-1.amazonaws.com/services-search-indexer' @@ -127,7 +127,7 @@ progressDeadlineSeconds: 1500 pvcs: [] replicaCount: default: 1 - max: 1 + max: 3 min: 1 resources: limits: diff --git a/charts/services/service-portal-api/values.staging.yaml b/charts/services/service-portal-api/values.staging.yaml index f766121d5b5b..07671994d3f9 100644 --- a/charts/services/service-portal-api/values.staging.yaml +++ b/charts/services/service-portal-api/values.staging.yaml @@ -67,8 +67,8 @@ hpa: cpuAverageUtilization: 90 nginxRequestsIrate: 5 replicas: - max: 30 - min: 2 + max: 3 + min: 1 image: repository: '821090935708.dkr.ecr.eu-west-1.amazonaws.com/services-user-profile' ingress: @@ -110,9 +110,9 @@ podSecurityContext: fsGroup: 65534 pvcs: [] replicaCount: - default: 2 - max: 30 - min: 2 + default: 1 + max: 3 + min: 1 resources: limits: cpu: '800m' diff --git a/charts/services/service-portal/values.staging.yaml b/charts/services/service-portal/values.staging.yaml index 682ab594ddcd..65f13f82b35e 100644 --- a/charts/services/service-portal/values.staging.yaml +++ b/charts/services/service-portal/values.staging.yaml @@ -46,8 +46,8 @@ hpa: cpuAverageUtilization: 90 nginxRequestsIrate: 5 replicas: - max: 30 - min: 2 + max: 3 + min: 1 image: repository: '821090935708.dkr.ecr.eu-west-1.amazonaws.com/service-portal' ingress: @@ -66,9 +66,9 @@ podDisruptionBudget: maxUnavailable: 1 pvcs: [] replicaCount: - default: 2 - max: 30 - min: 2 + default: 1 + max: 3 + min: 1 resources: limits: cpu: '300m' diff --git a/charts/services/services-auth-admin-api/values.staging.yaml b/charts/services/services-auth-admin-api/values.staging.yaml index b1c22013d7d8..1d972f8b160a 100644 --- a/charts/services/services-auth-admin-api/values.staging.yaml +++ b/charts/services/services-auth-admin-api/values.staging.yaml @@ -70,8 +70,8 @@ hpa: cpuAverageUtilization: 90 nginxRequestsIrate: 5 replicas: - max: 10 - min: 2 + max: 3 + min: 1 image: repository: '821090935708.dkr.ecr.eu-west-1.amazonaws.com/services-auth-admin-api' ingress: @@ -89,9 +89,9 @@ podDisruptionBudget: maxUnavailable: 1 pvcs: [] replicaCount: - default: 2 - max: 10 - min: 2 + default: 1 + max: 3 + min: 1 resources: limits: cpu: '400m' diff --git a/charts/services/services-auth-delegation-api/values.staging.yaml b/charts/services/services-auth-delegation-api/values.staging.yaml index 6547bd4e464b..03180c9e830d 100644 --- a/charts/services/services-auth-delegation-api/values.staging.yaml +++ b/charts/services/services-auth-delegation-api/values.staging.yaml @@ -71,8 +71,8 @@ hpa: cpuAverageUtilization: 90 nginxRequestsIrate: 5 replicas: - max: 10 - min: 2 + max: 3 + min: 1 image: repository: '821090935708.dkr.ecr.eu-west-1.amazonaws.com/services-auth-delegation-api' ingress: @@ -89,9 +89,9 @@ podDisruptionBudget: maxUnavailable: 1 pvcs: [] replicaCount: - default: 2 - max: 10 - min: 2 + default: 1 + max: 3 + min: 1 resources: limits: cpu: '400m' diff --git a/charts/services/services-auth-ids-api/values.dev.yaml b/charts/services/services-auth-ids-api/values.dev.yaml index e1461ecdd4a9..12367bce8312 100644 --- a/charts/services/services-auth-ids-api/values.dev.yaml +++ b/charts/services/services-auth-ids-api/values.dev.yaml @@ -19,6 +19,7 @@ global: name: 'services-auth-ids-api' enabled: true env: + ALSO_USE_FAKE_USER_API: 'true' CODE_OWNER: 'aranja' COMPANY_REGISTRY_REDIS_NODES: '["clustercfg.general-redis-cluster-group.5fzau3.euw1.cache.amazonaws.com:6379"]' COMPANY_REGISTRY_XROAD_PROVIDER_ID: 'IS-DEV/GOV/10006/Skatturinn/ft-v1' diff --git a/charts/services/services-auth-ids-api/values.prod.yaml b/charts/services/services-auth-ids-api/values.prod.yaml index 48b414b22bb9..8f72bda2431f 100644 --- a/charts/services/services-auth-ids-api/values.prod.yaml +++ b/charts/services/services-auth-ids-api/values.prod.yaml @@ -19,6 +19,7 @@ global: name: 'services-auth-ids-api' enabled: true env: + ALSO_USE_FAKE_USER_API: 'false' CODE_OWNER: 'aranja' COMPANY_REGISTRY_REDIS_NODES: '["clustercfg.general-redis-cluster-group.dnugi2.euw1.cache.amazonaws.com:6379"]' COMPANY_REGISTRY_XROAD_PROVIDER_ID: 'IS/GOV/5402696029/Skatturinn/ft-v1' diff --git a/charts/services/services-auth-ids-api/values.staging.yaml b/charts/services/services-auth-ids-api/values.staging.yaml index 5b620fa22960..054896398d70 100644 --- a/charts/services/services-auth-ids-api/values.staging.yaml +++ b/charts/services/services-auth-ids-api/values.staging.yaml @@ -19,6 +19,7 @@ global: name: 'services-auth-ids-api' enabled: true env: + ALSO_USE_FAKE_USER_API: 'false' CODE_OWNER: 'aranja' COMPANY_REGISTRY_REDIS_NODES: '["clustercfg.general-redis-cluster-group.ab9ckb.euw1.cache.amazonaws.com:6379"]' COMPANY_REGISTRY_XROAD_PROVIDER_ID: 'IS-TEST/GOV/5402696029/Skatturinn/ft-v1' @@ -80,8 +81,8 @@ hpa: cpuAverageUtilization: 90 nginxRequestsIrate: 5 replicas: - max: 15 - min: 2 + max: 3 + min: 1 image: repository: '821090935708.dkr.ecr.eu-west-1.amazonaws.com/services-auth-ids-api' initContainer: @@ -126,9 +127,9 @@ podDisruptionBudget: maxUnavailable: 1 pvcs: [] replicaCount: - default: 2 - max: 15 - min: 2 + default: 1 + max: 3 + min: 1 resources: limits: cpu: '800m' diff --git a/charts/services/services-auth-personal-representative-public/values.staging.yaml b/charts/services/services-auth-personal-representative-public/values.staging.yaml index 5a132366628b..7f10d51b3fd0 100644 --- a/charts/services/services-auth-personal-representative-public/values.staging.yaml +++ b/charts/services/services-auth-personal-representative-public/values.staging.yaml @@ -44,8 +44,8 @@ hpa: cpuAverageUtilization: 90 nginxRequestsIrate: 5 replicas: - max: 10 - min: 2 + max: 3 + min: 1 image: repository: '821090935708.dkr.ecr.eu-west-1.amazonaws.com/services-auth-personal-representative-public' ingress: @@ -62,9 +62,9 @@ podDisruptionBudget: maxUnavailable: 1 pvcs: [] replicaCount: - default: 2 - max: 10 - min: 2 + default: 1 + max: 3 + min: 1 resources: limits: cpu: '400m' diff --git a/charts/services/services-auth-personal-representative/values.staging.yaml b/charts/services/services-auth-personal-representative/values.staging.yaml index 16fadeb06ab7..f6d9afc4f121 100644 --- a/charts/services/services-auth-personal-representative/values.staging.yaml +++ b/charts/services/services-auth-personal-representative/values.staging.yaml @@ -65,8 +65,8 @@ hpa: cpuAverageUtilization: 90 nginxRequestsIrate: 5 replicas: - max: 10 - min: 2 + max: 3 + min: 1 image: repository: '821090935708.dkr.ecr.eu-west-1.amazonaws.com/services-auth-personal-representative' ingress: @@ -83,9 +83,9 @@ podDisruptionBudget: maxUnavailable: 1 pvcs: [] replicaCount: - default: 2 - max: 10 - min: 2 + default: 1 + max: 3 + min: 1 resources: limits: cpu: '400m' diff --git a/charts/services/services-auth-public-api/values.staging.yaml b/charts/services/services-auth-public-api/values.staging.yaml index 31a9e6949e53..a2dbe2c7352a 100644 --- a/charts/services/services-auth-public-api/values.staging.yaml +++ b/charts/services/services-auth-public-api/values.staging.yaml @@ -77,8 +77,8 @@ hpa: cpuAverageUtilization: 90 nginxRequestsIrate: 5 replicas: - max: 10 - min: 2 + max: 3 + min: 1 image: repository: '821090935708.dkr.ecr.eu-west-1.amazonaws.com/services-auth-public-api' ingress: @@ -99,9 +99,9 @@ podDisruptionBudget: maxUnavailable: 1 pvcs: [] replicaCount: - default: 2 - max: 10 - min: 2 + default: 1 + max: 3 + min: 1 resources: limits: cpu: '400m' diff --git a/charts/services/services-bff-portals-admin/values.staging.yaml b/charts/services/services-bff-portals-admin/values.staging.yaml index a8b5553f847b..b27a1436a50d 100644 --- a/charts/services/services-bff-portals-admin/values.staging.yaml +++ b/charts/services/services-bff-portals-admin/values.staging.yaml @@ -58,8 +58,8 @@ hpa: cpuAverageUtilization: 90 nginxRequestsIrate: 5 replicas: - max: 10 - min: 2 + max: 3 + min: 1 image: repository: '821090935708.dkr.ecr.eu-west-1.amazonaws.com/services-bff' ingress: @@ -81,9 +81,9 @@ podSecurityContext: fsGroup: 65534 pvcs: [] replicaCount: - default: 2 - max: 10 - min: 2 + default: 1 + max: 3 + min: 1 resources: limits: cpu: '400m' diff --git a/charts/services/services-bff-portals-my-pages/values.staging.yaml b/charts/services/services-bff-portals-my-pages/values.staging.yaml index e4ce58391d55..ad1f25068192 100644 --- a/charts/services/services-bff-portals-my-pages/values.staging.yaml +++ b/charts/services/services-bff-portals-my-pages/values.staging.yaml @@ -57,8 +57,8 @@ hpa: cpuAverageUtilization: 90 nginxRequestsIrate: 5 replicas: - max: 10 - min: 2 + max: 3 + min: 1 image: repository: '821090935708.dkr.ecr.eu-west-1.amazonaws.com/services-bff' ingress: @@ -80,9 +80,9 @@ podSecurityContext: fsGroup: 65534 pvcs: [] replicaCount: - default: 2 - max: 10 - min: 2 + default: 1 + max: 3 + min: 1 resources: limits: cpu: '400m' diff --git a/charts/services/services-sessions/values.staging.yaml b/charts/services/services-sessions/values.staging.yaml index adc3e526bdc1..fdf795c80439 100644 --- a/charts/services/services-sessions/values.staging.yaml +++ b/charts/services/services-sessions/values.staging.yaml @@ -50,7 +50,7 @@ hpa: cpuAverageUtilization: 90 nginxRequestsIrate: 5 replicas: - max: 10 + max: 3 min: 1 image: repository: '821090935708.dkr.ecr.eu-west-1.amazonaws.com/services-sessions' @@ -69,7 +69,7 @@ podDisruptionBudget: pvcs: [] replicaCount: default: 1 - max: 10 + max: 3 min: 1 resources: limits: diff --git a/charts/services/services-university-gateway/values.staging.yaml b/charts/services/services-university-gateway/values.staging.yaml index 975b21ae2937..313eda0fc537 100644 --- a/charts/services/services-university-gateway/values.staging.yaml +++ b/charts/services/services-university-gateway/values.staging.yaml @@ -66,8 +66,8 @@ hpa: cpuAverageUtilization: 90 nginxRequestsIrate: 5 replicas: - max: 10 - min: 2 + max: 3 + min: 1 image: repository: '821090935708.dkr.ecr.eu-west-1.amazonaws.com/services-university-gateway' ingress: @@ -122,9 +122,9 @@ podSecurityContext: fsGroup: 65534 pvcs: [] replicaCount: - default: 2 - max: 10 - min: 2 + default: 1 + max: 3 + min: 1 resources: limits: cpu: '200m' diff --git a/charts/services/skilavottord-web/values.staging.yaml b/charts/services/skilavottord-web/values.staging.yaml index 592971c93b7c..59d876710b15 100644 --- a/charts/services/skilavottord-web/values.staging.yaml +++ b/charts/services/skilavottord-web/values.staging.yaml @@ -42,8 +42,8 @@ hpa: cpuAverageUtilization: 90 nginxRequestsIrate: 8 replicas: - max: 10 - min: 2 + max: 3 + min: 1 image: repository: '821090935708.dkr.ecr.eu-west-1.amazonaws.com/skilavottord-web' ingress: @@ -62,9 +62,9 @@ podDisruptionBudget: maxUnavailable: 1 pvcs: [] replicaCount: - default: 2 - max: 10 - min: 2 + default: 1 + max: 3 + min: 1 resources: limits: cpu: '400m' diff --git a/charts/services/user-notification-worker/values.staging.yaml b/charts/services/user-notification-worker/values.staging.yaml index ce46946924d2..5f2f70af09e6 100644 --- a/charts/services/user-notification-worker/values.staging.yaml +++ b/charts/services/user-notification-worker/values.staging.yaml @@ -78,7 +78,7 @@ hpa: cpuAverageUtilization: 90 nginxRequestsIrate: 5 replicas: - max: 2 + max: 3 min: 1 image: repository: '821090935708.dkr.ecr.eu-west-1.amazonaws.com/services-user-notification' @@ -113,7 +113,7 @@ podSecurityContext: pvcs: [] replicaCount: default: 1 - max: 2 + max: 3 min: 1 resources: limits: diff --git a/charts/services/web/values.staging.yaml b/charts/services/web/values.staging.yaml index 8e672b5827be..1c68d6367609 100644 --- a/charts/services/web/values.staging.yaml +++ b/charts/services/web/values.staging.yaml @@ -52,8 +52,8 @@ hpa: cpuAverageUtilization: 90 nginxRequestsIrate: 5 replicas: - max: 50 - min: 2 + max: 3 + min: 1 image: repository: '821090935708.dkr.ecr.eu-west-1.amazonaws.com/web' ingress: @@ -72,9 +72,9 @@ podDisruptionBudget: maxUnavailable: 1 pvcs: [] replicaCount: - default: 2 - max: 50 - min: 2 + default: 1 + max: 3 + min: 1 resources: limits: cpu: '1000m' diff --git a/codemagic.yaml b/codemagic.yaml index a0840a6144b2..e6d07bc39ad9 100644 --- a/codemagic.yaml +++ b/codemagic.yaml @@ -219,7 +219,7 @@ workflows: - island-upload-keystore groups: - google_credentials - - firebase_credentials + - firebase_credentials_dev vars: <<: *shared_envs PACKAGE_NAME: 'is.island.app.dev' diff --git a/infra/src/cli/render-secrets.ts b/infra/src/cli/render-secrets.ts index 9c859e2afba8..0ba1ba705b36 100644 --- a/infra/src/cli/render-secrets.ts +++ b/infra/src/cli/render-secrets.ts @@ -68,9 +68,7 @@ export const renderSecrets = async (service: string) => { logger.debug('env when rendering', { envMap }) Object.entries(envMap).forEach(([key, value]) => { - const escapedValue = (value ?? '') - .replace(/\n/g, '\\n') - .replace(/"/g, '\\"') + const escapedValue = (value ?? '').replace(/'/g, "\\'") console.log(`export ${key}='${escapedValue}'`) }) return envMap diff --git a/infra/src/dsl/basic.spec.ts b/infra/src/dsl/basic.spec.ts index f3d24bb8d736..81a3e44397b7 100644 --- a/infra/src/dsl/basic.spec.ts +++ b/infra/src/dsl/basic.spec.ts @@ -9,7 +9,7 @@ const Staging: EnvironmentConfig = { auroraHost: 'a', redisHost: 'b', domain: 'staging01.devland.is', - type: 'staging', + type: 'prod', featuresOn: [], defaultMaxReplicas: 3, defaultMinReplicas: 2, diff --git a/infra/src/dsl/hpa.spec.ts b/infra/src/dsl/hpa.spec.ts index 6182c6fef66f..509c36fa5a57 100644 --- a/infra/src/dsl/hpa.spec.ts +++ b/infra/src/dsl/hpa.spec.ts @@ -9,7 +9,7 @@ const Staging: EnvironmentConfig = { auroraHost: 'a', redisHost: 'b', domain: 'staging01.devland.is', - type: 'staging', + type: 'prod', featuresOn: [], defaultMaxReplicas: 3, defaultMinReplicas: 2, diff --git a/infra/src/dsl/output-generators/map-to-helm-values.ts b/infra/src/dsl/output-generators/map-to-helm-values.ts index fdd6297613ba..e18e6ab23e21 100644 --- a/infra/src/dsl/output-generators/map-to-helm-values.ts +++ b/infra/src/dsl/output-generators/map-to-helm-values.ts @@ -109,17 +109,25 @@ const serializeService: SerializeMethod = async ( result.resources = serviceDef.resources // replicas - if (serviceDef.replicaCount) { + if (env1.type == 'staging') { result.replicaCount = { - min: serviceDef.replicaCount.min, - max: serviceDef.replicaCount.max, - default: serviceDef.replicaCount.default, + min: 1, + max: 3, + default: 1, } } else { - result.replicaCount = { - min: env1.defaultMinReplicas, - max: env1.defaultMaxReplicas, - default: env1.defaultMinReplicas, + if (serviceDef.replicaCount) { + result.replicaCount = { + min: serviceDef.replicaCount.min, + max: serviceDef.replicaCount.max, + default: serviceDef.replicaCount.default, + } + } else { + result.replicaCount = { + min: env1.defaultMinReplicas, + max: env1.defaultMaxReplicas, + default: env1.defaultMinReplicas, + } } } diff --git a/libs/api/domains/social-insurance/src/lib/dtos/pensionCalculation.input.ts b/libs/api/domains/social-insurance/src/lib/dtos/pensionCalculation.input.ts index e6f73046d462..79b0efda8b55 100644 --- a/libs/api/domains/social-insurance/src/lib/dtos/pensionCalculation.input.ts +++ b/libs/api/domains/social-insurance/src/lib/dtos/pensionCalculation.input.ts @@ -7,6 +7,9 @@ export enum BasePensionType { Rehabilitation = 'Rehabilitation', HalfRetirement = 'HalfRetirement', NewSystem = 'NewSystem', + NewSystemDisability = 'NewSystemDisability', + NewSystemPartialDisability = 'NewSystemPartialDisability', + NewSystemMedicalAndRehabilitation = 'NewSystemMedicalAndRehabilitation', } registerEnumType(BasePensionType, { diff --git a/libs/api/domains/social-insurance/src/lib/utils.ts b/libs/api/domains/social-insurance/src/lib/utils.ts index 6341bbcd7ed0..8bd2d340f4b4 100644 --- a/libs/api/domains/social-insurance/src/lib/utils.ts +++ b/libs/api/domains/social-insurance/src/lib/utils.ts @@ -21,7 +21,10 @@ const basePensionTypeMapping: Record = { [BasePensionType.Disability]: 3, // Örorkulífeyrir [BasePensionType.Rehabilitation]: 4, // Endurhæfingarlífeyrir [BasePensionType.HalfRetirement]: 5, // Hálfur Ellilífeyrir - [BasePensionType.NewSystem]: 6, // Nýtt kerfi sem tekur gildi 1. september 2025 + [BasePensionType.NewSystem]: 6, // Örorkulífeyrir - Nýtt kerfi sem tekur gildi 1. september 2025 + [BasePensionType.NewSystemDisability]: 6, // Örorkulífeyrir - Nýtt kerfi sem tekur gildi 1. september 2025 + [BasePensionType.NewSystemPartialDisability]: 7, // Hlutaörorka - Nýtt kerfi sem tekur gildi 1. september 2025 + [BasePensionType.NewSystemMedicalAndRehabilitation]: 8, // Sjúkra- og endurhæfingargreiðslur - Nýtt kerfi sem tekur gildi 1. september 2025 } const livingConditionMapping: Record = { diff --git a/libs/application/core/src/lib/fieldBuilders.ts b/libs/application/core/src/lib/fieldBuilders.ts index a1035cbc3b55..b8f46194e70f 100644 --- a/libs/application/core/src/lib/fieldBuilders.ts +++ b/libs/application/core/src/lib/fieldBuilders.ts @@ -46,6 +46,8 @@ import { MaybeWithApplicationAndFieldAndLocale, DisplayField, FieldsRepeaterField, + AccordionField, + BankAccountField, } from '@island.is/application/types' import { Locale } from '@island.is/shared/types' import { Colors } from '@island.is/island-ui/theme' @@ -71,6 +73,8 @@ const extractCommonFields = ( dataTestId, width = 'full', nextButtonText, + marginBottom, + marginTop, } = data return { @@ -84,6 +88,8 @@ const extractCommonFields = ( title, width, nextButtonText, + marginBottom, + marginTop, } } @@ -152,8 +158,6 @@ export const buildDescriptionField = ( tooltip, titleTooltip, space, - marginBottom, - marginTop, doesNotRequireAnswer = true, } = data return { @@ -165,8 +169,6 @@ export const buildDescriptionField = ( tooltip, titleTooltip, space, - marginBottom, - marginTop, type: FieldTypes.DESCRIPTION, component: FieldComponents.DESCRIPTION, } @@ -398,8 +400,10 @@ export const buildDividerField = (data: { condition?: Condition title?: FormText color?: Colors + marginBottom?: BoxProps['marginBottom'] + marginTop?: BoxProps['marginTop'] }): DividerField => { - const { title, color, condition } = data + const { title, color, condition, marginTop, marginBottom } = data return { id: '', children: undefined, @@ -409,6 +413,8 @@ export const buildDividerField = (data: { title: title ?? '', color, condition, + marginTop, + marginBottom, } } @@ -461,6 +467,8 @@ export const buildSubmitField = (data: { id: string title: FormText placement?: 'footer' | 'screen' + marginBottom?: BoxProps['marginBottom'] + marginTop?: BoxProps['marginTop'] refetchApplicationAfterSubmit?: boolean actions: CallToAction[] }): SubmitField => { @@ -470,6 +478,8 @@ export const buildSubmitField = (data: { title, actions, refetchApplicationAfterSubmit, + marginTop, + marginBottom, } = data return { children: undefined, @@ -482,6 +492,8 @@ export const buildSubmitField = (data: { typeof refetchApplicationAfterSubmit !== 'undefined' ? refetchApplicationAfterSubmit : false, + marginTop, + marginBottom, type: FieldTypes.SUBMIT, component: FieldComponents.SUBMIT, } @@ -512,12 +524,16 @@ export const buildFieldRequired = ( export const buildRedirectToServicePortalField = (data: { id: string title: FormText + marginBottom?: BoxProps['marginBottom'] + marginTop?: BoxProps['marginTop'] }): RedirectToServicePortalField => { - const { id, title } = data + const { id, title, marginTop, marginBottom } = data return { children: undefined, id, title, + marginTop, + marginBottom, type: FieldTypes.REDIRECT_TO_SERVICE_PORTAL, component: FieldComponents.REDIRECT_TO_SERVICE_PORTAL, } @@ -540,7 +556,7 @@ export const buildPaymentPendingField = (data: { export const buildMessageWithLinkButtonField = ( data: Omit, ): MessageWithLinkButtonField => { - const { id, title, url, message, buttonTitle, marginBottom, marginTop } = data + const { id, title, url, message, buttonTitle } = data return { ...extractCommonFields(data), children: undefined, @@ -549,8 +565,6 @@ export const buildMessageWithLinkButtonField = ( url, message, buttonTitle, - marginTop, - marginBottom, type: FieldTypes.MESSAGE_WITH_LINK_BUTTON_FIELD, component: FieldComponents.MESSAGE_WITH_LINK_BUTTON_FIELD, } @@ -561,6 +575,7 @@ export const buildExpandableDescriptionField = ( ): ExpandableDescriptionField => { const { id, title, description, introText, startExpanded } = data return { + ...extractCommonFields(data), children: undefined, id, title, @@ -574,7 +589,7 @@ export const buildExpandableDescriptionField = ( export const buildAlertMessageField = ( data: Omit, ): AlertMessageField => { - const { message, alertType, marginTop, marginBottom, links } = data + const { message, alertType, links } = data return { ...extractCommonFields(data), children: undefined, @@ -582,8 +597,6 @@ export const buildAlertMessageField = ( alertType, type: FieldTypes.ALERT_MESSAGE, component: FieldComponents.ALERT_MESSAGE, - marginTop, - marginBottom, links, } } @@ -609,6 +622,7 @@ export const buildPaymentChargeOverviewField = ( const { id, title, forPaymentLabel, totalLabel, getSelectedChargeItems } = data return { + ...extractCommonFields(data), children: undefined, id, title, @@ -628,8 +642,6 @@ export const buildImageField = ( title, image, alt, - marginTop, - marginBottom, condition, titleVariant = 'h4', // imageWidth and imagePosition can be arrays [sm, md, lg, xl] for different screen sizes @@ -637,14 +649,13 @@ export const buildImageField = ( imagePosition = 'left', } = data return { + ...extractCommonFields(data), children: undefined, id, title, image, alt, imageWidth, - marginTop, - marginBottom, condition, titleVariant, imagePosition, @@ -752,8 +763,6 @@ export const buildNationalIdWithNameField = ( searchCompanies, titleVariant, description, - marginTop, - marginBottom, } = data return { ...extractCommonFields(data), @@ -774,15 +783,13 @@ export const buildNationalIdWithNameField = ( component: FieldComponents.NATIONAL_ID_WITH_NAME, titleVariant, description, - marginTop, - marginBottom, } } export const buildActionCardListField = ( data: Omit, ): ActionCardListField => { - const { items, space, marginTop, marginBottom } = data + const { items, space } = data return { ...extractCommonFields(data), @@ -790,8 +797,6 @@ export const buildActionCardListField = ( type: FieldTypes.ACTION_CARD_LIST, component: FieldComponents.ACTION_CARD_LIST, items, - marginTop, - marginBottom, space, } } @@ -803,8 +808,6 @@ export const buildTableRepeaterField = ( fields, table, formTitle, - marginTop, - marginBottom, titleVariant, addItemButtonText, saveItemButtonText, @@ -823,8 +826,6 @@ export const buildTableRepeaterField = ( fields, table, formTitle, - marginTop, - marginBottom, titleVariant, addItemButtonText, saveItemButtonText, @@ -847,8 +848,6 @@ export const buildFieldsRepeaterField = ( formTitle, formTitleVariant, formTitleNumbering, - marginTop, - marginBottom, removeItemButtonText, addItemButtonText, saveItemButtonText, @@ -868,8 +867,6 @@ export const buildFieldsRepeaterField = ( formTitle, formTitleVariant, formTitleNumbering, - marginTop, - marginBottom, removeItemButtonText, addItemButtonText, saveItemButtonText, @@ -949,6 +946,8 @@ export const buildSliderField = ( labelMultiplier = 1, id, saveAsString, + marginTop, + marginBottom, } = data return { title: '', @@ -975,6 +974,8 @@ export const buildSliderField = ( labelMultiplier, condition, saveAsString, + marginTop, + marginBottom, } } @@ -986,8 +987,6 @@ export const buildDisplayField = ( titleVariant, label, variant, - marginTop, - marginBottom, value, suffix, rightAlign, @@ -999,8 +998,6 @@ export const buildDisplayField = ( titleVariant, label, variant, - marginTop, - marginBottom, type: FieldTypes.DISPLAY, component: FieldComponents.DISPLAY, children: undefined, @@ -1010,3 +1007,44 @@ export const buildDisplayField = ( halfWidthOwnline, } } + +export const buildAccordionField = ( + data: Omit, +): AccordionField => { + const { + accordionItems, + title, + titleVariant, + id, + marginTop, + marginBottom, + condition, + } = data + return { + children: undefined, + id, + title, + titleVariant, + marginTop, + marginBottom, + accordionItems, + condition, + type: FieldTypes.ACCORDION, + component: FieldComponents.ACCORDION, + } +} +export const buildBankAccountField = ( + data: Omit, +): BankAccountField => { + const { title, id, marginBottom, marginTop, titleVariant } = data + return { + children: undefined, + id, + title, + marginBottom, + marginTop, + titleVariant, + type: FieldTypes.BANK_ACCOUNT, + component: FieldComponents.BANK_ACCOUNT, + } +} diff --git a/libs/application/core/src/lib/messages.ts b/libs/application/core/src/lib/messages.ts index aaaafd03dee2..65cb2f5cdd67 100644 --- a/libs/application/core/src/lib/messages.ts +++ b/libs/application/core/src/lib/messages.ts @@ -318,6 +318,21 @@ export const coreDefaultFieldMessages = defineMessages({ defaultMessage: 'Veljið skjöl til að hlaða upp', description: 'Default file upload button label', }, + defaultBankAccountBankNumber: { + id: 'application.system:core.default.bankAccount.bankNumber', + defaultMessage: 'Bankanúmer', + description: 'Bank account bank number', + }, + defaultBankAccountLedger: { + id: 'application.system:core.default.bankAccount.ledger', + defaultMessage: 'Höfuðbók', + description: 'Bank account ledger', + }, + defaultBankAccountAccountNumber: { + id: 'application.system:core.default.bankAccount.accountNumber', + defaultMessage: 'Reikningsnúmer', + description: 'Bank account account number', + }, defaultDownloadButtonTitle: { id: 'application.system:core.default.pdfLinkButtonField.downloadButtonTitle', defaultMessage: 'Hlaða niður skjali', diff --git a/libs/application/template-api-modules/src/lib/modules/templates/new-primary-school/new-primary-school.service.ts b/libs/application/template-api-modules/src/lib/modules/templates/new-primary-school/new-primary-school.service.ts index 80ce338d5cd2..ce131be8fb24 100644 --- a/libs/application/template-api-modules/src/lib/modules/templates/new-primary-school/new-primary-school.service.ts +++ b/libs/application/template-api-modules/src/lib/modules/templates/new-primary-school/new-primary-school.service.ts @@ -38,6 +38,66 @@ export class NewPrimarySchoolService extends BaseTemplateApiService { } async getChildren({ auth }: TemplateApiModuleActionProps) { + if (isRunningOnEnvironment('dev')) { + if (auth.nationalId === '0101303019') { + return [ + { + nationalId: '1111111119', + fullName: 'Stubbur Maack', + genderCode: '3', + livesWithApplicant: true, + livesWithBothParents: true, + }, + ] + } + if (auth.nationalId === '0101302989') { + return [ + { + nationalId: '2222222229', + fullName: 'Stúfur Maack ', + genderCode: '3', + livesWithApplicant: true, + livesWithBothParents: true, + otherParent: { + nationalId: '0101302399', + fullName: 'Gervimaður Færeyjar', + address: { + streetName: 'Hvassaleiti 5', + postalCode: '103', + city: 'Reykjavík', + municipalityCode: '0000', + }, + genderCode: '2', + }, + }, + { + nationalId: '5555555559', + fullName: 'Bína Maack ', + genderCode: '4', + livesWithApplicant: true, + livesWithBothParents: true, + }, + { + nationalId: '6666666669', + fullName: 'Snúður Maack', + genderCode: '3', + livesWithApplicant: true, + livesWithBothParents: true, + }, + ] + } + if (auth.nationalId === '0101304929') { + return [ + { + nationalId: '6666666669', + fullName: 'Snúður Maack', + genderCode: '3', + livesWithApplicant: true, + livesWithBothParents: true, + }, + ] + } + } const children = await this.nationalRegistryService.getChildrenCustodyInformation(auth) diff --git a/libs/application/template-api-modules/src/lib/modules/templates/parental-leave/parental-leave.service.ts b/libs/application/template-api-modules/src/lib/modules/templates/parental-leave/parental-leave.service.ts index 8d064e4ce24f..2fdc49ef12d8 100644 --- a/libs/application/template-api-modules/src/lib/modules/templates/parental-leave/parental-leave.service.ts +++ b/libs/application/template-api-modules/src/lib/modules/templates/parental-leave/parental-leave.service.ts @@ -35,6 +35,7 @@ import { getAdditionalSingleParentRightsInMonths, clamp, getMultipleBirthsDaysInMonths, + Files, } from '@island.is/application/templates/parental-leave' import { Application, @@ -402,6 +403,23 @@ export class ParentalLeaveService extends BaseTemplateApiService { } } + async getPDFs( + application: Application, + documents: Files[], + attachmentType: string, + fileUpload: string, + ) { + const PDFs = [] + for (const index of documents.keys()) { + const pdf = await this.getPdf(application, index, fileUpload) + PDFs.push({ + attachmentType, + attachmentBytes: pdf, + }) + } + return PDFs + } + async getAttachments(application: Application): Promise { const attachments: Attachment[] = [] const { @@ -433,48 +451,36 @@ export class ParentalLeaveService extends BaseTemplateApiService { state === States.RESIDENCE_GRANT_APPLICATION ) { if (residenceGrantFiles) { - residenceGrantFiles.forEach(async (item, index) => { - const pdf = await this.getPdf( - application, - index, - 'fileUpload.residenceGrant', - ) - attachments.push({ - attachmentType: apiConstants.attachments.residenceGrant, - attachmentBytes: pdf, - }) - }) + const PDFs = await this.getPDFs( + application, + residenceGrantFiles, + apiConstants.attachments.residenceGrant, + 'fileUpload.residenceGrant', + ) + attachments.push(...PDFs) } } if (changeEmployerFile) { - changeEmployerFile.forEach(async (item, index) => { - const pdf = await this.getPdf( - application, - index, - 'fileUpload.changeEmployerFile', - ) - attachments.push({ - attachmentType: apiConstants.attachments.changeEmployer, - attachmentBytes: pdf, - }) - }) + const PDFs = await this.getPDFs( + application, + changeEmployerFile, + apiConstants.attachments.changeEmployer, + 'fileUpload.changeEmployerFile', + ) + attachments.push(...PDFs) } // We don't want to send old files to VMST again if (applicationFundId && applicationFundId !== '') { if (additionalDocuments) { - for (const index of additionalDocuments.keys()) { - const pdf = await this.getPdf( - application, - index, - 'fileUpload.additionalDocuments', - ) - attachments.push({ - attachmentType: apiConstants.attachments.other, - attachmentBytes: pdf, - }) - } + const PDFs = await this.getPDFs( + application, + additionalDocuments, + apiConstants.attachments.other, + 'fileUpload.additionalDocuments', + ) + attachments.push(...PDFs) } return attachments } diff --git a/libs/application/templates/accident-notification/src/dataProviders/index.ts b/libs/application/templates/accident-notification/src/dataProviders/index.ts new file mode 100644 index 000000000000..fb1bb027a65c --- /dev/null +++ b/libs/application/templates/accident-notification/src/dataProviders/index.ts @@ -0,0 +1,4 @@ +export { + IdentityApi, + NationalRegistryUserApi, +} from '@island.is/application/types' diff --git a/libs/application/templates/accident-notification/src/fields/AgreementDescription/index.tsx b/libs/application/templates/accident-notification/src/fields/AgreementDescription/index.tsx deleted file mode 100644 index 0470ab316795..000000000000 --- a/libs/application/templates/accident-notification/src/fields/AgreementDescription/index.tsx +++ /dev/null @@ -1,25 +0,0 @@ -import { FieldBaseProps } from '@island.is/application/types' -import { Bullet, Stack } from '@island.is/island-ui/core' -import { useLocale } from '@island.is/localization' -import React, { FC } from 'react' -import { externalData } from '../../lib/messages' - -export const AgreementDescription: FC< - React.PropsWithChildren -> = () => { - const { formatMessage } = useLocale() - - return ( - - - {formatMessage(externalData.agreementDescription.bulletOne)} - - - {formatMessage(externalData.agreementDescription.bulletTwo)} - - - {formatMessage(externalData.agreementDescription.bulletThree)} - - - ) -} diff --git a/libs/application/templates/accident-notification/src/fields/DateOfAccident/index.tsx b/libs/application/templates/accident-notification/src/fields/DateOfAccident/index.tsx index b212e92ae31b..27627c0f8f2b 100644 --- a/libs/application/templates/accident-notification/src/fields/DateOfAccident/index.tsx +++ b/libs/application/templates/accident-notification/src/fields/DateOfAccident/index.tsx @@ -5,7 +5,7 @@ import { useLocale } from '@island.is/localization' import { DatePickerController } from '@island.is/shared/form-fields' import React, { FC, useCallback, useEffect, useState } from 'react' import { Controller, useFormContext } from 'react-hook-form' -import { NO, YES } from '../../constants' +import { NO, YES } from '../../utils/constants' import { useLazyIsHealthInsured } from '../../hooks/useLazyIsHealthInsured' import { AccidentNotification } from '../../lib/dataSchema' import { accidentDetails } from '../../lib/messages' diff --git a/libs/application/templates/accident-notification/src/fields/DescriptionWithLink/descriptionWithLink.css.ts b/libs/application/templates/accident-notification/src/fields/DescriptionWithLink/descriptionWithLink.css.ts deleted file mode 100644 index 8ed6d0294c97..000000000000 --- a/libs/application/templates/accident-notification/src/fields/DescriptionWithLink/descriptionWithLink.css.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { style } from '@vanilla-extract/css' -import { theme } from '@island.is/island-ui/theme' - -export const link = style({ - color: theme.color.blue600, - selectors: { - '&:hover': { - backgroundColor: theme.color.purple100, - }, - }, -}) diff --git a/libs/application/templates/accident-notification/src/fields/DescriptionWithLink/index.tsx b/libs/application/templates/accident-notification/src/fields/DescriptionWithLink/index.tsx deleted file mode 100644 index b83eaff05827..000000000000 --- a/libs/application/templates/accident-notification/src/fields/DescriptionWithLink/index.tsx +++ /dev/null @@ -1,43 +0,0 @@ -import { Link, Text } from '@island.is/island-ui/core' -import React, { FC } from 'react' -import { useLocale } from '@island.is/localization' -import { formatText } from '@island.is/application/core' -import { FieldBaseProps } from '@island.is/application/types' -import { Box } from '@island.is/island-ui/core' -import * as styles from './descriptionWithLink.css' - -type DescriptionLinkProps = { - field: { - props: { - descriptionFirstPart: string - descriptionSecondPart: string - linkName: string - url: string - } - } -} - -export const DescriptionWithLink: FC< - React.PropsWithChildren -> = ({ application, field }) => { - const { props } = field - const { formatMessage } = useLocale() - const { descriptionFirstPart, descriptionSecondPart, linkName, url } = props - return ( - - - - {`${formatText(descriptionFirstPart, application, formatMessage)} `} - - {` ${formatText( - linkName, - application, - formatMessage, - )}`} - - {formatText(descriptionSecondPart, application, formatMessage)} - - - - ) -} diff --git a/libs/application/templates/accident-notification/src/fields/FormOverview/index.tsx b/libs/application/templates/accident-notification/src/fields/FormOverview/index.tsx index e3401b90871a..3eb21101ca94 100644 --- a/libs/application/templates/accident-notification/src/fields/FormOverview/index.tsx +++ b/libs/application/templates/accident-notification/src/fields/FormOverview/index.tsx @@ -18,7 +18,7 @@ import is from 'date-fns/locale/is' import parseISO from 'date-fns/parseISO' import kennitala from 'kennitala' import React, { FC } from 'react' -import { States, YES } from '../../constants' +import { States, YES } from '../../utils/constants' import { AccidentNotification } from '../../lib/dataSchema' import { accidentDetails, diff --git a/libs/application/templates/accident-notification/src/fields/index.ts b/libs/application/templates/accident-notification/src/fields/index.ts index d2880db80314..82bbce3df36a 100644 --- a/libs/application/templates/accident-notification/src/fields/index.ts +++ b/libs/application/templates/accident-notification/src/fields/index.ts @@ -1,8 +1,6 @@ -export { AgreementDescription } from './AgreementDescription' export { DateOfAccident } from './DateOfAccident' export { FormOverview } from './FormOverview' export { HiddenInformation } from './HiddenInformation' export { ApplicationStatus } from './ApplicationStatus' export { FormOverviewInReview } from './FormOverviewInReview' export { ProxyDocument } from './ProxyDocument' -export { DescriptionWithLink } from './DescriptionWithLink' diff --git a/libs/application/templates/accident-notification/src/forms/AccidentNotificationForm/aboutTheAccidentSection/attachmentsSubSection.ts b/libs/application/templates/accident-notification/src/forms/AccidentNotificationForm/aboutTheAccidentSection/attachmentsSubSection.ts index 8d666ce9d97c..e8c71b90e331 100644 --- a/libs/application/templates/accident-notification/src/forms/AccidentNotificationForm/aboutTheAccidentSection/attachmentsSubSection.ts +++ b/libs/application/templates/accident-notification/src/forms/AccidentNotificationForm/aboutTheAccidentSection/attachmentsSubSection.ts @@ -21,7 +21,12 @@ import { isRepresentativeOfCompanyOrInstitute, } from '../../../utils' import { AttachmentsEnum } from '../../../types' -import { FILE_SIZE_LIMIT, NO, UPLOAD_ACCEPT, YES } from '../../../constants' +import { + FILE_SIZE_LIMIT, + NO, + UPLOAD_ACCEPT, + YES, +} from '../../../utils/constants' // Injury certificate and fatal accident section export const attachmentsSubSection = buildSubSection({ diff --git a/libs/application/templates/accident-notification/src/forms/AccidentNotificationForm/aboutTheAccidentSection/locationSubSection.ts b/libs/application/templates/accident-notification/src/forms/AccidentNotificationForm/aboutTheAccidentSection/locationSubSection.ts index 7e97ccbd88ae..be855a49a6f0 100644 --- a/libs/application/templates/accident-notification/src/forms/AccidentNotificationForm/aboutTheAccidentSection/locationSubSection.ts +++ b/libs/application/templates/accident-notification/src/forms/AccidentNotificationForm/aboutTheAccidentSection/locationSubSection.ts @@ -22,7 +22,7 @@ import { isRescueWorkAccident, isStudiesAccident, } from '../../../utils' -import { NO, YES } from '../../../constants' +import { NO, YES } from '../../../utils/constants' import { isSportAccidentAndEmployee } from '../../../utils/isSportAccidentAndEmployee' import { AgricultureAccidentLocationEnum, diff --git a/libs/application/templates/accident-notification/src/forms/AccidentNotificationForm/aboutTheAccidentSection/workMachineSubSection.ts b/libs/application/templates/accident-notification/src/forms/AccidentNotificationForm/aboutTheAccidentSection/workMachineSubSection.ts index 67b73e98e2d6..bdfa59c43e79 100644 --- a/libs/application/templates/accident-notification/src/forms/AccidentNotificationForm/aboutTheAccidentSection/workMachineSubSection.ts +++ b/libs/application/templates/accident-notification/src/forms/AccidentNotificationForm/aboutTheAccidentSection/workMachineSubSection.ts @@ -10,7 +10,7 @@ import { isGeneralWorkplaceAccident, } from '../../../utils' import { isSportAccidentAndEmployee } from '../../../utils/isSportAccidentAndEmployee' -import { NO, YES } from '../../../constants' +import { NO, YES } from '../../../utils/constants' // Workmachine information only applicable to generic workplace accidents export const workMachineSubSection = buildSubSection({ diff --git a/libs/application/templates/accident-notification/src/forms/AccidentNotificationForm/applicantInformationSection.ts b/libs/application/templates/accident-notification/src/forms/AccidentNotificationForm/applicantInformationSection.ts index dc0cde867058..f91bcfaaee43 100644 --- a/libs/application/templates/accident-notification/src/forms/AccidentNotificationForm/applicantInformationSection.ts +++ b/libs/application/templates/accident-notification/src/forms/AccidentNotificationForm/applicantInformationSection.ts @@ -1,8 +1,6 @@ import { buildSection } from '@island.is/application/core' - import { applicantInformation } from '../../lib/messages' import { applicantInformationMultiField } from '@island.is/application/ui-forms' - export const applicantInformationSection = buildSection({ id: 'informationAboutApplicantSection', title: applicantInformation.general.title, diff --git a/libs/application/templates/accident-notification/src/forms/AccidentNotificationForm/betaTestSection.ts b/libs/application/templates/accident-notification/src/forms/AccidentNotificationForm/betaTestSection.ts deleted file mode 100644 index c37d5bbc3359..000000000000 --- a/libs/application/templates/accident-notification/src/forms/AccidentNotificationForm/betaTestSection.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { buildCustomField, buildSection } from '@island.is/application/core' -import { betaTest } from '../../lib/messages' - -// Should only be here with the soft release, remove on official release. -export const betaTestSection = buildSection({ - id: 'betaTest.section', - title: betaTest.title, - children: [ - buildCustomField( - { - id: 'betaTest.section.textField', - title: betaTest.title, - component: 'DescriptionWithLink', - doesNotRequireAnswer: true, - }, - { - descriptionFirstPart: betaTest.descriptionFirstPart, - descriptionSecondPart: betaTest.descriptionSecondPart, - linkName: betaTest.emailText, - url: betaTest.email, - }, - ), - ], -}) diff --git a/libs/application/templates/accident-notification/src/forms/AccidentNotificationForm/externalDataSection/agreementDescriptionMultiField.ts b/libs/application/templates/accident-notification/src/forms/AccidentNotificationForm/externalDataSection/agreementDescriptionMultiField.ts deleted file mode 100644 index ff2088966a1e..000000000000 --- a/libs/application/templates/accident-notification/src/forms/AccidentNotificationForm/externalDataSection/agreementDescriptionMultiField.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { buildCustomField, buildMultiField } from '@island.is/application/core' -import { externalData } from '../../../lib/messages' - -export const agreementDescriptionMultiField = buildMultiField({ - title: externalData.agreementDescription.sectionTitle, - id: 'agreementDescriptionMultiField', - space: 2, - children: [ - buildCustomField({ - id: 'agreementDescriptionCustomField', - title: '', - component: 'AgreementDescription', - doesNotRequireAnswer: true, - }), - buildCustomField( - { - id: 'extrainformationWithDataprovider', - title: '', - component: 'DescriptionWithLink', - doesNotRequireAnswer: true, - }, - { - descriptionFirstPart: externalData.extraInformation.description, - descriptionSecondPart: '', - linkName: externalData.extraInformation.linkText, - url: externalData.extraInformation.link, - }, - ), - ], -}) diff --git a/libs/application/templates/accident-notification/src/forms/AccidentNotificationForm/externalDataSection/index.ts b/libs/application/templates/accident-notification/src/forms/AccidentNotificationForm/externalDataSection/index.ts deleted file mode 100644 index d46bf5c0c1b0..000000000000 --- a/libs/application/templates/accident-notification/src/forms/AccidentNotificationForm/externalDataSection/index.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { buildSection } from '@island.is/application/core' -import { agreementDescriptionMultiField } from './agreementDescriptionMultiField' -import { accidentNotificationSubSection } from './accidentNotificationSubSection' -import { externalData } from '../../../lib/messages' - -export const externalDataSection = buildSection({ - id: 'ExternalDataSection', - title: externalData.agreementDescription.listTitle, - children: [agreementDescriptionMultiField, accidentNotificationSubSection], -}) diff --git a/libs/application/templates/accident-notification/src/forms/AccidentNotificationForm/index.ts b/libs/application/templates/accident-notification/src/forms/AccidentNotificationForm/index.ts index 82a2dfd20d95..e3b6e2d8ed99 100644 --- a/libs/application/templates/accident-notification/src/forms/AccidentNotificationForm/index.ts +++ b/libs/application/templates/accident-notification/src/forms/AccidentNotificationForm/index.ts @@ -2,14 +2,10 @@ import { buildForm } from '@island.is/application/core' import { Form, FormModes } from '@island.is/application/types' import Logo from '../../assets/Logo' import { application } from '../../lib/messages' - import { conclusionSection } from './conclusionSection' - import { overviewSection } from './overviewSection' -import { betaTestSection } from './betaTestSection' import { applicantInformationSection } from './applicantInformationSection' import { whoIsTheNotificationForSection } from './whoIsTheNotificationForSection' -import { externalDataSection } from './externalDataSection' import { aboutTheAccidentSection } from './aboutTheAccidentSection' export const AccidentNotificationForm: Form = buildForm({ @@ -18,8 +14,6 @@ export const AccidentNotificationForm: Form = buildForm({ logo: Logo, mode: FormModes.DRAFT, children: [ - betaTestSection, - externalDataSection, applicantInformationSection, whoIsTheNotificationForSection, aboutTheAccidentSection, diff --git a/libs/application/templates/accident-notification/src/forms/AccidentNotificationForm/whoIsTheNotificationForSection/juridicialPersonCompanySubSection.ts b/libs/application/templates/accident-notification/src/forms/AccidentNotificationForm/whoIsTheNotificationForSection/juridicialPersonCompanySubSection.ts index 45ec29a5a2a7..5d747453c1d0 100644 --- a/libs/application/templates/accident-notification/src/forms/AccidentNotificationForm/whoIsTheNotificationForSection/juridicialPersonCompanySubSection.ts +++ b/libs/application/templates/accident-notification/src/forms/AccidentNotificationForm/whoIsTheNotificationForSection/juridicialPersonCompanySubSection.ts @@ -6,7 +6,7 @@ import { } from '@island.is/application/core' import { juridicalPerson } from '../../../lib/messages' import { isReportingOnBehalfOfEmployee } from '../../../utils' -import { YES } from '../../../constants' +import { YES } from '../../../utils/constants' export const juridicalPersonCompanySubSection = buildSubSection({ id: 'juridicalPerson.company', diff --git a/libs/application/templates/accident-notification/src/forms/AccidentNotificationForm/whoIsTheNotificationForSection/powerOfAttorneyUploadSubSection.ts b/libs/application/templates/accident-notification/src/forms/AccidentNotificationForm/whoIsTheNotificationForSection/powerOfAttorneyUploadSubSection.ts index d3defa608ae5..00ec8aff756d 100644 --- a/libs/application/templates/accident-notification/src/forms/AccidentNotificationForm/whoIsTheNotificationForSection/powerOfAttorneyUploadSubSection.ts +++ b/libs/application/templates/accident-notification/src/forms/AccidentNotificationForm/whoIsTheNotificationForSection/powerOfAttorneyUploadSubSection.ts @@ -5,7 +5,7 @@ import { buildSubSection, } from '@island.is/application/core' import { error, powerOfAttorney } from '../../../lib/messages' -import { FILE_SIZE_LIMIT, UPLOAD_ACCEPT } from '../../../constants' +import { FILE_SIZE_LIMIT, UPLOAD_ACCEPT } from '../../../utils/constants' import { isUploadNow } from '../../../utils/isUploadNow' export const powerOfAttorneyUploadSubSection = buildSubSection({ diff --git a/libs/application/templates/accident-notification/src/forms/AccidentNotificationForm/whoIsTheNotificationForSection/whoIsTheNotificationForMultiField.ts b/libs/application/templates/accident-notification/src/forms/AccidentNotificationForm/whoIsTheNotificationForSection/whoIsTheNotificationForMultiField.ts index 766ea3128bc2..d59f1f345a83 100644 --- a/libs/application/templates/accident-notification/src/forms/AccidentNotificationForm/whoIsTheNotificationForSection/whoIsTheNotificationForMultiField.ts +++ b/libs/application/templates/accident-notification/src/forms/AccidentNotificationForm/whoIsTheNotificationForSection/whoIsTheNotificationForMultiField.ts @@ -1,34 +1,33 @@ import { buildMultiField, buildRadioField } from '@island.is/application/core' import { whoIsTheNotificationFor } from '../../../lib/messages' -import { WhoIsTheNotificationForEnum } from '../../../types' +import { + whoIsTheNotificationForOptions, + whoIsTheNotificationForProcureOptions, +} from '../../../utils/getWhoIstheNotificationForOptions' export const whoIsTheNotificationForMultiField = buildMultiField({ id: 'whoIsTheNotificationFor', title: whoIsTheNotificationFor.general.heading, - description: whoIsTheNotificationFor.general.description, + description: (application) => { + if (application.externalData.identity) { + return whoIsTheNotificationFor.general.procureDescription + } + return whoIsTheNotificationFor.general.description + }, children: [ buildRadioField({ id: 'whoIsTheNotificationFor.answer', title: '', width: 'half', - options: [ - { - value: WhoIsTheNotificationForEnum.ME, - label: whoIsTheNotificationFor.labels.me, - }, - { - value: WhoIsTheNotificationForEnum.POWEROFATTORNEY, - label: whoIsTheNotificationFor.labels.powerOfAttorney, - }, - { - value: WhoIsTheNotificationForEnum.JURIDICALPERSON, - label: whoIsTheNotificationFor.labels.juridicalPerson, - }, - { - value: WhoIsTheNotificationForEnum.CHILDINCUSTODY, - label: whoIsTheNotificationFor.labels.childInCustody, - }, - ], + condition: (_answers, externalData) => !externalData.identity, + options: whoIsTheNotificationForOptions, + }), + buildRadioField({ + id: 'whoIsTheNotificationFor.answer', + title: '', + width: 'half', + condition: (_answers, externalData) => !!externalData.identity, + options: whoIsTheNotificationForProcureOptions, }), ], }) diff --git a/libs/application/templates/accident-notification/src/forms/InReviewForm/addAttachmentsSection.ts b/libs/application/templates/accident-notification/src/forms/InReviewForm/addAttachmentsSection.ts index 13d264c39118..f0c88a39c67a 100644 --- a/libs/application/templates/accident-notification/src/forms/InReviewForm/addAttachmentsSection.ts +++ b/libs/application/templates/accident-notification/src/forms/InReviewForm/addAttachmentsSection.ts @@ -7,7 +7,7 @@ import { buildSubmitField, } from '@island.is/application/core' import { DefaultEvents, FormValue } from '@island.is/application/types' -import { FILE_SIZE_LIMIT, UPLOAD_ACCEPT } from '../../constants' +import { FILE_SIZE_LIMIT, UPLOAD_ACCEPT } from '../../utils/constants' import { addDocuments, error } from '../../lib/messages' import { hasReceivedInjuryCertificate, diff --git a/libs/application/templates/accident-notification/src/forms/PrerequisitesForm/dataHandlingSection.ts b/libs/application/templates/accident-notification/src/forms/PrerequisitesForm/dataHandlingSection.ts new file mode 100644 index 000000000000..240af507eadb --- /dev/null +++ b/libs/application/templates/accident-notification/src/forms/PrerequisitesForm/dataHandlingSection.ts @@ -0,0 +1,30 @@ +import { + buildDescriptionField, + buildMultiField, + buildSection, +} from '@island.is/application/core' +import { externalData } from '../../lib/messages' + +export const dataHandlingSection = buildSection({ + id: 'ExternalDataSection', + title: externalData.agreementDescription.listTitle, + children: [ + buildMultiField({ + title: externalData.agreementDescription.sectionTitle, + id: 'agreementDescriptionMultiField', + space: 2, + children: [ + buildDescriptionField({ + id: 'agreementDescriptionDescriptionField', + title: '', + description: externalData.agreementDescription.bullets, + }), + buildDescriptionField({ + id: 'moreInformation', + title: '', + description: externalData.agreementDescription.moreInformation, + }), + ], + }), + ], +}) diff --git a/libs/application/templates/accident-notification/src/forms/AccidentNotificationForm/externalDataSection/accidentNotificationSubSection.ts b/libs/application/templates/accident-notification/src/forms/PrerequisitesForm/externalDataSection.ts similarity index 74% rename from libs/application/templates/accident-notification/src/forms/AccidentNotificationForm/externalDataSection/accidentNotificationSubSection.ts rename to libs/application/templates/accident-notification/src/forms/PrerequisitesForm/externalDataSection.ts index 9551bdb5bad5..9edaba894625 100644 --- a/libs/application/templates/accident-notification/src/forms/AccidentNotificationForm/externalDataSection/accidentNotificationSubSection.ts +++ b/libs/application/templates/accident-notification/src/forms/PrerequisitesForm/externalDataSection.ts @@ -1,13 +1,15 @@ import { buildDataProviderItem, buildExternalDataProvider, - buildSubSection, + buildSection, + buildSubmitField, + coreMessages, } from '@island.is/application/core' -import { externalData } from '../../../lib/messages' -import { NationalRegistryUserApi } from '@island.is/application/types' +import { externalData } from '../../lib/messages' +import { NationalRegistryUserApi } from '../../dataProviders' -export const accidentNotificationSubSection = buildSubSection({ - id: 'AccidentNotificationForm', +export const externalDataSection = buildSection({ + id: 'ExternalDataRegularSection', title: externalData.dataProvider.sectionTitle, children: [ buildExternalDataProvider({ @@ -16,6 +18,19 @@ export const accidentNotificationSubSection = buildSubSection({ subTitle: externalData.dataProvider.subTitle, description: '', checkboxLabel: externalData.dataProvider.checkboxLabel, + submitField: buildSubmitField({ + id: 'submit', + placement: 'footer', + title: '', + refetchApplicationAfterSubmit: true, + actions: [ + { + event: 'SUBMIT', + name: coreMessages.buttonNext, + type: 'primary', + }, + ], + }), dataProviders: [ buildDataProviderItem({ id: 'directoryOfLabor', diff --git a/libs/application/templates/accident-notification/src/forms/PrerequisitesForm/index.ts b/libs/application/templates/accident-notification/src/forms/PrerequisitesForm/index.ts new file mode 100644 index 000000000000..89c7e17800ad --- /dev/null +++ b/libs/application/templates/accident-notification/src/forms/PrerequisitesForm/index.ts @@ -0,0 +1,15 @@ +import { buildForm } from '@island.is/application/core' +import { Form } from '@island.is/application/types' +import { application } from '../../lib/messages' +import Logo from '../../assets/Logo' +import { dataHandlingSection } from './dataHandlingSection' +import { externalDataSection } from './externalDataSection' + +export const PrerequisitesForm: Form = buildForm({ + id: 'PrerequisitesForm', + title: application.general.name, + logo: Logo, + renderLastScreenButton: true, + renderLastScreenBackButton: true, + children: [dataHandlingSection, externalDataSection], +}) diff --git a/libs/application/templates/accident-notification/src/forms/PrerequisitesProcureForm/externalDataSection.ts b/libs/application/templates/accident-notification/src/forms/PrerequisitesProcureForm/externalDataSection.ts new file mode 100644 index 000000000000..8cf32a765fd2 --- /dev/null +++ b/libs/application/templates/accident-notification/src/forms/PrerequisitesProcureForm/externalDataSection.ts @@ -0,0 +1,43 @@ +import { + buildDataProviderItem, + buildExternalDataProvider, + buildSection, + buildSubmitField, + coreMessages, +} from '@island.is/application/core' +import { externalData } from '../../lib/messages' +import { IdentityApi } from '../../dataProviders' + +export const externalDataSection = buildSection({ + id: 'ExternalDataProcureSection', + title: externalData.agreementDescription.listTitle, + children: [ + buildExternalDataProvider({ + title: externalData.dataProvider.pageTitle, + id: 'approveExternalData', + subTitle: externalData.dataProvider.subTitle, + description: '', + checkboxLabel: externalData.dataProvider.checkboxLabel, + submitField: buildSubmitField({ + id: 'submit', + placement: 'footer', + title: '', + refetchApplicationAfterSubmit: true, + actions: [ + { + event: 'SUBMIT', + name: coreMessages.buttonNext, + type: 'primary', + }, + ], + }), + dataProviders: [ + buildDataProviderItem({ + provider: IdentityApi, + title: externalData.nationalRegistry.title, + subTitle: externalData.nationalRegistry.subTitle, + }), + ], + }), + ], +}) diff --git a/libs/application/templates/accident-notification/src/forms/PrerequisitesProcureForm/index.ts b/libs/application/templates/accident-notification/src/forms/PrerequisitesProcureForm/index.ts new file mode 100644 index 000000000000..f792bfe3737a --- /dev/null +++ b/libs/application/templates/accident-notification/src/forms/PrerequisitesProcureForm/index.ts @@ -0,0 +1,15 @@ +import { buildForm } from '@island.is/application/core' +import { Form } from '@island.is/application/types' +import { application } from '../../lib/messages' +import Logo from '../../assets/Logo' +import { dataHandlingSection } from '../PrerequisitesForm/dataHandlingSection' +import { externalDataSection } from './externalDataSection' + +export const PrerequisitesProcureForm: Form = buildForm({ + id: 'PrerequisitesProcureForm', + title: application.general.name, + logo: Logo, + renderLastScreenButton: true, + renderLastScreenBackButton: true, + children: [dataHandlingSection, externalDataSection], +}) diff --git a/libs/application/templates/accident-notification/src/lib/AccidentNotificationTemplate.ts b/libs/application/templates/accident-notification/src/lib/AccidentNotificationTemplate.ts index 064f8b9d2530..e28f58669588 100644 --- a/libs/application/templates/accident-notification/src/lib/AccidentNotificationTemplate.ts +++ b/libs/application/templates/accident-notification/src/lib/AccidentNotificationTemplate.ts @@ -14,30 +14,33 @@ import { ApplicationTypes, DefaultEvents, defineTemplateApi, - NationalRegistryUserApi, PendingAction, + FormModes, } from '@island.is/application/types' import set from 'lodash/set' import { assign } from 'xstate' import { AccidentTypeEnum, ReviewApprovalEnum } from '..' -import { States } from '../constants' +import { States } from '../utils/constants' import { ApiActions } from '../shared' import { WhoIsTheNotificationForEnum } from '../types' import { AccidentNotificationSchema } from './dataSchema' import { anPendingActionMessages, application } from './messages' +import { AuthDelegationType } from '@island.is/shared/types' +import { IdentityApi, NationalRegistryUserApi } from '../dataProviders' // The applicant is the applicant of the application, can be someone in power of attorney or the representative for the company // The assignee is the person who is assigned to review the application can be the injured person or the representative for the company // The assignee should see all data related to the application being submitted to sjukra but not data only relevant to applicant enum Roles { + PROCURER = 'procurer', APPLICANT = 'applicant', ASSIGNEE = 'assignee', } type AccidentNotificationEvent = | { type: DefaultEvents.APPROVE } - | { type: DefaultEvents.SUBMIT } | { type: DefaultEvents.REJECT } + | { type: DefaultEvents.SUBMIT } | { type: DefaultEvents.ASSIGN } const assignStatePendingAction = ( @@ -61,7 +64,7 @@ const assignStatePendingAction = ( } const reviewStatePendingAction = ( - application: Application, + _application: Application, role: string, ): PendingAction => { if (role === Roles.ASSIGNEE) { @@ -91,15 +94,72 @@ const AccidentNotificationTemplate: ApplicationTemplate< ApplicationConfigurations.AccidentNotification.translation, ], dataSchema: AccidentNotificationSchema, + allowedDelegations: [ + { + type: AuthDelegationType.ProcurationHolder, + }, + { + type: AuthDelegationType.Custom, + }, + ], stateMachineConfig: { - initial: States.DRAFT, + initial: States.PREREQUISITES, states: { + [States.PREREQUISITES]: { + meta: { + name: application.general.name.defaultMessage, + progress: 0, + lifecycle: DefaultStateLifeCycle, + status: FormModes.DRAFT, + actionCard: { + historyLogs: [ + { + onEvent: DefaultEvents.SUBMIT, + logMessage: coreHistoryMessages.applicationStarted, + }, + ], + }, + roles: [ + { + id: Roles.APPLICANT, + formLoader: () => + import('../forms/PrerequisitesForm').then((val) => + Promise.resolve(val.PrerequisitesForm), + ), + actions: [ + { event: 'SUBMIT', name: 'Staðfesta', type: 'primary' }, + ], + write: 'all', + api: [NationalRegistryUserApi, IdentityApi], + delete: true, + }, + { + id: Roles.PROCURER, + formLoader: () => + import('../forms/PrerequisitesProcureForm').then((val) => + Promise.resolve(val.PrerequisitesProcureForm), + ), + actions: [ + { event: 'SUBMIT', name: 'Staðfesta', type: 'primary' }, + ], + write: 'all', + api: [NationalRegistryUserApi, IdentityApi], + delete: true, + }, + ], + }, + on: { + [DefaultEvents.SUBMIT]: { + target: States.DRAFT, + }, + }, + }, [States.DRAFT]: { meta: { name: application.general.name.defaultMessage, progress: 0.4, lifecycle: DefaultStateLifeCycle, - status: 'draft', + status: FormModes.DRAFT, actionCard: { historyLogs: [ { @@ -122,6 +182,19 @@ const AccidentNotificationTemplate: ApplicationTemplate< api: [NationalRegistryUserApi], delete: true, }, + { + id: Roles.PROCURER, + formLoader: () => + import('../forms/AccidentNotificationForm/index').then((val) => + Promise.resolve(val.AccidentNotificationForm), + ), + actions: [ + { event: 'SUBMIT', name: 'Staðfesta', type: 'primary' }, + ], + write: 'all', + api: [NationalRegistryUserApi], + delete: true, + }, ], }, on: { @@ -346,17 +419,16 @@ const AccidentNotificationTemplate: ApplicationTemplate< id: string, application: Application, ): ApplicationRole | undefined { - if (id === application.applicant && application.assignees.includes(id)) { - return Roles.ASSIGNEE - } + const { applicant, applicantActors, assignees } = application - if (id === application.applicant) { + if (id === applicant) { + if (applicantActors.length) return Roles.PROCURER + if (assignees.includes(id)) return Roles.ASSIGNEE return Roles.APPLICANT } - if (application.assignees.includes(id)) { - return Roles.ASSIGNEE - } + if (assignees.includes(id)) return Roles.ASSIGNEE + return undefined }, } diff --git a/libs/application/templates/accident-notification/src/lib/dataSchema.ts b/libs/application/templates/accident-notification/src/lib/dataSchema.ts index a9ee0e7b182b..afb53946fe3b 100644 --- a/libs/application/templates/accident-notification/src/lib/dataSchema.ts +++ b/libs/application/templates/accident-notification/src/lib/dataSchema.ts @@ -1,7 +1,7 @@ import { applicantInformationSchema } from '@island.is/application/ui-forms' import * as kennitala from 'kennitala' import { z } from 'zod' -import { YES } from '../constants' +import { YES } from '../utils/constants' import { AccidentTypeEnum, AgricultureAccidentLocationEnum, diff --git a/libs/application/templates/accident-notification/src/lib/messages/applicantInformation.ts b/libs/application/templates/accident-notification/src/lib/messages/applicantInformation.ts index 9c9a7954b983..e02b7d08abc8 100644 --- a/libs/application/templates/accident-notification/src/lib/messages/applicantInformation.ts +++ b/libs/application/templates/accident-notification/src/lib/messages/applicantInformation.ts @@ -55,6 +55,18 @@ export const applicantInformation = { description: 'Telephone number', }, }), + procure: defineMessages({ + titill: { + id: 'an.application:applicantInfo.procure.title', + defaultMessage: 'Upplýsingar um ', + description: 'Name of the procure identity', + }, + name: { + id: 'an.application:applicantInfo.procure.name', + defaultMessage: 'Nafn', + description: 'Name of the procure identity', + }, + }), forThirdParty: defineMessages({ title: { id: 'an.application:applicantInfo.forThirdParty.title', diff --git a/libs/application/templates/accident-notification/src/lib/messages/externalData.ts b/libs/application/templates/accident-notification/src/lib/messages/externalData.ts index 017a2fefda6f..869618dbdc54 100644 --- a/libs/application/templates/accident-notification/src/lib/messages/externalData.ts +++ b/libs/application/templates/accident-notification/src/lib/messages/externalData.ts @@ -12,30 +12,24 @@ export const externalData = { defaultMessage: 'Meðferð á gögnum', description: 'Data handling list item title', }, - bulletOne: { - id: 'an.application:section.agreementDescription.BulletOne', - defaultMessage: - 'Þegar tilkynning um slys er send Sjúkratryggingum Íslands mun stofnunin miðla upplýsingum um afstöðu til bótaskyldu með þeim atvinnurekanda eða íþróttafélagi sem á í hlut. Ástæðan þess er að umræddir aðilar kunna að eiga rétt á endurgreiðslu útlagðs kostnaðar og/eða dagpeningum ef greidd hafa verið laun í veikindaforföllum vegna slyssins. Þessir aðilar fá aldrei afhentar heilsufars- eða sjúkraskrárupplýsingar.', - description: 'List item 1 on data gathering information', - }, - bulletTwo: { - id: 'an.application:section.agreementDescription.BulletTwo', - defaultMessage: - 'Vinnueftirlit ríkisins kann einnig að fá afrit af tilkynningunni undir ákveðnum kringumstæðum á grundvelli 4. mgr. 79. gr. laga nr. 46/1980 sem og Rannsóknarnefnd samgönguslysa á grundvelli 12. og 16. gr. laga nr. 18/2013.', - description: 'List item 2 on data gathering information', - }, - bulletThree: { - id: 'an.application:section.agreementDescription.BulletThree', - defaultMessage: - 'Eitthvað óvænt verður að hafa gerst sem veldur tjóni á líkama hins tryggða og áhorfandi getur áttað sig á að hafi gerst.', - description: 'List item 3 on data gathering information', - }, bulletFour: { id: 'an.application:section.agreementDescription.BulletFour', defaultMessage: 'Ef tilkynningaskylda er vanrækt skal það ekki vera því til fyrirstöðu að sá slasaði eða vandamenn geti gert kröfu til bóta. Heimilt er að veita undanþágu þótt meira en ár sé liðið ef atvik slyss eru alveg ljós og drátturinn torveldar ekki gagnaöflun um atriði sem skipta máli. Þá er það skilyrði að unnt sé að meta orsakasamband slyssins og heilsutjóns slasaða.', description: 'List item 4 on data gathering information', }, + bullets: { + id: 'an.application:section.agreementDescription.bullets#markdown', + defaultMessage: + '* Þegar tilkynning um slys er send Sjúkratryggingum Íslands mun stofnunin miðla upplýsingum um afstöðu til bótaskyldu með þeim atvinnurekanda eða íþróttafélagi sem á í hlut. Ástæða þess er að umræddir aðilar kunna að eiga rétt á endurgreiðslu útlagðs kostnaðar og/eða dagpeningum ef greidd hafa verið laun í veikindaforföllum vegna slyssins. Þessir aðilar fá aldrei afhentar heilsufars- eða sjúkraskrárupplýsingar. \n\n* Vinnueftirlit ríkisins kann einnig að fá afrit af tilkynningunni undir ákveðnum kringumstæðum á grundvelli 4. mgr. 79. gr. laga nr. 46/1980 sem og Rannsóknarnefnd samgönguslysa á grundvelli 12. og 16. gr. laga nr. 18/2013. \n\n* Eitthvað óvænt verður að hafa gerst sem veldur tjóni á líkama hins tryggða og áhorfandi getur áttað sig á að hafi gerst.', + description: 'Information on data handling before prerequisites', + }, + moreInformation: { + id: 'an.application:section.agreementDescription.moreInformation#markdown', + defaultMessage: + 'Nánari upplýsingar um vinnslu persónuupplýsinga hjá Sjúkratryggingum Íslands á [Persónuverndarsíðu Sjúkratrygginga](https://www.sjukra.is/personuvernd)', + description: 'More information about data handling', + }, }), dataProvider: defineMessages({ sectionTitle: { @@ -72,6 +66,16 @@ export const externalData = { 'Upplýsingar um nafn, kennitölu og heimilisfang. Upplýsingar um börn og maka.', description: 'Description: National Registry', }, + procureDescription: { + id: 'an.application:section.externalData.nationalRegistry.procureDescription', + defaultMessage: 'Upplýsingar um nafn, kennitölu og heimilisfang.', + description: 'Description: National Registry for procure holder', + }, + subTitle: { + id: 'an.application:section.externalData.nationalRegistry.subTitle', + defaultMessage: 'Hér sækjum við nafn, kennitölu og heimilisfang', + description: 'We will fetch name, national id and address', + }, }), accidentProvider: defineMessages({ title: { @@ -152,22 +156,4 @@ export const externalData = { 'Approval of gathering information from Approval of Municipal Collection Agency', }, }), - extraInformation: defineMessages({ - description: { - id: 'an.application:section.externalData.extraInformation.descriptionFirstPart', - defaultMessage: - 'Nánari upplýsingar um vinnslu persónuupplýsinga hjá Sjúkratryggingum Íslands ', - description: 'Description for link in extrainformation', - }, - linkText: { - id: 'an.application:section.externalData.extraInformation.linkText', - defaultMessage: 'Persónuverndarsíðu SÍ.', - description: 'Link text for link', - }, - link: { - id: 'an.application:section.externalData.extraInformation.link', - defaultMessage: 'https://www.sjukra.is/personuvernd.', - description: 'The url the link text links to', - }, - }), } diff --git a/libs/application/templates/accident-notification/src/lib/messages/whoIsTheNotificationFor.ts b/libs/application/templates/accident-notification/src/lib/messages/whoIsTheNotificationFor.ts index 0c5a1b8195b3..035a2a62108f 100644 --- a/libs/application/templates/accident-notification/src/lib/messages/whoIsTheNotificationFor.ts +++ b/libs/application/templates/accident-notification/src/lib/messages/whoIsTheNotificationFor.ts @@ -17,6 +17,11 @@ export const whoIsTheNotificationFor = { defaultMessage: `Hægt er að tilkynna slys í eigin nafni , fyrir aðra einstaklinga sem þú ert með skriflegt umboð frá eða fyrir starfsmann lögaðila. Foreldrar og forráðamenn geta líka sent inn tilkynningu fyrir hönd barna sem þeir fara með forsjá yfir. Stofnanir, samtök og félög sem eru virk á sviði persónuverndar geta sent inn tilkynningu án umboðs að uppfylltum skilyrðum 80. gr. reglugerðar (ESB) 2016/679 (almennu persónuverndarreglugerðarinnar).`, description: 'Description for who is the notifaction for', }, + procureDescription: { + id: 'an.application:whoIsTheNotificationFor.procureDescription', + defaultMessage: `Í umboði er hægt að tilkynna slys fyrir einstaklinga sem þú ert með umboð frá eða fyrir starfsmann lögaðila. Foreldrar og forráðamenn geta líka sent inn tilkynningu fyrir hönd barna sem þeir fara með forsjá yfir. Stofnanir, samtök og félög sem eru virk á sviði persónuverndar geta sent inn tilkynningu án umboðs að uppfylltum skilyrðum 80. gr. reglugerðar (ESB) 2016/679 (almennu persónuverndarreglugerðarinnar).`, + description: 'Description for who is the notifaction for', + }, }), labels: defineMessages({ juridicalPerson: { @@ -34,6 +39,11 @@ export const whoIsTheNotificationFor = { defaultMessage: 'Í umboði fyrir annan einstakling', description: 'Label for power of attorney option', }, + powerOfAttorneyProcure: { + id: 'an.application:whoIsTheNotificationFor.labels.powerOfAttorneyProcure', + defaultMessage: 'Einstakling', + description: 'Label for power of attorney option', + }, childInCustody: { id: 'an.application:whoIsTheNotificationFor.labels.childInCustody', defaultMessage: 'Fyrir barn í minni forsjá', diff --git a/libs/application/templates/accident-notification/src/types/index.ts b/libs/application/templates/accident-notification/src/types/index.ts index 1b3694a9b695..da316a4fd5f7 100644 --- a/libs/application/templates/accident-notification/src/types/index.ts +++ b/libs/application/templates/accident-notification/src/types/index.ts @@ -1,4 +1,4 @@ -import { NO, YES } from './../constants' +import { NO, YES } from '../utils/constants' export type CompanyInfo = { nationalRegistrationId: string @@ -58,11 +58,6 @@ export enum ChoiceEnum { NO = 'no', } -export enum DataProviderTypes { - NationalRegistry = 'NationalRegistryProvider', - UserProfile = 'UserProfileProvider', -} - export enum WhoIsTheNotificationForEnum { JURIDICALPERSON = 'juridicalPerson', ME = 'me', diff --git a/libs/application/templates/accident-notification/src/constants/index.ts b/libs/application/templates/accident-notification/src/utils/constants/index.ts similarity index 90% rename from libs/application/templates/accident-notification/src/constants/index.ts rename to libs/application/templates/accident-notification/src/utils/constants/index.ts index f17e43d36595..c13413335ab9 100644 --- a/libs/application/templates/accident-notification/src/constants/index.ts +++ b/libs/application/templates/accident-notification/src/utils/constants/index.ts @@ -7,6 +7,7 @@ export const FILE_SIZE_LIMIT = 10000000 // 10MB export enum States { // Draft flow + PREREQUISITES = 'prerequisites', DRAFT = 'draft', REVIEW = 'review', REVIEW_ADD_ATTACHMENT = 'reviewAddAttachment', diff --git a/libs/application/templates/accident-notification/src/utils/getWhoIstheNotificationForOptions.ts b/libs/application/templates/accident-notification/src/utils/getWhoIstheNotificationForOptions.ts new file mode 100644 index 000000000000..28910229cf83 --- /dev/null +++ b/libs/application/templates/accident-notification/src/utils/getWhoIstheNotificationForOptions.ts @@ -0,0 +1,32 @@ +import { WhoIsTheNotificationForEnum } from '../types' +import { whoIsTheNotificationFor } from '../lib/messages' + +export const whoIsTheNotificationForOptions = [ + { + value: WhoIsTheNotificationForEnum.ME, + label: whoIsTheNotificationFor.labels.me, + }, + { + value: WhoIsTheNotificationForEnum.POWEROFATTORNEY, + label: whoIsTheNotificationFor.labels.powerOfAttorney, + }, + { + value: WhoIsTheNotificationForEnum.JURIDICALPERSON, + label: whoIsTheNotificationFor.labels.juridicalPerson, + }, + { + value: WhoIsTheNotificationForEnum.CHILDINCUSTODY, + label: whoIsTheNotificationFor.labels.childInCustody, + }, +] + +export const whoIsTheNotificationForProcureOptions = [ + { + value: WhoIsTheNotificationForEnum.POWEROFATTORNEY, + label: whoIsTheNotificationFor.labels.powerOfAttorneyProcure, + }, + { + value: WhoIsTheNotificationForEnum.JURIDICALPERSON, + label: whoIsTheNotificationFor.labels.juridicalPerson, + }, +] diff --git a/libs/application/templates/accident-notification/src/utils/getWorkplaceData.spec.ts b/libs/application/templates/accident-notification/src/utils/getWorkplaceData.spec.ts index 83bd9755d9ad..45a3cb6d6a11 100644 --- a/libs/application/templates/accident-notification/src/utils/getWorkplaceData.spec.ts +++ b/libs/application/templates/accident-notification/src/utils/getWorkplaceData.spec.ts @@ -1,5 +1,5 @@ import { FormValue } from '@island.is/application/types' -import { YES } from '../constants' +import { YES } from './constants' import { AccidentTypeEnum, WorkAccidentTypeEnum } from '../types' import { getWorkplaceData } from './getWorkplaceData' diff --git a/libs/application/templates/accident-notification/src/utils/hasMissingDocuments.spec.ts b/libs/application/templates/accident-notification/src/utils/hasMissingDocuments.spec.ts index b36f131d049a..945c4858ce4f 100644 --- a/libs/application/templates/accident-notification/src/utils/hasMissingDocuments.spec.ts +++ b/libs/application/templates/accident-notification/src/utils/hasMissingDocuments.spec.ts @@ -4,7 +4,7 @@ import { hasReceivedAllDocuments, } from './hasMissingDocuments' import { WhoIsTheNotificationForEnum, AttachmentsEnum } from '../types' -import { NO, YES } from '../constants' +import { NO, YES } from './constants' import { FormatMessage } from '@island.is/localization' import { FormValue } from '@island.is/application/types' import { AccidentNotification } from '../lib/dataSchema' diff --git a/libs/application/templates/accident-notification/src/utils/hasMissingDocuments.ts b/libs/application/templates/accident-notification/src/utils/hasMissingDocuments.ts index 3c53fe8daf71..d262c07b6226 100644 --- a/libs/application/templates/accident-notification/src/utils/hasMissingDocuments.ts +++ b/libs/application/templates/accident-notification/src/utils/hasMissingDocuments.ts @@ -2,7 +2,7 @@ import { getValueViaPath } from '@island.is/application/core' import { FormValue } from '@island.is/application/types' import { FormatMessage } from '@island.is/localization' import { AttachmentsEnum, FileType, WhoIsTheNotificationForEnum } from '..' -import { YES } from '../constants' +import { YES } from './constants' import { attachments } from '../lib/messages' import { AccidentNotificationAttachmentStatus, diff --git a/libs/application/templates/accident-notification/src/utils/index.spec.ts b/libs/application/templates/accident-notification/src/utils/index.spec.ts index 33d834780e7d..9bde4080715f 100644 --- a/libs/application/templates/accident-notification/src/utils/index.spec.ts +++ b/libs/application/templates/accident-notification/src/utils/index.spec.ts @@ -1,5 +1,5 @@ import { FormatMessage } from '@island.is/localization' -import { YES } from '../constants' +import { YES } from './constants' import { AccidentNotification } from '../lib/dataSchema' import { AttachmentsEnum, WhoIsTheNotificationForEnum } from '../types' import { diff --git a/libs/application/templates/accident-notification/src/utils/index.ts b/libs/application/templates/accident-notification/src/utils/index.ts index 969019bb45bf..2c1059df92f6 100644 --- a/libs/application/templates/accident-notification/src/utils/index.ts +++ b/libs/application/templates/accident-notification/src/utils/index.ts @@ -1,6 +1,6 @@ import { AttachmentsEnum, FileType, WhoIsTheNotificationForEnum } from '..' import { getValueViaPath } from '@island.is/application/core' -import { YES } from '../constants' +import { YES } from './constants' import { AccidentNotification } from '../lib/dataSchema' import { attachments, overview } from '../lib/messages' import { FormatMessage } from '@island.is/localization' diff --git a/libs/application/templates/accident-notification/src/utils/isFatalAccident.spec.ts b/libs/application/templates/accident-notification/src/utils/isFatalAccident.spec.ts index e1e2118355d3..67b9f7bb25ec 100644 --- a/libs/application/templates/accident-notification/src/utils/isFatalAccident.spec.ts +++ b/libs/application/templates/accident-notification/src/utils/isFatalAccident.spec.ts @@ -1,6 +1,6 @@ import { FormValue } from '@island.is/application/types' import { isFatalAccident } from './isFatalAccident' -import { NO, YES } from '../constants' +import { NO, YES } from './constants' describe('isFatalAccident', () => { const fatal: FormValue = { diff --git a/libs/application/templates/accident-notification/src/utils/isFatalAccident.ts b/libs/application/templates/accident-notification/src/utils/isFatalAccident.ts index 3866ad16930f..4094c3efbc99 100644 --- a/libs/application/templates/accident-notification/src/utils/isFatalAccident.ts +++ b/libs/application/templates/accident-notification/src/utils/isFatalAccident.ts @@ -1,6 +1,6 @@ import { getValueViaPath } from '@island.is/application/core' import { FormValue } from '@island.is/application/types' -import { YES } from '../constants' +import { YES } from './constants' import { YesOrNo } from '../types' export const isFatalAccident = (formValue: FormValue) => { diff --git a/libs/application/templates/accident-notification/src/utils/isMachineRelatedAccident.spec.ts b/libs/application/templates/accident-notification/src/utils/isMachineRelatedAccident.spec.ts index 6a66f77d0ad2..017a1e679a26 100644 --- a/libs/application/templates/accident-notification/src/utils/isMachineRelatedAccident.spec.ts +++ b/libs/application/templates/accident-notification/src/utils/isMachineRelatedAccident.spec.ts @@ -1,5 +1,5 @@ import { FormValue } from '@island.is/application/types' -import { NO, YES } from '../constants' +import { NO, YES } from './constants' import { AccidentTypeEnum, WorkAccidentTypeEnum } from '../types' import { isMachineRelatedAccident } from './isMachineRelatedAccident' describe('isMachineRelatedAccident', () => { diff --git a/libs/application/templates/accident-notification/src/utils/isMachineRelatedAccident.ts b/libs/application/templates/accident-notification/src/utils/isMachineRelatedAccident.ts index 627f2da6c98b..fd3cabc5347b 100644 --- a/libs/application/templates/accident-notification/src/utils/isMachineRelatedAccident.ts +++ b/libs/application/templates/accident-notification/src/utils/isMachineRelatedAccident.ts @@ -1,6 +1,6 @@ import { getValueViaPath } from '@island.is/application/core' import { FormValue } from '@island.is/application/types' -import { YES } from '../constants' +import { YES } from './constants' import { YesOrNo } from '../types' import { isGeneralWorkplaceAccident } from './isGeneralWorkplaceAccident' diff --git a/libs/application/templates/accident-notification/src/utils/isRepresentativeOfCompanyOrInstitute.spec.ts b/libs/application/templates/accident-notification/src/utils/isRepresentativeOfCompanyOrInstitute.spec.ts index f1ce2bcfd63c..aeff9475efef 100644 --- a/libs/application/templates/accident-notification/src/utils/isRepresentativeOfCompanyOrInstitute.spec.ts +++ b/libs/application/templates/accident-notification/src/utils/isRepresentativeOfCompanyOrInstitute.spec.ts @@ -5,7 +5,7 @@ import { isInjuredAndRepresentativeOfCompanyOrInstitute, isRepresentativeOfCompanyOrInstitute, } from './isRepresentativeOfCompanyOrInstitute' -import { NO, YES } from '../constants' +import { NO, YES } from './constants' const emptyObject = {} diff --git a/libs/application/templates/accident-notification/src/utils/isRepresentativeOfCompanyOrInstitute.ts b/libs/application/templates/accident-notification/src/utils/isRepresentativeOfCompanyOrInstitute.ts index 77ba93c9a40a..f8c98b7b61f5 100644 --- a/libs/application/templates/accident-notification/src/utils/isRepresentativeOfCompanyOrInstitute.ts +++ b/libs/application/templates/accident-notification/src/utils/isRepresentativeOfCompanyOrInstitute.ts @@ -1,6 +1,6 @@ import { getValueViaPath } from '@island.is/application/core' import { FormValue } from '@island.is/application/types' -import { YES } from '../constants' +import { YES } from './constants' import { WhoIsTheNotificationForEnum } from '../types' export const isRepresentativeOfCompanyOrInstitute = (formValue: FormValue) => { diff --git a/libs/application/templates/announcement-of-death/src/types/index.ts b/libs/application/templates/announcement-of-death/src/types/index.ts index 191ffbeb2b7c..537b31b4a217 100644 --- a/libs/application/templates/announcement-of-death/src/types/index.ts +++ b/libs/application/templates/announcement-of-death/src/types/index.ts @@ -22,7 +22,3 @@ export interface Child { export interface NationalRegistry extends Person { children: Child[] } - -export enum DataProviderTypes { - NationalRegistry = 'NationalRegistryProvider', -} diff --git a/libs/application/templates/aosh/work-accident-notification/src/fields/Components/CausesAndEffects.tsx b/libs/application/templates/aosh/work-accident-notification/src/fields/Components/CausesAndEffects.tsx index fffca7636ca6..b1b44b7a04ef 100644 --- a/libs/application/templates/aosh/work-accident-notification/src/fields/Components/CausesAndEffects.tsx +++ b/libs/application/templates/aosh/work-accident-notification/src/fields/Components/CausesAndEffects.tsx @@ -62,7 +62,7 @@ export const CausesAndEffects: FC< const [pickedValue, setPickedValue] = useState() const activityGroups = ( getValueViaPath(application.externalData, externalDataKey) ?? [] - ).filter((group) => !group.validToSelect) + ).filter((group) => group.code.endsWith('0')) const activites = ( getValueViaPath(application.externalData, externalDataKey) ?? [] ).filter((group) => group.validToSelect) diff --git a/libs/application/templates/aosh/work-accident-notification/src/fields/PdfOverview/pdfDocument.tsx b/libs/application/templates/aosh/work-accident-notification/src/fields/PdfOverview/pdfDocument.tsx index 4d8cf2ada277..10560f415cd5 100644 --- a/libs/application/templates/aosh/work-accident-notification/src/fields/PdfOverview/pdfDocument.tsx +++ b/libs/application/templates/aosh/work-accident-notification/src/fields/PdfOverview/pdfDocument.tsx @@ -29,6 +29,8 @@ interface PdfDocumentProps { formatMessage: FormatMessage } +const regEx = /\*\*/g // RegEx to remove ** from the text + export const PdfDocument: FC< React.PropsWithChildren > = ({ application, formatMessage }) => { @@ -38,12 +40,12 @@ export const PdfDocument: FC< application.answers, application.externalData, formatMessage, - ) + ).map((info) => info?.replace(regEx, '')) const accidentInfo = getAccidentInformationForOverview( application.answers, application.externalData, formatMessage, - ) + ).map((info) => info?.replace(regEx, '')) return ( @@ -82,13 +84,13 @@ export const PdfDocument: FC< application.externalData, employee, formatMessage, - ) + ).map((info) => info?.replace(regEx, '')) const causeandConsequencesInfo = getCauseAndConsequencesForOverview( application.externalData, application.answers, index, formatMessage, - ) + ).map((info) => info?.replace(regEx, '')) return ( diff --git a/libs/application/templates/aosh/work-accident-notification/src/forms/WorkAccidentNotificationForm/AccidentSection/about.ts b/libs/application/templates/aosh/work-accident-notification/src/forms/WorkAccidentNotificationForm/AccidentSection/about.ts index 7c583e68c242..e3080323b7db 100644 --- a/libs/application/templates/aosh/work-accident-notification/src/forms/WorkAccidentNotificationForm/AccidentSection/about.ts +++ b/libs/application/templates/aosh/work-accident-notification/src/forms/WorkAccidentNotificationForm/AccidentSection/about.ts @@ -101,6 +101,7 @@ export const aboutSection = buildSubSection({ id: 'accident.exactLocation', title: accident.about.exactLocation, width: 'half', + placeholder: accident.about.exactLocationPlaceholder, }), buildDescriptionField({ id: 'accident.describe.descriptionHeading', diff --git a/libs/application/templates/aosh/work-accident-notification/src/lib/messages/accident.ts b/libs/application/templates/aosh/work-accident-notification/src/lib/messages/accident.ts index 185bde25b75e..d7fe4d8ea121 100644 --- a/libs/application/templates/aosh/work-accident-notification/src/lib/messages/accident.ts +++ b/libs/application/templates/aosh/work-accident-notification/src/lib/messages/accident.ts @@ -53,6 +53,11 @@ export const accident = { defaultMessage: 'Nákvæm staðsetning', description: 'Label of exact location input field', }, + exactLocationPlaceholder: { + id: 'aosh.wan.application:accident.about.exactLocationPlaceholder', + defaultMessage: 'Við vörurekka á lager', + description: 'Exact location placeholder input field', + }, describeHeading: { id: 'aosh.wan.application:accident.about.describeHeading', defaultMessage: 'Lýstu tildrögum slyssins eins nákvæmlega og þú getur', diff --git a/libs/application/templates/aosh/work-accident-notification/src/utils/getAccidentInformationForOverview.ts b/libs/application/templates/aosh/work-accident-notification/src/utils/getAccidentInformationForOverview.ts index f473d2f6cf6e..359a21c08b80 100644 --- a/libs/application/templates/aosh/work-accident-notification/src/utils/getAccidentInformationForOverview.ts +++ b/libs/application/templates/aosh/work-accident-notification/src/utils/getAccidentInformationForOverview.ts @@ -26,29 +26,29 @@ export const getAccidentInformationForOverview = ( ) return [ - `${formatMessage(overview.labels.dateAndTime)}: ${formatDate( + `**${formatMessage(overview.labels.dateAndTime)}**: ${formatDate( accident?.date ?? '', )}, ${accident?.time.slice(0, 2)}:${accident?.time.slice(2, 4)}`, - `${formatMessage(overview.labels.didAoshCome)}: ${formatMessage( + `**${formatMessage(overview.labels.didAoshCome)}**: ${formatMessage( accident?.didAoshCome === 'yes' ? shared.options.yes : shared.options.no, )}`, - `${formatMessage(overview.labels.didPoliceCome)}: ${formatMessage( + `**${formatMessage(overview.labels.didPoliceCome)}**: ${formatMessage( accident?.didPoliceCome === 'yes' ? shared.options.yes : shared.options.no, )}`, - `${formatMessage(overview.labels.injuredAmount)}: ${employees.length}`, - `${formatMessage(overview.labels.municipality)}: ${ + `**${formatMessage(overview.labels.injuredAmount)}**: ${employees.length}`, + `**${formatMessage(overview.labels.municipality)}**: ${ chosenMunicipality?.name }`, - `${formatMessage(overview.labels.exactLocation)}: ${ + `**${formatMessage(overview.labels.exactLocation)}**: ${ accident?.exactLocation }`, - `${formatMessage(overview.labels.accidentDescription)}: + `**${formatMessage(overview.labels.accidentDescription)}**: \n ${accident?.wasDoing} \n ${accident?.wentWrong} \n ${accident?.how}`, - `${formatMessage(overview.labels.locationOfAccident)}: ${ + `**${formatMessage(overview.labels.locationOfAccident)}**: ${ accident?.accidentLocation.label }`, ].filter((n) => n) diff --git a/libs/application/templates/aosh/work-accident-notification/src/utils/getCauseAndConsequencesForOverview.ts b/libs/application/templates/aosh/work-accident-notification/src/utils/getCauseAndConsequencesForOverview.ts index be1ebb673519..d6f534f112de 100644 --- a/libs/application/templates/aosh/work-accident-notification/src/utils/getCauseAndConsequencesForOverview.ts +++ b/libs/application/templates/aosh/work-accident-notification/src/utils/getCauseAndConsequencesForOverview.ts @@ -91,23 +91,23 @@ export const getCauseAndConsequencesForOverview = ( .flat() return [ - `${formatMessage(overview.causeAndConsequences.absence)}: ${ + `**${formatMessage(overview.causeAndConsequences.absence)}**: ${ chosenAbsenceDueToAccident?.name }`, - `${formatMessage( + `**${formatMessage( overview.causeAndConsequences.circumstances, - )}: ${chosenCircumstances.join('. ')}`, - `${formatMessage( + )}**: ${chosenCircumstances.join('. ')}`, + `**${formatMessage( overview.causeAndConsequences.deviations, - )}: ${chosenDeviations.join('. ')}`, - `${formatMessage( + )}**: ${chosenDeviations.join('. ')}`, + `**${formatMessage( overview.causeAndConsequences.causeOfInjury, - )}: ${chosenCauseOfInjury.join('. ')}`, - `${formatMessage( + )}**: ${chosenCauseOfInjury.join('. ')}`, + `**${formatMessage( overview.causeAndConsequences.typeOfInjury, - )}: ${chosenTypeOfInjury.join('. ')}`, - `${formatMessage( + )}**: ${chosenTypeOfInjury.join('. ')}`, + `**${formatMessage( overview.causeAndConsequences.injuredBodyParts, - )}: ${chosenInjuredBodyParts.join('. ')}`, + )}**: ${chosenInjuredBodyParts.join('. ')}`, ].filter((n) => n) } diff --git a/libs/application/templates/aosh/work-accident-notification/src/utils/getCompanyInformationForOverview.ts b/libs/application/templates/aosh/work-accident-notification/src/utils/getCompanyInformationForOverview.ts index bdc845fa82e8..7ce14b5d7d5e 100644 --- a/libs/application/templates/aosh/work-accident-notification/src/utils/getCompanyInformationForOverview.ts +++ b/libs/application/templates/aosh/work-accident-notification/src/utils/getCompanyInformationForOverview.ts @@ -53,7 +53,7 @@ export const getCompanyInformationForOverview = ( `${basicCompany?.address ?? ''}, ${basicCompany?.postnumber ?? ''}`, company?.industryClassification ?? undefined, chosenSizeOfEnterprise?.name ?? undefined, - `${formatMessage(information.labels.workhealth.sectionTitle)}: ${ + `**${formatMessage(information.labels.workhealth.sectionTitle)}**: ${ workplaceHealthAndSafety.length > 0 ? companyLaborProtection?.workhealthAndSafetyOccupation ?.map((c) => { @@ -63,8 +63,8 @@ export const getCompanyInformationForOverview = ( : '' }`, - `${formatMessage(overview.labels.email)}: ${company?.email}`, - `${formatMessage(overview.labels.phonenumber)}: ${formatPhoneNumber( + `**${formatMessage(overview.labels.email)}**: ${company?.email}`, + `**${formatMessage(overview.labels.phonenumber)}**: ${formatPhoneNumber( company?.phonenumber ?? '', )}`, ].filter((n) => n) diff --git a/libs/application/templates/aosh/work-accident-notification/src/utils/getEmployeeInformationForOverview.ts b/libs/application/templates/aosh/work-accident-notification/src/utils/getEmployeeInformationForOverview.ts index 8b9539018d12..b11818f4ecf7 100644 --- a/libs/application/templates/aosh/work-accident-notification/src/utils/getEmployeeInformationForOverview.ts +++ b/libs/application/templates/aosh/work-accident-notification/src/utils/getEmployeeInformationForOverview.ts @@ -79,31 +79,31 @@ export const getEmployeeInformationForOverview = ( `${employee.address ?? ''}, ${chosenPostCode?.code} ${ chosenPostCode?.name }`, - `${formatMessage(overview.employee.nationality)}: ${ + `**${formatMessage(overview.employee.nationality)}**: ${ chosenNationality?.name }`, - `${formatMessage(overview.employee.employmentStatus)}: ${ + `**${formatMessage(overview.employee.employmentStatus)}**: ${ chosenEmploymentStatus?.name }`, - `${formatMessage(overview.employee.startDate)}: ${formatDate( + `**${formatMessage(overview.employee.startDate)}**: ${formatDate( employee.startDate, )}`, - `${formatMessage(overview.employee.employmentTime)}: ${ + `**${formatMessage(overview.employee.employmentTime)}**: ${ chosenEmploymentTime?.name }`, - `${formatMessage(overview.employee.employmentRate)}: ${ + `**${formatMessage(overview.employee.employmentRate)}**: ${ employee?.employmentRate }`, - `${formatMessage(overview.employee.workhourArrangement)}: ${ + `**${formatMessage(overview.employee.workhourArrangement)}**: ${ chosenWorkhourArrangement?.name }`, - `${formatMessage(overview.employee.startTime)}: ${formatDate( + `**${formatMessage(overview.employee.startTime)}**: ${formatDate( employee.startOfWorkdayDate, )}, ${employee.startTime.slice(0, 2)}:${employee.startTime.slice(2, 4)}`, - `${formatMessage(overview.employee.workstation)}: ${ + `**${formatMessage(overview.employee.workstation)}**: ${ chosenWorkstation?.name }`, - `${formatMessage(overview.employee.occupationTitle)}: ${ + `**${formatMessage(overview.employee.occupationTitle)}**: ${ employee.victimsOccupation.label }`, ].filter((n) => n) diff --git a/libs/application/templates/family-matters/children-residence-change-v2/src/types/index.ts b/libs/application/templates/family-matters/children-residence-change-v2/src/types/index.ts index 0a917b6ab728..9c90065864d8 100644 --- a/libs/application/templates/family-matters/children-residence-change-v2/src/types/index.ts +++ b/libs/application/templates/family-matters/children-residence-change-v2/src/types/index.ts @@ -23,9 +23,3 @@ export type CRCFieldBaseProps = Override< FieldBaseProps, { application: CRCApplication; errors: ErrorSchema } > - -export enum DataProviderTypes { - MockNationalRegistry = 'MockNationalRegistryProvider', - NationalRegistry = 'NationalRegistryProvider', - UserProfile = 'UserProfileProvider', -} diff --git a/libs/application/templates/general-fishing-license/src/dataProviders/index.ts b/libs/application/templates/general-fishing-license/src/dataProviders/index.ts index 90bb14e08174..57a090f5ae3d 100644 --- a/libs/application/templates/general-fishing-license/src/dataProviders/index.ts +++ b/libs/application/templates/general-fishing-license/src/dataProviders/index.ts @@ -20,5 +20,5 @@ export const ShipRegistryApi = defineTemplateApi({ }) export const IdentityApi = IdsApi.configure({ - externalDataId: 'identityRegistry', + externalDataId: 'identity', }) diff --git a/libs/application/templates/general-fishing-license/src/lib/dataSchema.ts b/libs/application/templates/general-fishing-license/src/lib/dataSchema.ts index 693e7797bf0b..90cfc3b6e76b 100644 --- a/libs/application/templates/general-fishing-license/src/lib/dataSchema.ts +++ b/libs/application/templates/general-fishing-license/src/lib/dataSchema.ts @@ -16,7 +16,7 @@ const FileSchema = z.object({ export const GeneralFishingLicenseSchema = z.object({ approveExternalData: z.boolean().refine((v) => v), externalData: z.object({ - identityRegistry: z.object({ + identity: z.object({ data: z.object({ date: z.string(), status: z.enum(['success', 'failure']), diff --git a/libs/application/templates/general-fishing-license/src/types/index.ts b/libs/application/templates/general-fishing-license/src/types/index.ts index 5c7c341f29b7..d5b63ee5f9d5 100644 --- a/libs/application/templates/general-fishing-license/src/types/index.ts +++ b/libs/application/templates/general-fishing-license/src/types/index.ts @@ -1,9 +1,3 @@ -export enum DataProviderTypes { - NationalRegistry = 'NationalRegistryProvider', - UserProfile = 'UserProfileProvider', - IdentityRegistry = 'IdentityProvider', -} - export enum FishingLicenseEnum { HOOKCATCHLIMIT = 'hookCatchLimit', FISHWITHDANISHSEINE = 'fishWithDanishSeine', // Dragnótaveiðileyfi diff --git a/libs/application/templates/inao/financial-statement-cemetery/src/dataProviders/index.ts b/libs/application/templates/inao/financial-statement-cemetery/src/dataProviders/index.ts index dd52c79ad7f2..b0b604d16ca3 100644 --- a/libs/application/templates/inao/financial-statement-cemetery/src/dataProviders/index.ts +++ b/libs/application/templates/inao/financial-statement-cemetery/src/dataProviders/index.ts @@ -1,10 +1,7 @@ import { defineTemplateApi } from '@island.is/application/types' import { UserProfileApi } from '@island.is/application/types' - -export { - NationalRegistryUserApi, - IdentityApi as IdentityApiProvider, -} from '@island.is/application/types' +import { IdentityApi } from '@island.is/application/types' +export { NationalRegistryUserApi } from '@island.is/application/types' export const CurrentUserTypeProvider = defineTemplateApi({ action: 'getUserType', @@ -16,3 +13,9 @@ export const UserInfoApi = UserProfileApi.configure({ catchMock: true, }, }) + +export const IdentityApiProvider = IdentityApi.configure({ + params: { + includeActorInfo: true, + }, +}) diff --git a/libs/application/templates/inao/financial-statement-cemetery/src/fields/CemeteryIncomeLimit/index.tsx b/libs/application/templates/inao/financial-statement-cemetery/src/fields/CemeteryIncomeLimit/index.tsx deleted file mode 100644 index 3e78d43e4af1..000000000000 --- a/libs/application/templates/inao/financial-statement-cemetery/src/fields/CemeteryIncomeLimit/index.tsx +++ /dev/null @@ -1,43 +0,0 @@ -import { useEffect } from 'react' -import { AlertMessage, ContentBlock } from '@island.is/island-ui/core' -import { useLocale } from '@island.is/localization' -import { useQuery } from '@apollo/client' -import { useFormContext } from 'react-hook-form' -import { m } from '../../lib/messages' -import { financialLimitQuery } from '../../graphql' -import { CEMETERYOPERATIONIDS } from '../../utils/constants' -import { FSIUSERTYPE } from '../../types/types' - -export const CemeteryIncomeLimit = () => { - const { getValues, setValue } = useFormContext() - const { formatMessage } = useLocale() - - const values = getValues() - const year: string = values?.conditionalAbout?.operatingYear - - const { data, error } = useQuery(financialLimitQuery, { - variables: { input: { year, clientType: `${FSIUSERTYPE.CEMETRY}` } }, - }) - - useEffect(() => { - const limit = data?.financialStatementsInaoClientFinancialLimit?.toString() - - if (limit) { - setValue(CEMETERYOPERATIONIDS.incomeLimit, limit) - } - }, [data, setValue]) - - if (error) { - return ( - - - - ) - } - - return null -} diff --git a/libs/application/templates/inao/financial-statement-cemetery/src/fields/CemeteryOverview/AboutOverview.tsx b/libs/application/templates/inao/financial-statement-cemetery/src/fields/CemeteryOverview/AboutOverview.tsx index 926d2038faba..f0d0177b8a94 100644 --- a/libs/application/templates/inao/financial-statement-cemetery/src/fields/CemeteryOverview/AboutOverview.tsx +++ b/libs/application/templates/inao/financial-statement-cemetery/src/fields/CemeteryOverview/AboutOverview.tsx @@ -1,61 +1,61 @@ import { GridColumn, GridRow } from '@island.is/island-ui/core' -import { formatPhoneNumber } from '@island.is/application/ui-components' - import { format as formatNationalId } from 'kennitala' -import { m } from '../../lib/messages' import { sectionColumn } from './overviewStyles.css' -import { FinancialStatementCemetery } from '../../lib/dataSchema' import { ValueLine } from './ValueLine' +import { FormValue } from '@island.is/application/types' +import { getAboutOverviewNumbers } from '../../utils/overviewUtils' +import { m } from '../../lib/messages' -export const AboutOverview = ({ - answers, -}: { - answers: FinancialStatementCemetery -}) => { +type Props = { + answers: FormValue +} + +export const AboutOverview = ({ answers }: Props) => { + const { + fullName, + nationalId, + powerOfAttorneyName, + powerOfAttorneyNationalId, + email, + phoneNumber, + } = getAboutOverviewNumbers(answers) return ( <> - + - {answers.about.powerOfAttorneyName ? ( + {powerOfAttorneyName ? ( ) : null} - {answers.about.powerOfAttorneyNationalId ? ( + {powerOfAttorneyNationalId ? ( ) : null} - + - + diff --git a/libs/application/templates/inao/financial-statement-cemetery/src/fields/CemeteryOverview/CapitalNumbersOverview.tsx b/libs/application/templates/inao/financial-statement-cemetery/src/fields/CemeteryOverview/CapitalNumbersOverview.tsx index f3e18079a7cf..8814e7cb42b8 100644 --- a/libs/application/templates/inao/financial-statement-cemetery/src/fields/CemeteryOverview/CapitalNumbersOverview.tsx +++ b/libs/application/templates/inao/financial-statement-cemetery/src/fields/CemeteryOverview/CapitalNumbersOverview.tsx @@ -1,18 +1,19 @@ import { Box, GridColumn, GridRow, Text } from '@island.is/island-ui/core' - -import { m } from '../../lib/messages' import { ValueLine } from './ValueLine' import { sectionColumn, starterColumnStyle } from './overviewStyles.css' import { useLocale } from '@island.is/localization' -import { FinancialStatementCemetery } from '../../lib/dataSchema' -import { formatCurrency } from '../../utils/helpers' +import { FormValue } from '@island.is/application/types' +import { getCapitalNumbersOverviewNumbers } from '../../utils/overviewUtils' +import { m } from '../../lib/messages' + +type Props = { + answers: FormValue +} -export const CapitalNumberOverview = ({ - answers, -}: { - answers: FinancialStatementCemetery -}) => { +export const CapitalNumberOverview = ({ answers }: Props) => { const { formatMessage } = useLocale() + const { capitalIncome, capitalCost, totalCapital } = + getCapitalNumbersOverviewNumbers(answers) return ( <> @@ -22,27 +23,17 @@ export const CapitalNumberOverview = ({ - + - {answers.capitalNumbers?.capitalCost ? ( + {capitalCost ? ( - + ) : null} - + diff --git a/libs/application/templates/inao/financial-statement-cemetery/src/fields/CemeteryOverview/index.tsx b/libs/application/templates/inao/financial-statement-cemetery/src/fields/CemeteryOverview/index.tsx index 0f8c89f2c9f0..b5e45641c1fd 100644 --- a/libs/application/templates/inao/financial-statement-cemetery/src/fields/CemeteryOverview/index.tsx +++ b/libs/application/templates/inao/financial-statement-cemetery/src/fields/CemeteryOverview/index.tsx @@ -1,6 +1,5 @@ import { Fragment } from 'react' import { FieldBaseProps } from '@island.is/application/types' -import { getValueViaPath } from '@island.is/application/core' import { AlertBanner, Box, @@ -11,9 +10,6 @@ import { } from '@island.is/island-ui/core' import { useLocale } from '@island.is/localization' import { format as formatNationalId } from 'kennitala' -import { m } from '../../lib/messages' -import { FinancialStatementCemetery } from '../../lib/dataSchema' -import { formatCurrency } from '../../utils/helpers' import { AboutOverview } from './AboutOverview' import { ValueLine } from './ValueLine' import { CapitalNumberOverview } from './CapitalNumbersOverview' @@ -24,117 +20,53 @@ import { sectionColumn, starterColumnStyle, } from './overviewStyles.css' +import { formatCurrency } from '../../utils/currency' +import { isCemetryUnderFinancialLimit } from '../../utils/helpers' +import { getOverviewNumbers } from '../../utils/overviewUtils' +import { m } from '../../lib/messages' export const CemeteryOverview = ({ application }: FieldBaseProps) => { const { formatMessage } = useLocale() - - const answers = application.answers as FinancialStatementCemetery - const file = getValueViaPath>(answers, 'attachments.file') - const fileName = file?.[0]?.name - const incomeLimit = - getValueViaPath(answers, 'cemeteryOperations.incomeLimit') ?? '0' - const email = getValueViaPath(answers, 'about.email') - const cemeteryCaretakers = answers.cemeteryCaretaker - - const careIncome = getValueViaPath( - answers, - 'cemeteryIncome.careIncome', - ) - const burialRevenue = getValueViaPath( - answers, - 'cemeteryIncome.burialRevenue', - ) - const grantFromTheCemeteryFund = getValueViaPath( - answers, - 'cemeteryIncome.grantFromTheCemeteryFund', - ) - const otherIncome = getValueViaPath( - answers, - 'cemeteryIncome.otherIncome', - ) - const totalIncome = getValueViaPath(answers, 'cemeteryIncome.total') - - const payroll = getValueViaPath(answers, 'cemeteryExpense.payroll') - const funeralCost = getValueViaPath( - answers, - 'cemeteryExpense.funeralCost', - ) - const chapelExpense = getValueViaPath( - answers, - 'cemeteryExpense.chapelExpense', - ) - const donationsToCemeteryFund = getValueViaPath( - answers, - 'cemeteryExpense.cemeteryFundExpense', - ) - const donationsToOther = getValueViaPath( - answers, - 'cemeteryExpense.donationsToOther', - ) - const otherOperationCost = getValueViaPath( - answers, - 'cemeteryExpense.otherOperationCost', - ) - const depreciation = getValueViaPath( - answers, - 'cemeteryExpense.depreciation', - ) - const totalExpenses = getValueViaPath( - answers, - 'cemeteryExpense.total', - ) - - const fixedAssetsTotal = getValueViaPath( - answers, - 'cemeteryAsset.fixedAssetsTotal', - ) - const currentAssets = getValueViaPath( - answers, - 'cemeteryAsset.currentAssets', - ) - const totalAssets = getValueViaPath(answers, 'assetsTotal') - - const longTerm = getValueViaPath( - answers, - 'cemeteryLiability.longTerm', - ) - const shortTerm = getValueViaPath( - answers, - 'cemeteryLiability.shortTerm', - ) - const totalLiabilities = getValueViaPath( - answers, - 'equityAndLiabilitiesTotals.liabilitiesTotal', - ) - - const equityAtTheBeginningOfTheYear = getValueViaPath( - answers, - 'cemeteryEquity.equityAtTheBeginningOfTheYear', - ) - const revaluationDueToPriceChanges = getValueViaPath( - answers, - 'cemeteryEquity.revaluationDueToPriceChanges', - ) - const reevaluateOther = getValueViaPath( - answers, - 'cemeteryEquity.reevaluateOther', - ) - const operationResult = getValueViaPath( - answers, - 'cemeteryEquity.operationResult', - ) - const totalEquity = getValueViaPath(answers, 'cemeteryEquity.total') - - const debtsAndCash = getValueViaPath( - answers, - 'equityAndLiabilitiesTotals.equityAndLiabilitiesTotal', + const cemeteryUnderFinancialLimit = isCemetryUnderFinancialLimit( + application.answers, ) + const { + careIncome, + burialRevenue, + grantFromTheCemeteryFund, + otherIncome, + totalIncome, + payroll, + funeralCost, + chapelExpense, + donationsToCemeteryFund, + donationsToOther, + otherOperationCost, + depreciation, + totalExpenses, + fixedAssetsTotal, + currentAssets, + totalAssets, + longTerm, + shortTerm, + totalLiabilities, + equityAtTheBeginningOfTheYear, + revaluationDueToPriceChanges, + reevaluateOther, + operationResult, + totalEquity, + debtsAndCash, + email, + fileName, + incomeLimit, + cemeteryCaretakers, + } = getOverviewNumbers(application.answers) return ( - + @@ -214,7 +146,7 @@ export const CemeteryOverview = ({ application }: FieldBaseProps) => { - + @@ -294,8 +226,9 @@ export const CemeteryOverview = ({ application }: FieldBaseProps) => { - {Number(totalIncome) < Number(incomeLimit) && - cemeteryCaretakers?.length > 0 ? ( + {cemeteryUnderFinancialLimit && + cemeteryCaretakers && + cemeteryCaretakers.length > 0 ? ( <> @@ -338,7 +271,7 @@ export const CemeteryOverview = ({ application }: FieldBaseProps) => { ) : null} {fileName ? ( <> - + ) : null} diff --git a/libs/application/templates/inao/financial-statement-cemetery/src/fields/FetchDataBasedOnSelectedYear/index.tsx b/libs/application/templates/inao/financial-statement-cemetery/src/fields/FetchDataBasedOnSelectedYear/index.tsx new file mode 100644 index 000000000000..1fbb78acc661 --- /dev/null +++ b/libs/application/templates/inao/financial-statement-cemetery/src/fields/FetchDataBasedOnSelectedYear/index.tsx @@ -0,0 +1,123 @@ +import { useEffect } from 'react' +import { + AlertMessage, + ContentBlock, + LoadingDots, +} from '@island.is/island-ui/core' +import { useLocale } from '@island.is/localization' +import { useQuery } from '@apollo/client' +import { useFormContext } from 'react-hook-form' +import { financialLimitQuery, taxInfoQuery } from '../../graphql' +import { CEMETERYOPERATIONIDS } from '../../utils/constants' +import { FSIUSERTYPE, TaxInfoData } from '../../types/types' +import { + getCareIncomeAndBurialRevenueAndGrant, + getTaxInfoFromAnswers, +} from '../../utils/helpers' +import { m } from '../../lib/messages' + +export const FetchDataBasedOnSelectedYear = () => { + const { getValues, setValue } = useFormContext() + const { formatMessage } = useLocale() + + const values = getValues() + const year: string = values?.conditionalAbout?.operatingYear + + const { data, error, loading } = useQuery(financialLimitQuery, { + variables: { input: { year, clientType: `${FSIUSERTYPE.CEMETRY}` } }, + }) + + const { data: taxInfoData, loading: taxInfoLoading } = useQuery( + taxInfoQuery, + { + variables: { year }, + }, + ) + + const { + careIncomeFromAnswers, + burialRevenueFromAnswers, + grantFromTheCemeteryFundFromAnswers, + donationsToCemeteryFundFromAnswers, + } = getTaxInfoFromAnswers(values) + + useEffect(() => { + const limit = data?.financialStatementsInaoClientFinancialLimit?.toString() + + if (limit) { + setValue(CEMETERYOPERATIONIDS.incomeLimit, limit) + } + }, [data, setValue]) + + useEffect(() => { + if (!taxInfoData) return + + const { + careIncome, + burialRevenue, + grantFromTheCemeteryFund, + donationsToCemeteryFund, + } = getCareIncomeAndBurialRevenueAndGrant( + taxInfoData.financialStatementsInaoTaxInfo, + ) + + const updates = [ + { + id: CEMETERYOPERATIONIDS.careIncome, + value: careIncome, + exists: careIncomeFromAnswers, + }, + { + id: CEMETERYOPERATIONIDS.burialRevenue, + value: burialRevenue, + exists: burialRevenueFromAnswers, + }, + { + id: CEMETERYOPERATIONIDS.grantFromTheCemeteryFund, + value: grantFromTheCemeteryFund, + exists: grantFromTheCemeteryFundFromAnswers, + }, + { + id: CEMETERYOPERATIONIDS.donationsToCemeteryFund, + value: donationsToCemeteryFund, + exists: donationsToCemeteryFundFromAnswers, + }, + ] + + updates.forEach((update) => { + if (!update.exists) { + setValue(update.id, update.value) + } + }) + }, [ + taxInfoData, + setValue, + careIncomeFromAnswers, + burialRevenueFromAnswers, + grantFromTheCemeteryFundFromAnswers, + donationsToCemeteryFundFromAnswers, + CEMETERYOPERATIONIDS, + ]) + + if (loading || taxInfoLoading) { + return ( + + + + ) + } + + if (error) { + return ( + + + + ) + } + + return null +} diff --git a/libs/application/templates/inao/financial-statement-cemetery/src/fields/PowerOfAttorney/index.tsx b/libs/application/templates/inao/financial-statement-cemetery/src/fields/PowerOfAttorney/index.tsx deleted file mode 100644 index f4dcf6f77248..000000000000 --- a/libs/application/templates/inao/financial-statement-cemetery/src/fields/PowerOfAttorney/index.tsx +++ /dev/null @@ -1,96 +0,0 @@ -import { useEffect } from 'react' -import { useFormContext } from 'react-hook-form' -import { useLazyQuery } from '@apollo/client' -import { - Box, - GridColumn, - GridContainer, - GridRow, - InputError, -} from '@island.is/island-ui/core' -import { InputController } from '@island.is/shared/form-fields' -import { useLocale } from '@island.is/localization' -import { IdentityInput, Query } from '@island.is/api/schema' -import { m } from '../../lib/messages' -import { FieldBaseProps } from '@island.is/application/types' -import { getErrorViaPath } from '@island.is/application/core' -import { IdentityQuery } from '../../graphql' -import { ABOUTIDS } from '../../utils/constants' - -export const PowerOfAttorneyFields = ({ application }: FieldBaseProps) => { - const { formatMessage } = useLocale() - const { - formState: { errors }, - setValue, - } = useFormContext() - - const currentActor = - application.applicantActors[application.applicantActors.length - 1] - - const [getIdentity, { loading, error: queryError }] = useLazyQuery< - Query, - { input: IdentityInput } - >(IdentityQuery, { - onCompleted: (data) => { - setValue(ABOUTIDS.powerOfAttorneyName, data.identity?.name ?? '') - }, - }) - - useEffect(() => { - if (currentActor) { - getIdentity({ - variables: { - input: { - nationalId: currentActor, - }, - }, - }) - } - }, []) - - if (application.applicantActors.length === 0) { - return null - } - - return ( - - - - - - - - - - - {queryError ? ( - - ) : null} - - - - - ) -} diff --git a/libs/application/templates/inao/financial-statement-cemetery/src/fields/index.ts b/libs/application/templates/inao/financial-statement-cemetery/src/fields/index.ts index 9903bafb3734..5c8739dcdcab 100644 --- a/libs/application/templates/inao/financial-statement-cemetery/src/fields/index.ts +++ b/libs/application/templates/inao/financial-statement-cemetery/src/fields/index.ts @@ -1,4 +1,3 @@ export { CemeteryCaretaker } from './CemeteryCareteker' -export { PowerOfAttorneyFields } from './PowerOfAttorney' export { CemeteryOverview } from './CemeteryOverview' -export { CemeteryIncomeLimit } from './CemeteryIncomeLimit' +export { FetchDataBasedOnSelectedYear } from './FetchDataBasedOnSelectedYear' diff --git a/libs/application/templates/inao/financial-statement-cemetery/src/forms/applicationForm/cemeteryCaretakerSection/caretakerMultiField.ts b/libs/application/templates/inao/financial-statement-cemetery/src/forms/applicationForm/cemeteryCaretakerSection/caretakerMultiField.ts deleted file mode 100644 index 21b59e7439fe..000000000000 --- a/libs/application/templates/inao/financial-statement-cemetery/src/forms/applicationForm/cemeteryCaretakerSection/caretakerMultiField.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { buildCustomField, buildMultiField } from '@island.is/application/core' -import { m } from '../../../lib/messages' -import { CEMETERYCARETAKER } from '../../../utils/constants' - -export const caretakerMultiField = buildMultiField({ - id: 'caretakers', - title: m.cemeteryBoardmembers, - description: m.cemeteryRegisterCaretakers, - children: [ - buildCustomField({ - id: 'cemeteryCaretaker', - title: m.cemeteryBoardmembers, - component: 'CemeteryCaretaker', - childInputIds: Object.values(CEMETERYCARETAKER), - }), - ], -}) diff --git a/libs/application/templates/inao/financial-statement-cemetery/src/forms/applicationForm/cemeteryCaretakerSection/index.ts b/libs/application/templates/inao/financial-statement-cemetery/src/forms/applicationForm/cemeteryCaretakerSection/index.ts index a5805af6e458..384036b026d1 100644 --- a/libs/application/templates/inao/financial-statement-cemetery/src/forms/applicationForm/cemeteryCaretakerSection/index.ts +++ b/libs/application/templates/inao/financial-statement-cemetery/src/forms/applicationForm/cemeteryCaretakerSection/index.ts @@ -1,9 +1,32 @@ -import { buildSection } from '@island.is/application/core' +import { + buildCustomField, + buildMultiField, + buildSection, +} from '@island.is/application/core' import { m } from '../../../lib/messages' -import { caretakerMultiField } from './caretakerMultiField' +import { CEMETERYCARETAKER } from '../../../utils/constants' +import { isCemetryUnderFinancialLimit } from '../../../utils/helpers' +// This section should appear if the cemetries total income is under the income limit export const cemeteryCaretekerSection = buildSection({ + condition: (answers) => { + return isCemetryUnderFinancialLimit(answers) + }, id: 'cemeteryCaretekerSection', title: m.cemeteryCaretakers, - children: [caretakerMultiField], + children: [ + buildMultiField({ + id: 'caretakers', + title: m.cemeteryBoardmembers, + description: m.cemeteryRegisterCaretakers, + children: [ + buildCustomField({ + id: 'cemeteryCaretaker', + title: m.cemeteryBoardmembers, + component: 'CemeteryCaretaker', + childInputIds: Object.values(CEMETERYCARETAKER), + }), + ], + }), + ], }) diff --git a/libs/application/templates/inao/financial-statement-cemetery/src/forms/applicationForm/cemeteryFinancialStatementSection/index.ts b/libs/application/templates/inao/financial-statement-cemetery/src/forms/applicationForm/cemeteryFinancialStatementSection/index.ts index 8df2c99ea9cd..b46b820b5714 100644 --- a/libs/application/templates/inao/financial-statement-cemetery/src/forms/applicationForm/cemeteryFinancialStatementSection/index.ts +++ b/libs/application/templates/inao/financial-statement-cemetery/src/forms/applicationForm/cemeteryFinancialStatementSection/index.ts @@ -1,30 +1,18 @@ import { buildFileUploadField, buildSection } from '@island.is/application/core' import { m } from '../../../lib/messages' -import { currencyStringToNumber } from '../../../utils/helpers' -import { FinancialStatementCemetery } from '../../../lib/dataSchema' +import { isCemetryUnderFinancialLimit } from '../../../utils/helpers' +// This section should appear if the cemetries total income is over the income limit export const cemeteryFinancialStatementSection = buildSection({ + condition: (answers) => { + return !isCemetryUnderFinancialLimit(answers) + }, id: 'documents', title: m.financialStatement, children: [ buildFileUploadField({ id: 'attachments.file', title: m.upload, - condition: (answers) => { - const applicationAnswers = answers as FinancialStatementCemetery - const careTakerLimit = - applicationAnswers.cemeteryOperation?.incomeLimit ?? '0' - const fixedAssetsTotal = - applicationAnswers.cemeteryAsset?.fixedAssetsTotal - const totalIncome = applicationAnswers.cemeteryIncome?.total - const longTermDebt = applicationAnswers.cemeteryLiability?.longTerm - const isUnderLimit = - currencyStringToNumber(totalIncome) < careTakerLimit - if (isUnderLimit && fixedAssetsTotal === '0' && longTermDebt === '0') { - return false - } - return true - }, introduction: m.uploadIntro, description: m.uploadDescription, uploadHeader: m.uploadHeader, diff --git a/libs/application/templates/inao/financial-statement-cemetery/src/forms/applicationForm/cemeteryKeyNumbersSection/capitalNumberSubSection.ts b/libs/application/templates/inao/financial-statement-cemetery/src/forms/applicationForm/cemeteryKeyNumbersSection/capitalNumberSubSection.ts index 86bc4ae3eaa0..c8f3ff8e67a3 100644 --- a/libs/application/templates/inao/financial-statement-cemetery/src/forms/applicationForm/cemeteryKeyNumbersSection/capitalNumberSubSection.ts +++ b/libs/application/templates/inao/financial-statement-cemetery/src/forms/applicationForm/cemeteryKeyNumbersSection/capitalNumberSubSection.ts @@ -6,7 +6,7 @@ import { } from '@island.is/application/core' import { m } from '../../../lib/messages' import { CAPITALNUMBERS } from '../../../utils/constants' -import { sumCapitalNumbers } from '../../../utils/helpers' +import { sumCapitalNumbers } from '../../../utils/sums' export const capitalNumberSubSection = buildSubSection({ id: 'keynumbers.capitalNumbers', diff --git a/libs/application/templates/inao/financial-statement-cemetery/src/forms/applicationForm/cemeteryKeyNumbersSection/equityAndLiabilitySubSection.ts b/libs/application/templates/inao/financial-statement-cemetery/src/forms/applicationForm/cemeteryKeyNumbersSection/equityAndLiabilitySubSection.ts index 1e0f6a2987f2..5a1b3b970132 100644 --- a/libs/application/templates/inao/financial-statement-cemetery/src/forms/applicationForm/cemeteryKeyNumbersSection/equityAndLiabilitySubSection.ts +++ b/libs/application/templates/inao/financial-statement-cemetery/src/forms/applicationForm/cemeteryKeyNumbersSection/equityAndLiabilitySubSection.ts @@ -13,12 +13,12 @@ import { } from '../../../utils/constants' import { operationResult, - showEquitiesAndLiabilitiesAlert, - sumAssets, sumLiabilities, - sumTotalEquity, sumTotalEquityAndLiabilities, -} from '../../../utils/helpers' + sumTotalEquity, + showEquitiesAndLiabilitiesAlert, + sumAssets, +} from '../../../utils/sums' export const equityAndLiabilitiesSubSection = buildSubSection({ id: 'keyNumbers.cemetryEquitiesAndLiabilities', diff --git a/libs/application/templates/inao/financial-statement-cemetery/src/forms/applicationForm/cemeteryKeyNumbersSection/opperatingCostSubSection.ts b/libs/application/templates/inao/financial-statement-cemetery/src/forms/applicationForm/cemeteryKeyNumbersSection/opperatingCostSubSection.ts index 34329fa8ee15..d15128bfd667 100644 --- a/libs/application/templates/inao/financial-statement-cemetery/src/forms/applicationForm/cemeteryKeyNumbersSection/opperatingCostSubSection.ts +++ b/libs/application/templates/inao/financial-statement-cemetery/src/forms/applicationForm/cemeteryKeyNumbersSection/opperatingCostSubSection.ts @@ -12,7 +12,7 @@ import { sumExpenses, sumIncome, sumOperatingResults, -} from '../../../utils/helpers' +} from '../../../utils/sums' export const opperatingCostSubSection = buildSubSection({ id: 'operatingCost', @@ -24,9 +24,9 @@ export const opperatingCostSubSection = buildSubSection({ description: m.fillOutAppopriate, children: [ buildCustomField({ - id: 'cemetryIncomeLimit', + id: 'fetchDataBasedOnYear', title: '', - component: 'CemeteryIncomeLimit', + component: 'FetchDataBasedOnSelectedYear', }), // Income buildDescriptionField({ diff --git a/libs/application/templates/inao/financial-statement-cemetery/src/forms/applicationForm/clientInfoSection/index.ts b/libs/application/templates/inao/financial-statement-cemetery/src/forms/applicationForm/clientInfoSection/index.ts index 9916366fd934..718b55a3d021 100644 --- a/libs/application/templates/inao/financial-statement-cemetery/src/forms/applicationForm/clientInfoSection/index.ts +++ b/libs/application/templates/inao/financial-statement-cemetery/src/forms/applicationForm/clientInfoSection/index.ts @@ -1,12 +1,13 @@ import { buildAsyncSelectField, - buildCustomField, buildDescriptionField, buildMultiField, + buildPhoneField, buildSection, buildTextField, + getValueViaPath, } from '@island.is/application/core' -import { Application, UserProfile } from '@island.is/application/types' +import { Application } from '@island.is/application/types' import { m } from '../../../lib/messages' import { ABOUTIDS } from '../../../utils/constants' import { Identity } from '@island.is/api/schema' @@ -58,42 +59,49 @@ export const clientInfoSection = buildSection({ return nationalRegistry.name }, }), - buildDescriptionField({ - id: 'about.description2', - title: '', + buildTextField({ + id: ABOUTIDS.powerOfAttorneyNationalId, + title: m.powerOfAttorneyNationalId, + width: 'half', + readOnly: true, + format: '######-####', + defaultValue: (application: Application) => + getValueViaPath( + application.externalData, + 'identity.data.actor.nationalId', + ), }), - buildCustomField({ - id: 'powerOfAttorney', - title: '', - description: '', - component: 'PowerOfAttorneyFields', - childInputIds: [ - ABOUTIDS.powerOfAttorneyNationalId, - ABOUTIDS.powerOfAttorneyName, - ], + buildTextField({ + id: ABOUTIDS.powerOfAttorneyName, + title: m.powerOfAttorneyName, + width: 'half', + readOnly: true, + defaultValue: (application: Application) => + getValueViaPath( + application.externalData, + 'identity.data.actor.name', + ), }), - buildTextField({ id: 'about.email', title: m.email, width: 'half', variant: 'email', - defaultValue: (application: Application) => { - const userProfile = application.externalData.userProfile - .data as UserProfile - return userProfile.email - }, + defaultValue: (application: Application) => + getValueViaPath( + application.externalData, + 'userProfile.data.email', + ), }), - buildTextField({ + buildPhoneField({ id: 'about.phoneNumber', title: m.phoneNumber, width: 'half', - variant: 'tel', - defaultValue: (application: Application) => { - const userProfile = application.externalData.userProfile - .data as UserProfile - return userProfile.mobilePhoneNumber - }, + defaultValue: (application: Application) => + getValueViaPath( + application.externalData, + 'userProfile.data.mobilePhoneNumber', + ), }), ], }), diff --git a/libs/application/templates/inao/financial-statement-cemetery/src/hooks/useTotals.ts b/libs/application/templates/inao/financial-statement-cemetery/src/hooks/useTotals.ts deleted file mode 100644 index 15a5873fdd5e..000000000000 --- a/libs/application/templates/inao/financial-statement-cemetery/src/hooks/useTotals.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { useCallback, useEffect, useState } from 'react' -import { useFormContext } from 'react-hook-form' -import { getTotal } from '../utils/helpers' - -const useTotals = (key: string): [() => void, number] => { - const [total, setTotal] = useState(0) - const { getValues } = useFormContext() - const getSum = useCallback(() => { - const values = getValues() - const sum = getTotal(values, key) - setTotal(sum) - }, [key, getValues, setTotal]) - - useEffect(() => { - getSum() - }, [getSum]) - - return [getSum, total] -} - -export { useTotals } diff --git a/libs/application/templates/inao/financial-statement-cemetery/src/lib/dataSchema.ts b/libs/application/templates/inao/financial-statement-cemetery/src/lib/dataSchema.ts index 97379678b103..35a8aefa428f 100644 --- a/libs/application/templates/inao/financial-statement-cemetery/src/lib/dataSchema.ts +++ b/libs/application/templates/inao/financial-statement-cemetery/src/lib/dataSchema.ts @@ -3,11 +3,9 @@ import { m } from './messages' import * as kennitala from 'kennitala' import { parsePhoneNumberFromString } from 'libphonenumber-js' import { BOARDMEMEBER, CARETAKER } from '../utils/constants' -import { - isPositiveNumberInString, - getBoardmembersAndCaretakers, -} from '../utils/helpers' +import { getBoardmembersAndCaretakers } from '../utils/helpers' import { YES } from '@island.is/application/types' +import { isPositiveNumberInString } from '../utils/currency' const FileSchema = z.object({ name: z.string(), diff --git a/libs/application/templates/inao/financial-statement-cemetery/src/types/types.ts b/libs/application/templates/inao/financial-statement-cemetery/src/types/types.ts index 53e29233513f..edd111488a8c 100644 --- a/libs/application/templates/inao/financial-statement-cemetery/src/types/types.ts +++ b/libs/application/templates/inao/financial-statement-cemetery/src/types/types.ts @@ -46,3 +46,19 @@ type InaoConfigItem = { export type AuditConfig = { financialStatementsInaoConfig: Array } + +export type CareTaker = { + nationalId: string + name: string + role: string +} + +export type TaxInfoItem = { + __typename: string + key: number + value: string +} + +export type TaxInfoData = { + financialStatementsInaoTaxInfo: Array +} diff --git a/libs/application/templates/inao/financial-statement-cemetery/src/utils/constants.ts b/libs/application/templates/inao/financial-statement-cemetery/src/utils/constants.ts index 2c0cb3bb6afe..190000af6700 100644 --- a/libs/application/templates/inao/financial-statement-cemetery/src/utils/constants.ts +++ b/libs/application/templates/inao/financial-statement-cemetery/src/utils/constants.ts @@ -26,6 +26,7 @@ export enum TaxInfoTypes { CARE_INCOME = 300, BURIAL_REVENUE = 301, GRANT_FROM_THE_CEMETERY_FUND = 302, + DONATIONS_TO_CEMETERYFUND = 334, } export const CEMETERYOPERATIONIDS = { diff --git a/libs/application/templates/inao/financial-statement-cemetery/src/utils/currency.ts b/libs/application/templates/inao/financial-statement-cemetery/src/utils/currency.ts new file mode 100644 index 000000000000..7ffe7149224c --- /dev/null +++ b/libs/application/templates/inao/financial-statement-cemetery/src/utils/currency.ts @@ -0,0 +1,16 @@ +export const currencyStringToNumber = (str: string) => { + if (!str) { + return str + } + const cleanString = str.replace(/[,\s]+|[.\s]+/g, '') + return parseInt(cleanString, 10) +} + +export const formatCurrency = (answer?: string) => { + if (!answer) return '0. kr' + return answer.replace(/\B(?=(\d{3})+(?!\d))/g, '.') + ' kr.' +} + +export const isPositiveNumberInString = (input: string) => { + return Number(input) >= 0 +} diff --git a/libs/application/templates/inao/financial-statement-cemetery/src/utils/helpers.ts b/libs/application/templates/inao/financial-statement-cemetery/src/utils/helpers.ts index aec943d790e8..9a6d72727122 100644 --- a/libs/application/templates/inao/financial-statement-cemetery/src/utils/helpers.ts +++ b/libs/application/templates/inao/financial-statement-cemetery/src/utils/helpers.ts @@ -1,42 +1,16 @@ -import { ExternalData, FormValue } from '@island.is/application/types' +import { FormValue } from '@island.is/application/types' import { getValueViaPath } from '@island.is/application/core' import { BOARDMEMEBER, - CAPITALNUMBERS, CARETAKER, CemeteriesBackwardLimit, CemeteriesYearAllowed, - CEMETERYEQUITIESANDLIABILITIESIDS, CEMETERYOPERATIONIDS, - EQUITYANDLIABILITIESTOTALS, - OPERATINGCOST, - TOTAL, + TaxInfoTypes, } from './constants' -import { FinancialStatementCemetery } from '../lib/dataSchema' import getYear from 'date-fns/getYear' import subYears from 'date-fns/subYears' -import { AuditConfig, BoardMember, Config, FSIUSERTYPE } from '../types/types' - -export const getTotal = (values: Record, key: string) => { - if (!values[key]) { - return 0 - } - const total = Object.entries(values[key]) - .filter(([k, v]) => k !== TOTAL && !isNaN(Number(v))) - .map(([_k, v]) => Number(v)) - .reduce((prev, current) => { - return (prev += current) - }, 0) - return total -} - -export const currencyStringToNumber = (str: string) => { - if (!str) { - return str - } - const cleanString = str.replace(/[,\s]+|[.\s]+/g, '') - return parseInt(cleanString, 10) -} +import { AuditConfig, BoardMember, TaxInfoItem } from '../types/types' export const getBoardmembersAndCaretakers = (members: Array) => { const careTakers = members @@ -60,11 +34,7 @@ export const isCemetryUnderFinancialLimit = (answers: FormValue) => { getValueViaPath(answers, 'cemeteryLiability.longTerm') || '0' const isUnderLimit = Number(totalIncome) < Number(incomeLimit) - if (isUnderLimit && fixedAssetsTotal === '0' && longTermDebt === '0') { - return true - } - - return false + return isUnderLimit && fixedAssetsTotal === '0' && longTermDebt === '0' } export const getYearOptions = (data: AuditConfig) => { @@ -103,226 +73,64 @@ export const possibleOperatingYears = ( return operationYears } -export const getConfigInfoForKey = (config: Config[], configKey: string) => { - return config?.filter((config: Config) => config.key === configKey)[0].value -} - -export const formatCurrency = (answer?: string) => { - if (!answer) return '0. kr' - return answer.replace(/\B(?=(\d{3})+(?!\d))/g, '.') + ' kr.' -} - -export const isPositiveNumberInString = (input: string) => { - return Number(input) > 0 -} - -export const sumIncome = (answers: FormValue) => { - const careIncome = - getValueViaPath(answers, CEMETERYOPERATIONIDS.careIncome) || '0' - const burialRevenue = - getValueViaPath(answers, CEMETERYOPERATIONIDS.burialRevenue) || '0' - const grantFromTheCemeteryFund = - getValueViaPath( - answers, - CEMETERYOPERATIONIDS.grantFromTheCemeteryFund, - ) || '0' - const otherIncome = - getValueViaPath(answers, CEMETERYOPERATIONIDS.otherIncome) || '0' - - return `${ - Number(careIncome) + - Number(burialRevenue) + - Number(grantFromTheCemeteryFund) + - Number(otherIncome) - }` -} - -export const sumExpenses = (answers: FormValue) => { - const payroll = getValueViaPath(answers, CEMETERYOPERATIONIDS.payroll) - const funeralCost = - getValueViaPath(answers, CEMETERYOPERATIONIDS.funeralCost) || '0' - const chapelExpense = - getValueViaPath(answers, CEMETERYOPERATIONIDS.chapelExpense) || '0' - const donationsToCemeteryFund = - getValueViaPath( - answers, - CEMETERYOPERATIONIDS.donationsToCemeteryFund, - ) || '0' - const donationsToOther = - getValueViaPath(answers, CEMETERYOPERATIONIDS.donationsToOther) || - '0' - const otherOperationCost = - getValueViaPath(answers, CEMETERYOPERATIONIDS.otherOperationCost) || - '0' - const depreciation = - getValueViaPath(answers, CEMETERYOPERATIONIDS.depreciation) || '0' - - return `${ - Number(payroll) + - Number(funeralCost) + - Number(chapelExpense) + - Number(donationsToCemeteryFund) + - Number(donationsToOther) + - Number(otherOperationCost) + - Number(depreciation) - }` -} - -export const sumOperatingResults = (answers: FormValue) => { - const income = - getValueViaPath(answers, CEMETERYOPERATIONIDS.totalIncome) || '0' - const expenses = - getValueViaPath(answers, CEMETERYOPERATIONIDS.totalExpense) || '0' - - return `${Number(income) - Number(expenses)}` -} - -export const sumCapitalNumbers = (answers: FormValue) => { - const capitalIncome = - getValueViaPath(answers, CAPITALNUMBERS.capitalIncome) || '0' - const capitalCost = - getValueViaPath(answers, CAPITALNUMBERS.capitalCost) || '0' - return `${Number(capitalIncome) - Number(capitalCost)}` -} - -export const sumAssets = (answers: FormValue) => { - const fixedAssetsTotal = - getValueViaPath( - answers, - CEMETERYEQUITIESANDLIABILITIESIDS.fixedAssetsTotal, - ) || '0' - const currentAssets = - getValueViaPath( - answers, - CEMETERYEQUITIESANDLIABILITIESIDS.currentAssets, - ) || '0' - return `${Number(fixedAssetsTotal) + Number(currentAssets)}` -} - -export const sumLiabilities = (answers: FormValue) => { - const longTerm = - getValueViaPath( - answers, - CEMETERYEQUITIESANDLIABILITIESIDS.longTerm, - ) || '0' - const shortTerm = - getValueViaPath( - answers, - CEMETERYEQUITIESANDLIABILITIESIDS.shortTerm, - ) || '0' - return `${Number(longTerm) + Number(shortTerm)}` -} - -export const operationResult = (answers: FormValue) => { - const operatingTotalCost = - getValueViaPath(answers, OPERATINGCOST.total) || '0' - const capitalTotal = - getValueViaPath(answers, CAPITALNUMBERS.total) || '0' - return `${Number(operatingTotalCost) + Number(capitalTotal)}` -} - -export const sumTotalEquity = (answers: FormValue) => { - const equityAtTheBeginningOfTheYear = - getValueViaPath( - answers, - CEMETERYEQUITIESANDLIABILITIESIDS.equityAtTheBeginningOfTheYear, - ) || '0' - const revaluationDueToPriceChanges = - getValueViaPath( - answers, - CEMETERYEQUITIESANDLIABILITIESIDS.revaluationDueToPriceChanges, - ) || '0' - const reevaluateOther = - getValueViaPath( - answers, - CEMETERYEQUITIESANDLIABILITIESIDS.reevaluateOther, - ) || '0' - const operationResult = - getValueViaPath( - answers, - CEMETERYEQUITIESANDLIABILITIESIDS.operationResult, - ) || '0' - - return `${ - Number(equityAtTheBeginningOfTheYear) + - Number(revaluationDueToPriceChanges) + - Number(reevaluateOther) + - Number(operationResult) - }` -} - -export const sumTotalEquityAndLiabilities = (answers: FormValue) => { - const liabilityTotal = - getValueViaPath( - answers, - EQUITYANDLIABILITIESTOTALS.liabilitiesTotal, - ) || '0' - const totalEquity = - getValueViaPath( - answers, - CEMETERYEQUITIESANDLIABILITIESIDS.equityTotal, - ) || '0' +export const getCareIncomeAndBurialRevenueAndGrant = ( + taxInfo?: Array, +) => { + if (!taxInfo) { + return { + careIncome: undefined, + burialRevenue: undefined, + grantFromTheCemeteryFund: undefined, + } + } - return `${Number(totalEquity) + Number(liabilityTotal)}` + const careIncome = taxInfo.find( + (item) => item.key === TaxInfoTypes.CARE_INCOME, + ) + const burialRevenue = taxInfo.find( + (item) => item.key === TaxInfoTypes.BURIAL_REVENUE, + ) + const grantFromTheCemeteryFund = taxInfo.find( + (item) => item.key === TaxInfoTypes.GRANT_FROM_THE_CEMETERY_FUND, + ) + const donationsToCemeteryFund = taxInfo.find( + (item) => item.key === TaxInfoTypes.DONATIONS_TO_CEMETERYFUND, + ) + + return { + careIncome: careIncome ? careIncome.value : undefined, + burialRevenue: burialRevenue ? burialRevenue.value : undefined, + grantFromTheCemeteryFund: grantFromTheCemeteryFund + ? grantFromTheCemeteryFund.value + : undefined, + donationsToCemeteryFund: donationsToCemeteryFund + ? donationsToCemeteryFund.value + : undefined, + } } -export const showEquitiesAndLiabilitiesAlert = (answers: FormValue) => { - const fixedAssetsTotal = - getValueViaPath( - answers, - CEMETERYEQUITIESANDLIABILITIESIDS.fixedAssetsTotal, - ) || '0' - const currentAssets = - getValueViaPath( - answers, - CEMETERYEQUITIESANDLIABILITIESIDS.currentAssets, - ) || '0' - const longTerm = - getValueViaPath( - answers, - CEMETERYEQUITIESANDLIABILITIESIDS.longTerm, - ) || '0' - const shortTerm = - getValueViaPath( - answers, - CEMETERYEQUITIESANDLIABILITIESIDS.shortTerm, - ) || '0' - const equityAtTheBeginningOfTheYear = - getValueViaPath( - answers, - CEMETERYEQUITIESANDLIABILITIESIDS.equityAtTheBeginningOfTheYear, - ) || '0' - const revaluationDueToPriceChanges = - getValueViaPath( - answers, - CEMETERYEQUITIESANDLIABILITIESIDS.revaluationDueToPriceChanges, - ) || '0' - const reevaluateOther = - getValueViaPath( - answers, - CEMETERYEQUITIESANDLIABILITIESIDS.reevaluateOther, - ) || '0' - - const totalAssets = - getValueViaPath(answers, EQUITYANDLIABILITIESTOTALS.assetsTotal) || - '0' - const totalEquityAndLiabilities = - getValueViaPath( - answers, - EQUITYANDLIABILITIESTOTALS.equityAndLiabilitiesTotal, - ) || '0' - - if ( - !fixedAssetsTotal || - !currentAssets || - !longTerm || - !shortTerm || - !equityAtTheBeginningOfTheYear || - !revaluationDueToPriceChanges || - !reevaluateOther || - !operationResult - ) { - return false +export const getTaxInfoFromAnswers = (answers: FormValue) => { + const careIncome = getValueViaPath( + answers, + CEMETERYOPERATIONIDS.careIncome, + ) + const burialRevenue = getValueViaPath( + answers, + CEMETERYOPERATIONIDS.burialRevenue, + ) + const grantFromTheCemeteryFund = getValueViaPath( + answers, + CEMETERYOPERATIONIDS.grantFromTheCemeteryFund, + ) + const donationsToCemeteryFund = getValueViaPath( + answers, + CEMETERYOPERATIONIDS.donationsToCemeteryFund, + ) + + return { + careIncomeFromAnswers: careIncome, + burialRevenueFromAnswers: burialRevenue, + grantFromTheCemeteryFundFromAnswers: grantFromTheCemeteryFund, + donationsToCemeteryFundFromAnswers: donationsToCemeteryFund, } - return totalAssets !== totalEquityAndLiabilities } diff --git a/libs/application/templates/inao/financial-statement-cemetery/src/utils/overviewUtils.ts b/libs/application/templates/inao/financial-statement-cemetery/src/utils/overviewUtils.ts new file mode 100644 index 000000000000..f27cb0ef6f96 --- /dev/null +++ b/libs/application/templates/inao/financial-statement-cemetery/src/utils/overviewUtils.ts @@ -0,0 +1,189 @@ +import { FormValue } from '@island.is/application/types' +import { getValueViaPath } from '@island.is/application/core' +import { CareTaker } from '../types/types' +import { formatPhoneNumber } from '@island.is/application/ui-components' +import { format as formatNationalId } from 'kennitala' +import { formatCurrency } from './currency' + +export const getOverviewNumbers = (answers: FormValue) => { + const file = getValueViaPath>(answers, 'attachments.file') + const fileName = file?.[0]?.name + const incomeLimit = + getValueViaPath(answers, 'cemeteryOperations.incomeLimit') ?? '0' + const email = getValueViaPath(answers, 'about.email') + const careIncome = getValueViaPath( + answers, + 'cemeteryIncome.careIncome', + ) + const cemeteryCaretakers = getValueViaPath>( + answers, + 'cemeteryCaretaker', + ) + const burialRevenue = getValueViaPath( + answers, + 'cemeteryIncome.burialRevenue', + ) + const grantFromTheCemeteryFund = getValueViaPath( + answers, + 'cemeteryIncome.grantFromTheCemeteryFund', + ) + const otherIncome = getValueViaPath( + answers, + 'cemeteryIncome.otherIncome', + ) + const totalIncome = getValueViaPath(answers, 'cemeteryIncome.total') + + const payroll = getValueViaPath(answers, 'cemeteryExpense.payroll') + const funeralCost = getValueViaPath( + answers, + 'cemeteryExpense.funeralCost', + ) + const chapelExpense = getValueViaPath( + answers, + 'cemeteryExpense.chapelExpense', + ) + const donationsToCemeteryFund = getValueViaPath( + answers, + 'cemeteryExpense.cemeteryFundExpense', + ) + const donationsToOther = getValueViaPath( + answers, + 'cemeteryExpense.donationsToOther', + ) + const otherOperationCost = getValueViaPath( + answers, + 'cemeteryExpense.otherOperationCost', + ) + const depreciation = getValueViaPath( + answers, + 'cemeteryExpense.depreciation', + ) + const totalExpenses = getValueViaPath( + answers, + 'cemeteryExpense.total', + ) + + const fixedAssetsTotal = getValueViaPath( + answers, + 'cemeteryAsset.fixedAssetsTotal', + ) + const currentAssets = getValueViaPath( + answers, + 'cemeteryAsset.currentAssets', + ) + const totalAssets = getValueViaPath(answers, 'assetsTotal') + + const longTerm = getValueViaPath( + answers, + 'cemeteryLiability.longTerm', + ) + const shortTerm = getValueViaPath( + answers, + 'cemeteryLiability.shortTerm', + ) + const totalLiabilities = getValueViaPath( + answers, + 'equityAndLiabilitiesTotals.liabilitiesTotal', + ) + + const equityAtTheBeginningOfTheYear = getValueViaPath( + answers, + 'cemeteryEquity.equityAtTheBeginningOfTheYear', + ) + const revaluationDueToPriceChanges = getValueViaPath( + answers, + 'cemeteryEquity.revaluationDueToPriceChanges', + ) + const reevaluateOther = getValueViaPath( + answers, + 'cemeteryEquity.reevaluateOther', + ) + const operationResult = getValueViaPath( + answers, + 'cemeteryEquity.operationResult', + ) + const totalEquity = getValueViaPath(answers, 'cemeteryEquity.total') + + const debtsAndCash = getValueViaPath( + answers, + 'equityAndLiabilitiesTotals.equityAndLiabilitiesTotal', + ) + + return { + file, + fileName, + incomeLimit, + email, + cemeteryCaretakers, + careIncome, + burialRevenue, + grantFromTheCemeteryFund, + otherIncome, + totalIncome, + payroll, + funeralCost, + chapelExpense, + donationsToCemeteryFund, + donationsToOther, + otherOperationCost, + depreciation, + totalExpenses, + fixedAssetsTotal, + currentAssets, + totalAssets, + longTerm, + shortTerm, + totalLiabilities, + equityAtTheBeginningOfTheYear, + revaluationDueToPriceChanges, + reevaluateOther, + operationResult, + totalEquity, + debtsAndCash, + } +} + +export const getAboutOverviewNumbers = (answers: FormValue) => { + const fullName = getValueViaPath(answers, 'about.fullName') + const nationalId = formatNationalId( + getValueViaPath(answers, 'about.nationalId') ?? '', + ) + const powerOfAttorneyName = getValueViaPath( + answers, + 'about.powerOfAttorneyName', + ) + const powerOfAttorneyNationalId = formatNationalId( + getValueViaPath(answers, 'about.powerOfAttorneyNationalId') ?? '', + ) + const email = getValueViaPath(answers, 'about.email') + const phoneNumber = formatPhoneNumber( + getValueViaPath(answers, 'about.phoneNumber') ?? '', + ) + + return { + fullName, + nationalId, + powerOfAttorneyName, + powerOfAttorneyNationalId, + email, + phoneNumber, + } +} + +export const getCapitalNumbersOverviewNumbers = (answers: FormValue) => { + const capitalIncome = formatCurrency( + getValueViaPath(answers, 'capitalNumbers.capitalIncome'), + ) + const capitalCost = formatCurrency( + getValueViaPath(answers, 'capitalNumbers.capitalCost'), + ) + const totalCapital = formatCurrency( + getValueViaPath(answers, 'capitalNumbers.total'), + ) + + return { + capitalIncome, + capitalCost, + totalCapital, + } +} diff --git a/libs/application/templates/inao/financial-statement-cemetery/src/utils/sums.ts b/libs/application/templates/inao/financial-statement-cemetery/src/utils/sums.ts new file mode 100644 index 000000000000..4b8e6c2e1738 --- /dev/null +++ b/libs/application/templates/inao/financial-statement-cemetery/src/utils/sums.ts @@ -0,0 +1,225 @@ +import { FormValue } from '@island.is/application/types' +import { getValueViaPath } from '@island.is/application/core' +import { + CAPITALNUMBERS, + CEMETERYEQUITIESANDLIABILITIESIDS, + CEMETERYOPERATIONIDS, + EQUITYANDLIABILITIESTOTALS, + OPERATINGCOST, +} from './constants' + +export const sumIncome = (answers: FormValue) => { + const careIncome = + getValueViaPath(answers, CEMETERYOPERATIONIDS.careIncome) || '0' + const burialRevenue = + getValueViaPath(answers, CEMETERYOPERATIONIDS.burialRevenue) || '0' + const grantFromTheCemeteryFund = + getValueViaPath( + answers, + CEMETERYOPERATIONIDS.grantFromTheCemeteryFund, + ) || '0' + const otherIncome = + getValueViaPath(answers, CEMETERYOPERATIONIDS.otherIncome) || '0' + + return `${ + Number(careIncome) + + Number(burialRevenue) + + Number(grantFromTheCemeteryFund) + + Number(otherIncome) + }` +} + +export const sumExpenses = (answers: FormValue) => { + const payroll = getValueViaPath(answers, CEMETERYOPERATIONIDS.payroll) + const funeralCost = + getValueViaPath(answers, CEMETERYOPERATIONIDS.funeralCost) || '0' + const chapelExpense = + getValueViaPath(answers, CEMETERYOPERATIONIDS.chapelExpense) || '0' + const donationsToCemeteryFund = + getValueViaPath( + answers, + CEMETERYOPERATIONIDS.donationsToCemeteryFund, + ) || '0' + const donationsToOther = + getValueViaPath(answers, CEMETERYOPERATIONIDS.donationsToOther) || + '0' + const otherOperationCost = + getValueViaPath(answers, CEMETERYOPERATIONIDS.otherOperationCost) || + '0' + const depreciation = + getValueViaPath(answers, CEMETERYOPERATIONIDS.depreciation) || '0' + + return `${ + Number(payroll) + + Number(funeralCost) + + Number(chapelExpense) + + Number(donationsToCemeteryFund) + + Number(donationsToOther) + + Number(otherOperationCost) + + Number(depreciation) + }` +} + +export const sumOperatingResults = (answers: FormValue) => { + const income = + getValueViaPath(answers, CEMETERYOPERATIONIDS.totalIncome) || '0' + const expenses = + getValueViaPath(answers, CEMETERYOPERATIONIDS.totalExpense) || '0' + + return `${Number(income) - Number(expenses)}` +} + +export const sumCapitalNumbers = (answers: FormValue) => { + const capitalIncome = + getValueViaPath(answers, CAPITALNUMBERS.capitalIncome) || '0' + const capitalCost = + getValueViaPath(answers, CAPITALNUMBERS.capitalCost) || '0' + return `${Number(capitalIncome) - Number(capitalCost)}` +} + +export const sumAssets = (answers: FormValue) => { + const fixedAssetsTotal = + getValueViaPath( + answers, + CEMETERYEQUITIESANDLIABILITIESIDS.fixedAssetsTotal, + ) || '0' + const currentAssets = + getValueViaPath( + answers, + CEMETERYEQUITIESANDLIABILITIESIDS.currentAssets, + ) || '0' + return `${Number(fixedAssetsTotal) + Number(currentAssets)}` +} + +export const sumLiabilities = (answers: FormValue) => { + const longTerm = + getValueViaPath( + answers, + CEMETERYEQUITIESANDLIABILITIESIDS.longTerm, + ) || '0' + const shortTerm = + getValueViaPath( + answers, + CEMETERYEQUITIESANDLIABILITIESIDS.shortTerm, + ) || '0' + return `${Number(longTerm) + Number(shortTerm)}` +} + +export const operationResult = (answers: FormValue) => { + const operatingTotalCost = + getValueViaPath(answers, OPERATINGCOST.total) || '0' + const capitalTotal = + getValueViaPath(answers, CAPITALNUMBERS.total) || '0' + return `${Number(operatingTotalCost) + Number(capitalTotal)}` +} + +export const sumTotalEquity = (answers: FormValue) => { + const equityAtTheBeginningOfTheYear = + getValueViaPath( + answers, + CEMETERYEQUITIESANDLIABILITIESIDS.equityAtTheBeginningOfTheYear, + ) || '0' + const revaluationDueToPriceChanges = + getValueViaPath( + answers, + CEMETERYEQUITIESANDLIABILITIESIDS.revaluationDueToPriceChanges, + ) || '0' + const reevaluateOther = + getValueViaPath( + answers, + CEMETERYEQUITIESANDLIABILITIESIDS.reevaluateOther, + ) || '0' + const operationResult = + getValueViaPath( + answers, + CEMETERYEQUITIESANDLIABILITIESIDS.operationResult, + ) || '0' + + return `${ + Number(equityAtTheBeginningOfTheYear) + + Number(revaluationDueToPriceChanges) + + Number(reevaluateOther) + + Number(operationResult) + }` +} + +export const sumTotalEquityAndLiabilities = (answers: FormValue) => { + const liabilityTotal = + getValueViaPath( + answers, + EQUITYANDLIABILITIESTOTALS.liabilitiesTotal, + ) || '0' + const totalEquity = + getValueViaPath( + answers, + CEMETERYEQUITIESANDLIABILITIESIDS.equityTotal, + ) || '0' + + return `${Number(totalEquity) + Number(liabilityTotal)}` +} + +export const showEquitiesAndLiabilitiesAlert = (answers: FormValue) => { + const fixedAssetsTotal = + getValueViaPath( + answers, + CEMETERYEQUITIESANDLIABILITIESIDS.fixedAssetsTotal, + ) || '0' + const currentAssets = + getValueViaPath( + answers, + CEMETERYEQUITIESANDLIABILITIESIDS.currentAssets, + ) || '0' + const longTerm = + getValueViaPath( + answers, + CEMETERYEQUITIESANDLIABILITIESIDS.longTerm, + ) || '0' + const shortTerm = + getValueViaPath( + answers, + CEMETERYEQUITIESANDLIABILITIESIDS.shortTerm, + ) || '0' + const equityAtTheBeginningOfTheYear = + getValueViaPath( + answers, + CEMETERYEQUITIESANDLIABILITIESIDS.equityAtTheBeginningOfTheYear, + ) || '0' + const revaluationDueToPriceChanges = + getValueViaPath( + answers, + CEMETERYEQUITIESANDLIABILITIESIDS.revaluationDueToPriceChanges, + ) || '0' + const reevaluateOther = + getValueViaPath( + answers, + CEMETERYEQUITIESANDLIABILITIESIDS.reevaluateOther, + ) || '0' + + const totalAssets = + getValueViaPath(answers, EQUITYANDLIABILITIESTOTALS.assetsTotal) || + '0' + const totalEquityAndLiabilities = + getValueViaPath( + answers, + EQUITYANDLIABILITIESTOTALS.equityAndLiabilitiesTotal, + ) || '0' + const operationResult = + getValueViaPath( + answers, + CEMETERYEQUITIESANDLIABILITIESIDS.operationResult, + ) || '0' + + if ( + !fixedAssetsTotal || + !currentAssets || + !longTerm || + !shortTerm || + !equityAtTheBeginningOfTheYear || + !revaluationDueToPriceChanges || + !reevaluateOther || + !operationResult + ) { + return false + } + return totalAssets !== totalEquityAndLiabilities +} diff --git a/libs/application/templates/public-debt-payment-plan/src/fields/Overview/Overview.tsx b/libs/application/templates/public-debt-payment-plan/src/fields/Overview/Overview.tsx index dc2d8f8c5f84..59646a7a88ad 100644 --- a/libs/application/templates/public-debt-payment-plan/src/fields/Overview/Overview.tsx +++ b/libs/application/templates/public-debt-payment-plan/src/fields/Overview/Overview.tsx @@ -53,7 +53,7 @@ export const Overview = ({ application, goToScreen }: FieldBaseProps) => { 'paymentPlans', ) as PaymentPlan[] - const identityRegistry = getValueViaPath( + const identity = getValueViaPath( application.externalData, 'identity', ) as IdentityResult @@ -138,14 +138,14 @@ export const Overview = ({ application, goToScreen }: FieldBaseProps) => { editAction('applicantSection')}> - {identityRegistry?.data?.name && ( + {identity?.data?.name && ( - {identityRegistry.data.name} + {identity.data.name} )} {applicant?.phoneNumber && ( @@ -158,12 +158,12 @@ export const Overview = ({ application, goToScreen }: FieldBaseProps) => { )} - {identityRegistry?.data?.address?.streetAddress && - identityRegistry?.data?.address?.postalCode && - identityRegistry?.data?.address?.city && ( + {identity?.data?.address?.streetAddress && + identity?.data?.address?.postalCode && + identity?.data?.address?.city && ( - {`${identityRegistry?.data?.address?.streetAddress}, ${identityRegistry?.data?.address?.postalCode} ${identityRegistry?.data?.address?.city}`} + {`${identity?.data?.address?.streetAddress}, ${identity?.data?.address?.postalCode} ${identity?.data?.address?.city}`} )} {applicant?.email && ( diff --git a/libs/application/templates/reference-template/src/lib/dataSchema.ts b/libs/application/templates/reference-template/src/lib/dataSchema.ts index faa3b728cff4..e4945ef27981 100644 --- a/libs/application/templates/reference-template/src/lib/dataSchema.ts +++ b/libs/application/templates/reference-template/src/lib/dataSchema.ts @@ -15,6 +15,20 @@ const careerHistoryCompaniesValidation = (data: any) => { } export const ExampleSchema = z.object({ approveExternalData: z.boolean().refine((v) => v), + tableRepeaterField: z.array( + z.object({ + nationalIdWithName: z.object({ + name: z.string().min(1).max(256), + nationalId: z.string().refine((n) => n && kennitala.isValid(n), { + params: m.dataSchemeNationalId, + }), + phone: z.string().refine(isValidNumber, { + params: m.dataSchemePhoneNumber, + }), + email: z.string().email(), + }), + }), + ), person: z.object({ name: z.string().min(1).max(256), age: z.string().refine((x) => { diff --git a/libs/application/templates/social-insurance-administration/income-plan/src/fields/Review/index.tsx b/libs/application/templates/social-insurance-administration/income-plan/src/fields/Review/index.tsx index 9a420ccf1e56..4dbb1ffe6f0c 100644 --- a/libs/application/templates/social-insurance-administration/income-plan/src/fields/Review/index.tsx +++ b/libs/application/templates/social-insurance-administration/income-plan/src/fields/Review/index.tsx @@ -126,21 +126,6 @@ export const Review: FC = ({ - {state === `${States.TRYGGINGASTOFNUN_SUBMITTED}` && ( - - )} + {subEyebrow ? ( + + + {eyebrow} + + + {subEyebrow} + + + ) : ( + + {eyebrow} + + )} + {renderLogo()} + ) } - return ( - - - {renderEyebrow()} + const renderContent = () => { + if (size === 'large') { + return ( + + + + + {title} + + {description && ( + + {description} + + )} + + {renderDetails()} + + + ) + } + return ( + <> {title} - {text && ( + {description && ( - {text} + {description} )} {renderDetails()} - - {renderTag()} - {renderCta()} - + + ) + } + + return ( + <> + {renderHeader()} + {renderContent()} + + {renderTags()} - + ) } diff --git a/libs/island-ui/core/src/lib/InfoCardGrid/InfoCard.css.ts b/libs/island-ui/core/src/lib/InfoCardGrid/InfoCard.css.ts new file mode 100644 index 000000000000..4c27d84947de --- /dev/null +++ b/libs/island-ui/core/src/lib/InfoCardGrid/InfoCard.css.ts @@ -0,0 +1,20 @@ +import { style } from '@vanilla-extract/css' + +export const infoCardSmall = style({ + maxWidth: 310, + minHeight: 450, +}) + +export const infoCard = style({ + maxWidth: 477, + minHeight: 432, +}) + +export const infoCardWide = style({ + maxWidth: 978, + minHeight: 318, +}) + +export const wideTitleBox = style({ + flexGrow: 2, +}) diff --git a/libs/island-ui/core/src/lib/InfoCardGrid/InfoCard.tsx b/libs/island-ui/core/src/lib/InfoCardGrid/InfoCard.tsx new file mode 100644 index 000000000000..339d50453d1a --- /dev/null +++ b/libs/island-ui/core/src/lib/InfoCardGrid/InfoCard.tsx @@ -0,0 +1,72 @@ +import { useEffect, useState } from 'react' +import { useWindowSize } from 'react-use' + +import { theme } from '@island.is/island-ui/theme' + +import { DetailedInfoCard, DetailedProps } from './DetailedInfoCard' +import { SimpleInfoCard } from './SimpleInfoCard' +import * as styles from './InfoCard.css' +import { Box, FocusableBox, LinkV2 } from '../..' + +export interface BaseProps { + id: string + title: string + description: string + eyebrow: string + size: 'large' | 'medium' | 'small' + link: { + label: string + href: string + } +} + +export type InfoCardProps = + | (BaseProps & { + variant?: 'simple' + }) + | (DetailedProps & { + variant: 'detailed' + }) + +export const InfoCard = ({ size, ...restOfProps }: InfoCardProps) => { + const [isMobile, setIsMobile] = useState(false) + const { width } = useWindowSize() + + useEffect(() => { + if (width < theme.breakpoints.md) { + return setIsMobile(true) + } + setIsMobile(false) + }, [width]) + + const cardSize = isMobile ? 'small' : size + + return ( + + + {restOfProps.variant === 'detailed' ? ( + + ) : ( + + )} + + + ) +} diff --git a/libs/island-ui/core/src/lib/InfoCardGrid/InfoCardGrid.tsx b/libs/island-ui/core/src/lib/InfoCardGrid/InfoCardGrid.tsx new file mode 100644 index 000000000000..73b454a9cabb --- /dev/null +++ b/libs/island-ui/core/src/lib/InfoCardGrid/InfoCardGrid.tsx @@ -0,0 +1,50 @@ +import { useEffect, useState } from 'react' +import { useWindowSize } from 'react-use' + +import { Inline, Stack } from '../..' +import { theme } from '@island.is/island-ui/theme' + +import { InfoCard, InfoCardProps } from './InfoCard' + +export type InfoCardItemProps = Omit + +interface Props { + cards: Array + variant?: 'detailed' | 'simple' + columns?: 1 | 2 | 3 +} + +export const InfoCardGrid = ({ cards, variant, columns }: Props) => { + const [isMobile, setIsMobile] = useState(false) + const { width } = useWindowSize() + + useEffect(() => { + if (width < theme.breakpoints.md) { + return setIsMobile(true) + } + setIsMobile(false) + }, [width]) + + if (columns === 1 || isMobile) { + return ( + + {cards.map((c) => ( + + ))} + + ) + } + + return ( + + {cards.map((c, index) => ( + + ))} + + ) +} diff --git a/libs/island-ui/core/src/lib/InfoCardGrid/SimpleInfoCard.tsx b/libs/island-ui/core/src/lib/InfoCardGrid/SimpleInfoCard.tsx new file mode 100644 index 000000000000..34b633891737 --- /dev/null +++ b/libs/island-ui/core/src/lib/InfoCardGrid/SimpleInfoCard.tsx @@ -0,0 +1,71 @@ +import { Box, GridColumn, GridContainer, GridRow, Text } from '../..' + +import { BaseProps } from './InfoCard' + +const eyebrowColor = 'blueberry600' + +export const SimpleInfoCard = ({ + title, + description, + size = 'medium', + eyebrow, +}: BaseProps) => { + const renderHeader = () => { + if (!eyebrow) { + return + } + return ( + + + {eyebrow} + + + ) + } + + const renderContent = () => { + if (size === 'large') { + return ( + + + + + {title} + + {description && ( + + {description} + + )} + + + + ) + } + return ( + <> + + {title} + + {description && ( + + {description} + + )} + + ) + } + + return ( + <> + {renderHeader()} + {renderContent()} + + ) +} diff --git a/libs/island-ui/core/src/lib/InfoCardGrid/index.ts b/libs/island-ui/core/src/lib/InfoCardGrid/index.ts new file mode 100644 index 000000000000..29cb05d74923 --- /dev/null +++ b/libs/island-ui/core/src/lib/InfoCardGrid/index.ts @@ -0,0 +1 @@ +export { InfoCardGrid } from './InfoCardGrid' diff --git a/libs/judicial-system/message/src/lib/message.service.ts b/libs/judicial-system/message/src/lib/message.service.ts index 671b1d099478..a457fc512d70 100644 --- a/libs/judicial-system/message/src/lib/message.service.ts +++ b/libs/judicial-system/message/src/lib/message.service.ts @@ -198,6 +198,9 @@ export class MessageService { ): Promise { const MAX_BATCH_SIZE = 10 + if (messages.length === 0) { + return // No messages to send + } if (messages.length <= MAX_BATCH_SIZE) { const queueUrl = await this.getQueueUrl() diff --git a/libs/judicial-system/message/src/lib/message.ts b/libs/judicial-system/message/src/lib/message.ts index c93854bab4e6..bb32cdc84e05 100644 --- a/libs/judicial-system/message/src/lib/message.ts +++ b/libs/judicial-system/message/src/lib/message.ts @@ -23,6 +23,7 @@ export enum MessageType { DELIVERY_TO_POLICE_INDICTMENT = 'DELIVERY_TO_POLICE_INDICTMENT', DELIVERY_TO_POLICE_CASE_FILES_RECORD = 'DELIVERY_TO_POLICE_CASE_FILES_RECORD', DELIVERY_TO_POLICE_SUBPOENA = 'DELIVERY_TO_POLICE_SUBPOENA', + DELIVERY_TO_POLICE_SIGNED_COURT_RECORD = 'DELIVERY_TO_POLICE_SIGNED_COURT_RECORD', DELIVERY_TO_POLICE_SIGNED_RULING = 'DELIVERY_TO_POLICE_SIGNED_RULING', DELIVERY_TO_POLICE_APPEAL = 'DELIVERY_TO_POLICE_APPEAL', NOTIFICATION = 'NOTIFICATION', @@ -62,6 +63,7 @@ export const messageEndpoint: { [key in MessageType]: string } = { DELIVERY_TO_POLICE_INDICTMENT: 'deliverIndictmentToPolice', DELIVERY_TO_POLICE_CASE_FILES_RECORD: 'deliverCaseFilesRecordToPolice', DELIVERY_TO_POLICE_SUBPOENA: 'deliverSubpoenaToPolice', + DELIVERY_TO_POLICE_SIGNED_COURT_RECORD: 'deliverSignedCourtRecordToPolice', DELIVERY_TO_POLICE_SIGNED_RULING: 'deliverSignedRulingToPolice', DELIVERY_TO_POLICE_APPEAL: 'deliverAppealToPolice', NOTIFICATION: 'notification', diff --git a/libs/judicial-system/types/src/index.ts b/libs/judicial-system/types/src/index.ts index 82a11272ee06..a10d648c52a1 100644 --- a/libs/judicial-system/types/src/index.ts +++ b/libs/judicial-system/types/src/index.ts @@ -7,6 +7,7 @@ export { DefendantPlea, ServiceRequirement, ServiceStatus, + PunishmentType, isSuccessfulServiceStatus, isFailedServiceStatus, } from './lib/defendant' diff --git a/libs/judicial-system/types/src/lib/defendant.ts b/libs/judicial-system/types/src/lib/defendant.ts index 03b843eb6d46..2bd9c1be3953 100644 --- a/libs/judicial-system/types/src/lib/defendant.ts +++ b/libs/judicial-system/types/src/lib/defendant.ts @@ -36,6 +36,14 @@ export enum ServiceStatus { EXPIRED = 'EXPIRED', // If a subpoena expires } +export enum PunishmentType { + IMPRISONMENT = 'IMPRISONMENT', + PROBATION = 'PROBATION', + FINE = 'FINE', + INDICTMENT_RULING_DECISION_FINE = 'INDICTMENT_RULING_DECISION_FINE', + SIGNED_FINE_INVITATION = 'SIGNED_FINE_INVITATION', +} + export const successfulServiceStatus: string[] = [ ServiceStatus.ELECTRONICALLY, ServiceStatus.DEFENDER, diff --git a/libs/judicial-system/types/src/lib/notification.ts b/libs/judicial-system/types/src/lib/notification.ts index 347cef7b5852..ee863976b056 100644 --- a/libs/judicial-system/types/src/lib/notification.ts +++ b/libs/judicial-system/types/src/lib/notification.ts @@ -3,6 +3,8 @@ export enum CaseNotificationType { READY_FOR_COURT = 'READY_FOR_COURT', RECEIVED_BY_COURT = 'RECEIVED_BY_COURT', COURT_DATE = 'COURT_DATE', + DISTRICT_COURT_JUDGE_ASSIGNED = 'DISTRICT_COURT_JUDGE_ASSIGNED', + DISTRICT_COURT_REGISTRAR_ASSIGNED = 'DISTRICT_COURT_REGISTRAR_ASSIGNED', RULING = 'RULING', MODIFIED = 'MODIFIED', REVOKED = 'REVOKED', diff --git a/libs/judicial-system/types/src/lib/user.ts b/libs/judicial-system/types/src/lib/user.ts index 8c0dcb478e20..408c3136cebd 100644 --- a/libs/judicial-system/types/src/lib/user.ts +++ b/libs/judicial-system/types/src/lib/user.ts @@ -70,8 +70,8 @@ export const isPublicProsecutorUser = (user?: InstitutionUser): boolean => { return Boolean( user?.role && publicProsecutorRoles.includes(user.role) && - user?.institution?.type === InstitutionType.PROSECUTORS_OFFICE && - user?.institution?.id === '8f9e2f6d-6a00-4a5e-b39b-95fd110d762e', // TODO: Create a new institution type to avoid hardcoding + user.institution?.type === InstitutionType.PROSECUTORS_OFFICE && + user.institution?.id === '8f9e2f6d-6a00-4a5e-b39b-95fd110d762e', // TODO: Create a new institution type to avoid hardcoding ) } @@ -85,7 +85,7 @@ export const isDistrictCourtUser = (user?: InstitutionUser): boolean => { return Boolean( user?.role && districtCourtRoles.includes(user.role) && - user?.institution?.type === InstitutionType.DISTRICT_COURT, + user.institution?.type === InstitutionType.DISTRICT_COURT, ) } @@ -99,7 +99,7 @@ export const isCourtOfAppealsUser = (user?: InstitutionUser): boolean => { return Boolean( user?.role && courtOfAppealsRoles.includes(user.role) && - user?.institution?.type === InstitutionType.COURT_OF_APPEALS, + user.institution?.type === InstitutionType.COURT_OF_APPEALS, ) } @@ -109,14 +109,14 @@ export const isPrisonSystemUser = (user?: InstitutionUser): boolean => { return Boolean( user?.role && prisonSystemRoles.includes(user.role) && - (user?.institution?.type === InstitutionType.PRISON || - user?.institution?.type === InstitutionType.PRISON_ADMIN), + (user.institution?.type === InstitutionType.PRISON || + user.institution?.type === InstitutionType.PRISON_ADMIN), ) } -export const isPrisonAdminUser = (user: InstitutionUser): boolean => +export const isPrisonAdminUser = (user?: InstitutionUser): boolean => Boolean( - user.role && + user?.role && prisonSystemRoles.includes(user.role) && user.institution?.type === InstitutionType.PRISON_ADMIN, ) diff --git a/libs/portals/my-pages/health/src/screens/Payments/PaymentOverview.tsx b/libs/portals/my-pages/health/src/screens/Payments/PaymentOverview.tsx index b8c4ea75b5b9..a5ecc6b76e34 100644 --- a/libs/portals/my-pages/health/src/screens/Payments/PaymentOverview.tsx +++ b/libs/portals/my-pages/health/src/screens/Payments/PaymentOverview.tsx @@ -1,5 +1,4 @@ import { - AlertMessage, Box, DatePicker, SkeletonLoader, @@ -16,7 +15,6 @@ import { DownloadFileButtons, UserInfoLine, amountFormat, - formSubmit, m, } from '@island.is/portals/my-pages/core' import { messages } from '../../lib/messages' @@ -88,10 +86,6 @@ export const PaymentOverview = () => { }) } - const onFetchDocument = (url: string) => { - formSubmit(url) - } - useEffect(() => { onFetchBills() // eslint-disable-next-line react-hooks/exhaustive-deps @@ -209,9 +203,6 @@ export const PaymentOverview = () => { {formatMessage(messages.insuranceShare)} - - {formatMessage(messages.paymentDocument)} - @@ -229,21 +220,6 @@ export const PaymentOverview = () => { {amountFormat(item.insuranceAmount ?? 0)} - - - ) })} diff --git a/libs/portals/my-pages/social-insurance-maintenance/src/lib/messages.ts b/libs/portals/my-pages/social-insurance-maintenance/src/lib/messages.ts index f90f69b54bab..233106923711 100644 --- a/libs/portals/my-pages/social-insurance-maintenance/src/lib/messages.ts +++ b/libs/portals/my-pages/social-insurance-maintenance/src/lib/messages.ts @@ -122,9 +122,9 @@ export const m = defineMessages({ id: 'sp.social-insurance-maintenance:income-plan-link-text', defaultMessage: 'Hvað er tekjuáætlun?', }, - incomePlanTemporarilyUnavailable: { - id: 'sp.social-insurance-maintenance:income-plan-temporarily-unavailable', + paymentPlanTemporarilyUnavailable: { + id: 'sp.social-insurance-maintenance:payment-plan-temporarily-unavailable', defaultMessage: - 'Bráðabirgðatekjuáætlun 2025 verður tilbúin seinni part desember', + 'Bráðabirgðagreiðsluáætlun 2025 verður tilbúin seinni part desember', }, }) diff --git a/libs/portals/my-pages/social-insurance-maintenance/src/screens/IncomePlanDetail/IncomePlanDetail.tsx b/libs/portals/my-pages/social-insurance-maintenance/src/screens/IncomePlanDetail/IncomePlanDetail.tsx index 51878ab260c9..5adb2a673a20 100644 --- a/libs/portals/my-pages/social-insurance-maintenance/src/screens/IncomePlanDetail/IncomePlanDetail.tsx +++ b/libs/portals/my-pages/social-insurance-maintenance/src/screens/IncomePlanDetail/IncomePlanDetail.tsx @@ -15,60 +15,14 @@ import { m as coreMessages, } from '@island.is/portals/my-pages/core' import { m } from '../../lib/messages' -import { - useGetIncomePlanDetailLazyQuery, - useGetIncomePlanDetailQuery, -} from './IncomePlanDetail.generated' +import { useGetIncomePlanDetailQuery } from './IncomePlanDetail.generated' import { Problem } from '@island.is/react-spa/shared' -import { useEffect, useState } from 'react' -import { useFeatureFlagClient } from '@island.is/react/feature-flags' const IncomePlanDetail = () => { useNamespaces('sp.social-insurance-maintenance') const { formatMessage } = useLocale() - const [displayPaymentPlan, setDisplayPaymentPlan] = useState(false) - const [query, { data, loading, error }] = useGetIncomePlanDetailLazyQuery() - - const featureFlagClient = useFeatureFlagClient() - useEffect(() => { - const isFlagEnabled = async () => { - const ffEnabled = await featureFlagClient.getValue( - `isServicePortalPaymentPlan2025Enabled`, - false, - ) - if (ffEnabled) { - setDisplayPaymentPlan(ffEnabled as boolean) - } - } - isFlagEnabled() - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []) - - useEffect(() => { - if (displayPaymentPlan) { - query() - } - }, [displayPaymentPlan]) - - if (!displayPaymentPlan) { - return ( - - - - ) - } - + const { data, loading, error } = useGetIncomePlanDetailQuery() return ( { useNamespaces('sp.social-insurance-maintenance') const { formatMessage } = useLocale() - const { data, loading, error } = useGetPreviousPaymentsQuery() + const [displayPaymentPlan, setDisplayPaymentPlan] = useState(false) + const [query, { data, loading, error }] = useGetPreviousPaymentsLazyQuery() + + const featureFlagClient = useFeatureFlagClient() + + useEffect(() => { + const isFlagEnabled = async () => { + const ffEnabled = await featureFlagClient.getValue( + `isServicePortalPaymentPlan2025Enabled`, + false, + ) + if (ffEnabled) { + setDisplayPaymentPlan(ffEnabled as boolean) + } + } + isFlagEnabled() + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []) + + useEffect(() => { + if (displayPaymentPlan) { + query() + } + }, [displayPaymentPlan]) + + if (!displayPaymentPlan) { + return ( + + + + ) + } return ( - { serviceProviderTooltip={formatMessage( coreMessages.socialInsuranceTooltip, )} - /> - {error && !loading ? ( - - ) : !error && !loading && !data?.socialInsurancePayments ? ( - - ) : ( - <> - - - - - - - + > + {error && !loading ? ( + + ) : !error && !loading && !data?.socialInsurancePayments ? ( + + ) : ( + <> + + + + + + + - - {formatMessage(coreMessages.period)} - + + {formatMessage(coreMessages.period)} + - - - - - {formatMessage(m.maintenanceFooter)} - {formatMessage(m.maintenanceFooterLink, { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - link: (str: any) => ( - - ), - })} - - - - )} - + + + + + {formatMessage(m.maintenanceFooter)} + {formatMessage(m.maintenanceFooterLink, { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + link: (str: any) => ( + + ), + })} + + + + )} + ) } diff --git a/libs/react-spa/bff/src/lib/BffPoller.tsx b/libs/react-spa/bff/src/lib/BffPoller.tsx index 8374bbcdc5b0..86f1330a1a12 100644 --- a/libs/react-spa/bff/src/lib/BffPoller.tsx +++ b/libs/react-spa/bff/src/lib/BffPoller.tsx @@ -3,7 +3,7 @@ import { BffUser } from '@island.is/shared/types' import { ReactNode, useCallback, useEffect, useMemo } from 'react' import { BffBroadcastEvents, - useBff, + useAuth, useBffBroadcaster, useUserInfo, } from './bff.hooks' @@ -43,9 +43,10 @@ export const BffPoller = ({ newSessionCb, pollIntervalMS = 10000, }: BffPollerProps) => { - const { signIn, bffUrlGenerator } = useBff() + const { signIn, bffUrlGenerator } = useAuth() const userInfo = useUserInfo() const { postMessage } = useBffBroadcaster() + const bffBaseUrl = bffUrlGenerator() const url = useMemo( () => bffUrlGenerator('/user', { refresh: 'true' }), @@ -86,12 +87,13 @@ export const BffPoller = ({ postMessage({ type: BffBroadcastEvents.NEW_SESSION, userInfo: newUser, + bffBaseUrl, }) newSessionCb() } } - }, [newUser, error, userInfo, signIn, postMessage, newSessionCb]) + }, [newUser, error, userInfo, signIn, postMessage, newSessionCb, bffBaseUrl]) return children } diff --git a/libs/react-spa/bff/src/lib/BffProvider.tsx b/libs/react-spa/bff/src/lib/BffProvider.tsx index f10534fc550e..a8917228a07e 100644 --- a/libs/react-spa/bff/src/lib/BffProvider.tsx +++ b/libs/react-spa/bff/src/lib/BffProvider.tsx @@ -43,25 +43,37 @@ export const BffProvider = ({ authState === 'logging-out' const isLoggedIn = authState === 'logged-in' const oldLoginPath = `${applicationBasePath}/login` + const bffBaseUrl = bffUrlGenerator() const { postMessage } = useBffBroadcaster((event) => { - if ( - isLoggedIn && - event.data.type === BffBroadcastEvents.NEW_SESSION && - isNewUser(state.userInfo, event.data.userInfo) - ) { - setSessionExpiredScreen(true) - } else if (event.data.type === BffBroadcastEvents.LOGOUT) { - // We will wait 1 seconds before we dispatch logout action. - // The reason is that IDS will not log the user out immediately. - // Note! The bff poller may have triggered logout by that time anyways. - setTimeout(() => { - dispatch({ - type: ActionType.LOGGED_OUT, - }) - - signIn() - }, 1000) + /** + * Filter broadcast events by matching BFF base url + * + * Since the Broadcaster sends messages to all tabs/windows/iframes + * sharing the same origin (domain), we need to explicitly check if + * the message belongs to our specific BFF instance by comparing base urls. + * This prevents handling events meant for other applications/contexts + * running on the same domain. + */ + if (event.data.bffBaseUrl === bffBaseUrl) { + if ( + isLoggedIn && + event.data.type === BffBroadcastEvents.NEW_SESSION && + isNewUser(state.userInfo, event.data.userInfo) + ) { + setSessionExpiredScreen(true) + } else if (event.data.type === BffBroadcastEvents.LOGOUT) { + // We will wait 1 seconds before we dispatch logout action. + // The reason is that IDS will not log the user out immediately. + // Note! The bff poller may have triggered logout by that time anyways. + setTimeout(() => { + dispatch({ + type: ActionType.LOGGED_OUT, + }) + + signIn() + }, 1000) + } } }) @@ -71,9 +83,10 @@ export const BffProvider = ({ postMessage({ type: BffBroadcastEvents.NEW_SESSION, userInfo: state.userInfo, + bffBaseUrl, }) } - }, [postMessage, state.userInfo, isLoggedIn]) + }, [postMessage, state.userInfo, isLoggedIn, bffBaseUrl]) /** * Builds authentication query parameters for login redirection: @@ -175,12 +188,13 @@ export const BffProvider = ({ // Broadcast to all tabs/windows/iframes that the user is logging out postMessage({ type: BffBroadcastEvents.LOGOUT, + bffBaseUrl, }) window.location.href = bffUrlGenerator('/logout', { sid: state.userInfo.profile.sid, }) - }, [bffUrlGenerator, postMessage, state.userInfo]) + }, [bffUrlGenerator, postMessage, state.userInfo, bffBaseUrl]) const switchUser = useCallback( (nationalId?: string) => { diff --git a/libs/react-spa/bff/src/lib/bff.hooks.ts b/libs/react-spa/bff/src/lib/bff.hooks.ts index b768ad209ba7..019258b759b4 100644 --- a/libs/react-spa/bff/src/lib/bff.hooks.ts +++ b/libs/react-spa/bff/src/lib/bff.hooks.ts @@ -8,11 +8,11 @@ import { BffContext, BffContextType } from './BffContext' /** * This hook is used to get the BFF authentication context. */ -export const useBff = () => { +export const useAuth = () => { const bffContext = useContext(BffContext) if (!bffContext) { - throw new Error('useBff must be used within a BffProvider') + throw new Error('useAuth must be used within a BffProvider') } return bffContext @@ -24,7 +24,7 @@ export const useBff = () => { export const useDynamicBffHook = ( returnField: Key, ): NonNullable => { - const bffContext = useBff() + const bffContext = useAuth() if (!isDefined(bffContext[returnField])) { throw new Error(`The field ${returnField} does not exist in the BffContext`) @@ -64,10 +64,12 @@ export enum BffBroadcastEvents { type NewSessionEvent = { type: BffBroadcastEvents.NEW_SESSION userInfo: BffUser + bffBaseUrl: string } type LogoutEvent = { type: BffBroadcastEvents.LOGOUT + bffBaseUrl: string } export type BffBroadcastEvent = NewSessionEvent | LogoutEvent diff --git a/libs/shared/components/src/auth/UserMenu/UserDelegations.tsx b/libs/shared/components/src/auth/UserMenu/UserDelegations.tsx index 707a82fa022f..b4db29d4d10f 100644 --- a/libs/shared/components/src/auth/UserMenu/UserDelegations.tsx +++ b/libs/shared/components/src/auth/UserMenu/UserDelegations.tsx @@ -1,6 +1,6 @@ import { Box, Stack } from '@island.is/island-ui/core' import { useLocale } from '@island.is/localization' -import { useBff, useUserInfo } from '@island.is/react-spa/bff' +import { useAuth, useUserInfo } from '@island.is/react-spa/bff' import { userMessages } from '@island.is/shared/translations' import { UserDropdownItem } from './UserDropdownItem' import { UserTopicCard } from './UserTopicCard' @@ -16,7 +16,7 @@ export const UserDelegations = ({ }: UserDelegationsProps) => { const user = useUserInfo() const { formatMessage } = useLocale() - const { switchUser } = useBff() + const { switchUser } = useAuth() const actor = user.profile.actor return ( diff --git a/libs/shared/components/src/auth/UserMenu/UserMenu.tsx b/libs/shared/components/src/auth/UserMenu/UserMenu.tsx index a2ffae0c76fb..875b16169a25 100644 --- a/libs/shared/components/src/auth/UserMenu/UserMenu.tsx +++ b/libs/shared/components/src/auth/UserMenu/UserMenu.tsx @@ -1,5 +1,5 @@ import { Box, Hidden } from '@island.is/island-ui/core' -import { useBff } from '@island.is/react-spa/bff' +import { useAuth } from '@island.is/react-spa/bff' import { useEffect, useState } from 'react' import { UserButton } from './UserButton' import { UserDropdown } from './UserDropdown' @@ -29,7 +29,7 @@ export const UserMenu = ({ const [dropdownState, setDropdownState] = useState<'closed' | 'open'>( 'closed', ) - const { signOut, switchUser, userInfo: user } = useBff() + const { signOut, switchUser, userInfo: user } = useAuth() const handleClick = () => { setDropdownState(dropdownState === 'open' ? 'closed' : 'open') diff --git a/yarn.lock b/yarn.lock index e0441eb6d923..26095abdf270 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2754,6 +2754,15 @@ __metadata: languageName: node linkType: hard +"@babel/helper-annotate-as-pure@npm:^7.25.9": + version: 7.25.9 + resolution: "@babel/helper-annotate-as-pure@npm:7.25.9" + dependencies: + "@babel/types": ^7.25.9 + checksum: 41edda10df1ae106a9b4fe617bf7c6df77db992992afd46192534f5cff29f9e49a303231733782dd65c5f9409714a529f215325569f14282046e9d3b7a1ffb6c + languageName: node + linkType: hard + "@babel/helper-builder-binary-assignment-operator-visitor@npm:^7.18.6": version: 7.18.9 resolution: "@babel/helper-builder-binary-assignment-operator-visitor@npm:7.18.9" @@ -2954,6 +2963,23 @@ __metadata: languageName: node linkType: hard +"@babel/helper-create-class-features-plugin@npm:^7.25.9": + version: 7.25.9 + resolution: "@babel/helper-create-class-features-plugin@npm:7.25.9" + dependencies: + "@babel/helper-annotate-as-pure": ^7.25.9 + "@babel/helper-member-expression-to-functions": ^7.25.9 + "@babel/helper-optimise-call-expression": ^7.25.9 + "@babel/helper-replace-supers": ^7.25.9 + "@babel/helper-skip-transparent-expression-wrappers": ^7.25.9 + "@babel/traverse": ^7.25.9 + semver: ^6.3.1 + peerDependencies: + "@babel/core": ^7.0.0 + checksum: 91dd5f203ed04568c70b052e2f26dfaac7c146447196c00b8ecbb6d3d2f3b517abadb985d3321a19d143adaed6fe17f7f79f8f50e0c20e9d8ad83e1027b42424 + languageName: node + linkType: hard + "@babel/helper-create-regexp-features-plugin@npm:^7.16.7, @babel/helper-create-regexp-features-plugin@npm:^7.17.12": version: 7.17.12 resolution: "@babel/helper-create-regexp-features-plugin@npm:7.17.12" @@ -3017,6 +3043,19 @@ __metadata: languageName: node linkType: hard +"@babel/helper-create-regexp-features-plugin@npm:^7.25.9": + version: 7.26.3 + resolution: "@babel/helper-create-regexp-features-plugin@npm:7.26.3" + dependencies: + "@babel/helper-annotate-as-pure": ^7.25.9 + regexpu-core: ^6.2.0 + semver: ^6.3.1 + peerDependencies: + "@babel/core": ^7.0.0 + checksum: 50a27d8ce6da5c2fa0c62c132c4d27cfeb36e3233ff1e5220d643de3dafe49423b507382f0b72a696fce7486014b134c1e742f55438590f9405d26765b009af0 + languageName: node + linkType: hard + "@babel/helper-define-polyfill-provider@npm:^0.3.3": version: 0.3.3 resolution: "@babel/helper-define-polyfill-provider@npm:0.3.3" @@ -3258,6 +3297,16 @@ __metadata: languageName: node linkType: hard +"@babel/helper-member-expression-to-functions@npm:^7.25.9": + version: 7.25.9 + resolution: "@babel/helper-member-expression-to-functions@npm:7.25.9" + dependencies: + "@babel/traverse": ^7.25.9 + "@babel/types": ^7.25.9 + checksum: 8e2f1979b6d596ac2a8cbf17f2cf709180fefc274ac3331408b48203fe19134ed87800774ef18838d0275c3965130bae22980d90caed756b7493631d4b2cf961 + languageName: node + linkType: hard + "@babel/helper-module-imports@npm:^7.0.0, @babel/helper-module-imports@npm:^7.16.0, @babel/helper-module-imports@npm:^7.16.7, @babel/helper-module-imports@npm:^7.18.6": version: 7.18.6 resolution: "@babel/helper-module-imports@npm:7.18.6" @@ -3452,6 +3501,15 @@ __metadata: languageName: node linkType: hard +"@babel/helper-optimise-call-expression@npm:^7.25.9": + version: 7.25.9 + resolution: "@babel/helper-optimise-call-expression@npm:7.25.9" + dependencies: + "@babel/types": ^7.25.9 + checksum: f09d0ad60c0715b9a60c31841b3246b47d67650c512ce85bbe24a3124f1a4d66377df793af393273bc6e1015b0a9c799626c48e53747581c1582b99167cc65dc + languageName: node + linkType: hard + "@babel/helper-plugin-utils@npm:^7.0.0, @babel/helper-plugin-utils@npm:^7.10.4, @babel/helper-plugin-utils@npm:^7.12.13, @babel/helper-plugin-utils@npm:^7.13.0, @babel/helper-plugin-utils@npm:^7.14.5, @babel/helper-plugin-utils@npm:^7.16.7, @babel/helper-plugin-utils@npm:^7.17.12, @babel/helper-plugin-utils@npm:^7.18.6, @babel/helper-plugin-utils@npm:^7.19.0, @babel/helper-plugin-utils@npm:^7.8.0, @babel/helper-plugin-utils@npm:^7.8.3": version: 7.19.0 resolution: "@babel/helper-plugin-utils@npm:7.19.0" @@ -3494,6 +3552,13 @@ __metadata: languageName: node linkType: hard +"@babel/helper-plugin-utils@npm:^7.25.9": + version: 7.25.9 + resolution: "@babel/helper-plugin-utils@npm:7.25.9" + checksum: e19ec8acf0b696756e6d84531f532c5fe508dce57aa68c75572a77798bd04587a844a9a6c8ea7d62d673e21fdc174d091c9097fb29aea1c1b49f9c6eaa80f022 + languageName: node + linkType: hard + "@babel/helper-remap-async-to-generator@npm:^7.18.9": version: 7.18.9 resolution: "@babel/helper-remap-async-to-generator@npm:7.18.9" @@ -3627,6 +3692,19 @@ __metadata: languageName: node linkType: hard +"@babel/helper-replace-supers@npm:^7.25.9": + version: 7.25.9 + resolution: "@babel/helper-replace-supers@npm:7.25.9" + dependencies: + "@babel/helper-member-expression-to-functions": ^7.25.9 + "@babel/helper-optimise-call-expression": ^7.25.9 + "@babel/traverse": ^7.25.9 + peerDependencies: + "@babel/core": ^7.0.0 + checksum: 84f40e12520b7023e52d289bf9d569a06284879fe23bbbacad86bec5d978b2669769f11b073fcfeb1567d8c547168323005fda88607a4681ecaeb4a5cdd48bb9 + languageName: node + linkType: hard + "@babel/helper-simple-access@npm:^7.18.2, @babel/helper-simple-access@npm:^7.18.6": version: 7.19.4 resolution: "@babel/helper-simple-access@npm:7.19.4" @@ -3710,6 +3788,16 @@ __metadata: languageName: node linkType: hard +"@babel/helper-skip-transparent-expression-wrappers@npm:^7.25.9": + version: 7.25.9 + resolution: "@babel/helper-skip-transparent-expression-wrappers@npm:7.25.9" + dependencies: + "@babel/traverse": ^7.25.9 + "@babel/types": ^7.25.9 + checksum: fdbb5248932198bc26daa6abf0d2ac42cab9c2dbb75b7e9f40d425c8f28f09620b886d40e7f9e4e08ffc7aaa2cefe6fc2c44be7c20e81f7526634702fb615bdc + languageName: node + linkType: hard + "@babel/helper-split-export-declaration@npm:^7.16.7, @babel/helper-split-export-declaration@npm:^7.18.6": version: 7.18.6 resolution: "@babel/helper-split-export-declaration@npm:7.18.6" @@ -5153,6 +5241,18 @@ __metadata: languageName: node linkType: hard +"@babel/plugin-transform-class-properties@npm:^7.0.0-0": + version: 7.25.9 + resolution: "@babel/plugin-transform-class-properties@npm:7.25.9" + dependencies: + "@babel/helper-create-class-features-plugin": ^7.25.9 + "@babel/helper-plugin-utils": ^7.25.9 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: a8d69e2c285486b63f49193cbcf7a15e1d3a5f632c1c07d7a97f65306df7f554b30270b7378dde143f8b557d1f8f6336c643377943dec8ec405e4cd11e90b9ea + languageName: node + linkType: hard + "@babel/plugin-transform-class-properties@npm:^7.22.3": version: 7.22.3 resolution: "@babel/plugin-transform-class-properties@npm:7.22.3" @@ -5234,6 +5334,22 @@ __metadata: languageName: node linkType: hard +"@babel/plugin-transform-classes@npm:^7.0.0-0": + version: 7.25.9 + resolution: "@babel/plugin-transform-classes@npm:7.25.9" + dependencies: + "@babel/helper-annotate-as-pure": ^7.25.9 + "@babel/helper-compilation-targets": ^7.25.9 + "@babel/helper-plugin-utils": ^7.25.9 + "@babel/helper-replace-supers": ^7.25.9 + "@babel/traverse": ^7.25.9 + globals: ^11.1.0 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: d12584f72125314cc0fa8c77586ece2888d677788ac75f7393f5da574dfe4e45a556f7e3488fab29c8777ab3e5856d7a2d79f6df02834083aaa9d766440e3c68 + languageName: node + linkType: hard + "@babel/plugin-transform-classes@npm:^7.21.0": version: 7.21.0 resolution: "@babel/plugin-transform-classes@npm:7.21.0" @@ -7372,6 +7488,18 @@ __metadata: languageName: node linkType: hard +"@babel/plugin-transform-unicode-regex@npm:^7.0.0-0": + version: 7.25.9 + resolution: "@babel/plugin-transform-unicode-regex@npm:7.25.9" + dependencies: + "@babel/helper-create-regexp-features-plugin": ^7.25.9 + "@babel/helper-plugin-utils": ^7.25.9 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: e8baae867526e179467c6ef5280d70390fa7388f8763a19a27c21302dd59b121032568be080749514b097097ceb9af716bf4b90638f1b3cf689aa837ba20150f + languageName: node + linkType: hard + "@babel/plugin-transform-unicode-regex@npm:^7.22.5": version: 7.22.5 resolution: "@babel/plugin-transform-unicode-regex@npm:7.22.5" @@ -13522,7 +13650,7 @@ __metadata: react-native-pdf: 6.7.5 react-native-quick-actions: 0.3.13 react-native-quick-base64: 2.1.2 - react-native-reanimated: 3.12.1 + react-native-reanimated: 3.16.5 react-native-share: 10.2.1 react-native-spotlight-search: 2.0.0 react-native-svg: 15.2.0 @@ -40842,7 +40970,7 @@ __metadata: languageName: node linkType: hard -"jsesc@npm:^3.0.2": +"jsesc@npm:^3.0.2, jsesc@npm:~3.0.2": version: 3.0.2 resolution: "jsesc@npm:3.0.2" bin: @@ -49993,15 +50121,18 @@ __metadata: languageName: node linkType: hard -"react-native-reanimated@npm:3.12.1": - version: 3.12.1 - resolution: "react-native-reanimated@npm:3.12.1" +"react-native-reanimated@npm:3.16.5": + version: 3.16.5 + resolution: "react-native-reanimated@npm:3.16.5" dependencies: "@babel/plugin-transform-arrow-functions": ^7.0.0-0 + "@babel/plugin-transform-class-properties": ^7.0.0-0 + "@babel/plugin-transform-classes": ^7.0.0-0 "@babel/plugin-transform-nullish-coalescing-operator": ^7.0.0-0 "@babel/plugin-transform-optional-chaining": ^7.0.0-0 "@babel/plugin-transform-shorthand-properties": ^7.0.0-0 "@babel/plugin-transform-template-literals": ^7.0.0-0 + "@babel/plugin-transform-unicode-regex": ^7.0.0-0 "@babel/preset-typescript": ^7.16.7 convert-source-map: ^2.0.0 invariant: ^2.2.4 @@ -50009,7 +50140,7 @@ __metadata: "@babel/core": ^7.0.0-0 react: "*" react-native: "*" - checksum: 91575b3a20a5878f42d0302cf304ed46ff35c12ce717018c0bfb6af047bf675f224ab95de778daae483b139e66c5290a661635c06304065879b02a5926243e1c + checksum: 29d28dcf99acb2e3928963106a2860d15c9929712832d8d8437fb563691d0199884a63e925548fe5e4b6fc7a9008eadec3e0294b521d9466c875caf16de9c303 languageName: node linkType: hard @@ -51053,6 +51184,15 @@ __metadata: languageName: node linkType: hard +"regenerate-unicode-properties@npm:^10.2.0": + version: 10.2.0 + resolution: "regenerate-unicode-properties@npm:10.2.0" + dependencies: + regenerate: ^1.4.2 + checksum: d5c5fc13f8b8d7e16e791637a4bfef741f8d70e267d51845ee7d5404a32fa14c75b181c4efba33e4bff8b0000a2f13e9773593713dfe5b66597df4259275ce63 + languageName: node + linkType: hard + "regenerate@npm:^1.4.2": version: 1.4.2 resolution: "regenerate@npm:1.4.2" @@ -51175,6 +51315,20 @@ __metadata: languageName: node linkType: hard +"regexpu-core@npm:^6.2.0": + version: 6.2.0 + resolution: "regexpu-core@npm:6.2.0" + dependencies: + regenerate: ^1.4.2 + regenerate-unicode-properties: ^10.2.0 + regjsgen: ^0.8.0 + regjsparser: ^0.12.0 + unicode-match-property-ecmascript: ^2.0.0 + unicode-match-property-value-ecmascript: ^2.1.0 + checksum: 67d3c4a3f6c99bc80b5d690074a27e6f675be1c1739f8a9acf028fbc36f1a468472574ea65e331e217995198ba4404d7878f3cb3739a73552dd3c70d3fb7f8e6 + languageName: node + linkType: hard + "regjsgen@npm:^0.6.0": version: 0.6.0 resolution: "regjsgen@npm:0.6.0" @@ -51182,6 +51336,24 @@ __metadata: languageName: node linkType: hard +"regjsgen@npm:^0.8.0": + version: 0.8.0 + resolution: "regjsgen@npm:0.8.0" + checksum: a1d925ff14a4b2be774e45775ee6b33b256f89c42d480e6d85152d2133f18bd3d6af662161b226fa57466f7efec367eaf7ccd2a58c0ec2a1306667ba2ad07b0d + languageName: node + linkType: hard + +"regjsparser@npm:^0.12.0": + version: 0.12.0 + resolution: "regjsparser@npm:0.12.0" + dependencies: + jsesc: ~3.0.2 + bin: + regjsparser: bin/parser + checksum: 094b55b0ab3e1fd58f8ce5132a1d44dab08d91f7b0eea4132b0157b303ebb8ded20a9cbd893d25402d2aeddb23fac1f428ab4947b295d6fa51dd1c334a9e76f0 + languageName: node + linkType: hard + "regjsparser@npm:^0.8.2": version: 0.8.4 resolution: "regjsparser@npm:0.8.4"